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