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 DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n"
221 " must be present for conferencing to operate properly. In addition, the chan_dahdi\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-DAHDI 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"
270 static const char *descrip3
=
271 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
272 " 'e' -- Eject last user that joined\n"
273 " 'k' -- Kick one user out of conference\n"
274 " 'K' -- Kick all users out of conference\n"
275 " 'l' -- Unlock conference\n"
276 " 'L' -- Lock conference\n"
277 " 'm' -- Unmute one user\n"
278 " 'M' -- Mute one user\n"
279 " 'n' -- Unmute all users in the conference\n"
280 " 'N' -- Mute all non-admin users in the conference\n"
281 " 'r' -- Reset one user's volume settings\n"
282 " 'R' -- Reset all users volume settings\n"
283 " 's' -- Lower entire conference speaking volume\n"
284 " 'S' -- Raise entire conference speaking volume\n"
285 " 't' -- Lower one user's talk volume\n"
286 " 'T' -- Raise one user's talk volume\n"
287 " 'u' -- Lower one user's listen volume\n"
288 " 'U' -- Raise one user's listen volume\n"
289 " 'v' -- Lower entire conference listening volume\n"
290 " 'V' -- Raise entire conference listening volume\n"
293 static const char *slastation_desc
=
294 " SLAStation(station):\n"
295 "This application should be executed by an SLA station. The argument depends\n"
296 "on how the call was initiated. If the phone was just taken off hook, then\n"
297 "the argument \"station\" should be just the station name. If the call was\n"
298 "initiated by pressing a line key, then the station name should be preceded\n"
299 "by an underscore and the trunk name associated with that line button.\n"
300 "For example: \"station1_line1\"."
301 " On exit, this application will set the variable SLASTATION_STATUS to\n"
302 "one of the following values:\n"
303 " FAILURE | CONGESTION | SUCCESS\n"
306 static const char *slatrunk_desc
=
307 " SLATrunk(trunk):\n"
308 "This application should be executed by an SLA trunk on an inbound call.\n"
309 "The channel calling this application should correspond to the SLA trunk\n"
310 "with the name \"trunk\" that is being passed as an argument.\n"
311 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
312 "one of the following values:\n"
313 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
316 #define MAX_CONFNUM 80
319 /*! \brief The MeetMe Conference object */
320 struct ast_conference
{
321 ast_mutex_t playlock
; /*!< Conference specific lock (players) */
322 ast_mutex_t listenlock
; /*!< Conference specific lock (listeners) */
323 char confno
[MAX_CONFNUM
]; /*!< Conference */
324 struct ast_channel
*chan
; /*!< Announcements channel */
325 struct ast_channel
*lchan
; /*!< Listen/Record channel */
326 int fd
; /*!< Announcements fd */
327 int zapconf
; /*!< Zaptel Conf # */
328 int users
; /*!< Number of active users */
329 int markedusers
; /*!< Number of marked users */
330 time_t start
; /*!< Start time (s) */
331 int refcount
; /*!< reference count of usage */
332 enum recording_state recording
:2; /*!< recording status */
333 unsigned int isdynamic
:1; /*!< Created on the fly? */
334 unsigned int locked
:1; /*!< Is the conference locked? */
335 pthread_t recordthread
; /*!< thread for recording */
336 ast_mutex_t recordthreadlock
; /*!< control threads trying to start recordthread */
337 pthread_attr_t attr
; /*!< thread attribute */
338 const char *recordingfilename
; /*!< Filename to record the Conference into */
339 const char *recordingformat
; /*!< Format to record the Conference in */
340 char pin
[MAX_PIN
]; /*!< If protected by a PIN */
341 char pinadmin
[MAX_PIN
]; /*!< If protected by a admin PIN */
342 struct ast_frame
*transframe
[32];
343 struct ast_frame
*origframe
;
344 struct ast_trans_pvt
*transpath
[32];
345 AST_LIST_HEAD_NOLOCK(, ast_conf_user
) userlist
;
346 AST_LIST_ENTRY(ast_conference
) list
;
349 static AST_LIST_HEAD_STATIC(confs
, ast_conference
);
351 static unsigned int conf_map
[1024] = {0, };
354 int desired
; /*!< Desired volume adjustment */
355 int actual
; /*!< Actual volume adjustment (for channels that can't adjust) */
358 struct ast_conf_user
{
359 int user_no
; /*!< User Number */
360 int userflags
; /*!< Flags as set in the conference */
361 int adminflags
; /*!< Flags set by the Admin */
362 struct ast_channel
*chan
; /*!< Connected channel */
363 int talking
; /*!< Is user talking */
364 int zapchannel
; /*!< Is a Zaptel channel */
365 char usrvalue
[50]; /*!< Custom User Value */
366 char namerecloc
[PATH_MAX
]; /*!< Name Recorded file Location */
367 time_t jointime
; /*!< Time the user joined the conference */
369 struct volume listen
;
370 AST_LIST_ENTRY(ast_conf_user
) list
;
373 enum sla_which_trunk_refs
{
378 enum sla_trunk_state
{
379 SLA_TRUNK_STATE_IDLE
,
380 SLA_TRUNK_STATE_RINGING
,
382 SLA_TRUNK_STATE_ONHOLD
,
383 SLA_TRUNK_STATE_ONHOLD_BYME
,
386 enum sla_hold_access
{
387 /*! This means that any station can put it on hold, and any station
388 * can retrieve the call from hold. */
390 /*! This means that only the station that put the call on hold may
391 * retrieve it from hold. */
395 struct sla_trunk_ref
;
398 AST_RWLIST_ENTRY(sla_station
) entry
;
399 AST_DECLARE_STRING_FIELDS(
400 AST_STRING_FIELD(name
);
401 AST_STRING_FIELD(device
);
402 AST_STRING_FIELD(autocontext
);
404 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref
) trunks
;
405 struct ast_dial
*dial
;
406 /*! Ring timeout for this station, for any trunk. If a ring timeout
407 * is set for a specific trunk on this station, that will take
408 * priority over this value. */
409 unsigned int ring_timeout
;
410 /*! Ring delay for this station, for any trunk. If a ring delay
411 * is set for a specific trunk on this station, that will take
412 * priority over this value. */
413 unsigned int ring_delay
;
414 /*! This option uses the values in the sla_hold_access enum and sets the
415 * access control type for hold on this station. */
416 unsigned int hold_access
:1;
419 struct sla_station_ref
{
420 AST_LIST_ENTRY(sla_station_ref
) entry
;
421 struct sla_station
*station
;
425 AST_RWLIST_ENTRY(sla_trunk
) entry
;
426 AST_DECLARE_STRING_FIELDS(
427 AST_STRING_FIELD(name
);
428 AST_STRING_FIELD(device
);
429 AST_STRING_FIELD(autocontext
);
431 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) stations
;
432 /*! Number of stations that use this trunk */
433 unsigned int num_stations
;
434 /*! Number of stations currently on a call with this trunk */
435 unsigned int active_stations
;
436 /*! Number of stations that have this trunk on hold. */
437 unsigned int hold_stations
;
438 struct ast_channel
*chan
;
439 unsigned int ring_timeout
;
440 /*! If set to 1, no station will be able to join an active call with
442 unsigned int barge_disabled
:1;
443 /*! This option uses the values in the sla_hold_access enum and sets the
444 * access control type for hold on this trunk. */
445 unsigned int hold_access
:1;
446 /*! Whether this trunk is currently on hold, meaning that once a station
447 * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
448 unsigned int on_hold
:1;
451 struct sla_trunk_ref
{
452 AST_LIST_ENTRY(sla_trunk_ref
) entry
;
453 struct sla_trunk
*trunk
;
454 enum sla_trunk_state state
;
455 struct ast_channel
*chan
;
456 /*! Ring timeout to use when this trunk is ringing on this specific
457 * station. This takes higher priority than a ring timeout set at
458 * the station level. */
459 unsigned int ring_timeout
;
460 /*! Ring delay to use when this trunk is ringing on this specific
461 * station. This takes higher priority than a ring delay set at
462 * the station level. */
463 unsigned int ring_delay
;
466 static AST_RWLIST_HEAD_STATIC(sla_stations
, sla_station
);
467 static AST_RWLIST_HEAD_STATIC(sla_trunks
, sla_trunk
);
469 static const char sla_registrar
[] = "SLA";
471 /*! \brief Event types that can be queued up for the SLA thread */
472 enum sla_event_type
{
473 /*! A station has put the call on hold */
475 /*! The state of a dial has changed */
476 SLA_EVENT_DIAL_STATE
,
477 /*! The state of a ringing trunk has changed */
478 SLA_EVENT_RINGING_TRUNK
,
482 enum sla_event_type type
;
483 struct sla_station
*station
;
484 struct sla_trunk_ref
*trunk_ref
;
485 AST_LIST_ENTRY(sla_event
) entry
;
488 /*! \brief A station that failed to be dialed
489 * \note Only used by the SLA thread. */
490 struct sla_failed_station
{
491 struct sla_station
*station
;
492 struct timeval last_try
;
493 AST_LIST_ENTRY(sla_failed_station
) entry
;
496 /*! \brief A trunk that is ringing */
497 struct sla_ringing_trunk
{
498 struct sla_trunk
*trunk
;
499 /*! The time that this trunk started ringing */
500 struct timeval ring_begin
;
501 AST_LIST_HEAD_NOLOCK(, sla_station_ref
) timed_out_stations
;
502 AST_LIST_ENTRY(sla_ringing_trunk
) entry
;
505 enum sla_station_hangup
{
506 SLA_STATION_HANGUP_NORMAL
,
507 SLA_STATION_HANGUP_TIMEOUT
,
510 /*! \brief A station that is ringing */
511 struct sla_ringing_station
{
512 struct sla_station
*station
;
513 /*! The time that this station started ringing */
514 struct timeval ring_begin
;
515 AST_LIST_ENTRY(sla_ringing_station
) entry
;
519 * \brief A structure for data used by the sla thread
522 /*! The SLA thread ID */
526 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk
) ringing_trunks
;
527 AST_LIST_HEAD_NOLOCK(, sla_ringing_station
) ringing_stations
;
528 AST_LIST_HEAD_NOLOCK(, sla_failed_station
) failed_stations
;
529 AST_LIST_HEAD_NOLOCK(, sla_event
) event_q
;
531 /*! Attempt to handle CallerID, even though it is known not to work
532 * properly in some situations. */
533 unsigned int attempt_callerid
:1;
535 .thread
= AST_PTHREADT_NULL
,
538 /*! The number of audio buffers to be allocated on pseudo channels
539 * when in a conference */
540 static int audio_buffers
;
542 /*! Map 'volume' levels from -5 through +5 into
543 * decibel (dB) settings for channel drivers
544 * Note: these are not a straight linear-to-dB
545 * conversion... the numbers have been modified
546 * to give the user a better level of adjustability
548 static char const gain_map
[] = {
563 static int admin_exec(struct ast_channel
*chan
, void *data
);
564 static void *recordthread(void *args
);
566 static char *istalking(int x
)
571 return "(unmonitored)";
573 return "(not talking)";
576 static int careful_write(int fd
, unsigned char *data
, int len
, int block
)
583 x
= DAHDI_IOMUX_WRITE
| DAHDI_IOMUX_SIGEVENT
;
584 res
= ioctl(fd
, DAHDI_IOMUX
, &x
);
588 res
= write(fd
, data
, len
);
590 if (errno
!= EAGAIN
) {
591 ast_log(LOG_WARNING
, "Failed to write audio data to conference: %s\n", strerror(errno
));
603 static int set_talk_volume(struct ast_conf_user
*user
, int volume
)
607 /* attempt to make the adjustment in the channel driver;
608 if successful, don't adjust in the frame reading routine
610 gain_adjust
= gain_map
[volume
+ 5];
612 return ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
615 static int set_listen_volume(struct ast_conf_user
*user
, int volume
)
619 /* attempt to make the adjustment in the channel driver;
620 if successful, don't adjust in the frame reading routine
622 gain_adjust
= gain_map
[volume
+ 5];
624 return ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &gain_adjust
, sizeof(gain_adjust
), 0);
627 static void tweak_volume(struct volume
*vol
, enum volume_action action
)
631 switch (vol
->desired
) {
646 switch (vol
->desired
) {
662 static void tweak_talk_volume(struct ast_conf_user
*user
, enum volume_action action
)
664 tweak_volume(&user
->talk
, action
);
665 /* attempt to make the adjustment in the channel driver;
666 if successful, don't adjust in the frame reading routine
668 if (!set_talk_volume(user
, user
->talk
.desired
))
669 user
->talk
.actual
= 0;
671 user
->talk
.actual
= user
->talk
.desired
;
674 static void tweak_listen_volume(struct ast_conf_user
*user
, enum volume_action action
)
676 tweak_volume(&user
->listen
, action
);
677 /* attempt to make the adjustment in the channel driver;
678 if successful, don't adjust in the frame reading routine
680 if (!set_listen_volume(user
, user
->listen
.desired
))
681 user
->listen
.actual
= 0;
683 user
->listen
.actual
= user
->listen
.desired
;
686 static void reset_volumes(struct ast_conf_user
*user
)
688 signed char zero_volume
= 0;
690 ast_channel_setoption(user
->chan
, AST_OPTION_TXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
691 ast_channel_setoption(user
->chan
, AST_OPTION_RXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
694 static void conf_play(struct ast_channel
*chan
, struct ast_conference
*conf
, enum entrance_sound sound
)
700 if (!chan
->_softhangup
)
701 res
= ast_autoservice_start(chan
);
703 AST_LIST_LOCK(&confs
);
719 careful_write(conf
->fd
, data
, len
, 1);
722 AST_LIST_UNLOCK(&confs
);
725 ast_autoservice_stop(chan
);
729 * \brief Find or create a conference
731 * \param confno The conference name/number
732 * \param pin The regular user pin
733 * \param pinadmin The admin pin
734 * \param make Make the conf if it doesn't exist
735 * \param dynamic Mark the newly created conference as dynamic
736 * \param refcount How many references to mark on the conference
738 * \return A pointer to the conference struct, or NULL if it wasn't found and
739 * make or dynamic were not set.
741 static struct ast_conference
*build_conf(char *confno
, char *pin
, char *pinadmin
, int make
, int dynamic
, int refcount
)
743 struct ast_conference
*cnf
;
744 struct dahdi_confinfo ztc
= { 0, };
747 AST_LIST_LOCK(&confs
);
749 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
750 if (!strcmp(confno
, cnf
->confno
))
754 if (cnf
|| (!make
&& !dynamic
))
758 if (!(cnf
= ast_calloc(1, sizeof(*cnf
))))
761 ast_mutex_init(&cnf
->playlock
);
762 ast_mutex_init(&cnf
->listenlock
);
763 cnf
->recordthread
= AST_PTHREADT_NULL
;
764 ast_mutex_init(&cnf
->recordthreadlock
);
765 ast_copy_string(cnf
->confno
, confno
, sizeof(cnf
->confno
));
766 ast_copy_string(cnf
->pin
, pin
, sizeof(cnf
->pin
));
767 ast_copy_string(cnf
->pinadmin
, pinadmin
, sizeof(cnf
->pinadmin
));
769 /* Setup a new zap conference */
771 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
773 cnf
->fd
= open("/dev/zap/pseudo", O_RDWR
);
775 cnf
->fd
= open("/dev/dahdi/pseudo", O_RDWR
);
777 if (cnf
->fd
< 0 || ioctl(cnf
->fd
, DAHDI_SETCONF
, &ztc
)) {
778 ast_log(LOG_WARNING
, "Unable to open pseudo device\n");
786 cnf
->zapconf
= ztc
.confno
;
788 /* Setup a new channel for playback of audio files */
789 cnf
->chan
= ast_request(dahdi_chan_name
, AST_FORMAT_SLINEAR
, "pseudo", NULL
);
791 ast_set_read_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
792 ast_set_write_format(cnf
->chan
, AST_FORMAT_SLINEAR
);
794 ztc
.confno
= cnf
->zapconf
;
795 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
796 if (ioctl(cnf
->chan
->fds
[0], DAHDI_SETCONF
, &ztc
)) {
797 ast_log(LOG_WARNING
, "Error setting conference\n");
799 ast_hangup(cnf
->chan
);
808 /* Fill the conference struct */
809 cnf
->start
= time(NULL
);
810 cnf
->isdynamic
= dynamic
? 1 : 0;
811 if (option_verbose
> 2)
812 ast_verbose(VERBOSE_PREFIX_3
"Created MeetMe conference %d for conference '%s'\n", cnf
->zapconf
, cnf
->confno
);
813 AST_LIST_INSERT_HEAD(&confs
, cnf
, list
);
815 /* Reserve conference number in map */
816 if ((sscanf(cnf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
817 conf_map
[confno_int
] = 1;
821 ast_atomic_fetchadd_int(&cnf
->refcount
, refcount
);
823 AST_LIST_UNLOCK(&confs
);
828 static int meetme_cmd(int fd
, int argc
, char **argv
)
830 /* Process the command */
831 struct ast_conference
*cnf
;
832 struct ast_conf_user
*user
;
834 int i
= 0, total
= 0;
836 char *header_format
= "%-14s %-14s %-10s %-8s %-8s\n";
837 char *data_format
= "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
838 char cmdline
[1024] = "";
841 ast_cli(fd
, "Invalid Arguments.\n");
842 /* Check for length so no buffer will overflow... */
843 for (i
= 0; i
< argc
; i
++) {
844 if (strlen(argv
[i
]) > 100)
845 ast_cli(fd
, "Invalid Arguments.\n");
848 /* 'MeetMe': List all the conferences */
850 AST_LIST_LOCK(&confs
);
851 if (AST_LIST_EMPTY(&confs
)) {
852 ast_cli(fd
, "No active MeetMe conferences.\n");
853 AST_LIST_UNLOCK(&confs
);
854 return RESULT_SUCCESS
;
856 ast_cli(fd
, header_format
, "Conf Num", "Parties", "Marked", "Activity", "Creation");
857 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
858 if (cnf
->markedusers
== 0)
859 strcpy(cmdline
, "N/A ");
861 snprintf(cmdline
, sizeof(cmdline
), "%4.4d", cnf
->markedusers
);
862 hr
= (now
- cnf
->start
) / 3600;
863 min
= ((now
- cnf
->start
) % 3600) / 60;
864 sec
= (now
- cnf
->start
) % 60;
866 ast_cli(fd
, data_format
, cnf
->confno
, cnf
->users
, cmdline
, hr
, min
, sec
, cnf
->isdynamic
? "Dynamic" : "Static");
870 AST_LIST_UNLOCK(&confs
);
871 ast_cli(fd
, "* Total number of MeetMe users: %d\n", total
);
872 return RESULT_SUCCESS
;
875 return RESULT_SHOWUSAGE
;
876 ast_copy_string(cmdline
, argv
[2], sizeof(cmdline
)); /* Argv 2: conference number */
877 if (strstr(argv
[1], "lock")) {
878 if (strcmp(argv
[1], "lock") == 0) {
880 strncat(cmdline
, "|L", sizeof(cmdline
) - strlen(cmdline
) - 1);
883 strncat(cmdline
, "|l", sizeof(cmdline
) - strlen(cmdline
) - 1);
885 } else if (strstr(argv
[1], "mute")) {
887 return RESULT_SHOWUSAGE
;
888 if (strcmp(argv
[1], "mute") == 0) {
890 if (strcmp(argv
[3], "all") == 0) {
891 strncat(cmdline
, "|N", sizeof(cmdline
) - strlen(cmdline
) - 1);
893 strncat(cmdline
, "|M|", sizeof(cmdline
) - strlen(cmdline
) - 1);
894 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
898 if (strcmp(argv
[3], "all") == 0) {
899 strncat(cmdline
, "|n", sizeof(cmdline
) - strlen(cmdline
) - 1);
901 strncat(cmdline
, "|m|", sizeof(cmdline
) - strlen(cmdline
) - 1);
902 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
905 } else if (strcmp(argv
[1], "kick") == 0) {
907 return RESULT_SHOWUSAGE
;
908 if (strcmp(argv
[3], "all") == 0) {
910 strncat(cmdline
, "|K", sizeof(cmdline
) - strlen(cmdline
) - 1);
912 /* Kick a single user */
913 strncat(cmdline
, "|k|", sizeof(cmdline
) - strlen(cmdline
) - 1);
914 strncat(cmdline
, argv
[3], sizeof(cmdline
) - strlen(cmdline
) - 1);
916 } else if(strcmp(argv
[1], "list") == 0) {
917 int concise
= ( 4 == argc
&& ( !strcasecmp(argv
[3], "concise") ) );
918 /* List all the users in a conference */
919 if (AST_LIST_EMPTY(&confs
)) {
921 ast_cli(fd
, "No active conferences.\n");
922 return RESULT_SUCCESS
;
924 /* Find the right conference */
925 AST_LIST_LOCK(&confs
);
926 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
927 if (strcmp(cnf
->confno
, argv
[2]) == 0)
932 ast_cli(fd
, "No such conference: %s.\n",argv
[2]);
933 AST_LIST_UNLOCK(&confs
);
934 return RESULT_SUCCESS
;
936 /* Show all the users */
938 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
939 hr
= (now
- user
->jointime
) / 3600;
940 min
= ((now
- user
->jointime
) % 3600) / 60;
941 sec
= (now
- user
->jointime
) % 60;
943 ast_cli(fd
, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %02d:%02d:%02d\n",
945 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
946 S_OR(user
->chan
->cid
.cid_name
, "<no name>"),
948 user
->userflags
& CONFFLAG_ADMIN
? "(Admin)" : "",
949 user
->userflags
& CONFFLAG_MONITOR
? "(Listen only)" : "",
950 user
->adminflags
& ADMINFLAG_MUTED
? "(Admin Muted)" : user
->adminflags
& ADMINFLAG_SELFMUTED
? "(Muted)" : "",
951 istalking(user
->talking
), hr
, min
, sec
);
953 ast_cli(fd
, "%d!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
955 S_OR(user
->chan
->cid
.cid_num
, ""),
956 S_OR(user
->chan
->cid
.cid_name
, ""),
958 user
->userflags
& CONFFLAG_ADMIN
? "1" : "",
959 user
->userflags
& CONFFLAG_MONITOR
? "1" : "",
960 user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
) ? "1" : "",
961 user
->talking
, hr
, min
, sec
);
965 ast_cli(fd
,"%d users in that conference.\n",cnf
->users
);
966 AST_LIST_UNLOCK(&confs
);
967 return RESULT_SUCCESS
;
969 return RESULT_SHOWUSAGE
;
970 ast_log(LOG_DEBUG
, "Cmdline: %s\n", cmdline
);
971 admin_exec(NULL
, cmdline
);
976 static char *complete_meetmecmd(const char *line
, const char *word
, int pos
, int state
)
978 static char *cmds
[] = {"lock", "unlock", "mute", "unmute", "kick", "list", NULL
};
980 int len
= strlen(word
);
982 struct ast_conference
*cnf
= NULL
;
983 struct ast_conf_user
*usr
= NULL
;
986 char *myline
, *ret
= NULL
;
988 if (pos
== 1) { /* Command */
989 return ast_cli_complete(word
, cmds
, state
);
990 } else if (pos
== 2) { /* Conference Number */
991 AST_LIST_LOCK(&confs
);
992 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
993 if (!strncasecmp(word
, cnf
->confno
, len
) && ++which
> state
) {
998 ret
= ast_strdup(ret
); /* dup before releasing the lock */
999 AST_LIST_UNLOCK(&confs
);
1001 } else if (pos
== 3) {
1002 /* User Number || Conf Command option*/
1003 if (strstr(line
, "mute") || strstr(line
, "kick")) {
1004 if (state
== 0 && (strstr(line
, "kick") || strstr(line
,"mute")) && !strncasecmp(word
, "all", len
))
1005 return strdup("all");
1007 AST_LIST_LOCK(&confs
);
1009 /* TODO: Find the conf number from the cmdline (ignore spaces) <- test this and make it fail-safe! */
1010 myline
= ast_strdupa(line
);
1011 if (strsep(&myline
, " ") && strsep(&myline
, " ") && !confno
) {
1012 while((confno
= strsep(&myline
, " ")) && (strcmp(confno
, " ") == 0))
1016 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
1017 if (!strcmp(confno
, cnf
->confno
))
1022 /* Search for the user */
1023 AST_LIST_TRAVERSE(&cnf
->userlist
, usr
, list
) {
1024 snprintf(usrno
, sizeof(usrno
), "%d", usr
->user_no
);
1025 if (!strncasecmp(word
, usrno
, len
) && ++which
> state
)
1029 AST_LIST_UNLOCK(&confs
);
1030 return usr
? strdup(usrno
) : NULL
;
1031 } else if ( strstr(line
, "list") && ( 0 == state
) )
1032 return strdup("concise");
1038 static char meetme_usage
[] =
1039 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
1040 " Executes a command for the conference or on a conferee\n";
1042 static const char *sla_hold_str(unsigned int hold_access
)
1044 const char *hold
= "Unknown";
1046 switch (hold_access
) {
1050 case SLA_HOLD_PRIVATE
:
1059 static int sla_show_trunks(int fd
, int argc
, char **argv
)
1061 const struct sla_trunk
*trunk
;
1064 "=============================================================\n"
1065 "=== Configured SLA Trunks ===================================\n"
1066 "=============================================================\n"
1068 AST_RWLIST_RDLOCK(&sla_trunks
);
1069 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
1070 struct sla_station_ref
*station_ref
;
1071 char ring_timeout
[16] = "(none)";
1072 if (trunk
->ring_timeout
)
1073 snprintf(ring_timeout
, sizeof(ring_timeout
), "%u Seconds", trunk
->ring_timeout
);
1074 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1075 "=== Trunk Name: %s\n"
1076 "=== ==> Device: %s\n"
1077 "=== ==> AutoContext: %s\n"
1078 "=== ==> RingTimeout: %s\n"
1079 "=== ==> BargeAllowed: %s\n"
1080 "=== ==> HoldAccess: %s\n"
1081 "=== ==> Stations ...\n",
1082 trunk
->name
, trunk
->device
,
1083 S_OR(trunk
->autocontext
, "(none)"),
1085 trunk
->barge_disabled
? "No" : "Yes",
1086 sla_hold_str(trunk
->hold_access
));
1087 AST_RWLIST_RDLOCK(&sla_stations
);
1088 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
)
1089 ast_cli(fd
, "=== ==> Station name: %s\n", station_ref
->station
->name
);
1090 AST_RWLIST_UNLOCK(&sla_stations
);
1091 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1094 AST_RWLIST_UNLOCK(&sla_trunks
);
1095 ast_cli(fd
, "=============================================================\n"
1098 return RESULT_SUCCESS
;
1101 static const char *trunkstate2str(enum sla_trunk_state state
)
1103 #define S(e) case e: return # e;
1105 S(SLA_TRUNK_STATE_IDLE
)
1106 S(SLA_TRUNK_STATE_RINGING
)
1107 S(SLA_TRUNK_STATE_UP
)
1108 S(SLA_TRUNK_STATE_ONHOLD
)
1109 S(SLA_TRUNK_STATE_ONHOLD_BYME
)
1111 return "Uknown State";
1115 static const char sla_show_trunks_usage
[] =
1116 "Usage: sla show trunks\n"
1117 " This will list all trunks defined in sla.conf\n";
1119 static int sla_show_stations(int fd
, int argc
, char **argv
)
1121 const struct sla_station
*station
;
1124 "=============================================================\n"
1125 "=== Configured SLA Stations =================================\n"
1126 "=============================================================\n"
1128 AST_RWLIST_RDLOCK(&sla_stations
);
1129 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1130 struct sla_trunk_ref
*trunk_ref
;
1131 char ring_timeout
[16] = "(none)";
1132 char ring_delay
[16] = "(none)";
1133 if (station
->ring_timeout
) {
1134 snprintf(ring_timeout
, sizeof(ring_timeout
),
1135 "%u", station
->ring_timeout
);
1137 if (station
->ring_delay
) {
1138 snprintf(ring_delay
, sizeof(ring_delay
),
1139 "%u", station
->ring_delay
);
1141 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1142 "=== Station Name: %s\n"
1143 "=== ==> Device: %s\n"
1144 "=== ==> AutoContext: %s\n"
1145 "=== ==> RingTimeout: %s\n"
1146 "=== ==> RingDelay: %s\n"
1147 "=== ==> HoldAccess: %s\n"
1148 "=== ==> Trunks ...\n",
1149 station
->name
, station
->device
,
1150 S_OR(station
->autocontext
, "(none)"),
1151 ring_timeout
, ring_delay
,
1152 sla_hold_str(station
->hold_access
));
1153 AST_RWLIST_RDLOCK(&sla_trunks
);
1154 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1155 if (trunk_ref
->ring_timeout
) {
1156 snprintf(ring_timeout
, sizeof(ring_timeout
),
1157 "%u", trunk_ref
->ring_timeout
);
1159 strcpy(ring_timeout
, "(none)");
1160 if (trunk_ref
->ring_delay
) {
1161 snprintf(ring_delay
, sizeof(ring_delay
),
1162 "%u", trunk_ref
->ring_delay
);
1164 strcpy(ring_delay
, "(none)");
1165 ast_cli(fd
, "=== ==> Trunk Name: %s\n"
1166 "=== ==> State: %s\n"
1167 "=== ==> RingTimeout: %s\n"
1168 "=== ==> RingDelay: %s\n",
1169 trunk_ref
->trunk
->name
,
1170 trunkstate2str(trunk_ref
->state
),
1171 ring_timeout
, ring_delay
);
1173 AST_RWLIST_UNLOCK(&sla_trunks
);
1174 ast_cli(fd
, "=== ---------------------------------------------------------\n"
1177 AST_RWLIST_UNLOCK(&sla_stations
);
1178 ast_cli(fd
, "============================================================\n"
1181 return RESULT_SUCCESS
;
1184 static const char sla_show_stations_usage
[] =
1185 "Usage: sla show stations\n"
1186 " This will list all stations defined in sla.conf\n";
1188 static struct ast_cli_entry cli_meetme
[] = {
1189 { { "meetme", NULL
, NULL
},
1190 meetme_cmd
, "Execute a command on a conference or conferee",
1191 meetme_usage
, complete_meetmecmd
},
1193 { { "sla", "show", "trunks", NULL
},
1194 sla_show_trunks
, "Show SLA Trunks",
1195 sla_show_trunks_usage
, NULL
},
1197 { { "sla", "show", "stations", NULL
},
1198 sla_show_stations
, "Show SLA Stations",
1199 sla_show_stations_usage
, NULL
},
1202 static void conf_flush(int fd
, struct ast_channel
*chan
)
1206 /* read any frames that may be waiting on the channel
1210 struct ast_frame
*f
;
1212 /* when no frames are available, this will wait
1213 for 1 millisecond maximum
1215 while (ast_waitfor(chan
, 1)) {
1219 else /* channel was hung up or something else happened */
1224 /* flush any data sitting in the pseudo channel */
1225 x
= DAHDI_FLUSH_ALL
;
1226 if (ioctl(fd
, DAHDI_FLUSH
, &x
))
1227 ast_log(LOG_WARNING
, "Error flushing channel\n");
1231 /* Remove the conference from the list and free it.
1232 We assume that this was called while holding conflock. */
1233 static int conf_free(struct ast_conference
*conf
)
1237 AST_LIST_REMOVE(&confs
, conf
, list
);
1239 if (conf
->recording
== MEETME_RECORD_ACTIVE
) {
1240 conf
->recording
= MEETME_RECORD_TERMINATE
;
1241 AST_LIST_UNLOCK(&confs
);
1244 AST_LIST_LOCK(&confs
);
1245 if (conf
->recording
== MEETME_RECORD_OFF
)
1247 AST_LIST_UNLOCK(&confs
);
1251 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
1252 if (conf
->transframe
[x
])
1253 ast_frfree(conf
->transframe
[x
]);
1254 if (conf
->transpath
[x
])
1255 ast_translator_free_path(conf
->transpath
[x
]);
1257 if (conf
->origframe
)
1258 ast_frfree(conf
->origframe
);
1260 ast_hangup(conf
->lchan
);
1262 ast_hangup(conf
->chan
);
1266 ast_mutex_destroy(&conf
->playlock
);
1267 ast_mutex_destroy(&conf
->listenlock
);
1268 ast_mutex_destroy(&conf
->recordthreadlock
);
1274 static void conf_queue_dtmf(const struct ast_conference
*conf
,
1275 const struct ast_conf_user
*sender
, struct ast_frame
*f
)
1277 struct ast_conf_user
*user
;
1279 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
1282 if (ast_write(user
->chan
, f
) < 0)
1283 ast_log(LOG_WARNING
, "Error writing frame to channel %s\n", user
->chan
->name
);
1287 static void sla_queue_event_full(enum sla_event_type type
,
1288 struct sla_trunk_ref
*trunk_ref
, struct sla_station
*station
, int lock
)
1290 struct sla_event
*event
;
1292 if (!(event
= ast_calloc(1, sizeof(*event
))))
1296 event
->trunk_ref
= trunk_ref
;
1297 event
->station
= station
;
1300 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1304 ast_mutex_lock(&sla
.lock
);
1305 AST_LIST_INSERT_TAIL(&sla
.event_q
, event
, entry
);
1306 ast_cond_signal(&sla
.cond
);
1307 ast_mutex_unlock(&sla
.lock
);
1310 static void sla_queue_event_nolock(enum sla_event_type type
)
1312 sla_queue_event_full(type
, NULL
, NULL
, 0);
1315 static void sla_queue_event(enum sla_event_type type
)
1317 sla_queue_event_full(type
, NULL
, NULL
, 1);
1320 /*! \brief Queue a SLA event from the conference */
1321 static void sla_queue_event_conf(enum sla_event_type type
, struct ast_channel
*chan
,
1322 struct ast_conference
*conf
)
1324 struct sla_station
*station
;
1325 struct sla_trunk_ref
*trunk_ref
= NULL
;
1328 trunk_name
= ast_strdupa(conf
->confno
);
1329 strsep(&trunk_name
, "_");
1330 if (ast_strlen_zero(trunk_name
)) {
1331 ast_log(LOG_ERROR
, "Invalid conference name for SLA - '%s'!\n", conf
->confno
);
1335 AST_RWLIST_RDLOCK(&sla_stations
);
1336 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
1337 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
1338 if (trunk_ref
->chan
== chan
&& !strcmp(trunk_ref
->trunk
->name
, trunk_name
))
1344 AST_RWLIST_UNLOCK(&sla_stations
);
1347 ast_log(LOG_DEBUG
, "Trunk not found for event!\n");
1351 sla_queue_event_full(type
, trunk_ref
, station
, 1);
1354 /* Decrement reference counts, as incremented by find_conf() */
1355 static int dispose_conf(struct ast_conference
*conf
)
1360 AST_LIST_LOCK(&confs
);
1361 if (ast_atomic_dec_and_test(&conf
->refcount
)) {
1362 /* Take the conference room number out of an inuse state */
1363 if ((sscanf(conf
->confno
, "%d", &confno_int
) == 1) && (confno_int
>= 0 && confno_int
< 1024))
1364 conf_map
[confno_int
] = 0;
1368 AST_LIST_UNLOCK(&confs
);
1374 static int conf_run(struct ast_channel
*chan
, struct ast_conference
*conf
, int confflags
, char *optargs
[])
1376 struct ast_conf_user
*user
= NULL
;
1377 struct ast_conf_user
*usr
= NULL
;
1379 struct dahdi_confinfo ztc
, ztc_empty
;
1380 struct ast_frame
*f
;
1381 struct ast_channel
*c
;
1382 struct ast_frame fr
;
1390 int musiconhold
= 0;
1393 int currentmarked
= 0;
1396 int menu_active
= 0;
1397 int using_pseudo
= 0;
1402 struct ast_dsp
*dsp
=NULL
;
1403 struct ast_app
*app
;
1404 const char *agifile
;
1405 const char *agifiledefault
= "conf-background.agi";
1406 char meetmesecs
[30] = "";
1407 char exitcontext
[AST_MAX_CONTEXT
] = "";
1408 char recordingtmp
[AST_MAX_EXTENSION
] = "";
1409 char members
[10] = "";
1410 int dtmf
, opt_waitmarked_timeout
= 0;
1412 struct dahdi_bufferinfo bi
;
1413 char __buf
[CONF_SIZE
+ AST_FRIENDLY_OFFSET
];
1414 char *buf
= __buf
+ AST_FRIENDLY_OFFSET
;
1415 int setusercount
= 0;
1417 if (!(user
= ast_calloc(1, sizeof(*user
))))
1420 /* Possible timeout waiting for marked user */
1421 if ((confflags
& CONFFLAG_WAITMARKED
) &&
1422 !ast_strlen_zero(optargs
[OPT_ARG_WAITMARKED
]) &&
1423 (sscanf(optargs
[OPT_ARG_WAITMARKED
], "%d", &opt_waitmarked_timeout
) == 1) &&
1424 (opt_waitmarked_timeout
> 0)) {
1425 timeout
= time(NULL
) + opt_waitmarked_timeout
;
1428 if (confflags
& CONFFLAG_RECORDCONF
) {
1429 if (!conf
->recordingfilename
) {
1430 conf
->recordingfilename
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFILE");
1431 if (!conf
->recordingfilename
) {
1432 snprintf(recordingtmp
, sizeof(recordingtmp
), "meetme-conf-rec-%s-%s", conf
->confno
, chan
->uniqueid
);
1433 conf
->recordingfilename
= ast_strdupa(recordingtmp
);
1435 conf
->recordingformat
= pbx_builtin_getvar_helper(chan
, "MEETME_RECORDINGFORMAT");
1436 if (!conf
->recordingformat
) {
1437 snprintf(recordingtmp
, sizeof(recordingtmp
), "wav");
1438 conf
->recordingformat
= ast_strdupa(recordingtmp
);
1440 ast_verbose(VERBOSE_PREFIX_4
"Starting recording of MeetMe Conference %s into file %s.%s.\n",
1441 conf
->confno
, conf
->recordingfilename
, conf
->recordingformat
);
1445 ast_mutex_lock(&conf
->recordthreadlock
);
1446 if ((conf
->recordthread
== AST_PTHREADT_NULL
) && (confflags
& CONFFLAG_RECORDCONF
) && ((conf
->lchan
= ast_request(dahdi_chan_name
, AST_FORMAT_SLINEAR
, "pseudo", NULL
)))) {
1447 ast_set_read_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1448 ast_set_write_format(conf
->lchan
, AST_FORMAT_SLINEAR
);
1450 ztc
.confno
= conf
->zapconf
;
1451 ztc
.confmode
= DAHDI_CONF_CONFANN
| DAHDI_CONF_CONFANNMON
;
1452 if (ioctl(conf
->lchan
->fds
[0], DAHDI_SETCONF
, &ztc
)) {
1453 ast_log(LOG_WARNING
, "Error starting listen channel\n");
1454 ast_hangup(conf
->lchan
);
1457 pthread_attr_init(&conf
->attr
);
1458 pthread_attr_setdetachstate(&conf
->attr
, PTHREAD_CREATE_DETACHED
);
1459 ast_pthread_create_background(&conf
->recordthread
, &conf
->attr
, recordthread
, conf
);
1460 pthread_attr_destroy(&conf
->attr
);
1463 ast_mutex_unlock(&conf
->recordthreadlock
);
1465 time(&user
->jointime
);
1467 if (conf
->locked
&& (!(confflags
& CONFFLAG_ADMIN
))) {
1468 /* Sorry, but this confernce is locked! */
1469 if (!ast_streamfile(chan
, "conf-locked", chan
->language
))
1470 ast_waitstream(chan
, "");
1474 ast_mutex_lock(&conf
->playlock
);
1476 if (AST_LIST_EMPTY(&conf
->userlist
))
1479 user
->user_no
= AST_LIST_LAST(&conf
->userlist
)->user_no
+ 1;
1481 AST_LIST_INSERT_TAIL(&conf
->userlist
, user
, list
);
1484 user
->userflags
= confflags
;
1485 user
->adminflags
= (confflags
& CONFFLAG_STARTMUTED
) ? ADMINFLAG_SELFMUTED
: 0;
1488 ast_mutex_unlock(&conf
->playlock
);
1490 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
1491 char destdir
[PATH_MAX
];
1493 snprintf(destdir
, sizeof(destdir
), "%s/meetme", ast_config_AST_SPOOL_DIR
);
1495 if (mkdir(destdir
, 0777) && errno
!= EEXIST
) {
1496 ast_log(LOG_WARNING
, "mkdir '%s' failed: %s\n", destdir
, strerror(errno
));
1500 snprintf(user
->namerecloc
, sizeof(user
->namerecloc
),
1501 "%s/meetme-username-%s-%d", destdir
,
1502 conf
->confno
, user
->user_no
);
1503 if (confflags
& CONFFLAG_INTROUSERNOREVIEW
)
1504 res
= ast_play_and_record(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, 128, 0, NULL
);
1506 res
= ast_record_review(chan
, "vm-rec-name", user
->namerecloc
, 10, "sln", &duration
, NULL
);
1511 ast_mutex_lock(&conf
->playlock
);
1513 if (confflags
& CONFFLAG_MARKEDUSER
)
1514 conf
->markedusers
++;
1517 snprintf(members
, sizeof(members
), "%d", conf
->users
);
1518 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
1521 /* This device changed state now - if this is the first user */
1522 if (conf
->users
== 1)
1523 ast_device_state_changed("meetme:%s", conf
->confno
);
1525 ast_mutex_unlock(&conf
->playlock
);
1527 if (confflags
& CONFFLAG_EXIT_CONTEXT
) {
1528 if ((agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_EXIT_CONTEXT")))
1529 ast_copy_string(exitcontext
, agifile
, sizeof(exitcontext
));
1530 else if (!ast_strlen_zero(chan
->macrocontext
))
1531 ast_copy_string(exitcontext
, chan
->macrocontext
, sizeof(exitcontext
));
1533 ast_copy_string(exitcontext
, chan
->context
, sizeof(exitcontext
));
1536 if ( !(confflags
& (CONFFLAG_QUIET
| CONFFLAG_NOONLYPERSON
)) ) {
1537 if (conf
->users
== 1 && !(confflags
& CONFFLAG_WAITMARKED
))
1538 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1539 ast_waitstream(chan
, "");
1540 if ((confflags
& CONFFLAG_WAITMARKED
) && conf
->markedusers
== 0)
1541 if (!ast_streamfile(chan
, "conf-waitforleader", chan
->language
))
1542 ast_waitstream(chan
, "");
1545 if (!(confflags
& CONFFLAG_QUIET
) && (confflags
& CONFFLAG_ANNOUNCEUSERCOUNT
) && conf
->users
> 1) {
1546 int keepplaying
= 1;
1548 if (conf
->users
== 2) {
1549 if (!ast_streamfile(chan
,"conf-onlyone",chan
->language
)) {
1550 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1551 ast_stopstream(chan
);
1558 if (!ast_streamfile(chan
, "conf-thereare", chan
->language
)) {
1559 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1560 ast_stopstream(chan
);
1567 res
= ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1573 if (keepplaying
&& !ast_streamfile(chan
, "conf-otherinparty", chan
->language
)) {
1574 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1575 ast_stopstream(chan
);
1584 ast_indicate(chan
, -1);
1586 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1587 ast_log(LOG_WARNING
, "Unable to set '%s' to write linear mode\n", chan
->name
);
1591 if (ast_set_read_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
1592 ast_log(LOG_WARNING
, "Unable to set '%s' to read linear mode\n", chan
->name
);
1596 retryzap
= (strcasecmp(chan
->tech
->type
, dahdi_chan_name
) || (chan
->audiohooks
|| chan
->monitor
) ? 1 : 0);
1597 user
->zapchannel
= !retryzap
;
1600 origfd
= chan
->fds
[0];
1603 fd
= open("/dev/zap/pseudo", O_RDWR
);
1605 fd
= open("/dev/dahdi/pseudo", O_RDWR
);
1608 ast_log(LOG_WARNING
, "Unable to open pseudo channel: %s\n", strerror(errno
));
1612 /* Make non-blocking */
1613 flags
= fcntl(fd
, F_GETFL
);
1615 ast_log(LOG_WARNING
, "Unable to get flags: %s\n", strerror(errno
));
1619 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
1620 ast_log(LOG_WARNING
, "Unable to set flags: %s\n", strerror(errno
));
1624 /* Setup buffering information */
1625 memset(&bi
, 0, sizeof(bi
));
1626 bi
.bufsize
= CONF_SIZE
/2;
1627 bi
.txbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
1628 bi
.rxbufpolicy
= DAHDI_POLICY_IMMEDIATE
;
1629 bi
.numbufs
= audio_buffers
;
1630 if (ioctl(fd
, DAHDI_SET_BUFINFO
, &bi
)) {
1631 ast_log(LOG_WARNING
, "Unable to set buffering information: %s\n", strerror(errno
));
1636 if (ioctl(fd
, DAHDI_SETLINEAR
, &x
)) {
1637 ast_log(LOG_WARNING
, "Unable to set linear mode: %s\n", strerror(errno
));
1643 /* XXX Make sure we're not running on a pseudo channel XXX */
1647 memset(&ztc
, 0, sizeof(ztc
));
1648 memset(&ztc_empty
, 0, sizeof(ztc_empty
));
1649 /* Check to see if we're in a conference... */
1651 if (ioctl(fd
, DAHDI_GETCONF
, &ztc
)) {
1652 ast_log(LOG_WARNING
, "Error getting conference\n");
1657 /* Whoa, already in a conference... Retry... */
1659 ast_log(LOG_DEBUG
, "%s channel is in a conference already, retrying with pseudo\n", dahdi_chan_name
);
1664 memset(&ztc
, 0, sizeof(ztc
));
1665 /* Add us to the conference */
1667 ztc
.confno
= conf
->zapconf
;
1669 ast_mutex_lock(&conf
->playlock
);
1671 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
)) && conf
->users
> 1) {
1672 if (conf
->chan
&& ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
1673 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
1674 ast_waitstream(conf
->chan
, "");
1675 if (!ast_streamfile(conf
->chan
, "conf-hasjoin", chan
->language
))
1676 ast_waitstream(conf
->chan
, "");
1680 if (confflags
& CONFFLAG_WAITMARKED
&& !conf
->markedusers
)
1681 ztc
.confmode
= DAHDI_CONF_CONF
;
1682 else if (confflags
& CONFFLAG_MONITOR
)
1683 ztc
.confmode
= DAHDI_CONF_CONFMON
| DAHDI_CONF_LISTENER
;
1684 else if (confflags
& CONFFLAG_TALKER
)
1685 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
;
1687 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
;
1689 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1690 ast_log(LOG_WARNING
, "Error setting conference\n");
1692 ast_mutex_unlock(&conf
->playlock
);
1695 ast_log(LOG_DEBUG
, "Placed channel %s in %s conf %d\n", chan
->name
, dahdi_chan_name
, conf
->zapconf
);
1698 manager_event(EVENT_FLAG_CALL
, "MeetmeJoin",
1703 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1707 if (!firstpass
&& !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
)) {
1709 if (!(confflags
& CONFFLAG_QUIET
))
1710 if (!(confflags
& CONFFLAG_WAITMARKED
) || ((confflags
& CONFFLAG_MARKEDUSER
) && (conf
->markedusers
>= 1)))
1711 conf_play(chan
, conf
, ENTER
);
1714 ast_mutex_unlock(&conf
->playlock
);
1716 conf_flush(fd
, chan
);
1718 if (confflags
& CONFFLAG_AGI
) {
1719 /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
1720 or use default filename of conf-background.agi */
1722 agifile
= pbx_builtin_getvar_helper(chan
, "MEETME_AGI_BACKGROUND");
1724 agifile
= agifiledefault
;
1726 if (user
->zapchannel
) {
1727 /* Set CONFMUTE mode on Zap channel to mute DTMF tones */
1729 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1731 /* Find a pointer to the agi app and execute the script */
1732 app
= pbx_findapp("agi");
1734 char *s
= ast_strdupa(agifile
);
1735 ret
= pbx_exec(chan
, app
, s
);
1737 ast_log(LOG_WARNING
, "Could not find application (agi)\n");
1740 if (user
->zapchannel
) {
1741 /* Remove CONFMUTE mode on Zap channel */
1743 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1746 if (user
->zapchannel
&& (confflags
& CONFFLAG_STARMENU
)) {
1747 /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
1749 ast_channel_setoption(chan
, AST_OPTION_TONE_VERIFY
, &x
, sizeof(char), 0);
1751 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
) && !(dsp
= ast_dsp_new())) {
1752 ast_log(LOG_WARNING
, "Unable to allocate DSP!\n");
1756 int menu_was_active
= 0;
1761 if (timeout
&& time(NULL
) >= timeout
)
1764 /* if we have just exited from the menu, and the user had a channel-driver
1765 volume adjustment, restore it
1767 if (!menu_active
&& menu_was_active
&& user
->listen
.desired
&& !user
->listen
.actual
)
1768 set_talk_volume(user
, user
->listen
.desired
);
1770 menu_was_active
= menu_active
;
1772 currentmarked
= conf
->markedusers
;
1773 if (!(confflags
& CONFFLAG_QUIET
) &&
1774 (confflags
& CONFFLAG_MARKEDUSER
) &&
1775 (confflags
& CONFFLAG_WAITMARKED
) &&
1777 if (currentmarked
== 1 && conf
->users
> 1) {
1778 ast_say_number(chan
, conf
->users
- 1, AST_DIGIT_ANY
, chan
->language
, (char *) NULL
);
1779 if (conf
->users
- 1 == 1) {
1780 if (!ast_streamfile(chan
, "conf-userwilljoin", chan
->language
))
1781 ast_waitstream(chan
, "");
1783 if (!ast_streamfile(chan
, "conf-userswilljoin", chan
->language
))
1784 ast_waitstream(chan
, "");
1787 if (conf
->users
== 1 && ! (confflags
& CONFFLAG_MARKEDUSER
))
1788 if (!ast_streamfile(chan
, "conf-onlyperson", chan
->language
))
1789 ast_waitstream(chan
, "");
1792 c
= ast_waitfor_nandfds(&chan
, 1, &fd
, nfds
, NULL
, &outfd
, &ms
);
1795 /* Update the struct with the actual confflags */
1796 user
->userflags
= confflags
;
1798 if (confflags
& CONFFLAG_WAITMARKED
) {
1799 if(currentmarked
== 0) {
1800 if (lastmarked
!= 0) {
1801 if (!(confflags
& CONFFLAG_QUIET
))
1802 if (!ast_streamfile(chan
, "conf-leaderhasleft", chan
->language
))
1803 ast_waitstream(chan
, "");
1804 if(confflags
& CONFFLAG_MARKEDEXIT
)
1807 ztc
.confmode
= DAHDI_CONF_CONF
;
1808 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1809 ast_log(LOG_WARNING
, "Error setting conference\n");
1815 if (musiconhold
== 0 && (confflags
& CONFFLAG_MOH
)) {
1816 ast_moh_start(chan
, NULL
, NULL
);
1819 } else if(currentmarked
>= 1 && lastmarked
== 0) {
1820 /* Marked user entered, so cancel timeout */
1822 if (confflags
& CONFFLAG_MONITOR
)
1823 ztc
.confmode
= DAHDI_CONF_CONFMON
| DAHDI_CONF_LISTENER
;
1824 else if (confflags
& CONFFLAG_TALKER
)
1825 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
;
1827 ztc
.confmode
= DAHDI_CONF_CONF
| DAHDI_CONF_TALKER
| DAHDI_CONF_LISTENER
;
1828 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1829 ast_log(LOG_WARNING
, "Error setting conference\n");
1833 if (musiconhold
&& (confflags
& CONFFLAG_MOH
)) {
1837 if ( !(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MARKEDUSER
)) {
1838 if (!ast_streamfile(chan
, "conf-placeintoconf", chan
->language
))
1839 ast_waitstream(chan
, "");
1840 conf_play(chan
, conf
, ENTER
);
1845 /* trying to add moh for single person conf */
1846 if ((confflags
& CONFFLAG_MOH
) && !(confflags
& CONFFLAG_WAITMARKED
)) {
1847 if (conf
->users
== 1) {
1848 if (musiconhold
== 0) {
1849 ast_moh_start(chan
, NULL
, NULL
);
1860 /* Leave if the last marked user left */
1861 if (currentmarked
== 0 && lastmarked
!= 0 && (confflags
& CONFFLAG_MARKEDEXIT
)) {
1866 /* Check if my modes have changed */
1868 /* If I should be muted but am still talker, mute me */
1869 if ((user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && (ztc
.confmode
& DAHDI_CONF_TALKER
)) {
1870 ztc
.confmode
^= DAHDI_CONF_TALKER
;
1871 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1872 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1877 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1883 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1886 /* If I should be un-muted but am not talker, un-mute me */
1887 if (!(user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) && !(confflags
& CONFFLAG_MONITOR
) && !(ztc
.confmode
& DAHDI_CONF_TALKER
)) {
1888 ztc
.confmode
|= DAHDI_CONF_TALKER
;
1889 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
1890 ast_log(LOG_WARNING
, "Error setting conference - Un/Mute \n");
1895 manager_event(EVENT_FLAG_CALL
, "MeetmeMute",
1901 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1904 /* If I have been kicked, exit the conference */
1905 if (user
->adminflags
& ADMINFLAG_KICKME
) {
1906 //You have been kicked.
1907 if (!(confflags
& CONFFLAG_QUIET
) &&
1908 !ast_streamfile(chan
, "conf-kicked", chan
->language
)) {
1909 ast_waitstream(chan
, "");
1915 /* Perform an extra hangup check just in case */
1916 if (ast_check_hangup(chan
))
1920 char dtmfstr
[2] = "";
1922 if (c
->fds
[0] != origfd
|| (user
->zapchannel
&& (c
->audiohooks
|| c
->monitor
))) {
1924 /* Kill old pseudo */
1928 ast_log(LOG_DEBUG
, "Ooh, something swapped out under us, starting over\n");
1929 retryzap
= (strcasecmp(c
->tech
->type
, dahdi_chan_name
) || (c
->audiohooks
|| c
->monitor
) ? 1 : 0);
1930 user
->zapchannel
= !retryzap
;
1933 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)))
1934 f
= ast_read_noaudio(c
);
1939 if (f
->frametype
== AST_FRAME_DTMF
) {
1940 dtmfstr
[0] = f
->subclass
;
1944 if ((f
->frametype
== AST_FRAME_VOICE
) && (f
->subclass
== AST_FORMAT_SLINEAR
)) {
1945 if (user
->talk
.actual
)
1946 ast_frame_adjust_volume(f
, user
->talk
.actual
);
1948 if (confflags
& (CONFFLAG_MONITORTALKER
| CONFFLAG_OPTIMIZETALKER
)) {
1951 if (user
->talking
== -1)
1954 res
= ast_dsp_silence(dsp
, f
, &totalsilence
);
1955 if (!user
->talking
&& totalsilence
< MEETME_DELAYDETECTTALK
) {
1957 if (confflags
& CONFFLAG_MONITORTALKER
)
1958 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1964 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1966 if (user
->talking
&& totalsilence
> MEETME_DELAYDETECTENDTALK
) {
1968 if (confflags
& CONFFLAG_MONITORTALKER
)
1969 manager_event(EVENT_FLAG_CALL
, "MeetmeTalking",
1975 chan
->name
, chan
->uniqueid
, conf
->confno
, user
->user_no
);
1979 /* Absolutely do _not_ use careful_write here...
1980 it is important that we read data from the channel
1981 as fast as it arrives, and feed it into the conference.
1982 The buffering in the pseudo channel will take care of any
1983 timing differences, unless they are so drastic as to lose
1984 audio frames (in which case carefully writing would only
1985 have delayed the audio even further).
1987 /* As it turns out, we do want to use careful write. We just
1988 don't want to block, but we do want to at least *try*
1989 to write out all the samples.
1991 if (user
->talking
|| !(confflags
& CONFFLAG_OPTIMIZETALKER
))
1992 careful_write(fd
, f
->data
, f
->datalen
, 0);
1994 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '#') && (confflags
& CONFFLAG_POUNDEXIT
)) {
1995 if (confflags
& CONFFLAG_PASS_DTMF
)
1996 conf_queue_dtmf(conf
, user
, f
);
2000 } else if (((f
->frametype
== AST_FRAME_DTMF
) && (f
->subclass
== '*') && (confflags
& CONFFLAG_STARMENU
)) || ((f
->frametype
== AST_FRAME_DTMF
) && menu_active
)) {
2001 if (confflags
& CONFFLAG_PASS_DTMF
)
2002 conf_queue_dtmf(conf
, user
, f
);
2003 if (ioctl(fd
, DAHDI_SETCONF
, &ztc_empty
)) {
2004 ast_log(LOG_WARNING
, "Error setting conference\n");
2010 /* if we are entering the menu, and the user has a channel-driver
2011 volume adjustment, clear it
2013 if (!menu_active
&& user
->talk
.desired
&& !user
->talk
.actual
)
2014 set_talk_volume(user
, 0);
2019 if ((confflags
& CONFFLAG_ADMIN
)) {
2023 /* Record this sound! */
2024 if (!ast_streamfile(chan
, "conf-adminmenu", chan
->language
)) {
2025 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2026 ast_stopstream(chan
);
2033 case '1': /* Un/Mute */
2036 /* for admin, change both admin and use flags */
2037 if (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))
2038 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2040 user
->adminflags
|= (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2042 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2043 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2044 ast_waitstream(chan
, "");
2046 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2047 ast_waitstream(chan
, "");
2050 case '2': /* Un/Lock the Conference */
2054 if (!ast_streamfile(chan
, "conf-unlockednow", chan
->language
))
2055 ast_waitstream(chan
, "");
2058 if (!ast_streamfile(chan
, "conf-lockednow", chan
->language
))
2059 ast_waitstream(chan
, "");
2062 case '3': /* Eject last user */
2064 usr
= AST_LIST_LAST(&conf
->userlist
);
2065 if ((usr
->chan
->name
== chan
->name
)||(usr
->userflags
& CONFFLAG_ADMIN
)) {
2066 if(!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2067 ast_waitstream(chan
, "");
2069 usr
->adminflags
|= ADMINFLAG_KICKME
;
2070 ast_stopstream(chan
);
2073 tweak_listen_volume(user
, VOL_DOWN
);
2076 tweak_listen_volume(user
, VOL_UP
);
2079 tweak_talk_volume(user
, VOL_DOWN
);
2085 tweak_talk_volume(user
, VOL_UP
);
2089 /* Play an error message! */
2090 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2091 ast_waitstream(chan
, "");
2099 if (!ast_streamfile(chan
, "conf-usermenu", chan
->language
)) {
2100 dtmf
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2101 ast_stopstream(chan
);
2108 case '1': /* Un/Mute */
2111 /* user can only toggle the self-muted state */
2112 user
->adminflags
^= ADMINFLAG_SELFMUTED
;
2114 /* they can't override the admin mute state */
2115 if ((confflags
& CONFFLAG_MONITOR
) || (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
))) {
2116 if (!ast_streamfile(chan
, "conf-muted", chan
->language
))
2117 ast_waitstream(chan
, "");
2119 if (!ast_streamfile(chan
, "conf-unmuted", chan
->language
))
2120 ast_waitstream(chan
, "");
2124 tweak_listen_volume(user
, VOL_DOWN
);
2127 tweak_listen_volume(user
, VOL_UP
);
2130 tweak_talk_volume(user
, VOL_DOWN
);
2136 tweak_talk_volume(user
, VOL_UP
);
2140 if (!ast_streamfile(chan
, "conf-errormenu", chan
->language
))
2141 ast_waitstream(chan
, "");
2147 ast_moh_start(chan
, NULL
, NULL
);
2149 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
2150 ast_log(LOG_WARNING
, "Error setting conference\n");
2156 conf_flush(fd
, chan
);
2157 /* Since this option could absorb dtmf for the previous, we have to check this one last */
2158 } else if ((f
->frametype
== AST_FRAME_DTMF
) && (confflags
& CONFFLAG_EXIT_CONTEXT
) && ast_exists_extension(chan
, exitcontext
, dtmfstr
, 1, "")) {
2159 if (confflags
& CONFFLAG_PASS_DTMF
)
2160 conf_queue_dtmf(conf
, user
, f
);
2162 if (!ast_goto_if_exists(chan
, exitcontext
, dtmfstr
, 1)) {
2163 ast_log(LOG_DEBUG
, "Got DTMF %c, goto context %s\n", dtmfstr
[0], exitcontext
);
2167 } else if (option_debug
> 1)
2168 ast_log(LOG_DEBUG
, "Exit by single digit did not work in meetme. Extension '%s' does not exist in context '%s'\n", dtmfstr
, exitcontext
);
2169 } else if ((f
->frametype
== AST_FRAME_DTMF_BEGIN
|| f
->frametype
== AST_FRAME_DTMF_END
)
2170 && confflags
& CONFFLAG_PASS_DTMF
) {
2171 conf_queue_dtmf(conf
, user
, f
);
2172 } else if ((confflags
& CONFFLAG_SLA_STATION
) && f
->frametype
== AST_FRAME_CONTROL
) {
2173 switch (f
->subclass
) {
2174 case AST_CONTROL_HOLD
:
2175 sla_queue_event_conf(SLA_EVENT_HOLD
, chan
, conf
);
2180 } else if (f
->frametype
== AST_FRAME_NULL
) {
2181 /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
2182 } else if (option_debug
) {
2184 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
2185 chan
->name
, f
->frametype
, f
->subclass
);
2188 } else if (outfd
> -1) {
2189 res
= read(outfd
, buf
, CONF_SIZE
);
2191 memset(&fr
, 0, sizeof(fr
));
2192 fr
.frametype
= AST_FRAME_VOICE
;
2193 fr
.subclass
= AST_FORMAT_SLINEAR
;
2197 fr
.offset
= AST_FRIENDLY_OFFSET
;
2198 if (!user
->listen
.actual
&&
2199 ((confflags
& CONFFLAG_MONITOR
) ||
2200 (user
->adminflags
& (ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
)) ||
2201 (!user
->talking
&& (confflags
& CONFFLAG_OPTIMIZETALKER
))
2204 for (index
=0;index
<AST_FRAME_BITS
;index
++)
2205 if (chan
->rawwriteformat
& (1 << index
))
2207 if (index
>= AST_FRAME_BITS
)
2208 goto bailoutandtrynormal
;
2209 ast_mutex_lock(&conf
->listenlock
);
2210 if (!conf
->transframe
[index
]) {
2211 if (conf
->origframe
) {
2212 if (!conf
->transpath
[index
])
2213 conf
->transpath
[index
] = ast_translator_build_path((1 << index
), AST_FORMAT_SLINEAR
);
2214 if (conf
->transpath
[index
]) {
2215 conf
->transframe
[index
] = ast_translate(conf
->transpath
[index
], conf
->origframe
, 0);
2216 if (!conf
->transframe
[index
])
2217 conf
->transframe
[index
] = &ast_null_frame
;
2221 if (conf
->transframe
[index
]) {
2222 if (conf
->transframe
[index
]->frametype
!= AST_FRAME_NULL
) {
2223 if (ast_write(chan
, conf
->transframe
[index
]))
2224 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2227 ast_mutex_unlock(&conf
->listenlock
);
2228 goto bailoutandtrynormal
;
2230 ast_mutex_unlock(&conf
->listenlock
);
2232 bailoutandtrynormal
:
2233 if (user
->listen
.actual
)
2234 ast_frame_adjust_volume(&fr
, user
->listen
.actual
);
2235 if (ast_write(chan
, &fr
) < 0) {
2236 ast_log(LOG_WARNING
, "Unable to write frame to channel %s\n", chan
->name
);
2240 ast_log(LOG_WARNING
, "Failed to read frame: %s\n", strerror(errno
));
2242 lastmarked
= currentmarked
;
2252 /* Take out of conference */
2256 if (ioctl(fd
, DAHDI_SETCONF
, &ztc
)) {
2257 ast_log(LOG_WARNING
, "Error setting conference\n");
2261 reset_volumes(user
);
2263 AST_LIST_LOCK(&confs
);
2264 if (!(confflags
& CONFFLAG_QUIET
) && !(confflags
& CONFFLAG_MONITOR
) && !(confflags
& CONFFLAG_ADMIN
))
2265 conf_play(chan
, conf
, LEAVE
);
2267 if (!(confflags
& CONFFLAG_QUIET
) && ((confflags
& CONFFLAG_INTROUSER
) || (confflags
& CONFFLAG_INTROUSERNOREVIEW
))) {
2268 if (ast_fileexists(user
->namerecloc
, NULL
, NULL
)) {
2269 if ((conf
->chan
) && (conf
->users
> 1)) {
2270 if (!ast_streamfile(conf
->chan
, user
->namerecloc
, chan
->language
))
2271 ast_waitstream(conf
->chan
, "");
2272 if (!ast_streamfile(conf
->chan
, "conf-hasleft", chan
->language
))
2273 ast_waitstream(conf
->chan
, "");
2275 ast_filedelete(user
->namerecloc
, NULL
);
2278 AST_LIST_UNLOCK(&confs
);
2281 AST_LIST_LOCK(&confs
);
2286 if (user
->user_no
) { /* Only cleanup users who really joined! */
2288 hr
= (now
- user
->jointime
) / 3600;
2289 min
= ((now
- user
->jointime
) % 3600) / 60;
2290 sec
= (now
- user
->jointime
) % 60;
2293 manager_event(EVENT_FLAG_CALL
, "MeetmeLeave",
2298 "CallerIDnum: %s\r\n"
2299 "CallerIDname: %s\r\n"
2300 "Duration: %ld\r\n",
2301 chan
->name
, chan
->uniqueid
, conf
->confno
,
2303 S_OR(user
->chan
->cid
.cid_num
, "<unknown>"),
2304 S_OR(user
->chan
->cid
.cid_name
, "<unknown>"),
2305 (long)(now
- user
->jointime
));
2311 snprintf(members
, sizeof(members
), "%d", conf
->users
);
2312 ast_update_realtime("meetme", "confno", conf
->confno
, "members", members
, NULL
);
2313 if (confflags
& CONFFLAG_MARKEDUSER
)
2314 conf
->markedusers
--;
2316 /* Remove ourselves from the list */
2317 AST_LIST_REMOVE(&conf
->userlist
, user
, list
);
2319 /* Change any states */
2321 ast_device_state_changed("meetme:%s", conf
->confno
);
2323 /* Return the number of seconds the user was in the conf */
2324 snprintf(meetmesecs
, sizeof(meetmesecs
), "%d", (int) (time(NULL
) - user
->jointime
));
2325 pbx_builtin_setvar_helper(chan
, "MEETMESECS", meetmesecs
);
2328 AST_LIST_UNLOCK(&confs
);
2333 static struct ast_conference
*find_conf_realtime(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2334 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2336 struct ast_variable
*var
;
2337 struct ast_conference
*cnf
;
2339 /* Check first in the conference list */
2340 AST_LIST_LOCK(&confs
);
2341 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2342 if (!strcmp(confno
, cnf
->confno
))
2346 cnf
->refcount
+= refcount
;
2348 AST_LIST_UNLOCK(&confs
);
2351 char *pin
= NULL
, *pinadmin
= NULL
; /* For temp use */
2353 var
= ast_load_realtime("meetme", "confno", confno
, NULL
);
2359 if (!strcasecmp(var
->name
, "pin")) {
2360 pin
= ast_strdupa(var
->value
);
2361 } else if (!strcasecmp(var
->name
, "adminpin")) {
2362 pinadmin
= ast_strdupa(var
->value
);
2366 ast_variables_destroy(var
);
2368 cnf
= build_conf(confno
, pin
? pin
: "", pinadmin
? pinadmin
: "", make
, dynamic
, refcount
);
2372 if (confflags
&& !cnf
->chan
&&
2373 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2374 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2375 ast_log(LOG_WARNING
, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name
);
2376 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2379 if (confflags
&& !cnf
->chan
&&
2380 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2381 ast_log(LOG_WARNING
, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name
);
2382 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2390 static struct ast_conference
*find_conf(struct ast_channel
*chan
, char *confno
, int make
, int dynamic
,
2391 char *dynamic_pin
, size_t pin_buf_len
, int refcount
, struct ast_flags
*confflags
)
2393 struct ast_config
*cfg
;
2394 struct ast_variable
*var
;
2395 struct ast_conference
*cnf
;
2397 AST_DECLARE_APP_ARGS(args
,
2398 AST_APP_ARG(confno
);
2400 AST_APP_ARG(pinadmin
);
2403 /* Check first in the conference list */
2404 AST_LIST_LOCK(&confs
);
2405 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2406 if (!strcmp(confno
, cnf
->confno
))
2410 cnf
->refcount
+= refcount
;
2412 AST_LIST_UNLOCK(&confs
);
2416 /* No need to parse meetme.conf */
2417 ast_log(LOG_DEBUG
, "Building dynamic conference '%s'\n", confno
);
2419 if (dynamic_pin
[0] == 'q') {
2420 /* Query the user to enter a PIN */
2421 if (ast_app_getdata(chan
, "conf-getpin", dynamic_pin
, pin_buf_len
- 1, 0) < 0)
2424 cnf
= build_conf(confno
, dynamic_pin
, "", make
, dynamic
, refcount
);
2426 cnf
= build_conf(confno
, "", "", make
, dynamic
, refcount
);
2429 /* Check the config */
2430 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2432 ast_log(LOG_WARNING
, "No %s file :(\n", CONFIG_FILE_NAME
);
2435 for (var
= ast_variable_browse(cfg
, "rooms"); var
; var
= var
->next
) {
2436 if (strcasecmp(var
->name
, "conf"))
2439 if (!(parse
= ast_strdupa(var
->value
)))
2442 AST_NONSTANDARD_APP_ARGS(args
, parse
, ',');
2443 if (!strcasecmp(args
.confno
, confno
)) {
2444 /* Bingo it's a valid conference */
2445 cnf
= build_conf(args
.confno
,
2447 S_OR(args
.pinadmin
, ""),
2448 make
, dynamic
, refcount
);
2453 ast_log(LOG_DEBUG
, "%s isn't a valid conference\n", confno
);
2455 ast_config_destroy(cfg
);
2457 } else if (dynamic_pin
) {
2458 /* Correct for the user selecting 'D' instead of 'd' to have
2459 someone join into a conference that has already been created
2461 if (dynamic_pin
[0] == 'q')
2462 dynamic_pin
[0] = '\0';
2466 if (confflags
&& !cnf
->chan
&&
2467 !ast_test_flag(confflags
, CONFFLAG_QUIET
) &&
2468 ast_test_flag(confflags
, CONFFLAG_INTROUSER
)) {
2469 ast_log(LOG_WARNING
, "No %s channel available for conference, user introduction disabled\n", dahdi_chan_name
);
2470 ast_clear_flag(confflags
, CONFFLAG_INTROUSER
);
2473 if (confflags
&& !cnf
->chan
&&
2474 ast_test_flag(confflags
, CONFFLAG_RECORDCONF
)) {
2475 ast_log(LOG_WARNING
, "No %s channel available for conference, conference recording disabled\n", dahdi_chan_name
);
2476 ast_clear_flag(confflags
, CONFFLAG_RECORDCONF
);
2483 /*! \brief The MeetmeCount application */
2484 static int count_exec(struct ast_channel
*chan
, void *data
)
2486 struct ast_module_user
*u
;
2488 struct ast_conference
*conf
;
2492 AST_DECLARE_APP_ARGS(args
,
2493 AST_APP_ARG(confno
);
2494 AST_APP_ARG(varname
);
2497 if (ast_strlen_zero(data
)) {
2498 ast_log(LOG_WARNING
, "MeetMeCount requires an argument (conference number)\n");
2502 u
= ast_module_user_add(chan
);
2504 if (!(localdata
= ast_strdupa(data
))) {
2505 ast_module_user_remove(u
);
2509 AST_STANDARD_APP_ARGS(args
, localdata
);
2511 conf
= find_conf(chan
, args
.confno
, 0, 0, NULL
, 0, 1, NULL
);
2514 count
= conf
->users
;
2520 if (!ast_strlen_zero(args
.varname
)){
2521 /* have var so load it and exit */
2522 snprintf(val
, sizeof(val
), "%d",count
);
2523 pbx_builtin_setvar_helper(chan
, args
.varname
, val
);
2525 if (chan
->_state
!= AST_STATE_UP
)
2527 res
= ast_say_number(chan
, count
, "", chan
->language
, (char *) NULL
); /* Needs gender */
2529 ast_module_user_remove(u
);
2534 /*! \brief The meetme() application */
2535 static int conf_exec(struct ast_channel
*chan
, void *data
)
2538 struct ast_module_user
*u
;
2539 char confno
[MAX_CONFNUM
] = "";
2542 struct ast_conference
*cnf
= NULL
;
2543 struct ast_flags confflags
= {0};
2545 int empty
= 0, empty_no_pin
= 0;
2546 int always_prompt
= 0;
2547 char *notdata
, *info
, the_pin
[MAX_PIN
] = "";
2548 AST_DECLARE_APP_ARGS(args
,
2549 AST_APP_ARG(confno
);
2550 AST_APP_ARG(options
);
2553 char *optargs
[OPT_ARG_ARRAY_SIZE
] = { NULL
, };
2555 u
= ast_module_user_add(chan
);
2557 if (ast_strlen_zero(data
)) {
2564 if (chan
->_state
!= AST_STATE_UP
)
2567 info
= ast_strdupa(notdata
);
2569 AST_STANDARD_APP_ARGS(args
, info
);
2572 ast_copy_string(confno
, args
.confno
, sizeof(confno
));
2573 if (ast_strlen_zero(confno
)) {
2579 ast_copy_string(the_pin
, args
.pin
, sizeof(the_pin
));
2582 ast_app_parse_options(meetme_opts
, &confflags
, optargs
, args
.options
);
2583 dynamic
= ast_test_flag(&confflags
, CONFFLAG_DYNAMIC
| CONFFLAG_DYNAMICPIN
);
2584 if (ast_test_flag(&confflags
, CONFFLAG_DYNAMICPIN
) && !args
.pin
)
2585 strcpy(the_pin
, "q");
2587 empty
= ast_test_flag(&confflags
, CONFFLAG_EMPTY
| CONFFLAG_EMPTYNOPIN
);
2588 empty_no_pin
= ast_test_flag(&confflags
, CONFFLAG_EMPTYNOPIN
);
2589 always_prompt
= ast_test_flag(&confflags
, CONFFLAG_ALWAYSPROMPT
);
2597 struct ast_config
*cfg
;
2598 struct ast_variable
*var
;
2601 /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
2602 if ((empty_no_pin
) || (!dynamic
)) {
2603 cfg
= ast_config_load(CONFIG_FILE_NAME
);
2605 var
= ast_variable_browse(cfg
, "rooms");
2607 if (!strcasecmp(var
->name
, "conf")) {
2608 char *stringp
= ast_strdupa(var
->value
);
2610 char *confno_tmp
= strsep(&stringp
, "|,");
2613 /* For static: run through the list and see if this conference is empty */
2614 AST_LIST_LOCK(&confs
);
2615 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2616 if (!strcmp(confno_tmp
, cnf
->confno
)) {
2617 /* The conference exists, therefore it's not empty */
2622 AST_LIST_UNLOCK(&confs
);
2624 /* At this point, we have a confno_tmp (static conference) that is empty */
2625 if ((empty_no_pin
&& ast_strlen_zero(stringp
)) || (!empty_no_pin
)) {
2626 /* Case 1: empty_no_pin and pin is nonexistent (NULL)
2627 * Case 2: empty_no_pin and pin is blank (but not NULL)
2628 * Case 3: not empty_no_pin
2630 ast_copy_string(confno
, confno_tmp
, sizeof(confno
));
2632 /* XXX the map is not complete (but we do have a confno) */
2640 ast_config_destroy(cfg
);
2644 /* Select first conference number not in use */
2645 if (ast_strlen_zero(confno
) && dynamic
) {
2646 AST_LIST_LOCK(&confs
);
2647 for (i
= 0; i
< sizeof(conf_map
) / sizeof(conf_map
[0]); i
++) {
2649 snprintf(confno
, sizeof(confno
), "%d", i
);
2654 AST_LIST_UNLOCK(&confs
);
2658 if (ast_strlen_zero(confno
)) {
2659 res
= ast_streamfile(chan
, "conf-noempty", chan
->language
);
2661 ast_waitstream(chan
, "");
2663 if (sscanf(confno
, "%d", &confno_int
) == 1) {
2664 res
= ast_streamfile(chan
, "conf-enteringno", chan
->language
);
2666 ast_waitstream(chan
, "");
2667 res
= ast_say_digits(chan
, confno_int
, "", chan
->language
);
2670 ast_log(LOG_ERROR
, "Could not scan confno '%s'\n", confno
);
2675 while (allowretry
&& (ast_strlen_zero(confno
)) && (++retrycnt
< 4)) {
2676 /* Prompt user for conference number */
2677 res
= ast_app_getdata(chan
, "conf-getconfno", confno
, sizeof(confno
) - 1, 0);
2679 /* Don't try to validate when we catch an error */
2685 if (!ast_strlen_zero(confno
)) {
2686 /* Check the validity of the conference */
2687 cnf
= find_conf(chan
, confno
, 1, dynamic
, the_pin
,
2688 sizeof(the_pin
), 1, &confflags
);
2690 cnf
= find_conf_realtime(chan
, confno
, 1, dynamic
,
2691 the_pin
, sizeof(the_pin
), 1, &confflags
);
2695 res
= ast_streamfile(chan
, "conf-invalid", chan
->language
);
2697 ast_waitstream(chan
, "");
2702 if ((!ast_strlen_zero(cnf
->pin
) &&
2703 !ast_test_flag(&confflags
, CONFFLAG_ADMIN
)) ||
2704 (!ast_strlen_zero(cnf
->pinadmin
) &&
2705 ast_test_flag(&confflags
, CONFFLAG_ADMIN
))) {
2706 char pin
[MAX_PIN
] = "";
2709 /* Allow the pin to be retried up to 3 times */
2710 for (j
= 0; j
< 3; j
++) {
2711 if (*the_pin
&& (always_prompt
== 0)) {
2712 ast_copy_string(pin
, the_pin
, sizeof(pin
));
2715 /* Prompt user for pin if pin is required */
2716 res
= ast_app_getdata(chan
, "conf-getpin", pin
+ strlen(pin
), sizeof(pin
) - 1 - strlen(pin
), 0);
2719 if (!strcasecmp(pin
, cnf
->pin
) ||
2720 (!ast_strlen_zero(cnf
->pinadmin
) &&
2721 !strcasecmp(pin
, cnf
->pinadmin
))) {
2724 if (!ast_strlen_zero(cnf
->pinadmin
) && !strcasecmp(pin
, cnf
->pinadmin
))
2725 ast_set_flag(&confflags
, CONFFLAG_ADMIN
);
2726 /* Run the conference */
2727 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2731 if (!ast_streamfile(chan
, "conf-invalidpin", chan
->language
)) {
2732 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
2733 ast_stopstream(chan
);
2736 ast_log(LOG_WARNING
, "Couldn't play invalid pin msg!\n");
2748 /* failed when getting the pin */
2751 /* see if we need to get rid of the conference */
2755 /* Don't retry pin with a static pin */
2756 if (*the_pin
&& (always_prompt
==0)) {
2761 /* No pin required */
2764 /* Run the conference */
2765 res
= conf_run(chan
, cnf
, confflags
.flags
, optargs
);
2771 } while (allowretry
);
2776 ast_module_user_remove(u
);
2781 static struct ast_conf_user
*find_user(struct ast_conference
*conf
, char *callerident
)
2783 struct ast_conf_user
*user
= NULL
;
2786 sscanf(callerident
, "%i", &cid
);
2787 if (conf
&& callerident
) {
2788 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
) {
2789 if (cid
== user
->user_no
)
2796 /*! \brief The MeetMeadmin application */
2797 /* MeetMeAdmin(confno, command, caller) */
2798 static int admin_exec(struct ast_channel
*chan
, void *data
) {
2800 struct ast_conference
*cnf
;
2801 struct ast_conf_user
*user
= NULL
;
2802 struct ast_module_user
*u
;
2803 AST_DECLARE_APP_ARGS(args
,
2804 AST_APP_ARG(confno
);
2805 AST_APP_ARG(command
);
2809 if (ast_strlen_zero(data
)) {
2810 ast_log(LOG_WARNING
, "MeetMeAdmin requires an argument!\n");
2814 u
= ast_module_user_add(chan
);
2816 AST_LIST_LOCK(&confs
);
2818 params
= ast_strdupa(data
);
2819 AST_STANDARD_APP_ARGS(args
, params
);
2821 if (!args
.command
) {
2822 ast_log(LOG_WARNING
, "MeetmeAdmin requires a command!\n");
2823 AST_LIST_UNLOCK(&confs
);
2824 ast_module_user_remove(u
);
2827 AST_LIST_TRAVERSE(&confs
, cnf
, list
) {
2828 if (!strcmp(cnf
->confno
, args
.confno
))
2833 ast_log(LOG_WARNING
, "Conference number '%s' not found!\n", args
.confno
);
2834 AST_LIST_UNLOCK(&confs
);
2835 ast_module_user_remove(u
);
2839 ast_atomic_fetchadd_int(&cnf
->refcount
, 1);
2842 user
= find_user(cnf
, args
.user
);
2844 switch (*args
.command
) {
2845 case 76: /* L: Lock */
2848 case 108: /* l: Unlock */
2851 case 75: /* K: kick all users */
2852 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2853 user
->adminflags
|= ADMINFLAG_KICKME
;
2855 case 101: /* e: Eject last user*/
2856 user
= AST_LIST_LAST(&cnf
->userlist
);
2857 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2858 user
->adminflags
|= ADMINFLAG_KICKME
;
2860 ast_log(LOG_NOTICE
, "Not kicking last user, is an Admin!\n");
2862 case 77: /* M: Mute */
2864 user
->adminflags
|= ADMINFLAG_MUTED
;
2866 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2868 case 78: /* N: Mute all (non-admin) users */
2869 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
) {
2870 if (!(user
->userflags
& CONFFLAG_ADMIN
))
2871 user
->adminflags
|= ADMINFLAG_MUTED
;
2874 case 109: /* m: Unmute */
2876 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2878 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2880 case 110: /* n: Unmute all users */
2881 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2882 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
);
2884 case 107: /* k: Kick user */
2886 user
->adminflags
|= ADMINFLAG_KICKME
;
2888 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2890 case 118: /* v: Lower all users listen volume */
2891 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2892 tweak_listen_volume(user
, VOL_DOWN
);
2894 case 86: /* V: Raise all users listen volume */
2895 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2896 tweak_listen_volume(user
, VOL_UP
);
2898 case 115: /* s: Lower all users speaking volume */
2899 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2900 tweak_talk_volume(user
, VOL_DOWN
);
2902 case 83: /* S: Raise all users speaking volume */
2903 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2904 tweak_talk_volume(user
, VOL_UP
);
2906 case 82: /* R: Reset all volume levels */
2907 AST_LIST_TRAVERSE(&cnf
->userlist
, user
, list
)
2908 reset_volumes(user
);
2910 case 114: /* r: Reset user's volume level */
2912 reset_volumes(user
);
2914 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2916 case 85: /* U: Raise user's listen volume */
2918 tweak_listen_volume(user
, VOL_UP
);
2920 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2922 case 117: /* u: Lower user's listen volume */
2924 tweak_listen_volume(user
, VOL_DOWN
);
2926 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2928 case 84: /* T: Raise user's talk volume */
2930 tweak_talk_volume(user
, VOL_UP
);
2932 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2934 case 116: /* t: Lower user's talk volume */
2936 tweak_talk_volume(user
, VOL_DOWN
);
2938 ast_log(LOG_NOTICE
, "Specified User not found!\n");
2942 AST_LIST_UNLOCK(&confs
);
2946 ast_module_user_remove(u
);
2951 static int meetmemute(struct mansession
*s
, const struct message
*m
, int mute
)
2953 struct ast_conference
*conf
;
2954 struct ast_conf_user
*user
;
2955 const char *confid
= astman_get_header(m
, "Meetme");
2956 char *userid
= ast_strdupa(astman_get_header(m
, "Usernum"));
2959 if (ast_strlen_zero(confid
)) {
2960 astman_send_error(s
, m
, "Meetme conference not specified");
2964 if (ast_strlen_zero(userid
)) {
2965 astman_send_error(s
, m
, "Meetme user number not specified");
2969 userno
= strtoul(userid
, &userid
, 10);
2972 astman_send_error(s
, m
, "Invalid user number");
2976 /* Look in the conference list */
2977 AST_LIST_LOCK(&confs
);
2978 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
2979 if (!strcmp(confid
, conf
->confno
))
2984 AST_LIST_UNLOCK(&confs
);
2985 astman_send_error(s
, m
, "Meetme conference does not exist");
2989 AST_LIST_TRAVERSE(&conf
->userlist
, user
, list
)
2990 if (user
->user_no
== userno
)
2994 AST_LIST_UNLOCK(&confs
);
2995 astman_send_error(s
, m
, "User number not found");
3000 user
->adminflags
|= ADMINFLAG_MUTED
; /* request user muting */
3002 user
->adminflags
&= ~(ADMINFLAG_MUTED
| ADMINFLAG_SELFMUTED
); /* request user unmuting */
3004 AST_LIST_UNLOCK(&confs
);
3006 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
);
3008 astman_send_ack(s
, m
, mute
? "User muted" : "User unmuted");
3012 static int action_meetmemute(struct mansession
*s
, const struct message
*m
)
3014 return meetmemute(s
, m
, 1);
3017 static int action_meetmeunmute(struct mansession
*s
, const struct message
*m
)
3019 return meetmemute(s
, m
, 0);
3022 static void *recordthread(void *args
)
3024 struct ast_conference
*cnf
= args
;
3025 struct ast_frame
*f
=NULL
;
3027 struct ast_filestream
*s
=NULL
;
3030 const char *oldrecordingfilename
= NULL
;
3032 if (!cnf
|| !cnf
->lchan
) {
3036 ast_stopstream(cnf
->lchan
);
3037 flags
= O_CREAT
|O_TRUNC
|O_WRONLY
;
3040 cnf
->recording
= MEETME_RECORD_ACTIVE
;
3041 while (ast_waitfor(cnf
->lchan
, -1) > -1) {
3042 if (cnf
->recording
== MEETME_RECORD_TERMINATE
) {
3043 AST_LIST_LOCK(&confs
);
3044 AST_LIST_UNLOCK(&confs
);
3047 if (!s
&& cnf
->recordingfilename
&& (cnf
->recordingfilename
!= oldrecordingfilename
)) {
3048 s
= ast_writefile(cnf
->recordingfilename
, cnf
->recordingformat
, NULL
, flags
, 0, 0644);
3049 oldrecordingfilename
= cnf
->recordingfilename
;
3052 f
= ast_read(cnf
->lchan
);
3057 if (f
->frametype
== AST_FRAME_VOICE
) {
3058 ast_mutex_lock(&cnf
->listenlock
);
3059 for (x
=0;x
<AST_FRAME_BITS
;x
++) {
3060 /* Free any translations that have occured */
3061 if (cnf
->transframe
[x
]) {
3062 ast_frfree(cnf
->transframe
[x
]);
3063 cnf
->transframe
[x
] = NULL
;
3067 ast_frfree(cnf
->origframe
);
3068 cnf
->origframe
= ast_frdup(f
);
3069 ast_mutex_unlock(&cnf
->listenlock
);
3071 res
= ast_writestream(s
, f
);
3079 cnf
->recording
= MEETME_RECORD_OFF
;
3086 /*! \brief Callback for devicestate providers */
3087 static int meetmestate(const char *data
)
3089 struct ast_conference
*conf
;
3091 /* Find conference */
3092 AST_LIST_LOCK(&confs
);
3093 AST_LIST_TRAVERSE(&confs
, conf
, list
) {
3094 if (!strcmp(data
, conf
->confno
))
3097 AST_LIST_UNLOCK(&confs
);
3099 return AST_DEVICE_INVALID
;
3104 return AST_DEVICE_NOT_INUSE
;
3106 return AST_DEVICE_INUSE
;
3109 static void load_config_meetme(void)
3111 struct ast_config
*cfg
;
3114 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3116 if (!(cfg
= ast_config_load(CONFIG_FILE_NAME
)))
3119 if ((val
= ast_variable_retrieve(cfg
, "general", "audiobuffers"))) {
3120 if ((sscanf(val
, "%d", &audio_buffers
) != 1)) {
3121 ast_log(LOG_WARNING
, "audiobuffers setting must be a number, not '%s'\n", val
);
3122 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3123 } else if ((audio_buffers
< DAHDI_DEFAULT_NUM_BUFS
) || (audio_buffers
> DAHDI_MAX_NUM_BUFS
)) {
3124 ast_log(LOG_WARNING
, "audiobuffers setting must be between %d and %d\n",
3125 DAHDI_DEFAULT_NUM_BUFS
, DAHDI_MAX_NUM_BUFS
);
3126 audio_buffers
= DEFAULT_AUDIO_BUFFERS
;
3128 if (audio_buffers
!= DEFAULT_AUDIO_BUFFERS
)
3129 ast_log(LOG_NOTICE
, "Audio buffers per channel set to %d\n", audio_buffers
);
3132 ast_config_destroy(cfg
);
3135 /*! \brief Find an SLA trunk by name
3136 * \note This must be called with the sla_trunks container locked
3138 static struct sla_trunk
*sla_find_trunk(const char *name
)
3140 struct sla_trunk
*trunk
= NULL
;
3142 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
3143 if (!strcasecmp(trunk
->name
, name
))
3150 /*! \brief Find an SLA station by name
3151 * \note This must be called with the sla_stations container locked
3153 static struct sla_station
*sla_find_station(const char *name
)
3155 struct sla_station
*station
= NULL
;
3157 AST_RWLIST_TRAVERSE(&sla_stations
, station
, entry
) {
3158 if (!strcasecmp(station
->name
, name
))
3165 static int sla_check_station_hold_access(const struct sla_trunk
*trunk
,
3166 const struct sla_station
*station
)
3168 struct sla_station_ref
*station_ref
;
3169 struct sla_trunk_ref
*trunk_ref
;
3171 /* For each station that has this call on hold, check for private hold. */
3172 AST_LIST_TRAVERSE(&trunk
->stations
, station_ref
, entry
) {
3173 AST_LIST_TRAVERSE(&station_ref
->station
->trunks
, trunk_ref
, entry
) {
3174 if (trunk_ref
->trunk
!= trunk
|| station_ref
->station
== station
)
3176 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
&&
3177 station_ref
->station
->hold_access
== SLA_HOLD_PRIVATE
)
3186 /*! \brief Find a trunk reference on a station by name
3187 * \param station the station
3188 * \param name the trunk's name
3189 * \return a pointer to the station's trunk reference. If the trunk
3190 * is not found, it is not idle and barge is disabled, or if
3191 * it is on hold and private hold is set, then NULL will be returned.
3193 static struct sla_trunk_ref
*sla_find_trunk_ref_byname(const struct sla_station
*station
,
3196 struct sla_trunk_ref
*trunk_ref
= NULL
;
3198 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3199 if (strcasecmp(trunk_ref
->trunk
->name
, name
))
3202 if ( (trunk_ref
->trunk
->barge_disabled
3203 && trunk_ref
->state
== SLA_TRUNK_STATE_UP
) ||
3204 (trunk_ref
->trunk
->hold_stations
3205 && trunk_ref
->trunk
->hold_access
== SLA_HOLD_PRIVATE
3206 && trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) ||
3207 sla_check_station_hold_access(trunk_ref
->trunk
, station
) )
3218 static struct sla_station_ref
*sla_create_station_ref(struct sla_station
*station
)
3220 struct sla_station_ref
*station_ref
;
3222 if (!(station_ref
= ast_calloc(1, sizeof(*station_ref
))))
3225 station_ref
->station
= station
;
3230 static struct sla_ringing_station
*sla_create_ringing_station(struct sla_station
*station
)
3232 struct sla_ringing_station
*ringing_station
;
3234 if (!(ringing_station
= ast_calloc(1, sizeof(*ringing_station
))))
3237 ringing_station
->station
= station
;
3238 ringing_station
->ring_begin
= ast_tvnow();
3240 return ringing_station
;
3243 static void sla_change_trunk_state(const struct sla_trunk
*trunk
, enum sla_trunk_state state
,
3244 enum sla_which_trunk_refs inactive_only
, const struct sla_trunk_ref
*exclude
)
3246 struct sla_station
*station
;
3247 struct sla_trunk_ref
*trunk_ref
;
3249 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3250 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3251 if (trunk_ref
->trunk
!= trunk
|| (inactive_only
? trunk_ref
->chan
: 0)
3252 || trunk_ref
== exclude
)
3254 trunk_ref
->state
= state
;
3255 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk
->name
);
3261 struct run_station_args
{
3262 struct sla_station
*station
;
3263 struct sla_trunk_ref
*trunk_ref
;
3264 ast_mutex_t
*cond_lock
;
3268 static void *run_station(void *data
)
3270 struct sla_station
*station
;
3271 struct sla_trunk_ref
*trunk_ref
;
3272 char conf_name
[MAX_CONFNUM
];
3273 struct ast_flags conf_flags
= { 0 };
3274 struct ast_conference
*conf
;
3277 struct run_station_args
*args
= data
;
3278 station
= args
->station
;
3279 trunk_ref
= args
->trunk_ref
;
3280 ast_mutex_lock(args
->cond_lock
);
3281 ast_cond_signal(args
->cond
);
3282 ast_mutex_unlock(args
->cond_lock
);
3283 /* args is no longer valid here. */
3286 ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1);
3287 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
3288 ast_set_flag(&conf_flags
,
3289 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
3290 ast_answer(trunk_ref
->chan
);
3291 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
3293 conf_run(trunk_ref
->chan
, conf
, conf_flags
.flags
, NULL
);
3297 trunk_ref
->chan
= NULL
;
3298 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
3299 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
3300 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
3301 admin_exec(NULL
, conf_name
);
3302 trunk_ref
->trunk
->hold_stations
= 0;
3303 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3306 ast_dial_join(station
->dial
);
3307 ast_dial_destroy(station
->dial
);
3308 station
->dial
= NULL
;
3313 static void sla_stop_ringing_trunk(struct sla_ringing_trunk
*ringing_trunk
)
3316 struct sla_station_ref
*station_ref
;
3318 snprintf(buf
, sizeof(buf
), "SLA_%s|K", ringing_trunk
->trunk
->name
);
3319 admin_exec(NULL
, buf
);
3320 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
3322 while ((station_ref
= AST_LIST_REMOVE_HEAD(&ringing_trunk
->timed_out_stations
, entry
)))
3325 free(ringing_trunk
);
3328 static void sla_stop_ringing_station(struct sla_ringing_station
*ringing_station
,
3329 enum sla_station_hangup hangup
)
3331 struct sla_ringing_trunk
*ringing_trunk
;
3332 struct sla_trunk_ref
*trunk_ref
;
3333 struct sla_station_ref
*station_ref
;
3335 ast_dial_join(ringing_station
->station
->dial
);
3336 ast_dial_destroy(ringing_station
->station
->dial
);
3337 ringing_station
->station
->dial
= NULL
;
3339 if (hangup
== SLA_STATION_HANGUP_NORMAL
)
3342 /* If the station is being hung up because of a timeout, then add it to the
3343 * list of timed out stations on each of the ringing trunks. This is so
3344 * that when doing further processing to figure out which stations should be
3345 * ringing, which trunk to answer, determining timeouts, etc., we know which
3346 * ringing trunks we should ignore. */
3347 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3348 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3349 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3354 if (!(station_ref
= sla_create_station_ref(ringing_station
->station
)))
3356 AST_LIST_INSERT_TAIL(&ringing_trunk
->timed_out_stations
, station_ref
, entry
);
3360 free(ringing_station
);
3363 static void sla_dial_state_callback(struct ast_dial
*dial
)
3365 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3368 /*! \brief Check to see if dialing this station already timed out for this ringing trunk
3369 * \note Assumes sla.lock is locked
3371 static int sla_check_timed_out_station(const struct sla_ringing_trunk
*ringing_trunk
,
3372 const struct sla_station
*station
)
3374 struct sla_station_ref
*timed_out_station
;
3376 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, timed_out_station
, entry
) {
3377 if (station
== timed_out_station
->station
)
3384 /*! \brief Choose the highest priority ringing trunk for a station
3385 * \param station the station
3386 * \param remove remove the ringing trunk once selected
3387 * \param trunk_ref a place to store the pointer to this stations reference to
3388 * the selected trunk
3389 * \return a pointer to the selected ringing trunk, or NULL if none found
3390 * \note Assumes that sla.lock is locked
3392 static struct sla_ringing_trunk
*sla_choose_ringing_trunk(struct sla_station
*station
,
3393 struct sla_trunk_ref
**trunk_ref
, int remove
)
3395 struct sla_trunk_ref
*s_trunk_ref
;
3396 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3398 AST_LIST_TRAVERSE(&station
->trunks
, s_trunk_ref
, entry
) {
3399 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3400 /* Make sure this is the trunk we're looking for */
3401 if (s_trunk_ref
->trunk
!= ringing_trunk
->trunk
)
3404 /* This trunk on the station is ringing. But, make sure this station
3405 * didn't already time out while this trunk was ringing. */
3406 if (sla_check_timed_out_station(ringing_trunk
, station
))
3410 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3413 *trunk_ref
= s_trunk_ref
;
3417 AST_LIST_TRAVERSE_SAFE_END
3423 return ringing_trunk
;
3426 static void sla_handle_dial_state_event(void)
3428 struct sla_ringing_station
*ringing_station
;
3430 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3431 struct sla_trunk_ref
*s_trunk_ref
= NULL
;
3432 struct sla_ringing_trunk
*ringing_trunk
= NULL
;
3433 struct run_station_args args
;
3434 enum ast_dial_result dial_res
;
3435 pthread_attr_t attr
;
3436 pthread_t dont_care
;
3437 ast_mutex_t cond_lock
;
3440 switch ((dial_res
= ast_dial_state(ringing_station
->station
->dial
))) {
3441 case AST_DIAL_RESULT_HANGUP
:
3442 case AST_DIAL_RESULT_INVALID
:
3443 case AST_DIAL_RESULT_FAILED
:
3444 case AST_DIAL_RESULT_TIMEOUT
:
3445 case AST_DIAL_RESULT_UNANSWERED
:
3446 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3447 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_NORMAL
);
3449 case AST_DIAL_RESULT_ANSWERED
:
3450 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3451 /* Find the appropriate trunk to answer. */
3452 ast_mutex_lock(&sla
.lock
);
3453 ringing_trunk
= sla_choose_ringing_trunk(ringing_station
->station
, &s_trunk_ref
, 1);
3454 ast_mutex_unlock(&sla
.lock
);
3455 if (!ringing_trunk
) {
3456 ast_log(LOG_DEBUG
, "Found no ringing trunk for station '%s' to answer!\n",
3457 ringing_station
->station
->name
);
3460 /* Track the channel that answered this trunk */
3461 s_trunk_ref
->chan
= ast_dial_answered(ringing_station
->station
->dial
);
3462 /* Actually answer the trunk */
3463 ast_answer(ringing_trunk
->trunk
->chan
);
3464 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
3465 /* Now, start a thread that will connect this station to the trunk. The rest of
3466 * the code here sets up the thread and ensures that it is able to save the arguments
3467 * before they are no longer valid since they are allocated on the stack. */
3468 args
.trunk_ref
= s_trunk_ref
;
3469 args
.station
= ringing_station
->station
;
3471 args
.cond_lock
= &cond_lock
;
3472 free(ringing_trunk
);
3473 free(ringing_station
);
3474 ast_mutex_init(&cond_lock
);
3475 ast_cond_init(&cond
, NULL
);
3476 pthread_attr_init(&attr
);
3477 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3478 ast_mutex_lock(&cond_lock
);
3479 ast_pthread_create_background(&dont_care
, &attr
, run_station
, &args
);
3480 ast_cond_wait(&cond
, &cond_lock
);
3481 ast_mutex_unlock(&cond_lock
);
3482 ast_mutex_destroy(&cond_lock
);
3483 ast_cond_destroy(&cond
);
3484 pthread_attr_destroy(&attr
);
3486 case AST_DIAL_RESULT_TRYING
:
3487 case AST_DIAL_RESULT_RINGING
:
3488 case AST_DIAL_RESULT_PROGRESS
:
3489 case AST_DIAL_RESULT_PROCEEDING
:
3492 if (dial_res
== AST_DIAL_RESULT_ANSWERED
) {
3493 /* Queue up reprocessing ringing trunks, and then ringing stations again */
3494 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
3495 sla_queue_event(SLA_EVENT_DIAL_STATE
);
3499 AST_LIST_TRAVERSE_SAFE_END
3502 /*! \brief Check to see if this station is already ringing
3503 * \note Assumes sla.lock is locked
3505 static int sla_check_ringing_station(const struct sla_station
*station
)
3507 struct sla_ringing_station
*ringing_station
;
3509 AST_LIST_TRAVERSE(&sla
.ringing_stations
, ringing_station
, entry
) {
3510 if (station
== ringing_station
->station
)
3517 /*! \brief Check to see if this station has failed to be dialed in the past minute
3518 * \note assumes sla.lock is locked
3520 static int sla_check_failed_station(const struct sla_station
*station
)
3522 struct sla_failed_station
*failed_station
;
3525 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.failed_stations
, failed_station
, entry
) {
3526 if (station
!= failed_station
->station
)
3528 if (ast_tvdiff_ms(ast_tvnow(), failed_station
->last_try
) > 1000) {
3529 AST_LIST_REMOVE_CURRENT(&sla
.failed_stations
, entry
);
3530 free(failed_station
);
3535 AST_LIST_TRAVERSE_SAFE_END
3540 /*! \brief Ring a station
3541 * \note Assumes sla.lock is locked
3543 static int sla_ring_station(struct sla_ringing_trunk
*ringing_trunk
, struct sla_station
*station
)
3545 char *tech
, *tech_data
;
3546 struct ast_dial
*dial
;
3547 struct sla_ringing_station
*ringing_station
;
3548 const char *cid_name
= NULL
, *cid_num
= NULL
;
3549 enum ast_dial_result res
;
3551 if (!(dial
= ast_dial_create()))
3554 ast_dial_set_state_callback(dial
, sla_dial_state_callback
);
3555 tech_data
= ast_strdupa(station
->device
);
3556 tech
= strsep(&tech_data
, "/");
3558 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
3559 ast_dial_destroy(dial
);
3563 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_name
)) {
3564 cid_name
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3565 free(ringing_trunk
->trunk
->chan
->cid
.cid_name
);
3566 ringing_trunk
->trunk
->chan
->cid
.cid_name
= NULL
;
3568 if (!sla
.attempt_callerid
&& !ast_strlen_zero(ringing_trunk
->trunk
->chan
->cid
.cid_num
)) {
3569 cid_num
= ast_strdupa(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3570 free(ringing_trunk
->trunk
->chan
->cid
.cid_num
);
3571 ringing_trunk
->trunk
->chan
->cid
.cid_num
= NULL
;
3574 res
= ast_dial_run(dial
, ringing_trunk
->trunk
->chan
, 1);
3577 ringing_trunk
->trunk
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
3579 ringing_trunk
->trunk
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
3581 if (res
!= AST_DIAL_RESULT_TRYING
) {
3582 struct sla_failed_station
*failed_station
;
3583 ast_dial_destroy(dial
);
3584 if (!(failed_station
= ast_calloc(1, sizeof(*failed_station
))))
3586 failed_station
->station
= station
;
3587 failed_station
->last_try
= ast_tvnow();
3588 AST_LIST_INSERT_HEAD(&sla
.failed_stations
, failed_station
, entry
);
3591 if (!(ringing_station
= sla_create_ringing_station(station
))) {
3592 ast_dial_join(dial
);
3593 ast_dial_destroy(dial
);
3597 station
->dial
= dial
;
3599 AST_LIST_INSERT_HEAD(&sla
.ringing_stations
, ringing_station
, entry
);
3604 /*! \brief Check to see if a station is in use
3606 static int sla_check_inuse_station(const struct sla_station
*station
)
3608 struct sla_trunk_ref
*trunk_ref
;
3610 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3611 if (trunk_ref
->chan
)
3618 static struct sla_trunk_ref
*sla_find_trunk_ref(const struct sla_station
*station
,
3619 const struct sla_trunk
*trunk
)
3621 struct sla_trunk_ref
*trunk_ref
= NULL
;
3623 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
3624 if (trunk_ref
->trunk
== trunk
)
3631 /*! \brief Calculate the ring delay for a given ringing trunk on a station
3632 * \param station the station
3633 * \param trunk the trunk. If NULL, the highest priority ringing trunk will be used
3634 * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
3636 static int sla_check_station_delay(struct sla_station
*station
,
3637 struct sla_ringing_trunk
*ringing_trunk
)
3639 struct sla_trunk_ref
*trunk_ref
;
3640 unsigned int delay
= UINT_MAX
;
3641 int time_left
, time_elapsed
;
3644 ringing_trunk
= sla_choose_ringing_trunk(station
, &trunk_ref
, 0);
3646 trunk_ref
= sla_find_trunk_ref(station
, ringing_trunk
->trunk
);
3648 if (!ringing_trunk
|| !trunk_ref
)
3651 /* If this station has a ring delay specific to the highest priority
3652 * ringing trunk, use that. Otherwise, use the ring delay specified
3653 * globally for the station. */
3654 delay
= trunk_ref
->ring_delay
;
3656 delay
= station
->ring_delay
;
3660 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3661 time_left
= (delay
* 1000) - time_elapsed
;
3666 /*! \brief Ring stations based on current set of ringing trunks
3667 * \note Assumes that sla.lock is locked
3669 static void sla_ring_stations(void)
3671 struct sla_station_ref
*station_ref
;
3672 struct sla_ringing_trunk
*ringing_trunk
;
3674 /* Make sure that every station that uses at least one of the ringing
3675 * trunks, is ringing. */
3676 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3677 AST_LIST_TRAVERSE(&ringing_trunk
->trunk
->stations
, station_ref
, entry
) {
3680 /* Is this station already ringing? */
3681 if (sla_check_ringing_station(station_ref
->station
))
3684 /* Is this station already in a call? */
3685 if (sla_check_inuse_station(station_ref
->station
))
3688 /* Did we fail to dial this station earlier? If so, has it been
3689 * a minute since we tried? */
3690 if (sla_check_failed_station(station_ref
->station
))
3693 /* If this station already timed out while this trunk was ringing,
3694 * do not dial it again for this ringing trunk. */
3695 if (sla_check_timed_out_station(ringing_trunk
, station_ref
->station
))
3698 /* Check for a ring delay in progress */
3699 time_left
= sla_check_station_delay(station_ref
->station
, ringing_trunk
);
3700 if (time_left
!= INT_MAX
&& time_left
> 0)
3703 /* It is time to make this station begin to ring. Do it! */
3704 sla_ring_station(ringing_trunk
, station_ref
->station
);
3707 /* Now, all of the stations that should be ringing, are ringing. */
3710 static void sla_hangup_stations(void)
3712 struct sla_trunk_ref
*trunk_ref
;
3713 struct sla_ringing_station
*ringing_station
;
3715 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3716 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3717 struct sla_ringing_trunk
*ringing_trunk
;
3718 ast_mutex_lock(&sla
.lock
);
3719 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3720 if (trunk_ref
->trunk
== ringing_trunk
->trunk
)
3723 ast_mutex_unlock(&sla
.lock
);
3728 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3729 ast_dial_join(ringing_station
->station
->dial
);
3730 ast_dial_destroy(ringing_station
->station
->dial
);
3731 ringing_station
->station
->dial
= NULL
;
3732 free(ringing_station
);
3735 AST_LIST_TRAVERSE_SAFE_END
3738 static void sla_handle_ringing_trunk_event(void)
3740 ast_mutex_lock(&sla
.lock
);
3741 sla_ring_stations();
3742 ast_mutex_unlock(&sla
.lock
);
3744 /* Find stations that shouldn't be ringing anymore. */
3745 sla_hangup_stations();
3748 static void sla_handle_hold_event(struct sla_event
*event
)
3750 ast_atomic_fetchadd_int((int *) &event
->trunk_ref
->trunk
->hold_stations
, 1);
3751 event
->trunk_ref
->state
= SLA_TRUNK_STATE_ONHOLD_BYME
;
3752 ast_device_state_changed("SLA:%s_%s",
3753 event
->station
->name
, event
->trunk_ref
->trunk
->name
);
3754 sla_change_trunk_state(event
->trunk_ref
->trunk
, SLA_TRUNK_STATE_ONHOLD
,
3755 INACTIVE_TRUNK_REFS
, event
->trunk_ref
);
3757 if (event
->trunk_ref
->trunk
->active_stations
== 1) {
3758 /* The station putting it on hold is the only one on the call, so start
3759 * Music on hold to the trunk. */
3760 event
->trunk_ref
->trunk
->on_hold
= 1;
3761 ast_indicate(event
->trunk_ref
->trunk
->chan
, AST_CONTROL_HOLD
);
3764 ast_softhangup(event
->trunk_ref
->chan
, AST_CAUSE_NORMAL
);
3765 event
->trunk_ref
->chan
= NULL
;
3768 /*! \brief Process trunk ring timeouts
3769 * \note Called with sla.lock locked
3770 * \return non-zero if a change to the ringing trunks was made
3772 static int sla_calc_trunk_timeouts(unsigned int *timeout
)
3774 struct sla_ringing_trunk
*ringing_trunk
;
3777 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3778 int time_left
, time_elapsed
;
3779 if (!ringing_trunk
->trunk
->ring_timeout
)
3781 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3782 time_left
= (ringing_trunk
->trunk
->ring_timeout
* 1000) - time_elapsed
;
3783 if (time_left
<= 0) {
3784 pbx_builtin_setvar_helper(ringing_trunk
->trunk
->chan
, "SLATRUNK_STATUS", "RINGTIMEOUT");
3785 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
3786 sla_stop_ringing_trunk(ringing_trunk
);
3790 if (time_left
< *timeout
)
3791 *timeout
= time_left
;
3793 AST_LIST_TRAVERSE_SAFE_END
3798 /*! \brief Process station ring timeouts
3799 * \note Called with sla.lock locked
3800 * \return non-zero if a change to the ringing stations was made
3802 static int sla_calc_station_timeouts(unsigned int *timeout
)
3804 struct sla_ringing_trunk
*ringing_trunk
;
3805 struct sla_ringing_station
*ringing_station
;
3808 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_stations
, ringing_station
, entry
) {
3809 unsigned int ring_timeout
= 0;
3810 int time_elapsed
, time_left
= INT_MAX
, final_trunk_time_left
= INT_MIN
;
3811 struct sla_trunk_ref
*trunk_ref
;
3813 /* If there are any ring timeouts specified for a specific trunk
3814 * on the station, then use the highest per-trunk ring timeout.
3815 * Otherwise, use the ring timeout set for the entire station. */
3816 AST_LIST_TRAVERSE(&ringing_station
->station
->trunks
, trunk_ref
, entry
) {
3817 struct sla_station_ref
*station_ref
;
3818 int trunk_time_elapsed
, trunk_time_left
;
3820 AST_LIST_TRAVERSE(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
3821 if (ringing_trunk
->trunk
== trunk_ref
->trunk
)
3827 /* If there is a trunk that is ringing without a timeout, then the
3828 * only timeout that could matter is a global station ring timeout. */
3829 if (!trunk_ref
->ring_timeout
)
3832 /* This trunk on this station is ringing and has a timeout.
3833 * However, make sure this trunk isn't still ringing from a
3834 * previous timeout. If so, don't consider it. */
3835 AST_LIST_TRAVERSE(&ringing_trunk
->timed_out_stations
, station_ref
, entry
) {
3836 if (station_ref
->station
== ringing_station
->station
)
3842 trunk_time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_trunk
->ring_begin
);
3843 trunk_time_left
= (trunk_ref
->ring_timeout
* 1000) - trunk_time_elapsed
;
3844 if (trunk_time_left
> final_trunk_time_left
)
3845 final_trunk_time_left
= trunk_time_left
;
3848 /* No timeout was found for ringing trunks, and no timeout for the entire station */
3849 if (final_trunk_time_left
== INT_MIN
&& !ringing_station
->station
->ring_timeout
)
3852 /* Compute how much time is left for a global station timeout */
3853 if (ringing_station
->station
->ring_timeout
) {
3854 ring_timeout
= ringing_station
->station
->ring_timeout
;
3855 time_elapsed
= ast_tvdiff_ms(ast_tvnow(), ringing_station
->ring_begin
);
3856 time_left
= (ring_timeout
* 1000) - time_elapsed
;
3859 /* If the time left based on the per-trunk timeouts is smaller than the
3860 * global station ring timeout, use that. */
3861 if (final_trunk_time_left
> INT_MIN
&& final_trunk_time_left
< time_left
)
3862 time_left
= final_trunk_time_left
;
3864 /* If there is no time left, the station needs to stop ringing */
3865 if (time_left
<= 0) {
3866 AST_LIST_REMOVE_CURRENT(&sla
.ringing_stations
, entry
);
3867 sla_stop_ringing_station(ringing_station
, SLA_STATION_HANGUP_TIMEOUT
);
3872 /* There is still some time left for this station to ring, so save that
3873 * timeout if it is the first event scheduled to occur */
3874 if (time_left
< *timeout
)
3875 *timeout
= time_left
;
3877 AST_LIST_TRAVERSE_SAFE_END
3882 /*! \brief Calculate the ring delay for a station
3883 * \note Assumes sla.lock is locked
3885 static int sla_calc_station_delays(unsigned int *timeout
)
3887 struct sla_station
*station
;
3890 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
3891 struct sla_ringing_trunk
*ringing_trunk
;
3894 /* Ignore stations already ringing */
3895 if (sla_check_ringing_station(station
))
3898 /* Ignore stations already on a call */
3899 if (sla_check_inuse_station(station
))
3902 /* Ignore stations that don't have one of their trunks ringing */
3903 if (!(ringing_trunk
= sla_choose_ringing_trunk(station
, NULL
, 0)))
3906 if ((time_left
= sla_check_station_delay(station
, ringing_trunk
)) == INT_MAX
)
3909 /* If there is no time left, then the station needs to start ringing.
3910 * Return non-zero so that an event will be queued up an event to
3911 * make that happen. */
3912 if (time_left
<= 0) {
3917 if (time_left
< *timeout
)
3918 *timeout
= time_left
;
3924 /*! \brief Calculate the time until the next known event
3925 * \note Called with sla.lock locked */
3926 static int sla_process_timers(struct timespec
*ts
)
3928 unsigned int timeout
= UINT_MAX
;
3930 unsigned int change_made
= 0;
3932 /* Check for ring timeouts on ringing trunks */
3933 if (sla_calc_trunk_timeouts(&timeout
))
3936 /* Check for ring timeouts on ringing stations */
3937 if (sla_calc_station_timeouts(&timeout
))
3940 /* Check for station ring delays */
3941 if (sla_calc_station_delays(&timeout
))
3944 /* queue reprocessing of ringing trunks */
3946 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK
);
3949 if (timeout
== UINT_MAX
)
3953 tv
= ast_tvadd(ast_tvnow(), ast_samp2tv(timeout
, 1000));
3954 ts
->tv_sec
= tv
.tv_sec
;
3955 ts
->tv_nsec
= tv
.tv_usec
* 1000;
3961 static void *sla_thread(void *data
)
3963 struct sla_failed_station
*failed_station
;
3964 struct sla_ringing_station
*ringing_station
;
3966 ast_mutex_lock(&sla
.lock
);
3969 struct sla_event
*event
;
3970 struct timespec ts
= { 0, };
3971 unsigned int have_timeout
= 0;
3973 if (AST_LIST_EMPTY(&sla
.event_q
)) {
3974 if ((have_timeout
= sla_process_timers(&ts
)))
3975 ast_cond_timedwait(&sla
.cond
, &sla
.lock
, &ts
);
3977 ast_cond_wait(&sla
.cond
, &sla
.lock
);
3983 sla_process_timers(NULL
);
3985 while ((event
= AST_LIST_REMOVE_HEAD(&sla
.event_q
, entry
))) {
3986 ast_mutex_unlock(&sla
.lock
);
3987 switch (event
->type
) {
3988 case SLA_EVENT_HOLD
:
3989 sla_handle_hold_event(event
);
3991 case SLA_EVENT_DIAL_STATE
:
3992 sla_handle_dial_state_event();
3994 case SLA_EVENT_RINGING_TRUNK
:
3995 sla_handle_ringing_trunk_event();
3999 ast_mutex_lock(&sla
.lock
);
4003 ast_mutex_unlock(&sla
.lock
);
4005 while ((ringing_station
= AST_LIST_REMOVE_HEAD(&sla
.ringing_stations
, entry
)))
4006 free(ringing_station
);
4008 while ((failed_station
= AST_LIST_REMOVE_HEAD(&sla
.failed_stations
, entry
)))
4009 free(failed_station
);
4014 struct dial_trunk_args
{
4015 struct sla_trunk_ref
*trunk_ref
;
4016 struct sla_station
*station
;
4017 ast_mutex_t
*cond_lock
;
4021 static void *dial_trunk(void *data
)
4023 struct dial_trunk_args
*args
= data
;
4024 struct ast_dial
*dial
;
4025 char *tech
, *tech_data
;
4026 enum ast_dial_result dial_res
;
4027 char conf_name
[MAX_CONFNUM
];
4028 struct ast_conference
*conf
;
4029 struct ast_flags conf_flags
= { 0 };
4030 struct sla_trunk_ref
*trunk_ref
= args
->trunk_ref
;
4031 const char *cid_name
= NULL
, *cid_num
= NULL
;
4033 if (!(dial
= ast_dial_create())) {
4034 ast_mutex_lock(args
->cond_lock
);
4035 ast_cond_signal(args
->cond
);
4036 ast_mutex_unlock(args
->cond_lock
);
4040 tech_data
= ast_strdupa(trunk_ref
->trunk
->device
);
4041 tech
= strsep(&tech_data
, "/");
4042 if (ast_dial_append(dial
, tech
, tech_data
) == -1) {
4043 ast_mutex_lock(args
->cond_lock
);
4044 ast_cond_signal(args
->cond
);
4045 ast_mutex_unlock(args
->cond_lock
);
4046 ast_dial_destroy(dial
);
4050 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_name
)) {
4051 cid_name
= ast_strdupa(trunk_ref
->chan
->cid
.cid_name
);
4052 free(trunk_ref
->chan
->cid
.cid_name
);
4053 trunk_ref
->chan
->cid
.cid_name
= NULL
;
4055 if (!sla
.attempt_callerid
&& !ast_strlen_zero(trunk_ref
->chan
->cid
.cid_num
)) {
4056 cid_num
= ast_strdupa(trunk_ref
->chan
->cid
.cid_num
);
4057 free(trunk_ref
->chan
->cid
.cid_num
);
4058 trunk_ref
->chan
->cid
.cid_num
= NULL
;
4061 dial_res
= ast_dial_run(dial
, trunk_ref
->chan
, 1);
4064 trunk_ref
->chan
->cid
.cid_name
= ast_strdup(cid_name
);
4066 trunk_ref
->chan
->cid
.cid_num
= ast_strdup(cid_num
);
4068 if (dial_res
!= AST_DIAL_RESULT_TRYING
) {
4069 ast_mutex_lock(args
->cond_lock
);
4070 ast_cond_signal(args
->cond
);
4071 ast_mutex_unlock(args
->cond_lock
);
4072 ast_dial_destroy(dial
);
4077 unsigned int done
= 0;
4078 switch ((dial_res
= ast_dial_state(dial
))) {
4079 case AST_DIAL_RESULT_ANSWERED
:
4080 trunk_ref
->trunk
->chan
= ast_dial_answered(dial
);
4081 case AST_DIAL_RESULT_HANGUP
:
4082 case AST_DIAL_RESULT_INVALID
:
4083 case AST_DIAL_RESULT_FAILED
:
4084 case AST_DIAL_RESULT_TIMEOUT
:
4085 case AST_DIAL_RESULT_UNANSWERED
:
4087 case AST_DIAL_RESULT_TRYING
:
4088 case AST_DIAL_RESULT_RINGING
:
4089 case AST_DIAL_RESULT_PROGRESS
:
4090 case AST_DIAL_RESULT_PROCEEDING
:
4097 if (!trunk_ref
->trunk
->chan
) {
4098 ast_mutex_lock(args
->cond_lock
);
4099 ast_cond_signal(args
->cond
);
4100 ast_mutex_unlock(args
->cond_lock
);
4101 ast_dial_join(dial
);
4102 ast_dial_destroy(dial
);
4106 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4107 ast_set_flag(&conf_flags
,
4108 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
|
4109 CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_TRUNK
);
4110 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4112 ast_mutex_lock(args
->cond_lock
);
4113 ast_cond_signal(args
->cond
);
4114 ast_mutex_unlock(args
->cond_lock
);
4117 conf_run(trunk_ref
->trunk
->chan
, conf
, conf_flags
.flags
, NULL
);
4122 /* If the trunk is going away, it is definitely now IDLE. */
4123 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4125 trunk_ref
->trunk
->chan
= NULL
;
4126 trunk_ref
->trunk
->on_hold
= 0;
4128 ast_dial_join(dial
);
4129 ast_dial_destroy(dial
);
4134 /*! \brief For a given station, choose the highest priority idle trunk
4136 static struct sla_trunk_ref
*sla_choose_idle_trunk(const struct sla_station
*station
)
4138 struct sla_trunk_ref
*trunk_ref
= NULL
;
4140 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4141 if (trunk_ref
->state
== SLA_TRUNK_STATE_IDLE
)
4148 static int sla_station_exec(struct ast_channel
*chan
, void *data
)
4150 char *station_name
, *trunk_name
;
4151 struct sla_station
*station
;
4152 struct sla_trunk_ref
*trunk_ref
= NULL
;
4153 char conf_name
[MAX_CONFNUM
];
4154 struct ast_flags conf_flags
= { 0 };
4155 struct ast_conference
*conf
;
4157 if (ast_strlen_zero(data
)) {
4158 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4159 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4163 trunk_name
= ast_strdupa(data
);
4164 station_name
= strsep(&trunk_name
, "_");
4166 if (ast_strlen_zero(station_name
)) {
4167 ast_log(LOG_WARNING
, "Invalid Arguments to SLAStation!\n");
4168 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4172 AST_RWLIST_RDLOCK(&sla_stations
);
4173 station
= sla_find_station(station_name
);
4174 AST_RWLIST_UNLOCK(&sla_stations
);
4177 ast_log(LOG_WARNING
, "Station '%s' not found!\n", station_name
);
4178 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "FAILURE");
4182 AST_RWLIST_RDLOCK(&sla_trunks
);
4183 if (!ast_strlen_zero(trunk_name
)) {
4184 trunk_ref
= sla_find_trunk_ref_byname(station
, trunk_name
);
4186 trunk_ref
= sla_choose_idle_trunk(station
);
4187 AST_RWLIST_UNLOCK(&sla_trunks
);
4190 if (ast_strlen_zero(trunk_name
))
4191 ast_log(LOG_NOTICE
, "No trunks available for call.\n");
4193 ast_log(LOG_NOTICE
, "Can't join existing call on trunk "
4194 "'%s' due to access controls.\n", trunk_name
);
4196 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4200 if (trunk_ref
->state
== SLA_TRUNK_STATE_ONHOLD_BYME
) {
4201 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->hold_stations
) == 1)
4202 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4204 trunk_ref
->state
= SLA_TRUNK_STATE_UP
;
4205 ast_device_state_changed("SLA:%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4207 } else if (trunk_ref
->state
== SLA_TRUNK_STATE_RINGING
) {
4208 struct sla_ringing_trunk
*ringing_trunk
;
4210 ast_mutex_lock(&sla
.lock
);
4211 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4212 if (ringing_trunk
->trunk
== trunk_ref
->trunk
) {
4213 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4217 AST_LIST_TRAVERSE_SAFE_END
4218 ast_mutex_unlock(&sla
.lock
);
4220 if (ringing_trunk
) {
4221 ast_answer(ringing_trunk
->trunk
->chan
);
4222 sla_change_trunk_state(ringing_trunk
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4224 free(ringing_trunk
);
4226 /* Queue up reprocessing ringing trunks, and then ringing stations again */
4227 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4228 sla_queue_event(SLA_EVENT_DIAL_STATE
);
4232 trunk_ref
->chan
= chan
;
4234 if (!trunk_ref
->trunk
->chan
) {
4235 ast_mutex_t cond_lock
;
4237 pthread_t dont_care
;
4238 pthread_attr_t attr
;
4239 struct dial_trunk_args args
= {
4240 .trunk_ref
= trunk_ref
,
4242 .cond_lock
= &cond_lock
,
4245 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4246 /* Create a thread to dial the trunk and dump it into the conference.
4247 * However, we want to wait until the trunk has been dialed and the
4248 * conference is created before continuing on here. */
4249 ast_autoservice_start(chan
);
4250 ast_mutex_init(&cond_lock
);
4251 ast_cond_init(&cond
, NULL
);
4252 pthread_attr_init(&attr
);
4253 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
4254 ast_mutex_lock(&cond_lock
);
4255 ast_pthread_create_background(&dont_care
, &attr
, dial_trunk
, &args
);
4256 ast_cond_wait(&cond
, &cond_lock
);
4257 ast_mutex_unlock(&cond_lock
);
4258 ast_mutex_destroy(&cond_lock
);
4259 ast_cond_destroy(&cond
);
4260 pthread_attr_destroy(&attr
);
4261 ast_autoservice_stop(chan
);
4262 if (!trunk_ref
->trunk
->chan
) {
4263 ast_log(LOG_DEBUG
, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref
->trunk
->chan
);
4264 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "CONGESTION");
4265 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4266 trunk_ref
->chan
= NULL
;
4271 if (ast_atomic_fetchadd_int((int *) &trunk_ref
->trunk
->active_stations
, 1) == 0 &&
4272 trunk_ref
->trunk
->on_hold
) {
4273 trunk_ref
->trunk
->on_hold
= 0;
4274 ast_indicate(trunk_ref
->trunk
->chan
, AST_CONTROL_UNHOLD
);
4275 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_UP
, ALL_TRUNK_REFS
, NULL
);
4278 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_ref
->trunk
->name
);
4279 ast_set_flag(&conf_flags
,
4280 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_PASS_DTMF
| CONFFLAG_SLA_STATION
);
4282 conf
= build_conf(conf_name
, "", "", 0, 0, 1);
4284 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4288 trunk_ref
->chan
= NULL
;
4289 if (ast_atomic_dec_and_test((int *) &trunk_ref
->trunk
->active_stations
) &&
4290 trunk_ref
->state
!= SLA_TRUNK_STATE_ONHOLD_BYME
) {
4291 strncat(conf_name
, "|K", sizeof(conf_name
) - strlen(conf_name
) - 1);
4292 admin_exec(NULL
, conf_name
);
4293 trunk_ref
->trunk
->hold_stations
= 0;
4294 sla_change_trunk_state(trunk_ref
->trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4297 pbx_builtin_setvar_helper(chan
, "SLASTATION_STATUS", "SUCCESS");
4302 static struct sla_trunk_ref
*create_trunk_ref(struct sla_trunk
*trunk
)
4304 struct sla_trunk_ref
*trunk_ref
;
4306 if (!(trunk_ref
= ast_calloc(1, sizeof(*trunk_ref
))))
4309 trunk_ref
->trunk
= trunk
;
4314 static struct sla_ringing_trunk
*queue_ringing_trunk(struct sla_trunk
*trunk
)
4316 struct sla_ringing_trunk
*ringing_trunk
;
4318 if (!(ringing_trunk
= ast_calloc(1, sizeof(*ringing_trunk
))))
4321 ringing_trunk
->trunk
= trunk
;
4322 ringing_trunk
->ring_begin
= ast_tvnow();
4324 sla_change_trunk_state(trunk
, SLA_TRUNK_STATE_RINGING
, ALL_TRUNK_REFS
, NULL
);
4326 ast_mutex_lock(&sla
.lock
);
4327 AST_LIST_INSERT_HEAD(&sla
.ringing_trunks
, ringing_trunk
, entry
);
4328 ast_mutex_unlock(&sla
.lock
);
4330 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4332 return ringing_trunk
;
4335 static int sla_trunk_exec(struct ast_channel
*chan
, void *data
)
4337 const char *trunk_name
= data
;
4338 char conf_name
[MAX_CONFNUM
];
4339 struct ast_conference
*conf
;
4340 struct ast_flags conf_flags
= { 0 };
4341 struct sla_trunk
*trunk
;
4342 struct sla_ringing_trunk
*ringing_trunk
;
4344 AST_RWLIST_RDLOCK(&sla_trunks
);
4345 trunk
= sla_find_trunk(trunk_name
);
4346 AST_RWLIST_UNLOCK(&sla_trunks
);
4348 ast_log(LOG_ERROR
, "SLA Trunk '%s' not found!\n", trunk_name
);
4349 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4353 ast_log(LOG_ERROR
, "Call came in on %s, but the trunk is already in use!\n",
4355 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4360 if (!(ringing_trunk
= queue_ringing_trunk(trunk
))) {
4361 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4365 snprintf(conf_name
, sizeof(conf_name
), "SLA_%s", trunk_name
);
4366 conf
= build_conf(conf_name
, "", "", 1, 1, 1);
4368 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "FAILURE");
4371 ast_set_flag(&conf_flags
,
4372 CONFFLAG_QUIET
| CONFFLAG_MARKEDEXIT
| CONFFLAG_MARKEDUSER
| CONFFLAG_PASS_DTMF
);
4373 ast_indicate(chan
, AST_CONTROL_RINGING
);
4374 conf_run(chan
, conf
, conf_flags
.flags
, NULL
);
4380 sla_change_trunk_state(trunk
, SLA_TRUNK_STATE_IDLE
, ALL_TRUNK_REFS
, NULL
);
4382 if (!pbx_builtin_getvar_helper(chan
, "SLATRUNK_STATUS"))
4383 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "SUCCESS");
4385 /* Remove the entry from the list of ringing trunks if it is still there. */
4386 ast_mutex_lock(&sla
.lock
);
4387 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla
.ringing_trunks
, ringing_trunk
, entry
) {
4388 if (ringing_trunk
->trunk
== trunk
) {
4389 AST_LIST_REMOVE_CURRENT(&sla
.ringing_trunks
, entry
);
4393 AST_LIST_TRAVERSE_SAFE_END
4394 ast_mutex_unlock(&sla
.lock
);
4395 if (ringing_trunk
) {
4396 free(ringing_trunk
);
4397 pbx_builtin_setvar_helper(chan
, "SLATRUNK_STATUS", "UNANSWERED");
4398 /* Queue reprocessing of ringing trunks to make stations stop ringing
4399 * that shouldn't be ringing after this trunk stopped. */
4400 sla_queue_event(SLA_EVENT_RINGING_TRUNK
);
4406 static int sla_state(const char *data
)
4408 char *buf
, *station_name
, *trunk_name
;
4409 struct sla_station
*station
;
4410 struct sla_trunk_ref
*trunk_ref
;
4411 int res
= AST_DEVICE_INVALID
;
4413 trunk_name
= buf
= ast_strdupa(data
);
4414 station_name
= strsep(&trunk_name
, "_");
4416 AST_RWLIST_RDLOCK(&sla_stations
);
4417 AST_LIST_TRAVERSE(&sla_stations
, station
, entry
) {
4418 if (strcasecmp(station_name
, station
->name
))
4420 AST_RWLIST_RDLOCK(&sla_trunks
);
4421 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4422 if (!strcasecmp(trunk_name
, trunk_ref
->trunk
->name
))
4426 AST_RWLIST_UNLOCK(&sla_trunks
);
4429 switch (trunk_ref
->state
) {
4430 case SLA_TRUNK_STATE_IDLE
:
4431 res
= AST_DEVICE_NOT_INUSE
;
4433 case SLA_TRUNK_STATE_RINGING
:
4434 res
= AST_DEVICE_RINGING
;
4436 case SLA_TRUNK_STATE_UP
:
4437 res
= AST_DEVICE_INUSE
;
4439 case SLA_TRUNK_STATE_ONHOLD
:
4440 case SLA_TRUNK_STATE_ONHOLD_BYME
:
4441 res
= AST_DEVICE_ONHOLD
;
4444 AST_RWLIST_UNLOCK(&sla_trunks
);
4446 AST_RWLIST_UNLOCK(&sla_stations
);
4448 if (res
== AST_DEVICE_INVALID
) {
4449 ast_log(LOG_ERROR
, "Could not determine state for trunk %s on station %s!\n",
4450 trunk_name
, station_name
);
4456 static void destroy_trunk(struct sla_trunk
*trunk
)
4458 struct sla_station_ref
*station_ref
;
4460 if (!ast_strlen_zero(trunk
->autocontext
))
4461 ast_context_remove_extension(trunk
->autocontext
, "s", 1, sla_registrar
);
4463 while ((station_ref
= AST_LIST_REMOVE_HEAD(&trunk
->stations
, entry
)))
4466 ast_string_field_free_memory(trunk
);
4470 static void destroy_station(struct sla_station
*station
)
4472 struct sla_trunk_ref
*trunk_ref
;
4474 if (!ast_strlen_zero(station
->autocontext
)) {
4475 AST_RWLIST_RDLOCK(&sla_trunks
);
4476 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4477 char exten
[AST_MAX_EXTENSION
];
4478 char hint
[AST_MAX_APP
];
4479 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4480 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4481 ast_context_remove_extension(station
->autocontext
, exten
,
4483 ast_context_remove_extension(station
->autocontext
, hint
,
4484 PRIORITY_HINT
, sla_registrar
);
4486 AST_RWLIST_UNLOCK(&sla_trunks
);
4489 while ((trunk_ref
= AST_LIST_REMOVE_HEAD(&station
->trunks
, entry
)))
4492 ast_string_field_free_memory(station
);
4496 static void sla_destroy(void)
4498 struct sla_trunk
*trunk
;
4499 struct sla_station
*station
;
4501 AST_RWLIST_WRLOCK(&sla_trunks
);
4502 while ((trunk
= AST_RWLIST_REMOVE_HEAD(&sla_trunks
, entry
)))
4503 destroy_trunk(trunk
);
4504 AST_RWLIST_UNLOCK(&sla_trunks
);
4506 AST_RWLIST_WRLOCK(&sla_stations
);
4507 while ((station
= AST_RWLIST_REMOVE_HEAD(&sla_stations
, entry
)))
4508 destroy_station(station
);
4509 AST_RWLIST_UNLOCK(&sla_stations
);
4511 if (sla
.thread
!= AST_PTHREADT_NULL
) {
4512 ast_mutex_lock(&sla
.lock
);
4514 ast_cond_signal(&sla
.cond
);
4515 ast_mutex_unlock(&sla
.lock
);
4516 pthread_join(sla
.thread
, NULL
);
4519 /* Drop any created contexts from the dialplan */
4520 ast_context_destroy(NULL
, sla_registrar
);
4522 ast_mutex_destroy(&sla
.lock
);
4523 ast_cond_destroy(&sla
.cond
);
4526 static int sla_check_device(const char *device
)
4528 char *tech
, *tech_data
;
4530 tech_data
= ast_strdupa(device
);
4531 tech
= strsep(&tech_data
, "/");
4533 if (ast_strlen_zero(tech
) || ast_strlen_zero(tech_data
))
4539 static int sla_build_trunk(struct ast_config
*cfg
, const char *cat
)
4541 struct sla_trunk
*trunk
;
4542 struct ast_variable
*var
;
4545 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4546 ast_log(LOG_ERROR
, "SLA Trunk '%s' defined with no device!\n", cat
);
4550 if (sla_check_device(dev
)) {
4551 ast_log(LOG_ERROR
, "SLA Trunk '%s' define with invalid device '%s'!\n",
4556 if (!(trunk
= ast_calloc(1, sizeof(*trunk
))))
4558 if (ast_string_field_init(trunk
, 32)) {
4563 ast_string_field_set(trunk
, name
, cat
);
4564 ast_string_field_set(trunk
, device
, dev
);
4566 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4567 if (!strcasecmp(var
->name
, "autocontext"))
4568 ast_string_field_set(trunk
, autocontext
, var
->value
);
4569 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4570 if (sscanf(var
->value
, "%u", &trunk
->ring_timeout
) != 1) {
4571 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
4572 var
->value
, trunk
->name
);
4573 trunk
->ring_timeout
= 0;
4575 } else if (!strcasecmp(var
->name
, "barge"))
4576 trunk
->barge_disabled
= ast_false(var
->value
);
4577 else if (!strcasecmp(var
->name
, "hold")) {
4578 if (!strcasecmp(var
->value
, "private"))
4579 trunk
->hold_access
= SLA_HOLD_PRIVATE
;
4580 else if (!strcasecmp(var
->value
, "open"))
4581 trunk
->hold_access
= SLA_HOLD_OPEN
;
4583 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on trunk %s\n",
4584 var
->value
, trunk
->name
);
4586 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4587 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4588 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4592 if (!ast_strlen_zero(trunk
->autocontext
)) {
4593 struct ast_context
*context
;
4594 context
= ast_context_find_or_create(NULL
, trunk
->autocontext
, sla_registrar
);
4596 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4597 "context '%s' for SLA!\n", trunk
->autocontext
);
4598 destroy_trunk(trunk
);
4601 if (ast_add_extension2(context
, 0 /* don't replace */, "s", 1,
4602 NULL
, NULL
, slatrunk_app
, ast_strdup(trunk
->name
), ast_free
, sla_registrar
)) {
4603 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4604 "for trunk '%s'!\n", trunk
->name
);
4605 destroy_trunk(trunk
);
4610 AST_RWLIST_WRLOCK(&sla_trunks
);
4611 AST_RWLIST_INSERT_TAIL(&sla_trunks
, trunk
, entry
);
4612 AST_RWLIST_UNLOCK(&sla_trunks
);
4617 static void sla_add_trunk_to_station(struct sla_station
*station
, struct ast_variable
*var
)
4619 struct sla_trunk
*trunk
;
4620 struct sla_trunk_ref
*trunk_ref
;
4621 struct sla_station_ref
*station_ref
;
4622 char *trunk_name
, *options
, *cur
;
4624 options
= ast_strdupa(var
->value
);
4625 trunk_name
= strsep(&options
, ",");
4627 AST_RWLIST_RDLOCK(&sla_trunks
);
4628 AST_RWLIST_TRAVERSE(&sla_trunks
, trunk
, entry
) {
4629 if (!strcasecmp(trunk
->name
, trunk_name
))
4633 AST_RWLIST_UNLOCK(&sla_trunks
);
4635 ast_log(LOG_ERROR
, "Trunk '%s' not found!\n", var
->value
);
4638 if (!(trunk_ref
= create_trunk_ref(trunk
)))
4640 trunk_ref
->state
= SLA_TRUNK_STATE_IDLE
;
4642 while ((cur
= strsep(&options
, ","))) {
4643 char *name
, *value
= cur
;
4644 name
= strsep(&value
, "=");
4645 if (!strcasecmp(name
, "ringtimeout")) {
4646 if (sscanf(value
, "%u", &trunk_ref
->ring_timeout
) != 1) {
4647 ast_log(LOG_WARNING
, "Invalid ringtimeout value '%s' for "
4648 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4649 trunk_ref
->ring_timeout
= 0;
4651 } else if (!strcasecmp(name
, "ringdelay")) {
4652 if (sscanf(value
, "%u", &trunk_ref
->ring_delay
) != 1) {
4653 ast_log(LOG_WARNING
, "Invalid ringdelay value '%s' for "
4654 "trunk '%s' on station '%s'\n", value
, trunk
->name
, station
->name
);
4655 trunk_ref
->ring_delay
= 0;
4658 ast_log(LOG_WARNING
, "Invalid option '%s' for "
4659 "trunk '%s' on station '%s'\n", name
, trunk
->name
, station
->name
);
4663 if (!(station_ref
= sla_create_station_ref(station
))) {
4667 ast_atomic_fetchadd_int((int *) &trunk
->num_stations
, 1);
4668 AST_RWLIST_WRLOCK(&sla_trunks
);
4669 AST_LIST_INSERT_TAIL(&trunk
->stations
, station_ref
, entry
);
4670 AST_RWLIST_UNLOCK(&sla_trunks
);
4671 AST_LIST_INSERT_TAIL(&station
->trunks
, trunk_ref
, entry
);
4674 static int sla_build_station(struct ast_config
*cfg
, const char *cat
)
4676 struct sla_station
*station
;
4677 struct ast_variable
*var
;
4680 if (!(dev
= ast_variable_retrieve(cfg
, cat
, "device"))) {
4681 ast_log(LOG_ERROR
, "SLA Station '%s' defined with no device!\n", cat
);
4685 if (!(station
= ast_calloc(1, sizeof(*station
))))
4687 if (ast_string_field_init(station
, 32)) {
4692 ast_string_field_set(station
, name
, cat
);
4693 ast_string_field_set(station
, device
, dev
);
4695 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4696 if (!strcasecmp(var
->name
, "trunk"))
4697 sla_add_trunk_to_station(station
, var
);
4698 else if (!strcasecmp(var
->name
, "autocontext"))
4699 ast_string_field_set(station
, autocontext
, var
->value
);
4700 else if (!strcasecmp(var
->name
, "ringtimeout")) {
4701 if (sscanf(var
->value
, "%u", &station
->ring_timeout
) != 1) {
4702 ast_log(LOG_WARNING
, "Invalid ringtimeout '%s' specified for station '%s'\n",
4703 var
->value
, station
->name
);
4704 station
->ring_timeout
= 0;
4706 } else if (!strcasecmp(var
->name
, "ringdelay")) {
4707 if (sscanf(var
->value
, "%u", &station
->ring_delay
) != 1) {
4708 ast_log(LOG_WARNING
, "Invalid ringdelay '%s' specified for station '%s'\n",
4709 var
->value
, station
->name
);
4710 station
->ring_delay
= 0;
4712 } else if (!strcasecmp(var
->name
, "hold")) {
4713 if (!strcasecmp(var
->value
, "private"))
4714 station
->hold_access
= SLA_HOLD_PRIVATE
;
4715 else if (!strcasecmp(var
->value
, "open"))
4716 station
->hold_access
= SLA_HOLD_OPEN
;
4718 ast_log(LOG_WARNING
, "Invalid value '%s' for hold on station %s\n",
4719 var
->value
, station
->name
);
4722 } else if (strcasecmp(var
->name
, "type") && strcasecmp(var
->name
, "device")) {
4723 ast_log(LOG_ERROR
, "Invalid option '%s' specified at line %d of %s!\n",
4724 var
->name
, var
->lineno
, SLA_CONFIG_FILE
);
4728 if (!ast_strlen_zero(station
->autocontext
)) {
4729 struct ast_context
*context
;
4730 struct sla_trunk_ref
*trunk_ref
;
4731 context
= ast_context_find_or_create(NULL
, station
->autocontext
, sla_registrar
);
4733 ast_log(LOG_ERROR
, "Failed to automatically find or create "
4734 "context '%s' for SLA!\n", station
->autocontext
);
4735 destroy_station(station
);
4738 /* The extension for when the handset goes off-hook.
4739 * exten => station1,1,SLAStation(station1) */
4740 if (ast_add_extension2(context
, 0 /* don't replace */, station
->name
, 1,
4741 NULL
, NULL
, slastation_app
, ast_strdup(station
->name
), ast_free
, sla_registrar
)) {
4742 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4743 "for trunk '%s'!\n", station
->name
);
4744 destroy_station(station
);
4747 AST_RWLIST_RDLOCK(&sla_trunks
);
4748 AST_LIST_TRAVERSE(&station
->trunks
, trunk_ref
, entry
) {
4749 char exten
[AST_MAX_EXTENSION
];
4750 char hint
[AST_MAX_APP
];
4751 snprintf(exten
, sizeof(exten
), "%s_%s", station
->name
, trunk_ref
->trunk
->name
);
4752 snprintf(hint
, sizeof(hint
), "SLA:%s", exten
);
4753 /* Extension for this line button
4754 * exten => station1_line1,1,SLAStation(station1_line1) */
4755 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, 1,
4756 NULL
, NULL
, slastation_app
, ast_strdup(exten
), ast_free
, sla_registrar
)) {
4757 ast_log(LOG_ERROR
, "Failed to automatically create extension "
4758 "for trunk '%s'!\n", station
->name
);
4759 destroy_station(station
);
4762 /* Hint for this line button
4763 * exten => station1_line1,hint,SLA:station1_line1 */
4764 if (ast_add_extension2(context
, 0 /* don't replace */, exten
, PRIORITY_HINT
,
4765 NULL
, NULL
, hint
, NULL
, NULL
, sla_registrar
)) {
4766 ast_log(LOG_ERROR
, "Failed to automatically create hint "
4767 "for trunk '%s'!\n", station
->name
);
4768 destroy_station(station
);
4772 AST_RWLIST_UNLOCK(&sla_trunks
);
4775 AST_RWLIST_WRLOCK(&sla_stations
);
4776 AST_RWLIST_INSERT_TAIL(&sla_stations
, station
, entry
);
4777 AST_RWLIST_UNLOCK(&sla_stations
);
4782 static int sla_load_config(void)
4784 struct ast_config
*cfg
;
4785 const char *cat
= NULL
;
4789 ast_mutex_init(&sla
.lock
);
4790 ast_cond_init(&sla
.cond
, NULL
);
4792 if (!(cfg
= ast_config_load(SLA_CONFIG_FILE
)))
4793 return 0; /* Treat no config as normal */
4795 if ((val
= ast_variable_retrieve(cfg
, "general", "attemptcallerid")))
4796 sla
.attempt_callerid
= ast_true(val
);
4798 while ((cat
= ast_category_browse(cfg
, cat
)) && !res
) {
4800 if (!strcasecmp(cat
, "general"))
4802 if (!(type
= ast_variable_retrieve(cfg
, cat
, "type"))) {
4803 ast_log(LOG_WARNING
, "Invalid entry in %s defined with no type!\n",
4807 if (!strcasecmp(type
, "trunk"))
4808 res
= sla_build_trunk(cfg
, cat
);
4809 else if (!strcasecmp(type
, "station"))
4810 res
= sla_build_station(cfg
, cat
);
4812 ast_log(LOG_WARNING
, "Entry in %s defined with invalid type '%s'!\n",
4813 SLA_CONFIG_FILE
, type
);
4817 ast_config_destroy(cfg
);
4819 if (!AST_LIST_EMPTY(&sla_stations
) || !AST_LIST_EMPTY(&sla_stations
))
4820 ast_pthread_create(&sla
.thread
, NULL
, sla_thread
, NULL
);
4825 static int load_config(int reload
)
4829 load_config_meetme();
4831 res
= sla_load_config();
4836 static int unload_module(void)
4840 ast_cli_unregister_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4841 res
= ast_manager_unregister("MeetmeMute");
4842 res
|= ast_manager_unregister("MeetmeUnmute");
4843 res
|= ast_unregister_application(app3
);
4844 res
|= ast_unregister_application(app2
);
4845 res
|= ast_unregister_application(app
);
4846 res
|= ast_unregister_application(slastation_app
);
4847 res
|= ast_unregister_application(slatrunk_app
);
4849 ast_devstate_prov_del("Meetme");
4850 ast_devstate_prov_del("SLA");
4852 ast_module_user_hangup_all();
4859 static int load_module(void)
4863 res
|= load_config(0);
4865 ast_cli_register_multiple(cli_meetme
, ARRAY_LEN(cli_meetme
));
4866 res
|= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL
,
4867 action_meetmemute
, "Mute a Meetme user");
4868 res
|= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL
,
4869 action_meetmeunmute
, "Unmute a Meetme user");
4870 res
|= ast_register_application(app3
, admin_exec
, synopsis3
, descrip3
);
4871 res
|= ast_register_application(app2
, count_exec
, synopsis2
, descrip2
);
4872 res
|= ast_register_application(app
, conf_exec
, synopsis
, descrip
);
4873 res
|= ast_register_application(slastation_app
, sla_station_exec
,
4874 slastation_synopsis
, slastation_desc
);
4875 res
|= ast_register_application(slatrunk_app
, sla_trunk_exec
,
4876 slatrunk_synopsis
, slatrunk_desc
);
4878 res
|= ast_devstate_prov_add("Meetme", meetmestate
);
4879 res
|= ast_devstate_prov_add("SLA", sla_state
);
4884 static int reload(void)
4886 return load_config(1);
4889 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "MeetMe conference bridge",
4890 .load
= load_module
,
4891 .unload
= unload_module
,