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