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