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