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