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