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