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