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