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