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