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