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