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