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