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