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