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: 238185 $")
00039
00040 #include <dahdi/user.h>
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/config.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/dsp.h"
00050 #include "asterisk/musiconhold.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/translate.h"
00056 #include "asterisk/ulaw.h"
00057 #include "asterisk/astobj2.h"
00058 #include "asterisk/devicestate.h"
00059 #include "asterisk/dial.h"
00060 #include "asterisk/causes.h"
00061 #include "asterisk/paths.h"
00062
00063 #include "enter.h"
00064 #include "leave.h"
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 #define CONFIG_FILE_NAME "meetme.conf"
00426 #define SLA_CONFIG_FILE "sla.conf"
00427
00428
00429 #define DEFAULT_AUDIO_BUFFERS 32
00430
00431
00432 #define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
00433
00434 enum {
00435 ADMINFLAG_MUTED = (1 << 1),
00436 ADMINFLAG_SELFMUTED = (1 << 2),
00437 ADMINFLAG_KICKME = (1 << 3),
00438
00439 ADMINFLAG_T_REQUEST = (1 << 4),
00440 };
00441
00442 #define MEETME_DELAYDETECTTALK 300
00443 #define MEETME_DELAYDETECTENDTALK 1000
00444
00445 #define AST_FRAME_BITS 32
00446
00447 enum volume_action {
00448 VOL_UP,
00449 VOL_DOWN
00450 };
00451
00452 enum entrance_sound {
00453 ENTER,
00454 LEAVE
00455 };
00456
00457 enum recording_state {
00458 MEETME_RECORD_OFF,
00459 MEETME_RECORD_STARTED,
00460 MEETME_RECORD_ACTIVE,
00461 MEETME_RECORD_TERMINATE
00462 };
00463
00464 #define CONF_SIZE 320
00465
00466 enum {
00467
00468 CONFFLAG_ADMIN = (1 << 0),
00469
00470 CONFFLAG_MONITOR = (1 << 1),
00471
00472 CONFFLAG_KEYEXIT = (1 << 2),
00473
00474 CONFFLAG_STARMENU = (1 << 3),
00475
00476 CONFFLAG_TALKER = (1 << 4),
00477
00478 CONFFLAG_QUIET = (1 << 5),
00479
00480
00481 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00482
00483 CONFFLAG_AGI = (1 << 7),
00484
00485 CONFFLAG_MOH = (1 << 8),
00486
00487 CONFFLAG_MARKEDEXIT = (1 << 9),
00488
00489 CONFFLAG_WAITMARKED = (1 << 10),
00490
00491 CONFFLAG_EXIT_CONTEXT = (1 << 11),
00492
00493 CONFFLAG_MARKEDUSER = (1 << 12),
00494
00495 CONFFLAG_INTROUSER = (1 << 13),
00496
00497 CONFFLAG_RECORDCONF = (1<< 14),
00498
00499 CONFFLAG_MONITORTALKER = (1 << 15),
00500 CONFFLAG_DYNAMIC = (1 << 16),
00501 CONFFLAG_DYNAMICPIN = (1 << 17),
00502 CONFFLAG_EMPTY = (1 << 18),
00503 CONFFLAG_EMPTYNOPIN = (1 << 19),
00504 CONFFLAG_ALWAYSPROMPT = (1 << 20),
00505
00506 CONFFLAG_OPTIMIZETALKER = (1 << 21),
00507
00508
00509 CONFFLAG_NOONLYPERSON = (1 << 22),
00510
00511
00512 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00513
00514 CONFFLAG_STARTMUTED = (1 << 24),
00515
00516 CONFFLAG_PASS_DTMF = (1 << 25),
00517 CONFFLAG_SLA_STATION = (1 << 26),
00518 CONFFLAG_SLA_TRUNK = (1 << 27),
00519
00520 CONFFLAG_KICK_CONTINUE = (1 << 28),
00521 CONFFLAG_DURATION_STOP = (1 << 29),
00522 CONFFLAG_DURATION_LIMIT = (1 << 30),
00523
00524 CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00525 };
00526
00527 enum {
00528 OPT_ARG_WAITMARKED = 0,
00529 OPT_ARG_EXITKEYS = 1,
00530 OPT_ARG_DURATION_STOP = 2,
00531 OPT_ARG_DURATION_LIMIT = 3,
00532 OPT_ARG_MOH_CLASS = 4,
00533 OPT_ARG_ARRAY_SIZE = 5,
00534 };
00535
00536 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
00537 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
00538 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
00539 AST_APP_OPTION('b', CONFFLAG_AGI ),
00540 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
00541 AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
00542 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
00543 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
00544 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
00545 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
00546 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
00547 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
00548 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
00549 AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ),
00550 AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
00551 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
00552 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
00553 AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ),
00554 AST_APP_OPTION('q', CONFFLAG_QUIET ),
00555 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
00556 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
00557 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
00558 AST_APP_OPTION('l', CONFFLAG_MONITOR ),
00559 AST_APP_OPTION('t', CONFFLAG_TALKER ),
00560 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
00561 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
00562 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
00563 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
00564 AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP),
00565 AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
00566 END_OPTIONS );
00567
00568 static const char *app = "MeetMe";
00569 static const char *app2 = "MeetMeCount";
00570 static const char *app3 = "MeetMeAdmin";
00571 static const char *app4 = "MeetMeChannelAdmin";
00572 static const char *slastation_app = "SLAStation";
00573 static const char *slatrunk_app = "SLATrunk";
00574
00575
00576 static int rt_schedule;
00577 static int fuzzystart;
00578 static int earlyalert;
00579 static int endalert;
00580 static int extendby;
00581
00582
00583 static int rt_log_members;
00584
00585 #define MAX_CONFNUM 80
00586 #define MAX_PIN 80
00587 #define OPTIONS_LEN 100
00588
00589
00590 #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
00591
00592 enum announcetypes {
00593 CONF_HASJOIN,
00594 CONF_HASLEFT
00595 };
00596
00597 struct announce_listitem {
00598 AST_LIST_ENTRY(announce_listitem) entry;
00599 char namerecloc[PATH_MAX];
00600 char language[MAX_LANGUAGE];
00601 struct ast_channel *confchan;
00602 int confusers;
00603 enum announcetypes announcetype;
00604 };
00605
00606
00607 struct ast_conference {
00608 ast_mutex_t playlock;
00609 ast_mutex_t listenlock;
00610 char confno[MAX_CONFNUM];
00611 struct ast_channel *chan;
00612 struct ast_channel *lchan;
00613 int fd;
00614 int dahdiconf;
00615 int users;
00616 int markedusers;
00617 int maxusers;
00618 int endalert;
00619 time_t start;
00620 int refcount;
00621 enum recording_state recording:2;
00622 unsigned int isdynamic:1;
00623 unsigned int locked:1;
00624 pthread_t recordthread;
00625 ast_mutex_t recordthreadlock;
00626 pthread_attr_t attr;
00627 char *recordingfilename;
00628 char *recordingformat;
00629 char pin[MAX_PIN];
00630 char pinadmin[MAX_PIN];
00631 char uniqueid[32];
00632 long endtime;
00633 const char *useropts;
00634 const char *adminopts;
00635 const char *bookid;
00636 struct ast_frame *transframe[32];
00637 struct ast_frame *origframe;
00638 struct ast_trans_pvt *transpath[32];
00639 AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
00640 AST_LIST_ENTRY(ast_conference) list;
00641
00642 pthread_t announcethread;
00643 ast_mutex_t announcethreadlock;
00644 unsigned int announcethread_stop:1;
00645 ast_cond_t announcelist_addition;
00646 AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist;
00647 ast_mutex_t announcelistlock;
00648 };
00649
00650 static AST_LIST_HEAD_STATIC(confs, ast_conference);
00651
00652 static unsigned int conf_map[1024] = {0, };
00653
00654 struct volume {
00655 int desired;
00656 int actual;
00657 };
00658
00659
00660 struct ast_conf_user {
00661 int user_no;
00662 int userflags;
00663 int adminflags;
00664 struct ast_channel *chan;
00665 int talking;
00666 int dahdichannel;
00667 char usrvalue[50];
00668 char namerecloc[PATH_MAX];
00669 time_t jointime;
00670 time_t kicktime;
00671 struct timeval start_time;
00672 long timelimit;
00673 long play_warning;
00674 long warning_freq;
00675 const char *warning_sound;
00676 const char *end_sound;
00677 struct volume talk;
00678 struct volume listen;
00679 AST_LIST_ENTRY(ast_conf_user) list;
00680 };
00681
00682 enum sla_which_trunk_refs {
00683 ALL_TRUNK_REFS,
00684 INACTIVE_TRUNK_REFS,
00685 };
00686
00687 enum sla_trunk_state {
00688 SLA_TRUNK_STATE_IDLE,
00689 SLA_TRUNK_STATE_RINGING,
00690 SLA_TRUNK_STATE_UP,
00691 SLA_TRUNK_STATE_ONHOLD,
00692 SLA_TRUNK_STATE_ONHOLD_BYME,
00693 };
00694
00695 enum sla_hold_access {
00696
00697
00698 SLA_HOLD_OPEN,
00699
00700
00701 SLA_HOLD_PRIVATE,
00702 };
00703
00704 struct sla_trunk_ref;
00705
00706 struct sla_station {
00707 AST_RWLIST_ENTRY(sla_station) entry;
00708 AST_DECLARE_STRING_FIELDS(
00709 AST_STRING_FIELD(name);
00710 AST_STRING_FIELD(device);
00711 AST_STRING_FIELD(autocontext);
00712 );
00713 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
00714 struct ast_dial *dial;
00715
00716
00717
00718 unsigned int ring_timeout;
00719
00720
00721
00722 unsigned int ring_delay;
00723
00724
00725 unsigned int hold_access:1;
00726
00727 unsigned int ref_count;
00728 };
00729
00730 struct sla_station_ref {
00731 AST_LIST_ENTRY(sla_station_ref) entry;
00732 struct sla_station *station;
00733 };
00734
00735 struct sla_trunk {
00736 AST_RWLIST_ENTRY(sla_trunk) entry;
00737 AST_DECLARE_STRING_FIELDS(
00738 AST_STRING_FIELD(name);
00739 AST_STRING_FIELD(device);
00740 AST_STRING_FIELD(autocontext);
00741 );
00742 AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
00743
00744 unsigned int num_stations;
00745
00746 unsigned int active_stations;
00747
00748 unsigned int hold_stations;
00749 struct ast_channel *chan;
00750 unsigned int ring_timeout;
00751
00752
00753 unsigned int barge_disabled:1;
00754
00755
00756 unsigned int hold_access:1;
00757
00758
00759 unsigned int on_hold:1;
00760
00761 unsigned int ref_count;
00762 };
00763
00764 struct sla_trunk_ref {
00765 AST_LIST_ENTRY(sla_trunk_ref) entry;
00766 struct sla_trunk *trunk;
00767 enum sla_trunk_state state;
00768 struct ast_channel *chan;
00769
00770
00771
00772 unsigned int ring_timeout;
00773
00774
00775
00776 unsigned int ring_delay;
00777 };
00778
00779 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
00780 static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
00781
00782 static const char sla_registrar[] = "SLA";
00783
00784
00785 enum sla_event_type {
00786
00787 SLA_EVENT_HOLD,
00788
00789 SLA_EVENT_DIAL_STATE,
00790
00791 SLA_EVENT_RINGING_TRUNK,
00792
00793 SLA_EVENT_RELOAD,
00794
00795 SLA_EVENT_CHECK_RELOAD,
00796 };
00797
00798 struct sla_event {
00799 enum sla_event_type type;
00800 struct sla_station *station;
00801 struct sla_trunk_ref *trunk_ref;
00802 AST_LIST_ENTRY(sla_event) entry;
00803 };
00804
00805
00806
00807 struct sla_failed_station {
00808 struct sla_station *station;
00809 struct timeval last_try;
00810 AST_LIST_ENTRY(sla_failed_station) entry;
00811 };
00812
00813
00814 struct sla_ringing_trunk {
00815 struct sla_trunk *trunk;
00816
00817 struct timeval ring_begin;
00818 AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
00819 AST_LIST_ENTRY(sla_ringing_trunk) entry;
00820 };
00821
00822 enum sla_station_hangup {
00823 SLA_STATION_HANGUP_NORMAL,
00824 SLA_STATION_HANGUP_TIMEOUT,
00825 };
00826
00827
00828 struct sla_ringing_station {
00829 struct sla_station *station;
00830
00831 struct timeval ring_begin;
00832 AST_LIST_ENTRY(sla_ringing_station) entry;
00833 };
00834
00835
00836
00837
00838 static struct {
00839
00840 pthread_t thread;
00841 ast_cond_t cond;
00842 ast_mutex_t lock;
00843 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
00844 AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
00845 AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
00846 AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
00847 unsigned int stop:1;
00848
00849
00850 unsigned int attempt_callerid:1;
00851
00852 unsigned int reload:1;
00853 } sla = {
00854 .thread = AST_PTHREADT_NULL,
00855 };
00856
00857
00858
00859 static int audio_buffers;
00860
00861
00862
00863
00864
00865
00866
00867 static char const gain_map[] = {
00868 -15,
00869 -13,
00870 -10,
00871 -6,
00872 0,
00873 0,
00874 0,
00875 6,
00876 10,
00877 13,
00878 15,
00879 };
00880
00881
00882 static int admin_exec(struct ast_channel *chan, void *data);
00883 static void *recordthread(void *args);
00884
00885 static char *istalking(int x)
00886 {
00887 if (x > 0)
00888 return "(talking)";
00889 else if (x < 0)
00890 return "(unmonitored)";
00891 else
00892 return "(not talking)";
00893 }
00894
00895 static int careful_write(int fd, unsigned char *data, int len, int block)
00896 {
00897 int res;
00898 int x;
00899
00900 while (len) {
00901 if (block) {
00902 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00903 res = ioctl(fd, DAHDI_IOMUX, &x);
00904 } else
00905 res = 0;
00906 if (res >= 0)
00907 res = write(fd, data, len);
00908 if (res < 1) {
00909 if (errno != EAGAIN) {
00910 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00911 return -1;
00912 } else
00913 return 0;
00914 }
00915 len -= res;
00916 data += res;
00917 }
00918
00919 return 0;
00920 }
00921
00922 static int set_talk_volume(struct ast_conf_user *user, int volume)
00923 {
00924 char gain_adjust;
00925
00926
00927
00928
00929 gain_adjust = gain_map[volume + 5];
00930
00931 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00932 }
00933
00934 static int set_listen_volume(struct ast_conf_user *user, int volume)
00935 {
00936 char gain_adjust;
00937
00938
00939
00940
00941 gain_adjust = gain_map[volume + 5];
00942
00943 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00944 }
00945
00946 static void tweak_volume(struct volume *vol, enum volume_action action)
00947 {
00948 switch (action) {
00949 case VOL_UP:
00950 switch (vol->desired) {
00951 case 5:
00952 break;
00953 case 0:
00954 vol->desired = 2;
00955 break;
00956 case -2:
00957 vol->desired = 0;
00958 break;
00959 default:
00960 vol->desired++;
00961 break;
00962 }
00963 break;
00964 case VOL_DOWN:
00965 switch (vol->desired) {
00966 case -5:
00967 break;
00968 case 2:
00969 vol->desired = 0;
00970 break;
00971 case 0:
00972 vol->desired = -2;
00973 break;
00974 default:
00975 vol->desired--;
00976 break;
00977 }
00978 }
00979 }
00980
00981 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
00982 {
00983 tweak_volume(&user->talk, action);
00984
00985
00986
00987 if (!set_talk_volume(user, user->talk.desired))
00988 user->talk.actual = 0;
00989 else
00990 user->talk.actual = user->talk.desired;
00991 }
00992
00993 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
00994 {
00995 tweak_volume(&user->listen, action);
00996
00997
00998
00999 if (!set_listen_volume(user, user->listen.desired))
01000 user->listen.actual = 0;
01001 else
01002 user->listen.actual = user->listen.desired;
01003 }
01004
01005 static void reset_volumes(struct ast_conf_user *user)
01006 {
01007 signed char zero_volume = 0;
01008
01009 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01010 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
01011 }
01012
01013 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
01014 {
01015 unsigned char *data;
01016 int len;
01017 int res = -1;
01018
01019 if (!ast_check_hangup(chan))
01020 res = ast_autoservice_start(chan);
01021
01022 AST_LIST_LOCK(&confs);
01023
01024 switch(sound) {
01025 case ENTER:
01026 data = enter;
01027 len = sizeof(enter);
01028 break;
01029 case LEAVE:
01030 data = leave;
01031 len = sizeof(leave);
01032 break;
01033 default:
01034 data = NULL;
01035 len = 0;
01036 }
01037 if (data) {
01038 careful_write(conf->fd, data, len, 1);
01039 }
01040
01041 AST_LIST_UNLOCK(&confs);
01042
01043 if (!res)
01044 ast_autoservice_stop(chan);
01045 }
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
01062 {
01063 struct ast_conference *cnf;
01064 struct dahdi_confinfo dahdic = { 0, };
01065 int confno_int = 0;
01066
01067 AST_LIST_LOCK(&confs);
01068
01069 AST_LIST_TRAVERSE(&confs, cnf, list) {
01070 if (!strcmp(confno, cnf->confno))
01071 break;
01072 }
01073
01074 if (cnf || (!make && !dynamic))
01075 goto cnfout;
01076
01077
01078 if (!(cnf = ast_calloc(1, sizeof(*cnf))))
01079 goto cnfout;
01080
01081 ast_mutex_init(&cnf->playlock);
01082 ast_mutex_init(&cnf->listenlock);
01083 cnf->recordthread = AST_PTHREADT_NULL;
01084 ast_mutex_init(&cnf->recordthreadlock);
01085 cnf->announcethread = AST_PTHREADT_NULL;
01086 ast_mutex_init(&cnf->announcethreadlock);
01087 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
01088 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
01089 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
01090 ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
01091
01092
01093 dahdic.confno = -1;
01094 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01095 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
01096 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
01097 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
01098 if (cnf->fd >= 0)
01099 close(cnf->fd);
01100 ast_free(cnf);
01101 cnf = NULL;
01102 goto cnfout;
01103 }
01104
01105 cnf->dahdiconf = dahdic.confno;
01106
01107
01108 cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
01109 if (cnf->chan) {
01110 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
01111 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
01112 dahdic.chan = 0;
01113 dahdic.confno = cnf->dahdiconf;
01114 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01115 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
01116 ast_log(LOG_WARNING, "Error setting conference\n");
01117 if (cnf->chan)
01118 ast_hangup(cnf->chan);
01119 else
01120 close(cnf->fd);
01121
01122 ast_free(cnf);
01123 cnf = NULL;
01124 goto cnfout;
01125 }
01126 }
01127
01128
01129 cnf->start = time(NULL);
01130 cnf->maxusers = 0x7fffffff;
01131 cnf->isdynamic = dynamic ? 1 : 0;
01132 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
01133 AST_LIST_INSERT_HEAD(&confs, cnf, list);
01134
01135
01136 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01137 conf_map[confno_int] = 1;
01138
01139 cnfout:
01140 if (cnf)
01141 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
01142
01143 AST_LIST_UNLOCK(&confs);
01144
01145 return cnf;
01146 }
01147
01148 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
01149 {
01150 static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
01151
01152 int len = strlen(word);
01153 int which = 0;
01154 struct ast_conference *cnf = NULL;
01155 struct ast_conf_user *usr = NULL;
01156 char *confno = NULL;
01157 char usrno[50] = "";
01158 char *myline, *ret = NULL;
01159
01160 if (pos == 1) {
01161 return ast_cli_complete(word, cmds, state);
01162 } else if (pos == 2) {
01163 AST_LIST_LOCK(&confs);
01164 AST_LIST_TRAVERSE(&confs, cnf, list) {
01165 if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
01166 ret = cnf->confno;
01167 break;
01168 }
01169 }
01170 ret = ast_strdup(ret);
01171 AST_LIST_UNLOCK(&confs);
01172 return ret;
01173 } else if (pos == 3) {
01174
01175 if (strstr(line, "mute") || strstr(line, "kick")) {
01176 if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
01177 return ast_strdup("all");
01178 which++;
01179 AST_LIST_LOCK(&confs);
01180
01181
01182 myline = ast_strdupa(line);
01183 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
01184 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
01185 ;
01186 }
01187
01188 AST_LIST_TRAVERSE(&confs, cnf, list) {
01189 if (!strcmp(confno, cnf->confno))
01190 break;
01191 }
01192
01193 if (cnf) {
01194
01195 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
01196 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
01197 if (!strncasecmp(word, usrno, len) && ++which > state)
01198 break;
01199 }
01200 }
01201 AST_LIST_UNLOCK(&confs);
01202 return usr ? ast_strdup(usrno) : NULL;
01203 }
01204 }
01205
01206 return NULL;
01207 }
01208
01209 static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01210 {
01211
01212 struct ast_conf_user *user;
01213 struct ast_conference *cnf;
01214 int hr, min, sec;
01215 int i = 0, total = 0;
01216 time_t now;
01217 struct ast_str *cmdline = NULL;
01218 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
01219 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
01220
01221 switch (cmd) {
01222 case CLI_INIT:
01223 e->command = "meetme list [concise]";
01224 e->usage =
01225 "Usage: meetme list [concise] <confno> \n"
01226 " List all or a specific conference.\n";
01227 return NULL;
01228 case CLI_GENERATE:
01229 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01230 }
01231
01232
01233 for (i = 0; i < a->argc; i++) {
01234 if (strlen(a->argv[i]) > 100)
01235 ast_cli(a->fd, "Invalid Arguments.\n");
01236 }
01237
01238
01239 if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01240 return CLI_FAILURE;
01241 }
01242
01243 if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], "concise"))) {
01244
01245 int concise = (a->argc == 3 && !strcasecmp(a->argv[2], "concise"));
01246 now = time(NULL);
01247 AST_LIST_LOCK(&confs);
01248 if (AST_LIST_EMPTY(&confs)) {
01249 if (!concise) {
01250 ast_cli(a->fd, "No active MeetMe conferences.\n");
01251 }
01252 AST_LIST_UNLOCK(&confs);
01253 ast_free(cmdline);
01254 return CLI_SUCCESS;
01255 }
01256 if (!concise) {
01257 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01258 }
01259 AST_LIST_TRAVERSE(&confs, cnf, list) {
01260 if (cnf->markedusers == 0) {
01261 ast_str_set(&cmdline, 0, "N/A ");
01262 } else {
01263 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01264 }
01265 hr = (now - cnf->start) / 3600;
01266 min = ((now - cnf->start) % 3600) / 60;
01267 sec = (now - cnf->start) % 60;
01268 if (!concise) {
01269 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, ast_str_buffer(cmdline), hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01270 } else {
01271 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01272 cnf->confno,
01273 cnf->users,
01274 cnf->markedusers,
01275 hr, min, sec,
01276 cnf->isdynamic,
01277 cnf->locked);
01278 }
01279
01280 total += cnf->users;
01281 }
01282 AST_LIST_UNLOCK(&confs);
01283 if (!concise) {
01284 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01285 }
01286 ast_free(cmdline);
01287 return CLI_SUCCESS;
01288 } else if (strcmp(a->argv[1], "list") == 0) {
01289 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01290
01291 if (AST_LIST_EMPTY(&confs)) {
01292 if (!concise) {
01293 ast_cli(a->fd, "No active MeetMe conferences.\n");
01294 }
01295 ast_free(cmdline);
01296 return CLI_SUCCESS;
01297 }
01298
01299 AST_LIST_LOCK(&confs);
01300 AST_LIST_TRAVERSE(&confs, cnf, list) {
01301 if (strcmp(cnf->confno, a->argv[2]) == 0) {
01302 break;
01303 }
01304 }
01305 if (!cnf) {
01306 if (!concise)
01307 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01308 AST_LIST_UNLOCK(&confs);
01309 ast_free(cmdline);
01310 return CLI_SUCCESS;
01311 }
01312
01313 time(&now);
01314 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01315 hr = (now - user->jointime) / 3600;
01316 min = ((now - user->jointime) % 3600) / 60;
01317 sec = (now - user->jointime) % 60;
01318 if (!concise) {
01319 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01320 user->user_no,
01321 S_OR(user->chan->cid.cid_num, "<unknown>"),
01322 S_OR(user->chan->cid.cid_name, "<no name>"),
01323 user->chan->name,
01324 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01325 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01326 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01327 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01328 istalking(user->talking), hr, min, sec);
01329 } else {
01330 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01331 user->user_no,
01332 S_OR(user->chan->cid.cid_num, ""),
01333 S_OR(user->chan->cid.cid_name, ""),
01334 user->chan->name,
01335 user->userflags & CONFFLAG_ADMIN ? "1" : "",
01336 user->userflags & CONFFLAG_MONITOR ? "1" : "",
01337 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01338 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01339 user->talking, hr, min, sec);
01340 }
01341 }
01342 if (!concise) {
01343 ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01344 }
01345 AST_LIST_UNLOCK(&confs);
01346 ast_free(cmdline);
01347 return CLI_SUCCESS;
01348 }
01349 if (a->argc < 2) {
01350 ast_free(cmdline);
01351 return CLI_SHOWUSAGE;
01352 }
01353
01354 ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01355
01356 admin_exec(NULL, ast_str_buffer(cmdline));
01357 ast_free(cmdline);
01358
01359 return CLI_SUCCESS;
01360 }
01361
01362
01363 static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01364 {
01365
01366 struct ast_str *cmdline = NULL;
01367 int i = 0;
01368
01369 switch (cmd) {
01370 case CLI_INIT:
01371 e->command = "meetme {lock|unlock|mute|unmute|kick}";
01372 e->usage =
01373 "Usage: meetme (un)lock|(un)mute|kick <confno> <usernumber>\n"
01374 " Executes a command for the conference or on a conferee\n";
01375 return NULL;
01376 case CLI_GENERATE:
01377 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
01378 }
01379
01380 if (a->argc > 8)
01381 ast_cli(a->fd, "Invalid Arguments.\n");
01382
01383 for (i = 0; i < a->argc; i++) {
01384 if (strlen(a->argv[i]) > 100)
01385 ast_cli(a->fd, "Invalid Arguments.\n");
01386 }
01387
01388
01389 if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01390 return CLI_FAILURE;
01391 }
01392
01393 if (a->argc < 1) {
01394 ast_free(cmdline);
01395 return CLI_SHOWUSAGE;
01396 }
01397
01398 ast_str_set(&cmdline, 0, "%s", a->argv[2]);
01399 if (strstr(a->argv[1], "lock")) {
01400 if (strcmp(a->argv[1], "lock") == 0) {
01401
01402 ast_str_append(&cmdline, 0, ",L");
01403 } else {
01404
01405 ast_str_append(&cmdline, 0, ",l");
01406 }
01407 } else if (strstr(a->argv[1], "mute")) {
01408 if (a->argc < 4) {
01409 ast_free(cmdline);
01410 return CLI_SHOWUSAGE;
01411 }
01412 if (strcmp(a->argv[1], "mute") == 0) {
01413
01414 if (strcmp(a->argv[3], "all") == 0) {
01415 ast_str_append(&cmdline, 0, ",N");
01416 } else {
01417 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
01418 }
01419 } else {
01420
01421 if (strcmp(a->argv[3], "all") == 0) {
01422 ast_str_append(&cmdline, 0, ",n");
01423 } else {
01424 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01425 }
01426 }
01427 } else if (strcmp(a->argv[1], "kick") == 0) {
01428 if (a->argc < 4) {
01429 ast_free(cmdline);
01430 return CLI_SHOWUSAGE;
01431 }
01432 if (strcmp(a->argv[3], "all") == 0) {
01433
01434 ast_str_append(&cmdline, 0, ",K");
01435 } else {
01436
01437 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01438 }
01439 } else {
01440 ast_free(cmdline);
01441 return CLI_SHOWUSAGE;
01442 }
01443
01444 ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
01445
01446 admin_exec(NULL, ast_str_buffer(cmdline));
01447 ast_free(cmdline);
01448
01449 return CLI_SUCCESS;
01450 }
01451
01452 static const char *sla_hold_str(unsigned int hold_access)
01453 {
01454 const char *hold = "Unknown";
01455
01456 switch (hold_access) {
01457 case SLA_HOLD_OPEN:
01458 hold = "Open";
01459 break;
01460 case SLA_HOLD_PRIVATE:
01461 hold = "Private";
01462 default:
01463 break;
01464 }
01465
01466 return hold;
01467 }
01468
01469 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01470 {
01471 const struct sla_trunk *trunk;
01472
01473 switch (cmd) {
01474 case CLI_INIT:
01475 e->command = "sla show trunks";
01476 e->usage =
01477 "Usage: sla show trunks\n"
01478 " This will list all trunks defined in sla.conf\n";
01479 return NULL;
01480 case CLI_GENERATE:
01481 return NULL;
01482 }
01483
01484 ast_cli(a->fd, "\n"
01485 "=============================================================\n"
01486 "=== Configured SLA Trunks ===================================\n"
01487 "=============================================================\n"
01488 "===\n");
01489 AST_RWLIST_RDLOCK(&sla_trunks);
01490 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01491 struct sla_station_ref *station_ref;
01492 char ring_timeout[16] = "(none)";
01493 if (trunk->ring_timeout)
01494 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01495 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01496 "=== Trunk Name: %s\n"
01497 "=== ==> Device: %s\n"
01498 "=== ==> AutoContext: %s\n"
01499 "=== ==> RingTimeout: %s\n"
01500 "=== ==> BargeAllowed: %s\n"
01501 "=== ==> HoldAccess: %s\n"
01502 "=== ==> Stations ...\n",
01503 trunk->name, trunk->device,
01504 S_OR(trunk->autocontext, "(none)"),
01505 ring_timeout,
01506 trunk->barge_disabled ? "No" : "Yes",
01507 sla_hold_str(trunk->hold_access));
01508 AST_RWLIST_RDLOCK(&sla_stations);
01509 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01510 ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
01511 AST_RWLIST_UNLOCK(&sla_stations);
01512 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01513 }
01514 AST_RWLIST_UNLOCK(&sla_trunks);
01515 ast_cli(a->fd, "=============================================================\n\n");
01516
01517 return CLI_SUCCESS;
01518 }
01519
01520 static const char *trunkstate2str(enum sla_trunk_state state)
01521 {
01522 #define S(e) case e: return # e;
01523 switch (state) {
01524 S(SLA_TRUNK_STATE_IDLE)
01525 S(SLA_TRUNK_STATE_RINGING)
01526 S(SLA_TRUNK_STATE_UP)
01527 S(SLA_TRUNK_STATE_ONHOLD)
01528 S(SLA_TRUNK_STATE_ONHOLD_BYME)
01529 }
01530 return "Uknown State";
01531 #undef S
01532 }
01533
01534 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01535 {
01536 const struct sla_station *station;
01537
01538 switch (cmd) {
01539 case CLI_INIT:
01540 e->command = "sla show stations";
01541 e->usage =
01542 "Usage: sla show stations\n"
01543 " This will list all stations defined in sla.conf\n";
01544 return NULL;
01545 case CLI_GENERATE:
01546 return NULL;
01547 }
01548
01549 ast_cli(a->fd, "\n"
01550 "=============================================================\n"
01551 "=== Configured SLA Stations =================================\n"
01552 "=============================================================\n"
01553 "===\n");
01554 AST_RWLIST_RDLOCK(&sla_stations);
01555 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01556 struct sla_trunk_ref *trunk_ref;
01557 char ring_timeout[16] = "(none)";
01558 char ring_delay[16] = "(none)";
01559 if (station->ring_timeout) {
01560 snprintf(ring_timeout, sizeof(ring_timeout),
01561 "%u", station->ring_timeout);
01562 }
01563 if (station->ring_delay) {
01564 snprintf(ring_delay, sizeof(ring_delay),
01565 "%u", station->ring_delay);
01566 }
01567 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01568 "=== Station Name: %s\n"
01569 "=== ==> Device: %s\n"
01570 "=== ==> AutoContext: %s\n"
01571 "=== ==> RingTimeout: %s\n"
01572 "=== ==> RingDelay: %s\n"
01573 "=== ==> HoldAccess: %s\n"
01574 "=== ==> Trunks ...\n",
01575 station->name, station->device,
01576 S_OR(station->autocontext, "(none)"),
01577 ring_timeout, ring_delay,
01578 sla_hold_str(station->hold_access));
01579 AST_RWLIST_RDLOCK(&sla_trunks);
01580 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01581 if (trunk_ref->ring_timeout) {
01582 snprintf(ring_timeout, sizeof(ring_timeout),
01583 "%u", trunk_ref->ring_timeout);
01584 } else
01585 strcpy(ring_timeout, "(none)");
01586 if (trunk_ref->ring_delay) {
01587 snprintf(ring_delay, sizeof(ring_delay),
01588 "%u", trunk_ref->ring_delay);
01589 } else
01590 strcpy(ring_delay, "(none)");
01591 ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
01592 "=== ==> State: %s\n"
01593 "=== ==> RingTimeout: %s\n"
01594 "=== ==> RingDelay: %s\n",
01595 trunk_ref->trunk->name,
01596 trunkstate2str(trunk_ref->state),
01597 ring_timeout, ring_delay);
01598 }
01599 AST_RWLIST_UNLOCK(&sla_trunks);
01600 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01601 "===\n");
01602 }
01603 AST_RWLIST_UNLOCK(&sla_stations);
01604 ast_cli(a->fd, "============================================================\n"
01605 "\n");
01606
01607 return CLI_SUCCESS;
01608 }
01609
01610 static struct ast_cli_entry cli_meetme[] = {
01611 AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
01612 AST_CLI_DEFINE(meetme_show_cmd, "List all or one conference"),
01613 AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
01614 AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
01615 };
01616
01617 static void conf_flush(int fd, struct ast_channel *chan)
01618 {
01619 int x;
01620
01621
01622
01623
01624 if (chan) {
01625 struct ast_frame *f;
01626
01627
01628
01629
01630 while (ast_waitfor(chan, 1)) {
01631 f = ast_read(chan);
01632 if (f)
01633 ast_frfree(f);
01634 else
01635 break;
01636 }
01637 }
01638
01639
01640 x = DAHDI_FLUSH_ALL;
01641 if (ioctl(fd, DAHDI_FLUSH, &x))
01642 ast_log(LOG_WARNING, "Error flushing channel\n");
01643
01644 }
01645
01646
01647
01648 static int conf_free(struct ast_conference *conf)
01649 {
01650 int x;
01651 struct announce_listitem *item;
01652
01653 AST_LIST_REMOVE(&confs, conf, list);
01654 manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01655
01656 if (conf->recording == MEETME_RECORD_ACTIVE) {
01657 conf->recording = MEETME_RECORD_TERMINATE;
01658 AST_LIST_UNLOCK(&confs);
01659 while (1) {
01660 usleep(1);
01661 AST_LIST_LOCK(&confs);
01662 if (conf->recording == MEETME_RECORD_OFF)
01663 break;
01664 AST_LIST_UNLOCK(&confs);
01665 }
01666 }
01667
01668 for (x = 0; x < AST_FRAME_BITS; x++) {
01669 if (conf->transframe[x])
01670 ast_frfree(conf->transframe[x]);
01671 if (conf->transpath[x])
01672 ast_translator_free_path(conf->transpath[x]);
01673 }
01674 if (conf->announcethread != AST_PTHREADT_NULL) {
01675 ast_mutex_lock(&conf->announcelistlock);
01676 conf->announcethread_stop = 1;
01677 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01678 ast_cond_signal(&conf->announcelist_addition);
01679 ast_mutex_unlock(&conf->announcelistlock);
01680 pthread_join(conf->announcethread, NULL);
01681
01682 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01683 ast_filedelete(item->namerecloc, NULL);
01684 ao2_ref(item, -1);
01685 }
01686 ast_mutex_destroy(&conf->announcelistlock);
01687 }
01688 if (conf->origframe)
01689 ast_frfree(conf->origframe);
01690 if (conf->lchan)
01691 ast_hangup(conf->lchan);
01692 if (conf->chan)
01693 ast_hangup(conf->chan);
01694 if (conf->fd >= 0)
01695 close(conf->fd);
01696 if (conf->recordingfilename) {
01697 ast_free(conf->recordingfilename);
01698 }
01699 if (conf->recordingformat) {
01700 ast_free(conf->recordingformat);
01701 }
01702 ast_mutex_destroy(&conf->playlock);
01703 ast_mutex_destroy(&conf->listenlock);
01704 ast_mutex_destroy(&conf->recordthreadlock);
01705 ast_mutex_destroy(&conf->announcethreadlock);
01706 ast_free(conf);
01707
01708 return 0;
01709 }
01710
01711 static void conf_queue_dtmf(const struct ast_conference *conf,
01712 const struct ast_conf_user *sender, struct ast_frame *f)
01713 {
01714 struct ast_conf_user *user;
01715
01716 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01717 if (user == sender)
01718 continue;
01719 if (ast_write(user->chan, f) < 0)
01720 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01721 }
01722 }
01723
01724 static void sla_queue_event_full(enum sla_event_type type,
01725 struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
01726 {
01727 struct sla_event *event;
01728
01729 if (sla.thread == AST_PTHREADT_NULL) {
01730 return;
01731 }
01732
01733 if (!(event = ast_calloc(1, sizeof(*event))))
01734 return;
01735
01736 event->type = type;
01737 event->trunk_ref = trunk_ref;
01738 event->station = station;
01739
01740 if (!lock) {
01741 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01742 return;
01743 }
01744
01745 ast_mutex_lock(&sla.lock);
01746 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01747 ast_cond_signal(&sla.cond);
01748 ast_mutex_unlock(&sla.lock);
01749 }
01750
01751 static void sla_queue_event_nolock(enum sla_event_type type)
01752 {
01753 sla_queue_event_full(type, NULL, NULL, 0);
01754 }
01755
01756 static void sla_queue_event(enum sla_event_type type)
01757 {
01758 sla_queue_event_full(type, NULL, NULL, 1);
01759 }
01760
01761
01762 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
01763 struct ast_conference *conf)
01764 {
01765 struct sla_station *station;
01766 struct sla_trunk_ref *trunk_ref = NULL;
01767 char *trunk_name;
01768
01769 trunk_name = ast_strdupa(conf->confno);
01770 strsep(&trunk_name, "_");
01771 if (ast_strlen_zero(trunk_name)) {
01772 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01773 return;
01774 }
01775
01776 AST_RWLIST_RDLOCK(&sla_stations);
01777 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01778 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01779 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01780 break;
01781 }
01782 if (trunk_ref)
01783 break;
01784 }
01785 AST_RWLIST_UNLOCK(&sla_stations);
01786
01787 if (!trunk_ref) {
01788 ast_debug(1, "Trunk not found for event!\n");
01789 return;
01790 }
01791
01792 sla_queue_event_full(type, trunk_ref, station, 1);
01793 }
01794
01795
01796 static int dispose_conf(struct ast_conference *conf)
01797 {
01798 int res = 0;
01799 int confno_int = 0;
01800
01801 AST_LIST_LOCK(&confs);
01802 if (ast_atomic_dec_and_test(&conf->refcount)) {
01803
01804 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
01805 conf_map[confno_int] = 0;
01806 }
01807 conf_free(conf);
01808 res = 1;
01809 }
01810 AST_LIST_UNLOCK(&confs);
01811
01812 return res;
01813 }
01814
01815 static int rt_extend_conf(char *confno)
01816 {
01817 char currenttime[32];
01818 char endtime[32];
01819 struct timeval now;
01820 struct ast_tm tm;
01821 struct ast_variable *var, *orig_var;
01822 char bookid[51];
01823
01824 if (!extendby) {
01825 return 0;
01826 }
01827
01828 now = ast_tvnow();
01829
01830 ast_localtime(&now, &tm, NULL);
01831 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01832
01833 var = ast_load_realtime("meetme", "confno",
01834 confno, "startTime<= ", currenttime,
01835 "endtime>= ", currenttime, NULL);
01836
01837 orig_var = var;
01838
01839
01840 while (var) {
01841 if (!strcasecmp(var->name, "bookid")) {
01842 ast_copy_string(bookid, var->value, sizeof(bookid));
01843 }
01844 if (!strcasecmp(var->name, "endtime")) {
01845 ast_copy_string(endtime, var->value, sizeof(endtime));
01846 }
01847
01848 var = var->next;
01849 }
01850 ast_variables_destroy(orig_var);
01851
01852 ast_strptime(endtime, DATE_FORMAT, &tm);
01853 now = ast_mktime(&tm, NULL);
01854
01855 now.tv_sec += extendby;
01856
01857 ast_localtime(&now, &tm, NULL);
01858 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
01859 strcat(currenttime, "0");
01860
01861 var = ast_load_realtime("meetme", "confno",
01862 confno, "startTime<= ", currenttime,
01863 "endtime>= ", currenttime, NULL);
01864
01865
01866 if (!var) {
01867 ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
01868 ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
01869 return 0;
01870
01871 }
01872
01873 ast_variables_destroy(var);
01874 return -1;
01875 }
01876
01877 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
01878 {
01879 char *original_moh;
01880
01881 ast_channel_lock(chan);
01882 original_moh = ast_strdupa(chan->musicclass);
01883 ast_string_field_set(chan, musicclass, musicclass);
01884 ast_channel_unlock(chan);
01885
01886 ast_moh_start(chan, original_moh, NULL);
01887
01888 ast_channel_lock(chan);
01889 ast_string_field_set(chan, musicclass, original_moh);
01890 ast_channel_unlock(chan);
01891 }
01892
01893 static const char *get_announce_filename(enum announcetypes type)
01894 {
01895 switch (type) {
01896 case CONF_HASLEFT:
01897 return "conf-hasleft";
01898 break;
01899 case CONF_HASJOIN:
01900 return "conf-hasjoin";
01901 break;
01902 default:
01903 return "";
01904 }
01905 }
01906
01907 static void *announce_thread(void *data)
01908 {
01909 struct announce_listitem *current;
01910 struct ast_conference *conf = data;
01911 int res;
01912 char filename[PATH_MAX] = "";
01913 AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01914 AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01915
01916 while (!conf->announcethread_stop) {
01917 ast_mutex_lock(&conf->announcelistlock);
01918 if (conf->announcethread_stop) {
01919 ast_mutex_unlock(&conf->announcelistlock);
01920 break;
01921 }
01922 if (AST_LIST_EMPTY(&conf->announcelist))
01923 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01924
01925 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01926 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01927
01928 ast_mutex_unlock(&conf->announcelistlock);
01929 if (conf->announcethread_stop) {
01930 break;
01931 }
01932
01933 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01934 ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01935 if (!ast_fileexists(current->namerecloc, NULL, NULL))
01936 continue;
01937 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01938 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01939 res = ast_waitstream(current->confchan, "");
01940 if (!res) {
01941 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01942 if (!ast_streamfile(current->confchan, filename, current->language))
01943 ast_waitstream(current->confchan, "");
01944 }
01945 }
01946 if (current->announcetype == CONF_HASLEFT) {
01947 ast_filedelete(current->namerecloc, NULL);
01948 }
01949 }
01950 }
01951
01952
01953 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01954 ast_filedelete(current->namerecloc, NULL);
01955 ao2_ref(current, -1);
01956 }
01957 return NULL;
01958 }
01959
01960 static int can_write(struct ast_channel *chan, int confflags)
01961 {
01962 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01963 return 1;
01964 }
01965
01966 return (chan->_state == AST_STATE_UP);
01967 }
01968
01969 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
01970 {
01971 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01972 "Channel: %s\r\n"
01973 "Uniqueid: %s\r\n"
01974 "Meetme: %s\r\n"
01975 "Usernum: %d\r\n"
01976 "Status: %s\r\n",
01977 chan->name, chan->uniqueid, conf->confno, user->user_no, talking ? "on" : "off");
01978 }
01979
01980 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
01981 {
01982 int last_talking = user->talking;
01983 if (last_talking == talking)
01984 return;
01985
01986 user->talking = talking;
01987
01988 if (monitor) {
01989
01990 int was_talking = (last_talking > 0);
01991 int now_talking = (talking > 0);
01992 if (was_talking != now_talking) {
01993 send_talking_event(chan, conf, user, now_talking);
01994 }
01995 }
01996 }
01997
01998 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
01999 {
02000 struct ast_conf_user *user = NULL;
02001 struct ast_conf_user *usr = NULL;
02002 int fd;
02003 struct dahdi_confinfo dahdic, dahdic_empty;
02004 struct ast_frame *f;
02005 struct ast_channel *c;
02006 struct ast_frame fr;
02007 int outfd;
02008 int ms;
02009 int nfds;
02010 int res;
02011 int retrydahdi;
02012 int origfd;
02013 int musiconhold = 0, mohtempstopped = 0;
02014 int firstpass = 0;
02015 int lastmarked = 0;
02016 int currentmarked = 0;
02017 int ret = -1;
02018 int x;
02019 int menu_active = 0;
02020 int talkreq_manager = 0;
02021 int using_pseudo = 0;
02022 int duration = 20;
02023 int hr, min, sec;
02024 int sent_event = 0;
02025 int checked = 0;
02026 int announcement_played = 0;
02027 struct timeval now;
02028 struct ast_dsp *dsp = NULL;
02029 struct ast_app *agi_app;
02030 char *agifile;
02031 const char *agifiledefault = "conf-background.agi", *tmpvar;
02032 char meetmesecs[30] = "";
02033 char exitcontext[AST_MAX_CONTEXT] = "";
02034 char recordingtmp[AST_MAX_EXTENSION] = "";
02035 char members[10] = "";
02036 int dtmf, opt_waitmarked_timeout = 0;
02037 time_t timeout = 0;
02038 struct dahdi_bufferinfo bi;
02039 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
02040 char *buf = __buf + AST_FRIENDLY_OFFSET;
02041 char *exitkeys = NULL;
02042 unsigned int calldurationlimit = 0;
02043 long timelimit = 0;
02044 long play_warning = 0;
02045 long warning_freq = 0;
02046 const char *warning_sound = NULL;
02047 const char *end_sound = NULL;
02048 char *parse;
02049 long time_left_ms = 0;
02050 struct timeval nexteventts = { 0, };
02051 int to;
02052 int setusercount = 0;
02053 int confsilence = 0, totalsilence = 0;
02054
02055 if (!(user = ast_calloc(1, sizeof(*user))))
02056 return ret;
02057
02058
02059 if ((confflags & CONFFLAG_WAITMARKED) &&
02060 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
02061 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
02062 (opt_waitmarked_timeout > 0)) {
02063 timeout = time(NULL) + opt_waitmarked_timeout;
02064 }
02065
02066 if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
02067 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
02068 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
02069 }
02070
02071 if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
02072 char *limit_str, *warning_str, *warnfreq_str;
02073 const char *var;
02074
02075 parse = optargs[OPT_ARG_DURATION_LIMIT];
02076 limit_str = strsep(&parse, ":");
02077 warning_str = strsep(&parse, ":");
02078 warnfreq_str = parse;
02079
02080 timelimit = atol(limit_str);
02081 if (warning_str)
02082 play_warning = atol(warning_str);
02083 if (warnfreq_str)
02084 warning_freq = atol(warnfreq_str);
02085
02086 if (!timelimit) {
02087 timelimit = play_warning = warning_freq = 0;
02088 warning_sound = NULL;
02089 } else if (play_warning > timelimit) {
02090 if (!warning_freq) {
02091 play_warning = 0;
02092 } else {
02093 while (play_warning > timelimit)
02094 play_warning -= warning_freq;
02095 if (play_warning < 1)
02096 play_warning = warning_freq = 0;
02097 }
02098 }
02099
02100 ast_channel_lock(chan);
02101 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
02102 var = ast_strdupa(var);
02103 }
02104 ast_channel_unlock(chan);
02105
02106 warning_sound = var ? var : "timeleft";
02107
02108 ast_channel_lock(chan);
02109 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
02110 var = ast_strdupa(var);
02111 }
02112 ast_channel_unlock(chan);
02113
02114 end_sound = var ? var : NULL;
02115
02116
02117 calldurationlimit = 0;
02118
02119 if (!play_warning && !end_sound && timelimit) {
02120 calldurationlimit = timelimit / 1000;
02121 timelimit = play_warning = warning_freq = 0;
02122 } else {
02123 ast_debug(2, "Limit Data for this call:\n");
02124 ast_debug(2, "- timelimit = %ld\n", timelimit);
02125 ast_debug(2, "- play_warning = %ld\n", play_warning);
02126 ast_debug(2, "- warning_freq = %ld\n", warning_freq);
02127 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
02128 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
02129 }
02130 }
02131
02132
02133 if ((confflags & CONFFLAG_KEYEXIT)) {
02134 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
02135 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
02136 else
02137 exitkeys = ast_strdupa("#");
02138 }
02139
02140 if (confflags & CONFFLAG_RECORDCONF) {
02141 if (!conf->recordingfilename) {
02142 const char *var;
02143 ast_channel_lock(chan);
02144 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
02145 conf->recordingfilename = ast_strdup(var);
02146 }
02147 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
02148 conf->recordingformat = ast_strdup(var);
02149 }
02150 ast_channel_unlock(chan);
02151 if (!conf->recordingfilename) {
02152 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
02153 conf->recordingfilename = ast_strdup(recordingtmp);
02154 }
02155 if (!conf->recordingformat) {
02156 conf->recordingformat = ast_strdup("wav");
02157 }
02158 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
02159 conf->confno, conf->recordingfilename, conf->recordingformat);
02160 }
02161 }
02162
02163 ast_mutex_lock(&conf->recordthreadlock);
02164 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
02165 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
02166 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
02167 dahdic.chan = 0;
02168 dahdic.confno = conf->dahdiconf;
02169 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
02170 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
02171 ast_log(LOG_WARNING, "Error starting listen channel\n");
02172 ast_hangup(conf->lchan);
02173 conf->lchan = NULL;
02174 } else {
02175 ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
02176 }
02177 }
02178 ast_mutex_unlock(&conf->recordthreadlock);
02179
02180 ast_mutex_lock(&conf->announcethreadlock);
02181 if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
02182 ast_mutex_init(&conf->announcelistlock);
02183 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
02184 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
02185 }
02186 ast_mutex_unlock(&conf->announcethreadlock);
02187
02188 time(&user->jointime);
02189
02190 user->timelimit = timelimit;
02191 user->play_warning = play_warning;
02192 user->warning_freq = warning_freq;
02193 user->warning_sound = warning_sound;
02194 user->end_sound = end_sound;
02195
02196 if (calldurationlimit > 0) {
02197 time(&user->kicktime);
02198 user->kicktime = user->kicktime + calldurationlimit;
02199 }
02200
02201 if (ast_tvzero(user->start_time))
02202 user->start_time = ast_tvnow();
02203 time_left_ms = user->timelimit;
02204
02205 if (user->timelimit) {
02206 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02207 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
02208 }
02209
02210 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
02211
02212 if (!ast_streamfile(chan, "conf-locked", chan->language))
02213 ast_waitstream(chan, "");
02214 goto outrun;
02215 }
02216
02217 ast_mutex_lock(&conf->playlock);
02218
02219 if (AST_LIST_EMPTY(&conf->userlist))
02220 user->user_no = 1;
02221 else
02222 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
02223
02224 if (rt_schedule && conf->maxusers)
02225 if (conf->users >= conf->maxusers) {
02226
02227 if (!ast_streamfile(chan, "conf-full", chan->language))
02228 ast_waitstream(chan, "");
02229 ast_mutex_unlock(&conf->playlock);
02230 user->user_no = 0;
02231 goto outrun;
02232 }
02233
02234 AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
02235
02236 user->chan = chan;
02237 user->userflags = confflags;
02238 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
02239 user->talking = -1;
02240
02241 ast_mutex_unlock(&conf->playlock);
02242
02243 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
02244 char destdir[PATH_MAX];
02245
02246 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
02247
02248 if (ast_mkdir(destdir, 0777) != 0) {
02249 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
02250 goto outrun;
02251 }
02252
02253 snprintf(user->namerecloc, sizeof(user->namerecloc),
02254 "%s/meetme-username-%s-%d", destdir,
02255 conf->confno, user->user_no);
02256 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
02257 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
02258 else
02259 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
02260 if (res == -1)
02261 goto outrun;
02262 }
02263
02264 ast_mutex_lock(&conf->playlock);
02265
02266 if (confflags & CONFFLAG_MARKEDUSER)
02267 conf->markedusers++;
02268 conf->users++;
02269 if (rt_log_members) {
02270
02271 snprintf(members, sizeof(members), "%d", conf->users);
02272 ast_realtime_require_field("meetme",
02273 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02274 "members", RQ_UINTEGER1, strlen(members),
02275 NULL);
02276 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02277 }
02278 setusercount = 1;
02279
02280
02281 if (conf->users == 1)
02282 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
02283
02284 ast_mutex_unlock(&conf->playlock);
02285
02286
02287 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
02288
02289 if (confflags & CONFFLAG_EXIT_CONTEXT) {
02290 ast_channel_lock(chan);
02291 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
02292 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
02293 } else if (!ast_strlen_zero(chan->macrocontext)) {
02294 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
02295 } else {
02296 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
02297 }
02298 ast_channel_unlock(chan);
02299 }
02300
02301 if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
02302 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
02303 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02304 ast_waitstream(chan, "");
02305 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
02306 if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
02307 ast_waitstream(chan, "");
02308 }
02309
02310 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
02311 int keepplaying = 1;
02312
02313 if (conf->users == 2) {
02314 if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
02315 res = ast_waitstream(chan, AST_DIGIT_ANY);
02316 ast_stopstream(chan);
02317 if (res > 0)
02318 keepplaying = 0;
02319 else if (res == -1)
02320 goto outrun;
02321 }
02322 } else {
02323 if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
02324 res = ast_waitstream(chan, AST_DIGIT_ANY);
02325 ast_stopstream(chan);
02326 if (res > 0)
02327 keepplaying = 0;
02328 else if (res == -1)
02329 goto outrun;
02330 }
02331 if (keepplaying) {
02332 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02333 if (res > 0)
02334 keepplaying = 0;
02335 else if (res == -1)
02336 goto outrun;
02337 }
02338 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
02339 res = ast_waitstream(chan, AST_DIGIT_ANY);
02340 ast_stopstream(chan);
02341 if (res > 0)
02342 keepplaying = 0;
02343 else if (res == -1)
02344 goto outrun;
02345 }
02346 }
02347 }
02348
02349 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
02350
02351 ast_indicate(chan, -1);
02352 }
02353
02354 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
02355 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
02356 goto outrun;
02357 }
02358
02359 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
02360 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
02361 goto outrun;
02362 }
02363
02364 retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
02365 user->dahdichannel = !retrydahdi;
02366
02367 dahdiretry:
02368 origfd = chan->fds[0];
02369 if (retrydahdi) {
02370
02371 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02372 if (fd < 0) {
02373 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02374 goto outrun;
02375 }
02376 using_pseudo = 1;
02377
02378 memset(&bi, 0, sizeof(bi));
02379 bi.bufsize = CONF_SIZE / 2;
02380 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02381 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02382 bi.numbufs = audio_buffers;
02383 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02384 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02385 close(fd);
02386 goto outrun;
02387 }
02388 x = 1;
02389 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02390 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02391 close(fd);
02392 goto outrun;
02393 }
02394 nfds = 1;
02395 } else {
02396
02397 fd = chan->fds[0];
02398 nfds = 0;
02399 }
02400 memset(&dahdic, 0, sizeof(dahdic));
02401 memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02402
02403 dahdic.chan = 0;
02404 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02405 ast_log(LOG_WARNING, "Error getting conference\n");
02406 close(fd);
02407 goto outrun;
02408 }
02409 if (dahdic.confmode) {
02410
02411 if (!retrydahdi) {
02412 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02413 retrydahdi = 1;
02414 goto dahdiretry;
02415 }
02416 }
02417 memset(&dahdic, 0, sizeof(dahdic));
02418
02419 dahdic.chan = 0;
02420 dahdic.confno = conf->dahdiconf;
02421
02422 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02423 struct announce_listitem *item;
02424 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02425 return -1;
02426 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02427 ast_copy_string(item->language, chan->language, sizeof(item->language));
02428 item->confchan = conf->chan;
02429 item->confusers = conf->users;
02430 item->announcetype = CONF_HASJOIN;
02431 ast_mutex_lock(&conf->announcelistlock);
02432 ao2_ref(item, +1);
02433 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02434 ast_cond_signal(&conf->announcelist_addition);
02435 ast_mutex_unlock(&conf->announcelistlock);
02436
02437 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02438 ;
02439 }
02440 ao2_ref(item, -1);
02441 }
02442
02443 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02444 dahdic.confmode = DAHDI_CONF_CONF;
02445 else if (confflags & CONFFLAG_MONITOR)
02446 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02447 else if (confflags & CONFFLAG_TALKER)
02448 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02449 else
02450 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02451
02452 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02453 ast_log(LOG_WARNING, "Error setting conference\n");
02454 close(fd);
02455 goto outrun;
02456 }
02457 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02458
02459 if (!sent_event) {
02460 manager_event(EVENT_FLAG_CALL, "MeetmeJoin",
02461 "Channel: %s\r\n"
02462 "Uniqueid: %s\r\n"
02463 "Meetme: %s\r\n"
02464 "Usernum: %d\r\n"
02465 "CallerIDnum: %s\r\n"
02466 "CallerIDname: %s\r\n",
02467 chan->name, chan->uniqueid, conf->confno,
02468 user->user_no,
02469 S_OR(user->chan->cid.cid_num, "<unknown>"),
02470 S_OR(user->chan->cid.cid_name, "<unknown>")
02471 );
02472 sent_event = 1;
02473 }
02474
02475 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02476 firstpass = 1;
02477 if (!(confflags & CONFFLAG_QUIET))
02478 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02479 conf_play(chan, conf, ENTER);
02480 }
02481
02482 conf_flush(fd, chan);
02483
02484 if (!(dsp = ast_dsp_new())) {
02485 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02486 res = -1;
02487 }
02488
02489 if (confflags & CONFFLAG_AGI) {
02490
02491
02492
02493 ast_channel_lock(chan);
02494 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02495 agifile = ast_strdupa(tmpvar);
02496 } else {
02497 agifile = ast_strdupa(agifiledefault);
02498 }
02499 ast_channel_unlock(chan);
02500
02501 if (user->dahdichannel) {
02502
02503 x = 1;
02504 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02505 }
02506
02507 agi_app = pbx_findapp("agi");
02508 if (agi_app) {
02509 ret = pbx_exec(chan, agi_app, agifile);
02510 } else {
02511 ast_log(LOG_WARNING, "Could not find application (agi)\n");
02512 ret = -2;
02513 }
02514 if (user->dahdichannel) {
02515
02516 x = 0;
02517 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02518 }
02519 } else {
02520 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02521
02522 x = 1;
02523 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02524 }
02525 for (;;) {
02526 int menu_was_active = 0;
02527
02528 outfd = -1;
02529 ms = -1;
02530 now = ast_tvnow();
02531
02532 if (rt_schedule && conf->endtime) {
02533 char currenttime[32];
02534 long localendtime = 0;
02535 int extended = 0;
02536 struct ast_tm tm;
02537 struct ast_variable *var, *origvar;
02538 struct timeval tmp;
02539
02540 if (now.tv_sec % 60 == 0) {
02541 if (!checked) {
02542 ast_localtime(&now, &tm, NULL);
02543 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02544 var = origvar = ast_load_realtime("meetme", "confno",
02545 conf->confno, "starttime <=", currenttime,
02546 "endtime >=", currenttime, NULL);
02547
02548 for ( ; var; var = var->next) {
02549 if (!strcasecmp(var->name, "endtime")) {
02550 struct ast_tm endtime_tm;
02551 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
02552 tmp = ast_mktime(&endtime_tm, NULL);
02553 localendtime = tmp.tv_sec;
02554 }
02555 }
02556 ast_variables_destroy(origvar);
02557
02558
02559
02560 if (localendtime > conf->endtime){
02561 conf->endtime = localendtime;
02562 extended = 1;
02563 }
02564
02565 if (conf->endtime && (now.tv_sec >= conf->endtime)) {
02566 ast_verbose("Quitting time...\n");
02567 goto outrun;
02568 }
02569
02570 if (!announcement_played && conf->endalert) {
02571 if (now.tv_sec + conf->endalert >= conf->endtime) {
02572 if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02573 ast_waitstream(chan, "");
02574 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02575 if (!ast_streamfile(chan, "minutes", chan->language))
02576 ast_waitstream(chan, "");
02577 announcement_played = 1;
02578 }
02579 }
02580
02581 if (extended) {
02582 announcement_played = 0;
02583 }
02584
02585 checked = 1;
02586 }
02587 } else {
02588 checked = 0;
02589 }
02590 }
02591
02592 if (user->kicktime && (user->kicktime <= now.tv_sec)) {
02593 break;
02594 }
02595
02596 to = -1;
02597 if (user->timelimit) {
02598 int minutes = 0, seconds = 0, remain = 0;
02599
02600 to = ast_tvdiff_ms(nexteventts, now);
02601 if (to < 0) {
02602 to = 0;
02603 }
02604 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02605 if (time_left_ms < to) {
02606 to = time_left_ms;
02607 }
02608
02609 if (time_left_ms <= 0) {
02610 if (user->end_sound) {
02611 res = ast_streamfile(chan, user->end_sound, chan->language);
02612 res = ast_waitstream(chan, "");
02613 }
02614 break;
02615 }
02616
02617 if (!to) {
02618 if (time_left_ms >= 5000) {
02619
02620 remain = (time_left_ms + 500) / 1000;
02621 if (remain / 60 >= 1) {
02622 minutes = remain / 60;
02623 seconds = remain % 60;
02624 } else {
02625 seconds = remain;
02626 }
02627
02628
02629 if (user->warning_sound && user->play_warning) {
02630 if (!strcmp(user->warning_sound, "timeleft")) {
02631
02632 res = ast_streamfile(chan, "vm-youhave", chan->language);
02633 res = ast_waitstream(chan, "");
02634 if (minutes) {
02635 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02636 res = ast_streamfile(chan, "queue-minutes", chan->language);
02637 res = ast_waitstream(chan, "");
02638 }
02639 if (seconds) {
02640 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02641 res = ast_streamfile(chan, "queue-seconds", chan->language);
02642 res = ast_waitstream(chan, "");
02643 }
02644 } else {
02645 res = ast_streamfile(chan, user->warning_sound, chan->language);
02646 res = ast_waitstream(chan, "");
02647 }
02648 }
02649 }
02650 if (user->warning_freq) {
02651 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02652 } else {
02653 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02654 }
02655 }
02656 }
02657
02658 now = ast_tvnow();
02659 if (timeout && now.tv_sec >= timeout) {
02660 break;
02661 }
02662
02663
02664
02665
02666 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual) {
02667 set_talk_volume(user, user->listen.desired);
02668 }
02669
02670 menu_was_active = menu_active;
02671
02672 currentmarked = conf->markedusers;
02673 if (!(confflags & CONFFLAG_QUIET) &&
02674 (confflags & CONFFLAG_MARKEDUSER) &&
02675 (confflags & CONFFLAG_WAITMARKED) &&
02676 lastmarked == 0) {
02677 if (currentmarked == 1 && conf->users > 1) {
02678 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02679 if (conf->users - 1 == 1) {
02680 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language)) {
02681 ast_waitstream(chan, "");
02682 }
02683 } else {
02684 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language)) {
02685 ast_waitstream(chan, "");
02686 }
02687 }
02688 }
02689 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER)) {
02690 if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
02691 ast_waitstream(chan, "");
02692 }
02693 }
02694 }
02695
02696
02697 user->userflags = confflags;
02698
02699 if (confflags & CONFFLAG_WAITMARKED) {
02700 if (currentmarked == 0) {
02701 if (lastmarked != 0) {
02702 if (!(confflags & CONFFLAG_QUIET)) {
02703 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language)) {
02704 ast_waitstream(chan, "");
02705 }
02706 }
02707 if (confflags & CONFFLAG_MARKEDEXIT) {
02708 if (confflags & CONFFLAG_KICK_CONTINUE) {
02709 ret = 0;
02710 }
02711 break;
02712 } else {
02713 dahdic.confmode = DAHDI_CONF_CONF;
02714 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02715 ast_log(LOG_WARNING, "Error setting conference\n");
02716 close(fd);
02717 goto outrun;
02718 }
02719 }
02720 }
02721 if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02722 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02723 musiconhold = 1;
02724 }
02725 } else if (currentmarked >= 1 && lastmarked == 0) {
02726
02727 timeout = 0;
02728 if (confflags & CONFFLAG_MONITOR) {
02729 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02730 } else if (confflags & CONFFLAG_TALKER) {
02731 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02732 } else {
02733 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02734 }
02735 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02736 ast_log(LOG_WARNING, "Error setting conference\n");
02737 close(fd);
02738 goto outrun;
02739 }
02740 if (musiconhold && (confflags & CONFFLAG_MOH)) {
02741 ast_moh_stop(chan);
02742 musiconhold = 0;
02743 }
02744 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02745 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language)) {
02746 ast_waitstream(chan, "");
02747 }
02748 conf_play(chan, conf, ENTER);
02749 }
02750 }
02751 }
02752
02753
02754 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02755 if (conf->users == 1) {
02756 if (!musiconhold) {
02757 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02758 musiconhold = 1;
02759 }
02760 } else {
02761 if (musiconhold) {
02762 ast_moh_stop(chan);
02763 musiconhold = 0;
02764 }
02765 }
02766 }
02767
02768
02769 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02770 if (confflags & CONFFLAG_KICK_CONTINUE) {
02771 ret = 0;
02772 } else {
02773 ret = -1;
02774 }
02775 break;
02776 }
02777
02778
02779
02780
02781 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02782 dahdic.confmode ^= DAHDI_CONF_TALKER;
02783 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02784 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02785 ret = -1;
02786 break;
02787 }
02788
02789
02790 if ((confflags & (CONFFLAG_MONITORTALKER | CONFFLAG_OPTIMIZETALKER))) {
02791 set_user_talking(chan, conf, user, -1, confflags & CONFFLAG_MONITORTALKER);
02792 }
02793
02794 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02795 "Channel: %s\r\n"
02796 "Uniqueid: %s\r\n"
02797 "Meetme: %s\r\n"
02798 "Usernum: %i\r\n"
02799 "Status: on\r\n",
02800 chan->name, chan->uniqueid, conf->confno, user->user_no);
02801 }
02802
02803
02804 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02805 dahdic.confmode |= DAHDI_CONF_TALKER;
02806 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02807 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02808 ret = -1;
02809 break;
02810 }
02811
02812 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02813 "Channel: %s\r\n"
02814 "Uniqueid: %s\r\n"
02815 "Meetme: %s\r\n"
02816 "Usernum: %i\r\n"
02817 "Status: off\r\n",
02818 chan->name, chan->uniqueid, conf->confno, user->user_no);
02819 }
02820
02821 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02822 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02823 talkreq_manager = 1;
02824
02825 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02826 "Channel: %s\r\n"
02827 "Uniqueid: %s\r\n"
02828 "Meetme: %s\r\n"
02829 "Usernum: %i\r\n"
02830 "Status: on\r\n",
02831 chan->name, chan->uniqueid, conf->confno, user->user_no);
02832 }
02833
02834
02835 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02836 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02837 talkreq_manager = 0;
02838 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02839 "Channel: %s\r\n"
02840 "Uniqueid: %s\r\n"
02841 "Meetme: %s\r\n"
02842 "Usernum: %i\r\n"
02843 "Status: off\r\n",
02844 chan->name, chan->uniqueid, conf->confno, user->user_no);
02845 }
02846
02847
02848 if (user->adminflags & ADMINFLAG_KICKME) {
02849
02850 if (!(confflags & CONFFLAG_QUIET) &&
02851 !ast_streamfile(chan, "conf-kicked", chan->language)) {
02852 ast_waitstream(chan, "");
02853 }
02854 ret = 0;
02855 break;
02856 }
02857
02858
02859 if (ast_check_hangup(chan)) {
02860 break;
02861 }
02862
02863 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02864
02865 if (c) {
02866 char dtmfstr[2] = "";
02867
02868 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02869 if (using_pseudo) {
02870
02871 close(fd);
02872 using_pseudo = 0;
02873 }
02874 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02875 retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02876 user->dahdichannel = !retrydahdi;
02877 goto dahdiretry;
02878 }
02879 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02880 f = ast_read_noaudio(c);
02881 } else {
02882 f = ast_read(c);
02883 }
02884 if (!f) {
02885 break;
02886 }
02887 if (f->frametype == AST_FRAME_DTMF) {
02888 dtmfstr[0] = f->subclass;
02889 dtmfstr[1] = '\0';
02890 }
02891
02892 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02893 if (user->talk.actual) {
02894 ast_frame_adjust_volume(f, user->talk.actual);
02895 }
02896
02897 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02898 if (user->talking == -1) {
02899 user->talking = 0;
02900 }
02901
02902 res = ast_dsp_silence(dsp, f, &totalsilence);
02903 if (totalsilence < MEETME_DELAYDETECTTALK) {
02904 set_user_talking(chan, conf, user, 1, confflags & CONFFLAG_MONITORTALKER);
02905 }
02906 if (totalsilence > MEETME_DELAYDETECTENDTALK) {
02907 set_user_talking(chan, conf, user, 0, confflags & CONFFLAG_MONITORTALKER);
02908 }
02909 }
02910 if (using_pseudo) {
02911
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923 if (user->talking || !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02924 careful_write(fd, f->data.ptr, f->datalen, 0);
02925 }
02926 }
02927 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02928 if (confflags & CONFFLAG_PASS_DTMF) {
02929 conf_queue_dtmf(conf, user, f);
02930 }
02931 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02932 ast_log(LOG_WARNING, "Error setting conference\n");
02933 close(fd);
02934 ast_frfree(f);
02935 goto outrun;
02936 }
02937
02938
02939
02940
02941 if (!menu_active && user->talk.desired && !user->talk.actual) {
02942 set_talk_volume(user, 0);
02943 }
02944
02945 if (musiconhold) {
02946 ast_moh_stop(chan);
02947 }
02948 if ((confflags & CONFFLAG_ADMIN)) {
02949
02950 if (!menu_active) {
02951 menu_active = 1;
02952
02953 if (!ast_streamfile(chan, "conf-adminmenu-162", chan->language)) {
02954 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02955 ast_stopstream(chan);
02956 } else {
02957 dtmf = 0;
02958 }
02959 } else {
02960 dtmf = f->subclass;
02961 }
02962 if (dtmf) {
02963 switch(dtmf) {
02964 case '1':
02965 menu_active = 0;
02966
02967
02968 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
02969 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02970 } else {
02971 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02972 }
02973
02974 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02975 if (!ast_streamfile(chan, "conf-muted", chan->language)) {
02976 ast_waitstream(chan, "");
02977 }
02978 } else {
02979 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
02980 ast_waitstream(chan, "");
02981 }
02982 }
02983 break;
02984 case '2':
02985 menu_active = 0;
02986 if (conf->locked) {
02987 conf->locked = 0;
02988 if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) {
02989 ast_waitstream(chan, "");
02990 }
02991 } else {
02992 conf->locked = 1;
02993 if (!ast_streamfile(chan, "conf-lockednow", chan->language)) {
02994 ast_waitstream(chan, "");
02995 }
02996 }
02997 break;
02998 case '3':
02999 menu_active = 0;
03000 usr = AST_LIST_LAST(&conf->userlist);
03001 if ((usr->chan->name == chan->name) || (usr->userflags & CONFFLAG_ADMIN)) {
03002 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03003 ast_waitstream(chan, "");
03004 }
03005 } else {
03006 usr->adminflags |= ADMINFLAG_KICKME;
03007 }
03008 ast_stopstream(chan);
03009 break;
03010 case '4':
03011 tweak_listen_volume(user, VOL_DOWN);
03012 break;
03013 case '5':
03014
03015 if (rt_schedule) {
03016 if (!rt_extend_conf(conf->confno)) {
03017 if (!ast_streamfile(chan, "conf-extended", chan->language)) {
03018 ast_waitstream(chan, "");
03019 }
03020 } else {
03021 if (!ast_streamfile(chan, "conf-nonextended", chan->language)) {
03022 ast_waitstream(chan, "");
03023 }
03024 }
03025 ast_stopstream(chan);
03026 }
03027 menu_active = 0;
03028 break;
03029 case '6':
03030 tweak_listen_volume(user, VOL_UP);
03031 break;
03032 case '7':
03033 tweak_talk_volume(user, VOL_DOWN);
03034 break;
03035 case '8':
03036 menu_active = 0;
03037 break;
03038 case '9':
03039 tweak_talk_volume(user, VOL_UP);
03040 break;
03041 default:
03042 menu_active = 0;
03043
03044 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03045 ast_waitstream(chan, "");
03046 }
03047 break;
03048 }
03049 }
03050 } else {
03051
03052 if (!menu_active) {
03053 menu_active = 1;
03054 if (!ast_streamfile(chan, "conf-usermenu-162", chan->language)) {
03055 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
03056 ast_stopstream(chan);
03057 } else {
03058 dtmf = 0;
03059 }
03060 } else {
03061 dtmf = f->subclass;
03062 }
03063 if (dtmf) {
03064 switch (dtmf) {
03065 case '1':
03066 menu_active = 0;
03067
03068
03069 user->adminflags ^= ADMINFLAG_SELFMUTED;
03070
03071
03072 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
03073 if (!ast_streamfile(chan, "conf-muted", chan->language)) {
03074 ast_waitstream(chan, "");
03075 }
03076 } else {
03077 if (!ast_streamfile(chan, "conf-unmuted", chan->language)) {
03078 ast_waitstream(chan, "");
03079 }
03080 }
03081 break;
03082 case '2':
03083 menu_active = 0;
03084 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) {
03085 user->adminflags |= ADMINFLAG_T_REQUEST;
03086 }
03087
03088 if (user->adminflags & ADMINFLAG_T_REQUEST) {
03089 if (!ast_streamfile(chan, "beep", chan->language)) {
03090 ast_waitstream(chan, "");
03091 }
03092 }
03093 break;
03094 case '4':
03095 tweak_listen_volume(user, VOL_DOWN);
03096 break;
03097 case '5':
03098
03099 if (rt_schedule) {
03100 rt_extend_conf(conf->confno);
03101 }
03102 menu_active = 0;
03103 break;
03104 case '6':
03105 tweak_listen_volume(user, VOL_UP);
03106 break;
03107 case '7':
03108 tweak_talk_volume(user, VOL_DOWN);
03109 break;
03110 case '8':
03111 menu_active = 0;
03112 break;
03113 case '9':
03114 tweak_talk_volume(user, VOL_UP);
03115 break;
03116 default:
03117 menu_active = 0;
03118 if (!ast_streamfile(chan, "conf-errormenu", chan->language)) {
03119 ast_waitstream(chan, "");
03120 }
03121 break;
03122 }
03123 }
03124 }
03125 if (musiconhold) {
03126 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
03127 }
03128
03129 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03130 ast_log(LOG_WARNING, "Error setting conference\n");
03131 close(fd);
03132 ast_frfree(f);
03133 goto outrun;
03134 }
03135
03136 conf_flush(fd, chan);
03137
03138 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
03139 if (confflags & CONFFLAG_PASS_DTMF) {
03140 conf_queue_dtmf(conf, user, f);
03141 }
03142
03143 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
03144 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
03145 ret = 0;
03146 ast_frfree(f);
03147 break;
03148 } else {
03149 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
03150 }
03151 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
03152 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
03153
03154 if (confflags & CONFFLAG_PASS_DTMF) {
03155 conf_queue_dtmf(conf, user, f);
03156 }
03157 ret = 0;
03158 ast_frfree(f);
03159 break;
03160 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
03161 && confflags & CONFFLAG_PASS_DTMF) {
03162 conf_queue_dtmf(conf, user, f);
03163 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
03164 switch (f->subclass) {
03165 case AST_CONTROL_HOLD:
03166 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
03167 break;
03168 default:
03169 break;
03170 }
03171 } else if (f->frametype == AST_FRAME_NULL) {
03172
03173 } else {
03174 ast_debug(1,
03175 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
03176 chan->name, f->frametype, f->subclass);
03177 }
03178 ast_frfree(f);
03179 } else if (outfd > -1) {
03180 res = read(outfd, buf, CONF_SIZE);
03181 if (res > 0) {
03182 memset(&fr, 0, sizeof(fr));
03183 fr.frametype = AST_FRAME_VOICE;
03184 fr.subclass = AST_FORMAT_SLINEAR;
03185 fr.datalen = res;
03186 fr.samples = res / 2;
03187 fr.data.ptr = buf;
03188 fr.offset = AST_FRIENDLY_OFFSET;
03189 if (!user->listen.actual &&
03190 ((confflags & CONFFLAG_MONITOR) ||
03191 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
03192 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
03193 )) {
03194 int idx;
03195 for (idx = 0; idx < AST_FRAME_BITS; idx++) {
03196 if (chan->rawwriteformat & (1 << idx)) {
03197 break;
03198 }
03199 }
03200 if (idx >= AST_FRAME_BITS) {
03201 goto bailoutandtrynormal;
03202 }
03203 ast_mutex_lock(&conf->listenlock);
03204 if (!conf->transframe[idx]) {
03205 if (conf->origframe) {
03206 if (!conf->transpath[idx]) {
03207 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
03208 }
03209 if (conf->transpath[idx]) {
03210 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
03211 if (!conf->transframe[idx]) {
03212 conf->transframe[idx] = &ast_null_frame;
03213 }
03214 }
03215 }
03216 }
03217 if (conf->transframe[idx]) {
03218 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
03219 can_write(chan, confflags)) {
03220 struct ast_frame *cur;
03221 if (musiconhold && !ast_dsp_silence(dsp, conf->transframe[idx], &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03222 ast_moh_stop(chan);
03223 mohtempstopped = 1;
03224 }
03225
03226
03227
03228
03229 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
03230 if (ast_write(chan, cur)) {
03231 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03232 break;
03233 }
03234 }
03235 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03236 mohtempstopped = 0;
03237 ast_moh_start(chan, NULL, NULL);
03238 }
03239 }
03240 } else {
03241 ast_mutex_unlock(&conf->listenlock);
03242 goto bailoutandtrynormal;
03243 }
03244 ast_mutex_unlock(&conf->listenlock);
03245 } else {
03246 bailoutandtrynormal:
03247 if (musiconhold && !ast_dsp_silence(dsp, &fr, &confsilence) && confsilence < MEETME_DELAYDETECTTALK) {
03248 ast_moh_stop(chan);
03249 mohtempstopped = 1;
03250 }
03251 if (user->listen.actual) {
03252 ast_frame_adjust_volume(&fr, user->listen.actual);
03253 }
03254 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
03255 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
03256 }
03257 if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
03258 mohtempstopped = 0;
03259 ast_moh_start(chan, NULL, NULL);
03260 }
03261 }
03262 } else {
03263 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
03264 }
03265 }
03266 lastmarked = currentmarked;
03267 }
03268 }
03269
03270 if (musiconhold) {
03271 ast_moh_stop(chan);
03272 }
03273
03274 if (using_pseudo) {
03275 close(fd);
03276 } else {
03277
03278 dahdic.chan = 0;
03279 dahdic.confno = 0;
03280 dahdic.confmode = 0;
03281 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
03282 ast_log(LOG_WARNING, "Error setting conference\n");
03283 }
03284 }
03285
03286 reset_volumes(user);
03287
03288 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
03289 conf_play(chan, conf, LEAVE);
03290 }
03291
03292 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
03293 struct announce_listitem *item;
03294 if (!(item = ao2_alloc(sizeof(*item), NULL)))
03295 return -1;
03296 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
03297 ast_copy_string(item->language, chan->language, sizeof(item->language));
03298 item->confchan = conf->chan;
03299 item->confusers = conf->users;
03300 item->announcetype = CONF_HASLEFT;
03301 ast_mutex_lock(&conf->announcelistlock);
03302 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
03303 ast_cond_signal(&conf->announcelist_addition);
03304 ast_mutex_unlock(&conf->announcelistlock);
03305 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
03306
03307 ast_filedelete(user->namerecloc, NULL);
03308 }
03309
03310 outrun:
03311 AST_LIST_LOCK(&confs);
03312
03313 if (dsp) {
03314 ast_dsp_free(dsp);
03315 }
03316
03317 if (user->user_no) {
03318 now = ast_tvnow();
03319 hr = (now.tv_sec - user->jointime) / 3600;
03320 min = ((now.tv_sec - user->jointime) % 3600) / 60;
03321 sec = (now.tv_sec - user->jointime) % 60;
03322
03323 if (sent_event) {
03324 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
03325 "Channel: %s\r\n"
03326 "Uniqueid: %s\r\n"
03327 "Meetme: %s\r\n"
03328 "Usernum: %d\r\n"
03329 "CallerIDNum: %s\r\n"
03330 "CallerIDName: %s\r\n"
03331 "Duration: %ld\r\n",
03332 chan->name, chan->uniqueid, conf->confno,
03333 user->user_no,
03334 S_OR(user->chan->cid.cid_num, "<unknown>"),
03335 S_OR(user->chan->cid.cid_name, "<unknown>"),
03336 (long)(now.tv_sec - user->jointime));
03337 }
03338
03339 if (setusercount) {
03340 conf->users--;
03341 if (rt_log_members) {
03342
03343 snprintf(members, sizeof(members), "%d", conf->users);
03344 ast_realtime_require_field("meetme",
03345 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
03346 "members", RQ_UINTEGER1, strlen(members),
03347 NULL);
03348 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
03349 }
03350 if (confflags & CONFFLAG_MARKEDUSER) {
03351 conf->markedusers--;
03352 }
03353 }
03354
03355 AST_LIST_REMOVE(&conf->userlist, user, list);
03356
03357
03358 if (!conf->users) {
03359 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
03360 }
03361
03362
03363 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
03364 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
03365 }
03366 ast_free(user);
03367 AST_LIST_UNLOCK(&confs);
03368
03369 return ret;
03370 }
03371
03372 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
03373 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, int *too_early)
03374 {
03375 struct ast_variable *var, *origvar;
03376 struct ast_conference *cnf;
03377
03378 *too_early = 0;
03379
03380
03381 AST_LIST_LOCK(&confs);
03382 AST_LIST_TRAVERSE(&confs, cnf, list) {
03383 if (!strcmp(confno, cnf->confno))
03384 break;
03385 }
03386 if (cnf) {
03387 cnf->refcount += refcount;
03388 }
03389 AST_LIST_UNLOCK(&confs);
03390
03391 if (!cnf) {
03392 char *pin = NULL, *pinadmin = NULL;
03393 int maxusers = 0;
03394 struct timeval now;
03395 char recordingfilename[256] = "";
03396 char recordingformat[11] = "";
03397 char currenttime[19] = "";
03398 char eatime[19] = "";
03399 char bookid[51] = "";
03400 char recordingtmp[AST_MAX_EXTENSION] = "";
03401 char useropts[OPTIONS_LEN + 1];
03402 char adminopts[OPTIONS_LEN + 1];
03403 struct ast_tm tm, etm;
03404 struct timeval endtime = { .tv_sec = 0 };
03405 const char *var2;
03406
03407 if (rt_schedule) {
03408 now = ast_tvnow();
03409
03410 ast_localtime(&now, &tm, NULL);
03411 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03412
03413 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
03414
03415 var = ast_load_realtime("meetme", "confno",
03416 confno, "starttime <= ", currenttime, "endtime >= ",
03417 currenttime, NULL);
03418
03419 if (!var && fuzzystart) {
03420 now = ast_tvnow();
03421 now.tv_sec += fuzzystart;
03422
03423 ast_localtime(&now, &tm, NULL);
03424 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03425 var = ast_load_realtime("meetme", "confno",
03426 confno, "starttime <= ", currenttime, "endtime >= ",
03427 currenttime, NULL);
03428 }
03429
03430 if (!var && earlyalert) {
03431 now = ast_tvnow();
03432 now.tv_sec += earlyalert;
03433 ast_localtime(&now, &etm, NULL);
03434 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03435 var = ast_load_realtime("meetme", "confno",
03436 confno, "starttime <= ", eatime, "endtime >= ",
03437 currenttime, NULL);
03438 if (var) {
03439 *too_early = 1;
03440 }
03441 }
03442
03443 } else {
03444 var = ast_load_realtime("meetme", "confno", confno, NULL);
03445 }
03446
03447 if (!var)
03448 return NULL;
03449
03450 if (rt_schedule && *too_early) {
03451
03452 if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
03453 ast_waitstream(chan, "");
03454 ast_variables_destroy(var);
03455 return NULL;
03456 }
03457
03458 for (origvar = var; var; var = var->next) {
03459 if (!strcasecmp(var->name, "pin")) {
03460 pin = ast_strdupa(var->value);
03461 } else if (!strcasecmp(var->name, "adminpin")) {
03462 pinadmin = ast_strdupa(var->value);
03463 } else if (!strcasecmp(var->name, "bookId")) {
03464 ast_copy_string(bookid, var->value, sizeof(bookid));
03465 } else if (!strcasecmp(var->name, "opts")) {
03466 ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03467 } else if (!strcasecmp(var->name, "maxusers")) {
03468 maxusers = atoi(var->value);
03469 } else if (!strcasecmp(var->name, "adminopts")) {
03470 ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03471 } else if (!strcasecmp(var->name, "recordingfilename")) {
03472 ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
03473 } else if (!strcasecmp(var->name, "recordingformat")) {
03474 ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
03475 } else if (!strcasecmp(var->name, "endtime")) {
03476 struct ast_tm endtime_tm;
03477 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03478 endtime = ast_mktime(&endtime_tm, NULL);
03479 }
03480 }
03481
03482 ast_variables_destroy(origvar);
03483
03484 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03485
03486 if (cnf) {
03487 cnf->maxusers = maxusers;
03488 cnf->endalert = endalert;
03489 cnf->endtime = endtime.tv_sec;
03490 cnf->useropts = ast_strdup(useropts);
03491 cnf->adminopts = ast_strdup(adminopts);
03492 cnf->bookid = ast_strdup(bookid);
03493 cnf->recordingfilename = ast_strdup(recordingfilename);
03494 cnf->recordingformat = ast_strdup(recordingformat);
03495
03496 if (strchr(cnf->useropts, 'r')) {
03497 if (ast_strlen_zero(recordingfilename)) {
03498 ast_channel_lock(chan);
03499 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03500 ast_free(cnf->recordingfilename);
03501 cnf->recordingfilename = ast_strdup(var2);
03502 }
03503 ast_channel_unlock(chan);
03504 if (ast_strlen_zero(cnf->recordingfilename)) {
03505 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
03506 ast_free(cnf->recordingfilename);
03507 cnf->recordingfilename = ast_strdup(recordingtmp);
03508 }
03509 }
03510 if (ast_strlen_zero(cnf->recordingformat)) {
03511 ast_channel_lock(chan);
03512 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03513 ast_free(cnf->recordingformat);
03514 cnf->recordingformat = ast_strdup(var2);
03515 }
03516 ast_channel_unlock(chan);
03517 if (ast_strlen_zero(cnf->recordingformat)) {
03518 ast_free(cnf->recordingformat);
03519 cnf->recordingformat = ast_strdup("wav");
03520 }
03521 }
03522 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03523 }
03524 }
03525 }
03526
03527 if (cnf) {
03528 if (confflags && !cnf->chan &&
03529 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03530 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03531 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03532 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03533 }
03534
03535 if (confflags && !cnf->chan &&
03536 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03537 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03538 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03539 }
03540 }
03541
03542 return cnf;
03543 }
03544
03545
03546 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
03547 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
03548 {
03549 struct ast_config *cfg;
03550 struct ast_variable *var;
03551 struct ast_flags config_flags = { 0 };
03552 struct ast_conference *cnf;
03553
03554 AST_DECLARE_APP_ARGS(args,
03555 AST_APP_ARG(confno);
03556 AST_APP_ARG(pin);
03557 AST_APP_ARG(pinadmin);
03558 );
03559
03560
03561 ast_debug(1, "The requested confno is '%s'?\n", confno);
03562 AST_LIST_LOCK(&confs);
03563 AST_LIST_TRAVERSE(&confs, cnf, list) {
03564 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03565 if (!strcmp(confno, cnf->confno))
03566 break;
03567 }
03568 if (cnf) {
03569 cnf->refcount += refcount;
03570 }
03571 AST_LIST_UNLOCK(&confs);
03572
03573 if (!cnf) {
03574 if (dynamic) {
03575
03576 ast_debug(1, "Building dynamic conference '%s'\n", confno);
03577 if (dynamic_pin) {
03578 if (dynamic_pin[0] == 'q') {
03579
03580 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03581 return NULL;
03582 }
03583 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03584 } else {
03585 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03586 }
03587 } else {
03588
03589 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03590 if (!cfg) {
03591 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03592 return NULL;
03593 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
03594 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
03595 return NULL;
03596 }
03597
03598 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03599 char parse[MAX_SETTINGS];
03600
03601 if (strcasecmp(var->name, "conf"))
03602 continue;
03603
03604 ast_copy_string(parse, var->value, sizeof(parse));
03605
03606 AST_STANDARD_APP_ARGS(args, parse);
03607 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03608 if (!strcasecmp(args.confno, confno)) {
03609
03610 cnf = build_conf(args.confno,
03611 S_OR(args.pin, ""),
03612 S_OR(args.pinadmin, ""),
03613 make, dynamic, refcount, chan);
03614 break;
03615 }
03616 }
03617 if (!var) {
03618 ast_debug(1, "%s isn't a valid conference\n", confno);
03619 }
03620 ast_config_destroy(cfg);
03621 }
03622 } else if (dynamic_pin) {
03623
03624
03625
03626 if (dynamic_pin[0] == 'q') {
03627 dynamic_pin[0] = '\0';
03628 }
03629 }
03630
03631 if (cnf) {
03632 if (confflags && !cnf->chan &&
03633 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03634 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03635 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03636 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03637 }
03638
03639 if (confflags && !cnf->chan &&
03640 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03641 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03642 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03643 }
03644 }
03645
03646 return cnf;
03647 }
03648
03649
03650 static int count_exec(struct ast_channel *chan, void *data)
03651 {
03652 int res = 0;
03653 struct ast_conference *conf;
03654 int count;
03655 char *localdata;
03656 char val[80] = "0";
03657 AST_DECLARE_APP_ARGS(args,
03658 AST_APP_ARG(confno);
03659 AST_APP_ARG(varname);
03660 );
03661
03662 if (ast_strlen_zero(data)) {
03663 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03664 return -1;
03665 }
03666
03667 if (!(localdata = ast_strdupa(data)))
03668 return -1;
03669
03670 AST_STANDARD_APP_ARGS(args, localdata);
03671
03672 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03673
03674 if (conf) {
03675 count = conf->users;
03676 dispose_conf(conf);
03677 conf = NULL;
03678 } else
03679 count = 0;
03680
03681 if (!ast_strlen_zero(args.varname)) {
03682
03683 snprintf(val, sizeof(val), "%d", count);
03684 pbx_builtin_setvar_helper(chan, args.varname, val);
03685 } else {
03686 if (chan->_state != AST_STATE_UP) {
03687 ast_answer(chan);
03688 }
03689 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
03690 }
03691
03692 return res;
03693 }
03694
03695
03696 static int conf_exec(struct ast_channel *chan, void *data)
03697 {
03698 int res = -1;
03699 char confno[MAX_CONFNUM] = "";
03700 int allowretry = 0;
03701 int retrycnt = 0;
03702 struct ast_conference *cnf = NULL;
03703 struct ast_flags confflags = {0}, config_flags = { 0 };
03704 int dynamic = 0;
03705 int empty = 0, empty_no_pin = 0;
03706 int always_prompt = 0;
03707 char *notdata, *info, the_pin[MAX_PIN] = "";
03708 AST_DECLARE_APP_ARGS(args,
03709 AST_APP_ARG(confno);
03710 AST_APP_ARG(options);
03711 AST_APP_ARG(pin);
03712 );
03713 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03714
03715 if (ast_strlen_zero(data)) {
03716 allowretry = 1;
03717 notdata = "";
03718 } else {
03719 notdata = data;
03720 }
03721
03722 if (chan->_state != AST_STATE_UP)
03723 ast_answer(chan);
03724
03725 info = ast_strdupa(notdata);
03726
03727 AST_STANDARD_APP_ARGS(args, info);
03728
03729 if (args.confno) {
03730 ast_copy_string(confno, args.confno, sizeof(confno));
03731 if (ast_strlen_zero(confno)) {
03732 allowretry = 1;
03733 }
03734 }
03735
03736 if (args.pin)
03737 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03738
03739 if (args.options) {
03740 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03741 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03742 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03743 strcpy(the_pin, "q");
03744
03745 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03746 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03747 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03748 }
03749
03750 do {
03751 if (retrycnt > 3)
03752 allowretry = 0;
03753 if (empty) {
03754 int i;
03755 struct ast_config *cfg;
03756 struct ast_variable *var;
03757 int confno_int;
03758
03759
03760 if ((empty_no_pin) || (!dynamic)) {
03761 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03762 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03763 var = ast_variable_browse(cfg, "rooms");
03764 while (var) {
03765 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03766 if (!strcasecmp(var->name, "conf")) {
03767 int found = 0;
03768 ast_copy_string(parse, var->value, sizeof(parse));
03769 confno_tmp = strsep(&stringp, "|,");
03770 if (!dynamic) {
03771
03772 AST_LIST_LOCK(&confs);
03773 AST_LIST_TRAVERSE(&confs, cnf, list) {
03774 if (!strcmp(confno_tmp, cnf->confno)) {
03775
03776 found = 1;
03777 break;
03778 }
03779 }
03780 AST_LIST_UNLOCK(&confs);
03781 if (!found) {
03782
03783 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03784
03785
03786
03787
03788 ast_copy_string(confno, confno_tmp, sizeof(confno));
03789 break;
03790
03791 }
03792 }
03793 }
03794 }
03795 var = var->next;
03796 }
03797 ast_config_destroy(cfg);
03798 }
03799 }
03800
03801
03802 if (ast_strlen_zero(confno) && dynamic) {
03803 AST_LIST_LOCK(&confs);
03804 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03805 if (!conf_map[i]) {
03806 snprintf(confno, sizeof(confno), "%d", i);
03807 conf_map[i] = 1;
03808 break;
03809 }
03810 }
03811 AST_LIST_UNLOCK(&confs);
03812 }
03813
03814
03815 if (ast_strlen_zero(confno)) {
03816 res = ast_streamfile(chan, "conf-noempty", chan->language);
03817 if (!res)
03818 ast_waitstream(chan, "");
03819 } else {
03820 if (sscanf(confno, "%30d", &confno_int) == 1) {
03821 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03822 res = ast_streamfile(chan, "conf-enteringno", chan->language);
03823 if (!res) {
03824 ast_waitstream(chan, "");
03825 res = ast_say_digits(chan, confno_int, "", chan->language);
03826 }
03827 }
03828 } else {
03829 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03830 }
03831 }
03832 }
03833
03834 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03835
03836 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03837 if (res < 0) {
03838
03839 confno[0] = '\0';
03840 allowretry = 0;
03841 break;
03842 }
03843 }
03844 if (!ast_strlen_zero(confno)) {
03845
03846 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
03847 sizeof(the_pin), 1, &confflags);
03848 if (!cnf) {
03849 int too_early = 0;
03850
03851 cnf = find_conf_realtime(chan, confno, 1, dynamic,
03852 the_pin, sizeof(the_pin), 1, &confflags,&too_early);
03853 if (rt_schedule && too_early)
03854 allowretry = 0;
03855 }
03856
03857 if (!cnf) {
03858 if (allowretry) {
03859 confno[0] = '\0';
03860 res = ast_streamfile(chan, "conf-invalid", chan->language);
03861 if (!res)
03862 ast_waitstream(chan, "");
03863 res = -1;
03864 }
03865 } else {
03866 if ((!ast_strlen_zero(cnf->pin) &&
03867 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03868 (!ast_strlen_zero(cnf->pinadmin) &&
03869 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03870 char pin[MAX_PIN] = "";
03871 int j;
03872
03873
03874 for (j = 0; j < 3; j++) {
03875 if (*the_pin && (always_prompt == 0)) {
03876 ast_copy_string(pin, the_pin, sizeof(pin));
03877 res = 0;
03878 } else {
03879
03880 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03881 }
03882 if (res >= 0) {
03883 if (!strcasecmp(pin, cnf->pin) ||
03884 (!ast_strlen_zero(cnf->pinadmin) &&
03885 !strcasecmp(pin, cnf->pinadmin))) {
03886
03887 allowretry = 0;
03888 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
03889 if (!ast_strlen_zero(cnf->adminopts)) {
03890 char *opts = ast_strdupa(cnf->adminopts);
03891 ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03892 }
03893 } else {
03894 if (!ast_strlen_zero(cnf->useropts)) {
03895 char *opts = ast_strdupa(cnf->useropts);
03896 ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03897 }
03898 }
03899
03900 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03901 res = conf_run(chan, cnf, confflags.flags, optargs);
03902 break;
03903 } else {
03904
03905 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03906 res = ast_waitstream(chan, AST_DIGIT_ANY);
03907 ast_stopstream(chan);
03908 } else {
03909 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03910 break;
03911 }
03912 if (res < 0)
03913 break;
03914 pin[0] = res;
03915 pin[1] = '\0';
03916 res = -1;
03917 if (allowretry)
03918 confno[0] = '\0';
03919 }
03920 } else {
03921
03922 res = -1;
03923 allowretry = 0;
03924
03925 break;
03926 }
03927
03928
03929 if (*the_pin && (always_prompt == 0)) {
03930 break;
03931 }
03932 }
03933 } else {
03934
03935 allowretry = 0;
03936
03937
03938 res = conf_run(chan, cnf, confflags.flags, optargs);
03939 }
03940 dispose_conf(cnf);
03941 cnf = NULL;
03942 }
03943 }
03944 } while (allowretry);
03945
03946 if (cnf)
03947 dispose_conf(cnf);
03948
03949 return res;
03950 }
03951
03952 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
03953 {
03954 struct ast_conf_user *user = NULL;
03955 int cid;
03956
03957 sscanf(callerident, "%30i", &cid);
03958 if (conf && callerident) {
03959 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03960 if (cid == user->user_no)
03961 return user;
03962 }
03963 }
03964 return NULL;
03965 }
03966
03967
03968
03969 static int admin_exec(struct ast_channel *chan, void *data) {
03970 char *params;
03971 struct ast_conference *cnf;
03972 struct ast_conf_user *user = NULL;
03973 AST_DECLARE_APP_ARGS(args,
03974 AST_APP_ARG(confno);
03975 AST_APP_ARG(command);
03976 AST_APP_ARG(user);
03977 );
03978 int res = 0;
03979
03980 if (ast_strlen_zero(data)) {
03981 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03982 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
03983 return -1;
03984 }
03985
03986 params = ast_strdupa(data);
03987 AST_STANDARD_APP_ARGS(args, params);
03988
03989 if (!args.command) {
03990 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03991 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
03992 return -1;
03993 }
03994
03995 AST_LIST_LOCK(&confs);
03996 AST_LIST_TRAVERSE(&confs, cnf, list) {
03997 if (!strcmp(cnf->confno, args.confno))
03998 break;
03999 }
04000
04001 if (!cnf) {
04002 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04003 AST_LIST_UNLOCK(&confs);
04004 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04005 return 0;
04006 }
04007
04008 ast_atomic_fetchadd_int(&cnf->refcount, 1);
04009
04010 if (args.user)
04011 user = find_user(cnf, args.user);
04012
04013 switch (*args.command) {
04014 case 76:
04015 cnf->locked = 1;
04016 break;
04017 case 108:
04018 cnf->locked = 0;
04019 break;
04020 case 75:
04021 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
04022 user->adminflags |= ADMINFLAG_KICKME;
04023 break;
04024 case 101:
04025 user = AST_LIST_LAST(&cnf->userlist);
04026 if (!(user->userflags & CONFFLAG_ADMIN))
04027 user->adminflags |= ADMINFLAG_KICKME;
04028 else {
04029 res = -1;
04030 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04031 }
04032 break;
04033 case 77:
04034 if (user) {
04035 user->adminflags |= ADMINFLAG_MUTED;
04036 } else {
04037 res = -2;
04038 ast_log(LOG_NOTICE, "Specified User not found!\n");
04039 }
04040 break;
04041 case 78:
04042 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04043 if (!(user->userflags & CONFFLAG_ADMIN)) {
04044 user->adminflags |= ADMINFLAG_MUTED;
04045 }
04046 }
04047 break;
04048 case 109:
04049 if (user) {
04050 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04051 } else {
04052 res = -2;
04053 ast_log(LOG_NOTICE, "Specified User not found!\n");
04054 }
04055 break;
04056 case 110:
04057 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04058 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04059 }
04060 break;
04061 case 107:
04062 if (user) {
04063 user->adminflags |= ADMINFLAG_KICKME;
04064 } else {
04065 res = -2;
04066 ast_log(LOG_NOTICE, "Specified User not found!\n");
04067 }
04068 break;
04069 case 118:
04070 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04071 tweak_listen_volume(user, VOL_DOWN);
04072 }
04073 break;
04074 case 86:
04075 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04076 tweak_listen_volume(user, VOL_UP);
04077 }
04078 break;
04079 case 115:
04080 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04081 tweak_talk_volume(user, VOL_DOWN);
04082 }
04083 break;
04084 case 83:
04085 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04086 tweak_talk_volume(user, VOL_UP);
04087 }
04088 break;
04089 case 82:
04090 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04091 reset_volumes(user);
04092 }
04093 break;
04094 case 114:
04095 if (user) {
04096 reset_volumes(user);
04097 } else {
04098 res = -2;
04099 ast_log(LOG_NOTICE, "Specified User not found!\n");
04100 }
04101 break;
04102 case 85:
04103 if (user) {
04104 tweak_listen_volume(user, VOL_UP);
04105 } else {
04106 res = -2;
04107 ast_log(LOG_NOTICE, "Specified User not found!\n");
04108 }
04109 break;
04110 case 117:
04111 if (user) {
04112 tweak_listen_volume(user, VOL_DOWN);
04113 } else {
04114 res = -2;
04115 ast_log(LOG_NOTICE, "Specified User not found!\n");
04116 }
04117 break;
04118 case 84:
04119 if (user) {
04120 tweak_talk_volume(user, VOL_UP);
04121 } else {
04122 res = -2;
04123 ast_log(LOG_NOTICE, "Specified User not found!\n");
04124 }
04125 break;
04126 case 116:
04127 if (user) {
04128 tweak_talk_volume(user, VOL_DOWN);
04129 } else {
04130 res = -2;
04131 ast_log(LOG_NOTICE, "Specified User not found!\n");
04132 }
04133 break;
04134 case 'E':
04135 if (rt_extend_conf(args.confno)) {
04136 res = -1;
04137 }
04138 break;
04139 }
04140
04141 AST_LIST_UNLOCK(&confs);
04142
04143 dispose_conf(cnf);
04144 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04145
04146 return 0;
04147 }
04148
04149
04150
04151 static int channel_admin_exec(struct ast_channel *chan, void *data) {
04152 char *params;
04153 struct ast_conference *conf = NULL;
04154 struct ast_conf_user *user = NULL;
04155 AST_DECLARE_APP_ARGS(args,
04156 AST_APP_ARG(channel);
04157 AST_APP_ARG(command);
04158 );
04159
04160 if (ast_strlen_zero(data)) {
04161 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04162 return -1;
04163 }
04164
04165 params = ast_strdupa(data);
04166 AST_STANDARD_APP_ARGS(args, params);
04167
04168 if (!args.channel) {
04169 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04170 return -1;
04171 }
04172
04173 if (!args.command) {
04174 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04175 return -1;
04176 }
04177
04178 AST_LIST_LOCK(&confs);
04179 AST_LIST_TRAVERSE(&confs, conf, list) {
04180 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
04181 if (!strcmp(user->chan->name, args.channel))
04182 break;
04183 }
04184 }
04185
04186 if (!user) {
04187 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04188 AST_LIST_UNLOCK(&confs);
04189 return 0;
04190 }
04191
04192
04193 switch (*args.command) {
04194 case 77:
04195 user->adminflags |= ADMINFLAG_MUTED;
04196 break;
04197 case 109:
04198 user->adminflags &= ~ADMINFLAG_MUTED;
04199 break;
04200 case 107:
04201 user->adminflags |= ADMINFLAG_KICKME;
04202 break;
04203 default:
04204 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04205 break;
04206 }
04207
04208 AST_LIST_UNLOCK(&confs);
04209
04210 return 0;
04211 }
04212
04213 static int meetmemute(struct mansession *s, const struct message *m, int mute)
04214 {
04215 struct ast_conference *conf;
04216 struct ast_conf_user *user;
04217 const char *confid = astman_get_header(m, "Meetme");
04218 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04219 int userno;
04220
04221 if (ast_strlen_zero(confid)) {
04222 astman_send_error(s, m, "Meetme conference not specified");
04223 return 0;
04224 }
04225
04226 if (ast_strlen_zero(userid)) {
04227 astman_send_error(s, m, "Meetme user number not specified");
04228 return 0;
04229 }
04230
04231 userno = strtoul(userid, &userid, 10);
04232
04233 if (*userid) {
04234 astman_send_error(s, m, "Invalid user number");
04235 return 0;
04236 }
04237
04238
04239 AST_LIST_LOCK(&confs);
04240 AST_LIST_TRAVERSE(&confs, conf, list) {
04241 if (!strcmp(confid, conf->confno))
04242 break;
04243 }
04244
04245 if (!conf) {
04246 AST_LIST_UNLOCK(&confs);
04247 astman_send_error(s, m, "Meetme conference does not exist");
04248 return 0;
04249 }
04250
04251 AST_LIST_TRAVERSE(&conf->userlist, user, list)
04252 if (user->user_no == userno)
04253 break;
04254
04255 if (!user) {
04256 AST_LIST_UNLOCK(&confs);
04257 astman_send_error(s, m, "User number not found");
04258 return 0;
04259 }
04260
04261 if (mute)
04262 user->adminflags |= ADMINFLAG_MUTED;
04263 else
04264 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04265
04266 AST_LIST_UNLOCK(&confs);
04267
04268 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);
04269
04270 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04271 return 0;
04272 }
04273
04274 static int action_meetmemute(struct mansession *s, const struct message *m)
04275 {
04276 return meetmemute(s, m, 1);
04277 }
04278
04279 static int action_meetmeunmute(struct mansession *s, const struct message *m)
04280 {
04281 return meetmemute(s, m, 0);
04282 }
04283
04284 static char mandescr_meetmelist[] =
04285 "Description: Lists all users in a particular MeetMe conference.\n"
04286 "MeetmeList will follow as separate events, followed by a final event called\n"
04287 "MeetmeListComplete.\n"
04288 "Variables:\n"
04289 " *ActionId: <id>\n"
04290 " *Conference: <confno>\n";
04291
04292 static int action_meetmelist(struct mansession *s, const struct message *m)
04293 {
04294 const char *actionid = astman_get_header(m, "ActionID");
04295 const char *conference = astman_get_header(m, "Conference");
04296 char idText[80] = "";
04297 struct ast_conference *cnf;
04298 struct ast_conf_user *user;
04299 int total = 0;
04300
04301 if (!ast_strlen_zero(actionid))
04302 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04303
04304 if (AST_LIST_EMPTY(&confs)) {
04305 astman_send_error(s, m, "No active conferences.");
04306 return 0;
04307 }
04308
04309 astman_send_listack(s, m, "Meetme user list will follow", "start");
04310
04311
04312 AST_LIST_LOCK(&confs);
04313 AST_LIST_TRAVERSE(&confs, cnf, list) {
04314
04315 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04316 continue;
04317
04318
04319 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04320 total++;
04321 astman_append(s,
04322 "Event: MeetmeList\r\n"
04323 "%s"
04324 "Conference: %s\r\n"
04325 "UserNumber: %d\r\n"
04326 "CallerIDNum: %s\r\n"
04327 "CallerIDName: %s\r\n"
04328 "Channel: %s\r\n"
04329 "Admin: %s\r\n"
04330 "Role: %s\r\n"
04331 "MarkedUser: %s\r\n"
04332 "Muted: %s\r\n"
04333 "Talking: %s\r\n"
04334 "\r\n",
04335 idText,
04336 cnf->confno,
04337 user->user_no,
04338 S_OR(user->chan->cid.cid_num, "<unknown>"),
04339 S_OR(user->chan->cid.cid_name, "<no name>"),
04340 user->chan->name,
04341 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
04342 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
04343 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
04344 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04345 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
04346 }
04347 }
04348 AST_LIST_UNLOCK(&confs);
04349
04350 astman_append(s,
04351 "Event: MeetmeListComplete\r\n"
04352 "EventList: Complete\r\n"
04353 "ListItems: %d\r\n"
04354 "%s"
04355 "\r\n", total, idText);
04356 return 0;
04357 }
04358
04359 static void *recordthread(void *args)
04360 {
04361 struct ast_conference *cnf = args;
04362 struct ast_frame *f = NULL;
04363 int flags;
04364 struct ast_filestream *s = NULL;
04365 int res = 0;
04366 int x;
04367 const char *oldrecordingfilename = NULL;
04368
04369 if (!cnf || !cnf->lchan) {
04370 pthread_exit(0);
04371 }
04372
04373 ast_stopstream(cnf->lchan);
04374 flags = O_CREAT | O_TRUNC | O_WRONLY;
04375
04376
04377 cnf->recording = MEETME_RECORD_ACTIVE;
04378 while (ast_waitfor(cnf->lchan, -1) > -1) {
04379 if (cnf->recording == MEETME_RECORD_TERMINATE) {
04380 AST_LIST_LOCK(&confs);
04381 AST_LIST_UNLOCK(&confs);
04382 break;
04383 }
04384 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
04385 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04386 oldrecordingfilename = cnf->recordingfilename;
04387 }
04388
04389 f = ast_read(cnf->lchan);
04390 if (!f) {
04391 res = -1;
04392 break;
04393 }
04394 if (f->frametype == AST_FRAME_VOICE) {
04395 ast_mutex_lock(&cnf->listenlock);
04396 for (x = 0; x < AST_FRAME_BITS; x++) {
04397
04398 if (cnf->transframe[x]) {
04399 ast_frfree(cnf->transframe[x]);
04400 cnf->transframe[x] = NULL;
04401 }
04402 }
04403 if (cnf->origframe)
04404 ast_frfree(cnf->origframe);
04405 cnf->origframe = ast_frdup(f);
04406 ast_mutex_unlock(&cnf->listenlock);
04407 if (s)
04408 res = ast_writestream(s, f);
04409 if (res) {
04410 ast_frfree(f);
04411 break;
04412 }
04413 }
04414 ast_frfree(f);
04415 }
04416 cnf->recording = MEETME_RECORD_OFF;
04417 if (s)
04418 ast_closestream(s);
04419
04420 pthread_exit(0);
04421 }
04422
04423
04424 static enum ast_device_state meetmestate(const char *data)
04425 {
04426 struct ast_conference *conf;
04427
04428
04429 AST_LIST_LOCK(&confs);
04430 AST_LIST_TRAVERSE(&confs, conf, list) {
04431 if (!strcmp(data, conf->confno))
04432 break;
04433 }
04434 AST_LIST_UNLOCK(&confs);
04435 if (!conf)
04436 return AST_DEVICE_INVALID;
04437
04438
04439
04440 if (!conf->users)
04441 return AST_DEVICE_NOT_INUSE;
04442
04443 return AST_DEVICE_INUSE;
04444 }
04445
04446 static void load_config_meetme(void)
04447 {
04448 struct ast_config *cfg;
04449 struct ast_flags config_flags = { 0 };
04450 const char *val;
04451
04452 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
04453 return;
04454 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04455 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
04456 return;
04457 }
04458
04459 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04460
04461
04462 rt_schedule = 0;
04463 fuzzystart = 0;
04464 earlyalert = 0;
04465 endalert = 0;
04466 extendby = 0;
04467
04468
04469 rt_log_members = 1;
04470
04471 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
04472 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
04473 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
04474 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04475 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
04476 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
04477 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
04478 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04479 }
04480 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
04481 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
04482 }
04483
04484 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
04485 rt_schedule = ast_true(val);
04486 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
04487 rt_log_members = ast_true(val);
04488 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
04489 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
04490 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
04491 fuzzystart = 0;
04492 }
04493 }
04494 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
04495 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
04496 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
04497 earlyalert = 0;
04498 }
04499 }
04500 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
04501 if ((sscanf(val, "%30d", &endalert) != 1)) {
04502 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
04503 endalert = 0;
04504 }
04505 }
04506 if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
04507 if ((sscanf(val, "%30d", &extendby) != 1)) {
04508 ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
04509 extendby = 0;
04510 }
04511 }
04512
04513 ast_config_destroy(cfg);
04514 }
04515
04516
04517
04518
04519 static struct sla_trunk *sla_find_trunk(const char *name)
04520 {
04521 struct sla_trunk *trunk = NULL;
04522
04523 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04524 if (!strcasecmp(trunk->name, name))
04525 break;
04526 }
04527
04528 return trunk;
04529 }
04530
04531
04532
04533
04534 static struct sla_station *sla_find_station(const char *name)
04535 {
04536 struct sla_station *station = NULL;
04537
04538 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04539 if (!strcasecmp(station->name, name))
04540 break;
04541 }
04542
04543 return station;
04544 }
04545
04546 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
04547 const struct sla_station *station)
04548 {
04549 struct sla_station_ref *station_ref;
04550 struct sla_trunk_ref *trunk_ref;
04551
04552
04553 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04554 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04555 if (trunk_ref->trunk != trunk || station_ref->station == station)
04556 continue;
04557 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04558 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04559 return 1;
04560 return 0;
04561 }
04562 }
04563
04564 return 0;
04565 }
04566
04567
04568
04569
04570
04571
04572
04573
04574 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
04575 const char *name)
04576 {
04577 struct sla_trunk_ref *trunk_ref = NULL;
04578
04579 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04580 if (strcasecmp(trunk_ref->trunk->name, name))
04581 continue;
04582
04583 if ( (trunk_ref->trunk->barge_disabled
04584 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04585 (trunk_ref->trunk->hold_stations
04586 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04587 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04588 sla_check_station_hold_access(trunk_ref->trunk, station) )
04589 {
04590 trunk_ref = NULL;
04591 }
04592
04593 break;
04594 }
04595
04596 return trunk_ref;
04597 }
04598
04599 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
04600 {
04601 struct sla_station_ref *station_ref;
04602
04603 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04604 return NULL;
04605
04606 station_ref->station = station;
04607
04608 return station_ref;
04609 }
04610
04611 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
04612 {
04613 struct sla_ringing_station *ringing_station;
04614
04615 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04616 return NULL;
04617
04618 ringing_station->station = station;
04619 ringing_station->ring_begin = ast_tvnow();
04620
04621 return ringing_station;
04622 }
04623
04624 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
04625 {
04626 switch (state) {
04627 case SLA_TRUNK_STATE_IDLE:
04628 return AST_DEVICE_NOT_INUSE;
04629 case SLA_TRUNK_STATE_RINGING:
04630 return AST_DEVICE_RINGING;
04631 case SLA_TRUNK_STATE_UP:
04632 return AST_DEVICE_INUSE;
04633 case SLA_TRUNK_STATE_ONHOLD:
04634 case SLA_TRUNK_STATE_ONHOLD_BYME:
04635 return AST_DEVICE_ONHOLD;
04636 }
04637
04638 return AST_DEVICE_UNKNOWN;
04639 }
04640
04641 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
04642 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
04643 {
04644 struct sla_station *station;
04645 struct sla_trunk_ref *trunk_ref;
04646
04647 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04648 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04649 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04650 || trunk_ref == exclude)
04651 continue;
04652 trunk_ref->state = state;
04653 ast_devstate_changed(sla_state_to_devstate(state),
04654 "SLA:%s_%s", station->name, trunk->name);
04655 break;
04656 }
04657 }
04658 }
04659
04660 struct run_station_args {
04661 struct sla_station *station;
04662 struct sla_trunk_ref *trunk_ref;
04663 ast_mutex_t *cond_lock;
04664 ast_cond_t *cond;
04665 };
04666
04667 static void answer_trunk_chan(struct ast_channel *chan)
04668 {
04669 ast_answer(chan);
04670 ast_indicate(chan, -1);
04671 }
04672
04673 static void *run_station(void *data)
04674 {
04675 struct sla_station *station;
04676 struct sla_trunk_ref *trunk_ref;
04677 struct ast_str *conf_name = ast_str_create(16);
04678 struct ast_flags conf_flags = { 0 };
04679 struct ast_conference *conf;
04680
04681 {
04682 struct run_station_args *args = data;
04683 station = args->station;
04684 trunk_ref = args->trunk_ref;
04685 ast_mutex_lock(args->cond_lock);
04686 ast_cond_signal(args->cond);
04687 ast_mutex_unlock(args->cond_lock);
04688
04689 }
04690
04691 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04692 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04693 ast_set_flag(&conf_flags,
04694 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04695 answer_trunk_chan(trunk_ref->chan);
04696 conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
04697 if (conf) {
04698 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04699 dispose_conf(conf);
04700 conf = NULL;
04701 }
04702 trunk_ref->chan = NULL;
04703 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04704 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04705 ast_str_append(&conf_name, 0, ",K");
04706 admin_exec(NULL, ast_str_buffer(conf_name));
04707 trunk_ref->trunk->hold_stations = 0;
04708 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04709 }
04710
04711 ast_dial_join(station->dial);
04712 ast_dial_destroy(station->dial);
04713 station->dial = NULL;
04714 ast_free(conf_name);
04715
04716 return NULL;
04717 }
04718
04719 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
04720 {
04721 char buf[80];
04722 struct sla_station_ref *station_ref;
04723
04724 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04725 admin_exec(NULL, buf);
04726 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04727
04728 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04729 ast_free(station_ref);
04730
04731 ast_free(ringing_trunk);
04732 }
04733
04734 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
04735 enum sla_station_hangup hangup)
04736 {
04737 struct sla_ringing_trunk *ringing_trunk;
04738 struct sla_trunk_ref *trunk_ref;
04739 struct sla_station_ref *station_ref;
04740
04741 ast_dial_join(ringing_station->station->dial);
04742 ast_dial_destroy(ringing_station->station->dial);
04743 ringing_station->station->dial = NULL;
04744
04745 if (hangup == SLA_STATION_HANGUP_NORMAL)
04746 goto done;
04747
04748
04749
04750
04751
04752
04753 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04754 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04755 if (ringing_trunk->trunk == trunk_ref->trunk)
04756 break;
04757 }
04758 if (!trunk_ref)
04759 continue;
04760 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04761 continue;
04762 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04763 }
04764
04765 done:
04766 ast_free(ringing_station);
04767 }
04768
04769 static void sla_dial_state_callback(struct ast_dial *dial)
04770 {
04771 sla_queue_event(SLA_EVENT_DIAL_STATE);
04772 }
04773
04774
04775
04776
04777 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
04778 const struct sla_station *station)
04779 {
04780 struct sla_station_ref *timed_out_station;
04781
04782 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04783 if (station == timed_out_station->station)
04784 return 1;
04785 }
04786
04787 return 0;
04788 }
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
04799 struct sla_trunk_ref **trunk_ref, int rm)
04800 {
04801 struct sla_trunk_ref *s_trunk_ref;
04802 struct sla_ringing_trunk *ringing_trunk = NULL;
04803
04804 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04805 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04806
04807 if (s_trunk_ref->trunk != ringing_trunk->trunk)
04808 continue;
04809
04810
04811
04812 if (sla_check_timed_out_station(ringing_trunk, station))
04813 continue;
04814
04815 if (rm)
04816 AST_LIST_REMOVE_CURRENT(entry);
04817
04818 if (trunk_ref)
04819 *trunk_ref = s_trunk_ref;
04820
04821 break;
04822 }
04823 AST_LIST_TRAVERSE_SAFE_END;
04824
04825 if (ringing_trunk)
04826 break;
04827 }
04828
04829 return ringing_trunk;
04830 }
04831
04832 static void sla_handle_dial_state_event(void)
04833 {
04834 struct sla_ringing_station *ringing_station;
04835
04836 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04837 struct sla_trunk_ref *s_trunk_ref = NULL;
04838 struct sla_ringing_trunk *ringing_trunk = NULL;
04839 struct run_station_args args;
04840 enum ast_dial_result dial_res;
04841 pthread_t dont_care;
04842 ast_mutex_t cond_lock;
04843 ast_cond_t cond;
04844
04845 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04846 case AST_DIAL_RESULT_HANGUP:
04847 case AST_DIAL_RESULT_INVALID:
04848 case AST_DIAL_RESULT_FAILED:
04849 case AST_DIAL_RESULT_TIMEOUT:
04850 case AST_DIAL_RESULT_UNANSWERED:
04851 AST_LIST_REMOVE_CURRENT(entry);
04852 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04853 break;
04854 case AST_DIAL_RESULT_ANSWERED:
04855 AST_LIST_REMOVE_CURRENT(entry);
04856
04857 ast_mutex_lock(&sla.lock);
04858 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04859 ast_mutex_unlock(&sla.lock);
04860 if (!ringing_trunk) {
04861 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04862 break;
04863 }
04864
04865 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04866
04867 answer_trunk_chan(ringing_trunk->trunk->chan);
04868 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04869
04870
04871
04872 args.trunk_ref = s_trunk_ref;
04873 args.station = ringing_station->station;
04874 args.cond = &cond;
04875 args.cond_lock = &cond_lock;
04876 ast_free(ringing_trunk);
04877 ast_free(ringing_station);
04878 ast_mutex_init(&cond_lock);
04879 ast_cond_init(&cond, NULL);
04880 ast_mutex_lock(&cond_lock);
04881 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04882 ast_cond_wait(&cond, &cond_lock);
04883 ast_mutex_unlock(&cond_lock);
04884 ast_mutex_destroy(&cond_lock);
04885 ast_cond_destroy(&cond);
04886 break;
04887 case AST_DIAL_RESULT_TRYING:
04888 case AST_DIAL_RESULT_RINGING:
04889 case AST_DIAL_RESULT_PROGRESS:
04890 case AST_DIAL_RESULT_PROCEEDING:
04891 break;
04892 }
04893 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04894
04895 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04896 sla_queue_event(SLA_EVENT_DIAL_STATE);
04897 break;
04898 }
04899 }
04900 AST_LIST_TRAVERSE_SAFE_END;
04901 }
04902
04903
04904
04905
04906 static int sla_check_ringing_station(const struct sla_station *station)
04907 {
04908 struct sla_ringing_station *ringing_station;
04909
04910 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04911 if (station == ringing_station->station)
04912 return 1;
04913 }
04914
04915 return 0;
04916 }
04917
04918
04919
04920
04921 static int sla_check_failed_station(const struct sla_station *station)
04922 {
04923 struct sla_failed_station *failed_station;
04924 int res = 0;
04925
04926 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04927 if (station != failed_station->station)
04928 continue;
04929 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04930 AST_LIST_REMOVE_CURRENT(entry);
04931 ast_free(failed_station);
04932 break;
04933 }
04934 res = 1;
04935 }
04936 AST_LIST_TRAVERSE_SAFE_END
04937
04938 return res;
04939 }
04940
04941
04942
04943
04944 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
04945 {
04946 char *tech, *tech_data;
04947 struct ast_dial *dial;
04948 struct sla_ringing_station *ringing_station;
04949 const char *cid_name = NULL, *cid_num = NULL;
04950 enum ast_dial_result res;
04951
04952 if (!(dial = ast_dial_create()))
04953 return -1;
04954
04955 ast_dial_set_state_callback(dial, sla_dial_state_callback);
04956 tech_data = ast_strdupa(station->device);
04957 tech = strsep(&tech_data, "/");
04958
04959 if (ast_dial_append(dial, tech, tech_data) == -1) {
04960 ast_dial_destroy(dial);
04961 return -1;
04962 }
04963
04964 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04965 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04966 ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04967 ringing_trunk->trunk->chan->cid.cid_name = NULL;
04968 }
04969 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04970 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04971 ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04972 ringing_trunk->trunk->chan->cid.cid_num = NULL;
04973 }
04974
04975 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04976
04977 if (cid_name)
04978 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04979 if (cid_num)
04980 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04981
04982 if (res != AST_DIAL_RESULT_TRYING) {
04983 struct sla_failed_station *failed_station;
04984 ast_dial_destroy(dial);
04985 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04986 return -1;
04987 failed_station->station = station;
04988 failed_station->last_try = ast_tvnow();
04989 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04990 return -1;
04991 }
04992 if (!(ringing_station = sla_create_ringing_station(station))) {
04993 ast_dial_join(dial);
04994 ast_dial_destroy(dial);
04995 return -1;
04996 }
04997
04998 station->dial = dial;
04999
05000 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05001
05002 return 0;
05003 }
05004
05005
05006
05007 static int sla_check_inuse_station(const struct sla_station *station)
05008 {
05009 struct sla_trunk_ref *trunk_ref;
05010
05011 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05012 if (trunk_ref->chan)
05013 return 1;
05014 }
05015
05016 return 0;
05017 }
05018
05019 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
05020 const struct sla_trunk *trunk)
05021 {
05022 struct sla_trunk_ref *trunk_ref = NULL;
05023
05024 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05025 if (trunk_ref->trunk == trunk)
05026 break;
05027 }
05028
05029 return trunk_ref;
05030 }
05031
05032
05033
05034
05035
05036
05037 static int sla_check_station_delay(struct sla_station *station,
05038 struct sla_ringing_trunk *ringing_trunk)
05039 {
05040 struct sla_trunk_ref *trunk_ref;
05041 unsigned int delay = UINT_MAX;
05042 int time_left, time_elapsed;
05043
05044 if (!ringing_trunk)
05045 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05046 else
05047 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05048
05049 if (!ringing_trunk || !trunk_ref)
05050 return delay;
05051
05052
05053
05054
05055 delay = trunk_ref->ring_delay;
05056 if (!delay)
05057 delay = station->ring_delay;
05058 if (!delay)
05059 return INT_MAX;
05060
05061 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05062 time_left = (delay * 1000) - time_elapsed;
05063
05064 return time_left;
05065 }
05066
05067
05068
05069
05070 static void sla_ring_stations(void)
05071 {
05072 struct sla_station_ref *station_ref;
05073 struct sla_ringing_trunk *ringing_trunk;
05074
05075
05076
05077 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05078 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05079 int time_left;
05080
05081
05082 if (sla_check_ringing_station(station_ref->station))
05083 continue;
05084
05085
05086 if (sla_check_inuse_station(station_ref->station))
05087 continue;
05088
05089
05090
05091 if (sla_check_failed_station(station_ref->station))
05092 continue;
05093
05094
05095
05096 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05097 continue;
05098
05099
05100 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05101 if (time_left != INT_MAX && time_left > 0)
05102 continue;
05103
05104
05105 sla_ring_station(ringing_trunk, station_ref->station);
05106 }
05107 }
05108
05109 }
05110
05111 static void sla_hangup_stations(void)
05112 {
05113 struct sla_trunk_ref *trunk_ref;
05114 struct sla_ringing_station *ringing_station;
05115
05116 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05117 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05118 struct sla_ringing_trunk *ringing_trunk;
05119 ast_mutex_lock(&sla.lock);
05120 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05121 if (trunk_ref->trunk == ringing_trunk->trunk)
05122 break;
05123 }
05124 ast_mutex_unlock(&sla.lock);
05125 if (ringing_trunk)
05126 break;
05127 }
05128 if (!trunk_ref) {
05129 AST_LIST_REMOVE_CURRENT(entry);
05130 ast_dial_join(ringing_station->station->dial);
05131 ast_dial_destroy(ringing_station->station->dial);
05132 ringing_station->station->dial = NULL;
05133 ast_free(ringing_station);
05134 }
05135 }
05136 AST_LIST_TRAVERSE_SAFE_END
05137 }
05138
05139 static void sla_handle_ringing_trunk_event(void)
05140 {
05141 ast_mutex_lock(&sla.lock);
05142 sla_ring_stations();
05143 ast_mutex_unlock(&sla.lock);
05144
05145
05146 sla_hangup_stations();
05147 }
05148
05149 static void sla_handle_hold_event(struct sla_event *event)
05150 {
05151 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05152 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05153 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s",
05154 event->station->name, event->trunk_ref->trunk->name);
05155 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
05156 INACTIVE_TRUNK_REFS, event->trunk_ref);
05157
05158 if (event->trunk_ref->trunk->active_stations == 1) {
05159
05160
05161 event->trunk_ref->trunk->on_hold = 1;
05162 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05163 }
05164
05165 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05166 event->trunk_ref->chan = NULL;
05167 }
05168
05169
05170
05171
05172
05173 static int sla_calc_trunk_timeouts(unsigned int *timeout)
05174 {
05175 struct sla_ringing_trunk *ringing_trunk;
05176 int res = 0;
05177
05178 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05179 int time_left, time_elapsed;
05180 if (!ringing_trunk->trunk->ring_timeout)
05181 continue;
05182 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05183 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05184 if (time_left <= 0) {
05185 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05186 AST_LIST_REMOVE_CURRENT(entry);
05187 sla_stop_ringing_trunk(ringing_trunk);
05188 res = 1;
05189 continue;
05190 }
05191 if (time_left < *timeout)
05192 *timeout = time_left;
05193 }
05194 AST_LIST_TRAVERSE_SAFE_END;
05195
05196 return res;
05197 }
05198
05199
05200
05201
05202
05203 static int sla_calc_station_timeouts(unsigned int *timeout)
05204 {
05205 struct sla_ringing_trunk *ringing_trunk;
05206 struct sla_ringing_station *ringing_station;
05207 int res = 0;
05208
05209 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05210 unsigned int ring_timeout = 0;
05211 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05212 struct sla_trunk_ref *trunk_ref;
05213
05214
05215
05216
05217 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05218 struct sla_station_ref *station_ref;
05219 int trunk_time_elapsed, trunk_time_left;
05220
05221 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05222 if (ringing_trunk->trunk == trunk_ref->trunk)
05223 break;
05224 }
05225 if (!ringing_trunk)
05226 continue;
05227
05228
05229
05230 if (!trunk_ref->ring_timeout)
05231 break;
05232
05233
05234
05235
05236 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05237 if (station_ref->station == ringing_station->station)
05238 break;
05239 }
05240 if (station_ref)
05241 continue;
05242
05243 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05244 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05245 if (trunk_time_left > final_trunk_time_left)
05246 final_trunk_time_left = trunk_time_left;
05247 }
05248
05249
05250 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05251 continue;
05252
05253
05254 if (ringing_station->station->ring_timeout) {
05255 ring_timeout = ringing_station->station->ring_timeout;
05256 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05257 time_left = (ring_timeout * 1000) - time_elapsed;
05258 }
05259
05260
05261
05262 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05263 time_left = final_trunk_time_left;
05264
05265
05266 if (time_left <= 0) {
05267 AST_LIST_REMOVE_CURRENT(entry);
05268 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05269 res = 1;
05270 continue;
05271 }
05272
05273
05274
05275 if (time_left < *timeout)
05276 *timeout = time_left;
05277 }
05278 AST_LIST_TRAVERSE_SAFE_END;
05279
05280 return res;
05281 }
05282
05283
05284
05285
05286 static int sla_calc_station_delays(unsigned int *timeout)
05287 {
05288 struct sla_station *station;
05289 int res = 0;
05290
05291 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05292 struct sla_ringing_trunk *ringing_trunk;
05293 int time_left;
05294
05295
05296 if (sla_check_ringing_station(station))
05297 continue;
05298
05299
05300 if (sla_check_inuse_station(station))
05301 continue;
05302
05303
05304 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05305 continue;
05306
05307 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05308 continue;
05309
05310
05311
05312
05313 if (time_left <= 0) {
05314 res = 1;
05315 continue;
05316 }
05317
05318 if (time_left < *timeout)
05319 *timeout = time_left;
05320 }
05321
05322 return res;
05323 }
05324
05325
05326
05327 static int sla_process_timers(struct timespec *ts)
05328 {
05329 unsigned int timeout = UINT_MAX;
05330 struct timeval wait;
05331 unsigned int change_made = 0;
05332
05333
05334 if (sla_calc_trunk_timeouts(&timeout))
05335 change_made = 1;
05336
05337
05338 if (sla_calc_station_timeouts(&timeout))
05339 change_made = 1;
05340
05341
05342 if (sla_calc_station_delays(&timeout))
05343 change_made = 1;
05344
05345
05346 if (change_made)
05347 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05348
05349
05350 if (timeout == UINT_MAX)
05351 return 0;
05352
05353 if (ts) {
05354 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05355 ts->tv_sec = wait.tv_sec;
05356 ts->tv_nsec = wait.tv_usec * 1000;
05357 }
05358
05359 return 1;
05360 }
05361
05362 static int sla_load_config(int reload);
05363
05364
05365 static void sla_check_reload(void)
05366 {
05367 struct sla_station *station;
05368 struct sla_trunk *trunk;
05369
05370 ast_mutex_lock(&sla.lock);
05371
05372 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
05373 || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05374 ast_mutex_unlock(&sla.lock);
05375 return;
05376 }
05377
05378 AST_RWLIST_RDLOCK(&sla_stations);
05379 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05380 if (station->ref_count)
05381 break;
05382 }
05383 AST_RWLIST_UNLOCK(&sla_stations);
05384 if (station) {
05385 ast_mutex_unlock(&sla.lock);
05386 return;
05387 }
05388
05389 AST_RWLIST_RDLOCK(&sla_trunks);
05390 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05391 if (trunk->ref_count)
05392 break;
05393 }
05394 AST_RWLIST_UNLOCK(&sla_trunks);
05395 if (trunk) {
05396 ast_mutex_unlock(&sla.lock);
05397 return;
05398 }
05399
05400
05401 sla_load_config(1);
05402 sla.reload = 0;
05403
05404 ast_mutex_unlock(&sla.lock);
05405 }
05406
05407 static void *sla_thread(void *data)
05408 {
05409 struct sla_failed_station *failed_station;
05410 struct sla_ringing_station *ringing_station;
05411
05412 ast_mutex_lock(&sla.lock);
05413
05414 while (!sla.stop) {
05415 struct sla_event *event;
05416 struct timespec ts = { 0, };
05417 unsigned int have_timeout = 0;
05418
05419 if (AST_LIST_EMPTY(&sla.event_q)) {
05420 if ((have_timeout = sla_process_timers(&ts)))
05421 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05422 else
05423 ast_cond_wait(&sla.cond, &sla.lock);
05424 if (sla.stop)
05425 break;
05426 }
05427
05428 if (have_timeout)
05429 sla_process_timers(NULL);
05430
05431 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05432 ast_mutex_unlock(&sla.lock);
05433 switch (event->type) {
05434 case SLA_EVENT_HOLD:
05435 sla_handle_hold_event(event);
05436 break;
05437 case SLA_EVENT_DIAL_STATE:
05438 sla_handle_dial_state_event();
05439 break;
05440 case SLA_EVENT_RINGING_TRUNK:
05441 sla_handle_ringing_trunk_event();
05442 break;
05443 case SLA_EVENT_RELOAD:
05444 sla.reload = 1;
05445 case SLA_EVENT_CHECK_RELOAD:
05446 break;
05447 }
05448 ast_free(event);
05449 ast_mutex_lock(&sla.lock);
05450 }
05451
05452 if (sla.reload)
05453 sla_check_reload();
05454 }
05455
05456 ast_mutex_unlock(&sla.lock);
05457
05458 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
05459 ast_free(ringing_station);
05460
05461 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
05462 ast_free(failed_station);
05463
05464 return NULL;
05465 }
05466
05467 struct dial_trunk_args {
05468 struct sla_trunk_ref *trunk_ref;
05469 struct sla_station *station;
05470 ast_mutex_t *cond_lock;
05471 ast_cond_t *cond;
05472 };
05473
05474 static void *dial_trunk(void *data)
05475 {
05476 struct dial_trunk_args *args = data;
05477 struct ast_dial *dial;
05478 char *tech, *tech_data;
05479 enum ast_dial_result dial_res;
05480 char conf_name[MAX_CONFNUM];
05481 struct ast_conference *conf;
05482 struct ast_flags conf_flags = { 0 };
05483 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
05484 const char *cid_name = NULL, *cid_num = NULL;
05485
05486 if (!(dial = ast_dial_create())) {
05487 ast_mutex_lock(args->cond_lock);
05488 ast_cond_signal(args->cond);
05489 ast_mutex_unlock(args->cond_lock);
05490 return NULL;
05491 }
05492
05493 tech_data = ast_strdupa(trunk_ref->trunk->device);
05494 tech = strsep(&tech_data, "/");
05495 if (ast_dial_append(dial, tech, tech_data) == -1) {
05496 ast_mutex_lock(args->cond_lock);
05497 ast_cond_signal(args->cond);
05498 ast_mutex_unlock(args->cond_lock);
05499 ast_dial_destroy(dial);
05500 return NULL;
05501 }
05502
05503 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
05504 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
05505 ast_free(trunk_ref->chan->cid.cid_name);
05506 trunk_ref->chan->cid.cid_name = NULL;
05507 }
05508 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
05509 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
05510 ast_free(trunk_ref->chan->cid.cid_num);
05511 trunk_ref->chan->cid.cid_num = NULL;
05512 }
05513
05514 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
05515
05516 if (cid_name)
05517 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
05518 if (cid_num)
05519 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
05520
05521 if (dial_res != AST_DIAL_RESULT_TRYING) {
05522 ast_mutex_lock(args->cond_lock);
05523 ast_cond_signal(args->cond);
05524 ast_mutex_unlock(args->cond_lock);
05525 ast_dial_destroy(dial);
05526 return NULL;
05527 }
05528
05529 for (;;) {
05530 unsigned int done = 0;
05531 switch ((dial_res = ast_dial_state(dial))) {
05532 case AST_DIAL_RESULT_ANSWERED:
05533 trunk_ref->trunk->chan = ast_dial_answered(dial);
05534 case AST_DIAL_RESULT_HANGUP:
05535 case AST_DIAL_RESULT_INVALID:
05536 case AST_DIAL_RESULT_FAILED:
05537 case AST_DIAL_RESULT_TIMEOUT:
05538 case AST_DIAL_RESULT_UNANSWERED:
05539 done = 1;
05540 case AST_DIAL_RESULT_TRYING:
05541 case AST_DIAL_RESULT_RINGING:
05542 case AST_DIAL_RESULT_PROGRESS:
05543 case AST_DIAL_RESULT_PROCEEDING:
05544 break;
05545 }
05546 if (done)
05547 break;
05548 }
05549
05550 if (!trunk_ref->trunk->chan) {
05551 ast_mutex_lock(args->cond_lock);
05552 ast_cond_signal(args->cond);
05553 ast_mutex_unlock(args->cond_lock);
05554 ast_dial_join(dial);
05555 ast_dial_destroy(dial);
05556 return NULL;
05557 }
05558
05559 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05560 ast_set_flag(&conf_flags,
05561 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
05562 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05563 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05564
05565 ast_mutex_lock(args->cond_lock);
05566 ast_cond_signal(args->cond);
05567 ast_mutex_unlock(args->cond_lock);
05568
05569 if (conf) {
05570 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05571 dispose_conf(conf);
05572 conf = NULL;
05573 }
05574
05575
05576 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05577
05578 trunk_ref->trunk->chan = NULL;
05579 trunk_ref->trunk->on_hold = 0;
05580
05581 ast_dial_join(dial);
05582 ast_dial_destroy(dial);
05583
05584 return NULL;
05585 }
05586
05587
05588
05589 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
05590 {
05591 struct sla_trunk_ref *trunk_ref = NULL;
05592
05593 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05594 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05595 break;
05596 }
05597
05598 return trunk_ref;
05599 }
05600
05601 static int sla_station_exec(struct ast_channel *chan, void *data)
05602 {
05603 char *station_name, *trunk_name;
05604 struct sla_station *station;
05605 struct sla_trunk_ref *trunk_ref = NULL;
05606 char conf_name[MAX_CONFNUM];
05607 struct ast_flags conf_flags = { 0 };
05608 struct ast_conference *conf;
05609
05610 if (ast_strlen_zero(data)) {
05611 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05612 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05613 return 0;
05614 }
05615
05616 trunk_name = ast_strdupa(data);
05617 station_name = strsep(&trunk_name, "_");
05618
05619 if (ast_strlen_zero(station_name)) {
05620 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05621 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05622 return 0;
05623 }
05624
05625 AST_RWLIST_RDLOCK(&sla_stations);
05626 station = sla_find_station(station_name);
05627 if (station)
05628 ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05629 AST_RWLIST_UNLOCK(&sla_stations);
05630
05631 if (!station) {
05632 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05633 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05634 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05635 return 0;
05636 }
05637
05638 AST_RWLIST_RDLOCK(&sla_trunks);
05639 if (!ast_strlen_zero(trunk_name)) {
05640 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05641 } else
05642 trunk_ref = sla_choose_idle_trunk(station);
05643 AST_RWLIST_UNLOCK(&sla_trunks);
05644
05645 if (!trunk_ref) {
05646 if (ast_strlen_zero(trunk_name))
05647 ast_log(LOG_NOTICE, "No trunks available for call.\n");
05648 else {
05649 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05650 "'%s' due to access controls.\n", trunk_name);
05651 }
05652 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05653 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05654 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05655 return 0;
05656 }
05657
05658 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05659 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05660 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05661 else {
05662 trunk_ref->state = SLA_TRUNK_STATE_UP;
05663 ast_devstate_changed(AST_DEVICE_INUSE,
05664 "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05665 }
05666 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05667 struct sla_ringing_trunk *ringing_trunk;
05668
05669 ast_mutex_lock(&sla.lock);
05670 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05671 if (ringing_trunk->trunk == trunk_ref->trunk) {
05672 AST_LIST_REMOVE_CURRENT(entry);
05673 break;
05674 }
05675 }
05676 AST_LIST_TRAVERSE_SAFE_END
05677 ast_mutex_unlock(&sla.lock);
05678
05679 if (ringing_trunk) {
05680 answer_trunk_chan(ringing_trunk->trunk->chan);
05681 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05682
05683 free(ringing_trunk);
05684
05685
05686 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05687 sla_queue_event(SLA_EVENT_DIAL_STATE);
05688 }
05689 }
05690
05691 trunk_ref->chan = chan;
05692
05693 if (!trunk_ref->trunk->chan) {
05694 ast_mutex_t cond_lock;
05695 ast_cond_t cond;
05696 pthread_t dont_care;
05697 struct dial_trunk_args args = {
05698 .trunk_ref = trunk_ref,
05699 .station = station,
05700 .cond_lock = &cond_lock,
05701 .cond = &cond,
05702 };
05703 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05704
05705
05706
05707 ast_autoservice_start(chan);
05708 ast_mutex_init(&cond_lock);
05709 ast_cond_init(&cond, NULL);
05710 ast_mutex_lock(&cond_lock);
05711 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05712 ast_cond_wait(&cond, &cond_lock);
05713 ast_mutex_unlock(&cond_lock);
05714 ast_mutex_destroy(&cond_lock);
05715 ast_cond_destroy(&cond);
05716 ast_autoservice_stop(chan);
05717 if (!trunk_ref->trunk->chan) {
05718 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05719 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05720 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05721 trunk_ref->chan = NULL;
05722 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05723 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05724 return 0;
05725 }
05726 }
05727
05728 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05729 trunk_ref->trunk->on_hold) {
05730 trunk_ref->trunk->on_hold = 0;
05731 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05732 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05733 }
05734
05735 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05736 ast_set_flag(&conf_flags,
05737 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05738 ast_answer(chan);
05739 conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05740 if (conf) {
05741 conf_run(chan, conf, conf_flags.flags, NULL);
05742 dispose_conf(conf);
05743 conf = NULL;
05744 }
05745 trunk_ref->chan = NULL;
05746 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05747 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05748 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05749 admin_exec(NULL, conf_name);
05750 trunk_ref->trunk->hold_stations = 0;
05751 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05752 }
05753
05754 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05755
05756 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05757 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05758
05759 return 0;
05760 }
05761
05762 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
05763 {
05764 struct sla_trunk_ref *trunk_ref;
05765
05766 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05767 return NULL;
05768
05769 trunk_ref->trunk = trunk;
05770
05771 return trunk_ref;
05772 }
05773
05774 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
05775 {
05776 struct sla_ringing_trunk *ringing_trunk;
05777
05778 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05779 return NULL;
05780
05781 ringing_trunk->trunk = trunk;
05782 ringing_trunk->ring_begin = ast_tvnow();
05783
05784 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05785
05786 ast_mutex_lock(&sla.lock);
05787 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05788 ast_mutex_unlock(&sla.lock);
05789
05790 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05791
05792 return ringing_trunk;
05793 }
05794
05795 enum {
05796 SLA_TRUNK_OPT_MOH = (1 << 0),
05797 };
05798
05799 enum {
05800 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05801 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05802 };
05803
05804 AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
05805 AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
05806 END_OPTIONS );
05807
05808 static int sla_trunk_exec(struct ast_channel *chan, void *data)
05809 {
05810 char conf_name[MAX_CONFNUM];
05811 struct ast_conference *conf;
05812 struct ast_flags conf_flags = { 0 };
05813 struct sla_trunk *trunk;
05814 struct sla_ringing_trunk *ringing_trunk;
05815 AST_DECLARE_APP_ARGS(args,
05816 AST_APP_ARG(trunk_name);
05817 AST_APP_ARG(options);
05818 );
05819 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05820 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05821 struct ast_flags opt_flags = { 0 };
05822 char *parse;
05823
05824 if (ast_strlen_zero(data)) {
05825 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05826 return -1;
05827 }
05828
05829 parse = ast_strdupa(data);
05830 AST_STANDARD_APP_ARGS(args, parse);
05831 if (args.argc == 2) {
05832 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05833 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05834 return -1;
05835 }
05836 }
05837
05838 AST_RWLIST_RDLOCK(&sla_trunks);
05839 trunk = sla_find_trunk(args.trunk_name);
05840 if (trunk)
05841 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05842 AST_RWLIST_UNLOCK(&sla_trunks);
05843
05844 if (!trunk) {
05845 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05846 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05847 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05848 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05849 return 0;
05850 }
05851
05852 if (trunk->chan) {
05853 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05854 args.trunk_name);
05855 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05856 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05857 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05858 return 0;
05859 }
05860
05861 trunk->chan = chan;
05862
05863 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05864 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05865 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05866 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05867 return 0;
05868 }
05869
05870 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05871 conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05872 if (!conf) {
05873 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05874 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05875 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05876 return 0;
05877 }
05878 ast_set_flag(&conf_flags,
05879 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05880
05881 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05882 ast_indicate(chan, -1);
05883 ast_set_flag(&conf_flags, CONFFLAG_MOH);
05884 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05885 } else
05886 ast_indicate(chan, AST_CONTROL_RINGING);
05887
05888 conf_run(chan, conf, conf_flags.flags, opts);
05889 dispose_conf(conf);
05890 conf = NULL;
05891 trunk->chan = NULL;
05892 trunk->on_hold = 0;
05893
05894 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05895
05896 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05897 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05898
05899
05900 ast_mutex_lock(&sla.lock);
05901 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05902 if (ringing_trunk->trunk == trunk) {
05903 AST_LIST_REMOVE_CURRENT(entry);
05904 break;
05905 }
05906 }
05907 AST_LIST_TRAVERSE_SAFE_END;
05908 ast_mutex_unlock(&sla.lock);
05909 if (ringing_trunk) {
05910 ast_free(ringing_trunk);
05911 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05912
05913
05914 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05915 }
05916
05917 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05918 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05919
05920 return 0;
05921 }
05922
05923 static enum ast_device_state sla_state(const char *data)
05924 {
05925 char *buf, *station_name, *trunk_name;
05926 struct sla_station *station;
05927 struct sla_trunk_ref *trunk_ref;
05928 enum ast_device_state res = AST_DEVICE_INVALID;
05929
05930 trunk_name = buf = ast_strdupa(data);
05931 station_name = strsep(&trunk_name, "_");
05932
05933 AST_RWLIST_RDLOCK(&sla_stations);
05934 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05935 if (strcasecmp(station_name, station->name))
05936 continue;
05937 AST_RWLIST_RDLOCK(&sla_trunks);
05938 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05939 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05940 break;
05941 }
05942 if (!trunk_ref) {
05943 AST_RWLIST_UNLOCK(&sla_trunks);
05944 break;
05945 }
05946 res = sla_state_to_devstate(trunk_ref->state);
05947 AST_RWLIST_UNLOCK(&sla_trunks);
05948 }
05949 AST_RWLIST_UNLOCK(&sla_stations);
05950
05951 if (res == AST_DEVICE_INVALID) {
05952 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05953 trunk_name, station_name);
05954 }
05955
05956 return res;
05957 }
05958
05959 static void destroy_trunk(struct sla_trunk *trunk)
05960 {
05961 struct sla_station_ref *station_ref;
05962
05963 if (!ast_strlen_zero(trunk->autocontext))
05964 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05965
05966 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05967 ast_free(station_ref);
05968
05969 ast_string_field_free_memory(trunk);
05970 ast_free(trunk);
05971 }
05972
05973 static void destroy_station(struct sla_station *station)
05974 {
05975 struct sla_trunk_ref *trunk_ref;
05976
05977 if (!ast_strlen_zero(station->autocontext)) {
05978 AST_RWLIST_RDLOCK(&sla_trunks);
05979 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05980 char exten[AST_MAX_EXTENSION];
05981 char hint[AST_MAX_APP];
05982 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05983 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05984 ast_context_remove_extension(station->autocontext, exten,
05985 1, sla_registrar);
05986 ast_context_remove_extension(station->autocontext, hint,
05987 PRIORITY_HINT, sla_registrar);
05988 }
05989 AST_RWLIST_UNLOCK(&sla_trunks);
05990 }
05991
05992 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05993 ast_free(trunk_ref);
05994
05995 ast_string_field_free_memory(station);
05996 ast_free(station);
05997 }
05998
05999 static void sla_destroy(void)
06000 {
06001 struct sla_trunk *trunk;
06002 struct sla_station *station;
06003
06004 AST_RWLIST_WRLOCK(&sla_trunks);
06005 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06006 destroy_trunk(trunk);
06007 AST_RWLIST_UNLOCK(&sla_trunks);
06008
06009 AST_RWLIST_WRLOCK(&sla_stations);
06010 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06011 destroy_station(station);
06012 AST_RWLIST_UNLOCK(&sla_stations);
06013
06014 if (sla.thread != AST_PTHREADT_NULL) {
06015 ast_mutex_lock(&sla.lock);
06016 sla.stop = 1;
06017 ast_cond_signal(&sla.cond);
06018 ast_mutex_unlock(&sla.lock);
06019 pthread_join(sla.thread, NULL);
06020 }
06021
06022
06023 ast_context_destroy(NULL, sla_registrar);
06024
06025 ast_mutex_destroy(&sla.lock);
06026 ast_cond_destroy(&sla.cond);
06027 }
06028
06029 static int sla_check_device(const char *device)
06030 {
06031 char *tech, *tech_data;
06032
06033 tech_data = ast_strdupa(device);
06034 tech = strsep(&tech_data, "/");
06035
06036 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06037 return -1;
06038
06039 return 0;
06040 }
06041
06042 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
06043 {
06044 struct sla_trunk *trunk;
06045 struct ast_variable *var;
06046 const char *dev;
06047
06048 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06049 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06050 return -1;
06051 }
06052
06053 if (sla_check_device(dev)) {
06054 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06055 cat, dev);
06056 return -1;
06057 }
06058
06059 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
06060 return -1;
06061 if (ast_string_field_init(trunk, 32)) {
06062 ast_free(trunk);
06063 return -1;
06064 }
06065
06066 ast_string_field_set(trunk, name, cat);
06067 ast_string_field_set(trunk, device, dev);
06068
06069 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06070 if (!strcasecmp(var->name, "autocontext"))
06071 ast_string_field_set(trunk, autocontext, var->value);
06072 else if (!strcasecmp(var->name, "ringtimeout")) {
06073 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06074 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06075 var->value, trunk->name);
06076 trunk->ring_timeout = 0;
06077 }
06078 } else if (!strcasecmp(var->name, "barge"))
06079 trunk->barge_disabled = ast_false(var->value);
06080 else if (!strcasecmp(var->name, "hold")) {
06081 if (!strcasecmp(var->value, "private"))
06082 trunk->hold_access = SLA_HOLD_PRIVATE;
06083 else if (!strcasecmp(var->value, "open"))
06084 trunk->hold_access = SLA_HOLD_OPEN;
06085 else {
06086 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06087 var->value, trunk->name);
06088 }
06089 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06090 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06091 var->name, var->lineno, SLA_CONFIG_FILE);
06092 }
06093 }
06094
06095 if (!ast_strlen_zero(trunk->autocontext)) {
06096 struct ast_context *context;
06097 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06098 if (!context) {
06099 ast_log(LOG_ERROR, "Failed to automatically find or create "
06100 "context '%s' for SLA!\n", trunk->autocontext);
06101 destroy_trunk(trunk);
06102 return -1;
06103 }
06104 if (ast_add_extension2(context, 0 , "s", 1,
06105 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06106 ast_log(LOG_ERROR, "Failed to automatically create extension "
06107 "for trunk '%s'!\n", trunk->name);
06108 destroy_trunk(trunk);
06109 return -1;
06110 }
06111 }
06112
06113 AST_RWLIST_WRLOCK(&sla_trunks);
06114 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06115 AST_RWLIST_UNLOCK(&sla_trunks);
06116
06117 return 0;
06118 }
06119
06120 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
06121 {
06122 struct sla_trunk *trunk;
06123 struct sla_trunk_ref *trunk_ref;
06124 struct sla_station_ref *station_ref;
06125 char *trunk_name, *options, *cur;
06126
06127 options = ast_strdupa(var->value);
06128 trunk_name = strsep(&options, ",");
06129
06130 AST_RWLIST_RDLOCK(&sla_trunks);
06131 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06132 if (!strcasecmp(trunk->name, trunk_name))
06133 break;
06134 }
06135
06136 AST_RWLIST_UNLOCK(&sla_trunks);
06137 if (!trunk) {
06138 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06139 return;
06140 }
06141 if (!(trunk_ref = create_trunk_ref(trunk)))
06142 return;
06143 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06144
06145 while ((cur = strsep(&options, ","))) {
06146 char *name, *value = cur;
06147 name = strsep(&value, "=");
06148 if (!strcasecmp(name, "ringtimeout")) {
06149 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06150 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06151 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06152 trunk_ref->ring_timeout = 0;
06153 }
06154 } else if (!strcasecmp(name, "ringdelay")) {
06155 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06156 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06157 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06158 trunk_ref->ring_delay = 0;
06159 }
06160 } else {
06161 ast_log(LOG_WARNING, "Invalid option '%s' for "
06162 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06163 }
06164 }
06165
06166 if (!(station_ref = sla_create_station_ref(station))) {
06167 ast_free(trunk_ref);
06168 return;
06169 }
06170 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06171 AST_RWLIST_WRLOCK(&sla_trunks);
06172 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06173 AST_RWLIST_UNLOCK(&sla_trunks);
06174 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06175 }
06176
06177 static int sla_build_station(struct ast_config *cfg, const char *cat)
06178 {
06179 struct sla_station *station;
06180 struct ast_variable *var;
06181 const char *dev;
06182
06183 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06184 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06185 return -1;
06186 }
06187
06188 if (!(station = ast_calloc(1, sizeof(*station))))
06189 return -1;
06190 if (ast_string_field_init(station, 32)) {
06191 ast_free(station);
06192 return -1;
06193 }
06194
06195 ast_string_field_set(station, name, cat);
06196 ast_string_field_set(station, device, dev);
06197
06198 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06199 if (!strcasecmp(var->name, "trunk"))
06200 sla_add_trunk_to_station(station, var);
06201 else if (!strcasecmp(var->name, "autocontext"))
06202 ast_string_field_set(station, autocontext, var->value);
06203 else if (!strcasecmp(var->name, "ringtimeout")) {
06204 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06205 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06206 var->value, station->name);
06207 station->ring_timeout = 0;
06208 }
06209 } else if (!strcasecmp(var->name, "ringdelay")) {
06210 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06211 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06212 var->value, station->name);
06213 station->ring_delay = 0;
06214 }
06215 } else if (!strcasecmp(var->name, "hold")) {
06216 if (!strcasecmp(var->value, "private"))
06217 station->hold_access = SLA_HOLD_PRIVATE;
06218 else if (!strcasecmp(var->value, "open"))
06219 station->hold_access = SLA_HOLD_OPEN;
06220 else {
06221 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06222 var->value, station->name);
06223 }
06224
06225 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06226 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06227 var->name, var->lineno, SLA_CONFIG_FILE);
06228 }
06229 }
06230
06231 if (!ast_strlen_zero(station->autocontext)) {
06232 struct ast_context *context;
06233 struct sla_trunk_ref *trunk_ref;
06234 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06235 if (!context) {
06236 ast_log(LOG_ERROR, "Failed to automatically find or create "
06237 "context '%s' for SLA!\n", station->autocontext);
06238 destroy_station(station);
06239 return -1;
06240 }
06241
06242
06243 if (ast_add_extension2(context, 0 , station->name, 1,
06244 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06245 ast_log(LOG_ERROR, "Failed to automatically create extension "
06246 "for trunk '%s'!\n", station->name);
06247 destroy_station(station);
06248 return -1;
06249 }
06250 AST_RWLIST_RDLOCK(&sla_trunks);
06251 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06252 char exten[AST_MAX_EXTENSION];
06253 char hint[AST_MAX_APP];
06254 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06255 snprintf(hint, sizeof(hint), "SLA:%s", exten);
06256
06257
06258 if (ast_add_extension2(context, 0 , exten, 1,
06259 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06260 ast_log(LOG_ERROR, "Failed to automatically create extension "
06261 "for trunk '%s'!\n", station->name);
06262 destroy_station(station);
06263 return -1;
06264 }
06265
06266
06267 if (ast_add_extension2(context, 0 , exten, PRIORITY_HINT,
06268 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06269 ast_log(LOG_ERROR, "Failed to automatically create hint "
06270 "for trunk '%s'!\n", station->name);
06271 destroy_station(station);
06272 return -1;
06273 }
06274 }
06275 AST_RWLIST_UNLOCK(&sla_trunks);
06276 }
06277
06278 AST_RWLIST_WRLOCK(&sla_stations);
06279 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06280 AST_RWLIST_UNLOCK(&sla_stations);
06281
06282 return 0;
06283 }
06284
06285 static int sla_load_config(int reload)
06286 {
06287 struct ast_config *cfg;
06288 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06289 const char *cat = NULL;
06290 int res = 0;
06291 const char *val;
06292
06293 if (!reload) {
06294 ast_mutex_init(&sla.lock);
06295 ast_cond_init(&sla.cond, NULL);
06296 }
06297
06298 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06299 return 0;
06300 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06301 return 0;
06302 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06303 ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
06304 return 0;
06305 }
06306
06307 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
06308 sla.attempt_callerid = ast_true(val);
06309
06310 while ((cat = ast_category_browse(cfg, cat)) && !res) {
06311 const char *type;
06312 if (!strcasecmp(cat, "general"))
06313 continue;
06314 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
06315 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
06316 SLA_CONFIG_FILE);
06317 continue;
06318 }
06319 if (!strcasecmp(type, "trunk"))
06320 res = sla_build_trunk(cfg, cat);
06321 else if (!strcasecmp(type, "station"))
06322 res = sla_build_station(cfg, cat);
06323 else {
06324 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
06325 SLA_CONFIG_FILE, type);
06326 }
06327 }
06328
06329 ast_config_destroy(cfg);
06330
06331 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
06332 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
06333
06334 return res;
06335 }
06336
06337 static int acf_meetme_info_eval(char *keyword, struct ast_conference *conf)
06338 {
06339 if (!strcasecmp("lock", keyword)) {
06340 return conf->locked;
06341 } else if (!strcasecmp("parties", keyword)) {
06342 return conf->users;
06343 } else if (!strcasecmp("activity", keyword)) {
06344 time_t now;
06345 now = time(NULL);
06346 return (now - conf->start);
06347 } else if (!strcasecmp("dynamic", keyword)) {
06348 return conf->isdynamic;
06349 } else {
06350 return -1;
06351 }
06352
06353 }
06354
06355 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06356 {
06357 struct ast_conference *conf;
06358 char *parse;
06359 int result = -2;
06360 AST_DECLARE_APP_ARGS(args,
06361 AST_APP_ARG(keyword);
06362 AST_APP_ARG(confno);
06363 );
06364
06365 if (ast_strlen_zero(data)) {
06366 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06367 return -1;
06368 }
06369
06370 parse = ast_strdupa(data);
06371 AST_STANDARD_APP_ARGS(args, parse);
06372
06373 if (ast_strlen_zero(args.keyword)) {
06374 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06375 return -1;
06376 }
06377
06378 if (ast_strlen_zero(args.confno)) {
06379 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06380 return -1;
06381 }
06382
06383 AST_LIST_LOCK(&confs);
06384 AST_LIST_TRAVERSE(&confs, conf, list) {
06385 if (!strcmp(args.confno, conf->confno)) {
06386 result = acf_meetme_info_eval(args.keyword, conf);
06387 break;
06388 }
06389 }
06390 AST_LIST_UNLOCK(&confs);
06391
06392 if (result > -1) {
06393 snprintf(buf, len, "%d", result);
06394 } else if (result == -1) {
06395 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06396 snprintf(buf, len, "0");
06397 } else if (result == -2) {
06398 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
06399 snprintf(buf, len, "0");
06400 }
06401
06402 return 0;
06403 }
06404
06405
06406 static struct ast_custom_function meetme_info_acf = {
06407 .name = "MEETME_INFO",
06408 .synopsis = "Query a given conference of various properties.",
06409 .syntax = "MEETME_INFO(<keyword>,<confno>)",
06410 .read = acf_meetme_info,
06411 .desc =
06412 "Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
06413 " Options:\n"
06414 " lock - boolean of whether the corresponding conference is locked\n"
06415 " parties - number of parties in a given conference\n"
06416 " activity - duration of conference in seconds\n"
06417 " dynamic - boolean of whether the corresponding coference is dynamic\n",
06418 };
06419
06420
06421 static int load_config(int reload)
06422 {
06423 load_config_meetme();
06424
06425 if (reload) {
06426 sla_queue_event(SLA_EVENT_RELOAD);
06427 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06428 "and will be completed when the system is idle.\n");
06429 return 0;
06430 }
06431
06432 return sla_load_config(0);
06433 }
06434
06435 static int unload_module(void)
06436 {
06437 int res = 0;
06438
06439 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06440 res = ast_manager_unregister("MeetmeMute");
06441 res |= ast_manager_unregister("MeetmeUnmute");
06442 res |= ast_manager_unregister("MeetmeList");
06443 res |= ast_unregister_application(app4);
06444 res |= ast_unregister_application(app3);
06445 res |= ast_unregister_application(app2);
06446 res |= ast_unregister_application(app);
06447 res |= ast_unregister_application(slastation_app);
06448 res |= ast_unregister_application(slatrunk_app);
06449
06450 ast_devstate_prov_del("Meetme");
06451 ast_devstate_prov_del("SLA");
06452
06453 sla_destroy();
06454
06455 res |= ast_custom_function_unregister(&meetme_info_acf);
06456 ast_unload_realtime("meetme");
06457
06458 return res;
06459 }
06460
06461 static int load_module(void)
06462 {
06463 int res = 0;
06464
06465 res |= load_config(0);
06466
06467 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06468 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
06469 action_meetmemute, "Mute a Meetme user");
06470 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
06471 action_meetmeunmute, "Unmute a Meetme user");
06472 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING,
06473 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
06474 res |= ast_register_application_xml(app4, channel_admin_exec);
06475 res |= ast_register_application_xml(app3, admin_exec);
06476 res |= ast_register_application_xml(app2, count_exec);
06477 res |= ast_register_application_xml(app, conf_exec);
06478 res |= ast_register_application_xml(slastation_app, sla_station_exec);
06479 res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
06480
06481 res |= ast_devstate_prov_add("Meetme", meetmestate);
06482 res |= ast_devstate_prov_add("SLA", sla_state);
06483
06484 res |= ast_custom_function_register(&meetme_info_acf);
06485 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
06486
06487 return res;
06488 }
06489
06490 static int reload(void)
06491 {
06492 ast_unload_realtime("meetme");
06493 return load_config(1);
06494 }
06495
06496 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
06497 .load = load_module,
06498 .unload = unload_module,
06499 .reload = reload,
06500 );
06501