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