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