app_meetme: Set default value for audio_buffers.
[asterisk/asterisk.git] / apps / app_meetme.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2007, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * SLA Implementation by:
9  * Russell Bryant <russell@digium.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief Meet me conference bridge and Shared Line Appearances
25  *
26  * \author Mark Spencer <markster@digium.com>
27  * \author (SLA) Russell Bryant <russell@digium.com>
28  * 
29  * \ingroup applications
30  */
31
32 /*! \li \ref app_meetme.c uses configuration file \ref meetme.conf
33  * \addtogroup configuration_file Configuration Files
34  */
35
36 /*! 
37  * \page meetme.conf meetme.conf
38  * \verbinclude meetme.conf.sample
39  */
40
41 /*** MODULEINFO
42         <depend>dahdi</depend>
43         <defaultenabled>no</defaultenabled>
44         <support_level>extended</support_level>
45         <replacement>app_confbridge</replacement>
46  ***/
47
48 #include "asterisk.h"
49
50 ASTERISK_REGISTER_FILE()
51
52 #include <dahdi/user.h>
53
54 #include "asterisk/lock.h"
55 #include "asterisk/file.h"
56 #include "asterisk/channel.h"
57 #include "asterisk/pbx.h"
58 #include "asterisk/module.h"
59 #include "asterisk/config.h"
60 #include "asterisk/app.h"
61 #include "asterisk/dsp.h"
62 #include "asterisk/musiconhold.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/say.h"
66 #include "asterisk/utils.h"
67 #include "asterisk/translate.h"
68 #include "asterisk/ulaw.h"
69 #include "asterisk/astobj2.h"
70 #include "asterisk/devicestate.h"
71 #include "asterisk/dial.h"
72 #include "asterisk/causes.h"
73 #include "asterisk/paths.h"
74 #include "asterisk/data.h"
75 #include "asterisk/test.h"
76 #include "asterisk/stasis.h"
77 #include "asterisk/stasis_channels.h"
78 #include "asterisk/stasis_message_router.h"
79 #include "asterisk/json.h"
80 #include "asterisk/format_compatibility.h"
81
82 #include "enter.h"
83 #include "leave.h"
84
85 /*** DOCUMENTATION
86         <application name="MeetMe" language="en_US">
87                 <synopsis>
88                         MeetMe conference bridge.
89                 </synopsis>
90                 <syntax>
91                         <parameter name="confno">
92                                 <para>The conference number</para>
93                         </parameter>
94                         <parameter name="options">
95                                 <optionlist>
96                                         <option name="a">
97                                                 <para>Set admin mode.</para>
98                                         </option>
99                                         <option name="A">
100                                                 <para>Set marked mode.</para>
101                                         </option>
102                                         <option name="b">
103                                                 <para>Run AGI script specified in <variable>MEETME_AGI_BACKGROUND</variable>
104                                                 Default: <literal>conf-background.agi</literal>.</para>
105                                                 <note><para>This does not work with non-DAHDI channels in the same
106                                                 conference).</para></note>
107                                         </option>
108                                         <option name="c">
109                                                 <para>Announce user(s) count on joining a conference.</para>
110                                         </option>
111                                         <option name="C">
112                                                 <para>Continue in dialplan when kicked out of conference.</para>
113                                         </option>
114                                         <option name="d">
115                                                 <para>Dynamically add conference.</para>
116                                         </option>
117                                         <option name="D">
118                                                 <para>Dynamically add conference, prompting for a PIN.</para>
119                                         </option>
120                                         <option name="e">
121                                                 <para>Select an empty conference.</para>
122                                         </option>
123                                         <option name="E">
124                                                 <para>Select an empty pinless conference.</para>
125                                         </option>
126                                         <option name="F">
127                                                 <para>Pass DTMF through the conference.</para>
128                                         </option>
129                                         <option name="G">
130                                                 <argument name="x" required="true">
131                                                         <para>The file to playback</para>
132                                                 </argument>
133                                                 <para>Play an intro announcement in conference.</para>
134                                         </option>
135                                         <option name="i">
136                                                 <para>Announce user join/leave with review.</para>
137                                         </option>
138                                         <option name="I">
139                                                 <para>Announce user join/leave without review.</para>
140                                         </option>
141                                         <option name="k">
142                                                 <para>Close the conference if there's only one active participant left at exit.</para>
143                                         </option>
144                                         <option name="l">
145                                                 <para>Set listen only mode (Listen only, no talking).</para>
146                                         </option>
147                                         <option name="m">
148                                                 <para>Set initially muted.</para>
149                                         </option>
150                                         <option name="M" hasparams="optional">
151                                                 <para>Enable music on hold when the conference has a single caller. Optionally,
152                                                 specify a musiconhold class to use. If one is not provided, it will use the
153                                                 channel's currently set music class, or <literal>default</literal>.</para>
154                                                 <argument name="class" required="true" />
155                                         </option>
156                                         <option name="n">
157                                                 <para>Disable the denoiser. By default, if <literal>func_speex</literal> is loaded, Asterisk
158                                                 will apply a denoiser to channels in the MeetMe conference. However, channel
159                                                 drivers that present audio with a varying rate will experience degraded
160                                                 performance with a denoiser attached. This parameter allows a channel joining
161                                                 the conference to choose not to have a denoiser attached without having to
162                                                 unload <literal>func_speex</literal>.</para>
163                                         </option>
164                                         <option name="o">
165                                                 <para>Set talker optimization - treats talkers who aren't speaking as
166                                                 being muted, meaning (a) No encode is done on transmission and (b)
167                                                 Received audio that is not registered as talking is omitted causing no
168                                                 buildup in background noise.</para>
169                                         </option>
170                                         <option name="p" hasparams="optional">
171                                                 <para>Allow user to exit the conference by pressing <literal>#</literal> (default)
172                                                 or any of the defined keys. Dial plan execution will continue at the next
173                                                 priority following MeetMe. The key used is set to channel variable
174                                                 <variable>MEETME_EXIT_KEY</variable>.</para>
175                                                 <argument name="keys" required="true" />
176                                                 <note>
177                                                         <para>Option <literal>s</literal> has priority for <literal>*</literal>
178                                                         since it cannot change its activation code.</para>
179                                                 </note>
180                                         </option>
181                                         <option name="P">
182                                                 <para>Always prompt for the pin even if it is specified.</para>
183                                         </option>
184                                         <option name="q">
185                                                 <para>Quiet mode (don't play enter/leave sounds).</para>
186                                         </option>
187                                         <option name="r">
188                                                 <para>Record conference (records as <variable>MEETME_RECORDINGFILE</variable>
189                                                 using format <variable>MEETME_RECORDINGFORMAT</variable>. Default filename is
190                                                 <literal>meetme-conf-rec-${CONFNO}-${UNIQUEID}</literal> and the default format is
191                                                 wav.</para>
192                                         </option>
193                                         <option name="s">
194                                                 <para>Present menu (user or admin) when <literal>*</literal> is received
195                                                 (send to menu).</para>
196                                         </option>
197                                         <option name="t">
198                                                 <para>Set talk only mode. (Talk only, no listening).</para>
199                                         </option>
200                                         <option name="T">
201                                                 <para>Set talker detection (sent to manager interface and meetme list).</para>
202                                         </option>
203                                         <option name="v" hasparams="optional">
204                                                 <para>Announce when a user is joining or leaving the conference.  Use the voicemail greeting as the announcement.
205                                                  If the i or I options are set, the application will fall back to them if no voicemail greeting can be found.</para>
206                                                 <argument name="mailbox@[context]" required="true">
207                                                         <para>The mailbox and voicemail context to play from.  If no context provided, assumed context is default.</para>
208                                                 </argument>
209                                         </option>
210                                         <option name="w" hasparams="optional">
211                                                 <para>Wait until the marked user enters the conference.</para>
212                                                 <argument name="secs" required="true" />
213                                         </option>
214                                         <option name="x">
215                                                 <para>Leave the conference when the last marked user leaves.</para>
216                                         </option>
217                                         <option name="X">
218                                                 <para>Allow user to exit the conference by entering a valid single digit
219                                                 extension <variable>MEETME_EXIT_CONTEXT</variable> or the current context
220                                                 if that variable is not defined.</para>
221                                                 <note>
222                                                         <para>Option <literal>s</literal> has priority for <literal>*</literal>
223                                                         since it cannot change its activation code.</para>
224                                                 </note>
225                                         </option>
226                                         <option name="1">
227                                                 <para>Do not play message when first person enters</para>
228                                         </option>
229                                         <option name="S">
230                                                 <para>Kick the user <replaceable>x</replaceable> seconds <emphasis>after</emphasis> he entered into
231                                                 the conference.</para>
232                                                 <argument name="x" required="true" />
233                                         </option>
234                                         <option name="L" argsep=":">
235                                                 <para>Limit the conference to <replaceable>x</replaceable> ms. Play a warning when
236                                                 <replaceable>y</replaceable> ms are left. Repeat the warning every <replaceable>z</replaceable> ms.
237                                                 The following special variables can be used with this option:</para>
238                                                 <variablelist>
239                                                         <variable name="CONF_LIMIT_TIMEOUT_FILE">
240                                                                 <para>File to play when time is up.</para>
241                                                         </variable>
242                                                         <variable name="CONF_LIMIT_WARNING_FILE">
243                                                                 <para>File to play as warning if <replaceable>y</replaceable> is defined. The
244                                                                 default is to say the time remaining.</para>
245                                                         </variable>
246                                                 </variablelist>
247                                                 <argument name="x" />
248                                                 <argument name="y" />
249                                                 <argument name="z" />
250                                         </option>
251                                 </optionlist>
252                         </parameter>
253                         <parameter name="pin" />
254                 </syntax>
255                 <description>
256                         <para>Enters the user into a specified MeetMe conference.  If the <replaceable>confno</replaceable>
257                         is omitted, the user will be prompted to enter one.  User can exit the conference by hangup, or
258                         if the <literal>p</literal> option is specified, by pressing <literal>#</literal>.</para>
259                         <note><para>The DAHDI kernel modules and a functional DAHDI timing source (see dahdi_test)
260                         must be present for conferencing to operate properly. In addition, the chan_dahdi channel driver
261                         must be loaded for the <literal>i</literal> and <literal>r</literal> options to operate at
262                         all.</para></note>
263                 </description>
264                 <see-also>
265                         <ref type="application">MeetMeCount</ref>
266                         <ref type="application">MeetMeAdmin</ref>
267                         <ref type="application">MeetMeChannelAdmin</ref>
268                 </see-also>
269         </application>
270         <application name="MeetMeCount" language="en_US">
271                 <synopsis>
272                         MeetMe participant count.
273                 </synopsis>
274                 <syntax>
275                         <parameter name="confno" required="true">
276                                 <para>Conference number.</para>
277                         </parameter>
278                         <parameter name="var" />
279                 </syntax>
280                 <description>
281                         <para>Plays back the number of users in the specified MeetMe conference.
282                         If <replaceable>var</replaceable> is specified, playback will be skipped and the value
283                         will be returned in the variable. Upon application completion, MeetMeCount will hangup
284                         the channel, unless priority <literal>n+1</literal> exists, in which case priority progress will
285                         continue.</para>
286                 </description>
287                 <see-also>
288                         <ref type="application">MeetMe</ref>
289                 </see-also>
290         </application>
291         <application name="MeetMeAdmin" language="en_US">
292                 <synopsis>
293                         MeetMe conference administration.
294                 </synopsis>
295                 <syntax>
296                         <parameter name="confno" required="true" />
297                         <parameter name="command" required="true">
298                                 <optionlist>
299                                         <option name="e">
300                                                 <para>Eject last user that joined.</para>
301                                         </option>
302                                         <option name="E">
303                                                 <para>Extend conference end time, if scheduled.</para>
304                                         </option>
305                                         <option name="k">
306                                                 <para>Kick one user out of conference.</para>
307                                         </option>
308                                         <option name="K">
309                                                 <para>Kick all users out of conference.</para>
310                                         </option>
311                                         <option name="l">
312                                                 <para>Unlock conference.</para>
313                                         </option>
314                                         <option name="L">
315                                                 <para>Lock conference.</para>
316                                         </option>
317                                         <option name="m">
318                                                 <para>Unmute one user.</para>
319                                         </option>
320                                         <option name="M">
321                                                 <para>Mute one user.</para>
322                                         </option>
323                                         <option name="n">
324                                                 <para>Unmute all users in the conference.</para>
325                                         </option>
326                                         <option name="N">
327                                                 <para>Mute all non-admin users in the conference.</para>
328                                         </option>
329                                         <option name="r">
330                                                 <para>Reset one user's volume settings.</para>
331                                         </option>
332                                         <option name="R">
333                                                 <para>Reset all users volume settings.</para>
334                                         </option>
335                                         <option name="s">
336                                                 <para>Lower entire conference speaking volume.</para>
337                                         </option>
338                                         <option name="S">
339                                                 <para>Raise entire conference speaking volume.</para>
340                                         </option>
341                                         <option name="t">
342                                                 <para>Lower one user's talk volume.</para>
343                                         </option>
344                                         <option name="T">
345                                                 <para>Raise one user's talk volume.</para>
346                                         </option>
347                                         <option name="u">
348                                                 <para>Lower one user's listen volume.</para>
349                                         </option>
350                                         <option name="U">
351                                                 <para>Raise one user's listen volume.</para>
352                                         </option>
353                                         <option name="v">
354                                                 <para>Lower entire conference listening volume.</para>
355                                         </option>
356                                         <option name="V">
357                                                 <para>Raise entire conference listening volume.</para>
358                                         </option>
359                                 </optionlist>
360                         </parameter>
361                         <parameter name="user" />
362                 </syntax>
363                 <description>
364                         <para>Run admin <replaceable>command</replaceable> for conference <replaceable>confno</replaceable>.</para>
365                         <para>Will additionally set the variable <variable>MEETMEADMINSTATUS</variable> with one of
366                         the following values:</para>
367                         <variablelist>
368                                 <variable name="MEETMEADMINSTATUS">
369                                         <value name="NOPARSE">
370                                                 Invalid arguments.
371                                         </value>
372                                         <value name="NOTFOUND">
373                                                 User specified was not found.
374                                         </value>
375                                         <value name="FAILED">
376                                                 Another failure occurred.
377                                         </value>
378                                         <value name="OK">
379                                                 The operation was completed successfully.
380                                         </value>
381                                 </variable>
382                         </variablelist>
383                 </description>
384                 <see-also>
385                         <ref type="application">MeetMe</ref>
386                 </see-also>
387         </application>
388         <application name="MeetMeChannelAdmin" language="en_US">
389                 <synopsis>
390                         MeetMe conference Administration (channel specific).
391                 </synopsis>
392                 <syntax>
393                         <parameter name="channel" required="true" />
394                         <parameter name="command" required="true">
395                                 <optionlist>
396                                         <option name="k">
397                                                 <para>Kick the specified user out of the conference he is in.</para>
398                                         </option>
399                                         <option name="m">
400                                                 <para>Unmute the specified user.</para>
401                                         </option>
402                                         <option name="M">
403                                                 <para>Mute the specified user.</para>
404                                         </option>
405                                 </optionlist>
406                         </parameter>
407                 </syntax>
408                 <description>
409                         <para>Run admin <replaceable>command</replaceable> for a specific
410                         <replaceable>channel</replaceable> in any conference.</para>
411                 </description>
412         </application>
413         <application name="SLAStation" language="en_US">
414                 <synopsis>
415                         Shared Line Appearance Station.
416                 </synopsis>
417                 <syntax>
418                         <parameter name="station" required="true">
419                                 <para>Station name</para>
420                         </parameter>
421                 </syntax>
422                 <description>
423                         <para>This application should be executed by an SLA station. The argument depends
424                         on how the call was initiated. If the phone was just taken off hook, then the argument
425                         <replaceable>station</replaceable> should be just the station name. If the call was
426                         initiated by pressing a line key, then the station name should be preceded by an underscore
427                         and the trunk name associated with that line button.</para>
428                         <para>For example: <literal>station1_line1</literal></para>
429                         <para>On exit, this application will set the variable <variable>SLASTATION_STATUS</variable> to
430                         one of the following values:</para>
431                         <variablelist>
432                                 <variable name="SLASTATION_STATUS">
433                                         <value name="FAILURE" />
434                                         <value name="CONGESTION" />
435                                         <value name="SUCCESS" />
436                                 </variable>
437                         </variablelist>
438                 </description>
439         </application>
440         <application name="SLATrunk" language="en_US">
441                 <synopsis>
442                         Shared Line Appearance Trunk.
443                 </synopsis>
444                 <syntax>
445                         <parameter name="trunk" required="true">
446                                 <para>Trunk name</para>
447                         </parameter>
448                         <parameter name="options">
449                                 <optionlist>
450                                         <option name="M" hasparams="optional">
451                                                 <para>Play back the specified MOH <replaceable>class</replaceable>
452                                                 instead of ringing</para>
453                                                 <argument name="class" required="true" />
454                                         </option>
455                                 </optionlist>
456                         </parameter>
457                 </syntax>
458                 <description>
459                         <para>This application should be executed by an SLA trunk on an inbound call. The channel calling
460                         this application should correspond to the SLA trunk with the name <replaceable>trunk</replaceable>
461                         that is being passed as an argument.</para>
462                         <para>On exit, this application will set the variable <variable>SLATRUNK_STATUS</variable> to
463                         one of the following values:</para>
464                         <variablelist>
465                                 <variable name="SLATRUNK_STATUS">
466                                         <value name="FAILURE" />
467                                         <value name="SUCCESS" />
468                                         <value name="UNANSWERED" />
469                                         <value name="RINGTIMEOUT" />
470                                 </variable>
471                         </variablelist>
472                 </description>
473         </application>
474         <function name="MEETME_INFO" language="en_US">
475                 <synopsis>
476                         Query a given conference of various properties.
477                 </synopsis>
478                 <syntax>
479                         <parameter name="keyword" required="true">
480                                 <para>Options:</para>
481                                 <enumlist>
482                                         <enum name="lock">
483                                                 <para>Boolean of whether the corresponding conference is locked.</para>
484                                         </enum>
485                                         <enum name="parties">
486                                                 <para>Number of parties in a given conference</para>
487                                         </enum>
488                                         <enum name="activity">
489                                                 <para>Duration of conference in seconds.</para>
490                                         </enum>
491                                         <enum name="dynamic">
492                                                 <para>Boolean of whether the corresponding conference is dynamic.</para>
493                                         </enum>
494                                 </enumlist>
495                         </parameter>
496                         <parameter name="confno" required="true">
497                                 <para>Conference number to retrieve information from.</para>
498                         </parameter>
499                 </syntax>
500                 <description />
501                 <see-also>
502                         <ref type="application">MeetMe</ref>
503                         <ref type="application">MeetMeCount</ref>
504                         <ref type="application">MeetMeAdmin</ref>
505                         <ref type="application">MeetMeChannelAdmin</ref>
506                 </see-also>
507         </function>
508         <manager name="MeetmeMute" language="en_US">
509                 <synopsis>
510                         Mute a Meetme user.
511                 </synopsis>
512                 <syntax>
513                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
514                         <parameter name="Meetme" required="true" />
515                         <parameter name="Usernum" required="true" />
516                 </syntax>
517                 <description>
518                 </description>
519         </manager>
520         <manager name="MeetmeUnmute" language="en_US">
521                 <synopsis>
522                         Unmute a Meetme user.
523                 </synopsis>
524                 <syntax>
525                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
526                         <parameter name="Meetme" required="true" />
527                         <parameter name="Usernum" required="true" />
528                 </syntax>
529                 <description>
530                 </description>
531         </manager>
532         <manager name="MeetmeList" language="en_US">
533                 <synopsis>
534                         List participants in a conference.
535                 </synopsis>
536                 <syntax>
537                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
538                         <parameter name="Conference" required="false">
539                                 <para>Conference number.</para>
540                         </parameter>
541                 </syntax>
542                 <description>
543                         <para>Lists all users in a particular MeetMe conference.
544                         MeetmeList will follow as separate events, followed by a final event called
545                         MeetmeListComplete.</para>
546                 </description>
547         </manager>
548         <manager name="MeetmeListRooms" language="en_US">
549                 <synopsis>
550                         List active conferences.
551                 </synopsis>
552                 <syntax>
553                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
554                 </syntax>
555                 <description>
556                         <para>Lists data about all active conferences.
557                                 MeetmeListRooms will follow as separate events, followed by a final event called
558                                 MeetmeListRoomsComplete.</para>
559                 </description>
560         </manager>
561         <managerEvent language="en_US" name="MeetmeJoin">
562                 <managerEventInstance class="EVENT_FLAG_CALL">
563                         <synopsis>Raised when a user joins a MeetMe conference.</synopsis>
564                         <syntax>
565                                 <parameter name="Meetme">
566                                         <para>The identifier for the MeetMe conference.</para>
567                                 </parameter>
568                                 <parameter name="Usernum">
569                                         <para>The identifier of the MeetMe user who joined.</para>
570                                 </parameter>
571                                 <channel_snapshot/>
572                         </syntax>
573                         <see-also>
574                                 <ref type="managerEvent">MeetmeLeave</ref>
575                                 <ref type="application">MeetMe</ref>
576                         </see-also>
577                 </managerEventInstance>
578         </managerEvent>
579         <managerEvent language="en_US" name="MeetmeLeave">
580                 <managerEventInstance class="EVENT_FLAG_CALL">
581                         <synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
582                         <syntax>
583                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
584                                 <channel_snapshot/>
585                                 <parameter name="Duration">
586                                         <para>The length of time in seconds that the Meetme user was in the conference.</para>
587                                 </parameter>
588                         </syntax>
589                         <see-also>
590                                 <ref type="managerEvent">MeetmeJoin</ref>
591                         </see-also>
592                 </managerEventInstance>
593         </managerEvent>
594         <managerEvent language="en_US" name="MeetmeEnd">
595                 <managerEventInstance class="EVENT_FLAG_CALL">
596                         <synopsis>Raised when a MeetMe conference ends.</synopsis>
597                         <syntax>
598                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
599                         </syntax>
600                         <see-also>
601                                 <ref type="managerEvent">MeetmeJoin</ref>
602                         </see-also>
603                 </managerEventInstance>
604         </managerEvent>
605         <managerEvent language="en_US" name="MeetmeTalkRequest">
606                 <managerEventInstance class="EVENT_FLAG_CALL">
607                         <synopsis>Raised when a MeetMe user has started talking.</synopsis>
608                         <syntax>
609                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
610                                 <channel_snapshot/>
611                                 <parameter name="Duration">
612                                         <para>The length of time in seconds that the Meetme user has been in the conference at the time of this event.</para>
613                                 </parameter>
614                                 <parameter name="Status">
615                                         <enumlist>
616                                                 <enum name="on"/>
617                                                 <enum name="off"/>
618                                         </enumlist>
619                                 </parameter>
620                         </syntax>
621                 </managerEventInstance>
622         </managerEvent>
623         <managerEvent language="en_US" name="MeetmeTalking">
624                 <managerEventInstance class="EVENT_FLAG_CALL">
625                         <synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
626                         <syntax>
627                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
628                                 <channel_snapshot/>
629                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
630                         </syntax>
631                 </managerEventInstance>
632         </managerEvent>
633         <managerEvent language="en_US" name="MeetmeMute">
634                 <managerEventInstance class="EVENT_FLAG_CALL">
635                         <synopsis>Raised when a MeetMe user is muted or unmuted.</synopsis>
636                         <syntax>
637                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
638                                 <channel_snapshot/>
639                                 <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
640                         </syntax>
641                 </managerEventInstance>
642         </managerEvent>
643  ***/
644
645 #define CONFIG_FILE_NAME        "meetme.conf"
646 #define SLA_CONFIG_FILE         "sla.conf"
647 #define STR_CONCISE                     "concise"
648
649 /*! each buffer is 20ms, so this is 640ms total */
650 #define DEFAULT_AUDIO_BUFFERS  32
651
652 /*! String format for scheduled conferences */
653 #define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
654
655 enum {
656         ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
657         ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
658         ADMINFLAG_KICKME =    (1 << 3),  /*!< User has been kicked */
659         /*! User has requested to speak */
660         ADMINFLAG_T_REQUEST = (1 << 4),
661         ADMINFLAG_HANGUP = (1 << 5),    /*!< User will be leaving the conference */
662 };
663
664 #define MEETME_DELAYDETECTTALK     300
665 #define MEETME_DELAYDETECTENDTALK  1000
666
667 #define AST_FRAME_BITS  32
668
669 enum volume_action {
670         VOL_UP,
671         VOL_DOWN
672 };
673
674 enum entrance_sound {
675         ENTER,
676         LEAVE
677 };
678
679 enum recording_state {
680         MEETME_RECORD_OFF,
681         MEETME_RECORD_STARTED,
682         MEETME_RECORD_ACTIVE,
683         MEETME_RECORD_TERMINATE
684 };
685
686 #define CONF_SIZE  320
687
688 enum {
689         /*! user has admin access on the conference */
690         CONFFLAG_ADMIN = (1 << 0),
691         /*! If set the user can only receive audio from the conference */
692         CONFFLAG_MONITOR = (1 << 1),
693         /*! If set asterisk will exit conference when key defined in p() option is pressed */
694         CONFFLAG_KEYEXIT = (1 << 2),
695         /*! If set asterisk will provide a menu to the user when '*' is pressed */
696         CONFFLAG_STARMENU = (1 << 3),
697         /*! If set the use can only send audio to the conference */
698         CONFFLAG_TALKER = (1 << 4),
699         /*! If set there will be no enter or leave sounds */
700         CONFFLAG_QUIET = (1 << 5),
701         /*! If set, when user joins the conference, they will be told the number 
702          *  of users that are already in */
703         CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
704         /*! Set to run AGI Script in Background */
705         CONFFLAG_AGI = (1 << 7),
706         /*! Set to have music on hold when user is alone in conference */
707         CONFFLAG_MOH = (1 << 8),
708         /*! If set, the channel will leave the conference if all marked users leave */
709         CONFFLAG_MARKEDEXIT = (1 << 9),
710         /*! If set, the MeetMe will wait until a marked user enters */
711         CONFFLAG_WAITMARKED = (1 << 10),
712         /*! If set, the MeetMe will exit to the specified context */
713         CONFFLAG_EXIT_CONTEXT = (1 << 11),
714         /*! If set, the user will be marked */
715         CONFFLAG_MARKEDUSER = (1 << 12),
716         /*! If set, user will be ask record name on entry of conference */
717         CONFFLAG_INTROUSER = (1 << 13),
718         /*! If set, the MeetMe will be recorded */
719         CONFFLAG_RECORDCONF = (1<< 14),
720         /*! If set, the user will be monitored if the user is talking or not */
721         CONFFLAG_MONITORTALKER = (1 << 15),
722         CONFFLAG_DYNAMIC = (1 << 16),
723         CONFFLAG_DYNAMICPIN = (1 << 17),
724         CONFFLAG_EMPTY = (1 << 18),
725         CONFFLAG_EMPTYNOPIN = (1 << 19),
726         CONFFLAG_ALWAYSPROMPT = (1 << 20),
727         /*! If set, treat talking users as muted users */
728         CONFFLAG_OPTIMIZETALKER = (1 << 21),
729         /*! If set, won't speak the extra prompt when the first person 
730          *  enters the conference */
731         CONFFLAG_NOONLYPERSON = (1 << 22),
732         /*! If set, user will be asked to record name on entry of conference 
733          *  without review */
734         CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
735         /*! If set, the user will be initially self-muted */
736         CONFFLAG_STARTMUTED = (1 << 24),
737         /*! Pass DTMF through the conference */
738         CONFFLAG_PASS_DTMF = (1 << 25),
739         CONFFLAG_SLA_STATION = (1 << 26),
740         CONFFLAG_SLA_TRUNK = (1 << 27),
741         /*! If set, the user should continue in the dialplan if kicked out */
742         CONFFLAG_KICK_CONTINUE = (1 << 28),
743         CONFFLAG_DURATION_STOP = (1 << 29),
744         CONFFLAG_DURATION_LIMIT = (1 << 30),
745 };
746
747 /* These flags are defined separately because we ran out of bits that an enum can be used to represent. 
748    If you add new flags, be sure to do it in the same way that these are. */
749 /*! Do not write any audio to this channel until the state is up. */
750 #define CONFFLAG_NO_AUDIO_UNTIL_UP  (1ULL << 31)
751 #define CONFFLAG_INTROMSG           (1ULL << 32) /*!< If set play an intro announcement at start of conference */
752 #define CONFFLAG_INTROUSER_VMREC    (1ULL << 33)
753 /*! If there's only one person left in a conference when someone leaves, kill the conference */
754 #define CONFFLAG_KILL_LAST_MAN_STANDING (1ULL << 34)
755 /*! If set, don't enable a denoiser for the channel */
756 #define CONFFLAG_DONT_DENOISE       (1ULL << 35)
757
758 enum {
759         OPT_ARG_WAITMARKED = 0,
760         OPT_ARG_EXITKEYS   = 1,
761         OPT_ARG_DURATION_STOP = 2,
762         OPT_ARG_DURATION_LIMIT = 3,
763         OPT_ARG_MOH_CLASS = 4,
764         OPT_ARG_INTROMSG = 5,
765         OPT_ARG_INTROUSER_VMREC = 6,
766         OPT_ARG_ARRAY_SIZE = 7,
767 };
768
769 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
770         AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
771         AST_APP_OPTION('a', CONFFLAG_ADMIN ),
772         AST_APP_OPTION('b', CONFFLAG_AGI ),
773         AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
774         AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
775         AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
776         AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
777         AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
778         AST_APP_OPTION('e', CONFFLAG_EMPTY ),
779         AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
780         AST_APP_OPTION_ARG('G', CONFFLAG_INTROMSG, OPT_ARG_INTROMSG ),
781         AST_APP_OPTION_ARG('v', CONFFLAG_INTROUSER_VMREC , OPT_ARG_INTROUSER_VMREC),
782         AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
783         AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
784         AST_APP_OPTION('k', CONFFLAG_KILL_LAST_MAN_STANDING ),
785         AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ),
786         AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
787         AST_APP_OPTION('n', CONFFLAG_DONT_DENOISE ),
788         AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
789         AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
790         AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ),
791         AST_APP_OPTION('q', CONFFLAG_QUIET ),
792         AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
793         AST_APP_OPTION('s', CONFFLAG_STARMENU ),
794         AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
795         AST_APP_OPTION('l', CONFFLAG_MONITOR ),
796         AST_APP_OPTION('t', CONFFLAG_TALKER ),
797         AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
798         AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
799         AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
800         AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
801         AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP),
802         AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
803 END_OPTIONS );
804
805 static const char * const app = "MeetMe";
806 static const char * const app2 = "MeetMeCount";
807 static const char * const app3 = "MeetMeAdmin";
808 static const char * const app4 = "MeetMeChannelAdmin";
809 static const char * const slastation_app = "SLAStation";
810 static const char * const slatrunk_app = "SLATrunk";
811
812 /* Lookup RealTime conferences based on confno and current time */
813 static int rt_schedule;
814 static int fuzzystart;
815 static int earlyalert;
816 static int endalert;
817 static int extendby;
818
819 /*! Log participant count to the RealTime backend */
820 static int rt_log_members;
821
822 #define MAX_CONFNUM 80
823 #define MAX_PIN     80
824 #define OPTIONS_LEN 100
825
826 /* Enough space for "<conference #>,<pin>,<admin pin>" followed by a 0 byte. */
827 #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
828
829 enum announcetypes {
830         CONF_HASJOIN,
831         CONF_HASLEFT
832 };
833
834 struct announce_listitem {
835         AST_LIST_ENTRY(announce_listitem) entry;
836         char namerecloc[PATH_MAX];                              /*!< Name Recorded file Location */
837         char language[MAX_LANGUAGE];
838         struct ast_channel *confchan;
839         int confusers;
840         int vmrec;
841         enum announcetypes announcetype;
842 };
843
844 /*! \brief The MeetMe Conference object */
845 struct ast_conference {
846         ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
847         ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
848         char confno[MAX_CONFNUM];               /*!< Conference */
849         struct ast_channel *chan;               /*!< Announcements channel */
850         struct ast_channel *lchan;              /*!< Listen/Record channel */
851         int fd;                                 /*!< Announcements fd */
852         int dahdiconf;                            /*!< DAHDI Conf # */
853         int users;                              /*!< Number of active users */
854         int markedusers;                        /*!< Number of marked users */
855         int maxusers;                           /*!< Participant limit if scheduled */
856         int endalert;                           /*!< When to play conf ending message */
857         time_t start;                           /*!< Start time (s) */
858         int refcount;                           /*!< reference count of usage */
859         enum recording_state recording:2;       /*!< recording status */
860         unsigned int isdynamic:1;               /*!< Created on the fly? */
861         unsigned int locked:1;                  /*!< Is the conference locked? */
862         unsigned int gmuted:1;                  /*!< Is the conference globally muted? (all non-admins) */
863         pthread_t recordthread;                 /*!< thread for recording */
864         ast_mutex_t recordthreadlock;           /*!< control threads trying to start recordthread */
865         pthread_attr_t attr;                    /*!< thread attribute */
866         char *recordingfilename;                /*!< Filename to record the Conference into */
867         char *recordingformat;                  /*!< Format to record the Conference in */
868         char pin[MAX_PIN];                      /*!< If protected by a PIN */
869         char pinadmin[MAX_PIN];                 /*!< If protected by a admin PIN */
870         char uniqueid[32];
871         long endtime;                           /*!< When to end the conf if scheduled */
872         const char *useropts;                   /*!< RealTime user flags */
873         const char *adminopts;                  /*!< RealTime moderator flags */
874         const char *bookid;                     /*!< RealTime conference id */
875         struct ast_frame *transframe[32];
876         struct ast_frame *origframe;
877         struct ast_trans_pvt *transpath[32];
878         struct ao2_container *usercontainer;
879         AST_LIST_ENTRY(ast_conference) list;
880         /* announce_thread related data */
881         pthread_t announcethread;
882         ast_mutex_t announcethreadlock;
883         unsigned int announcethread_stop:1;
884         ast_cond_t announcelist_addition;
885         AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist;
886         ast_mutex_t announcelistlock;
887 };
888
889 static AST_LIST_HEAD_STATIC(confs, ast_conference);
890
891 static unsigned int conf_map[1024] = {0, };
892
893 struct volume {
894         int desired;                            /*!< Desired volume adjustment */
895         int actual;                             /*!< Actual volume adjustment (for channels that can't adjust) */
896 };
897
898 /*! \brief The MeetMe User object */
899 struct ast_conf_user {
900         int user_no;                            /*!< User Number */
901         struct ast_flags64 userflags;           /*!< Flags as set in the conference */
902         int adminflags;                         /*!< Flags set by the Admin */
903         struct ast_channel *chan;               /*!< Connected channel */
904         int talking;                            /*!< Is user talking */
905         int dahdichannel;                       /*!< Is a DAHDI channel */
906         char usrvalue[50];                      /*!< Custom User Value */
907         char namerecloc[PATH_MAX];              /*!< Name Recorded file Location */
908         time_t jointime;                        /*!< Time the user joined the conference */
909         time_t kicktime;                        /*!< Time the user will be kicked from the conference */
910         struct timeval start_time;              /*!< Time the user entered into the conference */
911         long timelimit;                         /*!< Time limit for the user to be in the conference L(x:y:z) */
912         long play_warning;                      /*!< Play a warning when 'y' ms are left */
913         long warning_freq;                      /*!< Repeat the warning every 'z' ms */
914         const char *warning_sound;              /*!< File to play as warning if 'y' is defined */
915         const char *end_sound;                  /*!< File to play when time is up. */
916         struct volume talk;
917         struct volume listen;
918         AST_LIST_ENTRY(ast_conf_user) list;
919 };
920
921 enum sla_which_trunk_refs {
922         ALL_TRUNK_REFS,
923         INACTIVE_TRUNK_REFS,
924 };
925
926 enum sla_trunk_state {
927         SLA_TRUNK_STATE_IDLE,
928         SLA_TRUNK_STATE_RINGING,
929         SLA_TRUNK_STATE_UP,
930         SLA_TRUNK_STATE_ONHOLD,
931         SLA_TRUNK_STATE_ONHOLD_BYME,
932 };
933
934 enum sla_hold_access {
935         /*! This means that any station can put it on hold, and any station
936          * can retrieve the call from hold. */
937         SLA_HOLD_OPEN,
938         /*! This means that only the station that put the call on hold may
939          * retrieve it from hold. */
940         SLA_HOLD_PRIVATE,
941 };
942
943 struct sla_trunk_ref;
944
945 struct sla_station {
946         AST_RWLIST_ENTRY(sla_station) entry;
947         AST_DECLARE_STRING_FIELDS(
948                 AST_STRING_FIELD(name); 
949                 AST_STRING_FIELD(device);       
950                 AST_STRING_FIELD(autocontext);  
951         );
952         AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
953         struct ast_dial *dial;
954         /*! Ring timeout for this station, for any trunk.  If a ring timeout
955          *  is set for a specific trunk on this station, that will take
956          *  priority over this value. */
957         unsigned int ring_timeout;
958         /*! Ring delay for this station, for any trunk.  If a ring delay
959          *  is set for a specific trunk on this station, that will take
960          *  priority over this value. */
961         unsigned int ring_delay;
962         /*! This option uses the values in the sla_hold_access enum and sets the
963          * access control type for hold on this station. */
964         unsigned int hold_access:1;
965         /*! Mark used during reload processing */
966         unsigned int mark:1;
967 };
968
969 /*!
970  * \brief A reference to a station
971  *
972  * This struct looks near useless at first glance.  However, its existence
973  * in the list of stations in sla_trunk means that this station references
974  * that trunk.  We use the mark to keep track of whether it needs to be
975  * removed from the sla_trunk's list of stations during a reload.
976  */
977 struct sla_station_ref {
978         AST_LIST_ENTRY(sla_station_ref) entry;
979         struct sla_station *station;
980         /*! Mark used during reload processing */
981         unsigned int mark:1;
982 };
983
984 struct sla_trunk {
985         AST_DECLARE_STRING_FIELDS(
986                 AST_STRING_FIELD(name);
987                 AST_STRING_FIELD(device);
988                 AST_STRING_FIELD(autocontext);  
989         );
990         AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
991         /*! Number of stations that use this trunk */
992         unsigned int num_stations;
993         /*! Number of stations currently on a call with this trunk */
994         unsigned int active_stations;
995         /*! Number of stations that have this trunk on hold. */
996         unsigned int hold_stations;
997         struct ast_channel *chan;
998         unsigned int ring_timeout;
999         /*! If set to 1, no station will be able to join an active call with
1000          *  this trunk. */
1001         unsigned int barge_disabled:1;
1002         /*! This option uses the values in the sla_hold_access enum and sets the
1003          * access control type for hold on this trunk. */
1004         unsigned int hold_access:1;
1005         /*! Whether this trunk is currently on hold, meaning that once a station
1006          *  connects to it, the trunk channel needs to have UNHOLD indicated to it. */
1007         unsigned int on_hold:1;
1008         /*! Mark used during reload processing */
1009         unsigned int mark:1;
1010 };
1011
1012 /*!
1013  * \brief A station's reference to a trunk
1014  *
1015  * An sla_station keeps a list of trunk_refs.  This holds metadata about the
1016  * stations usage of the trunk.
1017  */
1018 struct sla_trunk_ref {
1019         AST_LIST_ENTRY(sla_trunk_ref) entry;
1020         struct sla_trunk *trunk;
1021         enum sla_trunk_state state;
1022         struct ast_channel *chan;
1023         /*! Ring timeout to use when this trunk is ringing on this specific
1024          *  station.  This takes higher priority than a ring timeout set at
1025          *  the station level. */
1026         unsigned int ring_timeout;
1027         /*! Ring delay to use when this trunk is ringing on this specific
1028          *  station.  This takes higher priority than a ring delay set at
1029          *  the station level. */
1030         unsigned int ring_delay;
1031         /*! Mark used during reload processing */
1032         unsigned int mark:1;
1033 };
1034
1035 static struct ao2_container *sla_stations;
1036 static struct ao2_container *sla_trunks;
1037
1038 static const char sla_registrar[] = "SLA";
1039
1040 /*! \brief Event types that can be queued up for the SLA thread */
1041 enum sla_event_type {
1042         /*! A station has put the call on hold */
1043         SLA_EVENT_HOLD,
1044         /*! The state of a dial has changed */
1045         SLA_EVENT_DIAL_STATE,
1046         /*! The state of a ringing trunk has changed */
1047         SLA_EVENT_RINGING_TRUNK,
1048 };
1049
1050 struct sla_event {
1051         enum sla_event_type type;
1052         struct sla_station *station;
1053         struct sla_trunk_ref *trunk_ref;
1054         AST_LIST_ENTRY(sla_event) entry;
1055 };
1056
1057 /*! \brief A station that failed to be dialed 
1058  * \note Only used by the SLA thread. */
1059 struct sla_failed_station {
1060         struct sla_station *station;
1061         struct timeval last_try;
1062         AST_LIST_ENTRY(sla_failed_station) entry;
1063 };
1064
1065 /*! \brief A trunk that is ringing */
1066 struct sla_ringing_trunk {
1067         struct sla_trunk *trunk;
1068         /*! The time that this trunk started ringing */
1069         struct timeval ring_begin;
1070         AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
1071         AST_LIST_ENTRY(sla_ringing_trunk) entry;
1072 };
1073
1074 enum sla_station_hangup {
1075         SLA_STATION_HANGUP_NORMAL,
1076         SLA_STATION_HANGUP_TIMEOUT,
1077 };
1078
1079 /*! \brief A station that is ringing */
1080 struct sla_ringing_station {
1081         struct sla_station *station;
1082         /*! The time that this station started ringing */
1083         struct timeval ring_begin;
1084         AST_LIST_ENTRY(sla_ringing_station) entry;
1085 };
1086
1087 /*!
1088  * \brief A structure for data used by the sla thread
1089  */
1090 static struct {
1091         /*! The SLA thread ID */
1092         pthread_t thread;
1093         ast_cond_t cond;
1094         ast_mutex_t lock;
1095         AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
1096         AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
1097         AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
1098         AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
1099         unsigned int stop:1;
1100         /*! Attempt to handle CallerID, even though it is known not to work
1101          *  properly in some situations. */
1102         unsigned int attempt_callerid:1;
1103 } sla = {
1104         .thread = AST_PTHREADT_NULL,
1105 };
1106
1107 /*! \brief The number of audio buffers to be allocated on pseudo channels
1108  *  when in a conference */
1109 static int audio_buffers;
1110
1111 /*! \brief Map 'volume' levels from -5 through +5 into decibel (dB) 
1112  *    settings for channel drivers.
1113  *
1114  *  \note these are not a straight linear-to-dB
1115  *  conversion... the numbers have been modified
1116  *  to give the user a better level of adjustability.
1117  */
1118 static const char gain_map[] = {
1119         -15,
1120         -13,
1121         -10,
1122         -6,
1123         0,
1124         0,
1125         0,
1126         6,
1127         10,
1128         13,
1129         15,
1130 };
1131
1132 /* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
1133 static struct stasis_message_router *meetme_event_message_router;
1134
1135 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
1136 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
1137 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
1138 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
1139 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
1140 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
1141
1142 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1143         struct stasis_message *message);
1144
1145 static void meetme_stasis_cleanup(void)
1146 {
1147         if (meetme_event_message_router) {
1148                 stasis_message_router_unsubscribe(meetme_event_message_router);
1149                 meetme_event_message_router = NULL;
1150         }
1151
1152         STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
1153         STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
1154         STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
1155         STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
1156         STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
1157         STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
1158 }
1159
1160 static int meetme_stasis_init(void)
1161 {
1162
1163         STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
1164         STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
1165         STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
1166         STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
1167         STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
1168         STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
1169
1170         meetme_event_message_router = stasis_message_router_create(
1171                 ast_channel_topic_all_cached());
1172
1173         if (!meetme_event_message_router) {
1174                 meetme_stasis_cleanup();
1175                 return -1;
1176         }
1177
1178         if (stasis_message_router_add(meetme_event_message_router,
1179                         meetme_join_type(),
1180                         meetme_stasis_cb,
1181                         NULL)) {
1182                 meetme_stasis_cleanup();
1183                 return -1;
1184         }
1185
1186         if (stasis_message_router_add(meetme_event_message_router,
1187                         meetme_leave_type(),
1188                         meetme_stasis_cb,
1189                         NULL)) {
1190                 meetme_stasis_cleanup();
1191                 return -1;
1192         }
1193
1194         if (stasis_message_router_add(meetme_event_message_router,
1195                         meetme_end_type(),
1196                         meetme_stasis_cb,
1197                         NULL)) {
1198                 meetme_stasis_cleanup();
1199                 return -1;
1200         }
1201
1202         if (stasis_message_router_add(meetme_event_message_router,
1203                         meetme_mute_type(),
1204                         meetme_stasis_cb,
1205                         NULL)) {
1206                 meetme_stasis_cleanup();
1207                 return -1;
1208         }
1209
1210         if (stasis_message_router_add(meetme_event_message_router,
1211                         meetme_talking_type(),
1212                         meetme_stasis_cb,
1213                         NULL)) {
1214                 meetme_stasis_cleanup();
1215                 return -1;
1216         }
1217
1218         if (stasis_message_router_add(meetme_event_message_router,
1219                         meetme_talk_request_type(),
1220                         meetme_stasis_cb,
1221                         NULL)) {
1222                 meetme_stasis_cleanup();
1223                 return -1;
1224         }
1225
1226         return 0;
1227 }
1228
1229 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1230         struct stasis_message *message)
1231 {
1232         struct ast_channel_blob *channel_blob = stasis_message_data(message);
1233         struct stasis_message_type *message_type;
1234         const char *event;
1235         const char *conference_num;
1236         const char *status;
1237         struct ast_json *json_cur;
1238         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
1239         RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
1240
1241         if (!channel_blob) {
1242                 ast_assert(0);
1243                 return;
1244         }
1245
1246         message_type = stasis_message_type(message);
1247
1248         if (!message_type) {
1249                 ast_assert(0);
1250                 return;
1251         }
1252
1253         if (message_type == meetme_join_type()) {
1254                 event = "MeetmeJoin";
1255         } else if (message_type == meetme_leave_type()) {
1256                 event = "MeetmeLeave";
1257         } else if (message_type == meetme_end_type()) {
1258                 event = "MeetmeEnd";
1259         } else if (message_type == meetme_mute_type()) {
1260                 event = "MeetmeMute";
1261         } else if (message_type == meetme_talking_type()) {
1262                 event = "MeetmeTalking";
1263         } else if (message_type == meetme_talk_request_type()) {
1264                 event = "MeetmeTalkRequest";
1265         } else {
1266                 ast_assert(0);
1267                 return;
1268         }
1269
1270         if (!event) {
1271                 ast_assert(0);
1272                 return;
1273         }
1274
1275         conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
1276         if (!conference_num) {
1277                 ast_assert(0);
1278                 return;
1279         }
1280
1281         status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
1282         if (status) {
1283                 ast_str_append_event_header(&extra_text, "Status", status);
1284         }
1285
1286         if (channel_blob->snapshot) {
1287                 channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
1288         }
1289
1290         if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
1291                 int user_number = ast_json_integer_get(json_cur);
1292                 RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
1293                 if (!user_prop_str) {
1294                         return;
1295                 }
1296
1297                 ast_str_set(&user_prop_str, 0, "%d", user_number);
1298                 ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
1299
1300                 if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
1301                         int duration = ast_json_integer_get(json_cur);
1302                         ast_str_set(&user_prop_str, 0, "%d", duration);
1303                         ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
1304                 }
1305
1306                 json_cur = NULL;
1307         }
1308
1309         manager_event(EVENT_FLAG_CALL, event,
1310                 "Meetme: %s\r\n"
1311                 "%s"
1312                 "%s",
1313                 conference_num,
1314                 channel_text ? ast_str_buffer(channel_text) : "",
1315                 extra_text ? ast_str_buffer(extra_text) : "");
1316 }
1317
1318 /*!
1319  * \internal
1320  * \brief Build a json object from a status value for inclusion in json extras for meetme_stasis_generate_msg
1321  * \since 12.0.0
1322  *
1323  * \param on if true, then status is on. Otherwise status is off
1324  * \retval NULL on failure to allocate the JSON blob.
1325  * \retval pointer to the JSON blob if successful.
1326  */
1327 static struct ast_json *status_to_json(int on)
1328 {
1329         struct ast_json *json_object = ast_json_pack("{s: s}",
1330                 "status", on ? "on" : "off");
1331
1332         return json_object;
1333 }
1334
1335 /*!
1336  * \internal
1337  * \brief Generate a stasis message associated with a meetme event
1338  * \since 12.0.0
1339  *
1340  * \param meetme_confere The conference responsible for generating this message
1341  * \param chan The channel involved in the message (NULL allowed)
1342  * \param user The conference user involved in the message (NULL allowed)
1343  * \param message_type the type the stasis message being generated
1344  * \param extras Additional json fields desired for inclusion
1345  */
1346 static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan,
1347         struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
1348 {
1349         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1350         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1351
1352         json_object = ast_json_pack("{s: s}",
1353                 "Meetme", meetme_conference->confno);
1354
1355         if (!json_object) {
1356                 return;
1357         }
1358
1359         if (extras) {
1360                 ast_json_object_update(json_object, extras);
1361         }
1362
1363         if (user) {
1364                 struct timeval now = ast_tvnow();
1365                 long duration = (long)(now.tv_sec - user->jointime);
1366                 struct ast_json *json_user;
1367                 struct ast_json *json_user_duration;
1368
1369                 json_user = ast_json_integer_create(user->user_no);
1370                 if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
1371                         return;
1372                 }
1373
1374                 if (duration > 0) {
1375                         json_user_duration = ast_json_integer_create(duration);
1376                         if (!json_user_duration
1377                                 || ast_json_object_set(json_object, "duration", json_user_duration)) {
1378                                 return;
1379                         }
1380                 }
1381         }
1382
1383         if (chan) {
1384                 ast_channel_lock(chan);
1385         }
1386         msg = ast_channel_blob_create(chan, message_type, json_object);
1387         if (chan) {
1388                 ast_channel_unlock(chan);
1389         }
1390
1391         if (!msg) {
1392                 return;
1393         }
1394
1395         stasis_publish(ast_channel_topic(chan), msg);
1396 }
1397
1398 static int admin_exec(struct ast_channel *chan, const char *data);
1399 static void *recordthread(void *args);
1400
1401 static const char *istalking(int x)
1402 {
1403         if (x > 0)
1404                 return "(talking)";
1405         else if (x < 0)
1406                 return "(unmonitored)";
1407         else 
1408                 return "(not talking)";
1409 }
1410
1411 static int careful_write(int fd, unsigned char *data, int len, int block)
1412 {
1413         int res;
1414         int x;
1415
1416         while (len) {
1417                 if (block) {
1418                         x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1419                         res = ioctl(fd, DAHDI_IOMUX, &x);
1420                 } else
1421                         res = 0;
1422                 if (res >= 0)
1423                         res = write(fd, data, len);
1424                 if (res < 1) {
1425                         if (errno != EAGAIN) {
1426                                 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1427                                 return -1;
1428                         } else
1429                                 return 0;
1430                 }
1431                 len -= res;
1432                 data += res;
1433         }
1434
1435         return 0;
1436 }
1437
1438 static int set_talk_volume(struct ast_conf_user *user, int volume)
1439 {
1440         char gain_adjust;
1441
1442         /* attempt to make the adjustment in the channel driver;
1443            if successful, don't adjust in the frame reading routine
1444         */
1445         gain_adjust = gain_map[volume + 5];
1446
1447         return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1448 }
1449
1450 static int set_listen_volume(struct ast_conf_user *user, int volume)
1451 {
1452         char gain_adjust;
1453
1454         /* attempt to make the adjustment in the channel driver;
1455            if successful, don't adjust in the frame reading routine
1456         */
1457         gain_adjust = gain_map[volume + 5];
1458
1459         return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1460 }
1461
1462 static void tweak_volume(struct volume *vol, enum volume_action action)
1463 {
1464         switch (action) {
1465         case VOL_UP:
1466                 switch (vol->desired) { 
1467                 case 5:
1468                         break;
1469                 case 0:
1470                         vol->desired = 2;
1471                         break;
1472                 case -2:
1473                         vol->desired = 0;
1474                         break;
1475                 default:
1476                         vol->desired++;
1477                         break;
1478                 }
1479                 break;
1480         case VOL_DOWN:
1481                 switch (vol->desired) {
1482                 case -5:
1483                         break;
1484                 case 2:
1485                         vol->desired = 0;
1486                         break;
1487                 case 0:
1488                         vol->desired = -2;
1489                         break;
1490                 default:
1491                         vol->desired--;
1492                         break;
1493                 }
1494         }
1495 }
1496
1497 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
1498 {
1499         tweak_volume(&user->talk, action);
1500         /* attempt to make the adjustment in the channel driver;
1501            if successful, don't adjust in the frame reading routine
1502         */
1503         if (!set_talk_volume(user, user->talk.desired))
1504                 user->talk.actual = 0;
1505         else
1506                 user->talk.actual = user->talk.desired;
1507 }
1508
1509 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
1510 {
1511         tweak_volume(&user->listen, action);
1512         /* attempt to make the adjustment in the channel driver;
1513            if successful, don't adjust in the frame reading routine
1514         */
1515         if (!set_listen_volume(user, user->listen.desired))
1516                 user->listen.actual = 0;
1517         else
1518                 user->listen.actual = user->listen.desired;
1519 }
1520
1521 static void reset_volumes(struct ast_conf_user *user)
1522 {
1523         signed char zero_volume = 0;
1524
1525         ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1526         ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
1527 }
1528
1529 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
1530 {
1531         unsigned char *data;
1532         int len;
1533         int res = -1;
1534
1535         ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1536                 "Conference: %s\r\n"
1537                 "Marked: %d",
1538                 ast_channel_name(chan),
1539                 conf->confno,
1540                 conf->markedusers);
1541
1542         if (!ast_check_hangup(chan))
1543                 res = ast_autoservice_start(chan);
1544
1545         AST_LIST_LOCK(&confs);
1546
1547         switch(sound) {
1548         case ENTER:
1549                 data = enter;
1550                 len = sizeof(enter);
1551                 break;
1552         case LEAVE:
1553                 data = leave;
1554                 len = sizeof(leave);
1555                 break;
1556         default:
1557                 data = NULL;
1558                 len = 0;
1559         }
1560         if (data) {
1561                 careful_write(conf->fd, data, len, 1);
1562         }
1563
1564         AST_LIST_UNLOCK(&confs);
1565
1566         if (!res) 
1567                 ast_autoservice_stop(chan);
1568 }
1569
1570 static int user_no_cmp(void *obj, void *arg, int flags)
1571 {
1572         struct ast_conf_user *user = obj;
1573         int *user_no = arg;
1574
1575         if (user->user_no == *user_no) {
1576                 return (CMP_MATCH | CMP_STOP);
1577         }
1578
1579         return 0;
1580 }
1581
1582 static int user_max_cmp(void *obj, void *arg, int flags)
1583 {
1584         struct ast_conf_user *user = obj;
1585         int *max_no = arg;
1586
1587         if (user->user_no > *max_no) {
1588                 *max_no = user->user_no;
1589         }
1590
1591         return 0;
1592 }
1593
1594 /*!
1595  * \brief Find or create a conference
1596  *
1597  * \param confno The conference name/number
1598  * \param pin The regular user pin
1599  * \param pinadmin The admin pin
1600  * \param make Make the conf if it doesn't exist
1601  * \param dynamic Mark the newly created conference as dynamic
1602  * \param refcount How many references to mark on the conference
1603  * \param chan The asterisk channel
1604  * \param test
1605  *
1606  * \return A pointer to the conference struct, or NULL if it wasn't found and
1607  *         make or dynamic were not set.
1608  */
1609 static struct ast_conference *build_conf(const char *confno, const char *pin,
1610         const char *pinadmin, int make, int dynamic, int refcount,
1611         const struct ast_channel *chan, struct ast_test *test)
1612 {
1613         struct ast_conference *cnf;
1614         struct dahdi_confinfo dahdic = { 0, };
1615         int confno_int = 0;
1616         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
1617
1618         AST_LIST_LOCK(&confs);
1619
1620         AST_LIST_TRAVERSE(&confs, cnf, list) {
1621                 if (!strcmp(confno, cnf->confno)) 
1622                         break;
1623         }
1624
1625         if (cnf || (!make && !dynamic) || !cap_slin)
1626                 goto cnfout;
1627
1628         ast_format_cap_append(cap_slin, ast_format_slin, 0);
1629         /* Make a new one */
1630         if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
1631                 !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
1632                 goto cnfout;
1633         }
1634
1635         ast_mutex_init(&cnf->playlock);
1636         ast_mutex_init(&cnf->listenlock);
1637         cnf->recordthread = AST_PTHREADT_NULL;
1638         ast_mutex_init(&cnf->recordthreadlock);
1639         cnf->announcethread = AST_PTHREADT_NULL;
1640         ast_mutex_init(&cnf->announcethreadlock);
1641         ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1642         ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1643         ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1644         ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1645
1646         /* Setup a new dahdi conference */
1647         dahdic.confno = -1;
1648         dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1649         cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1650         if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1651                 if (test) {
1652                         /* if we are creating a conference for a unit test, it is not neccesary
1653                          * to open a pseudo channel, so, if we fail continue creating
1654                          * the conference. */
1655                         ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1656                 } else {
1657                         ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1658                         if (cnf->fd >= 0)
1659                                 close(cnf->fd);
1660                         ao2_ref(cnf->usercontainer, -1);
1661                         ast_mutex_destroy(&cnf->playlock);
1662                         ast_mutex_destroy(&cnf->listenlock);
1663                         ast_mutex_destroy(&cnf->recordthreadlock);
1664                         ast_mutex_destroy(&cnf->announcethreadlock);
1665                         ast_free(cnf);
1666                         cnf = NULL;
1667                         goto cnfout;
1668                 }
1669         }
1670
1671         cnf->dahdiconf = dahdic.confno;
1672
1673         /* Setup a new channel for playback of audio files */
1674         cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1675         if (cnf->chan) {
1676                 ast_set_read_format(cnf->chan, ast_format_slin);
1677                 ast_set_write_format(cnf->chan, ast_format_slin);
1678                 dahdic.chan = 0;
1679                 dahdic.confno = cnf->dahdiconf;
1680                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1681                 if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1682                         if (test) {
1683                                 ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1684                         }
1685                         ast_log(LOG_WARNING, "Error setting conference\n");
1686                         if (cnf->chan)
1687                                 ast_hangup(cnf->chan);
1688                         else
1689                                 close(cnf->fd);
1690                         ao2_ref(cnf->usercontainer, -1);
1691                         ast_mutex_destroy(&cnf->playlock);
1692                         ast_mutex_destroy(&cnf->listenlock);
1693                         ast_mutex_destroy(&cnf->recordthreadlock);
1694                         ast_mutex_destroy(&cnf->announcethreadlock);
1695                         ast_free(cnf);
1696                         cnf = NULL;
1697                         goto cnfout;
1698                 }
1699         }
1700
1701         /* Fill the conference struct */
1702         cnf->start = time(NULL);
1703         cnf->maxusers = 0x7fffffff;
1704         cnf->isdynamic = dynamic ? 1 : 0;
1705         ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1706         AST_LIST_INSERT_HEAD(&confs, cnf, list);
1707
1708         /* Reserve conference number in map */
1709         if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1710                 conf_map[confno_int] = 1;
1711         
1712 cnfout:
1713         ao2_cleanup(cap_slin);
1714         if (cnf)
1715                 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1716
1717         AST_LIST_UNLOCK(&confs);
1718
1719         return cnf;
1720 }
1721
1722 static char *complete_confno(const char *word, int state)
1723 {
1724         struct ast_conference *cnf;
1725         char *ret = NULL;
1726         int which = 0;
1727         int len = strlen(word);
1728
1729         AST_LIST_LOCK(&confs);
1730         AST_LIST_TRAVERSE(&confs, cnf, list) {
1731                 if (!strncmp(word, cnf->confno, len) && ++which > state) {
1732                         /* dup before releasing the lock */
1733                         ret = ast_strdup(cnf->confno);
1734                         break;
1735                 }
1736         }
1737         AST_LIST_UNLOCK(&confs);
1738         return ret;
1739 }
1740
1741 static char *complete_userno(struct ast_conference *cnf, const char *word, int state)
1742 {
1743         char usrno[50];
1744         struct ao2_iterator iter;
1745         struct ast_conf_user *usr;
1746         char *ret = NULL;
1747         int which = 0;
1748         int len = strlen(word);
1749
1750         iter = ao2_iterator_init(cnf->usercontainer, 0);
1751         for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1752                 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1753                 if (!strncmp(word, usrno, len) && ++which > state) {
1754                         ao2_ref(usr, -1);
1755                         ret = ast_strdup(usrno);
1756                         break;
1757                 }
1758         }
1759         ao2_iterator_destroy(&iter);
1760         return ret;
1761 }
1762
1763 static char *complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
1764 {
1765         if (pos == 2) {
1766                 return complete_confno(word, state);
1767         }
1768         if (pos == 3) {
1769                 int len = strlen(word);
1770                 char *ret = NULL;
1771                 char *saved = NULL;
1772                 char *myline;
1773                 char *confno;
1774                 struct ast_conference *cnf;
1775
1776                 if (!strncasecmp(word, "all", len)) {
1777                         if (state == 0) {
1778                                 return ast_strdup("all");
1779                         }
1780                         --state;
1781                 }
1782
1783                 /* Extract the confno from the command line. */
1784                 myline = ast_strdupa(line);
1785                 strtok_r(myline, " ", &saved);
1786                 strtok_r(NULL, " ", &saved);
1787                 confno = strtok_r(NULL, " ", &saved);
1788
1789                 AST_LIST_LOCK(&confs);
1790                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1791                         if (!strcmp(confno, cnf->confno)) {
1792                                 ret = complete_userno(cnf, word, state);
1793                                 break;
1794                         }
1795                 }
1796                 AST_LIST_UNLOCK(&confs);
1797
1798                 return ret;
1799         }
1800         return NULL;
1801 }
1802
1803 static char *complete_meetmecmd_lock(const char *word, int pos, int state)
1804 {
1805         if (pos == 2) {
1806                 return complete_confno(word, state);
1807         }
1808         return NULL;
1809 }
1810
1811 static char *complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
1812 {
1813         int len;
1814
1815         if (pos == 2) {
1816                 len = strlen(word);
1817                 if (!strncasecmp(word, STR_CONCISE, len)) {
1818                         if (state == 0) {
1819                                 return ast_strdup(STR_CONCISE);
1820                         }
1821                         --state;
1822                 }
1823
1824                 return complete_confno(word, state);
1825         }
1826         if (pos == 3 && state == 0) {
1827                 char *saved = NULL;
1828                 char *myline;
1829                 char *confno;
1830
1831                 /* Extract the confno from the command line. */
1832                 myline = ast_strdupa(line);
1833                 strtok_r(myline, " ", &saved);
1834                 strtok_r(NULL, " ", &saved);
1835                 confno = strtok_r(NULL, " ", &saved);
1836
1837                 if (!strcasecmp(confno, STR_CONCISE)) {
1838                         /* There is nothing valid in this position now. */
1839                         return NULL;
1840                 }
1841
1842                 len = strlen(word);
1843                 if (!strncasecmp(word, STR_CONCISE, len)) {
1844                         return ast_strdup(STR_CONCISE);
1845                 }
1846         }
1847         return NULL;
1848 }
1849
1850 static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1851 {
1852         /* Process the command */
1853         struct ast_conf_user *user;
1854         struct ast_conference *cnf;
1855         int hr, min, sec;
1856         int total = 0;
1857         time_t now;
1858 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
1859 #define MC_DATA_FORMAT "%-12.12s   %4.4d              %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
1860
1861         switch (cmd) {
1862         case CLI_INIT:
1863                 e->command = "meetme list";
1864                 e->usage =
1865                         "Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
1866                         "       List all conferences or a specific conference.\n";
1867                 return NULL;
1868         case CLI_GENERATE:
1869                 return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
1870         }
1871
1872         if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
1873                 /* List all the conferences */
1874                 int concise = (a->argc == 3);
1875                 struct ast_str *marked_users;
1876
1877                 if (!(marked_users = ast_str_create(30))) {
1878                         return CLI_FAILURE;
1879                 }
1880
1881                 now = time(NULL);
1882                 AST_LIST_LOCK(&confs);
1883                 if (AST_LIST_EMPTY(&confs)) {
1884                         if (!concise) {
1885                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1886                         }
1887                         AST_LIST_UNLOCK(&confs);
1888                         ast_free(marked_users);
1889                         return CLI_SUCCESS;
1890                 }
1891                 if (!concise) {
1892                         ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1893                 }
1894                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1895                         hr = (now - cnf->start) / 3600;
1896                         min = ((now - cnf->start) % 3600) / 60;
1897                         sec = (now - cnf->start) % 60;
1898                         if (!concise) {
1899                                 if (cnf->markedusers == 0) {
1900                                         ast_str_set(&marked_users, 0, "N/A ");
1901                                 } else {
1902                                         ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
1903                                 }
1904                                 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
1905                                         ast_str_buffer(marked_users), hr, min, sec,
1906                                         cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
1907                         } else {
1908                                 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1909                                         cnf->confno,
1910                                         cnf->users,
1911                                         cnf->markedusers,
1912                                         hr, min, sec,
1913                                         cnf->isdynamic,
1914                                         cnf->locked);
1915                         }
1916
1917                         total += cnf->users;
1918                 }
1919                 AST_LIST_UNLOCK(&confs);
1920                 if (!concise) {
1921                         ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1922                 }
1923                 ast_free(marked_users);
1924                 return CLI_SUCCESS;
1925         }
1926         if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
1927                 struct ao2_iterator user_iter;
1928                 int concise = (a->argc == 4);
1929
1930                 /* List all the users in a conference */
1931                 if (AST_LIST_EMPTY(&confs)) {
1932                         if (!concise) {
1933                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1934                         }
1935                         return CLI_SUCCESS;
1936                 }
1937                 /* Find the right conference */
1938                 AST_LIST_LOCK(&confs);
1939                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1940                         if (strcmp(cnf->confno, a->argv[2]) == 0) {
1941                                 break;
1942                         }
1943                 }
1944                 if (!cnf) {
1945                         if (!concise)
1946                                 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1947                         AST_LIST_UNLOCK(&confs);
1948                         return CLI_SUCCESS;
1949                 }
1950                 /* Show all the users */
1951                 time(&now);
1952                 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1953                 while((user = ao2_iterator_next(&user_iter))) {
1954                         hr = (now - user->jointime) / 3600;
1955                         min = ((now - user->jointime) % 3600) / 60;
1956                         sec = (now - user->jointime) % 60;
1957                         if (!concise) {
1958                                 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1959                                         user->user_no,
1960                                         S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
1961                                         S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
1962                                         ast_channel_name(user->chan),
1963                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
1964                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
1965                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1966                                         user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1967                                         istalking(user->talking), hr, min, sec); 
1968                         } else {
1969                                 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1970                                         user->user_no,
1971                                         S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, ""),
1972                                         S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, ""),
1973                                         ast_channel_name(user->chan),
1974                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
1975                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
1976                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1977                                         user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1978                                         user->talking, hr, min, sec);
1979                         }
1980                         ao2_ref(user, -1);
1981                 }
1982                 ao2_iterator_destroy(&user_iter);
1983                 if (!concise) {
1984                         ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1985                 }
1986                 AST_LIST_UNLOCK(&confs);
1987                 return CLI_SUCCESS;
1988         }
1989         return CLI_SHOWUSAGE;
1990 }
1991
1992
1993 static char *meetme_cmd_helper(struct ast_cli_args *a)
1994 {
1995         /* Process the command */
1996         struct ast_str *cmdline;
1997
1998         /* Max confno length */
1999         if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
2000                 return CLI_FAILURE;
2001         }
2002
2003         ast_str_set(&cmdline, 0, "%s", a->argv[2]);     /* Argv 2: conference number */
2004         if (strcasestr(a->argv[1], "lock")) {
2005                 if (strcasecmp(a->argv[1], "lock") == 0) {
2006                         /* Lock */
2007                         ast_str_append(&cmdline, 0, ",L");
2008                 } else {
2009                         /* Unlock */
2010                         ast_str_append(&cmdline, 0, ",l");
2011                 }
2012         } else if (strcasestr(a->argv[1], "mute")) { 
2013                 if (strcasecmp(a->argv[1], "mute") == 0) {
2014                         /* Mute */
2015                         if (strcasecmp(a->argv[3], "all") == 0) {
2016                                 ast_str_append(&cmdline, 0, ",N");
2017                         } else {
2018                                 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);       
2019                         }
2020                 } else {
2021                         /* Unmute */
2022                         if (strcasecmp(a->argv[3], "all") == 0) {
2023                                 ast_str_append(&cmdline, 0, ",n");
2024                         } else {
2025                                 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
2026                         }
2027                 }
2028         } else if (strcasecmp(a->argv[1], "kick") == 0) {
2029                 if (strcasecmp(a->argv[3], "all") == 0) {
2030                         /* Kick all */
2031                         ast_str_append(&cmdline, 0, ",K");
2032                 } else {
2033                         /* Kick a single user */
2034                         ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
2035                 }
2036         } else {
2037                 /*
2038                  * Should never get here because it is already filtered by the
2039                  * callers.
2040                  */
2041                 ast_free(cmdline);
2042                 return CLI_SHOWUSAGE;
2043         }
2044
2045         ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
2046
2047         admin_exec(NULL, ast_str_buffer(cmdline));
2048         ast_free(cmdline);
2049
2050         return CLI_SUCCESS;
2051 }
2052
2053 static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2054 {
2055         switch (cmd) {
2056         case CLI_INIT:
2057                 e->command = "meetme {lock|unlock}";
2058                 e->usage =
2059                         "Usage: meetme lock|unlock <confno>\n"
2060                         "       Lock or unlock a conference to new users.\n";
2061                 return NULL;
2062         case CLI_GENERATE:
2063                 return complete_meetmecmd_lock(a->word, a->pos, a->n);
2064         }
2065
2066         if (a->argc != 3) {
2067                 return CLI_SHOWUSAGE;
2068         }
2069
2070         return meetme_cmd_helper(a);
2071 }
2072
2073 static char *meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2074 {
2075         switch (cmd) {
2076         case CLI_INIT:
2077                 e->command = "meetme kick";
2078                 e->usage =
2079                         "Usage: meetme kick <confno> all|<userno>\n"
2080                         "       Kick a conference or a user in a conference.\n";
2081                 return NULL;
2082         case CLI_GENERATE:
2083                 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2084         }
2085
2086         if (a->argc != 4) {
2087                 return CLI_SHOWUSAGE;
2088         }
2089
2090         return meetme_cmd_helper(a);
2091 }
2092
2093 static char *meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2094 {
2095         switch (cmd) {
2096         case CLI_INIT:
2097                 e->command = "meetme {mute|unmute}";
2098                 e->usage =
2099                         "Usage: meetme mute|unmute <confno> all|<userno>\n"
2100                         "       Mute or unmute a conference or a user in a conference.\n";
2101                 return NULL;
2102         case CLI_GENERATE:
2103                 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2104         }
2105
2106         if (a->argc != 4) {
2107                 return CLI_SHOWUSAGE;
2108         }
2109
2110         return meetme_cmd_helper(a);
2111 }
2112
2113 static const char *sla_hold_str(unsigned int hold_access)
2114 {
2115         const char *hold = "Unknown";
2116
2117         switch (hold_access) {
2118         case SLA_HOLD_OPEN:
2119                 hold = "Open";
2120                 break;
2121         case SLA_HOLD_PRIVATE:
2122                 hold = "Private";
2123         default:
2124                 break;
2125         }
2126
2127         return hold;
2128 }
2129
2130 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2131 {
2132         struct ao2_iterator i;
2133         struct sla_trunk *trunk;
2134
2135         switch (cmd) {
2136         case CLI_INIT:
2137                 e->command = "sla show trunks";
2138                 e->usage =
2139                         "Usage: sla show trunks\n"
2140                         "       This will list all trunks defined in sla.conf\n";
2141                 return NULL;
2142         case CLI_GENERATE:
2143                 return NULL;
2144         }
2145
2146         ast_cli(a->fd, "\n"
2147                     "=============================================================\n"
2148                     "=== Configured SLA Trunks ===================================\n"
2149                     "=============================================================\n"
2150                     "===\n");
2151         i = ao2_iterator_init(sla_trunks, 0);
2152         for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
2153                 struct sla_station_ref *station_ref;
2154                 char ring_timeout[16] = "(none)";
2155
2156                 ao2_lock(trunk);
2157
2158                 if (trunk->ring_timeout) {
2159                         snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
2160                 }
2161
2162                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2163                             "=== Trunk Name:       %s\n"
2164                             "=== ==> Device:       %s\n"
2165                             "=== ==> AutoContext:  %s\n"
2166                             "=== ==> RingTimeout:  %s\n"
2167                             "=== ==> BargeAllowed: %s\n"
2168                             "=== ==> HoldAccess:   %s\n"
2169                             "=== ==> Stations ...\n",
2170                             trunk->name, trunk->device, 
2171                             S_OR(trunk->autocontext, "(none)"), 
2172                             ring_timeout,
2173                             trunk->barge_disabled ? "No" : "Yes",
2174                             sla_hold_str(trunk->hold_access));
2175
2176                 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
2177                         ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
2178                 }
2179
2180                 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
2181
2182                 ao2_unlock(trunk);
2183         }
2184         ao2_iterator_destroy(&i);
2185         ast_cli(a->fd, "=============================================================\n\n");
2186
2187         return CLI_SUCCESS;
2188 }
2189
2190 static const char *trunkstate2str(enum sla_trunk_state state)
2191 {
2192 #define S(e) case e: return # e;
2193         switch (state) {
2194         S(SLA_TRUNK_STATE_IDLE)
2195         S(SLA_TRUNK_STATE_RINGING)
2196         S(SLA_TRUNK_STATE_UP)
2197         S(SLA_TRUNK_STATE_ONHOLD)
2198         S(SLA_TRUNK_STATE_ONHOLD_BYME)
2199         }
2200         return "Uknown State";
2201 #undef S
2202 }
2203
2204 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2205 {
2206         struct ao2_iterator i;
2207         struct sla_station *station;
2208
2209         switch (cmd) {
2210         case CLI_INIT:
2211                 e->command = "sla show stations";
2212                 e->usage =
2213                         "Usage: sla show stations\n"
2214                         "       This will list all stations defined in sla.conf\n";
2215                 return NULL;
2216         case CLI_GENERATE:
2217                 return NULL;
2218         }
2219
2220         ast_cli(a->fd, "\n" 
2221                     "=============================================================\n"
2222                     "=== Configured SLA Stations =================================\n"
2223                     "=============================================================\n"
2224                     "===\n");
2225         i = ao2_iterator_init(sla_stations, 0);
2226         for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
2227                 struct sla_trunk_ref *trunk_ref;
2228                 char ring_timeout[16] = "(none)";
2229                 char ring_delay[16] = "(none)";
2230
2231                 ao2_lock(station);
2232
2233                 if (station->ring_timeout) {
2234                         snprintf(ring_timeout, sizeof(ring_timeout), 
2235                                 "%u", station->ring_timeout);
2236                 }
2237                 if (station->ring_delay) {
2238                         snprintf(ring_delay, sizeof(ring_delay), 
2239                                 "%u", station->ring_delay);
2240                 }
2241                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2242                             "=== Station Name:    %s\n"
2243                             "=== ==> Device:      %s\n"
2244                             "=== ==> AutoContext: %s\n"
2245                             "=== ==> RingTimeout: %s\n"
2246                             "=== ==> RingDelay:   %s\n"
2247                             "=== ==> HoldAccess:  %s\n"
2248                             "=== ==> Trunks ...\n",
2249                             station->name, station->device,
2250                             S_OR(station->autocontext, "(none)"), 
2251                             ring_timeout, ring_delay,
2252                             sla_hold_str(station->hold_access));
2253                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2254                         if (trunk_ref->ring_timeout) {
2255                                 snprintf(ring_timeout, sizeof(ring_timeout),
2256                                         "%u", trunk_ref->ring_timeout);
2257                         } else
2258                                 strcpy(ring_timeout, "(none)");
2259                         if (trunk_ref->ring_delay) {
2260                                 snprintf(ring_delay, sizeof(ring_delay),
2261                                         "%u", trunk_ref->ring_delay);
2262                         } else
2263                                 strcpy(ring_delay, "(none)");
2264                                 ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
2265                                     "===       ==> State:       %s\n"
2266                                     "===       ==> RingTimeout: %s\n"
2267                                     "===       ==> RingDelay:   %s\n",
2268                                     trunk_ref->trunk->name,
2269                                     trunkstate2str(trunk_ref->state),
2270                                     ring_timeout, ring_delay);
2271                 }
2272                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2273                             "===\n");
2274
2275                 ao2_unlock(station);
2276         }
2277         ao2_iterator_destroy(&i);
2278         ast_cli(a->fd, "============================================================\n"
2279                     "\n");
2280
2281         return CLI_SUCCESS;
2282 }
2283
2284 static struct ast_cli_entry cli_meetme[] = {
2285         AST_CLI_DEFINE(meetme_kick_cmd, "Kick a conference or a user in a conference."),
2286         AST_CLI_DEFINE(meetme_show_cmd, "List all conferences or a specific conference."),
2287         AST_CLI_DEFINE(meetme_lock_cmd, "Lock or unlock a conference to new users."),
2288         AST_CLI_DEFINE(meetme_mute_cmd, "Mute or unmute a conference or a user in a conference."),
2289         AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
2290         AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
2291 };
2292
2293 static void conf_flush(int fd, struct ast_channel *chan)
2294 {
2295         int x;
2296
2297         /* read any frames that may be waiting on the channel
2298            and throw them away
2299         */
2300         if (chan) {
2301                 struct ast_frame *f;
2302
2303                 /* when no frames are available, this will wait
2304                    for 1 millisecond maximum
2305                 */
2306                 while (ast_waitfor(chan, 1) > 0) {
2307                         f = ast_read(chan);
2308                         if (f)
2309                                 ast_frfree(f);
2310                         else /* channel was hung up or something else happened */
2311                                 break;
2312                 }
2313         }
2314
2315         /* flush any data sitting in the pseudo channel */
2316         x = DAHDI_FLUSH_ALL;
2317         if (ioctl(fd, DAHDI_FLUSH, &x))
2318                 ast_log(LOG_WARNING, "Error flushing channel\n");
2319
2320 }
2321
2322 /*! \brief Remove the conference from the list and free it.
2323
2324    We assume that this was called while holding conflock. */
2325 static int conf_free(struct ast_conference *conf)
2326 {
2327         int x;
2328         struct announce_listitem *item;
2329
2330         AST_LIST_REMOVE(&confs, conf, list);
2331
2332         meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2333
2334         if (conf->recording == MEETME_RECORD_ACTIVE) {
2335                 conf->recording = MEETME_RECORD_TERMINATE;
2336                 AST_LIST_UNLOCK(&confs);
2337                 while (1) {
2338                         usleep(1);
2339                         AST_LIST_LOCK(&confs);
2340                         if (conf->recording == MEETME_RECORD_OFF)
2341                                 break;
2342                         AST_LIST_UNLOCK(&confs);
2343                 }
2344         }
2345
2346         for (x = 0; x < AST_FRAME_BITS; x++) {
2347                 if (conf->transframe[x])
2348                         ast_frfree(conf->transframe[x]);
2349                 if (conf->transpath[x])
2350                         ast_translator_free_path(conf->transpath[x]);
2351         }
2352         if (conf->announcethread != AST_PTHREADT_NULL) {
2353                 ast_mutex_lock(&conf->announcelistlock);
2354                 conf->announcethread_stop = 1;
2355                 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
2356                 ast_cond_signal(&conf->announcelist_addition);
2357                 ast_mutex_unlock(&conf->announcelistlock);
2358                 pthread_join(conf->announcethread, NULL);
2359         
2360                 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2361                         /* If it's a voicemail greeting file we don't want to remove it */
2362                         if (!item->vmrec){
2363                                 ast_filedelete(item->namerecloc, NULL);
2364                         }
2365                         ao2_ref(item, -1);
2366                 }
2367                 ast_mutex_destroy(&conf->announcelistlock);
2368         }
2369
2370         if (conf->origframe)
2371                 ast_frfree(conf->origframe);
2372         ast_hangup(conf->lchan);
2373         ast_hangup(conf->chan);
2374         if (conf->fd >= 0)
2375                 close(conf->fd);
2376         if (conf->recordingfilename) {
2377                 ast_free(conf->recordingfilename);
2378         }
2379         if (conf->usercontainer) {
2380                 ao2_ref(conf->usercontainer, -1);
2381         }
2382         if (conf->recordingformat) {
2383                 ast_free(conf->recordingformat);
2384         }
2385         ast_mutex_destroy(&conf->playlock);
2386         ast_mutex_destroy(&conf->listenlock);
2387         ast_mutex_destroy(&conf->recordthreadlock);
2388         ast_mutex_destroy(&conf->announcethreadlock);
2389         ast_free(conf);
2390
2391         return 0;
2392 }
2393
2394 static void conf_queue_dtmf(const struct ast_conference *conf,
2395         const struct ast_conf_user *sender, struct ast_frame *f)
2396 {
2397         struct ast_conf_user *user;
2398         struct ao2_iterator user_iter;
2399
2400         user_iter = ao2_iterator_init(conf->usercontainer, 0);
2401         while ((user = ao2_iterator_next(&user_iter))) {
2402                 if (user == sender) {
2403                         ao2_ref(user, -1);
2404                         continue;
2405                 }
2406                 if (ast_write(user->chan, f) < 0)
2407                         ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2408                 ao2_ref(user, -1);
2409         }
2410         ao2_iterator_destroy(&user_iter);
2411 }
2412
2413 static void sla_queue_event_full(enum sla_event_type type, 
2414         struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
2415 {
2416         struct sla_event *event;
2417
2418         if (sla.thread == AST_PTHREADT_NULL) {
2419                 ao2_ref(station, -1);
2420                 ao2_ref(trunk_ref, -1);
2421                 return;
2422         }
2423
2424         if (!(event = ast_calloc(1, sizeof(*event)))) {
2425                 ao2_ref(station, -1);
2426                 ao2_ref(trunk_ref, -1);
2427                 return;
2428         }
2429
2430         event->type = type;
2431         event->trunk_ref = trunk_ref;
2432         event->station = station;
2433
2434         if (!lock) {
2435                 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2436                 return;
2437         }
2438
2439         ast_mutex_lock(&sla.lock);
2440         AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2441         ast_cond_signal(&sla.cond);
2442         ast_mutex_unlock(&sla.lock);
2443 }
2444
2445 static void sla_queue_event_nolock(enum sla_event_type type)
2446 {
2447         sla_queue_event_full(type, NULL, NULL, 0);
2448 }
2449
2450 static void sla_queue_event(enum sla_event_type type)
2451 {
2452         sla_queue_event_full(type, NULL, NULL, 1);
2453 }
2454
2455 /*! \brief Queue a SLA event from the conference */
2456 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
2457         struct ast_conference *conf)
2458 {
2459         struct sla_station *station;
2460         struct sla_trunk_ref *trunk_ref = NULL;
2461         char *trunk_name;
2462         struct ao2_iterator i;
2463
2464         trunk_name = ast_strdupa(conf->confno);
2465         strsep(&trunk_name, "_");
2466         if (ast_strlen_zero(trunk_name)) {
2467                 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
2468                 return;
2469         }
2470
2471         i = ao2_iterator_init(sla_stations, 0);
2472         while ((station = ao2_iterator_next(&i))) {
2473                 ao2_lock(station);
2474                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2475                         if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
2476                                 ao2_ref(trunk_ref, 1);
2477                                 break;
2478                         }
2479                 }
2480                 ao2_unlock(station);
2481                 if (trunk_ref) {
2482                         /* station reference given to sla_queue_event_full() */
2483                         break;
2484                 }
2485                 ao2_ref(station, -1);
2486         }
2487         ao2_iterator_destroy(&i);
2488
2489         if (!trunk_ref) {
2490                 ast_debug(1, "Trunk not found for event!\n");
2491                 return;
2492         }
2493
2494         sla_queue_event_full(type, trunk_ref, station, 1);
2495 }
2496
2497 /*! \brief Decrement reference counts, as incremented by find_conf() */
2498 static int dispose_conf(struct ast_conference *conf)
2499 {
2500         int res = 0;
2501         int confno_int = 0;
2502
2503         AST_LIST_LOCK(&confs);
2504         if (ast_atomic_dec_and_test(&conf->refcount)) {
2505                 /* Take the conference room number out of an inuse state */
2506                 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
2507                         conf_map[confno_int] = 0;
2508                 }
2509                 conf_free(conf);
2510                 res = 1;
2511         }
2512         AST_LIST_UNLOCK(&confs);
2513
2514         return res;
2515 }
2516
2517 static int rt_extend_conf(const char *confno)
2518 {
2519         char currenttime[32];
2520         char endtime[32];
2521         struct timeval now;
2522         struct ast_tm tm;
2523         struct ast_variable *var, *orig_var;
2524         char bookid[51];
2525
2526         if (!extendby) {
2527                 return 0;
2528         }
2529
2530         now = ast_tvnow();
2531
2532         ast_localtime(&now, &tm, NULL);
2533         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2534
2535         var = ast_load_realtime("meetme", "confno",
2536                 confno, "startTime<= ", currenttime,
2537                 "endtime>= ", currenttime, NULL);
2538
2539         orig_var = var;
2540
2541         /* Identify the specific RealTime conference */
2542         while (var) {
2543                 if (!strcasecmp(var->name, "bookid")) {
2544                         ast_copy_string(bookid, var->value, sizeof(bookid));
2545                 }
2546                 if (!strcasecmp(var->name, "endtime")) {
2547                         ast_copy_string(endtime, var->value, sizeof(endtime));
2548                 }
2549
2550                 var = var->next;
2551         }
2552         ast_variables_destroy(orig_var);
2553
2554         ast_strptime(endtime, DATE_FORMAT, &tm);
2555         now = ast_mktime(&tm, NULL);
2556
2557         now.tv_sec += extendby;
2558
2559         ast_localtime(&now, &tm, NULL);
2560         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2561         strcat(currenttime, "0"); /* Seconds needs to be 00 */
2562
2563         var = ast_load_realtime("meetme", "confno",
2564                 confno, "startTime<= ", currenttime,
2565                 "endtime>= ", currenttime, NULL);
2566
2567         /* If there is no conflict with extending the conference, update the DB */
2568         if (!var) {
2569                 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
2570                 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
2571                 return 0;
2572
2573         }
2574
2575         ast_variables_destroy(var);
2576         return -1;
2577 }
2578
2579 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
2580 {
2581         char *original_moh;
2582
2583         ast_channel_lock(chan);
2584         original_moh = ast_strdupa(ast_channel_musicclass(chan));
2585         ast_channel_musicclass_set(chan, musicclass);
2586         ast_channel_unlock(chan);
2587
2588         ast_moh_start(chan, original_moh, NULL);
2589
2590         ast_channel_lock(chan);
2591         ast_channel_musicclass_set(chan, original_moh);
2592         ast_channel_unlock(chan);
2593 }
2594
2595 static const char *get_announce_filename(enum announcetypes type)
2596 {
2597         switch (type) {
2598         case CONF_HASLEFT:
2599                 return "conf-hasleft";
2600                 break;
2601         case CONF_HASJOIN:
2602                 return "conf-hasjoin";
2603                 break;
2604         default:
2605                 return "";
2606         }
2607 }
2608
2609 static void *announce_thread(void *data)
2610 {
2611         struct announce_listitem *current;
2612         struct ast_conference *conf = data;
2613         int res;
2614         char filename[PATH_MAX] = "";
2615         AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
2616         AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2617
2618         while (!conf->announcethread_stop) {
2619                 ast_mutex_lock(&conf->announcelistlock);
2620                 if (conf->announcethread_stop) {
2621                         ast_mutex_unlock(&conf->announcelistlock);
2622                         break;
2623                 }
2624                 if (AST_LIST_EMPTY(&conf->announcelist))
2625                         ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2626
2627                 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2628                 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2629
2630                 ast_mutex_unlock(&conf->announcelistlock);
2631                 if (conf->announcethread_stop) {
2632                         break;
2633                 }
2634
2635                 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2636                         ast_debug(1, "About to play %s\n", current->namerecloc);
2637                         if (!ast_fileexists(current->namerecloc, NULL, NULL))
2638                                 continue;
2639                         if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2640                                 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2641                                         res = ast_waitstream(current->confchan, "");
2642                                 if (!res) {
2643                                         ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2644                                         if (!ast_streamfile(current->confchan, filename, current->language))
2645                                                 ast_waitstream(current->confchan, "");
2646                                 }
2647                         }
2648                         if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2649                                 /* only remove it if it isn't a VM recording file */
2650                                 ast_filedelete(current->namerecloc, NULL);
2651                         }
2652                 }
2653         }
2654
2655         /* thread marked to stop, clean up */
2656         while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2657                 /* only delete if it's a vm rec */
2658                 if (!current->vmrec) {
2659                         ast_filedelete(current->namerecloc, NULL);
2660                 }
2661                 ao2_ref(current, -1);
2662         }
2663         return NULL;
2664 }
2665
2666 static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
2667 {
2668         if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2669                 return 1;
2670         }
2671
2672         return (ast_channel_state(chan) == AST_STATE_UP);
2673 }
2674
2675 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
2676 {
2677         RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
2678         meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
2679 }
2680
2681 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
2682 {
2683         int last_talking = user->talking;
2684         if (last_talking == talking)
2685                 return;
2686
2687         user->talking = talking;
2688
2689         if (monitor) {
2690                 /* Check if talking state changed. Take care of -1 which means unmonitored */
2691                 int was_talking = (last_talking > 0);
2692                 int now_talking = (talking > 0);
2693                 if (was_talking != now_talking) {
2694                         send_talking_event(chan, conf, user, now_talking);
2695                 }
2696         }
2697 }
2698
2699 static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
2700 {
2701         struct ast_conf_user *user = obj;
2702         /* actual pointer contents of check_admin_arg is irrelevant */
2703
2704         if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2705                 user->adminflags |= ADMINFLAG_HANGUP;
2706         }
2707         return 0;
2708 }
2709
2710 static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
2711 {
2712         struct ast_conf_user *user = obj;
2713         /* actual pointer contents of check_admin_arg is irrelevant */
2714
2715         if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2716                 user->adminflags |= ADMINFLAG_KICKME;
2717         }
2718         return 0;
2719 }
2720
2721 static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
2722 {
2723         struct ast_conf_user *user = obj;
2724         /* actual pointer contents of check_admin_arg is irrelevant */
2725
2726         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2727                 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
2728         }
2729         return 0;
2730 }
2731
2732 static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
2733 {
2734         struct ast_conf_user *user = obj;
2735         /* actual pointer contents of check_admin_arg is irrelevant */
2736
2737         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2738                 user->adminflags |= ADMINFLAG_MUTED;
2739         }
2740         return 0;
2741 }
2742
2743 enum menu_modes {
2744         MENU_DISABLED = 0,
2745         MENU_NORMAL,
2746         MENU_ADMIN,
2747         MENU_ADMIN_EXTENDED,
2748 };
2749
2750 /*! \internal
2751  * \brief Processes menu options for the standard menu (accessible through the 's' option for app_meetme)
2752  *
2753  * \param menu_mode a pointer to the currently active menu_mode.
2754  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2755  * \param conf the active conference for which the user has called the menu from.
2756  * \param confflags flags used by conf for various options
2757  * \param chan ast_channel belonging to the user who called the menu
2758  * \param user which meetme conference user invoked the menu
2759  */
2760 static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
2761 {
2762         switch (*dtmf) {
2763         case '1': /* Un/Mute */
2764                 *menu_mode = MENU_DISABLED;
2765
2766                 /* user can only toggle the self-muted state */
2767                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2768
2769                 /* they can't override the admin mute state */
2770                 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2771                         if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2772                                 ast_waitstream(chan, "");
2773                         }
2774                 } else {
2775                         if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2776                                 ast_waitstream(chan, "");
2777                         }
2778                 }
2779                 break;
2780
2781         case '2':
2782                 *menu_mode = MENU_DISABLED;
2783                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2784                         user->adminflags |= ADMINFLAG_T_REQUEST;
2785                 }
2786
2787                 if (user->adminflags & ADMINFLAG_T_REQUEST) {
2788                         if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
2789                                 ast_waitstream(chan, "");
2790                         }
2791                 }
2792                 break;
2793
2794         case '4':
2795                 tweak_listen_volume(user, VOL_DOWN);
2796                 break;
2797         case '5':
2798                 /* Extend RT conference */
2799                 if (rt_schedule) {
2800                         rt_extend_conf(conf->confno);
2801                 }
2802                 *menu_mode = MENU_DISABLED;
2803                 break;
2804
2805         case '6':
2806                 tweak_listen_volume(user, VOL_UP);
2807                 break;
2808
2809         case '7':
2810                 tweak_talk_volume(user, VOL_DOWN);
2811                 break;
2812
2813         case '8':
2814                 *menu_mode = MENU_DISABLED;
2815                 break;
2816
2817         case '9':
2818                 tweak_talk_volume(user, VOL_UP);
2819                 break;
2820
2821         default:
2822                 *menu_mode = MENU_DISABLED;
2823                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2824                         ast_waitstream(chan, "");
2825                 }
2826                 break;
2827         }
2828 }
2829
2830 /*! \internal
2831  * \brief Processes menu options for the adminstrator menu (accessible through the 's' option for app_meetme)
2832  *
2833  * \param menu_mode a pointer to the currently active menu_mode.
2834  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2835  * \param conf the active conference for which the user has called the menu from.
2836  * \param confflags flags used by conf for various options
2837  * \param chan ast_channel belonging to the user who called the menu
2838  * \param user which meetme conference user invoked the menu
2839  */
2840 static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
2841 {
2842         switch(*dtmf) {
2843         case '1': /* Un/Mute */
2844                 *menu_mode = MENU_DISABLED;
2845                 /* for admin, change both admin and use flags */
2846                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2847                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2848                 } else {
2849                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2850                 }
2851
2852                 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2853                         if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2854                                 ast_waitstream(chan, "");
2855                         }
2856                 } else {
2857                         if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2858                                 ast_waitstream(chan, "");
2859                         }
2860                 }
2861                 break;
2862
2863         case '2': /* Un/Lock the Conference */
2864                 *menu_mode = MENU_DISABLED;
2865                 if (conf->locked) {
2866                         conf->locked = 0;
2867                         if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
2868                                 ast_waitstream(chan, "");
2869                         }
2870                 } else {
2871                         conf->locked = 1;
2872                         if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
2873                                 ast_waitstream(chan, "");
2874                         }
2875                 }
2876                 break;
2877
2878         case '3': /* Eject last user */
2879         {
2880                 struct ast_conf_user *usr = NULL;
2881                 int max_no = 0;
2882                 ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
2883                 *menu_mode = MENU_DISABLED;
2884                 usr = ao2_find(conf->usercontainer, &max_no, 0);
2885                 if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
2886                         if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2887                                 ast_waitstream(chan, "");
2888                         }
2889                 } else {
2890                         usr->adminflags |= ADMINFLAG_KICKME;
2891                 }
2892                 ao2_ref(usr, -1);
2893                 ast_stopstream(chan);
2894                 break;
2895         }
2896
2897         case '4':
2898                 tweak_listen_volume(user, VOL_DOWN);
2899                 break;
2900
2901         case '5':
2902                 /* Extend RT conference */
2903                 if (rt_schedule) {
2904                         if (!rt_extend_conf(conf->confno)) {
2905                                 if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
2906                                         ast_waitstream(chan, "");
2907                                 }
2908                         } else {
2909                                 if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
2910                                         ast_waitstream(chan, "");
2911                                 }
2912                         }
2913                         ast_stopstream(chan);
2914                 }
2915                 *menu_mode = MENU_DISABLED;
2916                 break;
2917
2918         case '6':
2919                 tweak_listen_volume(user, VOL_UP);
2920                 break;
2921
2922         case '7':
2923                 tweak_talk_volume(user, VOL_DOWN);
2924                 break;
2925
2926         case '8':
2927                 if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
2928                         /* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
2929                         *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2930                         ast_stopstream(chan);
2931                 }
2932                 *menu_mode = MENU_ADMIN_EXTENDED;
2933                 break;
2934
2935         case '9':
2936                 tweak_talk_volume(user, VOL_UP);
2937                 break;
2938         default:
2939                 menu_mode = MENU_DISABLED;
2940                 /* Play an error message! */
2941                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2942                         ast_waitstream(chan, "");
2943                 }
2944                 break;
2945         }
2946
2947 }
2948
2949 /*! \internal
2950  * \brief Processes menu options for the extended administrator menu (accessible through option 8 on the administrator menu)
2951  *
2952  * \param menu_mode a pointer to the currently active menu_mode.
2953  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2954  * \param conf the active conference for which the user has called the menu from.
2955  * \param confflags flags used by conf for various options
2956  * \param chan ast_channel belonging to the user who called the menu
2957  * \param user which meetme conference user invoked the menu
2958  * \param recordingtmp character buffer which may hold the name of the conference recording file
2959  */
2960 static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf,
2961         struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
2962         struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
2963         struct ast_format_cap *cap_slin)
2964 {
2965         int keepplaying;
2966         int playednamerec;
2967         int res;
2968         struct ao2_iterator user_iter;
2969         struct ast_conf_user *usr = NULL;
2970
2971         switch(*dtmf) {
2972         case '1': /* *81 Roll call */
2973                 keepplaying = 1;
2974                 playednamerec = 0;
2975                 if (conf->users == 1) {
2976                         if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
2977                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2978                                 ast_stopstream(chan);
2979                                 if (res > 0) {
2980                                         keepplaying = 0;
2981                                 }
2982                         }
2983                 } else if (conf->users == 2) {
2984                         if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
2985                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2986                                 ast_stopstream(chan);
2987                                 if (res > 0) {
2988                                         keepplaying = 0;
2989                                 }
2990                         }
2991                 } else {
2992                         if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
2993                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2994                                 ast_stopstream(chan);
2995                                 if (res > 0) {
2996                                         keepplaying = 0;
2997                                 }
2998                         }
2999                         if (keepplaying) {
3000                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3001                                 ast_stopstream(chan);
3002                                 if (res > 0) {
3003                                         keepplaying = 0;
3004                                 }
3005                         }
3006                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3007                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
3008                                 ast_stopstream(chan);
3009                                 if (res > 0) {
3010                                         keepplaying = 0;
3011                                 }
3012                         }
3013                 }
3014                 user_iter = ao2_iterator_init(conf->usercontainer, 0);
3015                 while((usr = ao2_iterator_next(&user_iter))) {
3016                         if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
3017                                 if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
3018                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
3019                                         ast_stopstream(chan);
3020                                         if (res > 0) {
3021                                                 keepplaying = 0;
3022                                         }
3023                                 }
3024                                 playednamerec = 1;
3025                         }
3026                         ao2_ref(usr, -1);
3027                 }
3028                 ao2_iterator_destroy(&user_iter);
3029                 if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
3030                         res = ast_waitstream(chan, AST_DIGIT_ANY);
3031                         ast_stopstream(chan);
3032                         if (res > 0) {
3033                                 keepplaying = 0;
3034                         }
3035                 }
3036
3037                 *menu_mode = MENU_DISABLED;
3038                 break;
3039
3040         case '2': /* *82 Eject all non-admins */
3041                 if (conf->users == 1) {
3042                         if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3043                                 ast_waitstream(chan, "");
3044                         }
3045                 } else {
3046                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
3047                 }
3048                 ast_stopstream(chan);
3049                 *menu_mode = MENU_DISABLED;
3050                 break;
3051
3052         case '3': /* *83 (Admin) mute/unmute all non-admins */
3053                 if(conf->gmuted) {
3054                         conf->gmuted = 0;
3055                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
3056                         if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
3057                                 ast_waitstream(chan, "");
3058                         }
3059                 } else {
3060                         conf->gmuted = 1;
3061                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
3062                         if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
3063                                 ast_waitstream(chan, "");
3064                         }
3065                 }
3066                 ast_stopstream(chan);
3067                 *menu_mode = MENU_DISABLED;
3068                 break;
3069
3070         case '4': /* *84 Record conference */
3071                 if (conf->recording != MEETME_RECORD_ACTIVE) {
3072                         ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
3073                         if (!conf->recordingfilename) {
3074                                 const char *var;
3075                                 ast_channel_lock(chan);
3076                                 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3077                                         conf->recordingfilename = ast_strdup(var);
3078                                 }
3079                                 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3080                                         conf->recordingformat = ast_strdup(var);
3081                                 }
3082                                 ast_channel_unlock(chan);
3083                                 if (!conf->recordingfilename) {
3084                                         snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3085                                         conf->recordingfilename = ast_strdup(recordingtmp);
3086                                 }
3087                                 if (!conf->recordingformat) {
3088                                         conf->recordingformat = ast_strdup("wav");
3089                                 }
3090                                 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3091                                 conf->confno, conf->recordingfilename, conf->recordingformat);
3092                         }
3093
3094                         ast_mutex_lock(&conf->recordthreadlock);
3095                         if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3096                                 struct dahdi_confinfo dahdic;
3097
3098                                 ast_set_read_format(conf->lchan, ast_format_slin);
3099                                 ast_set_write_format(conf->lchan, ast_format_slin);
3100                                 dahdic.chan = 0;
3101                                 dahdic.confno = conf->dahdiconf;
3102                                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3103                                 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3104                                         ast_log(LOG_WARNING, "Error starting listen channel\n");
3105                                         ast_hangup(conf->lchan);
3106                                         conf->lchan = NULL;
3107                                 } else {
3108                                         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
3109                                 }
3110                         }
3111                         ast_mutex_unlock(&conf->recordthreadlock);
3112                         if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
3113                                 ast_waitstream(chan, "");
3114                         }
3115                 }
3116
3117                 ast_stopstream(chan);
3118                 *menu_mode = MENU_DISABLED;
3119                 break;
3120
3121         case '8': /* *88 Exit the menu and return to the conference... without an error message */
3122                 ast_stopstream(chan);
3123                 *menu_mode = MENU_DISABLED;
3124                 break;
3125
3126         default:
3127                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3128                         ast_waitstream(chan, "");
3129                 }
3130                 ast_stopstream(chan);
3131                 *menu_mode = MENU_DISABLED;
3132                 break;
3133         }
3134 }
3135
3136 /*! \internal
3137  * \brief Processes menu options for the various menu types (accessible through the 's' option for app_meetme)
3138  *
3139  * \param menu_mode a pointer to the currently active menu_mode.
3140  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
3141  * \param conf the active conference for which the user has called the menu from.
3142  * \param confflags flags used by conf for various options
3143  * \param chan ast_channel belonging to the user who called the menu
3144  * \param user which meetme conference user invoked the menu
3145  * \param recordingtmp character buffer which may hold the name of the conference recording file
3146  */
3147 static void meetme_menu(enum menu_modes *menu_mode, int *dtmf,
3148         struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
3149         struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
3150         struct ast_format_cap *cap_slin)
3151 {
3152         switch (*menu_mode) {
3153         case MENU_DISABLED:
3154                 break;
3155         case MENU_NORMAL:
3156                 meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
3157                 break;
3158         case MENU_ADMIN:
3159                 meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
3160                 /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
3161                 if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
3162                         break;
3163                 }
3164         case MENU_ADMIN_EXTENDED:
3165                 meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user,
3166                         recordingtmp, recordingtmp_size, cap_slin);
3167                 break;
3168         }
3169 }
3170
3171 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
3172 {
3173         struct ast_conf_user *user = NULL;
3174         int fd;
3175         struct dahdi_confinfo dahdic, dahdic_empty;
3176         struct ast_frame *f;
3177         struct ast_channel *c;
3178         struct ast_frame fr;
3179         int outfd;
3180         int ms;
3181         int nfds;
3182         int res;
3183         int retrydahdi;
3184         int origfd;
3185         int musiconhold = 0, mohtempstopped = 0;
3186         int firstpass = 0;
3187         int lastmarked = 0;
3188         int currentmarked = 0;
3189         int ret = -1;
3190         int x;
3191         enum menu_modes menu_mode = MENU_DISABLED;
3192         int talkreq_manager = 0;
3193         int using_pseudo = 0;
3194         int duration = 20;
3195         int sent_event = 0;
3196         int checked = 0;
3197         int announcement_played = 0;
3198         struct timeval now;
3199         struct ast_dsp *dsp = NULL;
3200         struct ast_app *agi_app;
3201         char *agifile, *mod_speex;
3202         const char *agifiledefault = "conf-background.agi", *tmpvar;
3203         char meetmesecs[30] = "";
3204         char exitcontext[AST_MAX_CONTEXT] = "";
3205         char recordingtmp[AST_MAX_EXTENSION] = "";
3206         char members[10] = "";
3207         int dtmf = 0, opt_waitmarked_timeout = 0;
3208         time_t timeout = 0;
3209         struct dahdi_bufferinfo bi;
3210         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
3211         char *buf = __buf + AST_FRIENDLY_OFFSET;
3212         char *exitkeys = NULL;
3213         unsigned int calldurationlimit = 0;
3214         long timelimit = 0;
3215         long play_warning = 0;
3216         long warning_freq = 0;
3217         const char *warning_sound = NULL;
3218         const char *end_sound = NULL;
3219         char *parse;
3220         long time_left_ms = 0;
3221         struct timeval nexteventts = { 0, };
3222         int to;
3223         int setusercount = 0;
3224         int confsilence = 0, totalsilence = 0;
3225         char *mailbox, *context;
3226         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
3227
3228         if (!cap_slin) {
3229                 goto conf_run_cleanup;
3230         }
3231         ast_format_cap_append(cap_slin, ast_format_slin, 0);
3232
3233         if (!(user = ao2_alloc(sizeof(*user), NULL))) {
3234                 goto conf_run_cleanup;
3235         }
3236
3237         /* Possible timeout waiting for marked user */
3238         if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3239                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
3240                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
3241                 (opt_waitmarked_timeout > 0)) {
3242                 timeout = time(NULL) + opt_waitmarked_timeout;
3243         }
3244
3245         if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
3246                 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
3247                 ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
3248         }
3249
3250         if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
3251                 char *limit_str, *warning_str, *warnfreq_str;
3252                 const char *var;
3253
3254                 parse = optargs[OPT_ARG_DURATION_LIMIT];
3255                 limit_str = strsep(&parse, ":");
3256                 warning_str = strsep(&parse, ":");
3257                 warnfreq_str = parse;
3258
3259                 timelimit = atol(limit_str);
3260                 if (warning_str)
3261                         play_warning = atol(warning_str);
3262                 if (warnfreq_str)
3263                         warning_freq = atol(warnfreq_str);
3264
3265                 if (!timelimit) {
3266                         timelimit = play_warning = warning_freq = 0;
3267                         warning_sound = NULL;
3268                 } else if (play_warning > timelimit) {
3269                         if (!warning_freq) {
3270                                 play_warning = 0;
3271                         } else {
3272                                 while (play_warning > timelimit)
3273                                         play_warning -= warning_freq;
3274                                 if (play_warning < 1)
3275                                         play_warning = warning_freq = 0;
3276                         }
3277                 }
3278
3279                 ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
3280                 if (play_warning) {
3281                         ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
3282                 }
3283                 if (warning_freq) {
3284                         ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
3285                 }
3286
3287                 ast_channel_lock(chan);
3288                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
3289                         var = ast_strdupa(var);
3290                 }
3291                 ast_channel_unlock(chan);
3292
3293                 warning_sound = var ? var : "timeleft";
3294
3295                 ast_channel_lock(chan);
3296                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
3297                         var = ast_strdupa(var);
3298                 }
3299                 ast_channel_unlock(chan);
3300
3301                 end_sound = var ? var : NULL;
3302
3303                 /* undo effect of S(x) in case they are both used */
3304                 calldurationlimit = 0;
3305                 /* more efficient do it like S(x) does since no advanced opts */
3306                 if (!play_warning && !end_sound && timelimit) {
3307                         calldurationlimit = timelimit / 1000;
3308                         timelimit = play_warning = warning_freq = 0;
3309                 } else {
3310                         ast_debug(2, "Limit Data for this call:\n");
3311                         ast_debug(2, "- timelimit     = %ld\n", timelimit);
3312                         ast_debug(2, "- play_warning  = %ld\n", play_warning);
3313                         ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
3314                         ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
3315                         ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
3316                 }
3317         }
3318
3319         /* Get exit keys */
3320         if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
3321                 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
3322                         exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
3323                 else
3324                         exitkeys = ast_strdupa("#"); /* Default */
3325         }
3326         
3327         if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
3328                 if (!conf->recordingfilename) {
3329                         const char *var;
3330                         ast_channel_lock(chan);
3331                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3332                                 conf->recordingfilename = ast_strdup(var);
3333                         }
3334                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3335                                 conf->recordingformat = ast_strdup(var);
3336                         }
3337                         ast_channel_unlock(chan);
3338                         if (!conf->recordingfilename) {
3339                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3340                                 conf->recordingfilename = ast_strdup(recordingtmp);
3341                         }
3342                         if (!conf->recordingformat) {
3343                                 conf->recordingformat = ast_strdup("wav");
3344                         }
3345                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3346                                     conf->confno, conf->recordingfilename, conf->recordingformat);
3347                 }
3348         }
3349
3350         ast_mutex_lock(&conf->recordthreadlock);
3351         if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
3352                 ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3353                 ast_set_read_format(conf->lchan, ast_format_slin);
3354                 ast_set_write_format(conf->lchan, ast_format_slin);
3355                 dahdic.chan = 0;