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: 256020 $")
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
03367 if (rt_schedule) {
03368 pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
03369 }
03370 }
03371 ast_free(user);
03372 AST_LIST_UNLOCK(&confs);
03373
03374 return ret;
03375 }
03376
03377 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
03378 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags, int *too_early)
03379 {
03380 struct ast_variable *var, *origvar;
03381 struct ast_conference *cnf;
03382
03383 *too_early = 0;
03384
03385
03386 AST_LIST_LOCK(&confs);
03387 AST_LIST_TRAVERSE(&confs, cnf, list) {
03388 if (!strcmp(confno, cnf->confno))
03389 break;
03390 }
03391 if (cnf) {
03392 cnf->refcount += refcount;
03393 }
03394 AST_LIST_UNLOCK(&confs);
03395
03396 if (!cnf) {
03397 char *pin = NULL, *pinadmin = NULL;
03398 int maxusers = 0;
03399 struct timeval now;
03400 char recordingfilename[256] = "";
03401 char recordingformat[11] = "";
03402 char currenttime[19] = "";
03403 char eatime[19] = "";
03404 char bookid[51] = "";
03405 char recordingtmp[AST_MAX_EXTENSION] = "";
03406 char useropts[OPTIONS_LEN + 1];
03407 char adminopts[OPTIONS_LEN + 1];
03408 struct ast_tm tm, etm;
03409 struct timeval endtime = { .tv_sec = 0 };
03410 const char *var2;
03411
03412 if (rt_schedule) {
03413 now = ast_tvnow();
03414
03415 ast_localtime(&now, &tm, NULL);
03416 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03417
03418 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
03419
03420 var = ast_load_realtime("meetme", "confno",
03421 confno, "starttime <= ", currenttime, "endtime >= ",
03422 currenttime, NULL);
03423
03424 if (!var && fuzzystart) {
03425 now = ast_tvnow();
03426 now.tv_sec += fuzzystart;
03427
03428 ast_localtime(&now, &tm, NULL);
03429 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
03430 var = ast_load_realtime("meetme", "confno",
03431 confno, "starttime <= ", currenttime, "endtime >= ",
03432 currenttime, NULL);
03433 }
03434
03435 if (!var && earlyalert) {
03436 now = ast_tvnow();
03437 now.tv_sec += earlyalert;
03438 ast_localtime(&now, &etm, NULL);
03439 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
03440 var = ast_load_realtime("meetme", "confno",
03441 confno, "starttime <= ", eatime, "endtime >= ",
03442 currenttime, NULL);
03443 if (var) {
03444 *too_early = 1;
03445 }
03446 }
03447
03448 } else {
03449 var = ast_load_realtime("meetme", "confno", confno, NULL);
03450 }
03451
03452 if (!var)
03453 return NULL;
03454
03455 if (rt_schedule && *too_early) {
03456
03457 if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
03458 ast_waitstream(chan, "");
03459 ast_variables_destroy(var);
03460 return NULL;
03461 }
03462
03463 for (origvar = var; var; var = var->next) {
03464 if (!strcasecmp(var->name, "pin")) {
03465 pin = ast_strdupa(var->value);
03466 } else if (!strcasecmp(var->name, "adminpin")) {
03467 pinadmin = ast_strdupa(var->value);
03468 } else if (!strcasecmp(var->name, "bookId")) {
03469 ast_copy_string(bookid, var->value, sizeof(bookid));
03470 } else if (!strcasecmp(var->name, "opts")) {
03471 ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03472 } else if (!strcasecmp(var->name, "maxusers")) {
03473 maxusers = atoi(var->value);
03474 } else if (!strcasecmp(var->name, "adminopts")) {
03475 ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
03476 } else if (!strcasecmp(var->name, "recordingfilename")) {
03477 ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
03478 } else if (!strcasecmp(var->name, "recordingformat")) {
03479 ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
03480 } else if (!strcasecmp(var->name, "endtime")) {
03481 struct ast_tm endtime_tm;
03482 ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
03483 endtime = ast_mktime(&endtime_tm, NULL);
03484 }
03485 }
03486
03487 ast_variables_destroy(origvar);
03488
03489 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
03490
03491 if (cnf) {
03492 cnf->maxusers = maxusers;
03493 cnf->endalert = endalert;
03494 cnf->endtime = endtime.tv_sec;
03495 cnf->useropts = ast_strdup(useropts);
03496 cnf->adminopts = ast_strdup(adminopts);
03497 cnf->bookid = ast_strdup(bookid);
03498 cnf->recordingfilename = ast_strdup(recordingfilename);
03499 cnf->recordingformat = ast_strdup(recordingformat);
03500
03501 if (strchr(cnf->useropts, 'r')) {
03502 if (ast_strlen_zero(recordingfilename)) {
03503 ast_channel_lock(chan);
03504 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
03505 ast_free(cnf->recordingfilename);
03506 cnf->recordingfilename = ast_strdup(var2);
03507 }
03508 ast_channel_unlock(chan);
03509 if (ast_strlen_zero(cnf->recordingfilename)) {
03510 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, chan->uniqueid);
03511 ast_free(cnf->recordingfilename);
03512 cnf->recordingfilename = ast_strdup(recordingtmp);
03513 }
03514 }
03515 if (ast_strlen_zero(cnf->recordingformat)) {
03516 ast_channel_lock(chan);
03517 if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
03518 ast_free(cnf->recordingformat);
03519 cnf->recordingformat = ast_strdup(var2);
03520 }
03521 ast_channel_unlock(chan);
03522 if (ast_strlen_zero(cnf->recordingformat)) {
03523 ast_free(cnf->recordingformat);
03524 cnf->recordingformat = ast_strdup("wav");
03525 }
03526 }
03527 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03528 }
03529 }
03530 }
03531
03532 if (cnf) {
03533 if (confflags && !cnf->chan &&
03534 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03535 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03536 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03537 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03538 }
03539
03540 if (confflags && !cnf->chan &&
03541 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03542 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03543 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03544 }
03545 }
03546
03547 return cnf;
03548 }
03549
03550
03551 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
03552 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
03553 {
03554 struct ast_config *cfg;
03555 struct ast_variable *var;
03556 struct ast_flags config_flags = { 0 };
03557 struct ast_conference *cnf;
03558
03559 AST_DECLARE_APP_ARGS(args,
03560 AST_APP_ARG(confno);
03561 AST_APP_ARG(pin);
03562 AST_APP_ARG(pinadmin);
03563 );
03564
03565
03566 ast_debug(1, "The requested confno is '%s'?\n", confno);
03567 AST_LIST_LOCK(&confs);
03568 AST_LIST_TRAVERSE(&confs, cnf, list) {
03569 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03570 if (!strcmp(confno, cnf->confno))
03571 break;
03572 }
03573 if (cnf) {
03574 cnf->refcount += refcount;
03575 }
03576 AST_LIST_UNLOCK(&confs);
03577
03578 if (!cnf) {
03579 if (dynamic) {
03580
03581 ast_debug(1, "Building dynamic conference '%s'\n", confno);
03582 if (dynamic_pin) {
03583 if (dynamic_pin[0] == 'q') {
03584
03585 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03586 return NULL;
03587 }
03588 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03589 } else {
03590 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03591 }
03592 } else {
03593
03594 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03595 if (!cfg) {
03596 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03597 return NULL;
03598 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
03599 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
03600 return NULL;
03601 }
03602
03603 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03604 char parse[MAX_SETTINGS];
03605
03606 if (strcasecmp(var->name, "conf"))
03607 continue;
03608
03609 ast_copy_string(parse, var->value, sizeof(parse));
03610
03611 AST_STANDARD_APP_ARGS(args, parse);
03612 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03613 if (!strcasecmp(args.confno, confno)) {
03614
03615 cnf = build_conf(args.confno,
03616 S_OR(args.pin, ""),
03617 S_OR(args.pinadmin, ""),
03618 make, dynamic, refcount, chan);
03619 break;
03620 }
03621 }
03622 if (!var) {
03623 ast_debug(1, "%s isn't a valid conference\n", confno);
03624 }
03625 ast_config_destroy(cfg);
03626 }
03627 } else if (dynamic_pin) {
03628
03629
03630
03631 if (dynamic_pin[0] == 'q') {
03632 dynamic_pin[0] = '\0';
03633 }
03634 }
03635
03636 if (cnf) {
03637 if (confflags && !cnf->chan &&
03638 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03639 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03640 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03641 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03642 }
03643
03644 if (confflags && !cnf->chan &&
03645 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03646 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03647 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03648 }
03649 }
03650
03651 return cnf;
03652 }
03653
03654
03655 static int count_exec(struct ast_channel *chan, void *data)
03656 {
03657 int res = 0;
03658 struct ast_conference *conf;
03659 int count;
03660 char *localdata;
03661 char val[80] = "0";
03662 AST_DECLARE_APP_ARGS(args,
03663 AST_APP_ARG(confno);
03664 AST_APP_ARG(varname);
03665 );
03666
03667 if (ast_strlen_zero(data)) {
03668 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03669 return -1;
03670 }
03671
03672 if (!(localdata = ast_strdupa(data)))
03673 return -1;
03674
03675 AST_STANDARD_APP_ARGS(args, localdata);
03676
03677 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03678
03679 if (conf) {
03680 count = conf->users;
03681 dispose_conf(conf);
03682 conf = NULL;
03683 } else
03684 count = 0;
03685
03686 if (!ast_strlen_zero(args.varname)) {
03687
03688 snprintf(val, sizeof(val), "%d", count);
03689 pbx_builtin_setvar_helper(chan, args.varname, val);
03690 } else {
03691 if (chan->_state != AST_STATE_UP) {
03692 ast_answer(chan);
03693 }
03694 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
03695 }
03696
03697 return res;
03698 }
03699
03700
03701 static int conf_exec(struct ast_channel *chan, void *data)
03702 {
03703 int res = -1;
03704 char confno[MAX_CONFNUM] = "";
03705 int allowretry = 0;
03706 int retrycnt = 0;
03707 struct ast_conference *cnf = NULL;
03708 struct ast_flags confflags = {0}, config_flags = { 0 };
03709 int dynamic = 0;
03710 int empty = 0, empty_no_pin = 0;
03711 int always_prompt = 0;
03712 char *notdata, *info, the_pin[MAX_PIN] = "";
03713 AST_DECLARE_APP_ARGS(args,
03714 AST_APP_ARG(confno);
03715 AST_APP_ARG(options);
03716 AST_APP_ARG(pin);
03717 );
03718 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03719
03720 if (ast_strlen_zero(data)) {
03721 allowretry = 1;
03722 notdata = "";
03723 } else {
03724 notdata = data;
03725 }
03726
03727 if (chan->_state != AST_STATE_UP)
03728 ast_answer(chan);
03729
03730 info = ast_strdupa(notdata);
03731
03732 AST_STANDARD_APP_ARGS(args, info);
03733
03734 if (args.confno) {
03735 ast_copy_string(confno, args.confno, sizeof(confno));
03736 if (ast_strlen_zero(confno)) {
03737 allowretry = 1;
03738 }
03739 }
03740
03741 if (args.pin)
03742 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03743
03744 if (args.options) {
03745 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03746 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03747 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03748 strcpy(the_pin, "q");
03749
03750 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03751 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03752 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03753 }
03754
03755 do {
03756 if (retrycnt > 3)
03757 allowretry = 0;
03758 if (empty) {
03759 int i;
03760 struct ast_config *cfg;
03761 struct ast_variable *var;
03762 int confno_int;
03763
03764
03765 if ((empty_no_pin) || (!dynamic)) {
03766 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03767 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03768 var = ast_variable_browse(cfg, "rooms");
03769 while (var) {
03770 char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
03771 if (!strcasecmp(var->name, "conf")) {
03772 int found = 0;
03773 ast_copy_string(parse, var->value, sizeof(parse));
03774 confno_tmp = strsep(&stringp, "|,");
03775 if (!dynamic) {
03776
03777 AST_LIST_LOCK(&confs);
03778 AST_LIST_TRAVERSE(&confs, cnf, list) {
03779 if (!strcmp(confno_tmp, cnf->confno)) {
03780
03781 found = 1;
03782 break;
03783 }
03784 }
03785 AST_LIST_UNLOCK(&confs);
03786 if (!found) {
03787
03788 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03789
03790
03791
03792
03793 ast_copy_string(confno, confno_tmp, sizeof(confno));
03794 break;
03795
03796 }
03797 }
03798 }
03799 }
03800 var = var->next;
03801 }
03802 ast_config_destroy(cfg);
03803 }
03804 }
03805
03806
03807 if (ast_strlen_zero(confno) && dynamic) {
03808 AST_LIST_LOCK(&confs);
03809 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03810 if (!conf_map[i]) {
03811 snprintf(confno, sizeof(confno), "%d", i);
03812 conf_map[i] = 1;
03813 break;
03814 }
03815 }
03816 AST_LIST_UNLOCK(&confs);
03817 }
03818
03819
03820 if (ast_strlen_zero(confno)) {
03821 res = ast_streamfile(chan, "conf-noempty", chan->language);
03822 if (!res)
03823 ast_waitstream(chan, "");
03824 } else {
03825 if (sscanf(confno, "%30d", &confno_int) == 1) {
03826 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03827 res = ast_streamfile(chan, "conf-enteringno", chan->language);
03828 if (!res) {
03829 ast_waitstream(chan, "");
03830 res = ast_say_digits(chan, confno_int, "", chan->language);
03831 }
03832 }
03833 } else {
03834 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03835 }
03836 }
03837 }
03838
03839 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03840
03841 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03842 if (res < 0) {
03843
03844 confno[0] = '\0';
03845 allowretry = 0;
03846 break;
03847 }
03848 }
03849 if (!ast_strlen_zero(confno)) {
03850
03851 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
03852 sizeof(the_pin), 1, &confflags);
03853 if (!cnf) {
03854 int too_early = 0;
03855
03856 cnf = find_conf_realtime(chan, confno, 1, dynamic,
03857 the_pin, sizeof(the_pin), 1, &confflags,&too_early);
03858 if (rt_schedule && too_early)
03859 allowretry = 0;
03860 }
03861
03862 if (!cnf) {
03863 if (allowretry) {
03864 confno[0] = '\0';
03865 res = ast_streamfile(chan, "conf-invalid", chan->language);
03866 if (!res)
03867 ast_waitstream(chan, "");
03868 res = -1;
03869 }
03870 } else {
03871 if ((!ast_strlen_zero(cnf->pin) &&
03872 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03873 (!ast_strlen_zero(cnf->pinadmin) &&
03874 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03875 char pin[MAX_PIN] = "";
03876 int j;
03877
03878
03879 for (j = 0; j < 3; j++) {
03880 if (*the_pin && (always_prompt == 0)) {
03881 ast_copy_string(pin, the_pin, sizeof(pin));
03882 res = 0;
03883 } else {
03884
03885 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03886 }
03887 if (res >= 0) {
03888 if (!strcasecmp(pin, cnf->pin) ||
03889 (!ast_strlen_zero(cnf->pinadmin) &&
03890 !strcasecmp(pin, cnf->pinadmin))) {
03891
03892 allowretry = 0;
03893 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
03894 if (!ast_strlen_zero(cnf->adminopts)) {
03895 char *opts = ast_strdupa(cnf->adminopts);
03896 ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03897 }
03898 } else {
03899 if (!ast_strlen_zero(cnf->useropts)) {
03900 char *opts = ast_strdupa(cnf->useropts);
03901 ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03902 }
03903 }
03904
03905 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
03906 res = conf_run(chan, cnf, confflags.flags, optargs);
03907 break;
03908 } else {
03909
03910 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03911 res = ast_waitstream(chan, AST_DIGIT_ANY);
03912 ast_stopstream(chan);
03913 } else {
03914 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03915 break;
03916 }
03917 if (res < 0)
03918 break;
03919 pin[0] = res;
03920 pin[1] = '\0';
03921 res = -1;
03922 if (allowretry)
03923 confno[0] = '\0';
03924 }
03925 } else {
03926
03927 res = -1;
03928 allowretry = 0;
03929
03930 break;
03931 }
03932
03933
03934 if (*the_pin && (always_prompt == 0)) {
03935 break;
03936 }
03937 }
03938 } else {
03939
03940 allowretry = 0;
03941
03942
03943
03944
03945 if (!ast_strlen_zero(cnf->useropts)) {
03946 char *opts = ast_strdupa(cnf->useropts);
03947 ast_app_parse_options(meetme_opts, &confflags, optargs, opts);
03948 }
03949
03950
03951 res = conf_run(chan, cnf, confflags.flags, optargs);
03952 }
03953 dispose_conf(cnf);
03954 cnf = NULL;
03955 }
03956 }
03957 } while (allowretry);
03958
03959 if (cnf)
03960 dispose_conf(cnf);
03961
03962 return res;
03963 }
03964
03965 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
03966 {
03967 struct ast_conf_user *user = NULL;
03968 int cid;
03969
03970 sscanf(callerident, "%30i", &cid);
03971 if (conf && callerident) {
03972 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03973 if (cid == user->user_no)
03974 return user;
03975 }
03976 }
03977 return NULL;
03978 }
03979
03980
03981
03982 static int admin_exec(struct ast_channel *chan, void *data) {
03983 char *params;
03984 struct ast_conference *cnf;
03985 struct ast_conf_user *user = NULL;
03986 AST_DECLARE_APP_ARGS(args,
03987 AST_APP_ARG(confno);
03988 AST_APP_ARG(command);
03989 AST_APP_ARG(user);
03990 );
03991 int res = 0;
03992
03993 if (ast_strlen_zero(data)) {
03994 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03995 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
03996 return -1;
03997 }
03998
03999 params = ast_strdupa(data);
04000 AST_STANDARD_APP_ARGS(args, params);
04001
04002 if (!args.command) {
04003 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
04004 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
04005 return -1;
04006 }
04007
04008 AST_LIST_LOCK(&confs);
04009 AST_LIST_TRAVERSE(&confs, cnf, list) {
04010 if (!strcmp(cnf->confno, args.confno))
04011 break;
04012 }
04013
04014 if (!cnf) {
04015 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
04016 AST_LIST_UNLOCK(&confs);
04017 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
04018 return 0;
04019 }
04020
04021 ast_atomic_fetchadd_int(&cnf->refcount, 1);
04022
04023 if (args.user)
04024 user = find_user(cnf, args.user);
04025
04026 switch (*args.command) {
04027 case 76:
04028 cnf->locked = 1;
04029 break;
04030 case 108:
04031 cnf->locked = 0;
04032 break;
04033 case 75:
04034 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
04035 user->adminflags |= ADMINFLAG_KICKME;
04036 break;
04037 case 101:
04038 user = AST_LIST_LAST(&cnf->userlist);
04039 if (!(user->userflags & CONFFLAG_ADMIN))
04040 user->adminflags |= ADMINFLAG_KICKME;
04041 else {
04042 res = -1;
04043 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
04044 }
04045 break;
04046 case 77:
04047 if (user) {
04048 user->adminflags |= ADMINFLAG_MUTED;
04049 } else {
04050 res = -2;
04051 ast_log(LOG_NOTICE, "Specified User not found!\n");
04052 }
04053 break;
04054 case 78:
04055 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04056 if (!(user->userflags & CONFFLAG_ADMIN)) {
04057 user->adminflags |= ADMINFLAG_MUTED;
04058 }
04059 }
04060 break;
04061 case 109:
04062 if (user) {
04063 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04064 } else {
04065 res = -2;
04066 ast_log(LOG_NOTICE, "Specified User not found!\n");
04067 }
04068 break;
04069 case 110:
04070 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04071 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04072 }
04073 break;
04074 case 107:
04075 if (user) {
04076 user->adminflags |= ADMINFLAG_KICKME;
04077 } else {
04078 res = -2;
04079 ast_log(LOG_NOTICE, "Specified User not found!\n");
04080 }
04081 break;
04082 case 118:
04083 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04084 tweak_listen_volume(user, VOL_DOWN);
04085 }
04086 break;
04087 case 86:
04088 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04089 tweak_listen_volume(user, VOL_UP);
04090 }
04091 break;
04092 case 115:
04093 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04094 tweak_talk_volume(user, VOL_DOWN);
04095 }
04096 break;
04097 case 83:
04098 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04099 tweak_talk_volume(user, VOL_UP);
04100 }
04101 break;
04102 case 82:
04103 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04104 reset_volumes(user);
04105 }
04106 break;
04107 case 114:
04108 if (user) {
04109 reset_volumes(user);
04110 } else {
04111 res = -2;
04112 ast_log(LOG_NOTICE, "Specified User not found!\n");
04113 }
04114 break;
04115 case 85:
04116 if (user) {
04117 tweak_listen_volume(user, VOL_UP);
04118 } else {
04119 res = -2;
04120 ast_log(LOG_NOTICE, "Specified User not found!\n");
04121 }
04122 break;
04123 case 117:
04124 if (user) {
04125 tweak_listen_volume(user, VOL_DOWN);
04126 } else {
04127 res = -2;
04128 ast_log(LOG_NOTICE, "Specified User not found!\n");
04129 }
04130 break;
04131 case 84:
04132 if (user) {
04133 tweak_talk_volume(user, VOL_UP);
04134 } else {
04135 res = -2;
04136 ast_log(LOG_NOTICE, "Specified User not found!\n");
04137 }
04138 break;
04139 case 116:
04140 if (user) {
04141 tweak_talk_volume(user, VOL_DOWN);
04142 } else {
04143 res = -2;
04144 ast_log(LOG_NOTICE, "Specified User not found!\n");
04145 }
04146 break;
04147 case 'E':
04148 if (rt_extend_conf(args.confno)) {
04149 res = -1;
04150 }
04151 break;
04152 }
04153
04154 AST_LIST_UNLOCK(&confs);
04155
04156 dispose_conf(cnf);
04157 pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
04158
04159 return 0;
04160 }
04161
04162
04163
04164 static int channel_admin_exec(struct ast_channel *chan, void *data) {
04165 char *params;
04166 struct ast_conference *conf = NULL;
04167 struct ast_conf_user *user = NULL;
04168 AST_DECLARE_APP_ARGS(args,
04169 AST_APP_ARG(channel);
04170 AST_APP_ARG(command);
04171 );
04172
04173 if (ast_strlen_zero(data)) {
04174 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
04175 return -1;
04176 }
04177
04178 params = ast_strdupa(data);
04179 AST_STANDARD_APP_ARGS(args, params);
04180
04181 if (!args.channel) {
04182 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
04183 return -1;
04184 }
04185
04186 if (!args.command) {
04187 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
04188 return -1;
04189 }
04190
04191 AST_LIST_LOCK(&confs);
04192 AST_LIST_TRAVERSE(&confs, conf, list) {
04193 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
04194 if (!strcmp(user->chan->name, args.channel))
04195 break;
04196 }
04197 }
04198
04199 if (!user) {
04200 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
04201 AST_LIST_UNLOCK(&confs);
04202 return 0;
04203 }
04204
04205
04206 switch (*args.command) {
04207 case 77:
04208 user->adminflags |= ADMINFLAG_MUTED;
04209 break;
04210 case 109:
04211 user->adminflags &= ~ADMINFLAG_MUTED;
04212 break;
04213 case 107:
04214 user->adminflags |= ADMINFLAG_KICKME;
04215 break;
04216 default:
04217 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
04218 break;
04219 }
04220
04221 AST_LIST_UNLOCK(&confs);
04222
04223 return 0;
04224 }
04225
04226 static int meetmemute(struct mansession *s, const struct message *m, int mute)
04227 {
04228 struct ast_conference *conf;
04229 struct ast_conf_user *user;
04230 const char *confid = astman_get_header(m, "Meetme");
04231 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
04232 int userno;
04233
04234 if (ast_strlen_zero(confid)) {
04235 astman_send_error(s, m, "Meetme conference not specified");
04236 return 0;
04237 }
04238
04239 if (ast_strlen_zero(userid)) {
04240 astman_send_error(s, m, "Meetme user number not specified");
04241 return 0;
04242 }
04243
04244 userno = strtoul(userid, &userid, 10);
04245
04246 if (*userid) {
04247 astman_send_error(s, m, "Invalid user number");
04248 return 0;
04249 }
04250
04251
04252 AST_LIST_LOCK(&confs);
04253 AST_LIST_TRAVERSE(&confs, conf, list) {
04254 if (!strcmp(confid, conf->confno))
04255 break;
04256 }
04257
04258 if (!conf) {
04259 AST_LIST_UNLOCK(&confs);
04260 astman_send_error(s, m, "Meetme conference does not exist");
04261 return 0;
04262 }
04263
04264 AST_LIST_TRAVERSE(&conf->userlist, user, list)
04265 if (user->user_no == userno)
04266 break;
04267
04268 if (!user) {
04269 AST_LIST_UNLOCK(&confs);
04270 astman_send_error(s, m, "User number not found");
04271 return 0;
04272 }
04273
04274 if (mute)
04275 user->adminflags |= ADMINFLAG_MUTED;
04276 else
04277 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
04278
04279 AST_LIST_UNLOCK(&confs);
04280
04281 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);
04282
04283 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
04284 return 0;
04285 }
04286
04287 static int action_meetmemute(struct mansession *s, const struct message *m)
04288 {
04289 return meetmemute(s, m, 1);
04290 }
04291
04292 static int action_meetmeunmute(struct mansession *s, const struct message *m)
04293 {
04294 return meetmemute(s, m, 0);
04295 }
04296
04297 static char mandescr_meetmelist[] =
04298 "Description: Lists all users in a particular MeetMe conference.\n"
04299 "MeetmeList will follow as separate events, followed by a final event called\n"
04300 "MeetmeListComplete.\n"
04301 "Variables:\n"
04302 " *ActionId: <id>\n"
04303 " *Conference: <confno>\n";
04304
04305 static int action_meetmelist(struct mansession *s, const struct message *m)
04306 {
04307 const char *actionid = astman_get_header(m, "ActionID");
04308 const char *conference = astman_get_header(m, "Conference");
04309 char idText[80] = "";
04310 struct ast_conference *cnf;
04311 struct ast_conf_user *user;
04312 int total = 0;
04313
04314 if (!ast_strlen_zero(actionid))
04315 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
04316
04317 if (AST_LIST_EMPTY(&confs)) {
04318 astman_send_error(s, m, "No active conferences.");
04319 return 0;
04320 }
04321
04322 astman_send_listack(s, m, "Meetme user list will follow", "start");
04323
04324
04325 AST_LIST_LOCK(&confs);
04326 AST_LIST_TRAVERSE(&confs, cnf, list) {
04327
04328 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
04329 continue;
04330
04331
04332 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
04333 total++;
04334 astman_append(s,
04335 "Event: MeetmeList\r\n"
04336 "%s"
04337 "Conference: %s\r\n"
04338 "UserNumber: %d\r\n"
04339 "CallerIDNum: %s\r\n"
04340 "CallerIDName: %s\r\n"
04341 "Channel: %s\r\n"
04342 "Admin: %s\r\n"
04343 "Role: %s\r\n"
04344 "MarkedUser: %s\r\n"
04345 "Muted: %s\r\n"
04346 "Talking: %s\r\n"
04347 "\r\n",
04348 idText,
04349 cnf->confno,
04350 user->user_no,
04351 S_OR(user->chan->cid.cid_num, "<unknown>"),
04352 S_OR(user->chan->cid.cid_name, "<no name>"),
04353 user->chan->name,
04354 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
04355 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
04356 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
04357 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
04358 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
04359 }
04360 }
04361 AST_LIST_UNLOCK(&confs);
04362
04363 astman_append(s,
04364 "Event: MeetmeListComplete\r\n"
04365 "EventList: Complete\r\n"
04366 "ListItems: %d\r\n"
04367 "%s"
04368 "\r\n", total, idText);
04369 return 0;
04370 }
04371
04372 static void *recordthread(void *args)
04373 {
04374 struct ast_conference *cnf = args;
04375 struct ast_frame *f = NULL;
04376 int flags;
04377 struct ast_filestream *s = NULL;
04378 int res = 0;
04379 int x;
04380 const char *oldrecordingfilename = NULL;
04381
04382 if (!cnf || !cnf->lchan) {
04383 pthread_exit(0);
04384 }
04385
04386 ast_stopstream(cnf->lchan);
04387 flags = O_CREAT | O_TRUNC | O_WRONLY;
04388
04389
04390 cnf->recording = MEETME_RECORD_ACTIVE;
04391 while (ast_waitfor(cnf->lchan, -1) > -1) {
04392 if (cnf->recording == MEETME_RECORD_TERMINATE) {
04393 AST_LIST_LOCK(&confs);
04394 AST_LIST_UNLOCK(&confs);
04395 break;
04396 }
04397 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
04398 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
04399 oldrecordingfilename = cnf->recordingfilename;
04400 }
04401
04402 f = ast_read(cnf->lchan);
04403 if (!f) {
04404 res = -1;
04405 break;
04406 }
04407 if (f->frametype == AST_FRAME_VOICE) {
04408 ast_mutex_lock(&cnf->listenlock);
04409 for (x = 0; x < AST_FRAME_BITS; x++) {
04410
04411 if (cnf->transframe[x]) {
04412 ast_frfree(cnf->transframe[x]);
04413 cnf->transframe[x] = NULL;
04414 }
04415 }
04416 if (cnf->origframe)
04417 ast_frfree(cnf->origframe);
04418 cnf->origframe = ast_frdup(f);
04419 ast_mutex_unlock(&cnf->listenlock);
04420 if (s)
04421 res = ast_writestream(s, f);
04422 if (res) {
04423 ast_frfree(f);
04424 break;
04425 }
04426 }
04427 ast_frfree(f);
04428 }
04429 cnf->recording = MEETME_RECORD_OFF;
04430 if (s)
04431 ast_closestream(s);
04432
04433 pthread_exit(0);
04434 }
04435
04436
04437 static enum ast_device_state meetmestate(const char *data)
04438 {
04439 struct ast_conference *conf;
04440
04441
04442 AST_LIST_LOCK(&confs);
04443 AST_LIST_TRAVERSE(&confs, conf, list) {
04444 if (!strcmp(data, conf->confno))
04445 break;
04446 }
04447 AST_LIST_UNLOCK(&confs);
04448 if (!conf)
04449 return AST_DEVICE_INVALID;
04450
04451
04452
04453 if (!conf->users)
04454 return AST_DEVICE_NOT_INUSE;
04455
04456 return AST_DEVICE_INUSE;
04457 }
04458
04459 static void load_config_meetme(void)
04460 {
04461 struct ast_config *cfg;
04462 struct ast_flags config_flags = { 0 };
04463 const char *val;
04464
04465 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
04466 return;
04467 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04468 ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
04469 return;
04470 }
04471
04472 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04473
04474
04475 rt_schedule = 0;
04476 fuzzystart = 0;
04477 earlyalert = 0;
04478 endalert = 0;
04479 extendby = 0;
04480
04481
04482 rt_log_members = 1;
04483
04484 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
04485 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
04486 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
04487 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04488 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
04489 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
04490 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
04491 audio_buffers = DEFAULT_AUDIO_BUFFERS;
04492 }
04493 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
04494 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
04495 }
04496
04497 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
04498 rt_schedule = ast_true(val);
04499 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
04500 rt_log_members = ast_true(val);
04501 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
04502 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
04503 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
04504 fuzzystart = 0;
04505 }
04506 }
04507 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
04508 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
04509 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
04510 earlyalert = 0;
04511 }
04512 }
04513 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
04514 if ((sscanf(val, "%30d", &endalert) != 1)) {
04515 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
04516 endalert = 0;
04517 }
04518 }
04519 if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
04520 if ((sscanf(val, "%30d", &extendby) != 1)) {
04521 ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
04522 extendby = 0;
04523 }
04524 }
04525
04526 ast_config_destroy(cfg);
04527 }
04528
04529
04530
04531
04532 static struct sla_trunk *sla_find_trunk(const char *name)
04533 {
04534 struct sla_trunk *trunk = NULL;
04535
04536 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04537 if (!strcasecmp(trunk->name, name))
04538 break;
04539 }
04540
04541 return trunk;
04542 }
04543
04544
04545
04546
04547 static struct sla_station *sla_find_station(const char *name)
04548 {
04549 struct sla_station *station = NULL;
04550
04551 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04552 if (!strcasecmp(station->name, name))
04553 break;
04554 }
04555
04556 return station;
04557 }
04558
04559 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
04560 const struct sla_station *station)
04561 {
04562 struct sla_station_ref *station_ref;
04563 struct sla_trunk_ref *trunk_ref;
04564
04565
04566 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
04567 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
04568 if (trunk_ref->trunk != trunk || station_ref->station == station)
04569 continue;
04570 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
04571 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
04572 return 1;
04573 return 0;
04574 }
04575 }
04576
04577 return 0;
04578 }
04579
04580
04581
04582
04583
04584
04585
04586
04587 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
04588 const char *name)
04589 {
04590 struct sla_trunk_ref *trunk_ref = NULL;
04591
04592 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04593 if (strcasecmp(trunk_ref->trunk->name, name))
04594 continue;
04595
04596 if ( (trunk_ref->trunk->barge_disabled
04597 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04598 (trunk_ref->trunk->hold_stations
04599 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04600 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04601 sla_check_station_hold_access(trunk_ref->trunk, station) )
04602 {
04603 trunk_ref = NULL;
04604 }
04605
04606 break;
04607 }
04608
04609 return trunk_ref;
04610 }
04611
04612 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
04613 {
04614 struct sla_station_ref *station_ref;
04615
04616 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04617 return NULL;
04618
04619 station_ref->station = station;
04620
04621 return station_ref;
04622 }
04623
04624 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
04625 {
04626 struct sla_ringing_station *ringing_station;
04627
04628 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04629 return NULL;
04630
04631 ringing_station->station = station;
04632 ringing_station->ring_begin = ast_tvnow();
04633
04634 return ringing_station;
04635 }
04636
04637 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
04638 {
04639 switch (state) {
04640 case SLA_TRUNK_STATE_IDLE:
04641 return AST_DEVICE_NOT_INUSE;
04642 case SLA_TRUNK_STATE_RINGING:
04643 return AST_DEVICE_RINGING;
04644 case SLA_TRUNK_STATE_UP:
04645 return AST_DEVICE_INUSE;
04646 case SLA_TRUNK_STATE_ONHOLD:
04647 case SLA_TRUNK_STATE_ONHOLD_BYME:
04648 return AST_DEVICE_ONHOLD;
04649 }
04650
04651 return AST_DEVICE_UNKNOWN;
04652 }
04653
04654 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
04655 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
04656 {
04657 struct sla_station *station;
04658 struct sla_trunk_ref *trunk_ref;
04659
04660 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04661 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04662 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04663 || trunk_ref == exclude)
04664 continue;
04665 trunk_ref->state = state;
04666 ast_devstate_changed(sla_state_to_devstate(state),
04667 "SLA:%s_%s", station->name, trunk->name);
04668 break;
04669 }
04670 }
04671 }
04672
04673 struct run_station_args {
04674 struct sla_station *station;
04675 struct sla_trunk_ref *trunk_ref;
04676 ast_mutex_t *cond_lock;
04677 ast_cond_t *cond;
04678 };
04679
04680 static void answer_trunk_chan(struct ast_channel *chan)
04681 {
04682 ast_answer(chan);
04683 ast_indicate(chan, -1);
04684 }
04685
04686 static void *run_station(void *data)
04687 {
04688 struct sla_station *station;
04689 struct sla_trunk_ref *trunk_ref;
04690 struct ast_str *conf_name = ast_str_create(16);
04691 struct ast_flags conf_flags = { 0 };
04692 struct ast_conference *conf;
04693
04694 {
04695 struct run_station_args *args = data;
04696 station = args->station;
04697 trunk_ref = args->trunk_ref;
04698 ast_mutex_lock(args->cond_lock);
04699 ast_cond_signal(args->cond);
04700 ast_mutex_unlock(args->cond_lock);
04701
04702 }
04703
04704 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04705 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04706 ast_set_flag(&conf_flags,
04707 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04708 answer_trunk_chan(trunk_ref->chan);
04709 conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan);
04710 if (conf) {
04711 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04712 dispose_conf(conf);
04713 conf = NULL;
04714 }
04715 trunk_ref->chan = NULL;
04716 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04717 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04718 ast_str_append(&conf_name, 0, ",K");
04719 admin_exec(NULL, ast_str_buffer(conf_name));
04720 trunk_ref->trunk->hold_stations = 0;
04721 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04722 }
04723
04724 ast_dial_join(station->dial);
04725 ast_dial_destroy(station->dial);
04726 station->dial = NULL;
04727 ast_free(conf_name);
04728
04729 return NULL;
04730 }
04731
04732 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
04733 {
04734 char buf[80];
04735 struct sla_station_ref *station_ref;
04736
04737 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04738 admin_exec(NULL, buf);
04739 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04740
04741 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04742 ast_free(station_ref);
04743
04744 ast_free(ringing_trunk);
04745 }
04746
04747 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
04748 enum sla_station_hangup hangup)
04749 {
04750 struct sla_ringing_trunk *ringing_trunk;
04751 struct sla_trunk_ref *trunk_ref;
04752 struct sla_station_ref *station_ref;
04753
04754 ast_dial_join(ringing_station->station->dial);
04755 ast_dial_destroy(ringing_station->station->dial);
04756 ringing_station->station->dial = NULL;
04757
04758 if (hangup == SLA_STATION_HANGUP_NORMAL)
04759 goto done;
04760
04761
04762
04763
04764
04765
04766 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04767 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04768 if (ringing_trunk->trunk == trunk_ref->trunk)
04769 break;
04770 }
04771 if (!trunk_ref)
04772 continue;
04773 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04774 continue;
04775 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04776 }
04777
04778 done:
04779 ast_free(ringing_station);
04780 }
04781
04782 static void sla_dial_state_callback(struct ast_dial *dial)
04783 {
04784 sla_queue_event(SLA_EVENT_DIAL_STATE);
04785 }
04786
04787
04788
04789
04790 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
04791 const struct sla_station *station)
04792 {
04793 struct sla_station_ref *timed_out_station;
04794
04795 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04796 if (station == timed_out_station->station)
04797 return 1;
04798 }
04799
04800 return 0;
04801 }
04802
04803
04804
04805
04806
04807
04808
04809
04810
04811 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
04812 struct sla_trunk_ref **trunk_ref, int rm)
04813 {
04814 struct sla_trunk_ref *s_trunk_ref;
04815 struct sla_ringing_trunk *ringing_trunk = NULL;
04816
04817 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04818 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04819
04820 if (s_trunk_ref->trunk != ringing_trunk->trunk)
04821 continue;
04822
04823
04824
04825 if (sla_check_timed_out_station(ringing_trunk, station))
04826 continue;
04827
04828 if (rm)
04829 AST_LIST_REMOVE_CURRENT(entry);
04830
04831 if (trunk_ref)
04832 *trunk_ref = s_trunk_ref;
04833
04834 break;
04835 }
04836 AST_LIST_TRAVERSE_SAFE_END;
04837
04838 if (ringing_trunk)
04839 break;
04840 }
04841
04842 return ringing_trunk;
04843 }
04844
04845 static void sla_handle_dial_state_event(void)
04846 {
04847 struct sla_ringing_station *ringing_station;
04848
04849 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04850 struct sla_trunk_ref *s_trunk_ref = NULL;
04851 struct sla_ringing_trunk *ringing_trunk = NULL;
04852 struct run_station_args args;
04853 enum ast_dial_result dial_res;
04854 pthread_t dont_care;
04855 ast_mutex_t cond_lock;
04856 ast_cond_t cond;
04857
04858 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04859 case AST_DIAL_RESULT_HANGUP:
04860 case AST_DIAL_RESULT_INVALID:
04861 case AST_DIAL_RESULT_FAILED:
04862 case AST_DIAL_RESULT_TIMEOUT:
04863 case AST_DIAL_RESULT_UNANSWERED:
04864 AST_LIST_REMOVE_CURRENT(entry);
04865 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04866 break;
04867 case AST_DIAL_RESULT_ANSWERED:
04868 AST_LIST_REMOVE_CURRENT(entry);
04869
04870 ast_mutex_lock(&sla.lock);
04871 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04872 ast_mutex_unlock(&sla.lock);
04873 if (!ringing_trunk) {
04874 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04875 break;
04876 }
04877
04878 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04879
04880 answer_trunk_chan(ringing_trunk->trunk->chan);
04881 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04882
04883
04884
04885 args.trunk_ref = s_trunk_ref;
04886 args.station = ringing_station->station;
04887 args.cond = &cond;
04888 args.cond_lock = &cond_lock;
04889 ast_free(ringing_trunk);
04890 ast_free(ringing_station);
04891 ast_mutex_init(&cond_lock);
04892 ast_cond_init(&cond, NULL);
04893 ast_mutex_lock(&cond_lock);
04894 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04895 ast_cond_wait(&cond, &cond_lock);
04896 ast_mutex_unlock(&cond_lock);
04897 ast_mutex_destroy(&cond_lock);
04898 ast_cond_destroy(&cond);
04899 break;
04900 case AST_DIAL_RESULT_TRYING:
04901 case AST_DIAL_RESULT_RINGING:
04902 case AST_DIAL_RESULT_PROGRESS:
04903 case AST_DIAL_RESULT_PROCEEDING:
04904 break;
04905 }
04906 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04907
04908 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04909 sla_queue_event(SLA_EVENT_DIAL_STATE);
04910 break;
04911 }
04912 }
04913 AST_LIST_TRAVERSE_SAFE_END;
04914 }
04915
04916
04917
04918
04919 static int sla_check_ringing_station(const struct sla_station *station)
04920 {
04921 struct sla_ringing_station *ringing_station;
04922
04923 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04924 if (station == ringing_station->station)
04925 return 1;
04926 }
04927
04928 return 0;
04929 }
04930
04931
04932
04933
04934 static int sla_check_failed_station(const struct sla_station *station)
04935 {
04936 struct sla_failed_station *failed_station;
04937 int res = 0;
04938
04939 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04940 if (station != failed_station->station)
04941 continue;
04942 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04943 AST_LIST_REMOVE_CURRENT(entry);
04944 ast_free(failed_station);
04945 break;
04946 }
04947 res = 1;
04948 }
04949 AST_LIST_TRAVERSE_SAFE_END
04950
04951 return res;
04952 }
04953
04954
04955
04956
04957 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
04958 {
04959 char *tech, *tech_data;
04960 struct ast_dial *dial;
04961 struct sla_ringing_station *ringing_station;
04962 const char *cid_name = NULL, *cid_num = NULL;
04963 enum ast_dial_result res;
04964
04965 if (!(dial = ast_dial_create()))
04966 return -1;
04967
04968 ast_dial_set_state_callback(dial, sla_dial_state_callback);
04969 tech_data = ast_strdupa(station->device);
04970 tech = strsep(&tech_data, "/");
04971
04972 if (ast_dial_append(dial, tech, tech_data) == -1) {
04973 ast_dial_destroy(dial);
04974 return -1;
04975 }
04976
04977 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04978 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04979 ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04980 ringing_trunk->trunk->chan->cid.cid_name = NULL;
04981 }
04982 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04983 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04984 ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04985 ringing_trunk->trunk->chan->cid.cid_num = NULL;
04986 }
04987
04988 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04989
04990 if (cid_name)
04991 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04992 if (cid_num)
04993 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04994
04995 if (res != AST_DIAL_RESULT_TRYING) {
04996 struct sla_failed_station *failed_station;
04997 ast_dial_destroy(dial);
04998 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04999 return -1;
05000 failed_station->station = station;
05001 failed_station->last_try = ast_tvnow();
05002 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
05003 return -1;
05004 }
05005 if (!(ringing_station = sla_create_ringing_station(station))) {
05006 ast_dial_join(dial);
05007 ast_dial_destroy(dial);
05008 return -1;
05009 }
05010
05011 station->dial = dial;
05012
05013 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
05014
05015 return 0;
05016 }
05017
05018
05019
05020 static int sla_check_inuse_station(const struct sla_station *station)
05021 {
05022 struct sla_trunk_ref *trunk_ref;
05023
05024 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05025 if (trunk_ref->chan)
05026 return 1;
05027 }
05028
05029 return 0;
05030 }
05031
05032 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
05033 const struct sla_trunk *trunk)
05034 {
05035 struct sla_trunk_ref *trunk_ref = NULL;
05036
05037 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05038 if (trunk_ref->trunk == trunk)
05039 break;
05040 }
05041
05042 return trunk_ref;
05043 }
05044
05045
05046
05047
05048
05049
05050 static int sla_check_station_delay(struct sla_station *station,
05051 struct sla_ringing_trunk *ringing_trunk)
05052 {
05053 struct sla_trunk_ref *trunk_ref;
05054 unsigned int delay = UINT_MAX;
05055 int time_left, time_elapsed;
05056
05057 if (!ringing_trunk)
05058 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
05059 else
05060 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
05061
05062 if (!ringing_trunk || !trunk_ref)
05063 return delay;
05064
05065
05066
05067
05068 delay = trunk_ref->ring_delay;
05069 if (!delay)
05070 delay = station->ring_delay;
05071 if (!delay)
05072 return INT_MAX;
05073
05074 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05075 time_left = (delay * 1000) - time_elapsed;
05076
05077 return time_left;
05078 }
05079
05080
05081
05082
05083 static void sla_ring_stations(void)
05084 {
05085 struct sla_station_ref *station_ref;
05086 struct sla_ringing_trunk *ringing_trunk;
05087
05088
05089
05090 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05091 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
05092 int time_left;
05093
05094
05095 if (sla_check_ringing_station(station_ref->station))
05096 continue;
05097
05098
05099 if (sla_check_inuse_station(station_ref->station))
05100 continue;
05101
05102
05103
05104 if (sla_check_failed_station(station_ref->station))
05105 continue;
05106
05107
05108
05109 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
05110 continue;
05111
05112
05113 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
05114 if (time_left != INT_MAX && time_left > 0)
05115 continue;
05116
05117
05118 sla_ring_station(ringing_trunk, station_ref->station);
05119 }
05120 }
05121
05122 }
05123
05124 static void sla_hangup_stations(void)
05125 {
05126 struct sla_trunk_ref *trunk_ref;
05127 struct sla_ringing_station *ringing_station;
05128
05129 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05130 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05131 struct sla_ringing_trunk *ringing_trunk;
05132 ast_mutex_lock(&sla.lock);
05133 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05134 if (trunk_ref->trunk == ringing_trunk->trunk)
05135 break;
05136 }
05137 ast_mutex_unlock(&sla.lock);
05138 if (ringing_trunk)
05139 break;
05140 }
05141 if (!trunk_ref) {
05142 AST_LIST_REMOVE_CURRENT(entry);
05143 ast_dial_join(ringing_station->station->dial);
05144 ast_dial_destroy(ringing_station->station->dial);
05145 ringing_station->station->dial = NULL;
05146 ast_free(ringing_station);
05147 }
05148 }
05149 AST_LIST_TRAVERSE_SAFE_END
05150 }
05151
05152 static void sla_handle_ringing_trunk_event(void)
05153 {
05154 ast_mutex_lock(&sla.lock);
05155 sla_ring_stations();
05156 ast_mutex_unlock(&sla.lock);
05157
05158
05159 sla_hangup_stations();
05160 }
05161
05162 static void sla_handle_hold_event(struct sla_event *event)
05163 {
05164 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
05165 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
05166 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s",
05167 event->station->name, event->trunk_ref->trunk->name);
05168 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
05169 INACTIVE_TRUNK_REFS, event->trunk_ref);
05170
05171 if (event->trunk_ref->trunk->active_stations == 1) {
05172
05173
05174 event->trunk_ref->trunk->on_hold = 1;
05175 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
05176 }
05177
05178 ast_softhangup(event->trunk_ref->chan, AST_SOFTHANGUP_DEV);
05179 event->trunk_ref->chan = NULL;
05180 }
05181
05182
05183
05184
05185
05186 static int sla_calc_trunk_timeouts(unsigned int *timeout)
05187 {
05188 struct sla_ringing_trunk *ringing_trunk;
05189 int res = 0;
05190
05191 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05192 int time_left, time_elapsed;
05193 if (!ringing_trunk->trunk->ring_timeout)
05194 continue;
05195 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05196 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
05197 if (time_left <= 0) {
05198 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
05199 AST_LIST_REMOVE_CURRENT(entry);
05200 sla_stop_ringing_trunk(ringing_trunk);
05201 res = 1;
05202 continue;
05203 }
05204 if (time_left < *timeout)
05205 *timeout = time_left;
05206 }
05207 AST_LIST_TRAVERSE_SAFE_END;
05208
05209 return res;
05210 }
05211
05212
05213
05214
05215
05216 static int sla_calc_station_timeouts(unsigned int *timeout)
05217 {
05218 struct sla_ringing_trunk *ringing_trunk;
05219 struct sla_ringing_station *ringing_station;
05220 int res = 0;
05221
05222 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
05223 unsigned int ring_timeout = 0;
05224 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
05225 struct sla_trunk_ref *trunk_ref;
05226
05227
05228
05229
05230 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
05231 struct sla_station_ref *station_ref;
05232 int trunk_time_elapsed, trunk_time_left;
05233
05234 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
05235 if (ringing_trunk->trunk == trunk_ref->trunk)
05236 break;
05237 }
05238 if (!ringing_trunk)
05239 continue;
05240
05241
05242
05243 if (!trunk_ref->ring_timeout)
05244 break;
05245
05246
05247
05248
05249 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
05250 if (station_ref->station == ringing_station->station)
05251 break;
05252 }
05253 if (station_ref)
05254 continue;
05255
05256 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
05257 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
05258 if (trunk_time_left > final_trunk_time_left)
05259 final_trunk_time_left = trunk_time_left;
05260 }
05261
05262
05263 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
05264 continue;
05265
05266
05267 if (ringing_station->station->ring_timeout) {
05268 ring_timeout = ringing_station->station->ring_timeout;
05269 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
05270 time_left = (ring_timeout * 1000) - time_elapsed;
05271 }
05272
05273
05274
05275 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
05276 time_left = final_trunk_time_left;
05277
05278
05279 if (time_left <= 0) {
05280 AST_LIST_REMOVE_CURRENT(entry);
05281 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
05282 res = 1;
05283 continue;
05284 }
05285
05286
05287
05288 if (time_left < *timeout)
05289 *timeout = time_left;
05290 }
05291 AST_LIST_TRAVERSE_SAFE_END;
05292
05293 return res;
05294 }
05295
05296
05297
05298
05299 static int sla_calc_station_delays(unsigned int *timeout)
05300 {
05301 struct sla_station *station;
05302 int res = 0;
05303
05304 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05305 struct sla_ringing_trunk *ringing_trunk;
05306 int time_left;
05307
05308
05309 if (sla_check_ringing_station(station))
05310 continue;
05311
05312
05313 if (sla_check_inuse_station(station))
05314 continue;
05315
05316
05317 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
05318 continue;
05319
05320 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
05321 continue;
05322
05323
05324
05325
05326 if (time_left <= 0) {
05327 res = 1;
05328 continue;
05329 }
05330
05331 if (time_left < *timeout)
05332 *timeout = time_left;
05333 }
05334
05335 return res;
05336 }
05337
05338
05339
05340 static int sla_process_timers(struct timespec *ts)
05341 {
05342 unsigned int timeout = UINT_MAX;
05343 struct timeval wait;
05344 unsigned int change_made = 0;
05345
05346
05347 if (sla_calc_trunk_timeouts(&timeout))
05348 change_made = 1;
05349
05350
05351 if (sla_calc_station_timeouts(&timeout))
05352 change_made = 1;
05353
05354
05355 if (sla_calc_station_delays(&timeout))
05356 change_made = 1;
05357
05358
05359 if (change_made)
05360 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
05361
05362
05363 if (timeout == UINT_MAX)
05364 return 0;
05365
05366 if (ts) {
05367 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
05368 ts->tv_sec = wait.tv_sec;
05369 ts->tv_nsec = wait.tv_usec * 1000;
05370 }
05371
05372 return 1;
05373 }
05374
05375 static int sla_load_config(int reload);
05376
05377
05378 static void sla_check_reload(void)
05379 {
05380 struct sla_station *station;
05381 struct sla_trunk *trunk;
05382
05383 ast_mutex_lock(&sla.lock);
05384
05385 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
05386 || !AST_LIST_EMPTY(&sla.ringing_stations)) {
05387 ast_mutex_unlock(&sla.lock);
05388 return;
05389 }
05390
05391 AST_RWLIST_RDLOCK(&sla_stations);
05392 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
05393 if (station->ref_count)
05394 break;
05395 }
05396 AST_RWLIST_UNLOCK(&sla_stations);
05397 if (station) {
05398 ast_mutex_unlock(&sla.lock);
05399 return;
05400 }
05401
05402 AST_RWLIST_RDLOCK(&sla_trunks);
05403 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05404 if (trunk->ref_count)
05405 break;
05406 }
05407 AST_RWLIST_UNLOCK(&sla_trunks);
05408 if (trunk) {
05409 ast_mutex_unlock(&sla.lock);
05410 return;
05411 }
05412
05413
05414 sla_load_config(1);
05415 sla.reload = 0;
05416
05417 ast_mutex_unlock(&sla.lock);
05418 }
05419
05420 static void *sla_thread(void *data)
05421 {
05422 struct sla_failed_station *failed_station;
05423 struct sla_ringing_station *ringing_station;
05424
05425 ast_mutex_lock(&sla.lock);
05426
05427 while (!sla.stop) {
05428 struct sla_event *event;
05429 struct timespec ts = { 0, };
05430 unsigned int have_timeout = 0;
05431
05432 if (AST_LIST_EMPTY(&sla.event_q)) {
05433 if ((have_timeout = sla_process_timers(&ts)))
05434 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
05435 else
05436 ast_cond_wait(&sla.cond, &sla.lock);
05437 if (sla.stop)
05438 break;
05439 }
05440
05441 if (have_timeout)
05442 sla_process_timers(NULL);
05443
05444 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
05445 ast_mutex_unlock(&sla.lock);
05446 switch (event->type) {
05447 case SLA_EVENT_HOLD:
05448 sla_handle_hold_event(event);
05449 break;
05450 case SLA_EVENT_DIAL_STATE:
05451 sla_handle_dial_state_event();
05452 break;
05453 case SLA_EVENT_RINGING_TRUNK:
05454 sla_handle_ringing_trunk_event();
05455 break;
05456 case SLA_EVENT_RELOAD:
05457 sla.reload = 1;
05458 case SLA_EVENT_CHECK_RELOAD:
05459 break;
05460 }
05461 ast_free(event);
05462 ast_mutex_lock(&sla.lock);
05463 }
05464
05465 if (sla.reload)
05466 sla_check_reload();
05467 }
05468
05469 ast_mutex_unlock(&sla.lock);
05470
05471 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
05472 ast_free(ringing_station);
05473
05474 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
05475 ast_free(failed_station);
05476
05477 return NULL;
05478 }
05479
05480 struct dial_trunk_args {
05481 struct sla_trunk_ref *trunk_ref;
05482 struct sla_station *station;
05483 ast_mutex_t *cond_lock;
05484 ast_cond_t *cond;
05485 };
05486
05487 static void *dial_trunk(void *data)
05488 {
05489 struct dial_trunk_args *args = data;
05490 struct ast_dial *dial;
05491 char *tech, *tech_data;
05492 enum ast_dial_result dial_res;
05493 char conf_name[MAX_CONFNUM];
05494 struct ast_conference *conf;
05495 struct ast_flags conf_flags = { 0 };
05496 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
05497 const char *cid_name = NULL, *cid_num = NULL;
05498
05499 if (!(dial = ast_dial_create())) {
05500 ast_mutex_lock(args->cond_lock);
05501 ast_cond_signal(args->cond);
05502 ast_mutex_unlock(args->cond_lock);
05503 return NULL;
05504 }
05505
05506 tech_data = ast_strdupa(trunk_ref->trunk->device);
05507 tech = strsep(&tech_data, "/");
05508 if (ast_dial_append(dial, tech, tech_data) == -1) {
05509 ast_mutex_lock(args->cond_lock);
05510 ast_cond_signal(args->cond);
05511 ast_mutex_unlock(args->cond_lock);
05512 ast_dial_destroy(dial);
05513 return NULL;
05514 }
05515
05516 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
05517 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
05518 ast_free(trunk_ref->chan->cid.cid_name);
05519 trunk_ref->chan->cid.cid_name = NULL;
05520 }
05521 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
05522 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
05523 ast_free(trunk_ref->chan->cid.cid_num);
05524 trunk_ref->chan->cid.cid_num = NULL;
05525 }
05526
05527 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
05528
05529 if (cid_name)
05530 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
05531 if (cid_num)
05532 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
05533
05534 if (dial_res != AST_DIAL_RESULT_TRYING) {
05535 ast_mutex_lock(args->cond_lock);
05536 ast_cond_signal(args->cond);
05537 ast_mutex_unlock(args->cond_lock);
05538 ast_dial_destroy(dial);
05539 return NULL;
05540 }
05541
05542 for (;;) {
05543 unsigned int done = 0;
05544 switch ((dial_res = ast_dial_state(dial))) {
05545 case AST_DIAL_RESULT_ANSWERED:
05546 trunk_ref->trunk->chan = ast_dial_answered(dial);
05547 case AST_DIAL_RESULT_HANGUP:
05548 case AST_DIAL_RESULT_INVALID:
05549 case AST_DIAL_RESULT_FAILED:
05550 case AST_DIAL_RESULT_TIMEOUT:
05551 case AST_DIAL_RESULT_UNANSWERED:
05552 done = 1;
05553 case AST_DIAL_RESULT_TRYING:
05554 case AST_DIAL_RESULT_RINGING:
05555 case AST_DIAL_RESULT_PROGRESS:
05556 case AST_DIAL_RESULT_PROCEEDING:
05557 break;
05558 }
05559 if (done)
05560 break;
05561 }
05562
05563 if (!trunk_ref->trunk->chan) {
05564 ast_mutex_lock(args->cond_lock);
05565 ast_cond_signal(args->cond);
05566 ast_mutex_unlock(args->cond_lock);
05567 ast_dial_join(dial);
05568 ast_dial_destroy(dial);
05569 return NULL;
05570 }
05571
05572 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05573 ast_set_flag(&conf_flags,
05574 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
05575 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
05576 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
05577
05578 ast_mutex_lock(args->cond_lock);
05579 ast_cond_signal(args->cond);
05580 ast_mutex_unlock(args->cond_lock);
05581
05582 if (conf) {
05583 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
05584 dispose_conf(conf);
05585 conf = NULL;
05586 }
05587
05588
05589 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05590
05591 trunk_ref->trunk->chan = NULL;
05592 trunk_ref->trunk->on_hold = 0;
05593
05594 ast_dial_join(dial);
05595 ast_dial_destroy(dial);
05596
05597 return NULL;
05598 }
05599
05600
05601
05602 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
05603 {
05604 struct sla_trunk_ref *trunk_ref = NULL;
05605
05606 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05607 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05608 break;
05609 }
05610
05611 return trunk_ref;
05612 }
05613
05614 static int sla_station_exec(struct ast_channel *chan, void *data)
05615 {
05616 char *station_name, *trunk_name;
05617 struct sla_station *station;
05618 struct sla_trunk_ref *trunk_ref = NULL;
05619 char conf_name[MAX_CONFNUM];
05620 struct ast_flags conf_flags = { 0 };
05621 struct ast_conference *conf;
05622
05623 if (ast_strlen_zero(data)) {
05624 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05625 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05626 return 0;
05627 }
05628
05629 trunk_name = ast_strdupa(data);
05630 station_name = strsep(&trunk_name, "_");
05631
05632 if (ast_strlen_zero(station_name)) {
05633 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05634 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05635 return 0;
05636 }
05637
05638 AST_RWLIST_RDLOCK(&sla_stations);
05639 station = sla_find_station(station_name);
05640 if (station)
05641 ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05642 AST_RWLIST_UNLOCK(&sla_stations);
05643
05644 if (!station) {
05645 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05646 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05647 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05648 return 0;
05649 }
05650
05651 AST_RWLIST_RDLOCK(&sla_trunks);
05652 if (!ast_strlen_zero(trunk_name)) {
05653 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05654 } else
05655 trunk_ref = sla_choose_idle_trunk(station);
05656 AST_RWLIST_UNLOCK(&sla_trunks);
05657
05658 if (!trunk_ref) {
05659 if (ast_strlen_zero(trunk_name))
05660 ast_log(LOG_NOTICE, "No trunks available for call.\n");
05661 else {
05662 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05663 "'%s' due to access controls.\n", trunk_name);
05664 }
05665 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05666 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05667 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05668 return 0;
05669 }
05670
05671 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05672 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05673 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05674 else {
05675 trunk_ref->state = SLA_TRUNK_STATE_UP;
05676 ast_devstate_changed(AST_DEVICE_INUSE,
05677 "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05678 }
05679 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05680 struct sla_ringing_trunk *ringing_trunk;
05681
05682 ast_mutex_lock(&sla.lock);
05683 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05684 if (ringing_trunk->trunk == trunk_ref->trunk) {
05685 AST_LIST_REMOVE_CURRENT(entry);
05686 break;
05687 }
05688 }
05689 AST_LIST_TRAVERSE_SAFE_END
05690 ast_mutex_unlock(&sla.lock);
05691
05692 if (ringing_trunk) {
05693 answer_trunk_chan(ringing_trunk->trunk->chan);
05694 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05695
05696 free(ringing_trunk);
05697
05698
05699 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05700 sla_queue_event(SLA_EVENT_DIAL_STATE);
05701 }
05702 }
05703
05704 trunk_ref->chan = chan;
05705
05706 if (!trunk_ref->trunk->chan) {
05707 ast_mutex_t cond_lock;
05708 ast_cond_t cond;
05709 pthread_t dont_care;
05710 struct dial_trunk_args args = {
05711 .trunk_ref = trunk_ref,
05712 .station = station,
05713 .cond_lock = &cond_lock,
05714 .cond = &cond,
05715 };
05716 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05717
05718
05719
05720 ast_autoservice_start(chan);
05721 ast_mutex_init(&cond_lock);
05722 ast_cond_init(&cond, NULL);
05723 ast_mutex_lock(&cond_lock);
05724 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05725 ast_cond_wait(&cond, &cond_lock);
05726 ast_mutex_unlock(&cond_lock);
05727 ast_mutex_destroy(&cond_lock);
05728 ast_cond_destroy(&cond);
05729 ast_autoservice_stop(chan);
05730 if (!trunk_ref->trunk->chan) {
05731 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05732 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05733 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05734 trunk_ref->chan = NULL;
05735 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05736 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05737 return 0;
05738 }
05739 }
05740
05741 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05742 trunk_ref->trunk->on_hold) {
05743 trunk_ref->trunk->on_hold = 0;
05744 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05745 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05746 }
05747
05748 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05749 ast_set_flag(&conf_flags,
05750 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05751 ast_answer(chan);
05752 conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05753 if (conf) {
05754 conf_run(chan, conf, conf_flags.flags, NULL);
05755 dispose_conf(conf);
05756 conf = NULL;
05757 }
05758 trunk_ref->chan = NULL;
05759 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05760 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05761 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05762 admin_exec(NULL, conf_name);
05763 trunk_ref->trunk->hold_stations = 0;
05764 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05765 }
05766
05767 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05768
05769 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05770 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05771
05772 return 0;
05773 }
05774
05775 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
05776 {
05777 struct sla_trunk_ref *trunk_ref;
05778
05779 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05780 return NULL;
05781
05782 trunk_ref->trunk = trunk;
05783
05784 return trunk_ref;
05785 }
05786
05787 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
05788 {
05789 struct sla_ringing_trunk *ringing_trunk;
05790
05791 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05792 return NULL;
05793
05794 ringing_trunk->trunk = trunk;
05795 ringing_trunk->ring_begin = ast_tvnow();
05796
05797 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05798
05799 ast_mutex_lock(&sla.lock);
05800 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05801 ast_mutex_unlock(&sla.lock);
05802
05803 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05804
05805 return ringing_trunk;
05806 }
05807
05808 enum {
05809 SLA_TRUNK_OPT_MOH = (1 << 0),
05810 };
05811
05812 enum {
05813 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05814 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05815 };
05816
05817 AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
05818 AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
05819 END_OPTIONS );
05820
05821 static int sla_trunk_exec(struct ast_channel *chan, void *data)
05822 {
05823 char conf_name[MAX_CONFNUM];
05824 struct ast_conference *conf;
05825 struct ast_flags conf_flags = { 0 };
05826 struct sla_trunk *trunk;
05827 struct sla_ringing_trunk *ringing_trunk;
05828 AST_DECLARE_APP_ARGS(args,
05829 AST_APP_ARG(trunk_name);
05830 AST_APP_ARG(options);
05831 );
05832 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05833 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05834 struct ast_flags opt_flags = { 0 };
05835 char *parse;
05836
05837 if (ast_strlen_zero(data)) {
05838 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05839 return -1;
05840 }
05841
05842 parse = ast_strdupa(data);
05843 AST_STANDARD_APP_ARGS(args, parse);
05844 if (args.argc == 2) {
05845 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05846 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05847 return -1;
05848 }
05849 }
05850
05851 AST_RWLIST_RDLOCK(&sla_trunks);
05852 trunk = sla_find_trunk(args.trunk_name);
05853 if (trunk)
05854 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05855 AST_RWLIST_UNLOCK(&sla_trunks);
05856
05857 if (!trunk) {
05858 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05859 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05860 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05861 return 0;
05862 }
05863
05864 if (trunk->chan) {
05865 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05866 args.trunk_name);
05867 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05868 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05869 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05870 return 0;
05871 }
05872
05873 trunk->chan = chan;
05874
05875 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05876 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05877 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05878 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05879 return 0;
05880 }
05881
05882 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05883 conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05884 if (!conf) {
05885 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05886 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05887 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05888 return 0;
05889 }
05890 ast_set_flag(&conf_flags,
05891 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05892
05893 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05894 ast_indicate(chan, -1);
05895 ast_set_flag(&conf_flags, CONFFLAG_MOH);
05896 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05897 } else
05898 ast_indicate(chan, AST_CONTROL_RINGING);
05899
05900 conf_run(chan, conf, conf_flags.flags, opts);
05901 dispose_conf(conf);
05902 conf = NULL;
05903 trunk->chan = NULL;
05904 trunk->on_hold = 0;
05905
05906 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05907
05908 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05909 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05910
05911
05912 ast_mutex_lock(&sla.lock);
05913 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05914 if (ringing_trunk->trunk == trunk) {
05915 AST_LIST_REMOVE_CURRENT(entry);
05916 break;
05917 }
05918 }
05919 AST_LIST_TRAVERSE_SAFE_END;
05920 ast_mutex_unlock(&sla.lock);
05921 if (ringing_trunk) {
05922 ast_free(ringing_trunk);
05923 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05924
05925
05926 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05927 }
05928
05929 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05930 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05931
05932 return 0;
05933 }
05934
05935 static enum ast_device_state sla_state(const char *data)
05936 {
05937 char *buf, *station_name, *trunk_name;
05938 struct sla_station *station;
05939 struct sla_trunk_ref *trunk_ref;
05940 enum ast_device_state res = AST_DEVICE_INVALID;
05941
05942 trunk_name = buf = ast_strdupa(data);
05943 station_name = strsep(&trunk_name, "_");
05944
05945 AST_RWLIST_RDLOCK(&sla_stations);
05946 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05947 if (strcasecmp(station_name, station->name))
05948 continue;
05949 AST_RWLIST_RDLOCK(&sla_trunks);
05950 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05951 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05952 break;
05953 }
05954 if (!trunk_ref) {
05955 AST_RWLIST_UNLOCK(&sla_trunks);
05956 break;
05957 }
05958 res = sla_state_to_devstate(trunk_ref->state);
05959 AST_RWLIST_UNLOCK(&sla_trunks);
05960 }
05961 AST_RWLIST_UNLOCK(&sla_stations);
05962
05963 if (res == AST_DEVICE_INVALID) {
05964 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05965 trunk_name, station_name);
05966 }
05967
05968 return res;
05969 }
05970
05971 static void destroy_trunk(struct sla_trunk *trunk)
05972 {
05973 struct sla_station_ref *station_ref;
05974
05975 if (!ast_strlen_zero(trunk->autocontext))
05976 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05977
05978 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05979 ast_free(station_ref);
05980
05981 ast_string_field_free_memory(trunk);
05982 ast_free(trunk);
05983 }
05984
05985 static void destroy_station(struct sla_station *station)
05986 {
05987 struct sla_trunk_ref *trunk_ref;
05988
05989 if (!ast_strlen_zero(station->autocontext)) {
05990 AST_RWLIST_RDLOCK(&sla_trunks);
05991 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05992 char exten[AST_MAX_EXTENSION];
05993 char hint[AST_MAX_APP];
05994 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05995 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05996 ast_context_remove_extension(station->autocontext, exten,
05997 1, sla_registrar);
05998 ast_context_remove_extension(station->autocontext, hint,
05999 PRIORITY_HINT, sla_registrar);
06000 }
06001 AST_RWLIST_UNLOCK(&sla_trunks);
06002 }
06003
06004 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
06005 ast_free(trunk_ref);
06006
06007 ast_string_field_free_memory(station);
06008 ast_free(station);
06009 }
06010
06011 static void sla_destroy(void)
06012 {
06013 struct sla_trunk *trunk;
06014 struct sla_station *station;
06015
06016 AST_RWLIST_WRLOCK(&sla_trunks);
06017 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
06018 destroy_trunk(trunk);
06019 AST_RWLIST_UNLOCK(&sla_trunks);
06020
06021 AST_RWLIST_WRLOCK(&sla_stations);
06022 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
06023 destroy_station(station);
06024 AST_RWLIST_UNLOCK(&sla_stations);
06025
06026 if (sla.thread != AST_PTHREADT_NULL) {
06027 ast_mutex_lock(&sla.lock);
06028 sla.stop = 1;
06029 ast_cond_signal(&sla.cond);
06030 ast_mutex_unlock(&sla.lock);
06031 pthread_join(sla.thread, NULL);
06032 }
06033
06034
06035 ast_context_destroy(NULL, sla_registrar);
06036
06037 ast_mutex_destroy(&sla.lock);
06038 ast_cond_destroy(&sla.cond);
06039 }
06040
06041 static int sla_check_device(const char *device)
06042 {
06043 char *tech, *tech_data;
06044
06045 tech_data = ast_strdupa(device);
06046 tech = strsep(&tech_data, "/");
06047
06048 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
06049 return -1;
06050
06051 return 0;
06052 }
06053
06054 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
06055 {
06056 struct sla_trunk *trunk;
06057 struct ast_variable *var;
06058 const char *dev;
06059
06060 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06061 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
06062 return -1;
06063 }
06064
06065 if (sla_check_device(dev)) {
06066 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
06067 cat, dev);
06068 return -1;
06069 }
06070
06071 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
06072 return -1;
06073 if (ast_string_field_init(trunk, 32)) {
06074 ast_free(trunk);
06075 return -1;
06076 }
06077
06078 ast_string_field_set(trunk, name, cat);
06079 ast_string_field_set(trunk, device, dev);
06080
06081 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06082 if (!strcasecmp(var->name, "autocontext"))
06083 ast_string_field_set(trunk, autocontext, var->value);
06084 else if (!strcasecmp(var->name, "ringtimeout")) {
06085 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
06086 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
06087 var->value, trunk->name);
06088 trunk->ring_timeout = 0;
06089 }
06090 } else if (!strcasecmp(var->name, "barge"))
06091 trunk->barge_disabled = ast_false(var->value);
06092 else if (!strcasecmp(var->name, "hold")) {
06093 if (!strcasecmp(var->value, "private"))
06094 trunk->hold_access = SLA_HOLD_PRIVATE;
06095 else if (!strcasecmp(var->value, "open"))
06096 trunk->hold_access = SLA_HOLD_OPEN;
06097 else {
06098 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
06099 var->value, trunk->name);
06100 }
06101 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06102 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06103 var->name, var->lineno, SLA_CONFIG_FILE);
06104 }
06105 }
06106
06107 if (!ast_strlen_zero(trunk->autocontext)) {
06108 struct ast_context *context;
06109 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
06110 if (!context) {
06111 ast_log(LOG_ERROR, "Failed to automatically find or create "
06112 "context '%s' for SLA!\n", trunk->autocontext);
06113 destroy_trunk(trunk);
06114 return -1;
06115 }
06116 if (ast_add_extension2(context, 0 , "s", 1,
06117 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
06118 ast_log(LOG_ERROR, "Failed to automatically create extension "
06119 "for trunk '%s'!\n", trunk->name);
06120 destroy_trunk(trunk);
06121 return -1;
06122 }
06123 }
06124
06125 AST_RWLIST_WRLOCK(&sla_trunks);
06126 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
06127 AST_RWLIST_UNLOCK(&sla_trunks);
06128
06129 return 0;
06130 }
06131
06132 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
06133 {
06134 struct sla_trunk *trunk;
06135 struct sla_trunk_ref *trunk_ref;
06136 struct sla_station_ref *station_ref;
06137 char *trunk_name, *options, *cur;
06138
06139 options = ast_strdupa(var->value);
06140 trunk_name = strsep(&options, ",");
06141
06142 AST_RWLIST_RDLOCK(&sla_trunks);
06143 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
06144 if (!strcasecmp(trunk->name, trunk_name))
06145 break;
06146 }
06147
06148 AST_RWLIST_UNLOCK(&sla_trunks);
06149 if (!trunk) {
06150 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
06151 return;
06152 }
06153 if (!(trunk_ref = create_trunk_ref(trunk)))
06154 return;
06155 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
06156
06157 while ((cur = strsep(&options, ","))) {
06158 char *name, *value = cur;
06159 name = strsep(&value, "=");
06160 if (!strcasecmp(name, "ringtimeout")) {
06161 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
06162 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
06163 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06164 trunk_ref->ring_timeout = 0;
06165 }
06166 } else if (!strcasecmp(name, "ringdelay")) {
06167 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
06168 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
06169 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
06170 trunk_ref->ring_delay = 0;
06171 }
06172 } else {
06173 ast_log(LOG_WARNING, "Invalid option '%s' for "
06174 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
06175 }
06176 }
06177
06178 if (!(station_ref = sla_create_station_ref(station))) {
06179 ast_free(trunk_ref);
06180 return;
06181 }
06182 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
06183 AST_RWLIST_WRLOCK(&sla_trunks);
06184 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
06185 AST_RWLIST_UNLOCK(&sla_trunks);
06186 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
06187 }
06188
06189 static int sla_build_station(struct ast_config *cfg, const char *cat)
06190 {
06191 struct sla_station *station;
06192 struct ast_variable *var;
06193 const char *dev;
06194
06195 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
06196 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
06197 return -1;
06198 }
06199
06200 if (!(station = ast_calloc(1, sizeof(*station))))
06201 return -1;
06202 if (ast_string_field_init(station, 32)) {
06203 ast_free(station);
06204 return -1;
06205 }
06206
06207 ast_string_field_set(station, name, cat);
06208 ast_string_field_set(station, device, dev);
06209
06210 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
06211 if (!strcasecmp(var->name, "trunk"))
06212 sla_add_trunk_to_station(station, var);
06213 else if (!strcasecmp(var->name, "autocontext"))
06214 ast_string_field_set(station, autocontext, var->value);
06215 else if (!strcasecmp(var->name, "ringtimeout")) {
06216 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
06217 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
06218 var->value, station->name);
06219 station->ring_timeout = 0;
06220 }
06221 } else if (!strcasecmp(var->name, "ringdelay")) {
06222 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
06223 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
06224 var->value, station->name);
06225 station->ring_delay = 0;
06226 }
06227 } else if (!strcasecmp(var->name, "hold")) {
06228 if (!strcasecmp(var->value, "private"))
06229 station->hold_access = SLA_HOLD_PRIVATE;
06230 else if (!strcasecmp(var->value, "open"))
06231 station->hold_access = SLA_HOLD_OPEN;
06232 else {
06233 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
06234 var->value, station->name);
06235 }
06236
06237 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
06238 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
06239 var->name, var->lineno, SLA_CONFIG_FILE);
06240 }
06241 }
06242
06243 if (!ast_strlen_zero(station->autocontext)) {
06244 struct ast_context *context;
06245 struct sla_trunk_ref *trunk_ref;
06246 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
06247 if (!context) {
06248 ast_log(LOG_ERROR, "Failed to automatically find or create "
06249 "context '%s' for SLA!\n", station->autocontext);
06250 destroy_station(station);
06251 return -1;
06252 }
06253
06254
06255 if (ast_add_extension2(context, 0 , station->name, 1,
06256 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
06257 ast_log(LOG_ERROR, "Failed to automatically create extension "
06258 "for trunk '%s'!\n", station->name);
06259 destroy_station(station);
06260 return -1;
06261 }
06262 AST_RWLIST_RDLOCK(&sla_trunks);
06263 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
06264 char exten[AST_MAX_EXTENSION];
06265 char hint[AST_MAX_APP];
06266 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
06267 snprintf(hint, sizeof(hint), "SLA:%s", exten);
06268
06269
06270 if (ast_add_extension2(context, 0 , exten, 1,
06271 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
06272 ast_log(LOG_ERROR, "Failed to automatically create extension "
06273 "for trunk '%s'!\n", station->name);
06274 destroy_station(station);
06275 return -1;
06276 }
06277
06278
06279 if (ast_add_extension2(context, 0 , exten, PRIORITY_HINT,
06280 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
06281 ast_log(LOG_ERROR, "Failed to automatically create hint "
06282 "for trunk '%s'!\n", station->name);
06283 destroy_station(station);
06284 return -1;
06285 }
06286 }
06287 AST_RWLIST_UNLOCK(&sla_trunks);
06288 }
06289
06290 AST_RWLIST_WRLOCK(&sla_stations);
06291 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
06292 AST_RWLIST_UNLOCK(&sla_stations);
06293
06294 return 0;
06295 }
06296
06297 static int sla_load_config(int reload)
06298 {
06299 struct ast_config *cfg;
06300 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06301 const char *cat = NULL;
06302 int res = 0;
06303 const char *val;
06304
06305 if (!reload) {
06306 ast_mutex_init(&sla.lock);
06307 ast_cond_init(&sla.cond, NULL);
06308 }
06309
06310 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
06311 return 0;
06312 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06313 return 0;
06314 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06315 ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
06316 return 0;
06317 }
06318
06319 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
06320 sla.attempt_callerid = ast_true(val);
06321
06322 while ((cat = ast_category_browse(cfg, cat)) && !res) {
06323 const char *type;
06324 if (!strcasecmp(cat, "general"))
06325 continue;
06326 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
06327 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
06328 SLA_CONFIG_FILE);
06329 continue;
06330 }
06331 if (!strcasecmp(type, "trunk"))
06332 res = sla_build_trunk(cfg, cat);
06333 else if (!strcasecmp(type, "station"))
06334 res = sla_build_station(cfg, cat);
06335 else {
06336 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
06337 SLA_CONFIG_FILE, type);
06338 }
06339 }
06340
06341 ast_config_destroy(cfg);
06342
06343 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
06344 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
06345
06346 return res;
06347 }
06348
06349 static int acf_meetme_info_eval(char *keyword, struct ast_conference *conf)
06350 {
06351 if (!strcasecmp("lock", keyword)) {
06352 return conf->locked;
06353 } else if (!strcasecmp("parties", keyword)) {
06354 return conf->users;
06355 } else if (!strcasecmp("activity", keyword)) {
06356 time_t now;
06357 now = time(NULL);
06358 return (now - conf->start);
06359 } else if (!strcasecmp("dynamic", keyword)) {
06360 return conf->isdynamic;
06361 } else {
06362 return -1;
06363 }
06364
06365 }
06366
06367 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06368 {
06369 struct ast_conference *conf;
06370 char *parse;
06371 int result = -2;
06372 AST_DECLARE_APP_ARGS(args,
06373 AST_APP_ARG(keyword);
06374 AST_APP_ARG(confno);
06375 );
06376
06377 if (ast_strlen_zero(data)) {
06378 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
06379 return -1;
06380 }
06381
06382 parse = ast_strdupa(data);
06383 AST_STANDARD_APP_ARGS(args, parse);
06384
06385 if (ast_strlen_zero(args.keyword)) {
06386 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
06387 return -1;
06388 }
06389
06390 if (ast_strlen_zero(args.confno)) {
06391 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
06392 return -1;
06393 }
06394
06395 AST_LIST_LOCK(&confs);
06396 AST_LIST_TRAVERSE(&confs, conf, list) {
06397 if (!strcmp(args.confno, conf->confno)) {
06398 result = acf_meetme_info_eval(args.keyword, conf);
06399 break;
06400 }
06401 }
06402 AST_LIST_UNLOCK(&confs);
06403
06404 if (result > -1) {
06405 snprintf(buf, len, "%d", result);
06406 } else if (result == -1) {
06407 ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
06408 snprintf(buf, len, "0");
06409 } else if (result == -2) {
06410 ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
06411 snprintf(buf, len, "0");
06412 }
06413
06414 return 0;
06415 }
06416
06417
06418 static struct ast_custom_function meetme_info_acf = {
06419 .name = "MEETME_INFO",
06420 .synopsis = "Query a given conference of various properties.",
06421 .syntax = "MEETME_INFO(<keyword>,<confno>)",
06422 .read = acf_meetme_info,
06423 .desc =
06424 "Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
06425 " Options:\n"
06426 " lock - boolean of whether the corresponding conference is locked\n"
06427 " parties - number of parties in a given conference\n"
06428 " activity - duration of conference in seconds\n"
06429 " dynamic - boolean of whether the corresponding coference is dynamic\n",
06430 };
06431
06432
06433 static int load_config(int reload)
06434 {
06435 load_config_meetme();
06436
06437 if (reload) {
06438 sla_queue_event(SLA_EVENT_RELOAD);
06439 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
06440 "and will be completed when the system is idle.\n");
06441 return 0;
06442 }
06443
06444 return sla_load_config(0);
06445 }
06446
06447 static int unload_module(void)
06448 {
06449 int res = 0;
06450
06451 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06452 res = ast_manager_unregister("MeetmeMute");
06453 res |= ast_manager_unregister("MeetmeUnmute");
06454 res |= ast_manager_unregister("MeetmeList");
06455 res |= ast_unregister_application(app4);
06456 res |= ast_unregister_application(app3);
06457 res |= ast_unregister_application(app2);
06458 res |= ast_unregister_application(app);
06459 res |= ast_unregister_application(slastation_app);
06460 res |= ast_unregister_application(slatrunk_app);
06461
06462 ast_devstate_prov_del("Meetme");
06463 ast_devstate_prov_del("SLA");
06464
06465 sla_destroy();
06466
06467 res |= ast_custom_function_unregister(&meetme_info_acf);
06468 ast_unload_realtime("meetme");
06469
06470 return res;
06471 }
06472
06473 static int load_module(void)
06474 {
06475 int res = 0;
06476
06477 res |= load_config(0);
06478
06479 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
06480 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
06481 action_meetmemute, "Mute a Meetme user");
06482 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
06483 action_meetmeunmute, "Unmute a Meetme user");
06484 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING,
06485 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
06486 res |= ast_register_application_xml(app4, channel_admin_exec);
06487 res |= ast_register_application_xml(app3, admin_exec);
06488 res |= ast_register_application_xml(app2, count_exec);
06489 res |= ast_register_application_xml(app, conf_exec);
06490 res |= ast_register_application_xml(slastation_app, sla_station_exec);
06491 res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
06492
06493 res |= ast_devstate_prov_add("Meetme", meetmestate);
06494 res |= ast_devstate_prov_add("SLA", sla_state);
06495
06496 res |= ast_custom_function_register(&meetme_info_acf);
06497 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
06498
06499 return res;
06500 }
06501
06502 static int reload(void)
06503 {
06504 ast_unload_realtime("meetme");
06505 return load_config(1);
06506 }
06507
06508 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
06509 .load = load_module,
06510 .unload = unload_module,
06511 .reload = reload,
06512 );
06513