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