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