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