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