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