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>dahdi</depend>
38 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
45 #include <sys/ioctl.h>
47 #include <sys/types.h>
49 #include "asterisk/lock.h"
50 #include "asterisk/file.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/pbx.h"
54 #include "asterisk/module.h"
55 #include "asterisk/config.h"
56 #include "asterisk/app.h"
57 #include "asterisk/dsp.h"
58 #include "asterisk/musiconhold.h"
59 #include "asterisk/manager.h"
60 #include "asterisk/options.h"
61 #include "asterisk/cli.h"
62 #include "asterisk/say.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/translate.h"
65 #include "asterisk/ulaw.h"
66 #include "asterisk/astobj.h"
67 #include "asterisk/devicestate.h"
68 #include "asterisk/dial.h"
69 #include "asterisk/causes.h"
71 #include "asterisk/dahdi_compat.h"
76 #define CONFIG_FILE_NAME "meetme.conf"
77 #define SLA_CONFIG_FILE "sla.conf"
79 /*! each buffer is 20ms, so this is 640ms total */
80 #define DEFAULT_AUDIO_BUFFERS 32
83 ADMINFLAG_MUTED
= (1 << 1), /*!< User is muted */
84 ADMINFLAG_SELFMUTED
= (1 << 2), /*!< User muted self */
85 ADMINFLAG_KICKME
= (1 << 3) /*!< User has been kicked */
88 #define MEETME_DELAYDETECTTALK 300
89 #define MEETME_DELAYDETECTENDTALK 1000
91 #define AST_FRAME_BITS 32
103 enum recording_state
{
105 MEETME_RECORD_STARTED
,
106 MEETME_RECORD_ACTIVE
,
107 MEETME_RECORD_TERMINATE
110 #define CONF_SIZE 320
113 /*! user has admin access on the conference */
114 CONFFLAG_ADMIN
= (1 << 0),
115 /*! If set the user can only receive audio from the conference */
116 CONFFLAG_MONITOR
= (1 << 1),
117 /*! If set asterisk will exit conference when '#' is pressed */
118 CONFFLAG_POUNDEXIT
= (1 << 2),
119 /*! If set asterisk will provide a menu to the user when '*' is pressed */
120 CONFFLAG_STARMENU
= (1 << 3),
121 /*! If set the use can only send audio to the conference */
122 CONFFLAG_TALKER
= (1 << 4),
123 /*! If set there will be no enter or leave sounds */
124 CONFFLAG_QUIET
= (1 << 5),
125 /*! If set, when user joins the conference, they will be told the number
126 * of users that are already in */
127 CONFFLAG_ANNOUNCEUSERCOUNT
= (1 << 6),
128 /*! Set to run AGI Script in Background */
129 CONFFLAG_AGI
= (1 << 7),
130 /*! Set to have music on hold when user is alone in conference */
131 CONFFLAG_MOH
= (1 << 8),
132 /*! If set the MeetMe will return if all marked with this flag left */
133 CONFFLAG_MARKEDEXIT
= (1 << 9),
134 /*! If set, the MeetMe will wait until a marked user enters */
135 CONFFLAG_WAITMARKED
= (1 << 10),
136 /*! If set, the MeetMe will exit to the specified context */
137 CONFFLAG_EXIT_CONTEXT
= (1 << 11),
138 /*! If set, the user will be marked */
139 CONFFLAG_MARKEDUSER
= (1 << 12),
140 /*! If set, user will be ask record name on entry of conference */
141 CONFFLAG_INTROUSER
= (1 << 13),
142 /*! If set, the MeetMe will be recorded */
143 CONFFLAG_RECORDCONF
= (1<< 14),
144 /*! If set, the user will be monitored if the user is talking or not */
145 CONFFLAG_MONITORTALKER
= (1 << 15),
146 CONFFLAG_DYNAMIC
= (1 << 16),
147 CONFFLAG_DYNAMICPIN
= (1 << 17),
148 CONFFLAG_EMPTY
= (1 << 18),
149 CONFFLAG_EMPTYNOPIN
= (1 << 19),
150 CONFFLAG_ALWAYSPROMPT
= (1 << 20),
151 /*! If set, treats talking users as muted users */
152 CONFFLAG_OPTIMIZETALKER
= (1 << 21),
153 /*! If set, won't speak the extra prompt when the first person
154 * enters the conference */
155 CONFFLAG_NOONLYPERSON
= (1 << 22),
156 /*! If set, user will be asked to record name on entry of conference
158 CONFFLAG_INTROUSERNOREVIEW
= (1 << 23),
159 /*! If set, the user will be initially self-muted */
160 CONFFLAG_STARTMUTED
= (1 << 24),
161 /*! Pass DTMF through the conference */
162 CONFFLAG_PASS_DTMF
= (1 << 25),
163 /*! This is a SLA station. (Only for use by the SLA applications.) */
164 CONFFLAG_SLA_STATION
= (1 << 26),
165 /*! This is a SLA trunk. (Only for use by the SLA applications.) */
166 CONFFLAG_SLA_TRUNK
= (1 << 27),
170 OPT_ARG_WAITMARKED
= 0,
171 OPT_ARG_ARRAY_SIZE
= 1,
174 AST_APP_OPTIONS(meetme_opts
, BEGIN_OPTIONS
175 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER
),
176 AST_APP_OPTION('a', CONFFLAG_ADMIN
),
177 AST_APP_OPTION('b', CONFFLAG_AGI
),
178 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT
),
179 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN
),
180 AST_APP_OPTION('d', CONFFLAG_DYNAMIC
),
181 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN
),
182 AST_APP_OPTION('e', CONFFLAG_EMPTY
),
183 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF
),
184 AST_APP_OPTION('i', CONFFLAG_INTROUSER
),
185 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW
),
186 AST_APP_OPTION('M', CONFFLAG_MOH
),
187 AST_APP_OPTION('m', CONFFLAG_STARTMUTED
),
188 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER
),
189 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT
),
190 AST_APP_OPTION('p', CONFFLAG_POUNDEXIT
),
191 AST_APP_OPTION('q', CONFFLAG_QUIET
),
192 AST_APP_OPTION('r', CONFFLAG_RECORDCONF
),
193 AST_APP_OPTION('s', CONFFLAG_STARMENU
),
194 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER
),
195 AST_APP_OPTION('l', CONFFLAG_MONITOR
),
196 AST_APP_OPTION('t', CONFFLAG_TALKER
),
197 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED
, OPT_ARG_WAITMARKED
),
198 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT
),
199 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT
),
200 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON
),
203 static const char *app
= "MeetMe";
204 static const char *app2
= "MeetMeCount";
205 static const char *app3
= "MeetMeAdmin";
206 static const char *slastation_app
= "SLAStation";
207 static const char *slatrunk_app
= "SLATrunk";
209 static const char *synopsis
= "MeetMe conference bridge";
210 static const char *synopsis2
= "MeetMe participant count";
211 static const char *synopsis3
= "MeetMe conference Administration";
212 static const char *slastation_synopsis
= "Shared Line Appearance Station";
213 static const char *slatrunk_synopsis
= "Shared Line Appearance Trunk";
215 static const char *descrip
=
216 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
217 "conference. If the conference number is omitted, the user will be prompted\n"
218 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
219 "is specified, by pressing '#'.\n"
220 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
221 " must be present for conferencing to operate properly. In addition, the chan_zap\n"
222 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
223 "The option string may contain zero or more of the following characters:\n"
224 " 'a' -- set admin mode\n"
225 " 'A' -- set marked mode\n"
226 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
227 " Default: conf-background.agi (Note: This does not work with\n"
228 " non-Zap channels in the same conference)\n"
229 " 'c' -- announce user(s) count on joining a conference\n"
230 " 'd' -- dynamically add conference\n"
231 " 'D' -- dynamically add conference, prompting for a PIN\n"
232 " 'e' -- select an empty conference\n"
233 " 'E' -- select an empty pinless conference\n"
234 " 'F' -- Pass DTMF through the conference.\n"
235 " 'i' -- announce user join/leave with review\n"
236 " 'I' -- announce user join/leave without review\n"
237 " 'l' -- set listen only mode (Listen only, no talking)\n"
238 " 'm' -- set initially muted\n"
239 " 'M' -- enable music on hold when the conference has a single caller\n"
240 " 'o' -- set talker optimization - treats talkers who aren't speaking as\n"
241 " being muted, meaning (a) No encode is done on transmission and\n"
242 " (b) Received audio that is not registered as talking is omitted\n"
243 " causing no buildup in background noise. Note that this option\n"
244 " will be removed in 1.6 and enabled by default.\n"
245 " 'p' -- allow user to exit the conference by pressing '#'\n"
246 " 'P' -- always prompt for the pin even if it is specified\n"
247 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
248 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
249 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
250 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
252 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
253 " 't' -- set talk only mode. (Talk only, no listening)\n"
254 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
256 " -- wait until the marked user enters the conference\n"
257 " 'x' -- close the conference when last marked user exits\n"
258 " 'X' -- allow user to exit the conference by entering a valid single\n"
259 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
260 " if that variable is not defined.\n"
261 " '1' -- do not play message when first person enters\n";
263 static const char *descrip2
=
264 " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
265 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
266 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
267 "the channel, unless priority n+1 exists, in which case priority progress will\n"
269 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
271 static const char *descrip3
=
272 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
273 " 'e' -- Eject last user that joined\n"
274 " 'k' -- Kick one user out of conference\n"
275 " 'K' -- Kick all users out of conference\n"
276 " 'l' -- Unlock conference\n"
277 " 'L' -- Lock conference\n"
278 " 'm' -- Unmute one user\n"
279 " 'M' -- Mute one user\n"
280 " 'n' -- Unmute all users in the conference\n"
281 " 'N' -- Mute all non-admin users in the conference\n"
282 " 'r' -- Reset one user's volume settings\n"
283 " 'R' -- Reset all users volume settings\n"
284 " 's' -- Lower entire conference speaking volume\n"
285 " 'S' -- Raise entire conference speaking volume\n"
286 " 't' -- Lower one user's talk volume\n"
287 " 'T' -- Raise one user's talk volume\n"
288 " 'u' -- Lower one user's listen volume\n"
289 " 'U' -- Raise one user's listen volume\n"
290 " 'v' -- Lower entire conference listening volume\n"
291 " 'V' -- Raise entire conference listening volume\n"
294 static const char *slastation_desc
=
295 " SLAStation(station):\n"
296 "This application should be executed by an SLA station. The argument depends\n"
297 "on how the call was initiated. If the phone was just taken off hook, then\n"
298 "the argument \"station\" should be just the station name. If the call was\n"
299 "initiated by pressing a line key, then the station name should be preceded\n"
300 "by an underscore and the trunk name associated with that line button.\n"
301 "For example: \"station1_line1\"."
302 " On exit, this application will set the variable SLASTATION_STATUS to\n"
303 "one of the following values:\n"
304 " FAILURE | CONGESTION | SUCCESS\n"
307 static const char *slatrunk_desc
=
308 " SLATrunk(trunk):\n"
309 "This application should be executed by an SLA trunk on an inbound call.\n"
310 "The channel calling this application should correspond to the SLA trunk\n"
311 "with the name \"trunk\" that is being passed as an argument.\n"
312 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
313 "one of the following values:\n"
314 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
317 #define MAX_CONFNUM 80
320 /*! \brief The MeetMe Conference object */
321 struct ast_conference
{
322 ast_mutex_t playlock
; /*!< Conference specific lock (players) */
323 ast_mutex_t listenlock
; /*!< Conference specific lock (listeners) */
324 char confno
[MAX_CONFNUM
]; /*!< Conference */
325 struct ast_channel
*chan
; /*!< Announcements channel */
326 struct ast_channel
*lchan
; /*!< Listen/Record channel */
327 int fd
; /*!< Announcements fd */
328 int zapconf
; /*!< Zaptel Conf # */
329 int users
; /*!< Number of active users */
330 int markedusers
; /*!< Number of marked users */
331 time_t start
; /*!< Start time (s) */
332 int refcount
; /*!< reference count of usage */
333 enum recording_state recording
:2; /*!< recording status */
334 unsigned int isdynamic
:1; /*!< Created on the fly? */
335 unsigned int locked
:1; /*!< Is the conference locked? */
336 pthread_t recordthread
; /*!< thread for recording */
337 ast_mutex_t recordthreadlock
; /*!< control threads trying to start recordthread */
338 pthread_attr_t attr
; /*!< thread attribute */
339 const char *recordingfilename
; /*!< Filename to record the Conference into */
340 const char *recordingformat
; /*!< Format to record the Conference in */
341 char pin
[MAX_PIN
]; /*!< If protected by a PIN */
342 char pinadmin
[MAX_PIN
]; /*!< If protected by a admin PIN */
343 struct ast_frame
*transframe
[32];
344 struct ast_frame
*origframe
;
345 struct ast_trans_pvt
*transpath
[32];
346 AST_LIST_HEAD_NOLOCK(, ast_conf_user
) userlist
;
347 AST_LIST_ENTRY(ast_conference
) list
;
350 static AST_LIST_HEAD_STATIC(confs
, ast_conference
);
352 static unsigned int conf_map
[1024] = {0, };
355 int desired
; /*!< Desired volume adjustment */
356 int actual
; /*!< Actual volume adjustment (for channels that can't adjust) */
359 struct ast_conf_user
{
360 int user_no
; /*!< User Number */
361 int userflags
; /*!< Flags as set in the conference */
362 int adminflags
; /*!< Flags set by the Admin */
363 struct ast_channel
*chan
; /*!< Connected channel */
364 int talking
; /*!< Is user talking */
365 int zapchannel
; /*!< Is a Zaptel channel */
366 char usrvalue
[50]; /*!< Custom User Value */
367 char namerecloc
[PATH_MAX
]; /*!< Name Recorded file Location */
368 time_t jointime
; /*!< Time the user joined the conference */
370 struct volume listen
;
371 AST_LIST_ENTRY(ast_conf_user
) list
;
374 enum sla_which_trunk_refs
{
379 enum sla_trunk_state
{
380 SLA_TRUNK_STATE_IDLE
,
381 SLA_TRUNK_STATE_RINGING
,
383 SLA_TRUNK_STATE_ONHOLD
,
384 SLA_TRUNK_STATE_ONHOLD_BYME
,
387 enum sla_hold_access
{
388 /*! This means that any station can put it on hold, and any station
389 * can retrieve the call from hold. */
391 /*! This means that only the station that put the call on hold may
392 * retrieve it from hold. */
396 struct sla_trunk_ref
;
399 AST_RWLIST_ENTRY(sla_station
) entry
;
400 AST_DECLARE_STRING_FIELDS(
401 AST_STRING_FIELD(name
);
402 AST_STRING_FIELD(device
);
403 AST_STRING_FIELD(autocontext
);
405 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref
) trunks
;
406 struct ast_dial
*dial
;
407 /*! Ring timeout for this station, for any trunk. If a ring timeout
408 * is set for a specific trunk on this station, that will take
409 * priority over this value. */
410 unsigned int ring_timeout
;
411 /*! Ring delay for this station, for any trunk. If a ring delay
412 * is set for a specific trunk on this station, that will take
413 * priority over this value. */
414 unsigned int ring_delay
;
415 /*! This option uses the values in the sla_hold_access enum and sets the
416 * access control type for hold on this station. */
417 unsigned int hold_access
:1;
420 struct sla_station_ref
{
421 AST_LIST_ENTRY(sla_station_ref
) entry
;
422 struct sla_station
*station
;
426 AST_RWLIST_ENTRY(sla_trunk
) entry
;
427 AST_DECLARE_STRING_FIELDS(
428 AST_STRING_FIELD(name
);
429 AST_STRING_FIELD(device
);
430 AST_STRING_FIELD(autocontext
);
432 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) stations
;
433 /*! Number of stations that use this trunk */
434 unsigned int num_stations
;
435 /*! Number of stations currently on a call with this trunk */
436 unsigned int active_stations
;
437 /*! Number of stations that have this trunk on hold. */
438 unsigned int hold_stations
;
439 struct ast_channel
*chan
;
440 unsigned int ring_timeout
;
441 /*! If set to 1, no station will be able to join an active call with
443 unsigned int barge_disabled
:1;
444 /*! This option uses the values in the sla_hold_access enum and sets the
445 * access control type for hold on this trunk. */
446 unsigned int hold_access
:1;
447 /*! Whether this trunk is currently on hold, meaning that once a station
448 * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
449 unsigned int on_hold
:1;
452 struct sla_trunk_ref
{
453 AST_LIST_ENTRY(sla_trunk_ref
) entry
;
454 struct sla_trunk
*trunk
;
455 enum sla_trunk_state state
;
456 struct ast_channel
*chan
;
457 /*! Ring timeout to use when this trunk is ringing on this specific
458 * station. This takes higher priority than a ring timeout set at
459 * the station level. */
460 unsigned int ring_timeout
;
461 /*! Ring delay to use when this trunk is ringing on this specific
462 * station. This takes higher priority than a ring delay set at
463 * the station level. */
464 unsigned int ring_delay
;
467 static AST_RWLIST_HEAD_STATIC(sla_stations
, sla_station
);
468 static AST_RWLIST_HEAD_STATIC(sla_trunks
, sla_trunk
);
470 static const char sla_registrar
[] = "SLA";
472 /*! \brief Event types that can be queued up for the SLA thread */
473 enum sla_event_type
{
474 /*! A station has put the call on hold */
476 /*! The state of a dial has changed */
477 SLA_EVENT_DIAL_STATE
,
478 /*! The state of a ringing trunk has changed */
479 SLA_EVENT_RINGING_TRUNK
,
483 enum sla_event_type type
;
484 struct sla_station
*station
;
485 struct sla_trunk_ref
*trunk_ref
;
486 AST_LIST_ENTRY(sla_event
) entry
;
489 /*! \brief A station that failed to be dialed
490 * \note Only used by the SLA thread. */
491 struct sla_failed_station
{
492 struct sla_station
*station
;
493 struct timeval last_try
;
494 AST_LIST_ENTRY(sla_failed_station
) entry
;
497 /*! \brief A trunk that is ringing */
498 struct sla_ringing_trunk
{
499 struct sla_trunk
*trunk
;
500 /*! The time that this trunk started ringing */
501 struct timeval ring_begin
;
502 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) timed_out_stations
;
503 AST_LIST_ENTRY(sla_ringing_trunk
) entry
;
506 enum sla_station_hangup
{
507 SLA_STATION_HANGUP_NORMAL
,
508 SLA_STATION_HANGUP_TIMEOUT
,
511 /*! \brief A station that is ringing */
512 struct sla_ringing_station
{
513 struct sla_station
*station
;
514 /*! The time that this station started ringing */
515 struct timeval ring_begin
;
516 AST_LIST_ENTRY(sla_ringing_station
) entry
;
520 * \brief A structure for data used by the sla thread
523 /*! The SLA thread ID */
527 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk
) ringing_trunks
;
528 AST_LIST_HEAD_NOLOCK(, sla_ringing_station
) ringing_stations
;
529 AST_LIST_HEAD_NOLOCK(, sla_failed_station
) failed_stations
;
530 AST_LIST_HEAD_NOLOCK(, sla_event
) event_q
;
532 /*! Attempt to handle CallerID, even though it is known not to work
533 * properly in some situations. */
534 unsigned int attempt_callerid
:1;
536 .thread
= AST_PTHREADT_NULL
,
539 /*! The number of audio buffers to be allocated on pseudo channels
540 * when in a conference */
541 static int audio_buffers
;
543 /*! Map 'volume' levels from -5 through +5 into
544 * decibel (dB) settings for channel drivers
545 * Note: these are not a straight linear-to-dB
546 * conversion... the numbers have been modified
547 * to give the user a better level of adjustability
549 static char const gain_map
[] = {
564 static int admin_exec(struct ast_channel
*chan
, void *data
);
565 static void *recordthread(void *args
);
567 static char *istalking(int x
)
572 return "(unmonitored)";
574 return "(not talking)";
577 static int careful_write(int fd
, unsigned char *data
, int len
, int block
)
584 x
= DAHDI_IOMUX_WRITE
| DAHDI_IOMUX_SIGEVENT
;
585 res
= ioctl(fd
, DAHDI_IOMUX
, &x
);
589 res
= write(fd
, data
, len
);
591 if (errno
!= EAGAIN
) {
592 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
604 static int set_talk_volume(struct ast_conf_user
*user
, int volume
)
608 /* attempt to make the adjustment in the channel driver;
609 if successful, don't adjust in the frame reading routine
611 gain_adjust
= gain_map
[volume
+ 5];
613 return ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
616 static int set_listen_volume(struct ast_conf_user
*user
, int volume
)
620 /* attempt to make the adjustment in the channel driver;
621 if successful, don't adjust in the frame reading routine
623 gain_adjust
= gain_map
[volume
+ 5];
625 return ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
628 static void tweak_volume(struct volume
*vol
, enum volume_action action
)
632 switch (vol
->desired
) {
647 switch (vol
->desired
) {
663 static void tweak_talk_volume(struct ast_conf_user
*user
, enum volume_action action
)
665 tweak_volume(&user
->talk
, action
);
666 /* attempt to make the adjustment in the channel driver;
667 if successful, don't adjust in the frame reading routine
669 if (!set_talk_volume(user
, user
->talk
.desired
))
670 user
->talk
.actual
= 0;
672 user
->talk
.actual
= user
->talk
.desired
;
675 static void tweak_listen_volume(struct ast_conf_user
*user
, enum volume_action action
)
677 tweak_volume(&user
->listen
, action
);
678 /* attempt to make the adjustment in the channel driver;
679 if successful, don't adjust in the frame reading routine
681 if (!set_listen_volume(user
, user
->listen
.desired
))
682 user
->listen
.actual
= 0;
684 user
->listen
.actual
= user
->listen
.desired
;
687 static void reset_volumes(struct ast_conf_user
*user
)
689 signed char zero_volume
= 0;
691 ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
692 ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
695 static void conf_play(struct ast_channel
*chan
, struct ast_conference
*conf
, enum entrance_sound sound
)
701 if (!chan
->_softhangup
)
702 res
= ast_autoservice_start(chan
);
704 AST_LIST_LOCK(&confs
);
720 careful_write(conf
->fd
, data
, len
, 1);
723 AST_LIST_UNLOCK(&confs
);
726 ast_autoservice_stop(chan
);
730 * \brief Find or create a conference
732 * \param confno The conference name/number
733 * \param pin The regular user pin
734 * \param pinadmin The admin pin
735 * \param make Make the conf if it doesn't exist
736 * \param dynamic Mark the newly created conference as dynamic
737 * \param refcount How many references to mark on the conference
739 * \return A pointer to the conference struct, or NULL if it wasn't found and
740 * make or dynamic were not set.
742 static struct ast_conference
*build_conf(char *confno
, char *pin
, char *pinadmin
, int make
, int dynamic
, int refcount
)
744 struct ast_conference
*cnf
;
745 DAHDI_CONFINFO ztc
= { 0, };
748 AST_LIST_LOCK(&confs
);
750 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
751 if (!strcmp(confno
, cnf
->confno
))
755 if (cnf
|| (!make
&& !dynamic
))
759 if (!(cnf
= ast_calloc(1, sizeof(*cnf
))))
762 ast_mutex_init(&cnf
->playlock
);
763 ast_mutex_init(&cnf
->listenlock
);
764 cnf
->recordthread
= AST_PTHREADT_NULL
;
765 ast_mutex_init(&cnf
->recordthreadlock
);
766 ast_copy_string(cnf
->confno
, confno
, sizeof(cnf
->confno
));
767 ast_copy_string(cnf
->pin
, pin
, sizeof(cnf
->pin
));
768 ast_copy_string(cnf
->pinadmin
, pinadmin
, sizeof(cnf
->pinadmin
));
770 /* Setup a new zap conference */
772 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
773 cnf
->fd
= open("/dev/zap/pseudo", O_RDWR
);
774 if (cnf
->fd
< 0 || ioctl(cnf
->fd
, DAHDI_SETCONF
, &ztc
)) {
775 ast_log(LOG_WARNING
, "Unable to open pseudo device\n");
783 cnf
->zapconf
= ztc
.confno
;
785 /* Setup a new channel for playback of audio files */
786 cnf
->chan
= ast_request("zap", AST_FORMAT_SLINEAR
, "pseudo", NULL
);
788 ast_set_read_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
789 ast_set_write_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
791 ztc
.confno
= cnf
->zapconf
;
792 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
793 if (ioctl(cnf
->chan
->fds
[0], DAHDI_SETCONF
, &ztc
)) {
794 ast_log(LOG_WARNING
, "Error setting conference\n");
796 ast_hangup(cnf
->chan
);
805 /* Fill the conference struct */
806 cnf
->start
= time(NULL
);
807 cnf
->isdynamic
= dynamic
? 1 : 0;
808 if (option_verbose
> 2)
809 ast_verbose(VERBOSE_PREFIX_3
"Created MeetMe conference %d for conference '%s'\n", cnf
->zapconf
, cnf
->confno
);
810 AST_LIST_INSERT_HEAD(&confs
, cnf
, list
);
812 /* Reserve conference number in map */
813 if ((sscanf(cnf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
814 conf_map
[confno_int
] = 1;
818 ast_atomic_fetchadd_int(&cnf
->refcount
, refcount
);
820 AST_LIST_UNLOCK(&confs
);
825 static int meetme_cmd(int fd
, int argc
, char **argv
)
827 /* Process the command */
828 struct ast_conference
*cnf
;
829 struct ast_conf_user
*user
;
831 int i
= 0, total
= 0;
833 char *header_format
= "%-14s %-14s %-10s %-8s %-8s\n";
834 char *data_format
= "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
835 char cmdline
[1024] = "";
838 ast_cli(fd
, "Invalid Arguments.\n");
839 /* Check for length so no buffer will overflow... */
840 for (i
= 0; i
< argc
; i
++) {
841 if (strlen(argv
[i
]) > 100)
842 ast_cli(fd
, "Invalid Arguments.\n");
845 /* 'MeetMe': List all the conferences */
847 AST_LIST_LOCK(&confs
);
848 if (AST_LIST_EMPTY(&confs
)) {
849 ast_cli(fd
, "No active MeetMe conferences.\n");
850 AST_LIST_UNLOCK(&confs
);
851 return RESULT_SUCCESS
;
853 ast_cli(fd
, header_format
, "Conf Num", "Parties", "Marked", "Activity", "Creation");
854 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
855 if (cnf
->markedusers
== 0)
856 strcpy(cmdline
, "N/A ");
858 snprintf(cmdline
, sizeof(cmdline
), "%4.4d", cnf
->markedusers
);
859 hr
= (now
- cnf
->start
) / 3600;
860 min
= ((now
- cnf
->start
) % 3600) / 60;
861 sec
= (now
- cnf
->start
) % 60;
863 ast_cli(fd
, data_format
, cnf
->confno
, cnf
->users
, cmdline
, hr
, min
, sec
, cnf
->isdynamic
? "Dynamic" : "Static");
867 AST_LIST_UNLOCK(&confs
);
868 ast_cli(fd
, "* Total number of MeetMe users: %d\n", total
);
869 return RESULT_SUCCESS
;
872 return RESULT_SHOWUSAGE
;
873 ast_copy_string(cmdline
, argv
[2], sizeof(cmdline
)); /* Argv 2: conference number */
874 if (strstr(argv
[1], "lock")) {
875 if (strcmp(argv
[1], "lock") == 0) {
877 strncat(cmdline
, "|L", sizeof(cmdline
) - strlen(cmdline
) - 1);
880 strncat(cmdline
, "|l", sizeof(cmdline
) - strlen(cmdline
) - 1);
882 } else if (strstr(argv
[1], "mute")) {
884 return RESULT_SHOWUSAGE
;
885 if (strcmp(argv
[1], "mute") == 0) {
887 if (strcmp(argv
[3], "all") == 0) {
888 strncat(cmdline
, "|N", sizeof(cmdline
) - strlen(cmdline
) - 1);
890 strncat(cmdline
, "|M|", sizeof(cmdline
) - strlen(cmdline
) - 1);
891 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
895 if (strcmp(argv
[3], "all") == 0) {
896 strncat(cmdline
, "|n", sizeof(cmdline
) - strlen(cmdline
) - 1);
898 strncat(cmdline
, "|m|", sizeof(cmdline
) - strlen(cmdline
) - 1);
899 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
902 } else if (strcmp(argv
[1], "kick") == 0) {
904 return RESULT_SHOWUSAGE
;
905 if (strcmp(argv
[3], "all") == 0) {
907 strncat(cmdline
, "|K", sizeof(cmdline
) - strlen(cmdline
) - 1);
909 /* Kick a single user */
910 strncat(cmdline
, "|k|", sizeof(cmdline
) - strlen(cmdline
) - 1);
911 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
913 } else if(strcmp(argv
[1], "list") == 0) {
914 int concise
= ( 4 == argc
&& ( !strcasecmp(argv
[3], "concise") ) );
915 /* List all the users in a conference */
916 if (AST_LIST_EMPTY(&confs
)) {
918 ast_cli(fd
, "No active conferences.\n");
919 return RESULT_SUCCESS
;
921 /* Find the right conference */
922 AST_LIST_LOCK(&confs
);
923 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
924 if (strcmp(cnf
->confno
, argv
[2]) == 0)
929 ast_cli(fd
, "No such conference: %s.\n",argv
[2]);
930 AST_LIST_UNLOCK(&confs
);
931 return RESULT_SUCCESS
;
933 /* Show all the users */
935 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
936 hr
= (now
- user
->jointime
) / 3600;
937 min
= ((now
- user
->jointime
) % 3600) / 60;
938 sec
= (now
- user
->jointime
) % 60;
940 ast_cli(fd
, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
942 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
943 S_OR(user
->chan
->cid
.cid_name
, "<no name>"),
945 user
->userflags
& CONFFLAG_ADMIN
? "(Admin)" : "",
946 user
->userflags
& CONFFLAG_MONITOR
? "(Listen only)" : "",
947 user
->adminflags
& ADMINFLAG_MUTED
? "(Admin Muted)" : user
->adminflags
& ADMINFLAG_SELFMUTED
? "(Muted)" : "",
948 istalking(user
->talking
), hr
, min
, sec
);
950 ast_cli(fd
, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
952 S_OR(user
->chan
->cid
.cid_num
, ""),
953 S_OR(user
->chan
->cid
.cid_name
, ""),
955 user
->userflags
& CONFFLAG_ADMIN
? "1" : "",
956 user
->userflags
& CONFFLAG_MONITOR
? "1" : "",
957 user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
) ? "1" : "",
958 user
->talking
, hr
, min
, sec
);
962 ast_cli(fd
,"%d users in that conference.\n",cnf
->users
);
963 AST_LIST_UNLOCK(&confs
);
964 return RESULT_SUCCESS
;
966 return RESULT_SHOWUSAGE
;
967 ast_log(LOG_DEBUG
, "Cmdline: %s\n", cmdline
);
968 admin_exec(NULL
, cmdline
);
973 static char *complete_meetmecmd(const char *line
, const char *word
, int pos
, int state
)
975 static char *cmds
[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL
};
977 int len
= strlen(word
);
979 struct ast_conference
*cnf
= NULL
;
980 struct ast_conf_user
*usr
= NULL
;
983 char *myline
, *ret
= NULL
;
985 if (pos
== 1) { /* Command */
986 return ast_cli_complete(word
, cmds
, state
);
987 } else if (pos
== 2) { /* Conference Number */
988 AST_LIST_LOCK(&confs
);
989 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
990 if (!strncasecmp(word
, cnf
->confno
, len
) && ++which
> state
) {
995 ret
= ast_strdup(ret
); /* dup before releasing the lock */
996 AST_LIST_UNLOCK(&confs
);
998 } else if (pos
== 3) {
999 /* User Number || Conf Command option*/
1000 if (strstr(line
, "mute") || strstr(line
, "kick")) {
1001 if (state
== 0 && (strstr(line
, "kick") || strstr(line
,"mute")) && !strncasecmp(word
, "all", len
))
1002 return strdup("all");
1004 AST_LIST_LOCK(&confs
);
1006 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
1007 myline
= ast_strdupa(line
);
1008 if (strsep(&myline
, " ") && strsep(&myline
, " ") && !confno
) {
1009 while((confno
= strsep(&myline
, " ")) && (strcmp(confno
, " ") == 0))
1013 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
1014 if (!strcmp(confno
, cnf
->confno
))
1019 /* Search for the user */
1020 AST_LIST_TRAVERSE(&cnf
->userlist
, usr
, list
) {
1021 snprintf(usrno
, sizeof(usrno
), "%d", usr
->user_no
);
1022 if (!strncasecmp(word
, usrno
, len
) && ++which
> state
)
1026 AST_LIST_UNLOCK(&confs
);
1027 return usr
? strdup(usrno
) : NULL
;
1028 } else if ( strstr(line
, "list") && ( 0 == state
) )
1029 return strdup("concise");
1035 static char meetme_usage
[] =
1036 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
1037 " Executes a command for the conference or on a conferee\n";
1039 static const char *sla_hold_str(unsigned int hold_access
)
1041 const char *hold
= "Unknown";
1043 switch (hold_access
) {
1047 case SLA_HOLD_PRIVATE
:
1056 static int sla_show_trunks(int fd
, int argc
, char **argv
)
1058 const struct sla_trunk
*trunk
;
1061 "=============================================================\n"
1062 "=== Configured SLA Trunks ===================================\n"
1063 "=============================================================\n"
1065 AST_RWLIST_RDLOCK(&sla_trunks
);
1066 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
1067 struct sla_station_ref
*station_ref
;
1068 char ring_timeout
[16] = "(none)";
1069 if (trunk
->ring_timeout
)
1070 snprintf(ring_timeout
, sizeof(ring_timeout
), "%u Seconds", trunk
->ring_timeout
);
1071 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1072 "=== Trunk Name: %s\n"
1073 "=== ==> Device: %s\n"
1074 "=== ==> AutoContext: %s\n"
1075 "=== ==> RingTimeout: %s\n"
1076 "=== ==> BargeAllowed: %s\n"
1077 "=== ==> HoldAccess: %s\n"
1078 "=== ==> Stations ...\n",
1079 trunk
->name
, trunk
->device
,
1080 S_OR(trunk
->autocontext
, "(none)"),
1082 trunk
->barge_disabled
? "No" : "Yes",
1083 sla_hold_str(trunk
->hold_access
));
1084 AST_RWLIST_RDLOCK(&sla_stations
);
1085 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
)
1086 ast_cli(fd
, "=== ==> Station name: %s\n", station_ref
->station
->name
);
1087 AST_RWLIST_UNLOCK(&sla_stations
);
1088 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1091 AST_RWLIST_UNLOCK(&sla_trunks
);
1092 ast_cli(fd
, "=============================================================\n"
1095 return RESULT_SUCCESS
;
1098 static const char *trunkstate2str(enum sla_trunk_state state
)
1100 #define S(e) case e: return # e;
1102 S(SLA_TRUNK_STATE_IDLE
)
1103 S(SLA_TRUNK_STATE_RINGING
)
1104 S(SLA_TRUNK_STATE_UP
)
1105 S(SLA_TRUNK_STATE_ONHOLD
)
1106 S(SLA_TRUNK_STATE_ONHOLD_BYME
)
1108 return "Uknown State";
1112 static const char sla_show_trunks_usage
[] =
1113 "Usage: sla show trunks\n"
1114 " This will list all trunks defined in sla.conf\n";
1116 static int sla_show_stations(int fd
, int argc
, char **argv
)
1118 const struct sla_station
*station
;
1121 "=============================================================\n"
1122 "=== Configured SLA Stations =================================\n"
1123 "=============================================================\n"
1125 AST_RWLIST_RDLOCK(&sla_stations
);
1126 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1127 struct sla_trunk_ref
*trunk_ref
;
1128 char ring_timeout
[16] = "(none)";
1129 char ring_delay
[16] = "(none)";
1130 if (station
->ring_timeout
) {
1131 snprintf(ring_timeout
, sizeof(ring_timeout
),
1132 "%u", station
->ring_timeout
);
1134 if (station
->ring_delay
) {
1135 snprintf(ring_delay
, sizeof(ring_delay
),
1136 "%u", station
->ring_delay
);
1138 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1139 "=== Station Name: %s\n"
1140 "=== ==> Device: %s\n"
1141 "=== ==> AutoContext: %s\n"
1142 "=== ==> RingTimeout: %s\n"
1143 "=== ==> RingDelay: %s\n"
1144 "=== ==> HoldAccess: %s\n"
1145 "=== ==> Trunks ...\n",
1146 station
->name
, station
->device
,
1147 S_OR(station
->autocontext
, "(none)"),
1148 ring_timeout
, ring_delay
,
1149 sla_hold_str(station
->hold_access
));
1150 AST_RWLIST_RDLOCK(&sla_trunks
);
1151 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1152 if (trunk_ref
->ring_timeout
) {
1153 snprintf(ring_timeout
, sizeof(ring_timeout
),
1154 "%u", trunk_ref
->ring_timeout
);
1156 strcpy(ring_timeout
, "(none)");
1157 if (trunk_ref
->ring_delay
) {
1158 snprintf(ring_delay
, sizeof(ring_delay
),
1159 "%u", trunk_ref
->ring_delay
);
1161 strcpy(ring_delay
, "(none)");
1162 ast_cli(fd
, "=== ==> Trunk Name: %s\n"
1163 "=== ==> State: %s\n"
1164 "=== ==> RingTimeout: %s\n"
1165 "=== ==> RingDelay: %s\n",
1166 trunk_ref
->trunk
->name
,
1167 trunkstate2str(trunk_ref
->state
),
1168 ring_timeout
, ring_delay
);
1170 AST_RWLIST_UNLOCK(&sla_trunks
);
1171 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1174 AST_RWLIST_UNLOCK(&sla_stations
);
1175 ast_cli(fd
, "============================================================\n"
1178 return RESULT_SUCCESS
;
1181 static const char sla_show_stations_usage
[] =
1182 "Usage: sla show stations\n"
1183 " This will list all stations defined in sla.conf\n";
1185 static struct ast_cli_entry cli_meetme
[] = {
1186 { { "meetme", NULL
, NULL
},
1187 meetme_cmd
, "Execute a command on a conference or conferee",
1188 meetme_usage
, complete_meetmecmd
},
1190 { { "sla", "show", "trunks", NULL
},
1191 sla_show_trunks
, "Show SLA Trunks",
1192 sla_show_trunks_usage
, NULL
},
1194 { { "sla", "show", "stations", NULL
},
1195 sla_show_stations
, "Show SLA Stations",
1196 sla_show_stations_usage
, NULL
},
1199 static void conf_flush(int fd
, struct ast_channel
*chan
)
1203 /* read any frames that may be waiting on the channel
1207 struct ast_frame
*f
;
1209 /* when no frames are available, this will wait
1210 for 1 millisecond maximum
1212 while (ast_waitfor(chan
, 1)) {
1216 else /* channel was hung up or something else happened */
1221 /* flush any data sitting in the pseudo channel */
1222 x
= DAHDI_FLUSH_ALL
;
1223 if (ioctl(fd
, DAHDI_FLUSH
, &x
))
1224 ast_log(LOG_WARNING
, "Error flushing channel\n");
1228 /* Remove the conference from the list and free it.
1229 We assume that this was called while holding conflock. */
1230 static int conf_free(struct ast_conference
*conf
)
1234 AST_LIST_REMOVE(&confs
, conf
, list
);
1236 if (conf
->recording
== MEETME_RECORD_ACTIVE
) {
1237 conf
->recording
= MEETME_RECORD_TERMINATE
;
1238 AST_LIST_UNLOCK(&confs
);
1241 AST_LIST_LOCK(&confs
);
1242 if (conf
->recording
== MEETME_RECORD_OFF
)
1244 AST_LIST_UNLOCK(&confs
);
1248 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
1249 if (conf
->transframe
[x
])
1250 ast_frfree(conf
->transframe
[x
]);
1251 if (conf
->transpath
[x
])
1252 ast_translator_free_path(conf
->transpath
[x
]);
1254 if (conf
->origframe
)
1255 ast_frfree(conf
->origframe
);
1257 ast_hangup(conf
->lchan
);
1259 ast_hangup(conf
->chan
);
1263 ast_mutex_destroy(&conf
->playlock
);
1264 ast_mutex_destroy(&conf
->listenlock
);
1265 ast_mutex_destroy(&conf
->recordthreadlock
);
1271 static void conf_queue_dtmf(const struct ast_conference
*conf
,
1272 const struct ast_conf_user
*sender
, struct ast_frame
*f
)
1274 struct ast_conf_user
*user
;
1276 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
1279 if (ast_write(user
->chan
, f
) < 0)
1280 ast_log(LOG_WARNING
, "Error writing frame to channel %s\n", user
->chan
->name
);
1284 static void sla_queue_event_full(enum sla_event_type type
,
1285 struct sla_trunk_ref
*trunk_ref
, struct sla_station
*station
, int lock
)
1287 struct sla_event
*event
;
1289 if (!(event
= ast_calloc(1, sizeof(*event
))))
1293 event
->trunk_ref
= trunk_ref
;
1294 event
->station
= station
;
1297 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1301 ast_mutex_lock(&sla
.lock
);
1302 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1303 ast_cond_signal(&sla
.cond
);
1304 ast_mutex_unlock(&sla
.lock
);
1307 static void sla_queue_event_nolock(enum sla_event_type type
)
1309 sla_queue_event_full(type
, NULL
, NULL
, 0);
1312 static void sla_queue_event(enum sla_event_type type
)
1314 sla_queue_event_full(type
, NULL
, NULL
, 1);
1317 /*! \brief Queue a SLA event from the conference */
1318 static void sla_queue_event_conf(enum sla_event_type type
, struct ast_channel
*chan
,
1319 struct ast_conference
*conf
)
1321 struct sla_station
*station
;
1322 struct sla_trunk_ref
*trunk_ref
= NULL
;
1325 trunk_name
= ast_strdupa(conf
->confno
);
1326 strsep(&trunk_name
, "_");
1327 if (ast_strlen_zero(trunk_name
)) {
1328 ast_log(LOG_ERROR
, "Invalid conference name for SLA - '%s'!\n", conf
->confno
);
1332 AST_RWLIST_RDLOCK(&sla_stations
);
1333 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1334 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1335 if (trunk_ref
->chan
== chan
&& !strcmp(trunk_ref
->trunk
->name
, trunk_name
))
1341 AST_RWLIST_UNLOCK(&sla_stations
);
1344 ast_log(LOG_DEBUG
, "Trunk not found for event!\n");
1348 sla_queue_event_full(type
, trunk_ref
, station
, 1);
1351 /* Decrement reference counts, as incremented by find_conf() */
1352 static int dispose_conf(struct ast_conference
*conf
)
1357 AST_LIST_LOCK(&confs
);
1358 if (ast_atomic_dec_and_test(&conf
->refcount
)) {
1359 /* Take the conference room number out of an inuse state */
1360 if ((sscanf(conf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
1361 conf_map
[confno_int
] = 0;
1365 AST_LIST_UNLOCK(&confs
);
1371 static int conf_run(struct ast_channel
*chan
, struct ast_conference
*conf
, int confflags
, char *optargs
[])
1373 struct ast_conf_user
*user
= NULL
;
1374 struct ast_conf_user
*usr
= NULL
;
1376 DAHDI_CONFINFO ztc
, ztc_empty
;
1377 struct ast_frame
*f
;
1378 struct ast_channel
*c
;
1379 struct ast_frame fr
;
1387 int musiconhold
= 0;
1390 int currentmarked
= 0;
1393 int menu_active
= 0;
1394 int using_pseudo
= 0;
1399 struct ast_dsp
*dsp
=NULL
;
1400 struct ast_app
*app
;
1401 const char *agifile
;
1402 const char *agifiledefault
= "conf-background.agi";
1403 char meetmesecs
[30] = "";
1404 char exitcontext
[AST_MAX_CONTEXT
] = "";
1405 char recordingtmp
[AST_MAX_EXTENSION
] = "";
1406 char members
[10] = "";
1407 int dtmf
, opt_waitmarked_timeout
= 0;
1409 DAHDI_BUFFERINFO bi
;
1410 char __buf
[CONF_SIZE
+ AST_FRIENDLY_OFFSET
];
1411 char *buf
= __buf
+ AST_FRIENDLY_OFFSET
;
1412 int setusercount
= 0;
1414 if (!(user
= ast_calloc(1, sizeof(*user
))))
1417 /* Possible timeout waiting for marked user */
1418 if ((confflags
& CONFFLAG_WAITMARKED
) &&
1419 !ast_strlen_zero(optargs
[OPT_ARG_WAITMARKED
]) &&
1420 (sscanf(optargs
[OPT_ARG_WAITMARKED
], "%d", &opt_waitmarked_timeout
) == 1) &&
1421 (opt_waitmarked_timeout
> 0)) {
1422 timeout
= time(NULL
) + opt_waitmarked_timeout
;
1425 if (confflags
& CONFFLAG_RECORDCONF
) {
1426 if (!conf
->recordingfilename
) {
1427 conf
->recordingfilename
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFILE");
1428 if (!conf
->recordingfilename
) {
1429 snprintf(recordingtmp
, sizeof(recordingtmp
), "meetme-conf-rec-%s-%s", conf
->confno
, chan
->uniqueid
);
1430 conf
->recordingfilename
= ast_strdupa(recordingtmp
);
1432 conf
->recordingformat
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFORMAT");
1433 if (!conf
->recordingformat
) {
1434 snprintf(recordingtmp
, sizeof(recordingtmp
), "wav");
1435 conf
->recordingformat
= ast_strdupa(recordingtmp
);
1437 ast_verbose(VERBOSE_PREFIX_4
"Starting recording of MeetMe Conference %s into file %s.%s.\n",
1438 conf
->confno
, conf
->recordingfilename
, conf
->recordingformat
);
1442 ast_mutex_lock(&conf
->recordthreadlock
);
1443 if ((conf
->recordthread
== AST_PTHREADT_NULL
) && (confflags
& CONFFLAG_RECORDCONF
) && ((conf
->lchan
= ast_request("zap", AST_FORMAT_SLINEAR
, "pseudo", NULL
)))) {
1444 ast_set_read_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1445 ast_set_write_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1447 ztc
.confno
= conf
->zapconf
;
1448 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
1449 if (ioctl(conf
->lchan
->fds
[0], DAHDI_SETCONF
, &ztc
)) {
1450 ast_log(LOG_WARNING
, "Error starting listen channel\n");
1451 ast_hangup(conf
->lchan
);
1454 pthread_attr_init(&conf
->attr
);
1455 pthread_attr_setdetachstate(&conf
->attr
, PTHREAD_CREATE_DETACHED
);
1456 ast_pthread_create_background(&conf
->recordthread
, &conf
->attr
, recordthread
, conf
);
1457 pthread_attr_destroy(&conf
->attr
);
1460 ast_mutex_unlock(&conf
->recordthreadlock
);
1462 time(&user
->jointime
);
1464 if (conf
->locked
&& (!(confflags
& CONFFLAG_ADMIN
))) {
1465 /* Sorry, but this confernce is locked! */
1466 if (!ast_streamfile(chan
, "conf-locked", chan
->language
))
1467 ast_waitstream(chan
, "");
1471 ast_mutex_lock(&conf
->playlock
);
1473 if (AST_LIST_EMPTY(&conf
->userlist
))
1476 user
->user_no
= AST_LIST_LAST(&conf
->userlist
)->user_no
+ 1;
1478 AST_LIST_INSERT_TAIL(&conf
->userlist
, user
, list
);
1481 user
->userflags
= confflags
;
1482 user
->adminflags
= (confflags
& CONFFLAG_STARTMUTED
) ? ADMINFLAG_SELFMUTED
: 0;
1485 ast_mutex_unlock(&conf
->playlock
);
1487 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
1488 char destdir
[PATH_MAX
];
1490 snprintf(destdir
, sizeof(destdir
), "%s/meetme", ast_config_AST_SPOOL_DIR
);
1492 if (mkdir(destdir
, 0777) && errno
!= EEXIST
) {
1493 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", destdir
, strerror(errno
));
1497 snprintf(user
->namerecloc
, sizeof(user
->namerecloc
),
1498 "%s/meetme-username-%s-%d", destdir
,
1499 conf
->confno
, user
->user_no
);
1500 if (confflags
& CONFFLAG_INTROUSERNOREVIEW
)
1501 res
= ast_play_and_record(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, 128, 0, NULL
);
1503 res
= ast_record_review(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, NULL
);
1508 ast_mutex_lock(&conf
->playlock
);
1510 if (confflags
& CONFFLAG_MARKEDUSER
)
1511 conf
->markedusers
++;
1514 snprintf(members
, sizeof(members
), "%d", conf
->users
);
1515 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
1518 /* This device changed state now - if this is the first user */
1519 if (conf
->users
== 1)
1520 ast_device_state_changed("meetme:%s", conf
->confno
);
1522 ast_mutex_unlock(&conf
->playlock
);
1524 if (confflags
& CONFFLAG_EXIT_CONTEXT
) {
1525 if ((agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_EXIT_CONTEXT")))
1526 ast_copy_string(exitcontext
, agifile
, sizeof(exitcontext
));
1527 else if (!ast_strlen_zero(chan
->macrocontext
))
1528 ast_copy_string(exitcontext
, chan
->macrocontext
, sizeof(exitcontext
));
1530 ast_copy_string(exitcontext
, chan
->context
, sizeof(exitcontext
));
1533 if ( !(confflags
& (CONFFLAG_QUIET
| CONFFLAG_NOONLYPERSON
)) ) {
1534 if (conf
->users
== 1 && !(confflags
& CONFFLAG_WAITMARKED
))
1535 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1536 ast_waitstream(chan
, "");
1537 if ((confflags
& CONFFLAG_WAITMARKED
) && conf
->markedusers
== 0)
1538 if (!ast_streamfile(chan
, "conf-waitforleader", chan
->language
))
1539 ast_waitstream(chan
, "");
1542 if (!(confflags
& CONFFLAG_QUIET
) && (confflags
& CONFFLAG_ANNOUNCEUSERCOUNT
) && conf
->users
> 1) {
1543 int keepplaying
= 1;
1545 if (conf
->users
== 2) {
1546 if (!ast_streamfile(chan
,"conf-onlyone",chan
->language
)) {
1547 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1548 ast_stopstream(chan
);
1555 if (!ast_streamfile(chan
, "conf-thereare", chan
->language
)) {
1556 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1557 ast_stopstream(chan
);
1564 res
= ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1570 if (keepplaying
&& !ast_streamfile(chan
, "conf-otherinparty", chan
->language
)) {
1571 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1572 ast_stopstream(chan
);
1581 ast_indicate(chan
, -1);
1583 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1584 ast_log(LOG_WARNING
, "Unable to set '%s' to write linear mode\n", chan
->name
);
1588 if (ast_set_read_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1589 ast_log(LOG_WARNING
, "Unable to set '%s' to read linear mode\n", chan
->name
);
1593 retryzap
= (strcasecmp(chan
->tech
->type
, "Zap") || (chan
->audiohooks
|| chan
->monitor
) ? 1 : 0);
1594 user
->zapchannel
= !retryzap
;
1597 origfd
= chan
->fds
[0];
1599 fd
= open("/dev/zap/pseudo", O_RDWR
);
1601 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
1605 /* Make non-blocking */
1606 flags
= fcntl(fd
, F_GETFL
);
1608 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
1612 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
1613 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
1617 /* Setup buffering information */
1618 memset(&bi
, 0, sizeof(bi
));
1619 bi
.bufsize
= CONF_SIZE
/2;
1620 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
1621 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
1622 bi
.numbufs
= audio_buffers
;
1623 if (ioctl(fd
, DAHDI_SET_BUFINFO
, &bi
)) {
1624 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
1629 if (ioctl(fd
, DAHDI_SETLINEAR
, &x
)) {
1630 ast_log(LOG_WARNING
, "Unable to set linear mode: %s\n", strerror(errno
));
1636 /* XXX Make sure we're not running on a pseudo channel XXX */
1640 memset(&ztc
, 0, sizeof(ztc
));
1641 memset(&ztc_empty
, 0, sizeof(ztc_empty
));
1642 /* Check to see if we're in a conference... */
1644 if (ioctl(fd
, DAHDI_GETCONF
, &ztc
)) {
1645 ast_log(LOG_WARNING
, "Error getting conference\n");
1650 /* Whoa, already in a conference... Retry... */
1652 ast_log(LOG_DEBUG
, "Zap channel is in a conference already, retrying with pseudo\n");
1657 memset(&ztc
, 0, sizeof(ztc
));
1658 /* Add us to the conference */
1660 ztc
.confno
= conf
->zapconf
;
1662 ast_mutex_lock(&conf
->playlock
);
1664 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
)) && conf
->users
> 1) {
1665 if (conf
->chan
&& ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
1666 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
1667 ast_waitstream(conf
->chan
, "");
1668 if (!ast_streamfile(conf
->chan
, "conf-hasjoin", chan
->language
))
1669 ast_waitstream(conf
->chan
, "");
1673 if (confflags
& CONFFLAG_WAITMARKED
&& !conf
->markedusers
)
1674 ztc
.confmode
= DAHDI_CONF_CONF
;
1675 else if (confflags
& CONFFLAG_MONITOR
)
1676 ztc
.confmode
= DAHDI_CONF_CONFMON
| DAHDI_CONF_LISTENER
;
1677 else if (confflags
& CONFFLAG_TALKER
)
1678 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
;
1680 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
;
1682 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1683 ast_log(LOG_WARNING
, "Error setting conference\n");
1685 ast_mutex_unlock(&conf
->playlock
);
1688 ast_log(LOG_DEBUG
, "Placed channel %s in ZAP conf %d\n", chan
->name
, conf
->zapconf
);
1691 manager_event(EVENT_FLAG_CALL
, "MeetmeJoin",
1696 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1700 if (!firstpass
&& !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
)) {
1702 if (!(confflags
& CONFFLAG_QUIET
))
1703 if (!(confflags
& CONFFLAG_WAITMARKED
) || ((confflags
& CONFFLAG_MARKEDUSER
) && (conf
->markedusers
>= 1)))
1704 conf_play(chan
, conf
, ENTER
);
1707 ast_mutex_unlock(&conf
->playlock
);
1709 conf_flush(fd
, chan
);
1711 if (confflags
& CONFFLAG_AGI
) {
1712 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1713 or use default filename of conf-background.agi */
1715 agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_AGI_BACKGROUND");
1717 agifile
= agifiledefault
;
1719 if (user
->zapchannel
) {
1720 /* Set CONFMUTE mode on Zap channel to mute DTMF tones */
1722 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1724 /* Find a pointer to the agi app and execute the script */
1725 app
= pbx_findapp("agi");
1727 char *s
= ast_strdupa(agifile
);
1728 ret
= pbx_exec(chan
, app
, s
);
1730 ast_log(LOG_WARNING
, "Could not find application (agi)\n");
1733 if (user
->zapchannel
) {
1734 /* Remove CONFMUTE mode on Zap channel */
1736 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1739 if (user
->zapchannel
&& (confflags
& CONFFLAG_STARMENU
)) {
1740 /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1742 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1744 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
) && !(dsp
= ast_dsp_new())) {
1745 ast_log(LOG_WARNING
, "Unable to allocate DSP!\n");
1749 int menu_was_active
= 0;
1754 if (timeout
&& time(NULL
) >= timeout
)
1757 /* if we have just exited from the menu, and the user had a channel-driver
1758 volume adjustment, restore it
1760 if (!menu_active
&& menu_was_active
&& user
->listen
.desired
&& !user
->listen
.actual
)
1761 set_talk_volume(user
, user
->listen
.desired
);
1763 menu_was_active
= menu_active
;
1765 currentmarked
= conf
->markedusers
;
1766 if (!(confflags
& CONFFLAG_QUIET
) &&
1767 (confflags
& CONFFLAG_MARKEDUSER
) &&
1768 (confflags
& CONFFLAG_WAITMARKED
) &&
1770 if (currentmarked
== 1 && conf
->users
> 1) {
1771 ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1772 if (conf
->users
- 1 == 1) {
1773 if (!ast_streamfile(chan
, "conf-userwilljoin", chan
->language
))
1774 ast_waitstream(chan
, "");
1776 if (!ast_streamfile(chan
, "conf-userswilljoin", chan
->language
))
1777 ast_waitstream(chan
, "");
1780 if (conf
->users
== 1 && ! (confflags
& CONFFLAG_MARKEDUSER
))
1781 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1782 ast_waitstream(chan
, "");
1785 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
1788 /* Update the struct with the actual confflags */
1789 user
->userflags
= confflags
;
1791 if (confflags
& CONFFLAG_WAITMARKED
) {
1792 if(currentmarked
== 0) {
1793 if (lastmarked
!= 0) {
1794 if (!(confflags
& CONFFLAG_QUIET
))
1795 if (!ast_streamfile(chan
, "conf-leaderhasleft", chan
->language
))
1796 ast_waitstream(chan
, "");
1797 if(confflags
& CONFFLAG_MARKEDEXIT
)
1800 ztc
.confmode
= DAHDI_CONF_CONF
;
1801 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1802 ast_log(LOG_WARNING
, "Error setting conference\n");
1808 if (musiconhold
== 0 && (confflags
& CONFFLAG_MOH
)) {
1809 ast_moh_start(chan
, NULL
, NULL
);
1812 } else if(currentmarked
>= 1 && lastmarked
== 0) {
1813 /* Marked user entered, so cancel timeout */
1815 if (confflags
& CONFFLAG_MONITOR
)
1816 ztc
.confmode
= DAHDI_CONF_CONFMON
| DAHDI_CONF_LISTENER
;
1817 else if (confflags
& CONFFLAG_TALKER
)
1818 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
;
1820 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
;
1821 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1822 ast_log(LOG_WARNING
, "Error setting conference\n");
1826 if (musiconhold
&& (confflags
& CONFFLAG_MOH
)) {
1830 if ( !(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MARKEDUSER
)) {
1831 if (!ast_streamfile(chan
, "conf-placeintoconf", chan
->language
))
1832 ast_waitstream(chan
, "");
1833 conf_play(chan
, conf
, ENTER
);
1838 /* trying to add moh for single person conf */
1839 if ((confflags
& CONFFLAG_MOH
) && !(confflags
& CONFFLAG_WAITMARKED
)) {
1840 if (conf
->users
== 1) {
1841 if (musiconhold
== 0) {
1842 ast_moh_start(chan
, NULL
, NULL
);
1853 /* Leave if the last marked user left */
1854 if (currentmarked
== 0 && lastmarked
!= 0 && (confflags
& CONFFLAG_MARKEDEXIT
)) {
1859 /* Check if my modes have changed */
1861 /* If I should be muted but am still talker, mute me */
1862 if ((user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && (ztc
.confmode
& DAHDI_CONF_TALKER
)) {
1863 ztc
.confmode
^= DAHDI_CONF_TALKER
;
1864 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1865 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1870 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1876 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1879 /* If I should be un-muted but am not talker, un-mute me */
1880 if (!(user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && !(confflags
& CONFFLAG_MONITOR
) && !(ztc
.confmode
& DAHDI_CONF_TALKER
)) {
1881 ztc
.confmode
|= DAHDI_CONF_TALKER
;
1882 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1883 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1888 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1894 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1897 /* If I have been kicked, exit the conference */
1898 if (user
->adminflags
& ADMINFLAG_KICKME
) {
1899 //You have been kicked.
1900 if (!(confflags
& CONFFLAG_QUIET
) &&
1901 !ast_streamfile(chan
, "conf-kicked", chan
->language
)) {
1902 ast_waitstream(chan
, "");
1908 /* Perform an extra hangup check just in case */
1909 if (ast_check_hangup(chan
))
1913 char dtmfstr
[2] = "";
1915 if (c
->fds
[0] != origfd
|| (user
->zapchannel
&& (c
->audiohooks
|| c
->monitor
))) {
1917 /* Kill old pseudo */
1921 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
1922 retryzap
= (strcasecmp(c
->tech
->type
, "Zap") || (c
->audiohooks
|| c
->monitor
) ? 1 : 0);
1923 user
->zapchannel
= !retryzap
;
1926 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)))
1927 f
= ast_read_noaudio(c
);
1932 if (f
->frametype
== AST_FRAME_DTMF
) {
1933 dtmfstr
[0] = f
->subclass
;
1937 if ((f
->frametype
== AST_FRAME_VOICE
) && (f
->subclass
== AST_FORMAT_SLINEAR
)) {
1938 if (user
->talk
.actual
)
1939 ast_frame_adjust_volume(f
, user
->talk
.actual
);
1941 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
)) {
1944 if (user
->talking
== -1)
1947 res
= ast_dsp_silence(dsp
, f
, &totalsilence
);
1948 if (!user
->talking
&& totalsilence
< MEETME_DELAYDETECTTALK
) {
1950 if (confflags
& CONFFLAG_MONITORTALKER
)
1951 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1957 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1959 if (user
->talking
&& totalsilence
> MEETME_DELAYDETECTENDTALK
) {
1961 if (confflags
& CONFFLAG_MONITORTALKER
)
1962 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1968 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1972 /* Absolutely do _not_ use careful_write here...
1973 it is important that we read data from the channel
1974 as fast as it arrives, and feed it into the conference.
1975 The buffering in the pseudo channel will take care of any
1976 timing differences, unless they are so drastic as to lose
1977 audio frames (in which case carefully writing would only
1978 have delayed the audio even further).
1980 /* As it turns out, we do want to use careful write. We just
1981 don't want to block, but we do want to at least *try*
1982 to write out all the samples.
1984 if (user
->talking
|| !(confflags
& CONFFLAG_OPTIMIZETALKER
))
1985 careful_write(fd
, f
->data
, f
->datalen
, 0);
1987 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '#') && (confflags
& CONFFLAG_POUNDEXIT
)) {
1988 if (confflags
& CONFFLAG_PASS_DTMF
)
1989 conf_queue_dtmf(conf
, user
, f
);
1993 } else if (((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*') && (confflags
& CONFFLAG_STARMENU
)) || ((f
->frametype
== AST_FRAME_DTMF
) && menu_active
)) {
1994 if (confflags
& CONFFLAG_PASS_DTMF
)
1995 conf_queue_dtmf(conf
, user
, f
);
1996 if (ioctl(fd
, DAHDI_SETCONF
, &ztc_empty
)) {
1997 ast_log(LOG_WARNING
, "Error setting conference\n");
2003 /* if we are entering the menu, and the user has a channel-driver
2004 volume adjustment, clear it
2006 if (!menu_active
&& user
->talk
.desired
&& !user
->talk
.actual
)
2007 set_talk_volume(user
, 0);
2012 if ((confflags
& CONFFLAG_ADMIN
)) {
2016 /* Record this sound! */
2017 if (!ast_streamfile(chan
, "conf-adminmenu", chan
->language
)) {
2018 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2019 ast_stopstream(chan
);
2026 case '1': /* Un/Mute */
2029 /* for admin, change both admin and use flags */
2030 if (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))
2031 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2033 user
->adminflags
|= (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2035 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2036 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2037 ast_waitstream(chan
, "");
2039 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2040 ast_waitstream(chan
, "");
2043 case '2': /* Un/Lock the Conference */
2047 if (!ast_streamfile(chan
, "conf-unlockednow", chan
->language
))
2048 ast_waitstream(chan
, "");
2051 if (!ast_streamfile(chan
, "conf-lockednow", chan
->language
))
2052 ast_waitstream(chan
, "");
2055 case '3': /* Eject last user */
2057 usr
= AST_LIST_LAST(&conf
->userlist
);
2058 if ((usr
->chan
->name
== chan
->name
)||(usr
->userflags
& CONFFLAG_ADMIN
)) {
2059 if(!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2060 ast_waitstream(chan
, "");
2062 usr
->adminflags
|= ADMINFLAG_KICKME
;
2063 ast_stopstream(chan
);
2066 tweak_listen_volume(user
, VOL_DOWN
);
2069 tweak_listen_volume(user
, VOL_UP
);
2072 tweak_talk_volume(user
, VOL_DOWN
);
2078 tweak_talk_volume(user
, VOL_UP
);
2082 /* Play an error message! */
2083 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2084 ast_waitstream(chan
, "");
2092 if (!ast_streamfile(chan
, "conf-usermenu", chan
->language
)) {
2093 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2094 ast_stopstream(chan
);
2101 case '1': /* Un/Mute */
2104 /* user can only toggle the self-muted state */
2105 user
->adminflags
^= ADMINFLAG_SELFMUTED
;
2107 /* they can't override the admin mute state */
2108 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2109 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2110 ast_waitstream(chan
, "");
2112 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2113 ast_waitstream(chan
, "");
2117 tweak_listen_volume(user
, VOL_DOWN
);
2120 tweak_listen_volume(user
, VOL_UP
);
2123 tweak_talk_volume(user
, VOL_DOWN
);
2129 tweak_talk_volume(user
, VOL_UP
);
2133 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2134 ast_waitstream(chan
, "");
2140 ast_moh_start(chan
, NULL
, NULL
);
2142 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
2143 ast_log(LOG_WARNING
, "Error setting conference\n");
2149 conf_flush(fd
, chan
);
2150 /* Since this option could absorb dtmf for the previous, we have to check this one last */
2151 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (confflags
& CONFFLAG_EXIT_CONTEXT
) && ast_exists_extension(chan
, exitcontext
, dtmfstr
, 1, "")) {
2152 if (confflags
& CONFFLAG_PASS_DTMF
)
2153 conf_queue_dtmf(conf
, user
, f
);
2155 if (!ast_goto_if_exists(chan
, exitcontext
, dtmfstr
, 1)) {
2156 ast_log(LOG_DEBUG
, "Got DTMF %c, goto context %s\n", dtmfstr
[0], exitcontext
);
2160 } else if (option_debug
> 1)
2161 ast_log(LOG_DEBUG
, "Exit by single digit did not work in meetme. Extension '%s' does not exist in context '%s'\n", dtmfstr
, exitcontext
);
2162 } else if ((f
->frametype
== AST_FRAME_DTMF_BEGIN
|| f
->frametype
== AST_FRAME_DTMF_END
)
2163 && confflags
& CONFFLAG_PASS_DTMF
) {
2164 conf_queue_dtmf(conf
, user
, f
);
2165 } else if ((confflags
& CONFFLAG_SLA_STATION
) && f
->frametype
== AST_FRAME_CONTROL
) {
2166 switch (f
->subclass
) {
2167 case AST_CONTROL_HOLD
:
2168 sla_queue_event_conf(SLA_EVENT_HOLD
, chan
, conf
);
2173 } else if (f
->frametype
== AST_FRAME_NULL
) {
2174 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2175 } else if (option_debug
) {
2177 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2178 chan
->name
, f
->frametype
, f
->subclass
);
2181 } else if (outfd
> -1) {
2182 res
= read(outfd
, buf
, CONF_SIZE
);
2184 memset(&fr
, 0, sizeof(fr
));
2185 fr
.frametype
= AST_FRAME_VOICE
;
2186 fr
.subclass
= AST_FORMAT_SLINEAR
;
2190 fr
.offset
= AST_FRIENDLY_OFFSET
;
2191 if (!user
->listen
.actual
&&
2192 ((confflags
& CONFFLAG_MONITOR
) ||
2193 (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) ||
2194 (!user
->talking
&& (confflags
& CONFFLAG_OPTIMIZETALKER
))
2197 for (index
=0;index
<AST_FRAME_BITS
;index
++)
2198 if (chan
->rawwriteformat
& (1 << index
))
2200 if (index
>= AST_FRAME_BITS
)
2201 goto bailoutandtrynormal
;
2202 ast_mutex_lock(&conf
->listenlock
);
2203 if (!conf
->transframe
[index
]) {
2204 if (conf
->origframe
) {
2205 if (!conf
->transpath
[index
])
2206 conf
->transpath
[index
] = ast_translator_build_path((1 << index
), AST_FORMAT_SLINEAR
);
2207 if (conf
->transpath
[index
]) {
2208 conf
->transframe
[index
] = ast_translate(conf
->transpath
[index
], conf
->origframe
, 0);
2209 if (!conf
->transframe
[index
])
2210 conf
->transframe
[index
] = &ast_null_frame
;
2214 if (conf
->transframe
[index
]) {
2215 if (conf
->transframe
[index
]->frametype
!= AST_FRAME_NULL
) {
2216 if (ast_write(chan
, conf
->transframe
[index
]))
2217 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2220 ast_mutex_unlock(&conf
->listenlock
);
2221 goto bailoutandtrynormal
;
2223 ast_mutex_unlock(&conf
->listenlock
);
2225 bailoutandtrynormal
:
2226 if (user
->listen
.actual
)
2227 ast_frame_adjust_volume(&fr
, user
->listen
.actual
);
2228 if (ast_write(chan
, &fr
) < 0) {
2229 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2233 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
2235 lastmarked
= currentmarked
;
2245 /* Take out of conference */
2249 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
2250 ast_log(LOG_WARNING
, "Error setting conference\n");
2254 reset_volumes(user
);
2256 AST_LIST_LOCK(&confs
);
2257 if (!(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
))
2258 conf_play(chan
, conf
, LEAVE
);
2260 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
2261 if (ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
2262 if ((conf
->chan
) && (conf
->users
> 1)) {
2263 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
2264 ast_waitstream(conf
->chan
, "");
2265 if (!ast_streamfile(conf
->chan
, "conf-hasleft", chan
->language
))
2266 ast_waitstream(conf
->chan
, "");
2268 ast_filedelete(user
->namerecloc
, NULL
);
2271 AST_LIST_UNLOCK(&confs
);
2274 AST_LIST_LOCK(&confs
);
2279 if (user
->user_no
) { /* Only cleanup users who really joined! */
2281 hr
= (now
- user
->jointime
) / 3600;
2282 min
= ((now
- user
->jointime
) % 3600) / 60;
2283 sec
= (now
- user
->jointime
) % 60;
2286 manager_event(EVENT_FLAG_CALL
, "MeetmeLeave",
2291 "CallerIDnum: %s\r\n"
2292 "CallerIDname: %s\r\n"
2293 "Duration: %ld\r\n",
2294 chan
->name
, chan
->uniqueid
, conf
->confno
,
2296 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
2297 S_OR(user
->chan
->cid
.cid_name
, "<unknown>"),
2298 (long)(now
- user
->jointime
));
2304 snprintf(members
, sizeof(members
), "%d", conf
->users
);
2305 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
2306 if (confflags
& CONFFLAG_MARKEDUSER
)
2307 conf
->markedusers
--;
2309 /* Remove ourselves from the list */
2310 AST_LIST_REMOVE(&conf
->userlist
, user
, list
);
2312 /* Change any states */
2314 ast_device_state_changed("meetme:%s", conf
->confno
);
2316 /* Return the number of seconds the user was in the conf */
2317 snprintf(meetmesecs
, sizeof(meetmesecs
), "%d", (int) (time(NULL
) - user
->jointime
));
2318 pbx_builtin_setvar_helper(chan
, "MEETMESECS", meetmesecs
);
2321 AST_LIST_UNLOCK(&confs
);
2326 static struct ast_conference
*find_conf_realtime(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2327 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2329 struct ast_variable
*var
;
2330 struct ast_conference
*cnf
;
2332 /* Check first in the conference list */
2333 AST_LIST_LOCK(&confs
);
2334 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2335 if (!strcmp(confno
, cnf
->confno
))
2339 cnf
->refcount
+= refcount
;
2341 AST_LIST_UNLOCK(&confs
);
2344 char *pin
= NULL
, *pinadmin
= NULL
; /* For temp use */
2346 var
= ast_load_realtime("meetme", "confno", confno
, NULL
);
2352 if (!strcasecmp(var
->name
, "pin")) {
2353 pin
= ast_strdupa(var
->value
);
2354 } else if (!strcasecmp(var
->name
, "adminpin")) {
2355 pinadmin
= ast_strdupa(var
->value
);
2359 ast_variables_destroy(var
);
2361 cnf
= build_conf(confno
, pin
? pin
: "", pinadmin
? pinadmin
: "", make
, dynamic
, refcount
);
2365 if (confflags
&& !cnf
->chan
&&
2366 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2367 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2368 ast_log(LOG_WARNING
, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2369 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2372 if (confflags
&& !cnf
->chan
&&
2373 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2374 ast_log(LOG_WARNING
, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2375 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2383 static struct ast_conference
*find_conf(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2384 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2386 struct ast_config
*cfg
;
2387 struct ast_variable
*var
;
2388 struct ast_conference
*cnf
;
2390 AST_DECLARE_APP_ARGS(args
,
2391 AST_APP_ARG(confno
);
2393 AST_APP_ARG(pinadmin
);
2396 /* Check first in the conference list */
2397 AST_LIST_LOCK(&confs
);
2398 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2399 if (!strcmp(confno
, cnf
->confno
))
2403 cnf
->refcount
+= refcount
;
2405 AST_LIST_UNLOCK(&confs
);
2409 /* No need to parse meetme.conf */
2410 ast_log(LOG_DEBUG
, "Building dynamic conference '%s'\n", confno
);
2412 if (dynamic_pin
[0] == 'q') {
2413 /* Query the user to enter a PIN */
2414 if (ast_app_getdata(chan
, "conf-getpin", dynamic_pin
, pin_buf_len
- 1, 0) < 0)
2417 cnf
= build_conf(confno
, dynamic_pin
, "", make
, dynamic
, refcount
);
2419 cnf
= build_conf(confno
, "", "", make
, dynamic
, refcount
);
2422 /* Check the config */
2423 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2425 ast_log(LOG_WARNING
, "No %s file :(\n", CONFIG_FILE_NAME
);
2428 for (var
= ast_variable_browse(cfg
, "rooms"); var
; var
= var
->next
) {
2429 if (strcasecmp(var
->name
, "conf"))
2432 if (!(parse
= ast_strdupa(var
->value
)))
2435 AST_NONSTANDARD_APP_ARGS(args
, parse
, ',');
2436 if (!strcasecmp(args
.confno
, confno
)) {
2437 /* Bingo it's a valid conference */
2438 cnf
= build_conf(args
.confno
,
2440 S_OR(args
.pinadmin
, ""),
2441 make
, dynamic
, refcount
);
2446 ast_log(LOG_DEBUG
, "%s isn't a valid conference\n", confno
);
2448 ast_config_destroy(cfg
);
2450 } else if (dynamic_pin
) {
2451 /* Correct for the user selecting 'D' instead of 'd' to have
2452 someone join into a conference that has already been created
2454 if (dynamic_pin
[0] == 'q')
2455 dynamic_pin
[0] = '\0';
2459 if (confflags
&& !cnf
->chan
&&
2460 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2461 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2462 ast_log(LOG_WARNING
, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
2463 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2466 if (confflags
&& !cnf
->chan
&&
2467 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2468 ast_log(LOG_WARNING
, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
2469 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2476 /*! \brief The MeetmeCount application */
2477 static int count_exec(struct ast_channel
*chan
, void *data
)
2479 struct ast_module_user
*u
;
2481 struct ast_conference
*conf
;
2485 AST_DECLARE_APP_ARGS(args
,
2486 AST_APP_ARG(confno
);
2487 AST_APP_ARG(varname
);
2490 if (ast_strlen_zero(data
)) {
2491 ast_log(LOG_WARNING
, "MeetMeCount requires an argument (conference number)\n");
2495 u
= ast_module_user_add(chan
);
2497 if (!(localdata
= ast_strdupa(data
))) {
2498 ast_module_user_remove(u
);
2502 AST_STANDARD_APP_ARGS(args
, localdata
);
2504 conf
= find_conf(chan
, args
.confno
, 0, 0, NULL
, 0, 1, NULL
);
2507 count
= conf
->users
;
2513 if (!ast_strlen_zero(args
.varname
)){
2514 /* have var so load it and exit */
2515 snprintf(val
, sizeof(val
), "%d",count
);
2516 pbx_builtin_setvar_helper(chan
, args
.varname
, val
);
2518 if (chan
->_state
!= AST_STATE_UP
)
2520 res
= ast_say_number(chan
, count
, "", chan
->language
, (char *) NULL
); /* Needs gender */
2522 ast_module_user_remove(u
);
2527 /*! \brief The meetme() application */
2528 static int conf_exec(struct ast_channel
*chan
, void *data
)
2531 struct ast_module_user
*u
;
2532 char confno
[MAX_CONFNUM
] = "";
2535 struct ast_conference
*cnf
= NULL
;
2536 struct ast_flags confflags
= {0};
2538 int empty
= 0, empty_no_pin
= 0;
2539 int always_prompt
= 0;
2540 char *notdata
, *info
, the_pin
[MAX_PIN
] = "";
2541 AST_DECLARE_APP_ARGS(args
,
2542 AST_APP_ARG(confno
);
2543 AST_APP_ARG(options
);
2546 char *optargs
[OPT_ARG_ARRAY_SIZE
] = { NULL
, };
2548 u
= ast_module_user_add(chan
);
2550 if (ast_strlen_zero(data
)) {
2557 if (chan
->_state
!= AST_STATE_UP
)
2560 info
= ast_strdupa(notdata
);
2562 AST_STANDARD_APP_ARGS(args
, info
);
2565 ast_copy_string(confno
, args
.confno
, sizeof(confno
));
2566 if (ast_strlen_zero(confno
)) {
2572 ast_copy_string(the_pin
, args
.pin
, sizeof(the_pin
));
2575 ast_app_parse_options(meetme_opts
, &confflags
, optargs
, args
.options
);
2576 dynamic
= ast_test_flag(&confflags
, CONFFLAG_DYNAMIC
| CONFFLAG_DYNAMICPIN
);
2577 if (ast_test_flag(&confflags
, CONFFLAG_DYNAMICPIN
) && !args
.pin
)
2578 strcpy(the_pin
, "q");
2580 empty
= ast_test_flag(&confflags
, CONFFLAG_EMPTY
| CONFFLAG_EMPTYNOPIN
);
2581 empty_no_pin
= ast_test_flag(&confflags
, CONFFLAG_EMPTYNOPIN
);
2582 always_prompt
= ast_test_flag(&confflags
, CONFFLAG_ALWAYSPROMPT
);
2590 struct ast_config
*cfg
;
2591 struct ast_variable
*var
;
2594 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2595 if ((empty_no_pin
) || (!dynamic
)) {
2596 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2598 var
= ast_variable_browse(cfg
, "rooms");
2600 if (!strcasecmp(var
->name
, "conf")) {
2601 char *stringp
= ast_strdupa(var
->value
);
2603 char *confno_tmp
= strsep(&stringp
, "|,");
2606 /* For static: run through the list and see if this conference is empty */
2607 AST_LIST_LOCK(&confs
);
2608 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2609 if (!strcmp(confno_tmp
, cnf
->confno
)) {
2610 /* The conference exists, therefore it's not empty */
2615 AST_LIST_UNLOCK(&confs
);
2617 /* At this point, we have a confno_tmp (static conference) that is empty */
2618 if ((empty_no_pin
&& ast_strlen_zero(stringp
)) || (!empty_no_pin
)) {
2619 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
2620 * Case 2: empty_no_pin and pin is blank (but not NULL)
2621 * Case 3: not empty_no_pin
2623 ast_copy_string(confno
, confno_tmp
, sizeof(confno
));
2625 /* XXX the map is not complete (but we do have a confno) */
2633 ast_config_destroy(cfg
);
2637 /* Select first conference number not in use */
2638 if (ast_strlen_zero(confno
) && dynamic
) {
2639 AST_LIST_LOCK(&confs
);
2640 for (i
= 0; i
< sizeof(conf_map
) / sizeof(conf_map
[0]); i
++) {
2642 snprintf(confno
, sizeof(confno
), "%d", i
);
2647 AST_LIST_UNLOCK(&confs
);
2651 if (ast_strlen_zero(confno
)) {
2652 res
= ast_streamfile(chan
, "conf-noempty", chan
->language
);
2654 ast_waitstream(chan
, "");
2656 if (sscanf(confno
, "%d", &confno_int
) == 1) {
2657 res
= ast_streamfile(chan
, "conf-enteringno", chan
->language
);
2659 ast_waitstream(chan
, "");
2660 res
= ast_say_digits(chan
, confno_int
, "", chan
->language
);
2663 ast_log(LOG_ERROR
, "Could not scan confno '%s'\n", confno
);
2668 while (allowretry
&& (ast_strlen_zero(confno
)) && (++retrycnt
< 4)) {
2669 /* Prompt user for conference number */
2670 res
= ast_app_getdata(chan
, "conf-getconfno", confno
, sizeof(confno
) - 1, 0);
2672 /* Don't try to validate when we catch an error */
2678 if (!ast_strlen_zero(confno
)) {
2679 /* Check the validity of the conference */
2680 cnf
= find_conf(chan
, confno
, 1, dynamic
, the_pin
,
2681 sizeof(the_pin
), 1, &confflags
);
2683 cnf
= find_conf_realtime(chan
, confno
, 1, dynamic
,
2684 the_pin
, sizeof(the_pin
), 1, &confflags
);
2688 res
= ast_streamfile(chan
, "conf-invalid", chan
->language
);
2690 ast_waitstream(chan
, "");
2695 if ((!ast_strlen_zero(cnf
->pin
) &&
2696 !ast_test_flag(&confflags
, CONFFLAG_ADMIN
)) ||
2697 (!ast_strlen_zero(cnf
->pinadmin
) &&
2698 ast_test_flag(&confflags
, CONFFLAG_ADMIN
))) {
2699 char pin
[MAX_PIN
] = "";
2702 /* Allow the pin to be retried up to 3 times */
2703 for (j
= 0; j
< 3; j
++) {
2704 if (*the_pin
&& (always_prompt
== 0)) {
2705 ast_copy_string(pin
, the_pin
, sizeof(pin
));
2708 /* Prompt user for pin if pin is required */
2709 res
= ast_app_getdata(chan
, "conf-getpin", pin
+ strlen(pin
), sizeof(pin
) - 1 - strlen(pin
), 0);
2712 if (!strcasecmp(pin
, cnf
->pin
) ||
2713 (!ast_strlen_zero(cnf
->pinadmin
) &&
2714 !strcasecmp(pin
, cnf
->pinadmin
))) {
2717 if (!ast_strlen_zero(cnf
->pinadmin
) && !strcasecmp(pin
, cnf
->pinadmin
))
2718 ast_set_flag(&confflags
, CONFFLAG_ADMIN
);
2719 /* Run the conference */
2720 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2724 if (!ast_streamfile(chan
, "conf-invalidpin", chan
->language
)) {
2725 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2726 ast_stopstream(chan
);
2729 ast_log(LOG_WARNING
, "Couldn't play invalid pin msg!\n");
2741 /* failed when getting the pin */
2744 /* see if we need to get rid of the conference */
2748 /* Don't retry pin with a static pin */
2749 if (*the_pin
&& (always_prompt
==0)) {
2754 /* No pin required */
2757 /* Run the conference */
2758 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2764 } while (allowretry
);
2769 ast_module_user_remove(u
);
2774 static struct ast_conf_user
*find_user(struct ast_conference
*conf
, char *callerident
)
2776 struct ast_conf_user
*user
= NULL
;
2779 sscanf(callerident
, "%i", &cid
);
2780 if (conf
&& callerident
) {
2781 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
2782 if (cid
== user
->user_no
)
2789 /*! \brief The MeetMeadmin application */
2790 /* MeetMeAdmin(confno, command, caller) */
2791 static int admin_exec(struct ast_channel
*chan
, void *data
) {
2793 struct ast_conference
*cnf
;
2794 struct ast_conf_user
*user
= NULL
;
2795 struct ast_module_user
*u
;
2796 AST_DECLARE_APP_ARGS(args
,
2797 AST_APP_ARG(confno
);
2798 AST_APP_ARG(command
);
2802 if (ast_strlen_zero(data
)) {
2803 ast_log(LOG_WARNING
, "MeetMeAdmin requires an argument!\n");
2807 u
= ast_module_user_add(chan
);
2809 AST_LIST_LOCK(&confs
);
2811 params
= ast_strdupa(data
);
2812 AST_STANDARD_APP_ARGS(args
, params
);
2814 if (!args
.command
) {
2815 ast_log(LOG_WARNING
, "MeetmeAdmin requires a command!\n");
2816 AST_LIST_UNLOCK(&confs
);
2817 ast_module_user_remove(u
);
2820 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2821 if (!strcmp(cnf
->confno
, args
.confno
))
2826 ast_log(LOG_WARNING
, "Conference number '%s' not found!\n", args
.confno
);
2827 AST_LIST_UNLOCK(&confs
);
2828 ast_module_user_remove(u
);
2832 ast_atomic_fetchadd_int(&cnf
->refcount
, 1);
2835 user
= find_user(cnf
, args
.user
);
2837 switch (*args
.command
) {
2838 case 76: /* L: Lock */
2841 case 108: /* l: Unlock */
2844 case 75: /* K: kick all users */
2845 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2846 user
->adminflags
|= ADMINFLAG_KICKME
;
2848 case 101: /* e: Eject last user*/
2849 user
= AST_LIST_LAST(&cnf
->userlist
);
2850 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2851 user
->adminflags
|= ADMINFLAG_KICKME
;
2853 ast_log(LOG_NOTICE
, "Not kicking last user, is an Admin!\n");
2855 case 77: /* M: Mute */
2857 user
->adminflags
|= ADMINFLAG_MUTED
;
2859 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2861 case 78: /* N: Mute all (non-admin) users */
2862 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
2863 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2864 user
->adminflags
|= ADMINFLAG_MUTED
;
2867 case 109: /* m: Unmute */
2869 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2871 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2873 case 110: /* n: Unmute all users */
2874 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2875 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2877 case 107: /* k: Kick user */
2879 user
->adminflags
|= ADMINFLAG_KICKME
;
2881 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2883 case 118: /* v: Lower all users listen volume */
2884 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2885 tweak_listen_volume(user
, VOL_DOWN
);
2887 case 86: /* V: Raise all users listen volume */
2888 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2889 tweak_listen_volume(user
, VOL_UP
);
2891 case 115: /* s: Lower all users speaking volume */
2892 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2893 tweak_talk_volume(user
, VOL_DOWN
);
2895 case 83: /* S: Raise all users speaking volume */
2896 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2897 tweak_talk_volume(user
, VOL_UP
);
2899 case 82: /* R: Reset all volume levels */
2900 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2901 reset_volumes(user
);
2903 case 114: /* r: Reset user's volume level */
2905 reset_volumes(user
);
2907 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2909 case 85: /* U: Raise user's listen volume */
2911 tweak_listen_volume(user
, VOL_UP
);
2913 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2915 case 117: /* u: Lower user's listen volume */
2917 tweak_listen_volume(user
, VOL_DOWN
);
2919 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2921 case 84: /* T: Raise user's talk volume */
2923 tweak_talk_volume(user
, VOL_UP
);
2925 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2927 case 116: /* t: Lower user's talk volume */
2929 tweak_talk_volume(user
, VOL_DOWN
);
2931 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2935 AST_LIST_UNLOCK(&confs
);
2939 ast_module_user_remove(u
);
2944 static int meetmemute(struct mansession
*s
, const struct message
*m
, int mute
)
2946 struct ast_conference
*conf
;
2947 struct ast_conf_user
*user
;
2948 const char *confid
= astman_get_header(m
, "Meetme");
2949 char *userid
= ast_strdupa(astman_get_header(m
, "Usernum"));
2952 if (ast_strlen_zero(confid
)) {
2953 astman_send_error(s
, m
, "Meetme conference not specified");
2957 if (ast_strlen_zero(userid
)) {
2958 astman_send_error(s
, m
, "Meetme user number not specified");
2962 userno
= strtoul(userid
, &userid
, 10);
2965 astman_send_error(s
, m
, "Invalid user number");
2969 /* Look in the conference list */
2970 AST_LIST_LOCK(&confs
);
2971 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
2972 if (!strcmp(confid
, conf
->confno
))
2977 AST_LIST_UNLOCK(&confs
);
2978 astman_send_error(s
, m
, "Meetme conference does not exist");
2982 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
)
2983 if (user
->user_no
== userno
)
2987 AST_LIST_UNLOCK(&confs
);
2988 astman_send_error(s
, m
, "User number not found");
2993 user
->adminflags
|= ADMINFLAG_MUTED
; /* request user muting */
2995 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
); /* request user unmuting */
2997 AST_LIST_UNLOCK(&confs
);
2999 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
);
3001 astman_send_ack(s
, m
, mute
? "User muted" : "User unmuted");
3005 static int action_meetmemute(struct mansession
*s
, const struct message
*m
)
3007 return meetmemute(s
, m
, 1);
3010 static int action_meetmeunmute(struct mansession
*s
, const struct message
*m
)
3012 return meetmemute(s
, m
, 0);
3015 static void *recordthread(void *args
)
3017 struct ast_conference
*cnf
= args
;
3018 struct ast_frame
*f
=NULL
;
3020 struct ast_filestream
*s
=NULL
;
3023 const char *oldrecordingfilename
= NULL
;
3025 if (!cnf
|| !cnf
->lchan
) {
3029 ast_stopstream(cnf
->lchan
);
3030 flags
= O_CREAT
|O_TRUNC
|O_WRONLY
;
3033 cnf
->recording
= MEETME_RECORD_ACTIVE
;
3034 while (ast_waitfor(cnf
->lchan
, -1) > -1) {
3035 if (cnf
->recording
== MEETME_RECORD_TERMINATE
) {
3036 AST_LIST_LOCK(&confs
);
3037 AST_LIST_UNLOCK(&confs
);
3040 if (!s
&& cnf
->recordingfilename
&& (cnf
->recordingfilename
!= oldrecordingfilename
)) {
3041 s
= ast_writefile(cnf
->recordingfilename
, cnf
->recordingformat
, NULL
, flags
, 0, 0644);
3042 oldrecordingfilename
= cnf
->recordingfilename
;
3045 f
= ast_read(cnf
->lchan
);
3050 if (f
->frametype
== AST_FRAME_VOICE
) {
3051 ast_mutex_lock(&cnf
->listenlock
);
3052 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
3053 /* Free any translations that have occured */
3054 if (cnf
->transframe
[x
]) {
3055 ast_frfree(cnf
->transframe
[x
]);
3056 cnf
->transframe
[x
] = NULL
;
3060 ast_frfree(cnf
->origframe
);
3061 cnf
->origframe
= ast_frdup(f
);
3062 ast_mutex_unlock(&cnf
->listenlock
);
3064 res
= ast_writestream(s
, f
);
3072 cnf
->recording
= MEETME_RECORD_OFF
;
3079 /*! \brief Callback for devicestate providers */
3080 static int meetmestate(const char *data
)
3082 struct ast_conference
*conf
;
3084 /* Find conference */
3085 AST_LIST_LOCK(&confs
);
3086 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
3087 if (!strcmp(data
, conf
->confno
))
3090 AST_LIST_UNLOCK(&confs
);
3092 return AST_DEVICE_INVALID
;
3097 return AST_DEVICE_NOT_INUSE
;
3099 return AST_DEVICE_INUSE
;
3102 static void load_config_meetme(void)
3104 struct ast_config
*cfg
;
3107 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3109 if (!(cfg
= ast_config_load(CONFIG_FILE_NAME
)))
3112 if ((val
= ast_variable_retrieve(cfg
, "general", "audiobuffers"))) {
3113 if ((sscanf(val
, "%d", &audio_buffers
) != 1)) {
3114 ast_log(LOG_WARNING
, "audiobuffers setting must be a number, not '%s'\n", val
);
3115 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3116 } else if ((audio_buffers
< DAHDI_DEFAULT_NUM_BUFS
) || (audio_buffers
> DAHDI_MAX_NUM_BUFS
)) {
3117 ast_log(LOG_WARNING
, "audiobuffers setting must be between %d and %d\n",
3118 DAHDI_DEFAULT_NUM_BUFS
, DAHDI_MAX_NUM_BUFS
);
3119 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3121 if (audio_buffers
!= DEFAULT_AUDIO_BUFFERS
)
3122 ast_log(LOG_NOTICE
, "Audio buffers per channel set to %d\n", audio_buffers
);
3125 ast_config_destroy(cfg
);
3128 /*! \brief Find an SLA trunk by name
3129 * \note This must be called with the sla_trunks container locked
3131 static struct sla_trunk
*sla_find_trunk(const char *name
)
3133 struct sla_trunk
*trunk
= NULL
;
3135 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
3136 if (!strcasecmp(trunk
->name
, name
))
3143 /*! \brief Find an SLA station by name
3144 * \note This must be called with the sla_stations container locked
3146 static struct sla_station
*sla_find_station(const char *name
)
3148 struct sla_station
*station
= NULL
;
3150 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
3151 if (!strcasecmp(station
->name
, name
))
3158 static int sla_check_station_hold_access(const struct sla_trunk
*trunk
,
3159 const struct sla_station
*station
)
3161 struct sla_station_ref
*station_ref
;
3162 struct sla_trunk_ref
*trunk_ref
;
3164 /* For each station that has this call on hold, check for private hold. */
3165 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
) {
3166 AST_LIST_TRAVERSE(&station_ref
->station
->trunks
, trunk_ref
, entry
) {
3167 if (trunk_ref
->trunk
!= trunk
|| station_ref
->station
== station
)
3169 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
&&
3170 station_ref
->station
->hold_access
== SLA_HOLD_PRIVATE
)
3179 /*! \brief Find a trunk reference on a station by name
3180 * \param station the station
3181 * \param name the trunk's name
3182 * \return a pointer to the station's trunk reference. If the trunk
3183 * is not found, it is not idle and barge is disabled, or if
3184 * it is on hold and private hold is set, then NULL will be returned.
3186 static struct sla_trunk_ref
*sla_find_trunk_ref_byname(const struct sla_station
*station
,
3189 struct sla_trunk_ref
*trunk_ref
= NULL
;
3191 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3192 if (strcasecmp(trunk_ref
->trunk
->name
, name
))
3195 if ( (trunk_ref
->trunk
->barge_disabled
3196 && trunk_ref
->state
== SLA_TRUNK_STATE_UP
) ||
3197 (trunk_ref
->trunk
->hold_stations
3198 && trunk_ref
->trunk
->hold_access
== SLA_HOLD_PRIVATE
3199 && trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) ||
3200 sla_check_station_hold_access(trunk_ref
->trunk
, station
) )
3211 static struct sla_station_ref
*sla_create_station_ref(struct sla_station
*station
)
3213 struct sla_station_ref
*station_ref
;
3215 if (!(station_ref
= ast_calloc(1, sizeof(*station_ref
))))
3218 station_ref
->station
= station
;
3223 static struct sla_ringing_station
*sla_create_ringing_station(struct sla_station
*station
)
3225 struct sla_ringing_station
*ringing_station
;
3227 if (!(ringing_station
= ast_calloc(1, sizeof(*ringing_station
))))
3230 ringing_station
->station
= station
;
3231 ringing_station
->ring_begin
= ast_tvnow();
3233 return ringing_station
;
3236 static void sla_change_trunk_state(const struct sla_trunk
*trunk
, enum sla_trunk_state state
,
3237 enum sla_which_trunk_refs inactive_only
, const struct sla_trunk_ref
*exclude
)
3239 struct sla_station
*station
;
3240 struct sla_trunk_ref
*trunk_ref
;
3242 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3243 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3244 if (trunk_ref
->trunk
!= trunk
|| (inactive_only
? trunk_ref
->chan
: 0)
3245 || trunk_ref
== exclude
)
3247 trunk_ref
->state
= state
;
3248 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk
->name
);
3254 struct run_station_args
{
3255 struct sla_station
*station
;
3256 struct sla_trunk_ref
*trunk_ref
;
3257 ast_mutex_t
*cond_lock
;
3261 static void *run_station(void *data
)
3263 struct sla_station
*station
;
3264 struct sla_trunk_ref
*trunk_ref
;
3265 char conf_name
[MAX_CONFNUM
];
3266 struct ast_flags conf_flags
= { 0 };
3267 struct ast_conference
*conf
;
3270 struct run_station_args
*args
= data
;
3271 station
= args
->station
;
3272 trunk_ref
= args
->trunk_ref
;
3273 ast_mutex_lock(args
->cond_lock
);
3274 ast_cond_signal(args
->cond
);
3275 ast_mutex_unlock(args
->cond_lock
);
3276 /* args is no longer valid here. */
3279 ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1);
3280 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
3281 ast_set_flag(&conf_flags
,
3282 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
3283 ast_answer(trunk_ref
->chan
);
3284 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
3286 conf_run(trunk_ref
->chan
, conf
, conf_flags
.flags
, NULL
);
3290 trunk_ref
->chan
= NULL
;
3291 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
3292 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
3293 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
3294 admin_exec(NULL
, conf_name
);
3295 trunk_ref
->trunk
->hold_stations
= 0;
3296 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3299 ast_dial_join(station
->dial
);
3300 ast_dial_destroy(station
->dial
);
3301 station
->dial
= NULL
;
3306 static void sla_stop_ringing_trunk(struct sla_ringing_trunk
*ringing_trunk
)
3309 struct sla_station_ref
*station_ref
;
3311 snprintf(buf
, sizeof(buf
), "SLA_%s|K", ringing_trunk
->trunk
->name
);
3312 admin_exec(NULL
, buf
);
3313 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3315 while ((station_ref
= AST_LIST_REMOVE_HEAD(&ringing_trunk
->timed_out_stations
, entry
)))
3318 free(ringing_trunk
);
3321 static void sla_stop_ringing_station(struct sla_ringing_station
*ringing_station
,
3322 enum sla_station_hangup hangup
)
3324 struct sla_ringing_trunk
*ringing_trunk
;
3325 struct sla_trunk_ref
*trunk_ref
;
3326 struct sla_station_ref
*station_ref
;
3328 ast_dial_join(ringing_station
->station
->dial
);
3329 ast_dial_destroy(ringing_station
->station
->dial
);
3330 ringing_station
->station
->dial
= NULL
;
3332 if (hangup
== SLA_STATION_HANGUP_NORMAL
)
3335 /* If the station is being hung up because of a timeout, then add it to the
3336 * list of timed out stations on each of the ringing trunks. This is so
3337 * that when doing further processing to figure out which stations should be
3338 * ringing, which trunk to answer, determining timeouts, etc., we know which
3339 * ringing trunks we should ignore. */
3340 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3341 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3342 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3347 if (!(station_ref
= sla_create_station_ref(ringing_station
->station
)))
3349 AST_LIST_INSERT_TAIL(&ringing_trunk
->timed_out_stations
, station_ref
, entry
);
3353 free(ringing_station
);
3356 static void sla_dial_state_callback(struct ast_dial
*dial
)
3358 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3361 /*! \brief Check to see if dialing this station already timed out for this ringing trunk
3362 * \note Assumes sla.lock is locked
3364 static int sla_check_timed_out_station(const struct sla_ringing_trunk
*ringing_trunk
,
3365 const struct sla_station
*station
)
3367 struct sla_station_ref
*timed_out_station
;
3369 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, timed_out_station
, entry
) {
3370 if (station
== timed_out_station
->station
)
3377 /*! \brief Choose the highest priority ringing trunk for a station
3378 * \param station the station
3379 * \param remove remove the ringing trunk once selected
3380 * \param trunk_ref a place to store the pointer to this stations reference to
3381 * the selected trunk
3382 * \return a pointer to the selected ringing trunk, or NULL if none found
3383 * \note Assumes that sla.lock is locked
3385 static struct sla_ringing_trunk
*sla_choose_ringing_trunk(struct sla_station
*station
,
3386 struct sla_trunk_ref
**trunk_ref
, int remove
)
3388 struct sla_trunk_ref
*s_trunk_ref
;
3389 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3391 AST_LIST_TRAVERSE(&station
->trunks
, s_trunk_ref
, entry
) {
3392 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3393 /* Make sure this is the trunk we're looking for */
3394 if (s_trunk_ref
->trunk
!= ringing_trunk
->trunk
)
3397 /* This trunk on the station is ringing. But, make sure this station
3398 * didn't already time out while this trunk was ringing. */
3399 if (sla_check_timed_out_station(ringing_trunk
, station
))
3403 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3406 *trunk_ref
= s_trunk_ref
;
3410 AST_LIST_TRAVERSE_SAFE_END
3416 return ringing_trunk
;
3419 static void sla_handle_dial_state_event(void)
3421 struct sla_ringing_station
*ringing_station
;
3423 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3424 struct sla_trunk_ref
*s_trunk_ref
= NULL
;
3425 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3426 struct run_station_args args
;
3427 enum ast_dial_result dial_res
;
3428 pthread_attr_t attr
;
3429 pthread_t dont_care
;
3430 ast_mutex_t cond_lock
;
3433 switch ((dial_res
= ast_dial_state(ringing_station
->station
->dial
))) {
3434 case AST_DIAL_RESULT_HANGUP
:
3435 case AST_DIAL_RESULT_INVALID
:
3436 case AST_DIAL_RESULT_FAILED
:
3437 case AST_DIAL_RESULT_TIMEOUT
:
3438 case AST_DIAL_RESULT_UNANSWERED
:
3439 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3440 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_NORMAL
);
3442 case AST_DIAL_RESULT_ANSWERED
:
3443 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3444 /* Find the appropriate trunk to answer. */
3445 ast_mutex_lock(&sla
.lock
);
3446 ringing_trunk
= sla_choose_ringing_trunk(ringing_station
->station
, &s_trunk_ref
, 1);
3447 ast_mutex_unlock(&sla
.lock
);
3448 if (!ringing_trunk
) {
3449 ast_log(LOG_DEBUG
, "Found no ringing trunk for station '%s' to answer!\n",
3450 ringing_station
->station
->name
);
3453 /* Track the channel that answered this trunk */
3454 s_trunk_ref
->chan
= ast_dial_answered(ringing_station
->station
->dial
);
3455 /* Actually answer the trunk */
3456 ast_answer(ringing_trunk
->trunk
->chan
);
3457 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
3458 /* Now, start a thread that will connect this station to the trunk. The rest of
3459 * the code here sets up the thread and ensures that it is able to save the arguments
3460 * before they are no longer valid since they are allocated on the stack. */
3461 args
.trunk_ref
= s_trunk_ref
;
3462 args
.station
= ringing_station
->station
;
3464 args
.cond_lock
= &cond_lock
;
3465 free(ringing_trunk
);
3466 free(ringing_station
);
3467 ast_mutex_init(&cond_lock
);
3468 ast_cond_init(&cond
, NULL
);
3469 pthread_attr_init(&attr
);
3470 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3471 ast_mutex_lock(&cond_lock
);
3472 ast_pthread_create_background(&dont_care
, &attr
, run_station
, &args
);
3473 ast_cond_wait(&cond
, &cond_lock
);
3474 ast_mutex_unlock(&cond_lock
);
3475 ast_mutex_destroy(&cond_lock
);
3476 ast_cond_destroy(&cond
);
3477 pthread_attr_destroy(&attr
);
3479 case AST_DIAL_RESULT_TRYING
:
3480 case AST_DIAL_RESULT_RINGING
:
3481 case AST_DIAL_RESULT_PROGRESS
:
3482 case AST_DIAL_RESULT_PROCEEDING
:
3485 if (dial_res
== AST_DIAL_RESULT_ANSWERED
) {
3486 /* Queue up reprocessing ringing trunks, and then ringing stations again */
3487 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
3488 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3492 AST_LIST_TRAVERSE_SAFE_END
3495 /*! \brief Check to see if this station is already ringing
3496 * \note Assumes sla.lock is locked
3498 static int sla_check_ringing_station(const struct sla_station
*station
)
3500 struct sla_ringing_station
*ringing_station
;
3502 AST_LIST_TRAVERSE(&sla
.ringing_stations
, ringing_station
, entry
) {
3503 if (station
== ringing_station
->station
)
3510 /*! \brief Check to see if this station has failed to be dialed in the past minute
3511 * \note assumes sla.lock is locked
3513 static int sla_check_failed_station(const struct sla_station
*station
)
3515 struct sla_failed_station
*failed_station
;
3518 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.failed_stations
, failed_station
, entry
) {
3519 if (station
!= failed_station
->station
)
3521 if (ast_tvdiff_ms(ast_tvnow(), failed_station
->last_try
) > 1000) {
3522 AST_LIST_REMOVE_CURRENT(&sla
.failed_stations
, entry
);
3523 free(failed_station
);
3528 AST_LIST_TRAVERSE_SAFE_END
3533 /*! \brief Ring a station
3534 * \note Assumes sla.lock is locked
3536 static int sla_ring_station(struct sla_ringing_trunk
*ringing_trunk
, struct sla_station
*station
)
3538 char *tech
, *tech_data
;
3539 struct ast_dial
*dial
;
3540 struct sla_ringing_station
*ringing_station
;
3541 const char *cid_name
= NULL
, *cid_num
= NULL
;
3542 enum ast_dial_result res
;
3544 if (!(dial
= ast_dial_create()))
3547 ast_dial_set_state_callback(dial
, sla_dial_state_callback
);
3548 tech_data
= ast_strdupa(station
->device
);
3549 tech
= strsep(&tech_data
, "/");
3551 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
3552 ast_dial_destroy(dial
);
3556 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_name
)) {
3557 cid_name
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3558 free(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3559 ringing_trunk
->trunk
->chan
->cid
.cid_name
= NULL
;
3561 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_num
)) {
3562 cid_num
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3563 free(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3564 ringing_trunk
->trunk
->chan
->cid
.cid_num
= NULL
;
3567 res
= ast_dial_run(dial
, ringing_trunk
->trunk
->chan
, 1);
3570 ringing_trunk
->trunk
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
3572 ringing_trunk
->trunk
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
3574 if (res
!= AST_DIAL_RESULT_TRYING
) {
3575 struct sla_failed_station
*failed_station
;
3576 ast_dial_destroy(dial
);
3577 if (!(failed_station
= ast_calloc(1, sizeof(*failed_station
))))
3579 failed_station
->station
= station
;
3580 failed_station
->last_try
= ast_tvnow();
3581 AST_LIST_INSERT_HEAD(&sla
.failed_stations
, failed_station
, entry
);
3584 if (!(ringing_station
= sla_create_ringing_station(station
))) {
3585 ast_dial_join(dial
);
3586 ast_dial_destroy(dial
);
3590 station
->dial
= dial
;
3592 AST_LIST_INSERT_HEAD(&sla
.ringing_stations
, ringing_station
, entry
);
3597 /*! \brief Check to see if a station is in use
3599 static int sla_check_inuse_station(const struct sla_station
*station
)
3601 struct sla_trunk_ref
*trunk_ref
;
3603 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3604 if (trunk_ref
->chan
)
3611 static struct sla_trunk_ref
*sla_find_trunk_ref(const struct sla_station
*station
,
3612 const struct sla_trunk
*trunk
)
3614 struct sla_trunk_ref
*trunk_ref
= NULL
;
3616 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3617 if (trunk_ref
->trunk
== trunk
)
3624 /*! \brief Calculate the ring delay for a given ringing trunk on a station
3625 * \param station the station
3626 * \param trunk the trunk. If NULL, the highest priority ringing trunk will be used
3627 * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
3629 static int sla_check_station_delay(struct sla_station
*station
,
3630 struct sla_ringing_trunk
*ringing_trunk
)
3632 struct sla_trunk_ref
*trunk_ref
;
3633 unsigned int delay
= UINT_MAX
;
3634 int time_left
, time_elapsed
;
3637 ringing_trunk
= sla_choose_ringing_trunk(station
, &trunk_ref
, 0);
3639 trunk_ref
= sla_find_trunk_ref(station
, ringing_trunk
->trunk
);
3641 if (!ringing_trunk
|| !trunk_ref
)
3644 /* If this station has a ring delay specific to the highest priority
3645 * ringing trunk, use that. Otherwise, use the ring delay specified
3646 * globally for the station. */
3647 delay
= trunk_ref
->ring_delay
;
3649 delay
= station
->ring_delay
;
3653 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3654 time_left
= (delay
* 1000) - time_elapsed
;
3659 /*! \brief Ring stations based on current set of ringing trunks
3660 * \note Assumes that sla.lock is locked
3662 static void sla_ring_stations(void)
3664 struct sla_station_ref
*station_ref
;
3665 struct sla_ringing_trunk
*ringing_trunk
;
3667 /* Make sure that every station that uses at least one of the ringing
3668 * trunks, is ringing. */
3669 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3670 AST_LIST_TRAVERSE(&ringing_trunk
->trunk
->stations
, station_ref
, entry
) {
3673 /* Is this station already ringing? */
3674 if (sla_check_ringing_station(station_ref
->station
))
3677 /* Is this station already in a call? */
3678 if (sla_check_inuse_station(station_ref
->station
))
3681 /* Did we fail to dial this station earlier? If so, has it been
3682 * a minute since we tried? */
3683 if (sla_check_failed_station(station_ref
->station
))
3686 /* If this station already timed out while this trunk was ringing,
3687 * do not dial it again for this ringing trunk. */
3688 if (sla_check_timed_out_station(ringing_trunk
, station_ref
->station
))
3691 /* Check for a ring delay in progress */
3692 time_left
= sla_check_station_delay(station_ref
->station
, ringing_trunk
);
3693 if (time_left
!= INT_MAX
&& time_left
> 0)
3696 /* It is time to make this station begin to ring. Do it! */
3697 sla_ring_station(ringing_trunk
, station_ref
->station
);
3700 /* Now, all of the stations that should be ringing, are ringing. */
3703 static void sla_hangup_stations(void)
3705 struct sla_trunk_ref
*trunk_ref
;
3706 struct sla_ringing_station
*ringing_station
;
3708 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3709 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3710 struct sla_ringing_trunk
*ringing_trunk
;
3711 ast_mutex_lock(&sla
.lock
);
3712 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3713 if (trunk_ref
->trunk
== ringing_trunk
->trunk
)
3716 ast_mutex_unlock(&sla
.lock
);
3721 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3722 ast_dial_join(ringing_station
->station
->dial
);
3723 ast_dial_destroy(ringing_station
->station
->dial
);
3724 ringing_station
->station
->dial
= NULL
;
3725 free(ringing_station
);
3728 AST_LIST_TRAVERSE_SAFE_END
3731 static void sla_handle_ringing_trunk_event(void)
3733 ast_mutex_lock(&sla
.lock
);
3734 sla_ring_stations();
3735 ast_mutex_unlock(&sla
.lock
);
3737 /* Find stations that shouldn't be ringing anymore. */
3738 sla_hangup_stations();
3741 static void sla_handle_hold_event(struct sla_event
*event
)
3743 ast_atomic_fetchadd_int((int *) &event
->trunk_ref
->trunk
->hold_stations
, 1);
3744 event
->trunk_ref
->state
= SLA_TRUNK_STATE_ONHOLD_BYME
;
3745 ast_device_state_changed("SLA:%s_%s",
3746 event
->station
->name
, event
->trunk_ref
->trunk
->name
);
3747 sla_change_trunk_state(event
->trunk_ref
->trunk
, SLA_TRUNK_STATE_ONHOLD
,
3748 INACTIVE_TRUNK_REFS
, event
->trunk_ref
);
3750 if (event
->trunk_ref
->trunk
->active_stations
== 1) {
3751 /* The station putting it on hold is the only one on the call, so start
3752 * Music on hold to the trunk. */
3753 event
->trunk_ref
->trunk
->on_hold
= 1;
3754 ast_indicate(event
->trunk_ref
->trunk
->chan
, AST_CONTROL_HOLD
);
3757 ast_softhangup(event
->trunk_ref
->chan
, AST_CAUSE_NORMAL
);
3758 event
->trunk_ref
->chan
= NULL
;
3761 /*! \brief Process trunk ring timeouts
3762 * \note Called with sla.lock locked
3763 * \return non-zero if a change to the ringing trunks was made
3765 static int sla_calc_trunk_timeouts(unsigned int *timeout
)
3767 struct sla_ringing_trunk
*ringing_trunk
;
3770 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3771 int time_left
, time_elapsed
;
3772 if (!ringing_trunk
->trunk
->ring_timeout
)
3774 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3775 time_left
= (ringing_trunk
->trunk
->ring_timeout
* 1000) - time_elapsed
;
3776 if (time_left
<= 0) {
3777 pbx_builtin_setvar_helper(ringing_trunk
->trunk
->chan
, "SLATRUNK_STATUS", "RINGTIMEOUT");
3778 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3779 sla_stop_ringing_trunk(ringing_trunk
);
3783 if (time_left
< *timeout
)
3784 *timeout
= time_left
;
3786 AST_LIST_TRAVERSE_SAFE_END
3791 /*! \brief Process station ring timeouts
3792 * \note Called with sla.lock locked
3793 * \return non-zero if a change to the ringing stations was made
3795 static int sla_calc_station_timeouts(unsigned int *timeout
)
3797 struct sla_ringing_trunk
*ringing_trunk
;
3798 struct sla_ringing_station
*ringing_station
;
3801 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3802 unsigned int ring_timeout
= 0;
3803 int time_elapsed
, time_left
= INT_MAX
, final_trunk_time_left
= INT_MIN
;
3804 struct sla_trunk_ref
*trunk_ref
;
3806 /* If there are any ring timeouts specified for a specific trunk
3807 * on the station, then use the highest per-trunk ring timeout.
3808 * Otherwise, use the ring timeout set for the entire station. */
3809 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3810 struct sla_station_ref
*station_ref
;
3811 int trunk_time_elapsed
, trunk_time_left
;
3813 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3814 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3820 /* If there is a trunk that is ringing without a timeout, then the
3821 * only timeout that could matter is a global station ring timeout. */
3822 if (!trunk_ref
->ring_timeout
)
3825 /* This trunk on this station is ringing and has a timeout.
3826 * However, make sure this trunk isn't still ringing from a
3827 * previous timeout. If so, don't consider it. */
3828 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, station_ref
, entry
) {
3829 if (station_ref
->station
== ringing_station
->station
)
3835 trunk_time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3836 trunk_time_left
= (trunk_ref
->ring_timeout
* 1000) - trunk_time_elapsed
;
3837 if (trunk_time_left
> final_trunk_time_left
)
3838 final_trunk_time_left
= trunk_time_left
;
3841 /* No timeout was found for ringing trunks, and no timeout for the entire station */
3842 if (final_trunk_time_left
== INT_MIN
&& !ringing_station
->station
->ring_timeout
)
3845 /* Compute how much time is left for a global station timeout */
3846 if (ringing_station
->station
->ring_timeout
) {
3847 ring_timeout
= ringing_station
->station
->ring_timeout
;
3848 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_station
->ring_begin
);
3849 time_left
= (ring_timeout
* 1000) - time_elapsed
;
3852 /* If the time left based on the per-trunk timeouts is smaller than the
3853 * global station ring timeout, use that. */
3854 if (final_trunk_time_left
> INT_MIN
&& final_trunk_time_left
< time_left
)
3855 time_left
= final_trunk_time_left
;
3857 /* If there is no time left, the station needs to stop ringing */
3858 if (time_left
<= 0) {
3859 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3860 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_TIMEOUT
);
3865 /* There is still some time left for this station to ring, so save that
3866 * timeout if it is the first event scheduled to occur */
3867 if (time_left
< *timeout
)
3868 *timeout
= time_left
;
3870 AST_LIST_TRAVERSE_SAFE_END
3875 /*! \brief Calculate the ring delay for a station
3876 * \note Assumes sla.lock is locked
3878 static int sla_calc_station_delays(unsigned int *timeout
)
3880 struct sla_station
*station
;
3883 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3884 struct sla_ringing_trunk
*ringing_trunk
;
3887 /* Ignore stations already ringing */
3888 if (sla_check_ringing_station(station
))
3891 /* Ignore stations already on a call */
3892 if (sla_check_inuse_station(station
))
3895 /* Ignore stations that don't have one of their trunks ringing */
3896 if (!(ringing_trunk
= sla_choose_ringing_trunk(station
, NULL
, 0)))
3899 if ((time_left
= sla_check_station_delay(station
, ringing_trunk
)) == INT_MAX
)
3902 /* If there is no time left, then the station needs to start ringing.
3903 * Return non-zero so that an event will be queued up an event to
3904 * make that happen. */
3905 if (time_left
<= 0) {
3910 if (time_left
< *timeout
)
3911 *timeout
= time_left
;
3917 /*! \brief Calculate the time until the next known event
3918 * \note Called with sla.lock locked */
3919 static int sla_process_timers(struct timespec
*ts
)
3921 unsigned int timeout
= UINT_MAX
;
3923 unsigned int change_made
= 0;
3925 /* Check for ring timeouts on ringing trunks */
3926 if (sla_calc_trunk_timeouts(&timeout
))
3929 /* Check for ring timeouts on ringing stations */
3930 if (sla_calc_station_timeouts(&timeout
))
3933 /* Check for station ring delays */
3934 if (sla_calc_station_delays(&timeout
))
3937 /* queue reprocessing of ringing trunks */
3939 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK
);
3942 if (timeout
== UINT_MAX
)
3946 tv
= ast_tvadd(ast_tvnow(), ast_samp2tv(timeout
, 1000));
3947 ts
->tv_sec
= tv
.tv_sec
;
3948 ts
->tv_nsec
= tv
.tv_usec
* 1000;
3954 static void *sla_thread(void *data
)
3956 struct sla_failed_station
*failed_station
;
3957 struct sla_ringing_station
*ringing_station
;
3959 ast_mutex_lock(&sla
.lock
);
3962 struct sla_event
*event
;
3963 struct timespec ts
= { 0, };
3964 unsigned int have_timeout
= 0;
3966 if (AST_LIST_EMPTY(&sla
.event_q
)) {
3967 if ((have_timeout
= sla_process_timers(&ts
)))
3968 ast_cond_timedwait(&sla
.cond
, &sla
.lock
, &ts
);
3970 ast_cond_wait(&sla
.cond
, &sla
.lock
);
3976 sla_process_timers(NULL
);
3978 while ((event
= AST_LIST_REMOVE_HEAD(&sla
.event_q
, entry
))) {
3979 ast_mutex_unlock(&sla
.lock
);
3980 switch (event
->type
) {
3981 case SLA_EVENT_HOLD
:
3982 sla_handle_hold_event(event
);
3984 case SLA_EVENT_DIAL_STATE
:
3985 sla_handle_dial_state_event();
3987 case SLA_EVENT_RINGING_TRUNK
:
3988 sla_handle_ringing_trunk_event();
3992 ast_mutex_lock(&sla
.lock
);
3996 ast_mutex_unlock(&sla
.lock
);
3998 while ((ringing_station
= AST_LIST_REMOVE_HEAD(&sla
.ringing_stations
, entry
)))
3999 free(ringing_station
);
4001 while ((failed_station
= AST_LIST_REMOVE_HEAD(&sla
.failed_stations
, entry
)))
4002 free(failed_station
);
4007 struct dial_trunk_args
{
4008 struct sla_trunk_ref
*trunk_ref
;
4009 struct sla_station
*station
;
4010 ast_mutex_t
*cond_lock
;
4014 static void *dial_trunk(void *data
)
4016 struct dial_trunk_args
*args
= data
;
4017 struct ast_dial
*dial
;
4018 char *tech
, *tech_data
;
4019 enum ast_dial_result dial_res
;
4020 char conf_name
[MAX_CONFNUM
];
4021 struct ast_conference
*conf
;
4022 struct ast_flags conf_flags
= { 0 };
4023 struct sla_trunk_ref
*trunk_ref
= args
->trunk_ref
;
4024 const char *cid_name
= NULL
, *cid_num
= NULL
;
4026 if (!(dial
= ast_dial_create())) {
4027 ast_mutex_lock(args
->cond_lock
);
4028 ast_cond_signal(args
->cond
);
4029 ast_mutex_unlock(args
->cond_lock
);
4033 tech_data
= ast_strdupa(trunk_ref
->trunk
->device
);
4034 tech
= strsep(&tech_data
, "/");
4035 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
4036 ast_mutex_lock(args
->cond_lock
);
4037 ast_cond_signal(args
->cond
);
4038 ast_mutex_unlock(args
->cond_lock
);
4039 ast_dial_destroy(dial
);
4043 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_name
)) {
4044 cid_name
= ast_strdupa(trunk_ref
->chan
->cid
.cid_name
);
4045 free(trunk_ref
->chan
->cid
.cid_name
);
4046 trunk_ref
->chan
->cid
.cid_name
= NULL
;
4048 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_num
)) {
4049 cid_num
= ast_strdupa(trunk_ref
->chan
->cid
.cid_num
);
4050 free(trunk_ref
->chan
->cid
.cid_num
);
4051 trunk_ref
->chan
->cid
.cid_num
= NULL
;
4054 dial_res
= ast_dial_run(dial
, trunk_ref
->chan
, 1);
4057 trunk_ref
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
4059 trunk_ref
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
4061 if (dial_res
!= AST_DIAL_RESULT_TRYING
) {
4062 ast_mutex_lock(args
->cond_lock
);
4063 ast_cond_signal(args
->cond
);
4064 ast_mutex_unlock(args
->cond_lock
);
4065 ast_dial_destroy(dial
);
4070 unsigned int done
= 0;
4071 switch ((dial_res
= ast_dial_state(dial
))) {
4072 case AST_DIAL_RESULT_ANSWERED
:
4073 trunk_ref
->trunk
->chan
= ast_dial_answered(dial
);
4074 case AST_DIAL_RESULT_HANGUP
:
4075 case AST_DIAL_RESULT_INVALID
:
4076 case AST_DIAL_RESULT_FAILED
:
4077 case AST_DIAL_RESULT_TIMEOUT
:
4078 case AST_DIAL_RESULT_UNANSWERED
:
4080 case AST_DIAL_RESULT_TRYING
:
4081 case AST_DIAL_RESULT_RINGING
:
4082 case AST_DIAL_RESULT_PROGRESS
:
4083 case AST_DIAL_RESULT_PROCEEDING
:
4090 if (!trunk_ref
->trunk
->chan
) {
4091 ast_mutex_lock(args
->cond_lock
);
4092 ast_cond_signal(args
->cond
);
4093 ast_mutex_unlock(args
->cond_lock
);
4094 ast_dial_join(dial
);
4095 ast_dial_destroy(dial
);
4099 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4100 ast_set_flag(&conf_flags
,
4101 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
|
4102 CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_TRUNK
);
4103 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4105 ast_mutex_lock(args
->cond_lock
);
4106 ast_cond_signal(args
->cond
);
4107 ast_mutex_unlock(args
->cond_lock
);
4110 conf_run(trunk_ref
->trunk
->chan
, conf
, conf_flags
.flags
, NULL
);
4115 /* If the trunk is going away, it is definitely now IDLE. */
4116 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4118 trunk_ref
->trunk
->chan
= NULL
;
4119 trunk_ref
->trunk
->on_hold
= 0;
4121 ast_dial_join(dial
);
4122 ast_dial_destroy(dial
);
4127 /*! \brief For a given station, choose the highest priority idle trunk
4129 static struct sla_trunk_ref
*sla_choose_idle_trunk(const struct sla_station
*station
)
4131 struct sla_trunk_ref
*trunk_ref
= NULL
;
4133 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4134 if (trunk_ref
->state
== SLA_TRUNK_STATE_IDLE
)
4141 static int sla_station_exec(struct ast_channel
*chan
, void *data
)
4143 char *station_name
, *trunk_name
;
4144 struct sla_station
*station
;
4145 struct sla_trunk_ref
*trunk_ref
= NULL
;
4146 char conf_name
[MAX_CONFNUM
];
4147 struct ast_flags conf_flags
= { 0 };
4148 struct ast_conference
*conf
;
4150 if (ast_strlen_zero(data
)) {
4151 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4152 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4156 trunk_name
= ast_strdupa(data
);
4157 station_name
= strsep(&trunk_name
, "_");
4159 if (ast_strlen_zero(station_name
)) {
4160 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4161 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4165 AST_RWLIST_RDLOCK(&sla_stations
);
4166 station
= sla_find_station(station_name
);
4167 AST_RWLIST_UNLOCK(&sla_stations
);
4170 ast_log(LOG_WARNING
, "Station '%s' not found!\n", station_name
);
4171 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4175 AST_RWLIST_RDLOCK(&sla_trunks
);
4176 if (!ast_strlen_zero(trunk_name
)) {
4177 trunk_ref
= sla_find_trunk_ref_byname(station
, trunk_name
);
4179 trunk_ref
= sla_choose_idle_trunk(station
);
4180 AST_RWLIST_UNLOCK(&sla_trunks
);
4183 if (ast_strlen_zero(trunk_name
))
4184 ast_log(LOG_NOTICE
, "No trunks available for call.\n");
4186 ast_log(LOG_NOTICE
, "Can't join existing call on trunk "
4187 "'%s' due to access controls.\n", trunk_name
);
4189 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4193 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
) {
4194 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->hold_stations
) == 1)
4195 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4197 trunk_ref
->state
= SLA_TRUNK_STATE_UP
;
4198 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4200 } else if (trunk_ref
->state
== SLA_TRUNK_STATE_RINGING
) {
4201 struct sla_ringing_trunk
*ringing_trunk
;
4203 ast_mutex_lock(&sla
.lock
);
4204 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4205 if (ringing_trunk
->trunk
== trunk_ref
->trunk
) {
4206 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4210 AST_LIST_TRAVERSE_SAFE_END
4211 ast_mutex_unlock(&sla
.lock
);
4213 if (ringing_trunk
) {
4214 ast_answer(ringing_trunk
->trunk
->chan
);
4215 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4217 free(ringing_trunk
);
4219 /* Queue up reprocessing ringing trunks, and then ringing stations again */
4220 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4221 sla_queue_event(SLA_EVENT_DIAL_STATE
);
4225 trunk_ref
->chan
= chan
;
4227 if (!trunk_ref
->trunk
->chan
) {
4228 ast_mutex_t cond_lock
;
4230 pthread_t dont_care
;
4231 pthread_attr_t attr
;
4232 struct dial_trunk_args args
= {
4233 .trunk_ref
= trunk_ref
,
4235 .cond_lock
= &cond_lock
,
4238 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4239 /* Create a thread to dial the trunk and dump it into the conference.
4240 * However, we want to wait until the trunk has been dialed and the
4241 * conference is created before continuing on here. */
4242 ast_autoservice_start(chan
);
4243 ast_mutex_init(&cond_lock
);
4244 ast_cond_init(&cond
, NULL
);
4245 pthread_attr_init(&attr
);
4246 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4247 ast_mutex_lock(&cond_lock
);
4248 ast_pthread_create_background(&dont_care
, &attr
, dial_trunk
, &args
);
4249 ast_cond_wait(&cond
, &cond_lock
);
4250 ast_mutex_unlock(&cond_lock
);
4251 ast_mutex_destroy(&cond_lock
);
4252 ast_cond_destroy(&cond
);
4253 pthread_attr_destroy(&attr
);
4254 ast_autoservice_stop(chan
);
4255 if (!trunk_ref
->trunk
->chan
) {
4256 ast_log(LOG_DEBUG
, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref
->trunk
->chan
);
4257 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4258 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4259 trunk_ref
->chan
= NULL
;
4264 if (ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1) == 0 &&
4265 trunk_ref
->trunk
->on_hold
) {
4266 trunk_ref
->trunk
->on_hold
= 0;
4267 ast_indicate(trunk_ref
->trunk
->chan
, AST_CONTROL_UNHOLD
);
4268 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4271 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4272 ast_set_flag(&conf_flags
,
4273 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
4275 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
4277 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4281 trunk_ref
->chan
= NULL
;
4282 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
4283 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
4284 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
4285 admin_exec(NULL
, conf_name
);
4286 trunk_ref
->trunk
->hold_stations
= 0;
4287 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4290 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "SUCCESS");
4295 static struct sla_trunk_ref
*create_trunk_ref(struct sla_trunk
*trunk
)
4297 struct sla_trunk_ref
*trunk_ref
;
4299 if (!(trunk_ref
= ast_calloc(1, sizeof(*trunk_ref
))))
4302 trunk_ref
->trunk
= trunk
;
4307 static struct sla_ringing_trunk
*queue_ringing_trunk(struct sla_trunk
*trunk
)
4309 struct sla_ringing_trunk
*ringing_trunk
;
4311 if (!(ringing_trunk
= ast_calloc(1, sizeof(*ringing_trunk
))))
4314 ringing_trunk
->trunk
= trunk
;
4315 ringing_trunk
->ring_begin
= ast_tvnow();
4317 sla_change_trunk_state(trunk
, SLA_TRUNK_STATE_RINGING
, ALL_TRUNK_REFS
, NULL
);
4319 ast_mutex_lock(&sla
.lock
);
4320 AST_LIST_INSERT_HEAD(&sla
.ringing_trunks
, ringing_trunk
, entry
);
4321 ast_mutex_unlock(&sla
.lock
);
4323 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4325 return ringing_trunk
;
4328 static int sla_trunk_exec(struct ast_channel
*chan
, void *data
)
4330 const char *trunk_name
= data
;
4331 char conf_name
[MAX_CONFNUM
];
4332 struct ast_conference
*conf
;
4333 struct ast_flags conf_flags
= { 0 };
4334 struct sla_trunk
*trunk
;
4335 struct sla_ringing_trunk
*ringing_trunk
;
4337 AST_RWLIST_RDLOCK(&sla_trunks
);
4338 trunk
= sla_find_trunk(trunk_name
);
4339 AST_RWLIST_UNLOCK(&sla_trunks
);
4341 ast_log(LOG_ERROR
, "SLA Trunk '%s' not found!\n", trunk_name
);
4342 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4346 ast_log(LOG_ERROR
, "Call came in on %s, but the trunk is already in use!\n",
4348 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4353 if (!(ringing_trunk
= queue_ringing_trunk(trunk
))) {
4354 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4358 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_name
);
4359 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4361 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4364 ast_set_flag(&conf_flags
,
4365 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
| CONFFLAG_PASS_DTMF
);
4366 ast_indicate(chan
, AST_CONTROL_RINGING
);
4367 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4373 sla_change_trunk_state(trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4375 if (!pbx_builtin_getvar_helper(chan
, "SLATRUNK_STATUS"))
4376 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "SUCCESS");
4378 /* Remove the entry from the list of ringing trunks if it is still there. */
4379 ast_mutex_lock(&sla
.lock
);
4380 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4381 if (ringing_trunk
->trunk
== trunk
) {
4382 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4386 AST_LIST_TRAVERSE_SAFE_END
4387 ast_mutex_unlock(&sla
.lock
);
4388 if (ringing_trunk
) {
4389 free(ringing_trunk
);
4390 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "UNANSWERED");
4391 /* Queue reprocessing of ringing trunks to make stations stop ringing
4392 * that shouldn't be ringing after this trunk stopped. */
4393 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4399 static int sla_state(const char *data
)
4401 char *buf
, *station_name
, *trunk_name
;
4402 struct sla_station
*station
;
4403 struct sla_trunk_ref
*trunk_ref
;
4404 int res
= AST_DEVICE_INVALID
;
4406 trunk_name
= buf
= ast_strdupa(data
);
4407 station_name
= strsep(&trunk_name
, "_");
4409 AST_RWLIST_RDLOCK(&sla_stations
);
4410 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
4411 if (strcasecmp(station_name
, station
->name
))
4413 AST_RWLIST_RDLOCK(&sla_trunks
);
4414 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4415 if (!strcasecmp(trunk_name
, trunk_ref
->trunk
->name
))
4419 AST_RWLIST_UNLOCK(&sla_trunks
);
4422 switch (trunk_ref
->state
) {
4423 case SLA_TRUNK_STATE_IDLE
:
4424 res
= AST_DEVICE_NOT_INUSE
;
4426 case SLA_TRUNK_STATE_RINGING
:
4427 res
= AST_DEVICE_RINGING
;
4429 case SLA_TRUNK_STATE_UP
:
4430 res
= AST_DEVICE_INUSE
;
4432 case SLA_TRUNK_STATE_ONHOLD
:
4433 case SLA_TRUNK_STATE_ONHOLD_BYME
:
4434 res
= AST_DEVICE_ONHOLD
;
4437 AST_RWLIST_UNLOCK(&sla_trunks
);
4439 AST_RWLIST_UNLOCK(&sla_stations
);
4441 if (res
== AST_DEVICE_INVALID
) {
4442 ast_log(LOG_ERROR
, "Could not determine state for trunk %s on station %s!\n",
4443 trunk_name
, station_name
);
4449 static void destroy_trunk(struct sla_trunk
*trunk
)
4451 struct sla_station_ref
*station_ref
;
4453 if (!ast_strlen_zero(trunk
->autocontext
))
4454 ast_context_remove_extension(trunk
->autocontext
, "s", 1, sla_registrar
);
4456 while ((station_ref
= AST_LIST_REMOVE_HEAD(&trunk
->stations
, entry
)))
4459 ast_string_field_free_memory(trunk
);
4463 static void destroy_station(struct sla_station
*station
)
4465 struct sla_trunk_ref
*trunk_ref
;
4467 if (!ast_strlen_zero(station
->autocontext
)) {
4468 AST_RWLIST_RDLOCK(&sla_trunks
);
4469 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4470 char exten
[AST_MAX_EXTENSION
];
4471 char hint
[AST_MAX_APP
];
4472 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4473 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4474 ast_context_remove_extension(station
->autocontext
, exten
,
4476 ast_context_remove_extension(station
->autocontext
, hint
,
4477 PRIORITY_HINT
, sla_registrar
);
4479 AST_RWLIST_UNLOCK(&sla_trunks
);
4482 while ((trunk_ref
= AST_LIST_REMOVE_HEAD(&station
->trunks
, entry
)))
4485 ast_string_field_free_memory(station
);
4489 static void sla_destroy(void)
4491 struct sla_trunk
*trunk
;
4492 struct sla_station
*station
;
4494 AST_RWLIST_WRLOCK(&sla_trunks
);
4495 while ((trunk
= AST_RWLIST_REMOVE_HEAD(&sla_trunks
, entry
)))
4496 destroy_trunk(trunk
);
4497 AST_RWLIST_UNLOCK(&sla_trunks
);
4499 AST_RWLIST_WRLOCK(&sla_stations
);
4500 while ((station
= AST_RWLIST_REMOVE_HEAD(&sla_stations
, entry
)))
4501 destroy_station(station
);
4502 AST_RWLIST_UNLOCK(&sla_stations
);
4504 if (sla
.thread
!= AST_PTHREADT_NULL
) {
4505 ast_mutex_lock(&sla
.lock
);
4507 ast_cond_signal(&sla
.cond
);
4508 ast_mutex_unlock(&sla
.lock
);
4509 pthread_join(sla
.thread
, NULL
);
4512 /* Drop any created contexts from the dialplan */
4513 ast_context_destroy(NULL
, sla_registrar
);
4515 ast_mutex_destroy(&sla
.lock
);
4516 ast_cond_destroy(&sla
.cond
);
4519 static int sla_check_device(const char *device
)
4521 char *tech
, *tech_data
;
4523 tech_data
= ast_strdupa(device
);
4524 tech
= strsep(&tech_data
, "/");
4526 if (ast_strlen_zero(tech
) || ast_strlen_zero(tech_data
))
4532 static int sla_build_trunk(struct ast_config
*cfg
, const char *cat
)
4534 struct sla_trunk
*trunk
;
4535 struct ast_variable
*var
;
4538 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4539 ast_log(LOG_ERROR
, "SLA Trunk '%s' defined with no device!\n", cat
);
4543 if (sla_check_device(dev
)) {
4544 ast_log(LOG_ERROR
, "SLA Trunk '%s' define with invalid device '%s'!\n",
4549 if (!(trunk
= ast_calloc(1, sizeof(*trunk
))))
4551 if (ast_string_field_init(trunk
, 32)) {
4556 ast_string_field_set(trunk
, name
, cat
);
4557 ast_string_field_set(trunk
, device
, dev
);
4559 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4560 if (!strcasecmp(var
->name
, "autocontext"))
4561 ast_string_field_set(trunk
, autocontext
, var
->value
);
4562 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4563 if (sscanf(var
->value
, "%u", &trunk
->ring_timeout
) != 1) {
4564 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
4565 var
->value
, trunk
->name
);
4566 trunk
->ring_timeout
= 0;
4568 } else if (!strcasecmp(var
->name
, "barge"))
4569 trunk
->barge_disabled
= ast_false(var
->value
);
4570 else if (!strcasecmp(var
->name
, "hold")) {
4571 if (!strcasecmp(var
->value
, "private"))
4572 trunk
->hold_access
= SLA_HOLD_PRIVATE
;
4573 else if (!strcasecmp(var
->value
, "open"))
4574 trunk
->hold_access
= SLA_HOLD_OPEN
;
4576 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on trunk %s\n",
4577 var
->value
, trunk
->name
);
4579 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4580 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4581 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4585 if (!ast_strlen_zero(trunk
->autocontext
)) {
4586 struct ast_context
*context
;
4587 context
= ast_context_find_or_create(NULL
, trunk
->autocontext
, sla_registrar
);
4589 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4590 "context '%s' for SLA!\n", trunk
->autocontext
);
4591 destroy_trunk(trunk
);
4594 if (ast_add_extension2(context
, 0 /* don't replace */, "s", 1,
4595 NULL
, NULL
, slatrunk_app
, ast_strdup(trunk
->name
), ast_free
, sla_registrar
)) {
4596 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4597 "for trunk '%s'!\n", trunk
->name
);
4598 destroy_trunk(trunk
);
4603 AST_RWLIST_WRLOCK(&sla_trunks
);
4604 AST_RWLIST_INSERT_TAIL(&sla_trunks
, trunk
, entry
);
4605 AST_RWLIST_UNLOCK(&sla_trunks
);
4610 static void sla_add_trunk_to_station(struct sla_station
*station
, struct ast_variable
*var
)
4612 struct sla_trunk
*trunk
;
4613 struct sla_trunk_ref
*trunk_ref
;
4614 struct sla_station_ref
*station_ref
;
4615 char *trunk_name
, *options
, *cur
;
4617 options
= ast_strdupa(var
->value
);
4618 trunk_name
= strsep(&options
, ",");
4620 AST_RWLIST_RDLOCK(&sla_trunks
);
4621 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
4622 if (!strcasecmp(trunk
->name
, trunk_name
))
4626 AST_RWLIST_UNLOCK(&sla_trunks
);
4628 ast_log(LOG_ERROR
, "Trunk '%s' not found!\n", var
->value
);
4631 if (!(trunk_ref
= create_trunk_ref(trunk
)))
4633 trunk_ref
->state
= SLA_TRUNK_STATE_IDLE
;
4635 while ((cur
= strsep(&options
, ","))) {
4636 char *name
, *value
= cur
;
4637 name
= strsep(&value
, "=");
4638 if (!strcasecmp(name
, "ringtimeout")) {
4639 if (sscanf(value
, "%u", &trunk_ref
->ring_timeout
) != 1) {
4640 ast_log(LOG_WARNING
, "Invalid ringtimeout value '%s' for "
4641 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4642 trunk_ref
->ring_timeout
= 0;
4644 } else if (!strcasecmp(name
, "ringdelay")) {
4645 if (sscanf(value
, "%u", &trunk_ref
->ring_delay
) != 1) {
4646 ast_log(LOG_WARNING
, "Invalid ringdelay value '%s' for "
4647 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4648 trunk_ref
->ring_delay
= 0;
4651 ast_log(LOG_WARNING
, "Invalid option '%s' for "
4652 "trunk '%s' on station '%s'\n", name
, trunk
->name
, station
->name
);
4656 if (!(station_ref
= sla_create_station_ref(station
))) {
4660 ast_atomic_fetchadd_int((int *) &trunk
->num_stations
, 1);
4661 AST_RWLIST_WRLOCK(&sla_trunks
);
4662 AST_LIST_INSERT_TAIL(&trunk
->stations
, station_ref
, entry
);
4663 AST_RWLIST_UNLOCK(&sla_trunks
);
4664 AST_LIST_INSERT_TAIL(&station
->trunks
, trunk_ref
, entry
);
4667 static int sla_build_station(struct ast_config
*cfg
, const char *cat
)
4669 struct sla_station
*station
;
4670 struct ast_variable
*var
;
4673 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4674 ast_log(LOG_ERROR
, "SLA Station '%s' defined with no device!\n", cat
);
4678 if (!(station
= ast_calloc(1, sizeof(*station
))))
4680 if (ast_string_field_init(station
, 32)) {
4685 ast_string_field_set(station
, name
, cat
);
4686 ast_string_field_set(station
, device
, dev
);
4688 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4689 if (!strcasecmp(var
->name
, "trunk"))
4690 sla_add_trunk_to_station(station
, var
);
4691 else if (!strcasecmp(var
->name
, "autocontext"))
4692 ast_string_field_set(station
, autocontext
, var
->value
);
4693 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4694 if (sscanf(var
->value
, "%u", &station
->ring_timeout
) != 1) {
4695 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for station '%s'\n",
4696 var
->value
, station
->name
);
4697 station
->ring_timeout
= 0;
4699 } else if (!strcasecmp(var
->name
, "ringdelay")) {
4700 if (sscanf(var
->value
, "%u", &station
->ring_delay
) != 1) {
4701 ast_log(LOG_WARNING
, "Invalid ringdelay '%s' specified for station '%s'\n",
4702 var
->value
, station
->name
);
4703 station
->ring_delay
= 0;
4705 } else if (!strcasecmp(var
->name
, "hold")) {
4706 if (!strcasecmp(var
->value
, "private"))
4707 station
->hold_access
= SLA_HOLD_PRIVATE
;
4708 else if (!strcasecmp(var
->value
, "open"))
4709 station
->hold_access
= SLA_HOLD_OPEN
;
4711 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on station %s\n",
4712 var
->value
, station
->name
);
4715 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4716 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4717 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4721 if (!ast_strlen_zero(station
->autocontext
)) {
4722 struct ast_context
*context
;
4723 struct sla_trunk_ref
*trunk_ref
;
4724 context
= ast_context_find_or_create(NULL
, station
->autocontext
, sla_registrar
);
4726 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4727 "context '%s' for SLA!\n", station
->autocontext
);
4728 destroy_station(station
);
4731 /* The extension for when the handset goes off-hook.
4732 * exten => station1,1,SLAStation(station1) */
4733 if (ast_add_extension2(context
, 0 /* don't replace */, station
->name
, 1,
4734 NULL
, NULL
, slastation_app
, ast_strdup(station
->name
), ast_free
, sla_registrar
)) {
4735 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4736 "for trunk '%s'!\n", station
->name
);
4737 destroy_station(station
);
4740 AST_RWLIST_RDLOCK(&sla_trunks
);
4741 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4742 char exten
[AST_MAX_EXTENSION
];
4743 char hint
[AST_MAX_APP
];
4744 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4745 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4746 /* Extension for this line button
4747 * exten => station1_line1,1,SLAStation(station1_line1) */
4748 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, 1,
4749 NULL
, NULL
, slastation_app
, ast_strdup(exten
), ast_free
, sla_registrar
)) {
4750 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4751 "for trunk '%s'!\n", station
->name
);
4752 destroy_station(station
);
4755 /* Hint for this line button
4756 * exten => station1_line1,hint,SLA:station1_line1 */
4757 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, PRIORITY_HINT
,
4758 NULL
, NULL
, hint
, NULL
, NULL
, sla_registrar
)) {
4759 ast_log(LOG_ERROR
, "Failed to automatically create hint "
4760 "for trunk '%s'!\n", station
->name
);
4761 destroy_station(station
);
4765 AST_RWLIST_UNLOCK(&sla_trunks
);
4768 AST_RWLIST_WRLOCK(&sla_stations
);
4769 AST_RWLIST_INSERT_TAIL(&sla_stations
, station
, entry
);
4770 AST_RWLIST_UNLOCK(&sla_stations
);
4775 static int sla_load_config(void)
4777 struct ast_config
*cfg
;
4778 const char *cat
= NULL
;
4782 ast_mutex_init(&sla
.lock
);
4783 ast_cond_init(&sla
.cond
, NULL
);
4785 if (!(cfg
= ast_config_load(SLA_CONFIG_FILE
)))
4786 return 0; /* Treat no config as normal */
4788 if ((val
= ast_variable_retrieve(cfg
, "general", "attemptcallerid")))
4789 sla
.attempt_callerid
= ast_true(val
);
4791 while ((cat
= ast_category_browse(cfg
, cat
)) && !res
) {
4793 if (!strcasecmp(cat
, "general"))
4795 if (!(type
= ast_variable_retrieve(cfg
, cat
, "type"))) {
4796 ast_log(LOG_WARNING
, "Invalid entry in %s defined with no type!\n",
4800 if (!strcasecmp(type
, "trunk"))
4801 res
= sla_build_trunk(cfg
, cat
);
4802 else if (!strcasecmp(type
, "station"))
4803 res
= sla_build_station(cfg
, cat
);
4805 ast_log(LOG_WARNING
, "Entry in %s defined with invalid type '%s'!\n",
4806 SLA_CONFIG_FILE
, type
);
4810 ast_config_destroy(cfg
);
4812 if (!AST_LIST_EMPTY(&sla_stations
) || !AST_LIST_EMPTY(&sla_stations
))
4813 ast_pthread_create(&sla
.thread
, NULL
, sla_thread
, NULL
);
4818 static int load_config(int reload
)
4822 load_config_meetme();
4824 res
= sla_load_config();
4829 static int unload_module(void)
4833 ast_cli_unregister_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4834 res
= ast_manager_unregister("MeetmeMute");
4835 res
|= ast_manager_unregister("MeetmeUnmute");
4836 res
|= ast_unregister_application(app3
);
4837 res
|= ast_unregister_application(app2
);
4838 res
|= ast_unregister_application(app
);
4839 res
|= ast_unregister_application(slastation_app
);
4840 res
|= ast_unregister_application(slatrunk_app
);
4842 ast_devstate_prov_del("Meetme");
4843 ast_devstate_prov_del("SLA");
4845 ast_module_user_hangup_all();
4852 static int load_module(void)
4856 res
|= load_config(0);
4858 ast_cli_register_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4859 res
|= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL
,
4860 action_meetmemute
, "Mute a Meetme user");
4861 res
|= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL
,
4862 action_meetmeunmute
, "Unmute a Meetme user");
4863 res
|= ast_register_application(app3
, admin_exec
, synopsis3
, descrip3
);
4864 res
|= ast_register_application(app2
, count_exec
, synopsis2
, descrip2
);
4865 res
|= ast_register_application(app
, conf_exec
, synopsis
, descrip
);
4866 res
|= ast_register_application(slastation_app
, sla_station_exec
,
4867 slastation_synopsis
, slastation_desc
);
4868 res
|= ast_register_application(slatrunk_app
, sla_trunk_exec
,
4869 slatrunk_synopsis
, slatrunk_desc
);
4871 res
|= ast_devstate_prov_add("Meetme", meetmestate
);
4872 res
|= ast_devstate_prov_add("SLA", sla_state
);
4877 static int reload(void)
4879 return load_config(1);
4882 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "MeetMe conference bridge",
4883 .load
= load_module
,
4884 .unload
= unload_module
,