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