00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 262747 $")
00039
00040 #include <dahdi/user.h>
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/config.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/dsp.h"
00050 #include "asterisk/musiconhold.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/translate.h"
00056 #include "asterisk/ulaw.h"
00057 #include "asterisk/astobj2.h"
00058 #include "asterisk/devicestate.h"
00059 #include "asterisk/dial.h"
00060 #include "asterisk/causes.h"
00061 #include "asterisk/paths.h"
00062
00063 #include "enter.h"
00064 #include "leave.h"
00065
00066 #define CONFIG_FILE_NAME "meetme.conf"
00067 #define SLA_CONFIG_FILE "sla.conf"
00068
00069
00070 #define DEFAULT_AUDIO_BUFFERS 32
00071
00072
00073 #define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
00074
00075 enum {
00076 ADMINFLAG_MUTED = (1 << 1),
00077 ADMINFLAG_SELFMUTED = (1 << 2),
00078 ADMINFLAG_KICKME = (1 << 3),
00079
00080 ADMINFLAG_T_REQUEST = (1 << 4),
00081 };
00082
00083 #define MEETME_DELAYDETECTTALK 300
00084 #define MEETME_DELAYDETECTENDTALK 1000
00085
00086 #define AST_FRAME_BITS 32
00087
00088 enum volume_action {
00089 VOL_UP,
00090 VOL_DOWN
00091 };
00092
00093 enum entrance_sound {
00094 ENTER,
00095 LEAVE
00096 };
00097
00098 enum recording_state {
00099 MEETME_RECORD_OFF,
00100 MEETME_RECORD_STARTED,
00101 MEETME_RECORD_ACTIVE,
00102 MEETME_RECORD_TERMINATE
00103 };
00104
00105 #define CONF_SIZE 320
00106
00107 enum {
00108
00109 CONFFLAG_ADMIN = (1 << 0),
00110
00111 CONFFLAG_MONITOR = (1 << 1),
00112
00113 CONFFLAG_KEYEXIT = (1 << 2),
00114
00115 CONFFLAG_STARMENU = (1 << 3),
00116
00117 CONFFLAG_TALKER = (1 << 4),
00118
00119 CONFFLAG_QUIET = (1 << 5),
00120
00121
00122 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00123
00124 CONFFLAG_AGI = (1 << 7),
00125
00126 CONFFLAG_MOH = (1 << 8),
00127
00128 CONFFLAG_MARKEDEXIT = (1 << 9),
00129
00130 CONFFLAG_WAITMARKED = (1 << 10),
00131
00132 CONFFLAG_EXIT_CONTEXT = (1 << 11),
00133
00134 CONFFLAG_MARKEDUSER = (1 << 12),
00135
00136 CONFFLAG_INTROUSER = (1 << 13),
00137
00138 CONFFLAG_RECORDCONF = (1<< 14),
00139
00140 CONFFLAG_MONITORTALKER = (1 << 15),
00141 CONFFLAG_DYNAMIC = (1 << 16),
00142 CONFFLAG_DYNAMICPIN = (1 << 17),
00143 CONFFLAG_EMPTY = (1 << 18),
00144 CONFFLAG_EMPTYNOPIN = (1 << 19),
00145 CONFFLAG_ALWAYSPROMPT = (1 << 20),
00146
00147 CONFFLAG_OPTIMIZETALKER = (1 << 21),
00148
00149
00150 CONFFLAG_NOONLYPERSON = (1 << 22),
00151
00152
00153 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00154
00155 CONFFLAG_STARTMUTED = (1 << 24),
00156
00157 CONFFLAG_PASS_DTMF = (1 << 25),
00158 CONFFLAG_SLA_STATION = (1 << 26),
00159 CONFFLAG_SLA_TRUNK = (1 << 27),
00160
00161 CONFFLAG_KICK_CONTINUE = (1 << 28),
00162 CONFFLAG_DURATION_STOP = (1 << 29),
00163 CONFFLAG_DURATION_LIMIT = (1 << 30),
00164
00165 CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00166 };
00167
00168 enum {
00169 OPT_ARG_WAITMARKED = 0,
00170 OPT_ARG_EXITKEYS = 1,
00171 OPT_ARG_DURATION_STOP = 2,
00172 OPT_ARG_DURATION_LIMIT = 3,
00173 OPT_ARG_MOH_CLASS = 4,
00174 OPT_ARG_ARRAY_SIZE = 5,
00175 };
00176
00177 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
00178 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
00179 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
00180 AST_APP_OPTION('b', CONFFLAG_AGI ),
00181 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
00182 AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
00183 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
00184 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
00185 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
00186 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
00187 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
00188 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
00189 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
00190 AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ),
00191 AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
00192 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
00193 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
00194 AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ),
00195 AST_APP_OPTION('q', CONFFLAG_QUIET ),
00196 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
00197 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
00198 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
00199 AST_APP_OPTION('l', CONFFLAG_MONITOR ),
00200 AST_APP_OPTION('t', CONFFLAG_TALKER ),
00201 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
00202 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
00203 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
00204 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
00205 AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP),
00206 AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
00207 END_OPTIONS );
00208
00209 static const char *app = "MeetMe";
00210 static const char *app2 = "MeetMeCount";
00211 static const char *app3 = "MeetMeAdmin";
00212 static const char *app4 = "MeetMeChannelAdmin";
00213 static const char *slastation_app = "SLAStation";
00214 static const char *slatrunk_app = "SLATrunk";
00215
00216 static const char *synopsis = "MeetMe conference bridge";
00217 static const char *synopsis2 = "MeetMe participant count";
00218 static const char *synopsis3 = "MeetMe conference Administration";
00219 static const char *synopsis4 = "MeetMe conference Administration (channel specific)";
00220 static const char *slastation_synopsis = "Shared Line Appearance Station";
00221 static const char *slatrunk_synopsis = "Shared Line Appearance Trunk";
00222
00223
00224 static int rt_schedule;
00225 static int fuzzystart;
00226 static int earlyalert;
00227 static int endalert;
00228
00229
00230 static int rt_log_members;
00231
00232 static const char *descrip =
00233 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
00234 "conference. If the conference number is omitted, the user will be prompted\n"
00235 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
00236 "is specified, by pressing '#'.\n"
00237 "Please note: The DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n"
00238 " must be present for conferencing to operate properly. In addition, the chan_dahdi\n"
00239 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
00240 "The option string may contain zero or more of the following characters:\n"
00241 " 'a' -- set admin mode\n"
00242 " 'A' -- set marked mode\n"
00243 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
00244 " Default: conf-background.agi (Note: This does not work with\n"
00245 " non-DAHDI channels in the same conference)\n"
00246 " 'c' -- announce user(s) count on joining a conference\n"
00247 " 'C' -- continue in dialplan when kicked out of conference\n"
00248 " 'd' -- dynamically add conference\n"
00249 " 'D' -- dynamically add conference, prompting for a PIN\n"
00250 " 'e' -- select an empty conference\n"
00251 " 'E' -- select an empty pinless conference\n"
00252 " 'F' -- Pass DTMF through the conference.\n"
00253 " 'i' -- announce user join/leave with review\n"
00254 " 'I' -- announce user join/leave without review\n"
00255 " 'l' -- set listen only mode (Listen only, no talking)\n"
00256 " 'm' -- set initially muted\n"
00257 " 'M[(<class>)]'\n"
00258 " -- enable music on hold when the conference has a single caller.\n"
00259 " Optionally, specify a musiconhold class to use. If one is not\n"
00260 " provided, it will use the channel's currently set music class,\n"
00261 " or \"default\".\n"
00262 " 'o' -- set talker optimization - treats talkers who aren't speaking as\n"
00263 " being muted, meaning (a) No encode is done on transmission and\n"
00264 " (b) Received audio that is not registered as talking is omitted\n"
00265 " causing no buildup in background noise\n"
00266 " 'p[(<keys>)]'\n"
00267 " -- allow user to exit the conference by pressing '#' (default)\n"
00268 " or any of the defined keys. If keys contain '*' this will override\n"
00269 " option 's'. The key used is set to channel variable MEETME_EXIT_KEY.\n"
00270 " 'P' -- always prompt for the pin even if it is specified\n"
00271 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
00272 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
00273 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
00274 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
00275 " wav.\n"
00276 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
00277 " 't' -- set talk only mode. (Talk only, no listening)\n"
00278 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
00279 " 'w[(<secs>)]'\n"
00280 " -- wait until the marked user enters the conference\n"
00281 " 'x' -- close the conference when last marked user exits\n"
00282 " 'X' -- allow user to exit the conference by entering a valid single\n"
00283 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
00284 " if that variable is not defined.\n"
00285 " '1' -- do not play message when first person enters\n"
00286 " 'S(x)' -- Kick the user 'x' seconds *after* he entered into the conference.\n"
00287 " 'L(x[:y][:z])' - Limit the conference to 'x' ms. Play a warning when 'y' ms are\n"
00288 " left. Repeat the warning every 'z' ms. The following special\n"
00289 " variables can be used with this option:\n"
00290 " * CONF_LIMIT_TIMEOUT_FILE File to play when time is up.\n"
00291 " * CONF_LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n"
00292 " The default is to say the time remaining.\n"
00293 "";
00294
00295 static const char *descrip2 =
00296 " MeetMeCount(confno[,var]): Plays back the number of users in the specified\n"
00297 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
00298 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
00299 "the channel, unless priority n+1 exists, in which case priority progress will\n"
00300 "continue.\n"
00301 "";
00302
00303 static const char *descrip3 =
00304 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
00305 " 'e' -- Eject last user that joined\n"
00306 " 'k' -- Kick one user out of conference\n"
00307 " 'K' -- Kick all users out of conference\n"
00308 " 'l' -- Unlock conference\n"
00309 " 'L' -- Lock conference\n"
00310 " 'm' -- Unmute one user\n"
00311 " 'M' -- Mute one user\n"
00312 " 'n' -- Unmute all users in the conference\n"
00313 " 'N' -- Mute all non-admin users in the conference\n"
00314 " 'r' -- Reset one user's volume settings\n"
00315 " 'R' -- Reset all users volume settings\n"
00316 " 's' -- Lower entire conference speaking volume\n"
00317 " 'S' -- Raise entire conference speaking volume\n"
00318 " 't' -- Lower one user's talk volume\n"
00319 " 'T' -- Raise one user's talk volume\n"
00320 " 'u' -- Lower one user's listen volume\n"
00321 " 'U' -- Raise one user's listen volume\n"
00322 " 'v' -- Lower entire conference listening volume\n"
00323 " 'V' -- Raise entire conference listening volume\n"
00324 "";
00325
00326 static const char *descrip4 =
00327 " MeetMeChannelAdmin(channel,command): Run admin command for a specific\n"
00328 "channel in any coference.\n"
00329 " 'k' -- Kick the specified user out of the conference he is in\n"
00330 " 'm' -- Unmute the specified user\n"
00331 " 'M' -- Mute the specified user\n"
00332 "";
00333
00334 static const char *slastation_desc =
00335 " SLAStation(<station name>):\n"
00336 "This application should be executed by an SLA station. The argument depends\n"
00337 "on how the call was initiated. If the phone was just taken off hook, then\n"
00338 "the argument \"station\" should be just the station name. If the call was\n"
00339 "initiated by pressing a line key, then the station name should be preceded\n"
00340 "by an underscore and the trunk name associated with that line button.\n"
00341 "For example: \"station1_line1\"."
00342 " On exit, this application will set the variable SLASTATION_STATUS to\n"
00343 "one of the following values:\n"
00344 " FAILURE | CONGESTION | SUCCESS\n"
00345 "";
00346
00347 static const char *slatrunk_desc =
00348 " SLATrunk(<trunk name>[,options]):\n"
00349 "This application should be executed by an SLA trunk on an inbound call.\n"
00350 "The channel calling this application should correspond to the SLA trunk\n"
00351 "with the name \"trunk\" that is being passed as an argument.\n"
00352 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
00353 "one of the following values:\n"
00354 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
00355 " The available options are:\n"
00356 " M[(<class>)] - Play back the specified MOH class instead of ringing\n"
00357 "";
00358
00359 #define MAX_CONFNUM 80
00360 #define MAX_PIN 80
00361
00362
00363 #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
00364
00365 enum announcetypes {
00366 CONF_HASJOIN,
00367 CONF_HASLEFT
00368 };
00369
00370 struct announce_listitem {
00371 AST_LIST_ENTRY(announce_listitem) entry;
00372 char namerecloc[PATH_MAX];
00373 char language[MAX_LANGUAGE];
00374 struct ast_channel *confchan;
00375 int confusers;
00376 enum announcetypes announcetype;
00377 };
00378
00379
00380 struct ast_conference {
00381 ast_mutex_t playlock;
00382 ast_mutex_t listenlock;
00383 char confno[MAX_CONFNUM];
00384 struct ast_channel *chan;
00385 struct ast_channel *lchan;
00386 int fd;
00387 int dahdiconf;
00388 int users;
00389 int markedusers;
00390 int maxusers;
00391 int endalert;
00392 time_t start;
00393 int refcount;
00394 enum recording_state recording:2;
00395 unsigned int isdynamic:1;
00396 unsigned int locked:1;
00397 pthread_t recordthread;
00398 ast_mutex_t recordthreadlock;
00399 pthread_attr_t attr;
00400 char *recordingfilename;
00401 char *recordingformat;
00402 char pin[MAX_PIN];
00403 char pinadmin[MAX_PIN];
00404 char uniqueid[32];
00405 long endtime;
00406 struct ast_frame *transframe[32];
00407 struct ast_frame *origframe;
00408 struct ast_trans_pvt *transpath[32];
00409 AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
00410 AST_LIST_ENTRY(ast_conference) list;
00411
00412 pthread_t announcethread;
00413 ast_mutex_t announcethreadlock;
00414 unsigned int announcethread_stop:1;
00415 ast_cond_t announcelist_addition;
00416 AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist;
00417 ast_mutex_t announcelistlock;
00418 };
00419
00420 static AST_LIST_HEAD_STATIC(confs, ast_conference);
00421
00422 static unsigned int conf_map[1024] = {0, };
00423
00424 struct volume {
00425 int desired;
00426 int actual;
00427 };
00428
00429
00430 struct ast_conf_user {
00431 int user_no;
00432 int userflags;
00433 int adminflags;
00434 struct ast_channel *chan;
00435 int talking;
00436 int dahdichannel;
00437 char usrvalue[50];
00438 char namerecloc[PATH_MAX];
00439 time_t jointime;
00440 time_t kicktime;
00441 struct timeval start_time;
00442 long timelimit;
00443 long play_warning;
00444 long warning_freq;
00445 const char *warning_sound;
00446 const char *end_sound;
00447 struct volume talk;
00448 struct volume listen;
00449 AST_LIST_ENTRY(ast_conf_user) list;
00450 };
00451
00452 enum sla_which_trunk_refs {
00453 ALL_TRUNK_REFS,
00454 INACTIVE_TRUNK_REFS,
00455 };
00456
00457 enum sla_trunk_state {
00458 SLA_TRUNK_STATE_IDLE,
00459 SLA_TRUNK_STATE_RINGING,
00460 SLA_TRUNK_STATE_UP,
00461 SLA_TRUNK_STATE_ONHOLD,
00462 SLA_TRUNK_STATE_ONHOLD_BYME,
00463 };
00464
00465 enum sla_hold_access {
00466
00467
00468 SLA_HOLD_OPEN,
00469
00470
00471 SLA_HOLD_PRIVATE,
00472 };
00473
00474 struct sla_trunk_ref;
00475
00476 struct sla_station {
00477 AST_RWLIST_ENTRY(sla_station) entry;
00478 AST_DECLARE_STRING_FIELDS(
00479 AST_STRING_FIELD(name);
00480 AST_STRING_FIELD(device);
00481 AST_STRING_FIELD(autocontext);
00482 );
00483 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
00484 struct ast_dial *dial;
00485
00486
00487
00488 unsigned int ring_timeout;
00489
00490
00491
00492 unsigned int ring_delay;
00493
00494
00495 unsigned int hold_access:1;
00496
00497 unsigned int ref_count;
00498 };
00499
00500 struct sla_station_ref {
00501 AST_LIST_ENTRY(sla_station_ref) entry;
00502 struct sla_station *station;
00503 };
00504
00505 struct sla_trunk {
00506 AST_RWLIST_ENTRY(sla_trunk) entry;
00507 AST_DECLARE_STRING_FIELDS(
00508 AST_STRING_FIELD(name);
00509 AST_STRING_FIELD(device);
00510 AST_STRING_FIELD(autocontext);
00511 );
00512 AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
00513
00514 unsigned int num_stations;
00515
00516 unsigned int active_stations;
00517
00518 unsigned int hold_stations;
00519 struct ast_channel *chan;
00520 unsigned int ring_timeout;
00521
00522
00523 unsigned int barge_disabled:1;
00524
00525
00526 unsigned int hold_access:1;
00527
00528
00529 unsigned int on_hold:1;
00530
00531 unsigned int ref_count;
00532 };
00533
00534 struct sla_trunk_ref {
00535 AST_LIST_ENTRY(sla_trunk_ref) entry;
00536 struct sla_trunk *trunk;
00537 enum sla_trunk_state state;
00538 struct ast_channel *chan;
00539
00540
00541
00542 unsigned int ring_timeout;
00543
00544
00545
00546 unsigned int ring_delay;
00547 };
00548
00549 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
00550 static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
00551
00552 static const char sla_registrar[] = "SLA";
00553
00554
00555 enum sla_event_type {
00556
00557 SLA_EVENT_HOLD,
00558
00559 SLA_EVENT_DIAL_STATE,
00560
00561 SLA_EVENT_RINGING_TRUNK,
00562
00563 SLA_EVENT_RELOAD,
00564
00565 SLA_EVENT_CHECK_RELOAD,
00566 };
00567
00568 struct sla_event {
00569 enum sla_event_type type;
00570 struct sla_station *station;
00571 struct sla_trunk_ref *trunk_ref;
00572 AST_LIST_ENTRY(sla_event) entry;
00573 };
00574
00575
00576
00577 struct sla_failed_station {
00578 struct sla_station *station;
00579 struct timeval last_try;
00580 AST_LIST_ENTRY(sla_failed_station) entry;
00581 };
00582
00583
00584 struct sla_ringing_trunk {
00585 struct sla_trunk *trunk;
00586
00587 struct timeval ring_begin;
00588 AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
00589 AST_LIST_ENTRY(sla_ringing_trunk) entry;
00590 };
00591
00592 enum sla_station_hangup {
00593 SLA_STATION_HANGUP_NORMAL,
00594 SLA_STATION_HANGUP_TIMEOUT,
00595 };
00596
00597
00598 struct sla_ringing_station {
00599 struct sla_station *station;
00600
00601 struct timeval ring_begin;
00602 AST_LIST_ENTRY(sla_ringing_station) entry;
00603 };
00604
00605
00606
00607
00608 static struct {
00609
00610 pthread_t thread;
00611 ast_cond_t cond;
00612 ast_mutex_t lock;
00613 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
00614 AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
00615 AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
00616 AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
00617 unsigned int stop:1;
00618
00619
00620 unsigned int attempt_callerid:1;
00621
00622 unsigned int reload:1;
00623 } sla = {
00624 .thread = AST_PTHREADT_NULL,
00625 };
00626
00627
00628
00629 static int audio_buffers;
00630
00631
00632
00633
00634
00635
00636
00637 static char const gain_map[] = {
00638 -15,
00639 -13,
00640 -10,
00641 -6,
00642 0,
00643 0,
00644 0,
00645 6,
00646 10,
00647 13,
00648 15,
00649 };
00650
00651
00652 static int admin_exec(struct ast_channel *chan, void *data);
00653 static void *recordthread(void *args);
00654
00655 static char *istalking(int x)
00656 {
00657 if (x > 0)
00658 return "(talking)";
00659 else if (x < 0)
00660 return "(unmonitored)";
00661 else
00662 return "(not talking)";
00663 }
00664
00665 static int careful_write(int fd, unsigned char *data, int len, int block)
00666 {
00667 int res;
00668 int x;
00669
00670 while (len) {
00671 if (block) {
00672 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00673 res = ioctl(fd, DAHDI_IOMUX, &x);
00674 } else
00675 res = 0;
00676 if (res >= 0)
00677 res = write(fd, data, len);
00678 if (res < 1) {
00679 if (errno != EAGAIN) {
00680 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00681 return -1;
00682 } else
00683 return 0;
00684 }
00685 len -= res;
00686 data += res;
00687 }
00688
00689 return 0;
00690 }
00691
00692 static int set_talk_volume(struct ast_conf_user *user, int volume)
00693 {
00694 char gain_adjust;
00695
00696
00697
00698
00699 gain_adjust = gain_map[volume + 5];
00700
00701 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00702 }
00703
00704 static int set_listen_volume(struct ast_conf_user *user, int volume)
00705 {
00706 char gain_adjust;
00707
00708
00709
00710
00711 gain_adjust = gain_map[volume + 5];
00712
00713 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00714 }
00715
00716 static void tweak_volume(struct volume *vol, enum volume_action action)
00717 {
00718 switch (action) {
00719 case VOL_UP:
00720 switch (vol->desired) {
00721 case 5:
00722 break;
00723 case 0:
00724 vol->desired = 2;
00725 break;
00726 case -2:
00727 vol->desired = 0;
00728 break;
00729 default:
00730 vol->desired++;
00731 break;
00732 }
00733 break;
00734 case VOL_DOWN:
00735 switch (vol->desired) {
00736 case -5:
00737 break;
00738 case 2:
00739 vol->desired = 0;
00740 break;
00741 case 0:
00742 vol->desired = -2;
00743 break;
00744 default:
00745 vol->desired--;
00746 break;
00747 }
00748 }
00749 }
00750
00751 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
00752 {
00753 tweak_volume(&user->talk, action);
00754
00755
00756
00757 if (!set_talk_volume(user, user->talk.desired))
00758 user->talk.actual = 0;
00759 else
00760 user->talk.actual = user->talk.desired;
00761 }
00762
00763 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
00764 {
00765 tweak_volume(&user->listen, action);
00766
00767
00768
00769 if (!set_listen_volume(user, user->listen.desired))
00770 user->listen.actual = 0;
00771 else
00772 user->listen.actual = user->listen.desired;
00773 }
00774
00775 static void reset_volumes(struct ast_conf_user *user)
00776 {
00777 signed char zero_volume = 0;
00778
00779 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00780 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00781 }
00782
00783 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
00784 {
00785 unsigned char *data;
00786 int len;
00787 int res = -1;
00788
00789 if (!ast_check_hangup(chan))
00790 res = ast_autoservice_start(chan);
00791
00792 AST_LIST_LOCK(&confs);
00793
00794 switch(sound) {
00795 case ENTER:
00796 data = enter;
00797 len = sizeof(enter);
00798 break;
00799 case LEAVE:
00800 data = leave;
00801 len = sizeof(leave);
00802 break;
00803 default:
00804 data = NULL;
00805 len = 0;
00806 }
00807 if (data) {
00808 careful_write(conf->fd, data, len, 1);
00809 }
00810
00811 AST_LIST_UNLOCK(&confs);
00812
00813 if (!res)
00814 ast_autoservice_stop(chan);
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
00832 {
00833 struct ast_conference *cnf;
00834 struct dahdi_confinfo dahdic = { 0, };
00835 int confno_int = 0;
00836
00837 AST_LIST_LOCK(&confs);
00838
00839 AST_LIST_TRAVERSE(&confs, cnf, list) {
00840 if (!strcmp(confno, cnf->confno))
00841 break;
00842 }
00843
00844 if (cnf || (!make && !dynamic))
00845 goto cnfout;
00846
00847
00848 if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00849 goto cnfout;
00850
00851 ast_mutex_init(&cnf->playlock);
00852 ast_mutex_init(&cnf->listenlock);
00853 cnf->recordthread = AST_PTHREADT_NULL;
00854 ast_mutex_init(&cnf->recordthreadlock);
00855 cnf->announcethread = AST_PTHREADT_NULL;
00856 ast_mutex_init(&cnf->announcethreadlock);
00857 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00858 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00859 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00860 ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
00861
00862
00863 dahdic.confno = -1;
00864 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00865 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
00866 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
00867 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00868 if (cnf->fd >= 0)
00869 close(cnf->fd);
00870 ast_free(cnf);
00871 cnf = NULL;
00872 goto cnfout;
00873 }
00874
00875 cnf->dahdiconf = dahdic.confno;
00876
00877
00878 cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
00879 if (cnf->chan) {
00880 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00881 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00882 dahdic.chan = 0;
00883 dahdic.confno = cnf->dahdiconf;
00884 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00885 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
00886 ast_log(LOG_WARNING, "Error setting conference\n");
00887 if (cnf->chan)
00888 ast_hangup(cnf->chan);
00889 else
00890 close(cnf->fd);
00891
00892 ast_free(cnf);
00893 cnf = NULL;
00894 goto cnfout;
00895 }
00896 }
00897
00898
00899 cnf->start = time(NULL);
00900 cnf->maxusers = 0x7fffffff;
00901 cnf->isdynamic = dynamic ? 1 : 0;
00902 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
00903 AST_LIST_INSERT_HEAD(&confs, cnf, list);
00904
00905
00906 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00907 conf_map[confno_int] = 1;
00908
00909 cnfout:
00910 if (cnf)
00911 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00912
00913 AST_LIST_UNLOCK(&confs);
00914
00915 return cnf;
00916 }
00917
00918
00919 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
00920 {
00921 static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00922
00923 int len = strlen(word);
00924 int which = 0;
00925 struct ast_conference *cnf = NULL;
00926 struct ast_conf_user *usr = NULL;
00927 char *confno = NULL;
00928 char usrno[50] = "";
00929 char *myline, *ret = NULL;
00930
00931 if (pos == 1) {
00932 return ast_cli_complete(word, cmds, state);
00933 } else if (pos == 2) {
00934 AST_LIST_LOCK(&confs);
00935 AST_LIST_TRAVERSE(&confs, cnf, list) {
00936 if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00937 ret = cnf->confno;
00938 break;
00939 }
00940 }
00941 ret = ast_strdup(ret);
00942 AST_LIST_UNLOCK(&confs);
00943 return ret;
00944 } else if (pos == 3) {
00945
00946 if (strstr(line, "mute") || strstr(line, "kick")) {
00947 if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
00948 return ast_strdup("all");
00949 which++;
00950 AST_LIST_LOCK(&confs);
00951
00952
00953 myline = ast_strdupa(line);
00954 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00955 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00956 ;
00957 }
00958
00959 AST_LIST_TRAVERSE(&confs, cnf, list) {
00960 if (!strcmp(confno, cnf->confno))
00961 break;
00962 }
00963
00964 if (cnf) {
00965
00966 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
00967 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00968 if (!strncasecmp(word, usrno, len) && ++which > state)
00969 break;
00970 }
00971 }
00972 AST_LIST_UNLOCK(&confs);
00973 return usr ? ast_strdup(usrno) : NULL;
00974 } else if (strstr(line, "list") && (state == 0))
00975 return ast_strdup("concise");
00976 }
00977
00978 return NULL;
00979 }
00980
00981 static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00982 {
00983
00984 struct ast_conference *cnf;
00985 struct ast_conf_user *user;
00986 int hr, min, sec;
00987 int i = 0, total = 0;
00988 time_t now;
00989 struct ast_str *cmdline = NULL;
00990 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
00991 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
00992
00993 switch (cmd) {
00994 case CLI_INIT:
00995 e->command = "meetme";
00996 e->usage =
00997 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
00998 " Executes a command for the conference or on a conferee\n";
00999 return NULL;
01000 case CLI_GENERATE:
01001 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01002 }
01003
01004 if (a->argc > 8)
01005 ast_cli(a->fd, "Invalid Arguments.\n");
01006
01007 for (i = 0; i < a->argc; i++) {
01008 if (strlen(a->argv[i]) > 100)
01009 ast_cli(a->fd, "Invalid Arguments.\n");
01010 }
01011
01012
01013 if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01014 return CLI_FAILURE;
01015 }
01016
01017 if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) {
01018
01019 int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise"));
01020 now = time(NULL);
01021 AST_LIST_LOCK(&confs);
01022 if (AST_LIST_EMPTY(&confs)) {
01023 if (!concise) {
01024 ast_cli(a->fd, "No active MeetMe conferences.\n");
01025 }
01026 AST_LIST_UNLOCK(&confs);
01027 ast_free(cmdline);
01028 return CLI_SUCCESS;
01029 }
01030 if (!concise) {
01031 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01032 }
01033 AST_LIST_TRAVERSE(&confs, cnf, list) {
01034 if (cnf->markedusers == 0) {
01035 ast_str_set(&cmdline, 0, "N/A ");
01036 } else {
01037 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01038 }
01039 hr = (now - cnf->start) / 3600;
01040 min = ((now - cnf->start) % 3600) / 60;
01041 sec = (now - cnf->start) % 60;
01042 if (!concise) {
01043 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01044 } else {
01045 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01046 cnf->confno,
01047 cnf->users,
01048 cnf->markedusers,
01049 hr, min, sec,
01050 cnf->isdynamic,
01051 cnf->locked);
01052 }
01053
01054 total += cnf->users;
01055 }
01056 AST_LIST_UNLOCK(&confs);
01057 if (!concise) {
01058 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01059 }
01060 ast_free(cmdline);
01061 return CLI_SUCCESS;
01062 }
01063 if (a->argc < 3) {
01064 ast_free(cmdline);
01065 return CLI_SHOWUSAGE;
01066 }
01067
01068 ast_str_set(&cmdline, 0, "%s", a->argv[2]);
01069 if (strstr(a->argv[1], "lock")) {
01070 if (strcmp(a->argv[1], "lock") == 0) {
01071
01072 ast_str_append(&cmdline, 0, ",L");
01073 } else {
01074
01075 ast_str_append(&cmdline, 0, ",l");
01076 }
01077 } else if (strstr(a->argv[1], "mute")) {
01078 if (a->argc < 4) {
01079 ast_free(cmdline);
01080 return CLI_SHOWUSAGE;
01081 }
01082 if (strcmp(a->argv[1], "mute") == 0) {
01083
01084 if (strcmp(a->argv[3], "all") == 0) {
01085 ast_str_append(&cmdline, 0, ",N");
01086 } else {
01087 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
01088 }
01089 } else {
01090
01091 if (strcmp(a->argv[3], "all") == 0) {
01092 ast_str_append(&cmdline, 0, ",n");
01093 } else {
01094 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01095 }
01096 }
01097 } else if (strcmp(a->argv[1], "kick") == 0) {
01098 if (a->argc < 4) {
01099 ast_free(cmdline);
01100 return CLI_SHOWUSAGE;
01101 }
01102 if (strcmp(a->argv[3], "all") == 0) {
01103
01104 ast_str_append(&cmdline, 0, ",K");
01105 } else {
01106
01107 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01108 }
01109 } else if (strcmp(a->argv[1], "list") == 0) {
01110 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01111
01112 if (AST_LIST_EMPTY(&confs)) {
01113 if (!concise) {
01114 ast_cli(a->fd, "No active conferences.\n");
01115 }
01116 ast_free(cmdline);
01117 return CLI_SUCCESS;
01118 }
01119
01120 AST_LIST_LOCK(&confs);
01121 AST_LIST_TRAVERSE(&confs, cnf, list) {
01122 if (strcmp(cnf->confno, a->argv[2]) == 0) {
01123 break;
01124 }
01125 }
01126 if (!cnf) {
01127 if (!concise)
01128 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01129 AST_LIST_UNLOCK(&confs);
01130 ast_free(cmdline);
01131 return CLI_SUCCESS;
01132 }
01133
01134 time(&now);
01135 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01136 hr = (now - user->jointime) / 3600;
01137 min = ((now - user->jointime) % 3600) / 60;
01138 sec = (now - user->jointime) % 60;
01139 if (!concise) {
01140 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01141 user->user_no,
01142 S_OR(user->chan->cid.cid_num, "<unknown>"),
01143 S_OR(user->chan->cid.cid_name, "<no name>"),
01144 user->chan->name,
01145 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01146 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01147 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01148 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01149 istalking(user->talking), hr, min, sec);
01150 } else {
01151 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01152 user->user_no,
01153 S_OR(user->chan->cid.cid_num, ""),
01154 S_OR(user->chan->cid.cid_name, ""),
01155 user->chan->name,
01156 user->userflags & CONFFLAG_ADMIN ? "1" : "",
01157 user->userflags & CONFFLAG_MONITOR ? "1" : "",
01158 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01159 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01160 user->talking, hr, min, sec);
01161 }
01162 }
01163 if (!concise) {
01164 ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01165 }
01166 AST_LIST_UNLOCK(&confs);
01167 ast_free(cmdline);
01168 return CLI_SUCCESS;
01169 } else {
01170 ast_free(cmdline);
01171 return CLI_SHOWUSAGE;
01172 }
01173
01174 ast_debug(1, "Cmdline: %s\n", cmdline->str);
01175
01176 admin_exec(NULL, cmdline->str);
01177 ast_free(cmdline);
01178
01179 return CLI_SUCCESS;
01180 }
01181
01182 static const char *sla_hold_str(unsigned int hold_access)
01183 {
01184 const char *hold = "Unknown";
01185
01186 switch (hold_access) {
01187 case SLA_HOLD_OPEN:
01188 hold = "Open";
01189 break;
01190 case SLA_HOLD_PRIVATE:
01191 hold = "Private";
01192 default:
01193 break;
01194 }
01195
01196 return hold;
01197 }
01198
01199 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01200 {
01201 const struct sla_trunk *trunk;
01202
01203 switch (cmd) {
01204 case CLI_INIT:
01205 e->command = "sla show trunks";
01206 e->usage =
01207 "Usage: sla show trunks\n"
01208 " This will list all trunks defined in sla.conf\n";
01209 return NULL;
01210 case CLI_GENERATE:
01211 return NULL;
01212 }
01213
01214 ast_cli(a->fd, "\n"
01215 "=============================================================\n"
01216 "=== Configured SLA Trunks ===================================\n"
01217 "=============================================================\n"
01218 "===\n");
01219 AST_RWLIST_RDLOCK(&sla_trunks);
01220 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01221 struct sla_station_ref *station_ref;
01222 char ring_timeout[16] = "(none)";
01223 if (trunk->ring_timeout)
01224 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01225 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01226 "=== Trunk Name: %s\n"
01227 "=== ==> Device: %s\n"
01228 "=== ==> AutoContext: %s\n"
01229 "=== ==> RingTimeout: %s\n"
01230 "=== ==> BargeAllowed: %s\n"
01231 "=== ==> HoldAccess: %s\n"
01232 "=== ==> Stations ...\n",
01233 trunk->name, trunk->device,
01234 S_OR(trunk->autocontext, "(none)"),
01235 ring_timeout,
01236 trunk->barge_disabled ? "No" : "Yes",
01237 sla_hold_str(trunk->hold_access));
01238 AST_RWLIST_RDLOCK(&sla_stations);
01239 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01240 ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
01241 AST_RWLIST_UNLOCK(&sla_stations);
01242 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01243 }
01244 AST_RWLIST_UNLOCK(&sla_trunks);
01245 ast_cli(a->fd, "=============================================================\n\n");
01246
01247 return CLI_SUCCESS;
01248 }
01249
01250 static const char *trunkstate2str(enum sla_trunk_state state)
01251 {
01252 #define S(e) case e: return # e;
01253 switch (state) {
01254 S(SLA_TRUNK_STATE_IDLE)
01255 S(SLA_TRUNK_STATE_RINGING)
01256 S(SLA_TRUNK_STATE_UP)
01257 S(SLA_TRUNK_STATE_ONHOLD)
01258 S(SLA_TRUNK_STATE_ONHOLD_BYME)
01259 }
01260 return "Uknown State";
01261 #undef S
01262 }
01263
01264 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01265 {
01266 const struct sla_station *station;
01267
01268 switch (cmd) {
01269 case CLI_INIT:
01270 e->command = "sla show stations";
01271 e->usage =
01272 "Usage: sla show stations\n"
01273 " This will list all stations defined in sla.conf\n";
01274 return NULL;
01275 case CLI_GENERATE:
01276 return NULL;
01277 }
01278
01279 ast_cli(a->fd, "\n"
01280 "=============================================================\n"
01281 "=== Configured SLA Stations =================================\n"
01282 "=============================================================\n"
01283 "===\n");
01284 AST_RWLIST_RDLOCK(&sla_stations);
01285 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01286 struct sla_trunk_ref *trunk_ref;
01287 char ring_timeout[16] = "(none)";
01288 char ring_delay[16] = "(none)";
01289 if (station->ring_timeout) {
01290 snprintf(ring_timeout, sizeof(ring_timeout),
01291 "%u", station->ring_timeout);
01292 }
01293 if (station->ring_delay) {
01294 snprintf(ring_delay, sizeof(ring_delay),
01295 "%u", station->ring_delay);
01296 }
01297 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01298 "=== Station Name: %s\n"
01299 "=== ==> Device: %s\n"
01300 "=== ==> AutoContext: %s\n"
01301 "=== ==> RingTimeout: %s\n"
01302 "=== ==> RingDelay: %s\n"
01303 "=== ==> HoldAccess: %s\n"
01304 "=== ==> Trunks ...\n",
01305 station->name, station->device,
01306 S_OR(station->autocontext, "(none)"),
01307 ring_timeout, ring_delay,
01308 sla_hold_str(station->hold_access));
01309 AST_RWLIST_RDLOCK(&sla_trunks);
01310 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01311 if (trunk_ref->ring_timeout) {
01312 snprintf(ring_timeout, sizeof(ring_timeout),
01313 "%u", trunk_ref->ring_timeout);
01314 } else
01315 strcpy(ring_timeout, "(none)");
01316 if (trunk_ref->ring_delay) {
01317 snprintf(ring_delay, sizeof(ring_delay),
01318 "%u", trunk_ref->ring_delay);
01319 } else
01320 strcpy(ring_delay, "(none)");
01321 ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
01322 "=== ==> State: %s\n"
01323 "=== ==> RingTimeout: %s\n"
01324 "=== ==> RingDelay: %s\n",
01325 trunk_ref->trunk->name,
01326 trunkstate2str(trunk_ref->state),
01327 ring_timeout, ring_delay);
01328 }
01329 AST_RWLIST_UNLOCK(&sla_trunks);
01330 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01331 "===\n");
01332 }
01333 AST_RWLIST_UNLOCK(&sla_stations);
01334 ast_cli(a->fd, "============================================================\n"
01335 "\n");
01336
01337 return CLI_SUCCESS;
01338 }
01339
01340 static struct ast_cli_entry cli_meetme[] = {
01341 AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
01342 AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
01343 AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
01344 };
01345
01346 static void conf_flush(int fd, struct ast_channel *chan)
01347 {
01348 int x;
01349
01350
01351
01352
01353 if (chan) {
01354 struct ast_frame *f;
01355
01356
01357
01358
01359 while (ast_waitfor(chan, 1)) {
01360 f = ast_read(chan);
01361 if (f)
01362 ast_frfree(f);
01363 else
01364 break;
01365 }
01366 }
01367
01368
01369 x = DAHDI_FLUSH_ALL;
01370 if (ioctl(fd, DAHDI_FLUSH, &x))
01371 ast_log(LOG_WARNING, "Error flushing channel\n");
01372
01373 }
01374
01375
01376
01377 static int conf_free(struct ast_conference *conf)
01378 {
01379 int x;
01380 struct announce_listitem *item;
01381
01382 AST_LIST_REMOVE(&confs, conf, list);
01383 manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01384
01385 if (conf->recording == MEETME_RECORD_ACTIVE) {
01386 conf->recording = MEETME_RECORD_TERMINATE;
01387 AST_LIST_UNLOCK(&confs);
01388 while (1) {
01389 usleep(1);
01390 AST_LIST_LOCK(&confs);
01391 if (conf->recording == MEETME_RECORD_OFF)
01392 break;
01393 AST_LIST_UNLOCK(&confs);
01394 }
01395 }
01396
01397 for (x = 0; x < AST_FRAME_BITS; x++) {
01398 if (conf->transframe[x])
01399 ast_frfree(conf->transframe[x]);
01400 if (conf->transpath[x])
01401 ast_translator_free_path(conf->transpath[x]);
01402 }
01403 if (conf->announcethread != AST_PTHREADT_NULL) {
01404 ast_mutex_lock(&conf->announcelistlock);
01405 conf->announcethread_stop = 1;
01406 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01407 ast_cond_signal(&conf->announcelist_addition);
01408 ast_mutex_unlock(&conf->announcelistlock);
01409 pthread_join(conf->announcethread, NULL);
01410
01411 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01412 ast_filedelete(item->namerecloc, NULL);
01413 ao2_ref(item, -1);
01414 }
01415 ast_mutex_destroy(&conf->announcelistlock);
01416 }
01417 if (conf->origframe)
01418 ast_frfree(conf->origframe);
01419 if (conf->lchan)
01420 ast_hangup(conf->lchan);
01421 if (conf->chan)
01422 ast_hangup(conf->chan);
01423 if (conf->fd >= 0)
01424 close(conf->fd);
01425 if (conf->recordingfilename) {
01426 ast_free(conf->recordingfilename);
01427 }
01428 if (conf->recordingformat) {
01429 ast_free(conf->recordingformat);
01430 }
01431 ast_mutex_destroy(&conf->playlock);
01432 ast_mutex_destroy(&conf->listenlock);
01433 ast_mutex_destroy(&conf->recordthreadlock);
01434 ast_mutex_destroy(&conf->announcethreadlock);
01435 ast_free(conf);
01436
01437 return 0;
01438 }
01439
01440 static void conf_queue_dtmf(const struct ast_conference *conf,
01441 const struct ast_conf_user *sender, struct ast_frame *f)
01442 {
01443 struct ast_conf_user *user;
01444
01445 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01446 if (user == sender)
01447 continue;
01448 if (ast_write(user->chan, f) < 0)
01449 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01450 }
01451 }
01452
01453 static void sla_queue_event_full(enum sla_event_type type,
01454 struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
01455 {
01456 struct sla_event *event;
01457
01458 if (sla.thread == AST_PTHREADT_NULL) {
01459 return;
01460 }
01461
01462 if (!(event = ast_calloc(1, sizeof(*event))))
01463 return;
01464
01465 event->type = type;
01466 event->trunk_ref = trunk_ref;
01467 event->station = station;
01468
01469 if (!lock) {
01470 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01471 return;
01472 }
01473
01474 ast_mutex_lock(&sla.lock);
01475 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01476 ast_cond_signal(&sla.cond);
01477 ast_mutex_unlock(&sla.lock);
01478 }
01479
01480 static void sla_queue_event_nolock(enum sla_event_type type)
01481 {
01482 sla_queue_event_full(type, NULL, NULL, 0);
01483 }
01484
01485 static void sla_queue_event(enum sla_event_type type)
01486 {
01487 sla_queue_event_full(type, NULL, NULL, 1);
01488 }
01489
01490
01491 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
01492 struct ast_conference *conf)
01493 {
01494 struct sla_station *station;
01495 struct sla_trunk_ref *trunk_ref = NULL;
01496 char *trunk_name;
01497
01498 trunk_name = ast_strdupa(conf->confno);
01499 strsep(&trunk_name, "_");
01500 if (ast_strlen_zero(trunk_name)) {
01501 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01502 return;
01503 }
01504
01505 AST_RWLIST_RDLOCK(&sla_stations);
01506 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01507 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01508 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01509 break;
01510 }
01511 if (trunk_ref)
01512 break;
01513 }
01514 AST_RWLIST_UNLOCK(&sla_stations);
01515
01516 if (!trunk_ref) {
01517 ast_debug(1, "Trunk not found for event!\n");
01518 return;
01519 }
01520
01521 sla_queue_event_full(type, trunk_ref, station, 1);
01522 }
01523
01524
01525 static int dispose_conf(struct ast_conference *conf)
01526 {
01527 int res = 0;
01528 int confno_int = 0;
01529
01530 AST_LIST_LOCK(&confs);
01531 if (ast_atomic_dec_and_test(&conf->refcount)) {
01532
01533 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01534 conf_map[confno_int] = 0;
01535 conf_free(conf);
01536 res = 1;
01537 }
01538 AST_LIST_UNLOCK(&confs);
01539
01540 return res;
01541 }
01542
01543 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
01544 {
01545 char *original_moh;
01546
01547 ast_channel_lock(chan);
01548 original_moh = ast_strdupa(chan->musicclass);
01549 ast_string_field_set(chan, musicclass, musicclass);
01550 ast_channel_unlock(chan);
01551
01552 ast_moh_start(chan, original_moh, NULL);
01553
01554 ast_channel_lock(chan);
01555 ast_string_field_set(chan, musicclass, original_moh);
01556 ast_channel_unlock(chan);
01557 }
01558
01559 static const char *get_announce_filename(enum announcetypes type)
01560 {
01561 switch (type) {
01562 case CONF_HASLEFT:
01563 return "conf-hasleft";
01564 break;
01565 case CONF_HASJOIN:
01566 return "conf-hasjoin";
01567 break;
01568 default:
01569 return "";
01570 }
01571 }
01572
01573 static void *announce_thread(void *data)
01574 {
01575 struct announce_listitem *current;
01576 struct ast_conference *conf = data;
01577 int res = 0;
01578 char filename[PATH_MAX] = "";
01579 AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01580 AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01581
01582 while (!conf->announcethread_stop) {
01583 ast_mutex_lock(&conf->announcelistlock);
01584 if (conf->announcethread_stop) {
01585 ast_mutex_unlock(&conf->announcelistlock);
01586 break;
01587 }
01588 if (AST_LIST_EMPTY(&conf->announcelist))
01589 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01590
01591 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01592 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01593
01594 ast_mutex_unlock(&conf->announcelistlock);
01595 if (conf->announcethread_stop) {
01596 break;
01597 }
01598
01599 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01600 ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01601 if (!ast_fileexists(current->namerecloc, NULL, NULL))
01602 continue;
01603 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01604 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01605 res = ast_waitstream(current->confchan, "");
01606 if (!res) {
01607 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01608 if (!ast_streamfile(current->confchan, filename, current->language))
01609 ast_waitstream(current->confchan, "");
01610 }
01611 }
01612 if (current->announcetype == CONF_HASLEFT) {
01613 ast_filedelete(current->namerecloc, NULL);
01614 }
01615 }
01616 }
01617
01618
01619 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01620 ast_filedelete(current->namerecloc, NULL);
01621 ao2_ref(current, -1);
01622 }
01623 return NULL;
01624 }
01625
01626 static int can_write(struct ast_channel *chan, int confflags)
01627 {
01628 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01629 return 1;
01630 }
01631
01632 return (chan->_state == AST_STATE_UP);
01633 }
01634
01635 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
01636 {
01637 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01638 "Channel: %s\r\n"
01639 "Uniqueid: %s\r\n"
01640 "Meetme: %s\r\n"
01641 "Usernum: %d\r\n"
01642 "Status: %s\r\n",
01643 chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01644 }
01645
01646 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
01647 {
01648 int last_talking = user->talking;
01649 if (last_talking == talking)
01650 return;
01651
01652 user->talking = talking;
01653
01654 if (monitor) {
01655
01656 int was_talking = (last_talking > 0);
01657 int now_talking = (talking > 0);
01658 if (was_talking != now_talking) {
01659 send_talking_event(chan, conf, user, now_talking);
01660 }
01661 }
01662 }
01663
01664 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
01665 {
01666 struct ast_conf_user *user = NULL;
01667 struct ast_conf_user *usr = NULL;
01668 int fd;
01669 struct dahdi_confinfo dahdic, dahdic_empty;
01670 struct ast_frame *f;
01671 struct ast_channel *c;
01672 struct ast_frame fr;
01673 int outfd;
01674 int ms;
01675 int nfds;
01676 int res;
01677 int retrydahdi;
01678 int origfd;
01679 int musiconhold = 0, mohtempstopped = 0;
01680 int firstpass = 0;
01681 int lastmarked = 0;
01682 int currentmarked = 0;
01683 int ret = -1;
01684 int x;
01685 int menu_active = 0;
01686 int talkreq_manager = 0;
01687 int using_pseudo = 0;
01688 int duration = 20;
01689 int hr, min, sec;
01690 int sent_event = 0;
01691 int checked = 0;
01692 int announcement_played = 0;
01693 struct timeval now;
01694 struct ast_dsp *dsp = NULL;
01695 struct ast_app *agi_app;
01696 char *agifile;
01697 const char *agifiledefault = "conf-background.agi", *tmpvar;
01698 char meetmesecs[30] = "";
01699 char exitcontext[AST_MAX_CONTEXT] = "";
01700 char recordingtmp[AST_MAX_EXTENSION] = "";
01701 char members[10] = "";
01702 int dtmf, opt_waitmarked_timeout = 0;
01703 time_t timeout = 0;
01704 struct dahdi_bufferinfo bi;
01705 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01706 char *buf = __buf + AST_FRIENDLY_OFFSET;
01707 char *exitkeys = NULL;
01708 unsigned int calldurationlimit = 0;
01709 long timelimit = 0;
01710 long play_warning = 0;
01711 long warning_freq = 0;
01712 const char *warning_sound = NULL;
01713 const char *end_sound = NULL;
01714 char *parse;
01715 long time_left_ms = 0;
01716 struct timeval nexteventts = { 0, };
01717 int to;
01718 int setusercount = 0;
01719 int confsilence = 0, totalsilence = 0;
01720
01721 if (!(user = ast_calloc(1, sizeof(*user))))
01722 return ret;
01723
01724
01725 if ((confflags & CONFFLAG_WAITMARKED) &&
01726 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01727 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
01728 (opt_waitmarked_timeout > 0)) {
01729 timeout = time(NULL) + opt_waitmarked_timeout;
01730 }
01731
01732 if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
01733 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
01734 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
01735 }
01736
01737 if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
01738 char *limit_str, *warning_str, *warnfreq_str;
01739 const char *var;
01740
01741 parse = optargs[OPT_ARG_DURATION_LIMIT];
01742 limit_str = strsep(&parse, ":");
01743 warning_str = strsep(&parse, ":");
01744 warnfreq_str = parse;
01745
01746 timelimit = atol(limit_str);
01747 if (warning_str)
01748 play_warning = atol(warning_str);
01749 if (warnfreq_str)
01750 warning_freq = atol(warnfreq_str);
01751
01752 if (!timelimit) {
01753 timelimit = play_warning = warning_freq = 0;
01754 warning_sound = NULL;
01755 } else if (play_warning > timelimit) {
01756 if (!warning_freq) {
01757 play_warning = 0;
01758 } else {
01759 while (play_warning > timelimit)
01760 play_warning -= warning_freq;
01761 if (play_warning < 1)
01762 play_warning = warning_freq = 0;
01763 }
01764 }
01765
01766 ast_channel_lock(chan);
01767 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
01768 var = ast_strdupa(var);
01769 }
01770 ast_channel_unlock(chan);
01771
01772 warning_sound = var ? var : "timeleft";
01773
01774 ast_channel_lock(chan);
01775 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
01776 var = ast_strdupa(var);
01777 }
01778 ast_channel_unlock(chan);
01779
01780 end_sound = var ? var : NULL;
01781
01782
01783 calldurationlimit = 0;
01784
01785 if (!play_warning && !end_sound && timelimit) {
01786 calldurationlimit = timelimit / 1000;
01787 timelimit = play_warning = warning_freq = 0;
01788 } else {
01789 ast_debug(2, "Limit Data for this call:\n");
01790 ast_debug(2, "- timelimit = %ld\n", timelimit);
01791 ast_debug(2, "- play_warning = %ld\n", play_warning);
01792 ast_debug(2, "- warning_freq = %ld\n", warning_freq);
01793 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
01794 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
01795 }
01796 }
01797
01798
01799 if ((confflags & CONFFLAG_KEYEXIT)) {
01800 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
01801 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
01802 else
01803 exitkeys = ast_strdupa("#");
01804 }
01805
01806 if (confflags & CONFFLAG_RECORDCONF) {
01807 if (!conf->recordingfilename) {
01808 const char *var;
01809 ast_channel_lock(chan);
01810 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
01811 conf->recordingfilename = ast_strdup(var);
01812 }
01813 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
01814 conf->recordingformat = ast_strdup(var);
01815 }
01816 ast_channel_unlock(chan);
01817 if (!conf->recordingfilename) {
01818 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01819 conf->recordingfilename = ast_strdup(recordingtmp);
01820 }
01821 if (!conf->recordingformat) {
01822 conf->recordingformat = ast_strdup("wav");
01823 }
01824 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01825 conf->confno, conf->recordingfilename, conf->recordingformat);
01826 }
01827 }
01828
01829 ast_mutex_lock(&conf->recordthreadlock);
01830 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01831 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01832 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01833 dahdic.chan = 0;
01834 dahdic.confno = conf->dahdiconf;
01835 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01836 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
01837 ast_log(LOG_WARNING, "Error starting listen channel\n");
01838 ast_hangup(conf->lchan);
01839 conf->lchan = NULL;
01840 } else {
01841 ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
01842 }
01843 }
01844 ast_mutex_unlock(&conf->recordthreadlock);
01845
01846 ast_mutex_lock(&conf->announcethreadlock);
01847 if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01848 ast_mutex_init(&conf->announcelistlock);
01849 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01850 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
01851 }
01852 ast_mutex_unlock(&conf->announcethreadlock);
01853
01854 time(&user->jointime);
01855
01856 user->timelimit = timelimit;
01857 user->play_warning = play_warning;
01858 user->warning_freq = warning_freq;
01859 user->warning_sound = warning_sound;
01860 user->end_sound = end_sound;
01861
01862 if (calldurationlimit > 0) {
01863 time(&user->kicktime);
01864 user->kicktime = user->kicktime + calldurationlimit;
01865 }
01866
01867 if (ast_tvzero(user->start_time))
01868 user->start_time = ast_tvnow();
01869 time_left_ms = user->timelimit;
01870
01871 if (user->timelimit) {
01872 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
01873 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
01874 }
01875
01876 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01877
01878 if (!ast_streamfile(chan, "conf-locked", chan->language))
01879 ast_waitstream(chan, "");
01880 goto outrun;
01881 }
01882
01883 ast_mutex_lock(&conf->playlock);
01884
01885 if (AST_LIST_EMPTY(&conf->userlist))
01886 user->user_no = 1;
01887 else
01888 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
01889
01890 if (rt_schedule && conf->maxusers)
01891 if (conf->users >= conf->maxusers) {
01892
01893 if (!ast_streamfile(chan, "conf-full", chan->language))
01894 ast_waitstream(chan, "");
01895 ast_mutex_unlock(&conf->playlock);
01896 user->user_no = 0;
01897 goto outrun;
01898 }
01899
01900 AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
01901
01902 user->chan = chan;
01903 user->userflags = confflags;
01904 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01905 user->talking = -1;
01906
01907 ast_mutex_unlock(&conf->playlock);
01908
01909 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01910 char destdir[PATH_MAX];
01911
01912 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
01913
01914 if (ast_mkdir(destdir, 0777) != 0) {
01915 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
01916 goto outrun;
01917 }
01918
01919 snprintf(user->namerecloc, sizeof(user->namerecloc),
01920 "%s/meetme-username-%s-%d", destdir,
01921 conf->confno, user->user_no);
01922 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01923 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
01924 else
01925 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01926 if (res == -1)
01927 goto outrun;
01928 }
01929
01930 ast_mutex_lock(&conf->playlock);
01931
01932 if (confflags & CONFFLAG_MARKEDUSER)
01933 conf->markedusers++;
01934 conf->users++;
01935 if (rt_log_members) {
01936
01937 snprintf(members, sizeof(members), "%d", conf->users);
01938 ast_realtime_require_field("meetme",
01939 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
01940 "members", RQ_UINTEGER1, strlen(members),
01941 NULL);
01942 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
01943 }
01944 setusercount = 1;
01945
01946
01947 if (conf->users == 1)
01948 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
01949
01950 ast_mutex_unlock(&conf->playlock);
01951
01952
01953 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
01954
01955 if (confflags & CONFFLAG_EXIT_CONTEXT) {
01956 ast_channel_lock(chan);
01957 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
01958 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
01959 } else if (!ast_strlen_zero(chan->macrocontext)) {
01960 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01961 } else {
01962 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01963 }
01964 ast_channel_unlock(chan);
01965 }
01966
01967 if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
01968 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01969 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01970 ast_waitstream(chan, "");
01971 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01972 if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01973 ast_waitstream(chan, "");
01974 }
01975
01976 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01977 int keepplaying = 1;
01978
01979 if (conf->users == 2) {
01980 if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
01981 res = ast_waitstream(chan, AST_DIGIT_ANY);
01982 ast_stopstream(chan);
01983 if (res > 0)
01984 keepplaying = 0;
01985 else if (res == -1)
01986 goto outrun;
01987 }
01988 } else {
01989 if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01990 res = ast_waitstream(chan, AST_DIGIT_ANY);
01991 ast_stopstream(chan);
01992 if (res > 0)
01993 keepplaying = 0;
01994 else if (res == -1)
01995 goto outrun;
01996 }
01997 if (keepplaying) {
01998 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01999 if (res > 0)
02000 keepplaying = 0;
02001 else if (res == -1)
02002 goto outrun;
02003 }
02004 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02005 res = ast_waitstream(chan, AST_DIGIT_ANY);
02006 ast_stopstream(chan);
02007 if (res > 0)
02008 keepplaying = 0;
02009 else if (res == -1)
02010 goto outrun;
02011 }
02012 }
02013 }
02014
02015 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02016
02017 ast_indicate(chan, -1);
02018 }
02019
02020 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
02021 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
02022 goto outrun;
02023 }
02024
02025 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
02026 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
02027 goto outrun;
02028 }
02029
02030 retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
02031 user->dahdichannel = !retrydahdi;
02032
02033 dahdiretry:
02034 origfd = chan->fds[0];
02035 if (retrydahdi) {
02036
02037 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02038 if (fd < 0) {
02039 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02040 goto outrun;
02041 }
02042 using_pseudo = 1;
02043
02044 memset(&bi, 0, sizeof(bi));
02045 bi.bufsize = CONF_SIZE / 2;
02046 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02047 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02048 bi.numbufs = audio_buffers;
02049 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02050 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02051 close(fd);
02052 goto outrun;
02053 }
02054 x = 1;
02055 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02056 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02057 close(fd);
02058 goto outrun;
02059 }
02060 nfds = 1;
02061 } else {
02062
02063 fd = chan->fds[0];
02064 nfds = 0;
02065 }
02066 memset(&dahdic, 0, sizeof(dahdic));
02067 memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02068
02069 dahdic.chan = 0;
02070 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02071 ast_log(LOG_WARNING, "Error getting conference\n");
02072 close(fd);
02073 goto outrun;
02074 }
02075 if (dahdic.confmode) {
02076
02077 if (!retrydahdi) {
02078 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02079 retrydahdi = 1;
02080 goto dahdiretry;
02081 }
02082 }
02083 memset(&dahdic, 0, sizeof(dahdic));
02084
02085 dahdic.chan = 0;
02086 dahdic.confno = conf->dahdiconf;
02087
02088 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02089 struct announce_listitem *item;
02090 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02091 return -1;
02092 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02093 ast_copy_string(item->language, chan->language, sizeof(item->language));
02094 item->confchan = conf->chan;
02095 item->confusers = conf->users;
02096 item->announcetype = CONF_HASJOIN;
02097 ast_mutex_lock(&conf->announcelistlock);
02098 ao2_ref(item, +1);
02099 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02100 ast_cond_signal(&conf->announcelist_addition);
02101 ast_mutex_unlock(&conf->announcelistlock);
02102
02103 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02104 ;
02105 }
02106 ao2_ref(item, -1);
02107 }
02108
02109 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02110 dahdic.confmode = DAHDI_CONF_CONF;
02111 else if (confflags & CONFFLAG_MONITOR)
02112 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02113 else if (confflags & CONFFLAG_TALKER)
02114 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02115 else
02116 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02117
02118 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02119 ast_log(LOG_WARNING, "Error setting conference\n");
02120 close(fd);
02121 goto outrun;
02122 }
02123 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02124
02125 if (!sent_event) {
02126 manager_event(EVENT_FLAG_CALL, "MeetmeJoin",
02127 "Channel: %s\r\n"
02128 "Uniqueid: %s\r\n"
02129 "Meetme: %s\r\n"
02130 "Usernum: %d\r\n"
02131 "CallerIDnum: %s\r\n"
02132 "CallerIDname: %s\r\n",
02133 chan->name, chan->uniqueid, conf->confno,
02134 user->user_no,
02135 S_OR(user->chan->cid.cid_num, "<unknown>"),
02136 S_OR(user->chan->cid.cid_name, "<unknown>")
02137 );
02138 sent_event = 1;
02139 }
02140
02141 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02142 firstpass = 1;
02143 if (!(confflags & CONFFLAG_QUIET))
02144 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02145 conf_play(chan, conf, ENTER);
02146 }
02147
02148 conf_flush(fd, chan);
02149
02150 if (!(dsp = ast_dsp_new())) {
02151 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02152 res = -1;
02153 }
02154
02155 if (confflags & CONFFLAG_AGI) {
02156
02157
02158
02159 ast_channel_lock(chan);
02160 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02161 agifile = ast_strdupa(tmpvar);
02162 } else {
02163 agifile = ast_strdupa(agifiledefault);
02164 }
02165 ast_channel_unlock(chan);
02166
02167 if (user->dahdichannel) {
02168
02169 x = 1;
02170 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02171 }
02172
02173 agi_app = pbx_findapp("agi");
02174 if (agi_app) {
02175 ret = pbx_exec(chan, agi_app, agifile);
02176 } else {
02177 ast_log(LOG_WARNING, "Could not find application (agi)\n");
02178 ret = -2;
02179 }
02180 if (user->dahdichannel) {
02181
02182 x = 0;
02183 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02184 }
02185 } else {
02186 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02187
02188 x = 1;
02189 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02190 }
02191 for (;;) {
02192 int menu_was_active = 0;
02193
02194 outfd = -1;
02195 ms = -1;
02196 now = ast_tvnow();
02197
02198 if (rt_schedule) {
02199 if (now.tv_sec % 60 == 0) {
02200 if (!checked) {
02201 if (now.tv_sec >= conf->endtime) {
02202 goto outrun;
02203 }
02204
02205 if (!announcement_played && conf->endalert) {
02206 if (now.tv_sec + conf->endalert >= conf->endtime) {
02207 if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02208 ast_waitstream(chan, "");
02209 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02210 if (!ast_streamfile(chan, "minutes", chan->language))
02211 ast_waitstream(chan, "");
02212 announcement_played = 1;
02213 }
02214 }
02215 checked = 1;
02216
02217 }
02218 } else {
02219 checked = 0;
02220 }
02221 }
02222
02223 if (user->kicktime && (user->kicktime <= now.tv_sec))
02224 break;
02225
02226 to = -1;
02227 if (user->timelimit) {
02228 int minutes = 0, seconds = 0, remain = 0;
02229
02230 to = ast_tvdiff_ms(nexteventts, now);
02231 if (to < 0)
02232 to = 0;
02233 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02234 if (time_left_ms < to)
02235 to = time_left_ms;
02236
02237 if (time_left_ms <= 0) {
02238 if (user->end_sound) {
02239 res = ast_streamfile(chan, user->end_sound, chan->language);
02240 res = ast_waitstream(chan, "");
02241 }
02242 break;
02243 }
02244
02245 if (!to) {
02246 if (time_left_ms >= 5000) {
02247
02248 remain = (time_left_ms + 500) / 1000;
02249 if (remain / 60 >= 1) {
02250 minutes = remain / 60;
02251 seconds = remain % 60;
02252 } else {
02253 seconds = remain;
02254 }
02255
02256
02257 if (user->warning_sound && user->play_warning) {
02258 if (!strcmp(user->warning_sound, "timeleft")) {
02259
02260 res = ast_streamfile(chan, "vm-youhave", chan->language);
02261 res = ast_waitstream(chan, "");
02262 if (minutes) {
02263 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02264 res = ast_streamfile(chan, "queue-minutes", chan->language);
02265 res = ast_waitstream(chan, "");
02266 }
02267 if (seconds) {
02268 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02269 res = ast_streamfile(chan, "queue-seconds", chan->language);
02270 res = ast_waitstream(chan, "");
02271 }
02272 } else {
02273 res = ast_streamfile(chan, user->warning_sound, chan->language);
02274 res = ast_waitstream(chan, "");
02275 }
02276 }
02277 }
02278 if (user->warning_freq)
02279 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02280 else
02281 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02282 }
02283 }
02284
02285 now = ast_tvnow();
02286 if (timeout && now.tv_sec >= timeout)
02287 break;
02288
02289
02290
02291
02292 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
02293 set_talk_volume(user, user->listen.desired);
02294
02295 menu_was_active = menu_active;
02296
02297 currentmarked = conf->markedusers;
02298 if (!(confflags & CONFFLAG_QUIET) &&
02299 (confflags & CONFFLAG_MARKEDUSER) &&
02300 (confflags & CONFFLAG_WAITMARKED) &&
02301 lastmarked == 0) {
02302 if (currentmarked == 1 && conf->users > 1) {
02303 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02304 if (conf->users - 1 == 1) {
02305 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
02306 ast_waitstream(chan, "");
02307 } else {
02308 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
02309 ast_waitstream(chan, "");
02310 }
02311 }
02312 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
02313 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02314 ast_waitstream(chan, "");
02315 }
02316
02317
02318 user->userflags = confflags;
02319
02320 if (confflags & CONFFLAG_WAITMARKED) {
02321 if (currentmarked == 0) {
02322 if (lastmarked != 0) {
02323 if (!(confflags & CONFFLAG_QUIET))
02324 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
02325 ast_waitstream(chan, "");
02326 if (confflags & CONFFLAG_MARKEDEXIT) {
02327 if (confflags & CONFFLAG_KICK_CONTINUE)
02328 ret = 0;
02329 break;
02330 } else {
02331 dahdic.confmode = DAHDI_CONF_CONF;
02332 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02333 ast_log(LOG_WARNING, "Error setting conference\n");
02334 close(fd);
02335 goto outrun;
02336 }
02337 }
02338 }
02339 if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02340 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02341 musiconhold = 1;
02342 }
02343 } else if (currentmarked >= 1 && lastmarked == 0) {
02344
02345 timeout = 0;
02346 if (confflags & CONFFLAG_MONITOR)
02347 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02348 else if (confflags & CONFFLAG_TALKER)
02349 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02350 else
02351 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02352 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02353 ast_log(LOG_WARNING, "Error setting conference\n");
02354 close(fd);
02355 goto outrun;
02356 }
02357 if (musiconhold && (confflags & CONFFLAG_MOH)) {
02358 ast_moh_stop(chan);
02359 musiconhold = 0;
02360 }
02361 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02362 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
02363 ast_waitstream(chan, "");
02364 conf_play(chan, conf, ENTER);
02365 }
02366 }
02367 }
02368
02369
02370 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02371 if (conf->users == 1) {
02372 if (!musiconhold) {
02373 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02374 musiconhold = 1;
02375 }
02376 } else {
02377 if (musiconhold) {
02378 ast_moh_stop(chan);
02379 musiconhold = 0;
02380 }
02381 }
02382 }
02383
02384
02385 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02386 if (confflags & CONFFLAG_KICK_CONTINUE)
02387 ret = 0;
02388 else
02389 ret = -1;
02390 break;
02391 }
02392
02393
02394
02395
02396 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02397 dahdic.confmode ^= DAHDI_CONF_TALKER;
02398 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02399 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02400 ret = -1;
02401 break;
02402 }
02403
02404
02405 if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
02406 set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
02407 }
02408
02409 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02410 "Channel: %s\r\n"
02411 "Uniqueid: %s\r\n"
02412 "Meetme: %s\r\n"
02413 "Usernum: %i\r\n"
02414 "Status: on\r\n",
02415 chan->name, chan->uniqueid, conf->confno, user->user_no);
02416 }
02417
02418
02419 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02420 dahdic.confmode |= DAHDI_CONF_TALKER;
02421 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02422 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02423 ret = -1;
02424 break;
02425 }
02426
02427 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02428 "Channel: %s\r\n"
02429 "Uniqueid: %s\r\n"
02430 "Meetme: %s\r\n"
02431 "Usernum: %i\r\n"
02432 "Status: off\r\n",
02433 chan->name, chan->uniqueid, conf->confno, user->user_no);
02434 }
02435
02436 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02437 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02438 talkreq_manager = 1;
02439
02440 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02441 "Channel: %s\r\n"
02442 "Uniqueid: %s\r\n"
02443 "Meetme: %s\r\n"
02444 "Usernum: %i\r\n"
02445 "Status: on\r\n",
02446 chan->name, chan->uniqueid, conf->confno, user->user_no);
02447 }
02448
02449
02450 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02451 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02452 talkreq_manager = 0;
02453 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02454 "Channel: %s\r\n"
02455 "Uniqueid: %s\r\n"
02456 "Meetme: %s\r\n"
02457 "Usernum: %i\r\n"
02458 "Status: off\r\n",
02459 chan->name, chan->uniqueid, conf->confno, user->user_no);
02460 }
02461
02462
02463 if (user->adminflags & ADMINFLAG_KICKME) {
02464
02465 if (!(confflags & CONFFLAG_QUIET) &&
02466 !ast_streamfile(chan, "conf-kicked", chan->language)) {
02467 ast_waitstream(chan, "");
02468 }
02469 ret = 0;
02470 break;
02471 }
02472
02473
02474 if (ast_check_hangup(chan))
02475 break;
02476
02477 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02478
02479 if (c) {
02480 char dtmfstr[2] = "";
02481
02482 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02483 if (using_pseudo) {
02484
02485 close(fd);
02486 using_pseudo = 0;
02487 }
02488 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02489 retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02490 user->dahdichannel = !retrydahdi;
02491 goto dahdiretry;
02492 }
02493 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
02494 f = ast_read_noaudio(c);
02495 else
02496 f = ast_read(c);
02497 if (!f)
02498 break;
02499 if (f->frametype == AST_FRAME_DTMF) {
02500 dtmfstr[0] = f->subclass;
02501 dtmfstr[1] = '\0';
02502 }
02503
02504 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02505 if (user->talk.actual)
02506 ast_frame_adjust_volume(f, user->talk.actual);
02507
02508 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02509 if (user->talking == -1)
02510 user->talking = 0;
02511
02512 res = ast_dsp_silence(dsp, f, &totalsilence);
02513 if (totalsilence < MEETME_DELAYDETECTTALK) {
02514 set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
02515 }
02516 if (totalsilence > MEETME_DELAYDETECTENDTALK) {
02517 set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
02518 }
02519 }
02520 if (using_pseudo) {
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02534 careful_write(fd, f->data.ptr, f->datalen, 0);
02535 }
02536 }
02537 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02538 if (confflags & CONFFLAG_PASS_DTMF)
02539 conf_queue_dtmf(conf, user, f);
02540 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02541 ast_log(LOG_WARNING, "Error setting conference\n");
02542 close(fd);
02543 ast_frfree(f);
02544 goto outrun;
02545 }
02546
02547
02548
02549
02550 if (!menu_active && user->talk.desired && !user->talk.actual)
02551 set_talk_volume(user, 0);
02552
02553 if (musiconhold) {
02554 ast_moh_stop(chan);
02555 }
02556 if ((confflags & CONFFLAG_ADMIN)) {
02557
02558 if (!menu_active) {
02559 menu_active = 1;
02560
02561 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
02562 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02563 ast_stopstream(chan);
02564 } else
02565 dtmf = 0;
02566 } else
02567 dtmf = f->subclass;
02568 if (dtmf) {
02569 switch(dtmf) {
02570 case '1':
02571 menu_active = 0;
02572
02573
02574 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02575 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02576 else
02577 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02578
02579 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02580 if (!ast_streamfile(chan, "conf-muted", chan->language))
02581 ast_waitstream(chan, "");
02582 } else {
02583 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02584 ast_waitstream(chan, "");
02585 }
02586 break;
02587 case '2':
02588 menu_active = 0;
02589 if (conf->locked) {
02590 conf->locked = 0;
02591 if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02592 ast_waitstream(chan, "");
02593 } else {
02594 conf->locked = 1;
02595 if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02596 ast_waitstream(chan, "");
02597 }
02598 break;
02599 case '3':
02600 menu_active = 0;
02601 usr = AST_LIST_LAST(&conf->userlist);
02602 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02603 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02604 ast_waitstream(chan, "");
02605 } else
02606 usr->adminflags |= ADMINFLAG_KICKME;
02607 ast_stopstream(chan);
02608 break;
02609 case '4':
02610 tweak_listen_volume(user, VOL_DOWN);
02611 break;
02612 case '6':
02613 tweak_listen_volume(user, VOL_UP);
02614 break;
02615 case '7':
02616 tweak_talk_volume(user, VOL_DOWN);
02617 break;
02618 case '8':
02619 menu_active = 0;
02620 break;
02621 case '9':
02622 tweak_talk_volume(user, VOL_UP);
02623 break;
02624 default:
02625 menu_active = 0;
02626
02627 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02628 ast_waitstream(chan, "");
02629 break;
02630 }
02631 }
02632 } else {
02633
02634 if (!menu_active) {
02635 menu_active = 1;
02636 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02637 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02638 ast_stopstream(chan);
02639 } else
02640 dtmf = 0;
02641 } else
02642 dtmf = f->subclass;
02643 if (dtmf) {
02644 switch(dtmf) {
02645 case '1':
02646 menu_active = 0;
02647
02648
02649 user->adminflags ^= ADMINFLAG_SELFMUTED;
02650
02651
02652 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02653 if (!ast_streamfile(chan, "conf-muted", chan->language))
02654 ast_waitstream(chan, "");
02655 } else {
02656 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02657 ast_waitstream(chan, "");
02658 }
02659 break;
02660 case '2':
02661 menu_active = 0;
02662 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02663 user->adminflags |= ADMINFLAG_T_REQUEST;
02664
02665 if (user->adminflags & ADMINFLAG_T_REQUEST)
02666 if (!ast_streamfile(chan, "beep", chan->language))
02667 ast_waitstream(chan, "");
02668 break;
02669 case '4':
02670 tweak_listen_volume(user, VOL_DOWN);
02671 break;
02672 case '6':
02673 tweak_listen_volume(user, VOL_UP);
02674 break;
02675 case '7':
02676 tweak_talk_volume(user, VOL_DOWN);
02677 break;
02678 case '8':
02679 menu_active = 0;
02680 break;
02681 case '9':
02682 tweak_talk_volume(user, VOL_UP);
02683 break;
02684 default:
02685 menu_active = 0;
02686 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02687 ast_waitstream(chan, "");
02688 break;
02689 }
02690 }
02691 }
02692 if (musiconhold)
02693 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02694
02695 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02696 ast_log(LOG_WARNING, "Error setting conference\n");
02697 close(fd);
02698 ast_frfree(f);
02699 goto outrun;
02700 }
02701
02702 conf_flush(fd, chan);
02703
02704 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
02705 if (confflags & CONFFLAG_PASS_DTMF)
02706 conf_queue_dtmf(conf, user, f);
02707
02708 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
02709 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
02710 ret = 0;
02711 ast_frfree(f);
02712 break;
02713 } else {
02714 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
02715 }
02716 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
02717 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
02718
02719 if (confflags & CONFFLAG_PASS_DTMF)
02720 conf_queue_dtmf(conf, user, f);
02721 ret = 0;
02722 ast_frfree(f);
02723 break;
02724 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02725 && confflags & CONFFLAG_PASS_DTMF) {
02726 conf_queue_dtmf(conf, user, f);
02727 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02728 switch (f->subclass) {
02729 case AST_CONTROL_HOLD:
02730 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02731 break;
02732 default:
02733 break;
02734 }
02735 } else if (f->frametype == AST_FRAME_NULL) {
02736
02737 } else {
02738 ast_debug(1,
02739 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02740 chan->name, f->frametype, f->subclass);
02741 }
02742 ast_frfree(f);
02743 } else if (outfd > -1) {
02744 res = read(outfd, buf, CONF_SIZE);
02745 if (res > 0) {
02746 memset(&fr, 0, sizeof(fr));
02747 fr.frametype = AST_FRAME_VOICE;
02748 fr.subclass = AST_FORMAT_SLINEAR;
02749 fr.datalen = res;
02750 fr.samples = res / 2;
02751 fr.data.ptr = buf;
02752 fr.offset = AST_FRIENDLY_OFFSET;
02753 if (!user->listen.actual &&
02754 ((confflags & CONFFLAG_MONITOR) ||
02755 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02756 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02757 )) {
02758 int idx;
02759 for (idx = 0; idx < AST_FRAME_BITS; idx++)
02760 if (chan->rawwriteformat & (1 << idx))
02761 break;
02762 if (idx >= AST_FRAME_BITS)
02763 goto bailoutandtrynormal;
02764 ast_mutex_lock(&conf->listenlock);
02765 if (!conf->transframe[idx]) {
02766 if (conf->origframe) {
02767 if (musiconhold && !ast_dsp_silence(dsp, conf->origframe, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02768 ast_moh_stop(chan);
02769 mohtempstopped = 1;
02770 }
02771 if (!conf->transpath[idx])
02772 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
02773 if (conf->transpath[idx]) {
02774 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
02775 if (!conf->transframe[idx])
02776 conf->transframe[idx] = &ast_null_frame;
02777 }
02778 }
02779 }
02780 if (conf->transframe[idx]) {
02781 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
02782 can_write(chan, confflags)) {
02783 struct ast_frame *cur;
02784
02785
02786
02787 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02788 if (ast_write(chan, cur)) {
02789 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02790 break;
02791 }
02792 }
02793 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02794 mohtempstopped = 0;
02795 ast_moh_start(chan, NULL, NULL);
02796 }
02797 }
02798 } else {
02799 ast_mutex_unlock(&conf->listenlock);
02800 goto bailoutandtrynormal;
02801 }
02802 ast_mutex_unlock(&conf->listenlock);
02803 } else {
02804 bailoutandtrynormal:
02805 if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02806 ast_moh_stop(chan);
02807 mohtempstopped = 1;
02808 }
02809 if (user->listen.actual)
02810 ast_frame_adjust_volume(&fr, user->listen.actual);
02811 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02812 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02813 }
02814 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02815 mohtempstopped = 0;
02816 ast_moh_start(chan, NULL, NULL);
02817 }
02818 }
02819 } else
02820 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02821 }
02822 lastmarked = currentmarked;
02823 }
02824 }
02825
02826 if (musiconhold)
02827 ast_moh_stop(chan);
02828
02829 if (using_pseudo)
02830 close(fd);
02831 else {
02832
02833 dahdic.chan = 0;
02834 dahdic.confno = 0;
02835 dahdic.confmode = 0;
02836 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02837 ast_log(LOG_WARNING, "Error setting conference\n");
02838 }
02839 }
02840
02841 reset_volumes(user);
02842
02843 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02844 conf_play(chan, conf, LEAVE);
02845
02846 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02847 struct announce_listitem *item;
02848 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02849 return -1;
02850 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02851 ast_copy_string(item->language, chan->language, sizeof(item->language));
02852 item->confchan = conf->chan;
02853 item->confusers = conf->users;
02854 item->announcetype = CONF_HASLEFT;
02855 ast_mutex_lock(&conf->announcelistlock);
02856 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02857 ast_cond_signal(&conf->announcelist_addition);
02858 ast_mutex_unlock(&conf->announcelistlock);
02859 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02860
02861 ast_filedelete(user->namerecloc, NULL);
02862 }
02863
02864 outrun:
02865 AST_LIST_LOCK(&confs);
02866
02867 if (dsp)
02868 ast_dsp_free(dsp);
02869
02870 if (user->user_no) {
02871 now = ast_tvnow();
02872 hr = (now.tv_sec - user->jointime) / 3600;
02873 min = ((now.tv_sec - user->jointime) % 3600) / 60;
02874 sec = (now.tv_sec - user->jointime) % 60;
02875
02876 if (sent_event) {
02877 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02878 "Channel: %s\r\n"
02879 "Uniqueid: %s\r\n"
02880 "Meetme: %s\r\n"
02881 "Usernum: %d\r\n"
02882 "CallerIDNum: %s\r\n"
02883 "CallerIDName: %s\r\n"
02884 "Duration: %ld\r\n",
02885 chan->name, chan->uniqueid, conf->confno,
02886 user->user_no,
02887 S_OR(user->chan->cid.cid_num, "<unknown>"),
02888 S_OR(user->chan->cid.cid_name, "<unknown>"),
02889 (long)(now.tv_sec - user->jointime));
02890 }
02891
02892 if (setusercount) {
02893 conf->users--;
02894 if (rt_log_members) {
02895
02896 snprintf(members, sizeof(members), "%d", conf->users);
02897 ast_realtime_require_field("meetme",
02898 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02899 "members", RQ_UINTEGER1, strlen(members),
02900 NULL);
02901 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02902 }
02903 if (confflags & CONFFLAG_MARKEDUSER)
02904 conf->markedusers--;
02905 }
02906
02907 AST_LIST_REMOVE(&conf->userlist, user, list);
02908
02909
02910 if (!conf->users)
02911 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02912
02913
02914 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02915 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02916 }
02917 ast_free(user);
02918 AST_LIST_UNLOCK(&confs);
02919
02920 return ret;
02921 }
02922
02923 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
02924 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags,
02925 char *optargs[], int *too_early)
02926 {
02927 struct ast_variable *var;
02928 struct ast_conference *cnf;
02929
02930 *too_early = 0;
02931
02932
02933 AST_LIST_LOCK(&confs);
02934 AST_LIST_TRAVERSE(&confs, cnf, list) {
02935 if (!strcmp(confno, cnf->confno))
02936 break;
02937 }
02938 if (cnf) {
02939 cnf->refcount += refcount;
02940 }
02941 AST_LIST_UNLOCK(&confs);
02942
02943 if (!cnf) {
02944 char *pin = NULL, *pinadmin = NULL;
02945 int maxusers = 0;
02946 struct timeval now;
02947 char currenttime[19] = "";
02948 char eatime[19] = "";
02949 char useropts[32] = "";
02950 char adminopts[32] = "";
02951 struct ast_tm tm, etm;
02952 struct timeval endtime = { .tv_sec = 0 };
02953
02954 if (rt_schedule) {
02955 now = ast_tvnow();
02956
02957 ast_localtime(&now, &tm, NULL);
02958 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02959
02960 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02961
02962 var = ast_load_realtime("meetme", "confno",
02963 confno, "starttime <= ", currenttime, "endtime >= ",
02964 currenttime, NULL);
02965
02966 if (!var && fuzzystart) {
02967 now = ast_tvnow();
02968 now.tv_sec += fuzzystart;
02969
02970 ast_localtime(&now, &tm, NULL);
02971 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02972 var = ast_load_realtime("meetme", "confno",
02973 confno, "starttime <= ", currenttime, "endtime >= ",
02974 currenttime, NULL);
02975 }
02976
02977 if (!var && earlyalert) {
02978 now = ast_tvnow();
02979 now.tv_sec += earlyalert;
02980 ast_localtime(&now, &etm, NULL);
02981 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02982 var = ast_load_realtime("meetme", "confno",
02983 confno, "starttime <= ", eatime, "endtime >= ",
02984 currenttime, NULL);
02985 if (var)
02986 *too_early = 1;
02987 }
02988
02989 } else
02990 var = ast_load_realtime("meetme", "confno", confno, NULL);
02991
02992 if (!var)
02993 return NULL;
02994
02995 if (rt_schedule && *too_early) {
02996
02997 if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02998 ast_waitstream(chan, "");
02999 ast_variables_destroy(var);
03000 return NULL;
03001 }
03002
03003 while (var) {
03004 if (!strcasecmp(var->name, "pin")) {
03005 pin = ast_strdupa(var->value);
03006 } else if (!strcasecmp(var->name, "adminpin")) {
03007 pinadmin = ast_strdupa(var->value);
03008 } else if (!strcasecmp(var->name, "opts")) {
03009 ast_copy_string(useropts, var->value, sizeof(useropts));
03010 } else if (!strcasecmp(var->name, "maxusers")) {
03011 maxusers = atoi(var->value);
03012 } else if (!strcasecmp(var->name, "adminopts")) {
03013 ast_copy_string(adminopts, var->value, sizeof(adminopts));
03014 } else if (!strcasecmp(var->name, "endtime")) {
03015 union {
03016 struct ast_tm atm;
03017 struct tm tm;
03018 } t = { { 0, }, };
03019 strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
03020
03021
03022
03023
03024 t.tm.tm_isdst = -1;
03025 endtime = ast_mktime(&t.atm, NULL);
03026 }
03027
03028 var = var->next;
03029 }
03030
03031 ast_variables_destroy(var);
03032
03033 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03034
03035 if (cnf) {
03036 cnf->maxusers = maxusers;
03037 cnf->endalert = endalert;
03038 cnf->endtime = endtime.tv_sec;
03039 }
03040 }
03041
03042 if (cnf) {
03043 if (confflags && !cnf->chan &&
03044 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03045 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03046 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03047 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03048 }
03049
03050 if (confflags && !cnf->chan &&
03051 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03052 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03053 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03054 }
03055 }
03056
03057 return cnf;
03058 }
03059
03060
03061 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
03062 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
03063 {
03064 struct ast_config *cfg;
03065 struct ast_variable *var;
03066 struct ast_flags config_flags = { 0 };
03067 struct ast_conference *cnf;
03068
03069 AST_DECLARE_APP_ARGS(args,
03070 AST_APP_ARG(confno);
03071 AST_APP_ARG(pin);
03072 AST_APP_ARG(pinadmin);
03073 );
03074
03075
03076 ast_debug(1, "The requested confno is '%s'?\n", confno);
03077 AST_LIST_LOCK(&confs);
03078 AST_LIST_TRAVERSE(&confs, cnf, list) {
03079 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03080 if (!strcmp(confno, cnf->confno))
03081 break;
03082 }
03083 if (cnf) {
03084 cnf->refcount += refcount;
03085 }
03086 AST_LIST_UNLOCK(&confs);
03087
03088 if (!cnf) {
03089 if (dynamic) {
03090
03091 ast_debug(1, "Building dynamic conference '%s'\n", confno);
03092 if (dynamic_pin) {
03093 if (dynamic_pin[0] == 'q') {
03094
03095 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03096 return NULL;
03097 }
03098 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03099 } else {
03100 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03101 }
03102 } else {
03103
03104 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03105 if (!cfg) {
03106 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03107 return NULL;
03108 }
03109
03110 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03111 char parse[MAX_SETTINGS];
03112
03113 if (strcasecmp(var->name, "conf"))
03114 continue;
03115
03116 ast_copy_string(parse, var->value, sizeof(parse));
03117
03118 AST_STANDARD_APP_ARGS(args, parse);
03119 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03120 if (!strcasecmp(args.confno, confno)) {
03121
03122 cnf = build_conf(args.confno,
03123 S_OR(args.pin, ""),
03124 S_OR(args.pinadmin, ""),
03125 make, dynamic, refcount, chan);
03126 break;
03127 }
03128 }
03129 if (!var) {
03130 ast_debug(1, "%s isn't a valid conference\n", confno);
03131 }
03132 ast_config_destroy(cfg);
03133 }
03134 } else if (dynamic_pin) {
03135
03136
03137
03138 if (dynamic_pin[0] == 'q')
03139 dynamic_pin[0] = '\0';
03140 }
03141
03142 if (cnf) {
03143 if (confflags && !cnf->chan &&
03144 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03145 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03146 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03147 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03148 }
03149
03150 if (confflags && !cnf->chan &&
03151 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03152 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03153 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03154 }
03155 }
03156
03157 return cnf;
03158 }
03159
03160
03161 static int count_exec(struct ast_channel *chan, void *data)
03162 {
03163 int res = 0;
03164 struct ast_conference *conf;
03165 int count;
03166 char *localdata;
03167 char val[80] = "0";
03168 AST_DECLARE_APP_ARGS(args,
03169 AST_APP_ARG(confno);
03170 AST_APP_ARG(varname);
03171 );
03172
03173 if (ast_strlen_zero(data)) {
03174 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03175 return -1;
03176 }
03177
03178 if (!(localdata = ast_strdupa(data)))
03179 return -1;
03180
03181 AST_STANDARD_APP_ARGS(args, localdata);
03182
03183 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03184
03185 if (conf) {
03186 count = conf->users;
03187 dispose_conf(conf);
03188 conf = NULL;
03189 } else
03190 count = 0;
03191
03192 if (!ast_strlen_zero(args.varname)) {
03193
03194 snprintf(val, sizeof(val), "%d", count);
03195 pbx_builtin_setvar_helper(chan, args.varname, val);
03196 } else {
03197 if (chan->_state != AST_STATE_UP)
03198 ast_answer(chan);
03199 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
03200 }
03201
03202 return res;
03203 }
03204
03205
03206 static int conf_exec(struct ast_channel *chan, void *data)
03207 {
03208 int res = -1;
03209 char confno[MAX_CONFNUM] = "";
03210 int allowretry = 0;
03211 int retrycnt = 0;
03212 struct ast_conference *cnf = NULL;
03213 struct ast_flags confflags = {0}, config_flags = { 0 };
03214 int dynamic = 0;
03215 int empty = 0, empty_no_pin = 0;
03216 int always_prompt = 0;
03217 char *notdata, *info, the_pin[MAX_PIN] = "";
03218 AST_DECLARE_APP_ARGS(args,
03219 AST_APP_ARG(confno);
03220 AST_APP_ARG(options);
03221 AST_APP_ARG(pin);
03222 );
03223 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03224
03225 if (ast_strlen_zero(data)) {
03226 allowretry = 1;
03227 notdata = "";
03228 } else {
03229 notdata = data;
03230 }
03231
03232 if (chan->_state != AST_STATE_UP)
03233 ast_answer(chan);
03234
03235 info = ast_strdupa(notdata);
03236
03237 AST_STANDARD_APP_ARGS(args, info);
03238
03239 if (args.confno) {
03240 ast_copy_string(confno, args.confno, sizeof(confno));
03241 if (ast_strlen_zero(confno)) {
03242 allowretry = 1;
03243 }
03244 }
03245
03246 if (args.pin)
03247 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03248
03249 if (args.options) {
03250 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03251 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03252 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03253 strcpy(the_pin, "q");
03254
03255 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03256 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03257 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03258 }
03259
03260 do {
03261 if (retrycnt > 3)
03262 allowretry = 0;
03263 if (empty) {
03264 int i;
03265 struct ast_config *cfg;
03266 struct ast_variable *var;
03267 int confno_int;
03268
03269
03270 if ((empty_no_pin) || (!dynamic)) {
03271 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03272 if (cfg) {
03273 var = ast_variable_browse(cfg, "rooms");
03274 while (var) {
03275 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03276 if (!strcasecmp(var->name, "conf")) {
03277 int found = 0;
03278 ast_copy_string(parse, var->value, sizeof(parse));
03279 confno_tmp = strsep(&stringp, "|,");
03280 if (!dynamic) {
03281
03282 AST_LIST_LOCK(&confs);
03283 AST_LIST_TRAVERSE(&confs, cnf, list) {
03284 if (!strcmp(confno_tmp, cnf->confno)) {
03285
03286 found = 1;
03287 break;
03288 }
03289 }
03290 AST_LIST_UNLOCK(&confs);
03291 if (!found) {
03292
03293 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03294
03295
03296
03297
03298 ast_copy_string(confno, confno_tmp, sizeof(confno));
03299 break;
03300
03301 }
03302 }
03303 }
03304 }
03305 var = var->next;
03306 }
03307 ast_config_destroy(cfg);
03308 }
03309 }
03310
03311
03312 if (ast_strlen_zero(confno) && dynamic) {
03313 AST_LIST_LOCK(&confs);
03314 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03315 if (!conf_map[i]) {
03316 snprintf(confno, sizeof(confno), "%d", i);
03317 conf_map[i] = 1;
03318 break;
03319 }
03320 }
03321 AST_LIST_UNLOCK(&confs);
03322 }
03323
03324
03325 if (ast_strlen_zero(confno)) {
03326 res = ast_streamfile(chan, "conf-noempty", chan->language);
03327 if (!res)
03328 ast_waitstream(chan, "");
03329 } else {
03330 if (sscanf(confno, "%30d", &confno_int) == 1) {
03331 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03332 res = ast_streamfile(chan, "conf-enteringno", chan->language);
03333 if (!res) {
03334 ast_waitstream(chan, "");
03335 res = ast_say_digits(chan, confno_int, "", chan->language);
03336 }
03337 }
03338 } else {
03339 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03340 }
03341 }
03342 }
03343
03344 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03345
03346 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03347 if (res < 0) {
03348
03349 confno[0] = '\0';
03350 allowretry = 0;
03351 break;
03352 }
03353 }
03354 if (!ast_strlen_zero(confno)) {
03355
03356 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
03357 sizeof(the_pin), 1, &confflags);
03358 if (!cnf) {
03359 int too_early = 0;
03360 cnf = find_conf_realtime(chan, confno, 1, dynamic,
03361 the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early);
03362 if (rt_schedule && too_early)
03363 allowretry = 0;
03364 }
03365
03366 if (!cnf) {
03367 if (allowretry) {
03368 confno[0] = '\0';
03369 res = ast_streamfile(chan, "conf-invalid", chan->language);
03370 if (!res)
03371 ast_waitstream(chan, "");
03372 res = -1;
03373 }
03374 } else {
03375 if ((!ast_strlen_zero(cnf->pin) &&
03376 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03377 (!ast_strlen_zero(cnf->pinadmin) &&
03378 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03379 char pin[MAX_PIN] = "";
03380 int j;
03381
03382
03383 for (j = 0; j < 3; j++) {
03384 if (*the_pin && (always_prompt == 0)) {
03385 ast_copy_string(pin, the_pin, sizeof(pin));
03386 res = 0;
03387 } else {
03388
03389 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03390 }
03391 if (res >= 0) {
03392 if (!strcasecmp(pin, cnf->pin) ||
03393 (!ast_strlen_zero(cnf->pinadmin) &&
03394 !strcasecmp(pin, cnf->pinadmin))) {
03395
03396 allowretry = 0;
03397 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin))
03398 ast_set_flag(&confflags, CONFFLAG_ADMIN);
03399
03400 res = conf_run(chan, cnf, confflags.flags, optargs);
03401 break;
03402 } else {
03403
03404 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03405 res = ast_waitstream(chan, AST_DIGIT_ANY);
03406 ast_stopstream(chan);
03407 }
03408 else {
03409 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03410 break;
03411 }
03412 if (res < 0)
03413 break;
03414 pin[0] = res;
03415 pin[1] = '\0';
03416 res = -1;
03417 if (allowretry)
03418 confno[0] = '\0';
03419 }
03420 } else {
03421
03422 res = -1;
03423 allowretry = 0;
03424
03425 break;
03426 }
03427
03428
03429 if (*the_pin && (always_prompt == 0)) {
03430 break;
03431 }
03432 }
03433 } else {
03434
03435 allowretry = 0;
03436
03437
03438 res = conf_run(chan, cnf, confflags.flags, optargs);
03439 }
03440 dispose_conf(cnf);
03441 cnf = NULL;
03442 }
03443 }
03444 } while (allowretry);
03445
03446 if (cnf)
03447 dispose_conf(cnf);
03448
03449 return res;
03450 }
03451
03452 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
03453 {
03454 struct ast_conf_user *user = NULL;
03455 int cid;
03456
03457 sscanf(callerident, "%30i", &cid);
03458 if (conf && callerident) {
03459 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03460 if (cid == user->user_no)
03461 return user;
03462 }
03463 }
03464 return NULL;
03465 }
03466
03467
03468
03469 static int admin_exec(struct ast_channel *chan, void *data) {
03470 char *params;
03471 struct ast_conference *cnf;
03472 struct ast_conf_user *user = NULL;
03473 AST_DECLARE_APP_ARGS(args,
03474 AST_APP_ARG(confno);
03475 AST_APP_ARG(command);
03476 AST_APP_ARG(user);
03477 );
03478
03479 if (ast_strlen_zero(data)) {
03480 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03481 return -1;
03482 }
03483
03484 params = ast_strdupa(data);
03485 AST_STANDARD_APP_ARGS(args, params);
03486
03487 if (!args.command) {
03488 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03489 return -1;
03490 }
03491
03492 AST_LIST_LOCK(&confs);
03493 AST_LIST_TRAVERSE(&confs, cnf, list) {
03494 if (!strcmp(cnf->confno, args.confno))
03495 break;
03496 }
03497
03498 if (!cnf) {
03499 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03500 AST_LIST_UNLOCK(&confs);
03501 return 0;
03502 }
03503
03504 ast_atomic_fetchadd_int(&cnf->refcount, 1);
03505
03506 if (args.user)
03507 user = find_user(cnf, args.user);
03508
03509 switch (*args.command) {
03510 case 76:
03511 cnf->locked = 1;
03512 break;
03513 case 108:
03514 cnf->locked = 0;
03515 break;
03516 case 75:
03517 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03518 user->adminflags |= ADMINFLAG_KICKME;
03519 break;
03520 case 101:
03521 user = AST_LIST_LAST(&cnf->userlist);
03522 if (!(user->userflags & CONFFLAG_ADMIN))
03523 user->adminflags |= ADMINFLAG_KICKME;
03524 else
03525 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03526 break;
03527 case 77:
03528 if (user) {
03529 user->adminflags |= ADMINFLAG_MUTED;
03530 } else
03531 ast_log(LOG_NOTICE, "Specified User not found!\n");
03532 break;
03533 case 78:
03534 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03535 if (!(user->userflags & CONFFLAG_ADMIN))
03536 user->adminflags |= ADMINFLAG_MUTED;
03537 }
03538 break;
03539 case 109:
03540 if (user) {
03541 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03542 } else
03543 ast_log(LOG_NOTICE, "Specified User not found!\n");
03544 break;
03545 case 110:
03546 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03547 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03548 break;
03549 case 107:
03550 if (user)
03551 user->adminflags |= ADMINFLAG_KICKME;
03552 else
03553 ast_log(LOG_NOTICE, "Specified User not found!\n");
03554 break;
03555 case 118:
03556 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03557 tweak_listen_volume(user, VOL_DOWN);
03558 break;
03559 case 86:
03560 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03561 tweak_listen_volume(user, VOL_UP);
03562 break;
03563 case 115:
03564 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03565 tweak_talk_volume(user, VOL_DOWN);
03566 break;
03567 case 83:
03568 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03569 tweak_talk_volume(user, VOL_UP);
03570 break;
03571 case 82:
03572 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03573 reset_volumes(user);
03574 break;
03575 case 114:
03576 if (user)
03577 reset_volumes(user);
03578 else
03579 ast_log(LOG_NOTICE, "Specified User not found!\n");
03580 break;
03581 case 85:
03582 if (user)
03583 tweak_listen_volume(user, VOL_UP);
03584 else
03585 ast_log(LOG_NOTICE, "Specified User not found!\n");
03586 break;
03587 case 117:
03588 if (user)
03589 tweak_listen_volume(user, VOL_DOWN);
03590 else
03591 ast_log(LOG_NOTICE, "Specified User not found!\n");
03592 break;
03593 case 84:
03594 if (user)
03595 tweak_talk_volume(user, VOL_UP);
03596 else
03597 ast_log(LOG_NOTICE, "Specified User not found!\n");
03598 break;
03599 case 116:
03600 if (user)
03601 tweak_talk_volume(user, VOL_DOWN);
03602 else
03603 ast_log(LOG_NOTICE, "Specified User not found!\n");
03604 break;
03605 }
03606
03607 AST_LIST_UNLOCK(&confs);
03608
03609 dispose_conf(cnf);
03610
03611 return 0;
03612 }
03613
03614
03615
03616 static int channel_admin_exec(struct ast_channel *chan, void *data) {
03617 char *params;
03618 struct ast_conference *conf = NULL;
03619 struct ast_conf_user *user = NULL;
03620 AST_DECLARE_APP_ARGS(args,
03621 AST_APP_ARG(channel);
03622 AST_APP_ARG(command);
03623 );
03624
03625 if (ast_strlen_zero(data)) {
03626 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03627 return -1;
03628 }
03629
03630 params = ast_strdupa(data);
03631 AST_STANDARD_APP_ARGS(args, params);
03632
03633 if (!args.channel) {
03634 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03635 return -1;
03636 }
03637
03638 if (!args.command) {
03639 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03640 return -1;
03641 }
03642
03643 AST_LIST_LOCK(&confs);
03644 AST_LIST_TRAVERSE(&confs, conf, list) {
03645 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03646 if (!strcmp(user->chan->name, args.channel))
03647 break;
03648 }
03649 }
03650
03651 if (!user) {
03652 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03653 AST_LIST_UNLOCK(&confs);
03654 return 0;
03655 }
03656
03657
03658 switch (*args.command) {
03659 case 77:
03660 user->adminflags |= ADMINFLAG_MUTED;
03661 break;
03662 case 109:
03663 user->adminflags &= ~ADMINFLAG_MUTED;
03664 break;
03665 case 107:
03666 user->adminflags |= ADMINFLAG_KICKME;
03667 break;
03668 default:
03669 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03670 break;
03671 }
03672
03673 AST_LIST_UNLOCK(&confs);
03674
03675 return 0;
03676 }
03677
03678 static int meetmemute(struct mansession *s, const struct message *m, int mute)
03679 {
03680 struct ast_conference *conf;
03681 struct ast_conf_user *user;
03682 const char *confid = astman_get_header(m, "Meetme");
03683 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03684 int userno;
03685
03686 if (ast_strlen_zero(confid)) {
03687 astman_send_error(s, m, "Meetme conference not specified");
03688 return 0;
03689 }
03690
03691 if (ast_strlen_zero(userid)) {
03692 astman_send_error(s, m, "Meetme user number not specified");
03693 return 0;
03694 }
03695
03696 userno = strtoul(userid, &userid, 10);
03697
03698 if (*userid) {
03699 astman_send_error(s, m, "Invalid user number");
03700 return 0;
03701 }
03702
03703
03704 AST_LIST_LOCK(&confs);
03705 AST_LIST_TRAVERSE(&confs, conf, list) {
03706 if (!strcmp(confid, conf->confno))
03707 break;
03708 }
03709
03710 if (!conf) {
03711 AST_LIST_UNLOCK(&confs);
03712 astman_send_error(s, m, "Meetme conference does not exist");
03713 return 0;
03714 }
03715
03716 AST_LIST_TRAVERSE(&conf->userlist, user, list)
03717 if (user->user_no == userno)
03718 break;
03719
03720 if (!user) {
03721 AST_LIST_UNLOCK(&confs);
03722 astman_send_error(s, m, "User number not found");
03723 return 0;
03724 }
03725
03726 if (mute)
03727 user->adminflags |= ADMINFLAG_MUTED;
03728 else
03729 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03730
03731 AST_LIST_UNLOCK(&confs);
03732
03733 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);
03734
03735 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03736 return 0;
03737 }
03738
03739 static int action_meetmemute(struct mansession *s, const struct message *m)
03740 {
03741 return meetmemute(s, m, 1);
03742 }
03743
03744 static int action_meetmeunmute(struct mansession *s, const struct message *m)
03745 {
03746 return meetmemute(s, m, 0);
03747 }
03748
03749 static char mandescr_meetmelist[] =
03750 "Description: Lists all users in a particular MeetMe conference.\n"
03751 "MeetmeList will follow as separate events, followed by a final event called\n"
03752 "MeetmeListComplete.\n"
03753 "Variables:\n"
03754 " *ActionId: <id>\n"
03755 " *Conference: <confno>\n";
03756
03757 static int action_meetmelist(struct mansession *s, const struct message *m)
03758 {
03759 const char *actionid = astman_get_header(m, "ActionID");
03760 const char *conference = astman_get_header(m, "Conference");
03761 char idText[80] = "";
03762 struct ast_conference *cnf;
03763 struct ast_conf_user *user;
03764 int total = 0;
03765
03766 if (!ast_strlen_zero(actionid))
03767 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03768
03769 if (AST_LIST_EMPTY(&confs)) {
03770 astman_send_error(s, m, "No active conferences.");
03771 return 0;
03772 }
03773
03774 astman_send_listack(s, m, "Meetme user list will follow", "start");
03775
03776
03777 AST_LIST_LOCK(&confs);
03778 AST_LIST_TRAVERSE(&confs, cnf, list) {
03779
03780 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03781 continue;
03782
03783
03784 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03785 total++;
03786 astman_append(s,
03787 "Event: MeetmeList\r\n"
03788 "%s"
03789 "Conference: %s\r\n"
03790 "UserNumber: %d\r\n"
03791 "CallerIDNum: %s\r\n"
03792 "CallerIDName: %s\r\n"
03793 "Channel: %s\r\n"
03794 "Admin: %s\r\n"
03795 "Role: %s\r\n"
03796 "MarkedUser: %s\r\n"
03797 "Muted: %s\r\n"
03798 "Talking: %s\r\n"
03799 "\r\n",
03800 idText,
03801 cnf->confno,
03802 user->user_no,
03803 S_OR(user->chan->cid.cid_num, "<unknown>"),
03804 S_OR(user->chan->cid.cid_name, "<no name>"),
03805 user->chan->name,
03806 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03807 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03808 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03809 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03810 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
03811 }
03812 }
03813 AST_LIST_UNLOCK(&confs);
03814
03815 astman_append(s,
03816 "Event: MeetmeListComplete\r\n"
03817 "EventList: Complete\r\n"
03818 "ListItems: %d\r\n"
03819 "%s"
03820 "\r\n", total, idText);
03821 return 0;
03822 }
03823
03824 static void *recordthread(void *args)
03825 {
03826 struct ast_conference *cnf = args;
03827 struct ast_frame *f = NULL;
03828 int flags;
03829 struct ast_filestream *s = NULL;
03830 int res = 0;
03831 int x;
03832 const char *oldrecordingfilename = NULL;
03833
03834 if (!cnf || !cnf->lchan) {
03835 pthread_exit(0);
03836 }
03837
03838 ast_stopstream(cnf->lchan);
03839 flags = O_CREAT | O_TRUNC | O_WRONLY;
03840
03841
03842 cnf->recording = MEETME_RECORD_ACTIVE;
03843 while (ast_waitfor(cnf->lchan, -1) > -1) {
03844 if (cnf->recording == MEETME_RECORD_TERMINATE) {
03845 AST_LIST_LOCK(&confs);
03846 AST_LIST_UNLOCK(&confs);
03847 break;
03848 }
03849 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03850 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03851 oldrecordingfilename = cnf->recordingfilename;
03852 }
03853
03854 f = ast_read(cnf->lchan);
03855 if (!f) {
03856 res = -1;
03857 break;
03858 }
03859 if (f->frametype == AST_FRAME_VOICE) {
03860 ast_mutex_lock(&cnf->listenlock);
03861 for (x = 0; x < AST_FRAME_BITS; x++) {
03862
03863 if (cnf->transframe[x]) {
03864 ast_frfree(cnf->transframe[x]);
03865 cnf->transframe[x] = NULL;
03866 }
03867 }
03868 if (cnf->origframe)
03869 ast_frfree(cnf->origframe);
03870 cnf->origframe = ast_frdup(f);
03871 ast_mutex_unlock(&cnf->listenlock);
03872 if (s)
03873 res = ast_writestream(s, f);
03874 if (res) {
03875 ast_frfree(f);
03876 break;
03877 }
03878 }
03879 ast_frfree(f);
03880 }
03881 cnf->recording = MEETME_RECORD_OFF;
03882 if (s)
03883 ast_closestream(s);
03884
03885 pthread_exit(0);
03886 }
03887
03888
03889 static enum ast_device_state meetmestate(const char *data)
03890 {
03891 struct ast_conference *conf;
03892
03893
03894 AST_LIST_LOCK(&confs);
03895 AST_LIST_TRAVERSE(&confs, conf, list) {
03896 if (!strcmp(data, conf->confno))
03897 break;
03898 }
03899 AST_LIST_UNLOCK(&confs);
03900 if (!conf)
03901 return AST_DEVICE_INVALID;
03902
03903
03904
03905 if (!conf->users)
03906 return AST_DEVICE_NOT_INUSE;
03907
03908 return AST_DEVICE_INUSE;
03909 }
03910
03911 static void load_config_meetme(void)
03912 {
03913 struct ast_config *cfg;
03914 struct ast_flags config_flags = { 0 };
03915 const char *val;
03916
03917 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03918 return;
03919
03920 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03921
03922
03923 rt_schedule = 0;
03924 fuzzystart = 0;
03925 earlyalert = 0;
03926 endalert = 0;
03927
03928
03929 rt_log_members = 1;
03930
03931 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03932 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03933 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03934 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03935 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03936 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03937 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03938 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03939 }
03940 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03941 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03942 }
03943
03944 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03945 rt_schedule = ast_true(val);
03946 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03947 rt_log_members = ast_true(val);
03948 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03949 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
03950 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03951 fuzzystart = 0;
03952 }
03953 }
03954 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03955 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
03956 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03957 earlyalert = 0;
03958 }
03959 }
03960 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03961 if ((sscanf(val, "%30d", &endalert) != 1)) {
03962 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03963 endalert = 0;
03964 }
03965 }
03966
03967 ast_config_destroy(cfg);
03968 }
03969
03970
03971
03972
03973 static struct sla_trunk *sla_find_trunk(const char *name)
03974 {
03975 struct sla_trunk *trunk = NULL;
03976
03977 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03978 if (!strcasecmp(trunk->name, name))
03979 break;
03980 }
03981
03982 return trunk;
03983 }
03984
03985
03986
03987
03988 static struct sla_station *sla_find_station(const char *name)
03989 {
03990 struct sla_station *station = NULL;
03991
03992 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03993 if (!strcasecmp(station->name, name))
03994 break;
03995 }
03996
03997 return station;
03998 }
03999
04000 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
04001 const struct sla_station *station)
04002 {
04003 struct sla_station_ref *station_ref;
04004 struct sla_trunk_ref *trunk_ref;
04005
04006
04007 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04008 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04009 if (trunk_ref->trunk != trunk || station_ref->station == station)
04010 continue;
04011 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04012 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04013 return 1;
04014 return 0;
04015 }
04016 }
04017
04018 return 0;
04019 }
04020
04021
04022
04023
04024
04025
04026
04027
04028 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
04029 const char *name)
04030 {
04031 struct sla_trunk_ref *trunk_ref = NULL;
04032
04033 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04034 if (strcasecmp(trunk_ref->trunk->name, name))
04035 continue;
04036
04037 if ( (trunk_ref->trunk->barge_disabled
04038 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04039 (trunk_ref->trunk->hold_stations
04040 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04041 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04042 sla_check_station_hold_access(trunk_ref->trunk, station) )
04043 {
04044 trunk_ref = NULL;
04045 }
04046
04047 break;
04048 }
04049
04050 return trunk_ref;
04051 }
04052
04053 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
04054 {
04055 struct sla_station_ref *station_ref;
04056
04057 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04058 return NULL;
04059
04060 station_ref->station = station;
04061
04062 return station_ref;
04063 }
04064
04065 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
04066 {
04067 struct sla_ringing_station *ringing_station;
04068
04069 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04070 return NULL;
04071
04072 ringing_station->station = station;
04073 ringing_station->ring_begin = ast_tvnow();
04074
04075 return ringing_station;
04076 }
04077
04078 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
04079 {
04080 switch (state) {
04081 case SLA_TRUNK_STATE_IDLE:
04082 return AST_DEVICE_NOT_INUSE;
04083 case SLA_TRUNK_STATE_RINGING:
04084 return AST_DEVICE_RINGING;
04085 case SLA_TRUNK_STATE_UP:
04086 return AST_DEVICE_INUSE;
04087 case SLA_TRUNK_STATE_ONHOLD:
04088 case SLA_TRUNK_STATE_ONHOLD_BYME:
04089 return AST_DEVICE_ONHOLD;
04090 }
04091
04092 return AST_DEVICE_UNKNOWN;
04093 }
04094
04095 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
04096 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
04097 {
04098 struct sla_station *station;
04099 struct sla_trunk_ref *trunk_ref;
04100
04101 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04102 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04103 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04104 || trunk_ref == exclude)
04105 continue;
04106 trunk_ref->state = state;
04107 ast_devstate_changed(sla_state_to_devstate(state),
04108 "SLA:%s_%s", station->name, trunk->name);
04109 break;
04110 }
04111 }
04112 }
04113
04114 struct run_station_args {
04115 struct sla_station *station;
04116 struct sla_trunk_ref *trunk_ref;
04117 ast_mutex_t *cond_lock;
04118 ast_cond_t *cond;
04119 };
04120
04121 static void answer_trunk_chan(struct ast_channel *chan)
04122 {
04123 ast_answer(chan);
04124 ast_indicate(chan, -1);
04125 }
04126
04127 static void *run_station(void *data)
04128 {
04129 struct sla_station *station;
04130 struct sla_trunk_ref *trunk_ref;
04131 struct ast_str *conf_name = ast_str_create(16);
04132 struct ast_flags conf_flags = { 0 };
04133 struct ast_conference *conf;
04134
04135 {
04136 struct run_station_args *args = data;
04137 station = args->station;
04138 trunk_ref = args->trunk_ref;
04139 ast_mutex_lock(args->cond_lock);
04140 ast_cond_signal(args->cond);
04141 ast_mutex_unlock(args->cond_lock);
04142
04143 }
04144
04145 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04146 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04147 ast_set_flag(&conf_flags,
04148 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04149 answer_trunk_chan(trunk_ref->chan);
04150 conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
04151 if (conf) {
04152 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04153 dispose_conf(conf);
04154 conf = NULL;
04155 }
04156 trunk_ref->chan = NULL;
04157 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04158 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04159 ast_str_append(&conf_name, 0, ",K");
04160 admin_exec(NULL, conf_name->str);
04161 trunk_ref->trunk->hold_stations = 0;
04162 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04163 }
04164
04165 ast_dial_join(station->dial);
04166 ast_dial_destroy(station->dial);
04167 station->dial = NULL;
04168 ast_free(conf_name);
04169
04170 return NULL;
04171 }
04172
04173 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
04174 {
04175 char buf[80];
04176 struct sla_station_ref *station_ref;
04177
04178 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04179 admin_exec(NULL, buf);
04180 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04181
04182 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04183 ast_free(station_ref);
04184
04185 ast_free(ringing_trunk);
04186 }
04187
04188 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
04189 enum sla_station_hangup hangup)
04190 {
04191 struct sla_ringing_trunk *ringing_trunk;
04192 struct sla_trunk_ref *trunk_ref;
04193 struct sla_station_ref *station_ref;
04194
04195 ast_dial_join(ringing_station->station->dial);
04196 ast_dial_destroy(ringing_station->station->dial);
04197 ringing_station->station->dial = NULL;
04198
04199 if (hangup == SLA_STATION_HANGUP_NORMAL)
04200 goto done;
04201
04202
04203
04204
04205
04206
04207 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04208 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04209 if (ringing_trunk->trunk == trunk_ref->trunk)
04210 break;
04211 }
04212 if (!trunk_ref)
04213 continue;
04214 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04215 continue;
04216 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04217 }
04218
04219 done:
04220 ast_free(ringing_station);
04221 }
04222
04223 static void sla_dial_state_callback(struct ast_dial *dial)
04224 {
04225 sla_queue_event(SLA_EVENT_DIAL_STATE);
04226 }
04227
04228
04229
04230
04231 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
04232 const struct sla_station *station)
04233 {
04234 struct sla_station_ref *timed_out_station;
04235
04236 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04237 if (station == timed_out_station->station)
04238 return 1;
04239 }
04240
04241 return 0;
04242 }
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
04253 struct sla_trunk_ref **trunk_ref, int rm)
04254 {
04255 struct sla_trunk_ref *s_trunk_ref;
04256 struct sla_ringing_trunk *ringing_trunk = NULL;
04257
04258 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04259 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04260
04261 if (s_trunk_ref->trunk != ringing_trunk->trunk)
04262 continue;
04263
04264
04265
04266 if (sla_check_timed_out_station(ringing_trunk, station))
04267 continue;
04268
04269 if (rm)
04270 AST_LIST_REMOVE_CURRENT(entry);
04271
04272 if (trunk_ref)
04273 *trunk_ref = s_trunk_ref;
04274
04275 break;
04276 }
04277 AST_LIST_TRAVERSE_SAFE_END;
04278
04279 if (ringing_trunk)
04280 break;
04281 }
04282
04283 return ringing_trunk;
04284 }
04285
04286 static void sla_handle_dial_state_event(void)
04287 {
04288 struct sla_ringing_station *ringing_station;
04289
04290 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04291 struct sla_trunk_ref *s_trunk_ref = NULL;
04292 struct sla_ringing_trunk *ringing_trunk = NULL;
04293 struct run_station_args args;
04294 enum ast_dial_result dial_res;
04295 pthread_t dont_care;
04296 ast_mutex_t cond_lock;
04297 ast_cond_t cond;
04298
04299 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04300 case AST_DIAL_RESULT_HANGUP:
04301 case AST_DIAL_RESULT_INVALID:
04302 case AST_DIAL_RESULT_FAILED:
04303 case AST_DIAL_RESULT_TIMEOUT:
04304 case AST_DIAL_RESULT_UNANSWERED:
04305 AST_LIST_REMOVE_CURRENT(entry);
04306 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04307 break;
04308 case AST_DIAL_RESULT_ANSWERED:
04309 AST_LIST_REMOVE_CURRENT(entry);
04310
04311 ast_mutex_lock(&sla.lock);
04312 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04313 ast_mutex_unlock(&sla.lock);
04314 if (!ringing_trunk) {
04315 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04316 break;
04317 }
04318
04319 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04320
04321 answer_trunk_chan(ringing_trunk->trunk->chan);
04322 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04323
04324
04325
04326 args.trunk_ref = s_trunk_ref;
04327 args.station = ringing_station->station;
04328 args.cond = &cond;
04329 args.cond_lock = &cond_lock;
04330 ast_free(ringing_trunk);
04331 ast_free(ringing_station);
04332 ast_mutex_init(&cond_lock);
04333 ast_cond_init(&cond, NULL);
04334 ast_mutex_lock(&cond_lock);
04335 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04336 ast_cond_wait(&cond, &cond_lock);
04337 ast_mutex_unlock(&cond_lock);
04338 ast_mutex_destroy(&cond_lock);
04339 ast_cond_destroy(&cond);
04340 break;
04341 case AST_DIAL_RESULT_TRYING:
04342 case AST_DIAL_RESULT_RINGING:
04343 case AST_DIAL_RESULT_PROGRESS:
04344 case AST_DIAL_RESULT_PROCEEDING:
04345 break;
04346 }
04347 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04348
04349 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04350 sla_queue_event(SLA_EVENT_DIAL_STATE);
04351 break;
04352 }
04353 }
04354 AST_LIST_TRAVERSE_SAFE_END;
04355 }
04356
04357
04358
04359
04360 static int sla_check_ringing_station(const struct sla_station *station)
04361 {
04362 struct sla_ringing_station *ringing_station;
04363
04364 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04365 if (station == ringing_station->station)
04366 return 1;
04367 }
04368
04369 return 0;
04370 }
04371
04372
04373
04374
04375 static int sla_check_failed_station(const struct sla_station *station)
04376 {
04377 struct sla_failed_station *failed_station;
04378 int res = 0;
04379
04380 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04381 if (station != failed_station->station)
04382 continue;
04383 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04384 AST_LIST_REMOVE_CURRENT(entry);
04385 ast_free(failed_station);
04386 break;
04387 }
04388 res = 1;
04389 }
04390 AST_LIST_TRAVERSE_SAFE_END
04391
04392 return res;
04393 }
04394
04395
04396
04397
04398 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
04399 {
04400 char *tech, *tech_data;
04401 struct ast_dial *dial;
04402 struct sla_ringing_station *ringing_station;
04403 const char *cid_name = NULL, *cid_num = NULL;
04404 enum ast_dial_result res;
04405
04406 if (!(dial = ast_dial_create()))
04407 return -1;
04408
04409 ast_dial_set_state_callback(dial, sla_dial_state_callback);
04410 tech_data = ast_strdupa(station->device);
04411 tech = strsep(&tech_data, "/");
04412
04413 if (ast_dial_append(dial, tech, tech_data) == -1) {
04414 ast_dial_destroy(dial);
04415 return -1;
04416 }
04417
04418 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04419 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04420 ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04421 ringing_trunk->trunk->chan->cid.cid_name = NULL;
04422 }
04423 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04424 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04425 ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04426 ringing_trunk->trunk->chan->cid.cid_num = NULL;
04427 }
04428
04429 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04430
04431 if (cid_name)
04432 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04433 if (cid_num)
04434 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04435
04436 if (res != AST_DIAL_RESULT_TRYING) {
04437 struct sla_failed_station *failed_station;
04438 ast_dial_destroy(dial);
04439 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04440 return -1;
04441 failed_station->station = station;
04442 failed_station->last_try = ast_tvnow();
04443 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04444 return -1;
04445 }
04446 if (!(ringing_station = sla_create_ringing_station(station))) {
04447 ast_dial_join(dial);
04448 ast_dial_destroy(dial);
04449 return -1;
04450 }
04451
04452 station->dial = dial;
04453
04454 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04455
04456 return 0;
04457 }
04458
04459
04460
04461 static int sla_check_inuse_station(const struct sla_station *station)
04462 {
04463 struct sla_trunk_ref *trunk_ref;
04464
04465 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04466 if (trunk_ref->chan)
04467 return 1;
04468 }
04469
04470 return 0;
04471 }
04472
04473 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
04474 const struct sla_trunk *trunk)
04475 {
04476 struct sla_trunk_ref *trunk_ref = NULL;
04477
04478 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04479 if (trunk_ref->trunk == trunk)
04480 break;
04481 }
04482
04483 return trunk_ref;
04484 }
04485
04486
04487
04488
04489
04490
04491 static int sla_check_station_delay(struct sla_station *station,
04492 struct sla_ringing_trunk *ringing_trunk)
04493 {
04494 struct sla_trunk_ref *trunk_ref;
04495 unsigned int delay = UINT_MAX;
04496 int time_left, time_elapsed;
04497
04498 if (!ringing_trunk)
04499 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04500 else
04501 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04502
04503 if (!ringing_trunk || !trunk_ref)
04504 return delay;
04505
04506
04507
04508
04509 delay = trunk_ref->ring_delay;
04510 if (!delay)
04511 delay = station->ring_delay;
04512 if (!delay)
04513 return INT_MAX;
04514
04515 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04516 time_left = (delay * 1000) - time_elapsed;
04517
04518 return time_left;
04519 }
04520
04521
04522
04523
04524 static void sla_ring_stations(void)
04525 {
04526 struct sla_station_ref *station_ref;
04527 struct sla_ringing_trunk *ringing_trunk;
04528
04529
04530
04531 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04532 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04533 int time_left;
04534
04535
04536 if (sla_check_ringing_station(station_ref->station))
04537 continue;
04538
04539
04540 if (sla_check_inuse_station(station_ref->station))
04541 continue;
04542
04543
04544
04545 if (sla_check_failed_station(station_ref->station))
04546 continue;
04547
04548
04549
04550 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04551 continue;
04552
04553
04554 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04555 if (time_left != INT_MAX && time_left > 0)
04556 continue;
04557
04558
04559 sla_ring_station(ringing_trunk, station_ref->station);
04560 }
04561 }
04562
04563 }
04564
04565 static void sla_hangup_stations(void)
04566 {
04567 struct sla_trunk_ref *trunk_ref;
04568 struct sla_ringing_station *ringing_station;
04569
04570 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04571 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04572 struct sla_ringing_trunk *ringing_trunk;
04573 ast_mutex_lock(&sla.lock);
04574 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04575 if (trunk_ref->trunk == ringing_trunk->trunk)
04576 break;
04577 }
04578 ast_mutex_unlock(&sla.lock);
04579 if (ringing_trunk)
04580 break;
04581 }
04582 if (!trunk_ref) {
04583 AST_LIST_REMOVE_CURRENT(entry);
04584 ast_dial_join(ringing_station->station->dial);
04585 ast_dial_destroy(ringing_station->station->dial);
04586 ringing_station->station->dial = NULL;
04587 ast_free(ringing_station);
04588 }
04589 }
04590 AST_LIST_TRAVERSE_SAFE_END
04591 }
04592
04593 static void sla_handle_ringing_trunk_event(void)
04594 {
04595 ast_mutex_lock(&sla.lock);
04596 sla_ring_stations();
04597 ast_mutex_unlock(&sla.lock);
04598
04599
04600 sla_hangup_stations();
04601 }
04602
04603 static void sla_handle_hold_event(struct sla_event *event)
04604 {
04605 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04606 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04607 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s",
04608 event->station->name, event->trunk_ref->trunk->name);
04609 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
04610 INACTIVE_TRUNK_REFS, event->trunk_ref);
04611
04612 if (event->trunk_ref->trunk->active_stations == 1) {
04613
04614
04615 event->trunk_ref->trunk->on_hold = 1;
04616 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04617 }
04618
04619 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
04620 event->trunk_ref->chan = NULL;
04621 }
04622
04623
04624
04625
04626
04627 static int sla_calc_trunk_timeouts(unsigned int *timeout)
04628 {
04629 struct sla_ringing_trunk *ringing_trunk;
04630 int res = 0;
04631
04632 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04633 int time_left, time_elapsed;
04634 if (!ringing_trunk->trunk->ring_timeout)
04635 continue;
04636 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04637 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04638 if (time_left <= 0) {
04639 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04640 AST_LIST_REMOVE_CURRENT(entry);
04641 sla_stop_ringing_trunk(ringing_trunk);
04642 res = 1;
04643 continue;
04644 }
04645 if (time_left < *timeout)
04646 *timeout = time_left;
04647 }
04648 AST_LIST_TRAVERSE_SAFE_END;
04649
04650 return res;
04651 }
04652
04653
04654
04655
04656
04657 static int sla_calc_station_timeouts(unsigned int *timeout)
04658 {
04659 struct sla_ringing_trunk *ringing_trunk;
04660 struct sla_ringing_station *ringing_station;
04661 int res = 0;
04662
04663 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04664 unsigned int ring_timeout = 0;
04665 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04666 struct sla_trunk_ref *trunk_ref;
04667
04668
04669
04670
04671 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04672 struct sla_station_ref *station_ref;
04673 int trunk_time_elapsed, trunk_time_left;
04674
04675 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04676 if (ringing_trunk->trunk == trunk_ref->trunk)
04677 break;
04678 }
04679 if (!ringing_trunk)
04680 continue;
04681
04682
04683
04684 if (!trunk_ref->ring_timeout)
04685 break;
04686
04687
04688
04689
04690 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04691 if (station_ref->station == ringing_station->station)
04692 break;
04693 }
04694 if (station_ref)
04695 continue;
04696
04697 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04698 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04699 if (trunk_time_left > final_trunk_time_left)
04700 final_trunk_time_left = trunk_time_left;
04701 }
04702
04703
04704 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04705 continue;
04706
04707
04708 if (ringing_station->station->ring_timeout) {
04709 ring_timeout = ringing_station->station->ring_timeout;
04710 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04711 time_left = (ring_timeout * 1000) - time_elapsed;
04712 }
04713
04714
04715
04716 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04717 time_left = final_trunk_time_left;
04718
04719
04720 if (time_left <= 0) {
04721 AST_LIST_REMOVE_CURRENT(entry);
04722 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04723 res = 1;
04724 continue;
04725 }
04726
04727
04728
04729 if (time_left < *timeout)
04730 *timeout = time_left;
04731 }
04732 AST_LIST_TRAVERSE_SAFE_END;
04733
04734 return res;
04735 }
04736
04737
04738
04739
04740 static int sla_calc_station_delays(unsigned int *timeout)
04741 {
04742 struct sla_station *station;
04743 int res = 0;
04744
04745 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04746 struct sla_ringing_trunk *ringing_trunk;
04747 int time_left;
04748
04749
04750 if (sla_check_ringing_station(station))
04751 continue;
04752
04753
04754 if (sla_check_inuse_station(station))
04755 continue;
04756
04757
04758 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04759 continue;
04760
04761 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04762 continue;
04763
04764
04765
04766
04767 if (time_left <= 0) {
04768 res = 1;
04769 continue;
04770 }
04771
04772 if (time_left < *timeout)
04773 *timeout = time_left;
04774 }
04775
04776 return res;
04777 }
04778
04779
04780
04781 static int sla_process_timers(struct timespec *ts)
04782 {
04783 unsigned int timeout = UINT_MAX;
04784 struct timeval wait;
04785 unsigned int change_made = 0;
04786
04787
04788 if (sla_calc_trunk_timeouts(&timeout))
04789 change_made = 1;
04790
04791
04792 if (sla_calc_station_timeouts(&timeout))
04793 change_made = 1;
04794
04795
04796 if (sla_calc_station_delays(&timeout))
04797 change_made = 1;
04798
04799
04800 if (change_made)
04801 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04802
04803
04804 if (timeout == UINT_MAX)
04805 return 0;
04806
04807 if (ts) {
04808 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04809 ts->tv_sec = wait.tv_sec;
04810 ts->tv_nsec = wait.tv_usec * 1000;
04811 }
04812
04813 return 1;
04814 }
04815
04816 static int sla_load_config(int reload);
04817
04818
04819 static void sla_check_reload(void)
04820 {
04821 struct sla_station *station;
04822 struct sla_trunk *trunk;
04823
04824 ast_mutex_lock(&sla.lock);
04825
04826 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
04827 || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04828 ast_mutex_unlock(&sla.lock);
04829 return;
04830 }
04831
04832 AST_RWLIST_RDLOCK(&sla_stations);
04833 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04834 if (station->ref_count)
04835 break;
04836 }
04837 AST_RWLIST_UNLOCK(&sla_stations);
04838 if (station) {
04839 ast_mutex_unlock(&sla.lock);
04840 return;
04841 }
04842
04843 AST_RWLIST_RDLOCK(&sla_trunks);
04844 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04845 if (trunk->ref_count)
04846 break;
04847 }
04848 AST_RWLIST_UNLOCK(&sla_trunks);
04849 if (trunk) {
04850 ast_mutex_unlock(&sla.lock);
04851 return;
04852 }
04853
04854
04855 sla_load_config(1);
04856 sla.reload = 0;
04857
04858 ast_mutex_unlock(&sla.lock);
04859 }
04860
04861 static void *sla_thread(void *data)
04862 {
04863 struct sla_failed_station *failed_station;
04864 struct sla_ringing_station *ringing_station;
04865
04866 ast_mutex_lock(&sla.lock);
04867
04868 while (!sla.stop) {
04869 struct sla_event *event;
04870 struct timespec ts = { 0, };
04871 unsigned int have_timeout = 0;
04872
04873 if (AST_LIST_EMPTY(&sla.event_q)) {
04874 if ((have_timeout = sla_process_timers(&ts)))
04875 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04876 else
04877 ast_cond_wait(&sla.cond, &sla.lock);
04878 if (sla.stop)
04879 break;
04880 }
04881
04882 if (have_timeout)
04883 sla_process_timers(NULL);
04884
04885 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04886 ast_mutex_unlock(&sla.lock);
04887 switch (event->type) {
04888 case SLA_EVENT_HOLD:
04889 sla_handle_hold_event(event);
04890 break;
04891 case SLA_EVENT_DIAL_STATE:
04892 sla_handle_dial_state_event();
04893 break;
04894 case SLA_EVENT_RINGING_TRUNK:
04895 sla_handle_ringing_trunk_event();
04896 break;
04897 case SLA_EVENT_RELOAD:
04898 sla.reload = 1;
04899 case SLA_EVENT_CHECK_RELOAD:
04900 break;
04901 }
04902 ast_free(event);
04903 ast_mutex_lock(&sla.lock);
04904 }
04905
04906 if (sla.reload)
04907 sla_check_reload();
04908 }
04909
04910 ast_mutex_unlock(&sla.lock);
04911
04912 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04913 ast_free(ringing_station);
04914
04915 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04916 ast_free(failed_station);
04917
04918 return NULL;
04919 }
04920
04921 struct dial_trunk_args {
04922 struct sla_trunk_ref *trunk_ref;
04923 struct sla_station *station;
04924 ast_mutex_t *cond_lock;
04925 ast_cond_t *cond;
04926 };
04927
04928 static void *dial_trunk(void *data)
04929 {
04930 struct dial_trunk_args *args = data;
04931 struct ast_dial *dial;
04932 char *tech, *tech_data;
04933 enum ast_dial_result dial_res;
04934 char conf_name[MAX_CONFNUM];
04935 struct ast_conference *conf;
04936 struct ast_flags conf_flags = { 0 };
04937 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04938 const char *cid_name = NULL, *cid_num = NULL;
04939
04940 if (!(dial = ast_dial_create())) {
04941 ast_mutex_lock(args->cond_lock);
04942 ast_cond_signal(args->cond);
04943 ast_mutex_unlock(args->cond_lock);
04944 return NULL;
04945 }
04946
04947 tech_data = ast_strdupa(trunk_ref->trunk->device);
04948 tech = strsep(&tech_data, "/");
04949 if (ast_dial_append(dial, tech, tech_data) == -1) {
04950 ast_mutex_lock(args->cond_lock);
04951 ast_cond_signal(args->cond);
04952 ast_mutex_unlock(args->cond_lock);
04953 ast_dial_destroy(dial);
04954 return NULL;
04955 }
04956
04957 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04958 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04959 ast_free(trunk_ref->chan->cid.cid_name);
04960 trunk_ref->chan->cid.cid_name = NULL;
04961 }
04962 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04963 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04964 ast_free(trunk_ref->chan->cid.cid_num);
04965 trunk_ref->chan->cid.cid_num = NULL;
04966 }
04967
04968 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04969
04970 if (cid_name)
04971 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04972 if (cid_num)
04973 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04974
04975 if (dial_res != AST_DIAL_RESULT_TRYING) {
04976 ast_mutex_lock(args->cond_lock);
04977 ast_cond_signal(args->cond);
04978 ast_mutex_unlock(args->cond_lock);
04979 ast_dial_destroy(dial);
04980 return NULL;
04981 }
04982
04983 for (;;) {
04984 unsigned int done = 0;
04985 switch ((dial_res = ast_dial_state(dial))) {
04986 case AST_DIAL_RESULT_ANSWERED:
04987 trunk_ref->trunk->chan = ast_dial_answered(dial);
04988 case AST_DIAL_RESULT_HANGUP:
04989 case AST_DIAL_RESULT_INVALID:
04990 case AST_DIAL_RESULT_FAILED:
04991 case AST_DIAL_RESULT_TIMEOUT:
04992 case AST_DIAL_RESULT_UNANSWERED:
04993 done = 1;
04994 case AST_DIAL_RESULT_TRYING:
04995 case AST_DIAL_RESULT_RINGING:
04996 case AST_DIAL_RESULT_PROGRESS:
04997 case AST_DIAL_RESULT_PROCEEDING:
04998 break;
04999 }
05000 if (done)
05001 break;
05002 }
05003
05004 if (!trunk_ref->trunk->chan) {
05005 ast_mutex_lock(args->cond_lock);
05006 ast_cond_signal(args->cond);
05007 ast_mutex_unlock(args->cond_lock);
05008 ast_dial_join(dial);
05009 ast_dial_destroy(dial);
05010 return NULL;
05011 }
05012
05013 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05014 ast_set_flag(&conf_flags,
05015 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
05016 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05017 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05018
05019 ast_mutex_lock(args->cond_lock);
05020 ast_cond_signal(args->cond);
05021 ast_mutex_unlock(args->cond_lock);
05022
05023 if (conf) {
05024 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05025 dispose_conf(conf);
05026 conf = NULL;
05027 }
05028
05029
05030 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05031
05032 trunk_ref->trunk->chan = NULL;
05033 trunk_ref->trunk->on_hold = 0;
05034
05035 ast_dial_join(dial);
05036 ast_dial_destroy(dial);
05037
05038 return NULL;
05039 }
05040
05041
05042
05043 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
05044 {
05045 struct sla_trunk_ref *trunk_ref = NULL;
05046
05047 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05048 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05049 break;
05050 }
05051
05052 return trunk_ref;
05053 }
05054
05055 static int sla_station_exec(struct ast_channel *chan, void *data)
05056 {
05057 char *station_name, *trunk_name;
05058 struct sla_station *station;
05059 struct sla_trunk_ref *trunk_ref = NULL;
05060 char conf_name[MAX_CONFNUM];
05061 struct ast_flags conf_flags = { 0 };
05062 struct ast_conference *conf;
05063
05064 if (ast_strlen_zero(data)) {
05065 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05066 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05067 return 0;
05068 }
05069
05070 trunk_name = ast_strdupa(data);
05071 station_name = strsep(&trunk_name, "_");
05072
05073 if (ast_strlen_zero(station_name)) {
05074 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05075 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05076 return 0;
05077 }
05078
05079 AST_RWLIST_RDLOCK(&sla_stations);
05080 station = sla_find_station(station_name);
05081 if (station)
05082 ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05083 AST_RWLIST_UNLOCK(&sla_stations);
05084
05085 if (!station) {
05086 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05087 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05088 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05089 return 0;
05090 }
05091
05092 AST_RWLIST_RDLOCK(&sla_trunks);
05093 if (!ast_strlen_zero(trunk_name)) {
05094 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05095 } else
05096 trunk_ref = sla_choose_idle_trunk(station);
05097 AST_RWLIST_UNLOCK(&sla_trunks);
05098
05099 if (!trunk_ref) {
05100 if (ast_strlen_zero(trunk_name))
05101 ast_log(LOG_NOTICE, "No trunks available for call.\n");
05102 else {
05103 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05104 "'%s' due to access controls.\n", trunk_name);
05105 }
05106 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05107 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05108 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05109 return 0;
05110 }
05111
05112 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05113 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05114 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05115 else {
05116 trunk_ref->state = SLA_TRUNK_STATE_UP;
05117 ast_devstate_changed(AST_DEVICE_INUSE,
05118 "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05119 }
05120 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05121 struct sla_ringing_trunk *ringing_trunk;
05122
05123 ast_mutex_lock(&sla.lock);
05124 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05125 if (ringing_trunk->trunk == trunk_ref->trunk) {
05126 AST_LIST_REMOVE_CURRENT(entry);
05127 break;
05128 }
05129 }
05130 AST_LIST_TRAVERSE_SAFE_END
05131 ast_mutex_unlock(&sla.lock);
05132
05133 if (ringing_trunk) {
05134 answer_trunk_chan(ringing_trunk->trunk->chan);
05135 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05136
05137 free(ringing_trunk);
05138
05139
05140 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05141 sla_queue_event(SLA_EVENT_DIAL_STATE);
05142 }
05143 }
05144
05145 trunk_ref->chan = chan;
05146
05147 if (!trunk_ref->trunk->chan) {
05148 ast_mutex_t cond_lock;
05149 ast_cond_t cond;
05150 pthread_t dont_care;
05151 struct dial_trunk_args args = {
05152 .trunk_ref = trunk_ref,
05153 .station = station,
05154 .cond_lock = &cond_lock,
05155 .cond = &cond,
05156 };
05157 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05158
05159
05160
05161 ast_autoservice_start(chan);
05162 ast_mutex_init(&cond_lock);
05163 ast_cond_init(&cond, NULL);
05164 ast_mutex_lock(&cond_lock);
05165 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05166 ast_cond_wait(&cond, &cond_lock);
05167 ast_mutex_unlock(&cond_lock);
05168 ast_mutex_destroy(&cond_lock);
05169 ast_cond_destroy(&cond);
05170 ast_autoservice_stop(chan);
05171 if (!trunk_ref->trunk->chan) {
05172 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05173 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05174 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05175 trunk_ref->chan = NULL;
05176 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05177 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05178 return 0;
05179 }
05180 }
05181
05182 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05183 trunk_ref->trunk->on_hold) {
05184 trunk_ref->trunk->on_hold = 0;
05185 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05186 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05187 }
05188
05189 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05190 ast_set_flag(&conf_flags,
05191 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05192 ast_answer(chan);
05193 conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05194 if (conf) {
05195 conf_run(chan, conf, conf_flags.flags, NULL);
05196 dispose_conf(conf);
05197 conf = NULL;
05198 }
05199 trunk_ref->chan = NULL;
05200 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05201 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05202 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05203 admin_exec(NULL, conf_name);
05204 trunk_ref->trunk->hold_stations = 0;
05205 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05206 }
05207
05208 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05209
05210 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05211 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05212
05213 return 0;
05214 }
05215
05216 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
05217 {
05218 struct sla_trunk_ref *trunk_ref;
05219
05220 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05221 return NULL;
05222
05223 trunk_ref->trunk = trunk;
05224
05225 return trunk_ref;
05226 }
05227
05228 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
05229 {
05230 struct sla_ringing_trunk *ringing_trunk;
05231
05232 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05233 return NULL;
05234
05235 ringing_trunk->trunk = trunk;
05236 ringing_trunk->ring_begin = ast_tvnow();
05237
05238 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05239
05240 ast_mutex_lock(&sla.lock);
05241 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05242 ast_mutex_unlock(&sla.lock);
05243
05244 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05245
05246 return ringing_trunk;
05247 }
05248
05249 enum {
05250 SLA_TRUNK_OPT_MOH = (1 << 0),
05251 };
05252
05253 enum {
05254 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05255 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05256 };
05257
05258 AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
05259 AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
05260 END_OPTIONS );
05261
05262 static int sla_trunk_exec(struct ast_channel *chan, void *data)
05263 {
05264 char conf_name[MAX_CONFNUM];
05265 struct ast_conference *conf;
05266 struct ast_flags conf_flags = { 0 };
05267 struct sla_trunk *trunk;
05268 struct sla_ringing_trunk *ringing_trunk;
05269 AST_DECLARE_APP_ARGS(args,
05270 AST_APP_ARG(trunk_name);
05271 AST_APP_ARG(options);
05272 );
05273 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05274 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05275 struct ast_flags opt_flags = { 0 };
05276 char *parse;
05277
05278 if (ast_strlen_zero(data)) {
05279 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05280 return -1;
05281 }
05282
05283 parse = ast_strdupa(data);
05284 AST_STANDARD_APP_ARGS(args, parse);
05285 if (args.argc == 2) {
05286 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05287 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05288 return -1;
05289 }
05290 }
05291
05292 AST_RWLIST_RDLOCK(&sla_trunks);
05293 trunk = sla_find_trunk(args.trunk_name);
05294 if (trunk)
05295 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05296 AST_RWLIST_UNLOCK(&sla_trunks);
05297
05298 if (!trunk) {
05299 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05300 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05301 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05302 return 0;
05303 }
05304
05305 if (trunk->chan) {
05306 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05307 args.trunk_name);
05308 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05309 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05310 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05311 return 0;
05312 }
05313
05314 trunk->chan = chan;
05315
05316 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05317 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05318 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05319 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05320 return 0;
05321 }
05322
05323 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05324 conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05325 if (!conf) {
05326 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05327 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05328 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05329 return 0;
05330 }
05331 ast_set_flag(&conf_flags,
05332 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05333
05334 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05335 ast_indicate(chan, -1);
05336 ast_set_flag(&conf_flags, CONFFLAG_MOH);
05337 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05338 } else
05339 ast_indicate(chan, AST_CONTROL_RINGING);
05340
05341 conf_run(chan, conf, conf_flags.flags, opts);
05342 dispose_conf(conf);
05343 conf = NULL;
05344 trunk->chan = NULL;
05345 trunk->on_hold = 0;
05346
05347 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05348
05349 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05350 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05351
05352
05353 ast_mutex_lock(&sla.lock);
05354 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05355 if (ringing_trunk->trunk == trunk) {
05356 AST_LIST_REMOVE_CURRENT(entry);
05357 break;
05358 }
05359 }
05360 AST_LIST_TRAVERSE_SAFE_END;
05361 ast_mutex_unlock(&sla.lock);
05362 if (ringing_trunk) {
05363 ast_free(ringing_trunk);
05364 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05365
05366
05367 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05368 }
05369
05370 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05371 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05372
05373 return 0;
05374 }
05375
05376 static enum ast_device_state sla_state(const char *data)
05377 {
05378 char *buf, *station_name, *trunk_name;
05379 struct sla_station *station;
05380 struct sla_trunk_ref *trunk_ref;
05381 enum ast_device_state res = AST_DEVICE_INVALID;
05382
05383 trunk_name = buf = ast_strdupa(data);
05384 station_name = strsep(&trunk_name, "_");
05385
05386 AST_RWLIST_RDLOCK(&sla_stations);
05387 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05388 if (strcasecmp(station_name, station->name))
05389 continue;
05390 AST_RWLIST_RDLOCK(&sla_trunks);
05391 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05392 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05393 break;
05394 }
05395 if (!trunk_ref) {
05396 AST_RWLIST_UNLOCK(&sla_trunks);
05397 break;
05398 }
05399 res = sla_state_to_devstate(trunk_ref->state);
05400 AST_RWLIST_UNLOCK(&sla_trunks);
05401 }
05402 AST_RWLIST_UNLOCK(&sla_stations);
05403
05404 if (res == AST_DEVICE_INVALID) {
05405 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05406 trunk_name, station_name);
05407 }
05408
05409 return res;
05410 }
05411
05412 static void destroy_trunk(struct sla_trunk *trunk)
05413 {
05414 struct sla_station_ref *station_ref;
05415
05416 if (!ast_strlen_zero(trunk->autocontext))
05417 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05418
05419 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05420 ast_free(station_ref);
05421
05422 ast_string_field_free_memory(trunk);
05423 ast_free(trunk);
05424 }
05425
05426 static void destroy_station(struct sla_station *station)
05427 {
05428 struct sla_trunk_ref *trunk_ref;
05429
05430 if (!ast_strlen_zero(station->autocontext)) {
05431 AST_RWLIST_RDLOCK(&sla_trunks);
05432 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05433 char exten[AST_MAX_EXTENSION];
05434 char hint[AST_MAX_APP];
05435 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05436 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05437 ast_context_remove_extension(station->autocontext, exten,
05438 1, sla_registrar);
05439 ast_context_remove_extension(station->autocontext, hint,
05440 PRIORITY_HINT, sla_registrar);
05441 }
05442 AST_RWLIST_UNLOCK(&sla_trunks);
05443 }
05444
05445 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05446 ast_free(trunk_ref);
05447
05448 ast_string_field_free_memory(station);
05449 ast_free(station);
05450 }
05451
05452 static void sla_destroy(void)
05453 {
05454 struct sla_trunk *trunk;
05455 struct sla_station *station;
05456
05457 AST_RWLIST_WRLOCK(&sla_trunks);
05458 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05459 destroy_trunk(trunk);
05460 AST_RWLIST_UNLOCK(&sla_trunks);
05461
05462 AST_RWLIST_WRLOCK(&sla_stations);
05463 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05464 destroy_station(station);
05465 AST_RWLIST_UNLOCK(&sla_stations);
05466
05467 if (sla.thread != AST_PTHREADT_NULL) {
05468 ast_mutex_lock(&sla.lock);
05469 sla.stop = 1;
05470 ast_cond_signal(&sla.cond);
05471 ast_mutex_unlock(&sla.lock);
05472 pthread_join(sla.thread, NULL);
05473 }
05474
05475
05476 ast_context_destroy(NULL, sla_registrar);
05477
05478 ast_mutex_destroy(&sla.lock);
05479 ast_cond_destroy(&sla.cond);
05480 }
05481
05482 static int sla_check_device(const char *device)
05483 {
05484 char *tech, *tech_data;
05485
05486 tech_data = ast_strdupa(device);
05487 tech = strsep(&tech_data, "/");
05488
05489 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05490 return -1;
05491
05492 return 0;
05493 }
05494
05495 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
05496 {
05497 struct sla_trunk *trunk;
05498 struct ast_variable *var;
05499 const char *dev;
05500
05501 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05502 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05503 return -1;
05504 }
05505
05506 if (sla_check_device(dev)) {
05507 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05508 cat, dev);
05509 return -1;
05510 }
05511
05512 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05513 return -1;
05514 if (ast_string_field_init(trunk, 32)) {
05515 ast_free(trunk);
05516 return -1;
05517 }
05518
05519 ast_string_field_set(trunk, name, cat);
05520 ast_string_field_set(trunk, device, dev);
05521
05522 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05523 if (!strcasecmp(var->name, "autocontext"))
05524 ast_string_field_set(trunk, autocontext, var->value);
05525 else if (!strcasecmp(var->name, "ringtimeout")) {
05526 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
05527 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05528 var->value, trunk->name);
05529 trunk->ring_timeout = 0;
05530 }
05531 } else if (!strcasecmp(var->name, "barge"))
05532 trunk->barge_disabled = ast_false(var->value);
05533 else if (!strcasecmp(var->name, "hold")) {
05534 if (!strcasecmp(var->value, "private"))
05535 trunk->hold_access = SLA_HOLD_PRIVATE;
05536 else if (!strcasecmp(var->value, "open"))
05537 trunk->hold_access = SLA_HOLD_OPEN;
05538 else {
05539 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05540 var->value, trunk->name);
05541 }
05542 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05543 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05544 var->name, var->lineno, SLA_CONFIG_FILE);
05545 }
05546 }
05547
05548 if (!ast_strlen_zero(trunk->autocontext)) {
05549 struct ast_context *context;
05550 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05551 if (!context) {
05552 ast_log(LOG_ERROR, "Failed to automatically find or create "
05553 "context '%s' for SLA!\n", trunk->autocontext);
05554 destroy_trunk(trunk);
05555 return -1;
05556 }
05557 if (ast_add_extension2(context, 0 , "s", 1,
05558 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05559 ast_log(LOG_ERROR, "Failed to automatically create extension "
05560 "for trunk '%s'!\n", trunk->name);
05561 destroy_trunk(trunk);
05562 return -1;
05563 }
05564 }
05565
05566 AST_RWLIST_WRLOCK(&sla_trunks);
05567 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05568 AST_RWLIST_UNLOCK(&sla_trunks);
05569
05570 return 0;
05571 }
05572
05573 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
05574 {
05575 struct sla_trunk *trunk;
05576 struct sla_trunk_ref *trunk_ref;
05577 struct sla_station_ref *station_ref;
05578 char *trunk_name, *options, *cur;
05579
05580 options = ast_strdupa(var->value);
05581 trunk_name = strsep(&options, ",");
05582
05583 AST_RWLIST_RDLOCK(&sla_trunks);
05584 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05585 if (!strcasecmp(trunk->name, trunk_name))
05586 break;
05587 }
05588
05589 AST_RWLIST_UNLOCK(&sla_trunks);
05590 if (!trunk) {
05591 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05592 return;
05593 }
05594 if (!(trunk_ref = create_trunk_ref(trunk)))
05595 return;
05596 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05597
05598 while ((cur = strsep(&options, ","))) {
05599 char *name, *value = cur;
05600 name = strsep(&value, "=");
05601 if (!strcasecmp(name, "ringtimeout")) {
05602 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
05603 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05604 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05605 trunk_ref->ring_timeout = 0;
05606 }
05607 } else if (!strcasecmp(name, "ringdelay")) {
05608 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
05609 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05610 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05611 trunk_ref->ring_delay = 0;
05612 }
05613 } else {
05614 ast_log(LOG_WARNING, "Invalid option '%s' for "
05615 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05616 }
05617 }
05618
05619 if (!(station_ref = sla_create_station_ref(station))) {
05620 ast_free(trunk_ref);
05621 return;
05622 }
05623 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05624 AST_RWLIST_WRLOCK(&sla_trunks);
05625 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05626 AST_RWLIST_UNLOCK(&sla_trunks);
05627 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05628 }
05629
05630 static int sla_build_station(struct ast_config *cfg, const char *cat)
05631 {
05632 struct sla_station *station;
05633 struct ast_variable *var;
05634 const char *dev;
05635
05636 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05637 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05638 return -1;
05639 }
05640
05641 if (!(station = ast_calloc(1, sizeof(*station))))
05642 return -1;
05643 if (ast_string_field_init(station, 32)) {
05644 ast_free(station);
05645 return -1;
05646 }
05647
05648 ast_string_field_set(station, name, cat);
05649 ast_string_field_set(station, device, dev);
05650
05651 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05652 if (!strcasecmp(var->name, "trunk"))
05653 sla_add_trunk_to_station(station, var);
05654 else if (!strcasecmp(var->name, "autocontext"))
05655 ast_string_field_set(station, autocontext, var->value);
05656 else if (!strcasecmp(var->name, "ringtimeout")) {
05657 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05658 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05659 var->value, station->name);
05660 station->ring_timeout = 0;
05661 }
05662 } else if (!strcasecmp(var->name, "ringdelay")) {
05663 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05664 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05665 var->value, station->name);
05666 station->ring_delay = 0;
05667 }
05668 } else if (!strcasecmp(var->name, "hold")) {
05669 if (!strcasecmp(var->value, "private"))
05670 station->hold_access = SLA_HOLD_PRIVATE;
05671 else if (!strcasecmp(var->value, "open"))
05672 station->hold_access = SLA_HOLD_OPEN;
05673 else {
05674 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05675 var->value, station->name);
05676 }
05677
05678 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05679 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05680 var->name, var->lineno, SLA_CONFIG_FILE);
05681 }
05682 }
05683
05684 if (!ast_strlen_zero(station->autocontext)) {
05685 struct ast_context *context;
05686 struct sla_trunk_ref *trunk_ref;
05687 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05688 if (!context) {
05689 ast_log(LOG_ERROR, "Failed to automatically find or create "
05690 "context '%s' for SLA!\n", station->autocontext);
05691 destroy_station(station);
05692 return -1;
05693 }
05694
05695
05696 if (ast_add_extension2(context, 0 , station->name, 1,
05697 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05698 ast_log(LOG_ERROR, "Failed to automatically create extension "
05699 "for trunk '%s'!\n", station->name);
05700 destroy_station(station);
05701 return -1;
05702 }
05703 AST_RWLIST_RDLOCK(&sla_trunks);
05704 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05705 char exten[AST_MAX_EXTENSION];
05706 char hint[AST_MAX_APP];
05707 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05708 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05709
05710
05711 if (ast_add_extension2(context, 0 , exten, 1,
05712 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05713 ast_log(LOG_ERROR, "Failed to automatically create extension "
05714 "for trunk '%s'!\n", station->name);
05715 destroy_station(station);
05716 return -1;
05717 }
05718
05719
05720 if (ast_add_extension2(context, 0 , exten, PRIORITY_HINT,
05721 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05722 ast_log(LOG_ERROR, "Failed to automatically create hint "
05723 "for trunk '%s'!\n", station->name);
05724 destroy_station(station);
05725 return -1;
05726 }
05727 }
05728 AST_RWLIST_UNLOCK(&sla_trunks);
05729 }
05730
05731 AST_RWLIST_WRLOCK(&sla_stations);
05732 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05733 AST_RWLIST_UNLOCK(&sla_stations);
05734
05735 return 0;
05736 }
05737
05738 static int sla_load_config(int reload)
05739 {
05740 struct ast_config *cfg;
05741 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05742 const char *cat = NULL;
05743 int res = 0;
05744 const char *val;
05745
05746 if (!reload) {
05747 ast_mutex_init(&sla.lock);
05748 ast_cond_init(&sla.cond, NULL);
05749 }
05750
05751 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05752 return 0;
05753 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05754 return 0;
05755
05756 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05757 sla.attempt_callerid = ast_true(val);
05758
05759 while ((cat = ast_category_browse(cfg, cat)) && !res) {
05760 const char *type;
05761 if (!strcasecmp(cat, "general"))
05762 continue;
05763 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05764 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05765 SLA_CONFIG_FILE);
05766 continue;
05767 }
05768 if (!strcasecmp(type, "trunk"))
05769 res = sla_build_trunk(cfg, cat);
05770 else if (!strcasecmp(type, "station"))
05771 res = sla_build_station(cfg, cat);
05772 else {
05773 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05774 SLA_CONFIG_FILE, type);
05775 }
05776 }
05777
05778 ast_config_destroy(cfg);
05779
05780 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05781 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05782
05783 return res;
05784 }
05785
05786 static int acf_meetme_info_eval(char *keyword, struct ast_conference *conf)
05787 {
05788 if (!strcasecmp("lock", keyword)) {
05789 return conf->locked;
05790 } else if (!strcasecmp("parties", keyword)) {
05791 return conf->users;
05792 } else if (!strcasecmp("activity", keyword)) {
05793 time_t now;
05794 now = time(NULL);
05795 return (now - conf->start);
05796 } else if (!strcasecmp("dynamic", keyword)) {
05797 return conf->isdynamic;
05798 } else {
05799 return -1;
05800 }
05801
05802 }
05803
05804 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05805 {
05806 struct ast_conference *conf;
05807 char *parse;
05808 int result = -2;
05809 AST_DECLARE_APP_ARGS(args,
05810 AST_APP_ARG(keyword);
05811 AST_APP_ARG(confno);
05812 );
05813
05814 if (ast_strlen_zero(data)) {
05815 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
05816 return -1;
05817 }
05818
05819 parse = ast_strdupa(data);
05820 AST_STANDARD_APP_ARGS(args, parse);
05821
05822 if (ast_strlen_zero(args.keyword)) {
05823 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
05824 return -1;
05825 }
05826
05827 if (ast_strlen_zero(args.confno)) {
05828 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
05829 return -1;
05830 }
05831
05832 AST_LIST_LOCK(&confs);
05833 AST_LIST_TRAVERSE(&confs, conf, list) {
05834 if (!strcmp(args.confno, conf->confno)) {
05835 result = acf_meetme_info_eval(args.keyword, conf);
05836 break;
05837 }
05838 }
05839 AST_LIST_UNLOCK(&confs);
05840
05841 if (result > -1) {
05842 snprintf(buf, len, "%d", result);
05843 } else if (result == -1) {
05844 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
05845 snprintf(buf, len, "0");
05846 } else if (result == -2) {
05847 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
05848 snprintf(buf, len, "0");
05849 }
05850
05851 return 0;
05852 }
05853
05854
05855 static struct ast_custom_function meetme_info_acf = {
05856 .name = "MEETME_INFO",
05857 .synopsis = "Query a given conference of various properties.",
05858 .syntax = "MEETME_INFO(<keyword>,<confno>)",
05859 .read = acf_meetme_info,
05860 .desc =
05861 "Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
05862 " Options:\n"
05863 " lock - boolean of whether the corresponding conference is locked\n"
05864 " parties - number of parties in a given conference\n"
05865 " activity - duration of conference in seconds\n"
05866 " dynamic - boolean of whether the corresponding coference is dynamic\n",
05867 };
05868
05869
05870 static int load_config(int reload)
05871 {
05872 load_config_meetme();
05873
05874 if (reload) {
05875 sla_queue_event(SLA_EVENT_RELOAD);
05876 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05877 "and will be completed when the system is idle.\n");
05878 return 0;
05879 }
05880
05881 return sla_load_config(0);
05882 }
05883
05884 static int unload_module(void)
05885 {
05886 int res = 0;
05887
05888 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05889 res = ast_manager_unregister("MeetmeMute");
05890 res |= ast_manager_unregister("MeetmeUnmute");
05891 res |= ast_manager_unregister("MeetmeList");
05892 res |= ast_unregister_application(app4);
05893 res |= ast_unregister_application(app3);
05894 res |= ast_unregister_application(app2);
05895 res |= ast_unregister_application(app);
05896 res |= ast_unregister_application(slastation_app);
05897 res |= ast_unregister_application(slatrunk_app);
05898
05899 ast_devstate_prov_del("Meetme");
05900 ast_devstate_prov_del("SLA");
05901
05902 sla_destroy();
05903
05904 res |= ast_custom_function_unregister(&meetme_info_acf);
05905 ast_unload_realtime("meetme");
05906
05907 return res;
05908 }
05909
05910 static int load_module(void)
05911 {
05912 int res = 0;
05913
05914 res |= load_config(0);
05915
05916 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05917 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
05918 action_meetmemute, "Mute a Meetme user");
05919 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
05920 action_meetmeunmute, "Unmute a Meetme user");
05921 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING,
05922 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05923 res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05924 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05925 res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05926 res |= ast_register_application(app, conf_exec, synopsis, descrip);
05927 res |= ast_register_application(slastation_app, sla_station_exec,
05928 slastation_synopsis, slastation_desc);
05929 res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05930 slatrunk_synopsis, slatrunk_desc);
05931
05932 res |= ast_devstate_prov_add("Meetme", meetmestate);
05933 res |= ast_devstate_prov_add("SLA", sla_state);
05934
05935 res |= ast_custom_function_register(&meetme_info_acf);
05936 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
05937
05938 return res;
05939 }
05940
05941 static int reload(void)
05942 {
05943 ast_unload_realtime("meetme");
05944 return load_config(1);
05945 }
05946
05947 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
05948 .load = load_module,
05949 .unload = unload_module,
05950 .reload = reload,
05951 );
05952