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