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