Merged revisions 42783 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                                         if (confflags & CONFFLAG_MONITOR)
1436                                                 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1437                                         else if (confflags & CONFFLAG_TALKER)
1438                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1439                                         else
1440                                                 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1441                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1442                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1443                                                 close(fd);
1444                                                 goto outrun;
1445                                         }
1446                                         if (musiconhold && (confflags & CONFFLAG_MOH)) {
1447                                                 ast_moh_stop(chan);
1448                                                 musiconhold = 0;
1449                                         }
1450                                         if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1451                                                 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1452                                                         ast_waitstream(chan, "");
1453                                                 conf_play(chan, conf, ENTER);
1454                                         }
1455                                 }
1456                         }
1457
1458                         /* trying to add moh for single person conf */
1459                         if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1460                                 if (conf->users == 1) {
1461                                         if (musiconhold == 0) {
1462                                                 ast_moh_start(chan, NULL, NULL);
1463                                                 musiconhold = 1;
1464                                         } 
1465                                 } else {
1466                                         if (musiconhold) {
1467                                                 ast_moh_stop(chan);
1468                                                 musiconhold = 0;
1469                                         }
1470                                 }
1471                         }
1472                         
1473                         /* Leave if the last marked user left */
1474                         if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1475                                 ret = -1;
1476                                 break;
1477                         }
1478         
1479                         /* Check if my modes have changed */
1480
1481                         /* If I should be muted but am still talker, mute me */
1482                         if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1483                                 ztc.confmode ^= ZT_CONF_TALKER;
1484                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1485                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1486                                         ret = -1;
1487                                         break;
1488                                 }
1489
1490                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1491                                                 "Channel: %s\r\n"
1492                                                 "Uniqueid: %s\r\n"
1493                                                 "Meetme: %s\r\n"
1494                                                 "Usernum: %i\r\n"
1495                                                 "Status: on\r\n",
1496                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1497                         }
1498
1499                         /* If I should be un-muted but am not talker, un-mute me */
1500                         if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1501                                 ztc.confmode |= ZT_CONF_TALKER;
1502                                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1503                                         ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1504                                         ret = -1;
1505                                         break;
1506                                 }
1507
1508                                 manager_event(EVENT_FLAG_CALL, "MeetmeMute", 
1509                                                 "Channel: %s\r\n"
1510                                                 "Uniqueid: %s\r\n"
1511                                                 "Meetme: %s\r\n"
1512                                                 "Usernum: %i\r\n"
1513                                                 "Status: off\r\n",
1514                                                 chan->name, chan->uniqueid, conf->confno, user->user_no);
1515                         }
1516
1517                         /* If I have been kicked, exit the conference */
1518                         if (user->adminflags & ADMINFLAG_KICKME) {
1519                                 //You have been kicked.
1520                                 if (!ast_streamfile(chan, "conf-kicked", chan->language))
1521                                         ast_waitstream(chan, "");
1522                                 ret = 0;
1523                                 break;
1524                         }
1525
1526                         if (c) {
1527                                 if (c->fds[0] != origfd) {
1528                                         if (using_pseudo) {
1529                                                 /* Kill old pseudo */
1530                                                 close(fd);
1531                                                 using_pseudo = 0;
1532                                         }
1533                                         ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
1534                                         retryzap = strcasecmp(c->tech->type, "Zap");
1535                                         user->zapchannel = !retryzap;
1536                                         goto zapretry;
1537                                 }
1538                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1539                                         f = ast_read_noaudio(c);
1540                                 else
1541                                         f = ast_read(c);
1542                                 if (!f)
1543                                         break;
1544                                 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1545                                         if (user->talk.actual)
1546                                                 ast_frame_adjust_volume(f, user->talk.actual);
1547
1548                                         if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
1549                                                 int totalsilence;
1550
1551                                                 if (user->talking == -1)
1552                                                         user->talking = 0;
1553
1554                                                 res = ast_dsp_silence(dsp, f, &totalsilence);
1555                                                 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1556                                                         user->talking = 1;
1557                                                         if (confflags & CONFFLAG_MONITORTALKER)
1558                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1559                                                                       "Channel: %s\r\n"
1560                                                                       "Uniqueid: %s\r\n"
1561                                                                       "Meetme: %s\r\n"
1562                                                                       "Usernum: %d\r\n"
1563                                                                       "Status: on\r\n",
1564                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1565                                                 }
1566                                                 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1567                                                         user->talking = 0;
1568                                                         if (confflags & CONFFLAG_MONITORTALKER)
1569                                                                 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1570                                                                       "Channel: %s\r\n"
1571                                                                       "Uniqueid: %s\r\n"
1572                                                                       "Meetme: %s\r\n"
1573                                                                       "Usernum: %d\r\n"
1574                                                                       "Status: off\r\n",
1575                                                                       chan->name, chan->uniqueid, conf->confno, user->user_no);
1576                                                 }
1577                                         }
1578                                         if (using_pseudo) {
1579                                                 /* Absolutely do _not_ use careful_write here...
1580                                                    it is important that we read data from the channel
1581                                                    as fast as it arrives, and feed it into the conference.
1582                                                    The buffering in the pseudo channel will take care of any
1583                                                    timing differences, unless they are so drastic as to lose
1584                                                    audio frames (in which case carefully writing would only
1585                                                    have delayed the audio even further).
1586                                                 */
1587                                                 /* As it turns out, we do want to use careful write.  We just
1588                                                    don't want to block, but we do want to at least *try*
1589                                                    to write out all the samples.
1590                                                  */
1591                                                 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
1592                                                         careful_write(fd, f->data, f->datalen, 0);
1593                                         }
1594                                 } else if ((f->frametype == AST_FRAME_DTMF) && 
1595                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1596                                         conf_queue_dtmf(conf, f->subclass);
1597                                 } else if ((f->frametype == AST_FRAME_CONTROL) && 
1598                                                         (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))) {
1599                                         conf_queue_control(conf, f->subclass);
1600                                         if (f->subclass == AST_CONTROL_HOLD)
1601                                                 confflags |= CONFFLAG_HOLD;
1602                                         else if (f->subclass == AST_CONTROL_UNHOLD)
1603                                                 confflags &= ~CONFFLAG_HOLD;
1604                                         user->userflags = confflags;
1605                                 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1606                                         char tmp[2];
1607
1608                                         tmp[0] = f->subclass;
1609                                         tmp[1] = '\0';
1610                                         if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1611                                                 ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1612                                                 ret = 0;
1613                                                 ast_frfree(f);
1614                                                 break;
1615                                         } else if (option_debug > 1)
1616                                                 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1617                                 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1618                                         ret = 0;
1619                                         ast_frfree(f);
1620                                         break;
1621                                 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
1622                                         if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
1623                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1624                                                 close(fd);
1625                                                 ast_frfree(f);
1626                                                 goto outrun;
1627                                         }
1628
1629                                         /* if we are entering the menu, and the user has a channel-driver
1630                                            volume adjustment, clear it
1631                                         */
1632                                         if (!menu_active && user->talk.desired && !user->talk.actual)
1633                                                 set_talk_volume(user, 0);
1634
1635                                         if (musiconhold) {
1636                                                 ast_moh_stop(chan);
1637                                         }
1638                                         if ((confflags & CONFFLAG_ADMIN)) {
1639                                                 /* Admin menu */
1640                                                 if (!menu_active) {
1641                                                         menu_active = 1;
1642                                                         /* Record this sound! */
1643                                                         if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
1644                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1645                                                                 ast_stopstream(chan);
1646                                                         } else 
1647                                                                 dtmf = 0;
1648                                                 } else 
1649                                                         dtmf = f->subclass;
1650                                                 if (dtmf) {
1651                                                         switch(dtmf) {
1652                                                         case '1': /* Un/Mute */
1653                                                                 menu_active = 0;
1654
1655                                                                 /* for admin, change both admin and use flags */
1656                                                                 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
1657                                                                         user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1658                                                                 else
1659                                                                         user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
1660
1661                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1662                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1663                                                                                 ast_waitstream(chan, "");
1664                                                                 } else {
1665                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1666                                                                                 ast_waitstream(chan, "");
1667                                                                 }
1668                                                                 break;
1669                                                         case '2': /* Un/Lock the Conference */
1670                                                                 menu_active = 0;
1671                                                                 if (conf->locked) {
1672                                                                         conf->locked = 0;
1673                                                                         if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
1674                                                                                 ast_waitstream(chan, "");
1675                                                                 } else {
1676                                                                         conf->locked = 1;
1677                                                                         if (!ast_streamfile(chan, "conf-lockednow", chan->language))
1678                                                                                 ast_waitstream(chan, "");
1679                                                                 }
1680                                                                 break;
1681                                                         case '3': /* Eject last user */
1682                                                                 menu_active = 0;
1683                                                                 usr = AST_LIST_LAST(&conf->userlist);
1684                                                                 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
1685                                                                         if(!ast_streamfile(chan, "conf-errormenu", chan->language))
1686                                                                                 ast_waitstream(chan, "");
1687                                                                 } else 
1688                                                                         usr->adminflags |= ADMINFLAG_KICKME;
1689                                                                 ast_stopstream(chan);
1690                                                                 break;  
1691                                                         case '4':
1692                                                                 tweak_listen_volume(user, VOL_DOWN);
1693                                                                 break;
1694                                                         case '6':
1695                                                                 tweak_listen_volume(user, VOL_UP);
1696                                                                 break;
1697                                                         case '7':
1698                                                                 tweak_talk_volume(user, VOL_DOWN);
1699                                                                 break;
1700                                                         case '8':
1701                                                                 menu_active = 0;
1702                                                                 break;
1703                                                         case '9':
1704                                                                 tweak_talk_volume(user, VOL_UP);
1705                                                                 break;
1706                                                         default:
1707                                                                 menu_active = 0;
1708                                                                 /* Play an error message! */
1709                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1710                                                                         ast_waitstream(chan, "");
1711                                                                 break;
1712                                                         }
1713                                                 }
1714                                         } else {
1715                                                 /* User menu */
1716                                                 if (!menu_active) {
1717                                                         menu_active = 1;
1718                                                         if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
1719                                                                 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
1720                                                                 ast_stopstream(chan);
1721                                                         } else
1722                                                                 dtmf = 0;
1723                                                 } else 
1724                                                         dtmf = f->subclass;
1725                                                 if (dtmf) {
1726                                                         switch(dtmf) {
1727                                                         case '1': /* Un/Mute */
1728                                                                 menu_active = 0;
1729
1730                                                                 /* user can only toggle the self-muted state */
1731                                                                 user->adminflags ^= ADMINFLAG_SELFMUTED;
1732
1733                                                                 /* they can't override the admin mute state */
1734                                                                 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
1735                                                                         if (!ast_streamfile(chan, "conf-muted", chan->language))
1736                                                                                 ast_waitstream(chan, "");
1737                                                                 } else {
1738                                                                         if (!ast_streamfile(chan, "conf-unmuted", chan->language))
1739                                                                                 ast_waitstream(chan, "");
1740                                                                 }
1741                                                                 break;
1742                                                         case '4':
1743                                                                 tweak_listen_volume(user, VOL_DOWN);
1744                                                                 break;
1745                                                         case '6':
1746                                                                 tweak_listen_volume(user, VOL_UP);
1747                                                                 break;
1748                                                         case '7':
1749                                                                 tweak_talk_volume(user, VOL_DOWN);
1750                                                                 break;
1751                                                         case '8':
1752                                                                 menu_active = 0;
1753                                                                 break;
1754                                                         case '9':
1755                                                                 tweak_talk_volume(user, VOL_UP);
1756                                                                 break;
1757                                                         default:
1758                                                                 menu_active = 0;
1759                                                                 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
1760                                                                         ast_waitstream(chan, "");
1761                                                                 break;
1762                                                         }
1763                                                 }
1764                                         }
1765                                         if (musiconhold)
1766                                                 ast_moh_start(chan, NULL, NULL);
1767
1768                                         if (ioctl(fd, ZT_SETCONF, &ztc)) {
1769                                                 ast_log(LOG_WARNING, "Error setting conference\n");
1770                                                 close(fd);
1771                                                 ast_frfree(f);
1772                                                 goto outrun;
1773                                         }
1774
1775                                         conf_flush(fd, chan);
1776                                 } else if (option_debug) {
1777                                         ast_log(LOG_DEBUG,
1778                                                 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
1779                                                 chan->name, f->frametype, f->subclass);
1780                                 }
1781                                 ast_frfree(f);
1782                         } else if (outfd > -1) {
1783                                 if (user->control) {
1784                                         switch(user->control) {
1785                                         case AST_CONTROL_RINGING:
1786                                         case AST_CONTROL_PROGRESS:
1787                                         case AST_CONTROL_PROCEEDING:
1788                                                 ast_indicate(chan, user->control);
1789                                                 break;
1790                                         case AST_CONTROL_ANSWER:
1791                                                 if (chan->_state != AST_STATE_UP)
1792                                                         ast_answer(chan);
1793                                                 break;
1794                                         }
1795                                         user->control = 0;
1796                                         if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1797                                                 ast_device_state_changed("SLA:%s", conf->confno + 4);
1798                                         continue;
1799                                 }
1800                                 if (user->dtmf) {
1801                                         memset(&fr, 0, sizeof(fr));
1802                                         fr.frametype = AST_FRAME_DTMF;
1803                                         fr.subclass = user->dtmf;
1804                                         if (ast_write(chan, &fr) < 0) {
1805                                                 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1806                                         }
1807                                         user->dtmf = 0;
1808                                         continue;
1809                                 }
1810                                 res = read(outfd, buf, CONF_SIZE);
1811                                 if (res > 0) {
1812                                         memset(&fr, 0, sizeof(fr));
1813                                         fr.frametype = AST_FRAME_VOICE;
1814                                         fr.subclass = AST_FORMAT_SLINEAR;
1815                                         fr.datalen = res;
1816                                         fr.samples = res/2;
1817                                         fr.data = buf;
1818                                         fr.offset = AST_FRIENDLY_OFFSET;
1819                                         if (!user->listen.actual && 
1820                                                 ((confflags & CONFFLAG_MONITOR) || 
1821                                                  (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
1822                                                  (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
1823                                                  )) {
1824                                                 int index;
1825                                                 for (index=0;index<AST_FRAME_BITS;index++)
1826                                                         if (chan->rawwriteformat & (1 << index))
1827                                                                 break;
1828                                                 if (index >= AST_FRAME_BITS)
1829                                                         goto bailoutandtrynormal;
1830                                                 ast_mutex_lock(&conf->listenlock);
1831                                                 if (!conf->transframe[index]) {
1832                                                         if (conf->origframe) {
1833                                                                 if (!conf->transpath[index])
1834                                                                         conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
1835                                                                 if (conf->transpath[index]) {
1836                                                                         conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
1837                                                                         if (!conf->transframe[index])
1838                                                                                 conf->transframe[index] = &ast_null_frame;
1839                                                                 }
1840                                                         }
1841                                                 }
1842                                                 if (conf->transframe[index]) {
1843                                                         if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
1844                                                                 if (ast_write(chan, conf->transframe[index]))
1845                                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1846                                                         }
1847                                                 } else {
1848                                                         ast_mutex_unlock(&conf->listenlock);
1849                                                         goto bailoutandtrynormal;
1850                                                 }
1851                                                 ast_mutex_unlock(&conf->listenlock);
1852                                         } else {
1853 bailoutandtrynormal:                                    
1854                                                 if (user->listen.actual)
1855                                                         ast_frame_adjust_volume(&fr, user->listen.actual);
1856                                                 if (ast_write(chan, &fr) < 0) {
1857                                                         ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
1858                                                 }
1859                                         }
1860                                 } else 
1861                                         ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
1862                         }
1863                         lastmarked = currentmarked;
1864                 }
1865         }
1866
1867         if (musiconhold)
1868                 ast_moh_stop(chan);
1869         
1870         if (using_pseudo)
1871                 close(fd);
1872         else {
1873                 /* Take out of conference */
1874                 ztc.chan = 0;   
1875                 ztc.confno = 0;
1876                 ztc.confmode = 0;
1877                 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1878                         ast_log(LOG_WARNING, "Error setting conference\n");
1879                 }
1880         }
1881
1882         reset_volumes(user);
1883
1884         AST_LIST_LOCK(&confs);
1885         if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
1886                 conf_play(chan, conf, LEAVE);
1887
1888         if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1889                 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
1890                         if ((conf->chan) && (conf->users > 1)) {
1891                                 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1892                                         ast_waitstream(conf->chan, "");
1893                                 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
1894                                         ast_waitstream(conf->chan, "");
1895                         }
1896                         ast_filedelete(user->namerecloc, NULL);
1897                 }
1898         }
1899         AST_LIST_UNLOCK(&confs);
1900
1901  outrun:
1902         AST_LIST_LOCK(&confs);
1903
1904         if (dsp)
1905                 ast_dsp_free(dsp);
1906         
1907         if (user->user_no) { /* Only cleanup users who really joined! */
1908                 now = time(NULL);
1909                 hr = (now - user->jointime) / 3600;
1910                 min = ((now - user->jointime) % 3600) / 60;
1911                 sec = (now - user->jointime) % 60;
1912
1913                 if (sent_event) {
1914                         manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
1915                                       "Channel: %s\r\n"
1916                                       "Uniqueid: %s\r\n"
1917                                       "Meetme: %s\r\n"
1918                                       "Usernum: %d\r\n"
1919                                       "CallerIDnum: %s\r\n"
1920                                       "CallerIDname: %s\r\n"
1921                                       "Duration: %ld\r\n",
1922                                       chan->name, chan->uniqueid, conf->confno, 
1923                                       user->user_no,
1924                                       S_OR(user->chan->cid.cid_num, "<unknown>"),
1925                                       S_OR(user->chan->cid.cid_name, "<unknown>"),
1926                                       (now - user->jointime));
1927                 }
1928
1929                 conf->users--;
1930                 conf->refcount--;
1931                 /* Update table */
1932                 snprintf(members, sizeof(members), "%d", conf->users);
1933                 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
1934                 if (confflags & CONFFLAG_MARKEDUSER) 
1935                         conf->markedusers--;
1936                 /* Remove ourselves from the list */
1937                 AST_LIST_REMOVE(&conf->userlist, user, list);
1938                 if (AST_LIST_EMPTY(&conf->userlist)) {
1939                         /* close this one when no more users and no references*/
1940                         if (!conf->refcount)
1941                                 conf_free(conf);
1942                 }
1943                 /* Return the number of seconds the user was in the conf */
1944                 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
1945                 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
1946
1947                 /* This device changed state now */
1948                 if (!conf->users)       /* If there are no more members */
1949                         ast_device_state_changed("meetme:%s", conf->confno);
1950                 if (confflags & (CONFFLAG_SLA_STATION|CONFFLAG_SLA_TRUNK))
1951                         ast_device_state_changed("SLA:%s", conf->confno + 4);
1952         }
1953         free(user);
1954         AST_LIST_UNLOCK(&confs);
1955
1956         return ret;
1957 }
1958
1959 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
1960                                                  char *dynamic_pin, int refcount, struct ast_flags *confflags)
1961 {
1962         struct ast_variable *var;
1963         struct ast_conference *cnf;
1964
1965         /* Check first in the conference list */
1966         AST_LIST_LOCK(&confs);
1967         AST_LIST_TRAVERSE(&confs, cnf, list) {
1968                 if (!strcmp(confno, cnf->confno)) 
1969                         break;
1970         }
1971         if (cnf){
1972                 cnf->refcount += refcount;
1973         }
1974         AST_LIST_UNLOCK(&confs);
1975
1976         if (!cnf) {
1977                 char *pin = NULL, *pinadmin = NULL; /* For temp use */
1978
1979                 cnf = ast_calloc(1, sizeof(struct ast_conference));
1980                 if (!cnf) {
1981                         ast_log(LOG_ERROR, "Out of memory\n");
1982                         return NULL;
1983                 }
1984
1985                 var = ast_load_realtime("meetme", "confno", confno, NULL);
1986                 while (var) {
1987                         if (!strcasecmp(var->name, "confno")) {
1988                                 ast_copy_string(cnf->confno, var->value, sizeof(cnf->confno));
1989                         } else if (!strcasecmp(var->name, "pin")) {
1990                                 pin = ast_strdupa(var->value);
1991                         } else if (!strcasecmp(var->name, "adminpin")) {
1992                                 pinadmin = ast_strdupa(var->value);
1993                         }
1994                         var = var->next;
1995                 }
1996                 ast_variables_destroy(var);
1997
1998                 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
1999         }
2000
2001         if (cnf) {
2002                 if (confflags && !cnf->chan &&
2003                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2004                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2005                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2006                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2007                 }
2008                 
2009                 if (confflags && !cnf->chan &&
2010                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2011                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2012                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2013                 }
2014         }
2015
2016         return cnf;
2017 }
2018
2019
2020 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2021                                         char *dynamic_pin, int refcount, struct ast_flags *confflags)
2022 {
2023         struct ast_config *cfg;
2024         struct ast_variable *var;
2025         struct ast_conference *cnf;
2026         char *parse;
2027         AST_DECLARE_APP_ARGS(args,
2028                 AST_APP_ARG(confno);
2029                 AST_APP_ARG(pin);
2030                 AST_APP_ARG(pinadmin);
2031         );
2032
2033         /* Check first in the conference list */
2034         AST_LIST_LOCK(&confs);
2035         AST_LIST_TRAVERSE(&confs, cnf, list) {
2036                 if (!strcmp(confno, cnf->confno)) 
2037                         break;
2038         }
2039         if (cnf){
2040                 cnf->refcount += refcount;
2041         }
2042         AST_LIST_UNLOCK(&confs);
2043
2044         if (!cnf) {
2045                 if (dynamic) {
2046                         /* No need to parse meetme.conf */
2047                         ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
2048                         if (dynamic_pin) {
2049                                 if (dynamic_pin[0] == 'q') {
2050                                         /* Query the user to enter a PIN */
2051                                         if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
2052                                                 return NULL;
2053                                 }
2054                                 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
2055                         } else {
2056                                 cnf = build_conf(confno, "", "", make, dynamic, refcount);
2057                         }
2058                 } else {
2059                         /* Check the config */
2060                         cfg = ast_config_load(CONFIG_FILE_NAME);
2061                         if (!cfg) {
2062                                 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2063                                 return NULL;
2064                         }
2065                         for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2066                                 if (strcasecmp(var->name, "conf"))
2067                                         continue;
2068                                 
2069                                 if (!(parse = ast_strdupa(var->value)))
2070                                         return NULL;
2071                                 
2072                                 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2073                                 if (!strcasecmp(args.confno, confno)) {
2074                                         /* Bingo it's a valid conference */
2075                                         cnf = build_conf(args.confno,
2076                                                         S_OR(args.pin, ""),
2077                                                         S_OR(args.pinadmin, ""),
2078                                                         make, dynamic, refcount);
2079                                         break;
2080                                 }
2081                         }
2082                         if (!var) {
2083                                 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
2084                         }
2085                         ast_config_destroy(cfg);
2086                 }
2087         } else if (dynamic_pin) {
2088                 /* Correct for the user selecting 'D' instead of 'd' to have
2089                    someone join into a conference that has already been created
2090                    with a pin. */
2091                 if (dynamic_pin[0] == 'q')
2092                         dynamic_pin[0] = '\0';
2093         }
2094
2095         if (cnf) {
2096                 if (confflags && !cnf->chan &&
2097                     !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2098                     ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2099                         ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2100                         ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2101                 }
2102                 
2103                 if (confflags && !cnf->chan &&
2104                     ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2105                         ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2106                         ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2107                 }
2108         }
2109
2110         return cnf;
2111 }
2112
2113 /*! \brief The MeetmeCount application */
2114 static int count_exec(struct ast_channel *chan, void *data)
2115 {
2116         struct ast_module_user *u;
2117         int res = 0;
2118         struct ast_conference *conf;
2119         int count;
2120         char *localdata;
2121         char val[80] = "0"; 
2122         AST_DECLARE_APP_ARGS(args,
2123                 AST_APP_ARG(confno);
2124                 AST_APP_ARG(varname);
2125         );
2126
2127         if (ast_strlen_zero(data)) {
2128                 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2129                 return -1;
2130         }
2131
2132         u = ast_module_user_add(chan);
2133         
2134         if (!(localdata = ast_strdupa(data))) {
2135                 ast_module_user_remove(u);
2136                 return -1;
2137         }
2138
2139         AST_STANDARD_APP_ARGS(args, localdata);
2140         
2141         conf = find_conf(chan, args.confno, 0, 0, NULL, 0, NULL);
2142
2143         if (conf)
2144                 count = conf->users;
2145         else
2146                 count = 0;
2147
2148         if (!ast_strlen_zero(args.varname)){
2149                 /* have var so load it and exit */
2150                 snprintf(val, sizeof(val), "%d",count);
2151                 pbx_builtin_setvar_helper(chan, args.varname, val);
2152         } else {
2153                 if (chan->_state != AST_STATE_UP)
2154                         ast_answer(chan);
2155                 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2156         }
2157         ast_module_user_remove(u);
2158
2159         return res;
2160 }
2161
2162 /*! \brief The meetme() application */
2163 static int conf_exec(struct ast_channel *chan, void *data)
2164 {
2165         int res=-1;
2166         struct ast_module_user *u;
2167         char confno[AST_MAX_EXTENSION] = "";
2168         int allowretry = 0;
2169         int retrycnt = 0;
2170         struct ast_conference *cnf;
2171         struct ast_flags confflags = {0};
2172         int dynamic = 0;
2173         int empty = 0, empty_no_pin = 0;
2174         int always_prompt = 0;
2175         char *notdata, *info, the_pin[AST_MAX_EXTENSION] = "";
2176         AST_DECLARE_APP_ARGS(args,
2177                 AST_APP_ARG(confno);
2178                 AST_APP_ARG(options);
2179                 AST_APP_ARG(pin);
2180         );
2181         char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2182
2183         u = ast_module_user_add(chan);
2184
2185         if (ast_strlen_zero(data)) {
2186                 allowretry = 1;
2187                 notdata = "";
2188         } else {
2189                 notdata = data;
2190         }
2191         
2192         if (chan->_state != AST_STATE_UP)
2193                 ast_answer(chan);
2194
2195         info = ast_strdupa(notdata);
2196
2197         AST_STANDARD_APP_ARGS(args, info);      
2198
2199         if (args.confno) {
2200                 ast_copy_string(confno, args.confno, sizeof(confno));
2201                 if (ast_strlen_zero(confno)) {
2202                         allowretry = 1;
2203                 }
2204         }
2205         
2206         if (args.pin)
2207                 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2208
2209         if (args.options) {
2210                 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2211                 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2212                 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2213                         strcpy(the_pin, "q");
2214
2215                 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2216                 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2217                 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2218         }
2219
2220         do {
2221                 if (retrycnt > 3)
2222                         allowretry = 0;
2223                 if (empty) {
2224                         int i, map[1024] = { 0, };
2225                         struct ast_config *cfg;
2226                         struct ast_variable *var;
2227                         int confno_int;
2228
2229                         AST_LIST_LOCK(&confs);
2230                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2231                                 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
2232                                         /* Disqualify in use conference */
2233                                         if (confno_int >= 0 && confno_int < 1024)
2234                                                 map[confno_int]++;
2235                                 }
2236                         }
2237                         AST_LIST_UNLOCK(&confs);
2238
2239                         /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2240                         if ((empty_no_pin) || (!dynamic)) {
2241                                 cfg = ast_config_load(CONFIG_FILE_NAME);
2242                                 if (cfg) {
2243                                         var = ast_variable_browse(cfg, "rooms");
2244                                         while (var) {
2245                                                 if (!strcasecmp(var->name, "conf")) {
2246                                                         char *stringp = ast_strdupa(var->value);
2247                                                         if (stringp) {
2248                                                                 char *confno_tmp = strsep(&stringp, "|,");
2249                                                                 int found = 0;
2250                                                                 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
2251                                                                         if ((confno_int >= 0) && (confno_int < 1024)) {
2252                                                                                 if (stringp && empty_no_pin) {
2253                                                                                         map[confno_int]++;
2254                                                                                 }
2255                                                                         }
2256                                                                 }
2257                                                                 if (!dynamic) {
2258                                                                         /* For static:  run through the list and see if this conference is empty */
2259                                                                         AST_LIST_LOCK(&confs);
2260                                                                         AST_LIST_TRAVERSE(&confs, cnf, list) {
2261                                                                                 if (!strcmp(confno_tmp, cnf->confno)) {
2262                                                                                         /* The conference exists, therefore it's not empty */
2263                                                                                         found = 1;
2264                                                                                         break;
2265                                                                                 }
2266                                                                         }
2267                                                                         AST_LIST_UNLOCK(&confs);
2268                                                                         if (!found) {
2269                                                                                 /* At this point, we have a confno_tmp (static conference) that is empty */
2270                                                                                 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2271                                                                                         /* Case 1:  empty_no_pin and pin is nonexistent (NULL)
2272                                                                                          * Case 2:  empty_no_pin and pin is blank (but not NULL)
2273                                                                                          * Case 3:  not empty_no_pin
2274                                                                                          */
2275                                                                                         ast_copy_string(confno, confno_tmp, sizeof(confno));
2276                                                                                         break;
2277                                                                                         /* XXX the map is not complete (but we do have a confno) */
2278                                                                                 }
2279                                                                         }
2280                                                                 }
2281                                                         }
2282                                                 }
2283                                                 var = var->next;
2284                                         }
2285                                         ast_config_destroy(cfg);
2286                                 }
2287                         }
2288
2289                         /* Select first conference number not in use */
2290                         if (ast_strlen_zero(confno) && dynamic) {
2291                                 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
2292                                         if (!map[i]) {
2293                                                 snprintf(confno, sizeof(confno), "%d", i);
2294                                                 break;
2295                                         }
2296                                 }
2297                         }
2298
2299                         /* Not found? */
2300                         if (ast_strlen_zero(confno)) {
2301                                 res = ast_streamfile(chan, "conf-noempty", chan->language);
2302                                 if (!res)
2303                                         ast_waitstream(chan, "");
2304                         } else {
2305                                 if (sscanf(confno, "%d", &confno_int) == 1) {
2306                                         res = ast_streamfile(chan, "conf-enteringno", chan->language);
2307                                         if (!res) {
2308                                                 ast_waitstream(chan, "");
2309                                                 res = ast_say_digits(chan, confno_int, "", chan->language);
2310                                         }
2311                                 } else {
2312                                         ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2313                                 }
2314                         }
2315                 }
2316
2317                 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2318                         /* Prompt user for conference number */
2319                         res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2320                         if (res < 0) {
2321                                 /* Don't try to validate when we catch an error */
2322                                 confno[0] = '\0';
2323                                 allowretry = 0;
2324                                 break;
2325                         }
2326                 }
2327                 if (!ast_strlen_zero(confno)) {
2328                         /* Check the validity of the conference */
2329                         cnf = find_conf(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2330                         if (!cnf)
2331                                 cnf = find_conf_realtime(chan, confno, 1, dynamic, the_pin, 1, &confflags);
2332
2333                         if (!cnf) {
2334                                 res = ast_streamfile(chan, "conf-invalid", chan->language);
2335                                 if (!res)
2336                                         ast_waitstream(chan, "");
2337                                 res = -1;
2338                                 if (allowretry)
2339                                         confno[0] = '\0';
2340                         } else {
2341                                 if ((!ast_strlen_zero(cnf->pin) &&
2342                                      !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2343                                     (!ast_strlen_zero(cnf->pinadmin) &&
2344                                      ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2345                                         char pin[AST_MAX_EXTENSION]="";
2346                                         int j;
2347
2348                                         /* Allow the pin to be retried up to 3 times */
2349                                         for (j = 0; j < 3; j++) {
2350                                                 if (*the_pin && (always_prompt == 0)) {
2351                                                         ast_copy_string(pin, the_pin, sizeof(pin));
2352                                                         res = 0;
2353                                                 } else {
2354                                                         /* Prompt user for pin if pin is required */
2355                                                         res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2356                                                 }
2357                                                 if (res >= 0) {
2358                                                         if (!strcasecmp(pin, cnf->pin) ||
2359                                                             (!ast_strlen_zero(cnf->pinadmin) &&
2360                                                              !strcasecmp(pin, cnf->pinadmin))) {
2361                                                                 /* Pin correct */
2362                                                                 allowretry = 0;
2363                                                                 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) 
2364                                                                         ast_set_flag(&confflags, CONFFLAG_ADMIN);
2365                                                                 /* Run the conference */
2366                                                                 res = conf_run(chan, cnf, confflags.flags, optargs);
2367                                                                 break;
2368                                                         } else {
2369                                                                 /* Pin invalid */
2370                                                                 if (!ast_streamfile(chan, "conf-invalidpin", chan->language))
2371                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
2372                                                                 else {
2373                                                                         ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2374                                                                         break;
2375                                                                 }
2376                                                                 if (res < 0) {
2377                                                                         AST_LIST_LOCK(&confs);
2378                                                                         cnf->refcount--;
2379                                                                         if (!cnf->refcount){
2380                                                                                 conf_free(cnf);
2381                                                                         }
2382                                                                         AST_LIST_UNLOCK(&confs);
2383                                                                         break;
2384                                                                 }
2385                                                                 pin[0] = res;
2386                                                                 pin[1] = '\0';
2387                                                                 res = -1;
2388                                                                 if (allowretry)
2389                                                                         confno[0] = '\0';
2390                                                         }
2391                                                 } else {
2392                                                         /* failed when getting the pin */
2393                                                         res = -1;
2394                                                         allowretry = 0;
2395                                                         /* see if we need to get rid of the conference */
2396                                                         AST_LIST_LOCK(&confs);
2397                                                         cnf->refcount--;
2398                                                         if (!cnf->refcount) {
2399                                                                 conf_free(cnf);
2400                                                         }
2401                                                         AST_LIST_UNLOCK(&confs);
2402                                                         break;
2403                                                 }
2404
2405                                                 /* Don't retry pin with a static pin */
2406                                                 if (*the_pin && (always_prompt==0)) {
2407                                                         break;
2408                                                 }
2409                                         }
2410                                 } else {
2411                                         /* No pin required */
2412                                         allowretry = 0;
2413
2414                                         /* Run the conference */
2415                                         res = conf_run(chan, cnf, confflags.flags, optargs);
2416                                 }
2417                         }
2418                 }
2419         } while (allowretry);
2420         
2421         ast_module_user_remove(u);
2422         
2423         return res;
2424 }
2425
2426 struct sla_originate_helper {
2427         char tech[100];
2428         char data[200];
2429         char app[20];
2430         char appdata[100];
2431         char cid_name[100];
2432         char cid_num[100];
2433 };
2434
2435 static void *sla_originate(void *data)
2436 {
2437         struct sla_originate_helper *in = data;
2438         int reason = 0;
2439         struct ast_channel *chan = NULL;
2440
2441         ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, 99999, in->app, in->appdata, &reason, 1, 
2442                 S_OR(in->cid_num, NULL), 
2443                 S_OR(in->cid_name, NULL),
2444                 NULL, NULL, &chan);
2445         /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
2446         if (chan)
2447                 ast_channel_unlock(chan);
2448         free(in);
2449         return NULL;
2450 }
2451
2452 /*! Call in stations and trunk to the SLA */
2453 static void do_invite(struct ast_channel *orig, const char *tech, const char *dest, const char *app, const char *data)
2454 {
2455         struct sla_originate_helper *slal;
2456         pthread_attr_t attr;
2457         pthread_t th;
2458
2459         if (!(slal = ast_calloc(1, sizeof(*slal))))
2460                 return;
2461         
2462         ast_copy_string(slal->tech, tech, sizeof(slal->tech));
2463         ast_copy_string(slal->data, dest, sizeof(slal->data));
2464         ast_copy_string(slal->app, app, sizeof(slal->app));
2465         ast_copy_string(slal->appdata, data, sizeof(slal->appdata));
2466         if (orig->cid.cid_num)
2467                 ast_copy_string(slal->cid_num, orig->cid.cid_num, sizeof(slal->cid_num));
2468         if (orig->cid.cid_name)
2469                 ast_copy_string(slal->cid_name, orig->cid.cid_name, sizeof(slal->cid_name));
2470         pthread_attr_init(&attr);
2471         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2472         ast_pthread_create(&th, &attr, sla_originate, slal);
2473 }
2474
2475 static void invite_stations(struct ast_channel *orig, struct ast_sla *sla)
2476 {
2477         ASTOBJ_CONTAINER_TRAVERSE(&sla->stations, 1, {
2478                 do_invite(orig, iterator->tech, iterator->dest, "SLAStation", sla->name);
2479         });
2480 }
2481
2482 static void invite_trunk(struct ast_channel *orig, struct ast_sla *sla)
2483 {
2484         do_invite(orig, sla->trunktech, sla->trunkdest, "SLATrunk", sla->name);
2485 }
2486
2487
2488 static int sla_checkforhold(struct ast_conference *conf, int hangup)
2489 {
2490         struct ast_conf_user *user;
2491         struct ast_channel *onhold=NULL;
2492         int holdcount = 0;
2493         int stationcount = 0;
2494         int amonhold = 0;
2495         AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2496                 if (user->userflags & CONFFLAG_SLA_STATION) {
2497                         stationcount++;
2498                         if ((user->userflags & CONFFLAG_HOLD)) {
2499                                 holdcount++;
2500                                 onhold = user->chan;
2501                         }
2502                 }
2503         }
2504         if ((holdcount == 1) && (stationcount == 1)) {
2505                 amonhold = 1;
2506                 if (hangup)
2507                         ast_softhangup(onhold, AST_SOFTHANGUP_EXPLICIT);
2508         } else if (holdcount && (stationcount == holdcount))
2509                 amonhold = 1;
2510         return amonhold;
2511 }
2512
2513
2514 /*! \brief The slas()/slat() application */
2515 static int sla_exec(struct ast_channel *chan, void *data, int trunk)
2516 {
2517         int res=-1;
2518         struct ast_module_user *u;
2519         char confno[AST_MAX_EXTENSION] = "";
2520         struct ast_sla *sla;
2521         struct ast_conference *cnf;
2522         char *info;
2523         struct ast_flags confflags = {0};
2524         int dynamic = 1;
2525         char *options[OPT_ARG_ARRAY_SIZE] = { NULL, };
2526         AST_DECLARE_APP_ARGS(args,
2527                 AST_APP_ARG(confno);
2528                 AST_APP_ARG(options);
2529         );
2530
2531         if (ast_strlen_zero(data)) {
2532                 ast_log(LOG_WARNING, "SLA%c requires an argument (line)\n", trunk ? 'T' : 'S');
2533                 return -1;
2534         }
2535
2536         info = ast_strdupa(data);
2537
2538         AST_STANDARD_APP_ARGS(args, info);      
2539
2540         if (ast_strlen_zero(args.confno)) {
2541                 ast_log(LOG_WARNING, "SLA%c requires an SLA line number\n", trunk ? 'T' : 'S');
2542                 return -1;
2543         }
2544         
2545         u = ast_module_user_add(chan);
2546
2547         if (args.options)
2548                 ast_app_parse_options(sla_opts, &confflags, NULL, args.options);
2549                 
2550         ast_set_flag(&confflags, CONFFLAG_QUIET|CONFFLAG_DYNAMIC);
2551         if (trunk)
2552                 ast_set_flag(&confflags, CONFFLAG_WAITMARKED|CONFFLAG_MARKEDEXIT|CONFFLAG_SLA_TRUNK);
2553         else
2554                 ast_set_flag(&confflags, CONFFLAG_MARKEDUSER|CONFFLAG_SLA_STATION);
2555
2556         sla = ASTOBJ_CONTAINER_FIND(&slas, args.confno);
2557         if (sla) {
2558                 snprintf(confno, sizeof(confno), "sla-%s", args.confno);
2559                 cnf = find_conf(chan, confno, 1, dynamic, "", 1, &confflags);
2560                 if (cnf) {
2561                         sla_checkforhold(cnf, 1);
2562                         if (!cnf->users) {
2563                                 if (trunk) {
2564                                         ast_indicate(chan, AST_CONTROL_RINGING);
2565                                         invite_stations(chan, sla);
2566                                 } else
2567                                         invite_trunk(chan, sla);
2568                         } else if (chan->_state != AST_STATE_UP)
2569                                 ast_answer(chan);
2570
2571                         /* Run the conference */
2572                         res = conf_run(chan, cnf, confflags.flags, options);
2573                 } else
2574                         ast_log(LOG_WARNING, "SLA%c: Found SLA '%s' but unable to build conference!\n", trunk ? 'T' : 'S', args.confno);
2575                 ASTOBJ_UNREF(sla, sla_destroy);
2576         } else {
2577                 ast_log(LOG_WARNING, "SLA%c: SLA '%s' not found!\n", trunk ? 'T' : 'S', args.confno);
2578         }
2579         
2580         ast_module_user_remove(u);
2581         
2582         return res;
2583 }
2584
2585 /*! \brief The slas() wrapper */
2586 static int slas_exec(struct ast_channel *chan, void *data)
2587 {
2588         return sla_exec(chan, data, 0);
2589 }
2590
2591 /*! \brief The slat() wrapper */
2592 static int slat_exec(struct ast_channel *chan, void *data)
2593 {
2594         return sla_exec(chan, data, 1);
2595 }
2596
2597 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident) 
2598 {
2599         struct ast_conf_user *user = NULL;
2600         int cid;
2601         
2602         sscanf(callerident, "%i", &cid);
2603         if (conf && callerident) {
2604                 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2605                         if (cid == user->user_no)
2606                                 return user;
2607                 }
2608         }
2609         return NULL;
2610 }
2611
2612 /*! \brief The MeetMeadmin application */
2613 /* MeetMeAdmin(confno, command, caller) */
2614 static int admin_exec(struct ast_channel *chan, void *data) {
2615         char *params;
2616         struct ast_conference *cnf;
2617         struct ast_conf_user *user = NULL;
2618         struct ast_module_user *u;
2619         AST_DECLARE_APP_ARGS(args,
2620                 AST_APP_ARG(confno);
2621                 AST_APP_ARG(command);
2622                 AST_APP_ARG(user);
2623         );
2624
2625         if (ast_strlen_zero(data)) {
2626                 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
2627                 return -1;
2628         }
2629
2630         u = ast_module_user_add(chan);
2631
2632         AST_LIST_LOCK(&confs);
2633         
2634         params = ast_strdupa(data);
2635         AST_STANDARD_APP_ARGS(args, params);
2636
2637         if (!args.command) {
2638                 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2639                 AST_LIST_UNLOCK(&confs);
2640                 ast_module_user_remove(u);
2641                 return -1;
2642         }
2643         AST_LIST_TRAVERSE(&confs, cnf, list) {
2644                 if (!strcmp(cnf->confno, args.confno))
2645                         break;
2646         }
2647
2648         if (!cnf) {
2649                 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
2650                 AST_LIST_UNLOCK(&confs);
2651                 ast_module_user_remove(u);
2652                 return 0;
2653         }
2654
2655         if (args.user)
2656                 user = find_user(cnf, args.user);
2657
2658         switch (*args.command) {
2659         case 76: /* L: Lock */ 
2660                 cnf->locked = 1;
2661                 break;
2662         case 108: /* l: Unlock */ 
2663                 cnf->locked = 0;
2664                 break;
2665         case 75: /* K: kick all users */
2666                 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2667                         user->adminflags |= ADMINFLAG_KICKME;
2668                 break;
2669         case 101: /* e: Eject last user*/
2670     &nb