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