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