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