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