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