1a780e6ffc30063c904a12f8402203b642dd6b16
[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                                 <channel_snapshot/>
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                                 <channel_snapshot/>
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                                 <channel_snapshot/>
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                                 <channel_snapshot/>
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                                 <channel_snapshot/>
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 (1ULL << 34)
754 /*! If set, don't enable a denoiser for the channel */
755 #define CONFFLAG_DONT_DENOISE       (1ULL << 35)
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         /*! Mark used during reload processing */
965         unsigned int mark:1;
966 };
967
968 /*!
969  * \brief A reference to a station
970  *
971  * This struct looks near useless at first glance.  However, its existence
972  * in the list of stations in sla_trunk means that this station references
973  * that trunk.  We use the mark to keep track of whether it needs to be
974  * removed from the sla_trunk's list of stations during a reload.
975  */
976 struct sla_station_ref {
977         AST_LIST_ENTRY(sla_station_ref) entry;
978         struct sla_station *station;
979         /*! Mark used during reload processing */
980         unsigned int mark:1;
981 };
982
983 struct sla_trunk {
984         AST_DECLARE_STRING_FIELDS(
985                 AST_STRING_FIELD(name);
986                 AST_STRING_FIELD(device);
987                 AST_STRING_FIELD(autocontext);  
988         );
989         AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
990         /*! Number of stations that use this trunk */
991         unsigned int num_stations;
992         /*! Number of stations currently on a call with this trunk */
993         unsigned int active_stations;
994         /*! Number of stations that have this trunk on hold. */
995         unsigned int hold_stations;
996         struct ast_channel *chan;
997         unsigned int ring_timeout;
998         /*! If set to 1, no station will be able to join an active call with
999          *  this trunk. */
1000         unsigned int barge_disabled:1;
1001         /*! This option uses the values in the sla_hold_access enum and sets the
1002          * access control type for hold on this trunk. */
1003         unsigned int hold_access:1;
1004         /*! Whether this trunk is currently on hold, meaning that once a station
1005          *  connects to it, the trunk channel needs to have UNHOLD indicated to it. */
1006         unsigned int on_hold:1;
1007         /*! Mark used during reload processing */
1008         unsigned int mark:1;
1009 };
1010
1011 /*!
1012  * \brief A station's reference to a trunk
1013  *
1014  * An sla_station keeps a list of trunk_refs.  This holds metadata about the
1015  * stations usage of the trunk.
1016  */
1017 struct sla_trunk_ref {
1018         AST_LIST_ENTRY(sla_trunk_ref) entry;
1019         struct sla_trunk *trunk;
1020         enum sla_trunk_state state;
1021         struct ast_channel *chan;
1022         /*! Ring timeout to use when this trunk is ringing on this specific
1023          *  station.  This takes higher priority than a ring timeout set at
1024          *  the station level. */
1025         unsigned int ring_timeout;
1026         /*! Ring delay to use when this trunk is ringing on this specific
1027          *  station.  This takes higher priority than a ring delay set at
1028          *  the station level. */
1029         unsigned int ring_delay;
1030         /*! Mark used during reload processing */
1031         unsigned int mark:1;
1032 };
1033
1034 static struct ao2_container *sla_stations;
1035 static struct ao2_container *sla_trunks;
1036
1037 static const char sla_registrar[] = "SLA";
1038
1039 /*! \brief Event types that can be queued up for the SLA thread */
1040 enum sla_event_type {
1041         /*! A station has put the call on hold */
1042         SLA_EVENT_HOLD,
1043         /*! The state of a dial has changed */
1044         SLA_EVENT_DIAL_STATE,
1045         /*! The state of a ringing trunk has changed */
1046         SLA_EVENT_RINGING_TRUNK,
1047 };
1048
1049 struct sla_event {
1050         enum sla_event_type type;
1051         struct sla_station *station;
1052         struct sla_trunk_ref *trunk_ref;
1053         AST_LIST_ENTRY(sla_event) entry;
1054 };
1055
1056 /*! \brief A station that failed to be dialed 
1057  * \note Only used by the SLA thread. */
1058 struct sla_failed_station {
1059         struct sla_station *station;
1060         struct timeval last_try;
1061         AST_LIST_ENTRY(sla_failed_station) entry;
1062 };
1063
1064 /*! \brief A trunk that is ringing */
1065 struct sla_ringing_trunk {
1066         struct sla_trunk *trunk;
1067         /*! The time that this trunk started ringing */
1068         struct timeval ring_begin;
1069         AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
1070         AST_LIST_ENTRY(sla_ringing_trunk) entry;
1071 };
1072
1073 enum sla_station_hangup {
1074         SLA_STATION_HANGUP_NORMAL,
1075         SLA_STATION_HANGUP_TIMEOUT,
1076 };
1077
1078 /*! \brief A station that is ringing */
1079 struct sla_ringing_station {
1080         struct sla_station *station;
1081         /*! The time that this station started ringing */
1082         struct timeval ring_begin;
1083         AST_LIST_ENTRY(sla_ringing_station) entry;
1084 };
1085
1086 /*!
1087  * \brief A structure for data used by the sla thread
1088  */
1089 static struct {
1090         /*! The SLA thread ID */
1091         pthread_t thread;
1092         ast_cond_t cond;
1093         ast_mutex_t lock;
1094         AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
1095         AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
1096         AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
1097         AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
1098         unsigned int stop:1;
1099         /*! Attempt to handle CallerID, even though it is known not to work
1100          *  properly in some situations. */
1101         unsigned int attempt_callerid:1;
1102 } sla = {
1103         .thread = AST_PTHREADT_NULL,
1104 };
1105
1106 /*! \brief The number of audio buffers to be allocated on pseudo channels
1107  *  when in a conference */
1108 static int audio_buffers;
1109
1110 /*! \brief Map 'volume' levels from -5 through +5 into decibel (dB) 
1111  *    settings for channel drivers.
1112  *
1113  *  \note these are not a straight linear-to-dB
1114  *  conversion... the numbers have been modified
1115  *  to give the user a better level of adjustability.
1116  */
1117 static const char gain_map[] = {
1118         -15,
1119         -13,
1120         -10,
1121         -6,
1122         0,
1123         0,
1124         0,
1125         6,
1126         10,
1127         13,
1128         15,
1129 };
1130
1131 /* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
1132 static struct stasis_message_router *meetme_event_message_router;
1133
1134 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
1135 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
1136 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
1137 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
1138 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
1139 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
1140
1141 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1142         struct stasis_message *message);
1143
1144 static void meetme_stasis_cleanup(void)
1145 {
1146         if (meetme_event_message_router) {
1147                 stasis_message_router_unsubscribe(meetme_event_message_router);
1148                 meetme_event_message_router = NULL;
1149         }
1150
1151         STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
1152         STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
1153         STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
1154         STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
1155         STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
1156         STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
1157 }
1158
1159 static int meetme_stasis_init(void)
1160 {
1161
1162         STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
1163         STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
1164         STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
1165         STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
1166         STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
1167         STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
1168
1169         meetme_event_message_router = stasis_message_router_create(
1170                 ast_channel_topic_all_cached());
1171
1172         if (!meetme_event_message_router) {
1173                 meetme_stasis_cleanup();
1174                 return -1;
1175         }
1176
1177         if (stasis_message_router_add(meetme_event_message_router,
1178                         meetme_join_type(),
1179                         meetme_stasis_cb,
1180                         NULL)) {
1181                 meetme_stasis_cleanup();
1182                 return -1;
1183         }
1184
1185         if (stasis_message_router_add(meetme_event_message_router,
1186                         meetme_leave_type(),
1187                         meetme_stasis_cb,
1188                         NULL)) {
1189                 meetme_stasis_cleanup();
1190                 return -1;
1191         }
1192
1193         if (stasis_message_router_add(meetme_event_message_router,
1194                         meetme_end_type(),
1195                         meetme_stasis_cb,
1196                         NULL)) {
1197                 meetme_stasis_cleanup();
1198                 return -1;
1199         }
1200
1201         if (stasis_message_router_add(meetme_event_message_router,
1202                         meetme_mute_type(),
1203                         meetme_stasis_cb,
1204                         NULL)) {
1205                 meetme_stasis_cleanup();
1206                 return -1;
1207         }
1208
1209         if (stasis_message_router_add(meetme_event_message_router,
1210                         meetme_talking_type(),
1211                         meetme_stasis_cb,
1212                         NULL)) {
1213                 meetme_stasis_cleanup();
1214                 return -1;
1215         }
1216
1217         if (stasis_message_router_add(meetme_event_message_router,
1218                         meetme_talk_request_type(),
1219                         meetme_stasis_cb,
1220                         NULL)) {
1221                 meetme_stasis_cleanup();
1222                 return -1;
1223         }
1224
1225         return 0;
1226 }
1227
1228 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1229         struct stasis_message *message)
1230 {
1231         struct ast_channel_blob *channel_blob = stasis_message_data(message);
1232         struct stasis_message_type *message_type;
1233         const char *event;
1234         const char *conference_num;
1235         const char *status;
1236         struct ast_json *json_cur;
1237         RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
1238         RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
1239
1240         if (!channel_blob) {
1241                 ast_assert(0);
1242                 return;
1243         }
1244
1245         message_type = stasis_message_type(message);
1246
1247         if (!message_type) {
1248                 ast_assert(0);
1249                 return;
1250         }
1251
1252         if (message_type == meetme_join_type()) {
1253                 event = "MeetmeJoin";
1254         } else if (message_type == meetme_leave_type()) {
1255                 event = "MeetmeLeave";
1256         } else if (message_type == meetme_end_type()) {
1257                 event = "MeetmeEnd";
1258         } else if (message_type == meetme_mute_type()) {
1259                 event = "MeetmeMute";
1260         } else if (message_type == meetme_talking_type()) {
1261                 event = "MeetmeTalking";
1262         } else if (message_type == meetme_talk_request_type()) {
1263                 event = "MeetmeTalkRequest";
1264         } else {
1265                 ast_assert(0);
1266                 return;
1267         }
1268
1269         if (!event) {
1270                 ast_assert(0);
1271                 return;
1272         }
1273
1274         conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
1275         if (!conference_num) {
1276                 ast_assert(0);
1277                 return;
1278         }
1279
1280         status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
1281         if (status) {
1282                 ast_str_append_event_header(&extra_text, "Status", status);
1283         }
1284
1285         if (channel_blob->snapshot) {
1286                 channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
1287         }
1288
1289         if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
1290                 int user_number = ast_json_integer_get(json_cur);
1291                 RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
1292                 if (!user_prop_str) {
1293                         return;
1294                 }
1295
1296                 ast_str_set(&user_prop_str, 0, "%d", user_number);
1297                 ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
1298
1299                 if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
1300                         int duration = ast_json_integer_get(json_cur);
1301                         ast_str_set(&user_prop_str, 0, "%d", duration);
1302                         ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
1303                 }
1304
1305                 json_cur = NULL;
1306         }
1307
1308         manager_event(EVENT_FLAG_CALL, event,
1309                 "Meetme: %s\r\n"
1310                 "%s"
1311                 "%s",
1312                 conference_num,
1313                 channel_text ? ast_str_buffer(channel_text) : "",
1314                 extra_text ? ast_str_buffer(extra_text) : "");
1315 }
1316
1317 /*!
1318  * \internal
1319  * \brief Build a json object from a status value for inclusion in json extras for meetme_stasis_generate_msg
1320  * \since 12.0.0
1321  *
1322  * \param on if true, then status is on. Otherwise status is off
1323  * \retval NULL on failure to allocate the JSON blob.
1324  * \retval pointer to the JSON blob if successful.
1325  */
1326 static struct ast_json *status_to_json(int on)
1327 {
1328         struct ast_json *json_object = ast_json_pack("{s: s}",
1329                 "status", on ? "on" : "off");
1330
1331         return json_object;
1332 }
1333
1334 /*!
1335  * \internal
1336  * \brief Generate a stasis message associated with a meetme event
1337  * \since 12.0.0
1338  *
1339  * \param meetme_confere The conference responsible for generating this message
1340  * \param chan The channel involved in the message (NULL allowed)
1341  * \param user The conference user involved in the message (NULL allowed)
1342  * \param message_type the type the stasis message being generated
1343  * \param extras Additional json fields desired for inclusion
1344  */
1345 static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan,
1346         struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
1347 {
1348         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1349         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1350
1351         json_object = ast_json_pack("{s: s}",
1352                 "Meetme", meetme_conference->confno);
1353
1354         if (!json_object) {
1355                 return;
1356         }
1357
1358         if (extras) {
1359                 ast_json_object_update(json_object, extras);
1360         }
1361
1362         if (user) {
1363                 struct timeval now = ast_tvnow();
1364                 long duration = (long)(now.tv_sec - user->jointime);
1365                 struct ast_json *json_user;
1366                 struct ast_json *json_user_duration;
1367
1368                 json_user = ast_json_integer_create(user->user_no);
1369                 if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
1370                         return;
1371                 }
1372
1373                 if (duration > 0) {
1374                         json_user_duration = ast_json_integer_create(duration);
1375                         if (!json_user_duration
1376                                 || ast_json_object_set(json_object, "duration", json_user_duration)) {
1377                                 return;
1378                         }
1379                 }
1380         }
1381
1382         msg = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), message_type, json_object);
1383
1384         if (!msg) {
1385                 return;
1386         }
1387
1388         stasis_publish(ast_channel_topic(chan), msg);
1389 }
1390
1391 static int admin_exec(struct ast_channel *chan, const char *data);
1392 static void *recordthread(void *args);
1393
1394 static const char *istalking(int x)
1395 {
1396         if (x > 0)
1397                 return "(talking)";
1398         else if (x < 0)
1399                 return "(unmonitored)";
1400         else 
1401                 return "(not talking)";
1402 }
1403
1404 static int careful_write(int fd, unsigned char *data, int len, int block)
1405 {
1406         int res;
1407         int x;
1408
1409         while (len) {
1410                 if (block) {
1411                         x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1412                         res = ioctl(fd, DAHDI_IOMUX, &x);
1413                 } else
1414                         res = 0;
1415                 if (res >= 0)
1416                         res = write(fd, data, len);
1417                 if (res < 1) {
1418                         if (errno != EAGAIN) {
1419                                 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1420                                 return -1;
1421                         } else
1422                                 return 0;
1423                 }
1424                 len -= res;
1425                 data += res;
1426         }
1427
1428         return 0;
1429 }
1430
1431 static int set_talk_volume(struct ast_conf_user *user, int volume)
1432 {
1433         char gain_adjust;
1434
1435         /* attempt to make the adjustment in the channel driver;
1436            if successful, don't adjust in the frame reading routine
1437         */
1438         gain_adjust = gain_map[volume + 5];
1439
1440         return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1441 }
1442
1443 static int set_listen_volume(struct ast_conf_user *user, int volume)
1444 {
1445         char gain_adjust;
1446
1447         /* attempt to make the adjustment in the channel driver;
1448            if successful, don't adjust in the frame reading routine
1449         */
1450         gain_adjust = gain_map[volume + 5];
1451
1452         return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1453 }
1454
1455 static void tweak_volume(struct volume *vol, enum volume_action action)
1456 {
1457         switch (action) {
1458         case VOL_UP:
1459                 switch (vol->desired) { 
1460                 case 5:
1461                         break;
1462                 case 0:
1463                         vol->desired = 2;
1464                         break;
1465                 case -2:
1466                         vol->desired = 0;
1467                         break;
1468                 default:
1469                         vol->desired++;
1470                         break;
1471                 }
1472                 break;
1473         case VOL_DOWN:
1474                 switch (vol->desired) {
1475                 case -5:
1476                         break;
1477                 case 2:
1478                         vol->desired = 0;
1479                         break;
1480                 case 0:
1481                         vol->desired = -2;
1482                         break;
1483                 default:
1484                         vol->desired--;
1485                         break;
1486                 }
1487         }
1488 }
1489
1490 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
1491 {
1492         tweak_volume(&user->talk, action);
1493         /* attempt to make the adjustment in the channel driver;
1494            if successful, don't adjust in the frame reading routine
1495         */
1496         if (!set_talk_volume(user, user->talk.desired))
1497                 user->talk.actual = 0;
1498         else
1499                 user->talk.actual = user->talk.desired;
1500 }
1501
1502 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
1503 {
1504         tweak_volume(&user->listen, action);
1505         /* attempt to make the adjustment in the channel driver;
1506            if successful, don't adjust in the frame reading routine
1507         */
1508         if (!set_listen_volume(user, user->listen.desired))
1509                 user->listen.actual = 0;
1510         else
1511                 user->listen.actual = user->listen.desired;
1512 }
1513
1514 static void reset_volumes(struct ast_conf_user *user)
1515 {
1516         signed char zero_volume = 0;
1517
1518         ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1519         ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
1520 }
1521
1522 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
1523 {
1524         unsigned char *data;
1525         int len;
1526         int res = -1;
1527
1528         ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1529                 "Conference: %s\r\n"
1530                 "Marked: %d",
1531                 ast_channel_name(chan),
1532                 conf->confno,
1533                 conf->markedusers);
1534
1535         if (!ast_check_hangup(chan))
1536                 res = ast_autoservice_start(chan);
1537
1538         AST_LIST_LOCK(&confs);
1539
1540         switch(sound) {
1541         case ENTER:
1542                 data = enter;
1543                 len = sizeof(enter);
1544                 break;
1545         case LEAVE:
1546                 data = leave;
1547                 len = sizeof(leave);
1548                 break;
1549         default:
1550                 data = NULL;
1551                 len = 0;
1552         }
1553         if (data) {
1554                 careful_write(conf->fd, data, len, 1);
1555         }
1556
1557         AST_LIST_UNLOCK(&confs);
1558
1559         if (!res) 
1560                 ast_autoservice_stop(chan);
1561 }
1562
1563 static int user_no_cmp(void *obj, void *arg, int flags)
1564 {
1565         struct ast_conf_user *user = obj;
1566         int *user_no = arg;
1567
1568         if (user->user_no == *user_no) {
1569                 return (CMP_MATCH | CMP_STOP);
1570         }
1571
1572         return 0;
1573 }
1574
1575 static int user_max_cmp(void *obj, void *arg, int flags)
1576 {
1577         struct ast_conf_user *user = obj;
1578         int *max_no = arg;
1579
1580         if (user->user_no > *max_no) {
1581                 *max_no = user->user_no;
1582         }
1583
1584         return 0;
1585 }
1586
1587 /*!
1588  * \brief Find or create a conference
1589  *
1590  * \param confno The conference name/number
1591  * \param pin The regular user pin
1592  * \param pinadmin The admin pin
1593  * \param make Make the conf if it doesn't exist
1594  * \param dynamic Mark the newly created conference as dynamic
1595  * \param refcount How many references to mark on the conference
1596  * \param chan The asterisk channel
1597  * \param test
1598  *
1599  * \return A pointer to the conference struct, or NULL if it wasn't found and
1600  *         make or dynamic were not set.
1601  */
1602 static struct ast_conference *build_conf(const char *confno, const char *pin,
1603         const char *pinadmin, int make, int dynamic, int refcount,
1604         const struct ast_channel *chan, struct ast_test *test)
1605 {
1606         struct ast_conference *cnf;
1607         struct dahdi_confinfo dahdic = { 0, };
1608         int confno_int = 0;
1609         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
1610         struct ast_format tmp_fmt;
1611
1612         AST_LIST_LOCK(&confs);
1613
1614         AST_LIST_TRAVERSE(&confs, cnf, list) {
1615                 if (!strcmp(confno, cnf->confno)) 
1616                         break;
1617         }
1618
1619         if (cnf || (!make && !dynamic) || !cap_slin)
1620                 goto cnfout;
1621
1622         ast_format_cap_add(cap_slin, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
1623         /* Make a new one */
1624         if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
1625                 !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
1626                 goto cnfout;
1627         }
1628
1629         ast_mutex_init(&cnf->playlock);
1630         ast_mutex_init(&cnf->listenlock);
1631         cnf->recordthread = AST_PTHREADT_NULL;
1632         ast_mutex_init(&cnf->recordthreadlock);
1633         cnf->announcethread = AST_PTHREADT_NULL;
1634         ast_mutex_init(&cnf->announcethreadlock);
1635         ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1636         ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1637         ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1638         ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1639
1640         /* Setup a new dahdi conference */
1641         dahdic.confno = -1;
1642         dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1643         cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1644         if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1645                 if (test) {
1646                         /* if we are creating a conference for a unit test, it is not neccesary
1647                          * to open a pseudo channel, so, if we fail continue creating
1648                          * the conference. */
1649                         ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1650                 } else {
1651                         ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1652                         if (cnf->fd >= 0)
1653                                 close(cnf->fd);
1654                         ao2_ref(cnf->usercontainer, -1);
1655                         ast_mutex_destroy(&cnf->playlock);
1656                         ast_mutex_destroy(&cnf->listenlock);
1657                         ast_mutex_destroy(&cnf->recordthreadlock);
1658                         ast_mutex_destroy(&cnf->announcethreadlock);
1659                         ast_free(cnf);
1660                         cnf = NULL;
1661                         goto cnfout;
1662                 }
1663         }
1664
1665         cnf->dahdiconf = dahdic.confno;
1666
1667         /* Setup a new channel for playback of audio files */
1668         cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1669         if (cnf->chan) {
1670                 ast_set_read_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
1671                 ast_set_write_format_by_id(cnf->chan, AST_FORMAT_SLINEAR);
1672                 dahdic.chan = 0;
1673                 dahdic.confno = cnf->dahdiconf;
1674                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1675                 if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1676                         if (test) {
1677                                 ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1678                         }
1679                         ast_log(LOG_WARNING, "Error setting conference\n");
1680                         if (cnf->chan)
1681                                 ast_hangup(cnf->chan);
1682                         else
1683                                 close(cnf->fd);
1684                         ao2_ref(cnf->usercontainer, -1);
1685                         ast_mutex_destroy(&cnf->playlock);
1686                         ast_mutex_destroy(&cnf->listenlock);
1687                         ast_mutex_destroy(&cnf->recordthreadlock);
1688                         ast_mutex_destroy(&cnf->announcethreadlock);
1689                         ast_free(cnf);
1690                         cnf = NULL;
1691                         goto cnfout;
1692                 }
1693         }
1694
1695         /* Fill the conference struct */
1696         cnf->start = time(NULL);
1697         cnf->maxusers = 0x7fffffff;
1698         cnf->isdynamic = dynamic ? 1 : 0;
1699         ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1700         AST_LIST_INSERT_HEAD(&confs, cnf, list);
1701
1702         /* Reserve conference number in map */
1703         if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1704                 conf_map[confno_int] = 1;
1705         
1706 cnfout:
1707         cap_slin = ast_format_cap_destroy(cap_slin);
1708         if (cnf)
1709                 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1710
1711         AST_LIST_UNLOCK(&confs);
1712
1713         return cnf;
1714 }
1715
1716 static char *complete_confno(const char *word, int state)
1717 {
1718         struct ast_conference *cnf;
1719         char *ret = NULL;
1720         int which = 0;
1721         int len = strlen(word);
1722
1723         AST_LIST_LOCK(&confs);
1724         AST_LIST_TRAVERSE(&confs, cnf, list) {
1725                 if (!strncmp(word, cnf->confno, len) && ++which > state) {
1726                         /* dup before releasing the lock */
1727                         ret = ast_strdup(cnf->confno);
1728                         break;
1729                 }
1730         }
1731         AST_LIST_UNLOCK(&confs);
1732         return ret;
1733 }
1734
1735 static char *complete_userno(struct ast_conference *cnf, const char *word, int state)
1736 {
1737         char usrno[50];
1738         struct ao2_iterator iter;
1739         struct ast_conf_user *usr;
1740         char *ret = NULL;
1741         int which = 0;
1742         int len = strlen(word);
1743
1744         iter = ao2_iterator_init(cnf->usercontainer, 0);
1745         for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1746                 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1747                 if (!strncmp(word, usrno, len) && ++which > state) {
1748                         ao2_ref(usr, -1);
1749                         ret = ast_strdup(usrno);
1750                         break;
1751                 }
1752         }
1753         ao2_iterator_destroy(&iter);
1754         return ret;
1755 }
1756
1757 static char *complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
1758 {
1759         if (pos == 2) {
1760                 return complete_confno(word, state);
1761         }
1762         if (pos == 3) {
1763                 int len = strlen(word);
1764                 char *ret = NULL;
1765                 char *saved = NULL;
1766                 char *myline;
1767                 char *confno;
1768                 struct ast_conference *cnf;
1769
1770                 if (!strncasecmp(word, "all", len)) {
1771                         if (state == 0) {
1772                                 return ast_strdup("all");
1773                         }
1774                         --state;
1775                 }
1776
1777                 /* Extract the confno from the command line. */
1778                 myline = ast_strdupa(line);
1779                 strtok_r(myline, " ", &saved);
1780                 strtok_r(NULL, " ", &saved);
1781                 confno = strtok_r(NULL, " ", &saved);
1782
1783                 AST_LIST_LOCK(&confs);
1784                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1785                         if (!strcmp(confno, cnf->confno)) {
1786                                 ret = complete_userno(cnf, word, state);
1787                                 break;
1788                         }
1789                 }
1790                 AST_LIST_UNLOCK(&confs);
1791
1792                 return ret;
1793         }
1794         return NULL;
1795 }
1796
1797 static char *complete_meetmecmd_lock(const char *word, int pos, int state)
1798 {
1799         if (pos == 2) {
1800                 return complete_confno(word, state);
1801         }
1802         return NULL;
1803 }
1804
1805 static char *complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
1806 {
1807         int len;
1808
1809         if (pos == 2) {
1810                 len = strlen(word);
1811                 if (!strncasecmp(word, STR_CONCISE, len)) {
1812                         if (state == 0) {
1813                                 return ast_strdup(STR_CONCISE);
1814                         }
1815                         --state;
1816                 }
1817
1818                 return complete_confno(word, state);
1819         }
1820         if (pos == 3 && state == 0) {
1821                 char *saved = NULL;
1822                 char *myline;
1823                 char *confno;
1824
1825                 /* Extract the confno from the command line. */
1826                 myline = ast_strdupa(line);
1827                 strtok_r(myline, " ", &saved);
1828                 strtok_r(NULL, " ", &saved);
1829                 confno = strtok_r(NULL, " ", &saved);
1830
1831                 if (!strcasecmp(confno, STR_CONCISE)) {
1832                         /* There is nothing valid in this position now. */
1833                         return NULL;
1834                 }
1835
1836                 len = strlen(word);
1837                 if (!strncasecmp(word, STR_CONCISE, len)) {
1838                         return ast_strdup(STR_CONCISE);
1839                 }
1840         }
1841         return NULL;
1842 }
1843
1844 static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1845 {
1846         /* Process the command */
1847         struct ast_conf_user *user;
1848         struct ast_conference *cnf;
1849         int hr, min, sec;
1850         int total = 0;
1851         time_t now;
1852 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
1853 #define MC_DATA_FORMAT "%-12.12s   %4.4d              %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
1854
1855         switch (cmd) {
1856         case CLI_INIT:
1857                 e->command = "meetme list";
1858                 e->usage =
1859                         "Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
1860                         "       List all conferences or a specific conference.\n";
1861                 return NULL;
1862         case CLI_GENERATE:
1863                 return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
1864         }
1865
1866         if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
1867                 /* List all the conferences */
1868                 int concise = (a->argc == 3);
1869                 struct ast_str *marked_users;
1870
1871                 if (!(marked_users = ast_str_create(30))) {
1872                         return CLI_FAILURE;
1873                 }
1874
1875                 now = time(NULL);
1876                 AST_LIST_LOCK(&confs);
1877                 if (AST_LIST_EMPTY(&confs)) {
1878                         if (!concise) {
1879                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1880                         }
1881                         AST_LIST_UNLOCK(&confs);
1882                         ast_free(marked_users);
1883                         return CLI_SUCCESS;
1884                 }
1885                 if (!concise) {
1886                         ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1887                 }
1888                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1889                         hr = (now - cnf->start) / 3600;
1890                         min = ((now - cnf->start) % 3600) / 60;
1891                         sec = (now - cnf->start) % 60;
1892                         if (!concise) {
1893                                 if (cnf->markedusers == 0) {
1894                                         ast_str_set(&marked_users, 0, "N/A ");
1895                                 } else {
1896                                         ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
1897                                 }
1898                                 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
1899                                         ast_str_buffer(marked_users), hr, min, sec,
1900                                         cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
1901                         } else {
1902                                 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1903                                         cnf->confno,
1904                                         cnf->users,
1905                                         cnf->markedusers,
1906                                         hr, min, sec,
1907                                         cnf->isdynamic,
1908                                         cnf->locked);
1909                         }
1910
1911                         total += cnf->users;
1912                 }
1913                 AST_LIST_UNLOCK(&confs);
1914                 if (!concise) {
1915                         ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1916                 }
1917                 ast_free(marked_users);
1918                 return CLI_SUCCESS;
1919         }
1920         if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
1921                 struct ao2_iterator user_iter;
1922                 int concise = (a->argc == 4);
1923
1924                 /* List all the users in a conference */
1925                 if (AST_LIST_EMPTY(&confs)) {
1926                         if (!concise) {
1927                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1928                         }
1929                         return CLI_SUCCESS;
1930                 }
1931                 /* Find the right conference */
1932                 AST_LIST_LOCK(&confs);
1933                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1934                         if (strcmp(cnf->confno, a->argv[2]) == 0) {
1935                                 break;
1936                         }
1937                 }
1938                 if (!cnf) {
1939                         if (!concise)
1940                                 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1941                         AST_LIST_UNLOCK(&confs);
1942                         return CLI_SUCCESS;
1943                 }
1944                 /* Show all the users */
1945                 time(&now);
1946                 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1947                 while((user = ao2_iterator_next(&user_iter))) {
1948                         hr = (now - user->jointime) / 3600;
1949                         min = ((now - user->jointime) % 3600) / 60;
1950                         sec = (now - user->jointime) % 60;
1951                         if (!concise) {
1952                                 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1953                                         user->user_no,
1954                                         S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
1955                                         S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
1956                                         ast_channel_name(user->chan),
1957                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
1958                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
1959                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1960                                         user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1961                                         istalking(user->talking), hr, min, sec); 
1962                         } else {
1963                                 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1964                                         user->user_no,
1965                                         S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, ""),
1966                                         S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, ""),
1967                                         ast_channel_name(user->chan),
1968                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
1969                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
1970                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1971                                         user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1972                                         user->talking, hr, min, sec);
1973                         }
1974                         ao2_ref(user, -1);
1975                 }
1976                 ao2_iterator_destroy(&user_iter);
1977                 if (!concise) {
1978                         ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1979                 }
1980                 AST_LIST_UNLOCK(&confs);
1981                 return CLI_SUCCESS;
1982         }
1983         return CLI_SHOWUSAGE;
1984 }
1985
1986
1987 static char *meetme_cmd_helper(struct ast_cli_args *a)
1988 {
1989         /* Process the command */
1990         struct ast_str *cmdline;
1991
1992         /* Max confno length */
1993         if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
1994                 return CLI_FAILURE;
1995         }
1996
1997         ast_str_set(&cmdline, 0, "%s", a->argv[2]);     /* Argv 2: conference number */
1998         if (strcasestr(a->argv[1], "lock")) {
1999                 if (strcasecmp(a->argv[1], "lock") == 0) {
2000                         /* Lock */
2001                         ast_str_append(&cmdline, 0, ",L");
2002                 } else {
2003                         /* Unlock */
2004                         ast_str_append(&cmdline, 0, ",l");
2005                 }
2006         } else if (strcasestr(a->argv[1], "mute")) { 
2007                 if (strcasecmp(a->argv[1], "mute") == 0) {
2008                         /* Mute */
2009                         if (strcasecmp(a->argv[3], "all") == 0) {
2010                                 ast_str_append(&cmdline, 0, ",N");
2011                         } else {
2012                                 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);       
2013                         }
2014                 } else {
2015                         /* Unmute */
2016                         if (strcasecmp(a->argv[3], "all") == 0) {
2017                                 ast_str_append(&cmdline, 0, ",n");
2018                         } else {
2019                                 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
2020                         }
2021                 }
2022         } else if (strcasecmp(a->argv[1], "kick") == 0) {
2023                 if (strcasecmp(a->argv[3], "all") == 0) {
2024                         /* Kick all */
2025                         ast_str_append(&cmdline, 0, ",K");
2026                 } else {
2027                         /* Kick a single user */
2028                         ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
2029                 }
2030         } else {
2031                 /*
2032                  * Should never get here because it is already filtered by the
2033                  * callers.
2034                  */
2035                 ast_free(cmdline);
2036                 return CLI_SHOWUSAGE;
2037         }
2038
2039         ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
2040
2041         admin_exec(NULL, ast_str_buffer(cmdline));
2042         ast_free(cmdline);
2043
2044         return CLI_SUCCESS;
2045 }
2046
2047 static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2048 {
2049         switch (cmd) {
2050         case CLI_INIT:
2051                 e->command = "meetme {lock|unlock}";
2052                 e->usage =
2053                         "Usage: meetme lock|unlock <confno>\n"
2054                         "       Lock or unlock a conference to new users.\n";
2055                 return NULL;
2056         case CLI_GENERATE:
2057                 return complete_meetmecmd_lock(a->word, a->pos, a->n);
2058         }
2059
2060         if (a->argc != 3) {
2061                 return CLI_SHOWUSAGE;
2062         }
2063
2064         return meetme_cmd_helper(a);
2065 }
2066
2067 static char *meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2068 {
2069         switch (cmd) {
2070         case CLI_INIT:
2071                 e->command = "meetme kick";
2072                 e->usage =
2073                         "Usage: meetme kick <confno> all|<userno>\n"
2074                         "       Kick a conference or a user in a conference.\n";
2075                 return NULL;
2076         case CLI_GENERATE:
2077                 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2078         }
2079
2080         if (a->argc != 4) {
2081                 return CLI_SHOWUSAGE;
2082         }
2083
2084         return meetme_cmd_helper(a);
2085 }
2086
2087 static char *meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2088 {
2089         switch (cmd) {
2090         case CLI_INIT:
2091                 e->command = "meetme {mute|unmute}";
2092                 e->usage =
2093                         "Usage: meetme mute|unmute <confno> all|<userno>\n"
2094                         "       Mute or unmute a conference or a user in a conference.\n";
2095                 return NULL;
2096         case CLI_GENERATE:
2097                 return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2098         }
2099
2100         if (a->argc != 4) {
2101                 return CLI_SHOWUSAGE;
2102         }
2103
2104         return meetme_cmd_helper(a);
2105 }
2106
2107 static const char *sla_hold_str(unsigned int hold_access)
2108 {
2109         const char *hold = "Unknown";
2110
2111         switch (hold_access) {
2112         case SLA_HOLD_OPEN:
2113                 hold = "Open";
2114                 break;
2115         case SLA_HOLD_PRIVATE:
2116                 hold = "Private";
2117         default:
2118                 break;
2119         }
2120
2121         return hold;
2122 }
2123
2124 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2125 {
2126         struct ao2_iterator i;
2127         struct sla_trunk *trunk;
2128
2129         switch (cmd) {
2130         case CLI_INIT:
2131                 e->command = "sla show trunks";
2132                 e->usage =
2133                         "Usage: sla show trunks\n"
2134                         "       This will list all trunks defined in sla.conf\n";
2135                 return NULL;
2136         case CLI_GENERATE:
2137                 return NULL;
2138         }
2139
2140         ast_cli(a->fd, "\n"
2141                     "=============================================================\n"
2142                     "=== Configured SLA Trunks ===================================\n"
2143                     "=============================================================\n"
2144                     "===\n");
2145         i = ao2_iterator_init(sla_trunks, 0);
2146         for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
2147                 struct sla_station_ref *station_ref;
2148                 char ring_timeout[16] = "(none)";
2149
2150                 ao2_lock(trunk);
2151
2152                 if (trunk->ring_timeout) {
2153                         snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
2154                 }
2155
2156                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2157                             "=== Trunk Name:       %s\n"
2158                             "=== ==> Device:       %s\n"
2159                             "=== ==> AutoContext:  %s\n"
2160                             "=== ==> RingTimeout:  %s\n"
2161                             "=== ==> BargeAllowed: %s\n"
2162                             "=== ==> HoldAccess:   %s\n"
2163                             "=== ==> Stations ...\n",
2164                             trunk->name, trunk->device, 
2165                             S_OR(trunk->autocontext, "(none)"), 
2166                             ring_timeout,
2167                             trunk->barge_disabled ? "No" : "Yes",
2168                             sla_hold_str(trunk->hold_access));
2169
2170                 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
2171                         ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
2172                 }
2173
2174                 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
2175
2176                 ao2_unlock(trunk);
2177         }
2178         ao2_iterator_destroy(&i);
2179         ast_cli(a->fd, "=============================================================\n\n");
2180
2181         return CLI_SUCCESS;
2182 }
2183
2184 static const char *trunkstate2str(enum sla_trunk_state state)
2185 {
2186 #define S(e) case e: return # e;
2187         switch (state) {
2188         S(SLA_TRUNK_STATE_IDLE)
2189         S(SLA_TRUNK_STATE_RINGING)
2190         S(SLA_TRUNK_STATE_UP)
2191         S(SLA_TRUNK_STATE_ONHOLD)
2192         S(SLA_TRUNK_STATE_ONHOLD_BYME)
2193         }
2194         return "Uknown State";
2195 #undef S
2196 }
2197
2198 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2199 {
2200         struct ao2_iterator i;
2201         struct sla_station *station;
2202
2203         switch (cmd) {
2204         case CLI_INIT:
2205                 e->command = "sla show stations";
2206                 e->usage =
2207                         "Usage: sla show stations\n"
2208                         "       This will list all stations defined in sla.conf\n";
2209                 return NULL;
2210         case CLI_GENERATE:
2211                 return NULL;
2212         }
2213
2214         ast_cli(a->fd, "\n" 
2215                     "=============================================================\n"
2216                     "=== Configured SLA Stations =================================\n"
2217                     "=============================================================\n"
2218                     "===\n");
2219         i = ao2_iterator_init(sla_stations, 0);
2220         for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
2221                 struct sla_trunk_ref *trunk_ref;
2222                 char ring_timeout[16] = "(none)";
2223                 char ring_delay[16] = "(none)";
2224
2225                 ao2_lock(station);
2226
2227                 if (station->ring_timeout) {
2228                         snprintf(ring_timeout, sizeof(ring_timeout), 
2229                                 "%u", station->ring_timeout);
2230                 }
2231                 if (station->ring_delay) {
2232                         snprintf(ring_delay, sizeof(ring_delay), 
2233                                 "%u", station->ring_delay);
2234                 }
2235                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2236                             "=== Station Name:    %s\n"
2237                             "=== ==> Device:      %s\n"
2238                             "=== ==> AutoContext: %s\n"
2239                             "=== ==> RingTimeout: %s\n"
2240                             "=== ==> RingDelay:   %s\n"
2241                             "=== ==> HoldAccess:  %s\n"
2242                             "=== ==> Trunks ...\n",
2243                             station->name, station->device,
2244                             S_OR(station->autocontext, "(none)"), 
2245                             ring_timeout, ring_delay,
2246                             sla_hold_str(station->hold_access));
2247                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2248                         if (trunk_ref->ring_timeout) {
2249                                 snprintf(ring_timeout, sizeof(ring_timeout),
2250                                         "%u", trunk_ref->ring_timeout);
2251                         } else
2252                                 strcpy(ring_timeout, "(none)");
2253                         if (trunk_ref->ring_delay) {
2254                                 snprintf(ring_delay, sizeof(ring_delay),
2255                                         "%u", trunk_ref->ring_delay);
2256                         } else
2257                                 strcpy(ring_delay, "(none)");
2258                                 ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
2259                                     "===       ==> State:       %s\n"
2260                                     "===       ==> RingTimeout: %s\n"
2261                                     "===       ==> RingDelay:   %s\n",
2262                                     trunk_ref->trunk->name,
2263                                     trunkstate2str(trunk_ref->state),
2264                                     ring_timeout, ring_delay);
2265                 }
2266                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2267                             "===\n");
2268
2269                 ao2_unlock(station);
2270         }
2271         ao2_iterator_destroy(&i);
2272         ast_cli(a->fd, "============================================================\n"
2273                     "\n");
2274
2275         return CLI_SUCCESS;
2276 }
2277
2278 static struct ast_cli_entry cli_meetme[] = {
2279         AST_CLI_DEFINE(meetme_kick_cmd, "Kick a conference or a user in a conference."),
2280         AST_CLI_DEFINE(meetme_show_cmd, "List all conferences or a specific conference."),
2281         AST_CLI_DEFINE(meetme_lock_cmd, "Lock or unlock a conference to new users."),
2282         AST_CLI_DEFINE(meetme_mute_cmd, "Mute or unmute a conference or a user in a conference."),
2283         AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
2284         AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
2285 };
2286
2287 static void conf_flush(int fd, struct ast_channel *chan)
2288 {
2289         int x;
2290
2291         /* read any frames that may be waiting on the channel
2292            and throw them away
2293         */
2294         if (chan) {
2295                 struct ast_frame *f;
2296
2297                 /* when no frames are available, this will wait
2298                    for 1 millisecond maximum
2299                 */
2300                 while (ast_waitfor(chan, 1) > 0) {
2301                         f = ast_read(chan);
2302                         if (f)
2303                                 ast_frfree(f);
2304                         else /* channel was hung up or something else happened */
2305                                 break;
2306                 }
2307         }
2308
2309         /* flush any data sitting in the pseudo channel */
2310         x = DAHDI_FLUSH_ALL;
2311         if (ioctl(fd, DAHDI_FLUSH, &x))
2312                 ast_log(LOG_WARNING, "Error flushing channel\n");
2313
2314 }
2315
2316 /*! \brief Remove the conference from the list and free it.
2317
2318    We assume that this was called while holding conflock. */
2319 static int conf_free(struct ast_conference *conf)
2320 {
2321         int x;
2322         struct announce_listitem *item;
2323
2324         AST_LIST_REMOVE(&confs, conf, list);
2325
2326         meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2327
2328         if (conf->recording == MEETME_RECORD_ACTIVE) {
2329                 conf->recording = MEETME_RECORD_TERMINATE;
2330                 AST_LIST_UNLOCK(&confs);
2331                 while (1) {
2332                         usleep(1);
2333                         AST_LIST_LOCK(&confs);
2334                         if (conf->recording == MEETME_RECORD_OFF)
2335                                 break;
2336                         AST_LIST_UNLOCK(&confs);
2337                 }
2338         }
2339
2340         for (x = 0; x < AST_FRAME_BITS; x++) {
2341                 if (conf->transframe[x])
2342                         ast_frfree(conf->transframe[x]);
2343                 if (conf->transpath[x])
2344                         ast_translator_free_path(conf->transpath[x]);
2345         }
2346         if (conf->announcethread != AST_PTHREADT_NULL) {
2347                 ast_mutex_lock(&conf->announcelistlock);
2348                 conf->announcethread_stop = 1;
2349                 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
2350                 ast_cond_signal(&conf->announcelist_addition);
2351                 ast_mutex_unlock(&conf->announcelistlock);
2352                 pthread_join(conf->announcethread, NULL);
2353         
2354                 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2355                         /* If it's a voicemail greeting file we don't want to remove it */
2356                         if (!item->vmrec){
2357                                 ast_filedelete(item->namerecloc, NULL);
2358                         }
2359                         ao2_ref(item, -1);
2360                 }
2361                 ast_mutex_destroy(&conf->announcelistlock);
2362         }
2363
2364         if (conf->origframe)
2365                 ast_frfree(conf->origframe);
2366         ast_hangup(conf->lchan);
2367         ast_hangup(conf->chan);
2368         if (conf->fd >= 0)
2369                 close(conf->fd);
2370         if (conf->recordingfilename) {
2371                 ast_free(conf->recordingfilename);
2372         }
2373         if (conf->usercontainer) {
2374                 ao2_ref(conf->usercontainer, -1);
2375         }
2376         if (conf->recordingformat) {
2377                 ast_free(conf->recordingformat);
2378         }
2379         ast_mutex_destroy(&conf->playlock);
2380         ast_mutex_destroy(&conf->listenlock);
2381         ast_mutex_destroy(&conf->recordthreadlock);
2382         ast_mutex_destroy(&conf->announcethreadlock);
2383         ast_free(conf);
2384
2385         return 0;
2386 }
2387
2388 static void conf_queue_dtmf(const struct ast_conference *conf,
2389         const struct ast_conf_user *sender, struct ast_frame *f)
2390 {
2391         struct ast_conf_user *user;
2392         struct ao2_iterator user_iter;
2393
2394         user_iter = ao2_iterator_init(conf->usercontainer, 0);
2395         while ((user = ao2_iterator_next(&user_iter))) {
2396                 if (user == sender) {
2397                         ao2_ref(user, -1);
2398                         continue;
2399                 }
2400                 if (ast_write(user->chan, f) < 0)
2401                         ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2402                 ao2_ref(user, -1);
2403         }
2404         ao2_iterator_destroy(&user_iter);
2405 }
2406
2407 static void sla_queue_event_full(enum sla_event_type type, 
2408         struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
2409 {
2410         struct sla_event *event;
2411
2412         if (sla.thread == AST_PTHREADT_NULL) {
2413                 ao2_ref(station, -1);
2414                 ao2_ref(trunk_ref, -1);
2415                 return;
2416         }
2417
2418         if (!(event = ast_calloc(1, sizeof(*event)))) {
2419                 ao2_ref(station, -1);
2420                 ao2_ref(trunk_ref, -1);
2421                 return;
2422         }
2423
2424         event->type = type;
2425         event->trunk_ref = trunk_ref;
2426         event->station = station;
2427
2428         if (!lock) {
2429                 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2430                 return;
2431         }
2432
2433         ast_mutex_lock(&sla.lock);
2434         AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2435         ast_cond_signal(&sla.cond);
2436         ast_mutex_unlock(&sla.lock);
2437 }
2438
2439 static void sla_queue_event_nolock(enum sla_event_type type)
2440 {
2441         sla_queue_event_full(type, NULL, NULL, 0);
2442 }
2443
2444 static void sla_queue_event(enum sla_event_type type)
2445 {
2446         sla_queue_event_full(type, NULL, NULL, 1);
2447 }
2448
2449 /*! \brief Queue a SLA event from the conference */
2450 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
2451         struct ast_conference *conf)
2452 {
2453         struct sla_station *station;
2454         struct sla_trunk_ref *trunk_ref = NULL;
2455         char *trunk_name;
2456         struct ao2_iterator i;
2457
2458         trunk_name = ast_strdupa(conf->confno);
2459         strsep(&trunk_name, "_");
2460         if (ast_strlen_zero(trunk_name)) {
2461                 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
2462                 return;
2463         }
2464
2465         i = ao2_iterator_init(sla_stations, 0);
2466         while ((station = ao2_iterator_next(&i))) {
2467                 ao2_lock(station);
2468                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2469                         if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
2470                                 ao2_ref(trunk_ref, 1);
2471                                 break;
2472                         }
2473                 }
2474                 ao2_unlock(station);
2475                 if (trunk_ref) {
2476                         /* station reference given to sla_queue_event_full() */
2477                         break;
2478                 }
2479                 ao2_ref(station, -1);
2480         }
2481         ao2_iterator_destroy(&i);
2482
2483         if (!trunk_ref) {
2484                 ast_debug(1, "Trunk not found for event!\n");
2485                 return;
2486         }
2487
2488         sla_queue_event_full(type, trunk_ref, station, 1);
2489 }
2490
2491 /*! \brief Decrement reference counts, as incremented by find_conf() */
2492 static int dispose_conf(struct ast_conference *conf)
2493 {
2494         int res = 0;
2495         int confno_int = 0;
2496
2497         AST_LIST_LOCK(&confs);
2498         if (ast_atomic_dec_and_test(&conf->refcount)) {
2499                 /* Take the conference room number out of an inuse state */
2500                 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
2501                         conf_map[confno_int] = 0;
2502                 }
2503                 conf_free(conf);
2504                 res = 1;
2505         }
2506         AST_LIST_UNLOCK(&confs);
2507
2508         return res;
2509 }
2510
2511 static int rt_extend_conf(const char *confno)
2512 {
2513         char currenttime[32];
2514         char endtime[32];
2515         struct timeval now;
2516         struct ast_tm tm;
2517         struct ast_variable *var, *orig_var;
2518         char bookid[51];
2519
2520         if (!extendby) {
2521                 return 0;
2522         }
2523
2524         now = ast_tvnow();
2525
2526         ast_localtime(&now, &tm, NULL);
2527         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2528
2529         var = ast_load_realtime("meetme", "confno",
2530                 confno, "startTime<= ", currenttime,
2531                 "endtime>= ", currenttime, NULL);
2532
2533         orig_var = var;
2534
2535         /* Identify the specific RealTime conference */
2536         while (var) {
2537                 if (!strcasecmp(var->name, "bookid")) {
2538                         ast_copy_string(bookid, var->value, sizeof(bookid));
2539                 }
2540                 if (!strcasecmp(var->name, "endtime")) {
2541                         ast_copy_string(endtime, var->value, sizeof(endtime));
2542                 }
2543
2544                 var = var->next;
2545         }
2546         ast_variables_destroy(orig_var);
2547
2548         ast_strptime(endtime, DATE_FORMAT, &tm);
2549         now = ast_mktime(&tm, NULL);
2550
2551         now.tv_sec += extendby;
2552
2553         ast_localtime(&now, &tm, NULL);
2554         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2555         strcat(currenttime, "0"); /* Seconds needs to be 00 */
2556
2557         var = ast_load_realtime("meetme", "confno",
2558                 confno, "startTime<= ", currenttime,
2559                 "endtime>= ", currenttime, NULL);
2560
2561         /* If there is no conflict with extending the conference, update the DB */
2562         if (!var) {
2563                 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
2564                 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
2565                 return 0;
2566
2567         }
2568
2569         ast_variables_destroy(var);
2570         return -1;
2571 }
2572
2573 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
2574 {
2575         char *original_moh;
2576
2577         ast_channel_lock(chan);
2578         original_moh = ast_strdupa(ast_channel_musicclass(chan));
2579         ast_channel_musicclass_set(chan, musicclass);
2580         ast_channel_unlock(chan);
2581
2582         ast_moh_start(chan, original_moh, NULL);
2583
2584         ast_channel_lock(chan);
2585         ast_channel_musicclass_set(chan, original_moh);
2586         ast_channel_unlock(chan);
2587 }
2588
2589 static const char *get_announce_filename(enum announcetypes type)
2590 {
2591         switch (type) {
2592         case CONF_HASLEFT:
2593                 return "conf-hasleft";
2594                 break;
2595         case CONF_HASJOIN:
2596                 return "conf-hasjoin";
2597                 break;
2598         default:
2599                 return "";
2600         }
2601 }
2602
2603 static void *announce_thread(void *data)
2604 {
2605         struct announce_listitem *current;
2606         struct ast_conference *conf = data;
2607         int res;
2608         char filename[PATH_MAX] = "";
2609         AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
2610         AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2611
2612         while (!conf->announcethread_stop) {
2613                 ast_mutex_lock(&conf->announcelistlock);
2614                 if (conf->announcethread_stop) {
2615                         ast_mutex_unlock(&conf->announcelistlock);
2616                         break;
2617                 }
2618                 if (AST_LIST_EMPTY(&conf->announcelist))
2619                         ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2620
2621                 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2622                 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2623
2624                 ast_mutex_unlock(&conf->announcelistlock);
2625                 if (conf->announcethread_stop) {
2626                         break;
2627                 }
2628
2629                 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2630                         ast_debug(1, "About to play %s\n", current->namerecloc);
2631                         if (!ast_fileexists(current->namerecloc, NULL, NULL))
2632                                 continue;
2633                         if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2634                                 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2635                                         res = ast_waitstream(current->confchan, "");
2636                                 if (!res) {
2637                                         ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2638                                         if (!ast_streamfile(current->confchan, filename, current->language))
2639                                                 ast_waitstream(current->confchan, "");
2640                                 }
2641                         }
2642                         if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2643                                 /* only remove it if it isn't a VM recording file */
2644                                 ast_filedelete(current->namerecloc, NULL);
2645                         }
2646                 }
2647         }
2648
2649         /* thread marked to stop, clean up */
2650         while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2651                 /* only delete if it's a vm rec */
2652                 if (!current->vmrec) {
2653                         ast_filedelete(current->namerecloc, NULL);
2654                 }
2655                 ao2_ref(current, -1);
2656         }
2657         return NULL;
2658 }
2659
2660 static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
2661 {
2662         if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2663                 return 1;
2664         }
2665
2666         return (ast_channel_state(chan) == AST_STATE_UP);
2667 }
2668
2669 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
2670 {
2671         RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
2672         meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
2673 }
2674
2675 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
2676 {
2677         int last_talking = user->talking;
2678         if (last_talking == talking)
2679                 return;
2680
2681         user->talking = talking;
2682
2683         if (monitor) {
2684                 /* Check if talking state changed. Take care of -1 which means unmonitored */
2685                 int was_talking = (last_talking > 0);
2686                 int now_talking = (talking > 0);
2687                 if (was_talking != now_talking) {
2688                         send_talking_event(chan, conf, user, now_talking);
2689                 }
2690         }
2691 }
2692
2693 static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
2694 {
2695         struct ast_conf_user *user = obj;
2696         /* actual pointer contents of check_admin_arg is irrelevant */
2697
2698         if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2699                 user->adminflags |= ADMINFLAG_HANGUP;
2700         }
2701         return 0;
2702 }
2703
2704 static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
2705 {
2706         struct ast_conf_user *user = obj;
2707         /* actual pointer contents of check_admin_arg is irrelevant */
2708
2709         if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2710                 user->adminflags |= ADMINFLAG_KICKME;
2711         }
2712         return 0;
2713 }
2714
2715 static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
2716 {
2717         struct ast_conf_user *user = obj;
2718         /* actual pointer contents of check_admin_arg is irrelevant */
2719
2720         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2721                 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
2722         }
2723         return 0;
2724 }
2725
2726 static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
2727 {
2728         struct ast_conf_user *user = obj;
2729         /* actual pointer contents of check_admin_arg is irrelevant */
2730
2731         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2732                 user->adminflags |= ADMINFLAG_MUTED;
2733         }
2734         return 0;
2735 }
2736
2737 enum menu_modes {
2738         MENU_DISABLED = 0,
2739         MENU_NORMAL,
2740         MENU_ADMIN,
2741         MENU_ADMIN_EXTENDED,
2742 };
2743
2744 /*! \internal
2745  * \brief Processes menu options for the standard menu (accessible through the 's' option for app_meetme)
2746  *
2747  * \param menu_mode a pointer to the currently active menu_mode.
2748  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2749  * \param conf the active conference for which the user has called the menu from.
2750  * \param confflags flags used by conf for various options
2751  * \param chan ast_channel belonging to the user who called the menu
2752  * \param user which meetme conference user invoked the menu
2753  */
2754 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)
2755 {
2756         switch (*dtmf) {
2757         case '1': /* Un/Mute */
2758                 *menu_mode = MENU_DISABLED;
2759
2760                 /* user can only toggle the self-muted state */
2761                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2762
2763                 /* they can't override the admin mute state */
2764                 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2765                         if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2766                                 ast_waitstream(chan, "");
2767                         }
2768                 } else {
2769                         if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2770                                 ast_waitstream(chan, "");
2771                         }
2772                 }
2773                 break;
2774
2775         case '2':
2776                 *menu_mode = MENU_DISABLED;
2777                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2778                         user->adminflags |= ADMINFLAG_T_REQUEST;
2779                 }
2780
2781                 if (user->adminflags & ADMINFLAG_T_REQUEST) {
2782                         if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
2783                                 ast_waitstream(chan, "");
2784                         }
2785                 }
2786                 break;
2787
2788         case '4':
2789                 tweak_listen_volume(user, VOL_DOWN);
2790                 break;
2791         case '5':
2792                 /* Extend RT conference */
2793                 if (rt_schedule) {
2794                         rt_extend_conf(conf->confno);
2795                 }
2796                 *menu_mode = MENU_DISABLED;
2797                 break;
2798
2799         case '6':
2800                 tweak_listen_volume(user, VOL_UP);
2801                 break;
2802
2803         case '7':
2804                 tweak_talk_volume(user, VOL_DOWN);
2805                 break;
2806
2807         case '8':
2808                 *menu_mode = MENU_DISABLED;
2809                 break;
2810
2811         case '9':
2812                 tweak_talk_volume(user, VOL_UP);
2813                 break;
2814
2815         default:
2816                 *menu_mode = MENU_DISABLED;
2817                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2818                         ast_waitstream(chan, "");
2819                 }
2820                 break;
2821         }
2822 }
2823
2824 /*! \internal
2825  * \brief Processes menu options for the adminstrator menu (accessible through the 's' option for app_meetme)
2826  *
2827  * \param menu_mode a pointer to the currently active menu_mode.
2828  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2829  * \param conf the active conference for which the user has called the menu from.
2830  * \param confflags flags used by conf for various options
2831  * \param chan ast_channel belonging to the user who called the menu
2832  * \param user which meetme conference user invoked the menu
2833  */
2834 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)
2835 {
2836         switch(*dtmf) {
2837         case '1': /* Un/Mute */
2838                 *menu_mode = MENU_DISABLED;
2839                 /* for admin, change both admin and use flags */
2840                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
2841                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2842                 } else {
2843                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2844                 }
2845
2846                 if (ast_test_flag64(confflags, CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2847                         if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2848                                 ast_waitstream(chan, "");
2849                         }
2850                 } else {
2851                         if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2852                                 ast_waitstream(chan, "");
2853                         }
2854                 }
2855                 break;
2856
2857         case '2': /* Un/Lock the Conference */
2858                 *menu_mode = MENU_DISABLED;
2859                 if (conf->locked) {
2860                         conf->locked = 0;
2861                         if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
2862                                 ast_waitstream(chan, "");
2863                         }
2864                 } else {
2865                         conf->locked = 1;
2866                         if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
2867                                 ast_waitstream(chan, "");
2868                         }
2869                 }
2870                 break;
2871
2872         case '3': /* Eject last user */
2873         {
2874                 struct ast_conf_user *usr = NULL;
2875                 int max_no = 0;
2876                 ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &max_no);
2877                 *menu_mode = MENU_DISABLED;
2878                 usr = ao2_find(conf->usercontainer, &max_no, 0);
2879                 if ((ast_channel_name(usr->chan) == ast_channel_name(chan)) || ast_test_flag64(&usr->userflags, CONFFLAG_ADMIN)) {
2880                         if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2881                                 ast_waitstream(chan, "");
2882                         }
2883                 } else {
2884                         usr->adminflags |= ADMINFLAG_KICKME;
2885                 }
2886                 ao2_ref(usr, -1);
2887                 ast_stopstream(chan);
2888                 break;
2889         }
2890
2891         case '4':
2892                 tweak_listen_volume(user, VOL_DOWN);
2893                 break;
2894
2895         case '5':
2896                 /* Extend RT conference */
2897                 if (rt_schedule) {
2898                         if (!rt_extend_conf(conf->confno)) {
2899                                 if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
2900                                         ast_waitstream(chan, "");
2901                                 }
2902                         } else {
2903                                 if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
2904                                         ast_waitstream(chan, "");
2905                                 }
2906                         }
2907                         ast_stopstream(chan);
2908                 }
2909                 *menu_mode = MENU_DISABLED;
2910                 break;
2911
2912         case '6':
2913                 tweak_listen_volume(user, VOL_UP);
2914                 break;
2915
2916         case '7':
2917                 tweak_talk_volume(user, VOL_DOWN);
2918                 break;
2919
2920         case '8':
2921                 if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
2922                         /* 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. */
2923                         *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2924                         ast_stopstream(chan);
2925                 }
2926                 *menu_mode = MENU_ADMIN_EXTENDED;
2927                 break;
2928
2929         case '9':
2930                 tweak_talk_volume(user, VOL_UP);
2931                 break;
2932         default:
2933                 menu_mode = MENU_DISABLED;
2934                 /* Play an error message! */
2935                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2936                         ast_waitstream(chan, "");
2937                 }
2938                 break;
2939         }
2940
2941 }
2942
2943 /*! \internal
2944  * \brief Processes menu options for the extended administrator menu (accessible through option 8 on the administrator menu)
2945  *
2946  * \param menu_mode a pointer to the currently active menu_mode.
2947  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2948  * \param conf the active conference for which the user has called the menu from.
2949  * \param confflags flags used by conf for various options
2950  * \param chan ast_channel belonging to the user who called the menu
2951  * \param user which meetme conference user invoked the menu
2952  * \param recordingtmp character buffer which may hold the name of the conference recording file
2953  */
2954 static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf,
2955         struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
2956         struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
2957         struct ast_format_cap *cap_slin)
2958 {
2959         int keepplaying;
2960         int playednamerec;
2961         int res;
2962         struct ao2_iterator user_iter;
2963         struct ast_conf_user *usr = NULL;
2964
2965         switch(*dtmf) {
2966         case '1': /* *81 Roll call */
2967                 keepplaying = 1;
2968                 playednamerec = 0;
2969                 if (conf->users == 1) {
2970                         if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
2971                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2972                                 ast_stopstream(chan);
2973                                 if (res > 0) {
2974                                         keepplaying = 0;
2975                                 }
2976                         }
2977                 } else if (conf->users == 2) {
2978                         if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
2979                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2980                                 ast_stopstream(chan);
2981                                 if (res > 0) {
2982                                         keepplaying = 0;
2983                                 }
2984                         }
2985                 } else {
2986                         if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
2987                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2988                                 ast_stopstream(chan);
2989                                 if (res > 0) {
2990                                         keepplaying = 0;
2991                                 }
2992                         }
2993                         if (keepplaying) {
2994                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
2995                                 ast_stopstream(chan);
2996                                 if (res > 0) {
2997                                         keepplaying = 0;
2998                                 }
2999                         }
3000                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3001                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
3002                                 ast_stopstream(chan);
3003                                 if (res > 0) {
3004                                         keepplaying = 0;
3005                                 }
3006                         }
3007                 }
3008                 user_iter = ao2_iterator_init(conf->usercontainer, 0);
3009                 while((usr = ao2_iterator_next(&user_iter))) {
3010                         if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
3011                                 if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
3012                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
3013                                         ast_stopstream(chan);
3014                                         if (res > 0) {
3015                                                 keepplaying = 0;
3016                                         }
3017                                 }
3018                                 playednamerec = 1;
3019                         }
3020                         ao2_ref(usr, -1);
3021                 }
3022                 ao2_iterator_destroy(&user_iter);
3023                 if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
3024                         res = ast_waitstream(chan, AST_DIGIT_ANY);
3025                         ast_stopstream(chan);
3026                         if (res > 0) {
3027                                 keepplaying = 0;
3028                         }
3029                 }
3030
3031                 *menu_mode = MENU_DISABLED;
3032                 break;
3033
3034         case '2': /* *82 Eject all non-admins */
3035                 if (conf->users == 1) {
3036                         if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3037                                 ast_waitstream(chan, "");
3038                         }
3039                 } else {
3040                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_kickme_cb, &conf);
3041                 }
3042                 ast_stopstream(chan);
3043                 *menu_mode = MENU_DISABLED;
3044                 break;
3045
3046         case '3': /* *83 (Admin) mute/unmute all non-admins */
3047                 if(conf->gmuted) {
3048                         conf->gmuted = 0;
3049                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_unmuted_cb, &conf);
3050                         if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
3051                                 ast_waitstream(chan, "");
3052                         }
3053                 } else {
3054                         conf->gmuted = 1;
3055                         ao2_callback(conf->usercontainer, OBJ_NODATA, user_set_muted_cb, &conf);
3056                         if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
3057                                 ast_waitstream(chan, "");
3058                         }
3059                 }
3060                 ast_stopstream(chan);
3061                 *menu_mode = MENU_DISABLED;
3062                 break;
3063
3064         case '4': /* *84 Record conference */
3065                 if (conf->recording != MEETME_RECORD_ACTIVE) {
3066                         ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
3067                         if (!conf->recordingfilename) {
3068                                 const char *var;
3069                                 ast_channel_lock(chan);
3070                                 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3071                                         conf->recordingfilename = ast_strdup(var);
3072                                 }
3073                                 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3074                                         conf->recordingformat = ast_strdup(var);
3075                                 }
3076                                 ast_channel_unlock(chan);
3077                                 if (!conf->recordingfilename) {
3078                                         snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3079                                         conf->recordingfilename = ast_strdup(recordingtmp);
3080                                 }
3081                                 if (!conf->recordingformat) {
3082                                         conf->recordingformat = ast_strdup("wav");
3083                                 }
3084                                 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3085                                 conf->confno, conf->recordingfilename, conf->recordingformat);
3086                         }
3087
3088                         ast_mutex_lock(&conf->recordthreadlock);
3089                         if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3090                                 struct dahdi_confinfo dahdic;
3091
3092                                 ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
3093                                 ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
3094                                 dahdic.chan = 0;
3095                                 dahdic.confno = conf->dahdiconf;
3096                                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3097                                 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3098                                         ast_log(LOG_WARNING, "Error starting listen channel\n");
3099                                         ast_hangup(conf->lchan);
3100                                         conf->lchan = NULL;
3101                                 } else {
3102                                         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
3103                                 }
3104                         }
3105                         ast_mutex_unlock(&conf->recordthreadlock);
3106                         if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
3107                                 ast_waitstream(chan, "");
3108                         }
3109                 }
3110
3111                 ast_stopstream(chan);
3112                 *menu_mode = MENU_DISABLED;
3113                 break;
3114
3115         case '8': /* *88 Exit the menu and return to the conference... without an error message */
3116                 ast_stopstream(chan);
3117                 *menu_mode = MENU_DISABLED;
3118                 break;
3119
3120         default:
3121                 if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3122                         ast_waitstream(chan, "");
3123                 }
3124                 ast_stopstream(chan);
3125                 *menu_mode = MENU_DISABLED;
3126                 break;
3127         }
3128 }
3129
3130 /*! \internal
3131  * \brief Processes menu options for the various menu types (accessible through the 's' option for app_meetme)
3132  *
3133  * \param menu_mode a pointer to the currently active menu_mode.
3134  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
3135  * \param conf the active conference for which the user has called the menu from.
3136  * \param confflags flags used by conf for various options
3137  * \param chan ast_channel belonging to the user who called the menu
3138  * \param user which meetme conference user invoked the menu
3139  * \param recordingtmp character buffer which may hold the name of the conference recording file
3140  */
3141 static void meetme_menu(enum menu_modes *menu_mode, int *dtmf,
3142         struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
3143         struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
3144         struct ast_format_cap *cap_slin)
3145 {
3146         switch (*menu_mode) {
3147         case MENU_DISABLED:
3148                 break;
3149         case MENU_NORMAL:
3150                 meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
3151                 break;
3152         case MENU_ADMIN:
3153                 meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
3154                 /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
3155                 if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
3156                         break;
3157                 }
3158         case MENU_ADMIN_EXTENDED:
3159                 meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user,
3160                         recordingtmp, recordingtmp_size, cap_slin);
3161                 break;
3162         }
3163 }
3164
3165 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
3166 {
3167         struct ast_conf_user *user = NULL;
3168         int fd;
3169         struct dahdi_confinfo dahdic, dahdic_empty;
3170         struct ast_frame *f;
3171         struct ast_channel *c;
3172         struct ast_frame fr;
3173         int outfd;
3174         int ms;
3175         int nfds;
3176         int res;
3177         int retrydahdi;
3178         int origfd;
3179         int musiconhold = 0, mohtempstopped = 0;
3180         int firstpass = 0;
3181         int lastmarked = 0;
3182         int currentmarked = 0;
3183         int ret = -1;
3184         int x;
3185         enum menu_modes menu_mode = MENU_DISABLED;
3186         int talkreq_manager = 0;
3187         int using_pseudo = 0;
3188         int duration = 20;
3189         int sent_event = 0;
3190         int checked = 0;
3191         int announcement_played = 0;
3192         struct timeval now;
3193         struct ast_dsp *dsp = NULL;
3194         struct ast_app *agi_app;
3195         char *agifile, *mod_speex;
3196         const char *agifiledefault = "conf-background.agi", *tmpvar;
3197         char meetmesecs[30] = "";
3198         char exitcontext[AST_MAX_CONTEXT] = "";
3199         char recordingtmp[AST_MAX_EXTENSION] = "";
3200         char members[10] = "";
3201         int dtmf = 0, opt_waitmarked_timeout = 0;
3202         time_t timeout = 0;
3203         struct dahdi_bufferinfo bi;
3204         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
3205         char *buf = __buf + AST_FRIENDLY_OFFSET;
3206         char *exitkeys = NULL;
3207         unsigned int calldurationlimit = 0;
3208         long timelimit = 0;
3209         long play_warning = 0;
3210         long warning_freq = 0;
3211         const char *warning_sound = NULL;
3212         const char *end_sound = NULL;
3213         char *parse;
3214         long time_left_ms = 0;
3215         struct timeval nexteventts = { 0, };
3216         int to;
3217         int setusercount = 0;
3218         int confsilence = 0, totalsilence = 0;
3219         char *mailbox, *context;
3220         struct ast_format_cap *cap_slin = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
3221         struct ast_format tmpfmt;
3222
3223         if (!cap_slin) {
3224                 goto conf_run_cleanup;
3225         }
3226         ast_format_cap_add(cap_slin, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
3227
3228         if (!(user = ao2_alloc(sizeof(*user), NULL))) {
3229                 goto conf_run_cleanup;
3230         }
3231
3232         /* Possible timeout waiting for marked user */
3233         if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3234                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
3235                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
3236                 (opt_waitmarked_timeout > 0)) {
3237                 timeout = time(NULL) + opt_waitmarked_timeout;
3238         }
3239
3240         if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
3241                 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
3242                 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
3243         }
3244
3245         if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
3246                 char *limit_str, *warning_str, *warnfreq_str;
3247                 const char *var;
3248
3249                 parse = optargs[OPT_ARG_DURATION_LIMIT];
3250                 limit_str = strsep(&parse, ":");
3251                 warning_str = strsep(&parse, ":");
3252                 warnfreq_str = parse;
3253
3254                 timelimit = atol(limit_str);
3255                 if (warning_str)
3256                         play_warning = atol(warning_str);
3257                 if (warnfreq_str)
3258                         warning_freq = atol(warnfreq_str);
3259
3260                 if (!timelimit) {
3261                         timelimit = play_warning = warning_freq = 0;
3262                         warning_sound = NULL;
3263                 } else if (play_warning > timelimit) {
3264                         if (!warning_freq) {
3265                                 play_warning = 0;
3266                         } else {
3267                                 while (play_warning > timelimit)
3268                                         play_warning -= warning_freq;
3269                                 if (play_warning < 1)
3270                                         play_warning = warning_freq = 0;
3271                         }
3272                 }
3273
3274                 ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
3275                 if (play_warning) {
3276                         ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
3277                 }
3278                 if (warning_freq) {
3279                         ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
3280                 }
3281
3282                 ast_channel_lock(chan);
3283                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
3284                         var = ast_strdupa(var);
3285                 }
3286                 ast_channel_unlock(chan);
3287
3288                 warning_sound = var ? var : "timeleft";
3289
3290                 ast_channel_lock(chan);
3291                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
3292                         var = ast_strdupa(var);
3293                 }
3294                 ast_channel_unlock(chan);
3295
3296                 end_sound = var ? var : NULL;
3297
3298                 /* undo effect of S(x) in case they are both used */
3299                 calldurationlimit = 0;
3300                 /* more efficient do it like S(x) does since no advanced opts */
3301                 if (!play_warning && !end_sound && timelimit) {
3302                         calldurationlimit = timelimit / 1000;
3303                         timelimit = play_warning = warning_freq = 0;
3304                 } else {
3305                         ast_debug(2, "Limit Data for this call:\n");
3306                         ast_debug(2, "- timelimit     = %ld\n", timelimit);
3307                         ast_debug(2, "- play_warning  = %ld\n", play_warning);
3308                         ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
3309                         ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
3310                         ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
3311                 }
3312         }
3313
3314         /* Get exit keys */
3315         if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
3316                 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
3317                         exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
3318                 else
3319                         exitkeys = ast_strdupa("#"); /* Default */
3320         }
3321         
3322         if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
3323                 if (!conf->recordingfilename) {
3324                         const char *var;
3325                         ast_channel_lock(chan);
3326                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3327                                 conf->recordingfilename = ast_strdup(var);
3328                         }
3329                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3330                                 conf->recordingformat = ast_strdup(var);
3331                         }
3332                         ast_channel_unlock(chan);
3333                         if (!conf->recordingfilename) {
3334                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3335                                 conf->recordingfilename = ast_strdup(recordingtmp);
3336                         }
3337                         if (!conf->recordingformat) {
3338                                 conf->recordingformat = ast_strdup("wav");
3339                         }
3340                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3341                                     conf->confno, conf->recordingfilename, conf->recordingformat);
3342                 }
3343         }
3344
3345         ast_mutex_lock(&conf->recordthreadlock);
3346         if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
3347                 ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3348                 ast_set_read_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
3349                 ast_set_write_format_by_id(conf->lchan, AST_FORMAT_SLINEAR);
3350                 dahdic.chan = 0;
3351                 dahdic.confno = conf->dahdiconf;
3352                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3353                 if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3354                         ast_log(LOG_WARNING, "Error starting listen channel\n");
3355                         ast_hangup(conf->lchan);
3356                         conf->lchan = NULL;
3357                 } else {
3358                         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
3359                 }
3360         }
3361         ast_mutex_unlock(&conf->recordthreadlock);
3362
3363         ast_mutex_lock(&conf->announcethreadlock);
3364         if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3365                 ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
3366                 ast_mutex_init(&conf->announcelistlock);
3367                 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);