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