9ca81eb081eea452f903c1343c34d6cef5241602
[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>dahdi</depend>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <dahdi/user.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 DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n"
232 "             must be present for conferencing to operate properly. In addition, the chan_dahdi\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-DAHDI 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 "";
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 dahdiconf;                            /*!< DAHDI 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         char *recordingfilename;                /*!< Filename to record the Conference into */
378         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 dahdichannel;                         /*!< Is a DAHDI 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 = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
643                         res = ioctl(fd, DAHDI_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 dahdi_confinfo dahdic = { 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 dahdi conference */
831         dahdic.confno = -1;
832         dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
833         cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
834         if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
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->dahdiconf = dahdic.confno;
844
845         /* Setup a new channel for playback of audio files */
846         cnf->chan = ast_request("DAHDI", 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                 dahdic.chan = 0;
851                 dahdic.confno = cnf->dahdiconf;
852                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
853                 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
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->dahdiconf, 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         struct ast_str *cmdline = NULL;
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
980         /* Max confno length */
981         if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
982                 return CLI_FAILURE;
983         }
984
985         if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) {
986                 /* 'MeetMe': List all the conferences */        
987                 int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise"));
988                 now = time(NULL);
989                 AST_LIST_LOCK(&confs);
990                 if (AST_LIST_EMPTY(&confs)) {
991                         if (!concise) {
992                                 ast_cli(a->fd, "No active MeetMe conferences.\n");
993                         }
994                         AST_LIST_UNLOCK(&confs);
995                         ast_free(cmdline);
996                         return CLI_SUCCESS;
997                 }
998                 if (!concise) {
999                         ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1000                 }
1001                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1002                         if (cnf->markedusers == 0) {
1003                                 ast_str_set(&cmdline, 0, "N/A ");
1004                         } else {
1005                                 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
1006                         }
1007                         hr = (now - cnf->start) / 3600;
1008                         min = ((now - cnf->start) % 3600) / 60;
1009                         sec = (now - cnf->start) % 60;
1010                         if (!concise) {
1011                                 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
1012                         } else {
1013                                 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1014                                         cnf->confno,
1015                                         cnf->users,
1016                                         cnf->markedusers,
1017                                         hr, min, sec,
1018                                         cnf->isdynamic,
1019                                         cnf->locked);
1020                         }
1021
1022                         total += cnf->users;
1023                 }
1024                 AST_LIST_UNLOCK(&confs);
1025                 if (!concise) {
1026                         ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1027                 }
1028                 ast_free(cmdline);
1029                 return CLI_SUCCESS;
1030         }
1031         if (a->argc < 3) {
1032                 ast_free(cmdline);
1033                 return CLI_SHOWUSAGE;
1034         }
1035
1036         ast_str_set(&cmdline, 0, "%s", a->argv[2]);     /* Argv 2: conference number */
1037         if (strstr(a->argv[1], "lock")) {
1038                 if (strcmp(a->argv[1], "lock") == 0) {
1039                         /* Lock */
1040                         ast_str_append(&cmdline, 0, ",L");
1041                 } else {
1042                         /* Unlock */
1043                         ast_str_append(&cmdline, 0, ",l");
1044                 }
1045         } else if (strstr(a->argv[1], "mute")) { 
1046                 if (a->argc < 4) {
1047                         ast_free(cmdline);
1048                         return CLI_SHOWUSAGE;
1049                 }
1050                 if (strcmp(a->argv[1], "mute") == 0) {
1051                         /* Mute */
1052                         if (strcmp(a->argv[3], "all") == 0) {
1053                                 ast_str_append(&cmdline, 0, ",N");
1054                         } else {
1055                                 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);       
1056                         }
1057                 } else {
1058                         /* Unmute */
1059                         if (strcmp(a->argv[3], "all") == 0) {
1060                                 ast_str_append(&cmdline, 0, ",n");
1061                         } else {
1062                                 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
1063                         }
1064                 }
1065         } else if (strcmp(a->argv[1], "kick") == 0) {
1066                 if (a->argc < 4) {
1067                         ast_free(cmdline);
1068                         return CLI_SHOWUSAGE;
1069                 }
1070                 if (strcmp(a->argv[3], "all") == 0) {
1071                         /* Kick all */
1072                         ast_str_append(&cmdline, 0, ",K");
1073                 } else {
1074                         /* Kick a single user */
1075                         ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
1076                 }
1077         } else if (strcmp(a->argv[1], "list") == 0) {
1078                 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
1079                 /* List all the users in a conference */
1080                 if (AST_LIST_EMPTY(&confs)) {
1081                         if (!concise) {
1082                                 ast_cli(a->fd, "No active conferences.\n");
1083                         }
1084                         ast_free(cmdline);
1085                         return CLI_SUCCESS;     
1086                 }
1087                 /* Find the right conference */
1088                 AST_LIST_LOCK(&confs);
1089                 AST_LIST_TRAVERSE(&confs, cnf, list) {
1090                         if (strcmp(cnf->confno, a->argv[2]) == 0) {
1091                                 break;
1092                         }
1093                 }
1094                 if (!cnf) {
1095                         if (!concise)
1096                                 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1097                         AST_LIST_UNLOCK(&confs);
1098                         ast_free(cmdline);
1099                         return CLI_SUCCESS;
1100                 }
1101                 /* Show all the users */
1102                 time(&now);
1103                 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
1104                         hr = (now - user->jointime) / 3600;
1105                         min = ((now - user->jointime) % 3600) / 60;
1106                         sec = (now - user->jointime) % 60;
1107                         if (!concise) {
1108                                 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1109                                         user->user_no,
1110                                         S_OR(user->chan->cid.cid_num, "<unknown>"),
1111                                         S_OR(user->chan->cid.cid_name, "<no name>"),
1112                                         user->chan->name,
1113                                         user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
1114                                         user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
1115                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1116                                         user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1117                                         istalking(user->talking), hr, min, sec); 
1118                         } else {
1119                                 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1120                                         user->user_no,
1121                                         S_OR(user->chan->cid.cid_num, ""),
1122                                         S_OR(user->chan->cid.cid_name, ""),
1123                                         user->chan->name,
1124                                         user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
1125                                         user->userflags  & CONFFLAG_MONITOR ? "1" : "",
1126                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1127                                         user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1128                                         user->talking, hr, min, sec);
1129                         }
1130                 }
1131                 if (!concise) {
1132                         ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1133                 }
1134                 AST_LIST_UNLOCK(&confs);
1135                 ast_free(cmdline);
1136                 return CLI_SUCCESS;
1137         } else {
1138                 ast_free(cmdline);
1139                 return CLI_SHOWUSAGE;
1140         }
1141
1142         ast_debug(1, "Cmdline: %s\n", cmdline->str);
1143
1144         admin_exec(NULL, cmdline->str);
1145         ast_free(cmdline);
1146
1147         return CLI_SUCCESS;
1148 }
1149
1150 static const char *sla_hold_str(unsigned int hold_access)
1151 {
1152         const char *hold = "Unknown";
1153
1154         switch (hold_access) {
1155         case SLA_HOLD_OPEN:
1156                 hold = "Open";
1157                 break;
1158         case SLA_HOLD_PRIVATE:
1159                 hold = "Private";
1160         default:
1161                 break;
1162         }
1163
1164         return hold;
1165 }
1166
1167 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1168 {
1169         const struct sla_trunk *trunk;
1170
1171         switch (cmd) {
1172         case CLI_INIT:
1173                 e->command = "sla show trunks";
1174                 e->usage =
1175                         "Usage: sla show trunks\n"
1176                         "       This will list all trunks defined in sla.conf\n";
1177                 return NULL;
1178         case CLI_GENERATE:
1179                 return NULL;
1180         }
1181
1182         ast_cli(a->fd, "\n"
1183                     "=============================================================\n"
1184                     "=== Configured SLA Trunks ===================================\n"
1185                     "=============================================================\n"
1186                     "===\n");
1187         AST_RWLIST_RDLOCK(&sla_trunks);
1188         AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
1189                 struct sla_station_ref *station_ref;
1190                 char ring_timeout[16] = "(none)";
1191                 if (trunk->ring_timeout)
1192                         snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
1193                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1194                             "=== Trunk Name:       %s\n"
1195                             "=== ==> Device:       %s\n"
1196                             "=== ==> AutoContext:  %s\n"
1197                             "=== ==> RingTimeout:  %s\n"
1198                             "=== ==> BargeAllowed: %s\n"
1199                             "=== ==> HoldAccess:   %s\n"
1200                             "=== ==> Stations ...\n",
1201                             trunk->name, trunk->device, 
1202                             S_OR(trunk->autocontext, "(none)"), 
1203                             ring_timeout,
1204                             trunk->barge_disabled ? "No" : "Yes",
1205                             sla_hold_str(trunk->hold_access));
1206                 AST_RWLIST_RDLOCK(&sla_stations);
1207                 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
1208                         ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
1209                 AST_RWLIST_UNLOCK(&sla_stations);
1210                 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
1211         }
1212         AST_RWLIST_UNLOCK(&sla_trunks);
1213         ast_cli(a->fd, "=============================================================\n\n");
1214
1215         return CLI_SUCCESS;
1216 }
1217
1218 static const char *trunkstate2str(enum sla_trunk_state state)
1219 {
1220 #define S(e) case e: return # e;
1221         switch (state) {
1222         S(SLA_TRUNK_STATE_IDLE)
1223         S(SLA_TRUNK_STATE_RINGING)
1224         S(SLA_TRUNK_STATE_UP)
1225         S(SLA_TRUNK_STATE_ONHOLD)
1226         S(SLA_TRUNK_STATE_ONHOLD_BYME)
1227         }
1228         return "Uknown State";
1229 #undef S
1230 }
1231
1232 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1233 {
1234         const struct sla_station *station;
1235
1236         switch (cmd) {
1237         case CLI_INIT:
1238                 e->command = "sla show stations";
1239                 e->usage =
1240                         "Usage: sla show stations\n"
1241                         "       This will list all stations defined in sla.conf\n";
1242                 return NULL;
1243         case CLI_GENERATE:
1244                 return NULL;
1245         }
1246
1247         ast_cli(a->fd, "\n" 
1248                     "=============================================================\n"
1249                     "=== Configured SLA Stations =================================\n"
1250                     "=============================================================\n"
1251                     "===\n");
1252         AST_RWLIST_RDLOCK(&sla_stations);
1253         AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1254                 struct sla_trunk_ref *trunk_ref;
1255                 char ring_timeout[16] = "(none)";
1256                 char ring_delay[16] = "(none)";
1257                 if (station->ring_timeout) {
1258                         snprintf(ring_timeout, sizeof(ring_timeout), 
1259                                 "%u", station->ring_timeout);
1260                 }
1261                 if (station->ring_delay) {
1262                         snprintf(ring_delay, sizeof(ring_delay), 
1263                                 "%u", station->ring_delay);
1264                 }
1265                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1266                             "=== Station Name:    %s\n"
1267                             "=== ==> Device:      %s\n"
1268                             "=== ==> AutoContext: %s\n"
1269                             "=== ==> RingTimeout: %s\n"
1270                             "=== ==> RingDelay:   %s\n"
1271                             "=== ==> HoldAccess:  %s\n"
1272                             "=== ==> Trunks ...\n",
1273                             station->name, station->device,
1274                             S_OR(station->autocontext, "(none)"), 
1275                             ring_timeout, ring_delay,
1276                             sla_hold_str(station->hold_access));
1277                 AST_RWLIST_RDLOCK(&sla_trunks);
1278                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1279                         if (trunk_ref->ring_timeout) {
1280                                 snprintf(ring_timeout, sizeof(ring_timeout),
1281                                         "%u", trunk_ref->ring_timeout);
1282                         } else
1283                                 strcpy(ring_timeout, "(none)");
1284                         if (trunk_ref->ring_delay) {
1285                                 snprintf(ring_delay, sizeof(ring_delay),
1286                                         "%u", trunk_ref->ring_delay);
1287                         } else
1288                                 strcpy(ring_delay, "(none)");
1289                                 ast_cli(a->fd, "===    ==> Trunk Name: %s\n"
1290                                     "===       ==> State:       %s\n"
1291                                     "===       ==> RingTimeout: %s\n"
1292                                     "===       ==> RingDelay:   %s\n",
1293                                     trunk_ref->trunk->name,
1294                                     trunkstate2str(trunk_ref->state),
1295                                     ring_timeout, ring_delay);
1296                 }
1297                 AST_RWLIST_UNLOCK(&sla_trunks);
1298                 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
1299                             "===\n");
1300         }
1301         AST_RWLIST_UNLOCK(&sla_stations);
1302         ast_cli(a->fd, "============================================================\n"
1303                     "\n");
1304
1305         return CLI_SUCCESS;
1306 }
1307
1308 static struct ast_cli_entry cli_meetme[] = {
1309         AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
1310         AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
1311         AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
1312 };
1313
1314 static void conf_flush(int fd, struct ast_channel *chan)
1315 {
1316         int x;
1317
1318         /* read any frames that may be waiting on the channel
1319            and throw them away
1320         */
1321         if (chan) {
1322                 struct ast_frame *f;
1323
1324                 /* when no frames are available, this will wait
1325                    for 1 millisecond maximum
1326                 */
1327                 while (ast_waitfor(chan, 1)) {
1328                         f = ast_read(chan);
1329                         if (f)
1330                                 ast_frfree(f);
1331                         else /* channel was hung up or something else happened */
1332                                 break;
1333                 }
1334         }
1335
1336         /* flush any data sitting in the pseudo channel */
1337         x = DAHDI_FLUSH_ALL;
1338         if (ioctl(fd, DAHDI_FLUSH, &x))
1339                 ast_log(LOG_WARNING, "Error flushing channel\n");
1340
1341 }
1342
1343 /* Remove the conference from the list and free it.
1344    We assume that this was called while holding conflock. */
1345 static int conf_free(struct ast_conference *conf)
1346 {
1347         int x;
1348         
1349         AST_LIST_REMOVE(&confs, conf, list);
1350         manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
1351
1352         if (conf->recording == MEETME_RECORD_ACTIVE) {
1353                 conf->recording = MEETME_RECORD_TERMINATE;
1354                 AST_LIST_UNLOCK(&confs);
1355                 while (1) {
1356                         usleep(1);
1357                         AST_LIST_LOCK(&confs);
1358                         if (conf->recording == MEETME_RECORD_OFF)
1359                                 break;
1360                         AST_LIST_UNLOCK(&confs);
1361                 }
1362         }
1363
1364         for (x = 0; x < AST_FRAME_BITS; x++) {
1365                 if (conf->transframe[x])
1366                         ast_frfree(conf->transframe[x]);
1367                 if (conf->transpath[x])
1368                         ast_translator_free_path(conf->transpath[x]);
1369         }
1370         if (conf->origframe)
1371                 ast_frfree(conf->origframe);
1372         if (conf->lchan)
1373                 ast_hangup(conf->lchan);
1374         if (conf->chan)
1375                 ast_hangup(conf->chan);
1376         if (conf->fd >= 0)
1377                 close(conf->fd);
1378         if (conf->recordingfilename) {
1379                 ast_free(conf->recordingfilename);
1380         }
1381         if (conf->recordingformat) {
1382                 ast_free(conf->recordingformat);
1383         }
1384         ast_mutex_destroy(&conf->playlock);
1385         ast_mutex_destroy(&conf->listenlock);
1386         ast_mutex_destroy(&conf->recordthreadlock);
1387         ast_free(conf);
1388
1389         return 0;
1390 }
1391
1392 static void conf_queue_dtmf(const struct ast_conference *conf,
1393         const struct ast_conf_user *sender, struct ast_frame *f)
1394 {
1395         struct ast_conf_user *user;
1396
1397         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
1398                 if (user == sender)
1399                         continue;
1400                 if (ast_write(user->chan, f) < 0)
1401                         ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
1402         }
1403 }
1404
1405 static void sla_queue_event_full(enum sla_event_type type, 
1406         struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
1407 {
1408         struct sla_event *event;
1409
1410         if (!(event = ast_calloc(1, sizeof(*event))))
1411                 return;
1412
1413         event->type = type;
1414         event->trunk_ref = trunk_ref;
1415         event->station = station;
1416
1417         if (!lock) {
1418                 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1419                 return;
1420         }
1421
1422         ast_mutex_lock(&sla.lock);
1423         AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1424         ast_cond_signal(&sla.cond);
1425         ast_mutex_unlock(&sla.lock);
1426 }
1427
1428 static void sla_queue_event_nolock(enum sla_event_type type)
1429 {
1430         sla_queue_event_full(type, NULL, NULL, 0);
1431 }
1432
1433 static void sla_queue_event(enum sla_event_type type)
1434 {
1435         sla_queue_event_full(type, NULL, NULL, 1);
1436 }
1437
1438 /*! \brief Queue a SLA event from the conference */
1439 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
1440         struct ast_conference *conf)
1441 {
1442         struct sla_station *station;
1443         struct sla_trunk_ref *trunk_ref = NULL;
1444         char *trunk_name;
1445
1446         trunk_name = ast_strdupa(conf->confno);
1447         strsep(&trunk_name, "_");
1448         if (ast_strlen_zero(trunk_name)) {
1449                 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
1450                 return;
1451         }
1452
1453         AST_RWLIST_RDLOCK(&sla_stations);
1454         AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1455                 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1456                         if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
1457                                 break;
1458                 }
1459                 if (trunk_ref)
1460                         break;
1461         }
1462         AST_RWLIST_UNLOCK(&sla_stations);
1463
1464         if (!trunk_ref) {
1465                 ast_debug(1, "Trunk not found for event!\n");
1466                 return;
1467         }
1468
1469         sla_queue_event_full(type, trunk_ref, station, 1);
1470 }
1471
1472 /* Decrement reference counts, as incremented by find_conf() */
1473 static int dispose_conf(struct ast_conference *conf)
1474 {
1475         int res = 0;
1476         int confno_int = 0;
1477
1478         AST_LIST_LOCK(&confs);
1479         if (ast_atomic_dec_and_test(&conf->refcount)) {
1480                 /* Take the conference room number out of an inuse state */
1481                 if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1482                         conf_map[confno_int] = 0;
1483                 conf_free(conf);
1484                 res = 1;
1485         }
1486         AST_LIST_UNLOCK(&confs);
1487
1488         return res;
1489 }
1490
1491 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
1492 {
1493         char *original_moh;
1494
1495         ast_channel_lock(chan);
1496         original_moh = ast_strdupa(chan->musicclass);
1497         ast_string_field_set(chan, musicclass, musicclass);
1498         ast_channel_unlock(chan);
1499
1500         ast_moh_start(chan, original_moh, NULL);
1501
1502         ast_channel_lock(chan);
1503         ast_string_field_set(chan, musicclass, original_moh);
1504         ast_channel_unlock(chan);
1505 }
1506
1507 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
1508 {
1509         struct ast_conf_user *user = NULL;
1510         struct ast_conf_user *usr = NULL;
1511         int fd;
1512         struct dahdi_confinfo dahdic, dahdic_empty;
1513         struct ast_frame *f;
1514         struct ast_channel *c;
1515         struct ast_frame fr;
1516         int outfd;
1517         int ms;
1518         int nfds;
1519         int res;
1520         int flags;
1521         int retrydahdi;
1522         int origfd;
1523         int musiconhold = 0;
1524         int firstpass = 0;
1525         int lastmarked = 0;
1526         int currentmarked = 0;
1527         int ret = -1;
1528         int x;
1529         int menu_active = 0;
1530         int talkreq_manager = 0;
1531         int using_pseudo = 0;
1532         int duration = 20;
1533         int hr, min, sec;
1534         int sent_event = 0;
1535         int checked = 0;
1536         int announcement_played = 0;
1537         struct timeval now;
1538         struct ast_dsp *dsp = NULL;
1539         struct ast_app *agi_app;
1540         char *agifile;
1541         const char *agifiledefault = "conf-background.agi", *tmpvar;
1542         char meetmesecs[30] = "";
1543         char exitcontext[AST_MAX_CONTEXT] = "";
1544         char recordingtmp[AST_MAX_EXTENSION] = "";
1545         char members[10] = "";
1546         int dtmf, opt_waitmarked_timeout = 0;
1547         time_t timeout = 0;
1548         struct dahdi_bufferinfo bi;
1549         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
1550         char *buf = __buf + AST_FRIENDLY_OFFSET;
1551         char *exitkeys = NULL;
1552         unsigned int calldurationlimit = 0;
1553         long timelimit = 0;
1554         long play_warning = 0;
1555         long warning_freq = 0;
1556         const char *warning_sound = NULL;
1557         const char *end_sound = NULL;
1558         char *parse;    
1559         long time_left_ms = 0;
1560         struct timeval nexteventts = { 0, };
1561         int to;
1562         int setusercount = 0;
1563
1564         if (!(user = ast_calloc(1, sizeof(*user))))
1565                 return ret;
1566
1567         /* Possible timeout waiting for marked user */
1568         if ((confflags & CONFFLAG_WAITMARKED) &&
1569                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
1570                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
1571                 (opt_waitmarked_timeout > 0)) {
1572                 timeout = time(NULL) + opt_waitmarked_timeout;
1573         }
1574                 
1575         if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
1576                 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
1577                 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
1578         }
1579         
1580         if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
1581                 char *limit_str, *warning_str, *warnfreq_str;
1582                 const char *var;
1583  
1584                 parse = optargs[OPT_ARG_DURATION_LIMIT];
1585                 limit_str = strsep(&parse, ":");
1586                 warning_str = strsep(&parse, ":");
1587                 warnfreq_str = parse;
1588  
1589                 timelimit = atol(limit_str);
1590                 if (warning_str)
1591                         play_warning = atol(warning_str);
1592                 if (warnfreq_str)
1593                         warning_freq = atol(warnfreq_str);
1594  
1595                 if (!timelimit) {
1596                         timelimit = play_warning = warning_freq = 0;
1597                         warning_sound = NULL;
1598                 } else if (play_warning > timelimit) {                  
1599                         if (!warning_freq) {
1600                                 play_warning = 0;
1601                         } else {
1602                                 while (play_warning > timelimit)
1603                                         play_warning -= warning_freq;
1604                                 if (play_warning < 1)
1605                                         play_warning = warning_freq = 0;
1606                         }
1607                 }
1608                 
1609                 ast_channel_lock(chan);
1610                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
1611                         var = ast_strdupa(var);
1612                 }
1613                 ast_channel_unlock(chan);
1614
1615                 warning_sound = var ? var : "timeleft";
1616                 
1617                 ast_channel_lock(chan);
1618                 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
1619                         var = ast_strdupa(var);
1620                 }
1621                 ast_channel_unlock(chan);
1622                 
1623                 end_sound = var ? var : NULL;
1624                         
1625                 /* undo effect of S(x) in case they are both used */
1626                 calldurationlimit = 0;
1627                 /* more efficient do it like S(x) does since no advanced opts */
1628                 if (!play_warning && !end_sound && timelimit) { 
1629                         calldurationlimit = timelimit / 1000;
1630                         timelimit = play_warning = warning_freq = 0;
1631                 } else {
1632                         ast_debug(2, "Limit Data for this call:\n");
1633                         ast_debug(2, "- timelimit     = %ld\n", timelimit);
1634                         ast_debug(2, "- play_warning  = %ld\n", play_warning);
1635                         ast_debug(2, "- warning_freq  = %ld\n", warning_freq);
1636                         ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
1637                         ast_debug(2, "- end_sound     = %s\n", end_sound ? end_sound : "UNDEF");
1638                 }
1639         }
1640
1641         /* Get exit keys */
1642         if ((confflags & CONFFLAG_KEYEXIT)) {
1643                 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
1644                         exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
1645                 else
1646                         exitkeys = ast_strdupa("#"); /* Default */
1647         }
1648         
1649         if (confflags & CONFFLAG_RECORDCONF) {
1650                 if (!conf->recordingfilename) {
1651                         const char *var;
1652                         ast_channel_lock(chan);
1653                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
1654                                 conf->recordingfilename = ast_strdup(var);
1655                         }
1656                         if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
1657                                 conf->recordingformat = ast_strdup(var);
1658                         }
1659                         ast_channel_unlock(chan);
1660                         if (!conf->recordingfilename) {
1661                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
1662                                 conf->recordingfilename = ast_strdup(recordingtmp);
1663                         }
1664                         if (!conf->recordingformat) {
1665                                 conf->recordingformat = ast_strdup("wav");
1666                         }
1667                         ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
1668                                     conf->confno, conf->recordingfilename, conf->recordingformat);
1669                 }
1670         }
1671
1672         ast_mutex_lock(&conf->recordthreadlock);
1673         if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
1674                 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
1675                 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
1676                 dahdic.chan = 0;
1677                 dahdic.confno = conf->dahdiconf;
1678                 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1679                 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
1680                         ast_log(LOG_WARNING, "Error starting listen channel\n");
1681                         ast_hangup(conf->lchan);
1682                         conf->lchan = NULL;
1683                 } else {
1684                         ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
1685                 }
1686         }
1687         ast_mutex_unlock(&conf->recordthreadlock);
1688
1689         time(&user->jointime);
1690         
1691         user->timelimit = timelimit;
1692         user->play_warning = play_warning;
1693         user->warning_freq = warning_freq;
1694         user->warning_sound = warning_sound;
1695         user->end_sound = end_sound;    
1696         
1697         if (calldurationlimit > 0) {
1698                 time(&user->kicktime);
1699                 user->kicktime = user->kicktime + calldurationlimit;
1700         }
1701         
1702         if (ast_tvzero(user->start_time))
1703                 user->start_time = ast_tvnow();
1704         time_left_ms = user->timelimit;
1705         
1706         if (user->timelimit) {
1707                 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
1708                 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
1709         }
1710
1711         if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
1712                 /* Sorry, but this conference is locked! */     
1713                 if (!ast_streamfile(chan, "conf-locked", chan->language))
1714                         ast_waitstream(chan, "");
1715                 goto outrun;
1716         }
1717
1718         ast_mutex_lock(&conf->playlock);
1719
1720         if (AST_LIST_EMPTY(&conf->userlist))
1721                 user->user_no = 1;
1722         else
1723                 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
1724
1725         if (rt_schedule && conf->maxusers)
1726                 if (user->user_no > conf->maxusers) {
1727                         /* Sorry, but this confernce has reached the participant limit! */      
1728                         if (!ast_streamfile(chan, "conf-full", chan->language))
1729                                 ast_waitstream(chan, "");
1730                         goto outrun;
1731                 }
1732
1733         AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
1734
1735         user->chan = chan;
1736         user->userflags = confflags;
1737         user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
1738         user->talking = -1;
1739
1740         ast_mutex_unlock(&conf->playlock);
1741
1742         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1743                 char destdir[PATH_MAX];
1744
1745                 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
1746
1747                 if (ast_mkdir(destdir, 0777) != 0) {
1748                         ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1749                         goto outrun;
1750                 }
1751
1752                 snprintf(user->namerecloc, sizeof(user->namerecloc),
1753                          "%s/meetme-username-%s-%d", destdir,
1754                          conf->confno, user->user_no);
1755                 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
1756                         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
1757                 else
1758                         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
1759                 if (res == -1)
1760                         goto outrun;
1761         }
1762
1763         ast_mutex_lock(&conf->playlock);
1764
1765         if (confflags & CONFFLAG_MARKEDUSER)
1766                 conf->markedusers++;
1767         conf->users++;
1768         if (rt_log_members) {
1769                 /* Update table */
1770                 snprintf(members, sizeof(members), "%d", conf->users);
1771                 ast_realtime_require_field("meetme",
1772                         "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
1773                         "members", RQ_UINTEGER1, strlen(members),
1774                         NULL);
1775                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
1776         }
1777         setusercount = 1;
1778
1779         /* This device changed state now - if this is the first user */
1780         if (conf->users == 1)
1781                 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
1782
1783         ast_mutex_unlock(&conf->playlock);
1784
1785         /* return the unique ID of the conference */
1786         pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
1787
1788         if (confflags & CONFFLAG_EXIT_CONTEXT) {
1789                 ast_channel_lock(chan);
1790                 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
1791                         ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
1792                 } else if (!ast_strlen_zero(chan->macrocontext)) {
1793                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
1794                 } else {
1795                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
1796                 }
1797                 ast_channel_unlock(chan);
1798         }
1799
1800         if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
1801                 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
1802                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1803                                 ast_waitstream(chan, "");
1804                 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
1805                         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
1806                                 ast_waitstream(chan, "");
1807         }
1808
1809         if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
1810                 int keepplaying = 1;
1811
1812                 if (conf->users == 2) { 
1813                         if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
1814                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1815                                 ast_stopstream(chan);
1816                                 if (res > 0)
1817                                         keepplaying = 0;
1818                                 else if (res == -1)
1819                                         goto outrun;
1820                         }
1821                 } else { 
1822                         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
1823                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1824                                 ast_stopstream(chan);
1825                                 if (res > 0)
1826                                         keepplaying = 0;
1827                                 else if (res == -1)
1828                                         goto outrun;
1829                         }
1830                         if (keepplaying) {
1831                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1832                                 if (res > 0)
1833                                         keepplaying = 0;
1834                                 else if (res == -1)
1835                                         goto outrun;
1836                         }
1837                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
1838                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1839                                 ast_stopstream(chan);
1840                                 if (res > 0)
1841                                         keepplaying = 0;
1842                                 else if (res == -1) 
1843                                         goto outrun;
1844                         }
1845                 }
1846         }
1847
1848         ast_indicate(chan, -1);
1849
1850         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1851                 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
1852                 goto outrun;
1853         }
1854
1855         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
1856                 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
1857                 goto outrun;
1858         }
1859
1860         retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
1861         user->dahdichannel = !retrydahdi;
1862
1863  dahdiretry:
1864         origfd = chan->fds[0];
1865         if (retrydahdi) {
1866                 fd = open("/dev/dahdi/pseudo", O_RDWR);
1867                 if (fd < 0) {
1868                         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1869                         goto outrun;
1870                 }
1871                 using_pseudo = 1;
1872                 /* Make non-blocking */
1873                 flags = fcntl(fd, F_GETFL);
1874                 if (flags < 0) {
1875                         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
1876                         close(fd);
1877                         goto outrun;
1878                 }
1879                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
1880                         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
1881                         close(fd);
1882                         goto outrun;
1883                 }
1884                 /* Setup buffering information */
1885                 memset(&bi, 0, sizeof(bi));
1886                 bi.bufsize = CONF_SIZE / 2;
1887                 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
1888                 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
1889                 bi.numbufs = audio_buffers;
1890                 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
1891                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
1892                         close(fd);
1893                         goto outrun;
1894                 }
1895                 x = 1;
1896                 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
1897                         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
1898                         close(fd);
1899                         goto outrun;
1900                 }
1901                 nfds = 1;
1902         } else {
1903                 /* XXX Make sure we're not running on a pseudo channel XXX */
1904                 fd = chan->fds[0];
1905                 nfds = 0;
1906         }
1907         memset(&dahdic, 0, sizeof(dahdic));
1908         memset(&dahdic_empty, 0, sizeof(dahdic_empty));
1909         /* Check to see if we're in a conference... */
1910         dahdic.chan = 0;        
1911         if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
1912                 ast_log(LOG_WARNING, "Error getting conference\n");
1913                 close(fd);
1914                 goto outrun;
1915         }
1916         if (dahdic.confmode) {
1917                 /* Whoa, already in a conference...  Retry... */
1918                 if (!retrydahdi) {
1919                         ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
1920                         retrydahdi = 1;
1921                         goto dahdiretry;
1922                 }
1923         }
1924         memset(&dahdic, 0, sizeof(dahdic));
1925         /* Add us to the conference */
1926         dahdic.chan = 0;        
1927         dahdic.confno = conf->dahdiconf;
1928
1929         ast_mutex_lock(&conf->playlock);
1930
1931         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
1932                 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
1933                         if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1934                                 ast_waitstream(conf->chan, "");
1935                         if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
1936                                 ast_waitstream(conf->chan, "");
1937                 }
1938         }
1939
1940         if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
1941                 dahdic.confmode = DAHDI_CONF_CONF;
1942         else if (confflags & CONFFLAG_MONITOR)
1943                 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
1944         else if (confflags & CONFFLAG_TALKER)
1945                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
1946         else 
1947                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
1948
1949         if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
1950                 ast_log(LOG_WARNING, "Error setting conference\n");
1951                 close(fd);
1952                 ast_mutex_unlock(&conf->playlock);
1953                 goto outrun;
1954         }
1955         ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
1956
1957         if (!sent_event) {
1958                 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
1959                                 "Channel: %s\r\n"
1960                                 "Uniqueid: %s\r\n"
1961                                 "Meetme: %s\r\n"
1962                                 "Usernum: %d\r\n"
1963                                 "CallerIDnum: %s\r\n"
1964                                 "CallerIDname: %s\r\n",
1965                                 chan->name, chan->uniqueid, conf->confno, 
1966                                 user->user_no,
1967                                 S_OR(user->chan->cid.cid_num, "<unknown>"),
1968                                 S_OR(user->chan->cid.cid_name, "<unknown>")
1969                                 );
1970                 sent_event = 1;
1971         }
1972
1973         if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
1974                 firstpass = 1;
1975                 if (!(confflags & CONFFLAG_QUIET))
1976                         if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
1977                                 conf_play(chan, conf, ENTER);
1978         }
1979
1980         ast_mutex_unlock(&conf->playlock);
1981
1982         conf_flush(fd, chan);
1983
1984         if (confflags & CONFFLAG_AGI) {
1985                 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1986                    or use default filename of conf-background.agi */
1987
1988                 ast_channel_lock(chan);
1989                 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
1990                         agifile = ast_strdupa(tmpvar);
1991                 } else {
1992                         agifile = ast_strdupa(agifiledefault);
1993                 }
1994                 ast_channel_unlock(chan);
1995                 
1996                 if (user->dahdichannel) {
1997                         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
1998                         x = 1;
1999                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2000                 }
2001                 /* Find a pointer to the agi app and execute the script */
2002                 agi_app = pbx_findapp("agi");
2003                 if (agi_app) {
2004                         ret = pbx_exec(chan, agi_app, agifile);
2005                 } else {
2006                         ast_log(LOG_WARNING, "Could not find application (agi)\n");
2007                         ret = -2;
2008                 }
2009                 if (user->dahdichannel) {
2010                         /*  Remove CONFMUTE mode on DAHDI channel */
2011                         x = 0;
2012                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2013                 }
2014         } else {
2015                 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
2016                         /*  Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
2017                         x = 1;
2018                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
2019                 }       
2020                 if (!(confflags & CONFFLAG_MONITOR) && !(dsp = ast_dsp_new())) {
2021                         ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
2022                         res = -1;
2023                 }
2024                 for (;;) {
2025                         int menu_was_active = 0;
2026
2027                         outfd = -1;
2028                         ms = -1;
2029                         now = ast_tvnow();
2030
2031                         if (rt_schedule) {
2032                                 if (now.tv_sec % 60 == 0) {
2033                                         if (!checked) {
2034                                                 if (now.tv_sec > conf->endtime) {
2035                                                         ast_verbose("Quitting time...\n");
2036                                                         goto outrun;
2037                                                 }
2038
2039                                                 if (!announcement_played && conf->endalert) {
2040                                                         if (now.tv_sec + conf->endalert > conf->endtime) {
2041                                                                 if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
2042                                                                         ast_waitstream(chan, "");
2043                                                                 ast_say_digits(chan, (now.tv_sec + conf->endalert - conf->endtime) / 60, "", chan->language);
2044                                                                 if (!ast_streamfile(chan, "minutes", chan->language))
2045                                                                         ast_waitstream(chan, "");
2046                                                                 announcement_played = 1;
2047                                                         }
2048                                                 }
2049                                                 checked = 1;
2050                                                 
2051                                         }
2052                                 } else {
2053                                         checked = 0;
2054                                 }
2055                         }
2056
2057                         if (user->kicktime && (user->kicktime <= now.tv_sec)) 
2058                                 break;
2059   
2060                         to = -1;
2061                         if (user->timelimit) {
2062                                 int minutes = 0, seconds = 0, remain = 0;
2063  
2064                                 to = ast_tvdiff_ms(nexteventts, now);
2065                                 if (to < 0)
2066                                         to = 0;
2067                                 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
2068                                 if (time_left_ms < to)
2069                                         to = time_left_ms;
2070         
2071                                 if (time_left_ms <= 0) {
2072                                         if (user->end_sound) {                                          
2073                                                 res = ast_streamfile(chan, user->end_sound, chan->language);
2074                                                 res = ast_waitstream(chan, "");
2075                                         }
2076                                         break;
2077                                 }
2078                                 
2079                                 if (!to) {
2080                                         if (time_left_ms >= 5000) {                                             
2081                                                 
2082                                                 remain = (time_left_ms + 500) / 1000;
2083                                                 if (remain / 60 >= 1) {
2084                                                         minutes = remain / 60;
2085                                                         seconds = remain % 60;
2086                                                 } else {
2087                                                         seconds = remain;
2088                                                 }
2089                                                 
2090                                                 /* force the time left to round up if appropriate */
2091                                                 if (user->warning_sound && user->play_warning) {
2092                                                         if (!strcmp(user->warning_sound, "timeleft")) {
2093                                                                 
2094                                                                 res = ast_streamfile(chan, "vm-youhave", chan->language);
2095                                                                 res = ast_waitstream(chan, "");
2096                                                                 if (minutes) {
2097                                                                         res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
2098                                                                         res = ast_streamfile(chan, "queue-minutes", chan->language);
2099                                                                         res = ast_waitstream(chan, "");
2100                                                                 }
2101                                                                 if (seconds) {
2102                                                                         res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
2103                                                                         res = ast_streamfile(chan, "queue-seconds", chan->language);
2104                                                                         res = ast_waitstream(chan, "");
2105                                                                 }
2106                                                         } else {
2107                                                                 res = ast_streamfile(chan, user->warning_sound, chan->language);
2108                                                                 res = ast_waitstream(chan, "");
2109                                                         }
2110                                                 }
2111                                         }
2112                                         if (user->warning_freq)
2113                                                 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
2114                                         else
2115                                                 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
2116                                 }
2117                         }
2118
2119                         now = ast_tvnow();
2120                         if (timeout && now.tv_sec >= timeout)
2121                                 break;
2122
2123                         /* if we have just exited from the menu, and the user had a channel-driver
2124                            volume adjustment, restore it
2125                         */
2126                         if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
2127                                 set_talk_volume(user, user->listen.desired);
2128
2129                         menu_was_active = menu_active;
2130
2131                         currentmarked = conf->markedusers;
2132                         if (!(confflags & CONFFLAG_QUIET) &&
2133                             (confflags & CONFFLAG_MARKEDUSER) &&
2134                             (confflags & CONFFLAG_WAITMARKED) &&
2135                             lastmarked == 0) {
2136                                 if (currentmarked == 1 && conf->users > 1) {
2137                                         ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
2138                                         if (conf->users - 1 == 1) {
2139                                                 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
2140                                                         ast_waitstream(chan, "");
2141                                         } else {
2142                                                 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
2143                                                         ast_waitstream(chan, "");
2144                                         }
2145                                 }
2146                                 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
2147                                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
2148                                                 ast_waitstream(chan, "");
2149                         }
2150
2151                         c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
2152
2153                         /* Update the struct with the actual confflags */
2154                         user->userflags = confflags;
2155
2156                         if (confflags & CONFFLAG_WAITMARKED) {
2157                                 if (currentmarked == 0) {
2158                                         if (lastmarked != 0) {
2159                                                 if (!(confflags & CONFFLAG_QUIET))
2160                                                         if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
2161                                                                 ast_waitstream(chan, "");
2162                                                 if (confflags & CONFFLAG_MARKEDEXIT) {
2163                                                         if (confflags & CONFFLAG_KICK_CONTINUE)
2164                                                                 ret = 0;
2165                                                         break;
2166                                                 } else {
2167                                                         dahdic.confmode = DAHDI_CONF_CONF;
2168                                                         if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2169                                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2170                                                                 close(fd);
2171                                                                 goto outrun;
2172                                                         }
2173                                                 }
2174                                         }
2175                                         if (!musiconhold && (confflags & CONFFLAG_MOH)) {
2176                                                 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
2177                                                 musiconhold = 1;
2178                                         }
2179                                 } else if (currentmarked >= 1 && lastmarked == 0) {
2180                                         /* Marked user entered, so cancel timeout */
2181                                         timeout = 0;
2182                                         if (confflags & CONFFLAG_MONITOR)
2183                                                 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
2184                                         else if (confflags & CONFFLAG_TALKER)
2185                                                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
2186                                         else
2187                                                 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
2188                                         if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2189                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2190                                                 close(fd);
2191                                                 goto outrun;
2192                                         }
2193                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
2194                                                 ast_moh_stop(chan);
2195                                                 musiconhold = 0;
2196                                         }
2197                                         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
2198                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
2199                                                         ast_waitstream(chan, "");
2200                                                 conf_play(chan, conf, ENTER);
2201                                         }
2202                                 }
2203                         }
2204
2205                         /* trying to add moh for single person conf */
2206                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
2207                                 if (conf->users == 1) {
2208                                         if (!musiconhold) {
2209                                                 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
2210                                                 musiconhold = 1;
2211                                         } 
2212                                 } else {
2213                                         if (musiconhold) {
2214                                                 ast_moh_stop(chan);
2215                                                 musiconhold = 0;
2216                                         }
2217                                 }
2218                         }
2219                         
2220                         /* Leave if the last marked user left */
2221                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
2222                                 if (confflags & CONFFLAG_KICK_CONTINUE)
2223                                         ret = 0;
2224                                 else
2225                                         ret = -1;
2226                                 break;
2227                         }
2228         
2229                         /* Check if my modes have changed */
2230
2231                         /* If I should be muted but am still talker, mute me */
2232                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
2233                                 dahdic.confmode ^= DAHDI_CONF_TALKER;
2234                                 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2235                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
2236                                         ret = -1;
2237                                         break;
2238                                 }
2239
2240                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
2241                                                 "Channel: %s\r\n"
2242                                                 "Uniqueid: %s\r\n"
2243                                                 "Meetme: %s\r\n"
2244                                                 "Usernum: %i\r\n"
2245                                                 "Status: on\r\n",
2246                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
2247                         }
2248
2249                         /* If I should be un-muted but am not talker, un-mute me */
2250                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
2251                                 dahdic.confmode |= DAHDI_CONF_TALKER;
2252                                 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2253                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
2254                                         ret = -1;
2255                                         break;
2256                                 }
2257
2258                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
2259                                                 "Channel: %s\r\n"
2260                                                 "Uniqueid: %s\r\n"
2261                                                 "Meetme: %s\r\n"
2262                                                 "Usernum: %i\r\n"
2263                                                 "Status: off\r\n",
2264                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
2265                         }
2266                         
2267                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
2268                                 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
2269                                 talkreq_manager = 1;
2270
2271                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
2272                                               "Channel: %s\r\n"
2273                                                               "Uniqueid: %s\r\n"
2274                                                               "Meetme: %s\r\n"
2275                                                               "Usernum: %i\r\n"
2276                                                               "Status: on\r\n",
2277                                                               chan->name, chan->uniqueid, conf->confno, user->user_no);
2278                         }
2279
2280                         
2281                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && 
2282                                 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
2283                                 talkreq_manager = 0;
2284                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest", 
2285                                               "Channel: %s\r\n"
2286                                                               "Uniqueid: %s\r\n"
2287                                                               "Meetme: %s\r\n"
2288                                                               "Usernum: %i\r\n"
2289                                                               "Status: off\r\n",
2290                                                              chan->name, chan->uniqueid, conf->confno, user->user_no);
2291                         }
2292                         
2293                         /* If I have been kicked, exit the conference */
2294                         if (user->adminflags & ADMINFLAG_KICKME) {
2295                                 /* You have been kicked. */
2296                                 if (!(confflags & CONFFLAG_QUIET) && 
2297                                         !ast_streamfile(chan, "conf-kicked", chan->language)) {
2298                                         ast_waitstream(chan, "");
2299                                 }
2300                                 ret = 0;
2301                                 break;
2302                         }
2303
2304                         /* Perform an extra hangup check just in case */
2305                         if (ast_check_hangup(chan))
2306                                 break;
2307
2308                         if (c) {
2309                                 char dtmfstr[2] = "";
2310
2311                                 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
2312                                         if (using_pseudo) {
2313                                                 /* Kill old pseudo */
2314                                                 close(fd);
2315                                                 using_pseudo = 0;
2316                                         }
2317                                         ast_debug(1, "Ooh, something swapped out under us, starting over\n");
2318                                         retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
2319                                         user->dahdichannel = !retrydahdi;
2320                                         goto dahdiretry;
2321                                 }
2322                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
2323                                         f = ast_read_noaudio(c);
2324                                 else
2325                                         f = ast_read(c);
2326                                 if (!f)
2327                                         break;
2328                                 if (f->frametype == AST_FRAME_DTMF) {
2329                                         dtmfstr[0] = f->subclass;
2330                                         dtmfstr[1] = '\0';
2331                                 }
2332
2333                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
2334                                         if (user->talk.actual)
2335                                                 ast_frame_adjust_volume(f, user->talk.actual);
2336
2337                                         if (!(confflags & CONFFLAG_MONITOR)) {
2338                                                 int totalsilence;
2339
2340                                                 if (user->talking == -1)
2341                                                         user->talking = 0;
2342
2343                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
2344                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
2345                                                         user->talking = 1;
2346                                                         if (confflags & CONFFLAG_MONITORTALKER)
2347                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
2348                                                                       "Channel: %s\r\n"
2349                                                                       "Uniqueid: %s\r\n"
2350                                                                       "Meetme: %s\r\n"
2351                                                                       "Usernum: %d\r\n"
2352                                                                       "Status: on\r\n",
2353                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
2354                                                 }
2355                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
2356                                                         user->talking = 0;
2357                                                         if (confflags & CONFFLAG_MONITORTALKER)
2358                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
2359                                                                       "Channel: %s\r\n"
2360                                                                       "Uniqueid: %s\r\n"
2361                                                                       "Meetme: %s\r\n"
2362                                                                       "Usernum: %d\r\n"
2363                                                                       "Status: off\r\n",
2364                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
2365                                                 }
2366                                         }
2367                                         if (using_pseudo) {
2368                                                 /* Absolutely do _not_ use careful_write here...
2369                                                    it is important that we read data from the channel
2370                                                    as fast as it arrives, and feed it into the conference.
2371                                                    The buffering in the pseudo channel will take care of any
2372                                                    timing differences, unless they are so drastic as to lose
2373                                                    audio frames (in which case carefully writing would only
2374                                                    have delayed the audio even further).
2375                                                 */
2376                                                 /* As it turns out, we do want to use careful write.  We just
2377                                                    don't want to block, but we do want to at least *try*
2378                                                    to write out all the samples.
2379                                                  */
2380                                                 if (user->talking)
2381                                                         careful_write(fd, f->data.ptr, f->datalen, 0);
2382                                         }
2383                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
2384                                         if (confflags & CONFFLAG_PASS_DTMF)
2385                                                 conf_queue_dtmf(conf, user, f);
2386                                         if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
2387                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2388                                                 close(fd);
2389                                                 ast_frfree(f);
2390                                                 goto outrun;
2391                                         }
2392
2393                                         /* if we are entering the menu, and the user has a channel-driver
2394                                            volume adjustment, clear it
2395                                         */
2396                                         if (!menu_active && user->talk.desired && !user->talk.actual)
2397                                                 set_talk_volume(user, 0);
2398
2399                                         if (musiconhold) {
2400                                                 ast_moh_stop(chan);
2401                                         }
2402                                         if ((confflags & CONFFLAG_ADMIN)) {
2403                                                 /* Admin menu */
2404                                                 if (!menu_active) {
2405                                                         menu_active = 1;
2406                                                         /* Record this sound! */
2407                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
2408                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2409                                                                 ast_stopstream(chan);
2410                                                         } else 
2411                                                                 dtmf = 0;
2412                                                 } else 
2413                                                         dtmf = f->subclass;
2414                                                 if (dtmf) {
2415                                                         switch(dtmf) {
2416                                                         case '1': /* Un/Mute */
2417                                                                 menu_active = 0;
2418
2419                                                                 /* for admin, change both admin and use flags */
2420                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
2421                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2422                                                                 else
2423                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2424
2425                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2426                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2427                                                                                 ast_waitstream(chan, "");
2428                                                                 } else {
2429                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2430                                                                                 ast_waitstream(chan, "");
2431                                                                 }
2432                                                                 break;
2433                                                         case '2': /* Un/Lock the Conference */
2434                                                                 menu_active = 0;
2435                                                                 if (conf->locked) {
2436                                                                         conf->locked = 0;
2437                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
2438                                                                                 ast_waitstream(chan, "");
2439                                                                 } else {
2440                                                                         conf->locked = 1;
2441                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
2442                                                                                 ast_waitstream(chan, "");
2443                                                                 }
2444                                                                 break;
2445                                                         case '3': /* Eject last user */
2446                                                                 menu_active = 0;
2447                                                                 usr = AST_LIST_LAST(&conf->userlist);
2448                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
2449                                                                         if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2450                                                                                 ast_waitstream(chan, "");
2451                                                                 } else 
2452                                                                         usr->adminflags |= ADMINFLAG_KICKME;
2453                                                                 ast_stopstream(chan);
2454                                                                 break;  
2455                                                         case '4':
2456                                                                 tweak_listen_volume(user, VOL_DOWN);
2457                                                                 break;
2458                                                         case '6':
2459                                                                 tweak_listen_volume(user, VOL_UP);
2460                                                                 break;
2461                                                         case '7':
2462                                                                 tweak_talk_volume(user, VOL_DOWN);
2463                                                                 break;
2464                                                         case '8':
2465                                                                 menu_active = 0;
2466                                                                 break;
2467                                                         case '9':
2468                                                                 tweak_talk_volume(user, VOL_UP);
2469                                                                 break;
2470                                                         default:
2471                                                                 menu_active = 0;
2472                                                                 /* Play an error message! */
2473                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2474                                                                         ast_waitstream(chan, "");
2475                                                                 break;
2476                                                         }
2477                                                 }
2478                                         } else {
2479                                                 /* User menu */
2480                                                 if (!menu_active) {
2481                                                         menu_active = 1;
2482                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
2483                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2484                                                                 ast_stopstream(chan);
2485                                                         } else
2486                                                                 dtmf = 0;
2487                                                 } else 
2488                                                         dtmf = f->subclass;
2489                                                 if (dtmf) {
2490                                                         switch(dtmf) {
2491                                                         case '1': /* Un/Mute */
2492                                                                 menu_active = 0;
2493
2494                                                                 /* user can only toggle the self-muted state */
2495                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2496
2497                                                                 /* they can't override the admin mute state */
2498                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2499                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2500                                                                                 ast_waitstream(chan, "");
2501                                                                 } else {
2502                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2503                                                                                 ast_waitstream(chan, "");
2504                                                                 }
2505                                                                 break;
2506                                                         case '2':
2507                                                                 menu_active = 0;
2508                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
2509                                                                         user->adminflags |= ADMINFLAG_T_REQUEST;
2510                                                                         
2511                                                                 if (user->adminflags & ADMINFLAG_T_REQUEST)
2512                                                                         if (!ast_streamfile(chan, "beep", chan->language))
2513                                                                                 ast_waitstream(chan, "");
2514                                                                 break;
2515                                                         case '4':
2516                                                                 tweak_listen_volume(user, VOL_DOWN);
2517                                                                 break;
2518                                                         case '6':
2519                                                                 tweak_listen_volume(user, VOL_UP);
2520                                                                 break;
2521                                                         case '7':
2522                                                                 tweak_talk_volume(user, VOL_DOWN);
2523                                                                 break;
2524                                                         case '8':
2525                                                                 menu_active = 0;
2526                                                                 break;
2527                                                         case '9':
2528                                                                 tweak_talk_volume(user, VOL_UP);
2529                                                                 break;
2530                                                         default:
2531                                                                 menu_active = 0;
2532                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2533                                                                         ast_waitstream(chan, "");
2534                                                                 break;
2535                                                         }
2536                                                 }
2537                                         }
2538                                         if (musiconhold)
2539                                                 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
2540
2541                                         if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2542                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2543                                                 close(fd);
2544                                                 ast_frfree(f);
2545                                                 goto outrun;
2546                                         }
2547
2548                                         conf_flush(fd, chan);
2549                                 /* Since this option could absorb dtmf meant for the previous (menu), we have to check this one last */
2550                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
2551                                         if (confflags & CONFFLAG_PASS_DTMF)
2552                                                 conf_queue_dtmf(conf, user, f);
2553
2554                                         if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
2555                                                 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
2556                                                 ret = 0;
2557                                                 ast_frfree(f);
2558                                                 break;
2559                                         } else {
2560                                                 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
2561                                         }
2562                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
2563                                         pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
2564                                                 
2565                                         if (confflags & CONFFLAG_PASS_DTMF)
2566                                                 conf_queue_dtmf(conf, user, f);
2567                                         ret = 0;
2568                                         ast_frfree(f);
2569                                         break;
2570                                 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
2571                                         && confflags & CONFFLAG_PASS_DTMF) {
2572                                         conf_queue_dtmf(conf, user, f);
2573                                 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
2574                                         switch (f->subclass) {
2575                                         case AST_CONTROL_HOLD:
2576                                                 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
2577                                                 break;
2578                                         default:
2579                                                 break;
2580                                         }
2581                                 } else if (f->frametype == AST_FRAME_NULL) {
2582                                         /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2583                                 } else {
2584                                         ast_debug(1, 
2585                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2586                                                 chan->name, f->frametype, f->subclass);
2587                                 }
2588                                 ast_frfree(f);
2589                         } else if (outfd > -1) {
2590                                 res = read(outfd, buf, CONF_SIZE);
2591                                 if (res > 0) {
2592                                         memset(&fr, 0, sizeof(fr));
2593                                         fr.frametype = AST_FRAME_VOICE;
2594                                         fr.subclass = AST_FORMAT_SLINEAR;
2595                                         fr.datalen = res;
2596                                         fr.samples = res / 2;
2597                                         fr.data.ptr = buf;
2598                                         fr.offset = AST_FRIENDLY_OFFSET;
2599                                         if (!user->listen.actual && 
2600                                                 ((confflags & CONFFLAG_MONITOR) || 
2601                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
2602                                                  (!user->talking)) ) {
2603                                                 int idx;
2604                                                 for (idx = 0; idx < AST_FRAME_BITS; idx++)
2605                                                         if (chan->rawwriteformat & (1 << idx))
2606                                                                 break;
2607                                                 if (idx >= AST_FRAME_BITS)
2608                                                         goto bailoutandtrynormal;
2609                                                 ast_mutex_lock(&conf->listenlock);
2610                                                 if (!conf->transframe[idx]) {
2611                                                         if (conf->origframe) {
2612                                                                 if (!conf->transpath[idx])
2613                                                                         conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
2614                                                                 if (conf->transpath[idx]) {
2615                                                                         conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
2616                                                                         if (!conf->transframe[idx])
2617                                                                                 conf->transframe[idx] = &ast_null_frame;
2618                                                                 }
2619                                                         }
2620                                                 }
2621                                                 if (conf->transframe[idx]) {
2622                                                         if (conf->transframe[idx]->frametype != AST_FRAME_NULL) {
2623                                                                 if (ast_write(chan, conf->transframe[idx]))
2624                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2625                                                         }
2626                                                 } else {
2627                                                         ast_mutex_unlock(&conf->listenlock);
2628                                                         goto bailoutandtrynormal;
2629                                                 }
2630                                                 ast_mutex_unlock(&conf->listenlock);
2631                                         } else {
2632 bailoutandtrynormal:                                    
2633                                                 if (user->listen.actual)
2634                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
2635                                                 if (ast_write(chan, &fr) < 0) {
2636                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2637                                                 }
2638                                         }
2639                                 } else 
2640                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
2641                         }
2642                         lastmarked = currentmarked;
2643                 }
2644         }
2645
2646         if (musiconhold)
2647                 ast_moh_stop(chan);
2648         
2649         if (using_pseudo)
2650                 close(fd);
2651         else {
2652                 /* Take out of conference */
2653                 dahdic.chan = 0;        
2654                 dahdic.confno = 0;
2655                 dahdic.confmode = 0;
2656                 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
2657                         ast_log(LOG_WARNING, "Error setting conference\n");
2658                 }
2659         }
2660
2661         reset_volumes(user);
2662
2663         AST_LIST_LOCK(&confs);
2664         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
2665                 conf_play(chan, conf, LEAVE);
2666
2667         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
2668                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
2669                         if ((conf->chan) && (conf->users > 1)) {
2670                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
2671                                         ast_waitstream(conf->chan, "");
2672                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
2673                                         ast_waitstream(conf->chan, "");
2674                         }
2675                         ast_filedelete(user->namerecloc, NULL);
2676                 }
2677         }
2678         AST_LIST_UNLOCK(&confs);
2679
2680  outrun:
2681         AST_LIST_LOCK(&confs);
2682
2683         if (dsp)
2684                 ast_dsp_free(dsp);
2685         
2686         if (user->user_no) { /* Only cleanup users who really joined! */
2687                 now = ast_tvnow();
2688                 hr = (now.tv_sec - user->jointime) / 3600;
2689                 min = ((now.tv_sec - user->jointime) % 3600) / 60;
2690                 sec = (now.tv_sec - user->jointime) % 60;
2691
2692                 if (sent_event) {
2693                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
2694                                       "Channel: %s\r\n"
2695                                       "Uniqueid: %s\r\n"
2696                                       "Meetme: %s\r\n"
2697                                       "Usernum: %d\r\n"
2698                                       "CallerIDNum: %s\r\n"
2699                                       "CallerIDName: %s\r\n"
2700                                       "Duration: %ld\r\n",
2701                                       chan->name, chan->uniqueid, conf->confno, 
2702                                       user->user_no,
2703                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
2704                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
2705                                       (long)(now.tv_sec - user->jointime));
2706                 }
2707
2708                 if (setusercount) {
2709                         conf->users--;
2710                         if (rt_log_members) {
2711                                 /* Update table */
2712                                 snprintf(members, sizeof(members), "%d", conf->users);
2713                                 ast_realtime_require_field("meetme",
2714                                         "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
2715                                         "members", RQ_UINTEGER1, strlen(members),
2716                                         NULL);
2717                                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2718                         }
2719                         if (confflags & CONFFLAG_MARKEDUSER) 
2720                                 conf->markedusers--;
2721                 }
2722                 /* Remove ourselves from the list */
2723                 AST_LIST_REMOVE(&conf->userlist, user, list);
2724
2725                 /* Change any states */
2726                 if (!conf->users)
2727                         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
2728                 
2729                 /* Return the number of seconds the user was in the conf */
2730                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
2731                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
2732         }
2733         ast_free(user);
2734         AST_LIST_UNLOCK(&confs);
2735
2736         return ret;
2737 }
2738
2739 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
2740                                 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags,
2741                                 char *optargs[], int *too_early)
2742 {
2743         struct ast_variable *var;
2744         struct ast_conference *cnf;
2745
2746         *too_early = 0;
2747
2748         /* Check first in the conference list */
2749         AST_LIST_LOCK(&confs);
2750         AST_LIST_TRAVERSE(&confs, cnf, list) {
2751                 if (!strcmp(confno, cnf->confno)) 
2752                         break;
2753         }
2754         if (cnf) {
2755                 cnf->refcount += refcount;
2756         }
2757         AST_LIST_UNLOCK(&confs);
2758
2759         if (!cnf) {
2760                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
2761                 int maxusers = 0;
2762                 struct timeval now;
2763                 char currenttime[19] = "";
2764                 char eatime[19] = "";
2765                 char useropts[32] = "";
2766                 char adminopts[32] = "";
2767                 struct ast_tm tm, etm;
2768                 struct timeval endtime = { .tv_sec = 0 };
2769
2770                 if (rt_schedule) {
2771                         now = ast_tvnow();
2772
2773                         ast_localtime(&now, &tm, NULL);
2774                         ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2775
2776                         ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
2777
2778                         var = ast_load_realtime("meetme", "confno",
2779                                 confno, "starttime <= ", currenttime, "endtime >= ",
2780                                 currenttime, NULL);
2781
2782                         if (!var && fuzzystart) {
2783                                 now = ast_tvnow();
2784                                 now.tv_sec += fuzzystart;
2785
2786                                 ast_localtime(&now, &tm, NULL);
2787                                 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2788                                 var = ast_load_realtime("meetme", "confno",
2789                                         confno, "starttime <= ", currenttime, "endtime >= ",
2790                                         currenttime, NULL);
2791                         }
2792
2793                         if (!var && earlyalert) {
2794                                 now = ast_tvnow();
2795                                 now.tv_sec += earlyalert;
2796                                 ast_localtime(&now, &etm, NULL);
2797                                 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
2798                                 var = ast_load_realtime("meetme", "confno",
2799                                         confno, "starttime <= ", eatime, "endtime >= ",
2800                                         currenttime, NULL);
2801                                 if (var)
2802                                         *too_early = 1;
2803                         }
2804
2805                 } else
2806                          var = ast_load_realtime("meetme", "confno", confno, NULL);
2807
2808                 if (!var)
2809                         return NULL;
2810
2811                 if (rt_schedule && *too_early) {
2812                         /* Announce that the caller is early and exit */
2813                         if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
2814                                 ast_waitstream(chan, "");
2815                         ast_variables_destroy(var);
2816                         return NULL;
2817                 }
2818
2819                 while (var) {
2820                         if (!strcasecmp(var->name, "pin")) {
2821                                 pin = ast_strdupa(var->value);
2822                         } else if (!strcasecmp(var->name, "adminpin")) {
2823                                 pinadmin = ast_strdupa(var->value);
2824                         } else if (!strcasecmp(var->name, "opts")) {
2825                                 ast_copy_string(useropts, var->value, sizeof(useropts));
2826                         } else if (!strcasecmp(var->name, "maxusers")) {
2827                                 maxusers = atoi(var->value);
2828                         } else if (!strcasecmp(var->name, "adminopts")) {
2829                                 ast_copy_string(adminopts, var->value, sizeof(adminopts));
2830                         } else if (!strcasecmp(var->name, "endtime")) {
2831                                 union {
2832                                         struct ast_tm atm;
2833                                         struct tm tm;
2834                                 } t = { { 0, }, };
2835                                 strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
2836                                 /* strptime does not determine if a time is
2837                                  * in DST or not.  Set tm_isdst to -1 to 
2838                                  * allow ast_mktime to adjust for DST 
2839                                  * if needed */
2840                                 t.tm.tm_isdst = -1; 
2841                                 endtime = ast_mktime(&t.atm, NULL);
2842                         }
2843
2844                         var = var->next;
2845                 }
2846
2847                 ast_variables_destroy(var);
2848
2849                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
2850
2851                 if (cnf) {
2852                         cnf->maxusers = maxusers;
2853                         cnf->endalert = endalert;
2854                         cnf->endtime = endtime.tv_sec;
2855                 }
2856         }
2857
2858         if (cnf) {
2859                 if (confflags && !cnf->chan &&
2860                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2861                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2862                         ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
2863                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2864                 }
2865                 
2866                 if (confflags && !cnf->chan &&
2867                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2868                         ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
2869                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2870                 }
2871         }
2872
2873         return cnf;
2874 }
2875
2876
2877 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2878                                         char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2879 {
2880         struct ast_config *cfg;
2881         struct ast_variable *var;
2882         struct ast_flags config_flags = { 0 };
2883         struct ast_conference *cnf;
2884         char *parse;
2885         AST_DECLARE_APP_ARGS(args,
2886                 AST_APP_ARG(confno);
2887                 AST_APP_ARG(pin);
2888                 AST_APP_ARG(pinadmin);
2889         );
2890
2891         /* Check first in the conference list */
2892         ast_debug(1, "The requested confno is '%s'?\n", confno);
2893         AST_LIST_LOCK(&confs);
2894         AST_LIST_TRAVERSE(&confs, cnf, list) {
2895                 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
2896                 if (!strcmp(confno, cnf->confno)) 
2897                         break;
2898         }
2899         if (cnf) {
2900                 cnf->refcount += refcount;
2901         }
2902         AST_LIST_UNLOCK(&confs);
2903
2904         if (!cnf) {
2905                 if (dynamic) {
2906                         /* No need to parse meetme.conf */
2907                         ast_debug(1, "Building dynamic conference '%s'\n", confno);
2908                         if (dynamic_pin) {
2909                                 if (dynamic_pin[0] == 'q') {
2910                                         /* Query the user to enter a PIN */
2911                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
2912                                                 return NULL;
2913                                 }
2914                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
2915                         } else {
2916                                 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
2917                         }
2918                 } else {
2919                         /* Check the config */
2920                         cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
2921                         if (!cfg) {
2922                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2923                                 return NULL;
2924                         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
2925                                 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format.  Aborting.\n");
2926                                 return NULL;
2927                         }
2928                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2929                                 if (strcasecmp(var->name, "conf"))
2930                                         continue;
2931                                 
2932                                 if (!(parse = ast_strdupa(var->value)))
2933                                         return NULL;
2934                                 
2935                                 AST_STANDARD_APP_ARGS(args, parse);
2936                                 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
2937                                 if (!strcasecmp(args.confno, confno)) {
2938                                         /* Bingo it's a valid conference */
2939                                         cnf = build_conf(args.confno,
2940                                                         S_OR(args.pin, ""),
2941                                                         S_OR(args.pinadmin, ""),
2942                                                         make, dynamic, refcount, chan);
2943                                         break;
2944                                 }
2945                         }
2946                         if (!var) {
2947                                 ast_debug(1, "%s isn't a valid conference\n", confno);
2948                         }
2949                         ast_config_destroy(cfg);
2950                 }
2951         } else if (dynamic_pin) {
2952                 /* Correct for the user selecting 'D' instead of 'd' to have
2953                    someone join into a conference that has already been created
2954                    with a pin. */
2955                 if (dynamic_pin[0] == 'q')
2956                         dynamic_pin[0] = '\0';
2957         }
2958
2959         if (cnf) {
2960                 if (confflags && !cnf->chan &&
2961                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2962                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2963                         ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
2964                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2965                 }
2966                 
2967                 if (confflags && !cnf->chan &&
2968                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2969                         ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
2970                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2971                 }
2972         }
2973
2974         return cnf;
2975 }
2976
2977 /*! \brief The MeetmeCount application */
2978 static int count_exec(struct ast_channel *chan, void *data)
2979 {
2980         int res = 0;
2981         struct ast_conference *conf;
2982         int count;
2983         char *localdata;
2984         char val[80] = "0"; 
2985         AST_DECLARE_APP_ARGS(args,
2986                 AST_APP_ARG(confno);
2987                 AST_APP_ARG(varname);
2988         );
2989
2990         if (ast_strlen_zero(data)) {
2991                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2992                 return -1;
2993         }
2994         
2995         if (!(localdata = ast_strdupa(data)))
2996                 return -1;
2997
2998         AST_STANDARD_APP_ARGS(args, localdata);
2999         
3000         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
3001
3002         if (conf) {
3003                 count = conf->users;
3004                 dispose_conf(conf);
3005                 conf = NULL;
3006         } else
3007                 count = 0;
3008
3009         if (!ast_strlen_zero(args.varname)) {
3010                 /* have var so load it and exit */
3011                 snprintf(val, sizeof(val), "%d", count);
3012                 pbx_builtin_setvar_helper(chan, args.varname, val);
3013         } else {
3014                 if (chan->_state != AST_STATE_UP)
3015                         ast_answer(chan);
3016                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
3017         }
3018
3019         return res;
3020 }
3021
3022 /*! \brief The meetme() application */
3023 static int conf_exec(struct ast_channel *chan, void *data)
3024 {
3025         int res = -1;
3026         char confno[MAX_CONFNUM] = "";
3027         int allowretry = 0;
3028         int retrycnt = 0;
3029         struct ast_conference *cnf = NULL;
3030         struct ast_flags confflags = {0}, config_flags = { 0 };
3031         int dynamic = 0;
3032         int empty = 0, empty_no_pin = 0;
3033         int always_prompt = 0;
3034         char *notdata, *info, the_pin[MAX_PIN] = "";
3035         AST_DECLARE_APP_ARGS(args,
3036                 AST_APP_ARG(confno);
3037                 AST_APP_ARG(options);
3038                 AST_APP_ARG(pin);
3039         );
3040         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
3041
3042         if (ast_strlen_zero(data)) {
3043                 allowretry = 1;
3044                 notdata = "";
3045         } else {
3046                 notdata = data;
3047         }
3048         
3049         if (chan->_state != AST_STATE_UP)
3050                 ast_answer(chan);
3051
3052         info = ast_strdupa(notdata);
3053
3054         AST_STANDARD_APP_ARGS(args, info);      
3055
3056         if (args.confno) {
3057                 ast_copy_string(confno, args.confno, sizeof(confno));
3058                 if (ast_strlen_zero(confno)) {
3059                         allowretry = 1;
3060                 }
3061         }
3062         
3063         if (args.pin)
3064                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
3065
3066         if (args.options) {
3067                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
3068                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
3069                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
3070                         strcpy(the_pin, "q");
3071
3072                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
3073                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
3074                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
3075         }
3076
3077         do {
3078                 if (retrycnt > 3)
3079                         allowretry = 0;
3080                 if (empty) {
3081                         int i;
3082                         struct ast_config *cfg;
3083                         struct ast_variable *var;
3084                         int confno_int;
3085
3086                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
3087                         if ((empty_no_pin) || (!dynamic)) {
3088                                 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
3089                                 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
3090                                         var = ast_variable_browse(cfg, "rooms");
3091                                         while (var) {
3092                                                 if (!strcasecmp(var->name, "conf")) {
3093                                                         char *stringp = ast_strdupa(var->value);
3094                                                         if (stringp) {
3095               &