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