7f38c0880cab38915befb34f94b6add053b4b347
[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                         if (c) {
1902                                 if (c->fds[0] != origfd) {
1903                                         if (using_pseudo) {
1904                                                 /* Kill old pseudo */
1905                                                 close(fd);
1906                                                 using_pseudo = 0;
1907                                         }
1908                                         ast_debug(1, "Ooh, something swapped out under us, starting over\n");
1909                                         retryzap = strcasecmp(c->tech->type, "Zap");
1910                                         user->zapchannel = !retryzap;
1911                                         goto zapretry;
1912                                 }
1913                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1914                                         f = ast_read_noaudio(c);
1915                                 else
1916                                         f = ast_read(c);
1917                                 if (!f)
1918                                         break;
1919                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1920                                         if (user->talk.actual)
1921                                                 ast_frame_adjust_volume(f, user->talk.actual);
1922
1923                                         {
1924                                                 int totalsilence;
1925
1926                                                 if (user->talking == -1)
1927                                                         user->talking = 0;
1928
1929                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1930                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1931                                                         user->talking = 1;
1932                                                         if (confflags & CONFFLAG_MONITORTALKER)
1933                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1934                                                                       "Channel: %s\r\n"
1935                                                                       "Uniqueid: %s\r\n"
1936                                                                       "Meetme: %s\r\n"
1937                                                                       "Usernum: %d\r\n"
1938                                                                       "Status: on\r\n",
1939                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1940                                                 }
1941                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1942                                                         user->talking = 0;
1943                                                         if (confflags & CONFFLAG_MONITORTALKER)
1944                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1945                                                                       "Channel: %s\r\n"
1946                                                                       "Uniqueid: %s\r\n"
1947                                                                       "Meetme: %s\r\n"
1948                                                                       "Usernum: %d\r\n"
1949                                                                       "Status: off\r\n",
1950                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1951                                                 }
1952                                         }
1953                                         if (using_pseudo) {
1954                                                 /* Absolutely do _not_ use careful_write here...
1955                                                    it is important that we read data from the channel
1956                                                    as fast as it arrives, and feed it into the conference.
1957                                                    The buffering in the pseudo channel will take care of any
1958                                                    timing differences, unless they are so drastic as to lose
1959                                                    audio frames (in which case carefully writing would only
1960                                                    have delayed the audio even further).
1961                                                 */
1962                                                 /* As it turns out, we do want to use careful write.  We just
1963                                                    don't want to block, but we do want to at least *try*
1964                                                    to write out all the samples.
1965                                                  */
1966                                                 if (user->talking)
1967                                                         careful_write(fd, f->data, f->datalen, 0);
1968                                         }
1969                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1970                                         char tmp[2];
1971
1972                                         tmp[0] = f->subclass;
1973                                         tmp[1] = '\0';
1974                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1975                                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1976                                                 ret = 0;
1977                                                 ast_frfree(f);
1978                                                 break;
1979                                         } else {
1980                                                 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1981                                         }
1982                                 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1983                                         ret = 0;
1984                                         ast_frfree(f);
1985                                         break;
1986                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
1987                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
1988                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1989                                                 close(fd);
1990                                                 ast_frfree(f);
1991                                                 goto outrun;
1992                                         }
1993
1994                                         /* if we are entering the menu, and the user has a channel-driver
1995                                            volume adjustment, clear it
1996                                         */
1997                                         if (!menu_active && user->talk.desired && !user->talk.actual)
1998                                                 set_talk_volume(user, 0);
1999
2000                                         if (musiconhold) {
2001                                                 ast_moh_stop(chan);
2002                                         }
2003                                         if ((confflags & CONFFLAG_ADMIN)) {
2004                                                 /* Admin menu */
2005                                                 if (!menu_active) {
2006                                                         menu_active = 1;
2007                                                         /* Record this sound! */
2008                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
2009                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2010                                                                 ast_stopstream(chan);
2011                                                         } else 
2012                                                                 dtmf = 0;
2013                                                 } else 
2014                                                         dtmf = f->subclass;
2015                                                 if (dtmf) {
2016                                                         switch(dtmf) {
2017                                                         case '1': /* Un/Mute */
2018                                                                 menu_active = 0;
2019
2020                                                                 /* for admin, change both admin and use flags */
2021                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
2022                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2023                                                                 else
2024                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2025
2026                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2027                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2028                                                                                 ast_waitstream(chan, "");
2029                                                                 } else {
2030                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2031                                                                                 ast_waitstream(chan, "");
2032                                                                 }
2033                                                                 break;
2034                                                         case '2': /* Un/Lock the Conference */
2035                                                                 menu_active = 0;
2036                                                                 if (conf->locked) {
2037                                                                         conf->locked = 0;
2038                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
2039                                                                                 ast_waitstream(chan, "");
2040                                                                 } else {
2041                                                                         conf->locked = 1;
2042                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
2043                                                                                 ast_waitstream(chan, "");
2044                                                                 }
2045                                                                 break;
2046                                                         case '3': /* Eject last user */
2047                                                                 menu_active = 0;
2048                                                                 usr = AST_LIST_LAST(&conf->userlist);
2049                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
2050                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
2051                                                                                 ast_waitstream(chan, "");
2052                                                                 } else 
2053                                                                         usr->adminflags |= ADMINFLAG_KICKME;
2054                                                                 ast_stopstream(chan);
2055                                                                 break;  
2056                                                         case '4':
2057                                                                 tweak_listen_volume(user, VOL_DOWN);
2058                                                                 break;
2059                                                         case '6':
2060                                                                 tweak_listen_volume(user, VOL_UP);
2061                                                                 break;
2062                                                         case '7':
2063                                                                 tweak_talk_volume(user, VOL_DOWN);
2064                                                                 break;
2065                                                         case '8':
2066                                                                 menu_active = 0;
2067                                                                 break;
2068                                                         case '9':
2069                                                                 tweak_talk_volume(user, VOL_UP);
2070                                                                 break;
2071                                                         default:
2072                                                                 menu_active = 0;
2073                                                                 /* Play an error message! */
2074                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2075                                                                         ast_waitstream(chan, "");
2076                                                                 break;
2077                                                         }
2078                                                 }
2079                                         } else {
2080                                                 /* User menu */
2081                                                 if (!menu_active) {
2082                                                         menu_active = 1;
2083                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
2084                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2085                                                                 ast_stopstream(chan);
2086                                                         } else
2087                                                                 dtmf = 0;
2088                                                 } else 
2089                                                         dtmf = f->subclass;
2090                                                 if (dtmf) {
2091                                                         switch(dtmf) {
2092                                                         case '1': /* Un/Mute */
2093                                                                 menu_active = 0;
2094
2095                                                                 /* user can only toggle the self-muted state */
2096                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2097
2098                                                                 /* they can't override the admin mute state */
2099                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2100                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2101                                                                                 ast_waitstream(chan, "");
2102                                                                 } else {
2103                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2104                                                                                 ast_waitstream(chan, "");
2105                                                                 }
2106                                                                 break;
2107                                                         case '4':
2108                                                                 tweak_listen_volume(user, VOL_DOWN);
2109                                                                 break;
2110                                                         case '6':
2111                                                                 tweak_listen_volume(user, VOL_UP);
2112                                                                 break;
2113                                                         case '7':
2114                                                                 tweak_talk_volume(user, VOL_DOWN);
2115                                                                 break;
2116                                                         case '8':
2117                                                                 menu_active = 0;
2118                                                                 break;
2119                                                         case '9':
2120                                                                 tweak_talk_volume(user, VOL_UP);
2121                                                                 break;
2122                                                         default:
2123                                                                 menu_active = 0;
2124                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2125                                                                         ast_waitstream(chan, "");
2126                                                                 break;
2127                                                         }
2128                                                 }
2129                                         }
2130                                         if (musiconhold)
2131                                                 ast_moh_start(chan, NULL, NULL);
2132
2133                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
2134                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2135                                                 close(fd);
2136                                                 ast_frfree(f);
2137                                                 goto outrun;
2138                                         }
2139
2140                                         conf_flush(fd, chan);
2141                                 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
2142                                         && confflags & CONFFLAG_PASS_DTMF) {
2143                                         conf_queue_dtmf(conf, user, f);
2144                                 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
2145                                         switch (f->subclass) {
2146                                         case AST_CONTROL_HOLD:
2147                                                 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
2148                                                 break;
2149                                         default:
2150                                                 break;
2151                                         }
2152                                 } else if (f->frametype == AST_FRAME_NULL) {
2153                                         /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2154                                 } else if (option_debug) {
2155                                         ast_log(LOG_DEBUG,
2156                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2157                                                 chan->name, f->frametype, f->subclass);
2158                                 }
2159                                 ast_frfree(f);
2160                                 if (ast_check_hangup(chan))
2161                                         break;
2162                         } else if (outfd > -1) {
2163                                 res = read(outfd, buf, CONF_SIZE);
2164                                 if (res > 0) {
2165                                         memset(&fr, 0, sizeof(fr));
2166                                         fr.frametype = AST_FRAME_VOICE;
2167                                         fr.subclass = AST_FORMAT_SLINEAR;
2168                                         fr.datalen = res;
2169                                         fr.samples = res/2;
2170                                         fr.data = buf;
2171                                         fr.offset = AST_FRIENDLY_OFFSET;
2172                                         if ( !user->listen.actual && 
2173                                                 ((confflags & CONFFLAG_MONITOR) || 
2174                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
2175                                                  (!user->talking)) ) {
2176                                                 int index;
2177                                                 for (index=0;index<AST_FRAME_BITS;index++)
2178                                                         if (chan->rawwriteformat & (1 << index))
2179                                                                 break;
2180                                                 if (index >= AST_FRAME_BITS)
2181                                                         goto bailoutandtrynormal;
2182                                                 ast_mutex_lock(&conf->listenlock);
2183                                                 if (!conf->transframe[index]) {
2184                                                         if (conf->origframe) {
2185                                                                 if (!conf->transpath[index])
2186                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
2187                                                                 if (conf->transpath[index]) {
2188                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
2189                                                                         if (!conf->transframe[index])
2190                                                                                 conf->transframe[index] = &ast_null_frame;
2191                                                                 }
2192                                                         }
2193                                                 }
2194                                                 if (conf->transframe[index]) {
2195                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
2196                                                                 if (ast_write(chan, conf->transframe[index]))
2197                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2198                                                         }
2199                                                 } else {
2200                                                         ast_mutex_unlock(&conf->listenlock);
2201                                                         goto bailoutandtrynormal;
2202                                                 }
2203                                                 ast_mutex_unlock(&conf->listenlock);
2204                                         } else {
2205 bailoutandtrynormal:                                    
2206                                                 if (user->listen.actual)
2207                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
2208                                                 if (ast_write(chan, &fr) < 0) {
2209                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2210                                                 }
2211                                         }
2212                                 } else 
2213                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
2214                         }
2215                         lastmarked = currentmarked;
2216                 }
2217         }
2218
2219         if (musiconhold)
2220                 ast_moh_stop(chan);
2221         
2222         if (using_pseudo)
2223                 close(fd);
2224         else {
2225                 /* Take out of conference */
2226                 ztc.chan = 0;   
2227                 ztc.confno = 0;
2228                 ztc.confmode = 0;
2229                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
2230                         ast_log(LOG_WARNING, "Error setting conference\n");
2231                 }
2232         }
2233
2234         reset_volumes(user);
2235
2236         AST_LIST_LOCK(&confs);
2237         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
2238                 conf_play(chan, conf, LEAVE);
2239
2240         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
2241                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
2242                         if ((conf->chan) && (conf->users > 1)) {
2243                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
2244                                         ast_waitstream(conf->chan, "");
2245                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
2246                                         ast_waitstream(conf->chan, "");
2247                         }
2248                         ast_filedelete(user->namerecloc, NULL);
2249                 }
2250         }
2251         AST_LIST_UNLOCK(&confs);
2252
2253  outrun:
2254         AST_LIST_LOCK(&confs);
2255
2256         if (dsp)
2257                 ast_dsp_free(dsp);
2258         
2259         if (user->user_no) { /* Only cleanup users who really joined! */
2260                 now = time(NULL);
2261                 hr = (now - user->jointime) / 3600;
2262                 min = ((now - user->jointime) % 3600) / 60;
2263                 sec = (now - user->jointime) % 60;
2264
2265                 if (sent_event) {
2266                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
2267                                       "Channel: %s\r\n"
2268                                       "Uniqueid: %s\r\n"
2269                                       "Meetme: %s\r\n"
2270                                       "Usernum: %d\r\n"
2271                                       "CallerIDNum: %s\r\n"
2272                                       "CallerIDName: %s\r\n"
2273                                       "Duration: %ld\r\n",
2274                                       chan->name, chan->uniqueid, conf->confno, 
2275                                       user->user_no,
2276                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
2277                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
2278                                       (long)(now - user->jointime));
2279                 }
2280
2281                 conf->users--;
2282                 /* Update table */
2283                 snprintf(members, sizeof(members), "%d", conf->users);
2284                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2285                 if (confflags & CONFFLAG_MARKEDUSER) 
2286                         conf->markedusers--;
2287                 /* Remove ourselves from the list */
2288                 AST_LIST_REMOVE(&conf->userlist, user, list);
2289
2290                 /* Change any states */
2291                 if (!conf->users)
2292                         ast_device_state_changed("meetme:%s", conf->confno);
2293                 
2294                 /* Return the number of seconds the user was in the conf */
2295                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
2296                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
2297         }
2298         ast_free(user);
2299         AST_LIST_UNLOCK(&confs);
2300
2301         return ret;
2302 }
2303
2304 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
2305                                                  char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2306 {
2307         struct ast_variable *var;
2308         struct ast_conference *cnf;
2309
2310         /* Check first in the conference list */
2311         AST_LIST_LOCK(&confs);
2312         AST_LIST_TRAVERSE(&confs, cnf, list) {
2313                 if (!strcmp(confno, cnf->confno)) 
2314                         break;
2315         }
2316         if (cnf) {
2317                 cnf->refcount += refcount;
2318         }
2319         AST_LIST_UNLOCK(&confs);
2320
2321         if (!cnf) {
2322                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
2323                 
2324                 var = ast_load_realtime("meetme", "confno", confno, NULL);
2325
2326                 if (!var)
2327                         return NULL;
2328
2329                 while (var) {
2330                         if (!strcasecmp(var->name, "pin")) {
2331                                 pin = ast_strdupa(var->value);
2332                         } else if (!strcasecmp(var->name, "adminpin")) {
2333                                 pinadmin = ast_strdupa(var->value);
2334                         }
2335                         var = var->next;
2336                 }
2337                 ast_variables_destroy(var);
2338                 
2339                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
2340         }
2341
2342         if (cnf) {
2343                 if (confflags && !cnf->chan &&
2344                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2345                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2346                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2347                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2348                 }
2349                 
2350                 if (confflags && !cnf->chan &&
2351                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2352                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2353                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2354                 }
2355         }
2356
2357         return cnf;
2358 }
2359
2360
2361 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2362                                         char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2363 {
2364         struct ast_config *cfg;
2365         struct ast_variable *var;
2366         struct ast_conference *cnf;
2367         char *parse;
2368         AST_DECLARE_APP_ARGS(args,
2369                 AST_APP_ARG(confno);
2370                 AST_APP_ARG(pin);
2371                 AST_APP_ARG(pinadmin);
2372         );
2373
2374         /* Check first in the conference list */
2375         AST_LIST_LOCK(&confs);
2376         AST_LIST_TRAVERSE(&confs, cnf, list) {
2377                 if (!strcmp(confno, cnf->confno)) 
2378                         break;
2379         }
2380         if (cnf){
2381                 cnf->refcount += refcount;
2382         }
2383         AST_LIST_UNLOCK(&confs);
2384
2385         if (!cnf) {
2386                 if (dynamic) {
2387                         /* No need to parse meetme.conf */
2388                         ast_debug(1, "Building dynamic conference '%s'\n", confno);
2389                         if (dynamic_pin) {
2390                                 if (dynamic_pin[0] == 'q') {
2391                                         /* Query the user to enter a PIN */
2392                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
2393                                                 return NULL;
2394                                 }
2395                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
2396                         } else {
2397                                 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
2398                         }
2399                 } else {
2400                         /* Check the config */
2401                         cfg = ast_config_load(CONFIG_FILE_NAME);
2402                         if (!cfg) {
2403                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2404                                 return NULL;
2405                         }
2406                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2407                                 if (strcasecmp(var->name, "conf"))
2408                                         continue;
2409                                 
2410                                 if (!(parse = ast_strdupa(var->value)))
2411                                         return NULL;
2412                                 
2413                                 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2414                                 if (!strcasecmp(args.confno, confno)) {
2415                                         /* Bingo it's a valid conference */
2416                                         cnf = build_conf(args.confno,
2417                                                         S_OR(args.pin, ""),
2418                                                         S_OR(args.pinadmin, ""),
2419                                                         make, dynamic, refcount, chan);
2420                                         break;
2421                                 }
2422                         }
2423                         if (!var) {
2424                                 ast_debug(1, "%s isn't a valid conference\n", confno);
2425                         }
2426                         ast_config_destroy(cfg);
2427                 }
2428         } else if (dynamic_pin) {
2429                 /* Correct for the user selecting 'D' instead of 'd' to have
2430                    someone join into a conference that has already been created
2431                    with a pin. */
2432                 if (dynamic_pin[0] == 'q')
2433                         dynamic_pin[0] = '\0';
2434         }
2435
2436         if (cnf) {
2437                 if (confflags && !cnf->chan &&
2438                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2439                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2440                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2441                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2442                 }
2443                 
2444                 if (confflags && !cnf->chan &&
2445                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2446                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2447                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2448                 }
2449         }
2450
2451         return cnf;
2452 }
2453
2454 /*! \brief The MeetmeCount application */
2455 static int count_exec(struct ast_channel *chan, void *data)
2456 {
2457         struct ast_module_user *u;
2458         int res = 0;
2459         struct ast_conference *conf;
2460         int count;
2461         char *localdata;
2462         char val[80] = "0"; 
2463         AST_DECLARE_APP_ARGS(args,
2464                 AST_APP_ARG(confno);
2465                 AST_APP_ARG(varname);
2466         );
2467
2468         if (ast_strlen_zero(data)) {
2469                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2470                 return -1;
2471         }
2472
2473         u = ast_module_user_add(chan);
2474         
2475         if (!(localdata = ast_strdupa(data))) {
2476                 ast_module_user_remove(u);
2477                 return -1;
2478         }
2479
2480         AST_STANDARD_APP_ARGS(args, localdata);
2481         
2482         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
2483
2484         if (conf) {
2485                 count = conf->users;
2486                 dispose_conf(conf);
2487                 conf = NULL;
2488         } else
2489                 count = 0;
2490
2491         if (!ast_strlen_zero(args.varname)){
2492                 /* have var so load it and exit */
2493                 snprintf(val, sizeof(val), "%d",count);
2494                 pbx_builtin_setvar_helper(chan, args.varname, val);
2495         } else {
2496                 if (chan->_state != AST_STATE_UP)
2497                         ast_answer(chan);
2498                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2499         }
2500         ast_module_user_remove(u);
2501
2502         return res;
2503 }
2504
2505 /*! \brief The meetme() application */
2506 static int conf_exec(struct ast_channel *chan, void *data)
2507 {
2508         int res=-1;
2509         struct ast_module_user *u;
2510         char confno[MAX_CONFNUM] = "";
2511         int allowretry = 0;
2512         int retrycnt = 0;
2513         struct ast_conference *cnf = NULL;
2514         struct ast_flags confflags = {0};
2515         int dynamic = 0;
2516         int empty = 0, empty_no_pin = 0;
2517         int always_prompt = 0;
2518         char *notdata, *info, the_pin[MAX_PIN] = "";
2519         AST_DECLARE_APP_ARGS(args,
2520                 AST_APP_ARG(confno);
2521                 AST_APP_ARG(options);
2522                 AST_APP_ARG(pin);
2523         );
2524         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2525
2526         u = ast_module_user_add(chan);
2527
2528         if (ast_strlen_zero(data)) {
2529                 allowretry = 1;
2530                 notdata = "";
2531         } else {
2532                 notdata = data;
2533         }
2534         
2535         if (chan->_state != AST_STATE_UP)
2536                 ast_answer(chan);
2537
2538         info = ast_strdupa(notdata);
2539
2540         AST_STANDARD_APP_ARGS(args, info);      
2541
2542         if (args.confno) {
2543                 ast_copy_string(confno, args.confno, sizeof(confno));
2544                 if (ast_strlen_zero(confno)) {
2545                         allowretry = 1;
2546                 }
2547         }
2548         
2549         if (args.pin)
2550                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2551
2552         if (args.options) {
2553                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2554                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2555                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2556                         strcpy(the_pin, "q");
2557
2558                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2559                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2560                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2561         }
2562
2563         do {
2564                 if (retrycnt > 3)
2565                         allowretry = 0;
2566                 if (empty) {
2567                         int i;
2568                         struct ast_config *cfg;
2569                         struct ast_variable *var;
2570                         int confno_int;
2571
2572                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2573                         if ((empty_no_pin) || (!dynamic)) {
2574                                 cfg = ast_config_load(CONFIG_FILE_NAME);
2575                                 if (cfg) {
2576                                         var = ast_variable_browse(cfg, "rooms");
2577                                         while (var) {
2578                                                 if (!strcasecmp(var->name, "conf")) {
2579                                                         char *stringp = ast_strdupa(var->value);
2580                                                         if (stringp) {
2581                                                                 char *confno_tmp = strsep(&stringp, "|,");
2582                                                                 int found = 0;
2583                                                                 if (!dynamic) {
2584                                                                         /* For static:  run through the list and see if this conference is empty */
2585                                                                         AST_LIST_LOCK(&confs);
2586                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2587                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2588                                                                                         /* The conference exists, therefore it's not empty */
2589                                                                                         found = 1;
2590                                                                                         break;
2591                                                                                 }
2592                                                                         }
2593                                                                         AST_LIST_UNLOCK(&confs);
2594                                                                         if (!found) {
2595                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2596                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2597                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2598                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2599                                                                                          * Case 3:  not empty_no_pin
2600                                                                                          */
2601                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2602                                                                                         break;
2603                                                                                         /* XXX the map is not complete (but we do have a confno) */
2604                                                                                 }
2605                                                                         }
2606                                                                 }
2607                                                         }
2608                                                 }
2609                                                 var = var->next;
2610                                         }
2611                                         ast_config_destroy(cfg);
2612                                 }
2613                         }
2614
2615                         /* Select first conference number not in use */
2616                         if (ast_strlen_zero(confno) && dynamic) {
2617                                 AST_LIST_LOCK(&confs);
2618                                 for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
2619                                         if (!conf_map[i]) {
2620                                                 snprintf(confno, sizeof(confno), "%d", i);
2621                                                 conf_map[i] = 1;
2622                                                 break;
2623                                         }
2624                                 }
2625                                 AST_LIST_UNLOCK(&confs);
2626                         }
2627
2628                         /* Not found? */
2629                         if (ast_strlen_zero(confno)) {
2630                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2631                                 if (!res)
2632                                         ast_waitstream(chan, "");
2633                         } else {
2634                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2635                                         if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
2636                                                 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2637                                                 if (!res) {
2638                                                         ast_waitstream(chan, "");
2639                                                         res = ast_say_digits(chan, confno_int, "", chan->language);
2640                                                 }
2641                                         }
2642                                 } else {
2643                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2644                                 }
2645                         }
2646                 }
2647
2648                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2649                         /* Prompt user for conference number */
2650                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2651                         if (res < 0) {
2652                                 /* Don't try to validate when we catch an error */
2653                                 confno[0] = '\0';
2654                                 allowretry = 0;
2655                                 break;
2656                         }
2657                 }
2658                 if (!ast_strlen_zero(confno)) {
2659                         /* Check the validity of the conference */
2660                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
2661                                 sizeof(the_pin), 1, &confflags);
2662                         if (!cnf) {
2663                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, 
2664                                         the_pin, sizeof(the_pin), 1, &confflags);
2665                         }
2666
2667                         if (!cnf) {
2668                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2669                                 if (!res)
2670                                         ast_waitstream(chan, "");
2671                                 res = -1;
2672                                 if (allowretry)
2673                                         confno[0] = '\0';
2674                         } else {
2675                                 if ((!ast_strlen_zero(cnf->pin) &&
2676                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2677                                     (!ast_strlen_zero(cnf->pinadmin) &&
2678                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2679                                         char pin[MAX_PIN] = "";
2680                                         int j;
2681
2682                                         /* Allow the pin to be retried up to 3 times */
2683                                         for (j = 0; j < 3; j++) {
2684                                                 if (*the_pin && (always_prompt == 0)) {
2685                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2686                                                         res = 0;
2687                                                 } else {
2688                                                         /* Prompt user for pin if pin is required */
2689                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2690                                                 }
2691                                                 if (res >= 0) {
2692                                                         if (!strcasecmp(pin, cnf->pin) ||
2693                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2694                                                              !strcasecmp(pin, cnf->pinadmin))) {
2695                                                                 /* Pin correct */
2696                                                                 allowretry = 0;
2697                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
2698                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
2699                                                                 /* Run the conference */
2700                                                                 res = conf_run(chan, cnf, confflags.flags, optargs);
2701                                                                 break;
2702                                                         } else {
2703                                                                 /* Pin invalid */
2704                                                                 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
2705                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
2706                                                                         ast_stopstream(chan);
2707                                                                 }
2708                                                                 else {
2709                                                                         ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2710                                                                         break;
2711                                                                 }
2712                                                                 if (res < 0)
2713                                                                         break;
2714                                                                 pin[0] = res;
2715                                                                 pin[1] = '\0';
2716                                                                 res = -1;
2717                                                                 if (allowretry)
2718                                                                         confno[0] = '\0';
2719                                                         }
2720                                                 } else {
2721                                                         /* failed when getting the pin */
2722                                                         res = -1;
2723                                                         allowretry = 0;
2724                                                         /* see if we need to get rid of the conference */
2725                                                         break;
2726                                                 }
2727
2728                                                 /* Don't retry pin with a static pin */
2729                                                 if (*the_pin && (always_prompt==0)) {
2730                                                         break;
2731                                                 }
2732                                         }
2733                                 } else {
2734                                         /* No pin required */
2735                                         allowretry = 0;
2736
2737                                         /* Run the conference */
2738                                         res = conf_run(chan, cnf, confflags.flags, optargs);
2739                                 }
2740                                 dispose_conf(cnf);
2741                                 cnf = NULL;
2742                         }
2743                 }
2744         } while (allowretry);
2745
2746         if (cnf)
2747                 dispose_conf(cnf);
2748
2749         ast_module_user_remove(u);
2750         
2751         return res;
2752 }
2753
2754 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident) 
2755 {
2756         struct ast_conf_user *user = NULL;
2757         int cid;
2758         
2759         sscanf(callerident, "%i", &cid);
2760         if (conf && callerident) {
2761                 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2762                         if (cid == user->user_no)
2763                                 return user;
2764                 }
2765         }
2766         return NULL;
2767 }
2768
2769 /*! \brief The MeetMeadmin application */
2770 /* MeetMeAdmin(confno, command, caller) */
2771 static int admin_exec(struct ast_channel *chan, void *data) {
2772         char *params;
2773         struct ast_conference *cnf;
2774         struct ast_conf_user *user = NULL;
2775         struct ast_module_user *u;
2776         AST_DECLARE_APP_ARGS(args,
2777                 AST_APP_ARG(confno);
2778                 AST_APP_ARG(command);
2779                 AST_APP_ARG(user);
2780         );
2781
2782         if (ast_strlen_zero(data)) {
2783                 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
2784                 return -1;
2785         }
2786
2787         u = ast_module_user_add(chan);
2788
2789         params = ast_strdupa(data);
2790         AST_STANDARD_APP_ARGS(args, params);
2791
2792         if (!args.command) {
2793                 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2794                 ast_module_user_remove(u);
2795                 return -1;
2796         }
2797
2798         AST_LIST_LOCK(&confs);
2799         AST_LIST_TRAVERSE(&confs, cnf, list) {
2800                 if (!strcmp(cnf->confno, args.confno))
2801                         break;
2802         }
2803
2804         if (!cnf) {
2805                 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
2806                 AST_LIST_UNLOCK(&confs);
2807                 ast_module_user_remove(u);
2808                 return 0;
2809         }
2810
2811         ast_atomic_fetchadd_int(&cnf->refcount, 1);
2812
2813         if (args.user)
2814                 user = find_user(cnf, args.user);
2815
2816         switch (*args.command) {
2817         case 76: /* L: Lock */ 
2818                 cnf->locked = 1;
2819                 break;
2820         case 108: /* l: Unlock */ 
2821                 cnf->locked = 0;
2822                 break;
2823         case 75: /* K: kick all users */
2824                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2825                         user->adminflags |= ADMINFLAG_KICKME;
2826                 break;
2827         case 101: /* e: Eject last user*/
2828                 user = AST_LIST_LAST(&cnf->userlist);
2829                 if (!(user->userflags & CONFFLAG_ADMIN))
2830                         user->adminflags |= ADMINFLAG_KICKME;
2831                 else
2832                         ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
2833                 break;
2834         case 77: /* M: Mute */ 
2835                 if (user) {
2836                         user->adminflags |= ADMINFLAG_MUTED;
2837                 } else
2838                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2839                 break;
2840         case 78: /* N: Mute all (non-admin) users */
2841                 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
2842                         if (!(user->userflags & CONFFLAG_ADMIN))
2843                                 user->adminflags |= ADMINFLAG_MUTED;
2844                 }
2845                 break;                                  
2846         case 109: /* m: Unmute */ 
2847                 if (user) {
2848                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2849                 } else
2850                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2851                 break;
2852         case 110: /* n: Unmute all users */
2853                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2854                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2855                 break;
2856         case 107: /* k: Kick user */ 
2857                 if (user)
2858                         user->adminflags |= ADMINFLAG_KICKME;
2859                 else
2860                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2861                 break;
2862         case 118: /* v: Lower all users listen volume */
2863                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2864                         tweak_listen_volume(user, VOL_DOWN);
2865                 break;
2866         case 86: /* V: Raise all users listen volume */
2867                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2868                         tweak_listen_volume(user, VOL_UP);
2869                 break;
2870         case 115: /* s: Lower all users speaking volume */
2871                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2872                         tweak_talk_volume(user, VOL_DOWN);
2873                 break;
2874         case 83: /* S: Raise all users speaking volume */
2875                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2876                         tweak_talk_volume(user, VOL_UP);
2877                 break;
2878         case 82: /* R: Reset all volume levels */
2879                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2880                         reset_volumes(user);
2881                 break;
2882         case 114: /* r: Reset user's volume level */
2883                 if (user)
2884                         reset_volumes(user);
2885                 else
2886                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2887                 break;
2888         case 85: /* U: Raise user's listen volume */
2889                 if (user)
2890                         tweak_listen_volume(user, VOL_UP);
2891                 else
2892                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2893                 break;
2894         case 117: /* u: Lower user's listen volume */
2895                 if (user)
2896                         tweak_listen_volume(user, VOL_DOWN);
2897                 else
2898                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2899                 break;
2900         case 84: /* T: Raise user's talk volume */
2901                 if (user)
2902                         tweak_talk_volume(user, VOL_UP);
2903                 else
2904                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2905                 break;
2906         case 116: /* t: Lower user's talk volume */
2907                 if (user) 
2908                         tweak_talk_volume(user, VOL_DOWN);
2909                 else 
2910                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2911                 break;
2912         }
2913
2914         AST_LIST_UNLOCK(&confs);
2915
2916         dispose_conf(cnf);
2917
2918         ast_module_user_remove(u);
2919         
2920         return 0;
2921 }
2922
2923 /*--- channel_admin_exec: The MeetMeChannelAdmin application */
2924 /* MeetMeChannelAdmin(channel, command) */
2925 static int channel_admin_exec(struct ast_channel *chan, void *data) {
2926         char *params;
2927         struct ast_conference *conf = NULL;
2928         struct ast_conf_user *user = NULL;
2929         struct ast_module_user *u;
2930         AST_DECLARE_APP_ARGS(args,
2931                 AST_APP_ARG(channel);
2932                 AST_APP_ARG(command);
2933         );
2934
2935         if (ast_strlen_zero(data)) {
2936                 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
2937                 return -1;
2938         }
2939         
2940         u = ast_module_user_add(chan);
2941
2942         params = ast_strdupa(data);
2943         AST_STANDARD_APP_ARGS(args, params);
2944
2945         if (!args.channel) {
2946                 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
2947                 ast_module_user_remove(u);
2948                 return -1;
2949         }
2950
2951         if (!args.command) {
2952                 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
2953                 ast_module_user_remove(u);
2954                 return -1;
2955         }
2956
2957         AST_LIST_LOCK(&confs);
2958         AST_LIST_TRAVERSE(&confs, conf, list) {
2959                 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2960                         if (!strcmp(user->chan->name, args.channel))
2961                                 break;
2962                 }
2963         }
2964         
2965         if (!user) {
2966                 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
2967                 AST_LIST_UNLOCK(&confs);
2968                 ast_module_user_remove(u);
2969                 return 0;
2970         }
2971         
2972         /* perform the specified action */
2973         switch (*args.command) {
2974                 case 77: /* M: Mute */ 
2975                         user->adminflags |= ADMINFLAG_MUTED;
2976                         break;
2977                 case 109: /* m: Unmute */ 
2978                         user->adminflags &= ~ADMINFLAG_MUTED;
2979                         break;
2980                 case 107: /* k: Kick user */ 
2981                         user->adminflags |= ADMINFLAG_KICKME;
2982                         break;
2983                 default: /* unknown command */
2984                         ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
2985                         break;
2986         }
2987
2988         AST_LIST_UNLOCK(&confs);
2989
2990         ast_module_user_remove(u);
2991         
2992         return 0;
2993 }
2994
2995 static int meetmemute(struct mansession *s, const struct message *m, int mute)
2996 {
2997         struct ast_conference *conf;
2998         struct ast_conf_user *user;
2999         const char *confid = astman_get_header(m, "Meetme");
3000         char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
3001         int userno;
3002
3003         if (ast_strlen_zero(confid)) {
3004                 astman_send_error(s, m, "Meetme conference not specified");
3005                 return 0;
3006         }
3007
3008         if (ast_strlen_zero(userid)) {
3009                 astman_send_error(s, m, "Meetme user number not specified");
3010                 return 0;
3011         }
3012
3013         userno = strtoul(userid, &userid, 10);
3014
3015         if (*userid) {
3016                 astman_send_error(s, m, "Invalid user number");
3017                 return 0;
3018         }
3019
3020         /* Look in the conference list */
3021         AST_LIST_LOCK(&confs);
3022         AST_LIST_TRAVERSE(&confs, conf, list) {
3023                 if (!strcmp(confid, conf->confno))
3024                         break;
3025         }
3026
3027         if (!conf) {
3028                 AST_LIST_UNLOCK(&confs);
3029                 astman_send_error(s, m, "Meetme conference does not exist");
3030                 return 0;
3031         }
3032
3033         AST_LIST_TRAVERSE(&conf->userlist, user, list)
3034                 if (user->user_no == userno)
3035                         break;
3036
3037         if (!user) {
3038                 AST_LIST_UNLOCK(&confs);
3039                 astman_send_error(s, m, "User number not found");
3040                 return 0;
3041         }
3042
3043         if (mute)
3044                 user->adminflags |= ADMINFLAG_MUTED;    /* request user muting */
3045         else
3046                 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);   /* request user unmuting */
3047
3048         AST_LIST_UNLOCK(&confs);
3049
3050         ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, user->chan->name, user->chan->uniqueid);
3051
3052         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
3053         return 0;
3054 }
3055
3056 static int action_meetmemute(struct mansession *s, const struct message *m)
3057 {
3058         return meetmemute(s, m, 1);
3059 }
3060
3061 static int action_meetmeunmute(struct mansession *s, const struct message *m)
3062 {
3063         return meetmemute(s, m, 0);
3064 }
3065
3066 static void *recordthread(void *args)
3067 {
3068         struct ast_conference *cnf = args;
3069         struct ast_frame *f=NULL;
3070         int flags;
3071         struct ast_filestream *s=NULL;
3072         int res=0;
3073         int x;
3074         const char *oldrecordingfilename = NULL;
3075
3076         if (!cnf || !cnf->lchan) {
3077                 pthread_exit(0);
3078         }
3079
3080         ast_stopstream(cnf->lchan);
3081         flags = O_CREAT|O_TRUNC|O_WRONLY;
3082
3083
3084         cnf->recording = MEETME_RECORD_ACTIVE;
3085         while (ast_waitfor(cnf->lchan, -1) > -1) {
3086                 if (cnf->recording == MEETME_RECORD_TERMINATE) {
3087                         AST_LIST_LOCK(&confs);
3088                         AST_LIST_UNLOCK(&confs);
3089                         break;
3090                 }
3091                 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
3092                         s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
3093                         oldrecordingfilename = cnf->recordingfilename;
3094                 }
3095                 
3096                 f = ast_read(cnf->lchan);
3097                 if (!f) {
3098                         res = -1;
3099                         break;
3100                 }
3101                 if (f->frametype == AST_FRAME_VOICE) {
3102                         ast_mutex_lock(&cnf->listenlock);
3103                         for (x=0;x<AST_FRAME_BITS;x++) {
3104                                 /* Free any translations that have occured */
3105                                 if (cnf->transframe[x]) {
3106                                         ast_frfree(cnf->transframe[x]);
3107                                         cnf->transframe[x] = NULL;
3108                                 }
3109                         }
3110                         if (cnf->origframe)
3111                                 ast_frfree(cnf->origframe);
3112                         cnf->origframe = f;
3113                         ast_mutex_unlock(&cnf->listenlock);
3114                         if (s)
3115                                 res = ast_writestream(s, f);
3116                         if (res) {
3117                                 ast_frfree(f);
3118                                 break;
3119                         }
3120                 }
3121                 ast_frfree(f);
3122         }
3123         cnf->recording = MEETME_RECORD_OFF;
3124         if (s)
3125                 ast_closestream(s);
3126         
3127         pthread_exit(0);
3128 }
3129
3130 /*! \brief Callback for devicestate providers */
3131 static enum ast_device_state meetmestate(const char *data)
3132 {
3133         struct ast_conference *conf;
3134
3135         /* Find conference */
3136         AST_LIST_LOCK(&confs);
3137