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