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