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