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