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