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