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