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