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