Merged revisions 304774 via svnmerge from
[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
1193         AST_LIST_LOCK(&confs);
1194
1195         AST_LIST_TRAVERSE(&confs, cnf, list) {
1196                 if (!strcmp(confno, cnf->confno)) 
1197                         break;
1198         }
1199
1200         if (cnf || (!make && !dynamic))
1201                 goto cnfout;
1202
1203         /* Make a new one */
1204         if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
1205                 !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
1206                 goto cnfout;
1207         }
1208
1209         ast_mutex_init(&cnf->playlock);
1210         ast_mutex_init(&cnf->listenlock);
1211         cnf->recordthread = AST_PTHREADT_NULL;
1212         ast_mutex_init(&cnf->recordthreadlock);
1213         cnf->announcethread = AST_PTHREADT_NULL;
1214         ast_mutex_init(&cnf->announcethreadlock);
1215         ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1216         ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1217         ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1218         ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
1219
1220         /* Setup a new dahdi conference */
1221         dahdic.confno = -1;
1222         dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1223         cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1224         if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1225                 if (test) {
1226                         /* if we are creating a conference for a unit test, it is not neccesary
1227                          * to open a pseudo channel, so, if we fail continue creating
1228                          * the conference. */
1229                         ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1230                 } else {
1231                         ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1232                         if (cnf->fd >= 0)
1233                                 close(cnf->fd);
1234                         ao2_ref(cnf->usercontainer, -1);
1235                         ast_mutex_destroy(&cnf->playlock);
1236                         ast_mutex_destroy(&cnf->listenlock);
1237                         ast_mutex_destroy(&cnf->recordthreadlock);
1238                         ast_mutex_destroy(&cnf->announcethreadlock);
1239                         ast_free(cnf);
1240                         cnf = NULL;
1241                         goto cnfout;
1242                 }
1243         }
1244
1245         cnf->dahdiconf = dahdic.confno;
1246
1247         /* Setup a new channel for playback of audio files */
1248         cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL);
1249         if (cnf->chan) {
1250                 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
1251                 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
1252                 dahdic.chan = 0;
1253                 dahdic.confno = cnf->dahdiconf;
1254                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1255                 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
1256                         if (test) {
1257                                 ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1258                         }
1259                         ast_log(LOG_WARNING, "Error setting conference\n");
1260                         if (cnf->chan)
1261                                 ast_hangup(cnf->chan);
1262                         else
1263                                 close(cnf->fd);
1264                         ao2_ref(cnf->usercontainer, -1);
1265                         ast_mutex_destroy(&cnf->playlock);
1266                         ast_mutex_destroy(&cnf->listenlock);
1267                         ast_mutex_destroy(&cnf->recordthreadlock);
1268                         ast_mutex_destroy(&cnf->announcethreadlock);
1269                         ast_free(cnf);
1270                         cnf = NULL;
1271                         goto cnfout;
1272                 }
1273         }
1274
1275         /* Fill the conference struct */
1276         cnf->start = time(NULL);
1277         cnf->maxusers = 0x7fffffff;
1278         cnf->isdynamic = dynamic ? 1 : 0;
1279         ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1280         AST_LIST_INSERT_HEAD(&confs, cnf, list);
1281
1282         /* Reserve conference number in map */
1283         if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1284                 conf_map[confno_int] = 1;
1285         
1286 cnfout:
1287         if (cnf)
1288                 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1289
1290         AST_LIST_UNLOCK(&confs);
1291
1292         return cnf;
1293 }
1294
1295 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
1296 {
1297         static const char * const cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
1298
1299         int len = strlen(word);
1300         int which = 0;
1301         struct ast_conference *cnf = NULL;
1302         struct ast_conf_user *usr = NULL;
1303         char *confno = NULL;
1304         char usrno[50] = "";
1305         char *myline, *ret = NULL;
1306         
1307         if (pos == 1) {         /* Command */
1308                 return ast_cli_complete(word, cmds, state);
1309         } else if (pos == 2) {  /* Conference Number */
1310                 AST_LIST_LOCK(&confs);
1311                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1312                         if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
1313                                 ret = cnf->confno;
1314                                 break;
1315                         }
1316                 }
1317                 ret = ast_strdup(ret); /* dup before releasing the lock */
1318                 AST_LIST_UNLOCK(&confs);
1319                 return ret;
1320         } else if (pos == 3) {
1321                 /* User Number || Conf Command option*/
1322                 if (strstr(line, "mute") || strstr(line, "kick")) {
1323                         if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
1324                                 return ast_strdup("all");
1325                         which++;
1326                         AST_LIST_LOCK(&confs);
1327
1328                         /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
1329                         myline = ast_strdupa(line);
1330                         if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
1331                                 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
1332                                         ;
1333                         }
1334                         
1335                         AST_LIST_TRAVERSE(&confs, cnf, list) {
1336                                 if (!strcmp(confno, cnf->confno))
1337                                     break;
1338                         }
1339
1340                         if (cnf) {
1341                                 struct ao2_iterator user_iter;
1342                                 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1343
1344                                 while((usr = ao2_iterator_next(&user_iter))) {
1345                                         snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1346                                         if (!strncasecmp(word, usrno, len) && ++which > state) {
1347                                                 ao2_ref(usr, -1);
1348                                                 break;
1349                                         }
1350                                         ao2_ref(usr, -1);
1351                                 }
1352                                 ao2_iterator_destroy(&user_iter);
1353                                 AST_LIST_UNLOCK(&confs);
1354                                 return usr ? ast_strdup(usrno) : NULL;
1355                         }
1356                 }
1357         }
1358
1359         return NULL;
1360 }
1361
1362 static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1363 {
1364         /* Process the command */
1365         struct ast_conf_user *user;
1366         struct ast_conference *cnf;
1367         int hr, min, sec;
1368         int i = 0, total = 0;
1369         time_t now;
1370         struct ast_str *cmdline = NULL;
1371 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s  %-8s  %-6s\n"
1372 #define MC_DATA_FORMAT "%-12.12s   %4.4d              %4.4s       %02d:%02d:%02d  %-8s  %-6s\n"
1373
1374         switch (cmd) {
1375         case CLI_INIT:
1376                 e->command = "meetme list [concise]";
1377                 e->usage =
1378                         "Usage: meetme list [concise] <confno> \n"
1379                         "       List all or a specific conference.\n";
1380                 return NULL;
1381         case CLI_GENERATE:
1382                 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
1383         }
1384
1385         /* Check for length so no buffer will overflow... */
1386         for (i = 0; i < a->argc; i++) {
1387                 if (strlen(a->argv[i]) > 100)
1388                         ast_cli(a->fd, "Invalid Arguments.\n");
1389         }
1390
1391         /* Max confno length */
1392         if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
1393                 return CLI_FAILURE;
1394         }
1395
1396         if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
1397                 /* List all the conferences */  
1398                 int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
1399                 now = time(NULL);
1400                 AST_LIST_LOCK(&confs);
1401                 if (AST_LIST_EMPTY(&confs)) {
1402                         if (!concise) {
1403                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1404                         }
1405                         AST_LIST_UNLOCK(&confs);
1406                         ast_free(cmdline);
1407                         return CLI_SUCCESS;
1408                 }
1409                 if (!concise) {
1410                         ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1411                 }
1412                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1413                         if (cnf->markedusers == 0) {
1414                                 ast_str_set(&cmdline, 0, "N/A ");
1415                         } else {
1416                                 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
1417                         }
1418                         hr = (now - cnf->start) / 3600;
1419                         min = ((now - cnf->start) % 3600) / 60;
1420                         sec = (now - cnf->start) % 60;
1421                         if (!concise) {
1422                                 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");
1423                         } else {
1424                                 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1425                                         cnf->confno,
1426                                         cnf->users,
1427                                         cnf->markedusers,
1428                                         hr, min, sec,
1429                                         cnf->isdynamic,
1430                                         cnf->locked);
1431                         }
1432
1433                         total += cnf->users;
1434                 }
1435                 AST_LIST_UNLOCK(&confs);
1436                 if (!concise) {
1437                         ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1438                 }
1439                 ast_free(cmdline);
1440                 return CLI_SUCCESS;
1441         } else if (strcmp(a->argv[1], "list") == 0) {
1442                 struct ao2_iterator user_iter;
1443                 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
1444                 /* List all the users in a conference */
1445                 if (AST_LIST_EMPTY(&confs)) {
1446                         if (!concise) {
1447                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
1448                         }
1449                         ast_free(cmdline);
1450                         return CLI_SUCCESS;     
1451                 }
1452                 /* Find the right conference */
1453                 AST_LIST_LOCK(&confs);
1454                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1455                         if (strcmp(cnf->confno, a->argv[2]) == 0) {
1456                                 break;
1457                         }
1458                 }
1459                 if (!cnf) {
1460                         if (!concise)
1461                                 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1462                         AST_LIST_UNLOCK(&confs);
1463                         ast_free(cmdline);
1464                         return CLI_SUCCESS;
1465                 }
1466                 /* Show all the users */
1467                 time(&now);
1468                 user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1469                 while((user = ao2_iterator_next(&user_iter))) {
1470                         hr = (now - user->jointime) / 3600;
1471                         min = ((now - user->jointime) % 3600) / 60;
1472                         sec = (now - user->jointime) % 60;
1473                         if (!concise) {
1474                                 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1475                                         user->user_no,
1476                                         S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
1477                                         S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
1478                                         user->chan->name,
1479                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
1480                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
1481                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1482                                         user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1483                                         istalking(user->talking), hr, min, sec); 
1484                         } else {
1485                                 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1486                                         user->user_no,
1487                                         S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, ""),
1488                                         S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, ""),
1489                                         user->chan->name,
1490                                         ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
1491                                         ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
1492                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1493                                         user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1494                                         user->talking, hr, min, sec);
1495                         }
1496                         ao2_ref(user, -1);
1497                 }
1498                 ao2_iterator_destroy(&user_iter);
1499                 if (!concise) {
1500                         ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1501                 }
1502                 AST_LIST_UNLOCK(&confs);
1503                 ast_free(cmdline);
1504                 return CLI_SUCCESS;
1505         }
1506         if (a->argc < 2) {
1507                 ast_free(cmdline);
1508                 return CLI_SHOWUSAGE;
1509         }
1510
1511         ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
1512
1513         admin_exec(NULL, ast_str_buffer(cmdline));
1514         ast_free(cmdline);
1515
1516         return CLI_SUCCESS;
1517 }
1518
1519
1520 static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1521 {
1522         /* Process the command */
1523         struct ast_str *cmdline = NULL;
1524         int i = 0;
1525
1526         switch (cmd) {
1527         case CLI_INIT:
1528                 e->command = "meetme {lock|unlock|mute|unmute|kick}";
1529                 e->usage =
1530                         "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
1531                         "       Executes a command for the conference or on a conferee\n";
1532                 return NULL;
1533         case CLI_GENERATE:
1534                 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
1535         }
1536
1537         if (a->argc > 8)
1538                 ast_cli(a->fd, "Invalid Arguments.\n");
1539         /* Check for length so no buffer will overflow... */
1540         for (i = 0; i < a->argc; i++) {
1541                 if (strlen(a->argv[i]) > 100)
1542                         ast_cli(a->fd, "Invalid Arguments.\n");
1543         }
1544
1545         /* Max confno length */
1546         if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
1547                 return CLI_FAILURE;
1548         }
1549
1550         if (a->argc < 1) {
1551                 ast_free(cmdline);
1552                 return CLI_SHOWUSAGE;
1553         }
1554
1555         ast_str_set(&cmdline, 0, "%s", a->argv[2]);     /* Argv 2: conference number */
1556         if (strstr(a->argv[1], "lock")) {
1557                 if (strcmp(a->argv[1], "lock") == 0) {
1558                         /* Lock */
1559                         ast_str_append(&cmdline, 0, ",L");
1560                 } else {
1561                         /* Unlock */
1562                         ast_str_append(&cmdline, 0, ",l");
1563                 }
1564         } else if (strstr(a->argv[1], "mute")) { 
1565                 if (a->argc < 4) {
1566                         ast_free(cmdline);
1567                         return CLI_SHOWUSAGE;
1568                 }
1569                 if (strcmp(a->argv[1], "mute") == 0) {
1570                         /* Mute */
1571                         if (strcmp(a->argv[3], "all") == 0) {
1572                                 ast_str_append(&cmdline, 0, ",N");
1573                         } else {
1574                                 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);       
1575                         }
1576                 } else {
1577                         /* Unmute */
1578                         if (strcmp(a->argv[3], "all") == 0) {
1579                                 ast_str_append(&cmdline, 0, ",n");
1580                         } else {
1581                                 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
1582                         }
1583                 }
1584         } else if (strcmp(a->argv[1], "kick") == 0) {
1585                 if (a->argc < 4) {
1586                         ast_free(cmdline);
1587                         return CLI_SHOWUSAGE;
1588                 }
1589                 if (strcmp(a->argv[3], "all") == 0) {
1590                         /* Kick all */
1591                         ast_str_append(&cmdline, 0, ",K");
1592                 } else {
1593                         /* Kick a single user */
1594                         ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
1595                 }
1596         } else {
1597                 ast_free(cmdline);
1598                 return CLI_SHOWUSAGE;
1599         }
1600
1601         ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
1602
1603         admin_exec(NULL, ast_str_buffer(cmdline));
1604         ast_free(cmdline);
1605
1606         return CLI_SUCCESS;
1607 }
1608
1609 static const char *sla_hold_str(unsigned int hold_access)
1610 {
1611         const char *hold = "Unknown";
1612
1613         switch (hold_access) {
1614         case SLA_HOLD_OPEN:
1615                 hold = "Open";
1616                 break;
1617         case SLA_HOLD_PRIVATE:
1618                 hold = "Private";
1619         default:
1620                 break;
1621         }
1622
1623         return hold;
1624 }
1625
1626 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1627 {
1628         const struct sla_trunk *trunk;
1629
1630         switch (cmd) {
1631         case CLI_INIT:
1632                 e->command = "sla show trunks";
1633                 e->usage =
1634                         "Usage: sla show trunks\n"
1635                         "       This will list all trunks defined in sla.conf\n";
1636                 return NULL;
1637         case CLI_GENERATE:
1638                 return NULL;
1639         }
1640
1641         ast_cli(a->fd, "\n"
1642                     "=============================================================\n"
1643                     "=== Configured SLA Trunks ===================================\n"
1644                     "=============================================================\n"
1645                     "===\n");
1646         AST_RWLIST_RDLOCK(&sla_trunks);
1647         AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
1648                 struct sla_station_ref *station_ref;
1649                 char ring_timeout[16] = "(none)";
1650                 if (trunk->ring_timeout)
1651                         snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
1652                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1653                             "=== Trunk Name:       %s\n"
1654                             "=== ==> Device:       %s\n"
1655                             "=== ==> AutoContext:  %s\n"
1656                             "=== ==> RingTimeout:  %s\n"
1657                             "=== ==> BargeAllowed: %s\n"
1658                             "=== ==> HoldAccess:   %s\n"
1659                             "=== ==> Stations ...\n",
1660                             trunk->name, trunk->device, 
1661                             S_OR(trunk->autocontext, "(none)"), 
1662                             ring_timeout,
1663                             trunk->barge_disabled ? "No" : "Yes",
1664                             sla_hold_str(trunk->hold_access));
1665                 AST_RWLIST_RDLOCK(&sla_stations);
1666                 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
1667                         ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
1668                 AST_RWLIST_UNLOCK(&sla_stations);
1669                 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
1670         }
1671         AST_RWLIST_UNLOCK(&sla_trunks);
1672         ast_cli(a->fd, "=============================================================\n\n");
1673
1674         return CLI_SUCCESS;
1675 }
1676
1677 static const char *trunkstate2str(enum sla_trunk_state state)
1678 {
1679 #define S(e) case e: return # e;
1680         switch (state) {
1681         S(SLA_TRUNK_STATE_IDLE)
1682         S(SLA_TRUNK_STATE_RINGING)
1683         S(SLA_TRUNK_STATE_UP)
1684         S(SLA_TRUNK_STATE_ONHOLD)
1685         S(SLA_TRUNK_STATE_ONHOLD_BYME)
1686         }
1687         return "Uknown State";
1688 #undef S
1689 }
1690
1691 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1692 {
1693         const struct sla_station *station;
1694
1695         switch (cmd) {
1696         case CLI_INIT:
1697                 e->command = "sla show stations";
1698                 e->usage =
1699                         "Usage: sla show stations\n"
1700                         "       This will list all stations defined in sla.conf\n";
1701                 return NULL;
1702         case CLI_GENERATE:
1703                 return NULL;
1704         }
1705
1706         ast_cli(a->fd, "\n" 
1707                     "=============================================================\n"
1708                     "=== Configured SLA Stations =================================\n"
1709                     "=============================================================\n"
1710                     "===\n");
1711         AST_RWLIST_RDLOCK(&sla_stations);
1712         AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1713                 struct sla_trunk_ref *trunk_ref;
1714                 char ring_timeout[16] = "(none)";
1715                 char ring_delay[16] = "(none)";
1716                 if (station->ring_timeout) {
1717                         snprintf(ring_timeout, sizeof(ring_timeout), 
1718                                 "%u", station->ring_timeout);
1719                 }
1720                 if (station->ring_delay) {
1721                         snprintf(ring_delay, sizeof(ring_delay), 
1722                                 "%u", station->ring_delay);
1723                 }
1724                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1725                             "=== Station Name:    %s\n"
1726                             "=== ==> Device:      %s\n"
1727                             "=== ==> AutoContext: %s\n"
1728                             "=== ==> RingTimeout: %s\n"
1729                             "=== ==> RingDelay:   %s\n"
1730                             "=== ==> HoldAccess:  %s\n"
1731                             "=== ==> Trunks ...\n",
1732                             station->name, station->device,
1733                             S_OR(station->autocontext, "(none)"), 
1734                             ring_timeout, ring_delay,
1735                             sla_hold_str(station->hold_access));
1736                 AST_RWLIST_RDLOCK(&sla_trunks);
1737                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1738                         if (trunk_ref->ring_timeout) {
1739                                 snprintf(ring_timeout, sizeof(ring_timeout),
1740                                         "%u", trunk_ref->ring_timeout);
1741                         } else
1742                                 strcpy(ring_timeout, "(none)");
1743                         if (trunk_ref->ring_delay) {
1744                                 snprintf(ring_delay, sizeof(ring_delay),
1745                                         "%u", trunk_ref->ring_delay);
1746                         } else
1747                                 strcpy(ring_delay, "(none)");
1748                                 ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
1749                                     "===       ==> State:       %s\n"
1750                                     "===       ==> RingTimeout: %s\n"
1751                                     "===       ==> RingDelay:   %s\n",
1752                                     trunk_ref->trunk->name,
1753                                     trunkstate2str(trunk_ref->state),
1754                                     ring_timeout, ring_delay);
1755                 }
1756                 AST_RWLIST_UNLOCK(&sla_trunks);
1757                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1758                             "===\n");
1759         }
1760         AST_RWLIST_UNLOCK(&sla_stations);
1761         ast_cli(a->fd, "============================================================\n"
1762                     "\n");
1763
1764         return CLI_SUCCESS;
1765 }
1766
1767 static struct ast_cli_entry cli_meetme[] = {
1768         AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
1769         AST_CLI_DEFINE(meetme_show_cmd, "List all or one conference"),
1770         AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
1771         AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
1772 };
1773
1774 static void conf_flush(int fd, struct ast_channel *chan)
1775 {
1776         int x;
1777
1778         /* read any frames that may be waiting on the channel
1779            and throw them away
1780         */
1781         if (chan) {
1782                 struct ast_frame *f;
1783
1784                 /* when no frames are available, this will wait
1785                    for 1 millisecond maximum
1786                 */
1787                 while (ast_waitfor(chan, 1)) {
1788                         f = ast_read(chan);
1789                         if (f)
1790                                 ast_frfree(f);
1791                         else /* channel was hung up or something else happened */
1792                                 break;
1793                 }
1794         }
1795
1796         /* flush any data sitting in the pseudo channel */
1797         x = DAHDI_FLUSH_ALL;
1798         if (ioctl(fd, DAHDI_FLUSH, &x))
1799                 ast_log(LOG_WARNING, "Error flushing channel\n");
1800
1801 }
1802
1803 /*! \brief Remove the conference from the list and free it.
1804
1805    We assume that this was called while holding conflock. */
1806 static int conf_free(struct ast_conference *conf)
1807 {
1808         int x;
1809         struct announce_listitem *item;
1810         
1811         AST_LIST_REMOVE(&confs, conf, list);
1812         manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
1813
1814         if (conf->recording == MEETME_RECORD_ACTIVE) {
1815                 conf->recording = MEETME_RECORD_TERMINATE;
1816                 AST_LIST_UNLOCK(&confs);
1817                 while (1) {
1818                         usleep(1);
1819                         AST_LIST_LOCK(&confs);
1820                         if (conf->recording == MEETME_RECORD_OFF)
1821                                 break;
1822                         AST_LIST_UNLOCK(&confs);
1823                 }
1824         }
1825
1826         for (x = 0; x < AST_FRAME_BITS; x++) {
1827                 if (conf->transframe[x])
1828                         ast_frfree(conf->transframe[x]);
1829                 if (conf->transpath[x])
1830                         ast_translator_free_path(conf->transpath[x]);
1831         }
1832         if (conf->announcethread != AST_PTHREADT_NULL) {
1833                 ast_mutex_lock(&conf->announcelistlock);
1834                 conf->announcethread_stop = 1;
1835                 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
1836                 ast_cond_signal(&conf->announcelist_addition);
1837                 ast_mutex_unlock(&conf->announcelistlock);
1838                 pthread_join(conf->announcethread, NULL);
1839         
1840                 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
1841                         /* If it's a voicemail greeting file we don't want to remove it */
1842                         if (!item->vmrec){
1843                                 ast_filedelete(item->namerecloc, NULL);
1844                         }
1845                         ao2_ref(item, -1);
1846                 }
1847                 ast_mutex_destroy(&conf->announcelistlock);
1848         }
1849
1850         if (conf->origframe)
1851                 ast_frfree(conf->origframe);
1852         if (conf->lchan)
1853                 ast_hangup(conf->lchan);
1854         if (conf->chan)
1855                 ast_hangup(conf->chan);
1856         if (conf->fd >= 0)
1857                 close(conf->fd);
1858         if (conf->recordingfilename) {
1859                 ast_free(conf->recordingfilename);
1860         }
1861         if (conf->usercontainer) {
1862                 ao2_ref(conf->usercontainer, -1);
1863         }
1864         if (conf->recordingformat) {
1865                 ast_free(conf->recordingformat);
1866         }
1867         ast_mutex_destroy(&conf->playlock);
1868         ast_mutex_destroy(&conf->listenlock);
1869         ast_mutex_destroy(&conf->recordthreadlock);
1870         ast_mutex_destroy(&conf->announcethreadlock);
1871         ast_free(conf);
1872
1873         return 0;
1874 }
1875
1876 static void conf_queue_dtmf(const struct ast_conference *conf,
1877         const struct ast_conf_user *sender, struct ast_frame *f)
1878 {
1879         struct ast_conf_user *user;
1880         struct ao2_iterator user_iter;
1881
1882         user_iter = ao2_iterator_init(conf->usercontainer, 0);
1883         while ((user = ao2_iterator_next(&user_iter))) {
1884                 if (user == sender) {
1885                         ao2_ref(user, -1);
1886                         continue;
1887                 }
1888                 if (ast_write(user->chan, f) < 0)
1889                         ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
1890                 ao2_ref(user, -1);
1891         }
1892         ao2_iterator_destroy(&user_iter);
1893 }
1894
1895 static void sla_queue_event_full(enum sla_event_type type, 
1896         struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
1897 {
1898         struct sla_event *event;
1899
1900         if (sla.thread == AST_PTHREADT_NULL) {
1901                 return;
1902         }
1903
1904         if (!(event = ast_calloc(1, sizeof(*event))))
1905                 return;
1906
1907         event->type = type;
1908         event->trunk_ref = trunk_ref;
1909         event->station = station;
1910
1911         if (!lock) {
1912                 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1913                 return;
1914         }
1915
1916         ast_mutex_lock(&sla.lock);
1917         AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1918         ast_cond_signal(&sla.cond);
1919         ast_mutex_unlock(&sla.lock);
1920 }
1921
1922 static void sla_queue_event_nolock(enum sla_event_type type)
1923 {
1924         sla_queue_event_full(type, NULL, NULL, 0);
1925 }
1926
1927 static void sla_queue_event(enum sla_event_type type)
1928 {
1929         sla_queue_event_full(type, NULL, NULL, 1);
1930 }
1931
1932 /*! \brief Queue a SLA event from the conference */
1933 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
1934         struct ast_conference *conf)
1935 {
1936         struct sla_station *station;
1937         struct sla_trunk_ref *trunk_ref = NULL;
1938         char *trunk_name;
1939
1940         trunk_name = ast_strdupa(conf->confno);
1941         strsep(&trunk_name, "_");
1942         if (ast_strlen_zero(trunk_name)) {
1943                 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
1944                 return;
1945         }
1946
1947         AST_RWLIST_RDLOCK(&sla_stations);
1948         AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1949                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1950                         if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
1951                                 break;
1952                 }
1953                 if (trunk_ref)
1954                         break;
1955         }
1956         AST_RWLIST_UNLOCK(&sla_stations);
1957
1958         if (!trunk_ref) {
1959                 ast_debug(1, "Trunk not found for event!\n");
1960                 return;
1961         }
1962
1963         sla_queue_event_full(type, trunk_ref, station, 1);
1964 }
1965
1966 /*! \brief Decrement reference counts, as incremented by find_conf() */
1967 static int dispose_conf(struct ast_conference *conf)
1968 {
1969         int res = 0;
1970         int confno_int = 0;
1971
1972         AST_LIST_LOCK(&confs);
1973         if (ast_atomic_dec_and_test(&conf->refcount)) {
1974                 /* Take the conference room number out of an inuse state */
1975                 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
1976                         conf_map[confno_int] = 0;
1977                 }
1978                 conf_free(conf);
1979                 res = 1;
1980         }
1981         AST_LIST_UNLOCK(&confs);
1982
1983         return res;
1984 }
1985
1986 static int rt_extend_conf(const char *confno)
1987 {
1988         char currenttime[32];
1989         char endtime[32];
1990         struct timeval now;
1991         struct ast_tm tm;
1992         struct ast_variable *var, *orig_var;
1993         char bookid[51];
1994
1995         if (!extendby) {
1996                 return 0;
1997         }
1998
1999         now = ast_tvnow();
2000
2001         ast_localtime(&now, &tm, NULL);
2002         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2003
2004         var = ast_load_realtime("meetme", "confno",
2005                 confno, "startTime<= ", currenttime,
2006                 "endtime>= ", currenttime, NULL);
2007
2008         orig_var = var;
2009
2010         /* Identify the specific RealTime conference */
2011         while (var) {
2012                 if (!strcasecmp(var->name, "bookid")) {
2013                         ast_copy_string(bookid, var->value, sizeof(bookid));
2014                 }
2015                 if (!strcasecmp(var->name, "endtime")) {
2016                         ast_copy_string(endtime, var->value, sizeof(endtime));
2017                 }
2018
2019                 var = var->next;
2020         }
2021         ast_variables_destroy(orig_var);
2022
2023         ast_strptime(endtime, DATE_FORMAT, &tm);
2024         now = ast_mktime(&tm, NULL);
2025
2026         now.tv_sec += extendby;
2027
2028         ast_localtime(&now, &tm, NULL);
2029         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2030         strcat(currenttime, "0"); /* Seconds needs to be 00 */
2031
2032         var = ast_load_realtime("meetme", "confno",
2033                 confno, "startTime<= ", currenttime,
2034                 "endtime>= ", currenttime, NULL);
2035
2036         /* If there is no conflict with extending the conference, update the DB */
2037         if (!var) {
2038                 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
2039                 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
2040                 return 0;
2041
2042         }
2043
2044         ast_variables_destroy(var);
2045         return -1;
2046 }
2047
2048 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
2049 {
2050         char *original_moh;
2051
2052         ast_channel_lock(chan);
2053         original_moh = ast_strdupa(chan->musicclass);
2054         ast_string_field_set(chan, musicclass, musicclass);
2055         ast_channel_unlock(chan);
2056
2057         ast_moh_start(chan, original_moh, NULL);
2058
2059         ast_channel_lock(chan);
2060         ast_string_field_set(chan, musicclass, original_moh);
2061         ast_channel_unlock(chan);
2062 }
2063
2064 static const char *get_announce_filename(enum announcetypes type)
2065 {
2066         switch (type) {
2067         case CONF_HASLEFT:
2068                 return "conf-hasleft";
2069                 break;
2070         case CONF_HASJOIN:
2071                 return "conf-hasjoin";
2072                 break;
2073         default:
2074                 return "";
2075         }
2076 }
2077
2078 static void *announce_thread(void *data)
2079 {
2080         struct announce_listitem *current;
2081         struct ast_conference *conf = data;
2082         int res;
2083         char filename[PATH_MAX] = "";
2084         AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
2085         AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2086
2087         while (!conf->announcethread_stop) {
2088                 ast_mutex_lock(&conf->announcelistlock);
2089                 if (conf->announcethread_stop) {
2090                         ast_mutex_unlock(&conf->announcelistlock);
2091                         break;
2092                 }
2093                 if (AST_LIST_EMPTY(&conf->announcelist))
2094                         ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
2095
2096                 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2097                 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2098
2099                 ast_mutex_unlock(&conf->announcelistlock);
2100                 if (conf->announcethread_stop) {
2101                         break;
2102                 }
2103
2104                 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2105                         ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
2106                         if (!ast_fileexists(current->namerecloc, NULL, NULL))
2107                                 continue;
2108                         if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2109                                 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2110                                         res = ast_waitstream(current->confchan, "");
2111                                 if (!res) {
2112                                         ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2113                                         if (!ast_streamfile(current->confchan, filename, current->language))
2114                                                 ast_waitstream(current->confchan, "");
2115                                 }
2116                         }
2117                         if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2118                                 /* only remove it if it isn't a VM recording file */
2119                                 ast_filedelete(current->namerecloc, NULL);
2120                         }
2121                 }
2122         }
2123
2124         /* thread marked to stop, clean up */
2125         while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2126                 /* only delete if it's a vm rec */
2127                 if (!current->vmrec) {
2128                         ast_filedelete(current->namerecloc, NULL);
2129                 }
2130                 ao2_ref(current, -1);
2131         }
2132         return NULL;
2133 }
2134
2135 static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
2136 {
2137         if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2138                 return 1;
2139         }
2140
2141         return (chan->_state == AST_STATE_UP);
2142 }
2143
2144 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
2145 {
2146         ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeTalking",
2147               "Channel: %s\r\n"
2148               "Uniqueid: %s\r\n"
2149               "Meetme: %s\r\n"
2150               "Usernum: %d\r\n"
2151               "Status: %s\r\n",
2152               chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
2153 }
2154
2155 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
2156 {
2157         int last_talking = user->talking;
2158         if (last_talking == talking)
2159                 return;
2160
2161         user->talking = talking;
2162
2163         if (monitor) {
2164                 /* Check if talking state changed. Take care of -1 which means unmonitored */
2165                 int was_talking = (last_talking > 0);
2166                 int now_talking = (talking > 0);
2167                 if (was_talking != now_talking) {
2168                         send_talking_event(chan, conf, user, now_talking);
2169                 }
2170         }
2171 }
2172
2173 static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
2174 {
2175         struct ast_conf_user *user = obj;
2176         /* actual pointer contents of check_admin_arg is irrelevant */
2177
2178         if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2179                 user->adminflags |= ADMINFLAG_KICKME;
2180         }
2181         return 0;
2182 }
2183
2184 static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
2185 {
2186         struct ast_conf_user *user = obj;
2187         /* actual pointer contents of check_admin_arg is irrelevant */
2188
2189         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2190                 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
2191         }
2192         return 0;
2193 }
2194
2195 static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
2196 {
2197         struct ast_conf_user *user = obj;
2198         /* actual pointer contents of check_admin_arg is irrelevant */
2199
2200         if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2201                 user->adminflags |= ADMINFLAG_MUTED;
2202         }
2203         return 0;
2204 }
2205
2206 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
2207 {
2208         struct ast_conf_user *user = NULL;
2209         int fd;
2210         struct dahdi_confinfo dahdic, dahdic_empty;
2211         struct ast_frame *f;
2212         struct ast_channel *c;
2213         struct ast_frame fr;
2214         int outfd;
2215         int ms;
2216         int nfds;
2217         int res;
2218         int retrydahdi;
2219         int origfd;
2220         int musiconhold = 0, mohtempstopped = 0;
2221         int firstpass = 0;
2222         int lastmarked = 0;
2223         int currentmarked = 0;
2224         int ret = -1;
2225         int x;
2226         int menu_active = 0;
2227         int menu8_active = 0;
2228         int talkreq_manager = 0;
2229         int using_pseudo = 0;
2230         int duration = 20;
2231         int hr, min, sec;
2232         int sent_event = 0;
2233         int checked = 0;
2234         int announcement_played = 0;
2235         struct timeval now;
2236         struct ast_dsp *dsp = NULL;
2237         struct ast_app *agi_app;
2238         char *agifile, *mod_speex;
2239         const char *agifiledefault = "conf-background.agi", *tmpvar;
2240         char meetmesecs[30] = "";
2241         char exitcontext[AST_MAX_CONTEXT] = "";
2242         char recordingtmp[AST_MAX_EXTENSION] = "";
2243         char members[10] = "";
2244         int dtmf, opt_waitmarked_timeout = 0;
2245         time_t timeout = 0;
2246         struct dahdi_bufferinfo bi;
2247         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
2248         char *buf = __buf + AST_FRIENDLY_OFFSET;
2249         char *exitkeys = NULL;
2250         unsigned int calldurationlimit = 0;
2251         long timelimit = 0;
2252         long play_warning = 0;
2253         long warning_freq = 0;
2254         const char *warning_sound = NULL;
2255         const char *end_sound = NULL;
2256         char *parse;    
2257         long time_left_ms = 0;
2258         struct timeval nexteventts = { 0, };
2259         int to;
2260         int setusercount = 0;
2261         int confsilence = 0, totalsilence = 0;
2262         char *mailbox, *context;
2263
2264         if (!(user = ao2_alloc(sizeof(*user), NULL))) {
2265                 return ret;
2266         }
2267
2268         /* Possible timeout waiting for marked user */
2269         if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
2270                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
2271                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
2272                 (opt_waitmarked_timeout > 0)) {
2273                 timeout = time(NULL) + opt_waitmarked_timeout;
2274         }
2275                 
2276         if (ast_test_flag64(confflags, CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
2277                 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
2278                 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
2279         }
2280         
2281         if (ast_test_flag64(confflags, CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
2282                 char *limit_str, *warning_str, *warnfreq_str;
2283                 const char *var;
2284  
2285                 parse = optargs[OPT_ARG_DURATION_LIMIT];
2286                 limit_str = strsep(&parse, ":");
2287                 warning_str = strsep(&parse, ":");
2288                 warnfreq_str = parse;
2289  
2290                 timelimit = atol(limit_str);
2291                 if (warning_str)
2292                         play_warning = atol(warning_str);
2293                 if (warnfreq_str)
2294                         warning_freq = atol(warnfreq_str);
2295  
2296                 if (!timelimit) {
2297                         timelimit = play_warning = warning_freq = 0;
2298                         warning_sound = NULL;
2299                 } else if (play_warning > timelimit) {                  
2300                         if (!warning_freq) {
2301                                 play_warning = 0;
2302                         } else {
2303                                 while (play_warning > timelimit)
2304                                         play_warning -= warning_freq;
2305                                 if (play_warning < 1)
2306                                         play_warning = warning_freq = 0;
2307                         }
2308                 }
2309                 
2310                 ast_channel_lock(chan);
2311                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
2312                         var = ast_strdupa(var);
2313                 }
2314                 ast_channel_unlock(chan);
2315
2316                 warning_sound = var ? var : "timeleft";
2317                 
2318                 ast_channel_lock(chan);
2319                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
2320                         var = ast_strdupa(var);
2321                 }
2322                 ast_channel_unlock(chan);
2323                 
2324                 end_sound = var ? var : NULL;
2325                         
2326                 /* undo effect of S(x) in case they are both used */
2327                 calldurationlimit = 0;
2328                 /* more efficient do it like S(x) does since no advanced opts */
2329                 if (!play_warning && !end_sound && timelimit) { 
2330                         calldurationlimit = timelimit / 1000;
2331                         timelimit = play_warning = warning_freq = 0;
2332                 } else {
2333                         ast_debug(2, "Limit Data for this call:\n");
2334                         ast_debug(2, "- timelimit     = %ld\n", timelimit);
2335                         ast_debug(2, "- play_warning  = %ld\n", play_warning);
2336                         ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
2337                         ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
2338                         ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
2339                 }
2340         }
2341
2342         /* Get exit keys */
2343         if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
2344                 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
2345                         exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
2346                 else
2347                         exitkeys = ast_strdupa("#"); /* Default */
2348         }
2349         
2350         if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
2351                 if (!conf->recordingfilename) {
2352                         const char *var;
2353                         ast_channel_lock(chan);
2354                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
2355                                 conf->recordingfilename = ast_strdup(var);
2356                         }
2357                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
2358                                 conf->recordingformat = ast_strdup(var);
2359                         }
2360                         ast_channel_unlock(chan);
2361                         if (!conf->recordingfilename) {
2362                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
2363                                 conf->recordingfilename = ast_strdup(recordingtmp);
2364                         }
2365                         if (!conf->recordingformat) {
2366                                 conf->recordingformat = ast_strdup("wav");
2367                         }
2368                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
2369                                     conf->confno, conf->recordingfilename, conf->recordingformat);
2370                 }
2371         }
2372
2373         ast_mutex_lock(&conf->recordthreadlock);
2374         if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
2375                 ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, chan, "pseudo", NULL)))) {
2376                 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
2377                 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
2378                 dahdic.chan = 0;
2379                 dahdic.confno = conf->dahdiconf;
2380                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
2381                 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
2382                         ast_log(LOG_WARNING, "Error starting listen channel\n");
2383                         ast_hangup(conf->lchan);
2384                         conf->lchan = NULL;
2385                 } else {
2386                         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
2387                 }
2388         }
2389         ast_mutex_unlock(&conf->recordthreadlock);
2390
2391         ast_mutex_lock(&conf->announcethreadlock);
2392         if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
2393                 ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC)) {
2394                 ast_mutex_init(&conf->announcelistlock);
2395                 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
2396                 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
2397         }
2398         ast_mutex_unlock(&conf->announcethreadlock);
2399
2400         time(&user->jointime);
2401         
2402         user->timelimit = timelimit;
2403         user->play_warning = play_warning;
2404         user->warning_freq = warning_freq;
2405         user->warning_sound = warning_sound;
2406         user->end_sound = end_sound;    
2407         
2408         if (calldurationlimit > 0) {
2409                 time(&user->kicktime);
2410                 user->kicktime = user->kicktime + calldurationlimit;
2411         }
2412         
2413         if (ast_tvzero(user->start_time))
2414                 user->start_time = ast_tvnow();
2415         time_left_ms = user->timelimit;
2416         
2417         if (user->timelimit) {
2418                 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
2419                 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
2420         }
2421
2422         if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
2423                 /* Sorry, but this conference is locked! */     
2424                 if (!ast_streamfile(chan, "conf-locked", chan->language))
2425                         ast_waitstream(chan, "");
2426                 goto outrun;
2427         }
2428
2429         ast_mutex_lock(&conf->playlock);
2430
2431         if (rt_schedule && conf->maxusers) {
2432                 if (conf->users >= conf->maxusers) {
2433                         /* Sorry, but this confernce has reached the participant limit! */      
2434                         if (!ast_streamfile(chan, "conf-full", chan->language))
2435                                 ast_waitstream(chan, "");
2436                         ast_mutex_unlock(&conf->playlock);
2437                         goto outrun;
2438                 }
2439         }
2440
2441         ao2_lock(conf->usercontainer);
2442         ao2_callback(conf->usercontainer, OBJ_NODATA, user_max_cmp, &user->user_no);
2443         user->user_no++;
2444         ao2_link(conf->usercontainer, user);
2445         ao2_unlock(conf->usercontainer);
2446
2447         user->chan = chan;
2448         user->userflags = *confflags;
2449         user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
2450         user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
2451         user->talking = -1;
2452
2453         ast_mutex_unlock(&conf->playlock);
2454
2455         if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW | CONFFLAG_INTROUSER_VMREC))) {
2456                 char destdir[PATH_MAX];
2457
2458                 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
2459
2460                 if (ast_mkdir(destdir, 0777) != 0) {
2461                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
2462                         goto outrun;
2463                 }
2464
2465                 if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
2466                         context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
2467                         mailbox = strsep(&context, "@");
2468
2469                         if (ast_strlen_zero(mailbox)) {
2470                                 /* invalid input, clear the v flag*/
2471                                 ast_clear_flag64(confflags,CONFFLAG_INTROUSER_VMREC);
2472                                 ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
2473                         } else {
2474                                 if (ast_strlen_zero(context)) {
2475                                     context = "default";
2476                                 }
2477                                 /* if there is no mailbox we don't need to do this logic  */
2478                                 snprintf(user->namerecloc, sizeof(user->namerecloc),
2479                                          "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
2480
2481                                 /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
2482                                 if (!ast_fileexists(user->namerecloc, NULL, NULL)){
2483                                         snprintf(user->namerecloc, sizeof(user->namerecloc),
2484                                                  "%s/meetme-username-%s-%d", destdir,
2485                                                  conf->confno, user->user_no);
2486                                         ast_clear_flag64(confflags, CONFFLAG_INTROUSER_VMREC);
2487                                 }
2488                         }
2489                 } else {
2490                         snprintf(user->namerecloc, sizeof(user->namerecloc),
2491                                  "%s/meetme-username-%s-%d", destdir,
2492                                  conf->confno, user->user_no);
2493                 }
2494
2495                 res = 0;
2496                 if (ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) && !ast_fileexists(user->namerecloc, NULL, NULL))
2497                         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
2498                 else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
2499                         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
2500                 if (res == -1)
2501                         goto outrun;
2502
2503         }
2504
2505         ast_mutex_lock(&conf->playlock);
2506
2507         if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
2508                 conf->markedusers++;
2509         conf->users++;
2510         if (rt_log_members) {
2511                 /* Update table */
2512                 snprintf(members, sizeof(members), "%d", conf->users);
2513                 ast_realtime_require_field("meetme",
2514                         "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
2515                         "members", RQ_UINTEGER1, strlen(members),
2516                         NULL);
2517                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2518         }
2519         setusercount = 1;
2520
2521         /* This device changed state now - if this is the first user */
2522         if (conf->users == 1)
2523                 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
2524
2525         ast_mutex_unlock(&conf->playlock);
2526
2527         /* return the unique ID of the conference */
2528         pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
2529
2530         if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
2531                 ast_channel_lock(chan);
2532                 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
2533                         ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
2534                 } else if (!ast_strlen_zero(chan->macrocontext)) {
2535                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
2536                 } else {
2537                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
2538                 }
2539                 ast_channel_unlock(chan);
2540         }
2541
2542         /* Play an arbitrary intro message */
2543         if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
2544                         !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
2545                 if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], chan->language)) {
2546                         ast_waitstream(chan, "");
2547                 }
2548         }
2549
2550         if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
2551                 if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
2552                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
2553                                 ast_waitstream(chan, "");
2554                 if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
2555                         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
2556                                 ast_waitstream(chan, "");
2557         }
2558
2559         if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) &&
2560                 conf->users > 1) {
2561                 int keepplaying = 1;
2562
2563                 if (conf->users == 2) { 
2564                         if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
2565                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2566                                 ast_stopstream(chan);
2567                                 if (res > 0)
2568                                         keepplaying = 0;
2569                                 else if (res == -1)
2570                                         goto outrun;
2571                         }
2572                 } else { 
2573                         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
2574                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2575                                 ast_stopstream(chan);
2576                                 if (res > 0)
2577                                         keepplaying = 0;
2578                                 else if (res == -1)
2579                                         goto outrun;
2580                         }
2581                         if (keepplaying) {
2582                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
2583                                 if (res > 0)
2584                                         keepplaying = 0;
2585                                 else if (res == -1)
2586                                         goto outrun;
2587                         }
2588                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
2589                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
2590                                 ast_stopstream(chan);
2591                                 if (res > 0)
2592                                         keepplaying = 0;
2593                                 else if (res == -1) 
2594                                         goto outrun;
2595                         }
2596                 }
2597         }
2598
2599         if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2600                 /* We're leaving this alone until the state gets changed to up */
2601                 ast_indicate(chan, -1);
2602         }
2603
2604         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
2605                 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
2606                 goto outrun;
2607         }
2608
2609         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
2610                 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
2611                 goto outrun;
2612         }
2613
2614         /* Reduce background noise from each participant */
2615         if ((mod_speex = ast_module_helper("", "codec_speex", 0, 0, 0, 0))) {
2616                 ast_free(mod_speex);
2617                 ast_func_write(chan, "DENOISE(rx)", "on");
2618         }
2619
2620         retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
2621         user->dahdichannel = !retrydahdi;
2622
2623  dahdiretry:
2624         origfd = chan->fds[0];
2625         if (retrydahdi) {
2626                 /* open pseudo in non-blocking mode */
2627                 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
2628                 if (fd < 0) {
2629                         ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
2630                         goto outrun;
2631                 }
2632                 using_pseudo = 1;
2633                 /* Setup buffering information */
2634                 memset(&bi, 0, sizeof(bi));
2635                 bi.bufsize = CONF_SIZE / 2;
2636                 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
2637                 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
2638                 bi.numbufs = audio_buffers;
2639                 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
2640                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
2641                         close(fd);
2642                         goto outrun;
2643                 }
2644                 x = 1;
2645                 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
2646                         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
2647                         close(fd);
2648                         goto outrun;
2649                 }
2650                 nfds = 1;
2651         } else {
2652                 /* XXX Make sure we're not running on a pseudo channel XXX */
2653                 fd = chan->fds[0];
2654                 nfds = 0;
2655         }
2656         memset(&dahdic, 0, sizeof(dahdic));
2657         memset(&dahdic_empty, 0, sizeof(dahdic_empty));
2658         /* Check to see if we're in a conference... */
2659         dahdic.chan = 0;        
2660         if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
2661                 ast_log(LOG_WARNING, "Error getting conference\n");
2662                 close(fd);
2663                 goto outrun;
2664         }
2665         if (dahdic.confmode) {
2666                 /* Whoa, already in a conference...  Retry... */
2667                 if (!retrydahdi) {
2668                         ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
2669                         retrydahdi = 1;
2670                         goto dahdiretry;
2671                 }
2672         }
2673         memset(&dahdic, 0, sizeof(dahdic));
2674         /* Add us to the conference */
2675         dahdic.chan = 0;        
2676         dahdic.confno = conf->dahdiconf;
2677
2678         if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
2679                         ast_test_flag64(confflags, CONFFLAG_INTROUSERNOREVIEW) || ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)) && conf->users > 1) {
2680                 struct announce_listitem *item;
2681                 if (!(item = ao2_alloc(sizeof(*item), NULL)))
2682                         return -1;
2683                 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
2684                 ast_copy_string(item->language, chan->language, sizeof(item->language));
2685                 item->confchan = conf->chan;
2686                 item->confusers = conf->users;
2687                 if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
2688                         item->vmrec = 1;
2689                 }
2690                 item->announcetype = CONF_HASJOIN;
2691                 ast_mutex_lock(&conf->announcelistlock);
2692                 ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
2693                 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
2694                 ast_cond_signal(&conf->announcelist_addition);
2695                 ast_mutex_unlock(&conf->announcelistlock);
2696
2697                 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
2698                         ;
2699                 }
2700                 ao2_ref(item, -1);
2701         }
2702
2703         if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED && !conf->markedusers))
2704                 dahdic.confmode = DAHDI_CONF_CONF;
2705         else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
2706                 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
2707         else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
2708                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
2709         else 
2710                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
2711
2712         if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2713                 ast_log(LOG_WARNING, "Error setting conference\n");
2714                 close(fd);
2715                 goto outrun;
2716         }
2717         ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
2718
2719         if (!sent_event) {
2720                 ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeJoin",
2721                         "Channel: %s\r\n"
2722                         "Uniqueid: %s\r\n"
2723                         "Meetme: %s\r\n"
2724                         "Usernum: %d\r\n"
2725                         "CallerIDnum: %s\r\n"
2726                         "CallerIDname: %s\r\n",
2727                         chan->name, chan->uniqueid, conf->confno,
2728                         user->user_no,
2729                         S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
2730                         S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>")
2731                         );
2732                 sent_event = 1;
2733         }
2734
2735         if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
2736                 !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
2737                 firstpass = 1;
2738                 if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
2739                         if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
2740                                 (conf->markedusers >= 1))) {
2741                                 conf_play(chan, conf, ENTER);
2742                         }
2743         }
2744
2745         conf_flush(fd, chan);
2746
2747         if (dsp)
2748                 ast_dsp_free(dsp);
2749
2750         if (!(dsp = ast_dsp_new())) {
2751                 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
2752                 res = -1;
2753         }
2754
2755         if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
2756                 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
2757                    or use default filename of conf-background.agi */
2758
2759                 ast_channel_lock(chan);
2760                 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
2761                         agifile = ast_strdupa(tmpvar);
2762                 } else {
2763                         agifile = ast_strdupa(agifiledefault);
2764                 }
2765                 ast_channel_unlock(chan);
2766                 
2767                 if (user->dahdichannel) {
2768                         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
2769                         x = 1;
2770                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2771                 }
2772                 /* Find a pointer to the agi app and execute the script */
2773                 agi_app = pbx_findapp("agi");
2774                 if (agi_app) {
2775                         ret = pbx_exec(chan, agi_app, agifile);
2776                 } else {
2777                         ast_log(LOG_WARNING, "Could not find application (agi)\n");
2778                         ret = -2;
2779                 }
2780                 if (user->dahdichannel) {
2781                         /*  Remove CONFMUTE mode on DAHDI channel */
2782                         x = 0;
2783                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2784                 }
2785         } else {
2786                 if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
2787                         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
2788                         x = 1;
2789                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2790                 }       
2791                 for (;;) {
2792                         int menu_was_active = 0;
2793
2794                         outfd = -1;
2795                         ms = -1;
2796                         now = ast_tvnow();
2797
2798                         if (rt_schedule && conf->endtime) {
2799                                 char currenttime[32];
2800                                 long localendtime = 0;
2801                                 int extended = 0;
2802                                 struct ast_tm tm;
2803                                 struct ast_variable *var, *origvar;
2804                                 struct timeval tmp;
2805
2806                                 if (now.tv_sec % 60 == 0) {
2807                                         if (!checked) {
2808                                                 ast_localtime(&now, &tm, NULL);
2809                                                 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2810                                                 var = origvar = ast_load_realtime("meetme", "confno",
2811                                                         conf->confno, "starttime <=", currenttime,
2812                                                          "endtime >=", currenttime, NULL);
2813
2814                                                 for ( ; var; var = var->next) {
2815                                                         if (!strcasecmp(var->name, "endtime")) {
2816                                                                 struct ast_tm endtime_tm;
2817                                                                 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
2818                                                                 tmp = ast_mktime(&endtime_tm, NULL);
2819                                                                 localendtime = tmp.tv_sec;
2820                                                         }
2821                                                 }
2822                                                 ast_variables_destroy(origvar);
2823
2824                                                 /* A conference can be extended from the
2825                                                    Admin/User menu or by an external source */
2826                                                 if (localendtime > conf->endtime){
2827                                                         conf->endtime = localendtime;
2828                                                         extended = 1;
2829                                                 }
2830
2831                                                 if (conf->endtime && (now.tv_sec >= conf->endtime)) {
2832                                                         ast_verbose("Quitting time...\n");
2833                                                         goto outrun;
2834                                                 }
2835
2836                                                 if (!announcement_played && conf->endalert) {
2837                                                         if (now.tv_sec + conf->endalert >= conf->endtime) {
2838                                                                 if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
2839                                                                         ast_waitstream(chan, "");
2840                                                                 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
2841                                                                 if (!ast_streamfile(chan, "minutes", chan->language))
2842                                                                         ast_waitstream(chan, "");
2843                                                                 if (musiconhold) {
2844                                                                         conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
2845                                                                 }
2846                                                                 announcement_played = 1;
2847                                                         }
2848                                                 }
2849
2850                                                 if (extended) {
2851                                                         announcement_played = 0;
2852                                                 }
2853
2854                                                 checked = 1;
2855                                         }
2856                                 } else {
2857                                         checked = 0;
2858                                 }
2859                         }
2860
2861                         if (user->kicktime && (user->kicktime <= now.tv_sec)) {
2862                                 if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
2863                                         ret = 0;
2864                                 } else {
2865                                         ret = -1;
2866                                 }
2867                                 break;
2868                         }
2869   
2870                         to = -1;
2871                         if (user->timelimit) {
2872                                 int minutes = 0, seconds = 0, remain = 0;
2873  
2874                                 to = ast_tvdiff_ms(nexteventts, now);
2875                                 if (to < 0) {
2876                                         to = 0;
2877                                 }
2878                                 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
2879                                 if (time_left_ms < to) {