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