Don't reload a configuration file if nothing has changed.
[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                                         } else {
1823                                                 ztc.confmode = ZT_CONF_CONF;
1824                                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1825                                                         ast_log(LOG_WARNING, "Error setting conference\n");
1826                                                         close(fd);
1827                                                         goto outrun;
1828                                                 }
1829                                         }
1830                                 } else if(currentmarked >= 1 && lastmarked == 0) {
1831                                         /* Marked user entered, so cancel timeout */
1832                                         timeout = 0;
1833                                         if (confflags & CONFFLAG_MONITOR)
1834                                                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1835                                         else if (confflags & CONFFLAG_TALKER)
1836                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1837                                         else
1838                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1839                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1840                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1841                                                 close(fd);
1842                                                 goto outrun;
1843                                         }
1844                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
1845                                                 ast_moh_stop(chan);
1846                                                 musiconhold = 0;
1847                                         }
1848                                         if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1849                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1850                                                         ast_waitstream(chan, "");
1851                                                 conf_play(chan, conf, ENTER);
1852                                         }
1853                                 }
1854                         }
1855
1856                         /* trying to add moh for single person conf */
1857                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1858                                 if (conf->users == 1) {
1859                                         if (musiconhold == 0) {
1860                                                 ast_moh_start(chan, NULL, NULL);
1861                                                 musiconhold = 1;
1862                                         } 
1863                                 } else {
1864                                         if (musiconhold) {
1865                                                 ast_moh_stop(chan);
1866                                                 musiconhold = 0;
1867                                         }
1868                                 }
1869                         }
1870                         
1871                         /* Leave if the last marked user left */
1872                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1873                                 if (confflags & CONFFLAG_KICK_CONTINUE)
1874                                         ret = 0;
1875                                 else
1876                                         ret = -1;
1877                                 break;
1878                         }
1879         
1880                         /* Check if my modes have changed */
1881
1882                         /* If I should be muted but am still talker, mute me */
1883                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1884                                 ztc.confmode ^= ZT_CONF_TALKER;
1885                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1886                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1887                                         ret = -1;
1888                                         break;
1889                                 }
1890
1891                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1892                                                 "Channel: %s\r\n"
1893                                                 "Uniqueid: %s\r\n"
1894                                                 "Meetme: %s\r\n"
1895                                                 "Usernum: %i\r\n"
1896                                                 "Status: on\r\n",
1897                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1898                         }
1899
1900                         /* If I should be un-muted but am not talker, un-mute me */
1901                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1902                                 ztc.confmode |= ZT_CONF_TALKER;
1903                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1904                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1905                                         ret = -1;
1906                                         break;
1907                                 }
1908
1909                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1910                                                 "Channel: %s\r\n"
1911                                                 "Uniqueid: %s\r\n"
1912                                                 "Meetme: %s\r\n"
1913                                                 "Usernum: %i\r\n"
1914                                                 "Status: off\r\n",
1915                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1916                         }
1917
1918                         /* If I have been kicked, exit the conference */
1919                         if (user->adminflags & ADMINFLAG_KICKME) {
1920                                 //You have been kicked.
1921                                 if (!(confflags & CONFFLAG_QUIET) && 
1922                                         !ast_streamfile(chan, "conf-kicked", chan->language)) {
1923                                         ast_waitstream(chan, "");
1924                                 }
1925                                 ret = 0;
1926                                 break;
1927                         }
1928
1929                         /* Perform an extra hangup check just in case */
1930                         if (ast_check_hangup(chan))
1931                                 break;
1932
1933                         if (c) {
1934                                 if (c->fds[0] != origfd) {
1935                                         if (using_pseudo) {
1936                                                 /* Kill old pseudo */
1937                                                 close(fd);
1938                                                 using_pseudo = 0;
1939                                         }
1940                                         ast_debug(1, "Ooh, something swapped out under us, starting over\n");
1941                                         retryzap = strcasecmp(c->tech->type, "Zap");
1942                                         user->zapchannel = !retryzap;
1943                                         goto zapretry;
1944                                 }
1945                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1946                                         f = ast_read_noaudio(c);
1947                                 else
1948                                         f = ast_read(c);
1949                                 if (!f)
1950                                         break;
1951                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1952                                         if (user->talk.actual)
1953                                                 ast_frame_adjust_volume(f, user->talk.actual);
1954
1955                                         {
1956                                                 int totalsilence;
1957
1958                                                 if (user->talking == -1)
1959                                                         user->talking = 0;
1960
1961                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1962                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1963                                                         user->talking = 1;
1964                                                         if (confflags & CONFFLAG_MONITORTALKER)
1965                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1966                                                                       "Channel: %s\r\n"
1967                                                                       "Uniqueid: %s\r\n"
1968                                                                       "Meetme: %s\r\n"
1969                                                                       "Usernum: %d\r\n"
1970                                                                       "Status: on\r\n",
1971                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1972                                                 }
1973                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1974                                                         user->talking = 0;
1975                                                         if (confflags & CONFFLAG_MONITORTALKER)
1976                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1977                                                                       "Channel: %s\r\n"
1978                                                                       "Uniqueid: %s\r\n"
1979                                                                       "Meetme: %s\r\n"
1980                                                                       "Usernum: %d\r\n"
1981                                                                       "Status: off\r\n",
1982                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1983                                                 }
1984                                         }
1985                                         if (using_pseudo) {
1986                                                 /* Absolutely do _not_ use careful_write here...
1987                                                    it is important that we read data from the channel
1988                                                    as fast as it arrives, and feed it into the conference.
1989                                                    The buffering in the pseudo channel will take care of any
1990                                                    timing differences, unless they are so drastic as to lose
1991                                                    audio frames (in which case carefully writing would only
1992                                                    have delayed the audio even further).
1993                                                 */
1994                                                 /* As it turns out, we do want to use careful write.  We just
1995                                                    don't want to block, but we do want to at least *try*
1996                                                    to write out all the samples.
1997                                                  */
1998                                                 if (user->talking)
1999                                                         careful_write(fd, f->data, f->datalen, 0);
2000                                         }
2001                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
2002                                         char tmp[2];
2003
2004                                         if (confflags & CONFFLAG_PASS_DTMF)
2005                                                 conf_queue_dtmf(conf, user, f);
2006
2007                                         tmp[0] = f->subclass;
2008                                         tmp[1] = '\0';
2009                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
2010                                                 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
2011                                                 ret = 0;
2012                                                 ast_frfree(f);
2013                                                 break;
2014                                         } else {
2015                                                 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
2016                                         }
2017                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
2018                                         char exitkey[2];
2019
2020                                         exitkey[0] = f->subclass;
2021                                         exitkey[1] = '\0';
2022                                         
2023                                         pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", exitkey);
2024                                                 
2025                                         if (confflags & CONFFLAG_PASS_DTMF)
2026                                                 conf_queue_dtmf(conf, user, f);
2027                                         ret = 0;
2028                                         ast_frfree(f);
2029                                         break;
2030                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
2031                                         if (confflags & CONFFLAG_PASS_DTMF)
2032                                                 conf_queue_dtmf(conf, user, f);
2033                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
2034                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2035                                                 close(fd);
2036                                                 ast_frfree(f);
2037                                                 goto outrun;
2038                                         }
2039
2040                                         /* if we are entering the menu, and the user has a channel-driver
2041                                            volume adjustment, clear it
2042                                         */
2043                                         if (!menu_active && user->talk.desired && !user->talk.actual)
2044                                                 set_talk_volume(user, 0);
2045
2046                                         if (musiconhold) {
2047                                                 ast_moh_stop(chan);
2048                                         }
2049                                         if ((confflags & CONFFLAG_ADMIN)) {
2050                                                 /* Admin menu */
2051                                                 if (!menu_active) {
2052                                                         menu_active = 1;
2053                                                         /* Record this sound! */
2054                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
2055                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2056                                                                 ast_stopstream(chan);
2057                                                         } else 
2058                                                                 dtmf = 0;
2059                                                 } else 
2060                                                         dtmf = f->subclass;
2061                                                 if (dtmf) {
2062                                                         switch(dtmf) {
2063                                                         case '1': /* Un/Mute */
2064                                                                 menu_active = 0;
2065
2066                                                                 /* for admin, change both admin and use flags */
2067                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
2068                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2069                                                                 else
2070                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2071
2072                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2073                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2074                                                                                 ast_waitstream(chan, "");
2075                                                                 } else {
2076                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2077                                                                                 ast_waitstream(chan, "");
2078                                                                 }
2079                                                                 break;
2080                                                         case '2': /* Un/Lock the Conference */
2081                                                                 menu_active = 0;
2082                                                                 if (conf->locked) {
2083                                                                         conf->locked = 0;
2084                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
2085                                                                                 ast_waitstream(chan, "");
2086                                                                 } else {
2087                                                                         conf->locked = 1;
2088                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
2089                                                                                 ast_waitstream(chan, "");
2090                                                                 }
2091                                                                 break;
2092                                                         case '3': /* Eject last user */
2093                                                                 menu_active = 0;
2094                                                                 usr = AST_LIST_LAST(&conf->userlist);
2095                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
2096                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
2097                                                                                 ast_waitstream(chan, "");
2098                                                                 } else 
2099                                                                         usr->adminflags |= ADMINFLAG_KICKME;
2100                                                                 ast_stopstream(chan);
2101                                                                 break;  
2102                                                         case '4':
2103                                                                 tweak_listen_volume(user, VOL_DOWN);
2104                                                                 break;
2105                                                         case '6':
2106                                                                 tweak_listen_volume(user, VOL_UP);
2107                                                                 break;
2108                                                         case '7':
2109                                                                 tweak_talk_volume(user, VOL_DOWN);
2110                                                                 break;
2111                                                         case '8':
2112                                                                 menu_active = 0;
2113                                                                 break;
2114                                                         case '9':
2115                                                                 tweak_talk_volume(user, VOL_UP);
2116                                                                 break;
2117                                                         default:
2118                                                                 menu_active = 0;
2119                                                                 /* Play an error message! */
2120                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2121                                                                         ast_waitstream(chan, "");
2122                                                                 break;
2123                                                         }
2124                                                 }
2125                                         } else {
2126                                                 /* User menu */
2127                                                 if (!menu_active) {
2128                                                         menu_active = 1;
2129                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
2130                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2131                                                                 ast_stopstream(chan);
2132                                                         } else
2133                                                                 dtmf = 0;
2134                                                 } else 
2135                                                         dtmf = f->subclass;
2136                                                 if (dtmf) {
2137                                                         switch(dtmf) {
2138                                                         case '1': /* Un/Mute */
2139                                                                 menu_active = 0;
2140
2141                                                                 /* user can only toggle the self-muted state */
2142                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2143
2144                                                                 /* they can't override the admin mute state */
2145                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2146                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2147                                                                                 ast_waitstream(chan, "");
2148                                                                 } else {
2149                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2150                                                                                 ast_waitstream(chan, "");
2151                                                                 }
2152                                                                 break;
2153                                                         case '4':
2154                                                                 tweak_listen_volume(user, VOL_DOWN);
2155                                                                 break;
2156                                                         case '6':
2157                                                                 tweak_listen_volume(user, VOL_UP);
2158                                                                 break;
2159                                                         case '7':
2160                                                                 tweak_talk_volume(user, VOL_DOWN);
2161                                                                 break;
2162                                                         case '8':
2163                                                                 menu_active = 0;
2164                                                                 break;
2165                                                         case '9':
2166                                                                 tweak_talk_volume(user, VOL_UP);
2167                                                                 break;
2168                                                         default:
2169                                                                 menu_active = 0;
2170                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2171                                                                         ast_waitstream(chan, "");
2172                                                                 break;
2173                                                         }
2174                                                 }
2175                                         }
2176                                         if (musiconhold)
2177                                                 ast_moh_start(chan, NULL, NULL);
2178
2179                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
2180                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2181                                                 close(fd);
2182                                                 ast_frfree(f);
2183                                                 goto outrun;
2184                                         }
2185
2186                                         conf_flush(fd, chan);
2187                                 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
2188                                         && confflags & CONFFLAG_PASS_DTMF) {
2189                                         conf_queue_dtmf(conf, user, f);
2190                                 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
2191                                         switch (f->subclass) {
2192                                         case AST_CONTROL_HOLD:
2193                                                 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
2194                                                 break;
2195                                         default:
2196                                                 break;
2197                                         }
2198                                 } else if (f->frametype == AST_FRAME_NULL) {
2199                                         /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2200                                 } else {
2201                                         ast_debug(1, 
2202                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2203                                                 chan->name, f->frametype, f->subclass);
2204                                 }
2205                                 ast_frfree(f);
2206                         } else if (outfd > -1) {
2207                                 res = read(outfd, buf, CONF_SIZE);
2208                                 if (res > 0) {
2209                                         memset(&fr, 0, sizeof(fr));
2210                                         fr.frametype = AST_FRAME_VOICE;
2211                                         fr.subclass = AST_FORMAT_SLINEAR;
2212                                         fr.datalen = res;
2213                                         fr.samples = res/2;
2214                                         fr.data = buf;
2215                                         fr.offset = AST_FRIENDLY_OFFSET;
2216                                         if ( !user->listen.actual && 
2217                                                 ((confflags & CONFFLAG_MONITOR) || 
2218                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
2219                                                  (!user->talking)) ) {
2220                                                 int index;
2221                                                 for (index=0;index<AST_FRAME_BITS;index++)
2222                                                         if (chan->rawwriteformat & (1 << index))
2223                                                                 break;
2224                                                 if (index >= AST_FRAME_BITS)
2225                                                         goto bailoutandtrynormal;
2226                                                 ast_mutex_lock(&conf->listenlock);
2227                                                 if (!conf->transframe[index]) {
2228                                                         if (conf->origframe) {
2229                                                                 if (!conf->transpath[index])
2230                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
2231                                                                 if (conf->transpath[index]) {
2232                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
2233                                                                         if (!conf->transframe[index])
2234                                                                                 conf->transframe[index] = &ast_null_frame;
2235                                                                 }
2236                                                         }
2237                                                 }
2238                                                 if (conf->transframe[index]) {
2239                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
2240                                                                 if (ast_write(chan, conf->transframe[index]))
2241                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2242                                                         }
2243                                                 } else {
2244                                                         ast_mutex_unlock(&conf->listenlock);
2245                                                         goto bailoutandtrynormal;
2246                                                 }
2247                                                 ast_mutex_unlock(&conf->listenlock);
2248                                         } else {
2249 bailoutandtrynormal:                                    
2250                                                 if (user->listen.actual)
2251                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
2252                                                 if (ast_write(chan, &fr) < 0) {
2253                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2254                                                 }
2255                                         }
2256                                 } else 
2257                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
2258                         }
2259                         lastmarked = currentmarked;
2260                 }
2261         }
2262
2263         if (musiconhold)
2264                 ast_moh_stop(chan);
2265         
2266         if (using_pseudo)
2267                 close(fd);
2268         else {
2269                 /* Take out of conference */
2270                 ztc.chan = 0;   
2271                 ztc.confno = 0;
2272                 ztc.confmode = 0;
2273                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
2274                         ast_log(LOG_WARNING, "Error setting conference\n");
2275                 }
2276         }
2277
2278         reset_volumes(user);
2279
2280         AST_LIST_LOCK(&confs);
2281         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
2282                 conf_play(chan, conf, LEAVE);
2283
2284         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
2285                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
2286                         if ((conf->chan) && (conf->users > 1)) {
2287                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
2288                                         ast_waitstream(conf->chan, "");
2289                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
2290                                         ast_waitstream(conf->chan, "");
2291                         }
2292                         ast_filedelete(user->namerecloc, NULL);
2293                 }
2294         }
2295         AST_LIST_UNLOCK(&confs);
2296
2297  outrun:
2298         AST_LIST_LOCK(&confs);
2299
2300         if (dsp)
2301                 ast_dsp_free(dsp);
2302         
2303         if (user->user_no) { /* Only cleanup users who really joined! */
2304                 now = time(NULL);
2305                 hr = (now - user->jointime) / 3600;
2306                 min = ((now - user->jointime) % 3600) / 60;
2307                 sec = (now - user->jointime) % 60;
2308
2309                 if (sent_event) {
2310                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
2311                                       "Channel: %s\r\n"
2312                                       "Uniqueid: %s\r\n"
2313                                       "Meetme: %s\r\n"
2314                                       "Usernum: %d\r\n"
2315                                       "CallerIDNum: %s\r\n"
2316                                       "CallerIDName: %s\r\n"
2317                                       "Duration: %ld\r\n",
2318                                       chan->name, chan->uniqueid, conf->confno, 
2319                                       user->user_no,
2320                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
2321                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
2322                                       (long)(now - user->jointime));
2323                 }
2324
2325                 conf->users--;
2326                 /* Update table */
2327                 snprintf(members, sizeof(members), "%d", conf->users);
2328                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2329                 if (confflags & CONFFLAG_MARKEDUSER) 
2330                         conf->markedusers--;
2331                 /* Remove ourselves from the list */
2332                 AST_LIST_REMOVE(&conf->userlist, user, list);
2333
2334                 /* Change any states */
2335                 if (!conf->users)
2336                         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
2337                 
2338                 /* Return the number of seconds the user was in the conf */
2339                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
2340                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
2341         }
2342         ast_free(user);
2343         AST_LIST_UNLOCK(&confs);
2344
2345         return ret;
2346 }
2347
2348 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
2349                                                  char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2350 {
2351         struct ast_variable *var;
2352         struct ast_conference *cnf;
2353
2354         /* Check first in the conference list */
2355         AST_LIST_LOCK(&confs);
2356         AST_LIST_TRAVERSE(&confs, cnf, list) {
2357                 if (!strcmp(confno, cnf->confno)) 
2358                         break;
2359         }
2360         if (cnf) {
2361                 cnf->refcount += refcount;
2362         }
2363         AST_LIST_UNLOCK(&confs);
2364
2365         if (!cnf) {
2366                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
2367                 
2368                 var = ast_load_realtime("meetme", "confno", confno, NULL);
2369
2370                 if (!var)
2371                         return NULL;
2372
2373                 while (var) {
2374                         if (!strcasecmp(var->name, "pin")) {
2375                                 pin = ast_strdupa(var->value);
2376                         } else if (!strcasecmp(var->name, "adminpin")) {
2377                                 pinadmin = ast_strdupa(var->value);
2378                         }
2379                         var = var->next;
2380                 }
2381                 ast_variables_destroy(var);
2382                 
2383                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
2384         }
2385
2386         if (cnf) {
2387                 if (confflags && !cnf->chan &&
2388                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2389                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2390                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2391                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2392                 }
2393                 
2394                 if (confflags && !cnf->chan &&
2395                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2396                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2397                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2398                 }
2399         }
2400
2401         return cnf;
2402 }
2403
2404
2405 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2406                                         char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2407 {
2408         struct ast_config *cfg;
2409         struct ast_variable *var;
2410         struct ast_flags config_flags = { 0 };
2411         struct ast_conference *cnf;
2412         char *parse;
2413         AST_DECLARE_APP_ARGS(args,
2414                 AST_APP_ARG(confno);
2415                 AST_APP_ARG(pin);
2416                 AST_APP_ARG(pinadmin);
2417         );
2418
2419         /* Check first in the conference list */
2420         ast_log(LOG_NOTICE,"The requested confno is '%s'?\n", confno);
2421         AST_LIST_LOCK(&confs);
2422         AST_LIST_TRAVERSE(&confs, cnf, list) {
2423                 ast_log(LOG_NOTICE,"Does conf %s match %s?\n", confno, cnf->confno);
2424                 if (!strcmp(confno, cnf->confno)) 
2425                         break;
2426         }
2427         if (cnf){
2428                 cnf->refcount += refcount;
2429         }
2430         AST_LIST_UNLOCK(&confs);
2431
2432         if (!cnf) {
2433                 if (dynamic) {
2434                         /* No need to parse meetme.conf */
2435                         ast_debug(1, "Building dynamic conference '%s'\n", confno);
2436                         if (dynamic_pin) {
2437                                 if (dynamic_pin[0] == 'q') {
2438                                         /* Query the user to enter a PIN */
2439                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
2440                                                 return NULL;
2441                                 }
2442                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
2443                         } else {
2444                                 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
2445                         }
2446                 } else {
2447                         /* Check the config */
2448                         cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
2449                         if (!cfg) {
2450                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2451                                 return NULL;
2452                         }
2453                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2454                                 if (strcasecmp(var->name, "conf"))
2455                                         continue;
2456                                 
2457                                 if (!(parse = ast_strdupa(var->value)))
2458                                         return NULL;
2459                                 
2460                                 AST_STANDARD_APP_ARGS(args, parse);
2461                                 ast_log(LOG_NOTICE,"Will conf %s match %s?\n", confno, args.confno);
2462                                 if (!strcasecmp(args.confno, confno)) {
2463                                         /* Bingo it's a valid conference */
2464                                         cnf = build_conf(args.confno,
2465                                                         S_OR(args.pin, ""),
2466                                                         S_OR(args.pinadmin, ""),
2467                                                         make, dynamic, refcount, chan);
2468                                         break;
2469                                 }
2470                         }
2471                         if (!var) {
2472                                 ast_debug(1, "%s isn't a valid conference\n", confno);
2473                         }
2474                         ast_config_destroy(cfg);
2475                 }
2476         } else if (dynamic_pin) {
2477                 /* Correct for the user selecting 'D' instead of 'd' to have
2478                    someone join into a conference that has already been created
2479                    with a pin. */
2480                 if (dynamic_pin[0] == 'q')
2481                         dynamic_pin[0] = '\0';
2482         }
2483
2484         if (cnf) {
2485                 if (confflags && !cnf->chan &&
2486                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2487                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2488                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2489                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2490                 }
2491                 
2492                 if (confflags && !cnf->chan &&
2493                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2494                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2495                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2496                 }
2497         }
2498
2499         return cnf;
2500 }
2501
2502 /*! \brief The MeetmeCount application */
2503 static int count_exec(struct ast_channel *chan, void *data)
2504 {
2505         int res = 0;
2506         struct ast_conference *conf;
2507         int count;
2508         char *localdata;
2509         char val[80] = "0"; 
2510         AST_DECLARE_APP_ARGS(args,
2511                 AST_APP_ARG(confno);
2512                 AST_APP_ARG(varname);
2513         );
2514
2515         if (ast_strlen_zero(data)) {
2516                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2517                 return -1;
2518         }
2519         
2520         if (!(localdata = ast_strdupa(data)))
2521                 return -1;
2522
2523         AST_STANDARD_APP_ARGS(args, localdata);
2524         
2525         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
2526
2527         if (conf) {
2528                 count = conf->users;
2529                 dispose_conf(conf);
2530                 conf = NULL;
2531         } else
2532                 count = 0;
2533
2534         if (!ast_strlen_zero(args.varname)){
2535                 /* have var so load it and exit */
2536                 snprintf(val, sizeof(val), "%d",count);
2537                 pbx_builtin_setvar_helper(chan, args.varname, val);
2538         } else {
2539                 if (chan->_state != AST_STATE_UP)
2540                         ast_answer(chan);
2541                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2542         }
2543
2544         return res;
2545 }
2546
2547 /*! \brief The meetme() application */
2548 static int conf_exec(struct ast_channel *chan, void *data)
2549 {
2550         int res=-1;
2551         char confno[MAX_CONFNUM] = "";
2552         int allowretry = 0;
2553         int retrycnt = 0;
2554         struct ast_conference *cnf = NULL;
2555         struct ast_flags confflags = {0}, config_flags = { 0 };
2556         int dynamic = 0;
2557         int empty = 0, empty_no_pin = 0;
2558         int always_prompt = 0;
2559         char *notdata, *info, the_pin[MAX_PIN] = "";
2560         AST_DECLARE_APP_ARGS(args,
2561                 AST_APP_ARG(confno);
2562                 AST_APP_ARG(options);
2563                 AST_APP_ARG(pin);
2564         );
2565         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2566
2567         if (ast_strlen_zero(data)) {
2568                 allowretry = 1;
2569                 notdata = "";
2570         } else {
2571                 notdata = data;
2572         }
2573         
2574         if (chan->_state != AST_STATE_UP)
2575                 ast_answer(chan);
2576
2577         info = ast_strdupa(notdata);
2578
2579         AST_STANDARD_APP_ARGS(args, info);      
2580
2581         if (args.confno) {
2582                 ast_copy_string(confno, args.confno, sizeof(confno));
2583                 if (ast_strlen_zero(confno)) {
2584                         allowretry = 1;
2585                 }
2586         }
2587         
2588         if (args.pin)
2589                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2590
2591         if (args.options) {
2592                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2593                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2594                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2595                         strcpy(the_pin, "q");
2596
2597                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2598                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2599                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2600         }
2601
2602         do {
2603                 if (retrycnt > 3)
2604                         allowretry = 0;
2605                 if (empty) {
2606                         int i;
2607                         struct ast_config *cfg;
2608                         struct ast_variable *var;
2609                         int confno_int;
2610
2611                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2612                         if ((empty_no_pin) || (!dynamic)) {
2613                                 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
2614                                 if (cfg) {
2615                                         var = ast_variable_browse(cfg, "rooms");
2616                                         while (var) {
2617                                                 if (!strcasecmp(var->name, "conf")) {
2618                                                         char *stringp = ast_strdupa(var->value);
2619                                                         if (stringp) {
2620                                                                 char *confno_tmp = strsep(&stringp, "|,");
2621                                                                 int found = 0;
2622                                                                 if (!dynamic) {
2623                                                                         /* For static:  run through the list and see if this conference is empty */
2624                                                                         AST_LIST_LOCK(&confs);
2625                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2626                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2627                                                                                         /* The conference exists, therefore it's not empty */
2628                                                                                         found = 1;
2629                                                                                         break;
2630                                                                                 }
2631                                                                         }
2632                                                                         AST_LIST_UNLOCK(&confs);
2633                                                                         if (!found) {
2634                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2635                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2636                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2637                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2638                                                                                          * Case 3:  not empty_no_pin
2639                                                                                          */
2640                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2641                                                                                         break;
2642                                                                                         /* XXX the map is not complete (but we do have a confno) */
2643                                                                                 }
2644                                                                         }
2645                                                                 }
2646                                                         }
2647                                                 }
2648                                                 var = var->next;
2649                                         }
2650                                         ast_config_destroy(cfg);
2651                                 }
2652                         }
2653
2654                         /* Select first conference number not in use */
2655                         if (ast_strlen_zero(confno) && dynamic) {
2656                                 AST_LIST_LOCK(&confs);
2657                                 for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
2658                                         if (!conf_map[i]) {
2659                                                 snprintf(confno, sizeof(confno), "%d", i);
2660                                                 conf_map[i] = 1;
2661                                                 break;
2662                                         }
2663                                 }
2664                                 AST_LIST_UNLOCK(&confs);
2665                         }
2666
2667                         /* Not found? */
2668                         if (ast_strlen_zero(confno)) {
2669                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2670                                 if (!res)
2671                                         ast_waitstream(chan, "");
2672                         } else {
2673                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2674                                         if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
2675                                                 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2676                                                 if (!res) {
2677                                                         ast_waitstream(chan, "");
2678                                                         res = ast_say_digits(chan, confno_int, "", chan->language);
2679                                                 }
2680                                         }
2681                                 } else {
2682                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2683                                 }
2684                         }
2685                 }
2686
2687                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2688                         /* Prompt user for conference number */
2689                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2690                         if (res < 0) {
2691                                 /* Don't try to validate when we catch an error */
2692                                 confno[0] = '\0';
2693                                 allowretry = 0;
2694                                 break;
2695                         }
2696                 }
2697                 if (!ast_strlen_zero(confno)) {
2698                         /* Check the validity of the conference */
2699                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
2700                                 sizeof(the_pin), 1, &confflags);
2701                         if (!cnf) {
2702                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, 
2703                                         the_pin, sizeof(the_pin), 1, &confflags);
2704                         }
2705
2706                         if (!cnf) {
2707                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2708                                 if (!res)
2709                                         ast_waitstream(chan, "");
2710                                 res = -1;
2711                                 if (allowretry)
2712                                         confno[0] = '\0';
2713                         } else {
2714                                 if ((!ast_strlen_zero(cnf->pin) &&
2715                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2716                                     (!ast_strlen_zero(cnf->pinadmin) &&
2717                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2718                                         char pin[MAX_PIN] = "";
2719                                         int j;
2720
2721                                         /* Allow the pin to be retried up to 3 times */
2722                                         for (j = 0; j < 3; j++) {
2723                                                 if (*the_pin && (always_prompt == 0)) {
2724                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2725                                                         res = 0;
2726                                                 } else {
2727                                                         /* Prompt user for pin if pin is required */
2728                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2729                                                 }
2730                                                 if (res >= 0) {
2731                                                         if (!strcasecmp(pin, cnf->pin) ||
2732                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2733                                                              !strcasecmp(pin, cnf->pinadmin))) {
2734                                                                 /* Pin correct */
2735                                                                 allowretry = 0;
2736