Merged revisions 58512 via svnmerge from
[asterisk/asterisk.git] / apps / app_meetme.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2007, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * SLA Implementation by:
9  * Russell Bryant <russell@digium.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21
22 /*! \file
23  *
24  * \brief Meet me conference bridge and Shared Line Appearances
25  *
26  * \author Mark Spencer <markster@digium.com>
27  * \author (SLA) Russell Bryant <russell@digium.com>
28  * 
29  * \ingroup applications
30  */
31
32 /*** MODULEINFO
33         <depend>zaptel</depend>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45
46 #include "asterisk/zapata.h"
47
48 #include "asterisk/lock.h"
49 #include "asterisk/file.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/module.h"
54 #include "asterisk/config.h"
55 #include "asterisk/app.h"
56 #include "asterisk/dsp.h"
57 #include "asterisk/musiconhold.h"
58 #include "asterisk/manager.h"
59 #include "asterisk/options.h"
60 #include "asterisk/cli.h"
61 #include "asterisk/say.h"
62 #include "asterisk/utils.h"
63 #include "asterisk/translate.h"
64 #include "asterisk/ulaw.h"
65 #include "asterisk/astobj.h"
66 #include "asterisk/devicestate.h"
67 #include "asterisk/dial.h"
68 #include "asterisk/causes.h"
69
70 #include "enter.h"
71 #include "leave.h"
72
73 #define CONFIG_FILE_NAME "meetme.conf"
74 #define SLA_CONFIG_FILE  "sla.conf"
75
76 /*! each buffer is 20ms, so this is 640ms total */
77 #define DEFAULT_AUDIO_BUFFERS  32
78
79 enum {
80         ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
81         ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
82         ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
83 };
84
85 #define MEETME_DELAYDETECTTALK     300
86 #define MEETME_DELAYDETECTENDTALK  1000
87
88 #define AST_FRAME_BITS  32
89
90 enum volume_action {
91         VOL_UP,
92         VOL_DOWN
93 };
94
95 enum entrance_sound {
96         ENTER,
97         LEAVE
98 };
99
100 enum recording_state {
101         MEETME_RECORD_OFF,
102         MEETME_RECORD_STARTED,
103         MEETME_RECORD_ACTIVE,
104         MEETME_RECORD_TERMINATE
105 };
106
107 #define CONF_SIZE  320
108
109 enum {
110         /*! user has admin access on the conference */
111         CONFFLAG_ADMIN = (1 << 0),
112         /*! If set the user can only receive audio from the conference */
113         CONFFLAG_MONITOR = (1 << 1),
114         /*! If set asterisk will exit conference when '#' is pressed */
115         CONFFLAG_POUNDEXIT = (1 << 2),
116         /*! If set asterisk will provide a menu to the user when '*' is pressed */
117         CONFFLAG_STARMENU = (1 << 3),
118         /*! If set the use can only send audio to the conference */
119         CONFFLAG_TALKER = (1 << 4),
120         /*! If set there will be no enter or leave sounds */
121         CONFFLAG_QUIET = (1 << 5),
122         /*! If set, when user joins the conference, they will be told the number 
123          *  of users that are already in */
124         CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
125         /*! Set to run AGI Script in Background */
126         CONFFLAG_AGI = (1 << 7),
127         /*! Set to have music on hold when user is alone in conference */
128         CONFFLAG_MOH = (1 << 8),
129         /*! If set the MeetMe will return if all marked with this flag left */
130         CONFFLAG_MARKEDEXIT = (1 << 9),
131         /*! If set, the MeetMe will wait until a marked user enters */
132         CONFFLAG_WAITMARKED = (1 << 10),
133         /*! If set, the MeetMe will exit to the specified context */
134         CONFFLAG_EXIT_CONTEXT = (1 << 11),
135         /*! If set, the user will be marked */
136         CONFFLAG_MARKEDUSER = (1 << 12),
137         /*! If set, user will be ask record name on entry of conference */
138         CONFFLAG_INTROUSER = (1 << 13),
139         /*! If set, the MeetMe will be recorded */
140         CONFFLAG_RECORDCONF = (1<< 14),
141         /*! If set, the user will be monitored if the user is talking or not */
142         CONFFLAG_MONITORTALKER = (1 << 15),
143         CONFFLAG_DYNAMIC = (1 << 16),
144         CONFFLAG_DYNAMICPIN = (1 << 17),
145         CONFFLAG_EMPTY = (1 << 18),
146         CONFFLAG_EMPTYNOPIN = (1 << 19),
147         CONFFLAG_ALWAYSPROMPT = (1 << 20),
148         /*! If set, treats talking users as muted users */
149         CONFFLAG_OPTIMIZETALKER = (1 << 21),
150         /*! If set, won't speak the extra prompt when the first person 
151          *  enters the conference */
152         CONFFLAG_NOONLYPERSON = (1 << 22),
153         /*! If set, user will be asked to record name on entry of conference 
154          *  without review */
155         CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
156         /*! If set, the user will be initially self-muted */
157         CONFFLAG_STARTMUTED = (1 << 24),
158         /*! Pass DTMF through the conference */
159         CONFFLAG_PASS_DTMF = (1 << 25),
160         CONFFLAG_SLA_STATION = (1 << 26),
161         CONFFLAG_SLA_TRUNK = (1 << 27),
162         /*! If set, the user should continue in the dialplan if kicked out */
163         CONFFLAG_KICK_CONTINUE = (1 << 28)
164 };
165
166 enum {
167         OPT_ARG_WAITMARKED = 0,
168         OPT_ARG_ARRAY_SIZE = 1,
169 };
170
171 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
172         AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
173         AST_APP_OPTION('a', CONFFLAG_ADMIN ),
174         AST_APP_OPTION('b', CONFFLAG_AGI ),
175         AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
176         AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
177         AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
178         AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
179         AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
180         AST_APP_OPTION('e', CONFFLAG_EMPTY ),
181         AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
182         AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
183         AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
184         AST_APP_OPTION('M', CONFFLAG_MOH ),
185         AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
186         AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
187         AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
188         AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
189         AST_APP_OPTION('q', CONFFLAG_QUIET ),
190         AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
191         AST_APP_OPTION('s', CONFFLAG_STARMENU ),
192         AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
193         AST_APP_OPTION('l', CONFFLAG_MONITOR ),
194         AST_APP_OPTION('t', CONFFLAG_TALKER ),
195         AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
196         AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
197         AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
198         AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
199 END_OPTIONS );
200
201 static const char *app = "MeetMe";
202 static const char *app2 = "MeetMeCount";
203 static const char *app3 = "MeetMeAdmin";
204 static const char *slastation_app = "SLAStation";
205 static const char *slatrunk_app = "SLATrunk";
206
207 static const char *synopsis = "MeetMe conference bridge";
208 static const char *synopsis2 = "MeetMe participant count";
209 static const char *synopsis3 = "MeetMe conference Administration";
210 static const char *slastation_synopsis = "Shared Line Appearance Station";
211 static const char *slatrunk_synopsis = "Shared Line Appearance Trunk";
212
213 static const char *descrip =
214 "  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
215 "conference.  If the conference number is omitted, the user will be prompted\n"
216 "to enter one.  User can exit the conference by hangup, or if the 'p' option\n"
217 "is specified, by pressing '#'.\n"
218 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
219 "             must be present for conferencing to operate properly. In addition, the chan_zap\n"
220 "             channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
221 "The option string may contain zero or more of the following characters:\n"
222 "      'a' -- set admin mode\n"
223 "      'A' -- set marked mode\n"
224 "      'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
225 "             Default: conf-background.agi  (Note: This does not work with\n"
226 "             non-Zap channels in the same conference)\n"
227 "      'c' -- announce user(s) count on joining a conference\n"
228 "      'C' -- continue in dialplan when kicked out of conference\n"
229 "      'd' -- dynamically add conference\n"
230 "      'D' -- dynamically add conference, prompting for a PIN\n"
231 "      'e' -- select an empty conference\n"
232 "      'E' -- select an empty pinless conference\n"
233 "      'F' -- Pass DTMF through the conference.  DTMF used to activate any\n"
234 "             conference features will not be passed through.\n"
235 "      'i' -- announce user join/leave with review\n"
236 "      'I' -- announce user join/leave without review\n"
237 "      'l' -- set listen only mode (Listen only, no talking)\n"
238 "      'm' -- set initially muted\n"
239 "      'M' -- enable music on hold when the conference has a single caller\n"
240 "      'o' -- set talker optimization - treats talkers who aren't speaking as\n"
241 "             being muted, meaning (a) No encode is done on transmission and\n"
242 "             (b) Received audio that is not registered as talking is omitted\n"
243 "             causing no buildup in background noise\n"
244 "      'p' -- allow user to exit the conference by pressing '#'\n"
245 "      'P' -- always prompt for the pin even if it is specified\n"
246 "      'q' -- quiet mode (don't play enter/leave sounds)\n"
247 "      'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
248 "             using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
249 "             meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
250 "             wav.\n"
251 "      's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
252 "      't' -- set talk only mode. (Talk only, no listening)\n"
253 "      'T' -- set talker detection (sent to manager interface and meetme list)\n"
254 "      'w[(<secs>)]'\n"
255 "          -- wait until the marked user enters the conference\n"
256 "      'x' -- close the conference when last marked user exits\n"
257 "      'X' -- allow user to exit the conference by entering a valid single\n"
258 "             digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
259 "             if that variable is not defined.\n"
260 "      '1' -- do not play message when first person enters\n";
261
262 static const char *descrip2 =
263 "  MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
264 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
265 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
266 "the channel, unless priority n+1 exists, in which case priority progress will\n"
267 "continue.\n"
268 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
269
270 static const char *descrip3 = 
271 "  MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
272 "      'e' -- Eject last user that joined\n"
273 "      'k' -- Kick one user out of conference\n"
274 "      'K' -- Kick all users out of conference\n"
275 "      'l' -- Unlock conference\n"
276 "      'L' -- Lock conference\n"
277 "      'm' -- Unmute one user\n"
278 "      'M' -- Mute one user\n"
279 "      'n' -- Unmute all users in the conference\n"
280 "      'N' -- Mute all non-admin users in the conference\n"
281 "      'r' -- Reset one user's volume settings\n"
282 "      'R' -- Reset all users volume settings\n"
283 "      's' -- Lower entire conference speaking volume\n"
284 "      'S' -- Raise entire conference speaking volume\n"
285 "      't' -- Lower one user's talk volume\n"
286 "      'T' -- Raise one user's talk volume\n"
287 "      'u' -- Lower one user's listen volume\n"
288 "      'U' -- Raise one user's listen volume\n"
289 "      'v' -- Lower entire conference listening volume\n"
290 "      'V' -- Raise entire conference listening volume\n"
291 "";
292
293 static const char *slastation_desc =
294 "  SLAStation():\n";
295
296 static const char *slatrunk_desc =
297 "  SLATrunk():\n";
298
299 #define MAX_CONFNUM 80
300 #define MAX_PIN     80
301
302 /*! \brief The MeetMe Conference object */
303 struct ast_conference {
304         ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
305         ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
306         char confno[MAX_CONFNUM];               /*!< Conference */
307         struct ast_channel *chan;               /*!< Announcements channel */
308         struct ast_channel *lchan;              /*!< Listen/Record channel */
309         int fd;                                 /*!< Announcements fd */
310         int zapconf;                            /*!< Zaptel Conf # */
311         int users;                              /*!< Number of active users */
312         int markedusers;                        /*!< Number of marked users */
313         time_t start;                           /*!< Start time (s) */
314         int refcount;                           /*!< reference count of usage */
315         enum recording_state recording:2;       /*!< recording status */
316         unsigned int isdynamic:1;               /*!< Created on the fly? */
317         unsigned int locked:1;                  /*!< Is the conference locked? */
318         pthread_t recordthread;                 /*!< thread for recording */
319         pthread_attr_t attr;                    /*!< thread attribute */
320         const char *recordingfilename;          /*!< Filename to record the Conference into */
321         const char *recordingformat;            /*!< Format to record the Conference in */
322         char pin[MAX_PIN];                      /*!< If protected by a PIN */
323         char pinadmin[MAX_PIN];                 /*!< If protected by a admin PIN */
324         struct ast_frame *transframe[32];
325         struct ast_frame *origframe;
326         struct ast_trans_pvt *transpath[32];
327         AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
328         AST_LIST_ENTRY(ast_conference) list;
329 };
330
331 static AST_LIST_HEAD_STATIC(confs, ast_conference);
332
333 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         sla_queue_event_full(type, trunk_ref, station, 1);
1306 }
1307
1308 /* Decrement reference counts, as incremented by find_conf() */
1309 static int dispose_conf(struct ast_conference *conf)
1310 {
1311         int res = 0;
1312
1313         AST_LIST_LOCK(&confs);
1314         if (ast_atomic_dec_and_test(&conf->refcount)) {
1315                 conf_free(conf);
1316                 res = 1;
1317         }
1318         AST_LIST_UNLOCK(&confs);
1319
1320         return res;
1321 }
1322
1323
1324 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
1325 {
1326         struct ast_conf_user *user = NULL;
1327         struct ast_conf_user *usr = NULL;
1328         int fd;
1329         struct zt_confinfo ztc, ztc_empty;
1330         struct ast_frame *f;
1331         struct ast_channel *c;
1332         struct ast_frame fr;
1333         int outfd;
1334         int ms;
1335         int nfds;
1336         int res;
1337         int flags;
1338         int retryzap;
1339         int origfd;
1340         int musiconhold = 0;
1341         int firstpass = 0;
1342         int lastmarked = 0;
1343         int currentmarked = 0;
1344         int ret = -1;
1345         int x;
1346         int menu_active = 0;
1347         int using_pseudo = 0;
1348         int duration=20;
1349         int hr, min, sec;
1350         int sent_event = 0;
1351         time_t now;
1352         struct ast_dsp *dsp=NULL;
1353         struct ast_app *app;
1354         const char *agifile;
1355         const char *agifiledefault = "conf-background.agi";
1356         char meetmesecs[30] = "";
1357         char exitcontext[AST_MAX_CONTEXT] = "";
1358         char recordingtmp[AST_MAX_EXTENSION] = "";
1359         char members[10] = "";
1360         int dtmf, opt_waitmarked_timeout = 0;
1361         time_t timeout = 0;
1362         ZT_BUFFERINFO bi;
1363         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
1364         char *buf = __buf + AST_FRIENDLY_OFFSET;
1365
1366         if (!(user = ast_calloc(1, sizeof(*user))))
1367                 return ret;
1368
1369         /* Possible timeout waiting for marked user */
1370         if ((confflags & CONFFLAG_WAITMARKED) &&
1371                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
1372                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
1373                 (opt_waitmarked_timeout > 0)) {
1374                 timeout = time(NULL) + opt_waitmarked_timeout;
1375         }
1376
1377         if (confflags & CONFFLAG_RECORDCONF) {
1378                 if (!conf->recordingfilename) {
1379                         conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
1380                         if (!conf->recordingfilename) {
1381                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
1382                                 conf->recordingfilename = ast_strdupa(recordingtmp);
1383                         }
1384                         conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
1385                         if (!conf->recordingformat) {
1386                                 snprintf(recordingtmp, sizeof(recordingtmp), "wav");
1387                                 conf->recordingformat = ast_strdupa(recordingtmp);
1388                         }
1389                         ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
1390                                     conf->confno, conf->recordingfilename, conf->recordingformat);
1391                 }
1392         }
1393
1394         if ((conf->recording == MEETME_RECORD_OFF) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
1395                 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
1396                 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
1397                 ztc.chan = 0;
1398                 ztc.confno = conf->zapconf;
1399                 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
1400                 if (ioctl(conf->lchan->fds[0], ZT_SETCONF, &ztc)) {
1401                         ast_log(LOG_WARNING, "Error starting listen channel\n");
1402                         ast_hangup(conf->lchan);
1403                         conf->lchan = NULL;
1404                 } else {
1405                         pthread_attr_init(&conf->attr);
1406                         pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
1407                         ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
1408                         pthread_attr_destroy(&conf->attr);
1409                 }
1410         }
1411
1412         time(&user->jointime);
1413
1414         if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
1415                 /* Sorry, but this conference is locked! */     
1416                 if (!ast_streamfile(chan, "conf-locked", chan->language))
1417                         ast_waitstream(chan, "");
1418                 goto outrun;
1419         }
1420
1421         if (confflags & CONFFLAG_MARKEDUSER)
1422                 conf->markedusers++;
1423       
1424         ast_mutex_lock(&conf->playlock);
1425
1426         if (AST_LIST_EMPTY(&conf->userlist))
1427                 user->user_no = 1;
1428         else
1429                 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
1430
1431         AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
1432
1433         user->chan = chan;
1434         user->userflags = confflags;
1435         user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
1436         user->talking = -1;
1437         conf->users++;
1438         /* Update table */
1439         snprintf(members, sizeof(members), "%d", conf->users);
1440         ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
1441
1442         /* This device changed state now - if this is the first user */
1443         if (conf->users == 1)
1444                 ast_device_state_changed("meetme:%s", conf->confno);
1445
1446         ast_mutex_unlock(&conf->playlock);
1447
1448         if (confflags & CONFFLAG_EXIT_CONTEXT) {
1449                 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
1450                         ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
1451                 else if (!ast_strlen_zero(chan->macrocontext)) 
1452                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
1453                 else
1454                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
1455         }
1456
1457         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1458                 snprintf(user->namerecloc, sizeof(user->namerecloc),
1459                          "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
1460                          conf->confno, user->user_no);
1461                 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
1462                         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
1463                 else
1464                         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
1465                 if (res == -1)
1466                         goto outrun;
1467         }
1468
1469         if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
1470                 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
1471                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1472                                 ast_waitstream(chan, "");
1473                 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
1474                         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
1475                                 ast_waitstream(chan, "");
1476         }
1477
1478         if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
1479                 int keepplaying = 1;
1480
1481                 if (conf->users == 2) { 
1482                         if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
1483                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1484                                 ast_stopstream(chan);
1485                                 if (res > 0)
1486                                         keepplaying=0;
1487                                 else if (res == -1)
1488                                         goto outrun;
1489                         }
1490                 } else { 
1491                         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
1492                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1493                                 ast_stopstream(chan);
1494                                 if (res > 0)
1495                                         keepplaying=0;
1496                                 else if (res == -1)
1497                                         goto outrun;
1498                         }
1499                         if (keepplaying) {
1500                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1501                                 if (res > 0)
1502                                         keepplaying=0;
1503                                 else if (res == -1)
1504                                         goto outrun;
1505                         }
1506                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
1507                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1508                                 ast_stopstream(chan);
1509                                 if (res > 0)
1510                                         keepplaying=0;
1511                                 else if (res == -1) 
1512                                         goto outrun;
1513                         }
1514                 }
1515         }
1516
1517         ast_indicate(chan, -1);
1518
1519         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1520                 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
1521                 goto outrun;
1522         }
1523
1524         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
1525                 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
1526                 goto outrun;
1527         }
1528
1529         retryzap = strcasecmp(chan->tech->type, "Zap");
1530         user->zapchannel = !retryzap;
1531
1532  zapretry:
1533         origfd = chan->fds[0];
1534         if (retryzap) {
1535                 fd = open("/dev/zap/pseudo", O_RDWR);
1536                 if (fd < 0) {
1537                         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1538                         goto outrun;
1539                 }
1540                 using_pseudo = 1;
1541                 /* Make non-blocking */
1542                 flags = fcntl(fd, F_GETFL);
1543                 if (flags < 0) {
1544                         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
1545                         close(fd);
1546                         goto outrun;
1547                 }
1548                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
1549                         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
1550                         close(fd);
1551                         goto outrun;
1552                 }
1553                 /* Setup buffering information */
1554                 memset(&bi, 0, sizeof(bi));
1555                 bi.bufsize = CONF_SIZE/2;
1556                 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
1557                 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
1558                 bi.numbufs = audio_buffers;
1559                 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
1560                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
1561                         close(fd);
1562                         goto outrun;
1563                 }
1564                 x = 1;
1565                 if (ioctl(fd, ZT_SETLINEAR, &x)) {
1566                         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
1567                         close(fd);
1568                         goto outrun;
1569                 }
1570                 nfds = 1;
1571         } else {
1572                 /* XXX Make sure we're not running on a pseudo channel XXX */
1573                 fd = chan->fds[0];
1574                 nfds = 0;
1575         }
1576         memset(&ztc, 0, sizeof(ztc));
1577         memset(&ztc_empty, 0, sizeof(ztc_empty));
1578         /* Check to see if we're in a conference... */
1579         ztc.chan = 0;   
1580         if (ioctl(fd, ZT_GETCONF, &ztc)) {
1581                 ast_log(LOG_WARNING, "Error getting conference\n");
1582                 close(fd);
1583                 goto outrun;
1584         }
1585         if (ztc.confmode) {
1586                 /* Whoa, already in a conference...  Retry... */
1587                 if (!retryzap) {
1588                         if (option_debug)
1589                                 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
1590                         retryzap = 1;
1591                         goto zapretry;
1592                 }
1593         }
1594         memset(&ztc, 0, sizeof(ztc));
1595         /* Add us to the conference */
1596         ztc.chan = 0;   
1597         ztc.confno = conf->zapconf;
1598
1599         ast_mutex_lock(&conf->playlock);
1600
1601         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
1602                 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
1603                         if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1604                                 ast_waitstream(conf->chan, "");
1605                         if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
1606                                 ast_waitstream(conf->chan, "");
1607                 }
1608         }
1609
1610         if (confflags & CONFFLAG_MONITOR)
1611                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1612         else if (confflags & CONFFLAG_TALKER)
1613                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1614         else 
1615                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1616
1617         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1618                 ast_log(LOG_WARNING, "Error setting conference\n");
1619                 close(fd);
1620                 ast_mutex_unlock(&conf->playlock);
1621                 goto outrun;
1622         }
1623         if (option_debug)
1624                 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
1625
1626         if (!sent_event) {
1627                 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
1628                               "Channel: %s\r\n"
1629                               "Uniqueid: %s\r\n"
1630                               "Meetme: %s\r\n"
1631                               "Usernum: %d\r\n",
1632                               chan->name, chan->uniqueid, conf->confno, user->user_no);
1633                 sent_event = 1;
1634         }
1635
1636         if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
1637                 firstpass = 1;
1638                 if (!(confflags & CONFFLAG_QUIET))
1639                         if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
1640                                 conf_play(chan, conf, ENTER);
1641         }
1642
1643         ast_mutex_unlock(&conf->playlock);
1644
1645         conf_flush(fd, chan);
1646
1647         if (confflags & CONFFLAG_AGI) {
1648                 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1649                    or use default filename of conf-background.agi */
1650
1651                 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
1652                 if (!agifile)
1653                         agifile = agifiledefault;
1654
1655                 if (user->zapchannel) {
1656                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
1657                         x = 1;
1658                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1659                 }
1660                 /* Find a pointer to the agi app and execute the script */
1661                 app = pbx_findapp("agi");
1662                 if (app) {
1663                         char *s = ast_strdupa(agifile);
1664                         ret = pbx_exec(chan, app, s);
1665                 } else {
1666                         ast_log(LOG_WARNING, "Could not find application (agi)\n");
1667                         ret = -2;
1668                 }
1669                 if (user->zapchannel) {
1670                         /*  Remove CONFMUTE mode on Zap channel */
1671                         x = 0;
1672                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1673                 }
1674         } else {
1675                 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
1676                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1677                         x = 1;
1678                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1679                 }       
1680                 if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER) && !(dsp = ast_dsp_new())) {
1681                         ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
1682                         res = -1;
1683                 }
1684                 for(;;) {
1685                         int menu_was_active = 0;
1686
1687                         outfd = -1;
1688                         ms = -1;
1689
1690                         if (timeout && time(NULL) >= timeout)
1691                                 break;
1692
1693                         /* if we have just exited from the menu, and the user had a channel-driver
1694                            volume adjustment, restore it
1695                         */
1696                         if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
1697                                 set_talk_volume(user, user->listen.desired);
1698
1699                         menu_was_active = menu_active;
1700
1701                         currentmarked = conf->markedusers;
1702                         if (!(confflags & CONFFLAG_QUIET) &&
1703                             (confflags & CONFFLAG_MARKEDUSER) &&
1704                             (confflags & CONFFLAG_WAITMARKED) &&
1705                             lastmarked == 0) {
1706                                 if (currentmarked == 1 && conf->users > 1) {
1707                                         ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1708                                         if (conf->users - 1 == 1) {
1709                                                 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
1710                                                         ast_waitstream(chan, "");
1711                                         } else {
1712                                                 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
1713                                                         ast_waitstream(chan, "");
1714                                         }
1715                                 }
1716                                 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
1717                                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1718                                                 ast_waitstream(chan, "");
1719                         }
1720
1721                         c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
1722                         
1723                         
1724                         /* Update the struct with the actual confflags */
1725                         user->userflags = confflags;
1726                         
1727                         if (confflags & CONFFLAG_WAITMARKED) {
1728                                 if(currentmarked == 0) {
1729                                         if (lastmarked != 0) {
1730                                                 if (!(confflags & CONFFLAG_QUIET))
1731                                                         if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
1732                                                                 ast_waitstream(chan, "");
1733                                                 if (confflags & CONFFLAG_MARKEDEXIT) {
1734                                                         if (confflags & CONFFLAG_KICK_CONTINUE)
1735                                                                 ret = 0;
1736                                                         break;
1737                                                 } else {
1738                                                         ztc.confmode = ZT_CONF_CONF;
1739                                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1740                                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1741                                                                 close(fd);
1742                                                                 goto outrun;
1743                                                         }
1744                                                 }
1745                                         }
1746                                         if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
1747                                                 ast_moh_start(chan, NULL, NULL);
1748                                                 musiconhold = 1;
1749                                         } else {
1750                                                 ztc.confmode = ZT_CONF_CONF;
1751                                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1752                                                         ast_log(LOG_WARNING, "Error setting conference\n");
1753                                                         close(fd);
1754                                                         goto outrun;
1755                                                 }
1756                                         }
1757                                 } else if(currentmarked >= 1 && lastmarked == 0) {
1758                                         /* Marked user entered, so cancel timeout */
1759                                         timeout = 0;
1760                                         if (confflags & CONFFLAG_MONITOR)
1761                                                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1762                                         else if (confflags & CONFFLAG_TALKER)
1763                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1764                                         else
1765                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1766                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1767                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1768                                                 close(fd);
1769                                                 goto outrun;
1770                                         }
1771                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
1772                                                 ast_moh_stop(chan);
1773                                                 musiconhold = 0;
1774                                         }
1775                                         if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1776                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1777                                                         ast_waitstream(chan, "");
1778                                                 conf_play(chan, conf, ENTER);
1779                                         }
1780                                 }
1781                         }
1782
1783                         /* trying to add moh for single person conf */
1784                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1785                                 if (conf->users == 1) {
1786                                         if (musiconhold == 0) {
1787                                                 ast_moh_start(chan, NULL, NULL);
1788                                                 musiconhold = 1;
1789                                         } 
1790                                 } else {
1791                                         if (musiconhold) {
1792                                                 ast_moh_stop(chan);
1793                                                 musiconhold = 0;
1794                                         }
1795                                 }
1796                         }
1797                         
1798                         /* Leave if the last marked user left */
1799                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1800                                 if (confflags & CONFFLAG_KICK_CONTINUE)
1801                                         ret = 0;
1802                                 else
1803                                         ret = -1;
1804                                 break;
1805                         }
1806         
1807                         /* Check if my modes have changed */
1808
1809                         /* If I should be muted but am still talker, mute me */
1810                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1811                                 ztc.confmode ^= ZT_CONF_TALKER;
1812                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1813                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1814                                         ret = -1;
1815                                         break;
1816                                 }
1817
1818                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1819                                                 "Channel: %s\r\n"
1820                                                 "Uniqueid: %s\r\n"
1821                                                 "Meetme: %s\r\n"
1822                                                 "Usernum: %i\r\n"
1823                                                 "Status: on\r\n",
1824                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1825                         }
1826
1827                         /* If I should be un-muted but am not talker, un-mute me */
1828                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1829                                 ztc.confmode |= ZT_CONF_TALKER;
1830                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1831                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1832                                         ret = -1;
1833                                         break;
1834                                 }
1835
1836                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1837                                                 "Channel: %s\r\n"
1838                                                 "Uniqueid: %s\r\n"
1839                                                 "Meetme: %s\r\n"
1840                                                 "Usernum: %i\r\n"
1841                                                 "Status: off\r\n",
1842                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1843                         }
1844
1845                         /* If I have been kicked, exit the conference */
1846                         if (user->adminflags & ADMINFLAG_KICKME) {
1847                                 //You have been kicked.
1848                                 if (!(confflags & CONFFLAG_QUIET) && 
1849                                         !ast_streamfile(chan, "conf-kicked", chan->language)) {
1850                                         ast_waitstream(chan, "");
1851                                 }
1852                                 ret = 0;
1853                                 break;
1854                         }
1855
1856                         if (c) {
1857                                 if (c->fds[0] != origfd) {
1858                                         if (using_pseudo) {
1859                                                 /* Kill old pseudo */
1860                                                 close(fd);
1861                                                 using_pseudo = 0;
1862                                         }
1863                                         if (option_debug)
1864                                                 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
1865                                         retryzap = strcasecmp(c->tech->type, "Zap");
1866                                         user->zapchannel = !retryzap;
1867                                         goto zapretry;
1868                                 }
1869                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1870                                         f = ast_read_noaudio(c);
1871                                 else
1872                                         f = ast_read(c);
1873                                 if (!f)
1874                                         break;
1875                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1876                                         if (user->talk.actual)
1877                                                 ast_frame_adjust_volume(f, user->talk.actual);
1878
1879                                         if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
1880                                                 int totalsilence;
1881
1882                                                 if (user->talking == -1)
1883                                                         user->talking = 0;
1884
1885                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1886                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1887                                                         user->talking = 1;
1888                                                         if (confflags & CONFFLAG_MONITORTALKER)
1889                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1890                                                                       "Channel: %s\r\n"
1891                                                                       "Uniqueid: %s\r\n"
1892                                                                       "Meetme: %s\r\n"
1893                                                                       "Usernum: %d\r\n"
1894                                                                       "Status: on\r\n",
1895                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1896                                                 }
1897                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1898                                                         user->talking = 0;
1899                                                         if (confflags & CONFFLAG_MONITORTALKER)
1900                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1901                                                                       "Channel: %s\r\n"
1902                                                                       "Uniqueid: %s\r\n"
1903                                                                       "Meetme: %s\r\n"
1904                                                                       "Usernum: %d\r\n"
1905                                                                       "Status: off\r\n",
1906                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1907                                                 }
1908                                         }
1909                                         if (using_pseudo) {
1910                                                 /* Absolutely do _not_ use careful_write here...
1911                                                    it is important that we read data from the channel
1912                                                    as fast as it arrives, and feed it into the conference.
1913                                                    The buffering in the pseudo channel will take care of any
1914                                                    timing differences, unless they are so drastic as to lose
1915                                                    audio frames (in which case carefully writing would only
1916                                                    have delayed the audio even further).
1917                                                 */
1918                                                 /* As it turns out, we do want to use careful write.  We just
1919                                                    don't want to block, but we do want to at least *try*
1920                                                    to write out all the samples.
1921                                                  */
1922                                                 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
1923                                                         careful_write(fd, f->data, f->datalen, 0);
1924                                         }
1925                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1926                                         char tmp[2];
1927
1928                                         tmp[0] = f->subclass;
1929                                         tmp[1] = '\0';
1930                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1931                                                 if (option_debug)
1932                                                         ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1933                                                 ret = 0;
1934                                                 ast_frfree(f);
1935                                                 break;
1936                                         } else if (option_debug > 1)
1937                                                 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1938                                 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1939                                         ret = 0;
1940                                         ast_frfree(f);
1941                                         break;
1942                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
1943                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
1944                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1945                                                 close(fd);
1946                                                 ast_frfree(f);
1947                                                 goto outrun;
1948                                         }
1949
1950                                         /* if we are entering the menu, and the user has a channel-driver
1951                                            volume adjustment, clear it
1952                                         */
1953                                         if (!menu_active && user->talk.desired && !user->talk.actual)
1954                                                 set_talk_volume(user, 0);
1955
1956                                         if (musiconhold) {
1957                                                 ast_moh_stop(chan);
1958                                         }
1959                                         if ((confflags & CONFFLAG_ADMIN)) {
1960                                                 /* Admin menu */
1961                                                 if (!menu_active) {
1962                                                         menu_active = 1;
1963                                                         /* Record this sound! */
1964                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
1965                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1966                                                                 ast_stopstream(chan);
1967                                                         } else 
1968                                                                 dtmf = 0;
1969                                                 } else 
1970                                                         dtmf = f->subclass;
1971                                                 if (dtmf) {
1972                                                         switch(dtmf) {
1973                                                         case '1': /* Un/Mute */
1974                                                                 menu_active = 0;
1975
1976                                                                 /* for admin, change both admin and use flags */
1977                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
1978                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1979                                                                 else
1980                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1981
1982                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1983                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1984                                                                                 ast_waitstream(chan, "");
1985                                                                 } else {
1986                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1987                                                                                 ast_waitstream(chan, "");
1988                                                                 }
1989                                                                 break;
1990                                                         case '2': /* Un/Lock the Conference */
1991                                                                 menu_active = 0;
1992                                                                 if (conf->locked) {
1993                                                                         conf->locked = 0;
1994                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
1995                                                                                 ast_waitstream(chan, "");
1996                                                                 } else {
1997                                                                         conf->locked = 1;
1998                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
1999                                                                                 ast_waitstream(chan, "");
2000                                                                 }
2001                                                                 break;
2002                                                         case '3': /* Eject last user */
2003                                                                 menu_active = 0;
2004                                                                 usr = AST_LIST_LAST(&conf->userlist);
2005                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
2006                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
2007                                                                                 ast_waitstream(chan, "");
2008                                                                 } else 
2009                                                                         usr->adminflags |= ADMINFLAG_KICKME;
2010                                                                 ast_stopstream(chan);
2011                                                                 break;  
2012                                                         case '4':
2013                                                                 tweak_listen_volume(user, VOL_DOWN);
2014                                                                 break;
2015                                                         case '6':
2016                                                                 tweak_listen_volume(user, VOL_UP);
2017                                                                 break;
2018                                                         case '7':
2019                                                                 tweak_talk_volume(user, VOL_DOWN);
2020                                                                 break;
2021                                                         case '8':
2022                                                                 menu_active = 0;
2023                                                                 break;
2024                                                         case '9':
2025                                                                 tweak_talk_volume(user, VOL_UP);
2026                                                                 break;
2027                                                         default:
2028                                                                 menu_active = 0;
2029                                                                 /* Play an error message! */
2030                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2031                                                                         ast_waitstream(chan, "");
2032                                                                 break;
2033                                                         }
2034                                                 }
2035                                         } else {
2036                                                 /* User menu */
2037                                                 if (!menu_active) {
2038                                                         menu_active = 1;
2039                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
2040                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2041                                                                 ast_stopstream(chan);
2042                                                         } else
2043                                                                 dtmf = 0;
2044                                                 } else 
2045                                                         dtmf = f->subclass;
2046                                                 if (dtmf) {
2047                                                         switch(dtmf) {
2048                                                         case '1': /* Un/Mute */
2049                                                                 menu_active = 0;
2050
2051                                                                 /* user can only toggle the self-muted state */
2052                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
2053
2054                                                                 /* they can't override the admin mute state */
2055                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2056                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
2057                                                                                 ast_waitstream(chan, "");
2058                                                                 } else {
2059                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2060                                                                                 ast_waitstream(chan, "");
2061                                                                 }
2062                                                                 break;
2063                                                         case '4':
2064                                                                 tweak_listen_volume(user, VOL_DOWN);
2065                                                                 break;
2066                                                         case '6':
2067                                                                 tweak_listen_volume(user, VOL_UP);
2068                                                                 break;
2069                                                         case '7':
2070                                                                 tweak_talk_volume(user, VOL_DOWN);
2071                                                                 break;
2072                                                         case '8':
2073                                                                 menu_active = 0;
2074                                                                 break;
2075                                                         case '9':
2076                                                                 tweak_talk_volume(user, VOL_UP);
2077                                                                 break;
2078                                                         default:
2079                                                                 menu_active = 0;
2080                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2081                                                                         ast_waitstream(chan, "");
2082                                                                 break;
2083                                                         }
2084                                                 }
2085                                         }
2086                                         if (musiconhold)
2087                                                 ast_moh_start(chan, NULL, NULL);
2088
2089                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
2090                                                 ast_log(LOG_WARNING, "Error setting conference\n");
2091                                                 close(fd);
2092                                                 ast_frfree(f);
2093                                                 goto outrun;
2094                                         }
2095
2096                                         conf_flush(fd, chan);
2097                                 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
2098                                         && confflags & CONFFLAG_PASS_DTMF) {
2099                                         conf_queue_dtmf(conf, user, f);
2100                                 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
2101                                         switch (f->subclass) {
2102                                         case AST_CONTROL_HOLD:
2103                                                 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
2104                                                 break;
2105                                         default:
2106                                                 break;
2107                                         }
2108                                 } else if (option_debug) {
2109                                         ast_log(LOG_DEBUG,
2110                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2111                                                 chan->name, f->frametype, f->subclass);
2112                                 }
2113                                 ast_frfree(f);
2114                         } else if (outfd > -1) {
2115                                 res = read(outfd, buf, CONF_SIZE);
2116                                 if (res > 0) {
2117                                         memset(&fr, 0, sizeof(fr));
2118                                         fr.frametype = AST_FRAME_VOICE;
2119                                         fr.subclass = AST_FORMAT_SLINEAR;
2120                                         fr.datalen = res;
2121                                         fr.samples = res/2;
2122                                         fr.data = buf;
2123                                         fr.offset = AST_FRIENDLY_OFFSET;
2124                                         if (!user->listen.actual && 
2125                                                 ((confflags & CONFFLAG_MONITOR) || 
2126                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
2127                                                  (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
2128                                                  )) {
2129                                                 int index;
2130                                                 for (index=0;index<AST_FRAME_BITS;index++)
2131                                                         if (chan->rawwriteformat & (1 << index))
2132                                                                 break;
2133                                                 if (index >= AST_FRAME_BITS)
2134                                                         goto bailoutandtrynormal;
2135                                                 ast_mutex_lock(&conf->listenlock);
2136                                                 if (!conf->transframe[index]) {
2137                                                         if (conf->origframe) {
2138                                                                 if (!conf->transpath[index])
2139                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
2140                                                                 if (conf->transpath[index]) {
2141                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
2142                                                                         if (!conf->transframe[index])
2143                                                                                 conf->transframe[index] = &ast_null_frame;
2144                                                                 }
2145                                                         }
2146                                                 }
2147                                                 if (conf->transframe[index]) {
2148                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
2149                                                                 if (ast_write(chan, conf->transframe[index]))
2150                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2151                                                         }
2152                                                 } else {
2153                                                         ast_mutex_unlock(&conf->listenlock);
2154                                                         goto bailoutandtrynormal;
2155                                                 }
2156                                                 ast_mutex_unlock(&conf->listenlock);
2157                                         } else {
2158 bailoutandtrynormal:                                    
2159                                                 if (user->listen.actual)
2160                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
2161                                                 if (ast_write(chan, &fr) < 0) {
2162                                                         ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2163                                                 }
2164                                         }
2165                                 } else 
2166                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
2167                         }
2168                         lastmarked = currentmarked;
2169                 }
2170         }
2171
2172         if (musiconhold)
2173                 ast_moh_stop(chan);
2174         
2175         if (using_pseudo)
2176                 close(fd);
2177         else {
2178                 /* Take out of conference */
2179                 ztc.chan = 0;   
2180                 ztc.confno = 0;
2181                 ztc.confmode = 0;
2182                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
2183                         ast_log(LOG_WARNING, "Error setting conference\n");
2184                 }
2185         }
2186
2187         reset_volumes(user);
2188
2189         AST_LIST_LOCK(&confs);
2190         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
2191                 conf_play(chan, conf, LEAVE);
2192
2193         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
2194                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
2195                         if ((conf->chan) && (conf->users > 1)) {
2196                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
2197                                         ast_waitstream(conf->chan, "");
2198                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
2199                                         ast_waitstream(conf->chan, "");
2200                         }
2201                         ast_filedelete(user->namerecloc, NULL);
2202                 }
2203         }
2204         AST_LIST_UNLOCK(&confs);
2205
2206  outrun:
2207         AST_LIST_LOCK(&confs);
2208
2209         if (dsp)
2210                 ast_dsp_free(dsp);
2211         
2212         if (user->user_no) { /* Only cleanup users who really joined! */
2213                 now = time(NULL);
2214                 hr = (now - user->jointime) / 3600;
2215                 min = ((now - user->jointime) % 3600) / 60;
2216                 sec = (now - user->jointime) % 60;
2217
2218                 if (sent_event) {
2219                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
2220                                       "Channel: %s\r\n"
2221                                       "Uniqueid: %s\r\n"
2222                                       "Meetme: %s\r\n"
2223                                       "Usernum: %d\r\n"
2224                                       "CallerIDNum: %s\r\n"
2225                                       "CallerIDName: %s\r\n"
2226                                       "Duration: %ld\r\n",
2227                                       chan->name, chan->uniqueid, conf->confno, 
2228                                       user->user_no,
2229                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
2230                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
2231                                       (long)(now - user->jointime));
2232                 }
2233
2234                 conf->users--;
2235                 /* Update table */
2236                 snprintf(members, sizeof(members), "%d", conf->users);
2237                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2238                 if (confflags & CONFFLAG_MARKEDUSER) 
2239                         conf->markedusers--;
2240                 /* Remove ourselves from the list */
2241                 AST_LIST_REMOVE(&conf->userlist, user, list);
2242
2243                 /* Change any states */
2244                 if (!conf->users)
2245                         ast_device_state_changed("meetme:%s", conf->confno);
2246                 
2247                 /* Return the number of seconds the user was in the conf */
2248                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
2249                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
2250         }
2251         free(user);
2252         AST_LIST_UNLOCK(&confs);
2253
2254         return ret;
2255 }
2256
2257 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
2258                                                  char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2259 {
2260         struct ast_variable *var;
2261         struct ast_conference *cnf;
2262
2263         /* Check first in the conference list */
2264         AST_LIST_LOCK(&confs);
2265         AST_LIST_TRAVERSE(&confs, cnf, list) {
2266                 if (!strcmp(confno, cnf->confno)) 
2267                         break;
2268         }
2269         if (cnf) {
2270                 cnf->refcount += refcount;
2271         }
2272         AST_LIST_UNLOCK(&confs);
2273
2274         if (!cnf) {
2275                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
2276                 
2277                 var = ast_load_realtime("meetme", "confno", confno, NULL);
2278
2279                 if (!var)
2280                         return NULL;
2281
2282                 while (var) {
2283                         if (!strcasecmp(var->name, "pin")) {
2284                                 pin = ast_strdupa(var->value);
2285                         } else if (!strcasecmp(var->name, "adminpin")) {
2286                                 pinadmin = ast_strdupa(var->value);
2287                         }
2288                         var = var->next;
2289                 }
2290                 ast_variables_destroy(var);
2291                 
2292                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
2293         }
2294
2295         if (cnf) {
2296                 if (confflags && !cnf->chan &&
2297                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2298                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2299                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2300                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2301                 }
2302                 
2303                 if (confflags && !cnf->chan &&
2304                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2305                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2306                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2307                 }
2308         }
2309
2310         return cnf;
2311 }
2312
2313
2314 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2315                                         char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2316 {
2317         struct ast_config *cfg;
2318         struct ast_variable *var;
2319         struct ast_conference *cnf;
2320         char *parse;
2321         AST_DECLARE_APP_ARGS(args,
2322                 AST_APP_ARG(confno);
2323                 AST_APP_ARG(pin);
2324                 AST_APP_ARG(pinadmin);
2325         );
2326
2327         /* Check first in the conference list */
2328         AST_LIST_LOCK(&confs);
2329         AST_LIST_TRAVERSE(&confs, cnf, list) {
2330                 if (!strcmp(confno, cnf->confno)) 
2331                         break;
2332         }
2333         if (cnf){
2334                 cnf->refcount += refcount;
2335         }
2336         AST_LIST_UNLOCK(&confs);
2337
2338         if (!cnf) {
2339                 if (dynamic) {
2340                         /* No need to parse meetme.conf */
2341                         if (option_debug)
2342                                 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
2343                         if (dynamic_pin) {
2344                                 if (dynamic_pin[0] == 'q') {
2345                                         /* Query the user to enter a PIN */
2346                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
2347                                                 return NULL;
2348                                 }
2349                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
2350                         } else {
2351                                 cnf = build_conf(confno, "", "", make, dynamic, refcount);
2352                         }
2353                 } else {
2354                         /* Check the config */
2355                         cfg = ast_config_load(CONFIG_FILE_NAME);
2356                         if (!cfg) {
2357                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2358                                 return NULL;
2359                         }
2360                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2361                                 if (strcasecmp(var->name, "conf"))
2362                                         continue;
2363                                 
2364                                 if (!(parse = ast_strdupa(var->value)))
2365                                         return NULL;
2366                                 
2367                                 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2368                                 if (!strcasecmp(args.confno, confno)) {
2369                                         /* Bingo it's a valid conference */
2370                                         cnf = build_conf(args.confno,
2371                                                         S_OR(args.pin, ""),
2372                                                         S_OR(args.pinadmin, ""),
2373                                                         make, dynamic, refcount);
2374                                         break;
2375                                 }
2376                         }
2377                         if (!var) {
2378                                 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
2379                         }
2380                         ast_config_destroy(cfg);
2381                 }
2382         } else if (dynamic_pin) {
2383                 /* Correct for the user selecting 'D' instead of 'd' to have
2384                    someone join into a conference that has already been created
2385                    with a pin. */
2386                 if (dynamic_pin[0] == 'q')
2387                         dynamic_pin[0] = '\0';
2388         }
2389
2390         if (cnf) {
2391                 if (confflags && !cnf->chan &&
2392                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2393                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2394                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2395                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2396                 }
2397                 
2398                 if (confflags && !cnf->chan &&
2399                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2400                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2401                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2402                 }
2403         }
2404
2405         return cnf;
2406 }
2407
2408 /*! \brief The MeetmeCount application */
2409 static int count_exec(struct ast_channel *chan, void *data)
2410 {
2411         struct ast_module_user *u;
2412         int res = 0;
2413         struct ast_conference *conf;
2414         int count;
2415         char *localdata;
2416         char val[80] = "0"; 
2417         AST_DECLARE_APP_ARGS(args,
2418                 AST_APP_ARG(confno);
2419                 AST_APP_ARG(varname);
2420         );
2421
2422         if (ast_strlen_zero(data)) {
2423                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2424                 return -1;
2425         }
2426
2427         u = ast_module_user_add(chan);
2428         
2429         if (!(localdata = ast_strdupa(data))) {
2430                 ast_module_user_remove(u);
2431                 return -1;
2432         }
2433
2434         AST_STANDARD_APP_ARGS(args, localdata);
2435         
2436         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
2437
2438         if (conf) {
2439                 count = conf->users;
2440                 dispose_conf(conf);
2441                 conf = NULL;
2442         } else
2443                 count = 0;
2444
2445         if (!ast_strlen_zero(args.varname)){
2446                 /* have var so load it and exit */
2447                 snprintf(val, sizeof(val), "%d",count);
2448                 pbx_builtin_setvar_helper(chan, args.varname, val);
2449         } else {
2450                 if (chan->_state != AST_STATE_UP)
2451                         ast_answer(chan);
2452                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2453         }
2454         ast_module_user_remove(u);
2455
2456         return res;
2457 }
2458
2459 /*! \brief The meetme() application */
2460 static int conf_exec(struct ast_channel *chan, void *data)
2461 {
2462         int res=-1;
2463         struct ast_module_user *u;
2464         char confno[MAX_CONFNUM] = "";
2465         int allowretry = 0;
2466         int retrycnt = 0;
2467         struct ast_conference *cnf = NULL;
2468         struct ast_flags confflags = {0};
2469         int dynamic = 0;
2470         int empty = 0, empty_no_pin = 0;
2471         int always_prompt = 0;
2472         char *notdata, *info, the_pin[MAX_PIN] = "";
2473         AST_DECLARE_APP_ARGS(args,
2474                 AST_APP_ARG(confno);
2475                 AST_APP_ARG(options);
2476                 AST_APP_ARG(pin);
2477         );
2478         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2479
2480         u = ast_module_user_add(chan);
2481
2482         if (ast_strlen_zero(data)) {
2483                 allowretry = 1;
2484                 notdata = "";
2485         } else {
2486                 notdata = data;
2487         }
2488         
2489         if (chan->_state != AST_STATE_UP)
2490                 ast_answer(chan);
2491
2492         info = ast_strdupa(notdata);
2493
2494         AST_STANDARD_APP_ARGS(args, info);      
2495
2496         if (args.confno) {
2497                 ast_copy_string(confno, args.confno, sizeof(confno));
2498                 if (ast_strlen_zero(confno)) {
2499                         allowretry = 1;
2500                 }
2501         }
2502         
2503         if (args.pin)
2504                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2505
2506         if (args.options) {
2507                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2508                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2509                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2510                         strcpy(the_pin, "q");
2511
2512                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2513                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2514                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2515         }
2516
2517         do {
2518                 if (retrycnt > 3)
2519                         allowretry = 0;
2520                 if (empty) {
2521                         int i, map[1024] = { 0, };
2522                         struct ast_config *cfg;
2523                         struct ast_variable *var;
2524                         int confno_int;
2525
2526                         AST_LIST_LOCK(&confs);
2527                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2528                                 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
2529                                         /* Disqualify in use conference */
2530                                         if (confno_int >= 0 && confno_int < 1024)
2531                                                 map[confno_int]++;
2532                                 }
2533                         }
2534                         AST_LIST_UNLOCK(&confs);
2535
2536                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2537                         if ((empty_no_pin) || (!dynamic)) {
2538                                 cfg = ast_config_load(CONFIG_FILE_NAME);
2539                                 if (cfg) {
2540                                         var = ast_variable_browse(cfg, "rooms");
2541                                         while (var) {
2542                                                 if (!strcasecmp(var->name, "conf")) {
2543                                                         char *stringp = ast_strdupa(var->value);
2544                                                         if (stringp) {
2545                                                                 char *confno_tmp = strsep(&stringp, "|,");
2546                                                                 int found = 0;
2547                                                                 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
2548                                                                         if ((confno_int >= 0) && (confno_int < 1024)) {
2549                                                                                 if (stringp && empty_no_pin) {
2550                                                                                         map[confno_int]++;
2551                                                                                 }
2552                                                                         }
2553                                                                 }
2554                                                                 if (!dynamic) {
2555                                                                         /* For static:  run through the list and see if this conference is empty */
2556                                                                         AST_LIST_LOCK(&confs);
2557                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2558                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2559                                                                                         /* The conference exists, therefore it's not empty */
2560                                                                                         found = 1;
2561                                                                                         break;
2562                                                                                 }
2563                                                                         }
2564                                                                         AST_LIST_UNLOCK(&confs);
2565                                                                         if (!found) {
2566                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2567                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2568                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2569                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2570                                                                                          * Case 3:  not empty_no_pin
2571                                                                                          */
2572                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2573                                                                                         break;
2574                                                                                         /* XXX the map is not complete (but we do have a confno) */
2575                                                                                 }
2576                                                                         }
2577                                                                 }
2578                                                         }
2579                                                 }
2580                                                 var = var->next;
2581                                         }
2582                                         ast_config_destroy(cfg);
2583                                 }
2584                         }
2585
2586                         /* Select first conference number not in use */
2587                         if (ast_strlen_zero(confno) && dynamic) {
2588                                 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
2589                                         if (!map[i]) {
2590                                                 snprintf(confno, sizeof(confno), "%d", i);
2591                                                 break;
2592                                         }
2593                                 }
2594                         }
2595
2596                         /* Not found? */
2597                         if (ast_strlen_zero(confno)) {
2598                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2599                                 if (!res)
2600                                         ast_waitstream(chan, "");
2601                         } else {
2602                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2603                                         if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
2604                                                 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2605                                                 if (!res) {
2606                                                         ast_waitstream(chan, "");
2607                                                         res = ast_say_digits(chan, confno_int, "", chan->language);
2608                                                 }
2609                                         }
2610                                 } else {
2611                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2612                                 }
2613                         }
2614                 }
2615
2616                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2617                         /* Prompt user for conference number */
2618                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2619                         if (res < 0) {
2620                                 /* Don't try to validate when we catch an error */
2621                                 confno[0] = '\0';
2622                                 allowretry = 0;
2623                                 break;
2624                         }
2625                 }
2626                 if (!ast_strlen_zero(confno)) {
2627                         /* Check the validity of the conference */
2628                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 
2629                                 sizeof(the_pin), 1, &confflags);
2630                         if (!cnf) {
2631                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, 
2632                                         the_pin, sizeof(the_pin), 1, &confflags);
2633                         }
2634
2635                         if (!cnf) {
2636                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2637                                 if (!res)
2638                                         ast_waitstream(chan, "");
2639                                 res = -1;
2640                                 if (allowretry)
2641                                         confno[0] = '\0';
2642                         } else {
2643                                 if ((!ast_strlen_zero(cnf->pin) &&
2644                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2645                                     (!ast_strlen_zero(cnf->pinadmin) &&
2646                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2647                                         char pin[MAX_PIN] = "";
2648                                         int j;
2649
2650                                         /* Allow the pin to be retried up to 3 times */
2651                                         for (j = 0; j < 3; j++) {
2652                                                 if (*the_pin && (always_prompt == 0)) {
2653                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2654                                                         res = 0;
2655                                                 } else {
2656                                                         /* Prompt user for pin if pin is required */
2657                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2658                                                 }
2659                                                 if (res >= 0) {
2660                                                         if (!strcasecmp(pin, cnf->pin) ||
2661                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2662                                                              !strcasecmp(pin, cnf->pinadmin))) {
2663                                                                 /* Pin correct */
2664                                                                 allowretry = 0;
2665                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
2666                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
2667                                                                 /* Run the conference */
2668                                                                 res = conf_run(chan, cnf, confflags.flags, optargs);
2669                                                                 break;
2670                                                         } else {
2671                                                                 /* Pin invalid */
2672                                                                 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
2673                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
2674                                                                         ast_stopstream(chan);
2675                                                                 }
2676                                                                 else {
2677                                                                         ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2678                                                                         break;
2679                                                                 }
2680                                                                 if (res < 0)
2681                                                                         break;
2682                                                                 pin[0] = res;
2683                                                                 pin[1] = '\0';
2684                                                                 res = -1;
2685                                                                 if (allowretry)
2686                                                                         confno[0] = '\0';
2687                                                         }
2688                                                 } else {
2689                                                         /* failed when getting the pin */
2690                                                         res = -1;
2691                                                         allowretry = 0;
2692                                                         /* see if we need to get rid of the conference */
2693                                                         break;
2694                                                 }
2695
2696                                                 /* Don't retry pin with a static pin */
2697                                                 if (*the_pin && (always_prompt==0)) {
2698                                                         break;
2699                                                 }
2700                                         }
2701                                 } else {
2702