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