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