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