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.
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
33 <depend>zaptel</depend>
38 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
45 #include <sys/ioctl.h>
46 #include <zaptel/zaptel.h>
48 #include "asterisk/lock.h"
49 #include "asterisk/file.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/module.h"
54 #include "asterisk/config.h"
55 #include "asterisk/app.h"
56 #include "asterisk/dsp.h"
57 #include "asterisk/musiconhold.h"
58 #include "asterisk/manager.h"
59 #include "asterisk/options.h"
60 #include "asterisk/cli.h"
61 #include "asterisk/say.h"
62 #include "asterisk/utils.h"
63 #include "asterisk/translate.h"
64 #include "asterisk/ulaw.h"
65 #include "asterisk/astobj.h"
66 #include "asterisk/devicestate.h"
67 #include "asterisk/dial.h"
68 #include "asterisk/causes.h"
73 #define CONFIG_FILE_NAME "meetme.conf"
74 #define SLA_CONFIG_FILE "sla.conf"
76 /*! each buffer is 20ms, so this is 640ms total */
77 #define DEFAULT_AUDIO_BUFFERS 32
80 ADMINFLAG_MUTED
= (1 << 1), /*!< User is muted */
81 ADMINFLAG_SELFMUTED
= (1 << 2), /*!< User muted self */
82 ADMINFLAG_KICKME
= (1 << 3) /*!< User has been kicked */
85 #define MEETME_DELAYDETECTTALK 300
86 #define MEETME_DELAYDETECTENDTALK 1000
88 #define AST_FRAME_BITS 32
100 enum recording_state
{
102 MEETME_RECORD_STARTED
,
103 MEETME_RECORD_ACTIVE
,
104 MEETME_RECORD_TERMINATE
107 #define CONF_SIZE 320
110 /*! user has admin access on the conference */
111 CONFFLAG_ADMIN
= (1 << 0),
112 /*! If set the user can only receive audio from the conference */
113 CONFFLAG_MONITOR
= (1 << 1),
114 /*! If set asterisk will exit conference when '#' is pressed */
115 CONFFLAG_POUNDEXIT
= (1 << 2),
116 /*! If set asterisk will provide a menu to the user when '*' is pressed */
117 CONFFLAG_STARMENU
= (1 << 3),
118 /*! If set the use can only send audio to the conference */
119 CONFFLAG_TALKER
= (1 << 4),
120 /*! If set there will be no enter or leave sounds */
121 CONFFLAG_QUIET
= (1 << 5),
122 /*! If set, when user joins the conference, they will be told the number
123 * of users that are already in */
124 CONFFLAG_ANNOUNCEUSERCOUNT
= (1 << 6),
125 /*! Set to run AGI Script in Background */
126 CONFFLAG_AGI
= (1 << 7),
127 /*! Set to have music on hold when user is alone in conference */
128 CONFFLAG_MOH
= (1 << 8),
129 /*! If set the MeetMe will return if all marked with this flag left */
130 CONFFLAG_MARKEDEXIT
= (1 << 9),
131 /*! If set, the MeetMe will wait until a marked user enters */
132 CONFFLAG_WAITMARKED
= (1 << 10),
133 /*! If set, the MeetMe will exit to the specified context */
134 CONFFLAG_EXIT_CONTEXT
= (1 << 11),
135 /*! If set, the user will be marked */
136 CONFFLAG_MARKEDUSER
= (1 << 12),
137 /*! If set, user will be ask record name on entry of conference */
138 CONFFLAG_INTROUSER
= (1 << 13),
139 /*! If set, the MeetMe will be recorded */
140 CONFFLAG_RECORDCONF
= (1<< 14),
141 /*! If set, the user will be monitored if the user is talking or not */
142 CONFFLAG_MONITORTALKER
= (1 << 15),
143 CONFFLAG_DYNAMIC
= (1 << 16),
144 CONFFLAG_DYNAMICPIN
= (1 << 17),
145 CONFFLAG_EMPTY
= (1 << 18),
146 CONFFLAG_EMPTYNOPIN
= (1 << 19),
147 CONFFLAG_ALWAYSPROMPT
= (1 << 20),
148 /*! If set, treats talking users as muted users */
149 CONFFLAG_OPTIMIZETALKER
= (1 << 21),
150 /*! If set, won't speak the extra prompt when the first person
151 * enters the conference */
152 CONFFLAG_NOONLYPERSON
= (1 << 22),
153 /*! If set, user will be asked to record name on entry of conference
155 CONFFLAG_INTROUSERNOREVIEW
= (1 << 23),
156 /*! If set, the user will be initially self-muted */
157 CONFFLAG_STARTMUTED
= (1 << 24),
158 /*! Pass DTMF through the conference */
159 CONFFLAG_PASS_DTMF
= (1 << 25),
160 /*! This is a SLA station. (Only for use by the SLA applications.) */
161 CONFFLAG_SLA_STATION
= (1 << 26),
162 /*! This is a SLA trunk. (Only for use by the SLA applications.) */
163 CONFFLAG_SLA_TRUNK
= (1 << 27),
167 OPT_ARG_WAITMARKED
= 0,
168 OPT_ARG_ARRAY_SIZE
= 1,
171 AST_APP_OPTIONS(meetme_opts
, BEGIN_OPTIONS
172 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER
),
173 AST_APP_OPTION('a', CONFFLAG_ADMIN
),
174 AST_APP_OPTION('b', CONFFLAG_AGI
),
175 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT
),
176 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN
),
177 AST_APP_OPTION('d', CONFFLAG_DYNAMIC
),
178 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN
),
179 AST_APP_OPTION('e', CONFFLAG_EMPTY
),
180 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF
),
181 AST_APP_OPTION('i', CONFFLAG_INTROUSER
),
182 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW
),
183 AST_APP_OPTION('M', CONFFLAG_MOH
),
184 AST_APP_OPTION('m', CONFFLAG_STARTMUTED
),
185 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER
),
186 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT
),
187 AST_APP_OPTION('p', CONFFLAG_POUNDEXIT
),
188 AST_APP_OPTION('q', CONFFLAG_QUIET
),
189 AST_APP_OPTION('r', CONFFLAG_RECORDCONF
),
190 AST_APP_OPTION('s', CONFFLAG_STARMENU
),
191 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER
),
192 AST_APP_OPTION('l', CONFFLAG_MONITOR
),
193 AST_APP_OPTION('t', CONFFLAG_TALKER
),
194 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED
, OPT_ARG_WAITMARKED
),
195 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT
),
196 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT
),
197 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON
),
200 static const char *app
= "MeetMe";
201 static const char *app2
= "MeetMeCount";
202 static const char *app3
= "MeetMeAdmin";
203 static const char *slastation_app
= "SLAStation";
204 static const char *slatrunk_app
= "SLATrunk";
206 static const char *synopsis
= "MeetMe conference bridge";
207 static const char *synopsis2
= "MeetMe participant count";
208 static const char *synopsis3
= "MeetMe conference Administration";
209 static const char *slastation_synopsis
= "Shared Line Appearance Station";
210 static const char *slatrunk_synopsis
= "Shared Line Appearance Trunk";
212 static const char *descrip
=
213 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
214 "conference. If the conference number is omitted, the user will be prompted\n"
215 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
216 "is specified, by pressing '#'.\n"
217 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
218 " must be present for conferencing to operate properly. In addition, the chan_zap\n"
219 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
220 "The option string may contain zero or more of the following characters:\n"
221 " 'a' -- set admin mode\n"
222 " 'A' -- set marked mode\n"
223 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
224 " Default: conf-background.agi (Note: This does not work with\n"
225 " non-Zap channels in the same conference)\n"
226 " 'c' -- announce user(s) count on joining a conference\n"
227 " 'd' -- dynamically add conference\n"
228 " 'D' -- dynamically add conference, prompting for a PIN\n"
229 " 'e' -- select an empty conference\n"
230 " 'E' -- select an empty pinless conference\n"
231 " 'F' -- Pass DTMF through the conference.\n"
232 " 'i' -- announce user join/leave with review\n"
233 " 'I' -- announce user join/leave without review\n"
234 " 'l' -- set listen only mode (Listen only, no talking)\n"
235 " 'm' -- set initially muted\n"
236 " 'M' -- enable music on hold when the conference has a single caller\n"
237 " 'o' -- set talker optimization - treats talkers who aren't speaking as\n"
238 " being muted, meaning (a) No encode is done on transmission and\n"
239 " (b) Received audio that is not registered as talking is omitted\n"
240 " causing no buildup in background noise. Note that this option\n"
241 " will be removed in 1.6 and enabled by default.\n"
242 " 'p' -- allow user to exit the conference by pressing '#'\n"
243 " 'P' -- always prompt for the pin even if it is specified\n"
244 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
245 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
246 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
247 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
249 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
250 " 't' -- set talk only mode. (Talk only, no listening)\n"
251 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
253 " -- wait until the marked user enters the conference\n"
254 " 'x' -- close the conference when last marked user exits\n"
255 " 'X' -- allow user to exit the conference by entering a valid single\n"
256 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
257 " if that variable is not defined.\n"
258 " '1' -- do not play message when first person enters\n";
260 static const char *descrip2
=
261 " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
262 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
263 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
264 "the channel, unless priority n+1 exists, in which case priority progress will\n"
266 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
268 static const char *descrip3
=
269 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
270 " 'e' -- Eject last user that joined\n"
271 " 'k' -- Kick one user out of conference\n"
272 " 'K' -- Kick all users out of conference\n"
273 " 'l' -- Unlock conference\n"
274 " 'L' -- Lock conference\n"
275 " 'm' -- Unmute one user\n"
276 " 'M' -- Mute one user\n"
277 " 'n' -- Unmute all users in the conference\n"
278 " 'N' -- Mute all non-admin users in the conference\n"
279 " 'r' -- Reset one user's volume settings\n"
280 " 'R' -- Reset all users volume settings\n"
281 " 's' -- Lower entire conference speaking volume\n"
282 " 'S' -- Raise entire conference speaking volume\n"
283 " 't' -- Lower one user's talk volume\n"
284 " 'T' -- Raise one user's talk volume\n"
285 " 'u' -- Lower one user's listen volume\n"
286 " 'U' -- Raise one user's listen volume\n"
287 " 'v' -- Lower entire conference listening volume\n"
288 " 'V' -- Raise entire conference listening volume\n"
291 static const char *slastation_desc
=
292 " SLAStation(station):\n"
293 "This application should be executed by an SLA station. The argument depends\n"
294 "on how the call was initiated. If the phone was just taken off hook, then\n"
295 "the argument \"station\" should be just the station name. If the call was\n"
296 "initiated by pressing a line key, then the station name should be preceded\n"
297 "by an underscore and the trunk name associated with that line button.\n"
298 "For example: \"station1_line1\"."
299 " On exit, this application will set the variable SLASTATION_STATUS to\n"
300 "one of the following values:\n"
301 " FAILURE | CONGESTION | SUCCESS\n"
304 static const char *slatrunk_desc
=
305 " SLATrunk(trunk):\n"
306 "This application should be executed by an SLA trunk on an inbound call.\n"
307 "The channel calling this application should correspond to the SLA trunk\n"
308 "with the name \"trunk\" that is being passed as an argument.\n"
309 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
310 "one of the following values:\n"
311 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
314 #define MAX_CONFNUM 80
317 /*! \brief The MeetMe Conference object */
318 struct ast_conference
{
319 ast_mutex_t playlock
; /*!< Conference specific lock (players) */
320 ast_mutex_t listenlock
; /*!< Conference specific lock (listeners) */
321 char confno
[MAX_CONFNUM
]; /*!< Conference */
322 struct ast_channel
*chan
; /*!< Announcements channel */
323 struct ast_channel
*lchan
; /*!< Listen/Record channel */
324 int fd
; /*!< Announcements fd */
325 int zapconf
; /*!< Zaptel Conf # */
326 int users
; /*!< Number of active users */
327 int markedusers
; /*!< Number of marked users */
328 time_t start
; /*!< Start time (s) */
329 int refcount
; /*!< reference count of usage */
330 enum recording_state recording
:2; /*!< recording status */
331 unsigned int isdynamic
:1; /*!< Created on the fly? */
332 unsigned int locked
:1; /*!< Is the conference locked? */
333 pthread_t recordthread
; /*!< thread for recording */
334 ast_mutex_t recordthreadlock
; /*!< control threads trying to start recordthread */
335 pthread_attr_t attr
; /*!< thread attribute */
336 const char *recordingfilename
; /*!< Filename to record the Conference into */
337 const char *recordingformat
; /*!< Format to record the Conference in */
338 char pin
[MAX_PIN
]; /*!< If protected by a PIN */
339 char pinadmin
[MAX_PIN
]; /*!< If protected by a admin PIN */
340 struct ast_frame
*transframe
[32];
341 struct ast_frame
*origframe
;
342 struct ast_trans_pvt
*transpath
[32];
343 AST_LIST_HEAD_NOLOCK(, ast_conf_user
) userlist
;
344 AST_LIST_ENTRY(ast_conference
) list
;
347 static AST_LIST_HEAD_STATIC(confs
, ast_conference
);
349 static unsigned int conf_map
[1024] = {0, };
352 int desired
; /*!< Desired volume adjustment */
353 int actual
; /*!< Actual volume adjustment (for channels that can't adjust) */
356 struct ast_conf_user
{
357 int user_no
; /*!< User Number */
358 int userflags
; /*!< Flags as set in the conference */
359 int adminflags
; /*!< Flags set by the Admin */
360 struct ast_channel
*chan
; /*!< Connected channel */
361 int talking
; /*!< Is user talking */
362 int zapchannel
; /*!< Is a Zaptel channel */
363 char usrvalue
[50]; /*!< Custom User Value */
364 char namerecloc
[PATH_MAX
]; /*!< Name Recorded file Location */
365 time_t jointime
; /*!< Time the user joined the conference */
367 struct volume listen
;
368 AST_LIST_ENTRY(ast_conf_user
) list
;
371 enum sla_which_trunk_refs
{
376 enum sla_trunk_state
{
377 SLA_TRUNK_STATE_IDLE
,
378 SLA_TRUNK_STATE_RINGING
,
380 SLA_TRUNK_STATE_ONHOLD
,
381 SLA_TRUNK_STATE_ONHOLD_BYME
,
384 enum sla_hold_access
{
385 /*! This means that any station can put it on hold, and any station
386 * can retrieve the call from hold. */
388 /*! This means that only the station that put the call on hold may
389 * retrieve it from hold. */
393 struct sla_trunk_ref
;
396 AST_RWLIST_ENTRY(sla_station
) entry
;
397 AST_DECLARE_STRING_FIELDS(
398 AST_STRING_FIELD(name
);
399 AST_STRING_FIELD(device
);
400 AST_STRING_FIELD(autocontext
);
402 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref
) trunks
;
403 struct ast_dial
*dial
;
404 /*! Ring timeout for this station, for any trunk. If a ring timeout
405 * is set for a specific trunk on this station, that will take
406 * priority over this value. */
407 unsigned int ring_timeout
;
408 /*! Ring delay for this station, for any trunk. If a ring delay
409 * is set for a specific trunk on this station, that will take
410 * priority over this value. */
411 unsigned int ring_delay
;
412 /*! This option uses the values in the sla_hold_access enum and sets the
413 * access control type for hold on this station. */
414 unsigned int hold_access
:1;
417 struct sla_station_ref
{
418 AST_LIST_ENTRY(sla_station_ref
) entry
;
419 struct sla_station
*station
;
423 AST_RWLIST_ENTRY(sla_trunk
) entry
;
424 AST_DECLARE_STRING_FIELDS(
425 AST_STRING_FIELD(name
);
426 AST_STRING_FIELD(device
);
427 AST_STRING_FIELD(autocontext
);
429 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) stations
;
430 /*! Number of stations that use this trunk */
431 unsigned int num_stations
;
432 /*! Number of stations currently on a call with this trunk */
433 unsigned int active_stations
;
434 /*! Number of stations that have this trunk on hold. */
435 unsigned int hold_stations
;
436 struct ast_channel
*chan
;
437 unsigned int ring_timeout
;
438 /*! If set to 1, no station will be able to join an active call with
440 unsigned int barge_disabled
:1;
441 /*! This option uses the values in the sla_hold_access enum and sets the
442 * access control type for hold on this trunk. */
443 unsigned int hold_access
:1;
444 /*! Whether this trunk is currently on hold, meaning that once a station
445 * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
446 unsigned int on_hold
:1;
449 struct sla_trunk_ref
{
450 AST_LIST_ENTRY(sla_trunk_ref
) entry
;
451 struct sla_trunk
*trunk
;
452 enum sla_trunk_state state
;
453 struct ast_channel
*chan
;
454 /*! Ring timeout to use when this trunk is ringing on this specific
455 * station. This takes higher priority than a ring timeout set at
456 * the station level. */
457 unsigned int ring_timeout
;
458 /*! Ring delay to use when this trunk is ringing on this specific
459 * station. This takes higher priority than a ring delay set at
460 * the station level. */
461 unsigned int ring_delay
;
464 static AST_RWLIST_HEAD_STATIC(sla_stations
, sla_station
);
465 static AST_RWLIST_HEAD_STATIC(sla_trunks
, sla_trunk
);
467 static const char sla_registrar
[] = "SLA";
469 /*! \brief Event types that can be queued up for the SLA thread */
470 enum sla_event_type
{
471 /*! A station has put the call on hold */
473 /*! The state of a dial has changed */
474 SLA_EVENT_DIAL_STATE
,
475 /*! The state of a ringing trunk has changed */
476 SLA_EVENT_RINGING_TRUNK
,
480 enum sla_event_type type
;
481 struct sla_station
*station
;
482 struct sla_trunk_ref
*trunk_ref
;
483 AST_LIST_ENTRY(sla_event
) entry
;
486 /*! \brief A station that failed to be dialed
487 * \note Only used by the SLA thread. */
488 struct sla_failed_station
{
489 struct sla_station
*station
;
490 struct timeval last_try
;
491 AST_LIST_ENTRY(sla_failed_station
) entry
;
494 /*! \brief A trunk that is ringing */
495 struct sla_ringing_trunk
{
496 struct sla_trunk
*trunk
;
497 /*! The time that this trunk started ringing */
498 struct timeval ring_begin
;
499 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) timed_out_stations
;
500 AST_LIST_ENTRY(sla_ringing_trunk
) entry
;
503 enum sla_station_hangup
{
504 SLA_STATION_HANGUP_NORMAL
,
505 SLA_STATION_HANGUP_TIMEOUT
,
508 /*! \brief A station that is ringing */
509 struct sla_ringing_station
{
510 struct sla_station
*station
;
511 /*! The time that this station started ringing */
512 struct timeval ring_begin
;
513 AST_LIST_ENTRY(sla_ringing_station
) entry
;
517 * \brief A structure for data used by the sla thread
520 /*! The SLA thread ID */
524 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk
) ringing_trunks
;
525 AST_LIST_HEAD_NOLOCK(, sla_ringing_station
) ringing_stations
;
526 AST_LIST_HEAD_NOLOCK(, sla_failed_station
) failed_stations
;
527 AST_LIST_HEAD_NOLOCK(, sla_event
) event_q
;
529 /*! Attempt to handle CallerID, even though it is known not to work
530 * properly in some situations. */
531 unsigned int attempt_callerid
:1;
533 .thread
= AST_PTHREADT_NULL
,
536 /*! The number of audio buffers to be allocated on pseudo channels
537 * when in a conference */
538 static int audio_buffers
;
540 /*! Map 'volume' levels from -5 through +5 into
541 * decibel (dB) settings for channel drivers
542 * Note: these are not a straight linear-to-dB
543 * conversion... the numbers have been modified
544 * to give the user a better level of adjustability
546 static char const gain_map
[] = {
561 static int admin_exec(struct ast_channel
*chan
, void *data
);
562 static void *recordthread(void *args
);
564 static char *istalking(int x
)
569 return "(unmonitored)";
571 return "(not talking)";
574 static int careful_write(int fd
, unsigned char *data
, int len
, int block
)
581 x
= ZT_IOMUX_WRITE
| ZT_IOMUX_SIGEVENT
;
582 res
= ioctl(fd
, ZT_IOMUX
, &x
);
586 res
= write(fd
, data
, len
);
588 if (errno
!= EAGAIN
) {
589 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
601 static int set_talk_volume(struct ast_conf_user
*user
, int volume
)
605 /* attempt to make the adjustment in the channel driver;
606 if successful, don't adjust in the frame reading routine
608 gain_adjust
= gain_map
[volume
+ 5];
610 return ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
613 static int set_listen_volume(struct ast_conf_user
*user
, int volume
)
617 /* attempt to make the adjustment in the channel driver;
618 if successful, don't adjust in the frame reading routine
620 gain_adjust
= gain_map
[volume
+ 5];
622 return ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
625 static void tweak_volume(struct volume
*vol
, enum volume_action action
)
629 switch (vol
->desired
) {
644 switch (vol
->desired
) {
660 static void tweak_talk_volume(struct ast_conf_user
*user
, enum volume_action action
)
662 tweak_volume(&user
->talk
, action
);
663 /* attempt to make the adjustment in the channel driver;
664 if successful, don't adjust in the frame reading routine
666 if (!set_talk_volume(user
, user
->talk
.desired
))
667 user
->talk
.actual
= 0;
669 user
->talk
.actual
= user
->talk
.desired
;
672 static void tweak_listen_volume(struct ast_conf_user
*user
, enum volume_action action
)
674 tweak_volume(&user
->listen
, action
);
675 /* attempt to make the adjustment in the channel driver;
676 if successful, don't adjust in the frame reading routine
678 if (!set_listen_volume(user
, user
->listen
.desired
))
679 user
->listen
.actual
= 0;
681 user
->listen
.actual
= user
->listen
.desired
;
684 static void reset_volumes(struct ast_conf_user
*user
)
686 signed char zero_volume
= 0;
688 ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
689 ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
692 static void conf_play(struct ast_channel
*chan
, struct ast_conference
*conf
, enum entrance_sound sound
)
698 if (!chan
->_softhangup
)
699 res
= ast_autoservice_start(chan
);
701 AST_LIST_LOCK(&confs
);
717 careful_write(conf
->fd
, data
, len
, 1);
720 AST_LIST_UNLOCK(&confs
);
723 ast_autoservice_stop(chan
);
727 * \brief Find or create a conference
729 * \param confno The conference name/number
730 * \param pin The regular user pin
731 * \param pinadmin The admin pin
732 * \param make Make the conf if it doesn't exist
733 * \param dynamic Mark the newly created conference as dynamic
734 * \param refcount How many references to mark on the conference
736 * \return A pointer to the conference struct, or NULL if it wasn't found and
737 * make or dynamic were not set.
739 static struct ast_conference
*build_conf(char *confno
, char *pin
, char *pinadmin
, int make
, int dynamic
, int refcount
)
741 struct ast_conference
*cnf
;
742 struct zt_confinfo ztc
= { 0, };
745 AST_LIST_LOCK(&confs
);
747 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
748 if (!strcmp(confno
, cnf
->confno
))
752 if (cnf
|| (!make
&& !dynamic
))
756 if (!(cnf
= ast_calloc(1, sizeof(*cnf
))))
759 ast_mutex_init(&cnf
->playlock
);
760 ast_mutex_init(&cnf
->listenlock
);
761 cnf
->recordthread
= AST_PTHREADT_NULL
;
762 ast_mutex_init(&cnf
->recordthreadlock
);
763 ast_copy_string(cnf
->confno
, confno
, sizeof(cnf
->confno
));
764 ast_copy_string(cnf
->pin
, pin
, sizeof(cnf
->pin
));
765 ast_copy_string(cnf
->pinadmin
, pinadmin
, sizeof(cnf
->pinadmin
));
767 /* Setup a new zap conference */
769 ztc
.confmode
= ZT_CONF_CONFANN
| ZT_CONF_CONFANNMON
;
770 cnf
->fd
= open("/dev/zap/pseudo", O_RDWR
);
771 if (cnf
->fd
< 0 || ioctl(cnf
->fd
, ZT_SETCONF
, &ztc
)) {
772 ast_log(LOG_WARNING
, "Unable to open pseudo device\n");
780 cnf
->zapconf
= ztc
.confno
;
782 /* Setup a new channel for playback of audio files */
783 cnf
->chan
= ast_request("zap", AST_FORMAT_SLINEAR
, "pseudo", NULL
);
785 ast_set_read_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
786 ast_set_write_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
788 ztc
.confno
= cnf
->zapconf
;
789 ztc
.confmode
= ZT_CONF_CONFANN
| ZT_CONF_CONFANNMON
;
790 if (ioctl(cnf
->chan
->fds
[0], ZT_SETCONF
, &ztc
)) {
791 ast_log(LOG_WARNING
, "Error setting conference\n");
793 ast_hangup(cnf
->chan
);
802 /* Fill the conference struct */
803 cnf
->start
= time(NULL
);
804 cnf
->isdynamic
= dynamic
? 1 : 0;
805 if (option_verbose
> 2)
806 ast_verbose(VERBOSE_PREFIX_3
"Created MeetMe conference %d for conference '%s'\n", cnf
->zapconf
, cnf
->confno
);
807 AST_LIST_INSERT_HEAD(&confs
, cnf
, list
);
809 /* Reserve conference number in map */
810 if ((sscanf(cnf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
811 conf_map
[confno_int
] = 1;
815 ast_atomic_fetchadd_int(&cnf
->refcount
, refcount
);
817 AST_LIST_UNLOCK(&confs
);
822 static int meetme_cmd(int fd
, int argc
, char **argv
)
824 /* Process the command */
825 struct ast_conference
*cnf
;
826 struct ast_conf_user
*user
;
828 int i
= 0, total
= 0;
830 char *header_format
= "%-14s %-14s %-10s %-8s %-8s\n";
831 char *data_format
= "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
832 char cmdline
[1024] = "";
835 ast_cli(fd
, "Invalid Arguments.\n");
836 /* Check for length so no buffer will overflow... */
837 for (i
= 0; i
< argc
; i
++) {
838 if (strlen(argv
[i
]) > 100)
839 ast_cli(fd
, "Invalid Arguments.\n");
842 /* 'MeetMe': List all the conferences */
844 AST_LIST_LOCK(&confs
);
845 if (AST_LIST_EMPTY(&confs
)) {
846 ast_cli(fd
, "No active MeetMe conferences.\n");
847 AST_LIST_UNLOCK(&confs
);
848 return RESULT_SUCCESS
;
850 ast_cli(fd
, header_format
, "Conf Num", "Parties", "Marked", "Activity", "Creation");
851 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
852 if (cnf
->markedusers
== 0)
853 strcpy(cmdline
, "N/A ");
855 snprintf(cmdline
, sizeof(cmdline
), "%4.4d", cnf
->markedusers
);
856 hr
= (now
- cnf
->start
) / 3600;
857 min
= ((now
- cnf
->start
) % 3600) / 60;
858 sec
= (now
- cnf
->start
) % 60;
860 ast_cli(fd
, data_format
, cnf
->confno
, cnf
->users
, cmdline
, hr
, min
, sec
, cnf
->isdynamic
? "Dynamic" : "Static");
864 AST_LIST_UNLOCK(&confs
);
865 ast_cli(fd
, "* Total number of MeetMe users: %d\n", total
);
866 return RESULT_SUCCESS
;
869 return RESULT_SHOWUSAGE
;
870 ast_copy_string(cmdline
, argv
[2], sizeof(cmdline
)); /* Argv 2: conference number */
871 if (strstr(argv
[1], "lock")) {
872 if (strcmp(argv
[1], "lock") == 0) {
874 strncat(cmdline
, "|L", sizeof(cmdline
) - strlen(cmdline
) - 1);
877 strncat(cmdline
, "|l", sizeof(cmdline
) - strlen(cmdline
) - 1);
879 } else if (strstr(argv
[1], "mute")) {
881 return RESULT_SHOWUSAGE
;
882 if (strcmp(argv
[1], "mute") == 0) {
884 if (strcmp(argv
[3], "all") == 0) {
885 strncat(cmdline
, "|N", sizeof(cmdline
) - strlen(cmdline
) - 1);
887 strncat(cmdline
, "|M|", sizeof(cmdline
) - strlen(cmdline
) - 1);
888 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
892 if (strcmp(argv
[3], "all") == 0) {
893 strncat(cmdline
, "|n", sizeof(cmdline
) - strlen(cmdline
) - 1);
895 strncat(cmdline
, "|m|", sizeof(cmdline
) - strlen(cmdline
) - 1);
896 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
899 } else if (strcmp(argv
[1], "kick") == 0) {
901 return RESULT_SHOWUSAGE
;
902 if (strcmp(argv
[3], "all") == 0) {
904 strncat(cmdline
, "|K", sizeof(cmdline
) - strlen(cmdline
) - 1);
906 /* Kick a single user */
907 strncat(cmdline
, "|k|", sizeof(cmdline
) - strlen(cmdline
) - 1);
908 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
910 } else if(strcmp(argv
[1], "list") == 0) {
911 int concise
= ( 4 == argc
&& ( !strcasecmp(argv
[3], "concise") ) );
912 /* List all the users in a conference */
913 if (AST_LIST_EMPTY(&confs
)) {
915 ast_cli(fd
, "No active conferences.\n");
916 return RESULT_SUCCESS
;
918 /* Find the right conference */
919 AST_LIST_LOCK(&confs
);
920 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
921 if (strcmp(cnf
->confno
, argv
[2]) == 0)
926 ast_cli(fd
, "No such conference: %s.\n",argv
[2]);
927 AST_LIST_UNLOCK(&confs
);
928 return RESULT_SUCCESS
;
930 /* Show all the users */
932 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
933 hr
= (now
- user
->jointime
) / 3600;
934 min
= ((now
- user
->jointime
) % 3600) / 60;
935 sec
= (now
- user
->jointime
) % 60;
937 ast_cli(fd
, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
939 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
940 S_OR(user
->chan
->cid
.cid_name
, "<no name>"),
942 user
->userflags
& CONFFLAG_ADMIN
? "(Admin)" : "",
943 user
->userflags
& CONFFLAG_MONITOR
? "(Listen only)" : "",
944 user
->adminflags
& ADMINFLAG_MUTED
? "(Admin Muted)" : user
->adminflags
& ADMINFLAG_SELFMUTED
? "(Muted)" : "",
945 istalking(user
->talking
), hr
, min
, sec
);
947 ast_cli(fd
, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
949 S_OR(user
->chan
->cid
.cid_num
, ""),
950 S_OR(user
->chan
->cid
.cid_name
, ""),
952 user
->userflags
& CONFFLAG_ADMIN
? "1" : "",
953 user
->userflags
& CONFFLAG_MONITOR
? "1" : "",
954 user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
) ? "1" : "",
955 user
->talking
, hr
, min
, sec
);
959 ast_cli(fd
,"%d users in that conference.\n",cnf
->users
);
960 AST_LIST_UNLOCK(&confs
);
961 return RESULT_SUCCESS
;
963 return RESULT_SHOWUSAGE
;
964 ast_log(LOG_DEBUG
, "Cmdline: %s\n", cmdline
);
965 admin_exec(NULL
, cmdline
);
970 static char *complete_meetmecmd(const char *line
, const char *word
, int pos
, int state
)
972 static char *cmds
[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL
};
974 int len
= strlen(word
);
976 struct ast_conference
*cnf
= NULL
;
977 struct ast_conf_user
*usr
= NULL
;
980 char *myline
, *ret
= NULL
;
982 if (pos
== 1) { /* Command */
983 return ast_cli_complete(word
, cmds
, state
);
984 } else if (pos
== 2) { /* Conference Number */
985 AST_LIST_LOCK(&confs
);
986 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
987 if (!strncasecmp(word
, cnf
->confno
, len
) && ++which
> state
) {
992 ret
= ast_strdup(ret
); /* dup before releasing the lock */
993 AST_LIST_UNLOCK(&confs
);
995 } else if (pos
== 3) {
996 /* User Number || Conf Command option*/
997 if (strstr(line
, "mute") || strstr(line
, "kick")) {
998 if (state
== 0 && (strstr(line
, "kick") || strstr(line
,"mute")) && !strncasecmp(word
, "all", len
))
999 return strdup("all");
1001 AST_LIST_LOCK(&confs
);
1003 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
1004 myline
= ast_strdupa(line
);
1005 if (strsep(&myline
, " ") && strsep(&myline
, " ") && !confno
) {
1006 while((confno
= strsep(&myline
, " ")) && (strcmp(confno
, " ") == 0))
1010 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
1011 if (!strcmp(confno
, cnf
->confno
))
1016 /* Search for the user */
1017 AST_LIST_TRAVERSE(&cnf
->userlist
, usr
, list
) {
1018 snprintf(usrno
, sizeof(usrno
), "%d", usr
->user_no
);
1019 if (!strncasecmp(word
, usrno
, len
) && ++which
> state
)
1023 AST_LIST_UNLOCK(&confs
);
1024 return usr
? strdup(usrno
) : NULL
;
1025 } else if ( strstr(line
, "list") && ( 0 == state
) )
1026 return strdup("concise");
1032 static char meetme_usage
[] =
1033 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
1034 " Executes a command for the conference or on a conferee\n";
1036 static const char *sla_hold_str(unsigned int hold_access
)
1038 const char *hold
= "Unknown";
1040 switch (hold_access
) {
1044 case SLA_HOLD_PRIVATE
:
1053 static int sla_show_trunks(int fd
, int argc
, char **argv
)
1055 const struct sla_trunk
*trunk
;
1058 "=============================================================\n"
1059 "=== Configured SLA Trunks ===================================\n"
1060 "=============================================================\n"
1062 AST_RWLIST_RDLOCK(&sla_trunks
);
1063 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
1064 struct sla_station_ref
*station_ref
;
1065 char ring_timeout
[16] = "(none)";
1066 if (trunk
->ring_timeout
)
1067 snprintf(ring_timeout
, sizeof(ring_timeout
), "%u Seconds", trunk
->ring_timeout
);
1068 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1069 "=== Trunk Name: %s\n"
1070 "=== ==> Device: %s\n"
1071 "=== ==> AutoContext: %s\n"
1072 "=== ==> RingTimeout: %s\n"
1073 "=== ==> BargeAllowed: %s\n"
1074 "=== ==> HoldAccess: %s\n"
1075 "=== ==> Stations ...\n",
1076 trunk
->name
, trunk
->device
,
1077 S_OR(trunk
->autocontext
, "(none)"),
1079 trunk
->barge_disabled
? "No" : "Yes",
1080 sla_hold_str(trunk
->hold_access
));
1081 AST_RWLIST_RDLOCK(&sla_stations
);
1082 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
)
1083 ast_cli(fd
, "=== ==> Station name: %s\n", station_ref
->station
->name
);
1084 AST_RWLIST_UNLOCK(&sla_stations
);
1085 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1088 AST_RWLIST_UNLOCK(&sla_trunks
);
1089 ast_cli(fd
, "=============================================================\n"
1092 return RESULT_SUCCESS
;
1095 static const char *trunkstate2str(enum sla_trunk_state state
)
1097 #define S(e) case e: return # e;
1099 S(SLA_TRUNK_STATE_IDLE
)
1100 S(SLA_TRUNK_STATE_RINGING
)
1101 S(SLA_TRUNK_STATE_UP
)
1102 S(SLA_TRUNK_STATE_ONHOLD
)
1103 S(SLA_TRUNK_STATE_ONHOLD_BYME
)
1105 return "Uknown State";
1109 static const char sla_show_trunks_usage
[] =
1110 "Usage: sla show trunks\n"
1111 " This will list all trunks defined in sla.conf\n";
1113 static int sla_show_stations(int fd
, int argc
, char **argv
)
1115 const struct sla_station
*station
;
1118 "=============================================================\n"
1119 "=== Configured SLA Stations =================================\n"
1120 "=============================================================\n"
1122 AST_RWLIST_RDLOCK(&sla_stations
);
1123 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1124 struct sla_trunk_ref
*trunk_ref
;
1125 char ring_timeout
[16] = "(none)";
1126 char ring_delay
[16] = "(none)";
1127 if (station
->ring_timeout
) {
1128 snprintf(ring_timeout
, sizeof(ring_timeout
),
1129 "%u", station
->ring_timeout
);
1131 if (station
->ring_delay
) {
1132 snprintf(ring_delay
, sizeof(ring_delay
),
1133 "%u", station
->ring_delay
);
1135 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1136 "=== Station Name: %s\n"
1137 "=== ==> Device: %s\n"
1138 "=== ==> AutoContext: %s\n"
1139 "=== ==> RingTimeout: %s\n"
1140 "=== ==> RingDelay: %s\n"
1141 "=== ==> HoldAccess: %s\n"
1142 "=== ==> Trunks ...\n",
1143 station
->name
, station
->device
,
1144 S_OR(station
->autocontext
, "(none)"),
1145 ring_timeout
, ring_delay
,
1146 sla_hold_str(station
->hold_access
));
1147 AST_RWLIST_RDLOCK(&sla_trunks
);
1148 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1149 if (trunk_ref
->ring_timeout
) {
1150 snprintf(ring_timeout
, sizeof(ring_timeout
),
1151 "%u", trunk_ref
->ring_timeout
);
1153 strcpy(ring_timeout
, "(none)");
1154 if (trunk_ref
->ring_delay
) {
1155 snprintf(ring_delay
, sizeof(ring_delay
),
1156 "%u", trunk_ref
->ring_delay
);
1158 strcpy(ring_delay
, "(none)");
1159 ast_cli(fd
, "=== ==> Trunk Name: %s\n"
1160 "=== ==> State: %s\n"
1161 "=== ==> RingTimeout: %s\n"
1162 "=== ==> RingDelay: %s\n",
1163 trunk_ref
->trunk
->name
,
1164 trunkstate2str(trunk_ref
->state
),
1165 ring_timeout
, ring_delay
);
1167 AST_RWLIST_UNLOCK(&sla_trunks
);
1168 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1171 AST_RWLIST_UNLOCK(&sla_stations
);
1172 ast_cli(fd
, "============================================================\n"
1175 return RESULT_SUCCESS
;
1178 static const char sla_show_stations_usage
[] =
1179 "Usage: sla show stations\n"
1180 " This will list all stations defined in sla.conf\n";
1182 static struct ast_cli_entry cli_meetme
[] = {
1183 { { "meetme", NULL
, NULL
},
1184 meetme_cmd
, "Execute a command on a conference or conferee",
1185 meetme_usage
, complete_meetmecmd
},
1187 { { "sla", "show", "trunks", NULL
},
1188 sla_show_trunks
, "Show SLA Trunks",
1189 sla_show_trunks_usage
, NULL
},
1191 { { "sla", "show", "stations", NULL
},
1192 sla_show_stations
, "Show SLA Stations",
1193 sla_show_stations_usage
, NULL
},
1196 static void conf_flush(int fd
, struct ast_channel
*chan
)
1200 /* read any frames that may be waiting on the channel
1204 struct ast_frame
*f
;
1206 /* when no frames are available, this will wait
1207 for 1 millisecond maximum
1209 while (ast_waitfor(chan
, 1)) {
1213 else /* channel was hung up or something else happened */
1218 /* flush any data sitting in the pseudo channel */
1220 if (ioctl(fd
, ZT_FLUSH
, &x
))
1221 ast_log(LOG_WARNING
, "Error flushing channel\n");
1225 /* Remove the conference from the list and free it.
1226 We assume that this was called while holding conflock. */
1227 static int conf_free(struct ast_conference
*conf
)
1231 AST_LIST_REMOVE(&confs
, conf
, list
);
1233 if (conf
->recording
== MEETME_RECORD_ACTIVE
) {
1234 conf
->recording
= MEETME_RECORD_TERMINATE
;
1235 AST_LIST_UNLOCK(&confs
);
1238 AST_LIST_LOCK(&confs
);
1239 if (conf
->recording
== MEETME_RECORD_OFF
)
1241 AST_LIST_UNLOCK(&confs
);
1245 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
1246 if (conf
->transframe
[x
])
1247 ast_frfree(conf
->transframe
[x
]);
1248 if (conf
->transpath
[x
])
1249 ast_translator_free_path(conf
->transpath
[x
]);
1251 if (conf
->origframe
)
1252 ast_frfree(conf
->origframe
);
1254 ast_hangup(conf
->lchan
);
1256 ast_hangup(conf
->chan
);
1260 ast_mutex_destroy(&conf
->playlock
);
1261 ast_mutex_destroy(&conf
->listenlock
);
1262 ast_mutex_destroy(&conf
->recordthreadlock
);
1268 static void conf_queue_dtmf(const struct ast_conference
*conf
,
1269 const struct ast_conf_user
*sender
, struct ast_frame
*f
)
1271 struct ast_conf_user
*user
;
1273 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
1276 if (ast_write(user
->chan
, f
) < 0)
1277 ast_log(LOG_WARNING
, "Error writing frame to channel %s\n", user
->chan
->name
);
1281 static void sla_queue_event_full(enum sla_event_type type
,
1282 struct sla_trunk_ref
*trunk_ref
, struct sla_station
*station
, int lock
)
1284 struct sla_event
*event
;
1286 if (!(event
= ast_calloc(1, sizeof(*event
))))
1290 event
->trunk_ref
= trunk_ref
;
1291 event
->station
= station
;
1294 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1298 ast_mutex_lock(&sla
.lock
);
1299 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1300 ast_cond_signal(&sla
.cond
);
1301 ast_mutex_unlock(&sla
.lock
);
1304 static void sla_queue_event_nolock(enum sla_event_type type
)
1306 sla_queue_event_full(type
, NULL
, NULL
, 0);
1309 static void sla_queue_event(enum sla_event_type type
)
1311 sla_queue_event_full(type
, NULL
, NULL
, 1);
1314 /*! \brief Queue a SLA event from the conference */
1315 static void sla_queue_event_conf(enum sla_event_type type
, struct ast_channel
*chan
,
1316 struct ast_conference
*conf
)
1318 struct sla_station
*station
;
1319 struct sla_trunk_ref
*trunk_ref
= NULL
;
1322 trunk_name
= ast_strdupa(conf
->confno
);
1323 strsep(&trunk_name
, "_");
1324 if (ast_strlen_zero(trunk_name
)) {
1325 ast_log(LOG_ERROR
, "Invalid conference name for SLA - '%s'!\n", conf
->confno
);
1329 AST_RWLIST_RDLOCK(&sla_stations
);
1330 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1331 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1332 if (trunk_ref
->chan
== chan
&& !strcmp(trunk_ref
->trunk
->name
, trunk_name
))
1338 AST_RWLIST_UNLOCK(&sla_stations
);
1341 ast_log(LOG_DEBUG
, "Trunk not found for event!\n");
1345 sla_queue_event_full(type
, trunk_ref
, station
, 1);
1348 /* Decrement reference counts, as incremented by find_conf() */
1349 static int dispose_conf(struct ast_conference
*conf
)
1354 AST_LIST_LOCK(&confs
);
1355 if (ast_atomic_dec_and_test(&conf
->refcount
)) {
1356 /* Take the conference room number out of an inuse state */
1357 if ((sscanf(conf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
1358 conf_map
[confno_int
] = 0;
1362 AST_LIST_UNLOCK(&confs
);
1368 static int conf_run(struct ast_channel
*chan
, struct ast_conference
*conf
, int confflags
, char *optargs
[])
1370 struct ast_conf_user
*user
= NULL
;
1371 struct ast_conf_user
*usr
= NULL
;
1373 struct zt_confinfo ztc
, ztc_empty
;
1374 struct ast_frame
*f
;
1375 struct ast_channel
*c
;
1376 struct ast_frame fr
;
1384 int musiconhold
= 0;
1387 int currentmarked
= 0;
1390 int menu_active
= 0;
1391 int using_pseudo
= 0;
1396 struct ast_dsp
*dsp
=NULL
;
1397 struct ast_app
*app
;
1398 const char *agifile
;
1399 const char *agifiledefault
= "conf-background.agi";
1400 char meetmesecs
[30] = "";
1401 char exitcontext
[AST_MAX_CONTEXT
] = "";
1402 char recordingtmp
[AST_MAX_EXTENSION
] = "";
1403 char members
[10] = "";
1404 int dtmf
, opt_waitmarked_timeout
= 0;
1407 char __buf
[CONF_SIZE
+ AST_FRIENDLY_OFFSET
];
1408 char *buf
= __buf
+ AST_FRIENDLY_OFFSET
;
1410 if (!(user
= ast_calloc(1, sizeof(*user
))))
1413 /* Possible timeout waiting for marked user */
1414 if ((confflags
& CONFFLAG_WAITMARKED
) &&
1415 !ast_strlen_zero(optargs
[OPT_ARG_WAITMARKED
]) &&
1416 (sscanf(optargs
[OPT_ARG_WAITMARKED
], "%d", &opt_waitmarked_timeout
) == 1) &&
1417 (opt_waitmarked_timeout
> 0)) {
1418 timeout
= time(NULL
) + opt_waitmarked_timeout
;
1421 if (confflags
& CONFFLAG_RECORDCONF
) {
1422 if (!conf
->recordingfilename
) {
1423 conf
->recordingfilename
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFILE");
1424 if (!conf
->recordingfilename
) {
1425 snprintf(recordingtmp
, sizeof(recordingtmp
), "meetme-conf-rec-%s-%s", conf
->confno
, chan
->uniqueid
);
1426 conf
->recordingfilename
= ast_strdupa(recordingtmp
);
1428 conf
->recordingformat
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFORMAT");
1429 if (!conf
->recordingformat
) {
1430 snprintf(recordingtmp
, sizeof(recordingtmp
), "wav");
1431 conf
->recordingformat
= ast_strdupa(recordingtmp
);
1433 ast_verbose(VERBOSE_PREFIX_4
"Starting recording of MeetMe Conference %s into file %s.%s.\n",
1434 conf
->confno
, conf
->recordingfilename
, conf
->recordingformat
);
1438 ast_mutex_lock(&conf
->recordthreadlock
);
1439 if ((conf
->recordthread
== AST_PTHREADT_NULL
) && (confflags
& CONFFLAG_RECORDCONF
) && ((conf
->lchan
= ast_request("zap", AST_FORMAT_SLINEAR
, "pseudo", NULL
)))) {
1440 ast_set_read_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1441 ast_set_write_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1443 ztc
.confno
= conf
->zapconf
;
1444 ztc
.confmode
= ZT_CONF_CONFANN
| ZT_CONF_CONFANNMON
;
1445 if (ioctl(conf
->lchan
->fds
[0], ZT_SETCONF
, &ztc
)) {
1446 ast_log(LOG_WARNING
, "Error starting listen channel\n");
1447 ast_hangup(conf
->lchan
);
1450 pthread_attr_init(&conf
->attr
);
1451 pthread_attr_setdetachstate(&conf
->attr
, PTHREAD_CREATE_DETACHED
);
1452 ast_pthread_create_background(&conf
->recordthread
, &conf
->attr
, recordthread
, conf
);
1453 pthread_attr_destroy(&conf
->attr
);
1456 ast_mutex_unlock(&conf
->recordthreadlock
);
1458 time(&user
->jointime
);
1460 if (conf
->locked
&& (!(confflags
& CONFFLAG_ADMIN
))) {
1461 /* Sorry, but this confernce is locked! */
1462 if (!ast_streamfile(chan
, "conf-locked", chan
->language
))
1463 ast_waitstream(chan
, "");
1467 if (confflags
& CONFFLAG_MARKEDUSER
)
1468 conf
->markedusers
++;
1470 ast_mutex_lock(&conf
->playlock
);
1472 if (AST_LIST_EMPTY(&conf
->userlist
))
1475 user
->user_no
= AST_LIST_LAST(&conf
->userlist
)->user_no
+ 1;
1477 AST_LIST_INSERT_TAIL(&conf
->userlist
, user
, list
);
1480 user
->userflags
= confflags
;
1481 user
->adminflags
= (confflags
& CONFFLAG_STARTMUTED
) ? ADMINFLAG_SELFMUTED
: 0;
1485 snprintf(members
, sizeof(members
), "%d", conf
->users
);
1486 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
1488 /* This device changed state now - if this is the first user */
1489 if (conf
->users
== 1)
1490 ast_device_state_changed("meetme:%s", conf
->confno
);
1492 ast_mutex_unlock(&conf
->playlock
);
1494 if (confflags
& CONFFLAG_EXIT_CONTEXT
) {
1495 if ((agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_EXIT_CONTEXT")))
1496 ast_copy_string(exitcontext
, agifile
, sizeof(exitcontext
));
1497 else if (!ast_strlen_zero(chan
->macrocontext
))
1498 ast_copy_string(exitcontext
, chan
->macrocontext
, sizeof(exitcontext
));
1500 ast_copy_string(exitcontext
, chan
->context
, sizeof(exitcontext
));
1503 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
1504 snprintf(user
->namerecloc
, sizeof(user
->namerecloc
),
1505 "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR
,
1506 conf
->confno
, user
->user_no
);
1507 if (confflags
& CONFFLAG_INTROUSERNOREVIEW
)
1508 res
= ast_play_and_record(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, 128, 0, NULL
);
1510 res
= ast_record_review(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, NULL
);
1515 if ( !(confflags
& (CONFFLAG_QUIET
| CONFFLAG_NOONLYPERSON
)) ) {
1516 if (conf
->users
== 1 && !(confflags
& CONFFLAG_WAITMARKED
))
1517 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1518 ast_waitstream(chan
, "");
1519 if ((confflags
& CONFFLAG_WAITMARKED
) && conf
->markedusers
== 0)
1520 if (!ast_streamfile(chan
, "conf-waitforleader", chan
->language
))
1521 ast_waitstream(chan
, "");
1524 if (!(confflags
& CONFFLAG_QUIET
) && (confflags
& CONFFLAG_ANNOUNCEUSERCOUNT
) && conf
->users
> 1) {
1525 int keepplaying
= 1;
1527 if (conf
->users
== 2) {
1528 if (!ast_streamfile(chan
,"conf-onlyone",chan
->language
)) {
1529 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1530 ast_stopstream(chan
);
1537 if (!ast_streamfile(chan
, "conf-thereare", chan
->language
)) {
1538 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1539 ast_stopstream(chan
);
1546 res
= ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1552 if (keepplaying
&& !ast_streamfile(chan
, "conf-otherinparty", chan
->language
)) {
1553 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1554 ast_stopstream(chan
);
1563 ast_indicate(chan
, -1);
1565 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1566 ast_log(LOG_WARNING
, "Unable to set '%s' to write linear mode\n", chan
->name
);
1570 if (ast_set_read_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1571 ast_log(LOG_WARNING
, "Unable to set '%s' to read linear mode\n", chan
->name
);
1575 retryzap
= (strcasecmp(chan
->tech
->type
, "Zap") || chan
->spies
? 1 : 0);
1576 user
->zapchannel
= !retryzap
;
1579 origfd
= chan
->fds
[0];
1581 fd
= open("/dev/zap/pseudo", O_RDWR
);
1583 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
1587 /* Make non-blocking */
1588 flags
= fcntl(fd
, F_GETFL
);
1590 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
1594 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
1595 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
1599 /* Setup buffering information */
1600 memset(&bi
, 0, sizeof(bi
));
1601 bi
.bufsize
= CONF_SIZE
/2;
1602 bi
.txbufpolicy
= ZT_POLICY_IMMEDIATE
;
1603 bi
.rxbufpolicy
= ZT_POLICY_IMMEDIATE
;
1604 bi
.numbufs
= audio_buffers
;
1605 if (ioctl(fd
, ZT_SET_BUFINFO
, &bi
)) {
1606 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
1611 if (ioctl(fd
, ZT_SETLINEAR
, &x
)) {
1612 ast_log(LOG_WARNING
, "Unable to set linear mode: %s\n", strerror(errno
));
1618 /* XXX Make sure we're not running on a pseudo channel XXX */
1622 memset(&ztc
, 0, sizeof(ztc
));
1623 memset(&ztc_empty
, 0, sizeof(ztc_empty
));
1624 /* Check to see if we're in a conference... */
1626 if (ioctl(fd
, ZT_GETCONF
, &ztc
)) {
1627 ast_log(LOG_WARNING
, "Error getting conference\n");
1632 /* Whoa, already in a conference... Retry... */
1634 ast_log(LOG_DEBUG
, "Zap channel is in a conference already, retrying with pseudo\n");
1639 memset(&ztc
, 0, sizeof(ztc
));
1640 /* Add us to the conference */
1642 ztc
.confno
= conf
->zapconf
;
1644 ast_mutex_lock(&conf
->playlock
);
1646 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
)) && conf
->users
> 1) {
1647 if (conf
->chan
&& ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
1648 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
1649 ast_waitstream(conf
->chan
, "");
1650 if (!ast_streamfile(conf
->chan
, "conf-hasjoin", chan
->language
))
1651 ast_waitstream(conf
->chan
, "");
1655 if (confflags
& CONFFLAG_MONITOR
)
1656 ztc
.confmode
= ZT_CONF_CONFMON
| ZT_CONF_LISTENER
;
1657 else if (confflags
& CONFFLAG_TALKER
)
1658 ztc
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
;
1660 ztc
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
;
1662 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
1663 ast_log(LOG_WARNING
, "Error setting conference\n");
1665 ast_mutex_unlock(&conf
->playlock
);
1668 ast_log(LOG_DEBUG
, "Placed channel %s in ZAP conf %d\n", chan
->name
, conf
->zapconf
);
1671 manager_event(EVENT_FLAG_CALL
, "MeetmeJoin",
1676 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1680 if (!firstpass
&& !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
)) {
1682 if (!(confflags
& CONFFLAG_QUIET
))
1683 if (!(confflags
& CONFFLAG_WAITMARKED
) || ((confflags
& CONFFLAG_MARKEDUSER
) && (conf
->markedusers
>= 1)))
1684 conf_play(chan
, conf
, ENTER
);
1687 ast_mutex_unlock(&conf
->playlock
);
1689 conf_flush(fd
, chan
);
1691 if (confflags
& CONFFLAG_AGI
) {
1692 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1693 or use default filename of conf-background.agi */
1695 agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_AGI_BACKGROUND");
1697 agifile
= agifiledefault
;
1699 if (user
->zapchannel
) {
1700 /* Set CONFMUTE mode on Zap channel to mute DTMF tones */
1702 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1704 /* Find a pointer to the agi app and execute the script */
1705 app
= pbx_findapp("agi");
1707 char *s
= ast_strdupa(agifile
);
1708 ret
= pbx_exec(chan
, app
, s
);
1710 ast_log(LOG_WARNING
, "Could not find application (agi)\n");
1713 if (user
->zapchannel
) {
1714 /* Remove CONFMUTE mode on Zap channel */
1716 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1719 if (user
->zapchannel
&& (confflags
& CONFFLAG_STARMENU
)) {
1720 /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1722 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1724 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
) && !(dsp
= ast_dsp_new())) {
1725 ast_log(LOG_WARNING
, "Unable to allocate DSP!\n");
1729 int menu_was_active
= 0;
1734 if (timeout
&& time(NULL
) >= timeout
)
1737 /* if we have just exited from the menu, and the user had a channel-driver
1738 volume adjustment, restore it
1740 if (!menu_active
&& menu_was_active
&& user
->listen
.desired
&& !user
->listen
.actual
)
1741 set_talk_volume(user
, user
->listen
.desired
);
1743 menu_was_active
= menu_active
;
1745 currentmarked
= conf
->markedusers
;
1746 if (!(confflags
& CONFFLAG_QUIET
) &&
1747 (confflags
& CONFFLAG_MARKEDUSER
) &&
1748 (confflags
& CONFFLAG_WAITMARKED
) &&
1750 if (currentmarked
== 1 && conf
->users
> 1) {
1751 ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1752 if (conf
->users
- 1 == 1) {
1753 if (!ast_streamfile(chan
, "conf-userwilljoin", chan
->language
))
1754 ast_waitstream(chan
, "");
1756 if (!ast_streamfile(chan
, "conf-userswilljoin", chan
->language
))
1757 ast_waitstream(chan
, "");
1760 if (conf
->users
== 1 && ! (confflags
& CONFFLAG_MARKEDUSER
))
1761 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1762 ast_waitstream(chan
, "");
1765 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
1768 /* Update the struct with the actual confflags */
1769 user
->userflags
= confflags
;
1771 if (confflags
& CONFFLAG_WAITMARKED
) {
1772 if(currentmarked
== 0) {
1773 if (lastmarked
!= 0) {
1774 if (!(confflags
& CONFFLAG_QUIET
))
1775 if (!ast_streamfile(chan
, "conf-leaderhasleft", chan
->language
))
1776 ast_waitstream(chan
, "");
1777 if(confflags
& CONFFLAG_MARKEDEXIT
)
1780 ztc
.confmode
= ZT_CONF_CONF
;
1781 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
1782 ast_log(LOG_WARNING
, "Error setting conference\n");
1788 if (musiconhold
== 0 && (confflags
& CONFFLAG_MOH
)) {
1789 ast_moh_start(chan
, NULL
, NULL
);
1792 } else if(currentmarked
>= 1 && lastmarked
== 0) {
1793 /* Marked user entered, so cancel timeout */
1795 if (confflags
& CONFFLAG_MONITOR
)
1796 ztc
.confmode
= ZT_CONF_CONFMON
| ZT_CONF_LISTENER
;
1797 else if (confflags
& CONFFLAG_TALKER
)
1798 ztc
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
;
1800 ztc
.confmode
= ZT_CONF_CONF
| ZT_CONF_TALKER
| ZT_CONF_LISTENER
;
1801 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
1802 ast_log(LOG_WARNING
, "Error setting conference\n");
1806 if (musiconhold
&& (confflags
& CONFFLAG_MOH
)) {
1810 if ( !(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MARKEDUSER
)) {
1811 if (!ast_streamfile(chan
, "conf-placeintoconf", chan
->language
))
1812 ast_waitstream(chan
, "");
1813 conf_play(chan
, conf
, ENTER
);
1818 /* trying to add moh for single person conf */
1819 if ((confflags
& CONFFLAG_MOH
) && !(confflags
& CONFFLAG_WAITMARKED
)) {
1820 if (conf
->users
== 1) {
1821 if (musiconhold
== 0) {
1822 ast_moh_start(chan
, NULL
, NULL
);
1833 /* Leave if the last marked user left */
1834 if (currentmarked
== 0 && lastmarked
!= 0 && (confflags
& CONFFLAG_MARKEDEXIT
)) {
1839 /* Check if my modes have changed */
1841 /* If I should be muted but am still talker, mute me */
1842 if ((user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && (ztc
.confmode
& ZT_CONF_TALKER
)) {
1843 ztc
.confmode
^= ZT_CONF_TALKER
;
1844 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
1845 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1850 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1856 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1859 /* If I should be un-muted but am not talker, un-mute me */
1860 if (!(user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && !(confflags
& CONFFLAG_MONITOR
) && !(ztc
.confmode
& ZT_CONF_TALKER
)) {
1861 ztc
.confmode
|= ZT_CONF_TALKER
;
1862 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
1863 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1868 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1874 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1877 /* If I have been kicked, exit the conference */
1878 if (user
->adminflags
& ADMINFLAG_KICKME
) {
1879 //You have been kicked.
1880 if (!(confflags
& CONFFLAG_QUIET
) &&
1881 !ast_streamfile(chan
, "conf-kicked", chan
->language
)) {
1882 ast_waitstream(chan
, "");
1888 /* Perform an extra hangup check just in case */
1889 if (ast_check_hangup(chan
))
1893 if (c
->fds
[0] != origfd
|| (user
->zapchannel
&& c
->spies
)) {
1895 /* Kill old pseudo */
1899 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
1900 retryzap
= (strcasecmp(c
->tech
->type
, "Zap") || c
->spies
? 1 : 0);
1901 user
->zapchannel
= !retryzap
;
1904 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)))
1905 f
= ast_read_noaudio(c
);
1910 if ((f
->frametype
== AST_FRAME_VOICE
) && (f
->subclass
== AST_FORMAT_SLINEAR
)) {
1911 if (user
->talk
.actual
)
1912 ast_frame_adjust_volume(f
, user
->talk
.actual
);
1914 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
)) {
1917 if (user
->talking
== -1)
1920 res
= ast_dsp_silence(dsp
, f
, &totalsilence
);
1921 if (!user
->talking
&& totalsilence
< MEETME_DELAYDETECTTALK
) {
1923 if (confflags
& CONFFLAG_MONITORTALKER
)
1924 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1930 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1932 if (user
->talking
&& totalsilence
> MEETME_DELAYDETECTENDTALK
) {
1934 if (confflags
& CONFFLAG_MONITORTALKER
)
1935 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1941 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1945 /* Absolutely do _not_ use careful_write here...
1946 it is important that we read data from the channel
1947 as fast as it arrives, and feed it into the conference.
1948 The buffering in the pseudo channel will take care of any
1949 timing differences, unless they are so drastic as to lose
1950 audio frames (in which case carefully writing would only
1951 have delayed the audio even further).
1953 /* As it turns out, we do want to use careful write. We just
1954 don't want to block, but we do want to at least *try*
1955 to write out all the samples.
1957 if (user
->talking
|| !(confflags
& CONFFLAG_OPTIMIZETALKER
))
1958 careful_write(fd
, f
->data
, f
->datalen
, 0);
1960 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (confflags
& CONFFLAG_EXIT_CONTEXT
)) {
1963 if (confflags
& CONFFLAG_PASS_DTMF
)
1964 conf_queue_dtmf(conf
, user
, f
);
1966 tmp
[0] = f
->subclass
;
1968 if (!ast_goto_if_exists(chan
, exitcontext
, tmp
, 1)) {
1969 ast_log(LOG_DEBUG
, "Got DTMF %c, goto context %s\n", tmp
[0], exitcontext
);
1973 } else if (option_debug
> 1)
1974 ast_log(LOG_DEBUG
, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp
, exitcontext
);
1975 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '#') && (confflags
& CONFFLAG_POUNDEXIT
)) {
1976 if (confflags
& CONFFLAG_PASS_DTMF
)
1977 conf_queue_dtmf(conf
, user
, f
);
1981 } else if (((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*') && (confflags
& CONFFLAG_STARMENU
)) || ((f
->frametype
== AST_FRAME_DTMF
) && menu_active
)) {
1982 if (confflags
& CONFFLAG_PASS_DTMF
)
1983 conf_queue_dtmf(conf
, user
, f
);
1984 if (ioctl(fd
, ZT_SETCONF
, &ztc_empty
)) {
1985 ast_log(LOG_WARNING
, "Error setting conference\n");
1991 /* if we are entering the menu, and the user has a channel-driver
1992 volume adjustment, clear it
1994 if (!menu_active
&& user
->talk
.desired
&& !user
->talk
.actual
)
1995 set_talk_volume(user
, 0);
2000 if ((confflags
& CONFFLAG_ADMIN
)) {
2004 /* Record this sound! */
2005 if (!ast_streamfile(chan
, "conf-adminmenu", chan
->language
)) {
2006 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2007 ast_stopstream(chan
);
2014 case '1': /* Un/Mute */
2017 /* for admin, change both admin and use flags */
2018 if (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))
2019 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2021 user
->adminflags
|= (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2023 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2024 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2025 ast_waitstream(chan
, "");
2027 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2028 ast_waitstream(chan
, "");
2031 case '2': /* Un/Lock the Conference */
2035 if (!ast_streamfile(chan
, "conf-unlockednow", chan
->language
))
2036 ast_waitstream(chan
, "");
2039 if (!ast_streamfile(chan
, "conf-lockednow", chan
->language
))
2040 ast_waitstream(chan
, "");
2043 case '3': /* Eject last user */
2045 usr
= AST_LIST_LAST(&conf
->userlist
);
2046 if ((usr
->chan
->name
== chan
->name
)||(usr
->userflags
& CONFFLAG_ADMIN
)) {
2047 if(!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2048 ast_waitstream(chan
, "");
2050 usr
->adminflags
|= ADMINFLAG_KICKME
;
2051 ast_stopstream(chan
);
2054 tweak_listen_volume(user
, VOL_DOWN
);
2057 tweak_listen_volume(user
, VOL_UP
);
2060 tweak_talk_volume(user
, VOL_DOWN
);
2066 tweak_talk_volume(user
, VOL_UP
);
2070 /* Play an error message! */
2071 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2072 ast_waitstream(chan
, "");
2080 if (!ast_streamfile(chan
, "conf-usermenu", chan
->language
)) {
2081 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2082 ast_stopstream(chan
);
2089 case '1': /* Un/Mute */
2092 /* user can only toggle the self-muted state */
2093 user
->adminflags
^= ADMINFLAG_SELFMUTED
;
2095 /* they can't override the admin mute state */
2096 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2097 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2098 ast_waitstream(chan
, "");
2100 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2101 ast_waitstream(chan
, "");
2105 tweak_listen_volume(user
, VOL_DOWN
);
2108 tweak_listen_volume(user
, VOL_UP
);
2111 tweak_talk_volume(user
, VOL_DOWN
);
2117 tweak_talk_volume(user
, VOL_UP
);
2121 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2122 ast_waitstream(chan
, "");
2128 ast_moh_start(chan
, NULL
, NULL
);
2130 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
2131 ast_log(LOG_WARNING
, "Error setting conference\n");
2137 conf_flush(fd
, chan
);
2138 } else if ((f
->frametype
== AST_FRAME_DTMF_BEGIN
|| f
->frametype
== AST_FRAME_DTMF_END
)
2139 && confflags
& CONFFLAG_PASS_DTMF
) {
2140 conf_queue_dtmf(conf
, user
, f
);
2141 } else if ((confflags
& CONFFLAG_SLA_STATION
) && f
->frametype
== AST_FRAME_CONTROL
) {
2142 switch (f
->subclass
) {
2143 case AST_CONTROL_HOLD
:
2144 sla_queue_event_conf(SLA_EVENT_HOLD
, chan
, conf
);
2149 } else if (f
->frametype
== AST_FRAME_NULL
) {
2150 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2151 } else if (option_debug
) {
2153 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2154 chan
->name
, f
->frametype
, f
->subclass
);
2157 } else if (outfd
> -1) {
2158 res
= read(outfd
, buf
, CONF_SIZE
);
2160 memset(&fr
, 0, sizeof(fr
));
2161 fr
.frametype
= AST_FRAME_VOICE
;
2162 fr
.subclass
= AST_FORMAT_SLINEAR
;
2166 fr
.offset
= AST_FRIENDLY_OFFSET
;
2167 if (!user
->listen
.actual
&&
2168 ((confflags
& CONFFLAG_MONITOR
) ||
2169 (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) ||
2170 (!user
->talking
&& (confflags
& CONFFLAG_OPTIMIZETALKER
))
2173 for (index
=0;index
<AST_FRAME_BITS
;index
++)
2174 if (chan
->rawwriteformat
& (1 << index
))
2176 if (index
>= AST_FRAME_BITS
)
2177 goto bailoutandtrynormal
;
2178 ast_mutex_lock(&conf
->listenlock
);
2179 if (!conf
->transframe
[index
]) {
2180 if (conf
->origframe
) {
2181 if (!conf
->transpath
[index
])
2182 conf
->transpath
[index
] = ast_translator_build_path((1 << index
), AST_FORMAT_SLINEAR
);
2183 if (conf
->transpath
[index
]) {
2184 conf
->transframe
[index
] = ast_translate(conf
->transpath
[index
], conf
->origframe
, 0);
2185 if (!conf
->transframe
[index
])
2186 conf
->transframe
[index
] = &ast_null_frame
;
2190 if (conf
->transframe
[index
]) {
2191 if (conf
->transframe
[index
]->frametype
!= AST_FRAME_NULL
) {
2192 if (ast_write(chan
, conf
->transframe
[index
]))
2193 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2196 ast_mutex_unlock(&conf
->listenlock
);
2197 goto bailoutandtrynormal
;
2199 ast_mutex_unlock(&conf
->listenlock
);
2201 bailoutandtrynormal
:
2202 if (user
->listen
.actual
)
2203 ast_frame_adjust_volume(&fr
, user
->listen
.actual
);
2204 if (ast_write(chan
, &fr
) < 0) {
2205 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2209 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
2211 lastmarked
= currentmarked
;
2221 /* Take out of conference */
2225 if (ioctl(fd
, ZT_SETCONF
, &ztc
)) {
2226 ast_log(LOG_WARNING
, "Error setting conference\n");
2230 reset_volumes(user
);
2232 AST_LIST_LOCK(&confs
);
2233 if (!(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
))
2234 conf_play(chan
, conf
, LEAVE
);
2236 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
2237 if (ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
2238 if ((conf
->chan
) && (conf
->users
> 1)) {
2239 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
2240 ast_waitstream(conf
->chan
, "");
2241 if (!ast_streamfile(conf
->chan
, "conf-hasleft", chan
->language
))
2242 ast_waitstream(conf
->chan
, "");
2244 ast_filedelete(user
->namerecloc
, NULL
);
2247 AST_LIST_UNLOCK(&confs
);
2250 AST_LIST_LOCK(&confs
);
2255 if (user
->user_no
) { /* Only cleanup users who really joined! */
2257 hr
= (now
- user
->jointime
) / 3600;
2258 min
= ((now
- user
->jointime
) % 3600) / 60;
2259 sec
= (now
- user
->jointime
) % 60;
2262 manager_event(EVENT_FLAG_CALL
, "MeetmeLeave",
2267 "CallerIDnum: %s\r\n"
2268 "CallerIDname: %s\r\n"
2269 "Duration: %ld\r\n",
2270 chan
->name
, chan
->uniqueid
, conf
->confno
,
2272 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
2273 S_OR(user
->chan
->cid
.cid_name
, "<unknown>"),
2274 (long)(now
- user
->jointime
));
2279 snprintf(members
, sizeof(members
), "%d", conf
->users
);
2280 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
2281 if (confflags
& CONFFLAG_MARKEDUSER
)
2282 conf
->markedusers
--;
2283 /* Remove ourselves from the list */
2284 AST_LIST_REMOVE(&conf
->userlist
, user
, list
);
2286 /* Change any states */
2288 ast_device_state_changed("meetme:%s", conf
->confno
);
2290 /* Return the number of seconds the user was in the conf */
2291 snprintf(meetmesecs
, sizeof(meetmesecs
), "%d", (int) (time(NULL
) - user
->jointime
));
2292 pbx_builtin_setvar_helper(chan
, "MEETMESECS", meetmesecs
);
2295 AST_LIST_UNLOCK(&confs
);
2300 static struct ast_conference
*find_conf_realtime(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2301 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2303 struct ast_variable
*var
;
2304 struct ast_conference
*cnf
;
2306 /* Check first in the conference list */
2307 AST_LIST_LOCK(&confs
);
2308 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2309 if (!strcmp(confno
, cnf
->confno
))
2313 cnf
->refcount
+= refcount
;
2315 AST_LIST_UNLOCK(&confs
);
2318 char *pin
= NULL
, *pinadmin
= NULL
; /* For temp use */
2320 var
= ast_load_realtime("meetme", "confno", confno
, NULL
);
2326 if (!strcasecmp(var
->name
, "pin")) {
2327 pin
= ast_strdupa(var
->value
);
2328 } else if (!strcasecmp(var
->name
, "adminpin")) {
2329 pinadmin
= ast_strdupa(var
->value
);
2333 ast_variables_destroy(var
);
2335 cnf
= build_conf(confno
, pin
? pin
: "", pinadmin
? pinadmin
: "", make
, dynamic
, refcount
);
2339 if (confflags
&& !cnf
->chan
&&
2340 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2341 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2342 ast_log(LOG_WARNING
, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2343 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2346 if (confflags
&& !cnf
->chan
&&
2347 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2348 ast_log(LOG_WARNING
, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2349 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2357 static struct ast_conference
*find_conf(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2358 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2360 struct ast_config
*cfg
;
2361 struct ast_variable
*var
;
2362 struct ast_conference
*cnf
;
2364 AST_DECLARE_APP_ARGS(args
,
2365 AST_APP_ARG(confno
);
2367 AST_APP_ARG(pinadmin
);
2370 /* Check first in the conference list */
2371 AST_LIST_LOCK(&confs
);
2372 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2373 if (!strcmp(confno
, cnf
->confno
))
2377 cnf
->refcount
+= refcount
;
2379 AST_LIST_UNLOCK(&confs
);
2383 /* No need to parse meetme.conf */
2384 ast_log(LOG_DEBUG
, "Building dynamic conference '%s'\n", confno
);
2386 if (dynamic_pin
[0] == 'q') {
2387 /* Query the user to enter a PIN */
2388 if (ast_app_getdata(chan
, "conf-getpin", dynamic_pin
, pin_buf_len
- 1, 0) < 0)
2391 cnf
= build_conf(confno
, dynamic_pin
, "", make
, dynamic
, refcount
);
2393 cnf
= build_conf(confno
, "", "", make
, dynamic
, refcount
);
2396 /* Check the config */
2397 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2399 ast_log(LOG_WARNING
, "No %s file :(\n", CONFIG_FILE_NAME
);
2402 for (var
= ast_variable_browse(cfg
, "rooms"); var
; var
= var
->next
) {
2403 if (strcasecmp(var
->name
, "conf"))
2406 if (!(parse
= ast_strdupa(var
->value
)))
2409 AST_NONSTANDARD_APP_ARGS(args
, parse
, ',');
2410 if (!strcasecmp(args
.confno
, confno
)) {
2411 /* Bingo it's a valid conference */
2412 cnf
= build_conf(args
.confno
,
2414 S_OR(args
.pinadmin
, ""),
2415 make
, dynamic
, refcount
);
2420 ast_log(LOG_DEBUG
, "%s isn't a valid conference\n", confno
);
2422 ast_config_destroy(cfg
);
2424 } else if (dynamic_pin
) {
2425 /* Correct for the user selecting 'D' instead of 'd' to have
2426 someone join into a conference that has already been created
2428 if (dynamic_pin
[0] == 'q')
2429 dynamic_pin
[0] = '\0';
2433 if (confflags
&& !cnf
->chan
&&
2434 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2435 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2436 ast_log(LOG_WARNING
, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2437 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2440 if (confflags
&& !cnf
->chan
&&
2441 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2442 ast_log(LOG_WARNING
, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2443 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2450 /*! \brief The MeetmeCount application */
2451 static int count_exec(struct ast_channel
*chan
, void *data
)
2453 struct ast_module_user
*u
;
2455 struct ast_conference
*conf
;
2459 AST_DECLARE_APP_ARGS(args
,
2460 AST_APP_ARG(confno
);
2461 AST_APP_ARG(varname
);
2464 if (ast_strlen_zero(data
)) {
2465 ast_log(LOG_WARNING
, "MeetMeCount requires an argument (conference number)\n");
2469 u
= ast_module_user_add(chan
);
2471 if (!(localdata
= ast_strdupa(data
))) {
2472 ast_module_user_remove(u
);
2476 AST_STANDARD_APP_ARGS(args
, localdata
);
2478 conf
= find_conf(chan
, args
.confno
, 0, 0, NULL
, 0, 1, NULL
);
2481 count
= conf
->users
;
2487 if (!ast_strlen_zero(args
.varname
)){
2488 /* have var so load it and exit */
2489 snprintf(val
, sizeof(val
), "%d",count
);
2490 pbx_builtin_setvar_helper(chan
, args
.varname
, val
);
2492 if (chan
->_state
!= AST_STATE_UP
)
2494 res
= ast_say_number(chan
, count
, "", chan
->language
, (char *) NULL
); /* Needs gender */
2496 ast_module_user_remove(u
);
2501 /*! \brief The meetme() application */
2502 static int conf_exec(struct ast_channel
*chan
, void *data
)
2505 struct ast_module_user
*u
;
2506 char confno
[MAX_CONFNUM
] = "";
2509 struct ast_conference
*cnf
= NULL
;
2510 struct ast_flags confflags
= {0};
2512 int empty
= 0, empty_no_pin
= 0;
2513 int always_prompt
= 0;
2514 char *notdata
, *info
, the_pin
[MAX_PIN
] = "";
2515 AST_DECLARE_APP_ARGS(args
,
2516 AST_APP_ARG(confno
);
2517 AST_APP_ARG(options
);
2520 char *optargs
[OPT_ARG_ARRAY_SIZE
] = { NULL
, };
2522 u
= ast_module_user_add(chan
);
2524 if (ast_strlen_zero(data
)) {
2531 if (chan
->_state
!= AST_STATE_UP
)
2534 info
= ast_strdupa(notdata
);
2536 AST_STANDARD_APP_ARGS(args
, info
);
2539 ast_copy_string(confno
, args
.confno
, sizeof(confno
));
2540 if (ast_strlen_zero(confno
)) {
2546 ast_copy_string(the_pin
, args
.pin
, sizeof(the_pin
));
2549 ast_app_parse_options(meetme_opts
, &confflags
, optargs
, args
.options
);
2550 dynamic
= ast_test_flag(&confflags
, CONFFLAG_DYNAMIC
| CONFFLAG_DYNAMICPIN
);
2551 if (ast_test_flag(&confflags
, CONFFLAG_DYNAMICPIN
) && !args
.pin
)
2552 strcpy(the_pin
, "q");
2554 empty
= ast_test_flag(&confflags
, CONFFLAG_EMPTY
| CONFFLAG_EMPTYNOPIN
);
2555 empty_no_pin
= ast_test_flag(&confflags
, CONFFLAG_EMPTYNOPIN
);
2556 always_prompt
= ast_test_flag(&confflags
, CONFFLAG_ALWAYSPROMPT
);
2564 struct ast_config
*cfg
;
2565 struct ast_variable
*var
;
2568 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2569 if ((empty_no_pin
) || (!dynamic
)) {
2570 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2572 var
= ast_variable_browse(cfg
, "rooms");
2574 if (!strcasecmp(var
->name
, "conf")) {
2575 char *stringp
= ast_strdupa(var
->value
);
2577 char *confno_tmp
= strsep(&stringp
, "|,");
2580 /* For static: run through the list and see if this conference is empty */
2581 AST_LIST_LOCK(&confs
);
2582 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2583 if (!strcmp(confno_tmp
, cnf
->confno
)) {
2584 /* The conference exists, therefore it's not empty */
2589 AST_LIST_UNLOCK(&confs
);
2591 /* At this point, we have a confno_tmp (static conference) that is empty */
2592 if ((empty_no_pin
&& ast_strlen_zero(stringp
)) || (!empty_no_pin
)) {
2593 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
2594 * Case 2: empty_no_pin and pin is blank (but not NULL)
2595 * Case 3: not empty_no_pin
2597 ast_copy_string(confno
, confno_tmp
, sizeof(confno
));
2599 /* XXX the map is not complete (but we do have a confno) */
2607 ast_config_destroy(cfg
);
2611 /* Select first conference number not in use */
2612 if (ast_strlen_zero(confno
) && dynamic
) {
2613 AST_LIST_LOCK(&confs
);
2614 for (i
= 0; i
< sizeof(conf_map
) / sizeof(conf_map
[0]); i
++) {
2616 snprintf(confno
, sizeof(confno
), "%d", i
);
2621 AST_LIST_UNLOCK(&confs
);
2625 if (ast_strlen_zero(confno
)) {
2626 res
= ast_streamfile(chan
, "conf-noempty", chan
->language
);
2628 ast_waitstream(chan
, "");
2630 if (sscanf(confno
, "%d", &confno_int
) == 1) {
2631 res
= ast_streamfile(chan
, "conf-enteringno", chan
->language
);
2633 ast_waitstream(chan
, "");
2634 res
= ast_say_digits(chan
, confno_int
, "", chan
->language
);
2637 ast_log(LOG_ERROR
, "Could not scan confno '%s'\n", confno
);
2642 while (allowretry
&& (ast_strlen_zero(confno
)) && (++retrycnt
< 4)) {
2643 /* Prompt user for conference number */
2644 res
= ast_app_getdata(chan
, "conf-getconfno", confno
, sizeof(confno
) - 1, 0);
2646 /* Don't try to validate when we catch an error */
2652 if (!ast_strlen_zero(confno
)) {
2653 /* Check the validity of the conference */
2654 cnf
= find_conf(chan
, confno
, 1, dynamic
, the_pin
,
2655 sizeof(the_pin
), 1, &confflags
);
2657 cnf
= find_conf_realtime(chan
, confno
, 1, dynamic
,
2658 the_pin
, sizeof(the_pin
), 1, &confflags
);
2662 res
= ast_streamfile(chan
, "conf-invalid", chan
->language
);
2664 ast_waitstream(chan
, "");
2669 if ((!ast_strlen_zero(cnf
->pin
) &&
2670 !ast_test_flag(&confflags
, CONFFLAG_ADMIN
)) ||
2671 (!ast_strlen_zero(cnf
->pinadmin
) &&
2672 ast_test_flag(&confflags
, CONFFLAG_ADMIN
))) {
2673 char pin
[MAX_PIN
] = "";
2676 /* Allow the pin to be retried up to 3 times */
2677 for (j
= 0; j
< 3; j
++) {
2678 if (*the_pin
&& (always_prompt
== 0)) {
2679 ast_copy_string(pin
, the_pin
, sizeof(pin
));
2682 /* Prompt user for pin if pin is required */
2683 res
= ast_app_getdata(chan
, "conf-getpin", pin
+ strlen(pin
), sizeof(pin
) - 1 - strlen(pin
), 0);
2686 if (!strcasecmp(pin
, cnf
->pin
) ||
2687 (!ast_strlen_zero(cnf
->pinadmin
) &&
2688 !strcasecmp(pin
, cnf
->pinadmin
))) {
2691 if (!ast_strlen_zero(cnf
->pinadmin
) && !strcasecmp(pin
, cnf
->pinadmin
))
2692 ast_set_flag(&confflags
, CONFFLAG_ADMIN
);
2693 /* Run the conference */
2694 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2698 if (!ast_streamfile(chan
, "conf-invalidpin", chan
->language
)) {
2699 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2700 ast_stopstream(chan
);
2703 ast_log(LOG_WARNING
, "Couldn't play invalid pin msg!\n");
2715 /* failed when getting the pin */
2718 /* see if we need to get rid of the conference */
2722 /* Don't retry pin with a static pin */
2723 if (*the_pin
&& (always_prompt
==0)) {
2728 /* No pin required */
2731 /* Run the conference */
2732 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2738 } while (allowretry
);
2743 ast_module_user_remove(u
);
2748 static struct ast_conf_user
*find_user(struct ast_conference
*conf
, char *callerident
)
2750 struct ast_conf_user
*user
= NULL
;
2753 sscanf(callerident
, "%i", &cid
);
2754 if (conf
&& callerident
) {
2755 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
2756 if (cid
== user
->user_no
)
2763 /*! \brief The MeetMeadmin application */
2764 /* MeetMeAdmin(confno, command, caller) */
2765 static int admin_exec(struct ast_channel
*chan
, void *data
) {
2767 struct ast_conference
*cnf
;
2768 struct ast_conf_user
*user
= NULL
;
2769 struct ast_module_user
*u
;
2770 AST_DECLARE_APP_ARGS(args
,
2771 AST_APP_ARG(confno
);
2772 AST_APP_ARG(command
);
2776 if (ast_strlen_zero(data
)) {
2777 ast_log(LOG_WARNING
, "MeetMeAdmin requires an argument!\n");
2781 u
= ast_module_user_add(chan
);
2783 AST_LIST_LOCK(&confs
);
2785 params
= ast_strdupa(data
);
2786 AST_STANDARD_APP_ARGS(args
, params
);
2788 if (!args
.command
) {
2789 ast_log(LOG_WARNING
, "MeetmeAdmin requires a command!\n");
2790 AST_LIST_UNLOCK(&confs
);
2791 ast_module_user_remove(u
);
2794 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2795 if (!strcmp(cnf
->confno
, args
.confno
))
2800 ast_log(LOG_WARNING
, "Conference number '%s' not found!\n", args
.confno
);
2801 AST_LIST_UNLOCK(&confs
);
2802 ast_module_user_remove(u
);
2806 ast_atomic_fetchadd_int(&cnf
->refcount
, 1);
2809 user
= find_user(cnf
, args
.user
);
2811 switch (*args
.command
) {
2812 case 76: /* L: Lock */
2815 case 108: /* l: Unlock */
2818 case 75: /* K: kick all users */
2819 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2820 user
->adminflags
|= ADMINFLAG_KICKME
;
2822 case 101: /* e: Eject last user*/
2823 user
= AST_LIST_LAST(&cnf
->userlist
);
2824 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2825 user
->adminflags
|= ADMINFLAG_KICKME
;
2827 ast_log(LOG_NOTICE
, "Not kicking last user, is an Admin!\n");
2829 case 77: /* M: Mute */
2831 user
->adminflags
|= ADMINFLAG_MUTED
;
2833 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2835 case 78: /* N: Mute all (non-admin) users */
2836 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
2837 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2838 user
->adminflags
|= ADMINFLAG_MUTED
;
2841 case 109: /* m: Unmute */
2843 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2845 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2847 case 110: /* n: Unmute all users */
2848 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2849 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2851 case 107: /* k: Kick user */
2853 user
->adminflags
|= ADMINFLAG_KICKME
;
2855 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2857 case 118: /* v: Lower all users listen volume */
2858 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2859 tweak_listen_volume(user
, VOL_DOWN
);
2861 case 86: /* V: Raise all users listen volume */
2862 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2863 tweak_listen_volume(user
, VOL_UP
);
2865 case 115: /* s: Lower all users speaking volume */
2866 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2867 tweak_talk_volume(user
, VOL_DOWN
);
2869 case 83: /* S: Raise all users speaking volume */
2870 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2871 tweak_talk_volume(user
, VOL_UP
);
2873 case 82: /* R: Reset all volume levels */
2874 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2875 reset_volumes(user
);
2877 case 114: /* r: Reset user's volume level */
2879 reset_volumes(user
);
2881 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2883 case 85: /* U: Raise user's listen volume */
2885 tweak_listen_volume(user
, VOL_UP
);
2887 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2889 case 117: /* u: Lower user's listen volume */
2891 tweak_listen_volume(user
, VOL_DOWN
);
2893 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2895 case 84: /* T: Raise user's talk volume */
2897 tweak_talk_volume(user
, VOL_UP
);
2899 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2901 case 116: /* t: Lower user's talk volume */
2903 tweak_talk_volume(user
, VOL_DOWN
);
2905 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2909 AST_LIST_UNLOCK(&confs
);
2913 ast_module_user_remove(u
);
2918 static int meetmemute(struct mansession
*s
, const struct message
*m
, int mute
)
2920 struct ast_conference
*conf
;
2921 struct ast_conf_user
*user
;
2922 const char *confid
= astman_get_header(m
, "Meetme");
2923 char *userid
= ast_strdupa(astman_get_header(m
, "Usernum"));
2926 if (ast_strlen_zero(confid
)) {
2927 astman_send_error(s
, m
, "Meetme conference not specified");
2931 if (ast_strlen_zero(userid
)) {
2932 astman_send_error(s
, m
, "Meetme user number not specified");
2936 userno
= strtoul(userid
, &userid
, 10);
2939 astman_send_error(s
, m
, "Invalid user number");
2943 /* Look in the conference list */
2944 AST_LIST_LOCK(&confs
);
2945 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
2946 if (!strcmp(confid
, conf
->confno
))
2951 AST_LIST_UNLOCK(&confs
);
2952 astman_send_error(s
, m
, "Meetme conference does not exist");
2956 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
)
2957 if (user
->user_no
== userno
)
2961 AST_LIST_UNLOCK(&confs
);
2962 astman_send_error(s
, m
, "User number not found");
2967 user
->adminflags
|= ADMINFLAG_MUTED
; /* request user muting */
2969 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
); /* request user unmuting */
2971 AST_LIST_UNLOCK(&confs
);
2973 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
);
2975 astman_send_ack(s
, m
, mute
? "User muted" : "User unmuted");
2979 static int action_meetmemute(struct mansession
*s
, const struct message
*m
)
2981 return meetmemute(s
, m
, 1);
2984 static int action_meetmeunmute(struct mansession
*s
, const struct message
*m
)
2986 return meetmemute(s
, m
, 0);
2989 static void *recordthread(void *args
)
2991 struct ast_conference
*cnf
= args
;
2992 struct ast_frame
*f
=NULL
;
2994 struct ast_filestream
*s
=NULL
;
2997 const char *oldrecordingfilename
= NULL
;
2999 if (!cnf
|| !cnf
->lchan
) {
3003 ast_stopstream(cnf
->lchan
);
3004 flags
= O_CREAT
|O_TRUNC
|O_WRONLY
;
3007 cnf
->recording
= MEETME_RECORD_ACTIVE
;
3008 while (ast_waitfor(cnf
->lchan
, -1) > -1) {
3009 if (cnf
->recording
== MEETME_RECORD_TERMINATE
) {
3010 AST_LIST_LOCK(&confs
);
3011 AST_LIST_UNLOCK(&confs
);
3014 if (!s
&& cnf
->recordingfilename
&& (cnf
->recordingfilename
!= oldrecordingfilename
)) {
3015 s
= ast_writefile(cnf
->recordingfilename
, cnf
->recordingformat
, NULL
, flags
, 0, 0644);
3016 oldrecordingfilename
= cnf
->recordingfilename
;
3019 f
= ast_read(cnf
->lchan
);
3024 if (f
->frametype
== AST_FRAME_VOICE
) {
3025 ast_mutex_lock(&cnf
->listenlock
);
3026 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
3027 /* Free any translations that have occured */
3028 if (cnf
->transframe
[x
]) {
3029 ast_frfree(cnf
->transframe
[x
]);
3030 cnf
->transframe
[x
] = NULL
;
3034 ast_frfree(cnf
->origframe
);
3035 cnf
->origframe
= ast_frdup(f
);
3036 ast_mutex_unlock(&cnf
->listenlock
);
3038 res
= ast_writestream(s
, f
);
3046 cnf
->recording
= MEETME_RECORD_OFF
;
3053 /*! \brief Callback for devicestate providers */
3054 static int meetmestate(const char *data
)
3056 struct ast_conference
*conf
;
3058 /* Find conference */
3059 AST_LIST_LOCK(&confs
);
3060 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
3061 if (!strcmp(data
, conf
->confno
))
3064 AST_LIST_UNLOCK(&confs
);
3066 return AST_DEVICE_INVALID
;
3071 return AST_DEVICE_NOT_INUSE
;
3073 return AST_DEVICE_INUSE
;
3076 static void load_config_meetme(void)
3078 struct ast_config
*cfg
;
3081 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3083 if (!(cfg
= ast_config_load(CONFIG_FILE_NAME
)))
3086 if ((val
= ast_variable_retrieve(cfg
, "general", "audiobuffers"))) {
3087 if ((sscanf(val
, "%d", &audio_buffers
) != 1)) {
3088 ast_log(LOG_WARNING
, "audiobuffers setting must be a number, not '%s'\n", val
);
3089 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3090 } else if ((audio_buffers
< ZT_DEFAULT_NUM_BUFS
) || (audio_buffers
> ZT_MAX_NUM_BUFS
)) {
3091 ast_log(LOG_WARNING
, "audiobuffers setting must be between %d and %d\n",
3092 ZT_DEFAULT_NUM_BUFS
, ZT_MAX_NUM_BUFS
);
3093 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3095 if (audio_buffers
!= DEFAULT_AUDIO_BUFFERS
)
3096 ast_log(LOG_NOTICE
, "Audio buffers per channel set to %d\n", audio_buffers
);
3099 ast_config_destroy(cfg
);
3102 /*! \brief Find an SLA trunk by name
3103 * \note This must be called with the sla_trunks container locked
3105 static struct sla_trunk
*sla_find_trunk(const char *name
)
3107 struct sla_trunk
*trunk
= NULL
;
3109 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
3110 if (!strcasecmp(trunk
->name
, name
))
3117 /*! \brief Find an SLA station by name
3118 * \note This must be called with the sla_stations container locked
3120 static struct sla_station
*sla_find_station(const char *name
)
3122 struct sla_station
*station
= NULL
;
3124 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
3125 if (!strcasecmp(station
->name
, name
))
3132 static int sla_check_station_hold_access(const struct sla_trunk
*trunk
,
3133 const struct sla_station
*station
)
3135 struct sla_station_ref
*station_ref
;
3136 struct sla_trunk_ref
*trunk_ref
;
3138 /* For each station that has this call on hold, check for private hold. */
3139 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
) {
3140 AST_LIST_TRAVERSE(&station_ref
->station
->trunks
, trunk_ref
, entry
) {
3141 if (trunk_ref
->trunk
!= trunk
|| station_ref
->station
== station
)
3143 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
&&
3144 station_ref
->station
->hold_access
== SLA_HOLD_PRIVATE
)
3153 /*! \brief Find a trunk reference on a station by name
3154 * \param station the station
3155 * \param name the trunk's name
3156 * \return a pointer to the station's trunk reference. If the trunk
3157 * is not found, it is not idle and barge is disabled, or if
3158 * it is on hold and private hold is set, then NULL will be returned.
3160 static struct sla_trunk_ref
*sla_find_trunk_ref_byname(const struct sla_station
*station
,
3163 struct sla_trunk_ref
*trunk_ref
= NULL
;
3165 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3166 if (strcasecmp(trunk_ref
->trunk
->name
, name
))
3169 if ( (trunk_ref
->trunk
->barge_disabled
3170 && trunk_ref
->state
== SLA_TRUNK_STATE_UP
) ||
3171 (trunk_ref
->trunk
->hold_stations
3172 && trunk_ref
->trunk
->hold_access
== SLA_HOLD_PRIVATE
3173 && trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) ||
3174 sla_check_station_hold_access(trunk_ref
->trunk
, station
) )
3185 static struct sla_station_ref
*sla_create_station_ref(struct sla_station
*station
)
3187 struct sla_station_ref
*station_ref
;
3189 if (!(station_ref
= ast_calloc(1, sizeof(*station_ref
))))
3192 station_ref
->station
= station
;
3197 static struct sla_ringing_station
*sla_create_ringing_station(struct sla_station
*station
)
3199 struct sla_ringing_station
*ringing_station
;
3201 if (!(ringing_station
= ast_calloc(1, sizeof(*ringing_station
))))
3204 ringing_station
->station
= station
;
3205 ringing_station
->ring_begin
= ast_tvnow();
3207 return ringing_station
;
3210 static void sla_change_trunk_state(const struct sla_trunk
*trunk
, enum sla_trunk_state state
,
3211 enum sla_which_trunk_refs inactive_only
, const struct sla_trunk_ref
*exclude
)
3213 struct sla_station
*station
;
3214 struct sla_trunk_ref
*trunk_ref
;
3216 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3217 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3218 if (trunk_ref
->trunk
!= trunk
|| (inactive_only
? trunk_ref
->chan
: 0)
3219 || trunk_ref
== exclude
)
3221 trunk_ref
->state
= state
;
3222 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk
->name
);
3228 struct run_station_args
{
3229 struct sla_station
*station
;
3230 struct sla_trunk_ref
*trunk_ref
;
3231 ast_mutex_t
*cond_lock
;
3235 static void *run_station(void *data
)
3237 struct sla_station
*station
;
3238 struct sla_trunk_ref
*trunk_ref
;
3239 char conf_name
[MAX_CONFNUM
];
3240 struct ast_flags conf_flags
= { 0 };
3241 struct ast_conference
*conf
;
3244 struct run_station_args
*args
= data
;
3245 station
= args
->station
;
3246 trunk_ref
= args
->trunk_ref
;
3247 ast_mutex_lock(args
->cond_lock
);
3248 ast_cond_signal(args
->cond
);
3249 ast_mutex_unlock(args
->cond_lock
);
3250 /* args is no longer valid here. */
3253 ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1);
3254 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
3255 ast_set_flag(&conf_flags
,
3256 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
3257 ast_answer(trunk_ref
->chan
);
3258 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
3260 conf_run(trunk_ref
->chan
, conf
, conf_flags
.flags
, NULL
);
3264 trunk_ref
->chan
= NULL
;
3265 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
3266 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
3267 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
3268 admin_exec(NULL
, conf_name
);
3269 trunk_ref
->trunk
->hold_stations
= 0;
3270 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3273 ast_dial_join(station
->dial
);
3274 ast_dial_destroy(station
->dial
);
3275 station
->dial
= NULL
;
3280 static void sla_stop_ringing_trunk(struct sla_ringing_trunk
*ringing_trunk
)
3283 struct sla_station_ref
*station_ref
;
3285 snprintf(buf
, sizeof(buf
), "SLA_%s|K", ringing_trunk
->trunk
->name
);
3286 admin_exec(NULL
, buf
);
3287 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3289 while ((station_ref
= AST_LIST_REMOVE_HEAD(&ringing_trunk
->timed_out_stations
, entry
)))
3292 free(ringing_trunk
);
3295 static void sla_stop_ringing_station(struct sla_ringing_station
*ringing_station
,
3296 enum sla_station_hangup hangup
)
3298 struct sla_ringing_trunk
*ringing_trunk
;
3299 struct sla_trunk_ref
*trunk_ref
;
3300 struct sla_station_ref
*station_ref
;
3302 ast_dial_join(ringing_station
->station
->dial
);
3303 ast_dial_destroy(ringing_station
->station
->dial
);
3304 ringing_station
->station
->dial
= NULL
;
3306 if (hangup
== SLA_STATION_HANGUP_NORMAL
)
3309 /* If the station is being hung up because of a timeout, then add it to the
3310 * list of timed out stations on each of the ringing trunks. This is so
3311 * that when doing further processing to figure out which stations should be
3312 * ringing, which trunk to answer, determining timeouts, etc., we know which
3313 * ringing trunks we should ignore. */
3314 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3315 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3316 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3321 if (!(station_ref
= sla_create_station_ref(ringing_station
->station
)))
3323 AST_LIST_INSERT_TAIL(&ringing_trunk
->timed_out_stations
, station_ref
, entry
);
3327 free(ringing_station
);
3330 static void sla_dial_state_callback(struct ast_dial
*dial
)
3332 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3335 /*! \brief Check to see if dialing this station already timed out for this ringing trunk
3336 * \note Assumes sla.lock is locked
3338 static int sla_check_timed_out_station(const struct sla_ringing_trunk
*ringing_trunk
,
3339 const struct sla_station
*station
)
3341 struct sla_station_ref
*timed_out_station
;
3343 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, timed_out_station
, entry
) {
3344 if (station
== timed_out_station
->station
)
3351 /*! \brief Choose the highest priority ringing trunk for a station
3352 * \param station the station
3353 * \param remove remove the ringing trunk once selected
3354 * \param trunk_ref a place to store the pointer to this stations reference to
3355 * the selected trunk
3356 * \return a pointer to the selected ringing trunk, or NULL if none found
3357 * \note Assumes that sla.lock is locked
3359 static struct sla_ringing_trunk
*sla_choose_ringing_trunk(struct sla_station
*station
,
3360 struct sla_trunk_ref
**trunk_ref
, int remove
)
3362 struct sla_trunk_ref
*s_trunk_ref
;
3363 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3365 AST_LIST_TRAVERSE(&station
->trunks
, s_trunk_ref
, entry
) {
3366 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3367 /* Make sure this is the trunk we're looking for */
3368 if (s_trunk_ref
->trunk
!= ringing_trunk
->trunk
)
3371 /* This trunk on the station is ringing. But, make sure this station
3372 * didn't already time out while this trunk was ringing. */
3373 if (sla_check_timed_out_station(ringing_trunk
, station
))
3377 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3380 *trunk_ref
= s_trunk_ref
;
3384 AST_LIST_TRAVERSE_SAFE_END
3390 return ringing_trunk
;
3393 static void sla_handle_dial_state_event(void)
3395 struct sla_ringing_station
*ringing_station
;
3397 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3398 struct sla_trunk_ref
*s_trunk_ref
= NULL
;
3399 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3400 struct run_station_args args
;
3401 enum ast_dial_result dial_res
;
3402 pthread_attr_t attr
;
3403 pthread_t dont_care
;
3404 ast_mutex_t cond_lock
;
3407 switch ((dial_res
= ast_dial_state(ringing_station
->station
->dial
))) {
3408 case AST_DIAL_RESULT_HANGUP
:
3409 case AST_DIAL_RESULT_INVALID
:
3410 case AST_DIAL_RESULT_FAILED
:
3411 case AST_DIAL_RESULT_TIMEOUT
:
3412 case AST_DIAL_RESULT_UNANSWERED
:
3413 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3414 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_NORMAL
);
3416 case AST_DIAL_RESULT_ANSWERED
:
3417 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3418 /* Find the appropriate trunk to answer. */
3419 ast_mutex_lock(&sla
.lock
);
3420 ringing_trunk
= sla_choose_ringing_trunk(ringing_station
->station
, &s_trunk_ref
, 1);
3421 ast_mutex_unlock(&sla
.lock
);
3422 if (!ringing_trunk
) {
3423 ast_log(LOG_DEBUG
, "Found no ringing trunk for station '%s' to answer!\n",
3424 ringing_station
->station
->name
);
3427 /* Track the channel that answered this trunk */
3428 s_trunk_ref
->chan
= ast_dial_answered(ringing_station
->station
->dial
);
3429 /* Actually answer the trunk */
3430 ast_answer(ringing_trunk
->trunk
->chan
);
3431 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
3432 /* Now, start a thread that will connect this station to the trunk. The rest of
3433 * the code here sets up the thread and ensures that it is able to save the arguments
3434 * before they are no longer valid since they are allocated on the stack. */
3435 args
.trunk_ref
= s_trunk_ref
;
3436 args
.station
= ringing_station
->station
;
3438 args
.cond_lock
= &cond_lock
;
3439 free(ringing_trunk
);
3440 free(ringing_station
);
3441 ast_mutex_init(&cond_lock
);
3442 ast_cond_init(&cond
, NULL
);
3443 pthread_attr_init(&attr
);
3444 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3445 ast_mutex_lock(&cond_lock
);
3446 ast_pthread_create_background(&dont_care
, &attr
, run_station
, &args
);
3447 ast_cond_wait(&cond
, &cond_lock
);
3448 ast_mutex_unlock(&cond_lock
);
3449 ast_mutex_destroy(&cond_lock
);
3450 ast_cond_destroy(&cond
);
3451 pthread_attr_destroy(&attr
);
3453 case AST_DIAL_RESULT_TRYING
:
3454 case AST_DIAL_RESULT_RINGING
:
3455 case AST_DIAL_RESULT_PROGRESS
:
3456 case AST_DIAL_RESULT_PROCEEDING
:
3459 if (dial_res
== AST_DIAL_RESULT_ANSWERED
) {
3460 /* Queue up reprocessing ringing trunks, and then ringing stations again */
3461 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
3462 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3466 AST_LIST_TRAVERSE_SAFE_END
3469 /*! \brief Check to see if this station is already ringing
3470 * \note Assumes sla.lock is locked
3472 static int sla_check_ringing_station(const struct sla_station
*station
)
3474 struct sla_ringing_station
*ringing_station
;
3476 AST_LIST_TRAVERSE(&sla
.ringing_stations
, ringing_station
, entry
) {
3477 if (station
== ringing_station
->station
)
3484 /*! \brief Check to see if this station has failed to be dialed in the past minute
3485 * \note assumes sla.lock is locked
3487 static int sla_check_failed_station(const struct sla_station
*station
)
3489 struct sla_failed_station
*failed_station
;
3492 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.failed_stations
, failed_station
, entry
) {
3493 if (station
!= failed_station
->station
)
3495 if (ast_tvdiff_ms(ast_tvnow(), failed_station
->last_try
) > 1000) {
3496 AST_LIST_REMOVE_CURRENT(&sla
.failed_stations
, entry
);
3497 free(failed_station
);
3502 AST_LIST_TRAVERSE_SAFE_END
3507 /*! \brief Ring a station
3508 * \note Assumes sla.lock is locked
3510 static int sla_ring_station(struct sla_ringing_trunk
*ringing_trunk
, struct sla_station
*station
)
3512 char *tech
, *tech_data
;
3513 struct ast_dial
*dial
;
3514 struct sla_ringing_station
*ringing_station
;
3515 const char *cid_name
= NULL
, *cid_num
= NULL
;
3516 enum ast_dial_result res
;
3518 if (!(dial
= ast_dial_create()))
3521 ast_dial_set_state_callback(dial
, sla_dial_state_callback
);
3522 tech_data
= ast_strdupa(station
->device
);
3523 tech
= strsep(&tech_data
, "/");
3525 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
3526 ast_dial_destroy(dial
);
3530 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_name
)) {
3531 cid_name
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3532 free(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3533 ringing_trunk
->trunk
->chan
->cid
.cid_name
= NULL
;
3535 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_num
)) {
3536 cid_num
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3537 free(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3538 ringing_trunk
->trunk
->chan
->cid
.cid_num
= NULL
;
3541 res
= ast_dial_run(dial
, ringing_trunk
->trunk
->chan
, 1);
3544 ringing_trunk
->trunk
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
3546 ringing_trunk
->trunk
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
3548 if (res
!= AST_DIAL_RESULT_TRYING
) {
3549 struct sla_failed_station
*failed_station
;
3550 ast_dial_destroy(dial
);
3551 if (!(failed_station
= ast_calloc(1, sizeof(*failed_station
))))
3553 failed_station
->station
= station
;
3554 failed_station
->last_try
= ast_tvnow();
3555 AST_LIST_INSERT_HEAD(&sla
.failed_stations
, failed_station
, entry
);
3558 if (!(ringing_station
= sla_create_ringing_station(station
))) {
3559 ast_dial_join(dial
);
3560 ast_dial_destroy(dial
);
3564 station
->dial
= dial
;
3566 AST_LIST_INSERT_HEAD(&sla
.ringing_stations
, ringing_station
, entry
);
3571 /*! \brief Check to see if a station is in use
3573 static int sla_check_inuse_station(const struct sla_station
*station
)
3575 struct sla_trunk_ref
*trunk_ref
;
3577 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3578 if (trunk_ref
->chan
)
3585 static struct sla_trunk_ref
*sla_find_trunk_ref(const struct sla_station
*station
,
3586 const struct sla_trunk
*trunk
)
3588 struct sla_trunk_ref
*trunk_ref
= NULL
;
3590 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3591 if (trunk_ref
->trunk
== trunk
)
3598 /*! \brief Calculate the ring delay for a given ringing trunk on a station
3599 * \param station the station
3600 * \param trunk the trunk. If NULL, the highest priority ringing trunk will be used
3601 * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
3603 static int sla_check_station_delay(struct sla_station
*station
,
3604 struct sla_ringing_trunk
*ringing_trunk
)
3606 struct sla_trunk_ref
*trunk_ref
;
3607 unsigned int delay
= UINT_MAX
;
3608 int time_left
, time_elapsed
;
3611 ringing_trunk
= sla_choose_ringing_trunk(station
, &trunk_ref
, 0);
3613 trunk_ref
= sla_find_trunk_ref(station
, ringing_trunk
->trunk
);
3615 if (!ringing_trunk
|| !trunk_ref
)
3618 /* If this station has a ring delay specific to the highest priority
3619 * ringing trunk, use that. Otherwise, use the ring delay specified
3620 * globally for the station. */
3621 delay
= trunk_ref
->ring_delay
;
3623 delay
= station
->ring_delay
;
3627 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3628 time_left
= (delay
* 1000) - time_elapsed
;
3633 /*! \brief Ring stations based on current set of ringing trunks
3634 * \note Assumes that sla.lock is locked
3636 static void sla_ring_stations(void)
3638 struct sla_station_ref
*station_ref
;
3639 struct sla_ringing_trunk
*ringing_trunk
;
3641 /* Make sure that every station that uses at least one of the ringing
3642 * trunks, is ringing. */
3643 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3644 AST_LIST_TRAVERSE(&ringing_trunk
->trunk
->stations
, station_ref
, entry
) {
3647 /* Is this station already ringing? */
3648 if (sla_check_ringing_station(station_ref
->station
))
3651 /* Is this station already in a call? */
3652 if (sla_check_inuse_station(station_ref
->station
))
3655 /* Did we fail to dial this station earlier? If so, has it been
3656 * a minute since we tried? */
3657 if (sla_check_failed_station(station_ref
->station
))
3660 /* If this station already timed out while this trunk was ringing,
3661 * do not dial it again for this ringing trunk. */
3662 if (sla_check_timed_out_station(ringing_trunk
, station_ref
->station
))
3665 /* Check for a ring delay in progress */
3666 time_left
= sla_check_station_delay(station_ref
->station
, ringing_trunk
);
3667 if (time_left
!= INT_MAX
&& time_left
> 0)
3670 /* It is time to make this station begin to ring. Do it! */
3671 sla_ring_station(ringing_trunk
, station_ref
->station
);
3674 /* Now, all of the stations that should be ringing, are ringing. */
3677 static void sla_hangup_stations(void)
3679 struct sla_trunk_ref
*trunk_ref
;
3680 struct sla_ringing_station
*ringing_station
;
3682 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3683 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3684 struct sla_ringing_trunk
*ringing_trunk
;
3685 ast_mutex_lock(&sla
.lock
);
3686 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3687 if (trunk_ref
->trunk
== ringing_trunk
->trunk
)
3690 ast_mutex_unlock(&sla
.lock
);
3695 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3696 ast_dial_join(ringing_station
->station
->dial
);
3697 ast_dial_destroy(ringing_station
->station
->dial
);
3698 ringing_station
->station
->dial
= NULL
;
3699 free(ringing_station
);
3702 AST_LIST_TRAVERSE_SAFE_END
3705 static void sla_handle_ringing_trunk_event(void)
3707 ast_mutex_lock(&sla
.lock
);
3708 sla_ring_stations();
3709 ast_mutex_unlock(&sla
.lock
);
3711 /* Find stations that shouldn't be ringing anymore. */
3712 sla_hangup_stations();
3715 static void sla_handle_hold_event(struct sla_event
*event
)
3717 ast_atomic_fetchadd_int((int *) &event
->trunk_ref
->trunk
->hold_stations
, 1);
3718 event
->trunk_ref
->state
= SLA_TRUNK_STATE_ONHOLD_BYME
;
3719 ast_device_state_changed("SLA:%s_%s",
3720 event
->station
->name
, event
->trunk_ref
->trunk
->name
);
3721 sla_change_trunk_state(event
->trunk_ref
->trunk
, SLA_TRUNK_STATE_ONHOLD
,
3722 INACTIVE_TRUNK_REFS
, event
->trunk_ref
);
3724 if (event
->trunk_ref
->trunk
->active_stations
== 1) {
3725 /* The station putting it on hold is the only one on the call, so start
3726 * Music on hold to the trunk. */
3727 event
->trunk_ref
->trunk
->on_hold
= 1;
3728 ast_indicate(event
->trunk_ref
->trunk
->chan
, AST_CONTROL_HOLD
);
3731 ast_softhangup(event
->trunk_ref
->chan
, AST_CAUSE_NORMAL
);
3732 event
->trunk_ref
->chan
= NULL
;
3735 /*! \brief Process trunk ring timeouts
3736 * \note Called with sla.lock locked
3737 * \return non-zero if a change to the ringing trunks was made
3739 static int sla_calc_trunk_timeouts(unsigned int *timeout
)
3741 struct sla_ringing_trunk
*ringing_trunk
;
3744 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3745 int time_left
, time_elapsed
;
3746 if (!ringing_trunk
->trunk
->ring_timeout
)
3748 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3749 time_left
= (ringing_trunk
->trunk
->ring_timeout
* 1000) - time_elapsed
;
3750 if (time_left
<= 0) {
3751 pbx_builtin_setvar_helper(ringing_trunk
->trunk
->chan
, "SLATRUNK_STATUS", "RINGTIMEOUT");
3752 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3753 sla_stop_ringing_trunk(ringing_trunk
);
3757 if (time_left
< *timeout
)
3758 *timeout
= time_left
;
3760 AST_LIST_TRAVERSE_SAFE_END
3765 /*! \brief Process station ring timeouts
3766 * \note Called with sla.lock locked
3767 * \return non-zero if a change to the ringing stations was made
3769 static int sla_calc_station_timeouts(unsigned int *timeout
)
3771 struct sla_ringing_trunk
*ringing_trunk
;
3772 struct sla_ringing_station
*ringing_station
;
3775 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3776 unsigned int ring_timeout
= 0;
3777 int time_elapsed
, time_left
= INT_MAX
, final_trunk_time_left
= INT_MIN
;
3778 struct sla_trunk_ref
*trunk_ref
;
3780 /* If there are any ring timeouts specified for a specific trunk
3781 * on the station, then use the highest per-trunk ring timeout.
3782 * Otherwise, use the ring timeout set for the entire station. */
3783 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3784 struct sla_station_ref
*station_ref
;
3785 int trunk_time_elapsed
, trunk_time_left
;
3787 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3788 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3794 /* If there is a trunk that is ringing without a timeout, then the
3795 * only timeout that could matter is a global station ring timeout. */
3796 if (!trunk_ref
->ring_timeout
)
3799 /* This trunk on this station is ringing and has a timeout.
3800 * However, make sure this trunk isn't still ringing from a
3801 * previous timeout. If so, don't consider it. */
3802 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, station_ref
, entry
) {
3803 if (station_ref
->station
== ringing_station
->station
)
3809 trunk_time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3810 trunk_time_left
= (trunk_ref
->ring_timeout
* 1000) - trunk_time_elapsed
;
3811 if (trunk_time_left
> final_trunk_time_left
)
3812 final_trunk_time_left
= trunk_time_left
;
3815 /* No timeout was found for ringing trunks, and no timeout for the entire station */
3816 if (final_trunk_time_left
== INT_MIN
&& !ringing_station
->station
->ring_timeout
)
3819 /* Compute how much time is left for a global station timeout */
3820 if (ringing_station
->station
->ring_timeout
) {
3821 ring_timeout
= ringing_station
->station
->ring_timeout
;
3822 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_station
->ring_begin
);
3823 time_left
= (ring_timeout
* 1000) - time_elapsed
;
3826 /* If the time left based on the per-trunk timeouts is smaller than the
3827 * global station ring timeout, use that. */
3828 if (final_trunk_time_left
> INT_MIN
&& final_trunk_time_left
< time_left
)
3829 time_left
= final_trunk_time_left
;
3831 /* If there is no time left, the station needs to stop ringing */
3832 if (time_left
<= 0) {
3833 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3834 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_TIMEOUT
);
3839 /* There is still some time left for this station to ring, so save that
3840 * timeout if it is the first event scheduled to occur */
3841 if (time_left
< *timeout
)
3842 *timeout
= time_left
;
3844 AST_LIST_TRAVERSE_SAFE_END
3849 /*! \brief Calculate the ring delay for a station
3850 * \note Assumes sla.lock is locked
3852 static int sla_calc_station_delays(unsigned int *timeout
)
3854 struct sla_station
*station
;
3857 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3858 struct sla_ringing_trunk
*ringing_trunk
;
3861 /* Ignore stations already ringing */
3862 if (sla_check_ringing_station(station
))
3865 /* Ignore stations already on a call */
3866 if (sla_check_inuse_station(station
))
3869 /* Ignore stations that don't have one of their trunks ringing */
3870 if (!(ringing_trunk
= sla_choose_ringing_trunk(station
, NULL
, 0)))
3873 if ((time_left
= sla_check_station_delay(station
, ringing_trunk
)) == INT_MAX
)
3876 /* If there is no time left, then the station needs to start ringing.
3877 * Return non-zero so that an event will be queued up an event to
3878 * make that happen. */
3879 if (time_left
<= 0) {
3884 if (time_left
< *timeout
)
3885 *timeout
= time_left
;
3891 /*! \brief Calculate the time until the next known event
3892 * \note Called with sla.lock locked */
3893 static int sla_process_timers(struct timespec
*ts
)
3895 unsigned int timeout
= UINT_MAX
;
3897 unsigned int change_made
= 0;
3899 /* Check for ring timeouts on ringing trunks */
3900 if (sla_calc_trunk_timeouts(&timeout
))
3903 /* Check for ring timeouts on ringing stations */
3904 if (sla_calc_station_timeouts(&timeout
))
3907 /* Check for station ring delays */
3908 if (sla_calc_station_delays(&timeout
))
3911 /* queue reprocessing of ringing trunks */
3913 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK
);
3916 if (timeout
== UINT_MAX
)
3920 tv
= ast_tvadd(ast_tvnow(), ast_samp2tv(timeout
, 1000));
3921 ts
->tv_sec
= tv
.tv_sec
;
3922 ts
->tv_nsec
= tv
.tv_usec
* 1000;
3928 static void *sla_thread(void *data
)
3930 struct sla_failed_station
*failed_station
;
3931 struct sla_ringing_station
*ringing_station
;
3933 ast_mutex_lock(&sla
.lock
);
3936 struct sla_event
*event
;
3937 struct timespec ts
= { 0, };
3938 unsigned int have_timeout
= 0;
3940 if (AST_LIST_EMPTY(&sla
.event_q
)) {
3941 if ((have_timeout
= sla_process_timers(&ts
)))
3942 ast_cond_timedwait(&sla
.cond
, &sla
.lock
, &ts
);
3944 ast_cond_wait(&sla
.cond
, &sla
.lock
);
3950 sla_process_timers(NULL
);
3952 while ((event
= AST_LIST_REMOVE_HEAD(&sla
.event_q
, entry
))) {
3953 ast_mutex_unlock(&sla
.lock
);
3954 switch (event
->type
) {
3955 case SLA_EVENT_HOLD
:
3956 sla_handle_hold_event(event
);
3958 case SLA_EVENT_DIAL_STATE
:
3959 sla_handle_dial_state_event();
3961 case SLA_EVENT_RINGING_TRUNK
:
3962 sla_handle_ringing_trunk_event();
3966 ast_mutex_lock(&sla
.lock
);
3970 ast_mutex_unlock(&sla
.lock
);
3972 while ((ringing_station
= AST_LIST_REMOVE_HEAD(&sla
.ringing_stations
, entry
)))
3973 free(ringing_station
);
3975 while ((failed_station
= AST_LIST_REMOVE_HEAD(&sla
.failed_stations
, entry
)))
3976 free(failed_station
);
3981 struct dial_trunk_args
{
3982 struct sla_trunk_ref
*trunk_ref
;
3983 struct sla_station
*station
;
3984 ast_mutex_t
*cond_lock
;
3988 static void *dial_trunk(void *data
)
3990 struct dial_trunk_args
*args
= data
;
3991 struct ast_dial
*dial
;
3992 char *tech
, *tech_data
;
3993 enum ast_dial_result dial_res
;
3994 char conf_name
[MAX_CONFNUM
];
3995 struct ast_conference
*conf
;
3996 struct ast_flags conf_flags
= { 0 };
3997 struct sla_trunk_ref
*trunk_ref
= args
->trunk_ref
;
3998 const char *cid_name
= NULL
, *cid_num
= NULL
;
4000 if (!(dial
= ast_dial_create())) {
4001 ast_mutex_lock(args
->cond_lock
);
4002 ast_cond_signal(args
->cond
);
4003 ast_mutex_unlock(args
->cond_lock
);
4007 tech_data
= ast_strdupa(trunk_ref
->trunk
->device
);
4008 tech
= strsep(&tech_data
, "/");
4009 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
4010 ast_mutex_lock(args
->cond_lock
);
4011 ast_cond_signal(args
->cond
);
4012 ast_mutex_unlock(args
->cond_lock
);
4013 ast_dial_destroy(dial
);
4017 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_name
)) {
4018 cid_name
= ast_strdupa(trunk_ref
->chan
->cid
.cid_name
);
4019 free(trunk_ref
->chan
->cid
.cid_name
);
4020 trunk_ref
->chan
->cid
.cid_name
= NULL
;
4022 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_num
)) {
4023 cid_num
= ast_strdupa(trunk_ref
->chan
->cid
.cid_num
);
4024 free(trunk_ref
->chan
->cid
.cid_num
);
4025 trunk_ref
->chan
->cid
.cid_num
= NULL
;
4028 dial_res
= ast_dial_run(dial
, trunk_ref
->chan
, 1);
4031 trunk_ref
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
4033 trunk_ref
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
4035 if (dial_res
!= AST_DIAL_RESULT_TRYING
) {
4036 ast_mutex_lock(args
->cond_lock
);
4037 ast_cond_signal(args
->cond
);
4038 ast_mutex_unlock(args
->cond_lock
);
4039 ast_dial_destroy(dial
);
4044 unsigned int done
= 0;
4045 switch ((dial_res
= ast_dial_state(dial
))) {
4046 case AST_DIAL_RESULT_ANSWERED
:
4047 trunk_ref
->trunk
->chan
= ast_dial_answered(dial
);
4048 case AST_DIAL_RESULT_HANGUP
:
4049 case AST_DIAL_RESULT_INVALID
:
4050 case AST_DIAL_RESULT_FAILED
:
4051 case AST_DIAL_RESULT_TIMEOUT
:
4052 case AST_DIAL_RESULT_UNANSWERED
:
4054 case AST_DIAL_RESULT_TRYING
:
4055 case AST_DIAL_RESULT_RINGING
:
4056 case AST_DIAL_RESULT_PROGRESS
:
4057 case AST_DIAL_RESULT_PROCEEDING
:
4064 if (!trunk_ref
->trunk
->chan
) {
4065 ast_mutex_lock(args
->cond_lock
);
4066 ast_cond_signal(args
->cond
);
4067 ast_mutex_unlock(args
->cond_lock
);
4068 ast_dial_join(dial
);
4069 ast_dial_destroy(dial
);
4073 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4074 ast_set_flag(&conf_flags
,
4075 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
|
4076 CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_TRUNK
);
4077 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4079 ast_mutex_lock(args
->cond_lock
);
4080 ast_cond_signal(args
->cond
);
4081 ast_mutex_unlock(args
->cond_lock
);
4084 conf_run(trunk_ref
->trunk
->chan
, conf
, conf_flags
.flags
, NULL
);
4089 /* If the trunk is going away, it is definitely now IDLE. */
4090 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4092 trunk_ref
->trunk
->chan
= NULL
;
4093 trunk_ref
->trunk
->on_hold
= 0;
4095 ast_dial_join(dial
);
4096 ast_dial_destroy(dial
);
4101 /*! \brief For a given station, choose the highest priority idle trunk
4103 static struct sla_trunk_ref
*sla_choose_idle_trunk(const struct sla_station
*station
)
4105 struct sla_trunk_ref
*trunk_ref
= NULL
;
4107 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4108 if (trunk_ref
->state
== SLA_TRUNK_STATE_IDLE
)
4115 static int sla_station_exec(struct ast_channel
*chan
, void *data
)
4117 char *station_name
, *trunk_name
;
4118 struct sla_station
*station
;
4119 struct sla_trunk_ref
*trunk_ref
= NULL
;
4120 char conf_name
[MAX_CONFNUM
];
4121 struct ast_flags conf_flags
= { 0 };
4122 struct ast_conference
*conf
;
4124 if (ast_strlen_zero(data
)) {
4125 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4126 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4130 trunk_name
= ast_strdupa(data
);
4131 station_name
= strsep(&trunk_name
, "_");
4133 if (ast_strlen_zero(station_name
)) {
4134 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4135 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4139 AST_RWLIST_RDLOCK(&sla_stations
);
4140 station
= sla_find_station(station_name
);
4141 AST_RWLIST_UNLOCK(&sla_stations
);
4144 ast_log(LOG_WARNING
, "Station '%s' not found!\n", station_name
);
4145 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4149 AST_RWLIST_RDLOCK(&sla_trunks
);
4150 if (!ast_strlen_zero(trunk_name
)) {
4151 trunk_ref
= sla_find_trunk_ref_byname(station
, trunk_name
);
4153 trunk_ref
= sla_choose_idle_trunk(station
);
4154 AST_RWLIST_UNLOCK(&sla_trunks
);
4157 if (ast_strlen_zero(trunk_name
))
4158 ast_log(LOG_NOTICE
, "No trunks available for call.\n");
4160 ast_log(LOG_NOTICE
, "Can't join existing call on trunk "
4161 "'%s' due to access controls.\n", trunk_name
);
4163 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4167 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
) {
4168 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->hold_stations
) == 1)
4169 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4171 trunk_ref
->state
= SLA_TRUNK_STATE_UP
;
4172 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4174 } else if (trunk_ref
->state
== SLA_TRUNK_STATE_RINGING
) {
4175 struct sla_ringing_trunk
*ringing_trunk
;
4177 ast_mutex_lock(&sla
.lock
);
4178 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4179 if (ringing_trunk
->trunk
== trunk_ref
->trunk
) {
4180 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4184 AST_LIST_TRAVERSE_SAFE_END
4185 ast_mutex_unlock(&sla
.lock
);
4187 if (ringing_trunk
) {
4188 ast_answer(ringing_trunk
->trunk
->chan
);
4189 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4191 free(ringing_trunk
);
4193 /* Queue up reprocessing ringing trunks, and then ringing stations again */
4194 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4195 sla_queue_event(SLA_EVENT_DIAL_STATE
);
4199 trunk_ref
->chan
= chan
;
4201 if (!trunk_ref
->trunk
->chan
) {
4202 ast_mutex_t cond_lock
;
4204 pthread_t dont_care
;
4205 pthread_attr_t attr
;
4206 struct dial_trunk_args args
= {
4207 .trunk_ref
= trunk_ref
,
4209 .cond_lock
= &cond_lock
,
4212 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4213 /* Create a thread to dial the trunk and dump it into the conference.
4214 * However, we want to wait until the trunk has been dialed and the
4215 * conference is created before continuing on here. */
4216 ast_autoservice_start(chan
);
4217 ast_mutex_init(&cond_lock
);
4218 ast_cond_init(&cond
, NULL
);
4219 pthread_attr_init(&attr
);
4220 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4221 ast_mutex_lock(&cond_lock
);
4222 ast_pthread_create_background(&dont_care
, &attr
, dial_trunk
, &args
);
4223 ast_cond_wait(&cond
, &cond_lock
);
4224 ast_mutex_unlock(&cond_lock
);
4225 ast_mutex_destroy(&cond_lock
);
4226 ast_cond_destroy(&cond
);
4227 pthread_attr_destroy(&attr
);
4228 ast_autoservice_stop(chan
);
4229 if (!trunk_ref
->trunk
->chan
) {
4230 ast_log(LOG_DEBUG
, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref
->trunk
->chan
);
4231 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4232 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4233 trunk_ref
->chan
= NULL
;
4238 if (ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1) == 0 &&
4239 trunk_ref
->trunk
->on_hold
) {
4240 trunk_ref
->trunk
->on_hold
= 0;
4241 ast_indicate(trunk_ref
->trunk
->chan
, AST_CONTROL_UNHOLD
);
4242 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4245 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4246 ast_set_flag(&conf_flags
,
4247 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
4249 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
4251 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4255 trunk_ref
->chan
= NULL
;
4256 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
4257 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
4258 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
4259 admin_exec(NULL
, conf_name
);
4260 trunk_ref
->trunk
->hold_stations
= 0;
4261 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4264 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "SUCCESS");
4269 static struct sla_trunk_ref
*create_trunk_ref(struct sla_trunk
*trunk
)
4271 struct sla_trunk_ref
*trunk_ref
;
4273 if (!(trunk_ref
= ast_calloc(1, sizeof(*trunk_ref
))))
4276 trunk_ref
->trunk
= trunk
;
4281 static struct sla_ringing_trunk
*queue_ringing_trunk(struct sla_trunk
*trunk
)
4283 struct sla_ringing_trunk
*ringing_trunk
;
4285 if (!(ringing_trunk
= ast_calloc(1, sizeof(*ringing_trunk
))))
4288 ringing_trunk
->trunk
= trunk
;
4289 ringing_trunk
->ring_begin
= ast_tvnow();
4291 sla_change_trunk_state(trunk
, SLA_TRUNK_STATE_RINGING
, ALL_TRUNK_REFS
, NULL
);
4293 ast_mutex_lock(&sla
.lock
);
4294 AST_LIST_INSERT_HEAD(&sla
.ringing_trunks
, ringing_trunk
, entry
);
4295 ast_mutex_unlock(&sla
.lock
);
4297 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4299 return ringing_trunk
;
4302 static int sla_trunk_exec(struct ast_channel
*chan
, void *data
)
4304 const char *trunk_name
= data
;
4305 char conf_name
[MAX_CONFNUM
];
4306 struct ast_conference
*conf
;
4307 struct ast_flags conf_flags
= { 0 };
4308 struct sla_trunk
*trunk
;
4309 struct sla_ringing_trunk
*ringing_trunk
;
4311 AST_RWLIST_RDLOCK(&sla_trunks
);
4312 trunk
= sla_find_trunk(trunk_name
);
4313 AST_RWLIST_UNLOCK(&sla_trunks
);
4315 ast_log(LOG_ERROR
, "SLA Trunk '%s' not found!\n", trunk_name
);
4316 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4320 ast_log(LOG_ERROR
, "Call came in on %s, but the trunk is already in use!\n",
4322 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4327 if (!(ringing_trunk
= queue_ringing_trunk(trunk
))) {
4328 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4332 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_name
);
4333 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4335 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4338 ast_set_flag(&conf_flags
,
4339 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
| CONFFLAG_PASS_DTMF
);
4340 ast_indicate(chan
, AST_CONTROL_RINGING
);
4341 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4347 if (!pbx_builtin_getvar_helper(chan
, "SLATRUNK_STATUS"))
4348 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "SUCCESS");
4350 /* Remove the entry from the list of ringing trunks if it is still there. */
4351 ast_mutex_lock(&sla
.lock
);
4352 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4353 if (ringing_trunk
->trunk
== trunk
) {
4354 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4358 AST_LIST_TRAVERSE_SAFE_END
4359 ast_mutex_unlock(&sla
.lock
);
4360 if (ringing_trunk
) {
4361 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4362 free(ringing_trunk
);
4363 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "UNANSWERED");
4364 /* Queue reprocessing of ringing trunks to make stations stop ringing
4365 * that shouldn't be ringing after this trunk stopped. */
4366 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4372 static int sla_state(const char *data
)
4374 char *buf
, *station_name
, *trunk_name
;
4375 struct sla_station
*station
;
4376 struct sla_trunk_ref
*trunk_ref
;
4377 int res
= AST_DEVICE_INVALID
;
4379 trunk_name
= buf
= ast_strdupa(data
);
4380 station_name
= strsep(&trunk_name
, "_");
4382 AST_RWLIST_RDLOCK(&sla_stations
);
4383 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
4384 if (strcasecmp(station_name
, station
->name
))
4386 AST_RWLIST_RDLOCK(&sla_trunks
);
4387 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4388 if (!strcasecmp(trunk_name
, trunk_ref
->trunk
->name
))
4392 AST_RWLIST_UNLOCK(&sla_trunks
);
4395 switch (trunk_ref
->state
) {
4396 case SLA_TRUNK_STATE_IDLE
:
4397 res
= AST_DEVICE_NOT_INUSE
;
4399 case SLA_TRUNK_STATE_RINGING
:
4400 res
= AST_DEVICE_RINGING
;
4402 case SLA_TRUNK_STATE_UP
:
4403 res
= AST_DEVICE_INUSE
;
4405 case SLA_TRUNK_STATE_ONHOLD
:
4406 case SLA_TRUNK_STATE_ONHOLD_BYME
:
4407 res
= AST_DEVICE_ONHOLD
;
4410 AST_RWLIST_UNLOCK(&sla_trunks
);
4412 AST_RWLIST_UNLOCK(&sla_stations
);
4414 if (res
== AST_DEVICE_INVALID
) {
4415 ast_log(LOG_ERROR
, "Could not determine state for trunk %s on station %s!\n",
4416 trunk_name
, station_name
);
4422 static void destroy_trunk(struct sla_trunk
*trunk
)
4424 struct sla_station_ref
*station_ref
;
4426 if (!ast_strlen_zero(trunk
->autocontext
))
4427 ast_context_remove_extension(trunk
->autocontext
, "s", 1, sla_registrar
);
4429 while ((station_ref
= AST_LIST_REMOVE_HEAD(&trunk
->stations
, entry
)))
4432 ast_string_field_free_memory(trunk
);
4436 static void destroy_station(struct sla_station
*station
)
4438 struct sla_trunk_ref
*trunk_ref
;
4440 if (!ast_strlen_zero(station
->autocontext
)) {
4441 AST_RWLIST_RDLOCK(&sla_trunks
);
4442 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4443 char exten
[AST_MAX_EXTENSION
];
4444 char hint
[AST_MAX_APP
];
4445 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4446 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4447 ast_context_remove_extension(station
->autocontext
, exten
,
4449 ast_context_remove_extension(station
->autocontext
, hint
,
4450 PRIORITY_HINT
, sla_registrar
);
4452 AST_RWLIST_UNLOCK(&sla_trunks
);
4455 while ((trunk_ref
= AST_LIST_REMOVE_HEAD(&station
->trunks
, entry
)))
4458 ast_string_field_free_memory(station
);
4462 static void sla_destroy(void)
4464 struct sla_trunk
*trunk
;
4465 struct sla_station
*station
;
4467 AST_RWLIST_WRLOCK(&sla_trunks
);
4468 while ((trunk
= AST_RWLIST_REMOVE_HEAD(&sla_trunks
, entry
)))
4469 destroy_trunk(trunk
);
4470 AST_RWLIST_UNLOCK(&sla_trunks
);
4472 AST_RWLIST_WRLOCK(&sla_stations
);
4473 while ((station
= AST_RWLIST_REMOVE_HEAD(&sla_stations
, entry
)))
4474 destroy_station(station
);
4475 AST_RWLIST_UNLOCK(&sla_stations
);
4477 if (sla
.thread
!= AST_PTHREADT_NULL
) {
4478 ast_mutex_lock(&sla
.lock
);
4480 ast_cond_signal(&sla
.cond
);
4481 ast_mutex_unlock(&sla
.lock
);
4482 pthread_join(sla
.thread
, NULL
);
4485 ast_mutex_destroy(&sla
.lock
);
4486 ast_cond_destroy(&sla
.cond
);
4489 static int sla_check_device(const char *device
)
4491 char *tech
, *tech_data
;
4493 tech_data
= ast_strdupa(device
);
4494 tech
= strsep(&tech_data
, "/");
4496 if (ast_strlen_zero(tech
) || ast_strlen_zero(tech_data
))
4502 static int sla_build_trunk(struct ast_config
*cfg
, const char *cat
)
4504 struct sla_trunk
*trunk
;
4505 struct ast_variable
*var
;
4508 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4509 ast_log(LOG_ERROR
, "SLA Trunk '%s' defined with no device!\n", cat
);
4513 if (sla_check_device(dev
)) {
4514 ast_log(LOG_ERROR
, "SLA Trunk '%s' define with invalid device '%s'!\n",
4519 if (!(trunk
= ast_calloc(1, sizeof(*trunk
))))
4521 if (ast_string_field_init(trunk
, 32)) {
4526 ast_string_field_set(trunk
, name
, cat
);
4527 ast_string_field_set(trunk
, device
, dev
);
4529 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4530 if (!strcasecmp(var
->name
, "autocontext"))
4531 ast_string_field_set(trunk
, autocontext
, var
->value
);
4532 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4533 if (sscanf(var
->value
, "%u", &trunk
->ring_timeout
) != 1) {
4534 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
4535 var
->value
, trunk
->name
);
4536 trunk
->ring_timeout
= 0;
4538 } else if (!strcasecmp(var
->name
, "barge"))
4539 trunk
->barge_disabled
= ast_false(var
->value
);
4540 else if (!strcasecmp(var
->name
, "hold")) {
4541 if (!strcasecmp(var
->value
, "private"))
4542 trunk
->hold_access
= SLA_HOLD_PRIVATE
;
4543 else if (!strcasecmp(var
->value
, "open"))
4544 trunk
->hold_access
= SLA_HOLD_OPEN
;
4546 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on trunk %s\n",
4547 var
->value
, trunk
->name
);
4549 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4550 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4551 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4555 if (!ast_strlen_zero(trunk
->autocontext
)) {
4556 struct ast_context
*context
;
4557 context
= ast_context_find_or_create(NULL
, trunk
->autocontext
, sla_registrar
);
4559 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4560 "context '%s' for SLA!\n", trunk
->autocontext
);
4561 destroy_trunk(trunk
);
4564 if (ast_add_extension2(context
, 0 /* don't replace */, "s", 1,
4565 NULL
, NULL
, slatrunk_app
, ast_strdup(trunk
->name
), ast_free
, sla_registrar
)) {
4566 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4567 "for trunk '%s'!\n", trunk
->name
);
4568 destroy_trunk(trunk
);
4573 AST_RWLIST_WRLOCK(&sla_trunks
);
4574 AST_RWLIST_INSERT_TAIL(&sla_trunks
, trunk
, entry
);
4575 AST_RWLIST_UNLOCK(&sla_trunks
);
4580 static void sla_add_trunk_to_station(struct sla_station
*station
, struct ast_variable
*var
)
4582 struct sla_trunk
*trunk
;
4583 struct sla_trunk_ref
*trunk_ref
;
4584 struct sla_station_ref
*station_ref
;
4585 char *trunk_name
, *options
, *cur
;
4587 options
= ast_strdupa(var
->value
);
4588 trunk_name
= strsep(&options
, ",");
4590 AST_RWLIST_RDLOCK(&sla_trunks
);
4591 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
4592 if (!strcasecmp(trunk
->name
, trunk_name
))
4596 AST_RWLIST_UNLOCK(&sla_trunks
);
4598 ast_log(LOG_ERROR
, "Trunk '%s' not found!\n", var
->value
);
4601 if (!(trunk_ref
= create_trunk_ref(trunk
)))
4603 trunk_ref
->state
= SLA_TRUNK_STATE_IDLE
;
4605 while ((cur
= strsep(&options
, ","))) {
4606 char *name
, *value
= cur
;
4607 name
= strsep(&value
, "=");
4608 if (!strcasecmp(name
, "ringtimeout")) {
4609 if (sscanf(value
, "%u", &trunk_ref
->ring_timeout
) != 1) {
4610 ast_log(LOG_WARNING
, "Invalid ringtimeout value '%s' for "
4611 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4612 trunk_ref
->ring_timeout
= 0;
4614 } else if (!strcasecmp(name
, "ringdelay")) {
4615 if (sscanf(value
, "%u", &trunk_ref
->ring_delay
) != 1) {
4616 ast_log(LOG_WARNING
, "Invalid ringdelay value '%s' for "
4617 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4618 trunk_ref
->ring_delay
= 0;
4621 ast_log(LOG_WARNING
, "Invalid option '%s' for "
4622 "trunk '%s' on station '%s'\n", name
, trunk
->name
, station
->name
);
4626 if (!(station_ref
= sla_create_station_ref(station
))) {
4630 ast_atomic_fetchadd_int((int *) &trunk
->num_stations
, 1);
4631 AST_RWLIST_WRLOCK(&sla_trunks
);
4632 AST_LIST_INSERT_TAIL(&trunk
->stations
, station_ref
, entry
);
4633 AST_RWLIST_UNLOCK(&sla_trunks
);
4634 AST_LIST_INSERT_TAIL(&station
->trunks
, trunk_ref
, entry
);
4637 static int sla_build_station(struct ast_config
*cfg
, const char *cat
)
4639 struct sla_station
*station
;
4640 struct ast_variable
*var
;
4643 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4644 ast_log(LOG_ERROR
, "SLA Station '%s' defined with no device!\n", cat
);
4648 if (!(station
= ast_calloc(1, sizeof(*station
))))
4650 if (ast_string_field_init(station
, 32)) {
4655 ast_string_field_set(station
, name
, cat
);
4656 ast_string_field_set(station
, device
, dev
);
4658 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4659 if (!strcasecmp(var
->name
, "trunk"))
4660 sla_add_trunk_to_station(station
, var
);
4661 else if (!strcasecmp(var
->name
, "autocontext"))
4662 ast_string_field_set(station
, autocontext
, var
->value
);
4663 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4664 if (sscanf(var
->value
, "%u", &station
->ring_timeout
) != 1) {
4665 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for station '%s'\n",
4666 var
->value
, station
->name
);
4667 station
->ring_timeout
= 0;
4669 } else if (!strcasecmp(var
->name
, "ringdelay")) {
4670 if (sscanf(var
->value
, "%u", &station
->ring_delay
) != 1) {
4671 ast_log(LOG_WARNING
, "Invalid ringdelay '%s' specified for station '%s'\n",
4672 var
->value
, station
->name
);
4673 station
->ring_delay
= 0;
4675 } else if (!strcasecmp(var
->name
, "hold")) {
4676 if (!strcasecmp(var
->value
, "private"))
4677 station
->hold_access
= SLA_HOLD_PRIVATE
;
4678 else if (!strcasecmp(var
->value
, "open"))
4679 station
->hold_access
= SLA_HOLD_OPEN
;
4681 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on station %s\n",
4682 var
->value
, station
->name
);
4685 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4686 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4687 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4691 if (!ast_strlen_zero(station
->autocontext
)) {
4692 struct ast_context
*context
;
4693 struct sla_trunk_ref
*trunk_ref
;
4694 context
= ast_context_find_or_create(NULL
, station
->autocontext
, sla_registrar
);
4696 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4697 "context '%s' for SLA!\n", station
->autocontext
);
4698 destroy_station(station
);
4701 /* The extension for when the handset goes off-hook.
4702 * exten => station1,1,SLAStation(station1) */
4703 if (ast_add_extension2(context
, 0 /* don't replace */, station
->name
, 1,
4704 NULL
, NULL
, slastation_app
, ast_strdup(station
->name
), ast_free
, sla_registrar
)) {
4705 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4706 "for trunk '%s'!\n", station
->name
);
4707 destroy_station(station
);
4710 AST_RWLIST_RDLOCK(&sla_trunks
);
4711 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4712 char exten
[AST_MAX_EXTENSION
];
4713 char hint
[AST_MAX_APP
];
4714 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4715 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4716 /* Extension for this line button
4717 * exten => station1_line1,1,SLAStation(station1_line1) */
4718 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, 1,
4719 NULL
, NULL
, slastation_app
, ast_strdup(exten
), ast_free
, sla_registrar
)) {
4720 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4721 "for trunk '%s'!\n", station
->name
);
4722 destroy_station(station
);
4725 /* Hint for this line button
4726 * exten => station1_line1,hint,SLA:station1_line1 */
4727 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, PRIORITY_HINT
,
4728 NULL
, NULL
, hint
, NULL
, NULL
, sla_registrar
)) {
4729 ast_log(LOG_ERROR
, "Failed to automatically create hint "
4730 "for trunk '%s'!\n", station
->name
);
4731 destroy_station(station
);
4735 AST_RWLIST_UNLOCK(&sla_trunks
);
4738 AST_RWLIST_WRLOCK(&sla_stations
);
4739 AST_RWLIST_INSERT_TAIL(&sla_stations
, station
, entry
);
4740 AST_RWLIST_UNLOCK(&sla_stations
);
4745 static int sla_load_config(void)
4747 struct ast_config
*cfg
;
4748 const char *cat
= NULL
;
4752 ast_mutex_init(&sla
.lock
);
4753 ast_cond_init(&sla
.cond
, NULL
);
4755 if (!(cfg
= ast_config_load(SLA_CONFIG_FILE
)))
4756 return 0; /* Treat no config as normal */
4758 if ((val
= ast_variable_retrieve(cfg
, "general", "attemptcallerid")))
4759 sla
.attempt_callerid
= ast_true(val
);
4761 while ((cat
= ast_category_browse(cfg
, cat
)) && !res
) {
4763 if (!strcasecmp(cat
, "general"))
4765 if (!(type
= ast_variable_retrieve(cfg
, cat
, "type"))) {
4766 ast_log(LOG_WARNING
, "Invalid entry in %s defined with no type!\n",
4770 if (!strcasecmp(type
, "trunk"))
4771 res
= sla_build_trunk(cfg
, cat
);
4772 else if (!strcasecmp(type
, "station"))
4773 res
= sla_build_station(cfg
, cat
);
4775 ast_log(LOG_WARNING
, "Entry in %s defined with invalid type '%s'!\n",
4776 SLA_CONFIG_FILE
, type
);
4780 ast_config_destroy(cfg
);
4782 ast_pthread_create(&sla
.thread
, NULL
, sla_thread
, NULL
);
4787 static int load_config(int reload
)
4791 load_config_meetme();
4793 res
= sla_load_config();
4798 static int unload_module(void)
4802 ast_cli_unregister_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4803 res
= ast_manager_unregister("MeetmeMute");
4804 res
|= ast_manager_unregister("MeetmeUnmute");
4805 res
|= ast_unregister_application(app3
);
4806 res
|= ast_unregister_application(app2
);
4807 res
|= ast_unregister_application(app
);
4808 res
|= ast_unregister_application(slastation_app
);
4809 res
|= ast_unregister_application(slatrunk_app
);
4811 ast_devstate_prov_del("Meetme");
4812 ast_devstate_prov_del("SLA");
4814 ast_module_user_hangup_all();
4821 static int load_module(void)
4825 res
|= load_config(0);
4827 ast_cli_register_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4828 res
|= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL
,
4829 action_meetmemute
, "Mute a Meetme user");
4830 res
|= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL
,
4831 action_meetmeunmute
, "Unmute a Meetme user");
4832 res
|= ast_register_application(app3
, admin_exec
, synopsis3
, descrip3
);
4833 res
|= ast_register_application(app2
, count_exec
, synopsis2
, descrip2
);
4834 res
|= ast_register_application(app
, conf_exec
, synopsis
, descrip
);
4835 res
|= ast_register_application(slastation_app
, sla_station_exec
,
4836 slastation_synopsis
, slastation_desc
);
4837 res
|= ast_register_application(slatrunk_app
, sla_trunk_exec
,
4838 slatrunk_synopsis
, slatrunk_desc
);
4840 res
|= ast_devstate_prov_add("Meetme", meetmestate
);
4841 res
|= ast_devstate_prov_add("SLA", sla_state
);
4846 static int reload(void)
4848 return load_config(1);
4851 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "MeetMe conference bridge",
4852 .load
= load_module
,
4853 .unload
= unload_module
,