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