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