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