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