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