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