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