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