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