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