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