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