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