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