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