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