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