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