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