0a3e4a82b53eaf2995dca98bda0cb685a7c7e8e1
[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 "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <sys/ioctl.h>
42 #include <zaptel/zaptel.h>
43
44 #include "asterisk/lock.h"
45 #include "asterisk/file.h"
46 #include "asterisk/logger.h"
47 #include "asterisk/channel.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/module.h"
50 #include "asterisk/config.h"
51 #include "asterisk/app.h"
52 #include "asterisk/dsp.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/manager.h"
55 #include "asterisk/options.h"
56 #include "asterisk/cli.h"
57 #include "asterisk/say.h"
58 #include "asterisk/utils.h"
59 #include "asterisk/translate.h"
60 #include "asterisk/ulaw.h"
61 #include "asterisk/astobj.h"
62 #include "asterisk/devicestate.h"
63
64 #include "enter.h"
65 #include "leave.h"
66
67 #define CONFIG_FILE_NAME "meetme.conf"
68
69 /*! each buffer is 20ms, so this is 640ms total */
70 #define DEFAULT_AUDIO_BUFFERS  32
71
72 enum {
73         ADMINFLAG_MUTED =     (1 << 1), /*!< User is muted */
74         ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
75         ADMINFLAG_KICKME =    (1 << 3)  /*!< User has been kicked */
76 };
77
78 #define MEETME_DELAYDETECTTALK     300
79 #define MEETME_DELAYDETECTENDTALK  1000
80
81 #define AST_FRAME_BITS  32
82
83 enum volume_action {
84         VOL_UP,
85         VOL_DOWN
86 };
87
88 enum entrance_sound {
89         ENTER,
90         LEAVE
91 };
92
93 enum recording_state {
94         MEETME_RECORD_OFF,
95         MEETME_RECORD_STARTED,
96         MEETME_RECORD_ACTIVE,
97         MEETME_RECORD_TERMINATE
98 };
99
100 #define CONF_SIZE  320
101
102 enum {
103         /*! user has admin access on the conference */
104         CONFFLAG_ADMIN = (1 << 0),
105         /*! If set the user can only receive audio from the conference */
106         CONFFLAG_MONITOR = (1 << 1),
107         /*! If set asterisk will exit conference when '#' is pressed */
108         CONFFLAG_POUNDEXIT = (1 << 2),
109         /*! If set asterisk will provide a menu to the user when '*' is pressed */
110         CONFFLAG_STARMENU = (1 << 3),
111         /*! If set the use can only send audio to the conference */
112         CONFFLAG_TALKER = (1 << 4),
113         /*! If set there will be no enter or leave sounds */
114         CONFFLAG_QUIET = (1 << 5),
115         /*! If set, when user joins the conference, they will be told the number 
116          *  of users that are already in */
117         CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
118         /*! Set to run AGI Script in Background */
119         CONFFLAG_AGI = (1 << 7),
120         /*! Set to have music on hold when user is alone in conference */
121         CONFFLAG_MOH = (1 << 8),
122         /*! If set the MeetMe will return if all marked with this flag left */
123         CONFFLAG_MARKEDEXIT = (1 << 9),
124         /*! If set, the MeetMe will wait until a marked user enters */
125         CONFFLAG_WAITMARKED = (1 << 10),
126         /*! If set, the MeetMe will exit to the specified context */
127         CONFFLAG_EXIT_CONTEXT = (1 << 11),
128         /*! If set, the user will be marked */
129         CONFFLAG_MARKEDUSER = (1 << 12),
130         /*! If set, user will be ask record name on entry of conference */
131         CONFFLAG_INTROUSER = (1 << 13),
132         /*! If set, the MeetMe will be recorded */
133         CONFFLAG_RECORDCONF = (1<< 14),
134         /*! If set, the user will be monitored if the user is talking or not */
135         CONFFLAG_MONITORTALKER = (1 << 15),
136         CONFFLAG_DYNAMIC = (1 << 16),
137         CONFFLAG_DYNAMICPIN = (1 << 17),
138         CONFFLAG_EMPTY = (1 << 18),
139         CONFFLAG_EMPTYNOPIN = (1 << 19),
140         CONFFLAG_ALWAYSPROMPT = (1 << 20),
141         /*! If set, treats talking users as muted users */
142         CONFFLAG_OPTIMIZETALKER = (1 << 21),
143         /*! If set, won't speak the extra prompt when the first person 
144          *  enters the conference */
145         CONFFLAG_NOONLYPERSON = (1 << 22),
146         /*! If set, user will be asked to record name on entry of conference 
147          *  without review */
148         CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
149         /*! If set, the user will be initially self-muted */
150         CONFFLAG_STARTMUTED = (1 << 24),
151         /*! If set, the user is a shared line appearance station */
152         CONFFLAG_SLA_STATION = (1 << 25),
153         /*! If set, the user is a shared line appearance trunk */
154         CONFFLAG_SLA_TRUNK = (1 << 26),
155         /*! If set, the user has put us on hold */
156         CONFFLAG_HOLD = (1 << 27),
157         /*! If set, the user should continue in the dialplan if kicked out */
158         CONFFLAG_KICK_CONTINUE = (1 << 28)
159 };
160
161 enum {
162         OPT_ARG_WAITMARKED = 0,
163         OPT_ARG_ARRAY_SIZE = 1,
164 } meetme_option_args;
165
166 AST_APP_OPTIONS(meetme_opts, {
167         AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
168         AST_APP_OPTION('a', CONFFLAG_ADMIN ),
169         AST_APP_OPTION('b', CONFFLAG_AGI ),
170         AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
171         AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
172         AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
173         AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
174         AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
175         AST_APP_OPTION('e', CONFFLAG_EMPTY ),
176         AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
177         AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
178         AST_APP_OPTION('M', CONFFLAG_MOH ),
179         AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
180         AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
181         AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
182         AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
183         AST_APP_OPTION('q', CONFFLAG_QUIET ),
184         AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
185         AST_APP_OPTION('s', CONFFLAG_STARMENU ),
186         AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
187         AST_APP_OPTION('l', CONFFLAG_MONITOR ),
188         AST_APP_OPTION('t', CONFFLAG_TALKER ),
189         AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
190         AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
191         AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
192         AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
193 });
194
195 AST_APP_OPTIONS(sla_opts, {
196         /* Just a placeholder for now */
197 });
198 static const char *app = "MeetMe";
199 static const char *app2 = "MeetMeCount";
200 static const char *app3 = "MeetMeAdmin";
201 static const char *appslas = "SLAStation";
202 static const char *appslat = "SLATrunk";
203
204 static const char *synopsis = "MeetMe conference bridge";
205 static const char *synopsis2 = "MeetMe participant count";
206 static const char *synopsis3 = "MeetMe conference Administration";
207 static const char *synopslas = "Shared Line Appearance - Station";
208 static const char *synopslat = "Shared Line Appearance - Trunk";
209
210 static const char *descrip =
211 "  MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
212 "conference.  If the conference number is omitted, the user will be prompted\n"
213 "to enter one.  User can exit the conference by hangup, or if the 'p' option\n"
214 "is specified, by pressing '#'.\n"
215 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
216 "             must be present for conferencing to operate properly. In addition, the chan_zap\n"
217 "             channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
218 "The option string may contain zero or more of the following characters:\n"
219 "      'a' -- set admin mode\n"
220 "      'A' -- set marked mode\n"
221 "      'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
222 "             Default: conf-background.agi  (Note: This does not work with\n"
223 "             non-Zap channels in the same conference)\n"
224 "      'c' -- announce user(s) count on joining a conference\n"
225 "      'C' -- continue in dialplan when kicked out of conference\n"
226 "      'd' -- dynamically add conference\n"
227 "      'D' -- dynamically add conference, prompting for a PIN\n"
228 "      'e' -- select an empty conference\n"
229 "      'E' -- select an empty pinless conference\n"
230 "      'i' -- announce user join/leave with review\n"
231 "      'I' -- announce user join/leave without review\n"
232 "      'l' -- set listen only mode (Listen only, no talking)\n"
233 "      'm' -- set initially muted\n"
234 "      'M' -- enable music on hold when the conference has a single caller\n"
235 "      'o' -- set talker optimization - treats talkers who aren't speaking as\n"
236 "             being muted, meaning (a) No encode is done on transmission and\n"
237 "             (b) Received audio that is not registered as talking is omitted\n"
238 "             causing no buildup in background noise\n"
239 "      'p' -- allow user to exit the conference by pressing '#'\n"
240 "      'P' -- always prompt for the pin even if it is specified\n"
241 "      'q' -- quiet mode (don't play enter/leave sounds)\n"
242 "      'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
243 "             using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
244 "             meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
245 "             wav.\n"
246 "      's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
247 "      't' -- set talk only mode. (Talk only, no listening)\n"
248 "      'T' -- set talker detection (sent to manager interface and meetme list)\n"
249 "      'w[(<secs>)]'\n"
250 "          -- wait until the marked user enters the conference\n"
251 "      'x' -- close the conference when last marked user exits\n"
252 "      'X' -- allow user to exit the conference by entering a valid single\n"
253 "             digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
254 "             if that variable is not defined.\n"
255 "      '1' -- do not play message when first person enters\n";
256
257 static const char *descrip2 =
258 "  MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
259 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
260 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
261 "the channel, unless priority n+1 exists, in which case priority progress will\n"
262 "continue.\n"
263 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
264
265 static const char *descrip3 = 
266 "  MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
267 "      'e' -- Eject last user that joined\n"
268 "      'k' -- Kick one user out of conference\n"
269 "      'K' -- Kick all users out of conference\n"
270 "      'l' -- Unlock conference\n"
271 "      'L' -- Lock conference\n"
272 "      'm' -- Unmute one user\n"
273 "      'M' -- Mute one user\n"
274 "      'n' -- Unmute all users in the conference\n"
275 "      'N' -- Mute all non-admin users in the conference\n"
276 "      'r' -- Reset one user's volume settings\n"
277 "      'R' -- Reset all users volume settings\n"
278 "      's' -- Lower entire conference speaking volume\n"
279 "      'S' -- Raise entire conference speaking volume\n"
280 "      't' -- Lower one user's talk volume\n"
281 "      'T' -- Raise one user's talk volume\n"
282 "      'u' -- Lower one user's listen volume\n"
283 "      'U' -- Raise one user's listen volume\n"
284 "      'v' -- Lower entire conference listening volume\n"
285 "      'V' -- Raise entire conference listening volume\n"
286 "";
287
288 static const char *descripslas =
289 "  SLAStation(sla[,options]): Run Shared Line Appearance for station\n"
290 "Runs the share line appearance for a station calling in.  If there are no\n"
291 "other participants in the conference, the trunk is called and is dumped into\n"
292 "the bridge.\n";
293
294 static const char *descripslat =
295 "  SLATrunk(sla[,options]): Run Shared Line Appearance for trunk\n"
296 "Runs the share line appearance for a trunk calling in.  If there are no\n"
297 "other participants in the conference, all member stations are invited into\n"
298 "the bridge.\n";
299
300 #define CONFIG_FILE_NAME "meetme.conf"
301 #define CONFIG_FILE_NAME_SLA "sla.conf"
302
303 /*! \brief The MeetMe Conference object */
304 struct ast_conference {
305         ast_mutex_t playlock;                   /*!< Conference specific lock (players) */
306         ast_mutex_t listenlock;                 /*!< Conference specific lock (listeners) */
307         char confno[AST_MAX_EXTENSION];         /*!< Conference */
308         struct ast_channel *chan;               /*!< Announcements channel */
309         struct ast_channel *lchan;              /*!< Listen/Record channel */
310         int fd;                                 /*!< Announcements fd */
311         int zapconf;                            /*!< Zaptel Conf # */
312         int users;                              /*!< Number of active users */
313         int markedusers;                        /*!< Number of marked users */
314         time_t start;                           /*!< Start time (s) */
315         int refcount;                           /*!< reference count of usage */
316         enum recording_state recording:2;       /*!< recording status */
317         unsigned int isdynamic:1;               /*!< Created on the fly? */
318         unsigned int locked:1;                  /*!< Is the conference locked? */
319         pthread_t recordthread;                 /*!< thread for recording */
320         pthread_attr_t attr;                    /*!< thread attribute */
321         const char *recordingfilename;          /*!< Filename to record the Conference into */
322         const char *recordingformat;            /*!< Format to record the Conference in */
323         char pin[AST_MAX_EXTENSION];            /*!< If protected by a PIN */
324         char pinadmin[AST_MAX_EXTENSION];       /*!< If protected by a admin PIN */
325         struct ast_frame *transframe[32];
326         struct ast_frame *origframe;
327         struct ast_trans_pvt *transpath[32];
328         AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
329         AST_LIST_ENTRY(ast_conference) list;
330 };
331
332 static AST_LIST_HEAD_STATIC(confs, ast_conference);
333
334 struct volume {
335         int desired;                            /*!< Desired volume adjustment */
336         int actual;                             /*!< Actual volume adjustment (for channels that can't adjust) */
337 };
338
339 struct ast_conf_user {
340         int user_no;                            /*!< User Number */
341         int userflags;                          /*!< Flags as set in the conference */
342         int adminflags;                         /*!< Flags set by the Admin */
343         struct ast_channel *chan;               /*!< Connected channel */
344         int talking;                            /*!< Is user talking */
345         int zapchannel;                         /*!< Is a Zaptel channel */
346         char usrvalue[50];                      /*!< Custom User Value */
347         char namerecloc[PATH_MAX];                              /*!< Name Recorded file Location */
348         int control;                                                    /*! Queue Control for transmission */
349         int dtmf;                                                               /*! Queue DTMF for transmission */
350         time_t jointime;                        /*!< Time the user joined the conference */
351         struct volume talk;
352         struct volume listen;
353         AST_LIST_ENTRY(ast_conf_user) list;
354 };
355
356 /*! SLA station - one device in an SLA configuration */
357 struct ast_sla_station {
358         ASTOBJ_COMPONENTS(struct ast_sla_station);
359         char *dest;
360         char tech[0];
361 };
362
363 struct ast_sla_station_box {
364         ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla_station);
365 };
366
367 /*! SLA - Shared Line Appearance object. These consist of one trunk (outbound line)
368         and stations that receive incoming calls and place outbound calls over the trunk 
369 */
370 struct ast_sla {
371         ASTOBJ_COMPONENTS (struct ast_sla);
372         struct ast_sla_station_box stations;    /*!< Stations connected to this SLA */
373         char confname[80];      /*!< Name for this SLA bridge */
374         char trunkdest[256];    /*!< Device (channel) identifier for the trunk line */
375         char trunktech[20];     /*!< Technology used for the trunk (channel driver) */
376 };
377
378 struct ast_sla_box {
379         ASTOBJ_CONTAINER_COMPONENTS(struct ast_sla);
380 } slas;
381
382 static int audio_buffers;                       /*!< The number of audio buffers to be allocated on pseudo channels
383                                                    when in a conference
384                                                 */
385 /*! The number of audio buffers to be allocated on pseudo channels
386  *  when in a conference */
387 static int audio_buffers;
388
389 /*! Map 'volume' levels from -5 through +5 into
390  *  decibel (dB) settings for channel drivers
391  *  Note: these are not a straight linear-to-dB
392  *  conversion... the numbers have been modified
393  *  to give the user a better level of adjustability
394  */
395 static signed char gain_map[] = {
396         -15,
397         -13,
398         -10,
399         -6,
400         0,
401         0,
402         0,
403         6,
404         10,
405         13,
406         15,
407 };
408
409
410 static int admin_exec(struct ast_channel *chan, void *data);
411 static void *recordthread(void *args);
412
413 static char *istalking(int x)
414 {
415         if (x > 0)
416                 return "(talking)";
417         else if (x < 0)
418                 return "(unmonitored)";
419         else 
420                 return "(not talking)";
421 }
422
423 static int careful_write(int fd, unsigned char *data, int len, int block)
424 {
425         int res;
426         int x;
427
428         while (len) {
429                 if (block) {
430                         x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
431                         res = ioctl(fd, ZT_IOMUX, &x);
432                 } else
433                         res = 0;
434                 if (res >= 0)
435                         res = write(fd, data, len);
436                 if (res < 1) {
437                         if (errno != EAGAIN) {
438                                 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
439                                 return -1;
440                         } else
441                                 return 0;
442                 }
443                 len -= res;
444                 data += res;
445         }
446
447         return 0;
448 }
449
450 static int set_talk_volume(struct ast_conf_user *user, int volume)
451 {
452         signed char gain_adjust;
453
454         /* attempt to make the adjustment in the channel driver;
455            if successful, don't adjust in the frame reading routine
456         */
457         gain_adjust = gain_map[volume + 5];
458
459         return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
460 }
461
462 static int set_listen_volume(struct ast_conf_user *user, int volume)
463 {
464         signed char gain_adjust;
465
466         /* attempt to make the adjustment in the channel driver;
467            if successful, don't adjust in the frame reading routine
468         */
469         gain_adjust = gain_map[volume + 5];
470
471         return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
472 }
473
474 static void tweak_volume(struct volume *vol, enum volume_action action)
475 {
476         switch (action) {
477         case VOL_UP:
478                 switch (vol->desired) {
479                 case 5:
480                         break;
481                 case 0:
482                         vol->desired = 2;
483                         break;
484                 case -2:
485                         vol->desired = 0;
486                         break;
487                 default:
488                         vol->desired++;
489                         break;
490                 }
491                 break;
492         case VOL_DOWN:
493                 switch (vol->desired) {
494                 case -5:
495                         break;
496                 case 2:
497                         vol->desired = 0;
498                         break;
499                 case 0:
500                         vol->desired = -2;
501                         break;
502                 default:
503                         vol->desired--;
504                         break;
505                 }
506         }
507 }
508
509 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
510 {
511         tweak_volume(&user->talk, action);
512         /* attempt to make the adjustment in the channel driver;
513            if successful, don't adjust in the frame reading routine
514         */
515         if (!set_talk_volume(user, user->talk.desired))
516                 user->talk.actual = 0;
517         else
518                 user->talk.actual = user->talk.desired;
519 }
520
521 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
522 {
523         tweak_volume(&user->listen, action);
524         /* attempt to make the adjustment in the channel driver;
525            if successful, don't adjust in the frame reading routine
526         */
527         if (!set_listen_volume(user, user->listen.desired))
528                 user->listen.actual = 0;
529         else
530                 user->listen.actual = user->listen.desired;
531 }
532
533 static void reset_volumes(struct ast_conf_user *user)
534 {
535         signed char zero_volume = 0;
536
537         ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
538         ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
539 }
540
541 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
542 {
543         unsigned char *data;
544         int len;
545         int res = -1;
546
547         if (!chan->_softhangup)
548                 res = ast_autoservice_start(chan);
549
550         AST_LIST_LOCK(&confs);
551
552         switch(sound) {
553         case ENTER:
554                 data = enter;
555                 len = sizeof(enter);
556                 break;
557         case LEAVE:
558                 data = leave;
559                 len = sizeof(leave);
560                 break;
561         default:
562                 data = NULL;
563                 len = 0;
564         }
565         if (data) {
566                 careful_write(conf->fd, data, len, 1);
567         }
568
569         AST_LIST_UNLOCK(&confs);
570
571         if (!res) 
572                 ast_autoservice_stop(chan);
573 }
574
575 static void station_destroy(struct ast_sla_station *station)
576 {
577         free(station);
578 }
579
580 static void sla_destroy(struct ast_sla *sla)
581 {
582         ASTOBJ_CONTAINER_DESTROYALL(&sla->stations, station_destroy);
583         ASTOBJ_CONTAINER_DESTROY(&sla->stations);
584         free(sla);
585 }
586
587 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
588 {
589         struct ast_conference *cnf;
590         struct zt_confinfo ztc;
591
592         AST_LIST_LOCK(&confs);
593
594         AST_LIST_TRAVERSE(&confs, cnf, list) {
595                 if (!strcmp(confno, cnf->confno)) 
596                         break;
597         }
598
599         if (!cnf && (make || dynamic)) {
600                 /* Make a new one */
601                 if ((cnf = ast_calloc(1, sizeof(*cnf)))) {
602                         ast_mutex_init(&cnf->playlock);
603                         ast_mutex_init(&cnf->listenlock);
604                         ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
605                         ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
606                         ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
607                         cnf->refcount = 0;
608                         cnf->markedusers = 0;
609                         cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
610                         if (cnf->chan) {
611                                 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
612                                 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
613                                 cnf->fd = cnf->chan->fds[0];    /* for use by conf_play() */
614                         } else {
615                                 ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n");
616                                 cnf->fd = open("/dev/zap/pseudo", O_RDWR);
617                                 if (cnf->fd < 0) {
618                                         ast_log(LOG_WARNING, "Unable to open pseudo device\n");
619                                         free(cnf);
620                                         cnf = NULL;
621                                         goto cnfout;
622                                 }
623                         }
624                         memset(&ztc, 0, sizeof(ztc));
625                         /* Setup a new zap conference */
626                         ztc.chan = 0;
627                         ztc.confno = -1;
628                         ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
629                         if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
630                                 ast_log(LOG_WARNING, "Error setting conference\n");
631                                 if (cnf->chan)
632                                         ast_hangup(cnf->chan);
633                                 else
634                                         close(cnf->fd);
635                                 free(cnf);
636                                 cnf = NULL;
637                                 goto cnfout;
638                         }
639                         cnf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
640                         if (cnf->lchan) {
641                                 ast_set_read_format(cnf->lchan, AST_FORMAT_SLINEAR);
642                                 ast_set_write_format(cnf->lchan, AST_FORMAT_SLINEAR);
643                                 ztc.chan = 0;
644                                 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
645                                 if (ioctl(cnf->lchan->fds[0], ZT_SETCONF, &ztc)) {
646                                         ast_log(LOG_WARNING, "Error setting conference\n");
647                                         ast_hangup(cnf->lchan);
648                                         cnf->lchan = NULL;
649                                 }
650                         }
651                         /* Fill the conference struct */
652                         cnf->start = time(NULL);
653                         cnf->zapconf = ztc.confno;
654                         cnf->isdynamic = dynamic ? 1 : 0;
655                         if (option_verbose > 2)
656                                 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
657                         AST_LIST_INSERT_HEAD(&confs, cnf, list);
658                         manager_event(EVENT_FLAG_CALL, "MeetmeStart", "Meetme: %s\r\n", cnf->confno);
659                 } 
660         }
661  cnfout:
662         if (cnf){ 
663                 cnf->refcount += refcount;
664         }
665         AST_LIST_UNLOCK(&confs);
666         return cnf;
667 }
668
669 /*! \brief CLI command for showing SLAs */
670 static int sla_show(int fd, int argc, char *argv[]) 
671 {
672         struct ast_sla *sla;
673         if (argc != 2)
674                 return RESULT_SHOWUSAGE;
675
676         ast_cli(fd, "Shared line appearances:\n");
677         ASTOBJ_CONTAINER_TRAVERSE(&slas, 1, {
678                 ASTOBJ_RDLOCK(iterator);
679                 ast_cli(fd, "SLA %s\n", iterator->name);
680                 if (ast_strlen_zero(iterator->trunkdest) || ast_strlen_zero(iterator->trunktech))
681                         ast_cli(fd, "   Trunk => <unspecified>\n");
682                 else
683                         ast_cli(fd, "   Trunk => %s/%s\n", iterator->trunktech, iterator->trunkdest);
684                 sla = iterator;
685                 ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
686                         ast_cli(fd, "   Station: %s/%s\n", iterator->tech, iterator->dest);
687                 });
688                 ASTOBJ_UNLOCK(iterator);
689         });
690
691         return RESULT_SUCCESS;
692 }
693
694 static int meetme_cmd(int fd, int argc, char **argv) 
695 {
696         /* Process the command */
697         struct ast_conference *cnf;
698         struct ast_conf_user *user;
699         int hr, min, sec;
700         int i = 0, total = 0;
701         time_t now;
702         char *header_format = "%-14s %-14s %-10s %-8s  %-8s\n";
703         char *data_format = "%-12.12s   %4.4d         %4.4s       %02d:%02d:%02d  %-8s\n";
704         char cmdline[1024] = "";
705
706         if (argc > 8)
707                 ast_cli(fd, "Invalid Arguments.\n");
708         /* Check for length so no buffer will overflow... */
709         for (i = 0; i < argc; i++) {
710                 if (strlen(argv[i]) > 100)
711                         ast_cli(fd, "Invalid Arguments.\n");
712         }
713         if (argc == 1) {
714                 /* 'MeetMe': List all the conferences */        
715                 now = time(NULL);
716                 if (AST_LIST_EMPTY(&confs)) {
717                         ast_cli(fd, "No active MeetMe conferences.\n");
718                         return RESULT_SUCCESS;
719                 }
720                 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
721                 AST_LIST_TRAVERSE(&confs, cnf, list) {
722                         if (cnf->markedusers == 0)
723                                 strcpy(cmdline, "N/A ");
724                         else 
725                                 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
726                         hr = (now - cnf->start) / 3600;
727                         min = ((now - cnf->start) % 3600) / 60;
728                         sec = (now - cnf->start) % 60;
729
730                         ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
731
732                         total += cnf->users;    
733                 }
734                 ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
735                 return RESULT_SUCCESS;
736         }
737         if (argc < 3)
738                 return RESULT_SHOWUSAGE;
739         ast_copy_string(cmdline, argv[2], sizeof(cmdline));     /* Argv 2: conference number */
740         if (strstr(argv[1], "lock")) {  
741                 if (strcmp(argv[1], "lock") == 0) {
742                         /* Lock */
743                         strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
744                 } else {
745                         /* Unlock */
746                         strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
747                 }
748         } else if (strstr(argv[1], "mute")) { 
749                 if (argc < 4)
750                         return RESULT_SHOWUSAGE;
751                 if (strcmp(argv[1], "mute") == 0) {
752                         /* Mute */
753                         if (strcmp(argv[3], "all") == 0) {
754                                 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
755                         } else {
756                                 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1); 
757                                 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
758                         }
759                 } else {
760                         /* Unmute */
761                         if (strcmp(argv[3], "all") == 0) {
762                                 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
763                         } else {
764                                 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
765                                 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
766                         }
767                 }
768         } else if (strcmp(argv[1], "kick") == 0) {
769                 if (argc < 4)
770                         return RESULT_SHOWUSAGE;
771                 if (strcmp(argv[3], "all") == 0) {
772                         /* Kick all */
773                         strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
774                 } else {
775                         /* Kick a single user */
776                         strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
777                         strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
778                 }       
779         } else if(strcmp(argv[1], "list") == 0) {
780                 int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
781                 /* List all the users in a conference */
782                 if (AST_LIST_EMPTY(&confs)) {
783                         if ( !concise )
784                                 ast_cli(fd, "No active conferences.\n");
785                         return RESULT_SUCCESS;  
786                 }
787                 /* Find the right conference */
788                 AST_LIST_TRAVERSE(&confs, cnf, list) {
789                         if (strcmp(cnf->confno, argv[2]) == 0)
790                                 break;
791                 }
792                 if (!cnf) {
793                         if ( !concise )
794                                 ast_cli(fd, "No such conference: %s.\n",argv[2]);
795                         return RESULT_SUCCESS;
796                 }
797                 /* Show all the users */
798                 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
799                         now = time(NULL);
800                         hr = (now - user->jointime) / 3600;
801                         min = ((now - user->jointime) % 3600) / 60;
802                         sec = (now - user->jointime) % 60;
803                         if ( !concise )
804                                 ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
805                                         user->user_no,
806                                         S_OR(user->chan->cid.cid_num, "<unknown>"),
807                                         S_OR(user->chan->cid.cid_name, "<no name>"),
808                                         user->chan->name,
809                                         user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
810                                         user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
811                                         user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
812                                         istalking(user->talking), 
813                                         user->userflags & CONFFLAG_HOLD ? " (On Hold) " : "", hr, min, sec);
814                         else 
815                                 ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
816                                         user->user_no,
817                                         S_OR(user->chan->cid.cid_num, ""),
818                                         S_OR(user->chan->cid.cid_name, ""),
819                                         user->chan->name,
820                                         user->userflags  & CONFFLAG_ADMIN   ? "1" : "",
821                                         user->userflags  & CONFFLAG_MONITOR ? "1" : "",
822                                         user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)  ? "1" : "",
823                                         user->talking, hr, min, sec);
824                         
825                 }
826                 if ( !concise )
827                         ast_cli(fd,"%d users in that conference.\n",cnf->users);
828
829                 return RESULT_SUCCESS;
830         } else 
831                 return RESULT_SHOWUSAGE;
832
833         if (option_debug)
834                 ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
835
836         admin_exec(NULL, cmdline);
837
838         return 0;
839 }
840
841 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
842 {
843         static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
844
845         int len = strlen(word);
846         int which = 0;
847         struct ast_conference *cnf = NULL;
848         struct ast_conf_user *usr = NULL;
849         char *confno = NULL;
850         char usrno[50] = "";
851         char *myline, *ret = NULL;
852         
853         if (pos == 1) {         /* Command */
854                 return ast_cli_complete(word, cmds, state);
855         } else if (pos == 2) {  /* Conference Number */
856                 AST_LIST_LOCK(&confs);
857                 AST_LIST_TRAVERSE(&confs, cnf, list) {
858                         if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
859                                 ret = cnf->confno;
860                                 break;
861                         }
862                 }
863                 ret = ast_strdup(ret); /* dup before releasing the lock */
864                 AST_LIST_UNLOCK(&confs);
865                 return ret;
866         } else if (pos == 3) {
867                 /* User Number || Conf Command option*/
868                 if (strstr(line, "mute") || strstr(line, "kick")) {
869                         if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
870                                 return strdup("all");
871                         which++;
872                         AST_LIST_LOCK(&confs);
873
874                         /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
875                         myline = ast_strdupa(line);
876                         if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
877                                 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
878                                         ;
879                         }
880                         
881                         AST_LIST_TRAVERSE(&confs, cnf, list) {
882                                 if (!strcmp(confno, cnf->confno))
883                                     break;
884                         }
885
886                         if (cnf) {
887                                 /* Search for the user */
888                                 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
889                                         snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
890                                         if (!strncasecmp(word, usrno, len) && ++which > state)
891                                                 break;
892                                 }
893                         }
894                         AST_LIST_UNLOCK(&confs);
895                         return usr ? strdup(usrno) : NULL;
896                 } else if ( strstr(line, "list") && ( 0 == state ) )
897                         return strdup("concise");
898         }
899
900         return NULL;
901 }
902         
903 static const char meetme_usage[] =
904 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
905 "       Executes a command for the conference or on a conferee\n";
906
907 static const char sla_show_usage[] =
908 "Usage: sla show\n"
909 "       Lists status of all shared line appearances\n";
910
911 static struct ast_cli_entry cli_meetme[] = {
912         { { "sla", "show", NULL },
913         sla_show, "Show status of Shared Line Appearances",
914         sla_show_usage, NULL },
915
916         { { "meetme", NULL, NULL },
917         meetme_cmd, "Execute a command on a conference or conferee",
918         meetme_usage, complete_meetmecmd },
919 };
920
921 static void conf_flush(int fd, struct ast_channel *chan)
922 {
923         int x;
924
925         /* read any frames that may be waiting on the channel
926            and throw them away
927         */
928         if (chan) {
929                 struct ast_frame *f;
930
931                 /* when no frames are available, this will wait
932                    for 1 millisecond maximum
933                 */
934                 while (ast_waitfor(chan, 1)) {
935                         f = ast_read(chan);
936                         if (f)
937                                 ast_frfree(f);
938                         else /* channel was hung up or something else happened */
939                                 break;
940                 }
941         }
942
943         /* flush any data sitting in the pseudo channel */
944         x = ZT_FLUSH_ALL;
945         if (ioctl(fd, ZT_FLUSH, &x))
946                 ast_log(LOG_WARNING, "Error flushing channel\n");
947
948 }
949
950 /* Remove the conference from the list and free it.
951    We assume that this was called while holding conflock. */
952 static int conf_free(struct ast_conference *conf)
953 {
954         int x;
955         
956         AST_LIST_REMOVE(&confs, conf, list);
957         manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
958
959         if (conf->recording == MEETME_RECORD_ACTIVE) {
960                 conf->recording = MEETME_RECORD_TERMINATE;
961                 AST_LIST_UNLOCK(&confs);
962                 while (1) {
963                         AST_LIST_LOCK(&confs);
964                         if (conf->recording == MEETME_RECORD_OFF)
965                                 break;
966                         AST_LIST_UNLOCK(&confs);
967                 }
968         }
969
970         for (x=0;x<AST_FRAME_BITS;x++) {
971                 if (conf->transframe[x])
972                         ast_frfree(conf->transframe[x]);
973                 if (conf->transpath[x])
974                         ast_translator_free_path(conf->transpath[x]);
975         }
976         if (conf->origframe)
977                 ast_frfree(conf->origframe);
978         if (conf->lchan)
979                 ast_hangup(conf->lchan);
980         if (conf->chan)
981                 ast_hangup(conf->chan);
982         else
983                 close(conf->fd);
984         
985         free(conf);
986
987         return 0;
988 }
989
990 static void conf_queue_dtmf(struct ast_conference *conf, int digit)
991 {
992         struct ast_conf_user *user;
993         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
994                 user->dtmf = digit;
995         }
996 }
997
998 static void conf_queue_control(struct ast_conference *conf, int control)
999 {
1000         struct ast_conf_user *user;
1001         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
1002                 user->control = control;
1003         }
1004 }
1005
1006
1007 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
1008 {
1009         struct ast_conf_user *user = NULL;
1010         struct ast_conf_user *usr = NULL;
1011         int fd;
1012         struct zt_confinfo ztc, ztc_empty;
1013         struct ast_frame *f;
1014         struct ast_channel *c;
1015         struct ast_frame fr;
1016         int outfd;
1017         int ms;
1018         int nfds;
1019         int res;
1020         int flags;
1021         int retryzap;
1022         int origfd;
1023         int musiconhold = 0;
1024         int firstpass = 0;
1025         int lastmarked = 0;
1026         int currentmarked = 0;
1027         int ret = -1;
1028         int x;
1029         int menu_active = 0;
1030         int using_pseudo = 0;
1031         int duration=20;
1032         int hr, min, sec;
1033         int sent_event = 0;
1034         time_t now;
1035         struct ast_dsp *dsp=NULL;
1036         struct ast_app *app;
1037         const char *agifile;
1038         const char *agifiledefault = "conf-background.agi";
1039         char meetmesecs[30] = "";
1040         char exitcontext[AST_MAX_CONTEXT] = "";
1041         char recordingtmp[AST_MAX_EXTENSION] = "";
1042         char members[10] = "";
1043         int dtmf, opt_waitmarked_timeout = 0;
1044         time_t timeout = 0;
1045         ZT_BUFFERINFO bi;
1046         char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
1047         char *buf = __buf + AST_FRIENDLY_OFFSET;
1048
1049         if (!(user = ast_calloc(1, sizeof(*user)))) {
1050                 AST_LIST_LOCK(&confs);
1051                 conf->refcount--;
1052                 if (!conf->refcount){
1053                         conf_free(conf);
1054                 }
1055                 AST_LIST_UNLOCK(&confs);
1056                 return ret;
1057         }
1058
1059         /* Possible timeout waiting for marked user */
1060         if ((confflags & CONFFLAG_WAITMARKED) &&
1061                 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
1062                 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
1063                 (opt_waitmarked_timeout > 0)) {
1064                 timeout = time(NULL) + opt_waitmarked_timeout;
1065         }
1066
1067         if (confflags & CONFFLAG_RECORDCONF) {
1068                 if (!conf->recordingfilename) {
1069                         conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
1070                         if (!conf->recordingfilename) {
1071                                 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
1072                                 conf->recordingfilename = ast_strdupa(recordingtmp);
1073                         }
1074                         conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
1075                         if (!conf->recordingformat) {
1076                                 snprintf(recordingtmp, sizeof(recordingtmp), "wav");
1077                                 conf->recordingformat = ast_strdupa(recordingtmp);
1078                         }
1079                         ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
1080                                     conf->confno, conf->recordingfilename, conf->recordingformat);
1081                 }
1082         }
1083
1084         if ((conf->recording == MEETME_RECORD_OFF) && ((confflags & CONFFLAG_RECORDCONF) || (conf->lchan))) {
1085                 pthread_attr_init(&conf->attr);
1086                 pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
1087                 ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
1088         }
1089
1090         time(&user->jointime);
1091
1092         if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
1093                 /* Sorry, but this conference is locked! */     
1094                 if (!ast_streamfile(chan, "conf-locked", chan->language))
1095                         ast_waitstream(chan, "");
1096                 goto outrun;
1097         }
1098
1099         if (confflags & CONFFLAG_MARKEDUSER)
1100                 conf->markedusers++;
1101       
1102         ast_mutex_lock(&conf->playlock);
1103
1104         if (AST_LIST_EMPTY(&conf->userlist))
1105                 user->user_no = 1;
1106         else
1107                 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
1108
1109         AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
1110
1111         user->chan = chan;
1112         user->userflags = confflags;
1113         user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
1114         user->talking = -1;
1115         conf->users++;
1116         /* Update table */
1117         snprintf(members, sizeof(members), "%d", conf->users);
1118         ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
1119
1120         /* This device changed state now - if this is the first user */
1121         if (conf->users == 1)
1122                 ast_device_state_changed("meetme:%s", conf->confno);
1123         if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1124                 ast_device_state_changed("SLA:%s", conf->confno + 4);
1125
1126         ast_mutex_unlock(&conf->playlock);
1127
1128         if (confflags & CONFFLAG_EXIT_CONTEXT) {
1129                 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
1130                         ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
1131                 else if (!ast_strlen_zero(chan->macrocontext)) 
1132                         ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
1133                 else
1134                         ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
1135         }
1136
1137         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1138                 snprintf(user->namerecloc, sizeof(user->namerecloc),
1139                          "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
1140                          conf->confno, user->user_no);
1141                 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
1142                         res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
1143                 else
1144                         res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
1145                 if (res == -1)
1146                         goto outrun;
1147         }
1148
1149         if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
1150                 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
1151                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1152                                 ast_waitstream(chan, "");
1153                 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
1154                         if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
1155                                 ast_waitstream(chan, "");
1156         }
1157
1158         if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
1159                 int keepplaying = 1;
1160
1161                 if (conf->users == 2) { 
1162                         if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
1163                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1164                                 ast_stopstream(chan);
1165                                 if (res > 0)
1166                                         keepplaying=0;
1167                                 else if (res == -1)
1168                                         goto outrun;
1169                         }
1170                 } else { 
1171                         if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
1172                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1173                                 ast_stopstream(chan);
1174                                 if (res > 0)
1175                                         keepplaying=0;
1176                                 else if (res == -1)
1177                                         goto outrun;
1178                         }
1179                         if (keepplaying) {
1180                                 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1181                                 if (res > 0)
1182                                         keepplaying=0;
1183                                 else if (res == -1)
1184                                         goto outrun;
1185                         }
1186                         if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
1187                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1188                                 ast_stopstream(chan);
1189                                 if (res > 0)
1190                                         keepplaying=0;
1191                                 else if (res == -1) 
1192                                         goto outrun;
1193                         }
1194                 }
1195         }
1196
1197         ast_indicate(chan, -1);
1198
1199         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1200                 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
1201                 goto outrun;
1202         }
1203
1204         if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
1205                 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
1206                 goto outrun;
1207         }
1208
1209         retryzap = strcasecmp(chan->tech->type, "Zap");
1210         user->zapchannel = !retryzap;
1211
1212  zapretry:
1213         origfd = chan->fds[0];
1214         if (retryzap) {
1215                 fd = open("/dev/zap/pseudo", O_RDWR);
1216                 if (fd < 0) {
1217                         ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1218                         goto outrun;
1219                 }
1220                 using_pseudo = 1;
1221                 /* Make non-blocking */
1222                 flags = fcntl(fd, F_GETFL);
1223                 if (flags < 0) {
1224                         ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
1225                         close(fd);
1226                         goto outrun;
1227                 }
1228                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
1229                         ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
1230                         close(fd);
1231                         goto outrun;
1232                 }
1233                 /* Setup buffering information */
1234                 memset(&bi, 0, sizeof(bi));
1235                 bi.bufsize = CONF_SIZE/2;
1236                 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
1237                 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
1238                 bi.numbufs = audio_buffers;
1239                 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
1240                         ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
1241                         close(fd);
1242                         goto outrun;
1243                 }
1244                 x = 1;
1245                 if (ioctl(fd, ZT_SETLINEAR, &x)) {
1246                         ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
1247                         close(fd);
1248                         goto outrun;
1249                 }
1250                 nfds = 1;
1251         } else {
1252                 /* XXX Make sure we're not running on a pseudo channel XXX */
1253                 fd = chan->fds[0];
1254                 nfds = 0;
1255         }
1256         memset(&ztc, 0, sizeof(ztc));
1257         memset(&ztc_empty, 0, sizeof(ztc_empty));
1258         /* Check to see if we're in a conference... */
1259         ztc.chan = 0;   
1260         if (ioctl(fd, ZT_GETCONF, &ztc)) {
1261                 ast_log(LOG_WARNING, "Error getting conference\n");
1262                 close(fd);
1263                 goto outrun;
1264         }
1265         if (ztc.confmode) {
1266                 /* Whoa, already in a conference...  Retry... */
1267                 if (!retryzap) {
1268                         if (option_debug)
1269                                 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
1270                         retryzap = 1;
1271                         goto zapretry;
1272                 }
1273         }
1274         memset(&ztc, 0, sizeof(ztc));
1275         /* Add us to the conference */
1276         ztc.chan = 0;   
1277         ztc.confno = conf->zapconf;
1278
1279         ast_mutex_lock(&conf->playlock);
1280
1281         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
1282                 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
1283                         if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1284                                 ast_waitstream(conf->chan, "");
1285                         if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
1286                                 ast_waitstream(conf->chan, "");
1287                 }
1288         }
1289
1290         if (confflags & CONFFLAG_MONITOR)
1291                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1292         else if (confflags & CONFFLAG_TALKER)
1293                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1294         else 
1295                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1296
1297         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1298                 ast_log(LOG_WARNING, "Error setting conference\n");
1299                 close(fd);
1300                 ast_mutex_unlock(&conf->playlock);
1301                 goto outrun;
1302         }
1303         if (option_debug)
1304                 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
1305
1306         if (!sent_event) {
1307                 manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
1308                               "Channel: %s\r\n"
1309                               "Uniqueid: %s\r\n"
1310                               "Meetme: %s\r\n"
1311                               "Usernum: %d\r\n",
1312                               chan->name, chan->uniqueid, conf->confno, user->user_no);
1313                 sent_event = 1;
1314         }
1315
1316         if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
1317                 firstpass = 1;
1318                 if (!(confflags & CONFFLAG_QUIET))
1319                         if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
1320                                 conf_play(chan, conf, ENTER);
1321         }
1322
1323         ast_mutex_unlock(&conf->playlock);
1324
1325         conf_flush(fd, chan);
1326
1327         if (confflags & CONFFLAG_AGI) {
1328                 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1329                    or use default filename of conf-background.agi */
1330
1331                 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
1332                 if (!agifile)
1333                         agifile = agifiledefault;
1334
1335                 if (user->zapchannel) {
1336                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
1337                         x = 1;
1338                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1339                 }
1340                 /* Find a pointer to the agi app and execute the script */
1341                 app = pbx_findapp("agi");
1342                 if (app) {
1343                         char *s = ast_strdupa(agifile);
1344                         ret = pbx_exec(chan, app, s);
1345                 } else {
1346                         ast_log(LOG_WARNING, "Could not find application (agi)\n");
1347                         ret = -2;
1348                 }
1349                 if (user->zapchannel) {
1350                         /*  Remove CONFMUTE mode on Zap channel */
1351                         x = 0;
1352                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1353                 }
1354         } else {
1355                 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
1356                         /*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1357                         x = 1;
1358                         ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1359                 }       
1360                 if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER) && !(dsp = ast_dsp_new())) {
1361                         ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
1362                         res = -1;
1363                 }
1364                 for(;;) {
1365                         int menu_was_active = 0;
1366
1367                         outfd = -1;
1368                         ms = -1;
1369
1370                         if (timeout && time(NULL) >= timeout)
1371                                 break;
1372
1373                         /* if we have just exited from the menu, and the user had a channel-driver
1374                            volume adjustment, restore it
1375                         */
1376                         if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
1377                                 set_talk_volume(user, user->listen.desired);
1378
1379                         menu_was_active = menu_active;
1380
1381                         currentmarked = conf->markedusers;
1382                         if (!(confflags & CONFFLAG_QUIET) &&
1383                             (confflags & CONFFLAG_MARKEDUSER) &&
1384                             (confflags & CONFFLAG_WAITMARKED) &&
1385                             lastmarked == 0) {
1386                                 if (currentmarked == 1 && conf->users > 1) {
1387                                         ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1388                                         if (conf->users - 1 == 1) {
1389                                                 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
1390                                                         ast_waitstream(chan, "");
1391                                         } else {
1392                                                 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
1393                                                         ast_waitstream(chan, "");
1394                                         }
1395                                 }
1396                                 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
1397                                         if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1398                                                 ast_waitstream(chan, "");
1399                         }
1400
1401                         c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
1402                         
1403                         
1404                         /* Update the struct with the actual confflags */
1405                         user->userflags = confflags;
1406                         
1407                         if (confflags & CONFFLAG_WAITMARKED) {
1408                                 if(currentmarked == 0) {
1409                                         if (lastmarked != 0) {
1410                                                 if (!(confflags & CONFFLAG_QUIET))
1411                                                         if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
1412                                                                 ast_waitstream(chan, "");
1413                                                 if (confflags & CONFFLAG_MARKEDEXIT) {
1414                                                         if (confflags & CONFFLAG_KICK_CONTINUE)
1415                                                                 ret = 0;
1416                                                         break;
1417                                                 } else {
1418                                                         ztc.confmode = ZT_CONF_CONF;
1419                                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1420                                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1421                                                                 close(fd);
1422                                                                 goto outrun;
1423                                                         }
1424                                                 }
1425                                         }
1426                                         if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
1427                                                 ast_moh_start(chan, NULL, NULL);
1428                                                 musiconhold = 1;
1429                                         } else {
1430                                                 ztc.confmode = ZT_CONF_CONF;
1431                                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1432                                                         ast_log(LOG_WARNING, "Error setting conference\n");
1433                                                         close(fd);
1434                                                         goto outrun;
1435                                                 }
1436                                         }
1437                                 } else if(currentmarked >= 1 && lastmarked == 0) {
1438                                         /* Marked user entered, so cancel timeout */
1439                                         timeout = 0;
1440                                         if (confflags & CONFFLAG_MONITOR)
1441                                                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1442                                         else if (confflags & CONFFLAG_TALKER)
1443                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1444                                         else
1445                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1446                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1447                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1448                                                 close(fd);
1449                                                 goto outrun;
1450                                         }
1451                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
1452                                                 ast_moh_stop(chan);
1453                                                 musiconhold = 0;
1454                                         }
1455                                         if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1456                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1457                                                         ast_waitstream(chan, "");
1458                                                 conf_play(chan, conf, ENTER);
1459                                         }
1460                                 }
1461                         }
1462
1463                         /* trying to add moh for single person conf */
1464                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1465                                 if (conf->users == 1) {
1466                                         if (musiconhold == 0) {
1467                                                 ast_moh_start(chan, NULL, NULL);
1468                                                 musiconhold = 1;
1469                                         } 
1470                                 } else {
1471                                         if (musiconhold) {
1472                                                 ast_moh_stop(chan);
1473                                                 musiconhold = 0;
1474                                         }
1475                                 }
1476                         }
1477                         
1478                         /* Leave if the last marked user left */
1479                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1480                                 if (confflags & CONFFLAG_KICK_CONTINUE)
1481                                         ret = 0;
1482                                 else
1483                                         ret = -1;
1484                                 break;
1485                         }
1486         
1487                         /* Check if my modes have changed */
1488
1489                         /* If I should be muted but am still talker, mute me */
1490                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1491                                 ztc.confmode ^= ZT_CONF_TALKER;
1492                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1493                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1494                                         ret = -1;
1495                                         break;
1496                                 }
1497
1498                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1499                                                 "Channel: %s\r\n"
1500                                                 "Uniqueid: %s\r\n"
1501                                                 "Meetme: %s\r\n"
1502                                                 "Usernum: %i\r\n"
1503                                                 "Status: on\r\n",
1504                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1505                         }
1506
1507                         /* If I should be un-muted but am not talker, un-mute me */
1508                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1509                                 ztc.confmode |= ZT_CONF_TALKER;
1510                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1511                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1512                                         ret = -1;
1513                                         break;
1514                                 }
1515
1516                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1517                                                 "Channel: %s\r\n"
1518                                                 "Uniqueid: %s\r\n"
1519                                                 "Meetme: %s\r\n"
1520                                                 "Usernum: %i\r\n"
1521                                                 "Status: off\r\n",
1522                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1523                         }
1524
1525                         /* If I have been kicked, exit the conference */
1526                         if (user->adminflags & ADMINFLAG_KICKME) {
1527                                 //You have been kicked.
1528                                 if (!ast_streamfile(chan, "conf-kicked", chan->language))
1529                                         ast_waitstream(chan, "");
1530                                 ret = 0;
1531                                 break;
1532                         }
1533
1534                         if (c) {
1535                                 if (c->fds[0] != origfd) {
1536                                         if (using_pseudo) {
1537                                                 /* Kill old pseudo */
1538                                                 close(fd);
1539                                                 using_pseudo = 0;
1540                                         }
1541                                         if (option_debug)
1542                                                 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
1543                                         retryzap = strcasecmp(c->tech->type, "Zap");
1544                                         user->zapchannel = !retryzap;
1545                                         goto zapretry;
1546                                 }
1547                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1548                                         f = ast_read_noaudio(c);
1549                                 else
1550                                         f = ast_read(c);
1551                                 if (!f)
1552                                         break;
1553                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1554                                         if (user->talk.actual)
1555                                                 ast_frame_adjust_volume(f, user->talk.actual);
1556
1557                                         if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
1558                                                 int totalsilence;
1559
1560                                                 if (user->talking == -1)
1561                                                         user->talking = 0;
1562
1563                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1564                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1565                                                         user->talking = 1;
1566                                                         if (confflags & CONFFLAG_MONITORTALKER)
1567                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1568                                                                       "Channel: %s\r\n"
1569                                                                       "Uniqueid: %s\r\n"
1570                                                                       "Meetme: %s\r\n"
1571                                                                       "Usernum: %d\r\n"
1572                                                                       "Status: on\r\n",
1573                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1574                                                 }
1575                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1576                                                         user->talking = 0;
1577                                                         if (confflags & CONFFLAG_MONITORTALKER)
1578                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1579                                                                       "Channel: %s\r\n"
1580                                                                       "Uniqueid: %s\r\n"
1581                                                                       "Meetme: %s\r\n"
1582                                                                       "Usernum: %d\r\n"
1583                                                                       "Status: off\r\n",
1584                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1585                                                 }
1586                                         }
1587                                         if (using_pseudo) {
1588                                                 /* Absolutely do _not_ use careful_write here...
1589                                                    it is important that we read data from the channel
1590                                                    as fast as it arrives, and feed it into the conference.
1591                                                    The buffering in the pseudo channel will take care of any
1592                                                    timing differences, unless they are so drastic as to lose
1593                                                    audio frames (in which case carefully writing would only
1594                                                    have delayed the audio even further).
1595                                                 */
1596                                                 /* As it turns out, we do want to use careful write.  We just
1597                                                    don't want to block, but we do want to at least *try*
1598                                                    to write out all the samples.
1599                                                  */
1600                                                 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
1601                                                         careful_write(fd, f->data, f->datalen, 0);
1602                                         }
1603                                 } else if ((f->frametype == AST_FRAME_DTMF) && 
1604                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1605                                         conf_queue_dtmf(conf, f->subclass);
1606                                 } else if ((f->frametype == AST_FRAME_CONTROL) && 
1607                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1608                                         conf_queue_control(conf, f->subclass);
1609                                         if (f->subclass == AST_CONTROL_HOLD)
1610                                                 confflags |= CONFFLAG_HOLD;
1611                                         else if (f->subclass == AST_CONTROL_UNHOLD)
1612                                                 confflags &= ~CONFFLAG_HOLD;
1613                                         user->userflags = confflags;
1614                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1615                                         char tmp[2];
1616
1617                                         tmp[0] = f->subclass;
1618                                         tmp[1] = '\0';
1619                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1620                                                 if (option_debug)
1621                                                         ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1622                                                 ret = 0;
1623                                                 ast_frfree(f);
1624                                                 break;
1625                                         } else if (option_debug > 1)
1626                                                 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1627                                 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1628                                         ret = 0;
1629                                         ast_frfree(f);
1630                                         break;
1631                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
1632                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
1633                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1634                                                 close(fd);
1635                                                 ast_frfree(f);
1636                                                 goto outrun;
1637                                         }
1638
1639                                         /* if we are entering the menu, and the user has a channel-driver
1640                                            volume adjustment, clear it
1641                                         */
1642                                         if (!menu_active && user->talk.desired && !user->talk.actual)
1643                                                 set_talk_volume(user, 0);
1644
1645                                         if (musiconhold) {
1646                                                 ast_moh_stop(chan);
1647                                         }
1648                                         if ((confflags & CONFFLAG_ADMIN)) {
1649                                                 /* Admin menu */
1650                                                 if (!menu_active) {
1651                                                         menu_active = 1;
1652                                                         /* Record this sound! */
1653                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
1654                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1655                                                                 ast_stopstream(chan);
1656                                                         } else 
1657                                                                 dtmf = 0;
1658                                                 } else 
1659                                                         dtmf = f->subclass;
1660                                                 if (dtmf) {
1661                                                         switch(dtmf) {
1662                                                         case '1': /* Un/Mute */
1663                                                                 menu_active = 0;
1664
1665                                                                 /* for admin, change both admin and use flags */
1666                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
1667                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1668                                                                 else
1669                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1670
1671                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1672                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1673                                                                                 ast_waitstream(chan, "");
1674                                                                 } else {
1675                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1676                                                                                 ast_waitstream(chan, "");
1677                                                                 }
1678                                                                 break;
1679                                                         case '2': /* Un/Lock the Conference */
1680                                                                 menu_active = 0;
1681                                                                 if (conf->locked) {
1682                                                                         conf->locked = 0;
1683                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
1684                                                                                 ast_waitstream(chan, "");
1685                                                                 } else {
1686                                                                         conf->locked = 1;
1687                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
1688                                                                                 ast_waitstream(chan, "");
1689                                                                 }
1690                                                                 break;
1691                                                         case '3': /* Eject last user */
1692                                                                 menu_active = 0;
1693                                                                 usr = AST_LIST_LAST(&conf->userlist);
1694                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
1695                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
1696                                                                                 ast_waitstream(chan, "");
1697                                                                 } else 
1698                                                                         usr->adminflags |= ADMINFLAG_KICKME;
1699                                                                 ast_stopstream(chan);
1700                                                                 break;  
1701                                                         case '4':
1702                                                                 tweak_listen_volume(user, VOL_DOWN);
1703                                                                 break;
1704                                                         case '6':
1705                                                                 tweak_listen_volume(user, VOL_UP);
1706                                                                 break;
1707                                                         case '7':
1708                                                                 tweak_talk_volume(user, VOL_DOWN);
1709                                                                 break;
1710                                                         case '8':
1711                                                                 menu_active = 0;
1712                                                                 break;
1713                                                         case '9':
1714                                                                 tweak_talk_volume(user, VOL_UP);
1715                                                                 break;
1716                                                         default:
1717                                                                 menu_active = 0;
1718                                                                 /* Play an error message! */
1719                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1720                                                                         ast_waitstream(chan, "");
1721                                                                 break;
1722                                                         }
1723                                                 }
1724                                         } else {
1725                                                 /* User menu */
1726                                                 if (!menu_active) {
1727                                                         menu_active = 1;
1728                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
1729                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1730                                                                 ast_stopstream(chan);
1731                                                         } else
1732                                                                 dtmf = 0;
1733                                                 } else 
1734                                                         dtmf = f->subclass;
1735                                                 if (dtmf) {
1736                                                         switch(dtmf) {
1737                                                         case '1': /* Un/Mute */
1738                                                                 menu_active = 0;
1739
1740                                                                 /* user can only toggle the self-muted state */
1741                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
1742
1743                                                                 /* they can't override the admin mute state */
1744                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1745                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1746                                                                                 ast_waitstream(chan, "");
1747                                                                 } else {
1748                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1749                                                                                 ast_waitstream(chan, "");
1750                                                                 }
1751                                                                 break;
1752                                                         case '4':
1753                                                                 tweak_listen_volume(user, VOL_DOWN);
1754                                                                 break;
1755                                                         case '6':
1756                                                                 tweak_listen_volume(user, VOL_UP);
1757                                                                 break;
1758                                                         case '7':
1759                                                                 tweak_talk_volume(user, VOL_DOWN);
1760                                                                 break;
1761                                                         case '8':
1762                                                                 menu_active = 0;
1763                                                                 break;
1764                                                         case '9':
1765                                                                 tweak_talk_volume(user, VOL_UP);
1766                                                                 break;
1767                                                         default:
1768                                                                 menu_active = 0;
1769                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1770                                                                         ast_waitstream(chan, "");
1771                                                                 break;
1772                                                         }
1773                                                 }
1774                                         }
1775                                         if (musiconhold)
1776                                                 ast_moh_start(chan, NULL, NULL);
1777
1778                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1779                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1780                                                 close(fd);
1781                                                 ast_frfree(f);
1782                                                 goto outrun;
1783                                         }
1784
1785                                         conf_flush(fd, chan);
1786                                 } else if (option_debug) {
1787                                         ast_log(LOG_DEBUG,
1788                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
1789                                                 chan->name, f->frametype, f->subclass);
1790                                 }
1791                                 ast_frfree(f);
1792                         } else if (outfd > -1) {
1793                                 if (user->control) {
1794                                         switch(user->control) {
1795                                         case AST_CONTROL_RINGING:
1796                                         case AST_CONTROL_PROGRESS:
1797                                         case AST_CONTROL_PROCEEDING:
1798                                                 ast_indicate(chan, user->control);
1799                                                 break;
1800                                         case AST_CONTROL_ANSWER:
1801                                                 if (chan->_state != AST_STATE_UP)
1802                                                         ast_answer(chan);
1803                                                 break;
1804                                         }
1805                                         user->control = 0;
1806                                         if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1807                                                 ast_device_state_changed("SLA:%s", conf->confno + 4);
1808                                         continue;
1809                                 }
1810                                 if (user->dtmf) {
1811                                         memset(&fr, 0, sizeof(fr));
1812                                         fr.frametype = AST_FRAME_DTMF;
1813                                         fr.subclass = user->dtmf;
1814                                         if (ast_write(chan, &fr) < 0) {
1815                                                 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1816                                         }
1817                                         user->dtmf = 0;
1818                                         continue;
1819                                 }
1820                                 res = read(outfd, buf, CONF_SIZE);
1821                                 if (res > 0) {
1822                                         memset(&fr, 0, sizeof(fr));
1823                                         fr.frametype = AST_FRAME_VOICE;
1824                                         fr.subclass = AST_FORMAT_SLINEAR;
1825                                         fr.datalen = res;
1826                                         fr.samples = res/2;
1827                                         fr.data = buf;
1828                                         fr.offset = AST_FRIENDLY_OFFSET;
1829                                         if (!user->listen.actual && 
1830                                                 ((confflags & CONFFLAG_MONITOR) || 
1831                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
1832                                                  (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
1833                                                  )) {
1834                                                 int index;
1835                                                 for (index=0;index<AST_FRAME_BITS;index++)
1836                                                         if (chan->rawwriteformat & (1 << index))
1837                                                                 break;
1838                                                 if (index >= AST_FRAME_BITS)
1839                                                         goto bailoutandtrynormal;
1840                                                 ast_mutex_lock(&conf->listenlock);
1841                                                 if (!conf->transframe[index]) {
1842                                                         if (conf->origframe) {
1843                                                                 if (!conf->transpath[index])
1844                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
1845                                                                 if (conf->transpath[index]) {
1846                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
1847                                                                         if (!conf->transframe[index])
1848                                                                                 conf->transframe[index] = &ast_null_frame;
1849                                                                 }
1850                                                         }
1851                                                 }
1852                                                 if (conf->transframe[index]) {
1853                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
1854                                                                 if (ast_write(chan, conf->transframe[index]))
1855                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1856                                                         }
1857                                                 } else {
1858                                                         ast_mutex_unlock(&conf->listenlock);
1859                                                         goto bailoutandtrynormal;
1860                                                 }
1861                                                 ast_mutex_unlock(&conf->listenlock);
1862                                         } else {
1863 bailoutandtrynormal:                                    
1864                                                 if (user->listen.actual)
1865                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
1866                                                 if (ast_write(chan, &fr) < 0) {
1867                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1868                                                 }
1869                                         }
1870                                 } else 
1871                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
1872                         }
1873                         lastmarked = currentmarked;
1874                 }
1875         }
1876
1877         if (musiconhold)
1878                 ast_moh_stop(chan);
1879         
1880         if (using_pseudo)
1881                 close(fd);
1882         else {
1883                 /* Take out of conference */
1884                 ztc.chan = 0;   
1885                 ztc.confno = 0;
1886                 ztc.confmode = 0;
1887                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1888                         ast_log(LOG_WARNING, "Error setting conference\n");
1889                 }
1890         }
1891
1892         reset_volumes(user);
1893
1894         AST_LIST_LOCK(&confs);
1895         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
1896                 conf_play(chan, conf, LEAVE);
1897
1898         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1899                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
1900                         if ((conf->chan) && (conf->users > 1)) {
1901                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1902                                         ast_waitstream(conf->chan, "");
1903                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
1904                                         ast_waitstream(conf->chan, "");
1905                         }
1906                         ast_filedelete(user->namerecloc, NULL);
1907                 }
1908         }
1909         AST_LIST_UNLOCK(&confs);
1910
1911  outrun:
1912         AST_LIST_LOCK(&confs);
1913
1914         if (dsp)
1915                 ast_dsp_free(dsp);
1916         
1917         if (user->user_no) { /* Only cleanup users who really joined! */
1918                 now = time(NULL);
1919                 hr = (now - user->jointime) / 3600;
1920                 min = ((now - user->jointime) % 3600) / 60;
1921                 sec = (now - user->jointime) % 60;
1922
1923                 if (sent_event) {
1924                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
1925                                       "Channel: %s\r\n"
1926                                       "Uniqueid: %s\r\n"
1927                                       "Meetme: %s\r\n"
1928                                       "Usernum: %d\r\n"
1929                                       "CallerIDNum: %s\r\n"
1930                                       "CallerIDName: %s\r\n"
1931                                       "Duration: %ld\r\n",
1932                                       chan->name, chan->uniqueid, conf->confno, 
1933                                       user->user_no,
1934                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
1935                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
1936                                       (now - user->jointime));
1937                 }
1938
1939                 conf->users--;
1940                 conf->refcount--;
1941                 /* Update table */
1942                 snprintf(members, sizeof(members), "%d", conf->users);
1943                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
1944                 if (confflags & CONFFLAG_MARKEDUSER) 
1945                         conf->markedusers--;
1946                 /* Remove ourselves from the list */
1947                 AST_LIST_REMOVE(&conf->userlist, user, list);
1948
1949                 /* Change any states */
1950                 if (!conf->users)
1951                         ast_device_state_changed("meetme:%s", conf->confno);
1952                 if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1953                         ast_device_state_changed("SLA:%s", conf->confno + 4);
1954
1955                 if (AST_LIST_EMPTY(&conf->userlist)) {
1956                         /* close this one when no more users and no references*/
1957                         if (!conf->refcount)
1958                                 conf_free(conf);
1959                 }
1960                 /* Return the number of seconds the user was in the conf */
1961                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
1962                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
1963         }
1964         free(user);
1965         AST_LIST_UNLOCK(&confs);
1966
1967         return ret;
1968 }
1969
1970 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
1971                                                  char *dynamic_pin, int refcount, struct ast_flags *confflags)
1972 {
1973         struct ast_variable *var;
1974         struct ast_conference *cnf;
1975
1976         /* Check first in the conference list */
1977         AST_LIST_LOCK(&confs);
1978         AST_LIST_TRAVERSE(&confs, cnf, list) {
1979                 if (!strcmp(confno, cnf->confno)) 
1980                         break;
1981         }
1982         if (cnf){
1983                 cnf->refcount += refcount;
1984         }
1985         AST_LIST_UNLOCK(&confs);
1986
1987         if (!cnf) {
1988                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
1989
1990                 cnf = ast_calloc(1, sizeof(struct ast_conference));
1991                 if (!cnf) {
1992                         ast_log(LOG_ERROR, "Out of memory\n");
1993                         return NULL;
1994                 }
1995
1996                 var = ast_load_realtime("meetme", "confno", confno, NULL);
1997                 while (var) {
1998                         if (!strcasecmp(var->name, "confno")) {
1999                                 ast_copy_string(cnf->confno, var->value, sizeof(cnf->confno));
2000                         } else if (!strcasecmp(var->name, "pin")) {
2001                                 pin = ast_strdupa(var->value);
2002                         } else if (!strcasecmp(var->name, "adminpin")) {
2003                                 pinadmin = ast_strdupa(var->value);
2004                         }
2005                         var = var->next;
2006                 }
2007                 ast_variables_destroy(var);
2008
2009                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
2010         }
2011
2012         if (cnf) {
2013                 if (confflags && !cnf->chan &&
2014                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2015                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2016                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2017                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2018                 }
2019                 
2020                 if (confflags && !cnf->chan &&
2021                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2022                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2023                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2024                 }
2025         }
2026
2027         return cnf;
2028 }
2029
2030
2031 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2032                                         char *dynamic_pin, int refcount, struct ast_flags *confflags)
2033 {
2034         struct ast_config *cfg;
2035         struct ast_variable *var;
2036         struct ast_conference *cnf;
2037         char *parse;
2038         AST_DECLARE_APP_ARGS(args,
2039                 AST_APP_ARG(confno);
2040                 AST_APP_ARG(pin);
2041                 AST_APP_ARG(pinadmin);
2042         );
2043
2044         /* Check first in the conference list */
2045         AST_LIST_LOCK(&confs);
2046         AST_LIST_TRAVERSE(&confs, cnf, list) {
2047                 if (!strcmp(confno, cnf->confno)) 
2048                         break;
2049         }
2050         if (cnf){
2051                 cnf->refcount += refcount;
2052         }
2053         AST_LIST_UNLOCK(&confs);
2054
2055         if (!cnf) {
2056                 if (dynamic) {
2057                         /* No need to parse meetme.conf */
2058                         if (option_debug)
2059                                 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
2060                         if (dynamic_pin) {
2061                                 if (dynamic_pin[0] == 'q') {
2062                                         /* Query the user to enter a PIN */
2063                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
2064                                                 return NULL;
2065                                 }
2066                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
2067                         } else {
2068                                 cnf = build_conf(confno, "", "", make, dynamic, refcount);
2069                         }
2070                 } else {
2071                         /* Check the config */
2072                         cfg = ast_config_load(CONFIG_FILE_NAME);
2073                         if (!cfg) {
2074                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2075                                 return NULL;
2076                         }
2077                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2078                                 if (strcasecmp(var->name, "conf"))
2079                                         continue;
2080                                 
2081                                 if (!(parse = ast_strdupa(var->value)))
2082                                         return NULL;
2083                                 
2084                                 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2085                                 if (!strcasecmp(args.confno, confno)) {
2086                                         /* Bingo it's a valid conference */
2087                                         cnf = build_conf(args.confno,
2088                                                         S_OR(args.pin, ""),
2089                                                         S_OR(args.pinadmin, ""),
2090                                                         make, dynamic, refcount);
2091                                         break;
2092                                 }
2093                         }
2094                         if (!var) {
2095                                 if (option_debug)
2096                                         ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
2097                         }
2098                         ast_config_destroy(cfg);
2099                 }
2100         } else if (dynamic_pin) {
2101                 /* Correct for the user selecting 'D' instead of 'd' to have
2102                    someone join into a conference that has already been created
2103                    with a pin. */
2104                 if (dynamic_pin[0] == 'q')
2105                         dynamic_pin[0] = '\0';
2106         }
2107
2108         if (cnf) {
2109                 if (confflags && !cnf->chan &&
2110                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2111                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2112                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2113                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2114                 }
2115                 
2116                 if (confflags && !cnf->chan &&
2117                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2118                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2119                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2120                 }
2121         }
2122
2123         return cnf;
2124 }
2125
2126 /*! \brief The MeetmeCount application */
2127 static int count_exec(struct ast_channel *chan, void *data)
2128 {
2129         struct ast_module_user *u;
2130         int res = 0;
2131         struct ast_conference *conf;
2132         int count;
2133         char *localdata;
2134         char val[80] = "0"; 
2135         AST_DECLARE_APP_ARGS(args,
2136                 AST_APP_ARG(confno);
2137                 AST_APP_ARG(varname);
2138         );
2139
2140         if (ast_strlen_zero(data)) {
2141                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2142                 return -1;
2143         }
2144
2145         u = ast_module_user_add(chan);
2146         
2147         if (!(localdata = ast_strdupa(data))) {
2148                 ast_module_user_remove(u);
2149                 return -1;
2150         }
2151
2152         AST_STANDARD_APP_ARGS(args, localdata);
2153         
2154         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, NULL);
2155
2156         if (conf)
2157                 count = conf->users;
2158         else
2159                 count = 0;
2160
2161         if (!ast_strlen_zero(args.varname)){
2162                 /* have var so load it and exit */
2163                 snprintf(val, sizeof(val), "%d",count);
2164                 pbx_builtin_setvar_helper(chan, args.varname, val);
2165         } else {
2166                 if (chan->_state != AST_STATE_UP)
2167                         ast_answer(chan);
2168                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2169         }
2170         ast_module_user_remove(u);
2171
2172         return res;
2173 }
2174
2175 /*! \brief The meetme() application */
2176 static int conf_exec(struct ast_channel *chan, void *data)
2177 {
2178         int res=-1;
2179         struct ast_module_user *u;
2180         char confno[AST_MAX_EXTENSION] = "";
2181         int allowretry = 0;
2182         int retrycnt = 0;
2183         struct ast_conference *cnf;
2184         struct ast_flags confflags = {0};
2185         int dynamic = 0;
2186         int empty = 0, empty_no_pin = 0;
2187         int always_prompt = 0;
2188         char *notdata, *info, the_pin[AST_MAX_EXTENSION] = "";
2189         AST_DECLARE_APP_ARGS(args,
2190                 AST_APP_ARG(confno);
2191                 AST_APP_ARG(options);
2192                 AST_APP_ARG(pin);
2193         );
2194         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2195
2196         u = ast_module_user_add(chan);
2197
2198         if (ast_strlen_zero(data)) {
2199                 allowretry = 1;
2200                 notdata = "";
2201         } else {
2202                 notdata = data;
2203         }
2204         
2205         if (chan->_state != AST_STATE_UP)
2206                 ast_answer(chan);
2207
2208         info = ast_strdupa(notdata);
2209
2210         AST_STANDARD_APP_ARGS(args, info);      
2211
2212         if (args.confno) {
2213                 ast_copy_string(confno, args.confno, sizeof(confno));
2214                 if (ast_strlen_zero(confno)) {
2215                         allowretry = 1;
2216                 }
2217         }
2218         
2219         if (args.pin)
2220                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2221
2222         if (args.options) {
2223                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2224                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2225                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2226                         strcpy(the_pin, "q");
2227
2228                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2229                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2230                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2231         }
2232
2233         do {
2234                 if (retrycnt > 3)
2235                         allowretry = 0;
2236                 if (empty) {
2237                         int i, map[1024] = { 0, };
2238                         struct ast_config *cfg;
2239                         struct ast_variable *var;
2240                         int confno_int;
2241
2242                         AST_LIST_LOCK(&confs);
2243                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2244                                 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
2245                                         /* Disqualify in use conference */
2246                                         if (confno_int >= 0 && confno_int < 1024)
2247                                                 map[confno_int]++;
2248                                 }
2249                         }
2250                         AST_LIST_UNLOCK(&confs);
2251
2252                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2253                         if ((empty_no_pin) || (!dynamic)) {
2254                                 cfg = ast_config_load(CONFIG_FILE_NAME);
2255                                 if (cfg) {
2256                                         var = ast_variable_browse(cfg, "rooms");
2257                                         while (var) {
2258                                                 if (!strcasecmp(var->name, "conf")) {
2259                                                         char *stringp = ast_strdupa(var->value);
2260                                                         if (stringp) {
2261                                                                 char *confno_tmp = strsep(&stringp, "|,");
2262                                                                 int found = 0;
2263                                                                 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
2264                                                                         if ((confno_int >= 0) && (confno_int < 1024)) {
2265                                                                                 if (stringp && empty_no_pin) {
2266                                                                                         map[confno_int]++;
2267                                                                                 }
2268                                                                         }
2269                                                                 }
2270                                                                 if (!dynamic) {
2271                                                                         /* For static:  run through the list and see if this conference is empty */
2272                                                                         AST_LIST_LOCK(&confs);
2273                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2274                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2275                                                                                         /* The conference exists, therefore it's not empty */
2276                                                                                         found = 1;
2277                                                                                         break;
2278                                                                                 }
2279                                                                         }
2280                                                                         AST_LIST_UNLOCK(&confs);
2281                                                                         if (!found) {
2282                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2283                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2284                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2285                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2286                                                                                          * Case 3:  not empty_no_pin
2287                                                                                          */
2288                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2289                                                                                         break;
2290                                                                                         /* XXX the map is not complete (but we do have a confno) */
2291                                                                                 }
2292                                                                         }
2293                                                                 }
2294                                                         }
2295                                                 }
2296                                                 var = var->next;
2297                                         }
2298                                         ast_config_destroy(cfg);
2299                                 }
2300                         }
2301
2302                         /* Select first conference number not in use */
2303                         if (ast_strlen_zero(confno) && dynamic) {
2304                                 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
2305                                         if (!map[i]) {
2306                                                 snprintf(confno, sizeof(confno), "%d", i);
2307                                                 break;
2308                                         }
2309                                 }
2310                         }
2311
2312                         /* Not found? */
2313                         if (ast_strlen_zero(confno)) {
2314                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2315                                 if (!res)
2316                                         ast_waitstream(chan, "");
2317                         } else {
2318                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2319                                         if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
2320                                                 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2321                                                 if (!res) {
2322                                                         ast_waitstream(chan, "");
2323                                                         res = ast_say_digits(chan, confno_int, "", chan->language);
2324                                                 }
2325                                         }
2326                                 } else {
2327                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2328                                 }
2329                         }
2330                 }
2331
2332                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2333                         /* Prompt user for conference number */
2334                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2335                         if (res < 0) {
2336                                 /* Don't try to validate when we catch an error */
2337                                 confno[0] = '\0';
2338                                 allowretry = 0;
2339                                 break;
2340                         }
2341                 }
2342                 if (!ast_strlen_zero(confno)) {
2343                         /* Check the validity of the conference */
2344                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2345                         if (!cnf)
2346                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2347
2348                         if (!cnf) {
2349                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2350                                 if (!res)
2351                                         ast_waitstream(chan, "");
2352                                 res = -1;
2353                                 if (allowretry)
2354                                         confno[0] = '\0';
2355                         } else {
2356                                 if ((!ast_strlen_zero(cnf->pin) &&
2357                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2358                                     (!ast_strlen_zero(cnf->pinadmin) &&
2359                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2360                                         char pin[AST_MAX_EXTENSION]="";
2361                                         int j;
2362
2363                                         /* Allow the pin to be retried up to 3 times */
2364                                         for (j = 0; j < 3; j++) {
2365                                                 if (*the_pin && (always_prompt == 0)) {
2366                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2367                                                         res = 0;
2368                                                 } else {
2369                                                         /* Prompt user for pin if pin is required */
2370                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2371                                                 }
2372                                                 if (res >= 0) {
2373                                                         if (!strcasecmp(pin, cnf->pin) ||
2374                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2375                                                              !strcasecmp(pin, cnf->pinadmin))) {
2376                                                                 /* Pin correct */
2377                                                                 allowretry = 0;
2378                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
2379                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
2380                                                                 /* Run the conference */
2381                                                                 res = conf_run(chan, cnf, confflags.flags, optargs);
2382                                                                 break;
2383                                                         } else {
2384                                                                 /* Pin invalid */
2385                                                                 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
2386                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
2387                                                                         ast_stopstream(chan);
2388                                                                 }
2389                                                                 else {
2390                                                                         ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2391                                                                         break;
2392                                                                 }
2393                                                                 if (res < 0) {
2394                                                                         AST_LIST_LOCK(&confs);
2395                                                                         cnf->refcount--;
2396                                                                         if (!cnf->refcount){
2397                                                                                 conf_free(cnf);
2398                                                                         }
2399                                                                         AST_LIST_UNLOCK(&confs);
2400                                                                         break;
2401                                                                 }
2402                                                                 pin[0] = res;
2403                                                                 pin[1] = '\0';
2404                                                                 res = -1;
2405                                                                 if (allowretry)
2406                                                                         confno[0] = '\0';
2407                                                         }
2408                                                 } else {
2409                                                         /* failed when getting the pin */
2410                                                         res = -1;
2411                                                         allowretry = 0;
2412                                                         /* see if we need to get rid of the conference */
2413                                                         AST_LIST_LOCK(&confs);
2414                                                         cnf->refcount--;
2415                                                         if (!cnf->refcount) {
2416                                                                 conf_free(cnf);
2417                                                         }
2418                                                         AST_LIST_UNLOCK(&confs);
2419                                                         break;
2420                                                 }
2421
2422                                                 /* Don't retry pin with a static pin */
2423                                                 if (*the_pin && (always_prompt==0)) {
2424                                                         break;
2425                                                 }
2426                                         }
2427                                 } else {
2428                                         /* No pin required */
2429                                         allowretry = 0;
2430
2431                                         /* Run the conference */
2432                                         res = conf_run(chan, cnf, confflags.flags, optargs);
2433                                 }
2434                         }
2435                 }
2436         } while (allowretry);
2437         
2438         ast_module_user_remove(u);
2439         
2440         return res;
2441 }
2442
2443 struct sla_originate_helper {
2444         char tech[100];
2445         char data[200];
2446         char app[20];
2447         char appdata[100];
2448         char cid_name[100];
2449         char cid_num[100];
2450 };
2451
2452 static void *sla_originate(void *data)
2453 {
2454         struct sla_originate_helper *in = data;
2455         int reason = 0;
2456         struct ast_channel *chan = NULL;
2457
2458         ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, 99999, in->app, in->appdata, &reason, 1, 
2459                 S_OR(in->cid_num, NULL), 
2460                 S_OR(in->cid_name, NULL),
2461                 NULL, NULL, &chan);
2462         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2463         if (chan)
2464                 ast_channel_unlock(chan);
2465         free(in);
2466         return NULL;
2467 }
2468
2469 /*! Call in stations and trunk to the SLA */
2470 static void do_invite(struct ast_channel *orig, const char *tech, const char *dest, const char *app, const char *data)
2471 {
2472         struct sla_originate_helper *slal;
2473         pthread_attr_t attr;
2474         pthread_t th;
2475
2476         if (!(slal = ast_calloc(1, sizeof(*slal))))
2477                 return;
2478         
2479         ast_copy_string(slal->tech, tech, sizeof(slal->tech));
2480         ast_copy_string(slal->data, dest, sizeof(slal->data));
2481         ast_copy_string(slal->app, app, sizeof(slal->app));
2482         ast_copy_string(slal->appdata, data, sizeof(slal->appdata));
2483         if (orig->cid.cid_num)
2484                 ast_copy_string(slal->cid_num, orig->cid.cid_num, sizeof(slal->cid_num));
2485         if (orig->cid.cid_name)
2486                 ast_copy_string(slal->cid_name, orig->cid.cid_name, sizeof(slal->cid_name));
2487         pthread_attr_init(&attr);
2488         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2489         ast_pthread_create(&th, &attr, sla_originate, slal);
2490 }
2491
2492 static void invite_stations(struct ast_channel *orig, struct ast_sla *sla)
2493 {
2494         ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
2495                 do_invite(orig, iterator->tech, iterator->dest, "SLAStation", sla->name);
2496         });
2497 }
2498
2499 static void invite_trunk(struct ast_channel *orig, struct ast_sla *sla)
2500 {
2501         do_invite(orig, sla->trunktech, sla->trunkdest, "SLATrunk", sla->name);
2502 }
2503
2504
2505 static int sla_checkforhold(struct ast_conference *conf, int hangup)
2506 {
2507         struct ast_conf_user *user;
2508         struct ast_channel *onhold=NULL;
2509         int holdcount = 0;
2510         int stationcount = 0;
2511         int amonhold = 0;
2512         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2513                 if (user->userflags & CONFFLAG_SLA_STATION) {
2514                         stationcount++;
2515                         if ((user->userflags & CONFFLAG_HOLD)) {
2516                                 holdcount++;
2517                                 onhold = user->chan;
2518                         }
2519                 }
2520         }
2521         if ((holdcount == 1) && (stationcount == 1)) {
2522                 amonhold = 1;
2523                 if (hangup)
2524                         ast_softhangup(onhold, AST_SOFTHANGUP_EXPLICIT);
2525         } else if (holdcount && (stationcount == holdcount))
2526                 amonhold = 1;
2527         return amonhold;
2528 }
2529
2530
2531 /*! \brief The slas()/slat() application */
2532 static int sla_exec(struct ast_channel *chan, void *data, int trunk)
2533 {
2534         int res=-1;
2535         struct ast_module_user *u;
2536         char confno[AST_MAX_EXTENSION] = "";
2537         struct ast_sla *sla;
2538         struct ast_conference *cnf;
2539         char *info;
2540         struct ast_flags confflags = {0};
2541         int dynamic = 1;
2542         char *options[OPT_ARG_ARRAY_SIZE] = { NULL, };
2543         AST_DECLARE_APP_ARGS(args,
2544                 AST_APP_ARG(confno);
2545                 AST_APP_ARG(options);
2546         );
2547
2548         if (ast_strlen_zero(data)) {
2549                 ast_log(LOG_WARNING, "SLA%c requires an argument (line)\n", trunk ? 'T' : 'S');
2550                 return -1;
2551         }
2552
2553         info = ast_strdupa(data);
2554
2555         AST_STANDARD_APP_ARGS(args, info);      
2556
2557         if (ast_strlen_zero(args.confno)) {
2558                 ast_log(LOG_WARNING, "SLA%c requires an SLA line number\n", trunk ? 'T' : 'S');
2559                 return -1;
2560         }
2561         
2562         u = ast_module_user_add(chan);
2563
2564         if (args.options)
2565                 ast_app_parse_options(sla_opts, &confflags, NULL, args.options);
2566                 
2567         ast_set_flag(&confflags, CONFFLAG_QUIET|CONFFLAG_DYNAMIC);
2568         if (trunk)
2569                 ast_set_flag(&confflags, CONFFLAG_WAITMARKED|CONFFLAG_MARKEDEXIT|CONFFLAG_SLA_TRUNK);
2570         else
2571                 ast_set_flag(&confflags, CONFFLAG_MARKEDUSER|CONFFLAG_SLA_STATION);
2572
2573         sla = ASTOBJ_CONTAINER_FIND(&slas, args.confno);
2574         if (sla) {
2575                 snprintf(confno, sizeof(confno), "sla-%s", args.confno);
2576                 cnf = find_conf(chan, confno, 1, dynamic, "", 1, &confflags);
2577                 if (cnf) {
2578                         sla_checkforhold(cnf, 1);
2579                         if (!cnf->users) {
2580                                 if (trunk) {
2581                                         ast_indicate(chan, AST_CONTROL_RINGING);
2582                                         invite_stations(chan, sla);
2583                                 } else
2584                                         invite_trunk(chan, sla);
2585                         } else if (chan->_state != AST_STATE_UP)
2586                                 ast_answer(chan);
2587
2588                         /* Run the conference */
2589                         res = conf_run(chan, cnf, confflags.flags, options);
2590                 } else
2591                         ast_log(LOG_WARNING, "SLA%c: Found SLA '%s' but unable to build conference!\n", trunk ? 'T' : 'S', args.confno);
2592                 ASTOBJ_UNREF(sla, sla_destroy);
2593         } else {
2594                 ast_log(LOG_WARNING, "SLA%c: SLA '%s' not found!\n", trunk ? 'T' : 'S', args.confno);
2595         }
2596         
2597         ast_module_user_remove(u);
2598         
2599         return res;
2600 }
2601
2602 /*! \brief The slas() wrapper */
2603 static int slas_exec(struct ast_channel *chan, void *data)
2604 {
2605         return sla_exec(chan, data, 0);
2606 }
2607
2608 /*! \brief The slat() wrapper */
2609 static int slat_exec(struct ast_channel *chan, void *data)
2610 {
2611         return sla_exec(chan, data, 1);
2612 }
2613
2614 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident) 
2615 {
2616         struct ast_conf_user *user = NULL;
2617         int cid;
2618         
2619         sscanf(callerident, "%i", &cid);
2620         if (conf && callerident) {
2621                 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2622                         if (cid == user->user_no)
2623                                 return user;
2624                 }
2625         }
2626         return NULL;
2627 }
2628
2629 /*! \brief The MeetMeadmin application */
2630 /* MeetMeAdmin(confno, command, caller) */
2631 static int admin_exec(struct ast_channel *chan, void *data) {
2632         char *params;
2633         struct ast_conference *cnf;
2634         struct ast_conf_user *user = NULL;
2635         struct ast_module_user *u;
2636         AST_DECLARE_APP_ARGS(args,
2637                 AST_APP_ARG(confno);
2638                 AST_APP_ARG(command);
2639                 AST_APP_ARG(user);
2640         );
2641
2642         if (ast_strlen_zero(data)) {
2643                 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
2644                 return -1;
2645         }
2646
2647         u = ast_module_user_add(chan);
2648
2649         AST_LIST_LOCK(&confs);
2650         
2651         params = ast_strdupa(data);
2652         AST_STANDARD_APP_ARGS(args, params);
2653
2654         if (!args.command) {
2655                 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2656                 AST_LIST_UNLOCK(&confs);
2657                 ast_module_user_remove(u);
2658                 return -1;
2659         }
2660         AST_LIST_TRAVERSE(&confs, cnf, list) {
2661                 if (!strcmp(cnf->confno, args.confno))
2662                         break;
2663         }
2664
2665         if (!cnf) {
2666                 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
2667                 AST_LIST_UNLOCK(&confs);
2668                 ast_module_user_remove(u);
2669                 return 0;
2670         }
2671
2672         if (args.user)
2673                 user = find_user(cnf, args.user);
2674
2675         switch (*args.command) {
2676         case 76: /* L: Lock */ 
2677                 cnf->locked = 1;
2678                 break;
2679         case 108: /* l: Unlock */ 
2680                 cnf->locked = 0;
2681                 break;
2682         case 75: /* K: kick all users */
2683                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2684                         user->adminflags |= ADMINFLAG_KICKME;
2685                 break;
2686         case 101: /* e: Eject last user*/
2687                 user = AST_LIST_LAST(&cnf->userlist);
2688                 if (!(user->userflags & CONFFLAG_ADMIN))
2689                         user->adminflags |= ADMINFLAG_KICKME;
2690                 else
2691                         ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
2692                 break;
2693         case 77: /* M: Mute */ 
2694                 if (user) {
2695                         user->adminflags |= ADMINFLAG_MUTED;
2696                 } else
2697                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2698                 break;
2699         case 78: /* N: Mute all (non-admin) users */
2700                 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
2701                         if (!(user->userflags & CONFFLAG_ADMIN))
2702                                 user->adminflags |= ADMINFLAG_MUTED;
2703                 }
2704                 break;                                  
2705         case 109: /* m: Unmute */ 
2706                 if (user) {
2707                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2708                 } else
2709                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2710                 break;
2711         case 110: /* n: Unmute all users */
2712                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2713                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2714                 break;
2715         case 107: /* k: Kick user */ 
2716                 if (user)
2717                         user->adminflags |= ADMINFLAG_KICKME;
2718                 else
2719                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2720                 break;
2721         case 118: /* v: Lower all users listen volume */
2722                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2723                         tweak_listen_volume(user, VOL_DOWN);
2724                 break;
2725         case 86: /* V: Raise all users listen volume */
2726                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2727                         tweak_listen_volume(user, VOL_UP);
2728                 break;
2729         case 115: /* s: Lower all users speaking volume */
2730                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2731                         tweak_talk_volume(user, VOL_DOWN);
2732                 break;
2733         case 83: /* S: Raise all users speaking volume */
2734                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2735                         tweak_talk_volume(user, VOL_UP);
2736                 break;
2737         case 82: /* R: Reset all volume levels */
2738                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2739                         reset_volumes(user);
2740                 break;
2741         case 114: /* r: Reset user's volume level */
2742                 if (user)
2743                         reset_volumes(user);
2744                 else
2745                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2746                 break;
2747         case 85: /* U: Raise user's listen volume */
2748                 if (user)
2749                         tweak_listen_volume(user, VOL_UP);
2750                 else
2751                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2752                 break;
2753         case 117: /* u: Lower user's listen volume */
2754                 if (user)
2755                         tweak_listen_volume(user, VOL_DOWN);
2756                 else
2757                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2758                 break;
2759         case 84: /* T: Raise user's talk volume */
2760                 if (user)
2761                         tweak_talk_volume(user, VOL_UP);
2762                 else
2763                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2764                 break;
2765         case 116: /* t: Lower user's talk volume */
2766                 if (user) 
2767                         tweak_talk_volume(user, VOL_DOWN);
2768                 else 
2769                         ast_log(LOG_NOTICE, "Specified User not found!\n");
2770                 break;
2771         }
2772
2773         AST_LIST_UNLOCK(&confs);
2774
2775         ast_module_user_remove(u);
2776         
2777         return 0;
2778 }
2779
2780 static int meetmemute(struct mansession *s, struct message *m, int mute)
2781 {
2782         struct ast_conference *conf;
2783         struct ast_conf_user *user;
2784         char *confid = astman_get_header(m, "Meetme");
2785         char *userid = astman_get_header(m, "Usernum");
2786         int userno;
2787
2788         if (ast_strlen_zero(confid)) {
2789                 astman_send_error(s, m, "Meetme conference not specified");
2790                 return 0;
2791         }
2792
2793         if (ast_strlen_zero(userid)) {
2794                 astman_send_error(s, m, "Meetme user number not specified");
2795                 return 0;
2796         }
2797
2798         userno = strtoul(userid, &userid, 10);
2799
2800         if (*userid) {
2801                 astman_send_error(s, m, "Invalid user number");
2802                 return 0;
2803         }
2804
2805         /* Look in the conference list */
2806         AST_LIST_LOCK(&confs);
2807         AST_LIST_TRAVERSE(&confs, conf, list) {
2808                 if (!strcmp(confid, conf->confno))
2809                         break;
2810         }
2811
2812         if (!conf) {
2813                 AST_LIST_UNLOCK(&confs);
2814                 astman_send_error(s, m, "Meetme conference does not exist");
2815                 return 0;
2816         }
2817
2818         AST_LIST_TRAVERSE(&conf->userlist, user, list)
2819                 if (user->user_no == userno)
2820                         break;
2821
2822         if (!user) {
2823                 AST_LIST_UNLOCK(&confs);
2824                 astman_send_error(s, m, "User number not found");
2825                 return 0;
2826         }
2827
2828         if (mute)
2829                 user->adminflags |= ADMINFLAG_MUTED;    /* request user muting */
2830         else
2831                 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);   /* request user unmuting */
2832
2833         AST_LIST_UNLOCK(&confs);
2834
2835         ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, user->chan->name, user->chan->uniqueid);
2836
2837         astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2838         return 0;
2839 }
2840
2841 static int action_meetmemute(struct mansession *s, struct message *m)
2842 {
2843         return meetmemute(s, m, 1);
2844 }
2845
2846 static int action_meetmeunmute(struct mansession *s, struct message *m)
2847 {
2848         return meetmemute(s, m, 0);
2849 }
2850
2851 static void *recordthread(void *args)
2852 {
2853         struct ast_conference *cnf = args;
2854         struct ast_frame *f=NULL;
2855         int flags;
2856         struct ast_filestream *s=NULL;
2857         int res=0;
2858         int x;
2859         const char *oldrecordingfilename = NULL;
2860
2861         if (!cnf || !cnf->lchan) {
2862                 pthread_exit(0);
2863         }
2864
2865         ast_stopstream(cnf->lchan);
2866         flags = O_CREAT|O_TRUNC|O_WRONLY;
2867
2868
2869         cnf->recording = MEETME_RECORD_ACTIVE;
2870         while (ast_waitfor(cnf->lchan, -1) > -1) {
2871                 if (cnf->recording == MEETME_RECORD_TERMINATE) {
2872                         AST_LIST_LOCK(&confs);
2873                         AST_LIST_UNLOCK(&confs);
2874                         break;
2875                 }
2876                 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
2877                         s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
2878                         oldrecordingfilename = cnf->recordingfilename;
2879                 }
2880                 
2881                 f = ast_read(cnf->lchan);
2882                 if (!f) {
2883                         res = -1;
2884                         break;
2885                 }
2886                 if (f->frametype == AST_FRAME_VOICE) {
2887                         ast_mutex_lock(&cnf->listenlock);
2888                         for (x=0;x<AST_FRAME_BITS;x++) {
2889                                 /* Free any translations that have occured */
2890                                 if (cnf->transframe[x]) {
2891                                         ast_frfree(cnf->transframe[x]);
2892                                         cnf->transframe[x] = NULL;
2893                                 }
2894                         }
2895                         if (cnf->origframe)
2896                                 ast_frfree(cnf->origframe);
2897                         cnf->origframe = f;
2898                         ast_mutex_unlock(&cnf->listenlock);
2899                         if (s)
2900                                 res = ast_writestream(s, f);
2901                         if (res) {
2902                                 ast_frfree(f);
2903                                 break;
2904                         }
2905                 }
2906                 ast_frfree(f);
2907         }
2908         cnf->recording = MEETME_RECORD_OFF;
2909         if (s)
2910                 ast_closestream(s);
2911         
2912         pthread_exit(0);
2913 }
2914
2915 /*! \brief Callback for devicestate providers */
2916 static int meetmestate(const char *data)
2917 {
2918         struct ast_conference *conf;
2919
2920         /* Find conference */
2921         AST_LIST_LOCK(&confs);
2922         AST_LIST_TRAVERSE(&confs, conf, list) {
2923                 if (!strcmp(data, conf->confno))
2924                         break;
2925         }
2926         AST_LIST_UNLOCK(&confs);
2927         if (!conf)
2928                 return AST_DEVICE_INVALID;
2929
2930
2931         /* SKREP to fill */
2932         if (!conf->users)
2933                 return AST_DEVICE_NOT_INUSE;
2934
2935         return AST_DEVICE_INUSE;
2936 }
2937
2938 /*! \brief Callback for devicestate providers */
2939 static int slastate(const char *data)
2940 {
2941         struct ast_conference *conf;
2942         struct ast_sla *sla, *sla2;
2943
2944         if (option_debug)
2945                 ast_log(LOG_DEBUG, "asked for sla state for '%s'\n", data);
2946
2947         /* Find conference */
2948         AST_LIST_LOCK(&confs);
2949         AST_LIST_TRAVERSE(&confs, conf, list) {
2950                 if (!strncmp(conf->confno, "sla-", 4) && !strcmp(data, conf->confno + 4))
2951                         break;
2952         }
2953         AST_LIST_UNLOCK(&confs);
2954
2955         /* Find conference */
2956         sla = sla2 = ASTOBJ_CONTAINER_FIND(&slas, data);
2957
2958         if (!sla2)
2959                 return AST_DEVICE_INVALID;
2960
2961         ASTOBJ_UNREF(sla2, sla_destroy);
2962
2963         if (option_debug)
2964                 ast_log(LOG_DEBUG, "for '%s' conf = %p, sla = %p\n", data, conf, sla);
2965
2966         if (!conf && !sla)
2967                 return AST_DEVICE_INVALID;
2968
2969         /* SKREP to fill */
2970         if (!conf || !conf->users)
2971                 return AST_DEVICE_NOT_INUSE;
2972         
2973         if (conf && sla_checkforhold(conf, 0))
2974                 return AST_DEVICE_ONHOLD;
2975
2976         if ((conf->users == 1) && (AST_LIST_FIRST(&conf->userlist)->userflags & CONFFLAG_SLA_TRUNK))
2977                 return AST_DEVICE_RINGING;
2978
2979         return AST_DEVICE_INUSE;
2980 }
2981
2982 static void load_config_meetme(void)
2983 {
2984         struct ast_config *cfg;
2985         const char *val;
2986
2987         audio_buffers = DEFAULT_AUDIO_BUFFERS;
2988
2989         if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
2990                 return;
2991
2992         if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
2993                 if ((sscanf(val, "%d", &audio_buffers) != 1)) {
2994                         ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
2995                         audio_buffers = DEFAULT_AUDIO_BUFFERS;
2996                 } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
2997                         ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
2998                                 ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
2999                         audio_buffers = DEFAULT_AUDIO_BUFFERS;
3000                 }
3001                 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
3002                         ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
3003         }
3004
3005         ast_config_destroy(cfg);
3006 }
3007
3008 /*! Append SLA station to station list */
3009 static void append_station(struct ast_sla *sla, const char *station)
3010 {
3011         struct ast_sla_station *s;
3012         char *c;
3013
3014         s = ast_calloc(1, sizeof(struct ast_sla_station) + strlen(station) + 2);
3015         if (s) {
3016                 ASTOBJ_INIT(s);
3017                 strcpy(s->tech, station);
3018                 c = strchr(s->tech, '/');
3019                 if (c) {
3020                         *c = '\0';
3021                         s->dest = c + 1;
3022                         ASTOBJ_CONTAINER_LINK(&sla->stations, s);
3023                 } else {
3024                         ast_log(LOG_WARNING, "station '%s' should be in tech/destination format! Ignoring!\n", station);
3025                         free(s);
3026                 }
3027         }
3028 }
3029
3030 /*! Parse SLA configuration file and create objects */
3031 static void parse_sla(const char *cat, struct ast_variable *v)
3032 {
3033         struct ast_sla *sla;
3034
3035         sla = ASTOBJ_CONTAINER_FIND(&slas, cat);
3036         if (!sla) {
3037                 sla = ast_calloc(1, sizeof(struct ast_sla));
3038                 if (sla) {
3039                         ASTOBJ_INIT(sla);
3040                         ast_copy_string(sla->name, cat, sizeof(sla->name));
3041                         snprintf(sla->confname, sizeof(sla->confname), "sla-%s", sla->name);
3042                         ASTOBJ_CONTAINER_LINK(&slas, sla);
3043                 }
3044         }
3045         if (sla) {
3046                 ASTOBJ_UNMARK(sla);
3047                 ASTOBJ_WRLOCK(sla);
3048                 ASTOBJ_CONTAINER_DESTROYALL(&sla->stations, station_destroy);
3049                 while (v) {
3050                         if (!strcasecmp(v->name, "trunk")) {
3051                                 char *c;
3052                                 c = strchr(v->value, '/');
3053                                 if (c) {
3054                                         ast_copy_string(sla->trunktech, v->value, (c - v->value) + 1);
3055                                         ast_copy_string(sla->trunkdest, c + 1, sizeof(sla->trunkdest));
3056                                 }
3057                         } else if (!strcasecmp(v->name, "station")) {
3058                                 append_station(sla, v->value);
3059                         }
3060                         v = v->next;
3061                 }
3062                 ASTOBJ_UNLOCK(sla);
3063                 ast_device_state_changed("SLA:%s", cat);
3064         }
3065 }
3066
3067 /*! If there is a SLA configuration file, parse it */