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