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