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