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