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