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