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