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