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: 238183 $")
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 (!conf->transpath[idx])
02768 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
02769 if (conf->transpath[idx]) {
02770 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
02771 if (!conf->transframe[idx])
02772 conf->transframe[idx] = &ast_null_frame;
02773 }
02774 }
02775 }
02776 if (conf->transframe[idx]) {
02777 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
02778 can_write(chan, confflags)) {
02779 struct ast_frame *cur;
02780 if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02781 ast_moh_stop(chan);
02782 mohtempstopped = 1;
02783 }
02784
02785
02786
02787
02788 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02789 if (ast_write(chan, cur)) {
02790 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02791 break;
02792 }
02793 }
02794 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02795 mohtempstopped = 0;
02796 ast_moh_start(chan, NULL, NULL);
02797 }
02798 }
02799 } else {
02800 ast_mutex_unlock(&conf->listenlock);
02801 goto bailoutandtrynormal;
02802 }
02803 ast_mutex_unlock(&conf->listenlock);
02804 } else {
02805 bailoutandtrynormal:
02806 if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
02807 ast_moh_stop(chan);
02808 mohtempstopped = 1;
02809 }
02810 if (user->listen.actual)
02811 ast_frame_adjust_volume(&fr, user->listen.actual);
02812 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02813 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02814 }
02815 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
02816 mohtempstopped = 0;
02817 ast_moh_start(chan, NULL, NULL);
02818 }
02819 }
02820 } else
02821 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02822 }
02823 lastmarked = currentmarked;
02824 }
02825 }
02826
02827 if (musiconhold)
02828 ast_moh_stop(chan);
02829
02830 if (using_pseudo)
02831 close(fd);
02832 else {
02833
02834 dahdic.chan = 0;
02835 dahdic.confno = 0;
02836 dahdic.confmode = 0;
02837 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02838 ast_log(LOG_WARNING, "Error setting conference\n");
02839 }
02840 }
02841
02842 reset_volumes(user);
02843
02844 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02845 conf_play(chan, conf, LEAVE);
02846
02847 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02848 struct announce_listitem *item;
02849 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02850 return -1;
02851 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02852 ast_copy_string(item->language, chan->language, sizeof(item->language));
02853 item->confchan = conf->chan;
02854 item->confusers = conf->users;
02855 item->announcetype = CONF_HASLEFT;
02856 ast_mutex_lock(&conf->announcelistlock);
02857 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02858 ast_cond_signal(&conf->announcelist_addition);
02859 ast_mutex_unlock(&conf->announcelistlock);
02860 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02861
02862 ast_filedelete(user->namerecloc, NULL);
02863 }
02864
02865 outrun:
02866 AST_LIST_LOCK(&confs);
02867
02868 if (dsp)
02869 ast_dsp_free(dsp);
02870
02871 if (user->user_no) {
02872 now = ast_tvnow();
02873 hr = (now.tv_sec - user->jointime) / 3600;
02874 min = ((now.tv_sec - user->jointime) % 3600) / 60;
02875 sec = (now.tv_sec - user->jointime) % 60;
02876
02877 if (sent_event) {
02878 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02879 "Channel: %s\r\n"
02880 "Uniqueid: %s\r\n"
02881 "Meetme: %s\r\n"
02882 "Usernum: %d\r\n"
02883 "CallerIDNum: %s\r\n"
02884 "CallerIDName: %s\r\n"
02885 "Duration: %ld\r\n",
02886 chan->name, chan->uniqueid, conf->confno,
02887 user->user_no,
02888 S_OR(user->chan->cid.cid_num, "<unknown>"),
02889 S_OR(user->chan->cid.cid_name, "<unknown>"),
02890 (long)(now.tv_sec - user->jointime));
02891 }
02892
02893 if (setusercount) {
02894 conf->users--;
02895 if (rt_log_members) {
02896
02897 snprintf(members, sizeof(members), "%d", conf->users);
02898 ast_realtime_require_field("meetme",
02899 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02900 "members", RQ_UINTEGER1, strlen(members),
02901 NULL);
02902 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02903 }
02904 if (confflags & CONFFLAG_MARKEDUSER)
02905 conf->markedusers--;
02906 }
02907
02908 AST_LIST_REMOVE(&conf->userlist, user, list);
02909
02910
02911 if (!conf->users)
02912 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02913
02914
02915 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02916 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02917 }
02918 ast_free(user);
02919 AST_LIST_UNLOCK(&confs);
02920
02921 return ret;
02922 }
02923
02924 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
02925 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags,
02926 char *optargs[], int *too_early)
02927 {
02928 struct ast_variable *var;
02929 struct ast_conference *cnf;
02930
02931 *too_early = 0;
02932
02933
02934 AST_LIST_LOCK(&confs);
02935 AST_LIST_TRAVERSE(&confs, cnf, list) {
02936 if (!strcmp(confno, cnf->confno))
02937 break;
02938 }
02939 if (cnf) {
02940 cnf->refcount += refcount;
02941 }
02942 AST_LIST_UNLOCK(&confs);
02943
02944 if (!cnf) {
02945 char *pin = NULL, *pinadmin = NULL;
02946 int maxusers = 0;
02947 struct timeval now;
02948 char currenttime[19] = "";
02949 char eatime[19] = "";
02950 char useropts[32] = "";
02951 char adminopts[32] = "";
02952 struct ast_tm tm, etm;
02953 struct timeval endtime = { .tv_sec = 0 };
02954
02955 if (rt_schedule) {
02956 now = ast_tvnow();
02957
02958 ast_localtime(&now, &tm, NULL);
02959 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02960
02961 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02962
02963 var = ast_load_realtime("meetme", "confno",
02964 confno, "starttime <= ", currenttime, "endtime >= ",
02965 currenttime, NULL);
02966
02967 if (!var && fuzzystart) {
02968 now = ast_tvnow();
02969 now.tv_sec += fuzzystart;
02970
02971 ast_localtime(&now, &tm, NULL);
02972 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02973 var = ast_load_realtime("meetme", "confno",
02974 confno, "starttime <= ", currenttime, "endtime >= ",
02975 currenttime, NULL);
02976 }
02977
02978 if (!var && earlyalert) {
02979 now = ast_tvnow();
02980 now.tv_sec += earlyalert;
02981 ast_localtime(&now, &etm, NULL);
02982 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02983 var = ast_load_realtime("meetme", "confno",
02984 confno, "starttime <= ", eatime, "endtime >= ",
02985 currenttime, NULL);
02986 if (var)
02987 *too_early = 1;
02988 }
02989
02990 } else
02991 var = ast_load_realtime("meetme", "confno", confno, NULL);
02992
02993 if (!var)
02994 return NULL;
02995
02996 if (rt_schedule && *too_early) {
02997
02998 if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02999 ast_waitstream(chan, "");
03000 ast_variables_destroy(var);
03001 return NULL;
03002 }
03003
03004 while (var) {
03005 if (!strcasecmp(var->name, "pin")) {
03006 pin = ast_strdupa(var->value);
03007 } else if (!strcasecmp(var->name, "adminpin")) {
03008 pinadmin = ast_strdupa(var->value);
03009 } else if (!strcasecmp(var->name, "opts")) {
03010 ast_copy_string(useropts, var->value, sizeof(useropts));
03011 } else if (!strcasecmp(var->name, "maxusers")) {
03012 maxusers = atoi(var->value);
03013 } else if (!strcasecmp(var->name, "adminopts")) {
03014 ast_copy_string(adminopts, var->value, sizeof(adminopts));
03015 } else if (!strcasecmp(var->name, "endtime")) {
03016 union {
03017 struct ast_tm atm;
03018 struct tm tm;
03019 } t = { { 0, }, };
03020 strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
03021
03022
03023
03024
03025 t.tm.tm_isdst = -1;
03026 endtime = ast_mktime(&t.atm, NULL);
03027 }
03028
03029 var = var->next;
03030 }
03031
03032 ast_variables_destroy(var);
03033
03034 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03035
03036 if (cnf) {
03037 cnf->maxusers = maxusers;
03038 cnf->endalert = endalert;
03039 cnf->endtime = endtime.tv_sec;
03040 }
03041 }
03042
03043 if (cnf) {
03044 if (confflags && !cnf->chan &&
03045 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03046 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03047 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03048 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03049 }
03050
03051 if (confflags && !cnf->chan &&
03052 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03053 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03054 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03055 }
03056 }
03057
03058 return cnf;
03059 }
03060
03061
03062 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
03063 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
03064 {
03065 struct ast_config *cfg;
03066 struct ast_variable *var;
03067 struct ast_flags config_flags = { 0 };
03068 struct ast_conference *cnf;
03069
03070 AST_DECLARE_APP_ARGS(args,
03071 AST_APP_ARG(confno);
03072 AST_APP_ARG(pin);
03073 AST_APP_ARG(pinadmin);
03074 );
03075
03076
03077 ast_debug(1, "The requested confno is '%s'?\n", confno);
03078 AST_LIST_LOCK(&confs);
03079 AST_LIST_TRAVERSE(&confs, cnf, list) {
03080 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03081 if (!strcmp(confno, cnf->confno))
03082 break;
03083 }
03084 if (cnf) {
03085 cnf->refcount += refcount;
03086 }
03087 AST_LIST_UNLOCK(&confs);
03088
03089 if (!cnf) {
03090 if (dynamic) {
03091
03092 ast_debug(1, "Building dynamic conference '%s'\n", confno);
03093 if (dynamic_pin) {
03094 if (dynamic_pin[0] == 'q') {
03095
03096 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03097 return NULL;
03098 }
03099 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03100 } else {
03101 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03102 }
03103 } else {
03104
03105 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03106 if (!cfg) {
03107 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03108 return NULL;
03109 }
03110
03111 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03112 char parse[MAX_SETTINGS];
03113
03114 if (strcasecmp(var->name, "conf"))
03115 continue;
03116
03117 ast_copy_string(parse, var->value, sizeof(parse));
03118
03119 AST_STANDARD_APP_ARGS(args, parse);
03120 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03121 if (!strcasecmp(args.confno, confno)) {
03122
03123 cnf = build_conf(args.confno,
03124 S_OR(args.pin, ""),
03125 S_OR(args.pinadmin, ""),
03126 make, dynamic, refcount, chan);
03127 break;
03128 }
03129 }
03130 if (!var) {
03131 ast_debug(1, "%s isn't a valid conference\n", confno);
03132 }
03133 ast_config_destroy(cfg);
03134 }
03135 } else if (dynamic_pin) {
03136
03137
03138
03139 if (dynamic_pin[0] == 'q')
03140 dynamic_pin[0] = '\0';
03141 }
03142
03143 if (cnf) {
03144 if (confflags && !cnf->chan &&
03145 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03146 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03147 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03148 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03149 }
03150
03151 if (confflags && !cnf->chan &&
03152 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03153 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03154 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03155 }
03156 }
03157
03158 return cnf;
03159 }
03160
03161
03162 static int count_exec(struct ast_channel *chan, void *data)
03163 {
03164 int res = 0;
03165 struct ast_conference *conf;
03166 int count;
03167 char *localdata;
03168 char val[80] = "0";
03169 AST_DECLARE_APP_ARGS(args,
03170 AST_APP_ARG(confno);
03171 AST_APP_ARG(varname);
03172 );
03173
03174 if (ast_strlen_zero(data)) {
03175 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03176 return -1;
03177 }
03178
03179 if (!(localdata = ast_strdupa(data)))
03180 return -1;
03181
03182 AST_STANDARD_APP_ARGS(args, localdata);
03183
03184 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03185
03186 if (conf) {
03187 count = conf->users;
03188 dispose_conf(conf);
03189 conf = NULL;
03190 } else
03191 count = 0;
03192
03193 if (!ast_strlen_zero(args.varname)) {
03194
03195 snprintf(val, sizeof(val), "%d", count);
03196 pbx_builtin_setvar_helper(chan, args.varname, val);
03197 } else {
03198 if (chan->_state != AST_STATE_UP)
03199 ast_answer(chan);
03200 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
03201 }
03202
03203 return res;
03204 }
03205
03206
03207 static int conf_exec(struct ast_channel *chan, void *data)
03208 {
03209 int res = -1;
03210 char confno[MAX_CONFNUM] = "";
03211 int allowretry = 0;
03212 int retrycnt = 0;
03213 struct ast_conference *cnf = NULL;
03214 struct ast_flags confflags = {0}, config_flags = { 0 };
03215 int dynamic = 0;
03216 int empty = 0, empty_no_pin = 0;
03217 int always_prompt = 0;
03218 char *notdata, *info, the_pin[MAX_PIN] = "";
03219 AST_DECLARE_APP_ARGS(args,
03220 AST_APP_ARG(confno);
03221 AST_APP_ARG(options);
03222 AST_APP_ARG(pin);
03223 );
03224 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03225
03226 if (ast_strlen_zero(data)) {
03227 allowretry = 1;
03228 notdata = "";
03229 } else {
03230 notdata = data;
03231 }
03232
03233 if (chan->_state != AST_STATE_UP)
03234 ast_answer(chan);
03235
03236 info = ast_strdupa(notdata);
03237
03238 AST_STANDARD_APP_ARGS(args, info);
03239
03240 if (args.confno) {
03241 ast_copy_string(confno, args.confno, sizeof(confno));
03242 if (ast_strlen_zero(confno)) {
03243 allowretry = 1;
03244 }
03245 }
03246
03247 if (args.pin)
03248 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03249
03250 if (args.options) {
03251 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03252 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03253 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03254 strcpy(the_pin, "q");
03255
03256 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03257 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03258 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03259 }
03260
03261 do {
03262 if (retrycnt > 3)
03263 allowretry = 0;
03264 if (empty) {
03265 int i;
03266 struct ast_config *cfg;
03267 struct ast_variable *var;
03268 int confno_int;
03269
03270
03271 if ((empty_no_pin) || (!dynamic)) {
03272 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03273 if (cfg) {
03274 var = ast_variable_browse(cfg, "rooms");
03275 while (var) {
03276 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03277 if (!strcasecmp(var->name, "conf")) {
03278 int found = 0;
03279 ast_copy_string(parse, var->value, sizeof(parse));
03280 confno_tmp = strsep(&stringp, "|,");
03281 if (!dynamic) {
03282
03283 AST_LIST_LOCK(&confs);
03284 AST_LIST_TRAVERSE(&confs, cnf, list) {
03285 if (!strcmp(confno_tmp, cnf->confno)) {
03286
03287 found = 1;
03288 break;
03289 }
03290 }
03291 AST_LIST_UNLOCK(&confs);
03292 if (!found) {
03293
03294 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03295
03296
03297
03298
03299 ast_copy_string(confno, confno_tmp, sizeof(confno));
03300 break;
03301
03302 }
03303 }
03304 }
03305 }
03306 var = var->next;
03307 }
03308 ast_config_destroy(cfg);
03309 }
03310 }
03311
03312
03313 if (ast_strlen_zero(confno) && dynamic) {
03314 AST_LIST_LOCK(&confs);
03315 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03316 if (!conf_map[i]) {
03317 snprintf(confno, sizeof(confno), "%d", i);
03318 conf_map[i] = 1;
03319 break;
03320 }
03321 }
03322 AST_LIST_UNLOCK(&confs);
03323 }
03324
03325
03326 if (ast_strlen_zero(confno)) {
03327 res = ast_streamfile(chan, "conf-noempty", chan->language);
03328 if (!res)
03329 ast_waitstream(chan, "");
03330 } else {
03331 if (sscanf(confno, "%30d", &confno_int) == 1) {
03332 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03333 res = ast_streamfile(chan, "conf-enteringno", chan->language);
03334 if (!res) {
03335 ast_waitstream(chan, "");
03336 res = ast_say_digits(chan, confno_int, "", chan->language);
03337 }
03338 }
03339 } else {
03340 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03341 }
03342 }
03343 }
03344
03345 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03346
03347 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03348 if (res < 0) {
03349
03350 confno[0] = '\0';
03351 allowretry = 0;
03352 break;
03353 }
03354 }
03355 if (!ast_strlen_zero(confno)) {
03356
03357 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
03358 sizeof(the_pin), 1, &confflags);
03359 if (!cnf) {
03360 int too_early = 0;
03361 cnf = find_conf_realtime(chan, confno, 1, dynamic,
03362 the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early);
03363 if (rt_schedule && too_early)
03364 allowretry = 0;
03365 }
03366
03367 if (!cnf) {
03368 if (allowretry) {
03369 confno[0] = '\0';
03370 res = ast_streamfile(chan, "conf-invalid", chan->language);
03371 if (!res)
03372 ast_waitstream(chan, "");
03373 res = -1;
03374 }
03375 } else {
03376 if ((!ast_strlen_zero(cnf->pin) &&
03377 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03378 (!ast_strlen_zero(cnf->pinadmin) &&
03379 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03380 char pin[MAX_PIN] = "";
03381 int j;
03382
03383
03384 for (j = 0; j < 3; j++) {
03385 if (*the_pin && (always_prompt == 0)) {
03386 ast_copy_string(pin, the_pin, sizeof(pin));
03387 res = 0;
03388 } else {
03389
03390 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03391 }
03392 if (res >= 0) {
03393 if (!strcasecmp(pin, cnf->pin) ||
03394 (!ast_strlen_zero(cnf->pinadmin) &&
03395 !strcasecmp(pin, cnf->pinadmin))) {
03396
03397 allowretry = 0;
03398 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin))
03399 ast_set_flag(&confflags, CONFFLAG_ADMIN);
03400
03401 res = conf_run(chan, cnf, confflags.flags, optargs);
03402 break;
03403 } else {
03404
03405 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03406 res = ast_waitstream(chan, AST_DIGIT_ANY);
03407 ast_stopstream(chan);
03408 }
03409 else {
03410 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03411 break;
03412 }
03413 if (res < 0)
03414 break;
03415 pin[0] = res;
03416 pin[1] = '\0';
03417 res = -1;
03418 if (allowretry)
03419 confno[0] = '\0';
03420 }
03421 } else {
03422
03423 res = -1;
03424 allowretry = 0;
03425
03426 break;
03427 }
03428
03429
03430 if (*the_pin && (always_prompt == 0)) {
03431 break;
03432 }
03433 }
03434 } else {
03435
03436 allowretry = 0;
03437
03438
03439 res = conf_run(chan, cnf, confflags.flags, optargs);
03440 }
03441 dispose_conf(cnf);
03442 cnf = NULL;
03443 }
03444 }
03445 } while (allowretry);
03446
03447 if (cnf)
03448 dispose_conf(cnf);
03449
03450 return res;
03451 }
03452
03453 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
03454 {
03455 struct ast_conf_user *user = NULL;
03456 int cid;
03457
03458 sscanf(callerident, "%30i", &cid);
03459 if (conf && callerident) {
03460 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03461 if (cid == user->user_no)
03462 return user;
03463 }
03464 }
03465 return NULL;
03466 }
03467
03468
03469
03470 static int admin_exec(struct ast_channel *chan, void *data) {
03471 char *params;
03472 struct ast_conference *cnf;
03473 struct ast_conf_user *user = NULL;
03474 AST_DECLARE_APP_ARGS(args,
03475 AST_APP_ARG(confno);
03476 AST_APP_ARG(command);
03477 AST_APP_ARG(user);
03478 );
03479
03480 if (ast_strlen_zero(data)) {
03481 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03482 return -1;
03483 }
03484
03485 params = ast_strdupa(data);
03486 AST_STANDARD_APP_ARGS(args, params);
03487
03488 if (!args.command) {
03489 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03490 return -1;
03491 }
03492
03493 AST_LIST_LOCK(&confs);
03494 AST_LIST_TRAVERSE(&confs, cnf, list) {
03495 if (!strcmp(cnf->confno, args.confno))
03496 break;
03497 }
03498
03499 if (!cnf) {
03500 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03501 AST_LIST_UNLOCK(&confs);
03502 return 0;
03503 }
03504
03505 ast_atomic_fetchadd_int(&cnf->refcount, 1);
03506
03507 if (args.user)
03508 user = find_user(cnf, args.user);
03509
03510 switch (*args.command) {
03511 case 76:
03512 cnf->locked = 1;
03513 break;
03514 case 108:
03515 cnf->locked = 0;
03516 break;
03517 case 75:
03518 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03519 user->adminflags |= ADMINFLAG_KICKME;
03520 break;
03521 case 101:
03522 user = AST_LIST_LAST(&cnf->userlist);
03523 if (!(user->userflags & CONFFLAG_ADMIN))
03524 user->adminflags |= ADMINFLAG_KICKME;
03525 else
03526 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03527 break;
03528 case 77:
03529 if (user) {
03530 user->adminflags |= ADMINFLAG_MUTED;
03531 } else
03532 ast_log(LOG_NOTICE, "Specified User not found!\n");
03533 break;
03534 case 78:
03535 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03536 if (!(user->userflags & CONFFLAG_ADMIN))
03537 user->adminflags |= ADMINFLAG_MUTED;
03538 }
03539 break;
03540 case 109:
03541 if (user) {
03542 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03543 } else
03544 ast_log(LOG_NOTICE, "Specified User not found!\n");
03545 break;
03546 case 110:
03547 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03548 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03549 break;
03550 case 107:
03551 if (user)
03552 user->adminflags |= ADMINFLAG_KICKME;
03553 else
03554 ast_log(LOG_NOTICE, "Specified User not found!\n");
03555 break;
03556 case 118:
03557 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03558 tweak_listen_volume(user, VOL_DOWN);
03559 break;
03560 case 86:
03561 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03562 tweak_listen_volume(user, VOL_UP);
03563 break;
03564 case 115:
03565 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03566 tweak_talk_volume(user, VOL_DOWN);
03567 break;
03568 case 83:
03569 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03570 tweak_talk_volume(user, VOL_UP);
03571 break;
03572 case 82:
03573 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03574 reset_volumes(user);
03575 break;
03576 case 114:
03577 if (user)
03578 reset_volumes(user);
03579 else
03580 ast_log(LOG_NOTICE, "Specified User not found!\n");
03581 break;
03582 case 85:
03583 if (user)
03584 tweak_listen_volume(user, VOL_UP);
03585 else
03586 ast_log(LOG_NOTICE, "Specified User not found!\n");
03587 break;
03588 case 117:
03589 if (user)
03590 tweak_listen_volume(user, VOL_DOWN);
03591 else
03592 ast_log(LOG_NOTICE, "Specified User not found!\n");
03593 break;
03594 case 84:
03595 if (user)
03596 tweak_talk_volume(user, VOL_UP);
03597 else
03598 ast_log(LOG_NOTICE, "Specified User not found!\n");
03599 break;
03600 case 116:
03601 if (user)
03602 tweak_talk_volume(user, VOL_DOWN);
03603 else
03604 ast_log(LOG_NOTICE, "Specified User not found!\n");
03605 break;
03606 }
03607
03608 AST_LIST_UNLOCK(&confs);
03609
03610 dispose_conf(cnf);
03611
03612 return 0;
03613 }
03614
03615
03616
03617 static int channel_admin_exec(struct ast_channel *chan, void *data) {
03618 char *params;
03619 struct ast_conference *conf = NULL;
03620 struct ast_conf_user *user = NULL;
03621 AST_DECLARE_APP_ARGS(args,
03622 AST_APP_ARG(channel);
03623 AST_APP_ARG(command);
03624 );
03625
03626 if (ast_strlen_zero(data)) {
03627 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03628 return -1;
03629 }
03630
03631 params = ast_strdupa(data);
03632 AST_STANDARD_APP_ARGS(args, params);
03633
03634 if (!args.channel) {
03635 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03636 return -1;
03637 }
03638
03639 if (!args.command) {
03640 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03641 return -1;
03642 }
03643
03644 AST_LIST_LOCK(&confs);
03645 AST_LIST_TRAVERSE(&confs, conf, list) {
03646 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03647 if (!strcmp(user->chan->name, args.channel))
03648 break;
03649 }
03650 }
03651
03652 if (!user) {
03653 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03654 AST_LIST_UNLOCK(&confs);
03655 return 0;
03656 }
03657
03658
03659 switch (*args.command) {
03660 case 77:
03661 user->adminflags |= ADMINFLAG_MUTED;
03662 break;
03663 case 109:
03664 user->adminflags &= ~ADMINFLAG_MUTED;
03665 break;
03666 case 107:
03667 user->adminflags |= ADMINFLAG_KICKME;
03668 break;
03669 default:
03670 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03671 break;
03672 }
03673
03674 AST_LIST_UNLOCK(&confs);
03675
03676 return 0;
03677 }
03678
03679 static int meetmemute(struct mansession *s, const struct message *m, int mute)
03680 {
03681 struct ast_conference *conf;
03682 struct ast_conf_user *user;
03683 const char *confid = astman_get_header(m, "Meetme");
03684 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03685 int userno;
03686
03687 if (ast_strlen_zero(confid)) {
03688 astman_send_error(s, m, "Meetme conference not specified");
03689 return 0;
03690 }
03691
03692 if (ast_strlen_zero(userid)) {
03693 astman_send_error(s, m, "Meetme user number not specified");
03694 return 0;
03695 }
03696
03697 userno = strtoul(userid, &userid, 10);
03698
03699 if (*userid) {
03700 astman_send_error(s, m, "Invalid user number");
03701 return 0;
03702 }
03703
03704
03705 AST_LIST_LOCK(&confs);
03706 AST_LIST_TRAVERSE(&confs, conf, list) {
03707 if (!strcmp(confid, conf->confno))
03708 break;
03709 }
03710
03711 if (!conf) {
03712 AST_LIST_UNLOCK(&confs);
03713 astman_send_error(s, m, "Meetme conference does not exist");
03714 return 0;
03715 }
03716
03717 AST_LIST_TRAVERSE(&conf->userlist, user, list)
03718 if (user->user_no == userno)
03719 break;
03720
03721 if (!user) {
03722 AST_LIST_UNLOCK(&confs);
03723 astman_send_error(s, m, "User number not found");
03724 return 0;
03725 }
03726
03727 if (mute)
03728 user->adminflags |= ADMINFLAG_MUTED;
03729 else
03730 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03731
03732 AST_LIST_UNLOCK(&confs);
03733
03734 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);
03735
03736 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03737 return 0;
03738 }
03739
03740 static int action_meetmemute(struct mansession *s, const struct message *m)
03741 {
03742 return meetmemute(s, m, 1);
03743 }
03744
03745 static int action_meetmeunmute(struct mansession *s, const struct message *m)
03746 {
03747 return meetmemute(s, m, 0);
03748 }
03749
03750 static char mandescr_meetmelist[] =
03751 "Description: Lists all users in a particular MeetMe conference.\n"
03752 "MeetmeList will follow as separate events, followed by a final event called\n"
03753 "MeetmeListComplete.\n"
03754 "Variables:\n"
03755 " *ActionId: <id>\n"
03756 " *Conference: <confno>\n";
03757
03758 static int action_meetmelist(struct mansession *s, const struct message *m)
03759 {
03760 const char *actionid = astman_get_header(m, "ActionID");
03761 const char *conference = astman_get_header(m, "Conference");
03762 char idText[80] = "";
03763 struct ast_conference *cnf;
03764 struct ast_conf_user *user;
03765 int total = 0;
03766
03767 if (!ast_strlen_zero(actionid))
03768 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03769
03770 if (AST_LIST_EMPTY(&confs)) {
03771 astman_send_error(s, m, "No active conferences.");
03772 return 0;
03773 }
03774
03775 astman_send_listack(s, m, "Meetme user list will follow", "start");
03776
03777
03778 AST_LIST_LOCK(&confs);
03779 AST_LIST_TRAVERSE(&confs, cnf, list) {
03780
03781 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03782 continue;
03783
03784
03785 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03786 total++;
03787 astman_append(s,
03788 "Event: MeetmeList\r\n"
03789 "%s"
03790 "Conference: %s\r\n"
03791 "UserNumber: %d\r\n"
03792 "CallerIDNum: %s\r\n"
03793 "CallerIDName: %s\r\n"
03794 "Channel: %s\r\n"
03795 "Admin: %s\r\n"
03796 "Role: %s\r\n"
03797 "MarkedUser: %s\r\n"
03798 "Muted: %s\r\n"
03799 "Talking: %s\r\n"
03800 "\r\n",
03801 idText,
03802 cnf->confno,
03803 user->user_no,
03804 S_OR(user->chan->cid.cid_num, "<unknown>"),
03805 S_OR(user->chan->cid.cid_name, "<no name>"),
03806 user->chan->name,
03807 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03808 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03809 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03810 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03811 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
03812 }
03813 }
03814 AST_LIST_UNLOCK(&confs);
03815
03816 astman_append(s,
03817 "Event: MeetmeListComplete\r\n"
03818 "EventList: Complete\r\n"
03819 "ListItems: %d\r\n"
03820 "%s"
03821 "\r\n", total, idText);
03822 return 0;
03823 }
03824
03825 static void *recordthread(void *args)
03826 {
03827 struct ast_conference *cnf = args;
03828 struct ast_frame *f = NULL;
03829 int flags;
03830 struct ast_filestream *s = NULL;
03831 int res = 0;
03832 int x;
03833 const char *oldrecordingfilename = NULL;
03834
03835 if (!cnf || !cnf->lchan) {
03836 pthread_exit(0);
03837 }
03838
03839 ast_stopstream(cnf->lchan);
03840 flags = O_CREAT | O_TRUNC | O_WRONLY;
03841
03842
03843 cnf->recording = MEETME_RECORD_ACTIVE;
03844 while (ast_waitfor(cnf->lchan, -1) > -1) {
03845 if (cnf->recording == MEETME_RECORD_TERMINATE) {
03846 AST_LIST_LOCK(&confs);
03847 AST_LIST_UNLOCK(&confs);
03848 break;
03849 }
03850 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03851 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03852 oldrecordingfilename = cnf->recordingfilename;
03853 }
03854
03855 f = ast_read(cnf->lchan);
03856 if (!f) {
03857 res = -1;
03858 break;
03859 }
03860 if (f->frametype == AST_FRAME_VOICE) {
03861 ast_mutex_lock(&cnf->listenlock);
03862 for (x = 0; x < AST_FRAME_BITS; x++) {
03863
03864 if (cnf->transframe[x]) {
03865 ast_frfree(cnf->transframe[x]);
03866 cnf->transframe[x] = NULL;
03867 }
03868 }
03869 if (cnf->origframe)
03870 ast_frfree(cnf->origframe);
03871 cnf->origframe = ast_frdup(f);
03872 ast_mutex_unlock(&cnf->listenlock);
03873 if (s)
03874 res = ast_writestream(s, f);
03875 if (res) {
03876 ast_frfree(f);
03877 break;
03878 }
03879 }
03880 ast_frfree(f);
03881 }
03882 cnf->recording = MEETME_RECORD_OFF;
03883 if (s)
03884 ast_closestream(s);
03885
03886 pthread_exit(0);
03887 }
03888
03889
03890 static enum ast_device_state meetmestate(const char *data)
03891 {
03892 struct ast_conference *conf;
03893
03894
03895 AST_LIST_LOCK(&confs);
03896 AST_LIST_TRAVERSE(&confs, conf, list) {
03897 if (!strcmp(data, conf->confno))
03898 break;
03899 }
03900 AST_LIST_UNLOCK(&confs);
03901 if (!conf)
03902 return AST_DEVICE_INVALID;
03903
03904
03905
03906 if (!conf->users)
03907 return AST_DEVICE_NOT_INUSE;
03908
03909 return AST_DEVICE_INUSE;
03910 }
03911
03912 static void load_config_meetme(void)
03913 {
03914 struct ast_config *cfg;
03915 struct ast_flags config_flags = { 0 };
03916 const char *val;
03917
03918 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03919 return;
03920
03921 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03922
03923
03924 rt_schedule = 0;
03925 fuzzystart = 0;
03926 earlyalert = 0;
03927 endalert = 0;
03928
03929
03930 rt_log_members = 1;
03931
03932 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03933 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03934 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03935 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03936 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03937 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03938 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03939 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03940 }
03941 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03942 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03943 }
03944
03945 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03946 rt_schedule = ast_true(val);
03947 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03948 rt_log_members = ast_true(val);
03949 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03950 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
03951 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03952 fuzzystart = 0;
03953 }
03954 }
03955 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03956 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
03957 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03958 earlyalert = 0;
03959 }
03960 }
03961 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03962 if ((sscanf(val, "%30d", &endalert) != 1)) {
03963 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03964 endalert = 0;
03965 }
03966 }
03967
03968 ast_config_destroy(cfg);
03969 }
03970
03971
03972
03973
03974 static struct sla_trunk *sla_find_trunk(const char *name)
03975 {
03976 struct sla_trunk *trunk = NULL;
03977
03978 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03979 if (!strcasecmp(trunk->name, name))
03980 break;
03981 }
03982
03983 return trunk;
03984 }
03985
03986
03987
03988
03989 static struct sla_station *sla_find_station(const char *name)
03990 {
03991 struct sla_station *station = NULL;
03992
03993 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03994 if (!strcasecmp(station->name, name))
03995 break;
03996 }
03997
03998 return station;
03999 }
04000
04001 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
04002 const struct sla_station *station)
04003 {
04004 struct sla_station_ref *station_ref;
04005 struct sla_trunk_ref *trunk_ref;
04006
04007
04008 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04009 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04010 if (trunk_ref->trunk != trunk || station_ref->station == station)
04011 continue;
04012 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04013 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04014 return 1;
04015 return 0;
04016 }
04017 }
04018
04019 return 0;
04020 }
04021
04022
04023
04024
04025
04026
04027
04028
04029 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
04030 const char *name)
04031 {
04032 struct sla_trunk_ref *trunk_ref = NULL;
04033
04034 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04035 if (strcasecmp(trunk_ref->trunk->name, name))
04036 continue;
04037
04038 if ( (trunk_ref->trunk->barge_disabled
04039 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04040 (trunk_ref->trunk->hold_stations
04041 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04042 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04043 sla_check_station_hold_access(trunk_ref->trunk, station) )
04044 {
04045 trunk_ref = NULL;
04046 }
04047
04048 break;
04049 }
04050
04051 return trunk_ref;
04052 }
04053
04054 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
04055 {
04056 struct sla_station_ref *station_ref;
04057
04058 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04059 return NULL;
04060
04061 station_ref->station = station;
04062
04063 return station_ref;
04064 }
04065
04066 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
04067 {
04068 struct sla_ringing_station *ringing_station;
04069
04070 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04071 return NULL;
04072
04073 ringing_station->station = station;
04074 ringing_station->ring_begin = ast_tvnow();
04075
04076 return ringing_station;
04077 }
04078
04079 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
04080 {
04081 switch (state) {
04082 case SLA_TRUNK_STATE_IDLE:
04083 return AST_DEVICE_NOT_INUSE;
04084 case SLA_TRUNK_STATE_RINGING:
04085 return AST_DEVICE_RINGING;
04086 case SLA_TRUNK_STATE_UP:
04087 return AST_DEVICE_INUSE;
04088 case SLA_TRUNK_STATE_ONHOLD:
04089 case SLA_TRUNK_STATE_ONHOLD_BYME:
04090 return AST_DEVICE_ONHOLD;
04091 }
04092
04093 return AST_DEVICE_UNKNOWN;
04094 }
04095
04096 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
04097 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
04098 {
04099 struct sla_station *station;
04100 struct sla_trunk_ref *trunk_ref;
04101
04102 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04103 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04104 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04105 || trunk_ref == exclude)
04106 continue;
04107 trunk_ref->state = state;
04108 ast_devstate_changed(sla_state_to_devstate(state),
04109 "SLA:%s_%s", station->name, trunk->name);
04110 break;
04111 }
04112 }
04113 }
04114
04115 struct run_station_args {
04116 struct sla_station *station;
04117 struct sla_trunk_ref *trunk_ref;
04118 ast_mutex_t *cond_lock;
04119 ast_cond_t *cond;
04120 };
04121
04122 static void answer_trunk_chan(struct ast_channel *chan)
04123 {
04124 ast_answer(chan);
04125 ast_indicate(chan, -1);
04126 }
04127
04128 static void *run_station(void *data)
04129 {
04130 struct sla_station *station;
04131 struct sla_trunk_ref *trunk_ref;
04132 struct ast_str *conf_name = ast_str_create(16);
04133 struct ast_flags conf_flags = { 0 };
04134 struct ast_conference *conf;
04135
04136 {
04137 struct run_station_args *args = data;
04138 station = args->station;
04139 trunk_ref = args->trunk_ref;
04140 ast_mutex_lock(args->cond_lock);
04141 ast_cond_signal(args->cond);
04142 ast_mutex_unlock(args->cond_lock);
04143
04144 }
04145
04146 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04147 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04148 ast_set_flag(&conf_flags,
04149 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04150 answer_trunk_chan(trunk_ref->chan);
04151 conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
04152 if (conf) {
04153 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04154 dispose_conf(conf);
04155 conf = NULL;
04156 }
04157 trunk_ref->chan = NULL;
04158 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04159 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04160 ast_str_append(&conf_name, 0, ",K");
04161 admin_exec(NULL, conf_name->str);
04162 trunk_ref->trunk->hold_stations = 0;
04163 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04164 }
04165
04166 ast_dial_join(station->dial);
04167 ast_dial_destroy(station->dial);
04168 station->dial = NULL;
04169 ast_free(conf_name);
04170
04171 return NULL;
04172 }
04173
04174 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
04175 {
04176 char buf[80];
04177 struct sla_station_ref *station_ref;
04178
04179 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04180 admin_exec(NULL, buf);
04181 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04182
04183 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04184 ast_free(station_ref);
04185
04186 ast_free(ringing_trunk);
04187 }
04188
04189 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
04190 enum sla_station_hangup hangup)
04191 {
04192 struct sla_ringing_trunk *ringing_trunk;
04193 struct sla_trunk_ref *trunk_ref;
04194 struct sla_station_ref *station_ref;
04195
04196 ast_dial_join(ringing_station->station->dial);
04197 ast_dial_destroy(ringing_station->station->dial);
04198 ringing_station->station->dial = NULL;
04199
04200 if (hangup == SLA_STATION_HANGUP_NORMAL)
04201 goto done;
04202
04203
04204
04205
04206
04207
04208 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04209 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04210 if (ringing_trunk->trunk == trunk_ref->trunk)
04211 break;
04212 }
04213 if (!trunk_ref)
04214 continue;
04215 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04216 continue;
04217 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04218 }
04219
04220 done:
04221 ast_free(ringing_station);
04222 }
04223
04224 static void sla_dial_state_callback(struct ast_dial *dial)
04225 {
04226 sla_queue_event(SLA_EVENT_DIAL_STATE);
04227 }
04228
04229
04230
04231
04232 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
04233 const struct sla_station *station)
04234 {
04235 struct sla_station_ref *timed_out_station;
04236
04237 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04238 if (station == timed_out_station->station)
04239 return 1;
04240 }
04241
04242 return 0;
04243 }
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
04254 struct sla_trunk_ref **trunk_ref, int rm)
04255 {
04256 struct sla_trunk_ref *s_trunk_ref;
04257 struct sla_ringing_trunk *ringing_trunk = NULL;
04258
04259 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04260 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04261
04262 if (s_trunk_ref->trunk != ringing_trunk->trunk)
04263 continue;
04264
04265
04266
04267 if (sla_check_timed_out_station(ringing_trunk, station))
04268 continue;
04269
04270 if (rm)
04271 AST_LIST_REMOVE_CURRENT(entry);
04272
04273 if (trunk_ref)
04274 *trunk_ref = s_trunk_ref;
04275
04276 break;
04277 }
04278 AST_LIST_TRAVERSE_SAFE_END;
04279
04280 if (ringing_trunk)
04281 break;
04282 }
04283
04284 return ringing_trunk;
04285 }
04286
04287 static void sla_handle_dial_state_event(void)
04288 {
04289 struct sla_ringing_station *ringing_station;
04290
04291 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04292 struct sla_trunk_ref *s_trunk_ref = NULL;
04293 struct sla_ringing_trunk *ringing_trunk = NULL;
04294 struct run_station_args args;
04295 enum ast_dial_result dial_res;
04296 pthread_t dont_care;
04297 ast_mutex_t cond_lock;
04298 ast_cond_t cond;
04299
04300 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04301 case AST_DIAL_RESULT_HANGUP:
04302 case AST_DIAL_RESULT_INVALID:
04303 case AST_DIAL_RESULT_FAILED:
04304 case AST_DIAL_RESULT_TIMEOUT:
04305 case AST_DIAL_RESULT_UNANSWERED:
04306 AST_LIST_REMOVE_CURRENT(entry);
04307 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04308 break;
04309 case AST_DIAL_RESULT_ANSWERED:
04310 AST_LIST_REMOVE_CURRENT(entry);
04311
04312 ast_mutex_lock(&sla.lock);
04313 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04314 ast_mutex_unlock(&sla.lock);
04315 if (!ringing_trunk) {
04316 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04317 break;
04318 }
04319
04320 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04321
04322 answer_trunk_chan(ringing_trunk->trunk->chan);
04323 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04324
04325
04326
04327 args.trunk_ref = s_trunk_ref;
04328 args.station = ringing_station->station;
04329 args.cond = &cond;
04330 args.cond_lock = &cond_lock;
04331 ast_free(ringing_trunk);
04332 ast_free(ringing_station);
04333 ast_mutex_init(&cond_lock);
04334 ast_cond_init(&cond, NULL);
04335 ast_mutex_lock(&cond_lock);
04336 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04337 ast_cond_wait(&cond, &cond_lock);
04338 ast_mutex_unlock(&cond_lock);
04339 ast_mutex_destroy(&cond_lock);
04340 ast_cond_destroy(&cond);
04341 break;
04342 case AST_DIAL_RESULT_TRYING:
04343 case AST_DIAL_RESULT_RINGING:
04344 case AST_DIAL_RESULT_PROGRESS:
04345 case AST_DIAL_RESULT_PROCEEDING:
04346 break;
04347 }
04348 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04349
04350 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04351 sla_queue_event(SLA_EVENT_DIAL_STATE);
04352 break;
04353 }
04354 }
04355 AST_LIST_TRAVERSE_SAFE_END;
04356 }
04357
04358
04359
04360
04361 static int sla_check_ringing_station(const struct sla_station *station)
04362 {
04363 struct sla_ringing_station *ringing_station;
04364
04365 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04366 if (station == ringing_station->station)
04367 return 1;
04368 }
04369
04370 return 0;
04371 }
04372
04373
04374
04375
04376 static int sla_check_failed_station(const struct sla_station *station)
04377 {
04378 struct sla_failed_station *failed_station;
04379 int res = 0;
04380
04381 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04382 if (station != failed_station->station)
04383 continue;
04384 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04385 AST_LIST_REMOVE_CURRENT(entry);
04386 ast_free(failed_station);
04387 break;
04388 }
04389 res = 1;
04390 }
04391 AST_LIST_TRAVERSE_SAFE_END
04392
04393 return res;
04394 }
04395
04396
04397
04398
04399 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
04400 {
04401 char *tech, *tech_data;
04402 struct ast_dial *dial;
04403 struct sla_ringing_station *ringing_station;
04404 const char *cid_name = NULL, *cid_num = NULL;
04405 enum ast_dial_result res;
04406
04407 if (!(dial = ast_dial_create()))
04408 return -1;
04409
04410 ast_dial_set_state_callback(dial, sla_dial_state_callback);
04411 tech_data = ast_strdupa(station->device);
04412 tech = strsep(&tech_data, "/");
04413
04414 if (ast_dial_append(dial, tech, tech_data) == -1) {
04415 ast_dial_destroy(dial);
04416 return -1;
04417 }
04418
04419 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04420 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04421 ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04422 ringing_trunk->trunk->chan->cid.cid_name = NULL;
04423 }
04424 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04425 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04426 ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04427 ringing_trunk->trunk->chan->cid.cid_num = NULL;
04428 }
04429
04430 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04431
04432 if (cid_name)
04433 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04434 if (cid_num)
04435 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04436
04437 if (res != AST_DIAL_RESULT_TRYING) {
04438 struct sla_failed_station *failed_station;
04439 ast_dial_destroy(dial);
04440 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04441 return -1;
04442 failed_station->station = station;
04443 failed_station->last_try = ast_tvnow();
04444 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04445 return -1;
04446 }
04447 if (!(ringing_station = sla_create_ringing_station(station))) {
04448 ast_dial_join(dial);
04449 ast_dial_destroy(dial);
04450 return -1;
04451 }
04452
04453 station->dial = dial;
04454
04455 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04456
04457 return 0;
04458 }
04459
04460
04461
04462 static int sla_check_inuse_station(const struct sla_station *station)
04463 {
04464 struct sla_trunk_ref *trunk_ref;
04465
04466 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04467 if (trunk_ref->chan)
04468 return 1;
04469 }
04470
04471 return 0;
04472 }
04473
04474 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
04475 const struct sla_trunk *trunk)
04476 {
04477 struct sla_trunk_ref *trunk_ref = NULL;
04478
04479 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04480 if (trunk_ref->trunk == trunk)
04481 break;
04482 }
04483
04484 return trunk_ref;
04485 }
04486
04487
04488
04489
04490
04491
04492 static int sla_check_station_delay(struct sla_station *station,
04493 struct sla_ringing_trunk *ringing_trunk)
04494 {
04495 struct sla_trunk_ref *trunk_ref;
04496 unsigned int delay = UINT_MAX;
04497 int time_left, time_elapsed;
04498
04499 if (!ringing_trunk)
04500 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04501 else
04502 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04503
04504 if (!ringing_trunk || !trunk_ref)
04505 return delay;
04506
04507
04508
04509
04510 delay = trunk_ref->ring_delay;
04511 if (!delay)
04512 delay = station->ring_delay;
04513 if (!delay)
04514 return INT_MAX;
04515
04516 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04517 time_left = (delay * 1000) - time_elapsed;
04518
04519 return time_left;
04520 }
04521
04522
04523
04524
04525 static void sla_ring_stations(void)
04526 {
04527 struct sla_station_ref *station_ref;
04528 struct sla_ringing_trunk *ringing_trunk;
04529
04530
04531
04532 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04533 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04534 int time_left;
04535
04536
04537 if (sla_check_ringing_station(station_ref->station))
04538 continue;
04539
04540
04541 if (sla_check_inuse_station(station_ref->station))
04542 continue;
04543
04544
04545
04546 if (sla_check_failed_station(station_ref->station))
04547 continue;
04548
04549
04550
04551 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04552 continue;
04553
04554
04555 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04556 if (time_left != INT_MAX && time_left > 0)
04557 continue;
04558
04559
04560 sla_ring_station(ringing_trunk, station_ref->station);
04561 }
04562 }
04563
04564 }
04565
04566 static void sla_hangup_stations(void)
04567 {
04568 struct sla_trunk_ref *trunk_ref;
04569 struct sla_ringing_station *ringing_station;
04570
04571 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04572 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04573 struct sla_ringing_trunk *ringing_trunk;
04574 ast_mutex_lock(&sla.lock);
04575 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04576 if (trunk_ref->trunk == ringing_trunk->trunk)
04577 break;
04578 }
04579 ast_mutex_unlock(&sla.lock);
04580 if (ringing_trunk)
04581 break;
04582 }
04583 if (!trunk_ref) {
04584 AST_LIST_REMOVE_CURRENT(entry);
04585 ast_dial_join(ringing_station->station->dial);
04586 ast_dial_destroy(ringing_station->station->dial);
04587 ringing_station->station->dial = NULL;
04588 ast_free(ringing_station);
04589 }
04590 }
04591 AST_LIST_TRAVERSE_SAFE_END
04592 }
04593
04594 static void sla_handle_ringing_trunk_event(void)
04595 {
04596 ast_mutex_lock(&sla.lock);
04597 sla_ring_stations();
04598 ast_mutex_unlock(&sla.lock);
04599
04600
04601 sla_hangup_stations();
04602 }
04603
04604 static void sla_handle_hold_event(struct sla_event *event)
04605 {
04606 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04607 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04608 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s",
04609 event->station->name, event->trunk_ref->trunk->name);
04610 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
04611 INACTIVE_TRUNK_REFS, event->trunk_ref);
04612
04613 if (event->trunk_ref->trunk->active_stations == 1) {
04614
04615
04616 event->trunk_ref->trunk->on_hold = 1;
04617 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04618 }
04619
04620 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
04621 event->trunk_ref->chan = NULL;
04622 }
04623
04624
04625
04626
04627
04628 static int sla_calc_trunk_timeouts(unsigned int *timeout)
04629 {
04630 struct sla_ringing_trunk *ringing_trunk;
04631 int res = 0;
04632
04633 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04634 int time_left, time_elapsed;
04635 if (!ringing_trunk->trunk->ring_timeout)
04636 continue;
04637 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04638 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04639 if (time_left <= 0) {
04640 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04641 AST_LIST_REMOVE_CURRENT(entry);
04642 sla_stop_ringing_trunk(ringing_trunk);
04643 res = 1;
04644 continue;
04645 }
04646 if (time_left < *timeout)
04647 *timeout = time_left;
04648 }
04649 AST_LIST_TRAVERSE_SAFE_END;
04650
04651 return res;
04652 }
04653
04654
04655
04656
04657
04658 static int sla_calc_station_timeouts(unsigned int *timeout)
04659 {
04660 struct sla_ringing_trunk *ringing_trunk;
04661 struct sla_ringing_station *ringing_station;
04662 int res = 0;
04663
04664 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04665 unsigned int ring_timeout = 0;
04666 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04667 struct sla_trunk_ref *trunk_ref;
04668
04669
04670
04671
04672 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04673 struct sla_station_ref *station_ref;
04674 int trunk_time_elapsed, trunk_time_left;
04675
04676 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04677 if (ringing_trunk->trunk == trunk_ref->trunk)
04678 break;
04679 }
04680 if (!ringing_trunk)
04681 continue;
04682
04683
04684
04685 if (!trunk_ref->ring_timeout)
04686 break;
04687
04688
04689
04690
04691 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04692 if (station_ref->station == ringing_station->station)
04693 break;
04694 }
04695 if (station_ref)
04696 continue;
04697
04698 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04699 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04700 if (trunk_time_left > final_trunk_time_left)
04701 final_trunk_time_left = trunk_time_left;
04702 }
04703
04704
04705 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04706 continue;
04707
04708
04709 if (ringing_station->station->ring_timeout) {
04710 ring_timeout = ringing_station->station->ring_timeout;
04711 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04712 time_left = (ring_timeout * 1000) - time_elapsed;
04713 }
04714
04715
04716
04717 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04718 time_left = final_trunk_time_left;
04719
04720
04721 if (time_left <= 0) {
04722 AST_LIST_REMOVE_CURRENT(entry);
04723 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04724 res = 1;
04725 continue;
04726 }
04727
04728
04729
04730 if (time_left < *timeout)
04731 *timeout = time_left;
04732 }
04733 AST_LIST_TRAVERSE_SAFE_END;
04734
04735 return res;
04736 }
04737
04738
04739
04740
04741 static int sla_calc_station_delays(unsigned int *timeout)
04742 {
04743 struct sla_station *station;
04744 int res = 0;
04745
04746 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04747 struct sla_ringing_trunk *ringing_trunk;
04748 int time_left;
04749
04750
04751 if (sla_check_ringing_station(station))
04752 continue;
04753
04754
04755 if (sla_check_inuse_station(station))
04756 continue;
04757
04758
04759 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04760 continue;
04761
04762 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04763 continue;
04764
04765
04766
04767
04768 if (time_left <= 0) {
04769 res = 1;
04770 continue;
04771 }
04772
04773 if (time_left < *timeout)
04774 *timeout = time_left;
04775 }
04776
04777 return res;
04778 }
04779
04780
04781
04782 static int sla_process_timers(struct timespec *ts)
04783 {
04784 unsigned int timeout = UINT_MAX;
04785 struct timeval wait;
04786 unsigned int change_made = 0;
04787
04788
04789 if (sla_calc_trunk_timeouts(&timeout))
04790 change_made = 1;
04791
04792
04793 if (sla_calc_station_timeouts(&timeout))
04794 change_made = 1;
04795
04796
04797 if (sla_calc_station_delays(&timeout))
04798 change_made = 1;
04799
04800
04801 if (change_made)
04802 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04803
04804
04805 if (timeout == UINT_MAX)
04806 return 0;
04807
04808 if (ts) {
04809 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04810 ts->tv_sec = wait.tv_sec;
04811 ts->tv_nsec = wait.tv_usec * 1000;
04812 }
04813
04814 return 1;
04815 }
04816
04817 static int sla_load_config(int reload);
04818
04819
04820 static void sla_check_reload(void)
04821 {
04822 struct sla_station *station;
04823 struct sla_trunk *trunk;
04824
04825 ast_mutex_lock(&sla.lock);
04826
04827 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
04828 || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04829 ast_mutex_unlock(&sla.lock);
04830 return;
04831 }
04832
04833 AST_RWLIST_RDLOCK(&sla_stations);
04834 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04835 if (station->ref_count)
04836 break;
04837 }
04838 AST_RWLIST_UNLOCK(&sla_stations);
04839 if (station) {
04840 ast_mutex_unlock(&sla.lock);
04841 return;
04842 }
04843
04844 AST_RWLIST_RDLOCK(&sla_trunks);
04845 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04846 if (trunk->ref_count)
04847 break;
04848 }
04849 AST_RWLIST_UNLOCK(&sla_trunks);
04850 if (trunk) {
04851 ast_mutex_unlock(&sla.lock);
04852 return;
04853 }
04854
04855
04856 sla_load_config(1);
04857 sla.reload = 0;
04858
04859 ast_mutex_unlock(&sla.lock);
04860 }
04861
04862 static void *sla_thread(void *data)
04863 {
04864 struct sla_failed_station *failed_station;
04865 struct sla_ringing_station *ringing_station;
04866
04867 ast_mutex_lock(&sla.lock);
04868
04869 while (!sla.stop) {
04870 struct sla_event *event;
04871 struct timespec ts = { 0, };
04872 unsigned int have_timeout = 0;
04873
04874 if (AST_LIST_EMPTY(&sla.event_q)) {
04875 if ((have_timeout = sla_process_timers(&ts)))
04876 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04877 else
04878 ast_cond_wait(&sla.cond, &sla.lock);
04879 if (sla.stop)
04880 break;
04881 }
04882
04883 if (have_timeout)
04884 sla_process_timers(NULL);
04885
04886 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04887 ast_mutex_unlock(&sla.lock);
04888 switch (event->type) {
04889 case SLA_EVENT_HOLD:
04890 sla_handle_hold_event(event);
04891 break;
04892 case SLA_EVENT_DIAL_STATE:
04893 sla_handle_dial_state_event();
04894 break;
04895 case SLA_EVENT_RINGING_TRUNK:
04896 sla_handle_ringing_trunk_event();
04897 break;
04898 case SLA_EVENT_RELOAD:
04899 sla.reload = 1;
04900 case SLA_EVENT_CHECK_RELOAD:
04901 break;
04902 }
04903 ast_free(event);
04904 ast_mutex_lock(&sla.lock);
04905 }
04906
04907 if (sla.reload)
04908 sla_check_reload();
04909 }
04910
04911 ast_mutex_unlock(&sla.lock);
04912
04913 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04914 ast_free(ringing_station);
04915
04916 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04917 ast_free(failed_station);
04918
04919 return NULL;
04920 }
04921
04922 struct dial_trunk_args {
04923 struct sla_trunk_ref *trunk_ref;
04924 struct sla_station *station;
04925 ast_mutex_t *cond_lock;
04926 ast_cond_t *cond;
04927 };
04928
04929 static void *dial_trunk(void *data)
04930 {
04931 struct dial_trunk_args *args = data;
04932 struct ast_dial *dial;
04933 char *tech, *tech_data;
04934 enum ast_dial_result dial_res;
04935 char conf_name[MAX_CONFNUM];
04936 struct ast_conference *conf;
04937 struct ast_flags conf_flags = { 0 };
04938 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04939 const char *cid_name = NULL, *cid_num = NULL;
04940
04941 if (!(dial = ast_dial_create())) {
04942 ast_mutex_lock(args->cond_lock);
04943 ast_cond_signal(args->cond);
04944 ast_mutex_unlock(args->cond_lock);
04945 return NULL;
04946 }
04947
04948 tech_data = ast_strdupa(trunk_ref->trunk->device);
04949 tech = strsep(&tech_data, "/");
04950 if (ast_dial_append(dial, tech, tech_data) == -1) {
04951 ast_mutex_lock(args->cond_lock);
04952 ast_cond_signal(args->cond);
04953 ast_mutex_unlock(args->cond_lock);
04954 ast_dial_destroy(dial);
04955 return NULL;
04956 }
04957
04958 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04959 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04960 ast_free(trunk_ref->chan->cid.cid_name);
04961 trunk_ref->chan->cid.cid_name = NULL;
04962 }
04963 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04964 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04965 ast_free(trunk_ref->chan->cid.cid_num);
04966 trunk_ref->chan->cid.cid_num = NULL;
04967 }
04968
04969 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04970
04971 if (cid_name)
04972 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04973 if (cid_num)
04974 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04975
04976 if (dial_res != AST_DIAL_RESULT_TRYING) {
04977 ast_mutex_lock(args->cond_lock);
04978 ast_cond_signal(args->cond);
04979 ast_mutex_unlock(args->cond_lock);
04980 ast_dial_destroy(dial);
04981 return NULL;
04982 }
04983
04984 for (;;) {
04985 unsigned int done = 0;
04986 switch ((dial_res = ast_dial_state(dial))) {
04987 case AST_DIAL_RESULT_ANSWERED:
04988 trunk_ref->trunk->chan = ast_dial_answered(dial);
04989 case AST_DIAL_RESULT_HANGUP:
04990 case AST_DIAL_RESULT_INVALID:
04991 case AST_DIAL_RESULT_FAILED:
04992 case AST_DIAL_RESULT_TIMEOUT:
04993 case AST_DIAL_RESULT_UNANSWERED:
04994 done = 1;
04995 case AST_DIAL_RESULT_TRYING:
04996 case AST_DIAL_RESULT_RINGING:
04997 case AST_DIAL_RESULT_PROGRESS:
04998 case AST_DIAL_RESULT_PROCEEDING:
04999 break;
05000 }
05001 if (done)
05002 break;
05003 }
05004
05005 if (!trunk_ref->trunk->chan) {
05006 ast_mutex_lock(args->cond_lock);
05007 ast_cond_signal(args->cond);
05008 ast_mutex_unlock(args->cond_lock);
05009 ast_dial_join(dial);
05010 ast_dial_destroy(dial);
05011 return NULL;
05012 }
05013
05014 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05015 ast_set_flag(&conf_flags,
05016 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
05017 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05018 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05019
05020 ast_mutex_lock(args->cond_lock);
05021 ast_cond_signal(args->cond);
05022 ast_mutex_unlock(args->cond_lock);
05023
05024 if (conf) {
05025 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05026 dispose_conf(conf);
05027 conf = NULL;
05028 }
05029
05030
05031 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05032
05033 trunk_ref->trunk->chan = NULL;
05034 trunk_ref->trunk->on_hold = 0;
05035
05036 ast_dial_join(dial);
05037 ast_dial_destroy(dial);
05038
05039 return NULL;
05040 }
05041
05042
05043
05044 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
05045 {
05046 struct sla_trunk_ref *trunk_ref = NULL;
05047
05048 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05049 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05050 break;
05051 }
05052
05053 return trunk_ref;
05054 }
05055
05056 static int sla_station_exec(struct ast_channel *chan, void *data)
05057 {
05058 char *station_name, *trunk_name;
05059 struct sla_station *station;
05060 struct sla_trunk_ref *trunk_ref = NULL;
05061 char conf_name[MAX_CONFNUM];
05062 struct ast_flags conf_flags = { 0 };
05063 struct ast_conference *conf;
05064
05065 if (ast_strlen_zero(data)) {
05066 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05067 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05068 return 0;
05069 }
05070
05071 trunk_name = ast_strdupa(data);
05072 station_name = strsep(&trunk_name, "_");
05073
05074 if (ast_strlen_zero(station_name)) {
05075 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05076 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05077 return 0;
05078 }
05079
05080 AST_RWLIST_RDLOCK(&sla_stations);
05081 station = sla_find_station(station_name);
05082 if (station)
05083 ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05084 AST_RWLIST_UNLOCK(&sla_stations);
05085
05086 if (!station) {
05087 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05088 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05089 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05090 return 0;
05091 }
05092
05093 AST_RWLIST_RDLOCK(&sla_trunks);
05094 if (!ast_strlen_zero(trunk_name)) {
05095 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05096 } else
05097 trunk_ref = sla_choose_idle_trunk(station);
05098 AST_RWLIST_UNLOCK(&sla_trunks);
05099
05100 if (!trunk_ref) {
05101 if (ast_strlen_zero(trunk_name))
05102 ast_log(LOG_NOTICE, "No trunks available for call.\n");
05103 else {
05104 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05105 "'%s' due to access controls.\n", trunk_name);
05106 }
05107 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05108 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05109 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05110 return 0;
05111 }
05112
05113 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05114 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05115 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05116 else {
05117 trunk_ref->state = SLA_TRUNK_STATE_UP;
05118 ast_devstate_changed(AST_DEVICE_INUSE,
05119 "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05120 }
05121 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05122 struct sla_ringing_trunk *ringing_trunk;
05123
05124 ast_mutex_lock(&sla.lock);
05125 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05126 if (ringing_trunk->trunk == trunk_ref->trunk) {
05127 AST_LIST_REMOVE_CURRENT(entry);
05128 break;
05129 }
05130 }
05131 AST_LIST_TRAVERSE_SAFE_END
05132 ast_mutex_unlock(&sla.lock);
05133
05134 if (ringing_trunk) {
05135 answer_trunk_chan(ringing_trunk->trunk->chan);
05136 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05137
05138 free(ringing_trunk);
05139
05140
05141 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05142 sla_queue_event(SLA_EVENT_DIAL_STATE);
05143 }
05144 }
05145
05146 trunk_ref->chan = chan;
05147
05148 if (!trunk_ref->trunk->chan) {
05149 ast_mutex_t cond_lock;
05150 ast_cond_t cond;
05151 pthread_t dont_care;
05152 struct dial_trunk_args args = {
05153 .trunk_ref = trunk_ref,
05154 .station = station,
05155 .cond_lock = &cond_lock,
05156 .cond = &cond,
05157 };
05158 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05159
05160
05161
05162 ast_autoservice_start(chan);
05163 ast_mutex_init(&cond_lock);
05164 ast_cond_init(&cond, NULL);
05165 ast_mutex_lock(&cond_lock);
05166 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05167 ast_cond_wait(&cond, &cond_lock);
05168 ast_mutex_unlock(&cond_lock);
05169 ast_mutex_destroy(&cond_lock);
05170 ast_cond_destroy(&cond);
05171 ast_autoservice_stop(chan);
05172 if (!trunk_ref->trunk->chan) {
05173 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05174 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05175 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05176 trunk_ref->chan = NULL;
05177 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05178 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05179 return 0;
05180 }
05181 }
05182
05183 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05184 trunk_ref->trunk->on_hold) {
05185 trunk_ref->trunk->on_hold = 0;
05186 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05187 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05188 }
05189
05190 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05191 ast_set_flag(&conf_flags,
05192 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05193 ast_answer(chan);
05194 conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05195 if (conf) {
05196 conf_run(chan, conf, conf_flags.flags, NULL);
05197 dispose_conf(conf);
05198 conf = NULL;
05199 }
05200 trunk_ref->chan = NULL;
05201 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05202 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05203 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05204 admin_exec(NULL, conf_name);
05205 trunk_ref->trunk->hold_stations = 0;
05206 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05207 }
05208
05209 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05210
05211 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05212 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05213
05214 return 0;
05215 }
05216
05217 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
05218 {
05219 struct sla_trunk_ref *trunk_ref;
05220
05221 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05222 return NULL;
05223
05224 trunk_ref->trunk = trunk;
05225
05226 return trunk_ref;
05227 }
05228
05229 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
05230 {
05231 struct sla_ringing_trunk *ringing_trunk;
05232
05233 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05234 return NULL;
05235
05236 ringing_trunk->trunk = trunk;
05237 ringing_trunk->ring_begin = ast_tvnow();
05238
05239 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05240
05241 ast_mutex_lock(&sla.lock);
05242 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05243 ast_mutex_unlock(&sla.lock);
05244
05245 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05246
05247 return ringing_trunk;
05248 }
05249
05250 enum {
05251 SLA_TRUNK_OPT_MOH = (1 << 0),
05252 };
05253
05254 enum {
05255 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05256 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05257 };
05258
05259 AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
05260 AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
05261 END_OPTIONS );
05262
05263 static int sla_trunk_exec(struct ast_channel *chan, void *data)
05264 {
05265 char conf_name[MAX_CONFNUM];
05266 struct ast_conference *conf;
05267 struct ast_flags conf_flags = { 0 };
05268 struct sla_trunk *trunk;
05269 struct sla_ringing_trunk *ringing_trunk;
05270 AST_DECLARE_APP_ARGS(args,
05271 AST_APP_ARG(trunk_name);
05272 AST_APP_ARG(options);
05273 );
05274 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05275 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05276 struct ast_flags opt_flags = { 0 };
05277 char *parse;
05278
05279 if (ast_strlen_zero(data)) {
05280 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05281 return -1;
05282 }
05283
05284 parse = ast_strdupa(data);
05285 AST_STANDARD_APP_ARGS(args, parse);
05286 if (args.argc == 2) {
05287 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05288 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05289 return -1;
05290 }
05291 }
05292
05293 AST_RWLIST_RDLOCK(&sla_trunks);
05294 trunk = sla_find_trunk(args.trunk_name);
05295 if (trunk)
05296 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05297 AST_RWLIST_UNLOCK(&sla_trunks);
05298
05299 if (!trunk) {
05300 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05301 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05302 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05303 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05304 return 0;
05305 }
05306
05307 if (trunk->chan) {
05308 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05309 args.trunk_name);
05310 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05311 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05312 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05313 return 0;
05314 }
05315
05316 trunk->chan = chan;
05317
05318 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05319 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05320 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05321 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05322 return 0;
05323 }
05324
05325 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05326 conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05327 if (!conf) {
05328 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05329 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05330 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05331 return 0;
05332 }
05333 ast_set_flag(&conf_flags,
05334 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05335
05336 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05337 ast_indicate(chan, -1);
05338 ast_set_flag(&conf_flags, CONFFLAG_MOH);
05339 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05340 } else
05341 ast_indicate(chan, AST_CONTROL_RINGING);
05342
05343 conf_run(chan, conf, conf_flags.flags, opts);
05344 dispose_conf(conf);
05345 conf = NULL;
05346 trunk->chan = NULL;
05347 trunk->on_hold = 0;
05348
05349 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05350
05351 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05352 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05353
05354
05355 ast_mutex_lock(&sla.lock);
05356 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05357 if (ringing_trunk->trunk == trunk) {
05358 AST_LIST_REMOVE_CURRENT(entry);
05359 break;
05360 }
05361 }
05362 AST_LIST_TRAVERSE_SAFE_END;
05363 ast_mutex_unlock(&sla.lock);
05364 if (ringing_trunk) {
05365 ast_free(ringing_trunk);
05366 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05367
05368
05369 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05370 }
05371
05372 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05373 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05374
05375 return 0;
05376 }
05377
05378 static enum ast_device_state sla_state(const char *data)
05379 {
05380 char *buf, *station_name, *trunk_name;
05381 struct sla_station *station;
05382 struct sla_trunk_ref *trunk_ref;
05383 enum ast_device_state res = AST_DEVICE_INVALID;
05384
05385 trunk_name = buf = ast_strdupa(data);
05386 station_name = strsep(&trunk_name, "_");
05387
05388 AST_RWLIST_RDLOCK(&sla_stations);
05389 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05390 if (strcasecmp(station_name, station->name))
05391 continue;
05392 AST_RWLIST_RDLOCK(&sla_trunks);
05393 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05394 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05395 break;
05396 }
05397 if (!trunk_ref) {
05398 AST_RWLIST_UNLOCK(&sla_trunks);
05399 break;
05400 }
05401 res = sla_state_to_devstate(trunk_ref->state);
05402 AST_RWLIST_UNLOCK(&sla_trunks);
05403 }
05404 AST_RWLIST_UNLOCK(&sla_stations);
05405
05406 if (res == AST_DEVICE_INVALID) {
05407 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05408 trunk_name, station_name);
05409 }
05410
05411 return res;
05412 }
05413
05414 static void destroy_trunk(struct sla_trunk *trunk)
05415 {
05416 struct sla_station_ref *station_ref;
05417
05418 if (!ast_strlen_zero(trunk->autocontext))
05419 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05420
05421 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05422 ast_free(station_ref);
05423
05424 ast_string_field_free_memory(trunk);
05425 ast_free(trunk);
05426 }
05427
05428 static void destroy_station(struct sla_station *station)
05429 {
05430 struct sla_trunk_ref *trunk_ref;
05431
05432 if (!ast_strlen_zero(station->autocontext)) {
05433 AST_RWLIST_RDLOCK(&sla_trunks);
05434 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05435 char exten[AST_MAX_EXTENSION];
05436 char hint[AST_MAX_APP];
05437 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05438 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05439 ast_context_remove_extension(station->autocontext, exten,
05440 1, sla_registrar);
05441 ast_context_remove_extension(station->autocontext, hint,
05442 PRIORITY_HINT, sla_registrar);
05443 }
05444 AST_RWLIST_UNLOCK(&sla_trunks);
05445 }
05446
05447 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05448 ast_free(trunk_ref);
05449
05450 ast_string_field_free_memory(station);
05451 ast_free(station);
05452 }
05453
05454 static void sla_destroy(void)
05455 {
05456 struct sla_trunk *trunk;
05457 struct sla_station *station;
05458
05459 AST_RWLIST_WRLOCK(&sla_trunks);
05460 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05461 destroy_trunk(trunk);
05462 AST_RWLIST_UNLOCK(&sla_trunks);
05463
05464 AST_RWLIST_WRLOCK(&sla_stations);
05465 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05466 destroy_station(station);
05467 AST_RWLIST_UNLOCK(&sla_stations);
05468
05469 if (sla.thread != AST_PTHREADT_NULL) {
05470 ast_mutex_lock(&sla.lock);
05471 sla.stop = 1;
05472 ast_cond_signal(&sla.cond);
05473 ast_mutex_unlock(&sla.lock);
05474 pthread_join(sla.thread, NULL);
05475 }
05476
05477
05478 ast_context_destroy(NULL, sla_registrar);
05479
05480 ast_mutex_destroy(&sla.lock);
05481 ast_cond_destroy(&sla.cond);
05482 }
05483
05484 static int sla_check_device(const char *device)
05485 {
05486 char *tech, *tech_data;
05487
05488 tech_data = ast_strdupa(device);
05489 tech = strsep(&tech_data, "/");
05490
05491 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05492 return -1;
05493
05494 return 0;
05495 }
05496
05497 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
05498 {
05499 struct sla_trunk *trunk;
05500 struct ast_variable *var;
05501 const char *dev;
05502
05503 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05504 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05505 return -1;
05506 }
05507
05508 if (sla_check_device(dev)) {
05509 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05510 cat, dev);
05511 return -1;
05512 }
05513
05514 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05515 return -1;
05516 if (ast_string_field_init(trunk, 32)) {
05517 ast_free(trunk);
05518 return -1;
05519 }
05520
05521 ast_string_field_set(trunk, name, cat);
05522 ast_string_field_set(trunk, device, dev);
05523
05524 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05525 if (!strcasecmp(var->name, "autocontext"))
05526 ast_string_field_set(trunk, autocontext, var->value);
05527 else if (!strcasecmp(var->name, "ringtimeout")) {
05528 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
05529 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05530 var->value, trunk->name);
05531 trunk->ring_timeout = 0;
05532 }
05533 } else if (!strcasecmp(var->name, "barge"))
05534 trunk->barge_disabled = ast_false(var->value);
05535 else if (!strcasecmp(var->name, "hold")) {
05536 if (!strcasecmp(var->value, "private"))
05537 trunk->hold_access = SLA_HOLD_PRIVATE;
05538 else if (!strcasecmp(var->value, "open"))
05539 trunk->hold_access = SLA_HOLD_OPEN;
05540 else {
05541 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05542 var->value, trunk->name);
05543 }
05544 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05545 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05546 var->name, var->lineno, SLA_CONFIG_FILE);
05547 }
05548 }
05549
05550 if (!ast_strlen_zero(trunk->autocontext)) {
05551 struct ast_context *context;
05552 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05553 if (!context) {
05554 ast_log(LOG_ERROR, "Failed to automatically find or create "
05555 "context '%s' for SLA!\n", trunk->autocontext);
05556 destroy_trunk(trunk);
05557 return -1;
05558 }
05559 if (ast_add_extension2(context, 0 , "s", 1,
05560 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05561 ast_log(LOG_ERROR, "Failed to automatically create extension "
05562 "for trunk '%s'!\n", trunk->name);
05563 destroy_trunk(trunk);
05564 return -1;
05565 }
05566 }
05567
05568 AST_RWLIST_WRLOCK(&sla_trunks);
05569 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05570 AST_RWLIST_UNLOCK(&sla_trunks);
05571
05572 return 0;
05573 }
05574
05575 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
05576 {
05577 struct sla_trunk *trunk;
05578 struct sla_trunk_ref *trunk_ref;
05579 struct sla_station_ref *station_ref;
05580 char *trunk_name, *options, *cur;
05581
05582 options = ast_strdupa(var->value);
05583 trunk_name = strsep(&options, ",");
05584
05585 AST_RWLIST_RDLOCK(&sla_trunks);
05586 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05587 if (!strcasecmp(trunk->name, trunk_name))
05588 break;
05589 }
05590
05591 AST_RWLIST_UNLOCK(&sla_trunks);
05592 if (!trunk) {
05593 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05594 return;
05595 }
05596 if (!(trunk_ref = create_trunk_ref(trunk)))
05597 return;
05598 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05599
05600 while ((cur = strsep(&options, ","))) {
05601 char *name, *value = cur;
05602 name = strsep(&value, "=");
05603 if (!strcasecmp(name, "ringtimeout")) {
05604 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
05605 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05606 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05607 trunk_ref->ring_timeout = 0;
05608 }
05609 } else if (!strcasecmp(name, "ringdelay")) {
05610 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
05611 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05612 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05613 trunk_ref->ring_delay = 0;
05614 }
05615 } else {
05616 ast_log(LOG_WARNING, "Invalid option '%s' for "
05617 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05618 }
05619 }
05620
05621 if (!(station_ref = sla_create_station_ref(station))) {
05622 ast_free(trunk_ref);
05623 return;
05624 }
05625 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05626 AST_RWLIST_WRLOCK(&sla_trunks);
05627 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05628 AST_RWLIST_UNLOCK(&sla_trunks);
05629 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05630 }
05631
05632 static int sla_build_station(struct ast_config *cfg, const char *cat)
05633 {
05634 struct sla_station *station;
05635 struct ast_variable *var;
05636 const char *dev;
05637
05638 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05639 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05640 return -1;
05641 }
05642
05643 if (!(station = ast_calloc(1, sizeof(*station))))
05644 return -1;
05645 if (ast_string_field_init(station, 32)) {
05646 ast_free(station);
05647 return -1;
05648 }
05649
05650 ast_string_field_set(station, name, cat);
05651 ast_string_field_set(station, device, dev);
05652
05653 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05654 if (!strcasecmp(var->name, "trunk"))
05655 sla_add_trunk_to_station(station, var);
05656 else if (!strcasecmp(var->name, "autocontext"))
05657 ast_string_field_set(station, autocontext, var->value);
05658 else if (!strcasecmp(var->name, "ringtimeout")) {
05659 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05660 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05661 var->value, station->name);
05662 station->ring_timeout = 0;
05663 }
05664 } else if (!strcasecmp(var->name, "ringdelay")) {
05665 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05666 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05667 var->value, station->name);
05668 station->ring_delay = 0;
05669 }
05670 } else if (!strcasecmp(var->name, "hold")) {
05671 if (!strcasecmp(var->value, "private"))
05672 station->hold_access = SLA_HOLD_PRIVATE;
05673 else if (!strcasecmp(var->value, "open"))
05674 station->hold_access = SLA_HOLD_OPEN;
05675 else {
05676 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05677 var->value, station->name);
05678 }
05679
05680 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05681 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05682 var->name, var->lineno, SLA_CONFIG_FILE);
05683 }
05684 }
05685
05686 if (!ast_strlen_zero(station->autocontext)) {
05687 struct ast_context *context;
05688 struct sla_trunk_ref *trunk_ref;
05689 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05690 if (!context) {
05691 ast_log(LOG_ERROR, "Failed to automatically find or create "
05692 "context '%s' for SLA!\n", station->autocontext);
05693 destroy_station(station);
05694 return -1;
05695 }
05696
05697
05698 if (ast_add_extension2(context, 0 , station->name, 1,
05699 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05700 ast_log(LOG_ERROR, "Failed to automatically create extension "
05701 "for trunk '%s'!\n", station->name);
05702 destroy_station(station);
05703 return -1;
05704 }
05705 AST_RWLIST_RDLOCK(&sla_trunks);
05706 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05707 char exten[AST_MAX_EXTENSION];
05708 char hint[AST_MAX_APP];
05709 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05710 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05711
05712
05713 if (ast_add_extension2(context, 0 , exten, 1,
05714 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05715 ast_log(LOG_ERROR, "Failed to automatically create extension "
05716 "for trunk '%s'!\n", station->name);
05717 destroy_station(station);
05718 return -1;
05719 }
05720
05721
05722 if (ast_add_extension2(context, 0 , exten, PRIORITY_HINT,
05723 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05724 ast_log(LOG_ERROR, "Failed to automatically create hint "
05725 "for trunk '%s'!\n", station->name);
05726 destroy_station(station);
05727 return -1;
05728 }
05729 }
05730 AST_RWLIST_UNLOCK(&sla_trunks);
05731 }
05732
05733 AST_RWLIST_WRLOCK(&sla_stations);
05734 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05735 AST_RWLIST_UNLOCK(&sla_stations);
05736
05737 return 0;
05738 }
05739
05740 static int sla_load_config(int reload)
05741 {
05742 struct ast_config *cfg;
05743 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05744 const char *cat = NULL;
05745 int res = 0;
05746 const char *val;
05747
05748 if (!reload) {
05749 ast_mutex_init(&sla.lock);
05750 ast_cond_init(&sla.cond, NULL);
05751 }
05752
05753 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05754 return 0;
05755 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05756 return 0;
05757
05758 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05759 sla.attempt_callerid = ast_true(val);
05760
05761 while ((cat = ast_category_browse(cfg, cat)) && !res) {
05762 const char *type;
05763 if (!strcasecmp(cat, "general"))
05764 continue;
05765 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05766 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05767 SLA_CONFIG_FILE);
05768 continue;
05769 }
05770 if (!strcasecmp(type, "trunk"))
05771 res = sla_build_trunk(cfg, cat);
05772 else if (!strcasecmp(type, "station"))
05773 res = sla_build_station(cfg, cat);
05774 else {
05775 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05776 SLA_CONFIG_FILE, type);
05777 }
05778 }
05779
05780 ast_config_destroy(cfg);
05781
05782 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05783 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05784
05785 return res;
05786 }
05787
05788 static int acf_meetme_info_eval(char *keyword, struct ast_conference *conf)
05789 {
05790 if (!strcasecmp("lock", keyword)) {
05791 return conf->locked;
05792 } else if (!strcasecmp("parties", keyword)) {
05793 return conf->users;
05794 } else if (!strcasecmp("activity", keyword)) {
05795 time_t now;
05796 now = time(NULL);
05797 return (now - conf->start);
05798 } else if (!strcasecmp("dynamic", keyword)) {
05799 return conf->isdynamic;
05800 } else {
05801 return -1;
05802 }
05803
05804 }
05805
05806 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05807 {
05808 struct ast_conference *conf;
05809 char *parse;
05810 int result = -2;
05811 AST_DECLARE_APP_ARGS(args,
05812 AST_APP_ARG(keyword);
05813 AST_APP_ARG(confno);
05814 );
05815
05816 if (ast_strlen_zero(data)) {
05817 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
05818 return -1;
05819 }
05820
05821 parse = ast_strdupa(data);
05822 AST_STANDARD_APP_ARGS(args, parse);
05823
05824 if (ast_strlen_zero(args.keyword)) {
05825 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
05826 return -1;
05827 }
05828
05829 if (ast_strlen_zero(args.confno)) {
05830 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
05831 return -1;
05832 }
05833
05834 AST_LIST_LOCK(&confs);
05835 AST_LIST_TRAVERSE(&confs, conf, list) {
05836 if (!strcmp(args.confno, conf->confno)) {
05837 result = acf_meetme_info_eval(args.keyword, conf);
05838 break;
05839 }
05840 }
05841 AST_LIST_UNLOCK(&confs);
05842
05843 if (result > -1) {
05844 snprintf(buf, len, "%d", result);
05845 } else if (result == -1) {
05846 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
05847 snprintf(buf, len, "0");
05848 } else if (result == -2) {
05849 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
05850 snprintf(buf, len, "0");
05851 }
05852
05853 return 0;
05854 }
05855
05856
05857 static struct ast_custom_function meetme_info_acf = {
05858 .name = "MEETME_INFO",
05859 .synopsis = "Query a given conference of various properties.",
05860 .syntax = "MEETME_INFO(<keyword>,<confno>)",
05861 .read = acf_meetme_info,
05862 .desc =
05863 "Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
05864 " Options:\n"
05865 " lock - boolean of whether the corresponding conference is locked\n"
05866 " parties - number of parties in a given conference\n"
05867 " activity - duration of conference in seconds\n"
05868 " dynamic - boolean of whether the corresponding coference is dynamic\n",
05869 };
05870
05871
05872 static int load_config(int reload)
05873 {
05874 load_config_meetme();
05875
05876 if (reload) {
05877 sla_queue_event(SLA_EVENT_RELOAD);
05878 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05879 "and will be completed when the system is idle.\n");
05880 return 0;
05881 }
05882
05883 return sla_load_config(0);
05884 }
05885
05886 static int unload_module(void)
05887 {
05888 int res = 0;
05889
05890 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05891 res = ast_manager_unregister("MeetmeMute");
05892 res |= ast_manager_unregister("MeetmeUnmute");
05893 res |= ast_manager_unregister("MeetmeList");
05894 res |= ast_unregister_application(app4);
05895 res |= ast_unregister_application(app3);
05896 res |= ast_unregister_application(app2);
05897 res |= ast_unregister_application(app);
05898 res |= ast_unregister_application(slastation_app);
05899 res |= ast_unregister_application(slatrunk_app);
05900
05901 ast_devstate_prov_del("Meetme");
05902 ast_devstate_prov_del("SLA");
05903
05904 sla_destroy();
05905
05906 res |= ast_custom_function_unregister(&meetme_info_acf);
05907 ast_unload_realtime("meetme");
05908
05909 return res;
05910 }
05911
05912 static int load_module(void)
05913 {
05914 int res = 0;
05915
05916 res |= load_config(0);
05917
05918 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05919 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
05920 action_meetmemute, "Mute a Meetme user");
05921 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
05922 action_meetmeunmute, "Unmute a Meetme user");
05923 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING,
05924 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05925 res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05926 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05927 res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05928 res |= ast_register_application(app, conf_exec, synopsis, descrip);
05929 res |= ast_register_application(slastation_app, sla_station_exec,
05930 slastation_synopsis, slastation_desc);
05931 res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05932 slatrunk_synopsis, slatrunk_desc);
05933
05934 res |= ast_devstate_prov_add("Meetme", meetmestate);
05935 res |= ast_devstate_prov_add("SLA", sla_state);
05936
05937 res |= ast_custom_function_register(&meetme_info_acf);
05938 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
05939
05940 return res;
05941 }
05942
05943 static int reload(void)
05944 {
05945 ast_unload_realtime("meetme");
05946 return load_config(1);
05947 }
05948
05949 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
05950 .load = load_module,
05951 .unload = unload_module,
05952 .reload = reload,
05953 );
05954