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