Don't give up on attempting an outbound registration if we receive a 408 Timeout.
[asterisk-bristuff.git] / apps / app_meetme.c
blob1a2b8da5c2a345b0370521813d3caea0b381cab6
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2007, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * SLA Implementation by:
9 * Russell Bryant <russell@digium.com>
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.
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.
22 /*! \file
24 * \brief Meet me conference bridge and Shared Line Appearances
26 * \author Mark Spencer <markster@digium.com>
27 * \author (SLA) Russell Bryant <russell@digium.com>
29 * \ingroup applications
32 /*** MODULEINFO
33 <depend>zaptel</depend>
34 ***/
36 #include "asterisk.h"
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <sys/ioctl.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <zaptel/zaptel.h>
50 #include "asterisk/lock.h"
51 #include "asterisk/file.h"
52 #include "asterisk/logger.h"
53 #include "asterisk/channel.h"
54 #include "asterisk/pbx.h"
55 #include "asterisk/module.h"
56 #include "asterisk/config.h"
57 #include "asterisk/app.h"
58 #include "asterisk/dsp.h"
59 #include "asterisk/musiconhold.h"
60 #include "asterisk/manager.h"
61 #include "asterisk/options.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/say.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/translate.h"
66 #include "asterisk/ulaw.h"
67 #include "asterisk/astobj.h"
68 #include "asterisk/devicestate.h"
69 #include "asterisk/dial.h"
70 #include "asterisk/causes.h"
72 #include "enter.h"
73 #include "leave.h"
75 #define CONFIG_FILE_NAME "meetme.conf"
76 #define SLA_CONFIG_FILE "sla.conf"
78 /*! each buffer is 20ms, so this is 640ms total */
79 #define DEFAULT_AUDIO_BUFFERS 32
81 enum {
82 ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
83 ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
84 ADMINFLAG_KICKME = (1 << 3) /*!< User has been kicked */
87 #define MEETME_DELAYDETECTTALK 300
88 #define MEETME_DELAYDETECTENDTALK 1000
90 #define AST_FRAME_BITS 32
92 enum volume_action {
93 VOL_UP,
94 VOL_DOWN
97 enum entrance_sound {
98 ENTER,
99 LEAVE
102 enum recording_state {
103 MEETME_RECORD_OFF,
104 MEETME_RECORD_STARTED,
105 MEETME_RECORD_ACTIVE,
106 MEETME_RECORD_TERMINATE
109 #define CONF_SIZE 320
111 enum {
112 /*! user has admin access on the conference */
113 CONFFLAG_ADMIN = (1 << 0),
114 /*! If set the user can only receive audio from the conference */
115 CONFFLAG_MONITOR = (1 << 1),
116 /*! If set asterisk will exit conference when '#' is pressed */
117 CONFFLAG_POUNDEXIT = (1 << 2),
118 /*! If set asterisk will provide a menu to the user when '*' is pressed */
119 CONFFLAG_STARMENU = (1 << 3),
120 /*! If set the use can only send audio to the conference */
121 CONFFLAG_TALKER = (1 << 4),
122 /*! If set there will be no enter or leave sounds */
123 CONFFLAG_QUIET = (1 << 5),
124 /*! If set, when user joins the conference, they will be told the number
125 * of users that are already in */
126 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
127 /*! Set to run AGI Script in Background */
128 CONFFLAG_AGI = (1 << 7),
129 /*! Set to have music on hold when user is alone in conference */
130 CONFFLAG_MOH = (1 << 8),
131 /*! If set the MeetMe will return if all marked with this flag left */
132 CONFFLAG_MARKEDEXIT = (1 << 9),
133 /*! If set, the MeetMe will wait until a marked user enters */
134 CONFFLAG_WAITMARKED = (1 << 10),
135 /*! If set, the MeetMe will exit to the specified context */
136 CONFFLAG_EXIT_CONTEXT = (1 << 11),
137 /*! If set, the user will be marked */
138 CONFFLAG_MARKEDUSER = (1 << 12),
139 /*! If set, user will be ask record name on entry of conference */
140 CONFFLAG_INTROUSER = (1 << 13),
141 /*! If set, the MeetMe will be recorded */
142 CONFFLAG_RECORDCONF = (1<< 14),
143 /*! If set, the user will be monitored if the user is talking or not */
144 CONFFLAG_MONITORTALKER = (1 << 15),
145 CONFFLAG_DYNAMIC = (1 << 16),
146 CONFFLAG_DYNAMICPIN = (1 << 17),
147 CONFFLAG_EMPTY = (1 << 18),
148 CONFFLAG_EMPTYNOPIN = (1 << 19),
149 CONFFLAG_ALWAYSPROMPT = (1 << 20),
150 /*! If set, treats talking users as muted users */
151 CONFFLAG_OPTIMIZETALKER = (1 << 21),
152 /*! If set, won't speak the extra prompt when the first person
153 * enters the conference */
154 CONFFLAG_NOONLYPERSON = (1 << 22),
155 /*! If set, user will be asked to record name on entry of conference
156 * without review */
157 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
158 /*! If set, the user will be initially self-muted */
159 CONFFLAG_STARTMUTED = (1 << 24),
160 /*! Pass DTMF through the conference */
161 CONFFLAG_PASS_DTMF = (1 << 25),
162 /*! This is a SLA station. (Only for use by the SLA applications.) */
163 CONFFLAG_SLA_STATION = (1 << 26),
164 /*! This is a SLA trunk. (Only for use by the SLA applications.) */
165 CONFFLAG_SLA_TRUNK = (1 << 27),
168 enum {
169 OPT_ARG_WAITMARKED = 0,
170 OPT_ARG_ARRAY_SIZE = 1,
173 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
174 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
175 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
176 AST_APP_OPTION('b', CONFFLAG_AGI ),
177 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
178 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
179 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
180 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
181 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
182 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
183 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
184 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
185 AST_APP_OPTION('M', CONFFLAG_MOH ),
186 AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
187 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
188 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
189 AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
190 AST_APP_OPTION('q', CONFFLAG_QUIET ),
191 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
192 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
193 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
194 AST_APP_OPTION('l', CONFFLAG_MONITOR ),
195 AST_APP_OPTION('t', CONFFLAG_TALKER ),
196 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
197 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
198 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
199 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
200 END_OPTIONS );
202 static const char *app = "MeetMe";
203 static const char *app2 = "MeetMeCount";
204 static const char *app3 = "MeetMeAdmin";
205 static const char *slastation_app = "SLAStation";
206 static const char *slatrunk_app = "SLATrunk";
208 static const char *synopsis = "MeetMe conference bridge";
209 static const char *synopsis2 = "MeetMe participant count";
210 static const char *synopsis3 = "MeetMe conference Administration";
211 static const char *slastation_synopsis = "Shared Line Appearance Station";
212 static const char *slatrunk_synopsis = "Shared Line Appearance Trunk";
214 static const char *descrip =
215 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
216 "conference. If the conference number is omitted, the user will be prompted\n"
217 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
218 "is specified, by pressing '#'.\n"
219 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
220 " must be present for conferencing to operate properly. In addition, the chan_zap\n"
221 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
222 "The option string may contain zero or more of the following characters:\n"
223 " 'a' -- set admin mode\n"
224 " 'A' -- set marked mode\n"
225 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
226 " Default: conf-background.agi (Note: This does not work with\n"
227 " non-Zap channels in the same conference)\n"
228 " 'c' -- announce user(s) count on joining a conference\n"
229 " 'd' -- dynamically add conference\n"
230 " 'D' -- dynamically add conference, prompting for a PIN\n"
231 " 'e' -- select an empty conference\n"
232 " 'E' -- select an empty pinless conference\n"
233 " 'F' -- Pass DTMF through the conference.\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. Note that this option\n"
243 " will be removed in 1.6 and enabled by default.\n"
244 " 'p' -- allow user to exit the conference by pressing '#'\n"
245 " 'P' -- always prompt for the pin even if it is specified\n"
246 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
247 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
248 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
249 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
250 " wav.\n"
251 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
252 " 't' -- set talk only mode. (Talk only, no listening)\n"
253 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
254 " 'w[(<secs>)]'\n"
255 " -- wait until the marked user enters the conference\n"
256 " 'x' -- close the conference when last marked user exits\n"
257 " 'X' -- allow user to exit the conference by entering a valid single\n"
258 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
259 " if that variable is not defined.\n"
260 " '1' -- do not play message when first person enters\n";
262 static const char *descrip2 =
263 " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
264 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
265 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
266 "the channel, unless priority n+1 exists, in which case priority progress will\n"
267 "continue.\n"
268 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
270 static const char *descrip3 =
271 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
272 " 'e' -- Eject last user that joined\n"
273 " 'k' -- Kick one user out of conference\n"
274 " 'K' -- Kick all users out of conference\n"
275 " 'l' -- Unlock conference\n"
276 " 'L' -- Lock conference\n"
277 " 'm' -- Unmute one user\n"
278 " 'M' -- Mute one user\n"
279 " 'n' -- Unmute all users in the conference\n"
280 " 'N' -- Mute all non-admin users in the conference\n"
281 " 'r' -- Reset one user's volume settings\n"
282 " 'R' -- Reset all users volume settings\n"
283 " 's' -- Lower entire conference speaking volume\n"
284 " 'S' -- Raise entire conference speaking volume\n"
285 " 't' -- Lower one user's talk volume\n"
286 " 'T' -- Raise one user's talk volume\n"
287 " 'u' -- Lower one user's listen volume\n"
288 " 'U' -- Raise one user's listen volume\n"
289 " 'v' -- Lower entire conference listening volume\n"
290 " 'V' -- Raise entire conference listening volume\n"
293 static const char *slastation_desc =
294 " SLAStation(station):\n"
295 "This application should be executed by an SLA station. The argument depends\n"
296 "on how the call was initiated. If the phone was just taken off hook, then\n"
297 "the argument \"station\" should be just the station name. If the call was\n"
298 "initiated by pressing a line key, then the station name should be preceded\n"
299 "by an underscore and the trunk name associated with that line button.\n"
300 "For example: \"station1_line1\"."
301 " On exit, this application will set the variable SLASTATION_STATUS to\n"
302 "one of the following values:\n"
303 " FAILURE | CONGESTION | SUCCESS\n"
306 static const char *slatrunk_desc =
307 " SLATrunk(trunk):\n"
308 "This application should be executed by an SLA trunk on an inbound call.\n"
309 "The channel calling this application should correspond to the SLA trunk\n"
310 "with the name \"trunk\" that is being passed as an argument.\n"
311 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
312 "one of the following values:\n"
313 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
316 #define MAX_CONFNUM 80
317 #define MAX_PIN 80
319 /*! \brief The MeetMe Conference object */
320 struct ast_conference {
321 ast_mutex_t playlock; /*!< Conference specific lock (players) */
322 ast_mutex_t listenlock; /*!< Conference specific lock (listeners) */
323 char confno[MAX_CONFNUM]; /*!< Conference */
324 struct ast_channel *chan; /*!< Announcements channel */
325 struct ast_channel *lchan; /*!< Listen/Record channel */
326 int fd; /*!< Announcements fd */
327 int zapconf; /*!< Zaptel Conf # */
328 int users; /*!< Number of active users */
329 int markedusers; /*!< Number of marked users */
330 time_t start; /*!< Start time (s) */
331 int refcount; /*!< reference count of usage */
332 enum recording_state recording:2; /*!< recording status */
333 unsigned int isdynamic:1; /*!< Created on the fly? */
334 unsigned int locked:1; /*!< Is the conference locked? */
335 pthread_t recordthread; /*!< thread for recording */
336 ast_mutex_t recordthreadlock; /*!< control threads trying to start recordthread */
337 pthread_attr_t attr; /*!< thread attribute */
338 const char *recordingfilename; /*!< Filename to record the Conference into */
339 const char *recordingformat; /*!< Format to record the Conference in */
340 char pin[MAX_PIN]; /*!< If protected by a PIN */
341 char pinadmin[MAX_PIN]; /*!< If protected by a admin PIN */
342 struct ast_frame *transframe[32];
343 struct ast_frame *origframe;
344 struct ast_trans_pvt *transpath[32];
345 AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
346 AST_LIST_ENTRY(ast_conference) list;
349 static AST_LIST_HEAD_STATIC(confs, ast_conference);
351 static unsigned int conf_map[1024] = {0, };
353 struct volume {
354 int desired; /*!< Desired volume adjustment */
355 int actual; /*!< Actual volume adjustment (for channels that can't adjust) */
358 struct ast_conf_user {
359 int user_no; /*!< User Number */
360 int userflags; /*!< Flags as set in the conference */
361 int adminflags; /*!< Flags set by the Admin */
362 struct ast_channel *chan; /*!< Connected channel */
363 int talking; /*!< Is user talking */
364 int zapchannel; /*!< Is a Zaptel channel */
365 char usrvalue[50]; /*!< Custom User Value */
366 char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
367 time_t jointime; /*!< Time the user joined the conference */
368 struct volume talk;
369 struct volume listen;
370 AST_LIST_ENTRY(ast_conf_user) list;
373 enum sla_which_trunk_refs {
374 ALL_TRUNK_REFS,
375 INACTIVE_TRUNK_REFS,
378 enum sla_trunk_state {
379 SLA_TRUNK_STATE_IDLE,
380 SLA_TRUNK_STATE_RINGING,
381 SLA_TRUNK_STATE_UP,
382 SLA_TRUNK_STATE_ONHOLD,
383 SLA_TRUNK_STATE_ONHOLD_BYME,
386 enum sla_hold_access {
387 /*! This means that any station can put it on hold, and any station
388 * can retrieve the call from hold. */
389 SLA_HOLD_OPEN,
390 /*! This means that only the station that put the call on hold may
391 * retrieve it from hold. */
392 SLA_HOLD_PRIVATE,
395 struct sla_trunk_ref;
397 struct sla_station {
398 AST_RWLIST_ENTRY(sla_station) entry;
399 AST_DECLARE_STRING_FIELDS(
400 AST_STRING_FIELD(name);
401 AST_STRING_FIELD(device);
402 AST_STRING_FIELD(autocontext);
404 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
405 struct ast_dial *dial;
406 /*! Ring timeout for this station, for any trunk. If a ring timeout
407 * is set for a specific trunk on this station, that will take
408 * priority over this value. */
409 unsigned int ring_timeout;
410 /*! Ring delay for this station, for any trunk. If a ring delay
411 * is set for a specific trunk on this station, that will take
412 * priority over this value. */
413 unsigned int ring_delay;
414 /*! This option uses the values in the sla_hold_access enum and sets the
415 * access control type for hold on this station. */
416 unsigned int hold_access:1;
419 struct sla_station_ref {
420 AST_LIST_ENTRY(sla_station_ref) entry;
421 struct sla_station *station;
424 struct sla_trunk {
425 AST_RWLIST_ENTRY(sla_trunk) entry;
426 AST_DECLARE_STRING_FIELDS(
427 AST_STRING_FIELD(name);
428 AST_STRING_FIELD(device);
429 AST_STRING_FIELD(autocontext);
431 AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
432 /*! Number of stations that use this trunk */
433 unsigned int num_stations;
434 /*! Number of stations currently on a call with this trunk */
435 unsigned int active_stations;
436 /*! Number of stations that have this trunk on hold. */
437 unsigned int hold_stations;
438 struct ast_channel *chan;
439 unsigned int ring_timeout;
440 /*! If set to 1, no station will be able to join an active call with
441 * this trunk. */
442 unsigned int barge_disabled:1;
443 /*! This option uses the values in the sla_hold_access enum and sets the
444 * access control type for hold on this trunk. */
445 unsigned int hold_access:1;
446 /*! Whether this trunk is currently on hold, meaning that once a station
447 * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
448 unsigned int on_hold:1;
451 struct sla_trunk_ref {
452 AST_LIST_ENTRY(sla_trunk_ref) entry;
453 struct sla_trunk *trunk;
454 enum sla_trunk_state state;
455 struct ast_channel *chan;
456 /*! Ring timeout to use when this trunk is ringing on this specific
457 * station. This takes higher priority than a ring timeout set at
458 * the station level. */
459 unsigned int ring_timeout;
460 /*! Ring delay to use when this trunk is ringing on this specific
461 * station. This takes higher priority than a ring delay set at
462 * the station level. */
463 unsigned int ring_delay;
466 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
467 static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
469 static const char sla_registrar[] = "SLA";
471 /*! \brief Event types that can be queued up for the SLA thread */
472 enum sla_event_type {
473 /*! A station has put the call on hold */
474 SLA_EVENT_HOLD,
475 /*! The state of a dial has changed */
476 SLA_EVENT_DIAL_STATE,
477 /*! The state of a ringing trunk has changed */
478 SLA_EVENT_RINGING_TRUNK,
481 struct sla_event {
482 enum sla_event_type type;
483 struct sla_station *station;
484 struct sla_trunk_ref *trunk_ref;
485 AST_LIST_ENTRY(sla_event) entry;
488 /*! \brief A station that failed to be dialed
489 * \note Only used by the SLA thread. */
490 struct sla_failed_station {
491 struct sla_station *station;
492 struct timeval last_try;
493 AST_LIST_ENTRY(sla_failed_station) entry;
496 /*! \brief A trunk that is ringing */
497 struct sla_ringing_trunk {
498 struct sla_trunk *trunk;
499 /*! The time that this trunk started ringing */
500 struct timeval ring_begin;
501 AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
502 AST_LIST_ENTRY(sla_ringing_trunk) entry;
505 enum sla_station_hangup {
506 SLA_STATION_HANGUP_NORMAL,
507 SLA_STATION_HANGUP_TIMEOUT,
510 /*! \brief A station that is ringing */
511 struct sla_ringing_station {
512 struct sla_station *station;
513 /*! The time that this station started ringing */
514 struct timeval ring_begin;
515 AST_LIST_ENTRY(sla_ringing_station) entry;
519 * \brief A structure for data used by the sla thread
521 static struct {
522 /*! The SLA thread ID */
523 pthread_t thread;
524 ast_cond_t cond;
525 ast_mutex_t lock;
526 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
527 AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
528 AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
529 AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
530 unsigned int stop:1;
531 /*! Attempt to handle CallerID, even though it is known not to work
532 * properly in some situations. */
533 unsigned int attempt_callerid:1;
534 } sla = {
535 .thread = AST_PTHREADT_NULL,
538 /*! The number of audio buffers to be allocated on pseudo channels
539 * when in a conference */
540 static int audio_buffers;
542 /*! Map 'volume' levels from -5 through +5 into
543 * decibel (dB) settings for channel drivers
544 * Note: these are not a straight linear-to-dB
545 * conversion... the numbers have been modified
546 * to give the user a better level of adjustability
548 static char const gain_map[] = {
549 -15,
550 -13,
551 -10,
563 static int admin_exec(struct ast_channel *chan, void *data);
564 static void *recordthread(void *args);
566 static char *istalking(int x)
568 if (x > 0)
569 return "(talking)";
570 else if (x < 0)
571 return "(unmonitored)";
572 else
573 return "(not talking)";
576 static int careful_write(int fd, unsigned char *data, int len, int block)
578 int res;
579 int x;
581 while (len) {
582 if (block) {
583 x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
584 res = ioctl(fd, ZT_IOMUX, &x);
585 } else
586 res = 0;
587 if (res >= 0)
588 res = write(fd, data, len);
589 if (res < 1) {
590 if (errno != EAGAIN) {
591 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
592 return -1;
593 } else
594 return 0;
596 len -= res;
597 data += res;
600 return 0;
603 static int set_talk_volume(struct ast_conf_user *user, int volume)
605 char gain_adjust;
607 /* attempt to make the adjustment in the channel driver;
608 if successful, don't adjust in the frame reading routine
610 gain_adjust = gain_map[volume + 5];
612 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
615 static int set_listen_volume(struct ast_conf_user *user, int volume)
617 char gain_adjust;
619 /* attempt to make the adjustment in the channel driver;
620 if successful, don't adjust in the frame reading routine
622 gain_adjust = gain_map[volume + 5];
624 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
627 static void tweak_volume(struct volume *vol, enum volume_action action)
629 switch (action) {
630 case VOL_UP:
631 switch (vol->desired) {
632 case 5:
633 break;
634 case 0:
635 vol->desired = 2;
636 break;
637 case -2:
638 vol->desired = 0;
639 break;
640 default:
641 vol->desired++;
642 break;
644 break;
645 case VOL_DOWN:
646 switch (vol->desired) {
647 case -5:
648 break;
649 case 2:
650 vol->desired = 0;
651 break;
652 case 0:
653 vol->desired = -2;
654 break;
655 default:
656 vol->desired--;
657 break;
662 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
664 tweak_volume(&user->talk, action);
665 /* attempt to make the adjustment in the channel driver;
666 if successful, don't adjust in the frame reading routine
668 if (!set_talk_volume(user, user->talk.desired))
669 user->talk.actual = 0;
670 else
671 user->talk.actual = user->talk.desired;
674 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
676 tweak_volume(&user->listen, action);
677 /* attempt to make the adjustment in the channel driver;
678 if successful, don't adjust in the frame reading routine
680 if (!set_listen_volume(user, user->listen.desired))
681 user->listen.actual = 0;
682 else
683 user->listen.actual = user->listen.desired;
686 static void reset_volumes(struct ast_conf_user *user)
688 signed char zero_volume = 0;
690 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
691 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
694 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
696 unsigned char *data;
697 int len;
698 int res = -1;
700 if (!chan->_softhangup)
701 res = ast_autoservice_start(chan);
703 AST_LIST_LOCK(&confs);
705 switch(sound) {
706 case ENTER:
707 data = enter;
708 len = sizeof(enter);
709 break;
710 case LEAVE:
711 data = leave;
712 len = sizeof(leave);
713 break;
714 default:
715 data = NULL;
716 len = 0;
718 if (data) {
719 careful_write(conf->fd, data, len, 1);
722 AST_LIST_UNLOCK(&confs);
724 if (!res)
725 ast_autoservice_stop(chan);
729 * \brief Find or create a conference
731 * \param confno The conference name/number
732 * \param pin The regular user pin
733 * \param pinadmin The admin pin
734 * \param make Make the conf if it doesn't exist
735 * \param dynamic Mark the newly created conference as dynamic
736 * \param refcount How many references to mark on the conference
738 * \return A pointer to the conference struct, or NULL if it wasn't found and
739 * make or dynamic were not set.
741 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
743 struct ast_conference *cnf;
744 struct zt_confinfo ztc = { 0, };
745 int confno_int = 0;
747 AST_LIST_LOCK(&confs);
749 AST_LIST_TRAVERSE(&confs, cnf, list) {
750 if (!strcmp(confno, cnf->confno))
751 break;
754 if (cnf || (!make && !dynamic))
755 goto cnfout;
757 /* Make a new one */
758 if (!(cnf = ast_calloc(1, sizeof(*cnf))))
759 goto cnfout;
761 ast_mutex_init(&cnf->playlock);
762 ast_mutex_init(&cnf->listenlock);
763 cnf->recordthread = AST_PTHREADT_NULL;
764 ast_mutex_init(&cnf->recordthreadlock);
765 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
766 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
767 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
769 /* Setup a new zap conference */
770 ztc.confno = -1;
771 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
772 cnf->fd = open("/dev/zap/pseudo", O_RDWR);
773 if (cnf->fd < 0 || ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
774 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
775 if (cnf->fd >= 0)
776 close(cnf->fd);
777 free(cnf);
778 cnf = NULL;
779 goto cnfout;
782 cnf->zapconf = ztc.confno;
784 /* Setup a new channel for playback of audio files */
785 cnf->chan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
786 if (cnf->chan) {
787 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
788 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
789 ztc.chan = 0;
790 ztc.confno = cnf->zapconf;
791 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
792 if (ioctl(cnf->chan->fds[0], ZT_SETCONF, &ztc)) {
793 ast_log(LOG_WARNING, "Error setting conference\n");
794 if (cnf->chan)
795 ast_hangup(cnf->chan);
796 else
797 close(cnf->fd);
798 free(cnf);
799 cnf = NULL;
800 goto cnfout;
804 /* Fill the conference struct */
805 cnf->start = time(NULL);
806 cnf->isdynamic = dynamic ? 1 : 0;
807 if (option_verbose > 2)
808 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
809 AST_LIST_INSERT_HEAD(&confs, cnf, list);
811 /* Reserve conference number in map */
812 if ((sscanf(cnf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
813 conf_map[confno_int] = 1;
815 cnfout:
816 if (cnf)
817 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
819 AST_LIST_UNLOCK(&confs);
821 return cnf;
824 static int meetme_cmd(int fd, int argc, char **argv)
826 /* Process the command */
827 struct ast_conference *cnf;
828 struct ast_conf_user *user;
829 int hr, min, sec;
830 int i = 0, total = 0;
831 time_t now;
832 char *header_format = "%-14s %-14s %-10s %-8s %-8s\n";
833 char *data_format = "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
834 char cmdline[1024] = "";
836 if (argc > 8)
837 ast_cli(fd, "Invalid Arguments.\n");
838 /* Check for length so no buffer will overflow... */
839 for (i = 0; i < argc; i++) {
840 if (strlen(argv[i]) > 100)
841 ast_cli(fd, "Invalid Arguments.\n");
843 if (argc == 1) {
844 /* 'MeetMe': List all the conferences */
845 now = time(NULL);
846 AST_LIST_LOCK(&confs);
847 if (AST_LIST_EMPTY(&confs)) {
848 ast_cli(fd, "No active MeetMe conferences.\n");
849 AST_LIST_UNLOCK(&confs);
850 return RESULT_SUCCESS;
852 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
853 AST_LIST_TRAVERSE(&confs, cnf, list) {
854 if (cnf->markedusers == 0)
855 strcpy(cmdline, "N/A ");
856 else
857 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
858 hr = (now - cnf->start) / 3600;
859 min = ((now - cnf->start) % 3600) / 60;
860 sec = (now - cnf->start) % 60;
862 ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
864 total += cnf->users;
866 AST_LIST_UNLOCK(&confs);
867 ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
868 return RESULT_SUCCESS;
870 if (argc < 3)
871 return RESULT_SHOWUSAGE;
872 ast_copy_string(cmdline, argv[2], sizeof(cmdline)); /* Argv 2: conference number */
873 if (strstr(argv[1], "lock")) {
874 if (strcmp(argv[1], "lock") == 0) {
875 /* Lock */
876 strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
877 } else {
878 /* Unlock */
879 strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
881 } else if (strstr(argv[1], "mute")) {
882 if (argc < 4)
883 return RESULT_SHOWUSAGE;
884 if (strcmp(argv[1], "mute") == 0) {
885 /* Mute */
886 if (strcmp(argv[3], "all") == 0) {
887 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
888 } else {
889 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);
890 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
892 } else {
893 /* Unmute */
894 if (strcmp(argv[3], "all") == 0) {
895 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
896 } else {
897 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
898 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
901 } else if (strcmp(argv[1], "kick") == 0) {
902 if (argc < 4)
903 return RESULT_SHOWUSAGE;
904 if (strcmp(argv[3], "all") == 0) {
905 /* Kick all */
906 strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
907 } else {
908 /* Kick a single user */
909 strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
910 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
912 } else if(strcmp(argv[1], "list") == 0) {
913 int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
914 /* List all the users in a conference */
915 if (AST_LIST_EMPTY(&confs)) {
916 if ( !concise )
917 ast_cli(fd, "No active conferences.\n");
918 return RESULT_SUCCESS;
920 /* Find the right conference */
921 AST_LIST_LOCK(&confs);
922 AST_LIST_TRAVERSE(&confs, cnf, list) {
923 if (strcmp(cnf->confno, argv[2]) == 0)
924 break;
926 if (!cnf) {
927 if ( !concise )
928 ast_cli(fd, "No such conference: %s.\n",argv[2]);
929 AST_LIST_UNLOCK(&confs);
930 return RESULT_SUCCESS;
932 /* Show all the users */
933 time(&now);
934 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
935 hr = (now - user->jointime) / 3600;
936 min = ((now - user->jointime) % 3600) / 60;
937 sec = (now - user->jointime) % 60;
938 if ( !concise )
939 ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
940 user->user_no,
941 S_OR(user->chan->cid.cid_num, "<unknown>"),
942 S_OR(user->chan->cid.cid_name, "<no name>"),
943 user->chan->name,
944 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
945 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
946 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
947 istalking(user->talking), hr, min, sec);
948 else
949 ast_cli(fd, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
950 user->user_no,
951 S_OR(user->chan->cid.cid_num, ""),
952 S_OR(user->chan->cid.cid_name, ""),
953 user->chan->name,
954 user->userflags & CONFFLAG_ADMIN ? "1" : "",
955 user->userflags & CONFFLAG_MONITOR ? "1" : "",
956 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
957 user->talking, hr, min, sec);
960 if ( !concise )
961 ast_cli(fd,"%d users in that conference.\n",cnf->users);
962 AST_LIST_UNLOCK(&confs);
963 return RESULT_SUCCESS;
964 } else
965 return RESULT_SHOWUSAGE;
966 ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
967 admin_exec(NULL, cmdline);
969 return 0;
972 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
974 static char *cmds[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL};
976 int len = strlen(word);
977 int which = 0;
978 struct ast_conference *cnf = NULL;
979 struct ast_conf_user *usr = NULL;
980 char *confno = NULL;
981 char usrno[50] = "";
982 char *myline, *ret = NULL;
984 if (pos == 1) { /* Command */
985 return ast_cli_complete(word, cmds, state);
986 } else if (pos == 2) { /* Conference Number */
987 AST_LIST_LOCK(&confs);
988 AST_LIST_TRAVERSE(&confs, cnf, list) {
989 if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
990 ret = cnf->confno;
991 break;
994 ret = ast_strdup(ret); /* dup before releasing the lock */
995 AST_LIST_UNLOCK(&confs);
996 return ret;
997 } else if (pos == 3) {
998 /* User Number || Conf Command option*/
999 if (strstr(line, "mute") || strstr(line, "kick")) {
1000 if (state == 0 && (strstr(line, "kick") || strstr(line,"mute")) && !strncasecmp(word, "all", len))
1001 return strdup("all");
1002 which++;
1003 AST_LIST_LOCK(&confs);
1005 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
1006 myline = ast_strdupa(line);
1007 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
1008 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
1012 AST_LIST_TRAVERSE(&confs, cnf, list) {
1013 if (!strcmp(confno, cnf->confno))
1014 break;
1017 if (cnf) {
1018 /* Search for the user */
1019 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
1020 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1021 if (!strncasecmp(word, usrno, len) && ++which > state)
1022 break;
1025 AST_LIST_UNLOCK(&confs);
1026 return usr ? strdup(usrno) : NULL;
1027 } else if ( strstr(line, "list") && ( 0 == state ) )
1028 return strdup("concise");
1031 return NULL;
1034 static char meetme_usage[] =
1035 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
1036 " Executes a command for the conference or on a conferee\n";
1038 static const char *sla_hold_str(unsigned int hold_access)
1040 const char *hold = "Unknown";
1042 switch (hold_access) {
1043 case SLA_HOLD_OPEN:
1044 hold = "Open";
1045 break;
1046 case SLA_HOLD_PRIVATE:
1047 hold = "Private";
1048 default:
1049 break;
1052 return hold;
1055 static int sla_show_trunks(int fd, int argc, char **argv)
1057 const struct sla_trunk *trunk;
1059 ast_cli(fd, "\n"
1060 "=============================================================\n"
1061 "=== Configured SLA Trunks ===================================\n"
1062 "=============================================================\n"
1063 "===\n");
1064 AST_RWLIST_RDLOCK(&sla_trunks);
1065 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
1066 struct sla_station_ref *station_ref;
1067 char ring_timeout[16] = "(none)";
1068 if (trunk->ring_timeout)
1069 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
1070 ast_cli(fd, "=== ---------------------------------------------------------\n"
1071 "=== Trunk Name: %s\n"
1072 "=== ==> Device: %s\n"
1073 "=== ==> AutoContext: %s\n"
1074 "=== ==> RingTimeout: %s\n"
1075 "=== ==> BargeAllowed: %s\n"
1076 "=== ==> HoldAccess: %s\n"
1077 "=== ==> Stations ...\n",
1078 trunk->name, trunk->device,
1079 S_OR(trunk->autocontext, "(none)"),
1080 ring_timeout,
1081 trunk->barge_disabled ? "No" : "Yes",
1082 sla_hold_str(trunk->hold_access));
1083 AST_RWLIST_RDLOCK(&sla_stations);
1084 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
1085 ast_cli(fd, "=== ==> Station name: %s\n", station_ref->station->name);
1086 AST_RWLIST_UNLOCK(&sla_stations);
1087 ast_cli(fd, "=== ---------------------------------------------------------\n"
1088 "===\n");
1090 AST_RWLIST_UNLOCK(&sla_trunks);
1091 ast_cli(fd, "=============================================================\n"
1092 "\n");
1094 return RESULT_SUCCESS;
1097 static const char *trunkstate2str(enum sla_trunk_state state)
1099 #define S(e) case e: return # e;
1100 switch (state) {
1101 S(SLA_TRUNK_STATE_IDLE)
1102 S(SLA_TRUNK_STATE_RINGING)
1103 S(SLA_TRUNK_STATE_UP)
1104 S(SLA_TRUNK_STATE_ONHOLD)
1105 S(SLA_TRUNK_STATE_ONHOLD_BYME)
1107 return "Uknown State";
1108 #undef S
1111 static const char sla_show_trunks_usage[] =
1112 "Usage: sla show trunks\n"
1113 " This will list all trunks defined in sla.conf\n";
1115 static int sla_show_stations(int fd, int argc, char **argv)
1117 const struct sla_station *station;
1119 ast_cli(fd, "\n"
1120 "=============================================================\n"
1121 "=== Configured SLA Stations =================================\n"
1122 "=============================================================\n"
1123 "===\n");
1124 AST_RWLIST_RDLOCK(&sla_stations);
1125 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1126 struct sla_trunk_ref *trunk_ref;
1127 char ring_timeout[16] = "(none)";
1128 char ring_delay[16] = "(none)";
1129 if (station->ring_timeout) {
1130 snprintf(ring_timeout, sizeof(ring_timeout),
1131 "%u", station->ring_timeout);
1133 if (station->ring_delay) {
1134 snprintf(ring_delay, sizeof(ring_delay),
1135 "%u", station->ring_delay);
1137 ast_cli(fd, "=== ---------------------------------------------------------\n"
1138 "=== Station Name: %s\n"
1139 "=== ==> Device: %s\n"
1140 "=== ==> AutoContext: %s\n"
1141 "=== ==> RingTimeout: %s\n"
1142 "=== ==> RingDelay: %s\n"
1143 "=== ==> HoldAccess: %s\n"
1144 "=== ==> Trunks ...\n",
1145 station->name, station->device,
1146 S_OR(station->autocontext, "(none)"),
1147 ring_timeout, ring_delay,
1148 sla_hold_str(station->hold_access));
1149 AST_RWLIST_RDLOCK(&sla_trunks);
1150 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1151 if (trunk_ref->ring_timeout) {
1152 snprintf(ring_timeout, sizeof(ring_timeout),
1153 "%u", trunk_ref->ring_timeout);
1154 } else
1155 strcpy(ring_timeout, "(none)");
1156 if (trunk_ref->ring_delay) {
1157 snprintf(ring_delay, sizeof(ring_delay),
1158 "%u", trunk_ref->ring_delay);
1159 } else
1160 strcpy(ring_delay, "(none)");
1161 ast_cli(fd, "=== ==> Trunk Name: %s\n"
1162 "=== ==> State: %s\n"
1163 "=== ==> RingTimeout: %s\n"
1164 "=== ==> RingDelay: %s\n",
1165 trunk_ref->trunk->name,
1166 trunkstate2str(trunk_ref->state),
1167 ring_timeout, ring_delay);
1169 AST_RWLIST_UNLOCK(&sla_trunks);
1170 ast_cli(fd, "=== ---------------------------------------------------------\n"
1171 "===\n");
1173 AST_RWLIST_UNLOCK(&sla_stations);
1174 ast_cli(fd, "============================================================\n"
1175 "\n");
1177 return RESULT_SUCCESS;
1180 static const char sla_show_stations_usage[] =
1181 "Usage: sla show stations\n"
1182 " This will list all stations defined in sla.conf\n";
1184 static struct ast_cli_entry cli_meetme[] = {
1185 { { "meetme", NULL, NULL },
1186 meetme_cmd, "Execute a command on a conference or conferee",
1187 meetme_usage, complete_meetmecmd },
1189 { { "sla", "show", "trunks", NULL },
1190 sla_show_trunks, "Show SLA Trunks",
1191 sla_show_trunks_usage, NULL },
1193 { { "sla", "show", "stations", NULL },
1194 sla_show_stations, "Show SLA Stations",
1195 sla_show_stations_usage, NULL },
1198 static void conf_flush(int fd, struct ast_channel *chan)
1200 int x;
1202 /* read any frames that may be waiting on the channel
1203 and throw them away
1205 if (chan) {
1206 struct ast_frame *f;
1208 /* when no frames are available, this will wait
1209 for 1 millisecond maximum
1211 while (ast_waitfor(chan, 1)) {
1212 f = ast_read(chan);
1213 if (f)
1214 ast_frfree(f);
1215 else /* channel was hung up or something else happened */
1216 break;
1220 /* flush any data sitting in the pseudo channel */
1221 x = ZT_FLUSH_ALL;
1222 if (ioctl(fd, ZT_FLUSH, &x))
1223 ast_log(LOG_WARNING, "Error flushing channel\n");
1227 /* Remove the conference from the list and free it.
1228 We assume that this was called while holding conflock. */
1229 static int conf_free(struct ast_conference *conf)
1231 int x;
1233 AST_LIST_REMOVE(&confs, conf, list);
1235 if (conf->recording == MEETME_RECORD_ACTIVE) {
1236 conf->recording = MEETME_RECORD_TERMINATE;
1237 AST_LIST_UNLOCK(&confs);
1238 while (1) {
1239 usleep(1);
1240 AST_LIST_LOCK(&confs);
1241 if (conf->recording == MEETME_RECORD_OFF)
1242 break;
1243 AST_LIST_UNLOCK(&confs);
1247 for (x=0;x<AST_FRAME_BITS;x++) {
1248 if (conf->transframe[x])
1249 ast_frfree(conf->transframe[x]);
1250 if (conf->transpath[x])
1251 ast_translator_free_path(conf->transpath[x]);
1253 if (conf->origframe)
1254 ast_frfree(conf->origframe);
1255 if (conf->lchan)
1256 ast_hangup(conf->lchan);
1257 if (conf->chan)
1258 ast_hangup(conf->chan);
1259 if (conf->fd >= 0)
1260 close(conf->fd);
1262 ast_mutex_destroy(&conf->playlock);
1263 ast_mutex_destroy(&conf->listenlock);
1264 ast_mutex_destroy(&conf->recordthreadlock);
1265 free(conf);
1267 return 0;
1270 static void conf_queue_dtmf(const struct ast_conference *conf,
1271 const struct ast_conf_user *sender, struct ast_frame *f)
1273 struct ast_conf_user *user;
1275 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
1276 if (user == sender)
1277 continue;
1278 if (ast_write(user->chan, f) < 0)
1279 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
1283 static void sla_queue_event_full(enum sla_event_type type,
1284 struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
1286 struct sla_event *event;
1288 if (!(event = ast_calloc(1, sizeof(*event))))
1289 return;
1291 event->type = type;
1292 event->trunk_ref = trunk_ref;
1293 event->station = station;
1295 if (!lock) {
1296 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1297 return;
1300 ast_mutex_lock(&sla.lock);
1301 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
1302 ast_cond_signal(&sla.cond);
1303 ast_mutex_unlock(&sla.lock);
1306 static void sla_queue_event_nolock(enum sla_event_type type)
1308 sla_queue_event_full(type, NULL, NULL, 0);
1311 static void sla_queue_event(enum sla_event_type type)
1313 sla_queue_event_full(type, NULL, NULL, 1);
1316 /*! \brief Queue a SLA event from the conference */
1317 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
1318 struct ast_conference *conf)
1320 struct sla_station *station;
1321 struct sla_trunk_ref *trunk_ref = NULL;
1322 char *trunk_name;
1324 trunk_name = ast_strdupa(conf->confno);
1325 strsep(&trunk_name, "_");
1326 if (ast_strlen_zero(trunk_name)) {
1327 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
1328 return;
1331 AST_RWLIST_RDLOCK(&sla_stations);
1332 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
1333 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
1334 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
1335 break;
1337 if (trunk_ref)
1338 break;
1340 AST_RWLIST_UNLOCK(&sla_stations);
1342 if (!trunk_ref) {
1343 ast_log(LOG_DEBUG, "Trunk not found for event!\n");
1344 return;
1347 sla_queue_event_full(type, trunk_ref, station, 1);
1350 /* Decrement reference counts, as incremented by find_conf() */
1351 static int dispose_conf(struct ast_conference *conf)
1353 int res = 0;
1354 int confno_int = 0;
1356 AST_LIST_LOCK(&confs);
1357 if (ast_atomic_dec_and_test(&conf->refcount)) {
1358 /* Take the conference room number out of an inuse state */
1359 if ((sscanf(conf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1360 conf_map[confno_int] = 0;
1361 conf_free(conf);
1362 res = 1;
1364 AST_LIST_UNLOCK(&confs);
1366 return res;
1370 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
1372 struct ast_conf_user *user = NULL;
1373 struct ast_conf_user *usr = NULL;
1374 int fd;
1375 struct zt_confinfo ztc, ztc_empty;
1376 struct ast_frame *f;
1377 struct ast_channel *c;
1378 struct ast_frame fr;
1379 int outfd;
1380 int ms;
1381 int nfds;
1382 int res;
1383 int flags;
1384 int retryzap;
1385 int origfd;
1386 int musiconhold = 0;
1387 int firstpass = 0;
1388 int lastmarked = 0;
1389 int currentmarked = 0;
1390 int ret = -1;
1391 int x;
1392 int menu_active = 0;
1393 int using_pseudo = 0;
1394 int duration=20;
1395 int hr, min, sec;
1396 int sent_event = 0;
1397 time_t now;
1398 struct ast_dsp *dsp=NULL;
1399 struct ast_app *app;
1400 const char *agifile;
1401 const char *agifiledefault = "conf-background.agi";
1402 char meetmesecs[30] = "";
1403 char exitcontext[AST_MAX_CONTEXT] = "";
1404 char recordingtmp[AST_MAX_EXTENSION] = "";
1405 char members[10] = "";
1406 int dtmf, opt_waitmarked_timeout = 0;
1407 time_t timeout = 0;
1408 ZT_BUFFERINFO bi;
1409 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
1410 char *buf = __buf + AST_FRIENDLY_OFFSET;
1411 int setusercount = 0;
1413 if (!(user = ast_calloc(1, sizeof(*user))))
1414 return ret;
1416 /* Possible timeout waiting for marked user */
1417 if ((confflags & CONFFLAG_WAITMARKED) &&
1418 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
1419 (sscanf(optargs[OPT_ARG_WAITMARKED], "%d", &opt_waitmarked_timeout) == 1) &&
1420 (opt_waitmarked_timeout > 0)) {
1421 timeout = time(NULL) + opt_waitmarked_timeout;
1424 if (confflags & CONFFLAG_RECORDCONF) {
1425 if (!conf->recordingfilename) {
1426 conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
1427 if (!conf->recordingfilename) {
1428 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
1429 conf->recordingfilename = ast_strdupa(recordingtmp);
1431 conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
1432 if (!conf->recordingformat) {
1433 snprintf(recordingtmp, sizeof(recordingtmp), "wav");
1434 conf->recordingformat = ast_strdupa(recordingtmp);
1436 ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
1437 conf->confno, conf->recordingfilename, conf->recordingformat);
1441 ast_mutex_lock(&conf->recordthreadlock);
1442 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
1443 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
1444 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
1445 ztc.chan = 0;
1446 ztc.confno = conf->zapconf;
1447 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
1448 if (ioctl(conf->lchan->fds[0], ZT_SETCONF, &ztc)) {
1449 ast_log(LOG_WARNING, "Error starting listen channel\n");
1450 ast_hangup(conf->lchan);
1451 conf->lchan = NULL;
1452 } else {
1453 pthread_attr_init(&conf->attr);
1454 pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
1455 ast_pthread_create_background(&conf->recordthread, &conf->attr, recordthread, conf);
1456 pthread_attr_destroy(&conf->attr);
1459 ast_mutex_unlock(&conf->recordthreadlock);
1461 time(&user->jointime);
1463 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
1464 /* Sorry, but this confernce is locked! */
1465 if (!ast_streamfile(chan, "conf-locked", chan->language))
1466 ast_waitstream(chan, "");
1467 goto outrun;
1470 ast_mutex_lock(&conf->playlock);
1472 if (AST_LIST_EMPTY(&conf->userlist))
1473 user->user_no = 1;
1474 else
1475 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
1477 AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
1479 user->chan = chan;
1480 user->userflags = confflags;
1481 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
1482 user->talking = -1;
1484 ast_mutex_unlock(&conf->playlock);
1486 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
1487 char destdir[PATH_MAX];
1489 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
1491 if (mkdir(destdir, 0777) && errno != EEXIST) {
1492 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
1493 goto outrun;
1496 snprintf(user->namerecloc, sizeof(user->namerecloc),
1497 "%s/meetme-username-%s-%d", destdir,
1498 conf->confno, user->user_no);
1499 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
1500 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, 128, 0, NULL);
1501 else
1502 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
1503 if (res == -1)
1504 goto outrun;
1507 ast_mutex_lock(&conf->playlock);
1509 if (confflags & CONFFLAG_MARKEDUSER)
1510 conf->markedusers++;
1511 conf->users++;
1512 /* Update table */
1513 snprintf(members, sizeof(members), "%d", conf->users);
1514 ast_update_realtime("meetme", "confno", conf->confno, "members", members , NULL);
1515 setusercount = 1;
1517 /* This device changed state now - if this is the first user */
1518 if (conf->users == 1)
1519 ast_device_state_changed("meetme:%s", conf->confno);
1521 ast_mutex_unlock(&conf->playlock);
1523 if (confflags & CONFFLAG_EXIT_CONTEXT) {
1524 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT")))
1525 ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
1526 else if (!ast_strlen_zero(chan->macrocontext))
1527 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
1528 else
1529 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
1532 if ( !(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON)) ) {
1533 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
1534 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1535 ast_waitstream(chan, "");
1536 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
1537 if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
1538 ast_waitstream(chan, "");
1541 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
1542 int keepplaying = 1;
1544 if (conf->users == 2) {
1545 if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
1546 res = ast_waitstream(chan, AST_DIGIT_ANY);
1547 ast_stopstream(chan);
1548 if (res > 0)
1549 keepplaying=0;
1550 else if (res == -1)
1551 goto outrun;
1553 } else {
1554 if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
1555 res = ast_waitstream(chan, AST_DIGIT_ANY);
1556 ast_stopstream(chan);
1557 if (res > 0)
1558 keepplaying=0;
1559 else if (res == -1)
1560 goto outrun;
1562 if (keepplaying) {
1563 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1564 if (res > 0)
1565 keepplaying=0;
1566 else if (res == -1)
1567 goto outrun;
1569 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
1570 res = ast_waitstream(chan, AST_DIGIT_ANY);
1571 ast_stopstream(chan);
1572 if (res > 0)
1573 keepplaying=0;
1574 else if (res == -1)
1575 goto outrun;
1580 ast_indicate(chan, -1);
1582 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1583 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
1584 goto outrun;
1587 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
1588 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
1589 goto outrun;
1592 retryzap = (strcasecmp(chan->tech->type, "Zap") || (chan->audiohooks || chan->monitor) ? 1 : 0);
1593 user->zapchannel = !retryzap;
1595 zapretry:
1596 origfd = chan->fds[0];
1597 if (retryzap) {
1598 fd = open("/dev/zap/pseudo", O_RDWR);
1599 if (fd < 0) {
1600 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
1601 goto outrun;
1603 using_pseudo = 1;
1604 /* Make non-blocking */
1605 flags = fcntl(fd, F_GETFL);
1606 if (flags < 0) {
1607 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
1608 close(fd);
1609 goto outrun;
1611 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
1612 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
1613 close(fd);
1614 goto outrun;
1616 /* Setup buffering information */
1617 memset(&bi, 0, sizeof(bi));
1618 bi.bufsize = CONF_SIZE/2;
1619 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
1620 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
1621 bi.numbufs = audio_buffers;
1622 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
1623 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
1624 close(fd);
1625 goto outrun;
1627 x = 1;
1628 if (ioctl(fd, ZT_SETLINEAR, &x)) {
1629 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
1630 close(fd);
1631 goto outrun;
1633 nfds = 1;
1634 } else {
1635 /* XXX Make sure we're not running on a pseudo channel XXX */
1636 fd = chan->fds[0];
1637 nfds = 0;
1639 memset(&ztc, 0, sizeof(ztc));
1640 memset(&ztc_empty, 0, sizeof(ztc_empty));
1641 /* Check to see if we're in a conference... */
1642 ztc.chan = 0;
1643 if (ioctl(fd, ZT_GETCONF, &ztc)) {
1644 ast_log(LOG_WARNING, "Error getting conference\n");
1645 close(fd);
1646 goto outrun;
1648 if (ztc.confmode) {
1649 /* Whoa, already in a conference... Retry... */
1650 if (!retryzap) {
1651 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
1652 retryzap = 1;
1653 goto zapretry;
1656 memset(&ztc, 0, sizeof(ztc));
1657 /* Add us to the conference */
1658 ztc.chan = 0;
1659 ztc.confno = conf->zapconf;
1661 ast_mutex_lock(&conf->playlock);
1663 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
1664 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
1665 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
1666 ast_waitstream(conf->chan, "");
1667 if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
1668 ast_waitstream(conf->chan, "");
1672 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
1673 ztc.confmode = ZT_CONF_CONF;
1674 else if (confflags & CONFFLAG_MONITOR)
1675 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1676 else if (confflags & CONFFLAG_TALKER)
1677 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1678 else
1679 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1681 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1682 ast_log(LOG_WARNING, "Error setting conference\n");
1683 close(fd);
1684 ast_mutex_unlock(&conf->playlock);
1685 goto outrun;
1687 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
1689 if (!sent_event) {
1690 manager_event(EVENT_FLAG_CALL, "MeetmeJoin",
1691 "Channel: %s\r\n"
1692 "Uniqueid: %s\r\n"
1693 "Meetme: %s\r\n"
1694 "Usernum: %d\r\n",
1695 chan->name, chan->uniqueid, conf->confno, user->user_no);
1696 sent_event = 1;
1699 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
1700 firstpass = 1;
1701 if (!(confflags & CONFFLAG_QUIET))
1702 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
1703 conf_play(chan, conf, ENTER);
1706 ast_mutex_unlock(&conf->playlock);
1708 conf_flush(fd, chan);
1710 if (confflags & CONFFLAG_AGI) {
1711 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1712 or use default filename of conf-background.agi */
1714 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
1715 if (!agifile)
1716 agifile = agifiledefault;
1718 if (user->zapchannel) {
1719 /* Set CONFMUTE mode on Zap channel to mute DTMF tones */
1720 x = 1;
1721 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1723 /* Find a pointer to the agi app and execute the script */
1724 app = pbx_findapp("agi");
1725 if (app) {
1726 char *s = ast_strdupa(agifile);
1727 ret = pbx_exec(chan, app, s);
1728 } else {
1729 ast_log(LOG_WARNING, "Could not find application (agi)\n");
1730 ret = -2;
1732 if (user->zapchannel) {
1733 /* Remove CONFMUTE mode on Zap channel */
1734 x = 0;
1735 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1737 } else {
1738 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
1739 /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1740 x = 1;
1741 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
1743 if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER) && !(dsp = ast_dsp_new())) {
1744 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
1745 res = -1;
1747 for(;;) {
1748 int menu_was_active = 0;
1750 outfd = -1;
1751 ms = -1;
1753 if (timeout && time(NULL) >= timeout)
1754 break;
1756 /* if we have just exited from the menu, and the user had a channel-driver
1757 volume adjustment, restore it
1759 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
1760 set_talk_volume(user, user->listen.desired);
1762 menu_was_active = menu_active;
1764 currentmarked = conf->markedusers;
1765 if (!(confflags & CONFFLAG_QUIET) &&
1766 (confflags & CONFFLAG_MARKEDUSER) &&
1767 (confflags & CONFFLAG_WAITMARKED) &&
1768 lastmarked == 0) {
1769 if (currentmarked == 1 && conf->users > 1) {
1770 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
1771 if (conf->users - 1 == 1) {
1772 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
1773 ast_waitstream(chan, "");
1774 } else {
1775 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
1776 ast_waitstream(chan, "");
1779 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
1780 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
1781 ast_waitstream(chan, "");
1784 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
1787 /* Update the struct with the actual confflags */
1788 user->userflags = confflags;
1790 if (confflags & CONFFLAG_WAITMARKED) {
1791 if(currentmarked == 0) {
1792 if (lastmarked != 0) {
1793 if (!(confflags & CONFFLAG_QUIET))
1794 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
1795 ast_waitstream(chan, "");
1796 if(confflags & CONFFLAG_MARKEDEXIT)
1797 break;
1798 else {
1799 ztc.confmode = ZT_CONF_CONF;
1800 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1801 ast_log(LOG_WARNING, "Error setting conference\n");
1802 close(fd);
1803 goto outrun;
1807 if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
1808 ast_moh_start(chan, NULL, NULL);
1809 musiconhold = 1;
1811 } else if(currentmarked >= 1 && lastmarked == 0) {
1812 /* Marked user entered, so cancel timeout */
1813 timeout = 0;
1814 if (confflags & CONFFLAG_MONITOR)
1815 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
1816 else if (confflags & CONFFLAG_TALKER)
1817 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
1818 else
1819 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
1820 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1821 ast_log(LOG_WARNING, "Error setting conference\n");
1822 close(fd);
1823 goto outrun;
1825 if (musiconhold && (confflags & CONFFLAG_MOH)) {
1826 ast_moh_stop(chan);
1827 musiconhold = 0;
1829 if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
1830 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
1831 ast_waitstream(chan, "");
1832 conf_play(chan, conf, ENTER);
1837 /* trying to add moh for single person conf */
1838 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
1839 if (conf->users == 1) {
1840 if (musiconhold == 0) {
1841 ast_moh_start(chan, NULL, NULL);
1842 musiconhold = 1;
1844 } else {
1845 if (musiconhold) {
1846 ast_moh_stop(chan);
1847 musiconhold = 0;
1852 /* Leave if the last marked user left */
1853 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
1854 ret = -1;
1855 break;
1858 /* Check if my modes have changed */
1860 /* If I should be muted but am still talker, mute me */
1861 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (ztc.confmode & ZT_CONF_TALKER)) {
1862 ztc.confmode ^= ZT_CONF_TALKER;
1863 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1864 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1865 ret = -1;
1866 break;
1869 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
1870 "Channel: %s\r\n"
1871 "Uniqueid: %s\r\n"
1872 "Meetme: %s\r\n"
1873 "Usernum: %i\r\n"
1874 "Status: on\r\n",
1875 chan->name, chan->uniqueid, conf->confno, user->user_no);
1878 /* If I should be un-muted but am not talker, un-mute me */
1879 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
1880 ztc.confmode |= ZT_CONF_TALKER;
1881 if (ioctl(fd, ZT_SETCONF, &ztc)) {
1882 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
1883 ret = -1;
1884 break;
1887 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
1888 "Channel: %s\r\n"
1889 "Uniqueid: %s\r\n"
1890 "Meetme: %s\r\n"
1891 "Usernum: %i\r\n"
1892 "Status: off\r\n",
1893 chan->name, chan->uniqueid, conf->confno, user->user_no);
1896 /* If I have been kicked, exit the conference */
1897 if (user->adminflags & ADMINFLAG_KICKME) {
1898 //You have been kicked.
1899 if (!(confflags & CONFFLAG_QUIET) &&
1900 !ast_streamfile(chan, "conf-kicked", chan->language)) {
1901 ast_waitstream(chan, "");
1903 ret = 0;
1904 break;
1907 /* Perform an extra hangup check just in case */
1908 if (ast_check_hangup(chan))
1909 break;
1911 if (c) {
1912 if (c->fds[0] != origfd || (user->zapchannel && (c->audiohooks || c->monitor))) {
1913 if (using_pseudo) {
1914 /* Kill old pseudo */
1915 close(fd);
1916 using_pseudo = 0;
1918 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
1919 retryzap = (strcasecmp(c->tech->type, "Zap") || (c->audiohooks || c->monitor) ? 1 : 0);
1920 user->zapchannel = !retryzap;
1921 goto zapretry;
1923 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
1924 f = ast_read_noaudio(c);
1925 else
1926 f = ast_read(c);
1927 if (!f)
1928 break;
1929 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
1930 if (user->talk.actual)
1931 ast_frame_adjust_volume(f, user->talk.actual);
1933 if (confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER)) {
1934 int totalsilence;
1936 if (user->talking == -1)
1937 user->talking = 0;
1939 res = ast_dsp_silence(dsp, f, &totalsilence);
1940 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
1941 user->talking = 1;
1942 if (confflags & CONFFLAG_MONITORTALKER)
1943 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1944 "Channel: %s\r\n"
1945 "Uniqueid: %s\r\n"
1946 "Meetme: %s\r\n"
1947 "Usernum: %d\r\n"
1948 "Status: on\r\n",
1949 chan->name, chan->uniqueid, conf->confno, user->user_no);
1951 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
1952 user->talking = 0;
1953 if (confflags & CONFFLAG_MONITORTALKER)
1954 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
1955 "Channel: %s\r\n"
1956 "Uniqueid: %s\r\n"
1957 "Meetme: %s\r\n"
1958 "Usernum: %d\r\n"
1959 "Status: off\r\n",
1960 chan->name, chan->uniqueid, conf->confno, user->user_no);
1963 if (using_pseudo) {
1964 /* Absolutely do _not_ use careful_write here...
1965 it is important that we read data from the channel
1966 as fast as it arrives, and feed it into the conference.
1967 The buffering in the pseudo channel will take care of any
1968 timing differences, unless they are so drastic as to lose
1969 audio frames (in which case carefully writing would only
1970 have delayed the audio even further).
1972 /* As it turns out, we do want to use careful write. We just
1973 don't want to block, but we do want to at least *try*
1974 to write out all the samples.
1976 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER))
1977 careful_write(fd, f->data, f->datalen, 0);
1979 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
1980 char tmp[2];
1982 if (confflags & CONFFLAG_PASS_DTMF)
1983 conf_queue_dtmf(conf, user, f);
1985 tmp[0] = f->subclass;
1986 tmp[1] = '\0';
1987 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1988 ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
1989 ret = 0;
1990 ast_frfree(f);
1991 break;
1992 } else if (option_debug > 1)
1993 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
1994 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
1995 if (confflags & CONFFLAG_PASS_DTMF)
1996 conf_queue_dtmf(conf, user, f);
1997 ret = 0;
1998 ast_frfree(f);
1999 break;
2000 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
2001 if (confflags & CONFFLAG_PASS_DTMF)
2002 conf_queue_dtmf(conf, user, f);
2003 if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
2004 ast_log(LOG_WARNING, "Error setting conference\n");
2005 close(fd);
2006 ast_frfree(f);
2007 goto outrun;
2010 /* if we are entering the menu, and the user has a channel-driver
2011 volume adjustment, clear it
2013 if (!menu_active && user->talk.desired && !user->talk.actual)
2014 set_talk_volume(user, 0);
2016 if (musiconhold) {
2017 ast_moh_stop(chan);
2019 if ((confflags & CONFFLAG_ADMIN)) {
2020 /* Admin menu */
2021 if (!menu_active) {
2022 menu_active = 1;
2023 /* Record this sound! */
2024 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
2025 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2026 ast_stopstream(chan);
2027 } else
2028 dtmf = 0;
2029 } else
2030 dtmf = f->subclass;
2031 if (dtmf) {
2032 switch(dtmf) {
2033 case '1': /* Un/Mute */
2034 menu_active = 0;
2036 /* for admin, change both admin and use flags */
2037 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
2038 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2039 else
2040 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2042 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2043 if (!ast_streamfile(chan, "conf-muted", chan->language))
2044 ast_waitstream(chan, "");
2045 } else {
2046 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2047 ast_waitstream(chan, "");
2049 break;
2050 case '2': /* Un/Lock the Conference */
2051 menu_active = 0;
2052 if (conf->locked) {
2053 conf->locked = 0;
2054 if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
2055 ast_waitstream(chan, "");
2056 } else {
2057 conf->locked = 1;
2058 if (!ast_streamfile(chan, "conf-lockednow", chan->language))
2059 ast_waitstream(chan, "");
2061 break;
2062 case '3': /* Eject last user */
2063 menu_active = 0;
2064 usr = AST_LIST_LAST(&conf->userlist);
2065 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
2066 if(!ast_streamfile(chan, "conf-errormenu", chan->language))
2067 ast_waitstream(chan, "");
2068 } else
2069 usr->adminflags |= ADMINFLAG_KICKME;
2070 ast_stopstream(chan);
2071 break;
2072 case '4':
2073 tweak_listen_volume(user, VOL_DOWN);
2074 break;
2075 case '6':
2076 tweak_listen_volume(user, VOL_UP);
2077 break;
2078 case '7':
2079 tweak_talk_volume(user, VOL_DOWN);
2080 break;
2081 case '8':
2082 menu_active = 0;
2083 break;
2084 case '9':
2085 tweak_talk_volume(user, VOL_UP);
2086 break;
2087 default:
2088 menu_active = 0;
2089 /* Play an error message! */
2090 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2091 ast_waitstream(chan, "");
2092 break;
2095 } else {
2096 /* User menu */
2097 if (!menu_active) {
2098 menu_active = 1;
2099 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
2100 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2101 ast_stopstream(chan);
2102 } else
2103 dtmf = 0;
2104 } else
2105 dtmf = f->subclass;
2106 if (dtmf) {
2107 switch(dtmf) {
2108 case '1': /* Un/Mute */
2109 menu_active = 0;
2111 /* user can only toggle the self-muted state */
2112 user->adminflags ^= ADMINFLAG_SELFMUTED;
2114 /* they can't override the admin mute state */
2115 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
2116 if (!ast_streamfile(chan, "conf-muted", chan->language))
2117 ast_waitstream(chan, "");
2118 } else {
2119 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
2120 ast_waitstream(chan, "");
2122 break;
2123 case '4':
2124 tweak_listen_volume(user, VOL_DOWN);
2125 break;
2126 case '6':
2127 tweak_listen_volume(user, VOL_UP);
2128 break;
2129 case '7':
2130 tweak_talk_volume(user, VOL_DOWN);
2131 break;
2132 case '8':
2133 menu_active = 0;
2134 break;
2135 case '9':
2136 tweak_talk_volume(user, VOL_UP);
2137 break;
2138 default:
2139 menu_active = 0;
2140 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
2141 ast_waitstream(chan, "");
2142 break;
2146 if (musiconhold)
2147 ast_moh_start(chan, NULL, NULL);
2149 if (ioctl(fd, ZT_SETCONF, &ztc)) {
2150 ast_log(LOG_WARNING, "Error setting conference\n");
2151 close(fd);
2152 ast_frfree(f);
2153 goto outrun;
2156 conf_flush(fd, chan);
2157 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
2158 && confflags & CONFFLAG_PASS_DTMF) {
2159 conf_queue_dtmf(conf, user, f);
2160 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
2161 switch (f->subclass) {
2162 case AST_CONTROL_HOLD:
2163 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
2164 break;
2165 default:
2166 break;
2168 } else if (f->frametype == AST_FRAME_NULL) {
2169 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2170 } else if (option_debug) {
2171 ast_log(LOG_DEBUG,
2172 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2173 chan->name, f->frametype, f->subclass);
2175 ast_frfree(f);
2176 } else if (outfd > -1) {
2177 res = read(outfd, buf, CONF_SIZE);
2178 if (res > 0) {
2179 memset(&fr, 0, sizeof(fr));
2180 fr.frametype = AST_FRAME_VOICE;
2181 fr.subclass = AST_FORMAT_SLINEAR;
2182 fr.datalen = res;
2183 fr.samples = res/2;
2184 fr.data = buf;
2185 fr.offset = AST_FRIENDLY_OFFSET;
2186 if (!user->listen.actual &&
2187 ((confflags & CONFFLAG_MONITOR) ||
2188 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
2189 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
2190 )) {
2191 int index;
2192 for (index=0;index<AST_FRAME_BITS;index++)
2193 if (chan->rawwriteformat & (1 << index))
2194 break;
2195 if (index >= AST_FRAME_BITS)
2196 goto bailoutandtrynormal;
2197 ast_mutex_lock(&conf->listenlock);
2198 if (!conf->transframe[index]) {
2199 if (conf->origframe) {
2200 if (!conf->transpath[index])
2201 conf->transpath[index] = ast_translator_build_path((1 << index), AST_FORMAT_SLINEAR);
2202 if (conf->transpath[index]) {
2203 conf->transframe[index] = ast_translate(conf->transpath[index], conf->origframe, 0);
2204 if (!conf->transframe[index])
2205 conf->transframe[index] = &ast_null_frame;
2209 if (conf->transframe[index]) {
2210 if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
2211 if (ast_write(chan, conf->transframe[index]))
2212 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2214 } else {
2215 ast_mutex_unlock(&conf->listenlock);
2216 goto bailoutandtrynormal;
2218 ast_mutex_unlock(&conf->listenlock);
2219 } else {
2220 bailoutandtrynormal:
2221 if (user->listen.actual)
2222 ast_frame_adjust_volume(&fr, user->listen.actual);
2223 if (ast_write(chan, &fr) < 0) {
2224 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
2227 } else
2228 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
2230 lastmarked = currentmarked;
2234 if (musiconhold)
2235 ast_moh_stop(chan);
2237 if (using_pseudo)
2238 close(fd);
2239 else {
2240 /* Take out of conference */
2241 ztc.chan = 0;
2242 ztc.confno = 0;
2243 ztc.confmode = 0;
2244 if (ioctl(fd, ZT_SETCONF, &ztc)) {
2245 ast_log(LOG_WARNING, "Error setting conference\n");
2249 reset_volumes(user);
2251 AST_LIST_LOCK(&confs);
2252 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
2253 conf_play(chan, conf, LEAVE);
2255 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
2256 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
2257 if ((conf->chan) && (conf->users > 1)) {
2258 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
2259 ast_waitstream(conf->chan, "");
2260 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
2261 ast_waitstream(conf->chan, "");
2263 ast_filedelete(user->namerecloc, NULL);
2266 AST_LIST_UNLOCK(&confs);
2268 outrun:
2269 AST_LIST_LOCK(&confs);
2271 if (dsp)
2272 ast_dsp_free(dsp);
2274 if (user->user_no) { /* Only cleanup users who really joined! */
2275 now = time(NULL);
2276 hr = (now - user->jointime) / 3600;
2277 min = ((now - user->jointime) % 3600) / 60;
2278 sec = (now - user->jointime) % 60;
2280 if (sent_event) {
2281 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
2282 "Channel: %s\r\n"
2283 "Uniqueid: %s\r\n"
2284 "Meetme: %s\r\n"
2285 "Usernum: %d\r\n"
2286 "CallerIDnum: %s\r\n"
2287 "CallerIDname: %s\r\n"
2288 "Duration: %ld\r\n",
2289 chan->name, chan->uniqueid, conf->confno,
2290 user->user_no,
2291 S_OR(user->chan->cid.cid_num, "<unknown>"),
2292 S_OR(user->chan->cid.cid_name, "<unknown>"),
2293 (long)(now - user->jointime));
2296 if (setusercount) {
2297 conf->users--;
2298 /* Update table */
2299 snprintf(members, sizeof(members), "%d", conf->users);
2300 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
2301 if (confflags & CONFFLAG_MARKEDUSER)
2302 conf->markedusers--;
2304 /* Remove ourselves from the list */
2305 AST_LIST_REMOVE(&conf->userlist, user, list);
2307 /* Change any states */
2308 if (!conf->users)
2309 ast_device_state_changed("meetme:%s", conf->confno);
2311 /* Return the number of seconds the user was in the conf */
2312 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
2313 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
2315 free(user);
2316 AST_LIST_UNLOCK(&confs);
2318 return ret;
2321 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
2322 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2324 struct ast_variable *var;
2325 struct ast_conference *cnf;
2327 /* Check first in the conference list */
2328 AST_LIST_LOCK(&confs);
2329 AST_LIST_TRAVERSE(&confs, cnf, list) {
2330 if (!strcmp(confno, cnf->confno))
2331 break;
2333 if (cnf) {
2334 cnf->refcount += refcount;
2336 AST_LIST_UNLOCK(&confs);
2338 if (!cnf) {
2339 char *pin = NULL, *pinadmin = NULL; /* For temp use */
2341 var = ast_load_realtime("meetme", "confno", confno, NULL);
2343 if (!var)
2344 return NULL;
2346 while (var) {
2347 if (!strcasecmp(var->name, "pin")) {
2348 pin = ast_strdupa(var->value);
2349 } else if (!strcasecmp(var->name, "adminpin")) {
2350 pinadmin = ast_strdupa(var->value);
2352 var = var->next;
2354 ast_variables_destroy(var);
2356 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount);
2359 if (cnf) {
2360 if (confflags && !cnf->chan &&
2361 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2362 ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2363 ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2364 ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2367 if (confflags && !cnf->chan &&
2368 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2369 ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2370 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2374 return cnf;
2378 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
2379 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
2381 struct ast_config *cfg;
2382 struct ast_variable *var;
2383 struct ast_conference *cnf;
2384 char *parse;
2385 AST_DECLARE_APP_ARGS(args,
2386 AST_APP_ARG(confno);
2387 AST_APP_ARG(pin);
2388 AST_APP_ARG(pinadmin);
2391 /* Check first in the conference list */
2392 AST_LIST_LOCK(&confs);
2393 AST_LIST_TRAVERSE(&confs, cnf, list) {
2394 if (!strcmp(confno, cnf->confno))
2395 break;
2397 if (cnf){
2398 cnf->refcount += refcount;
2400 AST_LIST_UNLOCK(&confs);
2402 if (!cnf) {
2403 if (dynamic) {
2404 /* No need to parse meetme.conf */
2405 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
2406 if (dynamic_pin) {
2407 if (dynamic_pin[0] == 'q') {
2408 /* Query the user to enter a PIN */
2409 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
2410 return NULL;
2412 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount);
2413 } else {
2414 cnf = build_conf(confno, "", "", make, dynamic, refcount);
2416 } else {
2417 /* Check the config */
2418 cfg = ast_config_load(CONFIG_FILE_NAME);
2419 if (!cfg) {
2420 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
2421 return NULL;
2423 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
2424 if (strcasecmp(var->name, "conf"))
2425 continue;
2427 if (!(parse = ast_strdupa(var->value)))
2428 return NULL;
2430 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
2431 if (!strcasecmp(args.confno, confno)) {
2432 /* Bingo it's a valid conference */
2433 cnf = build_conf(args.confno,
2434 S_OR(args.pin, ""),
2435 S_OR(args.pinadmin, ""),
2436 make, dynamic, refcount);
2437 break;
2440 if (!var) {
2441 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
2443 ast_config_destroy(cfg);
2445 } else if (dynamic_pin) {
2446 /* Correct for the user selecting 'D' instead of 'd' to have
2447 someone join into a conference that has already been created
2448 with a pin. */
2449 if (dynamic_pin[0] == 'q')
2450 dynamic_pin[0] = '\0';
2453 if (cnf) {
2454 if (confflags && !cnf->chan &&
2455 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
2456 ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
2457 ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2458 ast_clear_flag(confflags, CONFFLAG_INTROUSER);
2461 if (confflags && !cnf->chan &&
2462 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
2463 ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2464 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
2468 return cnf;
2471 /*! \brief The MeetmeCount application */
2472 static int count_exec(struct ast_channel *chan, void *data)
2474 struct ast_module_user *u;
2475 int res = 0;
2476 struct ast_conference *conf;
2477 int count;
2478 char *localdata;
2479 char val[80] = "0";
2480 AST_DECLARE_APP_ARGS(args,
2481 AST_APP_ARG(confno);
2482 AST_APP_ARG(varname);
2485 if (ast_strlen_zero(data)) {
2486 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
2487 return -1;
2490 u = ast_module_user_add(chan);
2492 if (!(localdata = ast_strdupa(data))) {
2493 ast_module_user_remove(u);
2494 return -1;
2497 AST_STANDARD_APP_ARGS(args, localdata);
2499 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
2501 if (conf) {
2502 count = conf->users;
2503 dispose_conf(conf);
2504 conf = NULL;
2505 } else
2506 count = 0;
2508 if (!ast_strlen_zero(args.varname)){
2509 /* have var so load it and exit */
2510 snprintf(val, sizeof(val), "%d",count);
2511 pbx_builtin_setvar_helper(chan, args.varname, val);
2512 } else {
2513 if (chan->_state != AST_STATE_UP)
2514 ast_answer(chan);
2515 res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
2517 ast_module_user_remove(u);
2519 return res;
2522 /*! \brief The meetme() application */
2523 static int conf_exec(struct ast_channel *chan, void *data)
2525 int res=-1;
2526 struct ast_module_user *u;
2527 char confno[MAX_CONFNUM] = "";
2528 int allowretry = 0;
2529 int retrycnt = 0;
2530 struct ast_conference *cnf = NULL;
2531 struct ast_flags confflags = {0};
2532 int dynamic = 0;
2533 int empty = 0, empty_no_pin = 0;
2534 int always_prompt = 0;
2535 char *notdata, *info, the_pin[MAX_PIN] = "";
2536 AST_DECLARE_APP_ARGS(args,
2537 AST_APP_ARG(confno);
2538 AST_APP_ARG(options);
2539 AST_APP_ARG(pin);
2541 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
2543 u = ast_module_user_add(chan);
2545 if (ast_strlen_zero(data)) {
2546 allowretry = 1;
2547 notdata = "";
2548 } else {
2549 notdata = data;
2552 if (chan->_state != AST_STATE_UP)
2553 ast_answer(chan);
2555 info = ast_strdupa(notdata);
2557 AST_STANDARD_APP_ARGS(args, info);
2559 if (args.confno) {
2560 ast_copy_string(confno, args.confno, sizeof(confno));
2561 if (ast_strlen_zero(confno)) {
2562 allowretry = 1;
2566 if (args.pin)
2567 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
2569 if (args.options) {
2570 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
2571 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
2572 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !args.pin)
2573 strcpy(the_pin, "q");
2575 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
2576 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
2577 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
2580 do {
2581 if (retrycnt > 3)
2582 allowretry = 0;
2583 if (empty) {
2584 int i;
2585 struct ast_config *cfg;
2586 struct ast_variable *var;
2587 int confno_int;
2589 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2590 if ((empty_no_pin) || (!dynamic)) {
2591 cfg = ast_config_load(CONFIG_FILE_NAME);
2592 if (cfg) {
2593 var = ast_variable_browse(cfg, "rooms");
2594 while (var) {
2595 if (!strcasecmp(var->name, "conf")) {
2596 char *stringp = ast_strdupa(var->value);
2597 if (stringp) {
2598 char *confno_tmp = strsep(&stringp, "|,");
2599 int found = 0;
2600 if (!dynamic) {
2601 /* For static: run through the list and see if this conference is empty */
2602 AST_LIST_LOCK(&confs);
2603 AST_LIST_TRAVERSE(&confs, cnf, list) {
2604 if (!strcmp(confno_tmp, cnf->confno)) {
2605 /* The conference exists, therefore it's not empty */
2606 found = 1;
2607 break;
2610 AST_LIST_UNLOCK(&confs);
2611 if (!found) {
2612 /* At this point, we have a confno_tmp (static conference) that is empty */
2613 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
2614 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
2615 * Case 2: empty_no_pin and pin is blank (but not NULL)
2616 * Case 3: not empty_no_pin
2618 ast_copy_string(confno, confno_tmp, sizeof(confno));
2619 break;
2620 /* XXX the map is not complete (but we do have a confno) */
2626 var = var->next;
2628 ast_config_destroy(cfg);
2632 /* Select first conference number not in use */
2633 if (ast_strlen_zero(confno) && dynamic) {
2634 AST_LIST_LOCK(&confs);
2635 for (i = 0; i < sizeof(conf_map) / sizeof(conf_map[0]); i++) {
2636 if (!conf_map[i]) {
2637 snprintf(confno, sizeof(confno), "%d", i);
2638 conf_map[i] = 1;
2639 break;
2642 AST_LIST_UNLOCK(&confs);
2645 /* Not found? */
2646 if (ast_strlen_zero(confno)) {
2647 res = ast_streamfile(chan, "conf-noempty", chan->language);
2648 if (!res)
2649 ast_waitstream(chan, "");
2650 } else {
2651 if (sscanf(confno, "%d", &confno_int) == 1) {
2652 res = ast_streamfile(chan, "conf-enteringno", chan->language);
2653 if (!res) {
2654 ast_waitstream(chan, "");
2655 res = ast_say_digits(chan, confno_int, "", chan->language);
2657 } else {
2658 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
2663 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
2664 /* Prompt user for conference number */
2665 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
2666 if (res < 0) {
2667 /* Don't try to validate when we catch an error */
2668 confno[0] = '\0';
2669 allowretry = 0;
2670 break;
2673 if (!ast_strlen_zero(confno)) {
2674 /* Check the validity of the conference */
2675 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
2676 sizeof(the_pin), 1, &confflags);
2677 if (!cnf) {
2678 cnf = find_conf_realtime(chan, confno, 1, dynamic,
2679 the_pin, sizeof(the_pin), 1, &confflags);
2682 if (!cnf) {
2683 res = ast_streamfile(chan, "conf-invalid", chan->language);
2684 if (!res)
2685 ast_waitstream(chan, "");
2686 res = -1;
2687 if (allowretry)
2688 confno[0] = '\0';
2689 } else {
2690 if ((!ast_strlen_zero(cnf->pin) &&
2691 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
2692 (!ast_strlen_zero(cnf->pinadmin) &&
2693 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
2694 char pin[MAX_PIN] = "";
2695 int j;
2697 /* Allow the pin to be retried up to 3 times */
2698 for (j = 0; j < 3; j++) {
2699 if (*the_pin && (always_prompt == 0)) {
2700 ast_copy_string(pin, the_pin, sizeof(pin));
2701 res = 0;
2702 } else {
2703 /* Prompt user for pin if pin is required */
2704 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
2706 if (res >= 0) {
2707 if (!strcasecmp(pin, cnf->pin) ||
2708 (!ast_strlen_zero(cnf->pinadmin) &&
2709 !strcasecmp(pin, cnf->pinadmin))) {
2710 /* Pin correct */
2711 allowretry = 0;
2712 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin))
2713 ast_set_flag(&confflags, CONFFLAG_ADMIN);
2714 /* Run the conference */
2715 res = conf_run(chan, cnf, confflags.flags, optargs);
2716 break;
2717 } else {
2718 /* Pin invalid */
2719 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
2720 res = ast_waitstream(chan, AST_DIGIT_ANY);
2721 ast_stopstream(chan);
2723 else {
2724 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
2725 break;
2727 if (res < 0)
2728 break;
2729 pin[0] = res;
2730 pin[1] = '\0';
2731 res = -1;
2732 if (allowretry)
2733 confno[0] = '\0';
2735 } else {
2736 /* failed when getting the pin */
2737 res = -1;
2738 allowretry = 0;
2739 /* see if we need to get rid of the conference */
2740 break;
2743 /* Don't retry pin with a static pin */
2744 if (*the_pin && (always_prompt==0)) {
2745 break;
2748 } else {
2749 /* No pin required */
2750 allowretry = 0;
2752 /* Run the conference */
2753 res = conf_run(chan, cnf, confflags.flags, optargs);
2755 dispose_conf(cnf);
2756 cnf = NULL;
2759 } while (allowretry);
2761 if (cnf)
2762 dispose_conf(cnf);
2764 ast_module_user_remove(u);
2766 return res;
2769 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
2771 struct ast_conf_user *user = NULL;
2772 int cid;
2774 sscanf(callerident, "%i", &cid);
2775 if (conf && callerident) {
2776 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
2777 if (cid == user->user_no)
2778 return user;
2781 return NULL;
2784 /*! \brief The MeetMeadmin application */
2785 /* MeetMeAdmin(confno, command, caller) */
2786 static int admin_exec(struct ast_channel *chan, void *data) {
2787 char *params;
2788 struct ast_conference *cnf;
2789 struct ast_conf_user *user = NULL;
2790 struct ast_module_user *u;
2791 AST_DECLARE_APP_ARGS(args,
2792 AST_APP_ARG(confno);
2793 AST_APP_ARG(command);
2794 AST_APP_ARG(user);
2797 if (ast_strlen_zero(data)) {
2798 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
2799 return -1;
2802 u = ast_module_user_add(chan);
2804 AST_LIST_LOCK(&confs);
2806 params = ast_strdupa(data);
2807 AST_STANDARD_APP_ARGS(args, params);
2809 if (!args.command) {
2810 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
2811 AST_LIST_UNLOCK(&confs);
2812 ast_module_user_remove(u);
2813 return -1;
2815 AST_LIST_TRAVERSE(&confs, cnf, list) {
2816 if (!strcmp(cnf->confno, args.confno))
2817 break;
2820 if (!cnf) {
2821 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
2822 AST_LIST_UNLOCK(&confs);
2823 ast_module_user_remove(u);
2824 return 0;
2827 ast_atomic_fetchadd_int(&cnf->refcount, 1);
2829 if (args.user)
2830 user = find_user(cnf, args.user);
2832 switch (*args.command) {
2833 case 76: /* L: Lock */
2834 cnf->locked = 1;
2835 break;
2836 case 108: /* l: Unlock */
2837 cnf->locked = 0;
2838 break;
2839 case 75: /* K: kick all users */
2840 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2841 user->adminflags |= ADMINFLAG_KICKME;
2842 break;
2843 case 101: /* e: Eject last user*/
2844 user = AST_LIST_LAST(&cnf->userlist);
2845 if (!(user->userflags & CONFFLAG_ADMIN))
2846 user->adminflags |= ADMINFLAG_KICKME;
2847 else
2848 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
2849 break;
2850 case 77: /* M: Mute */
2851 if (user) {
2852 user->adminflags |= ADMINFLAG_MUTED;
2853 } else
2854 ast_log(LOG_NOTICE, "Specified User not found!\n");
2855 break;
2856 case 78: /* N: Mute all (non-admin) users */
2857 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
2858 if (!(user->userflags & CONFFLAG_ADMIN))
2859 user->adminflags |= ADMINFLAG_MUTED;
2861 break;
2862 case 109: /* m: Unmute */
2863 if (user) {
2864 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2865 } else
2866 ast_log(LOG_NOTICE, "Specified User not found!\n");
2867 break;
2868 case 110: /* n: Unmute all users */
2869 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2870 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
2871 break;
2872 case 107: /* k: Kick user */
2873 if (user)
2874 user->adminflags |= ADMINFLAG_KICKME;
2875 else
2876 ast_log(LOG_NOTICE, "Specified User not found!\n");
2877 break;
2878 case 118: /* v: Lower all users listen volume */
2879 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2880 tweak_listen_volume(user, VOL_DOWN);
2881 break;
2882 case 86: /* V: Raise all users listen volume */
2883 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2884 tweak_listen_volume(user, VOL_UP);
2885 break;
2886 case 115: /* s: Lower all users speaking volume */
2887 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2888 tweak_talk_volume(user, VOL_DOWN);
2889 break;
2890 case 83: /* S: Raise all users speaking volume */
2891 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2892 tweak_talk_volume(user, VOL_UP);
2893 break;
2894 case 82: /* R: Reset all volume levels */
2895 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
2896 reset_volumes(user);
2897 break;
2898 case 114: /* r: Reset user's volume level */
2899 if (user)
2900 reset_volumes(user);
2901 else
2902 ast_log(LOG_NOTICE, "Specified User not found!\n");
2903 break;
2904 case 85: /* U: Raise user's listen volume */
2905 if (user)
2906 tweak_listen_volume(user, VOL_UP);
2907 else
2908 ast_log(LOG_NOTICE, "Specified User not found!\n");
2909 break;
2910 case 117: /* u: Lower user's listen volume */
2911 if (user)
2912 tweak_listen_volume(user, VOL_DOWN);
2913 else
2914 ast_log(LOG_NOTICE, "Specified User not found!\n");
2915 break;
2916 case 84: /* T: Raise user's talk volume */
2917 if (user)
2918 tweak_talk_volume(user, VOL_UP);
2919 else
2920 ast_log(LOG_NOTICE, "Specified User not found!\n");
2921 break;
2922 case 116: /* t: Lower user's talk volume */
2923 if (user)
2924 tweak_talk_volume(user, VOL_DOWN);
2925 else
2926 ast_log(LOG_NOTICE, "Specified User not found!\n");
2927 break;
2930 AST_LIST_UNLOCK(&confs);
2932 dispose_conf(cnf);
2934 ast_module_user_remove(u);
2936 return 0;
2939 static int meetmemute(struct mansession *s, const struct message *m, int mute)
2941 struct ast_conference *conf;
2942 struct ast_conf_user *user;
2943 const char *confid = astman_get_header(m, "Meetme");
2944 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
2945 int userno;
2947 if (ast_strlen_zero(confid)) {
2948 astman_send_error(s, m, "Meetme conference not specified");
2949 return 0;
2952 if (ast_strlen_zero(userid)) {
2953 astman_send_error(s, m, "Meetme user number not specified");
2954 return 0;
2957 userno = strtoul(userid, &userid, 10);
2959 if (*userid) {
2960 astman_send_error(s, m, "Invalid user number");
2961 return 0;
2964 /* Look in the conference list */
2965 AST_LIST_LOCK(&confs);
2966 AST_LIST_TRAVERSE(&confs, conf, list) {
2967 if (!strcmp(confid, conf->confno))
2968 break;
2971 if (!conf) {
2972 AST_LIST_UNLOCK(&confs);
2973 astman_send_error(s, m, "Meetme conference does not exist");
2974 return 0;
2977 AST_LIST_TRAVERSE(&conf->userlist, user, list)
2978 if (user->user_no == userno)
2979 break;
2981 if (!user) {
2982 AST_LIST_UNLOCK(&confs);
2983 astman_send_error(s, m, "User number not found");
2984 return 0;
2987 if (mute)
2988 user->adminflags |= ADMINFLAG_MUTED; /* request user muting */
2989 else
2990 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED); /* request user unmuting */
2992 AST_LIST_UNLOCK(&confs);
2994 ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, user->chan->name, user->chan->uniqueid);
2996 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
2997 return 0;
3000 static int action_meetmemute(struct mansession *s, const struct message *m)
3002 return meetmemute(s, m, 1);
3005 static int action_meetmeunmute(struct mansession *s, const struct message *m)
3007 return meetmemute(s, m, 0);
3010 static void *recordthread(void *args)
3012 struct ast_conference *cnf = args;
3013 struct ast_frame *f=NULL;
3014 int flags;
3015 struct ast_filestream *s=NULL;
3016 int res=0;
3017 int x;
3018 const char *oldrecordingfilename = NULL;
3020 if (!cnf || !cnf->lchan) {
3021 pthread_exit(0);
3024 ast_stopstream(cnf->lchan);
3025 flags = O_CREAT|O_TRUNC|O_WRONLY;
3028 cnf->recording = MEETME_RECORD_ACTIVE;
3029 while (ast_waitfor(cnf->lchan, -1) > -1) {
3030 if (cnf->recording == MEETME_RECORD_TERMINATE) {
3031 AST_LIST_LOCK(&confs);
3032 AST_LIST_UNLOCK(&confs);
3033 break;
3035 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
3036 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
3037 oldrecordingfilename = cnf->recordingfilename;
3040 f = ast_read(cnf->lchan);
3041 if (!f) {
3042 res = -1;
3043 break;
3045 if (f->frametype == AST_FRAME_VOICE) {
3046 ast_mutex_lock(&cnf->listenlock);
3047 for (x=0;x<AST_FRAME_BITS;x++) {
3048 /* Free any translations that have occured */
3049 if (cnf->transframe[x]) {
3050 ast_frfree(cnf->transframe[x]);
3051 cnf->transframe[x] = NULL;
3054 if (cnf->origframe)
3055 ast_frfree(cnf->origframe);
3056 cnf->origframe = ast_frdup(f);
3057 ast_mutex_unlock(&cnf->listenlock);
3058 if (s)
3059 res = ast_writestream(s, f);
3060 if (res) {
3061 ast_frfree(f);
3062 break;
3065 ast_frfree(f);
3067 cnf->recording = MEETME_RECORD_OFF;
3068 if (s)
3069 ast_closestream(s);
3071 pthread_exit(0);
3074 /*! \brief Callback for devicestate providers */
3075 static int meetmestate(const char *data)
3077 struct ast_conference *conf;
3079 /* Find conference */
3080 AST_LIST_LOCK(&confs);
3081 AST_LIST_TRAVERSE(&confs, conf, list) {
3082 if (!strcmp(data, conf->confno))
3083 break;
3085 AST_LIST_UNLOCK(&confs);
3086 if (!conf)
3087 return AST_DEVICE_INVALID;
3090 /* SKREP to fill */
3091 if (!conf->users)
3092 return AST_DEVICE_NOT_INUSE;
3094 return AST_DEVICE_INUSE;
3097 static void load_config_meetme(void)
3099 struct ast_config *cfg;
3100 const char *val;
3102 audio_buffers = DEFAULT_AUDIO_BUFFERS;
3104 if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
3105 return;
3107 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
3108 if ((sscanf(val, "%d", &audio_buffers) != 1)) {
3109 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
3110 audio_buffers = DEFAULT_AUDIO_BUFFERS;
3111 } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
3112 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
3113 ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
3114 audio_buffers = DEFAULT_AUDIO_BUFFERS;
3116 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
3117 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
3120 ast_config_destroy(cfg);
3123 /*! \brief Find an SLA trunk by name
3124 * \note This must be called with the sla_trunks container locked
3126 static struct sla_trunk *sla_find_trunk(const char *name)
3128 struct sla_trunk *trunk = NULL;
3130 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
3131 if (!strcasecmp(trunk->name, name))
3132 break;
3135 return trunk;
3138 /*! \brief Find an SLA station by name
3139 * \note This must be called with the sla_stations container locked
3141 static struct sla_station *sla_find_station(const char *name)
3143 struct sla_station *station = NULL;
3145 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
3146 if (!strcasecmp(station->name, name))
3147 break;
3150 return station;
3153 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
3154 const struct sla_station *station)
3156 struct sla_station_ref *station_ref;
3157 struct sla_trunk_ref *trunk_ref;
3159 /* For each station that has this call on hold, check for private hold. */
3160 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
3161 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
3162 if (trunk_ref->trunk != trunk || station_ref->station == station)
3163 continue;
3164 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
3165 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
3166 return 1;
3167 return 0;
3171 return 0;
3174 /*! \brief Find a trunk reference on a station by name
3175 * \param station the station
3176 * \param name the trunk's name
3177 * \return a pointer to the station's trunk reference. If the trunk
3178 * is not found, it is not idle and barge is disabled, or if
3179 * it is on hold and private hold is set, then NULL will be returned.
3181 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
3182 const char *name)
3184 struct sla_trunk_ref *trunk_ref = NULL;
3186 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
3187 if (strcasecmp(trunk_ref->trunk->name, name))
3188 continue;
3190 if ( (trunk_ref->trunk->barge_disabled
3191 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
3192 (trunk_ref->trunk->hold_stations
3193 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
3194 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
3195 sla_check_station_hold_access(trunk_ref->trunk, station) )
3197 trunk_ref = NULL;
3200 break;
3203 return trunk_ref;
3206 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
3208 struct sla_station_ref *station_ref;
3210 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
3211 return NULL;
3213 station_ref->station = station;
3215 return station_ref;
3218 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
3220 struct sla_ringing_station *ringing_station;
3222 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
3223 return NULL;
3225 ringing_station->station = station;
3226 ringing_station->ring_begin = ast_tvnow();
3228 return ringing_station;
3231 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
3232 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
3234 struct sla_station *station;
3235 struct sla_trunk_ref *trunk_ref;
3237 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
3238 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
3239 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
3240 || trunk_ref == exclude)
3241 continue;
3242 trunk_ref->state = state;
3243 ast_device_state_changed("SLA:%s_%s", station->name, trunk->name);
3244 break;
3249 struct run_station_args {
3250 struct sla_station *station;
3251 struct sla_trunk_ref *trunk_ref;
3252 ast_mutex_t *cond_lock;
3253 ast_cond_t *cond;
3256 static void *run_station(void *data)
3258 struct sla_station *station;
3259 struct sla_trunk_ref *trunk_ref;
3260 char conf_name[MAX_CONFNUM];
3261 struct ast_flags conf_flags = { 0 };
3262 struct ast_conference *conf;
3265 struct run_station_args *args = data;
3266 station = args->station;
3267 trunk_ref = args->trunk_ref;
3268 ast_mutex_lock(args->cond_lock);
3269 ast_cond_signal(args->cond);
3270 ast_mutex_unlock(args->cond_lock);
3271 /* args is no longer valid here. */
3274 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
3275 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
3276 ast_set_flag(&conf_flags,
3277 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
3278 ast_answer(trunk_ref->chan);
3279 conf = build_conf(conf_name, "", "", 0, 0, 1);
3280 if (conf) {
3281 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
3282 dispose_conf(conf);
3283 conf = NULL;
3285 trunk_ref->chan = NULL;
3286 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
3287 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
3288 strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
3289 admin_exec(NULL, conf_name);
3290 trunk_ref->trunk->hold_stations = 0;
3291 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
3294 ast_dial_join(station->dial);
3295 ast_dial_destroy(station->dial);
3296 station->dial = NULL;
3298 return NULL;
3301 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
3303 char buf[80];
3304 struct sla_station_ref *station_ref;
3306 snprintf(buf, sizeof(buf), "SLA_%s|K", ringing_trunk->trunk->name);
3307 admin_exec(NULL, buf);
3308 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
3310 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
3311 free(station_ref);
3313 free(ringing_trunk);
3316 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
3317 enum sla_station_hangup hangup)
3319 struct sla_ringing_trunk *ringing_trunk;
3320 struct sla_trunk_ref *trunk_ref;
3321 struct sla_station_ref *station_ref;
3323 ast_dial_join(ringing_station->station->dial);
3324 ast_dial_destroy(ringing_station->station->dial);
3325 ringing_station->station->dial = NULL;
3327 if (hangup == SLA_STATION_HANGUP_NORMAL)
3328 goto done;
3330 /* If the station is being hung up because of a timeout, then add it to the
3331 * list of timed out stations on each of the ringing trunks. This is so
3332 * that when doing further processing to figure out which stations should be
3333 * ringing, which trunk to answer, determining timeouts, etc., we know which
3334 * ringing trunks we should ignore. */
3335 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
3336 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
3337 if (ringing_trunk->trunk == trunk_ref->trunk)
3338 break;
3340 if (!trunk_ref)
3341 continue;
3342 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
3343 continue;
3344 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
3347 done:
3348 free(ringing_station);
3351 static void sla_dial_state_callback(struct ast_dial *dial)
3353 sla_queue_event(SLA_EVENT_DIAL_STATE);
3356 /*! \brief Check to see if dialing this station already timed out for this ringing trunk
3357 * \note Assumes sla.lock is locked
3359 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
3360 const struct sla_station *station)
3362 struct sla_station_ref *timed_out_station;
3364 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
3365 if (station == timed_out_station->station)
3366 return 1;
3369 return 0;
3372 /*! \brief Choose the highest priority ringing trunk for a station
3373 * \param station the station
3374 * \param remove remove the ringing trunk once selected
3375 * \param trunk_ref a place to store the pointer to this stations reference to
3376 * the selected trunk
3377 * \return a pointer to the selected ringing trunk, or NULL if none found
3378 * \note Assumes that sla.lock is locked
3380 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
3381 struct sla_trunk_ref **trunk_ref, int remove)
3383 struct sla_trunk_ref *s_trunk_ref;
3384 struct sla_ringing_trunk *ringing_trunk = NULL;
3386 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
3387 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
3388 /* Make sure this is the trunk we're looking for */
3389 if (s_trunk_ref->trunk != ringing_trunk->trunk)
3390 continue;
3392 /* This trunk on the station is ringing. But, make sure this station
3393 * didn't already time out while this trunk was ringing. */
3394 if (sla_check_timed_out_station(ringing_trunk, station))
3395 continue;
3397 if (remove)
3398 AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
3400 if (trunk_ref)
3401 *trunk_ref = s_trunk_ref;
3403 break;
3405 AST_LIST_TRAVERSE_SAFE_END
3407 if (ringing_trunk)
3408 break;
3411 return ringing_trunk;
3414 static void sla_handle_dial_state_event(void)
3416 struct sla_ringing_station *ringing_station;
3418 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
3419 struct sla_trunk_ref *s_trunk_ref = NULL;
3420 struct sla_ringing_trunk *ringing_trunk = NULL;
3421 struct run_station_args args;
3422 enum ast_dial_result dial_res;
3423 pthread_attr_t attr;
3424 pthread_t dont_care;
3425 ast_mutex_t cond_lock;
3426 ast_cond_t cond;
3428 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
3429 case AST_DIAL_RESULT_HANGUP:
3430 case AST_DIAL_RESULT_INVALID:
3431 case AST_DIAL_RESULT_FAILED:
3432 case AST_DIAL_RESULT_TIMEOUT:
3433 case AST_DIAL_RESULT_UNANSWERED:
3434 AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
3435 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
3436 break;
3437 case AST_DIAL_RESULT_ANSWERED:
3438 AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
3439 /* Find the appropriate trunk to answer. */
3440 ast_mutex_lock(&sla.lock);
3441 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
3442 ast_mutex_unlock(&sla.lock);
3443 if (!ringing_trunk) {
3444 ast_log(LOG_DEBUG, "Found no ringing trunk for station '%s' to answer!\n",
3445 ringing_station->station->name);
3446 break;
3448 /* Track the channel that answered this trunk */
3449 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
3450 /* Actually answer the trunk */
3451 ast_answer(ringing_trunk->trunk->chan);
3452 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
3453 /* Now, start a thread that will connect this station to the trunk. The rest of
3454 * the code here sets up the thread and ensures that it is able to save the arguments
3455 * before they are no longer valid since they are allocated on the stack. */
3456 args.trunk_ref = s_trunk_ref;
3457 args.station = ringing_station->station;
3458 args.cond = &cond;
3459 args.cond_lock = &cond_lock;
3460 free(ringing_trunk);
3461 free(ringing_station);
3462 ast_mutex_init(&cond_lock);
3463 ast_cond_init(&cond, NULL);
3464 pthread_attr_init(&attr);
3465 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3466 ast_mutex_lock(&cond_lock);
3467 ast_pthread_create_background(&dont_care, &attr, run_station, &args);
3468 ast_cond_wait(&cond, &cond_lock);
3469 ast_mutex_unlock(&cond_lock);
3470 ast_mutex_destroy(&cond_lock);
3471 ast_cond_destroy(&cond);
3472 pthread_attr_destroy(&attr);
3473 break;
3474 case AST_DIAL_RESULT_TRYING:
3475 case AST_DIAL_RESULT_RINGING:
3476 case AST_DIAL_RESULT_PROGRESS:
3477 case AST_DIAL_RESULT_PROCEEDING:
3478 break;
3480 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
3481 /* Queue up reprocessing ringing trunks, and then ringing stations again */
3482 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
3483 sla_queue_event(SLA_EVENT_DIAL_STATE);
3484 break;
3487 AST_LIST_TRAVERSE_SAFE_END
3490 /*! \brief Check to see if this station is already ringing
3491 * \note Assumes sla.lock is locked
3493 static int sla_check_ringing_station(const struct sla_station *station)
3495 struct sla_ringing_station *ringing_station;
3497 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
3498 if (station == ringing_station->station)
3499 return 1;
3502 return 0;
3505 /*! \brief Check to see if this station has failed to be dialed in the past minute
3506 * \note assumes sla.lock is locked
3508 static int sla_check_failed_station(const struct sla_station *station)
3510 struct sla_failed_station *failed_station;
3511 int res = 0;
3513 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
3514 if (station != failed_station->station)
3515 continue;
3516 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
3517 AST_LIST_REMOVE_CURRENT(&sla.failed_stations, entry);
3518 free(failed_station);
3519 break;
3521 res = 1;
3523 AST_LIST_TRAVERSE_SAFE_END
3525 return res;
3528 /*! \brief Ring a station
3529 * \note Assumes sla.lock is locked
3531 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
3533 char *tech, *tech_data;
3534 struct ast_dial *dial;
3535 struct sla_ringing_station *ringing_station;
3536 const char *cid_name = NULL, *cid_num = NULL;
3537 enum ast_dial_result res;
3539 if (!(dial = ast_dial_create()))
3540 return -1;
3542 ast_dial_set_state_callback(dial, sla_dial_state_callback);
3543 tech_data = ast_strdupa(station->device);
3544 tech = strsep(&tech_data, "/");
3546 if (ast_dial_append(dial, tech, tech_data) == -1) {
3547 ast_dial_destroy(dial);
3548 return -1;
3551 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
3552 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
3553 free(ringing_trunk->trunk->chan->cid.cid_name);
3554 ringing_trunk->trunk->chan->cid.cid_name = NULL;
3556 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
3557 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
3558 free(ringing_trunk->trunk->chan->cid.cid_num);
3559 ringing_trunk->trunk->chan->cid.cid_num = NULL;
3562 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
3564 if (cid_name)
3565 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
3566 if (cid_num)
3567 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
3569 if (res != AST_DIAL_RESULT_TRYING) {
3570 struct sla_failed_station *failed_station;
3571 ast_dial_destroy(dial);
3572 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
3573 return -1;
3574 failed_station->station = station;
3575 failed_station->last_try = ast_tvnow();
3576 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
3577 return -1;
3579 if (!(ringing_station = sla_create_ringing_station(station))) {
3580 ast_dial_join(dial);
3581 ast_dial_destroy(dial);
3582 return -1;
3585 station->dial = dial;
3587 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
3589 return 0;
3592 /*! \brief Check to see if a station is in use
3594 static int sla_check_inuse_station(const struct sla_station *station)
3596 struct sla_trunk_ref *trunk_ref;
3598 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
3599 if (trunk_ref->chan)
3600 return 1;
3603 return 0;
3606 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
3607 const struct sla_trunk *trunk)
3609 struct sla_trunk_ref *trunk_ref = NULL;
3611 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
3612 if (trunk_ref->trunk == trunk)
3613 break;
3616 return trunk_ref;
3619 /*! \brief Calculate the ring delay for a given ringing trunk on a station
3620 * \param station the station
3621 * \param trunk the trunk. If NULL, the highest priority ringing trunk will be used
3622 * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
3624 static int sla_check_station_delay(struct sla_station *station,
3625 struct sla_ringing_trunk *ringing_trunk)
3627 struct sla_trunk_ref *trunk_ref;
3628 unsigned int delay = UINT_MAX;
3629 int time_left, time_elapsed;
3631 if (!ringing_trunk)
3632 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
3633 else
3634 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
3636 if (!ringing_trunk || !trunk_ref)
3637 return delay;
3639 /* If this station has a ring delay specific to the highest priority
3640 * ringing trunk, use that. Otherwise, use the ring delay specified
3641 * globally for the station. */
3642 delay = trunk_ref->ring_delay;
3643 if (!delay)
3644 delay = station->ring_delay;
3645 if (!delay)
3646 return INT_MAX;
3648 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
3649 time_left = (delay * 1000) - time_elapsed;
3651 return time_left;
3654 /*! \brief Ring stations based on current set of ringing trunks
3655 * \note Assumes that sla.lock is locked
3657 static void sla_ring_stations(void)
3659 struct sla_station_ref *station_ref;
3660 struct sla_ringing_trunk *ringing_trunk;
3662 /* Make sure that every station that uses at least one of the ringing
3663 * trunks, is ringing. */
3664 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
3665 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
3666 int time_left;
3668 /* Is this station already ringing? */
3669 if (sla_check_ringing_station(station_ref->station))
3670 continue;
3672 /* Is this station already in a call? */
3673 if (sla_check_inuse_station(station_ref->station))
3674 continue;
3676 /* Did we fail to dial this station earlier? If so, has it been
3677 * a minute since we tried? */
3678 if (sla_check_failed_station(station_ref->station))
3679 continue;
3681 /* If this station already timed out while this trunk was ringing,
3682 * do not dial it again for this ringing trunk. */
3683 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
3684 continue;
3686 /* Check for a ring delay in progress */
3687 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
3688 if (time_left != INT_MAX && time_left > 0)
3689 continue;
3691 /* It is time to make this station begin to ring. Do it! */
3692 sla_ring_station(ringing_trunk, station_ref->station);
3695 /* Now, all of the stations that should be ringing, are ringing. */
3698 static void sla_hangup_stations(void)
3700 struct sla_trunk_ref *trunk_ref;
3701 struct sla_ringing_station *ringing_station;
3703 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
3704 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
3705 struct sla_ringing_trunk *ringing_trunk;
3706 ast_mutex_lock(&sla.lock);
3707 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
3708 if (trunk_ref->trunk == ringing_trunk->trunk)
3709 break;
3711 ast_mutex_unlock(&sla.lock);
3712 if (ringing_trunk)
3713 break;
3715 if (!trunk_ref) {
3716 AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
3717 ast_dial_join(ringing_station->station->dial);
3718 ast_dial_destroy(ringing_station->station->dial);
3719 ringing_station->station->dial = NULL;
3720 free(ringing_station);
3723 AST_LIST_TRAVERSE_SAFE_END
3726 static void sla_handle_ringing_trunk_event(void)
3728 ast_mutex_lock(&sla.lock);
3729 sla_ring_stations();
3730 ast_mutex_unlock(&sla.lock);
3732 /* Find stations that shouldn't be ringing anymore. */
3733 sla_hangup_stations();
3736 static void sla_handle_hold_event(struct sla_event *event)
3738 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
3739 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
3740 ast_device_state_changed("SLA:%s_%s",
3741 event->station->name, event->trunk_ref->trunk->name);
3742 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
3743 INACTIVE_TRUNK_REFS, event->trunk_ref);
3745 if (event->trunk_ref->trunk->active_stations == 1) {
3746 /* The station putting it on hold is the only one on the call, so start
3747 * Music on hold to the trunk. */
3748 event->trunk_ref->trunk->on_hold = 1;
3749 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
3752 ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
3753 event->trunk_ref->chan = NULL;
3756 /*! \brief Process trunk ring timeouts
3757 * \note Called with sla.lock locked
3758 * \return non-zero if a change to the ringing trunks was made
3760 static int sla_calc_trunk_timeouts(unsigned int *timeout)
3762 struct sla_ringing_trunk *ringing_trunk;
3763 int res = 0;
3765 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
3766 int time_left, time_elapsed;
3767 if (!ringing_trunk->trunk->ring_timeout)
3768 continue;
3769 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
3770 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
3771 if (time_left <= 0) {
3772 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
3773 AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
3774 sla_stop_ringing_trunk(ringing_trunk);
3775 res = 1;
3776 continue;
3778 if (time_left < *timeout)
3779 *timeout = time_left;
3781 AST_LIST_TRAVERSE_SAFE_END
3783 return res;
3786 /*! \brief Process station ring timeouts
3787 * \note Called with sla.lock locked
3788 * \return non-zero if a change to the ringing stations was made
3790 static int sla_calc_station_timeouts(unsigned int *timeout)
3792 struct sla_ringing_trunk *ringing_trunk;
3793 struct sla_ringing_station *ringing_station;
3794 int res = 0;
3796 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
3797 unsigned int ring_timeout = 0;
3798 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
3799 struct sla_trunk_ref *trunk_ref;
3801 /* If there are any ring timeouts specified for a specific trunk
3802 * on the station, then use the highest per-trunk ring timeout.
3803 * Otherwise, use the ring timeout set for the entire station. */
3804 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
3805 struct sla_station_ref *station_ref;
3806 int trunk_time_elapsed, trunk_time_left;
3808 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
3809 if (ringing_trunk->trunk == trunk_ref->trunk)
3810 break;
3812 if (!ringing_trunk)
3813 continue;
3815 /* If there is a trunk that is ringing without a timeout, then the
3816 * only timeout that could matter is a global station ring timeout. */
3817 if (!trunk_ref->ring_timeout)
3818 break;
3820 /* This trunk on this station is ringing and has a timeout.
3821 * However, make sure this trunk isn't still ringing from a
3822 * previous timeout. If so, don't consider it. */
3823 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
3824 if (station_ref->station == ringing_station->station)
3825 break;
3827 if (station_ref)
3828 continue;
3830 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
3831 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
3832 if (trunk_time_left > final_trunk_time_left)
3833 final_trunk_time_left = trunk_time_left;
3836 /* No timeout was found for ringing trunks, and no timeout for the entire station */
3837 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
3838 continue;
3840 /* Compute how much time is left for a global station timeout */
3841 if (ringing_station->station->ring_timeout) {
3842 ring_timeout = ringing_station->station->ring_timeout;
3843 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
3844 time_left = (ring_timeout * 1000) - time_elapsed;
3847 /* If the time left based on the per-trunk timeouts is smaller than the
3848 * global station ring timeout, use that. */
3849 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
3850 time_left = final_trunk_time_left;
3852 /* If there is no time left, the station needs to stop ringing */
3853 if (time_left <= 0) {
3854 AST_LIST_REMOVE_CURRENT(&sla.ringing_stations, entry);
3855 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
3856 res = 1;
3857 continue;
3860 /* There is still some time left for this station to ring, so save that
3861 * timeout if it is the first event scheduled to occur */
3862 if (time_left < *timeout)
3863 *timeout = time_left;
3865 AST_LIST_TRAVERSE_SAFE_END
3867 return res;
3870 /*! \brief Calculate the ring delay for a station
3871 * \note Assumes sla.lock is locked
3873 static int sla_calc_station_delays(unsigned int *timeout)
3875 struct sla_station *station;
3876 int res = 0;
3878 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
3879 struct sla_ringing_trunk *ringing_trunk;
3880 int time_left;
3882 /* Ignore stations already ringing */
3883 if (sla_check_ringing_station(station))
3884 continue;
3886 /* Ignore stations already on a call */
3887 if (sla_check_inuse_station(station))
3888 continue;
3890 /* Ignore stations that don't have one of their trunks ringing */
3891 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
3892 continue;
3894 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
3895 continue;
3897 /* If there is no time left, then the station needs to start ringing.
3898 * Return non-zero so that an event will be queued up an event to
3899 * make that happen. */
3900 if (time_left <= 0) {
3901 res = 1;
3902 continue;
3905 if (time_left < *timeout)
3906 *timeout = time_left;
3909 return res;
3912 /*! \brief Calculate the time until the next known event
3913 * \note Called with sla.lock locked */
3914 static int sla_process_timers(struct timespec *ts)
3916 unsigned int timeout = UINT_MAX;
3917 struct timeval tv;
3918 unsigned int change_made = 0;
3920 /* Check for ring timeouts on ringing trunks */
3921 if (sla_calc_trunk_timeouts(&timeout))
3922 change_made = 1;
3924 /* Check for ring timeouts on ringing stations */
3925 if (sla_calc_station_timeouts(&timeout))
3926 change_made = 1;
3928 /* Check for station ring delays */
3929 if (sla_calc_station_delays(&timeout))
3930 change_made = 1;
3932 /* queue reprocessing of ringing trunks */
3933 if (change_made)
3934 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
3936 /* No timeout */
3937 if (timeout == UINT_MAX)
3938 return 0;
3940 if (ts) {
3941 tv = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
3942 ts->tv_sec = tv.tv_sec;
3943 ts->tv_nsec = tv.tv_usec * 1000;
3946 return 1;
3949 static void *sla_thread(void *data)
3951 struct sla_failed_station *failed_station;
3952 struct sla_ringing_station *ringing_station;
3954 ast_mutex_lock(&sla.lock);
3956 while (!sla.stop) {
3957 struct sla_event *event;
3958 struct timespec ts = { 0, };
3959 unsigned int have_timeout = 0;
3961 if (AST_LIST_EMPTY(&sla.event_q)) {
3962 if ((have_timeout = sla_process_timers(&ts)))
3963 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
3964 else
3965 ast_cond_wait(&sla.cond, &sla.lock);
3966 if (sla.stop)
3967 break;
3970 if (have_timeout)
3971 sla_process_timers(NULL);
3973 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
3974 ast_mutex_unlock(&sla.lock);
3975 switch (event->type) {
3976 case SLA_EVENT_HOLD:
3977 sla_handle_hold_event(event);
3978 break;
3979 case SLA_EVENT_DIAL_STATE:
3980 sla_handle_dial_state_event();
3981 break;
3982 case SLA_EVENT_RINGING_TRUNK:
3983 sla_handle_ringing_trunk_event();
3984 break;
3986 free(event);
3987 ast_mutex_lock(&sla.lock);
3991 ast_mutex_unlock(&sla.lock);
3993 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
3994 free(ringing_station);
3996 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
3997 free(failed_station);
3999 return NULL;
4002 struct dial_trunk_args {
4003 struct sla_trunk_ref *trunk_ref;
4004 struct sla_station *station;
4005 ast_mutex_t *cond_lock;
4006 ast_cond_t *cond;
4009 static void *dial_trunk(void *data)
4011 struct dial_trunk_args *args = data;
4012 struct ast_dial *dial;
4013 char *tech, *tech_data;
4014 enum ast_dial_result dial_res;
4015 char conf_name[MAX_CONFNUM];
4016 struct ast_conference *conf;
4017 struct ast_flags conf_flags = { 0 };
4018 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
4019 const char *cid_name = NULL, *cid_num = NULL;
4021 if (!(dial = ast_dial_create())) {
4022 ast_mutex_lock(args->cond_lock);
4023 ast_cond_signal(args->cond);
4024 ast_mutex_unlock(args->cond_lock);
4025 return NULL;
4028 tech_data = ast_strdupa(trunk_ref->trunk->device);
4029 tech = strsep(&tech_data, "/");
4030 if (ast_dial_append(dial, tech, tech_data) == -1) {
4031 ast_mutex_lock(args->cond_lock);
4032 ast_cond_signal(args->cond);
4033 ast_mutex_unlock(args->cond_lock);
4034 ast_dial_destroy(dial);
4035 return NULL;
4038 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
4039 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
4040 free(trunk_ref->chan->cid.cid_name);
4041 trunk_ref->chan->cid.cid_name = NULL;
4043 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
4044 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
4045 free(trunk_ref->chan->cid.cid_num);
4046 trunk_ref->chan->cid.cid_num = NULL;
4049 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
4051 if (cid_name)
4052 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
4053 if (cid_num)
4054 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
4056 if (dial_res != AST_DIAL_RESULT_TRYING) {
4057 ast_mutex_lock(args->cond_lock);
4058 ast_cond_signal(args->cond);
4059 ast_mutex_unlock(args->cond_lock);
4060 ast_dial_destroy(dial);
4061 return NULL;
4064 for (;;) {
4065 unsigned int done = 0;
4066 switch ((dial_res = ast_dial_state(dial))) {
4067 case AST_DIAL_RESULT_ANSWERED:
4068 trunk_ref->trunk->chan = ast_dial_answered(dial);
4069 case AST_DIAL_RESULT_HANGUP:
4070 case AST_DIAL_RESULT_INVALID:
4071 case AST_DIAL_RESULT_FAILED:
4072 case AST_DIAL_RESULT_TIMEOUT:
4073 case AST_DIAL_RESULT_UNANSWERED:
4074 done = 1;
4075 case AST_DIAL_RESULT_TRYING:
4076 case AST_DIAL_RESULT_RINGING:
4077 case AST_DIAL_RESULT_PROGRESS:
4078 case AST_DIAL_RESULT_PROCEEDING:
4079 break;
4081 if (done)
4082 break;
4085 if (!trunk_ref->trunk->chan) {
4086 ast_mutex_lock(args->cond_lock);
4087 ast_cond_signal(args->cond);
4088 ast_mutex_unlock(args->cond_lock);
4089 ast_dial_join(dial);
4090 ast_dial_destroy(dial);
4091 return NULL;
4094 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
4095 ast_set_flag(&conf_flags,
4096 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
4097 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
4098 conf = build_conf(conf_name, "", "", 1, 1, 1);
4100 ast_mutex_lock(args->cond_lock);
4101 ast_cond_signal(args->cond);
4102 ast_mutex_unlock(args->cond_lock);
4104 if (conf) {
4105 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
4106 dispose_conf(conf);
4107 conf = NULL;
4110 /* If the trunk is going away, it is definitely now IDLE. */
4111 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
4113 trunk_ref->trunk->chan = NULL;
4114 trunk_ref->trunk->on_hold = 0;
4116 ast_dial_join(dial);
4117 ast_dial_destroy(dial);
4119 return NULL;
4122 /*! \brief For a given station, choose the highest priority idle trunk
4124 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
4126 struct sla_trunk_ref *trunk_ref = NULL;
4128 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
4129 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
4130 break;
4133 return trunk_ref;
4136 static int sla_station_exec(struct ast_channel *chan, void *data)
4138 char *station_name, *trunk_name;
4139 struct sla_station *station;
4140 struct sla_trunk_ref *trunk_ref = NULL;
4141 char conf_name[MAX_CONFNUM];
4142 struct ast_flags conf_flags = { 0 };
4143 struct ast_conference *conf;
4145 if (ast_strlen_zero(data)) {
4146 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
4147 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
4148 return 0;
4151 trunk_name = ast_strdupa(data);
4152 station_name = strsep(&trunk_name, "_");
4154 if (ast_strlen_zero(station_name)) {
4155 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
4156 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
4157 return 0;
4160 AST_RWLIST_RDLOCK(&sla_stations);
4161 station = sla_find_station(station_name);
4162 AST_RWLIST_UNLOCK(&sla_stations);
4164 if (!station) {
4165 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
4166 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
4167 return 0;
4170 AST_RWLIST_RDLOCK(&sla_trunks);
4171 if (!ast_strlen_zero(trunk_name)) {
4172 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
4173 } else
4174 trunk_ref = sla_choose_idle_trunk(station);
4175 AST_RWLIST_UNLOCK(&sla_trunks);
4177 if (!trunk_ref) {
4178 if (ast_strlen_zero(trunk_name))
4179 ast_log(LOG_NOTICE, "No trunks available for call.\n");
4180 else {
4181 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
4182 "'%s' due to access controls.\n", trunk_name);
4184 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
4185 return 0;
4188 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
4189 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
4190 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
4191 else {
4192 trunk_ref->state = SLA_TRUNK_STATE_UP;
4193 ast_device_state_changed("SLA:%s_%s", station->name, trunk_ref->trunk->name);
4195 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
4196 struct sla_ringing_trunk *ringing_trunk;
4198 ast_mutex_lock(&sla.lock);
4199 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
4200 if (ringing_trunk->trunk == trunk_ref->trunk) {
4201 AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
4202 break;
4205 AST_LIST_TRAVERSE_SAFE_END
4206 ast_mutex_unlock(&sla.lock);
4208 if (ringing_trunk) {
4209 ast_answer(ringing_trunk->trunk->chan);
4210 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
4212 free(ringing_trunk);
4214 /* Queue up reprocessing ringing trunks, and then ringing stations again */
4215 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
4216 sla_queue_event(SLA_EVENT_DIAL_STATE);
4220 trunk_ref->chan = chan;
4222 if (!trunk_ref->trunk->chan) {
4223 ast_mutex_t cond_lock;
4224 ast_cond_t cond;
4225 pthread_t dont_care;
4226 pthread_attr_t attr;
4227 struct dial_trunk_args args = {
4228 .trunk_ref = trunk_ref,
4229 .station = station,
4230 .cond_lock = &cond_lock,
4231 .cond = &cond,
4233 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
4234 /* Create a thread to dial the trunk and dump it into the conference.
4235 * However, we want to wait until the trunk has been dialed and the
4236 * conference is created before continuing on here. */
4237 ast_autoservice_start(chan);
4238 ast_mutex_init(&cond_lock);
4239 ast_cond_init(&cond, NULL);
4240 pthread_attr_init(&attr);
4241 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4242 ast_mutex_lock(&cond_lock);
4243 ast_pthread_create_background(&dont_care, &attr, dial_trunk, &args);
4244 ast_cond_wait(&cond, &cond_lock);
4245 ast_mutex_unlock(&cond_lock);
4246 ast_mutex_destroy(&cond_lock);
4247 ast_cond_destroy(&cond);
4248 pthread_attr_destroy(&attr);
4249 ast_autoservice_stop(chan);
4250 if (!trunk_ref->trunk->chan) {
4251 ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
4252 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
4253 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
4254 trunk_ref->chan = NULL;
4255 return 0;
4259 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
4260 trunk_ref->trunk->on_hold) {
4261 trunk_ref->trunk->on_hold = 0;
4262 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
4263 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
4266 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
4267 ast_set_flag(&conf_flags,
4268 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
4269 ast_answer(chan);
4270 conf = build_conf(conf_name, "", "", 0, 0, 1);
4271 if (conf) {
4272 conf_run(chan, conf, conf_flags.flags, NULL);
4273 dispose_conf(conf);
4274 conf = NULL;
4276 trunk_ref->chan = NULL;
4277 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
4278 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
4279 strncat(conf_name, "|K", sizeof(conf_name) - strlen(conf_name) - 1);
4280 admin_exec(NULL, conf_name);
4281 trunk_ref->trunk->hold_stations = 0;
4282 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
4285 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
4287 return 0;
4290 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
4292 struct sla_trunk_ref *trunk_ref;
4294 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
4295 return NULL;
4297 trunk_ref->trunk = trunk;
4299 return trunk_ref;
4302 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
4304 struct sla_ringing_trunk *ringing_trunk;
4306 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
4307 return NULL;
4309 ringing_trunk->trunk = trunk;
4310 ringing_trunk->ring_begin = ast_tvnow();
4312 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
4314 ast_mutex_lock(&sla.lock);
4315 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
4316 ast_mutex_unlock(&sla.lock);
4318 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
4320 return ringing_trunk;
4323 static int sla_trunk_exec(struct ast_channel *chan, void *data)
4325 const char *trunk_name = data;
4326 char conf_name[MAX_CONFNUM];
4327 struct ast_conference *conf;
4328 struct ast_flags conf_flags = { 0 };
4329 struct sla_trunk *trunk;
4330 struct sla_ringing_trunk *ringing_trunk;
4332 AST_RWLIST_RDLOCK(&sla_trunks);
4333 trunk = sla_find_trunk(trunk_name);
4334 AST_RWLIST_UNLOCK(&sla_trunks);
4335 if (!trunk) {
4336 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", trunk_name);
4337 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
4338 return 0;
4340 if (trunk->chan) {
4341 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
4342 trunk_name);
4343 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
4344 return 0;
4346 trunk->chan = chan;
4348 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
4349 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
4350 return 0;
4353 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_name);
4354 conf = build_conf(conf_name, "", "", 1, 1, 1);
4355 if (!conf) {
4356 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
4357 return 0;
4359 ast_set_flag(&conf_flags,
4360 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF);
4361 ast_indicate(chan, AST_CONTROL_RINGING);
4362 conf_run(chan, conf, conf_flags.flags, NULL);
4363 dispose_conf(conf);
4364 conf = NULL;
4365 trunk->chan = NULL;
4366 trunk->on_hold = 0;
4368 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
4370 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
4371 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
4373 /* Remove the entry from the list of ringing trunks if it is still there. */
4374 ast_mutex_lock(&sla.lock);
4375 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
4376 if (ringing_trunk->trunk == trunk) {
4377 AST_LIST_REMOVE_CURRENT(&sla.ringing_trunks, entry);
4378 break;
4381 AST_LIST_TRAVERSE_SAFE_END
4382 ast_mutex_unlock(&sla.lock);
4383 if (ringing_trunk) {
4384 free(ringing_trunk);
4385 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
4386 /* Queue reprocessing of ringing trunks to make stations stop ringing
4387 * that shouldn't be ringing after this trunk stopped. */
4388 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
4391 return 0;
4394 static int sla_state(const char *data)
4396 char *buf, *station_name, *trunk_name;
4397 struct sla_station *station;
4398 struct sla_trunk_ref *trunk_ref;
4399 int res = AST_DEVICE_INVALID;
4401 trunk_name = buf = ast_strdupa(data);
4402 station_name = strsep(&trunk_name, "_");
4404 AST_RWLIST_RDLOCK(&sla_stations);
4405 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
4406 if (strcasecmp(station_name, station->name))
4407 continue;
4408 AST_RWLIST_RDLOCK(&sla_trunks);
4409 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
4410 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
4411 break;
4413 if (!trunk_ref) {
4414 AST_RWLIST_UNLOCK(&sla_trunks);
4415 break;
4417 switch (trunk_ref->state) {
4418 case SLA_TRUNK_STATE_IDLE:
4419 res = AST_DEVICE_NOT_INUSE;
4420 break;
4421 case SLA_TRUNK_STATE_RINGING:
4422 res = AST_DEVICE_RINGING;
4423 break;
4424 case SLA_TRUNK_STATE_UP:
4425 res = AST_DEVICE_INUSE;
4426 break;
4427 case SLA_TRUNK_STATE_ONHOLD:
4428 case SLA_TRUNK_STATE_ONHOLD_BYME:
4429 res = AST_DEVICE_ONHOLD;
4430 break;
4432 AST_RWLIST_UNLOCK(&sla_trunks);
4434 AST_RWLIST_UNLOCK(&sla_stations);
4436 if (res == AST_DEVICE_INVALID) {
4437 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
4438 trunk_name, station_name);
4441 return res;
4444 static void destroy_trunk(struct sla_trunk *trunk)
4446 struct sla_station_ref *station_ref;
4448 if (!ast_strlen_zero(trunk->autocontext))
4449 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
4451 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
4452 free(station_ref);
4454 ast_string_field_free_memory(trunk);
4455 free(trunk);
4458 static void destroy_station(struct sla_station *station)
4460 struct sla_trunk_ref *trunk_ref;
4462 if (!ast_strlen_zero(station->autocontext)) {
4463 AST_RWLIST_RDLOCK(&sla_trunks);
4464 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
4465 char exten[AST_MAX_EXTENSION];
4466 char hint[AST_MAX_APP];
4467 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
4468 snprintf(hint, sizeof(hint), "SLA:%s", exten);
4469 ast_context_remove_extension(station->autocontext, exten,
4470 1, sla_registrar);
4471 ast_context_remove_extension(station->autocontext, hint,
4472 PRIORITY_HINT, sla_registrar);
4474 AST_RWLIST_UNLOCK(&sla_trunks);
4477 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
4478 free(trunk_ref);
4480 ast_string_field_free_memory(station);
4481 free(station);
4484 static void sla_destroy(void)
4486 struct sla_trunk *trunk;
4487 struct sla_station *station;
4489 AST_RWLIST_WRLOCK(&sla_trunks);
4490 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
4491 destroy_trunk(trunk);
4492 AST_RWLIST_UNLOCK(&sla_trunks);
4494 AST_RWLIST_WRLOCK(&sla_stations);
4495 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
4496 destroy_station(station);
4497 AST_RWLIST_UNLOCK(&sla_stations);
4499 if (sla.thread != AST_PTHREADT_NULL) {
4500 ast_mutex_lock(&sla.lock);
4501 sla.stop = 1;
4502 ast_cond_signal(&sla.cond);
4503 ast_mutex_unlock(&sla.lock);
4504 pthread_join(sla.thread, NULL);
4507 /* Drop any created contexts from the dialplan */
4508 ast_context_destroy(NULL, sla_registrar);
4510 ast_mutex_destroy(&sla.lock);
4511 ast_cond_destroy(&sla.cond);
4514 static int sla_check_device(const char *device)
4516 char *tech, *tech_data;
4518 tech_data = ast_strdupa(device);
4519 tech = strsep(&tech_data, "/");
4521 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
4522 return -1;
4524 return 0;
4527 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
4529 struct sla_trunk *trunk;
4530 struct ast_variable *var;
4531 const char *dev;
4533 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
4534 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
4535 return -1;
4538 if (sla_check_device(dev)) {
4539 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
4540 cat, dev);
4541 return -1;
4544 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
4545 return -1;
4546 if (ast_string_field_init(trunk, 32)) {
4547 free(trunk);
4548 return -1;
4551 ast_string_field_set(trunk, name, cat);
4552 ast_string_field_set(trunk, device, dev);
4554 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
4555 if (!strcasecmp(var->name, "autocontext"))
4556 ast_string_field_set(trunk, autocontext, var->value);
4557 else if (!strcasecmp(var->name, "ringtimeout")) {
4558 if (sscanf(var->value, "%u", &trunk->ring_timeout) != 1) {
4559 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
4560 var->value, trunk->name);
4561 trunk->ring_timeout = 0;
4563 } else if (!strcasecmp(var->name, "barge"))
4564 trunk->barge_disabled = ast_false(var->value);
4565 else if (!strcasecmp(var->name, "hold")) {
4566 if (!strcasecmp(var->value, "private"))
4567 trunk->hold_access = SLA_HOLD_PRIVATE;
4568 else if (!strcasecmp(var->value, "open"))
4569 trunk->hold_access = SLA_HOLD_OPEN;
4570 else {
4571 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
4572 var->value, trunk->name);
4574 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
4575 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
4576 var->name, var->lineno, SLA_CONFIG_FILE);
4580 if (!ast_strlen_zero(trunk->autocontext)) {
4581 struct ast_context *context;
4582 context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
4583 if (!context) {
4584 ast_log(LOG_ERROR, "Failed to automatically find or create "
4585 "context '%s' for SLA!\n", trunk->autocontext);
4586 destroy_trunk(trunk);
4587 return -1;
4589 if (ast_add_extension2(context, 0 /* don't replace */, "s", 1,
4590 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free, sla_registrar)) {
4591 ast_log(LOG_ERROR, "Failed to automatically create extension "
4592 "for trunk '%s'!\n", trunk->name);
4593 destroy_trunk(trunk);
4594 return -1;
4598 AST_RWLIST_WRLOCK(&sla_trunks);
4599 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
4600 AST_RWLIST_UNLOCK(&sla_trunks);
4602 return 0;
4605 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
4607 struct sla_trunk *trunk;
4608 struct sla_trunk_ref *trunk_ref;
4609 struct sla_station_ref *station_ref;
4610 char *trunk_name, *options, *cur;
4612 options = ast_strdupa(var->value);
4613 trunk_name = strsep(&options, ",");
4615 AST_RWLIST_RDLOCK(&sla_trunks);
4616 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
4617 if (!strcasecmp(trunk->name, trunk_name))
4618 break;
4621 AST_RWLIST_UNLOCK(&sla_trunks);
4622 if (!trunk) {
4623 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
4624 return;
4626 if (!(trunk_ref = create_trunk_ref(trunk)))
4627 return;
4628 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
4630 while ((cur = strsep(&options, ","))) {
4631 char *name, *value = cur;
4632 name = strsep(&value, "=");
4633 if (!strcasecmp(name, "ringtimeout")) {
4634 if (sscanf(value, "%u", &trunk_ref->ring_timeout) != 1) {
4635 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
4636 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
4637 trunk_ref->ring_timeout = 0;
4639 } else if (!strcasecmp(name, "ringdelay")) {
4640 if (sscanf(value, "%u", &trunk_ref->ring_delay) != 1) {
4641 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
4642 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
4643 trunk_ref->ring_delay = 0;
4645 } else {
4646 ast_log(LOG_WARNING, "Invalid option '%s' for "
4647 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
4651 if (!(station_ref = sla_create_station_ref(station))) {
4652 free(trunk_ref);
4653 return;
4655 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
4656 AST_RWLIST_WRLOCK(&sla_trunks);
4657 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
4658 AST_RWLIST_UNLOCK(&sla_trunks);
4659 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
4662 static int sla_build_station(struct ast_config *cfg, const char *cat)
4664 struct sla_station *station;
4665 struct ast_variable *var;
4666 const char *dev;
4668 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
4669 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
4670 return -1;
4673 if (!(station = ast_calloc(1, sizeof(*station))))
4674 return -1;
4675 if (ast_string_field_init(station, 32)) {
4676 free(station);
4677 return -1;
4680 ast_string_field_set(station, name, cat);
4681 ast_string_field_set(station, device, dev);
4683 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
4684 if (!strcasecmp(var->name, "trunk"))
4685 sla_add_trunk_to_station(station, var);
4686 else if (!strcasecmp(var->name, "autocontext"))
4687 ast_string_field_set(station, autocontext, var->value);
4688 else if (!strcasecmp(var->name, "ringtimeout")) {
4689 if (sscanf(var->value, "%u", &station->ring_timeout) != 1) {
4690 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
4691 var->value, station->name);
4692 station->ring_timeout = 0;
4694 } else if (!strcasecmp(var->name, "ringdelay")) {
4695 if (sscanf(var->value, "%u", &station->ring_delay) != 1) {
4696 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
4697 var->value, station->name);
4698 station->ring_delay = 0;
4700 } else if (!strcasecmp(var->name, "hold")) {
4701 if (!strcasecmp(var->value, "private"))
4702 station->hold_access = SLA_HOLD_PRIVATE;
4703 else if (!strcasecmp(var->value, "open"))
4704 station->hold_access = SLA_HOLD_OPEN;
4705 else {
4706 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
4707 var->value, station->name);
4710 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
4711 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
4712 var->name, var->lineno, SLA_CONFIG_FILE);
4716 if (!ast_strlen_zero(station->autocontext)) {
4717 struct ast_context *context;
4718 struct sla_trunk_ref *trunk_ref;
4719 context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
4720 if (!context) {
4721 ast_log(LOG_ERROR, "Failed to automatically find or create "
4722 "context '%s' for SLA!\n", station->autocontext);
4723 destroy_station(station);
4724 return -1;
4726 /* The extension for when the handset goes off-hook.
4727 * exten => station1,1,SLAStation(station1) */
4728 if (ast_add_extension2(context, 0 /* don't replace */, station->name, 1,
4729 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free, sla_registrar)) {
4730 ast_log(LOG_ERROR, "Failed to automatically create extension "
4731 "for trunk '%s'!\n", station->name);
4732 destroy_station(station);
4733 return -1;
4735 AST_RWLIST_RDLOCK(&sla_trunks);
4736 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
4737 char exten[AST_MAX_EXTENSION];
4738 char hint[AST_MAX_APP];
4739 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
4740 snprintf(hint, sizeof(hint), "SLA:%s", exten);
4741 /* Extension for this line button
4742 * exten => station1_line1,1,SLAStation(station1_line1) */
4743 if (ast_add_extension2(context, 0 /* don't replace */, exten, 1,
4744 NULL, NULL, slastation_app, ast_strdup(exten), ast_free, sla_registrar)) {
4745 ast_log(LOG_ERROR, "Failed to automatically create extension "
4746 "for trunk '%s'!\n", station->name);
4747 destroy_station(station);
4748 return -1;
4750 /* Hint for this line button
4751 * exten => station1_line1,hint,SLA:station1_line1 */
4752 if (ast_add_extension2(context, 0 /* don't replace */, exten, PRIORITY_HINT,
4753 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
4754 ast_log(LOG_ERROR, "Failed to automatically create hint "
4755 "for trunk '%s'!\n", station->name);
4756 destroy_station(station);
4757 return -1;
4760 AST_RWLIST_UNLOCK(&sla_trunks);
4763 AST_RWLIST_WRLOCK(&sla_stations);
4764 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
4765 AST_RWLIST_UNLOCK(&sla_stations);
4767 return 0;
4770 static int sla_load_config(void)
4772 struct ast_config *cfg;
4773 const char *cat = NULL;
4774 int res = 0;
4775 const char *val;
4777 ast_mutex_init(&sla.lock);
4778 ast_cond_init(&sla.cond, NULL);
4780 if (!(cfg = ast_config_load(SLA_CONFIG_FILE)))
4781 return 0; /* Treat no config as normal */
4783 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
4784 sla.attempt_callerid = ast_true(val);
4786 while ((cat = ast_category_browse(cfg, cat)) && !res) {
4787 const char *type;
4788 if (!strcasecmp(cat, "general"))
4789 continue;
4790 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
4791 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
4792 SLA_CONFIG_FILE);
4793 continue;
4795 if (!strcasecmp(type, "trunk"))
4796 res = sla_build_trunk(cfg, cat);
4797 else if (!strcasecmp(type, "station"))
4798 res = sla_build_station(cfg, cat);
4799 else {
4800 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
4801 SLA_CONFIG_FILE, type);
4805 ast_config_destroy(cfg);
4807 if (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations))
4808 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
4810 return res;
4813 static int load_config(int reload)
4815 int res = 0;
4817 load_config_meetme();
4818 if (!reload)
4819 res = sla_load_config();
4821 return res;
4824 static int unload_module(void)
4826 int res = 0;
4828 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
4829 res = ast_manager_unregister("MeetmeMute");
4830 res |= ast_manager_unregister("MeetmeUnmute");
4831 res |= ast_unregister_application(app3);
4832 res |= ast_unregister_application(app2);
4833 res |= ast_unregister_application(app);
4834 res |= ast_unregister_application(slastation_app);
4835 res |= ast_unregister_application(slatrunk_app);
4837 ast_devstate_prov_del("Meetme");
4838 ast_devstate_prov_del("SLA");
4840 ast_module_user_hangup_all();
4842 sla_destroy();
4844 return res;
4847 static int load_module(void)
4849 int res = 0;
4851 res |= load_config(0);
4853 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
4854 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
4855 action_meetmemute, "Mute a Meetme user");
4856 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
4857 action_meetmeunmute, "Unmute a Meetme user");
4858 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
4859 res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
4860 res |= ast_register_application(app, conf_exec, synopsis, descrip);
4861 res |= ast_register_application(slastation_app, sla_station_exec,
4862 slastation_synopsis, slastation_desc);
4863 res |= ast_register_application(slatrunk_app, sla_trunk_exec,
4864 slatrunk_synopsis, slatrunk_desc);
4866 res |= ast_devstate_prov_add("Meetme", meetmestate);
4867 res |= ast_devstate_prov_add("SLA", sla_state);
4869 return res;
4872 static int reload(void)
4874 return load_config(1);
4877 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
4878 .load = load_module,
4879 .unload = unload_module,
4880 .reload = reload,