Merged revisions 51339 via svnmerge from
[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
64 #include "enter.h"
65 #include "leave.h"
66
67 #define CONFIG_FILE_NAME "meetme.conf"
68
69 /*! each buffer is 20ms, so this is 640ms total */
70 #define DEFAULT_AUDIO_BUFFERS  32
71
72 enum {
73         ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
74         ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
75         ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
76 };
77
78 #define MEETME_DELAYDETECTTALK     300
79 #define MEETME_DELAYDETECTENDTALK  1000
80
81 #define AST_FRAME_BITS  32
82
83 enum volume_action {
84         VOL_UP,
85         VOL_DOWN
86 };
87
88 enum entrance_sound {
89         ENTER,
90         LEAVE
91 };
92
93 enum recording_state {
94         MEETME_RECORD_OFF,
95         MEETME_RECORD_STARTED,
96         MEETME_RECORD_ACTIVE,
97         MEETME_RECORD_TERMINATE
98 };
99
100 #define CONF_SIZE  320
101
102 enum {
103         /*! user has admin access on the conference */
104         CONFFLAG_ADMIN = (1 << 0),
105         /*! If set the user can only receive audio from the conference */
106         CONFFLAG_MONITOR = (1 << 1),
107         /*! If set asterisk will exit conference when '#' is pressed */
108         CONFFLAG_POUNDEXIT = (1 << 2),
109         /*! If set asterisk will provide a menu to the user when '*' is pressed */
110         CONFFLAG_STARMENU = (1 << 3),
111         /*! If set the use can only send audio to the conference */
112         CONFFLAG_TALKER = (1 << 4),
113         /*! If set there will be no enter or leave sounds */
114         CONFFLAG_QUIET = (1 << 5),
115         /*! If set, when user joins the conference, they will be told the number 
116          *  of users that are already in */
117         CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
118         /*! Set to run AGI Script in Background */
119         CONFFLAG_AGI = (1 << 7),
120         /*! Set to have music on hold when user is alone in conference */
121         CONFFLAG_MOH = (1 << 8),
122         /*! If set the MeetMe will return if all marked with this flag left */
123         CONFFLAG_MARKEDEXIT = (1 << 9),
124         /*! If set, the MeetMe will wait until a marked user enters */
125         CONFFLAG_WAITMARKED = (1 << 10),
126         /*! If set, the MeetMe will exit to the specified context */
127         CONFFLAG_EXIT_CONTEXT = (1 << 11),
128         /*! If set, the user will be marked */
129         CONFFLAG_MARKEDUSER = (1 << 12),
130         /*! If set, user will be ask record name on entry of conference */
131         CONFFLAG_INTROUSER = (1 << 13),
132         /*! If set, the MeetMe will be recorded */
133         CONFFLAG_RECORDCONF = (1<< 14),
134         /*! If set, the user will be monitored if the user is talking or not */
135         CONFFLAG_MONITORTALKER = (1 << 15),
136         CONFFLAG_DYNAMIC = (1 << 16),
137         CONFFLAG_DYNAMICPIN = (1 << 17),
138         CONFFLAG_EMPTY = (1 << 18),
139         CONFFLAG_EMPTYNOPIN = (1 << 19),
140         CONFFLAG_ALWAYSPROMPT = (1 << 20),
141         /*! If set, treats talking users as muted users */
142         CONFFLAG_OPTIMIZETALKER = (1 << 21),
143         /*! If set, won't speak the extra prompt when the first person 
144          *  enters the conference */
145         CONFFLAG_NOONLYPERSON = (1 << 22),
146         /*! If set, user will be asked to record name on entry of conference 
147          *  without review */
148         CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
149         /*! If set, the user will be initially self-muted */
150         CONFFLAG_STARTMUTED = (1 << 24),
151         /*! If set, the user is a shared line appearance station */
152         CONFFLAG_SLA_STATION = (1 << 25),
153         /*! If set, the user is a shared line appearance trunk */
154         CONFFLAG_SLA_TRUNK = (1 << 26),
155         /*! If set, the user has put us on hold */
156         CONFFLAG_HOLD = (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 } meetme_option_args;
165
166 AST_APP_OPTIONS(meetme_opts, {
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('i', CONFFLAG_INTROUSER ),
177         AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
178         AST_APP_OPTION('M', CONFFLAG_MOH ),
179         AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
180         AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
181         AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
182         AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
183         AST_APP_OPTION('q', CONFFLAG_QUIET ),
184         AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
185         AST_APP_OPTION('s', CONFFLAG_STARMENU ),
186         AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
187         AST_APP_OPTION('l', CONFFLAG_MONITOR ),
188         AST_APP_OPTION('t', CONFFLAG_TALKER ),
189         AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
190         AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
191         AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
192         AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
193 });
194
195 AST_APP_OPTIONS(sla_opts, {
196         /* Just a placeholder for now */
197 });
198 static const char *app = "MeetMe";
199 static const char *app2 = "MeetMeCount";
200 static const char *app3 = "MeetMeAdmin";
201 static const char *appslas = "SLAStation";
202 static const char *appslat = "SLATrunk";
203
204 static const char *synopsis = "MeetMe conference bridge";
205 static const char *synopsis2 = "MeetMe participant count";
206 static const char *synopsis3 = "MeetMe conference Administration";
207 static const char *synopslas = "Shared Line Appearance - Station";
208 static const char *synopslat = "Shared Line Appearance - Trunk";
209
210 static const char *descrip =
211 "  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
212 "conference.  If the conference number is omitted, the user will be prompted\n"
213 "to enter one.  User can exit the conference by hangup, or if the 'p' option\n"
214 "is specified, by pressing '#'.\n"
215 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
216 "             must be present for conferencing to operate properly. In addition, the chan_zap\n"
217 "             channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
218 "The option string may contain zero or more of the following characters:\n"
219 "      'a' -- set admin mode\n"
220 "      'A' -- set marked mode\n"
221 "      'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
222 "             Default: conf-background.agi  (Note: This does not work with\n"
223 "             non-Zap channels in the same conference)\n"
224 "      'c' -- announce user(s) count on joining a conference\n"
225 "      'C' -- continue in dialplan when kicked out of conference\n"
226 "      'd' -- dynamically add conference\n"
227 "      'D' -- dynamically add conference, prompting for a PIN\n"
228 "      'e' -- select an empty conference\n"
229 "      'E' -- select an empty pinless conference\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 *descripslas =
289 "  SLAStation(sla[,options]): Run Shared Line Appearance for station\n"
290 "Runs the share line appearance for a station calling in.  If there are no\n"
291 "other participants in the conference, the trunk is called and is dumped into\n"
292 "the bridge.\n";
293
294 static const char *descripslat =
295 "  SLATrunk(sla[,options]): Run Shared Line Appearance for trunk\n"
296 "Runs the share line appearance for a trunk calling in.  If there are no\n"
297 "other participants in the conference, all member stations are invited into\n"
298 "the bridge.\n";
299
300 #define CONFIG_FILE_NAME "meetme.conf"
301 #define CONFIG_FILE_NAME_SLA "sla.conf"
302
303 /*! \brief The MeetMe Conference object */
304 struct ast_conference {
305         ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
306         ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
307         char confno[AST_MAX_EXTENSION];         /*!< Conference */
308         struct ast_channel *chan;               /*!< Announcements channel */
309         struct ast_channel *lchan;              /*!< Listen/Record channel */
310         int fd;                                 /*!< Announcements fd */
311         int zapconf;                            /*!< Zaptel Conf # */
312         int users;                              /*!< Number of active users */
313         int markedusers;                        /*!< Number of marked users */
314         time_t start;                           /*!< Start time (s) */
315         int refcount;                           /*!< reference count of usage */
316         enum recording_state recording:2;       /*!< recording status */
317         unsigned int isdynamic:1;               /*!< Created on the fly? */
318         unsigned int locked:1;                  /*!< Is the conference locked? */
319         pthread_t recordthread;                 /*!< thread for recording */
320         pthread_attr_t attr;                    /*!< thread attribute */
321         const char *recordingfilename;          /*!< Filename to record the Conference into */
322         const char *recordingformat;            /*!< Format to record the Conference in */
323         char pin[AST_MAX_EXTENSION];            /*!< If protected by a PIN */
324         char pinadmin[AST_MAX_EXTENSION];       /*!< If protected by a admin PIN */
325         struct ast_frame *transframe[32];
326         struct ast_frame *origframe;
327         struct ast_trans_pvt *transpath[32];
328         AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
329         AST_LIST_ENTRY(ast_conference) list;
330 };
331
332 static AST_LIST_HEAD_STATIC(confs, ast_conference);
333
334 struct volume {
335         int desired;                            /*!< Desired volume adjustment */
336         int actual;                             /*!< Actual volume adjustment (for channels that can't adjust) */
337 };
338
339 struct ast_conf_user {
340         int user_no;                            /*!< User Number */
341         int userflags;                          /*!< Flags as set in the conference */
342         int adminflags;                         /*!< Flags set by the Admin */
343         struct ast_channel *chan;               /*!< Connected channel */
344         int talking;                            /*!< Is user talking */
345         int zapchannel;                         /*!< Is a Zaptel channel */
346         char usrvalue[50];                      /*!< Custom User Value */
347         char namerecloc[PATH_MAX];                              /*!< Name Recorded file Location */
348         int control;                                                    /*! Queue Control for transmission */
349         int dtmf;                                                               /*! Queue DTMF for transmission */
350         time_t jointime;                        /*!< Time the user joined the conference */
351         struct volume talk;
352         struct volume listen;
353         AST_LIST_ENTRY(ast_conf_user) list;
354 };
355
356 /*! SLA station - one device in an SLA configuration */
357 struct ast_sla_station {
358         ASTOBJ_COMPONENTS(struct ast_sla_station);
359         char *dest;
360         char tech[0];
361 };
362
363 struct ast_sla_station_box {
364         ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla_station);
365 };
366
367 /*! SLA - Shared Line Appearance object. These consist of one trunk (outbound line)
368         and stations that receive incoming calls and place outbound calls over the trunk 
369 */
370 struct ast_sla {
371         ASTOBJ_COMPONENTS (struct ast_sla);
372         struct ast_sla_station_box stations;    /*!< Stations connected to this SLA */
373         char confname[80];      /*!< Name for this SLA bridge */
374         char trunkdest[256];    /*!< Device (channel) identifier for the trunk line */
375         char trunktech[20];     /*!< Technology used for the trunk (channel driver) */
376 };
377
378 struct ast_sla_box {
379         ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla);
380 } slas;
381
382 /*! The number of audio buffers to be allocated on pseudo channels
383  *  when in a conference */
384 static int audio_buffers;
385
386 /*! Map 'volume' levels from -5 through +5 into
387  *  decibel (dB) settings for channel drivers
388  *  Note: these are not a straight linear-to-dB
389  *  conversion... the numbers have been modified
390  *  to give the user a better level of adjustability
391  */
392 static signed char gain_map[] = {
393         -15,
394         -13,
395         -10,
396         -6,
397         0,
398         0,
399         0,
400         6,
401         10,
402         13,
403         15,
404 };
405
406
407 static int admin_exec(struct ast_channel *chan, void *data);
408 static void *recordthread(void *args);
409
410 static char *istalking(int x)
411 {
412         if (x > 0)
413                 return "(talking)";
414         else if (x < 0)
415                 return "(unmonitored)";
416         else 
417                 return "(not talking)";
418 }
419
420 static int careful_write(int fd, unsigned char *data, int len, int block)
421 {
422         int res;
423         int x;
424
425         while (len) {
426                 if (block) {
427                         x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
428                         res = ioctl(fd, ZT_IOMUX, &x);
429                 } else
430                         res = 0;
431                 if (res >= 0)
432                         res = write(fd, data, len);
433                 if (res < 1) {
434                         if (errno != EAGAIN) {
435                                 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
436                                 return -1;
437                         } else
438                                 return 0;
439                 }
440                 len -= res;
441                 data += res;
442         }
443
444         return 0;
445 }
446
447 static int set_talk_volume(struct ast_conf_user *user, int volume)
448 {
449         signed char gain_adjust;
450
451         /* attempt to make the adjustment in the channel driver;
452            if successful, don't adjust in the frame reading routine
453         */
454         gain_adjust = gain_map[volume + 5];
455
456         return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
457 }
458
459 static int set_listen_volume(struct ast_conf_user *user, int volume)
460 {
461         signed char gain_adjust;
462
463         /* attempt to make the adjustment in the channel driver;
464            if successful, don't adjust in the frame reading routine
465         */
466         gain_adjust = gain_map[volume + 5];
467
468         return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
469 }
470
471 static void tweak_volume(struct volume *vol, enum volume_action action)
472 {
473         switch (action) {
474         case VOL_UP:
475                 switch (vol->desired) {
476                 case 5:
477                         break;
478                 case 0:
479                         vol->desired = 2;
480                         break;
481                 case -2:
482                         vol->desired = 0;
483                         break;
484                 default:
485                         vol->desired++;
486                         break;
487                 }
488                 break;
489         case VOL_DOWN:
490                 switch (vol->desired) {
491                 case -5:
492                         break;
493                 case 2:
494                         vol->desired = 0;
495                         break;
496                 case 0:
497                         vol->desired = -2;
498                         break;
499                 default:
500                         vol->desired--;
501                         break;
502                 }
503         }
504 }
505
506 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
507 {
508         tweak_volume(&user->talk, action);
509         /* attempt to make the adjustment in the channel driver;
510            if successful, don't adjust in the frame reading routine
511         */
512         if (!set_talk_volume(user, user->talk.desired))
513                 user->talk.actual = 0;
514         else
515                 user->talk.actual = user->talk.desired;
516 }
517
518 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
519 {
520         tweak_volume(&user->listen, action);
521         /* attempt to make the adjustment in the channel driver;
522            if successful, don't adjust in the frame reading routine
523         */
524         if (!set_listen_volume(user, user->listen.desired))
525                 user->listen.actual = 0;
526         else
527                 user->listen.actual = user->listen.desired;
528 }
529
530 static void reset_volumes(struct ast_conf_user *user)
531 {
532         signed char zero_volume = 0;
533
534         ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
535         ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
536 }
537
538 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
539 {
540         unsigned char *data;
541         int len;
542         int res = -1;
543
544         if (!chan->_softhangup)
545                 res = ast_autoservice_start(chan);
546
547         AST_LIST_LOCK(&confs);
548
549         switch(sound) {
550         case ENTER:
551                 data = enter;
552                 len = sizeof(enter);
553                 break;
554         case LEAVE:
555                 data = leave;
556                 len = sizeof(leave);
557                 break;
558         default:
559                 data = NULL;
560                 len = 0;
561         }
562         if (data) {
563                 careful_write(conf->fd, data, len, 1);
564         }
565
566         AST_LIST_UNLOCK(&confs);
567
568         if (!res) 
569                 ast_autoservice_stop(chan);
570 }
571
572 static void station_destroy(struct ast_sla_station *station)
573 {
574         free(station);
575 }
576
577 static void sla_destroy(struct ast_sla *sla)
578 {
579         ASTOBJ_CONTAINER_DESTROYALL(&sla->stations, station_destroy);
580         ASTOBJ_CONTAINER_DESTROY(&sla->stations);
581         free(sla);
582 }
583
584 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
585 {
586         struct ast_conference *cnf;
587         struct zt_confinfo ztc;
588
589         AST_LIST_LOCK(&confs);
590
591         AST_LIST_TRAVERSE(&confs, cnf, list) {
592                 if (!strcmp(confno, cnf->confno)) 
593                         break;
594         }
595
596         if (!cnf && (make || dynamic)) {
597                 /* Make a new one */
598                 if ((cnf = ast_calloc(1, sizeof(*cnf)))) {
599                         ast_mutex_init(&cnf->playlock);
600                         ast_mutex_init(&cnf->listenlock);
601                         ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
602                         ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
603                         ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
604                         cnf->refcount = 0;
605                         cnf->markedusers = 0;
606                         cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
607                         if (cnf->chan) {
608                                 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
609                                 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
610                                 cnf->fd = cnf->chan->fds[0];    /* for use by conf_play() */
611                         } else {
612                                 ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n");
613                                 cnf->fd = open("/dev/zap/pseudo", O_RDWR);
614                                 if (cnf->fd < 0) {
615                                         ast_log(LOG_WARNING, "Unable to open pseudo device\n");
616                                         free(cnf);
617                                         cnf = NULL;
618                                         goto cnfout;
619                                 }
620                         }
621                         memset(&ztc, 0, sizeof(ztc));
622                         /* Setup a new zap conference */
623                         ztc.chan = 0;
624                         ztc.confno = -1;
625                         ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
626                         if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
627                                 ast_log(LOG_WARNING, "Error setting conference\n");
628                                 if (cnf->chan)
629                                         ast_hangup(cnf->chan);
630                                 else
631                                         close(cnf->fd);
632                                 free(cnf);
633                                 cnf = NULL;
634                                 goto cnfout;
635                         }
636                         cnf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
637                         if (cnf->lchan) {
638                                 ast_set_read_format(cnf->lchan, AST_FORMAT_SLINEAR);
639                                 ast_set_write_format(cnf->lchan, AST_FORMAT_SLINEAR);
640                                 ztc.chan = 0;
641                                 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
642                                 if (ioctl(cnf->lchan->fds[0], ZT_SETCONF, &ztc)) {
643                                         ast_log(LOG_WARNING, "Error setting conference\n");
644                                         ast_hangup(cnf->lchan);
645                                         cnf->lchan = NULL;
646                                 }
647                         }
648                         /* Fill the conference struct */
649                         cnf->start = time(NULL);
650                         cnf->zapconf = ztc.confno;
651                         cnf->isdynamic = dynamic ? 1 : 0;
652                         if (option_verbose > 2)
653                                 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
654                         AST_LIST_INSERT_HEAD(&confs, cnf, list);
655                         manager_event(EVENT_FLAG_CALL, "MeetmeStart", "Meetme: %s\r\n", cnf->confno);
656                 } 
657         }
658  cnfout:
659         if (cnf){ 
660                 cnf->refcount += refcount;
661         }
662         AST_LIST_UNLOCK(&confs);
663         return cnf;
664 }
665
666 /*! \brief CLI command for showing SLAs */
667 static int sla_show(int fd, int argc, char *argv[]) 
668 {
669         struct ast_sla *sla;
670         if (argc != 2)
671                 return RESULT_SHOWUSAGE;
672
673         ast_cli(fd, "Shared line appearances:\n");
674         ASTOBJ_CONTAINER_TRAVERSE(&slas, 1, {
675                 ASTOBJ_RDLOCK(iterator);
676                 ast_cli(fd, "SLA %s\n", iterator->name);
677                 if (ast_strlen_zero(iterator->trunkdest) || ast_strlen_zero(iterator->trunktech))
678                         ast_cli(fd, "   Trunk => <unspecified>\n");
679                 else
680                         ast_cli(fd, "   Trunk => %s/%s\n", iterator->trunktech, iterator->trunkdest);
681                 sla = iterator;
682                 ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
683                         ast_cli(fd, "   Station: %s/%s\n", iterator->tech, iterator->dest);
684                 });
685                 ASTOBJ_UNLOCK(iterator);
686         });
687
688         return RESULT_SUCCESS;
689 }
690
691 static int meetme_cmd(int fd, int argc, char **argv) 
692 {
693         /* Process the command */
694         struct ast_conference *cnf;
695         struct ast_conf_user *user;
696         int hr, min, sec;
697         int i = 0, total = 0;
698         time_t now;
699         char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
700         char *data_format = "%-12.12s   %4.4d         %4.4s       %02d:%02d:%02d  %-8s\n";
701         char cmdline[1024] = "";
702
703         if (argc > 8)
704                 ast_cli(fd, "Invalid Arguments.\n");
705         /* Check for length so no buffer will overflow... */
706         for (i = 0; i < argc; i++) {
707                 if (strlen(argv[i]) > 100)
708                         ast_cli(fd, "Invalid Arguments.\n");
709         }
710         if (argc == 1) {
711                 /* 'MeetMe': List all the conferences */        
712                 now = time(NULL);
713                 if (AST_LIST_EMPTY(&confs)) {
714                         ast_cli(fd, "No active MeetMe conferences.\n");
715                         return RESULT_SUCCESS;
716                 }
717                 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
718                 AST_LIST_TRAVERSE(&confs, cnf, list) {
719                         if (cnf->markedusers == 0)
720                                 strcpy(cmdline, "N/A ");
721                         else 
722                                 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
723                         hr = (now - cnf->start) / 3600;
724                         min = ((now - cnf->start) % 3600) / 60;
725                         sec = (now - cnf->start) % 60;
726
727                         ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
728
729                         total += cnf->users;    
730                 }
731                 ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
732                 return RESULT_SUCCESS;
733         }
734         if (argc < 3)
735                 return RESULT_SHOWUSAGE;
736         ast_copy_string(cmdline, argv[2], sizeof(cmdline));     /* Argv 2: conference number */
737         if (strstr(argv[1], "lock")) {  
738                 if (strcmp(argv[1], "lock") == 0) {
739                         /* Lock */
740                         strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
741                 } else {
742                         /* Unlock */
743                         strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
744                 }
745         } else if (strstr(argv[1], "mute")) { 
746                 if (argc < 4)
747                         return RESULT_SHOWUSAGE;
748                 if (strcmp(argv[1], "mute") == 0) {
749                         /* Mute */
750                         if (strcmp(argv[3], "all") == 0) {
751                                 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
752                         } else {
753                                 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1); 
754                                 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
755                         }
756                 } else {
757                         /* Unmute */
758                         if (strcmp(argv[3], "all") == 0) {
759                                 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
760                         } else {
761                                 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
762                                 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
763                         }
764                 }
765         } else if (strcmp(argv[1], "kick") == 0) {
766                 if (argc < 4)
767                         return RESULT_SHOWUSAGE;
768                 if (strcmp(argv[3], "all") == 0) {
769                         /* Kick all */
770                         strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
771                 } else {
772                         /* Kick a single user */
773                         strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
774                         strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
775                 }       
776         } else if(strcmp(argv[1], "list") == 0) {
777                 int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
778                 /* List all the users in a conference */
779                 if (AST_LIST_EMPTY(&confs)) {
780                         if ( !concise )
781                                 ast_cli(fd, "No active conferences.\n");
782                         return RESULT_SUCCESS;  
783                 }
784                 /* Find the right conference */
785                 AST_LIST_TRAVERSE(&confs, cnf, list) {
786                         if (strcmp(cnf->confno, argv[2]) == 0)
787                                 break;
788                 }
789                 if (!cnf) {
790                         if ( !concise )
791                                 ast_cli(fd, "No such conference: %s.\n",argv[2]);
792                         return RESULT_SUCCESS;
793                 }
794                 /* Show all the users */
795                 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
796                         now = time(NULL);
797                         hr = (now - user->jointime) / 3600;
798                         min = ((now - user->jointime) % 3600) / 60;
799                         sec = (now - user->jointime) % 60;
800                         if ( !concise )
801                                 ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
802                                         user->user_no,
803                                         S_OR(user->chan->cid.cid_num, "<unknown>"),
804                                         S_OR(user->chan->cid.cid_name, "<no name>"),
805                                         user->chan->name,
806                                         user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
807                                         user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
808                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
809                                         istalking(user->talking), 
810                                         user->userflags & CONFFLAG_HOLD ? " (On Hold) " : "", hr, min, sec);
811                         else 
812                                 ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
813                                         user->user_no,
814                                         S_OR(user->chan->cid.cid_num, ""),
815                                         S_OR(user->chan->cid.cid_name, ""),
816                                         user->chan->name,
817                                         user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
818                                         user->userflags  & CONFFLAG_MONITOR ? "1" : "",
819                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
820                                         user->talking, hr, min, sec);
821                         
822                 }
823                 if ( !concise )
824                         ast_cli(fd,"%d users in that conference.\n",cnf->users);
825
826                 return RESULT_SUCCESS;
827         } else 
828                 return RESULT_SHOWUSAGE;
829
830         if (option_debug)
831                 ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
832
833         admin_exec(NULL, cmdline);
834
835         return 0;
836 }
837
838 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
839 {
840         static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
841
842         int len = strlen(word);
843         int which = 0;
844         struct ast_conference *cnf = NULL;
845         struct ast_conf_user *usr = NULL;
846         char *confno = NULL;
847         char usrno[50] = "";
848         char *myline, *ret = NULL;
849         
850         if (pos == 1) {         /* Command */
851                 return ast_cli_complete(word, cmds, state);
852         } else if (pos == 2) {  /* Conference Number */
853                 AST_LIST_LOCK(&confs);
854                 AST_LIST_TRAVERSE(&confs, cnf, list) {
855                         if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
856                                 ret = cnf->confno;
857                                 break;
858                         }
859                 }
860                 ret = ast_strdup(ret); /* dup before releasing the lock */
861                 AST_LIST_UNLOCK(&confs);
862                 return ret;
863         } else if (pos == 3) {
864                 /* User Number || Conf Command option*/
865                 if (strstr(line, "mute") || strstr(line, "kick")) {
866                         if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
867                                 return strdup("all");
868                         which++;
869                         AST_LIST_LOCK(&confs);
870
871                         /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
872                         myline = ast_strdupa(line);
873                         if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
874                                 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
875                                         ;
876                         }
877                         
878                         AST_LIST_TRAVERSE(&confs, cnf, list) {
879                                 if (!strcmp(confno, cnf->confno))
880                                     break;
881                         }
882
883                         if (cnf) {
884                                 /* Search for the user */
885                                 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
886                                         snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
887                                         if (!strncasecmp(word, usrno, len) && ++which > state)
888                                                 break;
889                                 }
890                         }
891                         AST_LIST_UNLOCK(&confs);
892                         return usr ? strdup(usrno) : NULL;
893                 } else if ( strstr(line, "list") && ( 0 == state ) )
894                         return strdup("concise");
895         }
896
897         return NULL;
898 }
899         
900 static const char meetme_usage[] =
901 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
902 "       Executes a command for the conference or on a conferee\n";
903
904 static const char sla_show_usage[] =
905 "Usage: sla show\n"
906 "       Lists status of all shared line appearances\n";
907
908 static struct ast_cli_entry cli_meetme[] = {
909         { { "sla", "show", NULL },
910         sla_show, "Show status of Shared Line Appearances",
911         sla_show_usage, NULL },
912
913         { { "meetme", NULL, NULL },
914         meetme_cmd, "Execute a command on a conference or conferee",
915         meetme_usage, complete_meetmecmd },
916 };
917
918 static void conf_flush(int fd, struct ast_channel *chan)
919 {
920         int x;
921
922         /* read any frames that may be waiting on the channel
923            and throw them away
924         */
925         if (chan) {
926                 struct ast_frame *f;
927
928                 /* when no frames are available, this will wait
929                    for 1 millisecond maximum
930                 */
931                 while (ast_waitfor(chan, 1)) {
932                         f = ast_read(chan);
933                         if (f)
934                                 ast_frfree(f);
935                         else /* channel was hung up or something else happened */
936                                 break;
937                 }
938         }
939
940         /* flush any data sitting in the pseudo channel */
941         x = ZT_FLUSH_ALL;
942         if (ioctl(fd, ZT_FLUSH, &x))
943                 ast_log(LOG_WARNING, "Error flushing channel\n");
944
945 }
946
947 /* Remove the conference from the list and free it.
948    We assume that this was called while holding conflock. */
949 static int conf_free(struct ast_conference *conf)
950 {
951         int x;
952         
953         AST_LIST_REMOVE(&confs, conf, list);
954         manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
955
956         if (conf->recording == MEETME_RECORD_ACTIVE) {
957                 conf->recording = MEETME_RECORD_TERMINATE;
958                 AST_LIST_UNLOCK(&confs);
959                 while (1) {
960                         AST_LIST_LOCK(&confs);
961                         if (conf->recording == MEETME_RECORD_OFF)
962                                 break;
963                         AST_LIST_UNLOCK(&confs);
964                 }
965         }
966
967         for (x=0;x<AST_FRAME_BITS;x++) {
968                 if (conf->transframe[x])
969                         ast_frfree(conf->transframe[x]);
970                 if (conf->transpath[x])
971                         ast_translator_free_path(conf->transpath[x]);
972         }
973         if (conf->origframe)
974                 ast_frfree(conf->origframe);
975         if (conf->lchan)
976                 ast_hangup(conf->lchan);
977         if (conf->chan)
978                 ast_hangup(conf->chan);
979         else
980                 close(conf->fd);
981         
982         free(conf);
983
984         return 0;
985 }
986
987 static void conf_queue_dtmf(struct ast_conference *conf, int digit)
988 {
989         struct ast_conf_user *user;
990         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
991                 user->dtmf = digit;
992         }
993 }
994
995 static void conf_queue_control(struct ast_conference *conf, int control)
996 {
997         struct ast_conf_user *user;
998         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
999                 user->control = control;
1000         }
1001 }
1002
1003
1004 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
1005 {
1006         struct ast_conf_user *user = NULL;
1007         struct ast_conf_user *usr = NULL;
1008         int fd;
1009         struct zt_confinfo ztc, ztc_empty;
1010         struct ast_frame *f;
1011         struct ast_channel *c;
1012         struct ast_frame fr;
1013         int outfd;
1014         int ms;
1015         int nfds;
1016         int res;
1017         int flags;
1018         int retryzap;
1019         int origfd;
1020         int musiconhold = 0;
1021         int firstpass = 0;
1022         int lastmarked = 0;
1023         int currentmarked = 0;
1024         int ret = -1;
1025         int x;
1026         int menu_active = 0;
1027         int using_pseudo = 0;
1028         int duration=20;
1029         int hr, min, sec;
1030         int sent_event = 0;
1031         time_t now;
1032         struct ast_dsp *dsp=NULL;
1033         struct ast_app *app;
1034         const char *agifile;
1035         const char *agifiledefault = "conf-background.agi";
1036         char meetmesecs[30] = "";
1037         char exitcontext[AST_MAX_CONTEXT] = "";
1038         char recordingtmp[AST_MAX_EXTENSION] = "";
1039         char members[10] = "";
1040         int dtmf, opt_waitmarked_timeout = 0;
1041         time_t timeout = 0;
1042         ZT_BUFFERINFO bi;
1043         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
1044         char *buf = __buf + AST_FRIENDLY_OFFSET;
1045
1046         if (!(user = ast_calloc(1, sizeof(*user)))) {
1047                 AST_LIST_LOCK(&confs);
1048                 conf->refcount--;
1049                 if (!conf->refcount){
1050                         conf_free(conf);
1051                 }
1052                 AST_LIST_UNLOCK(&confs);
1053                 return ret;
1054         }
1055
1056         /* Possible timeout waiting for marked user */
1057         if ((confflags & CONFFLAG_WAITMARKED) &&
1058                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
1059                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
1060                 (opt_waitmarked_timeout > 0)) {
1061                 timeout = time(NULL) + opt_waitmarked_timeout;
1062         }
1063
1064         if (confflags & CONFFLAG_RECORDCONF) {
1065                 if (!conf->recordingfilename) {
1066                         conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
1067                         if (!conf->recordingfilename) {
1068                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
1069                                 conf->recordingfilename = ast_strdupa(recordingtmp);
1070                         }
1071                         conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
1072                         if (!conf->recordingformat) {
1073                                 snprintf(recordingtmp, sizeof(recordingtmp), "wav");
1074                                 conf->recordingformat = ast_strdupa(recordingtmp);
1075                         }
1076                         ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
1077                                     conf->confno, conf->recordingfilename, conf->recordingformat);
1078                 }
1079         }
1080
1081         if ((conf->recording == MEETME_RECORD_OFF) && ((confflags & CONFFLAG_RECORDCONF) || (conf->lchan))) {
1082                 pthread_attr_init(&conf->attr);
1083                 pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
1084                 ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
1085         }
1086
1087         time(&user->jointime);
1088
1089         if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
1090                 /* Sorry, but this conference is locked! */     
1091                 if (!ast_streamfile(chan, "conf-locked", chan->language))
1092                         ast_waitstream(chan, "");
1093                 goto outrun;
1094         }
1095
1096         if (confflags & CONFFLAG_MARKEDUSER)
1097                 conf->markedusers++;
1098       
1099         ast_mutex_lock(&conf->playlock);
1100
1101         if (AST_LIST_EMPTY(&conf->userlist))
1102                 user->user_no = 1;
1103         else
1104                 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
1105
1106         AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
1107
1108         user->chan = chan;
1109         user->userflags = confflags;
1110         user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
1111         user->talking = -1;
1112         conf->users++;
1113         /* Update table */
1114         snprintf(members, sizeof(members), "%d", conf->users);
1115         ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
1116
1117         /* This device changed state now - if this is the first user */
1118         if (conf->users == 1)
1119                 ast_device_state_changed("meetme:%s", conf->confno);
1120         if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1121                 ast_device_state_changed("SLA:%s", conf->confno + 4);
1122
1123         ast_mutex_unlock(&conf->playlock);
1124
1125         if (confflags & CONFFLAG_EXIT_CONTEXT) {
1126                 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
1127                         ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
1128                 else if (!ast_strlen_zero(chan->macrocontext)) 
1129                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
1130                 else
1131                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
1132         }
1133
1134         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1135                 snprintf(user->namerecloc, sizeof(user->namerecloc),
1136                          "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
1137                          conf->confno, user->user_no);
1138                 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
1139                         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
1140                 else
1141                         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
1142                 if (res == -1)
1143                         goto outrun;
1144         }
1145
1146         if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
1147                 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
1148                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1149                                 ast_waitstream(chan, "");
1150                 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
1151                         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
1152                                 ast_waitstream(chan, "");
1153         }
1154
1155         if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
1156                 int keepplaying = 1;
1157
1158                 if (conf->users == 2) { 
1159                         if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
1160                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1161                                 ast_stopstream(chan);
1162                                 if (res > 0)
1163                                         keepplaying=0;
1164                                 else if (res == -1)
1165                                         goto outrun;
1166                         }
1167                 } else { 
1168                         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
1169                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1170                                 ast_stopstream(chan);
1171                                 if (res > 0)
1172                                         keepplaying=0;
1173                                 else if (res == -1)
1174                                         goto outrun;
1175                         }
1176                         if (keepplaying) {
1177                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1178                                 if (res > 0)
1179                                         keepplaying=0;
1180                                 else if (res == -1)
1181                                         goto outrun;
1182                         }
1183                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
1184                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1185                                 ast_stopstream(chan);
1186                                 if (res > 0)
1187                                         keepplaying=0;
1188                                 else if (res == -1) 
1189                                         goto outrun;
1190                         }
1191                 }
1192         }
1193
1194         ast_indicate(chan, -1);
1195
1196         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1197                 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
1198                 goto outrun;
1199         }
1200
1201         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
1202                 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
1203                 goto outrun;
1204         }
1205
1206         retryzap = strcasecmp(chan->tech->type, "Zap");
1207         user->zapchannel = !retryzap;
1208
1209  zapretry:
1210         origfd = chan->fds[0];
1211         if (retryzap) {
1212                 fd = open("/dev/zap/pseudo", O_RDWR);
1213                 if (fd < 0) {
1214                         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1215                         goto outrun;
1216                 }
1217                 using_pseudo = 1;
1218                 /* Make non-blocking */
1219                 flags = fcntl(fd, F_GETFL);
1220                 if (flags < 0) {
1221                         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
1222                         close(fd);
1223                         goto outrun;
1224                 }
1225                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
1226                         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
1227                         close(fd);
1228                         goto outrun;
1229                 }
1230                 /* Setup buffering information */
1231                 memset(&bi, 0, sizeof(bi));
1232                 bi.bufsize = CONF_SIZE/2;
1233                 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
1234                 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
1235                 bi.numbufs = audio_buffers;
1236                 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
1237                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
1238                         close(fd);
1239                         goto outrun;
1240                 }
1241                 x = 1;
1242                 if (ioctl(fd, ZT_SETLINEAR, &x)) {
1243                         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
1244                         close(fd);
1245                         goto outrun;
1246                 }
1247                 nfds = 1;
1248         } else {
1249                 /* XXX Make sure we're not running on a pseudo channel XXX */
1250                 fd = chan->fds[0];
1251                 nfds = 0;
1252         }
1253         memset(&ztc, 0, sizeof(ztc));
1254         memset(&ztc_empty, 0, sizeof(ztc_empty));
1255         /* Check to see if we're in a conference... */
1256         ztc.chan = 0;   
1257         if (ioctl(fd, ZT_GETCONF, &ztc)) {
1258                 ast_log(LOG_WARNING, "Error getting conference\n");
1259                 close(fd);
1260                 goto outrun;
1261         }
1262         if (ztc.confmode) {
1263                 /* Whoa, already in a conference...  Retry... */
1264                 if (!retryzap) {
1265                         if (option_debug)
1266                                 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
1267                         retryzap = 1;
1268                         goto zapretry;
1269                 }
1270         }
1271         memset(&ztc, 0, sizeof(ztc));
1272         /* Add us to the conference */
1273         ztc.chan = 0;   
1274         ztc.confno = conf->zapconf;
1275
1276         ast_mutex_lock(&conf->playlock);
1277
1278         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
1279                 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
1280                         if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1281                                 ast_waitstream(conf->chan, "");
1282                         if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
1283                                 ast_waitstream(conf->chan, "");
1284                 }
1285         }
1286
1287         if (confflags & CONFFLAG_MONITOR)
1288                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1289         else if (confflags & CONFFLAG_TALKER)
1290                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1291         else 
1292                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1293
1294         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1295                 ast_log(LOG_WARNING, "Error setting conference\n");
1296                 close(fd);
1297                 ast_mutex_unlock(&conf->playlock);
1298                 goto outrun;
1299         }
1300         if (option_debug)
1301                 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
1302
1303         if (!sent_event) {
1304                 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
1305                               "Channel: %s\r\n"
1306                               "Uniqueid: %s\r\n"
1307                               "Meetme: %s\r\n"
1308                               "Usernum: %d\r\n",
1309                               chan->name, chan->uniqueid, conf->confno, user->user_no);
1310                 sent_event = 1;
1311         }
1312
1313         if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
1314                 firstpass = 1;
1315                 if (!(confflags & CONFFLAG_QUIET))
1316                         if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
1317                                 conf_play(chan, conf, ENTER);
1318         }
1319
1320         ast_mutex_unlock(&conf->playlock);
1321
1322         conf_flush(fd, chan);
1323
1324         if (confflags & CONFFLAG_AGI) {
1325                 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1326                    or use default filename of conf-background.agi */
1327
1328                 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
1329                 if (!agifile)
1330                         agifile = agifiledefault;
1331
1332                 if (user->zapchannel) {
1333                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
1334                         x = 1;
1335                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1336                 }
1337                 /* Find a pointer to the agi app and execute the script */
1338                 app = pbx_findapp("agi");
1339                 if (app) {
1340                         char *s = ast_strdupa(agifile);
1341                         ret = pbx_exec(chan, app, s);
1342                 } else {
1343                         ast_log(LOG_WARNING, "Could not find application (agi)\n");
1344                         ret = -2;
1345                 }
1346                 if (user->zapchannel) {
1347                         /*  Remove CONFMUTE mode on Zap channel */
1348                         x = 0;
1349                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1350                 }
1351         } else {
1352                 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
1353                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1354                         x = 1;
1355                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1356                 }       
1357                 if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER) && !(dsp = ast_dsp_new())) {
1358                         ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
1359                         res = -1;
1360                 }
1361                 for(;;) {
1362                         int menu_was_active = 0;
1363
1364                         outfd = -1;
1365                         ms = -1;
1366
1367                         if (timeout && time(NULL) >= timeout)
1368                                 break;
1369
1370                         /* if we have just exited from the menu, and the user had a channel-driver
1371                            volume adjustment, restore it
1372                         */
1373                         if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
1374                                 set_talk_volume(user, user->listen.desired);
1375
1376                         menu_was_active = menu_active;
1377
1378                         currentmarked = conf->markedusers;
1379                         if (!(confflags & CONFFLAG_QUIET) &&
1380                             (confflags & CONFFLAG_MARKEDUSER) &&
1381                             (confflags & CONFFLAG_WAITMARKED) &&
1382                             lastmarked == 0) {
1383                                 if (currentmarked == 1 && conf->users > 1) {
1384                                         ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1385                                         if (conf->users - 1 == 1) {
1386                                                 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
1387                                                         ast_waitstream(chan, "");
1388                                         } else {
1389                                                 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
1390                                                         ast_waitstream(chan, "");
1391                                         }
1392                                 }
1393                                 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
1394                                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1395                                                 ast_waitstream(chan, "");
1396                         }
1397
1398                         c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
1399                         
1400                         
1401                         /* Update the struct with the actual confflags */
1402                         user->userflags = confflags;
1403                         
1404                         if (confflags & CONFFLAG_WAITMARKED) {
1405                                 if(currentmarked == 0) {
1406                                         if (lastmarked != 0) {
1407                                                 if (!(confflags & CONFFLAG_QUIET))
1408                                                         if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
1409                                                                 ast_waitstream(chan, "");
1410                                                 if (confflags & CONFFLAG_MARKEDEXIT) {
1411                                                         if (confflags & CONFFLAG_KICK_CONTINUE)
1412                                                                 ret = 0;
1413                                                         break;
1414                                                 } else {
1415                                                         ztc.confmode = ZT_CONF_CONF;
1416                                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1417                                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1418                                                                 close(fd);
1419                                                                 goto outrun;
1420                                                         }
1421                                                 }
1422                                         }
1423                                         if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
1424                                                 ast_moh_start(chan, NULL, NULL);
1425                                                 musiconhold = 1;
1426                                         } else {
1427                                                 ztc.confmode = ZT_CONF_CONF;
1428                                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1429                                                         ast_log(LOG_WARNING, "Error setting conference\n");
1430                                                         close(fd);
1431                                                         goto outrun;
1432                                                 }
1433                                         }
1434                                 } else if(currentmarked >= 1 && lastmarked == 0) {
1435                                         /* Marked user entered, so cancel timeout */
1436                                         timeout = 0;
1437                                         if (confflags & CONFFLAG_MONITOR)
1438                                                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1439                                         else if (confflags & CONFFLAG_TALKER)
1440                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1441                                         else
1442                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1443                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1444                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1445                                                 close(fd);
1446                                                 goto outrun;
1447                                         }
1448                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
1449                                                 ast_moh_stop(chan);
1450                                                 musiconhold = 0;
1451                                         }
1452                                         if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1453                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1454                                                         ast_waitstream(chan, "");
1455                                                 conf_play(chan, conf, ENTER);
1456                                         }
1457                                 }
1458                         }
1459
1460                         /* trying to add moh for single person conf */
1461                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1462                                 if (conf->users == 1) {
1463                                         if (musiconhold == 0) {
1464                                                 ast_moh_start(chan, NULL, NULL);
1465                                                 musiconhold = 1;
1466                                         } 
1467                                 } else {
1468                                         if (musiconhold) {
1469                                                 ast_moh_stop(chan);
1470                                                 musiconhold = 0;
1471                                         }
1472                                 }
1473                         }
1474                         
1475                         /* Leave if the last marked user left */
1476                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1477                                 if (confflags & CONFFLAG_KICK_CONTINUE)
1478                                         ret = 0;
1479                                 else
1480                                         ret = -1;
1481                                 break;
1482                         }
1483         
1484                         /* Check if my modes have changed */
1485
1486                         /* If I should be muted but am still talker, mute me */
1487                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1488                                 ztc.confmode ^= ZT_CONF_TALKER;
1489                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1490                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1491                                         ret = -1;
1492                                         break;
1493                                 }
1494
1495                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1496                                                 "Channel: %s\r\n"
1497                                                 "Uniqueid: %s\r\n"
1498                                                 "Meetme: %s\r\n"
1499                                                 "Usernum: %i\r\n"
1500                                                 "Status: on\r\n",
1501                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1502                         }
1503
1504                         /* If I should be un-muted but am not talker, un-mute me */
1505                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1506                                 ztc.confmode |= ZT_CONF_TALKER;
1507                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1508                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1509                                         ret = -1;
1510                                         break;
1511                                 }
1512
1513                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1514                                                 "Channel: %s\r\n"
1515                                                 "Uniqueid: %s\r\n"
1516                                                 "Meetme: %s\r\n"
1517                                                 "Usernum: %i\r\n"
1518                                                 "Status: off\r\n",
1519                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1520                         }
1521
1522                         /* If I have been kicked, exit the conference */
1523                         if (user->adminflags & ADMINFLAG_KICKME) {
1524                                 //You have been kicked.
1525                                 if (!ast_streamfile(chan, "conf-kicked", chan->language))
1526                                         ast_waitstream(chan, "");
1527                                 ret = 0;
1528                                 break;
1529                         }
1530
1531                         if (c) {
1532                                 if (c->fds[0] != origfd) {
1533                                         if (using_pseudo) {
1534                                                 /* Kill old pseudo */
1535                                                 close(fd);
1536                                                 using_pseudo = 0;
1537                                         }
1538                                         if (option_debug)
1539                                                 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
1540                                         retryzap = strcasecmp(c->tech->type, "Zap");
1541                                         user->zapchannel = !retryzap;
1542                                         goto zapretry;
1543                                 }
1544                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1545                                         f = ast_read_noaudio(c);
1546                                 else
1547                                         f = ast_read(c);
1548                                 if (!f)
1549                                         break;
1550                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1551                                         if (user->talk.actual)
1552                                                 ast_frame_adjust_volume(f, user->talk.actual);
1553
1554                                         if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
1555                                                 int totalsilence;
1556
1557                                                 if (user->talking == -1)
1558                                                         user->talking = 0;
1559
1560                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1561                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1562                                                         user->talking = 1;
1563                                                         if (confflags & CONFFLAG_MONITORTALKER)
1564                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1565                                                                       "Channel: %s\r\n"
1566                                                                       "Uniqueid: %s\r\n"
1567                                                                       "Meetme: %s\r\n"
1568                                                                       "Usernum: %d\r\n"
1569                                                                       "Status: on\r\n",
1570                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1571                                                 }
1572                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1573                                                         user->talking = 0;
1574                                                         if (confflags & CONFFLAG_MONITORTALKER)
1575                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1576                                                                       "Channel: %s\r\n"
1577                                                                       "Uniqueid: %s\r\n"
1578                                                                       "Meetme: %s\r\n"
1579                                                                       "Usernum: %d\r\n"
1580                                                                       "Status: off\r\n",
1581                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1582                                                 }
1583                                         }
1584                                         if (using_pseudo) {
1585                                                 /* Absolutely do _not_ use careful_write here...
1586                                                    it is important that we read data from the channel
1587                                                    as fast as it arrives, and feed it into the conference.
1588                                                    The buffering in the pseudo channel will take care of any
1589                                                    timing differences, unless they are so drastic as to lose
1590                                                    audio frames (in which case carefully writing would only
1591                                                    have delayed the audio even further).
1592                                                 */
1593                                                 /* As it turns out, we do want to use careful write.  We just
1594                                                    don't want to block, but we do want to at least *try*
1595                                                    to write out all the samples.
1596                                                  */
1597                                                 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
1598                                                         careful_write(fd, f->data, f->datalen, 0);
1599                                         }
1600                                 } else if ((f->frametype == AST_FRAME_DTMF) && 
1601                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1602                                         conf_queue_dtmf(conf, f->subclass);
1603                                 } else if ((f->frametype == AST_FRAME_CONTROL) && 
1604                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1605                                         conf_queue_control(conf, f->subclass);
1606                                         if (f->subclass == AST_CONTROL_HOLD)
1607                                                 confflags |= CONFFLAG_HOLD;
1608                                         else if (f->subclass == AST_CONTROL_UNHOLD)
1609                                                 confflags &= ~CONFFLAG_HOLD;
1610                                         user->userflags = confflags;
1611                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1612                                         char tmp[2];
1613
1614                                         tmp[0] = f->subclass;
1615                                         tmp[1] = '\0';
1616                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1617                                                 if (option_debug)
1618                                                         ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1619                                                 ret = 0;
1620                                                 ast_frfree(f);
1621                                                 break;
1622                                         } else if (option_debug > 1)
1623                                                 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1624                                 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1625                                         ret = 0;
1626                                         ast_frfree(f);
1627                                         break;
1628                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
1629                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
1630                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1631                                                 close(fd);
1632                                                 ast_frfree(f);
1633                                                 goto outrun;
1634                                         }
1635
1636                                         /* if we are entering the menu, and the user has a channel-driver
1637                                            volume adjustment, clear it
1638                                         */
1639                                         if (!menu_active && user->talk.desired && !user->talk.actual)
1640                                                 set_talk_volume(user, 0);
1641
1642                                         if (musiconhold) {
1643                                                 ast_moh_stop(chan);
1644                                         }
1645                                         if ((confflags & CONFFLAG_ADMIN)) {
1646                                                 /* Admin menu */
1647                                                 if (!menu_active) {
1648                                                         menu_active = 1;
1649                                                         /* Record this sound! */
1650                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
1651                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1652                                                                 ast_stopstream(chan);
1653                                                         } else 
1654                                                                 dtmf = 0;
1655                                                 } else 
1656                                                         dtmf = f->subclass;
1657                                                 if (dtmf) {
1658                                                         switch(dtmf) {
1659                                                         case '1': /* Un/Mute */
1660                                                                 menu_active = 0;
1661
1662                                                                 /* for admin, change both admin and use flags */
1663                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
1664                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1665                                                                 else
1666                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1667
1668                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1669                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1670                                                                                 ast_waitstream(chan, "");
1671                                                                 } else {
1672                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1673                                                                                 ast_waitstream(chan, "");
1674                                                                 }
1675                                                                 break;
1676                                                         case '2': /* Un/Lock the Conference */
1677                                                                 menu_active = 0;
1678                                                                 if (conf->locked) {
1679                                                                         conf->locked = 0;
1680                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
1681                                                                                 ast_waitstream(chan, "");
1682                                                                 } else {
1683                                                                         conf->locked = 1;
1684                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
1685                                                                                 ast_waitstream(chan, "");
1686                                                                 }
1687                                                                 break;
1688                                                         case '3': /* Eject last user */
1689                                                                 menu_active = 0;
1690                                                                 usr = AST_LIST_LAST(&conf->userlist);
1691                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
1692                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
1693                                                                                 ast_waitstream(chan, "");
1694                                                                 } else 
1695                                                                         usr->adminflags |= ADMINFLAG_KICKME;
1696                                                                 ast_stopstream(chan);
1697                                                                 break;  
1698                                                         case '4':
1699                                                                 tweak_listen_volume(user, VOL_DOWN);
1700                                                                 break;
1701                                                         case '6':
1702                                                                 tweak_listen_volume(user, VOL_UP);
1703                                                                 break;
1704                                                         case '7':
1705                                                                 tweak_talk_volume(user, VOL_DOWN);
1706                                                                 break;
1707                                                         case '8':
1708                                                                 menu_active = 0;
1709                                                                 break;
1710                                                         case '9':
1711                                                                 tweak_talk_volume(user, VOL_UP);
1712                                                                 break;
1713                                                         default:
1714                                                                 menu_active = 0;
1715                                                                 /* Play an error message! */
1716                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1717                                                                         ast_waitstream(chan, "");
1718                                                                 break;
1719                                                         }
1720                                                 }
1721                                         } else {
1722                                                 /* User menu */
1723                                                 if (!menu_active) {
1724                                                         menu_active = 1;
1725                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
1726                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1727                                                                 ast_stopstream(chan);
1728                                                         } else
1729                                                                 dtmf = 0;
1730                                                 } else 
1731                                                         dtmf = f->subclass;
1732                                                 if (dtmf) {
1733                                                         switch(dtmf) {
1734                                                         case '1': /* Un/Mute */
1735                                                                 menu_active = 0;
1736
1737                                                                 /* user can only toggle the self-muted state */
1738                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
1739
1740                                                                 /* they can't override the admin mute state */
1741                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1742                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1743                                                                                 ast_waitstream(chan, "");
1744                                                                 } else {
1745                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1746                                                                                 ast_waitstream(chan, "");
1747                                                                 }
1748                                                                 break;
1749                                                         case '4':
1750                                                                 tweak_listen_volume(user, VOL_DOWN);
1751                                                                 break;
1752                                                         case '6':
1753                                                                 tweak_listen_volume(user, VOL_UP);
1754                                                                 break;
1755                                                         case '7':
1756                                                                 tweak_talk_volume(user, VOL_DOWN);
1757                                                                 break;
1758                                                         case '8':
1759                                                                 menu_active = 0;
1760                                                                 break;
1761                                                         case '9':
1762                                                                 tweak_talk_volume(user, VOL_UP);
1763                                                                 break;
1764                                                         default:
1765                                                                 menu_active = 0;
1766                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1767                                                                         ast_waitstream(chan, "");
1768                                                                 break;
1769                                                         }
1770                                                 }
1771                                         }
1772                                         if (musiconhold)
1773                                                 ast_moh_start(chan, NULL, NULL);
1774
1775                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1776                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1777                                                 close(fd);
1778                                                 ast_frfree(f);
1779                                                 goto outrun;
1780                                         }
1781
1782                                         conf_flush(fd, chan);
1783                                 } else if (option_debug) {
1784                                         ast_log(LOG_DEBUG,
1785                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
1786                                                 chan->name, f->frametype, f->subclass);
1787                                 }
1788                                 ast_frfree(f);
1789                         } else if (outfd > -1) {
1790                                 if (user->control) {
1791                                         switch(user->control) {
1792                                         case AST_CONTROL_RINGING:
1793                                         case AST_CONTROL_PROGRESS:
1794                                         case AST_CONTROL_PROCEEDING:
1795                                                 ast_indicate(chan, user->control);
1796                                                 break;
1797                                         case AST_CONTROL_ANSWER:
1798                                                 if (chan->_state != AST_STATE_UP)
1799                                                         ast_answer(chan);
1800                                                 break;
1801                                         }
1802                                         user->control = 0;
1803                                         if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1804                                                 ast_device_state_changed("SLA:%s", conf->confno + 4);
1805                                         continue;
1806                                 }
1807                                 if (user->dtmf) {
1808                                         memset(&fr, 0, sizeof(fr));
1809                                         fr.frametype = AST_FRAME_DTMF;
1810                                         fr.subclass = user->dtmf;
1811                                         if (ast_write(chan, &fr) < 0) {
1812                                                 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1813                                         }
1814                                         user->dtmf = 0;
1815                                         continue;
1816                                 }
1817                                 res = read(outfd, buf, CONF_SIZE);
1818                                 if (res > 0) {
1819                                         memset(&fr, 0, sizeof(fr));
1820                                         fr.frametype = AST_FRAME_VOICE;
1821                                         fr.subclass = AST_FORMAT_SLINEAR;
1822                                         fr.datalen = res;
1823                                         fr.samples = res/2;
1824                                         fr.data = buf;
1825                                         fr.offset = AST_FRIENDLY_OFFSET;
1826                                         if (!user->listen.actual && 
1827                                                 ((confflags & CONFFLAG_MONITOR) || 
1828                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
1829                                                  (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
1830                                                  )) {
1831                                                 int index;
1832                                                 for (index=0;index<AST_FRAME_BITS;index++)
1833                                                         if (chan->rawwriteformat & (1 << index))
1834                                                                 break;
1835                                                 if (index >= AST_FRAME_BITS)
1836                                                         goto bailoutandtrynormal;
1837                                                 ast_mutex_lock(&conf->listenlock);
1838                                                 if (!conf->transframe[index]) {
1839                                                         if (conf->origframe) {
1840                                                                 if (!conf->transpath[index])
1841                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
1842                                                                 if (conf->transpath[index]) {
1843                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
1844                                                                         if (!conf->transframe[index])
1845                                                                                 conf->transframe[index] = &ast_null_frame;
1846                                                                 }
1847                                                         }
1848                                                 }
1849                                                 if (conf->transframe[index]) {
1850                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
1851                                                                 if (ast_write(chan, conf->transframe[index]))
1852                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1853                                                         }
1854                                                 } else {
1855                                                         ast_mutex_unlock(&conf->listenlock);
1856                                                         goto bailoutandtrynormal;
1857                                                 }
1858                                                 ast_mutex_unlock(&conf->listenlock);
1859                                         } else {
1860 bailoutandtrynormal:                                    
1861                                                 if (user->listen.actual)
1862                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
1863                                                 if (ast_write(chan, &fr) < 0) {
1864                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1865                                                 }
1866                                         }
1867                                 } else 
1868                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
1869                         }
1870                         lastmarked = currentmarked;
1871                 }
1872         }
1873
1874         if (musiconhold)
1875                 ast_moh_stop(chan);
1876         
1877         if (using_pseudo)
1878                 close(fd);
1879         else {
1880                 /* Take out of conference */
1881                 ztc.chan = 0;   
1882                 ztc.confno = 0;
1883                 ztc.confmode = 0;
1884                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1885                         ast_log(LOG_WARNING, "Error setting conference\n");
1886                 }
1887         }
1888
1889         reset_volumes(user);
1890
1891         AST_LIST_LOCK(&confs);
1892         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
1893                 conf_play(chan, conf, LEAVE);
1894
1895         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1896                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
1897                         if ((conf->chan) && (conf->users > 1)) {
1898                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1899                                         ast_waitstream(conf->chan, "");
1900                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
1901                                         ast_waitstream(conf->chan, "");
1902                         }
1903                         ast_filedelete(user->namerecloc, NULL);
1904                 }
1905         }
1906         AST_LIST_UNLOCK(&confs);
1907
1908  outrun:
1909         AST_LIST_LOCK(&confs);
1910
1911         if (dsp)
1912                 ast_dsp_free(dsp);
1913         
1914         if (user->user_no) { /* Only cleanup users who really joined! */
1915                 now = time(NULL);
1916                 hr = (now - user->jointime) / 3600;
1917                 min = ((now - user->jointime) % 3600) / 60;
1918                 sec = (now - user->jointime) % 60;
1919
1920                 if (sent_event) {
1921                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
1922                                       "Channel: %s\r\n"
1923                                       "Uniqueid: %s\r\n"
1924                                       "Meetme: %s\r\n"
1925                                       "Usernum: %d\r\n"
1926                                       "CallerIDNum: %s\r\n"
1927                                       "CallerIDName: %s\r\n"
1928                                       "Duration: %ld\r\n",
1929                                       chan->name, chan->uniqueid, conf->confno, 
1930                                       user->user_no,
1931                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
1932                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
1933                                       (long)(now - user->jointime));
1934                 }
1935
1936                 conf->users--;
1937                 conf->refcount--;
1938                 /* Update table */
1939                 snprintf(members, sizeof(members), "%d", conf->users);
1940                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
1941                 if (confflags & CONFFLAG_MARKEDUSER) 
1942                         conf->markedusers--;
1943                 /* Remove ourselves from the list */
1944                 AST_LIST_REMOVE(&conf->userlist, user, list);
1945
1946                 /* Change any states */
1947                 if (!conf->users)
1948                         ast_device_state_changed("meetme:%s", conf->confno);
1949                 if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1950                         ast_device_state_changed("SLA:%s", conf->confno + 4);
1951
1952                 if (AST_LIST_EMPTY(&conf->userlist)) {
1953                         /* close this one when no more users and no references*/
1954                         if (!conf->refcount)
1955                                 conf_free(conf);
1956                 }
1957                 /* Return the number of seconds the user was in the conf */
1958                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
1959                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
1960         }
1961         free(user);
1962         AST_LIST_UNLOCK(&confs);
1963
1964         return ret;
1965 }
1966
1967 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
1968                                                  char *dynamic_pin, int refcount, struct ast_flags *confflags)
1969 {
1970         struct ast_variable *var;
1971         struct ast_conference *cnf;
1972
1973         /* Check first in the conference list */
1974         AST_LIST_LOCK(&confs);
1975         AST_LIST_TRAVERSE(&confs, cnf, list) {
1976                 if (!strcmp(confno, cnf->confno)) 
1977                         break;
1978         }
1979         if (cnf) {
1980                 cnf->refcount += refcount;
1981         }
1982         AST_LIST_UNLOCK(&confs);
1983
1984         if (!cnf) {
1985                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
1986                 
1987                 var = ast_load_realtime("meetme", "confno", confno, NULL);
1988
1989                 if (!var)
1990                         return NULL;
1991
1992                 while (var) {
1993                         if (!strcasecmp(var->name, "pin")) {
1994                                 pin = ast_strdupa(var->value);
1995                         } else if (!strcasecmp(var->name, "adminpin")) {
1996                                 pinadmin = ast_strdupa(var->value);
1997                         }
1998                         var = var->next;
1999                 }
2000                 ast_variables_destroy(var);
2001                 
2002                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
2003         }
2004
2005         if (cnf) {
2006                 if (confflags && !cnf->chan &&
2007                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2008                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2009                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2010                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2011                 }
2012                 
2013                 if (confflags && !cnf->chan &&
2014                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2015                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2016                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2017                 }
2018         }
2019
2020         return cnf;
2021 }
2022
2023
2024 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2025                                         char *dynamic_pin, int refcount, struct ast_flags *confflags)
2026 {
2027         struct ast_config *cfg;
2028         struct ast_variable *var;
2029         struct ast_conference *cnf;
2030         char *parse;
2031         AST_DECLARE_APP_ARGS(args,
2032                 AST_APP_ARG(confno);
2033                 AST_APP_ARG(pin);
2034                 AST_APP_ARG(pinadmin);
2035         );
2036
2037         /* Check first in the conference list */
2038         AST_LIST_LOCK(&confs);
2039         AST_LIST_TRAVERSE(&confs, cnf, list) {
2040                 if (!strcmp(confno, cnf->confno)) 
2041                         break;
2042         }
2043         if (cnf){
2044                 cnf->refcount += refcount;
2045         }
2046         AST_LIST_UNLOCK(&confs);
2047
2048         if (!cnf) {
2049                 if (dynamic) {
2050                         /* No need to parse meetme.conf */
2051                         if (option_debug)
2052                                 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
2053                         if (dynamic_pin) {
2054                                 if (dynamic_pin[0] == 'q') {
2055                                         /* Query the user to enter a PIN */
2056                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
2057                                                 return NULL;
2058                                 }
2059                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
2060                         } else {
2061                                 cnf = build_conf(confno, "", "", make, dynamic, refcount);
2062                         }
2063                 } else {
2064                         /* Check the config */
2065                         cfg = ast_config_load(CONFIG_FILE_NAME);
2066                         if (!cfg) {
2067                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2068                                 return NULL;
2069                         }
2070                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2071                                 if (strcasecmp(var->name, "conf"))
2072                                         continue;
2073                                 
2074                                 if (!(parse = ast_strdupa(var->value)))
2075                                         return NULL;
2076                                 
2077                                 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2078                                 if (!strcasecmp(args.confno, confno)) {
2079                                         /* Bingo it's a valid conference */
2080                                         cnf = build_conf(args.confno,
2081                                                         S_OR(args.pin, ""),
2082                                                         S_OR(args.pinadmin, ""),
2083                                                         make, dynamic, refcount);
2084                                         break;
2085                                 }
2086                         }
2087                         if (!var) {
2088                                 if (option_debug)
2089                                         ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
2090                         }
2091                         ast_config_destroy(cfg);
2092                 }
2093         } else if (dynamic_pin) {
2094                 /* Correct for the user selecting 'D' instead of 'd' to have
2095                    someone join into a conference that has already been created
2096                    with a pin. */
2097                 if (dynamic_pin[0] == 'q')
2098                         dynamic_pin[0] = '\0';
2099         }
2100
2101         if (cnf) {
2102                 if (confflags && !cnf->chan &&
2103                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2104                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2105                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2106                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2107                 }
2108                 
2109                 if (confflags && !cnf->chan &&
2110                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2111                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2112                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2113                 }
2114         }
2115
2116         return cnf;
2117 }
2118
2119 /*! \brief The MeetmeCount application */
2120 static int count_exec(struct ast_channel *chan, void *data)
2121 {
2122         struct ast_module_user *u;
2123         int res = 0;
2124         struct ast_conference *conf;
2125         int count;
2126         char *localdata;
2127         char val[80] = "0"; 
2128         AST_DECLARE_APP_ARGS(args,
2129                 AST_APP_ARG(confno);
2130                 AST_APP_ARG(varname);
2131         );
2132
2133         if (ast_strlen_zero(data)) {
2134                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2135                 return -1;
2136         }
2137
2138         u = ast_module_user_add(chan);
2139         
2140         if (!(localdata = ast_strdupa(data))) {
2141                 ast_module_user_remove(u);
2142                 return -1;
2143         }
2144
2145         AST_STANDARD_APP_ARGS(args, localdata);
2146         
2147         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, NULL);
2148
2149         if (conf)
2150                 count = conf->users;
2151         else
2152                 count = 0;
2153
2154         if (!ast_strlen_zero(args.varname)){
2155                 /* have var so load it and exit */
2156                 snprintf(val, sizeof(val), "%d",count);
2157                 pbx_builtin_setvar_helper(chan, args.varname, val);
2158         } else {
2159                 if (chan->_state != AST_STATE_UP)
2160                         ast_answer(chan);
2161                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2162         }
2163         ast_module_user_remove(u);
2164
2165         return res;
2166 }
2167
2168 /*! \brief The meetme() application */
2169 static int conf_exec(struct ast_channel *chan, void *data)
2170 {
2171         int res=-1;
2172         struct ast_module_user *u;
2173         char confno[AST_MAX_EXTENSION] = "";
2174         int allowretry = 0;
2175         int retrycnt = 0;
2176         struct ast_conference *cnf;
2177         struct ast_flags confflags = {0};
2178         int dynamic = 0;
2179         int empty = 0, empty_no_pin = 0;
2180         int always_prompt = 0;
2181         char *notdata, *info, the_pin[AST_MAX_EXTENSION] = "";
2182         AST_DECLARE_APP_ARGS(args,
2183                 AST_APP_ARG(confno);
2184                 AST_APP_ARG(options);
2185                 AST_APP_ARG(pin);
2186         );
2187         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2188
2189         u = ast_module_user_add(chan);
2190
2191         if (ast_strlen_zero(data)) {
2192                 allowretry = 1;
2193                 notdata = "";
2194         } else {
2195                 notdata = data;
2196         }
2197         
2198         if (chan->_state != AST_STATE_UP)
2199                 ast_answer(chan);
2200
2201         info = ast_strdupa(notdata);
2202
2203         AST_STANDARD_APP_ARGS(args, info);      
2204
2205         if (args.confno) {
2206                 ast_copy_string(confno, args.confno, sizeof(confno));
2207                 if (ast_strlen_zero(confno)) {
2208                         allowretry = 1;
2209                 }
2210         }
2211         
2212         if (args.pin)
2213                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2214
2215         if (args.options) {
2216                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2217                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2218                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2219                         strcpy(the_pin, "q");
2220
2221                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2222                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2223                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2224         }
2225
2226         do {
2227                 if (retrycnt > 3)
2228                         allowretry = 0;
2229                 if (empty) {
2230                         int i, map[1024] = { 0, };
2231                         struct ast_config *cfg;
2232                         struct ast_variable *var;
2233                         int confno_int;
2234
2235                         AST_LIST_LOCK(&confs);
2236                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2237                                 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
2238                                         /* Disqualify in use conference */
2239                                         if (confno_int >= 0 && confno_int < 1024)
2240                                                 map[confno_int]++;
2241                                 }
2242                         }
2243                         AST_LIST_UNLOCK(&confs);
2244
2245                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2246                         if ((empty_no_pin) || (!dynamic)) {
2247                                 cfg = ast_config_load(CONFIG_FILE_NAME);
2248                                 if (cfg) {
2249                                         var = ast_variable_browse(cfg, "rooms");
2250                                         while (var) {
2251                                                 if (!strcasecmp(var->name, "conf")) {
2252                                                         char *stringp = ast_strdupa(var->value);
2253                                                         if (stringp) {
2254                                                                 char *confno_tmp = strsep(&stringp, "|,");
2255                                                                 int found = 0;
2256                                                                 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
2257                                                                         if ((confno_int >= 0) && (confno_int < 1024)) {
2258                                                                                 if (stringp && empty_no_pin) {
2259                                                                                         map[confno_int]++;
2260                                                                                 }
2261                                                                         }
2262                                                                 }
2263                                                                 if (!dynamic) {
2264                                                                         /* For static:  run through the list and see if this conference is empty */
2265                                                                         AST_LIST_LOCK(&confs);
2266                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2267                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2268                                                                                         /* The conference exists, therefore it's not empty */
2269                                                                                         found = 1;
2270                                                                                         break;
2271                                                                                 }
2272                                                                         }
2273                                                                         AST_LIST_UNLOCK(&confs);
2274                                                                         if (!found) {
2275                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2276                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2277                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2278                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2279                                                                                          * Case 3:  not empty_no_pin
2280                                                                                          */
2281                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2282                                                                                         break;
2283                                                                                         /* XXX the map is not complete (but we do have a confno) */
2284                                                                                 }
2285                                                                         }
2286                                                                 }
2287                                                         }
2288                                                 }
2289                                                 var = var->next;
2290                                         }
2291                                         ast_config_destroy(cfg);
2292                                 }
2293                         }
2294
2295                         /* Select first conference number not in use */
2296                         if (ast_strlen_zero(confno) && dynamic) {
2297                                 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
2298                                         if (!map[i]) {
2299                                                 snprintf(confno, sizeof(confno), "%d", i);
2300                                                 break;
2301                                         }
2302                                 }
2303                         }
2304
2305                         /* Not found? */
2306                         if (ast_strlen_zero(confno)) {
2307                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2308                                 if (!res)
2309                                         ast_waitstream(chan, "");
2310                         } else {
2311                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2312                                         if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
2313                                                 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2314                                                 if (!res) {
2315                                                         ast_waitstream(chan, "");
2316                                                         res = ast_say_digits(chan, confno_int, "", chan->language);
2317                                                 }
2318                                         }
2319                                 } else {
2320                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2321                                 }
2322                         }
2323                 }
2324
2325                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2326                         /* Prompt user for conference number */
2327                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2328                         if (res < 0) {
2329                                 /* Don't try to validate when we catch an error */
2330                                 confno[0] = '\0';
2331                                 allowretry = 0;
2332                                 break;
2333                         }
2334                 }
2335                 if (!ast_strlen_zero(confno)) {
2336                         /* Check the validity of the conference */
2337                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2338                         if (!cnf)
2339                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2340
2341                         if (!cnf) {
2342                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2343                                 if (!res)
2344                                         ast_waitstream(chan, "");
2345                                 res = -1;
2346                                 if (allowretry)
2347                                         confno[0] = '\0';
2348                         } else {
2349                                 if ((!ast_strlen_zero(cnf->pin) &&
2350                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2351                                     (!ast_strlen_zero(cnf->pinadmin) &&
2352                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2353                                         char pin[AST_MAX_EXTENSION]="";
2354                                         int j;
2355
2356                                         /* Allow the pin to be retried up to 3 times */
2357                                         for (j = 0; j < 3; j++) {
2358                                                 if (*the_pin && (always_prompt == 0)) {
2359                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2360                                                         res = 0;
2361                                                 } else {
2362                                                         /* Prompt user for pin if pin is required */
2363                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2364                                                 }
2365                                                 if (res >= 0) {
2366                                                         if (!strcasecmp(pin, cnf->pin) ||
2367                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2368                                                              !strcasecmp(pin, cnf->pinadmin))) {
2369                                                                 /* Pin correct */
2370                                                                 allowretry = 0;
2371                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
2372                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
2373                                                                 /* Run the conference */
2374                                                                 res = conf_run(chan, cnf, confflags.flags, optargs);
2375                                                                 break;
2376                                                         } else {
2377                                                                 /* Pin invalid */
2378                                                                 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
2379                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
2380                                                                         ast_stopstream(chan);
2381                                                                 }
2382                                                                 else {
2383                                                                         ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2384                                                                         break;
2385                                                                 }
2386                                                                 if (res < 0) {
2387                                                                         AST_LIST_LOCK(&confs);
2388                                                                         cnf->refcount--;
2389                                                                         if (!cnf->refcount){
2390                                                                                 conf_free(cnf);
2391                                                                         }
2392                                                                         AST_LIST_UNLOCK(&confs);
2393                                                                         break;
2394                                                                 }
2395                                                                 pin[0] = res;
2396                                                                 pin[1] = '\0';
2397                                                                 res = -1;
2398                                                                 if (allowretry)
2399                                                                         confno[0] = '\0';
2400                                                         }
2401                                                 } else {
2402                                                         /* failed when getting the pin */
2403                                                         res = -1;
2404                                                         allowretry = 0;
2405                                                         /* see if we need to get rid of the conference */
2406                                                         AST_LIST_LOCK(&confs);
2407                                                         cnf->refcount--;
2408                                                         if (!cnf->refcount) {
2409                                                                 conf_free(cnf);
2410                                                         }
2411                                                         AST_LIST_UNLOCK(&confs);
2412                                                         break;
2413                                                 }
2414
2415                                                 /* Don't retry pin with a static pin */
2416                                                 if (*the_pin && (always_prompt==0)) {
2417                                                         break;
2418                                                 }
2419                                         }
2420                                 } else {
2421                                         /* No pin required */
2422                                         allowretry = 0;
2423
2424                                         /* Run the conference */
2425                                         res = conf_run(chan, cnf, confflags.flags, optargs);
2426                                 }
2427                         }
2428                 }
2429         } while (allowretry);
2430         
2431         ast_module_user_remove(u);
2432         
2433         return res;
2434 }
2435
2436 struct sla_originate_helper {
2437         char tech[100];
2438         char data[200];
2439         char app[20];
2440         char appdata[100];
2441         char cid_name[100];
2442         char cid_num[100];
2443 };
2444
2445 static void *sla_originate(void *data)
2446 {
2447         struct sla_originate_helper *in = data;
2448         int reason = 0;
2449         struct ast_channel *chan = NULL;
2450
2451         ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, 99999, in->app, in->appdata, &reason, 1, 
2452                 S_OR(in->cid_num, NULL), 
2453                 S_OR(in->cid_name, NULL),
2454                 NULL, NULL, &chan);
2455         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2456         if (chan)
2457                 ast_channel_unlock(chan);
2458         free(in);
2459         return NULL;
2460 }
2461
2462 /*! Call in stations and trunk to the SLA */
2463 static void do_invite(struct ast_channel *orig, const char *tech, const char *dest, const char *app, const char *data)
2464 {
2465         struct sla_originate_helper *slal;
2466         pthread_attr_t attr;
2467         pthread_t th;
2468
2469         if (!(slal = ast_calloc(1, sizeof(*slal))))
2470                 return;
2471         
2472         ast_copy_string(slal->tech, tech, sizeof(slal->tech));
2473         ast_copy_string(slal->data, dest, sizeof(slal->data));
2474         ast_copy_string(slal->app, app, sizeof(slal->app));
2475         ast_copy_string(slal->appdata, data, sizeof(slal->appdata));
2476         if (orig->cid.cid_num)
2477                 ast_copy_string(slal->cid_num, orig->cid.cid_num, sizeof(slal->cid_num));
2478         if (orig->cid.cid_name)
2479                 ast_copy_string(slal->cid_name, orig->cid.cid_name, sizeof(slal->cid_name));
2480         pthread_attr_init(&attr);
2481         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2482         ast_pthread_create(&th, &attr, sla_originate, slal);
2483 }
2484
2485 static void invite_stations(struct ast_channel *orig, struct ast_sla *sla)
2486 {
2487         ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
2488                 do_invite(orig, iterator->tech, iterator->dest, "SLAStation", sla->name);
2489         });
2490 }
2491
2492 static void invite_trunk(struct ast_channel *orig, struct ast_sla *sla)
2493 {
2494         do_invite(orig, sla->trunktech, sla->trunkdest, "SLATrunk", sla->name);
2495 }
2496
2497
2498 static int sla_checkforhold(struct ast_conference *conf, int hangup)
2499 {
2500         struct ast_conf_user *user;
2501         struct ast_channel *onhold=NULL;
2502         int holdcount = 0;
2503         int stationcount = 0;
2504         int amonhold = 0;
2505         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2506                 if (user->userflags & CONFFLAG_SLA_STATION) {
2507                         stationcount++;
2508                         if ((user->userflags & CONFFLAG_HOLD)) {
2509                                 holdcount++;
2510                                 onhold = user->chan;
2511                         }
2512                 }
2513         }
2514         if ((holdcount == 1) && (stationcount == 1)) {
2515                 amonhold = 1;
2516                 if (hangup)
2517                         ast_softhangup(onhold, AST_SOFTHANGUP_EXPLICIT);
2518         } else if (holdcount && (stationcount == holdcount))
2519                 amonhold = 1;
2520         return amonhold;
2521 }
2522
2523
2524 /*! \brief The slas()/slat() application */
2525 static int sla_exec(struct ast_channel *chan, void *data, int trunk)
2526 {
2527         int res=-1;
2528         struct ast_module_user *u;
2529         char confno[AST_MAX_EXTENSION] = "";
2530         struct ast_sla *sla;
2531         struct ast_conference *cnf;
2532         char *info;
2533         struct ast_flags confflags = {0};
2534         int dynamic = 1;
2535         char *options[OPT_ARG_ARRAY_SIZE] = { NULL, };
2536         AST_DECLARE_APP_ARGS(args,
2537                 AST_APP_ARG(confno);
2538                 AST_APP_ARG(options);
2539         );
2540
2541         if (ast_strlen_zero(data)) {
2542                 ast_log(LOG_WARNING, "SLA%c requires an argument (line)\n", trunk ? 'T' : 'S');
2543                 return -1;
2544         }
2545
2546         info = ast_strdupa(data);
2547
2548         AST_STANDARD_APP_ARGS(args, info);      
2549
2550         if (ast_strlen_zero(args.confno)) {
2551                 ast_log(LOG_WARNING, "SLA%c requires an SLA line number\n", trunk ? 'T' : 'S');
2552                 return -1;
2553         }
2554         
2555         u = ast_module_user_add(chan);
2556
2557         if (args.options)
2558                 ast_app_parse_options(sla_opts, &confflags, NULL, args.options);
2559                 
2560         ast_set_flag(&confflags, CONFFLAG_QUIET|CONFFLAG_DYNAMIC);
2561         if (trunk)
2562                 ast_set_flag(&confflags, CONFFLAG_WAITMARKED|CONFFLAG_MARKEDEXIT|CONFFLAG_SLA_TRUNK);
2563         else
2564                 ast_set_flag(&confflags, CONFFLAG_MARKEDUSER|CONFFLAG_SLA_STATION);
2565
2566         sla = ASTOBJ_CONTAINER_FIND(&slas, args.confno);
2567         if (sla) {
2568                 snprintf(confno, sizeof(confno), "sla-%s", args.confno);
2569                 cnf = find_conf(chan, confno, 1, dynamic, "", 1, &confflags);
2570                 if (cnf) {
2571                         sla_checkforhold(cnf, 1);
2572                         if (!cnf->users) {
2573                                 if (trunk) {
2574                                         ast_indicate(chan, AST_CONTROL_RINGING);
2575                                         invite_stations(chan, sla);
2576                                 } else
2577                                         invite_trunk(chan, sla);
2578                         } else if (chan->_state != AST_STATE_UP)
2579                                 ast_answer(chan);
2580
2581                         /* Run the conference */
2582                         res = conf_run(chan, cnf, confflags.flags, options);
2583                 } else
2584                         ast_log(LOG_WARNING, "SLA%c: Found SLA '%s' but unable to build conference!\n", trunk ? 'T' : 'S', args.confno);
2585                 ASTOBJ_UNREF(sla, sla_destroy);
2586         } else {
2587                 ast_log(LOG_WARNING, "SLA%c: SLA '%s' not found!\n", trunk ? 'T' : 'S', args.confno);
2588         }
2589         
2590         ast_module_user_remove(u);
2591         
2592         return res;
2593 }
2594
2595 /*! \brief The slas() wrapper */
2596 static int slas_exec(struct ast_channel *chan, void *data)
2597 {
2598         return sla_exec(chan, data, 0);
2599 }
2600
2601 /*! \brief The slat() wrapper */
2602 static int slat_exec(struct ast_channel *chan, void *data)
2603 {
2604         return sla_exec(chan, data, 1);
2605 }
2606
2607 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident) 
2608 {
2609         struct ast_conf_user *user = NULL;
2610         int cid;
2611         
2612         sscanf(callerident, "%i", &cid);
2613         if (conf && callerident) {
2614                 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2615                         if (cid == user->user_no)
2616                                 return user;
2617                 }
2618         }
2619         return NULL;
2620 }
2621
2622 /*! \brief The MeetMeadmin application */
2623 /* MeetMeAdmin(confno, command, caller) */
2624 static int admin_exec(struct ast_channel *chan, void *data) {
2625         char *params;
2626         struct ast_conference *cnf;
2627         struct ast_conf_user *user = NULL;
2628         struct ast_module_user *u;
2629         AST_DECLARE_APP_ARGS(args,
2630                 AST_APP_ARG(confno);
2631                 AST_APP_ARG(command);
2632                 AST_APP_ARG(user);
2633         );
2634
2635         if (ast_strlen_zero(data)) {
2636                 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
2637                 return -1;
2638         }
2639
2640         u = ast_module_user_add(chan);
2641
2642         AST_LIST_LOCK(&confs);
2643         
2644         params = ast_strdupa(data);
2645         AST_STANDARD_APP_ARGS(args, params);
2646
2647         if (!args.command) {
2648                 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2649                 AST_LIST_UNLOCK(&confs);
2650                 ast_module_user_remove(u);
2651                 return -1;
2652         }
2653         AST_LIST_TRAVERSE(&confs, cnf, list) {
2654                 if (!strcmp(cnf->confno, args.confno))
2655                         break;
2656         }
2657
2658         if (!cnf) {
2659                 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);