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