use app arg parsing macros (issue #5690)
[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         char *parse;
1612         AST_DECLARE_APP_ARGS(args,
1613                 AST_APP_ARG(confno);
1614                 AST_APP_ARG(pin);
1615                 AST_APP_ARG(pinadmin);
1616         );
1617
1618         /* Check first in the conference list */
1619         ast_mutex_lock(&conflock);
1620         for (cnf = confs; cnf; cnf = cnf->next) {
1621                 if (!strcmp(confno, cnf->confno)) 
1622                         break;
1623         }
1624         ast_mutex_unlock(&conflock);
1625
1626         if (!cnf) {
1627                 if (dynamic) {
1628                         /* No need to parse meetme.conf */
1629                         ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
1630                         if (dynamic_pin) {
1631                                 if (dynamic_pin[0] == 'q') {
1632                                         /* Query the user to enter a PIN */
1633                                         ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0);
1634                                 }
1635                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic);
1636                         } else {
1637                                 cnf = build_conf(confno, "", "", make, dynamic);
1638                         }
1639                 } else {
1640                         /* Check the config */
1641                         cfg = ast_config_load(CONFIG_FILE_NAME);
1642                         if (!cfg) {
1643                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
1644                                 return NULL;
1645                         }
1646                         var = ast_variable_browse(cfg, "rooms");
1647                         for (; var; var = var->next) {
1648                                 if (strcasecmp(var->name, "conf"))
1649                                         continue;
1650                                 
1651                                 parse = ast_strdupa(var->value);
1652                                 if (!parse) {
1653                                         ast_log(LOG_ERROR, "Out of Memory!\n");
1654                                         return NULL;
1655                                 }
1656                                 
1657                                 AST_STANDARD_APP_ARGS(args, parse);
1658                                 if (!strcasecmp(args.confno, confno)) {
1659                                         /* Bingo it's a valid conference */
1660                                         if (args.pin) {
1661                                                 if (args.pinadmin)
1662                                                         cnf = build_conf(args.confno, args.pin, args.pinadmin, make, dynamic);
1663                                                 else
1664                                                         cnf = build_conf(args.confno, args.pin, "", make, dynamic);
1665                                         } else {
1666                                                 if (args.pinadmin)
1667                                                         cnf = build_conf(args.confno, "", args.pinadmin, make, dynamic);
1668                                                 else
1669                                                         cnf = build_conf(args.confno, "", "", make, dynamic);
1670                                         }
1671                                         break;
1672                                 }
1673                         }
1674                         if (!var) {
1675                                 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
1676                         }
1677                         ast_config_destroy(cfg);
1678                 }
1679         } else if (dynamic_pin) {
1680                 /* Correct for the user selecting 'D' instead of 'd' to have
1681                    someone join into a conference that has already been created
1682                    with a pin. */
1683                 if (dynamic_pin[0] == 'q')
1684                         dynamic_pin[0] = '\0';
1685         }
1686
1687         return cnf;
1688 }
1689
1690 /*--- count_exec: The MeetmeCount application */
1691 static int count_exec(struct ast_channel *chan, void *data)
1692 {
1693         struct localuser *u;
1694         int res = 0;
1695         struct ast_conference *conf;
1696         int count;
1697         char *localdata;
1698         char val[80] = "0"; 
1699         AST_DECLARE_APP_ARGS(args,
1700                 AST_APP_ARG(confno);
1701                 AST_APP_ARG(varname);
1702         );
1703
1704         if (ast_strlen_zero(data)) {
1705                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
1706                 return -1;
1707         }
1708
1709         LOCAL_USER_ADD(u);
1710         
1711         localdata = ast_strdupa(data);
1712         if (!localdata) {
1713                 ast_log(LOG_ERROR, "Out of memory!\n");
1714                 LOCAL_USER_REMOVE(u);
1715                 return -1;
1716         }
1717
1718         AST_STANDARD_APP_ARGS(args, localdata);
1719         
1720         conf = find_conf(chan, args.confno, 0, 0, NULL);
1721         if (conf)
1722                 count = conf->users;
1723         else
1724                 count = 0;
1725
1726         if (!ast_strlen_zero(args.varname)){
1727                 /* have var so load it and exit */
1728                 snprintf(val, sizeof(val), "%d",count);
1729                 pbx_builtin_setvar_helper(chan, args.varname, val);
1730         } else {
1731                 if (chan->_state != AST_STATE_UP)
1732                         ast_answer(chan);
1733                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
1734         }
1735         LOCAL_USER_REMOVE(u);
1736
1737         return res;
1738 }
1739
1740 /*--- conf_exec: The meetme() application */
1741 static int conf_exec(struct ast_channel *chan, void *data)
1742 {
1743         int res=-1;
1744         struct localuser *u;
1745         char confno[AST_MAX_EXTENSION] = "";
1746         int allowretry = 0;
1747         int retrycnt = 0;
1748         struct ast_conference *cnf;
1749         struct ast_flags confflags = {0};
1750         int dynamic = 0;
1751         int empty = 0, empty_no_pin = 0;
1752         int always_prompt = 0;
1753         char *notdata, *info, the_pin[AST_MAX_EXTENSION] = "";
1754         AST_DECLARE_APP_ARGS(args,
1755                 AST_APP_ARG(confno);
1756                 AST_APP_ARG(options);
1757                 AST_APP_ARG(pin);
1758         );
1759
1760         LOCAL_USER_ADD(u);
1761
1762         if (ast_strlen_zero(data)) {
1763                 allowretry = 1;
1764                 notdata = "";
1765         } else {
1766                 notdata = data;
1767         }
1768         
1769         if (chan->_state != AST_STATE_UP)
1770                 ast_answer(chan);
1771
1772         info = ast_strdupa(notdata);
1773
1774         AST_STANDARD_APP_ARGS(args, info);      
1775
1776         if (args.confno) {
1777                 ast_copy_string(confno, args.confno, sizeof(confno));
1778                 if (ast_strlen_zero(confno)) {
1779                         allowretry = 1;
1780                 }
1781         }
1782         
1783         if (args.pin)
1784                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
1785
1786         if (args.options) {
1787                 ast_app_parse_options(meetme_opts, &confflags, NULL, args.options);
1788                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
1789                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
1790                         strcpy(the_pin, "q");
1791
1792                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
1793                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
1794                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
1795         }
1796
1797         do {
1798                 if (retrycnt > 3)
1799                         allowretry = 0;
1800                 if (empty) {
1801                         int i, map[1024] = { 0, };
1802                         struct ast_config *cfg;
1803                         struct ast_variable *var;
1804                         int confno_int;
1805
1806                         ast_mutex_lock(&conflock);
1807                         for (cnf = confs; cnf; cnf = cnf->next) {
1808                                 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
1809                                         /* Disqualify in use conference */
1810                                         if (confno_int >= 0 && confno_int < 1024)
1811                                                 map[confno_int]++;
1812                                 }
1813                         }
1814                         ast_mutex_unlock(&conflock);
1815
1816                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
1817                         if ((empty_no_pin) || (!dynamic)) {
1818                                 cfg = ast_config_load(CONFIG_FILE_NAME);
1819                                 if (cfg) {
1820                                         var = ast_variable_browse(cfg, "rooms");
1821                                         while (var) {
1822                                                 if (!strcasecmp(var->name, "conf")) {
1823                                                         char *stringp = ast_strdupa(var->value);
1824                                                         if (stringp) {
1825                                                                 char *confno_tmp = strsep(&stringp, "|,");
1826                                                                 int found = 0;
1827                                                                 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
1828                                                                         if ((confno_int >= 0) && (confno_int < 1024)) {
1829                                                                                 if (stringp && empty_no_pin) {
1830                                                                                         map[confno_int]++;
1831                                                                                 }
1832                                                                         }
1833                                                                 }
1834                                                                 if (!dynamic) {
1835                                                                         /* For static:  run through the list and see if this conference is empty */
1836                                                                         ast_mutex_lock(&conflock);
1837                                                                         cnf = confs;
1838                                                                         while (cnf) {
1839                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
1840                                                                                         /* The conference exists, therefore it's not empty */
1841                                                                                         found = 1;
1842                                                                                         break;
1843                                                                                 }
1844                                                                                 cnf = cnf->next;
1845                                                                         }
1846                                                                         ast_mutex_unlock(&conflock);
1847                                                                         if (!found) {
1848                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
1849                                                                                 if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
1850                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
1851                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
1852                                                                                          * Case 3:  not empty_no_pin
1853                                                                                          */
1854                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
1855                                                                                         break;
1856                                                                                         /* XXX the map is not complete (but we do have a confno) */
1857                                                                                 }
1858                                                                         }
1859                                                                 }
1860                                                         } else {
1861                                                                 ast_log(LOG_ERROR, "Out of memory\n");
1862                                                         }
1863                                                 }
1864                                                 var = var->next;
1865                                         }
1866                                         ast_config_destroy(cfg);
1867                                 }
1868                         }
1869
1870                         /* Select first conference number not in use */
1871                         if (ast_strlen_zero(confno) && dynamic) {
1872                                 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
1873                                         if (!map[i]) {
1874                                                 snprintf(confno, sizeof(confno), "%d", i);
1875                                                 break;
1876                                         }
1877                                 }
1878                         }
1879
1880                         /* Not found? */
1881                         if (ast_strlen_zero(confno)) {
1882                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
1883                                 if (!res)
1884                                         ast_waitstream(chan, "");
1885                         } else {
1886                                 if (sscanf(confno, "%d", &confno_int) == 1) {
1887                                         res = ast_streamfile(chan, "conf-enteringno", chan->language);
1888                                         if (!res) {
1889                                                 ast_waitstream(chan, "");
1890                                                 res = ast_say_digits(chan, confno_int, "", chan->language);
1891                                         }
1892                                 } else {
1893                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
1894                                 }
1895                         }
1896                 }
1897
1898                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
1899                         /* Prompt user for conference number */
1900                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
1901                         if (res < 0) {
1902                                 /* Don't try to validate when we catch an error */
1903                                 confno[0] = '\0';
1904                                 allowretry = 0;
1905                                 break;
1906                         }
1907                 }
1908                 if (!ast_strlen_zero(confno)) {
1909                         /* Check the validity of the conference */
1910                         cnf = find_conf(chan, confno, 1, dynamic, the_pin);
1911                         if (!cnf) {
1912                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
1913                                 if (!res)
1914                                         ast_waitstream(chan, "");
1915                                 res = -1;
1916                                 if (allowretry)
1917                                         confno[0] = '\0';
1918                         } else {
1919                                 if ((!ast_strlen_zero(cnf->pin) &&
1920                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
1921                                     (!ast_strlen_zero(cnf->pinadmin) &&
1922                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
1923                                         char pin[AST_MAX_EXTENSION]="";
1924                                         int j;
1925
1926                                         /* Allow the pin to be retried up to 3 times */
1927                                         for (j = 0; j < 3; j++) {
1928                                                 if (*the_pin && (always_prompt == 0)) {
1929                                                         ast_copy_string(pin, the_pin, sizeof(pin));
1930                                                         res = 0;
1931                                                 } else {
1932                                                         /* Prompt user for pin if pin is required */
1933                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
1934                                                 }
1935                                                 if (res >= 0) {
1936                                                         if (!strcasecmp(pin, cnf->pin) ||
1937                                                             (!ast_strlen_zero(cnf->pinadmin) &&
1938                                                              !strcasecmp(pin, cnf->pinadmin))) {
1939                                                                 /* Pin correct */
1940                                                                 allowretry = 0;
1941                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
1942                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
1943                                                                 /* Run the conference */
1944                                                                 res = conf_run(chan, cnf, confflags.flags);
1945                                                                 break;
1946                                                         } else {
1947                                                                 /* Pin invalid */
1948                                                                 res = ast_streamfile(chan, "conf-invalidpin", chan->language);
1949                                                                 if (!res)
1950                                                                         ast_waitstream(chan, AST_DIGIT_ANY);
1951                                                                 if (res < 0)
1952                                                                         break;
1953                                                                 pin[0] = res;
1954                                                                 pin[1] = '\0';
1955                                                                 res = -1;
1956                                                                 if (allowretry)
1957                                                                         confno[0] = '\0';
1958                                                         }
1959                                                 } else {
1960                                                         /* failed when getting the pin */
1961                                                         res = -1;
1962                                                         allowretry = 0;
1963                                                         /* see if we need to get rid of the conference */
1964                                                         ast_mutex_lock(&conflock);
1965                                                         if (!cnf->users) {
1966                                                                 conf_free(cnf); 
1967                                                         }
1968                                                         ast_mutex_unlock(&conflock);
1969                                                         break;
1970                                                 }
1971
1972                                                 /* Don't retry pin with a static pin */
1973                                                 if (*the_pin && (always_prompt==0)) {
1974                                                         break;
1975                                                 }
1976                                         }
1977                                 } else {
1978                                         /* No pin required */
1979                                         allowretry = 0;
1980
1981                                         /* Run the conference */
1982                                         res = conf_run(chan, cnf, confflags.flags);
1983                                 }
1984                         }
1985                 }
1986         } while (allowretry);
1987         
1988         LOCAL_USER_REMOVE(u);
1989         
1990         return res;
1991 }
1992
1993 static struct ast_conf_user* find_user(struct ast_conference *conf, char *callerident) {
1994         struct ast_conf_user *user = NULL;
1995         char usrno[1024] = "";
1996
1997         if (conf && callerident) {
1998                 user = conf->firstuser;
1999                 while (user) {
2000                         snprintf(usrno, sizeof(usrno), "%d", user->user_no);
2001                         if (strcmp(usrno, callerident) == 0)
2002                                 return user;
2003                         user = user->nextuser;
2004                 }
2005         }
2006         return NULL;
2007 }
2008
2009 /*--- admin_exec: The MeetMeadmin application */
2010 /* MeetMeAdmin(confno, command, caller) */
2011 static int admin_exec(struct ast_channel *chan, void *data) {
2012         char *params;
2013         struct ast_conference *cnf;
2014         struct ast_conf_user *user = NULL;
2015         struct localuser *u;
2016         AST_DECLARE_APP_ARGS(args,
2017                 AST_APP_ARG(confno);
2018                 AST_APP_ARG(command);
2019                 AST_APP_ARG(user);
2020         );
2021         
2022         LOCAL_USER_ADD(u);
2023
2024         ast_mutex_lock(&conflock);
2025         /* The param has the conference number the user and the command to execute */
2026         if (!ast_strlen_zero(data)) {           
2027                 params = ast_strdupa((char *) data);
2028
2029                 AST_STANDARD_APP_ARGS(args, params);
2030
2031                 if (!args.command) {
2032                         ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2033                         ast_mutex_unlock(&conflock);
2034                         LOCAL_USER_REMOVE(u);
2035                         return -1;
2036                 }
2037                 for (cnf = confs; cnf; cnf = cnf->next) {
2038                         if (!strcmp(cnf->confno, args.confno))
2039                                 break;
2040                 }
2041                 
2042                 if (args.user)
2043                         user = find_user(cnf, args.user);
2044                 
2045                 if (cnf) {
2046                         switch((int) (*args.command)) {
2047                         case 76: /* L: Lock */ 
2048                                 cnf->locked = 1;
2049                                 break;
2050                         case 108: /* l: Unlock */ 
2051                                 cnf->locked = 0;
2052                                 break;
2053                         case 75: /* K: kick all users*/
2054                                 user = cnf->firstuser;
2055                                 while(user) {
2056                                         user->adminflags |= ADMINFLAG_KICKME;
2057                                         if (user->nextuser) {
2058                                                 user = user->nextuser;
2059                                         } else {
2060                                                 break;
2061                                         }
2062                                 }
2063                                 break;
2064                         case 101: /* e: Eject last user*/
2065                                 user = cnf->lastuser;
2066                                 if (!(user->userflags & CONFFLAG_ADMIN)) {
2067                                         user->adminflags |= ADMINFLAG_KICKME;
2068                                         break;
2069                                 } else
2070                                         ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
2071                                 break;
2072                         case 77: /* M: Mute */ 
2073                                 if (user) {
2074                                         user->adminflags |= ADMINFLAG_MUTED;
2075                                 } else {
2076                                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2077                                 }
2078                                 break;
2079                         case 78: /* N: Mute all users */
2080                                 user = cnf->firstuser;
2081                                 while(user) {
2082                                         if (user && !(user->userflags & CONFFLAG_ADMIN))
2083                                                 user->adminflags |= ADMINFLAG_MUTED;
2084                                         if (user->nextuser) {
2085                                                 user = user->nextuser;
2086                                         } else {
2087                                                 break;
2088                                         }
2089                                 }
2090                                 break;                                  
2091                         case 109: /* m: Unmute */ 
2092                                 if (user && (user->adminflags & ADMINFLAG_MUTED)) {
2093                                         user->adminflags ^= ADMINFLAG_MUTED;
2094                                 } else {
2095                                         ast_log(LOG_NOTICE, "Specified User not found or he muted himself!");
2096                                 }
2097                                 break;
2098                         case  110: /* n: Unmute all users */
2099                                 user = cnf->firstuser;
2100                                 while(user) {
2101                                         if (user && (user-> adminflags & ADMINFLAG_MUTED)) {
2102                                                 user->adminflags ^= ADMINFLAG_MUTED;
2103                                         }
2104                                         if (user->nextuser) {
2105                                                 user = user->nextuser;
2106                                         } else {
2107                                                 break;
2108                                         }
2109                                 }
2110                                 break;
2111                         case 107: /* k: Kick user */ 
2112                                 if (user) {
2113                                         user->adminflags |= ADMINFLAG_KICKME;
2114                                 } else {
2115                                         ast_log(LOG_NOTICE, "Specified User not found!");
2116                                 }
2117                                 break;
2118                         }
2119                 } else {
2120                         ast_log(LOG_NOTICE, "Conference Number not found\n");
2121                 }
2122         }
2123         ast_mutex_unlock(&conflock);
2124
2125         LOCAL_USER_REMOVE(u);
2126         
2127         return 0;
2128 }
2129
2130 static void *recordthread(void *args)
2131 {
2132         struct ast_conference *cnf = args;
2133         struct ast_frame *f=NULL;
2134         int flags;
2135         struct ast_filestream *s;
2136         int res=0;
2137
2138         if (!cnf || !cnf->chan) {
2139                 pthread_exit(0);
2140         }
2141         ast_stopstream(cnf->chan);
2142         flags = O_CREAT|O_TRUNC|O_WRONLY;
2143         s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
2144
2145         if (s) {
2146                 cnf->recording = MEETME_RECORD_ACTIVE;
2147                 while (ast_waitfor(cnf->chan, -1) > -1) {
2148                         f = ast_read(cnf->chan);
2149                         if (!f) {
2150                                 res = -1;
2151                                 break;
2152                         }
2153                         if (f->frametype == AST_FRAME_VOICE) {
2154                                 res = ast_writestream(s, f);
2155                                 if (res) 
2156                                         break;
2157                         }
2158                         ast_frfree(f);
2159                         if (cnf->recording == MEETME_RECORD_TERMINATE) {
2160                                 ast_mutex_lock(&conflock);
2161                                 ast_mutex_unlock(&conflock);
2162                                 break;
2163                         }
2164                 }
2165                 cnf->recording = MEETME_RECORD_OFF;
2166                 ast_closestream(s);
2167         }
2168         pthread_exit(0);
2169 }
2170
2171 static void load_config(void)
2172 {
2173         struct ast_config *cfg;
2174         char *val;
2175
2176         audio_buffers = DEFAULT_AUDIO_BUFFERS;
2177
2178         if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
2179                 return;
2180
2181         if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
2182                 if ((sscanf(val, "%d", &audio_buffers) != 1)) {
2183                         ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
2184                         audio_buffers = DEFAULT_AUDIO_BUFFERS;
2185                 } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
2186                         ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
2187                                 ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
2188                         audio_buffers = DEFAULT_AUDIO_BUFFERS;
2189                 }
2190                 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
2191                         ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
2192         }
2193
2194         ast_config_destroy(cfg);
2195 }
2196
2197 int unload_module(void)
2198 {
2199         int res;
2200         
2201         res = ast_cli_unregister(&cli_show_confs);
2202         res |= ast_cli_unregister(&cli_conf);
2203         res |= ast_unregister_application(app3);
2204         res |= ast_unregister_application(app2);
2205         res |= ast_unregister_application(app);
2206
2207         STANDARD_HANGUP_LOCALUSERS;
2208
2209         return res;
2210 }
2211
2212 int load_module(void)
2213 {
2214         int res;
2215
2216         load_config();
2217
2218         res = ast_cli_register(&cli_show_confs);
2219         res |= ast_cli_register(&cli_conf);
2220         res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
2221         res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
2222         res |= ast_register_application(app, conf_exec, synopsis, descrip);
2223
2224         return res;
2225 }
2226
2227 int reload(void)
2228 {
2229         load_config();
2230
2231         return 0;
2232 }
2233
2234 char *description(void)
2235 {
2236         return (char *) tdesc;
2237 }
2238
2239 int usecount(void)
2240 {
2241         int res;
2242
2243         STANDARD_USECOUNT(res);
2244
2245         return res;
2246 }
2247
2248 char *key()
2249 {
2250         return ASTERISK_GPL_KEY;
2251 }
2252