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
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include "asterisk.h"
00060
00061 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398235 $")
00062
00063 #include <pthread.h>
00064 #include <sys/socket.h>
00065 #include <sys/time.h>
00066 #include <arpa/inet.h>
00067 #include <fcntl.h>
00068 #include <sys/ioctl.h>
00069 #include <signal.h>
00070 #include <sys/file.h>
00071 #include <semaphore.h>
00072 #include <ctype.h>
00073 #include <time.h>
00074
00075 #include "asterisk/channel.h"
00076 #include "asterisk/config.h"
00077 #include "asterisk/module.h"
00078 #include "asterisk/pbx.h"
00079 #include "asterisk/io.h"
00080 #include "asterisk/frame.h"
00081 #include "asterisk/translate.h"
00082 #include "asterisk/cli.h"
00083 #include "asterisk/musiconhold.h"
00084 #include "asterisk/dsp.h"
00085 #include "asterisk/file.h"
00086 #include "asterisk/callerid.h"
00087 #include "asterisk/indications.h"
00088 #include "asterisk/app.h"
00089 #include "asterisk/features.h"
00090 #include "asterisk/term.h"
00091 #include "asterisk/sched.h"
00092 #include "asterisk/stringfields.h"
00093 #include "asterisk/abstract_jb.h"
00094 #include "asterisk/causes.h"
00095
00096 #include "chan_misdn_config.h"
00097 #include "isdn_lib.h"
00098
00099 static char global_tracefile[BUFFERSIZE + 1];
00100
00101 static int g_config_initialized = 0;
00102
00103 struct misdn_jb{
00104 int size;
00105 int upper_threshold;
00106 char *samples, *ok;
00107 int wp,rp;
00108 int state_empty;
00109 int state_full;
00110 int state_buffer;
00111 int bytes_wrote;
00112 ast_mutex_t mutexjb;
00113 };
00114
00115
00116 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
00117
00118
00119 void misdn_jb_destroy(struct misdn_jb *jb);
00120
00121
00122
00123 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
00124
00125
00126
00127
00128 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
00129
00130 static char *complete_ch(struct ast_cli_args *a);
00131 static char *complete_debug_port(struct ast_cli_args *a);
00132 static char *complete_show_config(struct ast_cli_args *a);
00133
00134
00135
00136 #if defined(AST_MISDN_ENHANCEMENTS)
00137
00138
00139
00140
00141 #define MISDN_CC_RECORD_AGE_MAX (6UL * 60 * 60)
00142
00143 #define MISDN_CC_REQUEST_WAIT_MAX 5
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 struct misdn_cc_caller {
00156
00157 struct ast_channel *chan;
00158 };
00159
00160 struct misdn_cc_notify {
00161
00162 int priority;
00163
00164
00165 char context[AST_MAX_CONTEXT];
00166
00167
00168 char exten[AST_MAX_EXTENSION];
00169 };
00170
00171
00172 struct misdn_cc_record {
00173
00174 AST_LIST_ENTRY(misdn_cc_record) list;
00175
00176
00177 time_t time_created;
00178
00179
00180 long record_id;
00181
00182
00183
00184
00185
00186 int port;
00187
00188
00189 int ptp;
00190
00191
00192 union {
00193
00194 struct {
00195
00196
00197
00198
00199 struct misdn_bchannel *bc;
00200
00201
00202
00203
00204
00205 int requested_retention;
00206
00207
00208
00209
00210 int retention_enabled;
00211 } ptp;
00212
00213
00214 struct {
00215
00216 int linkage_id;
00217
00218
00219 int reference_id;
00220
00221
00222 int recall_mode;
00223 } ptmp;
00224 } mode;
00225
00226
00227 int activated;
00228
00229
00230 int invoke_id;
00231
00232
00233 int outstanding_message;
00234
00235
00236 int activation_requested;
00237
00238
00239
00240
00241
00242
00243 int party_a_free;
00244
00245
00246 enum FacErrorCode error_code;
00247
00248
00249 enum FacRejectCode reject_code;
00250
00251
00252
00253
00254
00255 struct {
00256
00257 struct misdn_party_id caller;
00258
00259
00260 struct misdn_party_dialing dialed;
00261
00262
00263 struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
00264
00265
00266 int capability;
00267
00268
00269 int hdlc;
00270 } redial;
00271
00272
00273 struct misdn_cc_notify remote_user_free;
00274
00275
00276 struct misdn_cc_notify b_free;
00277 };
00278
00279
00280 static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
00281
00282 static __u16 misdn_cc_record_id;
00283
00284 static __s16 misdn_invoke_id;
00285
00286 static const char misdn_no_response_from_network[] = "No response from network";
00287 static const char misdn_cc_record_not_found[] = "Call completion record not found";
00288
00289
00290 #define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
00291 #define MISDN_CC_STATUS "MISDN_CC_STATUS"
00292 #define MISDN_ERROR_MSG "MISDN_ERROR_MSG"
00293 #endif
00294
00295 static ast_mutex_t release_lock;
00296
00297 enum misdn_chan_state {
00298 MISDN_NOTHING = 0,
00299 MISDN_WAITING4DIGS,
00300 MISDN_EXTCANTMATCH,
00301 MISDN_INCOMING_SETUP,
00302 MISDN_DIALING,
00303 MISDN_PROGRESS,
00304 MISDN_PROCEEDING,
00305 MISDN_CALLING,
00306 MISDN_CALLING_ACKNOWLEDGE,
00307 MISDN_ALERTING,
00308 MISDN_BUSY,
00309 MISDN_CONNECTED,
00310 MISDN_DISCONNECTED,
00311 MISDN_CLEANING,
00312 };
00313
00314
00315 #define ORG_AST 1
00316
00317 #define ORG_MISDN 2
00318
00319 enum misdn_hold_state {
00320 MISDN_HOLD_IDLE,
00321 MISDN_HOLD_ACTIVE,
00322 MISDN_HOLD_TRANSFER,
00323 MISDN_HOLD_DISCONNECT,
00324 };
00325 struct hold_info {
00326
00327
00328
00329 enum misdn_hold_state state;
00330
00331
00332
00333
00334 int port;
00335
00336
00337
00338
00339
00340 int channel;
00341 };
00342
00343 #define chan_list_ref(obj, debug) (ao2_t_ref((obj), +1, (debug)), (obj))
00344 #define chan_list_unref(obj, debug) (ao2_t_ref((obj), -1, (debug)), NULL)
00345
00346
00347
00348
00349 struct chan_list {
00350
00351
00352
00353 char allowed_bearers[BUFFERSIZE + 1];
00354
00355
00356
00357
00358 enum misdn_chan_state state;
00359
00360
00361
00362
00363
00364 int need_queue_hangup;
00365
00366
00367
00368
00369 int need_hangup;
00370
00371
00372
00373
00374 int need_busy;
00375
00376
00377
00378
00379 int originator;
00380
00381
00382
00383
00384
00385 int noautorespond_on_setup;
00386
00387 int norxtone;
00388
00389
00390
00391
00392 int notxtone;
00393
00394
00395
00396
00397 int toggle_ec;
00398
00399
00400
00401
00402
00403
00404 int incoming_early_audio;
00405
00406
00407
00408
00409
00410 int ignore_dtmf;
00411
00412
00413
00414
00415
00416 int pipe[2];
00417
00418
00419
00420
00421 char ast_rd_buf[4096];
00422
00423
00424
00425
00426 struct ast_frame frame;
00427
00428
00429
00430
00431
00432
00433 int faxdetect;
00434
00435
00436
00437
00438
00439
00440 int faxdetect_timeout;
00441
00442
00443
00444
00445 struct timeval faxdetect_tv;
00446
00447
00448
00449
00450 int faxhandled;
00451
00452
00453
00454
00455
00456 int ast_dsp;
00457
00458
00459
00460
00461
00462 int jb_len;
00463
00464
00465
00466
00467
00468 int jb_upper_threshold;
00469
00470
00471
00472
00473
00474
00475 struct misdn_jb *jb;
00476
00477
00478
00479
00480
00481
00482 struct ast_dsp *dsp;
00483
00484
00485
00486
00487 struct ast_channel * ast;
00488
00489
00490
00491
00492 struct misdn_bchannel *bc;
00493
00494 #if defined(AST_MISDN_ENHANCEMENTS)
00495
00496
00497
00498 struct misdn_cc_caller *peer;
00499
00500
00501 long record_id;
00502 #endif
00503
00504
00505
00506
00507 struct hold_info hold;
00508
00509
00510
00511
00512
00513 unsigned int l3id;
00514
00515
00516
00517
00518
00519 int addr;
00520
00521
00522
00523
00524
00525 char context[AST_MAX_CONTEXT];
00526
00527
00528
00529
00530
00531 char mohinterpret[MAX_MUSICCLASS];
00532
00533
00534
00535
00536 int dropped_frame_cnt;
00537
00538
00539
00540
00541
00542 int far_alerting;
00543
00544
00545
00546
00547
00548 int nttimeout;
00549
00550
00551
00552
00553
00554 struct ast_tone_zone_sound *ts;
00555
00556
00557
00558
00559
00560 int overlap_dial;
00561
00562
00563
00564
00565 int overlap_dial_task;
00566
00567
00568
00569
00570 ast_mutex_t overlap_tv_lock;
00571
00572
00573
00574
00575 struct timeval overlap_tv;
00576
00577
00578
00579
00580 struct chan_list *next;
00581 };
00582
00583
00584 int MAXTICS = 8;
00585
00586
00587 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00588 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00589 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
00590
00591 struct robin_list {
00592 char *group;
00593 int port;
00594 int channel;
00595 struct robin_list *next;
00596 struct robin_list *prev;
00597 };
00598 static struct robin_list *robin = NULL;
00599
00600
00601 static void free_robin_list(void)
00602 {
00603 struct robin_list *r;
00604 struct robin_list *next;
00605
00606 for (r = robin, robin = NULL; r; r = next) {
00607 next = r->next;
00608 ast_free(r->group);
00609 ast_free(r);
00610 }
00611 }
00612
00613 static struct robin_list *get_robin_position(char *group)
00614 {
00615 struct robin_list *new;
00616 struct robin_list *iter = robin;
00617 for (; iter; iter = iter->next) {
00618 if (!strcasecmp(iter->group, group)) {
00619 return iter;
00620 }
00621 }
00622 new = ast_calloc(1, sizeof(*new));
00623 if (!new) {
00624 return NULL;
00625 }
00626 new->group = ast_strdup(group);
00627 if (!new->group) {
00628 ast_free(new);
00629 return NULL;
00630 }
00631 new->channel = 1;
00632 if (robin) {
00633 new->next = robin;
00634 robin->prev = new;
00635 }
00636 robin = new;
00637 return robin;
00638 }
00639
00640
00641
00642 static struct sched_context *misdn_tasks = NULL;
00643 static pthread_t misdn_tasks_thread;
00644
00645 static int *misdn_ports;
00646
00647 static void chan_misdn_log(int level, int port, char *tmpl, ...)
00648 __attribute__((format(printf, 3, 4)));
00649
00650 static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, const char *linkedid, int port, int c);
00651 static void send_digit_to_chan(struct chan_list *cl, char digit);
00652
00653 static int pbx_start_chan(struct chan_list *ch);
00654
00655 #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
00656
00657 #include "asterisk/strings.h"
00658
00659
00660
00661 static const char misdn_type[] = "mISDN";
00662
00663 static int tracing = 0;
00664
00665
00666 static int prefformat = AST_FORMAT_ALAW ;
00667
00668 static int *misdn_debug;
00669 static int *misdn_debug_only;
00670 static int max_ports;
00671
00672 static int *misdn_in_calls;
00673 static int *misdn_out_calls;
00674
00675
00676
00677
00678 static struct chan_list *cl_te=NULL;
00679 static ast_mutex_t cl_te_lock;
00680
00681 static enum event_response_e
00682 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
00683
00684 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
00685
00686 static void cl_queue_chan(struct chan_list *chan);
00687
00688 static int dialtone_indicate(struct chan_list *cl);
00689 static void hanguptone_indicate(struct chan_list *cl);
00690 static int stop_indicate(struct chan_list *cl);
00691
00692 static int start_bc_tones(struct chan_list *cl);
00693 static int stop_bc_tones(struct chan_list *cl);
00694 static void release_chan_early(struct chan_list *ch);
00695 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
00696
00697 #if defined(AST_MISDN_ENHANCEMENTS)
00698 static const char misdn_command_name[] = "misdn_command";
00699 static int misdn_command_exec(struct ast_channel *chan, const char *data);
00700 #endif
00701 static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
00702 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
00703 static int misdn_facility_exec(struct ast_channel *chan, const char *data);
00704
00705 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
00706
00707 void debug_numtype(int port, int numtype, char *type);
00708
00709 int add_out_calls(int port);
00710 int add_in_calls(int port);
00711
00712
00713 #ifdef MISDN_1_2
00714 static int update_pipeline_config(struct misdn_bchannel *bc);
00715 #else
00716 static int update_ec_config(struct misdn_bchannel *bc);
00717 #endif
00718
00719
00720
00721
00722
00723 static int misdn_chan_is_valid(struct chan_list *ch)
00724 {
00725 struct chan_list *list;
00726
00727 ast_mutex_lock(&cl_te_lock);
00728 for (list = cl_te; list; list = list->next) {
00729 if (list == ch) {
00730 ast_mutex_unlock(&cl_te_lock);
00731 return 1;
00732 }
00733 }
00734 ast_mutex_unlock(&cl_te_lock);
00735
00736 return 0;
00737 }
00738
00739
00740 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
00741 {
00742 struct chan_list *tmp;
00743
00744 ast_mutex_lock(&cl_te_lock);
00745 for (tmp = cl_te; tmp; tmp = tmp->next) {
00746 if (tmp->ast == ast) {
00747 chan_list_ref(tmp, "Found chan_list by ast");
00748 ast_mutex_unlock(&cl_te_lock);
00749 return tmp;
00750 }
00751 }
00752 ast_mutex_unlock(&cl_te_lock);
00753
00754 return NULL;
00755 }
00756
00757
00758 static struct chan_list *get_chan_by_ast_name(const char *name)
00759 {
00760 struct chan_list *tmp;
00761
00762 ast_mutex_lock(&cl_te_lock);
00763 for (tmp = cl_te; tmp; tmp = tmp->next) {
00764 if (tmp->ast && strcmp(tmp->ast->name, name) == 0) {
00765 chan_list_ref(tmp, "Found chan_list by ast name");
00766 ast_mutex_unlock(&cl_te_lock);
00767 return tmp;
00768 }
00769 }
00770 ast_mutex_unlock(&cl_te_lock);
00771
00772 return NULL;
00773 }
00774
00775 #if defined(AST_MISDN_ENHANCEMENTS)
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 static void misdn_cc_ds_destroy(void *data)
00800 {
00801 struct misdn_cc_caller *cc_caller = data;
00802
00803 ao2_lock(cc_caller);
00804 cc_caller->chan = NULL;
00805 ao2_unlock(cc_caller);
00806
00807 ao2_ref(cc_caller, -1);
00808 }
00809 #endif
00810
00811 #if defined(AST_MISDN_ENHANCEMENTS)
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823 static void *misdn_cc_ds_duplicate(void *data)
00824 {
00825 struct misdn_cc_caller *cc_caller = data;
00826
00827 ao2_ref(cc_caller, +1);
00828
00829 return cc_caller;
00830 }
00831 #endif
00832
00833 #if defined(AST_MISDN_ENHANCEMENTS)
00834 static const struct ast_datastore_info misdn_cc_ds_info = {
00835 .type = "misdn_cc",
00836 .destroy = misdn_cc_ds_destroy,
00837 .duplicate = misdn_cc_ds_duplicate,
00838 };
00839 #endif
00840
00841 #if defined(AST_MISDN_ENHANCEMENTS)
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855 static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
00856 const char *value)
00857 {
00858 ao2_lock(peer);
00859
00860
00861 while (peer->chan && ast_channel_trylock(peer->chan)) {
00862 ao2_unlock(peer);
00863 sched_yield();
00864 ao2_lock(peer);
00865 }
00866
00867 if (peer->chan) {
00868 pbx_builtin_setvar_helper(peer->chan, var, value);
00869 ast_channel_unlock(peer->chan);
00870 }
00871
00872 ao2_unlock(peer);
00873 }
00874 #endif
00875
00876 #if defined(AST_MISDN_ENHANCEMENTS)
00877
00878
00879
00880
00881 static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
00882 {
00883 struct ast_datastore *datastore;
00884 struct misdn_cc_caller *cc_caller;
00885
00886 ast_channel_lock(chan);
00887
00888 if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
00889 ast_channel_unlock(chan);
00890 return NULL;
00891 }
00892
00893 ao2_ref(datastore->data, +1);
00894 cc_caller = datastore->data;
00895
00896 ast_channel_unlock(chan);
00897
00898 return cc_caller;
00899 }
00900 #endif
00901
00902 #if defined(AST_MISDN_ENHANCEMENTS)
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914 static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
00915 {
00916 struct misdn_cc_record *current;
00917
00918 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
00919 if (current->record_id == record_id) {
00920
00921 break;
00922 }
00923 }
00924
00925 return current;
00926 }
00927 #endif
00928
00929 #if defined(AST_MISDN_ENHANCEMENTS)
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942 static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
00943 {
00944 struct misdn_cc_record *current;
00945
00946 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
00947 if (current->port == port
00948 && !current->ptp
00949 && current->mode.ptmp.linkage_id == linkage_id) {
00950
00951 break;
00952 }
00953 }
00954
00955 return current;
00956 }
00957 #endif
00958
00959 #if defined(AST_MISDN_ENHANCEMENTS)
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972 static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
00973 {
00974 struct misdn_cc_record *current;
00975
00976 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
00977 if (current->outstanding_message
00978 && current->invoke_id == invoke_id
00979 && current->port == port) {
00980
00981 break;
00982 }
00983 }
00984
00985 return current;
00986 }
00987 #endif
00988
00989 #if defined(AST_MISDN_ENHANCEMENTS)
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
01003 {
01004 struct misdn_cc_record *current;
01005
01006 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
01007 if (current->activated
01008 && current->port == port
01009 && !current->ptp
01010 && current->mode.ptmp.reference_id == reference_id) {
01011
01012 break;
01013 }
01014 }
01015
01016 return current;
01017 }
01018 #endif
01019
01020 #if defined(AST_MISDN_ENHANCEMENTS)
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
01033 {
01034 struct misdn_cc_record *current;
01035
01036 if (bc) {
01037 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
01038 if (current->ptp
01039 && current->mode.ptp.bc == bc) {
01040
01041 break;
01042 }
01043 }
01044 } else {
01045 current = NULL;
01046 }
01047
01048 return current;
01049 }
01050 #endif
01051
01052 #if defined(AST_MISDN_ENHANCEMENTS)
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063 static void misdn_cc_delete(struct misdn_cc_record *doomed)
01064 {
01065 struct misdn_cc_record *current;
01066
01067 AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
01068 if (current == doomed) {
01069 AST_LIST_REMOVE_CURRENT(list);
01070 ast_free(current);
01071 return;
01072 }
01073 }
01074 AST_LIST_TRAVERSE_SAFE_END;
01075
01076
01077 }
01078 #endif
01079
01080 #if defined(AST_MISDN_ENHANCEMENTS)
01081
01082
01083
01084
01085
01086
01087
01088
01089 static void misdn_cc_remove_old(void)
01090 {
01091 struct misdn_cc_record *current;
01092 time_t now;
01093
01094 now = time(NULL);
01095 AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
01096 if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
01097 if (current->ptp && current->mode.ptp.bc) {
01098
01099 current->mode.ptp.bc->fac_out.Function = Fac_None;
01100 current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
01101 misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
01102 }
01103
01104
01105 AST_LIST_REMOVE_CURRENT(list);
01106 ast_free(current);
01107 }
01108 }
01109 AST_LIST_TRAVERSE_SAFE_END;
01110 }
01111 #endif
01112
01113 #if defined(AST_MISDN_ENHANCEMENTS)
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123 static long misdn_cc_record_id_new(void)
01124 {
01125 long record_id;
01126 long first_id;
01127
01128 record_id = ++misdn_cc_record_id;
01129 first_id = record_id;
01130 while (misdn_cc_find_by_id(record_id)) {
01131 record_id = ++misdn_cc_record_id;
01132 if (record_id == first_id) {
01133
01134
01135
01136
01137 chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
01138 record_id = -1;
01139 break;
01140 }
01141 }
01142
01143 return record_id;
01144 }
01145 #endif
01146
01147 #if defined(AST_MISDN_ENHANCEMENTS)
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 static struct misdn_cc_record *misdn_cc_new(void)
01158 {
01159 struct misdn_cc_record *cc_record;
01160 long record_id;
01161
01162 misdn_cc_remove_old();
01163
01164 cc_record = ast_calloc(1, sizeof(*cc_record));
01165 if (cc_record) {
01166 record_id = misdn_cc_record_id_new();
01167 if (record_id < 0) {
01168 ast_free(cc_record);
01169 return NULL;
01170 }
01171
01172
01173 cc_record->record_id = record_id;
01174 cc_record->port = -1;
01175 cc_record->invoke_id = ++misdn_invoke_id;
01176 cc_record->party_a_free = 1;
01177 cc_record->error_code = FacError_None;
01178 cc_record->reject_code = FacReject_None;
01179 cc_record->time_created = time(NULL);
01180
01181
01182 AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
01183 }
01184 return cc_record;
01185 }
01186 #endif
01187
01188 #if defined(AST_MISDN_ENHANCEMENTS)
01189
01190
01191
01192
01193
01194
01195 static void misdn_cc_destroy(void)
01196 {
01197 struct misdn_cc_record *current;
01198
01199 while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
01200
01201 ast_free(current);
01202 }
01203 }
01204 #endif
01205
01206 #if defined(AST_MISDN_ENHANCEMENTS)
01207
01208
01209
01210
01211
01212
01213 static void misdn_cc_init(void)
01214 {
01215 misdn_cc_record_id = 0;
01216 }
01217 #endif
01218
01219 #if defined(AST_MISDN_ENHANCEMENTS)
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229 static int misdn_cc_response_check(void *data)
01230 {
01231 int not_responded;
01232 struct misdn_cc_record *cc_record;
01233
01234 AST_LIST_LOCK(&misdn_cc_records_db);
01235 cc_record = misdn_cc_find_by_id(*(long *) data);
01236 if (cc_record) {
01237 if (cc_record->outstanding_message) {
01238 not_responded = -1;
01239 } else {
01240 not_responded = 0;
01241 }
01242 } else {
01243
01244 not_responded = 0;
01245 }
01246 AST_LIST_UNLOCK(&misdn_cc_records_db);
01247
01248 return not_responded;
01249 }
01250 #endif
01251
01252 #if defined(AST_MISDN_ENHANCEMENTS)
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264 static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
01265 {
01266 unsigned count;
01267
01268 for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
01269
01270 if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
01271
01272 break;
01273 }
01274 }
01275 }
01276 #endif
01277
01278 #if defined(AST_MISDN_ENHANCEMENTS)
01279
01280
01281
01282
01283
01284
01285
01286
01287 static const char *misdn_to_str_reject_code(enum FacRejectCode code)
01288 {
01289 static const struct {
01290 enum FacRejectCode code;
01291 char *name;
01292 } arr[] = {
01293
01294 { FacReject_None, "No reject occurred" },
01295 { FacReject_Unknown, "Unknown reject code" },
01296
01297 { FacReject_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
01298 { FacReject_Gen_MistypedComponent, "General: Mistyped Component" },
01299 { FacReject_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
01300
01301 { FacReject_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
01302 { FacReject_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
01303 { FacReject_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
01304 { FacReject_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
01305 { FacReject_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
01306 { FacReject_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
01307 { FacReject_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
01308 { FacReject_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
01309
01310 { FacReject_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
01311 { FacReject_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
01312 { FacReject_Res_MistypedResult, "Result: Mistyped Result" },
01313
01314 { FacReject_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
01315 { FacReject_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
01316 { FacReject_Err_UnrecognizedError, "Error: Unrecognized Error" },
01317 { FacReject_Err_UnexpectedError, "Error: Unexpected Error" },
01318 { FacReject_Err_MistypedParameter, "Error: Mistyped Parameter" },
01319
01320 };
01321
01322 unsigned index;
01323
01324 for (index = 0; index < ARRAY_LEN(arr); ++index) {
01325 if (arr[index].code == code) {
01326 return arr[index].name;
01327 }
01328 }
01329
01330 return "unknown";
01331 }
01332 #endif
01333
01334 #if defined(AST_MISDN_ENHANCEMENTS)
01335
01336
01337
01338
01339
01340
01341
01342
01343 static const char *misdn_to_str_error_code(enum FacErrorCode code)
01344 {
01345 static const struct {
01346 enum FacErrorCode code;
01347 char *name;
01348 } arr[] = {
01349
01350 { FacError_None, "No error occurred" },
01351 { FacError_Unknown, "Unknown OID error code" },
01352
01353 { FacError_Gen_NotSubscribed, "General: Not Subscribed" },
01354 { FacError_Gen_NotAvailable, "General: Not Available" },
01355 { FacError_Gen_NotImplemented, "General: Not Implemented" },
01356 { FacError_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
01357 { FacError_Gen_InvalidCallState, "General: Invalid Call State" },
01358 { FacError_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
01359 { FacError_Gen_NotIncomingCall, "General: Not Incoming Call" },
01360 { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
01361 { FacError_Gen_ResourceUnavailable, "General: Resource Unavailable" },
01362
01363 { FacError_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
01364 { FacError_Div_SpecialServiceNr, "Diversion: Special Service Number" },
01365 { FacError_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
01366 { FacError_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
01367 { FacError_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
01368 { FacError_Div_NotActivated, "Diversion: Not Activated" },
01369 { FacError_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
01370
01371 { FacError_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
01372
01373 { FacError_CCBS_InvalidCallLinkageID, "CCBS: Invalid Call Linkage ID" },
01374 { FacError_CCBS_InvalidCCBSReference, "CCBS: Invalid CCBS Reference" },
01375 { FacError_CCBS_LongTermDenial, "CCBS: Long Term Denial" },
01376 { FacError_CCBS_ShortTermDenial, "CCBS: Short Term Denial" },
01377 { FacError_CCBS_IsAlreadyActivated, "CCBS: Is Already Activated" },
01378 { FacError_CCBS_AlreadyAccepted, "CCBS: Already Accepted" },
01379 { FacError_CCBS_OutgoingCCBSQueueFull, "CCBS: Outgoing CCBS Queue Full" },
01380 { FacError_CCBS_CallFailureReasonNotBusy, "CCBS: Call Failure Reason Not Busy" },
01381 { FacError_CCBS_NotReadyForCall, "CCBS: Not Ready For Call" },
01382
01383 { FacError_CCBS_T_LongTermDenial, "CCBS-T: Long Term Denial" },
01384 { FacError_CCBS_T_ShortTermDenial, "CCBS-T: Short Term Denial" },
01385
01386 { FacError_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" },
01387
01388 };
01389
01390 unsigned index;
01391
01392 for (index = 0; index < ARRAY_LEN(arr); ++index) {
01393 if (arr[index].code == code) {
01394 return arr[index].name;
01395 }
01396 }
01397
01398 return "unknown";
01399 }
01400 #endif
01401
01402 #if defined(AST_MISDN_ENHANCEMENTS)
01403
01404
01405
01406
01407
01408
01409
01410
01411 static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
01412 {
01413 unsigned diversion_reason;
01414
01415 switch (reason) {
01416 case mISDN_REDIRECTING_REASON_CALL_FWD:
01417 diversion_reason = 1;
01418 break;
01419 case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
01420 diversion_reason = 2;
01421 break;
01422 case mISDN_REDIRECTING_REASON_NO_REPLY:
01423 diversion_reason = 3;
01424 break;
01425 default:
01426 diversion_reason = 0;
01427 break;
01428 }
01429
01430 return diversion_reason;
01431 }
01432 #endif
01433
01434 #if defined(AST_MISDN_ENHANCEMENTS)
01435
01436
01437
01438
01439
01440
01441
01442
01443 static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
01444 {
01445 enum mISDN_REDIRECTING_REASON reason;
01446
01447 switch (diversion_reason) {
01448 case 1:
01449 reason = mISDN_REDIRECTING_REASON_CALL_FWD;
01450 break;
01451 case 2:
01452 reason = mISDN_REDIRECTING_REASON_CALL_FWD_BUSY;
01453 break;
01454 case 3:
01455 reason = mISDN_REDIRECTING_REASON_NO_REPLY;
01456 break;
01457 default:
01458 reason = mISDN_REDIRECTING_REASON_UNKNOWN;
01459 break;
01460 }
01461
01462 return reason;
01463 }
01464 #endif
01465
01466 #if defined(AST_MISDN_ENHANCEMENTS)
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476 static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
01477 {
01478 unsigned type;
01479
01480 switch (presentation) {
01481 case 0:
01482 if (number_present) {
01483 type = 0;
01484 } else {
01485 type = 2;
01486 }
01487 break;
01488 case 1:
01489 if (number_present) {
01490 type = 3;
01491 } else {
01492 type = 1;
01493 }
01494 break;
01495 default:
01496 type = 2;
01497 break;
01498 }
01499
01500 return type;
01501 }
01502 #endif
01503
01504 #if defined(AST_MISDN_ENHANCEMENTS)
01505
01506
01507
01508
01509
01510
01511
01512
01513 static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
01514 {
01515 int presentation;
01516
01517 switch (type) {
01518 default:
01519 case 0:
01520 presentation = 0;
01521 break;
01522
01523 case 1:
01524 case 3:
01525 presentation = 1;
01526 break;
01527
01528 case 2:
01529 presentation = 2;
01530 break;
01531 }
01532
01533 return presentation;
01534 }
01535 #endif
01536
01537 #if defined(AST_MISDN_ENHANCEMENTS)
01538
01539
01540
01541
01542
01543
01544
01545
01546 static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
01547 {
01548 unsigned party_plan;
01549
01550 switch (number_plan) {
01551 default:
01552 case NUMPLAN_UNKNOWN:
01553 party_plan = 0;
01554 break;
01555
01556 case NUMPLAN_ISDN:
01557 party_plan = 1;
01558 break;
01559
01560 case NUMPLAN_DATA:
01561 party_plan = 3;
01562 break;
01563
01564 case NUMPLAN_TELEX:
01565 party_plan = 4;
01566 break;
01567
01568 case NUMPLAN_NATIONAL:
01569 party_plan = 8;
01570 break;
01571
01572 case NUMPLAN_PRIVATE:
01573 party_plan = 5;
01574 break;
01575 }
01576
01577 return party_plan;
01578 }
01579 #endif
01580
01581 #if defined(AST_MISDN_ENHANCEMENTS)
01582
01583
01584
01585
01586
01587
01588
01589
01590 static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
01591 {
01592 enum mISDN_NUMBER_PLAN number_plan;
01593
01594 switch (party_plan) {
01595 default:
01596 case 0:
01597 number_plan = NUMPLAN_UNKNOWN;
01598 break;
01599 case 1:
01600 number_plan = NUMPLAN_ISDN;
01601 break;
01602 case 3:
01603 number_plan = NUMPLAN_DATA;
01604 break;
01605 case 4:
01606 number_plan = NUMPLAN_TELEX;
01607 break;
01608 case 8:
01609 number_plan = NUMPLAN_NATIONAL;
01610 break;
01611 case 5:
01612 number_plan = NUMPLAN_PRIVATE;
01613 break;
01614 }
01615
01616 return number_plan;
01617 }
01618 #endif
01619
01620 #if defined(AST_MISDN_ENHANCEMENTS)
01621
01622
01623
01624
01625
01626
01627
01628
01629 static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
01630 {
01631 unsigned party_ton;
01632
01633 switch (ton) {
01634 default:
01635 case NUMTYPE_UNKNOWN:
01636 party_ton = 0;
01637 break;
01638
01639 case NUMTYPE_INTERNATIONAL:
01640 party_ton = 1;
01641 break;
01642
01643 case NUMTYPE_NATIONAL:
01644 party_ton = 2;
01645 break;
01646
01647 case NUMTYPE_NETWORK_SPECIFIC:
01648 party_ton = 3;
01649 break;
01650
01651 case NUMTYPE_SUBSCRIBER:
01652 party_ton = 4;
01653 break;
01654
01655 case NUMTYPE_ABBREVIATED:
01656 party_ton = 6;
01657 break;
01658 }
01659
01660 return party_ton;
01661 }
01662 #endif
01663
01664 #if defined(AST_MISDN_ENHANCEMENTS)
01665
01666
01667
01668
01669
01670
01671
01672
01673 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
01674 {
01675 enum mISDN_NUMBER_TYPE ton;
01676
01677 switch (party_ton) {
01678 default:
01679 case 0:
01680 ton = NUMTYPE_UNKNOWN;
01681 break;
01682
01683 case 1:
01684 ton = NUMTYPE_INTERNATIONAL;
01685 break;
01686
01687 case 2:
01688 ton = NUMTYPE_NATIONAL;
01689 break;
01690
01691 case 3:
01692 ton = NUMTYPE_NETWORK_SPECIFIC;
01693 break;
01694
01695 case 4:
01696 ton = NUMTYPE_SUBSCRIBER;
01697 break;
01698
01699 case 6:
01700 ton = NUMTYPE_ABBREVIATED;
01701 break;
01702 }
01703
01704 return ton;
01705 }
01706 #endif
01707
01708 #if defined(AST_MISDN_ENHANCEMENTS)
01709
01710
01711
01712
01713
01714
01715
01716
01717 static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
01718 {
01719 unsigned party_ton;
01720
01721 switch (ton) {
01722 default:
01723 case NUMTYPE_UNKNOWN:
01724 party_ton = 0;
01725 break;
01726
01727 case NUMTYPE_INTERNATIONAL:
01728 party_ton = 1;
01729 break;
01730
01731 case NUMTYPE_NATIONAL:
01732 party_ton = 2;
01733 break;
01734
01735 case NUMTYPE_NETWORK_SPECIFIC:
01736 party_ton = 3;
01737 break;
01738
01739 case NUMTYPE_SUBSCRIBER:
01740 party_ton = 4;
01741 break;
01742
01743 case NUMTYPE_ABBREVIATED:
01744 party_ton = 6;
01745 break;
01746 }
01747
01748 return party_ton;
01749 }
01750 #endif
01751
01752 #if defined(AST_MISDN_ENHANCEMENTS)
01753
01754
01755
01756
01757
01758
01759
01760
01761 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
01762 {
01763 enum mISDN_NUMBER_TYPE ton;
01764
01765 switch (party_ton) {
01766 default:
01767 case 0:
01768 ton = NUMTYPE_UNKNOWN;
01769 break;
01770
01771 case 1:
01772 ton = NUMTYPE_INTERNATIONAL;
01773 break;
01774
01775 case 2:
01776 ton = NUMTYPE_NATIONAL;
01777 break;
01778
01779 case 3:
01780 ton = NUMTYPE_NETWORK_SPECIFIC;
01781 break;
01782
01783 case 4:
01784 ton = NUMTYPE_SUBSCRIBER;
01785 break;
01786
01787 case 6:
01788 ton = NUMTYPE_ABBREVIATED;
01789 break;
01790 }
01791
01792 return ton;
01793 }
01794 #endif
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804 static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
01805 {
01806 const char *str;
01807
01808 switch (number_type) {
01809 default:
01810 case NUMTYPE_UNKNOWN:
01811 str = "Unknown";
01812 break;
01813
01814 case NUMTYPE_INTERNATIONAL:
01815 str = "International";
01816 break;
01817
01818 case NUMTYPE_NATIONAL:
01819 str = "National";
01820 break;
01821
01822 case NUMTYPE_NETWORK_SPECIFIC:
01823 str = "Network Specific";
01824 break;
01825
01826 case NUMTYPE_SUBSCRIBER:
01827 str = "Subscriber";
01828 break;
01829
01830 case NUMTYPE_ABBREVIATED:
01831 str = "Abbreviated";
01832 break;
01833 }
01834
01835 return str;
01836 }
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846 static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
01847 {
01848 int ast_number_type;
01849
01850 switch (number_type) {
01851 default:
01852 case NUMTYPE_UNKNOWN:
01853 ast_number_type = NUMTYPE_UNKNOWN << 4;
01854 break;
01855
01856 case NUMTYPE_INTERNATIONAL:
01857 ast_number_type = NUMTYPE_INTERNATIONAL << 4;
01858 break;
01859
01860 case NUMTYPE_NATIONAL:
01861 ast_number_type = NUMTYPE_NATIONAL << 4;
01862 break;
01863
01864 case NUMTYPE_NETWORK_SPECIFIC:
01865 ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
01866 break;
01867
01868 case NUMTYPE_SUBSCRIBER:
01869 ast_number_type = NUMTYPE_SUBSCRIBER << 4;
01870 break;
01871
01872 case NUMTYPE_ABBREVIATED:
01873 ast_number_type = NUMTYPE_ABBREVIATED << 4;
01874 break;
01875 }
01876
01877 return ast_number_type;
01878 }
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888 static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
01889 {
01890 enum mISDN_NUMBER_TYPE number_type;
01891
01892 switch ((ast_number_type >> 4) & 0x07) {
01893 default:
01894 case NUMTYPE_UNKNOWN:
01895 number_type = NUMTYPE_UNKNOWN;
01896 break;
01897
01898 case NUMTYPE_INTERNATIONAL:
01899 number_type = NUMTYPE_INTERNATIONAL;
01900 break;
01901
01902 case NUMTYPE_NATIONAL:
01903 number_type = NUMTYPE_NATIONAL;
01904 break;
01905
01906 case NUMTYPE_NETWORK_SPECIFIC:
01907 number_type = NUMTYPE_NETWORK_SPECIFIC;
01908 break;
01909
01910 case NUMTYPE_SUBSCRIBER:
01911 number_type = NUMTYPE_SUBSCRIBER;
01912 break;
01913
01914 case NUMTYPE_ABBREVIATED:
01915 number_type = NUMTYPE_ABBREVIATED;
01916 break;
01917 }
01918
01919 return number_type;
01920 }
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930 static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
01931 {
01932 const char *str;
01933
01934 switch (number_plan) {
01935 default:
01936 case NUMPLAN_UNKNOWN:
01937 str = "Unknown";
01938 break;
01939
01940 case NUMPLAN_ISDN:
01941 str = "ISDN";
01942 break;
01943
01944 case NUMPLAN_DATA:
01945 str = "Data";
01946 break;
01947
01948 case NUMPLAN_TELEX:
01949 str = "Telex";
01950 break;
01951
01952 case NUMPLAN_NATIONAL:
01953 str = "National";
01954 break;
01955
01956 case NUMPLAN_PRIVATE:
01957 str = "Private";
01958 break;
01959 }
01960
01961 return str;
01962 }
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972 static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
01973 {
01974 int ast_number_plan;
01975
01976 switch (number_plan) {
01977 default:
01978 case NUMPLAN_UNKNOWN:
01979 ast_number_plan = NUMPLAN_UNKNOWN;
01980 break;
01981
01982 case NUMPLAN_ISDN:
01983 ast_number_plan = NUMPLAN_ISDN;
01984 break;
01985
01986 case NUMPLAN_DATA:
01987 ast_number_plan = NUMPLAN_DATA;
01988 break;
01989
01990 case NUMPLAN_TELEX:
01991 ast_number_plan = NUMPLAN_TELEX;
01992 break;
01993
01994 case NUMPLAN_NATIONAL:
01995 ast_number_plan = NUMPLAN_NATIONAL;
01996 break;
01997
01998 case NUMPLAN_PRIVATE:
01999 ast_number_plan = NUMPLAN_PRIVATE;
02000 break;
02001 }
02002
02003 return ast_number_plan;
02004 }
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014 static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
02015 {
02016 enum mISDN_NUMBER_PLAN number_plan;
02017
02018 switch (ast_number_plan & 0x0F) {
02019 default:
02020 case NUMPLAN_UNKNOWN:
02021 number_plan = NUMPLAN_UNKNOWN;
02022 break;
02023
02024 case NUMPLAN_ISDN:
02025 number_plan = NUMPLAN_ISDN;
02026 break;
02027
02028 case NUMPLAN_DATA:
02029 number_plan = NUMPLAN_DATA;
02030 break;
02031
02032 case NUMPLAN_TELEX:
02033 number_plan = NUMPLAN_TELEX;
02034 break;
02035
02036 case NUMPLAN_NATIONAL:
02037 number_plan = NUMPLAN_NATIONAL;
02038 break;
02039
02040 case NUMPLAN_PRIVATE:
02041 number_plan = NUMPLAN_PRIVATE;
02042 break;
02043 }
02044
02045 return number_plan;
02046 }
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056 static const char *misdn_to_str_pres(int presentation)
02057 {
02058 const char *str;
02059
02060 switch (presentation) {
02061 case 0:
02062 str = "Allowed";
02063 break;
02064
02065 case 1:
02066 str = "Restricted";
02067 break;
02068
02069 case 2:
02070 str = "Unavailable";
02071 break;
02072
02073 default:
02074 str = "Unknown";
02075 break;
02076 }
02077
02078 return str;
02079 }
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089 static int misdn_to_ast_pres(int presentation)
02090 {
02091 switch (presentation) {
02092 default:
02093 case 0:
02094 presentation = AST_PRES_ALLOWED;
02095 break;
02096
02097 case 1:
02098 presentation = AST_PRES_RESTRICTED;
02099 break;
02100
02101 case 2:
02102 presentation = AST_PRES_UNAVAILABLE;
02103 break;
02104 }
02105
02106 return presentation;
02107 }
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117 static int ast_to_misdn_pres(int presentation)
02118 {
02119 switch (presentation & AST_PRES_RESTRICTION) {
02120 default:
02121 case AST_PRES_ALLOWED:
02122 presentation = 0;
02123 break;
02124
02125 case AST_PRES_RESTRICTED:
02126 presentation = 1;
02127 break;
02128
02129 case AST_PRES_UNAVAILABLE:
02130 presentation = 2;
02131 break;
02132 }
02133
02134 return presentation;
02135 }
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145 static const char *misdn_to_str_screen(int screening)
02146 {
02147 const char *str;
02148
02149 switch (screening) {
02150 case 0:
02151 str = "Unscreened";
02152 break;
02153
02154 case 1:
02155 str = "Passed Screen";
02156 break;
02157
02158 case 2:
02159 str = "Failed Screen";
02160 break;
02161
02162 case 3:
02163 str = "Network Number";
02164 break;
02165
02166 default:
02167 str = "Unknown";
02168 break;
02169 }
02170
02171 return str;
02172 }
02173
02174
02175
02176
02177
02178
02179
02180
02181
02182 static int misdn_to_ast_screen(int screening)
02183 {
02184 switch (screening) {
02185 default:
02186 case 0:
02187 screening = AST_PRES_USER_NUMBER_UNSCREENED;
02188 break;
02189
02190 case 1:
02191 screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
02192 break;
02193
02194 case 2:
02195 screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
02196 break;
02197
02198 case 3:
02199 screening = AST_PRES_NETWORK_NUMBER;
02200 break;
02201 }
02202
02203 return screening;
02204 }
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214 static int ast_to_misdn_screen(int screening)
02215 {
02216 switch (screening & AST_PRES_NUMBER_TYPE) {
02217 default:
02218 case AST_PRES_USER_NUMBER_UNSCREENED:
02219 screening = 0;
02220 break;
02221
02222 case AST_PRES_USER_NUMBER_PASSED_SCREEN:
02223 screening = 1;
02224 break;
02225
02226 case AST_PRES_USER_NUMBER_FAILED_SCREEN:
02227 screening = 2;
02228 break;
02229
02230 case AST_PRES_NETWORK_NUMBER:
02231 screening = 3;
02232 break;
02233 }
02234
02235 return screening;
02236 }
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246 static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
02247 {
02248 unsigned index;
02249
02250 static const struct misdn_reasons {
02251 enum AST_REDIRECTING_REASON ast;
02252 enum mISDN_REDIRECTING_REASON q931;
02253 } misdn_reason_table[] = {
02254
02255 { AST_REDIRECTING_REASON_UNKNOWN, mISDN_REDIRECTING_REASON_UNKNOWN },
02256 { AST_REDIRECTING_REASON_USER_BUSY, mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
02257 { AST_REDIRECTING_REASON_NO_ANSWER, mISDN_REDIRECTING_REASON_NO_REPLY },
02258 { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY },
02259 { AST_REDIRECTING_REASON_UNCONDITIONAL, mISDN_REDIRECTING_REASON_CALL_FWD },
02260 { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN },
02261 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
02262 { AST_REDIRECTING_REASON_DEFLECTION, mISDN_REDIRECTING_REASON_DEFLECTION },
02263 { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN },
02264 { AST_REDIRECTING_REASON_OUT_OF_ORDER, mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
02265 { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN },
02266 { AST_REDIRECTING_REASON_CALL_FWD_DTE, mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
02267
02268 };
02269
02270 for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
02271 if (misdn_reason_table[index].ast == ast) {
02272 return misdn_reason_table[index].q931;
02273 }
02274 }
02275 return mISDN_REDIRECTING_REASON_UNKNOWN;
02276 }
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286 static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
02287 {
02288 enum AST_REDIRECTING_REASON ast;
02289
02290 switch (q931) {
02291 default:
02292 case mISDN_REDIRECTING_REASON_UNKNOWN:
02293 ast = AST_REDIRECTING_REASON_UNKNOWN;
02294 break;
02295
02296 case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
02297 ast = AST_REDIRECTING_REASON_USER_BUSY;
02298 break;
02299
02300 case mISDN_REDIRECTING_REASON_NO_REPLY:
02301 ast = AST_REDIRECTING_REASON_NO_ANSWER;
02302 break;
02303
02304 case mISDN_REDIRECTING_REASON_DEFLECTION:
02305 ast = AST_REDIRECTING_REASON_DEFLECTION;
02306 break;
02307
02308 case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
02309 ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
02310 break;
02311
02312 case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
02313 ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
02314 break;
02315
02316 case mISDN_REDIRECTING_REASON_CALL_FWD:
02317 ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
02318 break;
02319 }
02320
02321 return ast;
02322 }
02323
02324
02325
02326 struct allowed_bearers {
02327 char *name;
02328 char *display;
02329 int cap;
02330 int deprecated;
02331 };
02332
02333
02334 static const struct allowed_bearers allowed_bearers_array[] = {
02335
02336 { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
02337 { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
02338 { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
02339 { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
02340 { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 },
02341 { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
02342 };
02343
02344
02345 static const char *bearer2str(int cap)
02346 {
02347 unsigned index;
02348
02349 for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
02350 if (allowed_bearers_array[index].cap == cap) {
02351 return allowed_bearers_array[index].display;
02352 }
02353 }
02354
02355 return "Unknown Bearer";
02356 }
02357
02358 #if defined(AST_MISDN_ENHANCEMENTS)
02359
02360
02361
02362
02363
02364
02365
02366
02367
02368 static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
02369 {
02370 ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
02371 party->LengthOfNumber = strlen((char *) party->Number);
02372 party->Type = misdn_to_PartyNumber_plan(id->number_plan);
02373 switch (party->Type) {
02374 case 1:
02375 party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
02376 break;
02377 case 5:
02378 party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
02379 break;
02380 default:
02381 party->TypeOfNumber = 0;
02382 break;
02383 }
02384 }
02385 #endif
02386
02387 #if defined(AST_MISDN_ENHANCEMENTS)
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397 static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
02398 {
02399 if (party->LengthOfNumber) {
02400 ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
02401 id->number_plan = PartyNumber_to_misdn_plan(party->Type);
02402 switch (party->Type) {
02403 case 1:
02404 id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
02405 break;
02406 case 5:
02407 id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
02408 break;
02409 default:
02410 id->number_type = NUMTYPE_UNKNOWN;
02411 break;
02412 }
02413 } else {
02414
02415 id->number_type = NUMTYPE_UNKNOWN;
02416 id->number_plan = NUMPLAN_ISDN;
02417 id->number[0] = 0;
02418 }
02419 }
02420 #endif
02421
02422 #if defined(AST_MISDN_ENHANCEMENTS)
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432 static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
02433 {
02434 misdn_PartyNumber_fill(&Address->Party, id);
02435
02436
02437 Address->Subaddress.Length = 0;
02438 }
02439 #endif
02440
02441 #if defined(AST_MISDN_ENHANCEMENTS)
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451 static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
02452 {
02453 presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
02454 misdn_PartyNumber_fill(&presented->Unscreened, id);
02455 }
02456 #endif
02457
02458 #if defined(AST_MISDN_ENHANCEMENTS)
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468 static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
02469 {
02470 id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
02471 id->screening = 0;
02472 switch (presented->Type) {
02473 case 0:
02474 case 3:
02475 misdn_PartyNumber_extract(id, &presented->Unscreened);
02476 break;
02477 case 1:
02478 case 2:
02479 default:
02480
02481 id->number_type = NUMTYPE_UNKNOWN;
02482 id->number_plan = NUMPLAN_ISDN;
02483 id->number[0] = 0;
02484 break;
02485 }
02486 }
02487 #endif
02488
02489 #if defined(AST_MISDN_ENHANCEMENTS)
02490 static const char Level_Spacing[] = " ";
02491 #endif
02492
02493 #if defined(AST_MISDN_ENHANCEMENTS)
02494 static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
02495 {
02496 if (Party->LengthOfNumber) {
02497 const char *Spacing;
02498
02499 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02500 chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
02501 Spacing, Party->Type);
02502 switch (Party->Type) {
02503 case 0:
02504 chan_misdn_log(1, bc->port, " -->%s Unknown: %s\n",
02505 Spacing, Party->Number);
02506 break;
02507 case 1:
02508 chan_misdn_log(1, bc->port, " -->%s Public TON:%d %s\n",
02509 Spacing, Party->TypeOfNumber, Party->Number);
02510 break;
02511 case 2:
02512 chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
02513 Spacing, Party->Number);
02514 break;
02515 case 3:
02516 chan_misdn_log(1, bc->port, " -->%s Data: %s\n",
02517 Spacing, Party->Number);
02518 break;
02519 case 4:
02520 chan_misdn_log(1, bc->port, " -->%s Telex: %s\n",
02521 Spacing, Party->Number);
02522 break;
02523 case 5:
02524 chan_misdn_log(1, bc->port, " -->%s Private TON:%d %s\n",
02525 Spacing, Party->TypeOfNumber, Party->Number);
02526 break;
02527 case 8:
02528 chan_misdn_log(1, bc->port, " -->%s National: %s\n",
02529 Spacing, Party->Number);
02530 break;
02531 default:
02532 break;
02533 }
02534 }
02535 }
02536 #endif
02537
02538 #if defined(AST_MISDN_ENHANCEMENTS)
02539 static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
02540 {
02541 if (Subaddress->Length) {
02542 const char *Spacing;
02543
02544 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02545 chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
02546 Spacing, Subaddress->Type);
02547 switch (Subaddress->Type) {
02548 case 0:
02549 if (Subaddress->u.UserSpecified.OddCountPresent) {
02550 chan_misdn_log(1, bc->port, " -->%s User BCD OddCount:%d NumOctets:%d\n",
02551 Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
02552 } else {
02553 chan_misdn_log(1, bc->port, " -->%s User: %s\n",
02554 Spacing, Subaddress->u.UserSpecified.Information);
02555 }
02556 break;
02557 case 1:
02558 chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
02559 Spacing, Subaddress->u.Nsap);
02560 break;
02561 default:
02562 break;
02563 }
02564 }
02565 }
02566 #endif
02567
02568 #if defined(AST_MISDN_ENHANCEMENTS)
02569 static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
02570 {
02571 print_facility_PartyNumber(Level, &Address->Party, bc);
02572 print_facility_Subaddress(Level, &Address->Subaddress, bc);
02573 }
02574 #endif
02575
02576 #if defined(AST_MISDN_ENHANCEMENTS)
02577 static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
02578 {
02579 const char *Spacing;
02580
02581 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02582 chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
02583 switch (Presented->Type) {
02584 case 0:
02585 chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
02586 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
02587 break;
02588 case 1:
02589 chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
02590 break;
02591 case 2:
02592 chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
02593 break;
02594 case 3:
02595 chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
02596 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
02597 break;
02598 default:
02599 break;
02600 }
02601 }
02602 #endif
02603
02604 #if defined(AST_MISDN_ENHANCEMENTS)
02605 static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
02606 {
02607 const char *Spacing;
02608
02609 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02610 chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
02611 print_facility_PartyNumber(Level, &Address->Party, bc);
02612 print_facility_Subaddress(Level, &Address->Subaddress, bc);
02613 }
02614 #endif
02615
02616 #if defined(AST_MISDN_ENHANCEMENTS)
02617 static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
02618 {
02619 const char *Spacing;
02620
02621 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02622 chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
02623 switch (Presented->Type) {
02624 case 0:
02625 chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
02626 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
02627 break;
02628 case 1:
02629 chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
02630 break;
02631 case 2:
02632 chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
02633 break;
02634 case 3:
02635 chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
02636 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
02637 break;
02638 default:
02639 break;
02640 }
02641 }
02642 #endif
02643
02644 #if defined(AST_MISDN_ENHANCEMENTS)
02645 static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
02646 {
02647 const char *Spacing;
02648
02649 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02650 chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
02651 if (Q931ie->Bc.Length) {
02652 chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
02653 }
02654 if (Q931ie->Hlc.Length) {
02655 chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
02656 }
02657 if (Q931ie->Llc.Length) {
02658 chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
02659 }
02660 }
02661 #endif
02662
02663 #if defined(AST_MISDN_ENHANCEMENTS)
02664 static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
02665 {
02666 const char *Spacing;
02667
02668 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02669 chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
02670 if (Q931ie->Bc.Length) {
02671 chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
02672 }
02673 if (Q931ie->Hlc.Length) {
02674 chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
02675 }
02676 if (Q931ie->Llc.Length) {
02677 chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
02678 }
02679 if (Q931ie->UserInfo.Length) {
02680 chan_misdn_log(1, bc->port, " -->%s UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
02681 }
02682 }
02683 #endif
02684
02685 #if defined(AST_MISDN_ENHANCEMENTS)
02686 static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
02687 {
02688 const char *Spacing;
02689
02690 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02691 chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
02692 Spacing, CallInfo->CCBSReference);
02693 chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
02694 print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
02695 print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
02696 if (CallInfo->SubaddressOfA.Length) {
02697 chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
02698 print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
02699 }
02700 }
02701 #endif
02702
02703 #if defined(AST_MISDN_ENHANCEMENTS)
02704 static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
02705 {
02706 const char *Spacing;
02707
02708 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02709 if (Party->LengthOfNumber) {
02710 print_facility_PartyNumber(Level, Party, bc);
02711 } else {
02712 chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
02713 }
02714 }
02715 #endif
02716
02717 #if defined(AST_MISDN_ENHANCEMENTS)
02718 static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
02719 {
02720 const char *Spacing;
02721
02722 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02723 chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
02724 Spacing,
02725 ForwardingRecord->Procedure,
02726 ForwardingRecord->BasicService);
02727 chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
02728 print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
02729 chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
02730 print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
02731 }
02732 #endif
02733
02734 static void print_facility(const struct FacParm *fac, const struct misdn_bchannel *bc)
02735 {
02736 #if defined(AST_MISDN_ENHANCEMENTS)
02737 unsigned Index;
02738 #endif
02739
02740 switch (fac->Function) {
02741 #if defined(AST_MISDN_ENHANCEMENTS)
02742 case Fac_ActivationDiversion:
02743 chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
02744 fac->u.ActivationDiversion.InvokeID);
02745 switch (fac->u.ActivationDiversion.ComponentType) {
02746 case FacComponent_Invoke:
02747 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
02748 fac->u.ActivationDiversion.Component.Invoke.Procedure,
02749 fac->u.ActivationDiversion.Component.Invoke.BasicService);
02750 chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
02751 print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
02752 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
02753 print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
02754 break;
02755 case FacComponent_Result:
02756 chan_misdn_log(1, bc->port, " --> Result\n");
02757 break;
02758 default:
02759 break;
02760 }
02761 break;
02762 case Fac_DeactivationDiversion:
02763 chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
02764 fac->u.DeactivationDiversion.InvokeID);
02765 switch (fac->u.DeactivationDiversion.ComponentType) {
02766 case FacComponent_Invoke:
02767 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
02768 fac->u.DeactivationDiversion.Component.Invoke.Procedure,
02769 fac->u.DeactivationDiversion.Component.Invoke.BasicService);
02770 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
02771 print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
02772 break;
02773 case FacComponent_Result:
02774 chan_misdn_log(1, bc->port, " --> Result\n");
02775 break;
02776 default:
02777 break;
02778 }
02779 break;
02780 case Fac_ActivationStatusNotificationDiv:
02781 chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
02782 fac->u.ActivationStatusNotificationDiv.InvokeID,
02783 fac->u.ActivationStatusNotificationDiv.Procedure,
02784 fac->u.ActivationStatusNotificationDiv.BasicService);
02785 chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
02786 print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
02787 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
02788 print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
02789 break;
02790 case Fac_DeactivationStatusNotificationDiv:
02791 chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
02792 fac->u.DeactivationStatusNotificationDiv.InvokeID,
02793 fac->u.DeactivationStatusNotificationDiv.Procedure,
02794 fac->u.DeactivationStatusNotificationDiv.BasicService);
02795 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
02796 print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
02797 break;
02798 case Fac_InterrogationDiversion:
02799 chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
02800 fac->u.InterrogationDiversion.InvokeID);
02801 switch (fac->u.InterrogationDiversion.ComponentType) {
02802 case FacComponent_Invoke:
02803 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
02804 fac->u.InterrogationDiversion.Component.Invoke.Procedure,
02805 fac->u.InterrogationDiversion.Component.Invoke.BasicService);
02806 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
02807 print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
02808 break;
02809 case FacComponent_Result:
02810 chan_misdn_log(1, bc->port, " --> Result:\n");
02811 if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
02812 for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
02813 chan_misdn_log(1, bc->port, " --> IntResult[%d]:\n", Index);
02814 print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
02815 }
02816 }
02817 break;
02818 default:
02819 break;
02820 }
02821 break;
02822 case Fac_DiversionInformation:
02823 chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
02824 fac->u.DiversionInformation.InvokeID,
02825 fac->u.DiversionInformation.DiversionReason,
02826 fac->u.DiversionInformation.BasicService);
02827 if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
02828 chan_misdn_log(1, bc->port, " --> ServedUserSubaddress:\n");
02829 print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
02830 }
02831 if (fac->u.DiversionInformation.CallingAddressPresent) {
02832 chan_misdn_log(1, bc->port, " --> CallingAddress:\n");
02833 print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
02834 }
02835 if (fac->u.DiversionInformation.OriginalCalledPresent) {
02836 chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
02837 print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
02838 }
02839 if (fac->u.DiversionInformation.LastDivertingPresent) {
02840 chan_misdn_log(1, bc->port, " --> LastDivertingNr:\n");
02841 print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
02842 }
02843 if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
02844 chan_misdn_log(1, bc->port, " --> LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
02845 }
02846 if (fac->u.DiversionInformation.UserInfo.Length) {
02847 chan_misdn_log(1, bc->port, " --> UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
02848 }
02849 break;
02850 case Fac_CallDeflection:
02851 chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
02852 fac->u.CallDeflection.InvokeID);
02853 switch (fac->u.CallDeflection.ComponentType) {
02854 case FacComponent_Invoke:
02855 chan_misdn_log(1, bc->port, " --> Invoke:\n");
02856 if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
02857 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
02858 fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
02859 }
02860 chan_misdn_log(1, bc->port, " --> DeflectionAddress:\n");
02861 print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
02862 break;
02863 case FacComponent_Result:
02864 chan_misdn_log(1, bc->port, " --> Result\n");
02865 break;
02866 default:
02867 break;
02868 }
02869 break;
02870 case Fac_CallRerouteing:
02871 chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
02872 fac->u.CallRerouteing.InvokeID);
02873 switch (fac->u.CallRerouteing.ComponentType) {
02874 case FacComponent_Invoke:
02875 chan_misdn_log(1, bc->port, " --> Invoke: Reason:%d Counter:%d\n",
02876 fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
02877 fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
02878 chan_misdn_log(1, bc->port, " --> CalledAddress:\n");
02879 print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
02880 print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
02881 chan_misdn_log(1, bc->port, " --> LastReroutingNr:\n");
02882 print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
02883 chan_misdn_log(1, bc->port, " --> SubscriptionOption:%d\n",
02884 fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
02885 if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
02886 chan_misdn_log(1, bc->port, " --> CallingParty:\n");
02887 print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
02888 }
02889 break;
02890 case FacComponent_Result:
02891 chan_misdn_log(1, bc->port, " --> Result\n");
02892 break;
02893 default:
02894 break;
02895 }
02896 break;
02897 case Fac_InterrogateServedUserNumbers:
02898 chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
02899 fac->u.InterrogateServedUserNumbers.InvokeID);
02900 switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
02901 case FacComponent_Invoke:
02902 chan_misdn_log(1, bc->port, " --> Invoke\n");
02903 break;
02904 case FacComponent_Result:
02905 chan_misdn_log(1, bc->port, " --> Result:\n");
02906 if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
02907 for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
02908 chan_misdn_log(1, bc->port, " --> ServedUserNr[%d]:\n", Index);
02909 print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
02910 }
02911 }
02912 break;
02913 default:
02914 break;
02915 }
02916 break;
02917 case Fac_DivertingLegInformation1:
02918 chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
02919 fac->u.DivertingLegInformation1.InvokeID,
02920 fac->u.DivertingLegInformation1.DiversionReason,
02921 fac->u.DivertingLegInformation1.SubscriptionOption);
02922 if (fac->u.DivertingLegInformation1.DivertedToPresent) {
02923 chan_misdn_log(1, bc->port, " --> DivertedToNr:\n");
02924 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
02925 }
02926 break;
02927 case Fac_DivertingLegInformation2:
02928 chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
02929 fac->u.DivertingLegInformation2.InvokeID,
02930 fac->u.DivertingLegInformation2.DiversionReason,
02931 fac->u.DivertingLegInformation2.DiversionCounter);
02932 if (fac->u.DivertingLegInformation2.DivertingPresent) {
02933 chan_misdn_log(1, bc->port, " --> DivertingNr:\n");
02934 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
02935 }
02936 if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
02937 chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
02938 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
02939 }
02940 break;
02941 case Fac_DivertingLegInformation3:
02942 chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
02943 fac->u.DivertingLegInformation3.InvokeID,
02944 fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
02945 break;
02946
02947 #else
02948
02949 case Fac_CD:
02950 chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
02951 fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
02952 break;
02953 #endif
02954 case Fac_AOCDCurrency:
02955 if (fac->u.AOCDcur.chargeNotAvailable) {
02956 chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
02957 } else if (fac->u.AOCDcur.freeOfCharge) {
02958 chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
02959 } else if (fac->u.AOCDchu.billingId >= 0) {
02960 chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
02961 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
02962 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
02963 } else {
02964 chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
02965 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
02966 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
02967 }
02968 break;
02969 case Fac_AOCDChargingUnit:
02970 if (fac->u.AOCDchu.chargeNotAvailable) {
02971 chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
02972 } else if (fac->u.AOCDchu.freeOfCharge) {
02973 chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
02974 } else if (fac->u.AOCDchu.billingId >= 0) {
02975 chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
02976 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
02977 } else {
02978 chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
02979 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
02980 }
02981 break;
02982 #if defined(AST_MISDN_ENHANCEMENTS)
02983 case Fac_ERROR:
02984 chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
02985 fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
02986 break;
02987 case Fac_RESULT:
02988 chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
02989 fac->u.RESULT.InvokeID);
02990 break;
02991 case Fac_REJECT:
02992 if (fac->u.REJECT.InvokeIDPresent) {
02993 chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
02994 fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
02995 } else {
02996 chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
02997 fac->u.REJECT.Code);
02998 }
02999 break;
03000 case Fac_EctExecute:
03001 chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
03002 fac->u.EctExecute.InvokeID);
03003 break;
03004 case Fac_ExplicitEctExecute:
03005 chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
03006 fac->u.ExplicitEctExecute.InvokeID,
03007 fac->u.ExplicitEctExecute.LinkID);
03008 break;
03009 case Fac_RequestSubaddress:
03010 chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
03011 fac->u.RequestSubaddress.InvokeID);
03012 break;
03013 case Fac_SubaddressTransfer:
03014 chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
03015 fac->u.SubaddressTransfer.InvokeID);
03016 print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
03017 break;
03018 case Fac_EctLinkIdRequest:
03019 chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
03020 fac->u.EctLinkIdRequest.InvokeID);
03021 switch (fac->u.EctLinkIdRequest.ComponentType) {
03022 case FacComponent_Invoke:
03023 chan_misdn_log(1, bc->port, " --> Invoke\n");
03024 break;
03025 case FacComponent_Result:
03026 chan_misdn_log(1, bc->port, " --> Result: LinkID:%d\n",
03027 fac->u.EctLinkIdRequest.Component.Result.LinkID);
03028 break;
03029 default:
03030 break;
03031 }
03032 break;
03033 case Fac_EctInform:
03034 chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
03035 fac->u.EctInform.InvokeID,
03036 fac->u.EctInform.Status);
03037 if (fac->u.EctInform.RedirectionPresent) {
03038 chan_misdn_log(1, bc->port, " --> Redirection Number\n");
03039 print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
03040 }
03041 break;
03042 case Fac_EctLoopTest:
03043 chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
03044 fac->u.EctLoopTest.InvokeID);
03045 switch (fac->u.EctLoopTest.ComponentType) {
03046 case FacComponent_Invoke:
03047 chan_misdn_log(1, bc->port, " --> Invoke: CallTransferID:%d\n",
03048 fac->u.EctLoopTest.Component.Invoke.CallTransferID);
03049 break;
03050 case FacComponent_Result:
03051 chan_misdn_log(1, bc->port, " --> Result: LoopResult:%d\n",
03052 fac->u.EctLoopTest.Component.Result.LoopResult);
03053 break;
03054 default:
03055 break;
03056 }
03057 break;
03058 case Fac_StatusRequest:
03059 chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
03060 fac->u.StatusRequest.InvokeID);
03061 switch (fac->u.StatusRequest.ComponentType) {
03062 case FacComponent_Invoke:
03063 chan_misdn_log(1, bc->port, " --> Invoke: Compatibility:%d\n",
03064 fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
03065 break;
03066 case FacComponent_Result:
03067 chan_misdn_log(1, bc->port, " --> Result: Status:%d\n",
03068 fac->u.StatusRequest.Component.Result.Status);
03069 break;
03070 default:
03071 break;
03072 }
03073 break;
03074 case Fac_CallInfoRetain:
03075 chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
03076 fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
03077 break;
03078 case Fac_CCBSDeactivate:
03079 chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
03080 fac->u.CCBSDeactivate.InvokeID);
03081 switch (fac->u.CCBSDeactivate.ComponentType) {
03082 case FacComponent_Invoke:
03083 chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d\n",
03084 fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
03085 break;
03086 case FacComponent_Result:
03087 chan_misdn_log(1, bc->port, " --> Result\n");
03088 break;
03089 default:
03090 break;
03091 }
03092 break;
03093 case Fac_CCBSErase:
03094 chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
03095 fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
03096 fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
03097 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
03098 print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
03099 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
03100 break;
03101 case Fac_CCBSRemoteUserFree:
03102 chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
03103 fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
03104 fac->u.CCBSRemoteUserFree.RecallMode);
03105 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
03106 print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
03107 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
03108 break;
03109 case Fac_CCBSCall:
03110 chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
03111 fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
03112 break;
03113 case Fac_CCBSStatusRequest:
03114 chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
03115 fac->u.CCBSStatusRequest.InvokeID);
03116 switch (fac->u.CCBSStatusRequest.ComponentType) {
03117 case FacComponent_Invoke:
03118 chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d RecallMode:%d\n",
03119 fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
03120 fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
03121 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
03122 break;
03123 case FacComponent_Result:
03124 chan_misdn_log(1, bc->port, " --> Result: Free:%d\n",
03125 fac->u.CCBSStatusRequest.Component.Result.Free);
03126 break;
03127 default:
03128 break;
03129 }
03130 break;
03131 case Fac_CCBSBFree:
03132 chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
03133 fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
03134 fac->u.CCBSBFree.RecallMode);
03135 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
03136 print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
03137 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
03138 break;
03139 case Fac_EraseCallLinkageID:
03140 chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
03141 fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
03142 break;
03143 case Fac_CCBSStopAlerting:
03144 chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
03145 fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
03146 break;
03147 case Fac_CCBSRequest:
03148 chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
03149 fac->u.CCBSRequest.InvokeID);
03150 switch (fac->u.CCBSRequest.ComponentType) {
03151 case FacComponent_Invoke:
03152 chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
03153 fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
03154 break;
03155 case FacComponent_Result:
03156 chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
03157 fac->u.CCBSRequest.Component.Result.CCBSReference,
03158 fac->u.CCBSRequest.Component.Result.RecallMode);
03159 break;
03160 default:
03161 break;
03162 }
03163 break;
03164 case Fac_CCBSInterrogate:
03165 chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
03166 fac->u.CCBSInterrogate.InvokeID);
03167 switch (fac->u.CCBSInterrogate.ComponentType) {
03168 case FacComponent_Invoke:
03169 chan_misdn_log(1, bc->port, " --> Invoke\n");
03170 if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
03171 chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
03172 fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
03173 }
03174 if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
03175 chan_misdn_log(1, bc->port, " --> AParty\n");
03176 print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
03177 }
03178 break;
03179 case FacComponent_Result:
03180 chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
03181 fac->u.CCBSInterrogate.Component.Result.RecallMode);
03182 if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
03183 for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
03184 chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
03185 print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
03186 }
03187 }
03188 break;
03189 default:
03190 break;
03191 }
03192 break;
03193 case Fac_CCNRRequest:
03194 chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
03195 fac->u.CCNRRequest.InvokeID);
03196 switch (fac->u.CCNRRequest.ComponentType) {
03197 case FacComponent_Invoke:
03198 chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
03199 fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
03200 break;
03201 case FacComponent_Result:
03202 chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
03203 fac->u.CCNRRequest.Component.Result.CCBSReference,
03204 fac->u.CCNRRequest.Component.Result.RecallMode);
03205 break;
03206 default:
03207 break;
03208 }
03209 break;
03210 case Fac_CCNRInterrogate:
03211 chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
03212 fac->u.CCNRInterrogate.InvokeID);
03213 switch (fac->u.CCNRInterrogate.ComponentType) {
03214 case FacComponent_Invoke:
03215 chan_misdn_log(1, bc->port, " --> Invoke\n");
03216 if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
03217 chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
03218 fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
03219 }
03220 if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
03221 chan_misdn_log(1, bc->port, " --> AParty\n");
03222 print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
03223 }
03224 break;
03225 case FacComponent_Result:
03226 chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
03227 fac->u.CCNRInterrogate.Component.Result.RecallMode);
03228 if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
03229 for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
03230 chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
03231 print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
03232 }
03233 }
03234 break;
03235 default:
03236 break;
03237 }
03238 break;
03239 case Fac_CCBS_T_Call:
03240 chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
03241 fac->u.CCBS_T_Call.InvokeID);
03242 break;
03243 case Fac_CCBS_T_Suspend:
03244 chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
03245 fac->u.CCBS_T_Suspend.InvokeID);
03246 break;
03247 case Fac_CCBS_T_Resume:
03248 chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
03249 fac->u.CCBS_T_Resume.InvokeID);
03250 break;
03251 case Fac_CCBS_T_RemoteUserFree:
03252 chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
03253 fac->u.CCBS_T_RemoteUserFree.InvokeID);
03254 break;
03255 case Fac_CCBS_T_Available:
03256 chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
03257 fac->u.CCBS_T_Available.InvokeID);
03258 break;
03259 case Fac_CCBS_T_Request:
03260 chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
03261 fac->u.CCBS_T_Request.InvokeID);
03262 switch (fac->u.CCBS_T_Request.ComponentType) {
03263 case FacComponent_Invoke:
03264 chan_misdn_log(1, bc->port, " --> Invoke\n");
03265 chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
03266 print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
03267 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
03268 if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
03269 chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
03270 }
03271 if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
03272 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
03273 fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
03274 }
03275 if (fac->u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
03276 chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
03277 print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Originating, bc);
03278 }
03279 break;
03280 case FacComponent_Result:
03281 chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
03282 fac->u.CCBS_T_Request.Component.Result.RetentionSupported);
03283 break;
03284 default:
03285 break;
03286 }
03287 break;
03288 case Fac_CCNR_T_Request:
03289 chan_misdn_log(1, bc->port, " --> CCNR_T_Request: InvokeID:%d\n",
03290 fac->u.CCNR_T_Request.InvokeID);
03291 switch (fac->u.CCNR_T_Request.ComponentType) {
03292 case FacComponent_Invoke:
03293 chan_misdn_log(1, bc->port, " --> Invoke\n");
03294 chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
03295 print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Destination, bc);
03296 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCNR_T_Request.Component.Invoke.Q931ie, bc);
03297 if (fac->u.CCNR_T_Request.Component.Invoke.RetentionSupported) {
03298 chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
03299 }
03300 if (fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
03301 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
03302 fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicator);
03303 }
03304 if (fac->u.CCNR_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
03305 chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
03306 print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Originating, bc);
03307 }
03308 break;
03309 case FacComponent_Result:
03310 chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
03311 fac->u.CCNR_T_Request.Component.Result.RetentionSupported);
03312 break;
03313 default:
03314 break;
03315 }
03316 break;
03317 #endif
03318 case Fac_None:
03319
03320 break;
03321 default:
03322 chan_misdn_log(1, bc->port, " --> unknown facility\n");
03323 break;
03324 }
03325 }
03326
03327 static void print_bearer(struct misdn_bchannel *bc)
03328 {
03329 chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability));
03330
03331 switch(bc->law) {
03332 case INFO_CODEC_ALAW:
03333 chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
03334 break;
03335 case INFO_CODEC_ULAW:
03336 chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
03337 break;
03338 }
03339 }
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353 static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
03354 {
03355 size_t len_over;
03356 size_t len_total;
03357 size_t len_main;
03358 size_t len_prefix;
03359
03360 len_prefix = strlen(str_prefix);
03361 if (!len_prefix) {
03362
03363 return;
03364 }
03365 len_main = strlen(str_main);
03366 len_total = len_prefix + len_main;
03367 if (size <= len_total) {
03368
03369 len_over = len_total + 1 - size;
03370 if (len_over <= len_main) {
03371 len_main -= len_over;
03372 } else {
03373 len_over -= len_main;
03374 len_main = 0;
03375 len_prefix -= len_over;
03376 }
03377 }
03378 if (len_main) {
03379 memmove(str_main + len_prefix, str_main, len_main);
03380 }
03381 memcpy(str_main, str_prefix, len_prefix);
03382 str_main[len_prefix + len_main] = '\0';
03383 }
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396 static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
03397 {
03398 enum misdn_cfg_elements type_prefix;
03399 char num_prefix[MISDN_MAX_NUMBER_LEN];
03400
03401
03402 switch (number_type) {
03403 case NUMTYPE_UNKNOWN:
03404 type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
03405 break;
03406 case NUMTYPE_INTERNATIONAL:
03407 type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
03408 break;
03409 case NUMTYPE_NATIONAL:
03410 type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
03411 break;
03412 case NUMTYPE_NETWORK_SPECIFIC:
03413 type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC;
03414 break;
03415 case NUMTYPE_SUBSCRIBER:
03416 type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
03417 break;
03418 case NUMTYPE_ABBREVIATED:
03419 type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
03420 break;
03421 default:
03422
03423 return;
03424 }
03425 misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
03426
03427 misdn_prefix_string(num_prefix, number, size);
03428 }
03429
03430 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
03431 {
03432 char buf[128];
03433
03434 if (!bc->AOCD_need_export || !ast) {
03435 return;
03436 }
03437
03438 if (originator == ORG_AST) {
03439 ast = ast_bridged_channel(ast);
03440 if (!ast) {
03441 return;
03442 }
03443 }
03444
03445 switch (bc->AOCDtype) {
03446 case Fac_AOCDCurrency:
03447 pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
03448 if (bc->AOCD.currency.chargeNotAvailable) {
03449 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
03450 } else {
03451 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
03452 if (bc->AOCD.currency.freeOfCharge) {
03453 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
03454 } else {
03455 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
03456 if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
03457 pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
03458 if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
03459 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
03460 }
03461 }
03462 }
03463 }
03464 break;
03465 case Fac_AOCDChargingUnit:
03466 pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
03467 if (bc->AOCD.chargingUnit.chargeNotAvailable) {
03468 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
03469 } else {
03470 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
03471 if (bc->AOCD.chargingUnit.freeOfCharge) {
03472 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
03473 } else {
03474 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
03475 if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
03476 pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
03477 if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
03478 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
03479 }
03480 }
03481 }
03482 }
03483 break;
03484 default:
03485 break;
03486 }
03487
03488 bc->AOCD_need_export = 0;
03489 }
03490
03491
03492
03493 static void sighandler(int sig)
03494 {
03495 }
03496
03497 static void *misdn_tasks_thread_func(void *data)
03498 {
03499 int wait;
03500 struct sigaction sa;
03501
03502 sa.sa_handler = sighandler;
03503 sa.sa_flags = SA_NODEFER;
03504 sigemptyset(&sa.sa_mask);
03505 sigaddset(&sa.sa_mask, SIGUSR1);
03506 sigaction(SIGUSR1, &sa, NULL);
03507
03508 sem_post((sem_t *)data);
03509
03510 while (1) {
03511 wait = ast_sched_wait(misdn_tasks);
03512 if (wait < 0) {
03513 wait = 8000;
03514 }
03515 if (poll(NULL, 0, wait) < 0) {
03516 chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
03517 }
03518 ast_sched_runq(misdn_tasks);
03519 }
03520 return NULL;
03521 }
03522
03523 static void misdn_tasks_init(void)
03524 {
03525 sem_t blocker;
03526 int i = 5;
03527
03528 if (sem_init(&blocker, 0, 0)) {
03529 perror("chan_misdn: Failed to initialize semaphore!");
03530 exit(1);
03531 }
03532
03533 chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
03534
03535 misdn_tasks = sched_context_create();
03536 pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
03537
03538 while (sem_wait(&blocker) && --i) {
03539 }
03540 sem_destroy(&blocker);
03541 }
03542
03543 static void misdn_tasks_destroy(void)
03544 {
03545 if (misdn_tasks) {
03546 chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
03547 if (pthread_cancel(misdn_tasks_thread) == 0) {
03548 cb_log(4, 0, "Joining misdn_tasks thread\n");
03549 pthread_join(misdn_tasks_thread, NULL);
03550 }
03551 sched_context_destroy(misdn_tasks);
03552 }
03553 }
03554
03555 static inline void misdn_tasks_wakeup(void)
03556 {
03557 pthread_kill(misdn_tasks_thread, SIGUSR1);
03558 }
03559
03560 static inline int _misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data, int variable)
03561 {
03562 int task_id;
03563
03564 if (!misdn_tasks) {
03565 misdn_tasks_init();
03566 }
03567 task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
03568 misdn_tasks_wakeup();
03569
03570 return task_id;
03571 }
03572
03573 static int misdn_tasks_add(int timeout, ast_sched_cb callback, const void *data)
03574 {
03575 return _misdn_tasks_add_variable(timeout, callback, data, 0);
03576 }
03577
03578 static int misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data)
03579 {
03580 return _misdn_tasks_add_variable(timeout, callback, data, 1);
03581 }
03582
03583 static void misdn_tasks_remove(int task_id)
03584 {
03585 AST_SCHED_DEL(misdn_tasks, task_id);
03586 }
03587
03588 static int misdn_l1_task(const void *vdata)
03589 {
03590 const int *data = vdata;
03591
03592 misdn_lib_isdn_l1watcher(*data);
03593 chan_misdn_log(5, *data, "L1watcher timeout\n");
03594 return 1;
03595 }
03596
03597 static int misdn_overlap_dial_task(const void *data)
03598 {
03599 struct timeval tv_end, tv_now;
03600 int diff;
03601 struct chan_list *ch = (struct chan_list *) data;
03602 char *dad;
03603
03604 chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
03605
03606 if (ch->state != MISDN_WAITING4DIGS) {
03607 ch->overlap_dial_task = -1;
03608 return 0;
03609 }
03610
03611 ast_mutex_lock(&ch->overlap_tv_lock);
03612 tv_end = ch->overlap_tv;
03613 ast_mutex_unlock(&ch->overlap_tv_lock);
03614
03615 tv_end.tv_sec += ch->overlap_dial;
03616 tv_now = ast_tvnow();
03617
03618 diff = ast_tvdiff_ms(tv_end, tv_now);
03619 if (100 < diff) {
03620 return diff;
03621 }
03622
03623
03624 stop_indicate(ch);
03625
03626 if (ast_strlen_zero(ch->bc->dialed.number)) {
03627 dad = "s";
03628 strcpy(ch->ast->exten, dad);
03629 } else {
03630 dad = ch->bc->dialed.number;
03631 }
03632
03633 if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
03634 ch->state = MISDN_DIALING;
03635 if (pbx_start_chan(ch) < 0) {
03636 chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
03637 goto misdn_overlap_dial_task_disconnect;
03638 }
03639 } else {
03640 misdn_overlap_dial_task_disconnect:
03641 hanguptone_indicate(ch);
03642 ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
03643 ch->state = MISDN_CLEANING;
03644 misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
03645 }
03646 ch->overlap_dial_task = -1;
03647 return 0;
03648 }
03649
03650 static void send_digit_to_chan(struct chan_list *cl, char digit)
03651 {
03652 static const char * const dtmf_tones[] = {
03653
03654 "!941+1336/100,!0/100",
03655 "!697+1209/100,!0/100",
03656 "!697+1336/100,!0/100",
03657 "!697+1477/100,!0/100",
03658 "!770+1209/100,!0/100",
03659 "!770+1336/100,!0/100",
03660 "!770+1477/100,!0/100",
03661 "!852+1209/100,!0/100",
03662 "!852+1336/100,!0/100",
03663 "!852+1477/100,!0/100",
03664 "!697+1633/100,!0/100",
03665 "!770+1633/100,!0/100",
03666 "!852+1633/100,!0/100",
03667 "!941+1633/100,!0/100",
03668 "!941+1209/100,!0/100",
03669 "!941+1477/100,!0/100",
03670
03671 };
03672 struct ast_channel *chan = cl->ast;
03673
03674 if (digit >= '0' && digit <='9') {
03675 ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0);
03676 } else if (digit >= 'A' && digit <= 'D') {
03677 ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0);
03678 } else if (digit == '*') {
03679 ast_playtones_start(chan, 0, dtmf_tones[14], 0);
03680 } else if (digit == '#') {
03681 ast_playtones_start(chan, 0, dtmf_tones[15], 0);
03682 } else {
03683
03684 ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
03685 }
03686 }
03687
03688
03689 static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03690 {
03691 int level;
03692
03693 switch (cmd) {
03694 case CLI_INIT:
03695 e->command = "misdn set debug [on|off]";
03696 e->usage =
03697 "Usage: misdn set debug {on|off|<level>} [only] | [port <port> [only]]\n"
03698 " Set the debug level of the mISDN channel.\n";
03699 return NULL;
03700 case CLI_GENERATE:
03701 return complete_debug_port(a);
03702 }
03703
03704 if (a->argc < 4 || a->argc > 7) {
03705 return CLI_SHOWUSAGE;
03706 }
03707
03708 if (!strcasecmp(a->argv[3], "on")) {
03709 level = 1;
03710 } else if (!strcasecmp(a->argv[3], "off")) {
03711 level = 0;
03712 } else if (isdigit(a->argv[3][0])) {
03713 level = atoi(a->argv[3]);
03714 } else {
03715 return CLI_SHOWUSAGE;
03716 }
03717
03718 switch (a->argc) {
03719 case 4:
03720 case 5:
03721 {
03722 int i;
03723 int only = 0;
03724 if (a->argc == 5) {
03725 if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) {
03726 return CLI_SHOWUSAGE;
03727 } else {
03728 only = 1;
03729 }
03730 }
03731
03732 for (i = 0; i <= max_ports; i++) {
03733 misdn_debug[i] = level;
03734 misdn_debug_only[i] = only;
03735 }
03736 ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : "");
03737 }
03738 break;
03739 case 6:
03740 case 7:
03741 {
03742 int port;
03743 if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
03744 return CLI_SHOWUSAGE;
03745 port = atoi(a->argv[5]);
03746 if (port <= 0 || port > max_ports) {
03747 switch (max_ports) {
03748 case 0:
03749 ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
03750 break;
03751 case 1:
03752 ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
03753 break;
03754 default:
03755 ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
03756 }
03757 return 0;
03758 }
03759 if (a->argc == 7) {
03760 if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) {
03761 return CLI_SHOWUSAGE;
03762 } else {
03763 misdn_debug_only[port] = 1;
03764 }
03765 } else {
03766 misdn_debug_only[port] = 0;
03767 }
03768 misdn_debug[port] = level;
03769 ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port] ? " (only)" : "", port);
03770 }
03771 }
03772
03773 return CLI_SUCCESS;
03774 }
03775
03776 static char *handle_cli_misdn_set_crypt_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03777 {
03778 switch (cmd) {
03779 case CLI_INIT:
03780 e->command = "misdn set crypt debug";
03781 e->usage =
03782 "Usage: misdn set crypt debug <level>\n"
03783 " Set the crypt debug level of the mISDN channel. Level\n"
03784 " must be 1 or 2.\n";
03785 return NULL;
03786 case CLI_GENERATE:
03787 return NULL;
03788 }
03789
03790 if (a->argc != 5) {
03791 return CLI_SHOWUSAGE;
03792 }
03793
03794
03795
03796 return CLI_SUCCESS;
03797 }
03798
03799 static char *handle_cli_misdn_port_block(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03800 {
03801 switch (cmd) {
03802 case CLI_INIT:
03803 e->command = "misdn port block";
03804 e->usage =
03805 "Usage: misdn port block <port>\n"
03806 " Block the specified port by <port>.\n";
03807 return NULL;
03808 case CLI_GENERATE:
03809 return NULL;
03810 }
03811
03812 if (a->argc != 4) {
03813 return CLI_SHOWUSAGE;
03814 }
03815
03816 misdn_lib_port_block(atoi(a->argv[3]));
03817
03818 return CLI_SUCCESS;
03819 }
03820
03821 static char *handle_cli_misdn_port_unblock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03822 {
03823 switch (cmd) {
03824 case CLI_INIT:
03825 e->command = "misdn port unblock";
03826 e->usage =
03827 "Usage: misdn port unblock <port>\n"
03828 " Unblock the port specified by <port>.\n";
03829 return NULL;
03830 case CLI_GENERATE:
03831 return NULL;
03832 }
03833
03834 if (a->argc != 4) {
03835 return CLI_SHOWUSAGE;
03836 }
03837
03838 misdn_lib_port_unblock(atoi(a->argv[3]));
03839
03840 return CLI_SUCCESS;
03841 }
03842
03843 static char *handle_cli_misdn_restart_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03844 {
03845 switch (cmd) {
03846 case CLI_INIT:
03847 e->command = "misdn restart port";
03848 e->usage =
03849 "Usage: misdn restart port <port>\n"
03850 " Restart the given port.\n";
03851 return NULL;
03852 case CLI_GENERATE:
03853 return NULL;
03854 }
03855
03856 if (a->argc != 4) {
03857 return CLI_SHOWUSAGE;
03858 }
03859
03860 misdn_lib_port_restart(atoi(a->argv[3]));
03861
03862 return CLI_SUCCESS;
03863 }
03864
03865 static char *handle_cli_misdn_restart_pid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03866 {
03867 switch (cmd) {
03868 case CLI_INIT:
03869 e->command = "misdn restart pid";
03870 e->usage =
03871 "Usage: misdn restart pid <pid>\n"
03872 " Restart the given pid\n";
03873 return NULL;
03874 case CLI_GENERATE:
03875 return NULL;
03876 }
03877
03878 if (a->argc != 4) {
03879 return CLI_SHOWUSAGE;
03880 }
03881
03882 misdn_lib_pid_restart(atoi(a->argv[3]));
03883
03884 return CLI_SUCCESS;
03885 }
03886
03887 static char *handle_cli_misdn_port_up(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03888 {
03889 switch (cmd) {
03890 case CLI_INIT:
03891 e->command = "misdn port up";
03892 e->usage =
03893 "Usage: misdn port up <port>\n"
03894 " Try to establish L1 on the given port.\n";
03895 return NULL;
03896 case CLI_GENERATE:
03897 return NULL;
03898 }
03899
03900 if (a->argc != 4) {
03901 return CLI_SHOWUSAGE;
03902 }
03903
03904 misdn_lib_get_port_up(atoi(a->argv[3]));
03905
03906 return CLI_SUCCESS;
03907 }
03908
03909 static char *handle_cli_misdn_port_down(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03910 {
03911 switch (cmd) {
03912 case CLI_INIT:
03913 e->command = "misdn port down";
03914 e->usage =
03915 "Usage: misdn port down <port>\n"
03916 " Try to deactivate the L1 on the given port.\n";
03917 return NULL;
03918 case CLI_GENERATE:
03919 return NULL;
03920 }
03921
03922 if (a->argc != 4) {
03923 return CLI_SHOWUSAGE;
03924 }
03925
03926 misdn_lib_get_port_down(atoi(a->argv[3]));
03927
03928 return CLI_SUCCESS;
03929 }
03930
03931 static inline void show_config_description(int fd, enum misdn_cfg_elements elem)
03932 {
03933 char section[BUFFERSIZE];
03934 char name[BUFFERSIZE];
03935 char desc[BUFFERSIZE];
03936 char def[BUFFERSIZE];
03937 char tmp[BUFFERSIZE];
03938
03939 misdn_cfg_get_name(elem, tmp, sizeof(tmp));
03940 term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
03941 misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
03942
03943 if (elem < MISDN_CFG_LAST) {
03944 term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
03945 } else {
03946 term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
03947 }
03948
03949 if (*def) {
03950 ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc);
03951 } else {
03952 ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
03953 }
03954 }
03955
03956 static char *handle_cli_misdn_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03957 {
03958 char buffer[BUFFERSIZE];
03959 enum misdn_cfg_elements elem;
03960 int linebreak;
03961 int onlyport = -1;
03962 int ok = 0;
03963
03964 switch (cmd) {
03965 case CLI_INIT:
03966 e->command = "misdn show config";
03967 e->usage =
03968 "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
03969 " Use 0 for <port> to only print the general config.\n";
03970 return NULL;
03971 case CLI_GENERATE:
03972 return complete_show_config(a);
03973 }
03974
03975 if (a->argc >= 4) {
03976 if (!strcmp(a->argv[3], "description")) {
03977 if (a->argc == 5) {
03978 enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]);
03979 if (elem == MISDN_CFG_FIRST) {
03980 ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]);
03981 } else {
03982 show_config_description(a->fd, elem);
03983 }
03984 return CLI_SUCCESS;
03985 }
03986 return CLI_SHOWUSAGE;
03987 } else if (!strcmp(a->argv[3], "descriptions")) {
03988 if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "general"))) {
03989 for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
03990 show_config_description(a->fd, elem);
03991 ast_cli(a->fd, "\n");
03992 }
03993 ok = 1;
03994 }
03995 if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "ports"))) {
03996 for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 ; ++elem) {
03997 show_config_description(a->fd, elem);
03998 ast_cli(a->fd, "\n");
03999 }
04000 ok = 1;
04001 }
04002 return ok ? CLI_SUCCESS : CLI_SHOWUSAGE;
04003 } else if (!sscanf(a->argv[3], "%5d", &onlyport) || onlyport < 0) {
04004 ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
04005 return CLI_SHOWUSAGE;
04006 }
04007 }
04008
04009 if (a->argc == 3 || onlyport == 0) {
04010 ast_cli(a->fd, "mISDN General-Config:\n");
04011 for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
04012 misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
04013 ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04014 }
04015 ast_cli(a->fd, "\n");
04016 }
04017
04018 if (onlyport < 0) {
04019 int port = misdn_cfg_get_next_port(0);
04020
04021 for (; port > 0; port = misdn_cfg_get_next_port(port)) {
04022 ast_cli(a->fd, "\n[PORT %d]\n", port);
04023 for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
04024 misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
04025 ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04026 }
04027 ast_cli(a->fd, "\n");
04028 }
04029 }
04030
04031 if (onlyport > 0) {
04032 if (misdn_cfg_is_port_valid(onlyport)) {
04033 ast_cli(a->fd, "[PORT %d]\n", onlyport);
04034 for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
04035 misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
04036 ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04037 }
04038 ast_cli(a->fd, "\n");
04039 } else {
04040 ast_cli(a->fd, "Port %d is not active!\n", onlyport);
04041 }
04042 }
04043
04044 return CLI_SUCCESS;
04045 }
04046
04047 struct state_struct {
04048 enum misdn_chan_state state;
04049 char txt[255];
04050 };
04051
04052 static const struct state_struct state_array[] = {
04053
04054 { MISDN_NOTHING, "NOTHING" },
04055 { MISDN_WAITING4DIGS, "WAITING4DIGS" },
04056 { MISDN_EXTCANTMATCH, "EXTCANTMATCH" },
04057 { MISDN_INCOMING_SETUP, "INCOMING SETUP" },
04058 { MISDN_DIALING, "DIALING" },
04059 { MISDN_PROGRESS, "PROGRESS" },
04060 { MISDN_PROCEEDING, "PROCEEDING" },
04061 { MISDN_CALLING, "CALLING" },
04062 { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" },
04063 { MISDN_ALERTING, "ALERTING" },
04064 { MISDN_BUSY, "BUSY" },
04065 { MISDN_CONNECTED, "CONNECTED" },
04066 { MISDN_DISCONNECTED, "DISCONNECTED" },
04067 { MISDN_CLEANING, "CLEANING" },
04068
04069 };
04070
04071 static const char *misdn_get_ch_state(struct chan_list *p)
04072 {
04073 int i;
04074 static char state[8];
04075
04076 if (!p) {
04077 return NULL;
04078 }
04079
04080 for (i = 0; i < ARRAY_LEN(state_array); i++) {
04081 if (state_array[i].state == p->state) {
04082 return state_array[i].txt;
04083 }
04084 }
04085
04086 snprintf(state, sizeof(state), "%d", p->state) ;
04087
04088 return state;
04089 }
04090
04091
04092 static void reload_config(void)
04093 {
04094 int i, cfg_debug;
04095
04096 if (!g_config_initialized) {
04097 ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
04098 return ;
04099 }
04100
04101 free_robin_list();
04102 misdn_cfg_reload();
04103 misdn_cfg_update_ptp();
04104 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
04105 misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(cfg_debug));
04106
04107 for (i = 0; i <= max_ports; i++) {
04108 misdn_debug[i] = cfg_debug;
04109 misdn_debug_only[i] = 0;
04110 }
04111 }
04112
04113 static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04114 {
04115 switch (cmd) {
04116 case CLI_INIT:
04117 e->command = "misdn reload";
04118 e->usage =
04119 "Usage: misdn reload\n"
04120 " Reload internal mISDN config, read from the config\n"
04121 " file.\n";
04122 return NULL;
04123 case CLI_GENERATE:
04124 return NULL;
04125 }
04126
04127 if (a->argc != 2) {
04128 return CLI_SHOWUSAGE;
04129 }
04130
04131 ast_cli(a->fd, "Reloading mISDN configuration\n");
04132 reload_config();
04133 return CLI_SUCCESS;
04134 }
04135
04136 static void print_bc_info(int fd, struct chan_list *help, struct misdn_bchannel *bc)
04137 {
04138 struct ast_channel *ast = help->ast;
04139
04140 ast_cli(fd,
04141 "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n"
04142 " --> caller:\"%s\" <%s>\n"
04143 " --> redirecting-from:\"%s\" <%s>\n"
04144 " --> redirecting-to:\"%s\" <%s>\n"
04145 " --> context:%s state:%s\n",
04146 bc->pid,
04147 bc->port,
04148 bc->channel,
04149 bc->nt ? "NT" : "TE",
04150 help->originator == ORG_AST ? "*" : "I",
04151 ast ? ast->exten : "",
04152 (ast && ast->caller.id.name.valid && ast->caller.id.name.str)
04153 ? ast->caller.id.name.str : "",
04154 (ast && ast->caller.id.number.valid && ast->caller.id.number.str)
04155 ? ast->caller.id.number.str : "",
04156 bc->redirecting.from.name,
04157 bc->redirecting.from.number,
04158 bc->redirecting.to.name,
04159 bc->redirecting.to.number,
04160 ast ? ast->context : "",
04161 misdn_get_ch_state(help));
04162 if (misdn_debug[bc->port] > 0) {
04163 ast_cli(fd,
04164 " --> astname: %s\n"
04165 " --> ch_l3id: %x\n"
04166 " --> ch_addr: %x\n"
04167 " --> bc_addr: %x\n"
04168 " --> bc_l3id: %x\n"
04169 " --> display: %s\n"
04170 " --> activated: %d\n"
04171 " --> state: %s\n"
04172 " --> capability: %s\n"
04173 #ifdef MISDN_1_2
04174 " --> pipeline: %s\n"
04175 #else
04176 " --> echo_cancel: %d\n"
04177 #endif
04178 " --> notone : rx %d tx:%d\n"
04179 " --> bc_hold: %d\n",
04180 ast ? ast->name : "",
04181 help->l3id,
04182 help->addr,
04183 bc->addr,
04184 bc->l3_id,
04185 bc->display,
04186 bc->active,
04187 bc_state2str(bc->bc_state),
04188 bearer2str(bc->capability),
04189 #ifdef MISDN_1_2
04190 bc->pipeline,
04191 #else
04192 bc->ec_enable,
04193 #endif
04194 help->norxtone, help->notxtone,
04195 bc->holded);
04196 }
04197 }
04198
04199 static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04200 {
04201 struct chan_list *help;
04202
04203 switch (cmd) {
04204 case CLI_INIT:
04205 e->command = "misdn show channels";
04206 e->usage =
04207 "Usage: misdn show channels\n"
04208 " Show the internal mISDN channel list\n";
04209 return NULL;
04210 case CLI_GENERATE:
04211 return NULL;
04212 }
04213
04214 if (a->argc != 3) {
04215 return CLI_SHOWUSAGE;
04216 }
04217
04218 ast_cli(a->fd, "Channel List: %p\n", cl_te);
04219
04220
04221
04222
04223
04224
04225
04226 ast_mutex_lock(&cl_te_lock);
04227 for (help = cl_te; help; help = help->next) {
04228 struct misdn_bchannel *bc = help->bc;
04229 struct ast_channel *ast = help->ast;
04230 if (!ast) {
04231 if (!bc) {
04232 ast_cli(a->fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
04233 continue;
04234 }
04235 ast_cli(a->fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
04236 }
04237
04238 if (misdn_debug[0] > 2) {
04239 ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
04240 }
04241 if (bc) {
04242 print_bc_info(a->fd, help, bc);
04243 } else {
04244 if (help->hold.state != MISDN_HOLD_IDLE) {
04245 ast_cli(a->fd, "ITS A HELD CALL BC:\n");
04246 ast_cli(a->fd, " --> l3_id: %x\n"
04247 " --> dialed:%s\n"
04248 " --> caller:\"%s\" <%s>\n"
04249 " --> hold_port: %d\n"
04250 " --> hold_channel: %d\n",
04251 help->l3id,
04252 ast->exten,
04253 S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
04254 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
04255 help->hold.port,
04256 help->hold.channel
04257 );
04258 } else {
04259 ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n",
04260 ast->exten,
04261 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""));
04262 }
04263 }
04264 }
04265 ast_mutex_unlock(&cl_te_lock);
04266
04267 misdn_dump_chanlist();
04268
04269 return CLI_SUCCESS;
04270 }
04271
04272 static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04273 {
04274 struct chan_list *help;
04275
04276 switch (cmd) {
04277 case CLI_INIT:
04278 e->command = "misdn show channel";
04279 e->usage =
04280 "Usage: misdn show channel <channel>\n"
04281 " Show an internal mISDN channel\n.";
04282 return NULL;
04283 case CLI_GENERATE:
04284 return complete_ch(a);
04285 }
04286
04287 if (a->argc != 4) {
04288 return CLI_SHOWUSAGE;
04289 }
04290
04291 ast_mutex_lock(&cl_te_lock);
04292 for (help = cl_te; help; help = help->next) {
04293 struct misdn_bchannel *bc = help->bc;
04294 struct ast_channel *ast = help->ast;
04295
04296 if (bc && ast) {
04297 if (!strcasecmp(ast->name, a->argv[3])) {
04298 print_bc_info(a->fd, help, bc);
04299 break;
04300 }
04301 }
04302 }
04303 ast_mutex_unlock(&cl_te_lock);
04304
04305 return CLI_SUCCESS;
04306 }
04307
04308 static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04309 {
04310 switch (cmd) {
04311 case CLI_INIT:
04312 e->command = "misdn set tics";
04313 e->usage =
04314 "Usage: misdn set tics <value>\n";
04315 return NULL;
04316 case CLI_GENERATE:
04317 return NULL;
04318 }
04319
04320 if (a->argc != 4) {
04321 return CLI_SHOWUSAGE;
04322 }
04323
04324
04325 MAXTICS = atoi(a->argv[3]);
04326
04327 return CLI_SUCCESS;
04328 }
04329
04330 static char *handle_cli_misdn_show_stacks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04331 {
04332 int port;
04333
04334 switch (cmd) {
04335 case CLI_INIT:
04336 e->command = "misdn show stacks";
04337 e->usage =
04338 "Usage: misdn show stacks\n"
04339 " Show internal mISDN stack_list.\n";
04340 return NULL;
04341 case CLI_GENERATE:
04342 return NULL;
04343 }
04344
04345 if (a->argc != 3) {
04346 return CLI_SHOWUSAGE;
04347 }
04348
04349 ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04350 for (port = misdn_cfg_get_next_port(0); port > 0;
04351 port = misdn_cfg_get_next_port(port)) {
04352 char buf[128];
04353
04354 get_show_stack_details(port, buf);
04355 ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04356 }
04357
04358 return CLI_SUCCESS;
04359 }
04360
04361 static char *handle_cli_misdn_show_ports_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04362 {
04363 int port;
04364
04365 switch (cmd) {
04366 case CLI_INIT:
04367 e->command = "misdn show ports stats";
04368 e->usage =
04369 "Usage: misdn show ports stats\n"
04370 " Show mISDNs channel's call statistics per port.\n";
04371 return NULL;
04372 case CLI_GENERATE:
04373 return NULL;
04374 }
04375
04376 if (a->argc != 4) {
04377 return CLI_SHOWUSAGE;
04378 }
04379
04380 ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
04381 for (port = misdn_cfg_get_next_port(0); port > 0;
04382 port = misdn_cfg_get_next_port(port)) {
04383 ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
04384 }
04385 ast_cli(a->fd, "\n");
04386
04387 return CLI_SUCCESS;
04388 }
04389
04390 static char *handle_cli_misdn_show_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04391 {
04392 int port;
04393 char buf[128];
04394
04395 switch (cmd) {
04396 case CLI_INIT:
04397 e->command = "misdn show port";
04398 e->usage =
04399 "Usage: misdn show port <port>\n"
04400 " Show detailed information for given port.\n";
04401 return NULL;
04402 case CLI_GENERATE:
04403 return NULL;
04404 }
04405
04406 if (a->argc != 4) {
04407 return CLI_SHOWUSAGE;
04408 }
04409
04410 port = atoi(a->argv[3]);
04411
04412 ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04413 get_show_stack_details(port, buf);
04414 ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04415
04416 return CLI_SUCCESS;
04417 }
04418
04419 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
04420 static const struct FacParm Fac_Msgs[] = {
04421
04422 [0].Function = Fac_ERROR,
04423 [0].u.ERROR.invokeId = 8,
04424 [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
04425
04426 [1].Function = Fac_RESULT,
04427 [1].u.RESULT.InvokeID = 9,
04428
04429 [2].Function = Fac_REJECT,
04430 [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
04431
04432 [3].Function = Fac_REJECT,
04433 [3].u.REJECT.InvokeIDPresent = 1,
04434 [3].u.REJECT.InvokeID = 10,
04435 [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
04436
04437 [4].Function = Fac_REJECT,
04438 [4].u.REJECT.InvokeIDPresent = 1,
04439 [4].u.REJECT.InvokeID = 11,
04440 [4].u.REJECT.Code = FacReject_Res_MistypedResult,
04441
04442 [5].Function = Fac_REJECT,
04443 [5].u.REJECT.InvokeIDPresent = 1,
04444 [5].u.REJECT.InvokeID = 12,
04445 [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
04446
04447 [6].Function = Fac_StatusRequest,
04448 [6].u.StatusRequest.InvokeID = 13,
04449 [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
04450 [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04451 [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
04452 [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
04453 [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
04454 [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
04455 [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
04456 [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
04457
04458 [7].Function = Fac_StatusRequest,
04459 [7].u.StatusRequest.InvokeID = 14,
04460 [7].u.StatusRequest.ComponentType = FacComponent_Result,
04461 [7].u.StatusRequest.Component.Result.Status = 2,
04462
04463 [8].Function = Fac_CallInfoRetain,
04464 [8].u.CallInfoRetain.InvokeID = 15,
04465 [8].u.CallInfoRetain.CallLinkageID = 115,
04466
04467 [9].Function = Fac_EraseCallLinkageID,
04468 [9].u.EraseCallLinkageID.InvokeID = 16,
04469 [9].u.EraseCallLinkageID.CallLinkageID = 105,
04470
04471 [10].Function = Fac_CCBSDeactivate,
04472 [10].u.CCBSDeactivate.InvokeID = 17,
04473 [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
04474 [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
04475
04476 [11].Function = Fac_CCBSDeactivate,
04477 [11].u.CCBSDeactivate.InvokeID = 18,
04478 [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
04479
04480 [12].Function = Fac_CCBSErase,
04481 [12].u.CCBSErase.InvokeID = 19,
04482 [12].u.CCBSErase.Q931ie.Bc.Length = 2,
04483 [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04484 [12].u.CCBSErase.AddressOfB.Party.Type = 0,
04485 [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
04486 [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
04487 [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04488 [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04489 [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04490 [12].u.CCBSErase.RecallMode = 1,
04491 [12].u.CCBSErase.CCBSReference = 102,
04492 [12].u.CCBSErase.Reason = 3,
04493
04494 [13].Function = Fac_CCBSErase,
04495 [13].u.CCBSErase.InvokeID = 20,
04496 [13].u.CCBSErase.Q931ie.Bc.Length = 2,
04497 [13].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04498 [13].u.CCBSErase.AddressOfB.Party.Type = 1,
04499 [13].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04500 [13].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 1,
04501 [13].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04502 [13].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04503 [13].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04504 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCountPresent = 1,
04505 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCount = 1,
04506 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04507 [13].u.CCBSErase.RecallMode = 1,
04508 [13].u.CCBSErase.CCBSReference = 102,
04509 [13].u.CCBSErase.Reason = 3,
04510
04511 [14].Function = Fac_CCBSErase,
04512 [14].u.CCBSErase.InvokeID = 21,
04513 [14].u.CCBSErase.Q931ie.Bc.Length = 2,
04514 [14].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04515 [14].u.CCBSErase.AddressOfB.Party.Type = 2,
04516 [14].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04517 [14].u.CCBSErase.AddressOfB.Party.Number = "1803",
04518 [14].u.CCBSErase.AddressOfB.Subaddress.Type = 1,
04519 [14].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04520 [14].u.CCBSErase.AddressOfB.Subaddress.u.Nsap = "6492",
04521 [14].u.CCBSErase.RecallMode = 1,
04522 [14].u.CCBSErase.CCBSReference = 102,
04523 [14].u.CCBSErase.Reason = 3,
04524
04525 [15].Function = Fac_CCBSErase,
04526 [15].u.CCBSErase.InvokeID = 22,
04527 [15].u.CCBSErase.Q931ie.Bc.Length = 2,
04528 [15].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04529 [15].u.CCBSErase.AddressOfB.Party.Type = 3,
04530 [15].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04531 [15].u.CCBSErase.AddressOfB.Party.Number = "1803",
04532 [15].u.CCBSErase.RecallMode = 1,
04533 [15].u.CCBSErase.CCBSReference = 102,
04534 [15].u.CCBSErase.Reason = 3,
04535
04536 [16].Function = Fac_CCBSErase,
04537 [16].u.CCBSErase.InvokeID = 23,
04538 [16].u.CCBSErase.Q931ie.Bc.Length = 2,
04539 [16].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04540 [16].u.CCBSErase.AddressOfB.Party.Type = 4,
04541 [16].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04542 [16].u.CCBSErase.AddressOfB.Party.Number = "1803",
04543 [16].u.CCBSErase.RecallMode = 1,
04544 [16].u.CCBSErase.CCBSReference = 102,
04545 [16].u.CCBSErase.Reason = 3,
04546
04547 [17].Function = Fac_CCBSErase,
04548 [17].u.CCBSErase.InvokeID = 24,
04549 [17].u.CCBSErase.Q931ie.Bc.Length = 2,
04550 [17].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04551 [17].u.CCBSErase.AddressOfB.Party.Type = 5,
04552 [17].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04553 [17].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 4,
04554 [17].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04555 [17].u.CCBSErase.RecallMode = 1,
04556 [17].u.CCBSErase.CCBSReference = 102,
04557 [17].u.CCBSErase.Reason = 3,
04558
04559 [18].Function = Fac_CCBSErase,
04560 [18].u.CCBSErase.InvokeID = 25,
04561 [18].u.CCBSErase.Q931ie.Bc.Length = 2,
04562 [18].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04563 [18].u.CCBSErase.AddressOfB.Party.Type = 8,
04564 [18].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04565 [18].u.CCBSErase.AddressOfB.Party.Number = "1803",
04566 [18].u.CCBSErase.RecallMode = 1,
04567 [18].u.CCBSErase.CCBSReference = 102,
04568 [18].u.CCBSErase.Reason = 3,
04569
04570 [19].Function = Fac_CCBSRemoteUserFree,
04571 [19].u.CCBSRemoteUserFree.InvokeID = 26,
04572 [19].u.CCBSRemoteUserFree.Q931ie.Bc.Length = 2,
04573 [19].u.CCBSRemoteUserFree.Q931ie.Bc.Contents = "JK",
04574 [19].u.CCBSRemoteUserFree.AddressOfB.Party.Type = 8,
04575 [19].u.CCBSRemoteUserFree.AddressOfB.Party.LengthOfNumber = 4,
04576 [19].u.CCBSRemoteUserFree.AddressOfB.Party.Number = "1803",
04577 [19].u.CCBSRemoteUserFree.RecallMode = 1,
04578 [19].u.CCBSRemoteUserFree.CCBSReference = 102,
04579
04580 [20].Function = Fac_CCBSCall,
04581 [20].u.CCBSCall.InvokeID = 27,
04582 [20].u.CCBSCall.CCBSReference = 115,
04583
04584 [21].Function = Fac_CCBSStatusRequest,
04585 [21].u.CCBSStatusRequest.InvokeID = 28,
04586 [21].u.CCBSStatusRequest.ComponentType = FacComponent_Invoke,
04587 [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04588 [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Contents = "JK",
04589 [21].u.CCBSStatusRequest.Component.Invoke.RecallMode = 1,
04590 [21].u.CCBSStatusRequest.Component.Invoke.CCBSReference = 102,
04591
04592 [22].Function = Fac_CCBSStatusRequest,
04593 [22].u.CCBSStatusRequest.InvokeID = 29,
04594 [22].u.CCBSStatusRequest.ComponentType = FacComponent_Result,
04595 [22].u.CCBSStatusRequest.Component.Result.Free = 1,
04596
04597 [23].Function = Fac_CCBSBFree,
04598 [23].u.CCBSBFree.InvokeID = 30,
04599 [23].u.CCBSBFree.Q931ie.Bc.Length = 2,
04600 [23].u.CCBSBFree.Q931ie.Bc.Contents = "JK",
04601 [23].u.CCBSBFree.AddressOfB.Party.Type = 8,
04602 [23].u.CCBSBFree.AddressOfB.Party.LengthOfNumber = 4,
04603 [23].u.CCBSBFree.AddressOfB.Party.Number = "1803",
04604 [23].u.CCBSBFree.RecallMode = 1,
04605 [23].u.CCBSBFree.CCBSReference = 14,
04606
04607 [24].Function = Fac_CCBSStopAlerting,
04608 [24].u.CCBSStopAlerting.InvokeID = 31,
04609 [24].u.CCBSStopAlerting.CCBSReference = 37,
04610
04611 [25].Function = Fac_CCBSRequest,
04612 [25].u.CCBSRequest.InvokeID = 32,
04613 [25].u.CCBSRequest.ComponentType = FacComponent_Invoke,
04614 [25].u.CCBSRequest.Component.Invoke.CallLinkageID = 57,
04615
04616 [26].Function = Fac_CCBSRequest,
04617 [26].u.CCBSRequest.InvokeID = 33,
04618 [26].u.CCBSRequest.ComponentType = FacComponent_Result,
04619 [26].u.CCBSRequest.Component.Result.RecallMode = 1,
04620 [26].u.CCBSRequest.Component.Result.CCBSReference = 102,
04621
04622 [27].Function = Fac_CCBSInterrogate,
04623 [27].u.CCBSInterrogate.InvokeID = 34,
04624 [27].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04625 [27].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04626 [27].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04627 [27].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04628 [27].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04629 [27].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04630
04631 [28].Function = Fac_CCBSInterrogate,
04632 [28].u.CCBSInterrogate.InvokeID = 35,
04633 [28].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04634 [28].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04635 [28].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04636 [28].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04637
04638 [29].Function = Fac_CCBSInterrogate,
04639 [29].u.CCBSInterrogate.InvokeID = 36,
04640 [29].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04641 [29].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04642 [29].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04643
04644 [30].Function = Fac_CCBSInterrogate,
04645 [30].u.CCBSInterrogate.InvokeID = 37,
04646 [30].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04647
04648 [31].Function = Fac_CCBSInterrogate,
04649 [31].u.CCBSInterrogate.InvokeID = 38,
04650 [31].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04651 [31].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04652
04653 [32].Function = Fac_CCBSInterrogate,
04654 [32].u.CCBSInterrogate.InvokeID = 39,
04655 [32].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04656 [32].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04657 [32].u.CCBSInterrogate.Component.Result.NumRecords = 1,
04658 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04659 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04660 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04661 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04662 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04663 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04664 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Type = 1,
04665 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Length = 4,
04666 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.u.Nsap = "6492",
04667
04668 [33].Function = Fac_CCBSInterrogate,
04669 [33].u.CCBSInterrogate.InvokeID = 40,
04670 [33].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04671 [33].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04672 [33].u.CCBSInterrogate.Component.Result.NumRecords = 2,
04673 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04674 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04675 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04676 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04677 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04678 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04679 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].CCBSReference = 102,
04680 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Length = 2,
04681 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Contents = "LM",
04682 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Type = 8,
04683 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.LengthOfNumber = 4,
04684 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Number = "6229",
04685 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Type = 1,
04686 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Length = 4,
04687 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.u.Nsap = "8592",
04688 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Type = 1,
04689 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Length = 4,
04690 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.u.Nsap = "6492",
04691
04692 [34].Function = Fac_CCNRRequest,
04693 [34].u.CCNRRequest.InvokeID = 512,
04694 [34].u.CCNRRequest.ComponentType = FacComponent_Invoke,
04695 [34].u.CCNRRequest.Component.Invoke.CallLinkageID = 57,
04696
04697 [35].Function = Fac_CCNRRequest,
04698 [35].u.CCNRRequest.InvokeID = 150,
04699 [35].u.CCNRRequest.ComponentType = FacComponent_Result,
04700 [35].u.CCNRRequest.Component.Result.RecallMode = 1,
04701 [35].u.CCNRRequest.Component.Result.CCBSReference = 102,
04702
04703 [36].Function = Fac_CCNRInterrogate,
04704 [36].u.CCNRInterrogate.InvokeID = -129,
04705 [36].u.CCNRInterrogate.ComponentType = FacComponent_Invoke,
04706
04707 [37].Function = Fac_CCNRInterrogate,
04708 [37].u.CCNRInterrogate.InvokeID = -3,
04709 [37].u.CCNRInterrogate.ComponentType = FacComponent_Result,
04710 [37].u.CCNRInterrogate.Component.Result.RecallMode = 1,
04711
04712 [38].Function = Fac_CCBS_T_Call,
04713 [38].u.EctExecute.InvokeID = 41,
04714
04715 [39].Function = Fac_CCBS_T_Suspend,
04716 [39].u.EctExecute.InvokeID = 42,
04717
04718 [40].Function = Fac_CCBS_T_Resume,
04719 [40].u.EctExecute.InvokeID = 43,
04720
04721 [41].Function = Fac_CCBS_T_RemoteUserFree,
04722 [41].u.EctExecute.InvokeID = 44,
04723
04724 [42].Function = Fac_CCBS_T_Available,
04725 [42].u.EctExecute.InvokeID = 45,
04726
04727 [43].Function = Fac_CCBS_T_Request,
04728 [43].u.CCBS_T_Request.InvokeID = 46,
04729 [43].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04730 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04731 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04732 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04733 [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04734 [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04735 [43].u.CCBS_T_Request.Component.Invoke.RetentionSupported = 1,
04736 [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04737 [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04738 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04739 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04740 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04741
04742 [44].Function = Fac_CCBS_T_Request,
04743 [44].u.CCBS_T_Request.InvokeID = 47,
04744 [44].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04745 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04746 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04747 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04748 [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04749 [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04750 [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04751 [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04752 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04753 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04754 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04755
04756 [45].Function = Fac_CCBS_T_Request,
04757 [45].u.CCBS_T_Request.InvokeID = 48,
04758 [45].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04759 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04760 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04761 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04762 [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04763 [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04764 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04765 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04766 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04767
04768 [46].Function = Fac_CCBS_T_Request,
04769 [46].u.CCBS_T_Request.InvokeID = 49,
04770 [46].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04771 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04772 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04773 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04774 [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04775 [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04776 [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04777 [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04778
04779 [47].Function = Fac_CCBS_T_Request,
04780 [47].u.CCBS_T_Request.InvokeID = 50,
04781 [47].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04782 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04783 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04784 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04785 [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04786 [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04787
04788 [48].Function = Fac_CCBS_T_Request,
04789 [48].u.CCBS_T_Request.InvokeID = 51,
04790 [48].u.CCBS_T_Request.ComponentType = FacComponent_Result,
04791 [48].u.CCBS_T_Request.Component.Result.RetentionSupported = 1,
04792
04793 [49].Function = Fac_CCNR_T_Request,
04794 [49].u.CCNR_T_Request.InvokeID = 52,
04795 [49].u.CCNR_T_Request.ComponentType = FacComponent_Invoke,
04796 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Type = 8,
04797 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04798 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04799 [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04800 [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04801
04802 [50].Function = Fac_CCNR_T_Request,
04803 [50].u.CCNR_T_Request.InvokeID = 53,
04804 [50].u.CCNR_T_Request.ComponentType = FacComponent_Result,
04805 [50].u.CCNR_T_Request.Component.Result.RetentionSupported = 1,
04806
04807 [51].Function = Fac_EctExecute,
04808 [51].u.EctExecute.InvokeID = 54,
04809
04810 [52].Function = Fac_ExplicitEctExecute,
04811 [52].u.ExplicitEctExecute.InvokeID = 55,
04812 [52].u.ExplicitEctExecute.LinkID = 23,
04813
04814 [53].Function = Fac_RequestSubaddress,
04815 [53].u.RequestSubaddress.InvokeID = 56,
04816
04817 [54].Function = Fac_SubaddressTransfer,
04818 [54].u.SubaddressTransfer.InvokeID = 57,
04819 [54].u.SubaddressTransfer.Subaddress.Type = 1,
04820 [54].u.SubaddressTransfer.Subaddress.Length = 4,
04821 [54].u.SubaddressTransfer.Subaddress.u.Nsap = "6492",
04822
04823 [55].Function = Fac_EctLinkIdRequest,
04824 [55].u.EctLinkIdRequest.InvokeID = 58,
04825 [55].u.EctLinkIdRequest.ComponentType = FacComponent_Invoke,
04826
04827 [56].Function = Fac_EctLinkIdRequest,
04828 [56].u.EctLinkIdRequest.InvokeID = 59,
04829 [56].u.EctLinkIdRequest.ComponentType = FacComponent_Result,
04830 [56].u.EctLinkIdRequest.Component.Result.LinkID = 76,
04831
04832 [57].Function = Fac_EctInform,
04833 [57].u.EctInform.InvokeID = 60,
04834 [57].u.EctInform.Status = 1,
04835 [57].u.EctInform.RedirectionPresent = 1,
04836 [57].u.EctInform.Redirection.Type = 0,
04837 [57].u.EctInform.Redirection.Unscreened.Type = 8,
04838 [57].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04839 [57].u.EctInform.Redirection.Unscreened.Number = "6229",
04840
04841 [58].Function = Fac_EctInform,
04842 [58].u.EctInform.InvokeID = 61,
04843 [58].u.EctInform.Status = 1,
04844 [58].u.EctInform.RedirectionPresent = 1,
04845 [58].u.EctInform.Redirection.Type = 1,
04846
04847 [59].Function = Fac_EctInform,
04848 [59].u.EctInform.InvokeID = 62,
04849 [59].u.EctInform.Status = 1,
04850 [59].u.EctInform.RedirectionPresent = 1,
04851 [59].u.EctInform.Redirection.Type = 2,
04852
04853 [60].Function = Fac_EctInform,
04854 [60].u.EctInform.InvokeID = 63,
04855 [60].u.EctInform.Status = 1,
04856 [60].u.EctInform.RedirectionPresent = 1,
04857 [60].u.EctInform.Redirection.Type = 3,
04858 [60].u.EctInform.Redirection.Unscreened.Type = 8,
04859 [60].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04860 [60].u.EctInform.Redirection.Unscreened.Number = "3340",
04861
04862 [61].Function = Fac_EctInform,
04863 [61].u.EctInform.InvokeID = 64,
04864 [61].u.EctInform.Status = 1,
04865 [61].u.EctInform.RedirectionPresent = 0,
04866
04867 [62].Function = Fac_EctLoopTest,
04868 [62].u.EctLoopTest.InvokeID = 65,
04869 [62].u.EctLoopTest.ComponentType = FacComponent_Invoke,
04870 [62].u.EctLoopTest.Component.Invoke.CallTransferID = 7,
04871
04872 [63].Function = Fac_EctLoopTest,
04873 [63].u.EctLoopTest.InvokeID = 66,
04874 [63].u.EctLoopTest.ComponentType = FacComponent_Result,
04875 [63].u.EctLoopTest.Component.Result.LoopResult = 2,
04876
04877 [64].Function = Fac_ActivationDiversion,
04878 [64].u.ActivationDiversion.InvokeID = 67,
04879 [64].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04880 [64].u.ActivationDiversion.Component.Invoke.Procedure = 2,
04881 [64].u.ActivationDiversion.Component.Invoke.BasicService = 3,
04882 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04883 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04884 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04885 [64].u.ActivationDiversion.Component.Invoke.ServedUser.Type = 4,
04886 [64].u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber = 4,
04887 [64].u.ActivationDiversion.Component.Invoke.ServedUser.Number = "5398",
04888
04889 [65].Function = Fac_ActivationDiversion,
04890 [65].u.ActivationDiversion.InvokeID = 68,
04891 [65].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04892 [65].u.ActivationDiversion.Component.Invoke.Procedure = 1,
04893 [65].u.ActivationDiversion.Component.Invoke.BasicService = 5,
04894 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04895 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04896 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04897
04898 [66].Function = Fac_ActivationDiversion,
04899 [66].u.ActivationDiversion.InvokeID = 69,
04900 [66].u.ActivationDiversion.ComponentType = FacComponent_Result,
04901
04902 [67].Function = Fac_DeactivationDiversion,
04903 [67].u.DeactivationDiversion.InvokeID = 70,
04904 [67].u.DeactivationDiversion.ComponentType = FacComponent_Invoke,
04905 [67].u.DeactivationDiversion.Component.Invoke.Procedure = 1,
04906 [67].u.DeactivationDiversion.Component.Invoke.BasicService = 5,
04907
04908 [68].Function = Fac_DeactivationDiversion,
04909 [68].u.DeactivationDiversion.InvokeID = 71,
04910 [68].u.DeactivationDiversion.ComponentType = FacComponent_Result,
04911
04912 [69].Function = Fac_ActivationStatusNotificationDiv,
04913 [69].u.ActivationStatusNotificationDiv.InvokeID = 72,
04914 [69].u.ActivationStatusNotificationDiv.Procedure = 1,
04915 [69].u.ActivationStatusNotificationDiv.BasicService = 5,
04916 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Type = 4,
04917 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.LengthOfNumber = 4,
04918 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Number = "1803",
04919
04920 [70].Function = Fac_DeactivationStatusNotificationDiv,
04921 [70].u.DeactivationStatusNotificationDiv.InvokeID = 73,
04922 [70].u.DeactivationStatusNotificationDiv.Procedure = 1,
04923 [70].u.DeactivationStatusNotificationDiv.BasicService = 5,
04924
04925 [71].Function = Fac_InterrogationDiversion,
04926 [71].u.InterrogationDiversion.InvokeID = 74,
04927 [71].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04928 [71].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04929 [71].u.InterrogationDiversion.Component.Invoke.BasicService = 5,
04930
04931 [72].Function = Fac_InterrogationDiversion,
04932 [72].u.InterrogationDiversion.InvokeID = 75,
04933 [72].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04934 [72].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04935
04936 [73].Function = Fac_InterrogationDiversion,
04937 [73].u.InterrogationDiversion.InvokeID = 76,
04938 [73].u.InterrogationDiversion.ComponentType = FacComponent_Result,
04939 [73].u.InterrogationDiversion.Component.Result.NumRecords = 2,
04940 [73].u.InterrogationDiversion.Component.Result.List[0].Procedure = 2,
04941 [73].u.InterrogationDiversion.Component.Result.List[0].BasicService = 5,
04942 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Type = 4,
04943 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.LengthOfNumber = 4,
04944 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Number = "1803",
04945 [73].u.InterrogationDiversion.Component.Result.List[1].Procedure = 1,
04946 [73].u.InterrogationDiversion.Component.Result.List[1].BasicService = 3,
04947 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Type = 4,
04948 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.LengthOfNumber = 4,
04949 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Number = "1903",
04950 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Type = 4,
04951 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.LengthOfNumber = 4,
04952 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Number = "5398",
04953
04954 [74].Function = Fac_DiversionInformation,
04955 [74].u.DiversionInformation.InvokeID = 77,
04956 [74].u.DiversionInformation.DiversionReason = 3,
04957 [74].u.DiversionInformation.BasicService = 5,
04958 [74].u.DiversionInformation.ServedUserSubaddress.Type = 1,
04959 [74].u.DiversionInformation.ServedUserSubaddress.Length = 4,
04960 [74].u.DiversionInformation.ServedUserSubaddress.u.Nsap = "6492",
04961 [74].u.DiversionInformation.CallingAddressPresent = 1,
04962 [74].u.DiversionInformation.CallingAddress.Type = 0,
04963 [74].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 3,
04964 [74].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
04965 [74].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
04966 [74].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
04967 [74].u.DiversionInformation.OriginalCalledPresent = 1,
04968 [74].u.DiversionInformation.OriginalCalled.Type = 1,
04969 [74].u.DiversionInformation.LastDivertingPresent = 1,
04970 [74].u.DiversionInformation.LastDiverting.Type = 2,
04971 [74].u.DiversionInformation.LastDivertingReasonPresent = 1,
04972 [74].u.DiversionInformation.LastDivertingReason = 3,
04973 [74].u.DiversionInformation.UserInfo.Length = 5,
04974 [74].u.DiversionInformation.UserInfo.Contents = "79828",
04975
04976 [75].Function = Fac_DiversionInformation,
04977 [75].u.DiversionInformation.InvokeID = 78,
04978 [75].u.DiversionInformation.DiversionReason = 3,
04979 [75].u.DiversionInformation.BasicService = 5,
04980 [75].u.DiversionInformation.CallingAddressPresent = 1,
04981 [75].u.DiversionInformation.CallingAddress.Type = 1,
04982 [75].u.DiversionInformation.OriginalCalledPresent = 1,
04983 [75].u.DiversionInformation.OriginalCalled.Type = 2,
04984 [75].u.DiversionInformation.LastDivertingPresent = 1,
04985 [75].u.DiversionInformation.LastDiverting.Type = 1,
04986
04987 [76].Function = Fac_DiversionInformation,
04988 [76].u.DiversionInformation.InvokeID = 79,
04989 [76].u.DiversionInformation.DiversionReason = 2,
04990 [76].u.DiversionInformation.BasicService = 3,
04991 [76].u.DiversionInformation.CallingAddressPresent = 1,
04992 [76].u.DiversionInformation.CallingAddress.Type = 2,
04993
04994 [77].Function = Fac_DiversionInformation,
04995 [77].u.DiversionInformation.InvokeID = 80,
04996 [77].u.DiversionInformation.DiversionReason = 3,
04997 [77].u.DiversionInformation.BasicService = 5,
04998 [77].u.DiversionInformation.CallingAddressPresent = 1,
04999 [77].u.DiversionInformation.CallingAddress.Type = 3,
05000 [77].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 2,
05001 [77].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
05002 [77].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
05003 [77].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
05004
05005 [78].Function = Fac_DiversionInformation,
05006 [78].u.DiversionInformation.InvokeID = 81,
05007 [78].u.DiversionInformation.DiversionReason = 2,
05008 [78].u.DiversionInformation.BasicService = 4,
05009 [78].u.DiversionInformation.UserInfo.Length = 5,
05010 [78].u.DiversionInformation.UserInfo.Contents = "79828",
05011
05012 [79].Function = Fac_DiversionInformation,
05013 [79].u.DiversionInformation.InvokeID = 82,
05014 [79].u.DiversionInformation.DiversionReason = 2,
05015 [79].u.DiversionInformation.BasicService = 4,
05016
05017 [80].Function = Fac_CallDeflection,
05018 [80].u.CallDeflection.InvokeID = 83,
05019 [80].u.CallDeflection.ComponentType = FacComponent_Invoke,
05020 [80].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05021 [80].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05022 [80].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05023 [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05024 [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 1,
05025
05026 [81].Function = Fac_CallDeflection,
05027 [81].u.CallDeflection.InvokeID = 84,
05028 [81].u.CallDeflection.ComponentType = FacComponent_Invoke,
05029 [81].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05030 [81].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05031 [81].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05032 [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05033 [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0,
05034
05035 [82].Function = Fac_CallDeflection,
05036 [82].u.CallDeflection.InvokeID = 85,
05037 [82].u.CallDeflection.ComponentType = FacComponent_Invoke,
05038 [82].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05039 [82].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05040 [82].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05041
05042 [83].Function = Fac_CallDeflection,
05043 [83].u.CallDeflection.InvokeID = 86,
05044 [83].u.CallDeflection.ComponentType = FacComponent_Result,
05045
05046 [84].Function = Fac_CallRerouteing,
05047 [84].u.CallRerouteing.InvokeID = 87,
05048 [84].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05049 [84].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05050 [84].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05051 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05052 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05053 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05054 [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05055 [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05056 [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 3,
05057 [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Contents = "RTG",
05058 [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 2,
05059 [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Contents = "MY",
05060 [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 5,
05061 [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Contents = "YEHAW",
05062 [84].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05063 [84].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05064 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Type = 1,
05065 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 4,
05066 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.u.Nsap = "6492",
05067
05068 [85].Function = Fac_CallRerouteing,
05069 [85].u.CallRerouteing.InvokeID = 88,
05070 [85].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05071 [85].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05072 [85].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05073 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05074 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05075 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05076 [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05077 [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05078 [85].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05079 [85].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05080
05081 [86].Function = Fac_CallRerouteing,
05082 [86].u.CallRerouteing.InvokeID = 89,
05083 [86].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05084 [86].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05085 [86].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05086 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05087 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05088 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05089 [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05090 [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05091 [86].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 2,
05092
05093 [87].Function = Fac_CallRerouteing,
05094 [87].u.CallRerouteing.InvokeID = 90,
05095 [87].u.CallRerouteing.ComponentType = FacComponent_Result,
05096
05097 [88].Function = Fac_InterrogateServedUserNumbers,
05098 [88].u.InterrogateServedUserNumbers.InvokeID = 91,
05099 [88].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Invoke,
05100
05101 [89].Function = Fac_InterrogateServedUserNumbers,
05102 [89].u.InterrogateServedUserNumbers.InvokeID = 92,
05103 [89].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Result,
05104 [89].u.InterrogateServedUserNumbers.Component.Result.NumRecords = 2,
05105 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Type = 4,
05106 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].LengthOfNumber = 4,
05107 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Number = "1803",
05108 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Type = 4,
05109 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].LengthOfNumber = 4,
05110 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Number = "5786",
05111
05112 [90].Function = Fac_DivertingLegInformation1,
05113 [90].u.DivertingLegInformation1.InvokeID = 93,
05114 [90].u.DivertingLegInformation1.DiversionReason = 4,
05115 [90].u.DivertingLegInformation1.SubscriptionOption = 1,
05116 [90].u.DivertingLegInformation1.DivertedToPresent = 1,
05117 [90].u.DivertingLegInformation1.DivertedTo.Type = 2,
05118
05119 [91].Function = Fac_DivertingLegInformation1,
05120 [91].u.DivertingLegInformation1.InvokeID = 94,
05121 [91].u.DivertingLegInformation1.DiversionReason = 4,
05122 [91].u.DivertingLegInformation1.SubscriptionOption = 1,
05123
05124 [92].Function = Fac_DivertingLegInformation2,
05125 [92].u.DivertingLegInformation2.InvokeID = 95,
05126 [92].u.DivertingLegInformation2.DiversionCounter = 3,
05127 [92].u.DivertingLegInformation2.DiversionReason = 2,
05128 [92].u.DivertingLegInformation2.DivertingPresent = 1,
05129 [92].u.DivertingLegInformation2.Diverting.Type = 2,
05130 [92].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05131 [92].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05132
05133 [93].Function = Fac_DivertingLegInformation2,
05134 [93].u.DivertingLegInformation2.InvokeID = 96,
05135 [93].u.DivertingLegInformation2.DiversionCounter = 3,
05136 [93].u.DivertingLegInformation2.DiversionReason = 2,
05137 [93].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05138 [93].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05139
05140 [94].Function = Fac_DivertingLegInformation2,
05141 [94].u.DivertingLegInformation2.InvokeID = 97,
05142 [94].u.DivertingLegInformation2.DiversionCounter = 1,
05143 [94].u.DivertingLegInformation2.DiversionReason = 2,
05144
05145 [95].Function = Fac_DivertingLegInformation3,
05146 [95].u.DivertingLegInformation3.InvokeID = 98,
05147 [95].u.DivertingLegInformation3.PresentationAllowedIndicator = 1,
05148
05149 };
05150 #endif
05151
05152 static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05153 {
05154 const char *channame;
05155 const char *nr;
05156 struct chan_list *tmp;
05157 int port;
05158 const char *served_nr;
05159 struct misdn_bchannel dummy, *bc=&dummy;
05160 unsigned max_len;
05161
05162 switch (cmd) {
05163 case CLI_INIT:
05164 e->command = "misdn send facility";
05165 e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
05166 "\t type is one of:\n"
05167 "\t - calldeflect\n"
05168 #if defined(AST_MISDN_ENHANCEMENTS)
05169 "\t - callrerouting\n"
05170 #endif
05171 "\t - CFActivate\n"
05172 "\t - CFDeactivate\n";
05173
05174 return NULL;
05175 case CLI_GENERATE:
05176 return complete_ch(a);
05177 }
05178
05179 if (a->argc < 5) {
05180 return CLI_SHOWUSAGE;
05181 }
05182
05183 if (strstr(a->argv[3], "calldeflect")) {
05184 if (a->argc < 6) {
05185 ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
05186 return 0;
05187 }
05188 channame = a->argv[4];
05189 nr = a->argv[5];
05190
05191 ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
05192 tmp = get_chan_by_ast_name(channame);
05193 if (!tmp) {
05194 ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05195 return 0;
05196 }
05197 ao2_lock(tmp);
05198
05199 #if defined(AST_MISDN_ENHANCEMENTS)
05200 max_len = sizeof(tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
05201 if (max_len < strlen(nr)) {
05202 ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05203 nr, channame, max_len);
05204 ao2_unlock(tmp);
05205 chan_list_unref(tmp, "Number too long");
05206 return 0;
05207 }
05208 tmp->bc->fac_out.Function = Fac_CallDeflection;
05209 tmp->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
05210 tmp->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
05211 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
05212 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
05213 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;
05214 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(nr);
05215 strcpy((char *) tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, nr);
05216 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
05217
05218 #else
05219
05220 max_len = sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
05221 if (max_len < strlen(nr)) {
05222 ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05223 nr, channame, max_len);
05224 ao2_unlock(tmp);
05225 chan_list_unref(tmp, "Number too long");
05226 return 0;
05227 }
05228 tmp->bc->fac_out.Function = Fac_CD;
05229 tmp->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
05230
05231 strcpy((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr);
05232 #endif
05233
05234
05235 print_facility(&tmp->bc->fac_out, tmp->bc);
05236 ao2_unlock(tmp);
05237 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05238 chan_list_unref(tmp, "Send facility complete");
05239 #if defined(AST_MISDN_ENHANCEMENTS)
05240 } else if (strstr(a->argv[3], "callrerouteing") || strstr(a->argv[3], "callrerouting")) {
05241 if (a->argc < 6) {
05242 ast_verbose("callrerouting requires 1 arg: ToNumber\n\n");
05243 return 0;
05244 }
05245 channame = a->argv[4];
05246 nr = a->argv[5];
05247
05248 ast_verbose("Sending Callrerouting (%s) to %s\n", nr, channame);
05249 tmp = get_chan_by_ast_name(channame);
05250 if (!tmp) {
05251 ast_verbose("Sending Call Rerouting with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05252 return 0;
05253 }
05254 ao2_lock(tmp);
05255
05256 max_len = sizeof(tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
05257 if (max_len < strlen(nr)) {
05258 ast_verbose("Sending Call Rerouting with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05259 nr, channame, max_len);
05260 ao2_unlock(tmp);
05261 chan_list_unref(tmp, "Number too long");
05262 return 0;
05263 }
05264 tmp->bc->fac_out.Function = Fac_CallRerouteing;
05265 tmp->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
05266 tmp->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
05267
05268 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;
05269 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
05270
05271 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;
05272 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(nr);
05273 strcpy((char *) tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, nr);
05274 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
05275
05276 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
05277
05278
05279 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
05280 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
05281 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
05282 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
05283 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
05284 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
05285 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
05286
05287 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;
05288 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;
05289
05290
05291 print_facility(&tmp->bc->fac_out, tmp->bc);
05292 ao2_unlock(tmp);
05293 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05294 chan_list_unref(tmp, "Send facility complete");
05295 #endif
05296 } else if (strstr(a->argv[3], "CFActivate")) {
05297 if (a->argc < 7) {
05298 ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
05299 return 0;
05300 }
05301 port = atoi(a->argv[4]);
05302 served_nr = a->argv[5];
05303 nr = a->argv[6];
05304
05305 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05306
05307 ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
05308
05309 #if defined(AST_MISDN_ENHANCEMENTS)
05310 bc->fac_out.Function = Fac_ActivationDiversion;
05311 bc->fac_out.u.ActivationDiversion.InvokeID = ++misdn_invoke_id;
05312 bc->fac_out.u.ActivationDiversion.ComponentType = FacComponent_Invoke;
05313 bc->fac_out.u.ActivationDiversion.Component.Invoke.BasicService = 0;
05314 bc->fac_out.u.ActivationDiversion.Component.Invoke.Procedure = 0;
05315 ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number,
05316 served_nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number));
05317 bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05318 strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number);
05319 bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Type = 0;
05320 ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number,
05321 nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number));
05322 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber =
05323 strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number);
05324 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 0;
05325 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Subaddress.Length = 0;
05326
05327 #else
05328
05329 bc->fac_out.Function = Fac_CFActivate;
05330 bc->fac_out.u.CFActivate.BasicService = 0;
05331 bc->fac_out.u.CFActivate.Procedure = 0;
05332 ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05333 ast_copy_string((char *) bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));
05334 #endif
05335
05336
05337 print_facility(&bc->fac_out, bc);
05338 misdn_lib_send_event(bc, EVENT_FACILITY);
05339 } else if (strstr(a->argv[3], "CFDeactivate")) {
05340 if (a->argc < 6) {
05341 ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
05342 return 0;
05343 }
05344 port = atoi(a->argv[4]);
05345 served_nr = a->argv[5];
05346
05347 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05348 ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr);
05349
05350 #if defined(AST_MISDN_ENHANCEMENTS)
05351 bc->fac_out.Function = Fac_DeactivationDiversion;
05352 bc->fac_out.u.DeactivationDiversion.InvokeID = ++misdn_invoke_id;
05353 bc->fac_out.u.DeactivationDiversion.ComponentType = FacComponent_Invoke;
05354 bc->fac_out.u.DeactivationDiversion.Component.Invoke.BasicService = 0;
05355 bc->fac_out.u.DeactivationDiversion.Component.Invoke.Procedure = 0;
05356 ast_copy_string((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number,
05357 served_nr, sizeof(bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number));
05358 bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05359 strlen((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number);
05360 bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Type = 0;
05361
05362 #else
05363
05364 bc->fac_out.Function = Fac_CFDeactivate;
05365 bc->fac_out.u.CFDeactivate.BasicService = 0;
05366 bc->fac_out.u.CFDeactivate.Procedure = 0;
05367 ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05368 #endif
05369
05370
05371 print_facility(&bc->fac_out, bc);
05372 misdn_lib_send_event(bc, EVENT_FACILITY);
05373 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
05374 } else if (strstr(a->argv[3], "test")) {
05375 int msg_number;
05376
05377 if (a->argc < 5) {
05378 ast_verbose("test (<port> [<msg#>]) | (<channel-name> <msg#>)\n\n");
05379 return 0;
05380 }
05381 port = atoi(a->argv[4]);
05382
05383 channame = a->argv[4];
05384 tmp = get_chan_by_ast_name(channame);
05385 if (tmp) {
05386
05387 msg_number = atoi(a->argv[5]);
05388 if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05389 ao2_lock(tmp);
05390 tmp->bc->fac_out = Fac_Msgs[msg_number];
05391
05392
05393 print_facility(&tmp->bc->fac_out, tmp->bc);
05394 ao2_unlock(tmp);
05395 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05396 } else {
05397 ast_verbose("test <channel-name> <msg#>\n\n");
05398 }
05399 chan_list_unref(tmp, "Facility test done");
05400 } else if (a->argc < 6) {
05401 for (msg_number = 0; msg_number < ARRAY_LEN(Fac_Msgs); ++msg_number) {
05402 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05403 bc->fac_out = Fac_Msgs[msg_number];
05404
05405
05406 print_facility(&bc->fac_out, bc);
05407 misdn_lib_send_event(bc, EVENT_FACILITY);
05408 sleep(1);
05409 }
05410 } else {
05411 msg_number = atoi(a->argv[5]);
05412 if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05413 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05414 bc->fac_out = Fac_Msgs[msg_number];
05415
05416
05417 print_facility(&bc->fac_out, bc);
05418 misdn_lib_send_event(bc, EVENT_FACILITY);
05419 } else {
05420 ast_verbose("test <port> [<msg#>]\n\n");
05421 }
05422 }
05423 } else if (strstr(a->argv[3], "register")) {
05424 if (a->argc < 5) {
05425 ast_verbose("register <port>\n\n");
05426 return 0;
05427 }
05428 port = atoi(a->argv[4]);
05429
05430 bc = misdn_lib_get_register_bc(port);
05431 if (!bc) {
05432 ast_verbose("Could not allocate REGISTER bc struct\n\n");
05433 return 0;
05434 }
05435 bc->fac_out = Fac_Msgs[45];
05436
05437
05438 print_facility(&bc->fac_out, bc);
05439 misdn_lib_send_event(bc, EVENT_REGISTER);
05440 #endif
05441 }
05442
05443 return CLI_SUCCESS;
05444 }
05445
05446 static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05447 {
05448 int port;
05449 int channel;
05450
05451 switch (cmd) {
05452 case CLI_INIT:
05453 e->command = "misdn send restart";
05454 e->usage =
05455 "Usage: misdn send restart [port [channel]]\n"
05456 " Send a restart for every bchannel on the given port.\n";
05457 return NULL;
05458 case CLI_GENERATE:
05459 return NULL;
05460 }
05461
05462 if (a->argc < 4 || a->argc > 5) {
05463 return CLI_SHOWUSAGE;
05464 }
05465
05466 port = atoi(a->argv[3]);
05467
05468 if (a->argc == 5) {
05469 channel = atoi(a->argv[4]);
05470 misdn_lib_send_restart(port, channel);
05471 } else {
05472 misdn_lib_send_restart(port, -1);
05473 }
05474
05475 return CLI_SUCCESS;
05476 }
05477
05478 static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05479 {
05480 const char *channame;
05481 const char *msg;
05482 struct chan_list *tmp;
05483 int i, msglen;
05484
05485 switch (cmd) {
05486 case CLI_INIT:
05487 e->command = "misdn send digit";
05488 e->usage =
05489 "Usage: misdn send digit <channel> \"<msg>\" \n"
05490 " Send <digit> to <channel> as DTMF Tone\n"
05491 " when channel is a mISDN channel\n";
05492 return NULL;
05493 case CLI_GENERATE:
05494 return complete_ch(a);
05495 }
05496
05497 if (a->argc != 5) {
05498 return CLI_SHOWUSAGE;
05499 }
05500
05501 channame = a->argv[3];
05502 msg = a->argv[4];
05503 msglen = strlen(msg);
05504
05505 ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05506
05507 tmp = get_chan_by_ast_name(channame);
05508 if (!tmp) {
05509 ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
05510 return CLI_SUCCESS;
05511 }
05512 #if 1
05513 for (i = 0; i < msglen; i++) {
05514 if (!tmp->ast) {
05515 break;
05516 }
05517 ast_cli(a->fd, "Sending: %c\n", msg[i]);
05518 send_digit_to_chan(tmp, msg[i]);
05519
05520 usleep(250000);
05521
05522 }
05523 #else
05524 if (tmp->ast) {
05525 ast_dtmf_stream(tmp->ast, NULL, msg, 250);
05526 }
05527 #endif
05528 chan_list_unref(tmp, "Digit(s) sent");
05529
05530 return CLI_SUCCESS;
05531 }
05532
05533 static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05534 {
05535 const char *channame;
05536 struct chan_list *tmp;
05537
05538 switch (cmd) {
05539 case CLI_INIT:
05540 e->command = "misdn toggle echocancel";
05541 e->usage =
05542 "Usage: misdn toggle echocancel <channel>\n"
05543 " Toggle EchoCancel on mISDN Channel.\n";
05544 return NULL;
05545 case CLI_GENERATE:
05546 return complete_ch(a);
05547 }
05548
05549 if (a->argc != 4) {
05550 return CLI_SHOWUSAGE;
05551 }
05552
05553 channame = a->argv[3];
05554
05555 ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
05556
05557 tmp = get_chan_by_ast_name(channame);
05558 if (!tmp) {
05559 ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
05560 return CLI_SUCCESS;
05561 }
05562
05563 tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
05564
05565 if (tmp->toggle_ec) {
05566 #ifdef MISDN_1_2
05567 update_pipeline_config(tmp->bc);
05568 #else
05569 update_ec_config(tmp->bc);
05570 #endif
05571 manager_ec_enable(tmp->bc);
05572 } else {
05573 manager_ec_disable(tmp->bc);
05574 }
05575 chan_list_unref(tmp, "Done toggling echo cancel");
05576
05577 return CLI_SUCCESS;
05578 }
05579
05580 static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05581 {
05582 const char *channame;
05583 const char *msg;
05584 struct chan_list *tmp;
05585
05586 switch (cmd) {
05587 case CLI_INIT:
05588 e->command = "misdn send display";
05589 e->usage =
05590 "Usage: misdn send display <channel> \"<msg>\" \n"
05591 " Send <msg> to <channel> as Display Message\n"
05592 " when channel is a mISDN channel\n";
05593 return NULL;
05594 case CLI_GENERATE:
05595 return complete_ch(a);
05596 }
05597
05598 if (a->argc != 5) {
05599 return CLI_SHOWUSAGE;
05600 }
05601
05602 channame = a->argv[3];
05603 msg = a->argv[4];
05604
05605 ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05606
05607 tmp = get_chan_by_ast_name(channame);
05608 if (tmp && tmp->bc) {
05609 ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
05610 misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
05611 chan_list_unref(tmp, "Done sending display");
05612 } else {
05613 if (tmp) {
05614 chan_list_unref(tmp, "Display failed");
05615 }
05616 ast_cli(a->fd, "No such channel %s\n", channame);
05617 return CLI_SUCCESS;
05618 }
05619
05620 return CLI_SUCCESS;
05621 }
05622
05623 static char *complete_ch(struct ast_cli_args *a)
05624 {
05625 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05626 }
05627
05628 static char *complete_debug_port(struct ast_cli_args *a)
05629 {
05630 if (a->n) {
05631 return NULL;
05632 }
05633
05634 switch (a->pos) {
05635 case 4:
05636 if (a->word[0] == 'p') {
05637 return ast_strdup("port");
05638 } else if (a->word[0] == 'o') {
05639 return ast_strdup("only");
05640 }
05641 break;
05642 case 6:
05643 if (a->word[0] == 'o') {
05644 return ast_strdup("only");
05645 }
05646 break;
05647 }
05648 return NULL;
05649 }
05650
05651 static char *complete_show_config(struct ast_cli_args *a)
05652 {
05653 char buffer[BUFFERSIZE];
05654 enum misdn_cfg_elements elem;
05655 int wordlen = strlen(a->word);
05656 int which = 0;
05657 int port = 0;
05658
05659 switch (a->pos) {
05660 case 3:
05661 if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) {
05662 return ast_strdup("description");
05663 }
05664 if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) {
05665 return ast_strdup("descriptions");
05666 }
05667 if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) {
05668 return ast_strdup("0");
05669 }
05670 while ((port = misdn_cfg_get_next_port(port)) != -1) {
05671 snprintf(buffer, sizeof(buffer), "%d", port);
05672 if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
05673 return ast_strdup(buffer);
05674 }
05675 }
05676 break;
05677 case 4:
05678 if (strstr(a->line, "description ")) {
05679 for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
05680 if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) {
05681 continue;
05682 }
05683 misdn_cfg_get_name(elem, buffer, sizeof(buffer));
05684 if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
05685 if (++which > a->n) {
05686 return ast_strdup(buffer);
05687 }
05688 }
05689 }
05690 } else if (strstr(a->line, "descriptions ")) {
05691 if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) {
05692 return ast_strdup("general");
05693 }
05694 if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) {
05695 return ast_strdup("ports");
05696 }
05697 }
05698 break;
05699 }
05700 return NULL;
05701 }
05702
05703 static struct ast_cli_entry chan_misdn_clis[] = {
05704
05705 AST_CLI_DEFINE(handle_cli_misdn_port_block, "Block the given port"),
05706 AST_CLI_DEFINE(handle_cli_misdn_port_down, "Try to deactivate the L1 on the given port"),
05707 AST_CLI_DEFINE(handle_cli_misdn_port_unblock, "Unblock the given port"),
05708 AST_CLI_DEFINE(handle_cli_misdn_port_up, "Try to establish L1 on the given port"),
05709 AST_CLI_DEFINE(handle_cli_misdn_reload, "Reload internal mISDN config, read from the config file"),
05710 AST_CLI_DEFINE(handle_cli_misdn_restart_pid, "Restart the given pid"),
05711 AST_CLI_DEFINE(handle_cli_misdn_restart_port, "Restart the given port"),
05712 AST_CLI_DEFINE(handle_cli_misdn_show_channel, "Show an internal mISDN channel"),
05713 AST_CLI_DEFINE(handle_cli_misdn_show_channels, "Show the internal mISDN channel list"),
05714 AST_CLI_DEFINE(handle_cli_misdn_show_config, "Show internal mISDN config, read from the config file"),
05715 AST_CLI_DEFINE(handle_cli_misdn_show_port, "Show detailed information for given port"),
05716 AST_CLI_DEFINE(handle_cli_misdn_show_ports_stats, "Show mISDNs channel's call statistics per port"),
05717 AST_CLI_DEFINE(handle_cli_misdn_show_stacks, "Show internal mISDN stack_list"),
05718 AST_CLI_DEFINE(handle_cli_misdn_send_facility, "Sends a Facility Message to the mISDN Channel"),
05719 AST_CLI_DEFINE(handle_cli_misdn_send_digit, "Send DTMF digit to mISDN Channel"),
05720 AST_CLI_DEFINE(handle_cli_misdn_send_display, "Send Text to mISDN Channel"),
05721 AST_CLI_DEFINE(handle_cli_misdn_send_restart, "Send a restart for every bchannel on the given port"),
05722 AST_CLI_DEFINE(handle_cli_misdn_set_crypt_debug, "Set CryptDebuglevel of chan_misdn, at the moment, level={1,2}"),
05723 AST_CLI_DEFINE(handle_cli_misdn_set_debug, "Set Debuglevel of chan_misdn"),
05724 AST_CLI_DEFINE(handle_cli_misdn_set_tics, "???"),
05725 AST_CLI_DEFINE(handle_cli_misdn_toggle_echocancel, "Toggle EchoCancel on mISDN Channel"),
05726
05727 };
05728
05729
05730 static void update_config(struct chan_list *ch)
05731 {
05732 struct ast_channel *ast;
05733 struct misdn_bchannel *bc;
05734 int port;
05735 int hdlc = 0;
05736 int pres;
05737 int screen;
05738
05739 if (!ch) {
05740 ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05741 return;
05742 }
05743
05744 ast = ch->ast;
05745 bc = ch->bc;
05746 if (! ast || ! bc) {
05747 ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05748 return;
05749 }
05750
05751 port = bc->port;
05752
05753 chan_misdn_log(7, port, "update_config: Getting Config\n");
05754
05755 misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
05756 if (hdlc) {
05757 switch (bc->capability) {
05758 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05759 case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05760 chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05761 bc->hdlc = 1;
05762 break;
05763 }
05764 }
05765
05766
05767 misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
05768 misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
05769 chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
05770
05771 if (pres < 0 || screen < 0) {
05772 chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number.presentation);
05773
05774 bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
05775 chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
05776
05777 bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
05778 chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
05779 } else {
05780 bc->caller.screening = screen;
05781 bc->caller.presentation = pres;
05782 }
05783 }
05784
05785
05786 static void config_jitterbuffer(struct chan_list *ch)
05787 {
05788 struct misdn_bchannel *bc = ch->bc;
05789 int len = ch->jb_len;
05790 int threshold = ch->jb_upper_threshold;
05791
05792 chan_misdn_log(5, bc->port, "config_jb: Called\n");
05793
05794 if (!len) {
05795 chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
05796 bc->nojitter = 1;
05797 } else {
05798 if (len <= 100 || len > 8000) {
05799 chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
05800 len = 1000;
05801 }
05802
05803 if (threshold > len) {
05804 chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
05805 }
05806
05807 if (ch->jb) {
05808 cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
05809 misdn_jb_destroy(ch->jb);
05810 ch->jb = NULL;
05811 }
05812
05813 ch->jb = misdn_jb_init(len, threshold);
05814
05815 if (!ch->jb) {
05816 bc->nojitter = 1;
05817 }
05818 }
05819 }
05820
05821
05822 void debug_numtype(int port, int numtype, char *type)
05823 {
05824 switch (numtype) {
05825 case NUMTYPE_UNKNOWN:
05826 chan_misdn_log(2, port, " --> %s: Unknown\n", type);
05827 break;
05828 case NUMTYPE_INTERNATIONAL:
05829 chan_misdn_log(2, port, " --> %s: International\n", type);
05830 break;
05831 case NUMTYPE_NATIONAL:
05832 chan_misdn_log(2, port, " --> %s: National\n", type);
05833 break;
05834 case NUMTYPE_NETWORK_SPECIFIC:
05835 chan_misdn_log(2, port, " --> %s: Network Specific\n", type);
05836 break;
05837 case NUMTYPE_SUBSCRIBER:
05838 chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
05839 break;
05840 case NUMTYPE_ABBREVIATED:
05841 chan_misdn_log(2, port, " --> %s: Abbreviated\n", type);
05842 break;
05843
05844 default:
05845 chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
05846 break;
05847 }
05848 }
05849
05850
05851 #ifdef MISDN_1_2
05852 static int update_pipeline_config(struct misdn_bchannel *bc)
05853 {
05854 int ec;
05855
05856 misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline));
05857
05858 if (*bc->pipeline) {
05859 return 0;
05860 }
05861
05862 misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05863 if (ec == 1) {
05864 ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline));
05865 } else if (ec > 1) {
05866 snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec);
05867 }
05868
05869 return 0;
05870 }
05871 #else
05872 static int update_ec_config(struct misdn_bchannel *bc)
05873 {
05874 int ec;
05875 int port = bc->port;
05876
05877 misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05878
05879 if (ec == 1) {
05880 bc->ec_enable = 1;
05881 } else if (ec > 1) {
05882 bc->ec_enable = 1;
05883 bc->ec_deftaps = ec;
05884 }
05885
05886 return 0;
05887 }
05888 #endif
05889
05890
05891 static int read_config(struct chan_list *ch)
05892 {
05893 struct ast_channel *ast;
05894 struct misdn_bchannel *bc;
05895 int port;
05896 int hdlc = 0;
05897 char lang[BUFFERSIZE + 1];
05898 char faxdetect[BUFFERSIZE + 1];
05899 char buf[256];
05900 char buf2[256];
05901 ast_group_t pg;
05902 ast_group_t cg;
05903
05904 if (!ch) {
05905 ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05906 return -1;
05907 }
05908
05909 ast = ch->ast;
05910 bc = ch->bc;
05911 if (! ast || ! bc) {
05912 ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05913 return -1;
05914 }
05915
05916 port = bc->port;
05917 chan_misdn_log(1, port, "read_config: Getting Config\n");
05918
05919 misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
05920 ast_string_field_set(ast, language, lang);
05921
05922 misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
05923
05924 misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(bc->txgain));
05925 misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(bc->rxgain));
05926
05927 misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));
05928
05929 misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
05930
05931 misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
05932 if (ch->ast_dsp) {
05933 ch->ignore_dtmf = 1;
05934 }
05935
05936 misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos));
05937 misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(ch->nttimeout));
05938
05939 misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(ch->noautorespond_on_setup));
05940
05941 misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(ch->far_alerting));
05942
05943 misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, sizeof(ch->allowed_bearers));
05944
05945 misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
05946
05947 misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
05948 if (hdlc) {
05949 switch (bc->capability) {
05950 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05951 case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05952 chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05953 bc->hdlc = 1;
05954 break;
05955 }
05956
05957 }
05958
05959 misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
05960 misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(ch->jb_upper_threshold));
05961
05962 config_jitterbuffer(ch);
05963
05964 misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
05965
05966 ast_copy_string(ast->context, ch->context, sizeof(ast->context));
05967
05968 #ifdef MISDN_1_2
05969 update_pipeline_config(bc);
05970 #else
05971 update_ec_config(bc);
05972 #endif
05973
05974 misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
05975
05976 misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected));
05977 misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup));
05978 misdn_cfg_get(port, MISDN_CFG_OUTGOING_COLP, &bc->outgoing_colp, sizeof(bc->outgoing_colp));
05979
05980 misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
05981 misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
05982 chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
05983 ast->pickupgroup = pg;
05984 ast->callgroup = cg;
05985
05986 if (ch->originator == ORG_AST) {
05987 char callerid[BUFFERSIZE + 1];
05988
05989
05990
05991 misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel));
05992
05993 if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
05994 ch->faxdetect = strstr(faxdetect, "nojump") ? 2 : 1;
05995 }
05996
05997 misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
05998 if (!ast_strlen_zero(callerid)) {
05999 char *cid_name = NULL;
06000 char *cid_num = NULL;
06001
06002 ast_callerid_parse(callerid, &cid_name, &cid_num);
06003 if (cid_name) {
06004 ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name));
06005 } else {
06006 bc->caller.name[0] = '\0';
06007 }
06008 if (cid_num) {
06009 ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number));
06010 } else {
06011 bc->caller.number[0] = '\0';
06012 }
06013 chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number);
06014 }
06015
06016 misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type));
06017 bc->dialed.number_plan = NUMPLAN_ISDN;
06018 debug_numtype(port, bc->dialed.number_type, "TON");
06019
06020 ch->overlap_dial = 0;
06021 } else {
06022
06023
06024 if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
06025 ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
06026 }
06027
06028
06029 misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number));
06030
06031 if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) {
06032 ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number));
06033 }
06034
06035
06036 misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
06037
06038 ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten));
06039
06040 misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
06041 ast_mutex_init(&ch->overlap_tv_lock);
06042 }
06043
06044 misdn_cfg_get(port, MISDN_CFG_INCOMING_CALLERID_TAG, bc->incoming_cid_tag, sizeof(bc->incoming_cid_tag));
06045 if (!ast_strlen_zero(bc->incoming_cid_tag)) {
06046 chan_misdn_log(1, port, " --> * Setting incoming caller id tag to \"%s\"\n", bc->incoming_cid_tag);
06047 }
06048 ch->overlap_dial_task = -1;
06049
06050 if (ch->faxdetect || ch->ast_dsp) {
06051 misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
06052 if (!ch->dsp) {
06053 ch->dsp = ast_dsp_new();
06054 }
06055 if (ch->dsp) {
06056 ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | (ch->faxdetect ? DSP_FEATURE_FAX_DETECT : 0));
06057 }
06058 }
06059
06060
06061 bc->AOCDtype = Fac_None;
06062
06063 return 0;
06064 }
06065
06066
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077 static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
06078 {
06079 struct ast_party_connected_line connected;
06080 struct ast_set_party_connected_line update_connected;
06081
06082 ast_party_connected_line_init(&connected);
06083 memset(&update_connected, 0, sizeof(update_connected));
06084 update_connected.id.number = 1;
06085 connected.id.number.valid = 1;
06086 connected.id.number.str = (char *) id->number;
06087 connected.id.number.plan = misdn_to_ast_ton(id->number_type)
06088 | misdn_to_ast_plan(id->number_plan);
06089 connected.id.number.presentation = misdn_to_ast_pres(id->presentation)
06090 | misdn_to_ast_screen(id->screening);
06091 connected.id.tag = cid_tag;
06092 connected.source = source;
06093 ast_channel_queue_connected_line_update(ast, &connected, &update_connected);
06094 }
06095
06096
06097
06098
06099
06100
06101
06102
06103
06104
06105
06106 static void misdn_update_caller_id(struct ast_channel *ast, const struct misdn_party_id *id, char *cid_tag)
06107 {
06108 struct ast_party_caller caller;
06109 struct ast_set_party_caller update_caller;
06110
06111 memset(&update_caller, 0, sizeof(update_caller));
06112 update_caller.id.number = 1;
06113 update_caller.ani.number = 1;
06114
06115 ast_channel_lock(ast);
06116 ast_party_caller_set_init(&caller, &ast->caller);
06117
06118 caller.id.number.valid = 1;
06119 caller.id.number.str = (char *) id->number;
06120 caller.id.number.plan = misdn_to_ast_ton(id->number_type)
06121 | misdn_to_ast_plan(id->number_plan);
06122 caller.id.number.presentation = misdn_to_ast_pres(id->presentation)
06123 | misdn_to_ast_screen(id->screening);
06124
06125 caller.ani.number = caller.id.number;
06126
06127 caller.id.tag = cid_tag;
06128 caller.ani.tag = cid_tag;
06129
06130 ast_channel_set_caller_event(ast, &caller, &update_caller);
06131 ast_channel_unlock(ast);
06132 }
06133
06134
06135
06136
06137
06138
06139
06140
06141
06142
06143
06144
06145 static void misdn_update_remote_party(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
06146 {
06147 misdn_update_caller_id(ast, id, cid_tag);
06148 misdn_queue_connected_line_update(ast, id, source, cid_tag);
06149 }
06150
06151
06152
06153
06154
06155
06156
06157
06158
06159
06160
06161 static void misdn_get_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06162 {
06163 int number_type;
06164
06165 if (originator == ORG_MISDN) {
06166
06167
06168 ast_copy_string(bc->connected.name,
06169 S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
06170 sizeof(bc->connected.name));
06171 if (ast->connected.id.number.valid) {
06172 ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number.str, ""),
06173 sizeof(bc->connected.number));
06174 bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
06175 bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
06176 bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06177 bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06178 } else {
06179 bc->connected.number[0] = '\0';
06180 bc->connected.presentation = 0;
06181 bc->connected.screening = 0;
06182 bc->connected.number_type = NUMTYPE_UNKNOWN;
06183 bc->connected.number_plan = NUMPLAN_UNKNOWN;
06184 }
06185
06186 misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type));
06187 if (0 <= number_type) {
06188
06189 bc->connected.number_type = number_type;
06190 bc->connected.number_plan = NUMPLAN_ISDN;
06191 }
06192 debug_numtype(bc->port, bc->connected.number_type, "CTON");
06193 } else {
06194
06195
06196 ast_copy_string(bc->caller.name,
06197 S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
06198 sizeof(bc->caller.name));
06199 if (ast->connected.id.number.valid) {
06200 ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number.str, ""),
06201 sizeof(bc->caller.number));
06202 bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
06203 bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
06204 bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06205 bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06206 } else {
06207 bc->caller.number[0] = '\0';
06208 bc->caller.presentation = 0;
06209 bc->caller.screening = 0;
06210 bc->caller.number_type = NUMTYPE_UNKNOWN;
06211 bc->caller.number_plan = NUMPLAN_UNKNOWN;
06212 }
06213
06214 misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06215 if (0 <= number_type) {
06216
06217 bc->caller.number_type = number_type;
06218 bc->caller.number_plan = NUMPLAN_ISDN;
06219 }
06220 debug_numtype(bc->port, bc->caller.number_type, "LTON");
06221 }
06222 }
06223
06224
06225
06226
06227
06228
06229
06230
06231
06232
06233
06234 static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06235 {
06236 struct chan_list *ch;
06237
06238 misdn_get_connected_line(ast, bc, originator);
06239 if (originator == ORG_MISDN) {
06240 bc->redirecting.to = bc->connected;
06241 } else {
06242 bc->redirecting.to = bc->caller;
06243 }
06244 switch (bc->outgoing_colp) {
06245 case 1:
06246 bc->redirecting.to.presentation = 1;
06247 break;
06248 case 2:
06249
06250 return;
06251 default:
06252 break;
06253 }
06254
06255 ch = MISDN_ASTERISK_TECH_PVT(ast);
06256 if (ch->state == MISDN_CONNECTED
06257 || originator != ORG_MISDN) {
06258 int is_ptmp;
06259
06260 is_ptmp = !misdn_lib_is_ptp(bc->port);
06261 if (is_ptmp) {
06262
06263
06264
06265
06266
06267
06268 if (!misdn_lib_port_is_nt(bc->port)) {
06269 return;
06270 }
06271 if (ch->state != MISDN_CONNECTED) {
06272
06273 bc->redirecting.to_changed = 1;
06274 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06275 misdn_lib_send_event(bc, EVENT_NOTIFY);
06276 #if defined(AST_MISDN_ENHANCEMENTS)
06277 } else {
06278
06279 bc->redirecting.to_changed = 1;
06280 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06281 bc->fac_out.Function = Fac_RequestSubaddress;
06282 bc->fac_out.u.RequestSubaddress.InvokeID = ++misdn_invoke_id;
06283
06284
06285 print_facility(&bc->fac_out, bc);
06286 misdn_lib_send_event(bc, EVENT_FACILITY);
06287 #endif
06288 }
06289 #if defined(AST_MISDN_ENHANCEMENTS)
06290 } else {
06291
06292 bc->fac_out.Function = Fac_EctInform;
06293 bc->fac_out.u.EctInform.InvokeID = ++misdn_invoke_id;
06294 bc->fac_out.u.EctInform.Status = 1;
06295 bc->fac_out.u.EctInform.RedirectionPresent = 1;
06296 misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.EctInform.Redirection,
06297 &bc->redirecting.to);
06298
06299
06300 print_facility(&bc->fac_out, bc);
06301 misdn_lib_send_event(bc, EVENT_FACILITY);
06302 #endif
06303 }
06304 }
06305 }
06306
06307
06308
06309
06310
06311
06312
06313
06314
06315
06316 static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast)
06317 {
06318 ast_copy_string(bc->redirecting.from.name,
06319 S_COR(ast->redirecting.from.name.valid, ast->redirecting.from.name.str, ""),
06320 sizeof(bc->redirecting.from.name));
06321 if (ast->redirecting.from.number.valid) {
06322 ast_copy_string(bc->redirecting.from.number, S_OR(ast->redirecting.from.number.str, ""),
06323 sizeof(bc->redirecting.from.number));
06324 bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number.presentation);
06325 bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number.presentation);
06326 bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number.plan);
06327 bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number.plan);
06328 } else {
06329 bc->redirecting.from.number[0] = '\0';
06330 bc->redirecting.from.presentation = 0;
06331 bc->redirecting.from.screening = 0;
06332 bc->redirecting.from.number_type = NUMTYPE_UNKNOWN;
06333 bc->redirecting.from.number_plan = NUMPLAN_UNKNOWN;
06334 }
06335
06336 ast_copy_string(bc->redirecting.to.name,
06337 S_COR(ast->redirecting.to.name.valid, ast->redirecting.to.name.str, ""),
06338 sizeof(bc->redirecting.to.name));
06339 if (ast->redirecting.to.number.valid) {
06340 ast_copy_string(bc->redirecting.to.number, S_OR(ast->redirecting.to.number.str, ""),
06341 sizeof(bc->redirecting.to.number));
06342 bc->redirecting.to.presentation = ast_to_misdn_pres(ast->redirecting.to.number.presentation);
06343 bc->redirecting.to.screening = ast_to_misdn_screen(ast->redirecting.to.number.presentation);
06344 bc->redirecting.to.number_type = ast_to_misdn_ton(ast->redirecting.to.number.plan);
06345 bc->redirecting.to.number_plan = ast_to_misdn_plan(ast->redirecting.to.number.plan);
06346 } else {
06347 bc->redirecting.to.number[0] = '\0';
06348 bc->redirecting.to.presentation = 0;
06349 bc->redirecting.to.screening = 0;
06350 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
06351 bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
06352 }
06353
06354 bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason);
06355 bc->redirecting.count = ast->redirecting.count;
06356 }
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368 static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect, char *tag)
06369 {
06370 struct ast_party_redirecting redirecting;
06371 struct ast_set_party_redirecting update_redirecting;
06372
06373 ast_party_redirecting_set_init(&redirecting, &ast->redirecting);
06374 memset(&update_redirecting, 0, sizeof(update_redirecting));
06375
06376 update_redirecting.from.number = 1;
06377 redirecting.from.number.valid = 1;
06378 redirecting.from.number.str = (char *) redirect->from.number;
06379 redirecting.from.number.plan =
06380 misdn_to_ast_ton(redirect->from.number_type)
06381 | misdn_to_ast_plan(redirect->from.number_plan);
06382 redirecting.from.number.presentation =
06383 misdn_to_ast_pres(redirect->from.presentation)
06384 | misdn_to_ast_screen(redirect->from.screening);
06385 redirecting.from.tag = tag;
06386
06387 update_redirecting.to.number = 1;
06388 redirecting.to.number.valid = 1;
06389 redirecting.to.number.str = (char *) redirect->to.number;
06390 redirecting.to.number.plan =
06391 misdn_to_ast_ton(redirect->to.number_type)
06392 | misdn_to_ast_plan(redirect->to.number_plan);
06393 redirecting.to.number.presentation =
06394 misdn_to_ast_pres(redirect->to.presentation)
06395 | misdn_to_ast_screen(redirect->to.screening);
06396 redirecting.to.tag = tag;
06397
06398 redirecting.reason = misdn_to_ast_reason(redirect->reason);
06399 redirecting.count = redirect->count;
06400
06401 ast_channel_set_redirecting(ast, &redirecting, &update_redirecting);
06402 }
06403
06404
06405
06406
06407
06408
06409
06410
06411
06412
06413
06414 static void misdn_update_redirecting(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06415 {
06416 int is_ptmp;
06417
06418 misdn_copy_redirecting_from_ast(bc, ast);
06419 switch (bc->outgoing_colp) {
06420 case 1:
06421 bc->redirecting.to.presentation = 1;
06422 break;
06423 case 2:
06424
06425 return;
06426 default:
06427 break;
06428 }
06429
06430 if (originator != ORG_MISDN) {
06431 return;
06432 }
06433
06434 is_ptmp = !misdn_lib_is_ptp(bc->port);
06435 if (is_ptmp) {
06436
06437
06438
06439
06440
06441
06442 if (!misdn_lib_port_is_nt(bc->port)) {
06443 return;
06444 }
06445
06446 bc->redirecting.to_changed = 1;
06447 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_IS_DIVERTING;
06448 misdn_lib_send_event(bc, EVENT_NOTIFY);
06449 #if defined(AST_MISDN_ENHANCEMENTS)
06450 } else {
06451 int match;
06452
06453 match = (strcmp(ast->exten, bc->redirecting.to.number) == 0) ? 1 : 0;
06454 if (!bc->div_leg_3_tx_pending
06455 || !match) {
06456
06457 bc->fac_out.Function = Fac_DivertingLegInformation1;
06458 bc->fac_out.u.DivertingLegInformation1.InvokeID = ++misdn_invoke_id;
06459 bc->fac_out.u.DivertingLegInformation1.DiversionReason =
06460 misdn_to_diversion_reason(bc->redirecting.reason);
06461 bc->fac_out.u.DivertingLegInformation1.SubscriptionOption = 2;
06462 bc->fac_out.u.DivertingLegInformation1.DivertedToPresent = 1;
06463 misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.DivertingLegInformation1.DivertedTo, &bc->redirecting.to);
06464 print_facility(&bc->fac_out, bc);
06465 misdn_lib_send_event(bc, EVENT_FACILITY);
06466 }
06467 bc->div_leg_3_tx_pending = 0;
06468
06469
06470 bc->fac_out.Function = Fac_DivertingLegInformation3;
06471 bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06472 bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06473 bc->redirecting.to.presentation == 0 ? 1 : 0;
06474 print_facility(&bc->fac_out, bc);
06475 misdn_lib_send_event(bc, EVENT_FACILITY);
06476 #endif
06477 }
06478 }
06479
06480
06481
06482
06483
06484
06485 static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
06486 {
06487 int port = 0;
06488 int r;
06489 int exceed;
06490 int number_type;
06491 struct chan_list *ch;
06492 struct misdn_bchannel *newbc;
06493 char *dest_cp;
06494 int append_msn = 0;
06495
06496 AST_DECLARE_APP_ARGS(args,
06497 AST_APP_ARG(intf);
06498 AST_APP_ARG(ext);
06499 AST_APP_ARG(opts);
06500 );
06501
06502 if (!ast) {
06503 ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
06504 return -1;
06505 }
06506
06507 if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest) {
06508 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
06509 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06510 ast_setstate(ast, AST_STATE_DOWN);
06511 return -1;
06512 }
06513
06514 ch = MISDN_ASTERISK_TECH_PVT(ast);
06515 if (!ch) {
06516 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name);
06517 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06518 ast_setstate(ast, AST_STATE_DOWN);
06519 return -1;
06520 }
06521
06522 newbc = ch->bc;
06523 if (!newbc) {
06524 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name);
06525 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06526 ast_setstate(ast, AST_STATE_DOWN);
06527 return -1;
06528 }
06529
06530 port = newbc->port;
06531
06532 #if defined(AST_MISDN_ENHANCEMENTS)
06533 if ((ch->peer = misdn_cc_caller_get(ast))) {
06534 chan_misdn_log(3, port, " --> Found CC caller data, peer:%s\n",
06535 ch->peer->chan ? "available" : "NULL");
06536 }
06537
06538 if (ch->record_id != -1) {
06539 struct misdn_cc_record *cc_record;
06540
06541
06542 AST_LIST_LOCK(&misdn_cc_records_db);
06543 cc_record = misdn_cc_find_by_id(ch->record_id);
06544 if (!cc_record) {
06545 AST_LIST_UNLOCK(&misdn_cc_records_db);
06546 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, cc_record==NULL\n", ast->name);
06547 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06548 ast_setstate(ast, AST_STATE_DOWN);
06549 return -1;
06550 }
06551
06552
06553 newbc->dialed = cc_record->redial.dialed;
06554 newbc->caller = cc_record->redial.caller;
06555 memset(&newbc->redirecting, 0, sizeof(newbc->redirecting));
06556 newbc->capability = cc_record->redial.capability;
06557 newbc->hdlc = cc_record->redial.hdlc;
06558 newbc->sending_complete = 1;
06559
06560 if (cc_record->ptp) {
06561 newbc->fac_out.Function = Fac_CCBS_T_Call;
06562 newbc->fac_out.u.CCBS_T_Call.InvokeID = ++misdn_invoke_id;
06563 } else {
06564 newbc->fac_out.Function = Fac_CCBSCall;
06565 newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
06566 newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->mode.ptmp.reference_id;
06567 }
06568 AST_LIST_UNLOCK(&misdn_cc_records_db);
06569
06570 ast_copy_string(ast->exten, newbc->dialed.number, sizeof(ast->exten));
06571
06572 chan_misdn_log(1, port, "* Call completion to: %s\n", newbc->dialed.number);
06573 chan_misdn_log(2, port, " --> * tech:%s context:%s\n", ast->name, ast->context);
06574 } else
06575 #endif
06576 {
06577
06578
06579
06580
06581
06582
06583
06584
06585 dest_cp = ast_strdupa(dest);
06586 AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
06587 if (!args.ext) {
06588 args.ext = "";
06589 }
06590
06591 chan_misdn_log(1, port, "* CALL: %s\n", dest);
06592 chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
06593
06594 ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
06595 ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
06596
06597 if (ast_strlen_zero(newbc->caller.name)
06598 && ast->connected.id.name.valid
06599 && !ast_strlen_zero(ast->connected.id.name.str)) {
06600 ast_copy_string(newbc->caller.name, ast->connected.id.name.str, sizeof(newbc->caller.name));
06601 chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06602 }
06603 if (ast_strlen_zero(newbc->caller.number)
06604 && ast->connected.id.number.valid
06605 && !ast_strlen_zero(ast->connected.id.number.str)) {
06606 ast_copy_string(newbc->caller.number, ast->connected.id.number.str, sizeof(newbc->caller.number));
06607 chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06608 }
06609
06610 misdn_cfg_get(port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
06611 if (append_msn) {
06612 strncat(newbc->incoming_cid_tag, "_", sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06613 strncat(newbc->incoming_cid_tag, newbc->caller.number, sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06614 }
06615
06616 ast->caller.id.tag = ast_strdup(newbc->incoming_cid_tag);
06617
06618 misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06619 if (number_type < 0) {
06620 if (ast->connected.id.number.valid) {
06621 newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06622 newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06623 } else {
06624 newbc->caller.number_type = NUMTYPE_UNKNOWN;
06625 newbc->caller.number_plan = NUMPLAN_ISDN;
06626 }
06627 } else {
06628
06629 newbc->caller.number_type = number_type;
06630 newbc->caller.number_plan = NUMPLAN_ISDN;
06631 }
06632 debug_numtype(port, newbc->caller.number_type, "LTON");
06633
06634 newbc->capability = ast->transfercapability;
06635 pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
06636 if (ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
06637 chan_misdn_log(2, port, " --> * Call with flag Digital\n");
06638 }
06639
06640
06641 update_config(ch);
06642
06643
06644 import_ch(ast, newbc, ch);
06645
06646
06647 if (!ast_strlen_zero(args.opts)) {
06648 misdn_set_opt_exec(ast, args.opts);
06649 } else {
06650 chan_misdn_log(2, port, "NO OPTS GIVEN\n");
06651 }
06652 if (newbc->set_presentation) {
06653 newbc->caller.presentation = newbc->presentation;
06654 }
06655
06656 misdn_copy_redirecting_from_ast(newbc, ast);
06657 switch (newbc->outgoing_colp) {
06658 case 1:
06659 case 2:
06660 newbc->redirecting.from.presentation = 1;
06661 break;
06662 default:
06663 break;
06664 }
06665 #if defined(AST_MISDN_ENHANCEMENTS)
06666 if (newbc->redirecting.from.number[0] && misdn_lib_is_ptp(port)) {
06667 if (newbc->redirecting.count < 1) {
06668 newbc->redirecting.count = 1;
06669 }
06670
06671
06672 newbc->fac_out.Function = Fac_DivertingLegInformation2;
06673 newbc->fac_out.u.DivertingLegInformation2.InvokeID = ++misdn_invoke_id;
06674 newbc->fac_out.u.DivertingLegInformation2.DivertingPresent = 1;
06675 misdn_PresentedNumberUnscreened_fill(
06676 &newbc->fac_out.u.DivertingLegInformation2.Diverting,
06677 &newbc->redirecting.from);
06678 switch (newbc->outgoing_colp) {
06679 case 2:
06680
06681 newbc->fac_out.u.DivertingLegInformation2.Diverting.Type = 1;
06682
06683
06684 newbc->fac_out.u.DivertingLegInformation2.DiversionCounter = 1;
06685 newbc->fac_out.u.DivertingLegInformation2.DiversionReason = 0;
06686 break;
06687 default:
06688 newbc->fac_out.u.DivertingLegInformation2.DiversionCounter =
06689 newbc->redirecting.count;
06690 newbc->fac_out.u.DivertingLegInformation2.DiversionReason =
06691 misdn_to_diversion_reason(newbc->redirecting.reason);
06692 break;
06693 }
06694 newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 0;
06695 if (1 < newbc->fac_out.u.DivertingLegInformation2.DiversionCounter) {
06696 newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 1;
06697 newbc->fac_out.u.DivertingLegInformation2.OriginalCalled.Type = 2;
06698 }
06699
06700
06701
06702
06703
06704 newbc->div_leg_3_rx_wanted = 1;
06705 }
06706 #endif
06707 }
06708
06709 exceed = add_out_calls(port);
06710 if (exceed != 0) {
06711 char tmp[16];
06712
06713 snprintf(tmp, sizeof(tmp), "%d", exceed);
06714 pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
06715 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06716 ast_setstate(ast, AST_STATE_DOWN);
06717 return -1;
06718 }
06719
06720 #if defined(AST_MISDN_ENHANCEMENTS)
06721 if (newbc->fac_out.Function != Fac_None) {
06722 print_facility(&newbc->fac_out, newbc);
06723 }
06724 #endif
06725 r = misdn_lib_send_event(newbc, EVENT_SETUP);
06726
06727
06728 ch->l3id = newbc->l3_id;
06729
06730 if (r == -ENOCHAN) {
06731 chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
06732 chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
06733 ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
06734 ast_setstate(ast, AST_STATE_DOWN);
06735 return -1;
06736 }
06737
06738 chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);
06739
06740 ast_setstate(ast, AST_STATE_DIALING);
06741 ast->hangupcause = AST_CAUSE_NORMAL_CLEARING;
06742
06743 if (newbc->nt) {
06744 stop_bc_tones(ch);
06745 }
06746
06747 ch->state = MISDN_CALLING;
06748
06749 return 0;
06750 }
06751
06752
06753 static int misdn_answer(struct ast_channel *ast)
06754 {
06755 struct chan_list *p;
06756 const char *tmp;
06757
06758 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06759 return -1;
06760 }
06761
06762 chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
06763
06764 if (!p) {
06765 ast_log(LOG_WARNING, " --> Channel not connected ??\n");
06766 ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
06767 }
06768
06769 if (!p->bc) {
06770 chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");
06771
06772 ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR);
06773 }
06774
06775 ast_channel_lock(ast);
06776 tmp = pbx_builtin_getvar_helper(ast, "CRYPT_KEY");
06777 if (!ast_strlen_zero(tmp)) {
06778 chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
06779 ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
06780 } else {
06781 chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
06782 }
06783
06784 tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
06785 if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
06786 chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
06787 p->bc->nodsp = 1;
06788 p->bc->hdlc = 0;
06789 p->bc->nojitter = 1;
06790 }
06791 ast_channel_unlock(ast);
06792
06793 p->state = MISDN_CONNECTED;
06794 stop_indicate(p);
06795
06796 if (ast_strlen_zero(p->bc->connected.number)) {
06797 chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n");
06798 ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number));
06799
06800
06801
06802
06803
06804
06805 p->bc->connected.presentation = p->bc->presentation;
06806 p->bc->connected.screening = 0;
06807 p->bc->connected.number_type = p->bc->dialed.number_type;
06808 p->bc->connected.number_plan = p->bc->dialed.number_plan;
06809 }
06810
06811 switch (p->bc->outgoing_colp) {
06812 case 1:
06813 case 2:
06814 p->bc->connected.presentation = 1;
06815 break;
06816 default:
06817 break;
06818 }
06819
06820 #if defined(AST_MISDN_ENHANCEMENTS)
06821 if (p->bc->div_leg_3_tx_pending) {
06822 p->bc->div_leg_3_tx_pending = 0;
06823
06824
06825 p->bc->fac_out.Function = Fac_DivertingLegInformation3;
06826 p->bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06827 p->bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06828 (p->bc->connected.presentation == 0) ? 1 : 0;
06829 print_facility(&p->bc->fac_out, p->bc);
06830 }
06831 #endif
06832 misdn_lib_send_event(p->bc, EVENT_CONNECT);
06833 start_bc_tones(p);
06834
06835 return 0;
06836 }
06837
06838 static int misdn_digit_begin(struct ast_channel *chan, char digit)
06839 {
06840
06841 return 0;
06842 }
06843
06844 static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
06845 {
06846 struct chan_list *p;
06847 struct misdn_bchannel *bc;
06848 char buf[2] = { digit, 0 };
06849
06850 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06851 return -1;
06852 }
06853
06854 bc = p->bc;
06855 chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
06856
06857 if (!bc) {
06858 ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
06859 return -1;
06860 }
06861
06862 switch (p->state) {
06863 case MISDN_CALLING:
06864 if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
06865 strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
06866 }
06867 break;
06868 case MISDN_CALLING_ACKNOWLEDGE:
06869 ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
06870 if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) {
06871 strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
06872 }
06873 ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten));
06874 misdn_lib_send_event(bc, EVENT_INFORMATION);
06875 break;
06876 default:
06877 if (bc->send_dtmf) {
06878 send_digit_to_chan(p, digit);
06879 }
06880 break;
06881 }
06882
06883 return 0;
06884 }
06885
06886
06887 static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast)
06888 {
06889 struct chan_list *p;
06890
06891 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06892 return -1;
06893 }
06894
06895 chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id);
06896
06897 p->ast = ast;
06898
06899 return 0;
06900 }
06901
06902
06903
06904 static int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen)
06905 {
06906 struct chan_list *p;
06907
06908 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06909 ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
06910 return -1;
06911 }
06912
06913 if (!p->bc) {
06914 if (p->hold.state == MISDN_HOLD_IDLE) {
06915 chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
06916 ast->name);
06917 ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
06918 } else {
06919 chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
06920 cond, ast->name);
06921 }
06922 return -1;
06923 }
06924
06925 chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n", cond, ast->name);
06926
06927 switch (cond) {
06928 case AST_CONTROL_BUSY:
06929 chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid);
06930 ast_setstate(ast, AST_STATE_BUSY);
06931
06932 p->bc->out_cause = AST_CAUSE_USER_BUSY;
06933 if (p->state != MISDN_CONNECTED) {
06934 start_bc_tones(p);
06935 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
06936 }
06937 return -1;
06938 case AST_CONTROL_RING:
06939 chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid);
06940 return -1;
06941 case AST_CONTROL_RINGING:
06942 chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid);
06943 switch (p->state) {
06944 case MISDN_ALERTING:
06945 chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid);
06946 break;
06947 case MISDN_CONNECTED:
06948 chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc->pid);
06949 return -1;
06950 default:
06951 p->state = MISDN_ALERTING;
06952 chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid);
06953 misdn_lib_send_event(p->bc, EVENT_ALERTING);
06954
06955 chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid);
06956 ast_setstate(ast, AST_STATE_RING);
06957
06958 if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) {
06959 chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n");
06960 } else {
06961 return -1;
06962 }
06963 }
06964 break;
06965 case AST_CONTROL_ANSWER:
06966 chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid);
06967 start_bc_tones(p);
06968 break;
06969 case AST_CONTROL_TAKEOFFHOOK:
06970 chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid);
06971 return -1;
06972 case AST_CONTROL_OFFHOOK:
06973 chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid);
06974 return -1;
06975 case AST_CONTROL_FLASH:
06976 chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid);
06977 break;
06978 case AST_CONTROL_PROGRESS:
06979 chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid);
06980 misdn_lib_send_event(p->bc, EVENT_PROGRESS);
06981 break;
06982 case AST_CONTROL_PROCEEDING:
06983 chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid);
06984 misdn_lib_send_event(p->bc, EVENT_PROCEEDING);
06985 break;
06986 case AST_CONTROL_INCOMPLETE:
06987 chan_misdn_log(1, p->bc->port, " --> *\tincomplete pid:%d\n", p->bc->pid);
06988 if (!p->overlap_dial) {
06989
06990 p->bc->out_cause = AST_CAUSE_INVALID_NUMBER_FORMAT;
06991 start_bc_tones(p);
06992 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
06993
06994 if (p->bc->nt) {
06995 hanguptone_indicate(p);
06996 }
06997 }
06998 break;
06999 case AST_CONTROL_CONGESTION:
07000 chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid);
07001
07002 p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
07003 start_bc_tones(p);
07004 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
07005
07006 if (p->bc->nt) {
07007 hanguptone_indicate(p);
07008 }
07009 break;
07010 case -1 :
07011 chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid);
07012
07013 stop_indicate(p);
07014
07015 if (p->state == MISDN_CONNECTED) {
07016 start_bc_tones(p);
07017 }
07018 break;
07019 case AST_CONTROL_HOLD:
07020 ast_moh_start(ast, data, p->mohinterpret);
07021 chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid);
07022 break;
07023 case AST_CONTROL_UNHOLD:
07024 ast_moh_stop(ast);
07025 chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid);
07026 break;
07027 case AST_CONTROL_CONNECTED_LINE:
07028 chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid);
07029 misdn_update_connected_line(ast, p->bc, p->originator);
07030 break;
07031 case AST_CONTROL_REDIRECTING:
07032 chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid);
07033 misdn_update_redirecting(ast, p->bc, p->originator);
07034 break;
07035 default:
07036 chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
07037 return -1;
07038 }
07039
07040 return 0;
07041 }
07042
07043 static int misdn_hangup(struct ast_channel *ast)
07044 {
07045 struct chan_list *p;
07046 struct misdn_bchannel *bc;
07047 const char *var;
07048
07049 if (!ast) {
07050 return -1;
07051 }
07052
07053 ast_debug(1, "misdn_hangup(%s)\n", ast->name);
07054
07055
07056 ast_mutex_lock(&release_lock);
07057 p = MISDN_ASTERISK_TECH_PVT(ast);
07058 if (!p) {
07059 ast_mutex_unlock(&release_lock);
07060 return -1;
07061 }
07062 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
07063
07064 if (!misdn_chan_is_valid(p)) {
07065 ast_mutex_unlock(&release_lock);
07066 chan_list_unref(p, "Release ast_channel reference. Was not active?");
07067 return 0;
07068 }
07069
07070 if (p->hold.state == MISDN_HOLD_IDLE) {
07071 bc = p->bc;
07072 } else {
07073 p->hold.state = MISDN_HOLD_DISCONNECT;
07074 bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
07075 if (!bc) {
07076 chan_misdn_log(4, p->hold.port,
07077 "misdn_hangup: Could not find held bc for (%s)\n", ast->name);
07078 release_chan_early(p);
07079 ast_mutex_unlock(&release_lock);
07080 chan_list_unref(p, "Release ast_channel reference");
07081 return 0;
07082 }
07083 }
07084
07085 if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
07086
07087 ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
07088 release_chan_early(p);
07089 if (bc) {
07090 misdn_lib_release(bc);
07091 }
07092 ast_mutex_unlock(&release_lock);
07093 chan_list_unref(p, "Release ast_channel reference");
07094 return 0;
07095 }
07096 if (!bc) {
07097 ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
07098 misdn_get_ch_state(p), p->l3id);
07099 release_chan_early(p);
07100 ast_mutex_unlock(&release_lock);
07101 chan_list_unref(p, "Release ast_channel reference");
07102 return 0;
07103 }
07104
07105 p->ast = NULL;
07106 p->need_hangup = 0;
07107 p->need_queue_hangup = 0;
07108 p->need_busy = 0;
07109
07110 if (!bc->nt) {
07111 stop_bc_tones(p);
07112 }
07113
07114 bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
07115
07116
07117
07118 var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
07119 if (!var) {
07120 var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
07121 }
07122 if (var) {
07123 int tmpcause;
07124
07125 tmpcause = atoi(var);
07126 bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
07127 }
07128
07129 var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
07130 if (var) {
07131 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
07132 ast_copy_string(bc->uu, var, sizeof(bc->uu));
07133 bc->uulen = strlen(bc->uu);
07134 }
07135
07136
07137 chan_misdn_log(1, bc->port,
07138 "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n",
07139 bc->pid,
07140 ast->context,
07141 ast->exten,
07142 (ast->caller.id.name.valid && ast->caller.id.name.str)
07143 ? ast->caller.id.name.str : "",
07144 (ast->caller.id.number.valid && ast->caller.id.number.str)
07145 ? ast->caller.id.number.str : "",
07146 misdn_get_ch_state(p));
07147 chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
07148 chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
07149 chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
07150
07151 switch (p->state) {
07152 case MISDN_INCOMING_SETUP:
07153
07154
07155
07156
07157 ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
07158 release_chan(p, bc);
07159 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
07160 ast_mutex_unlock(&release_lock);
07161 chan_list_unref(p, "Release ast_channel reference");
07162 return 0;
07163 case MISDN_DIALING:
07164 if (p->hold.state == MISDN_HOLD_IDLE) {
07165 start_bc_tones(p);
07166 hanguptone_indicate(p);
07167 }
07168
07169 if (bc->need_disconnect) {
07170 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07171 }
07172 break;
07173 case MISDN_CALLING_ACKNOWLEDGE:
07174 if (p->hold.state == MISDN_HOLD_IDLE) {
07175 start_bc_tones(p);
07176 hanguptone_indicate(p);
07177 }
07178
07179 if (bc->need_disconnect) {
07180 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07181 }
07182 break;
07183
07184 case MISDN_CALLING:
07185 case MISDN_ALERTING:
07186 case MISDN_PROGRESS:
07187 case MISDN_PROCEEDING:
07188 if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
07189 hanguptone_indicate(p);
07190 }
07191
07192 if (bc->need_disconnect) {
07193 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07194 }
07195 break;
07196 case MISDN_CONNECTED:
07197
07198 if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
07199 start_bc_tones(p);
07200 hanguptone_indicate(p);
07201 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
07202 }
07203 if (bc->need_disconnect) {
07204 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07205 }
07206 break;
07207 case MISDN_DISCONNECTED:
07208 if (bc->need_release) {
07209 misdn_lib_send_event(bc, EVENT_RELEASE);
07210 }
07211 break;
07212
07213 case MISDN_CLEANING:
07214 ast_mutex_unlock(&release_lock);
07215 chan_list_unref(p, "Release ast_channel reference");
07216 return 0;
07217
07218 case MISDN_BUSY:
07219 break;
07220 default:
07221 if (bc->nt) {
07222 bc->out_cause = -1;
07223 if (bc->need_release) {
07224 misdn_lib_send_event(bc, EVENT_RELEASE);
07225 }
07226 } else {
07227 if (bc->need_disconnect) {
07228 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07229 }
07230 }
07231 break;
07232 }
07233
07234 p->state = MISDN_CLEANING;
07235 chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
07236 misdn_get_ch_state(p));
07237
07238 ast_mutex_unlock(&release_lock);
07239 chan_list_unref(p, "Release ast_channel reference");
07240 return 0;
07241 }
07242
07243
07244 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
07245 {
07246 struct ast_frame *f;
07247
07248 if (tmp->dsp) {
07249 f = ast_dsp_process(tmp->ast, tmp->dsp, frame);
07250 } else {
07251 chan_misdn_log(0, tmp->bc->port, "No DSP-Path found\n");
07252 return NULL;
07253 }
07254
07255 if (!f || (f->frametype != AST_FRAME_DTMF)) {
07256 return f;
07257 }
07258
07259 ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass.integer);
07260
07261 if (tmp->faxdetect && (f->subclass.integer == 'f')) {
07262
07263 if (!tmp->faxhandled) {
07264 struct ast_channel *ast = tmp->ast;
07265 tmp->faxhandled++;
07266 chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
07267 tmp->bc->rxgain = 0;
07268 isdn_lib_update_rxgain(tmp->bc);
07269 tmp->bc->txgain = 0;
07270 isdn_lib_update_txgain(tmp->bc);
07271 #ifdef MISDN_1_2
07272 *tmp->bc->pipeline = 0;
07273 #else
07274 tmp->bc->ec_enable = 0;
07275 #endif
07276 isdn_lib_update_ec(tmp->bc);
07277 isdn_lib_stop_dtmf(tmp->bc);
07278 switch (tmp->faxdetect) {
07279 case 1:
07280 if (strcmp(ast->exten, "fax")) {
07281 char *context;
07282 char context_tmp[BUFFERSIZE];
07283 misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
07284 context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
07285 if (ast_exists_extension(ast, context, "fax", 1,
07286 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
07287 ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
07288
07289 pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
07290 if (ast_async_goto(ast, context, "fax", 1)) {
07291 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
07292 }
07293 } else {
07294 ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten);
07295 }
07296 } else {
07297 ast_debug(1, "Already in a fax extension, not redirecting\n");
07298 }
07299 break;
07300 case 2:
07301 ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
07302 break;
07303 default:
07304 break;
07305 }
07306 } else {
07307 ast_debug(1, "Fax already handled\n");
07308 }
07309 }
07310
07311 if (tmp->ast_dsp && (f->subclass.integer != 'f')) {
07312 chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass.integer);
07313 }
07314
07315 return f;
07316 }
07317
07318
07319 static struct ast_frame *misdn_read(struct ast_channel *ast)
07320 {
07321 struct chan_list *tmp;
07322 int len, t;
07323 struct pollfd pfd = { .fd = -1, .events = POLLIN };
07324
07325 if (!ast) {
07326 chan_misdn_log(1, 0, "misdn_read called without ast\n");
07327 return NULL;
07328 }
07329 if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
07330 chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
07331 return NULL;
07332 }
07333
07334 if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
07335 chan_misdn_log(1, 0, "misdn_read called without bc\n");
07336 return NULL;
07337 }
07338
07339 pfd.fd = tmp->pipe[0];
07340 t = ast_poll(&pfd, 1, 20);
07341
07342 if (t < 0) {
07343 chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
07344 return NULL;
07345 }
07346
07347 if (!t) {
07348 chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
07349 len = 160;
07350 } else if (pfd.revents & POLLIN) {
07351 len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
07352
07353 if (len <= 0) {
07354
07355 chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
07356 return NULL;
07357 }
07358 } else {
07359 return NULL;
07360 }
07361
07362 tmp->frame.frametype = AST_FRAME_VOICE;
07363 tmp->frame.subclass.codec = AST_FORMAT_ALAW;
07364 tmp->frame.datalen = len;
07365 tmp->frame.samples = len;
07366 tmp->frame.mallocd = 0;
07367 tmp->frame.offset = 0;
07368 tmp->frame.delivery = ast_tv(0, 0);
07369 tmp->frame.src = NULL;
07370 tmp->frame.data.ptr = tmp->ast_rd_buf;
07371
07372 if (tmp->faxdetect && !tmp->faxhandled) {
07373 if (tmp->faxdetect_timeout) {
07374 if (ast_tvzero(tmp->faxdetect_tv)) {
07375 tmp->faxdetect_tv = ast_tvnow();
07376 chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
07377 return process_ast_dsp(tmp, &tmp->frame);
07378 } else {
07379 struct timeval tv_now = ast_tvnow();
07380 int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
07381 if (diff <= (tmp->faxdetect_timeout * 1000)) {
07382 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
07383 return process_ast_dsp(tmp, &tmp->frame);
07384 } else {
07385 chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
07386 tmp->faxdetect = 0;
07387 return &tmp->frame;
07388 }
07389 }
07390 } else {
07391 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
07392 return process_ast_dsp(tmp, &tmp->frame);
07393 }
07394 } else {
07395 if (tmp->ast_dsp) {
07396 return process_ast_dsp(tmp, &tmp->frame);
07397 } else {
07398 return &tmp->frame;
07399 }
07400 }
07401 }
07402
07403
07404 static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
07405 {
07406 struct chan_list *ch;
07407
07408 if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
07409 return -1;
07410 }
07411
07412 if (ch->hold.state != MISDN_HOLD_IDLE) {
07413 chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
07414 return 0;
07415 }
07416
07417 if (!ch->bc) {
07418 ast_log(LOG_WARNING, "private but no bc\n");
07419 return -1;
07420 }
07421
07422 if (ch->notxtone) {
07423 chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
07424 return 0;
07425 }
07426
07427
07428 if (!frame->subclass.codec) {
07429 chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
07430 return 0;
07431 }
07432
07433 if (!(frame->subclass.codec & prefformat)) {
07434 chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", ast_getformatname(frame->subclass.codec));
07435 return 0;
07436 }
07437
07438
07439 if (!frame->samples) {
07440 chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
07441
07442 if (!strcmp(frame->src,"ast_prod")) {
07443 chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
07444
07445 if (ch->ts) {
07446 chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
07447 misdn_lib_tone_generator_start(ch->bc);
07448 }
07449 return 0;
07450 }
07451
07452 return -1;
07453 }
07454
07455 if (!ch->bc->addr) {
07456 chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
07457 return 0;
07458 }
07459
07460 #ifdef MISDN_DEBUG
07461 {
07462 int i;
07463 int max = 5 > frame->samples ? frame->samples : 5;
07464
07465 ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
07466
07467 for (i = 0; i < max; i++) {
07468 ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]);
07469 }
07470 }
07471 #endif
07472
07473 switch (ch->bc->bc_state) {
07474 case BCHAN_ACTIVATED:
07475 case BCHAN_BRIDGED:
07476 break;
07477 default:
07478 if (!ch->dropped_frame_cnt) {
07479 chan_misdn_log(5, ch->bc->port,
07480 "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n",
07481 frame->samples, ch->bc->addr, ast->exten,
07482 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
07483 misdn_get_ch_state(ch), ch->bc->bc_state, ch->bc->l3_id);
07484 }
07485
07486 if (++ch->dropped_frame_cnt > 100) {
07487 ch->dropped_frame_cnt = 0;
07488 chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x dropped > 100 frames!\n", frame->samples, ch->bc->addr);
07489 }
07490
07491 return 0;
07492 }
07493
07494 chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
07495 if (!ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability)) {
07496
07497 if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) {
07498 if (ch->bc->active) {
07499 cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
07500 }
07501 }
07502
07503 } else {
07504
07505 misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
07506 }
07507
07508 return 0;
07509 }
07510
07511 static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
07512 struct ast_channel *c1, int flags,
07513 struct ast_frame **fo,
07514 struct ast_channel **rc,
07515 int timeoutms)
07516 {
07517 struct chan_list *ch1, *ch2;
07518 struct ast_channel *carr[2], *who;
07519 int to = -1;
07520 struct ast_frame *f;
07521 int p1_b, p2_b;
07522 int bridging;
07523
07524 ch1 = get_chan_by_ast(c0);
07525 if (!ch1) {
07526 return -1;
07527 }
07528 ch2 = get_chan_by_ast(c1);
07529 if (!ch2) {
07530 chan_list_unref(ch1, "Failed to find ch2");
07531 return -1;
07532 }
07533
07534 carr[0] = c0;
07535 carr[1] = c1;
07536
07537 misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
07538 misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));
07539
07540 if (! p1_b || ! p2_b) {
07541 ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
07542 chan_list_unref(ch1, "Bridge fallback ch1");
07543 chan_list_unref(ch2, "Bridge fallback ch2");
07544 return AST_BRIDGE_FAILED;
07545 }
07546
07547 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
07548 if (bridging) {
07549
07550 chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
07551 misdn_lib_bridge(ch1->bc, ch2->bc);
07552 }
07553
07554 ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
07555
07556 chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n",
07557 ch1->bc->caller.name,
07558 ch1->bc->caller.number,
07559 ch2->bc->caller.name,
07560 ch2->bc->caller.number);
07561
07562 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
07563 ch1->ignore_dtmf = 1;
07564 }
07565
07566 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
07567 ch2->ignore_dtmf = 1;
07568 }
07569
07570 for (;;) {
07571 to = -1;
07572 who = ast_waitfor_n(carr, 2, &to);
07573
07574 if (!who) {
07575 ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
07576 break;
07577 }
07578 f = ast_read(who);
07579
07580 if (!f || f->frametype == AST_FRAME_CONTROL) {
07581
07582
07583 if (!f) {
07584 chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
07585 } else {
07586 chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass.integer);
07587 }
07588
07589 *fo = f;
07590 *rc = who;
07591 break;
07592 }
07593
07594 if (f->frametype == AST_FRAME_DTMF) {
07595 chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass.integer, who->exten);
07596
07597 *fo = f;
07598 *rc = who;
07599 break;
07600 }
07601
07602 #if 0
07603 if (f->frametype == AST_FRAME_VOICE) {
07604 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
07605
07606 continue;
07607 }
07608 #endif
07609
07610 ast_write((who == c0) ? c1 : c0, f);
07611 }
07612
07613 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
07614
07615 misdn_lib_split_bridge(ch1->bc, ch2->bc);
07616
07617 chan_list_unref(ch1, "Bridge complete ch1");
07618 chan_list_unref(ch2, "Bridge complete ch2");
07619 return AST_BRIDGE_COMPLETE;
07620 }
07621
07622
07623
07624 static int dialtone_indicate(struct chan_list *cl)
07625 {
07626 struct ast_channel *ast = cl->ast;
07627 int nd = 0;
07628
07629 if (!ast) {
07630 chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
07631 return -1;
07632 }
07633
07634 misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));
07635
07636 if (nd) {
07637 chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
07638 return 0;
07639 }
07640
07641 chan_misdn_log(3, cl->bc->port, " --> Dial\n");
07642
07643 cl->ts = ast_get_indication_tone(ast->zone, "dial");
07644
07645 if (cl->ts) {
07646 cl->notxtone = 0;
07647 cl->norxtone = 0;
07648
07649 ast_playtones_start(ast, 0, cl->ts->data, 0);
07650 }
07651
07652 return 0;
07653 }
07654
07655 static void hanguptone_indicate(struct chan_list *cl)
07656 {
07657 misdn_lib_send_tone(cl->bc, TONE_HANGUP);
07658 }
07659
07660 static int stop_indicate(struct chan_list *cl)
07661 {
07662 struct ast_channel *ast = cl->ast;
07663
07664 if (!ast) {
07665 chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
07666 return -1;
07667 }
07668
07669 chan_misdn_log(3, cl->bc->port, " --> None\n");
07670 misdn_lib_tone_generator_stop(cl->bc);
07671 ast_playtones_stop(ast);
07672
07673 if (cl->ts) {
07674 cl->ts = ast_tone_zone_sound_unref(cl->ts);
07675 }
07676
07677 return 0;
07678 }
07679
07680
07681 static int start_bc_tones(struct chan_list* cl)
07682 {
07683 misdn_lib_tone_generator_stop(cl->bc);
07684 cl->notxtone = 0;
07685 cl->norxtone = 0;
07686 return 0;
07687 }
07688
07689 static int stop_bc_tones(struct chan_list *cl)
07690 {
07691 if (!cl) {
07692 return -1;
07693 }
07694
07695 cl->notxtone = 1;
07696 cl->norxtone = 1;
07697
07698 return 0;
07699 }
07700
07701
07702
07703
07704
07705
07706
07707
07708
07709 static void chan_list_destructor(void *obj)
07710 {
07711 struct chan_list *ch = obj;
07712
07713 #if defined(AST_MISDN_ENHANCEMENTS)
07714 if (ch->peer) {
07715 ao2_ref(ch->peer, -1);
07716 ch->peer = NULL;
07717 }
07718 #endif
07719
07720 if (ch->dsp) {
07721 ast_dsp_free(ch->dsp);
07722 ch->dsp = NULL;
07723 }
07724
07725
07726 if (ch->jb) {
07727 misdn_jb_destroy(ch->jb);
07728 ch->jb = NULL;
07729 }
07730
07731 if (ch->overlap_dial) {
07732 if (ch->overlap_dial_task != -1) {
07733 misdn_tasks_remove(ch->overlap_dial_task);
07734 ch->overlap_dial_task = -1;
07735 }
07736 ast_mutex_destroy(&ch->overlap_tv_lock);
07737 }
07738
07739 if (-1 < ch->pipe[0]) {
07740 close(ch->pipe[0]);
07741 }
07742 if (-1 < ch->pipe[1]) {
07743 close(ch->pipe[1]);
07744 }
07745 }
07746
07747
07748 static struct chan_list *chan_list_init(int orig)
07749 {
07750 struct chan_list *cl;
07751
07752 cl = ao2_alloc(sizeof(*cl), chan_list_destructor);
07753 if (!cl) {
07754 chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
07755 return NULL;
07756 }
07757
07758 cl->originator = orig;
07759 cl->need_queue_hangup = 1;
07760 cl->need_hangup = 1;
07761 cl->need_busy = 1;
07762 cl->overlap_dial_task = -1;
07763 #if defined(AST_MISDN_ENHANCEMENTS)
07764 cl->record_id = -1;
07765 #endif
07766 cl->pipe[0] = -1;
07767 cl->pipe[1] = -1;
07768
07769 return cl;
07770 }
07771
07772 static struct ast_channel *misdn_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
07773 {
07774 struct ast_channel *ast;
07775 char group[BUFFERSIZE + 1] = "";
07776 char dial_str[128];
07777 char *dest_cp;
07778 char *p = NULL;
07779 int channel = 0;
07780 int port = 0;
07781 struct misdn_bchannel *newbc = NULL;
07782 int dec = 0;
07783 #if defined(AST_MISDN_ENHANCEMENTS)
07784 int cc_retry_call = 0;
07785 long record_id = -1;
07786 struct misdn_cc_record *cc_record;
07787 const char *err_msg;
07788 #endif
07789 struct chan_list *cl;
07790
07791 AST_DECLARE_APP_ARGS(args,
07792 AST_APP_ARG(intf);
07793 AST_APP_ARG(ext);
07794 AST_APP_ARG(opts);
07795 );
07796
07797 snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
07798
07799
07800
07801
07802
07803
07804
07805
07806
07807
07808 dest_cp = ast_strdupa(data);
07809 AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
07810 if (!args.ext) {
07811 args.ext = "";
07812 }
07813
07814 if (!ast_strlen_zero(args.intf)) {
07815 if (args.intf[0] == 'g' && args.intf[1] == ':') {
07816
07817 args.intf += 2;
07818 ast_copy_string(group, args.intf, sizeof(group));
07819 chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
07820 #if defined(AST_MISDN_ENHANCEMENTS)
07821 } else if (strcmp(args.intf, "cc") == 0) {
07822 cc_retry_call = 1;
07823 #endif
07824 } else if ((p = strchr(args.intf, ':'))) {
07825
07826 *p++ = 0;
07827 channel = atoi(p);
07828 port = atoi(args.intf);
07829 chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
07830 } else {
07831 port = atoi(args.intf);
07832 }
07833 } else {
07834 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
07835 return NULL;
07836 }
07837
07838 #if defined(AST_MISDN_ENHANCEMENTS)
07839 if (cc_retry_call) {
07840 if (ast_strlen_zero(args.ext)) {
07841 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT cc-record-id, check extensions.conf\n", dial_str);
07842 return NULL;
07843 }
07844 if (!isdigit(*args.ext)) {
07845 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) cc-record-id must be a number.\n", dial_str);
07846 return NULL;
07847 }
07848 record_id = atol(args.ext);
07849
07850 AST_LIST_LOCK(&misdn_cc_records_db);
07851 cc_record = misdn_cc_find_by_id(record_id);
07852 if (!cc_record) {
07853 AST_LIST_UNLOCK(&misdn_cc_records_db);
07854 err_msg = misdn_cc_record_not_found;
07855 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07856 return NULL;
07857 }
07858 if (!cc_record->activated) {
07859 AST_LIST_UNLOCK(&misdn_cc_records_db);
07860 err_msg = "Call completion has not been activated";
07861 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07862 return NULL;
07863 }
07864 port = cc_record->port;
07865 AST_LIST_UNLOCK(&misdn_cc_records_db);
07866 }
07867 #endif
07868
07869 if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
07870 chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
07871 dec = 1;
07872 }
07873
07874 if (!ast_strlen_zero(group)) {
07875 char cfg_group[BUFFERSIZE + 1];
07876 struct robin_list *rr = NULL;
07877
07878
07879
07880 if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
07881 chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
07882 rr = get_robin_position(group);
07883 }
07884
07885 if (rr) {
07886 int port_start;
07887 int bchan_start;
07888 int port_up;
07889 int check;
07890 int maxbchans;
07891 int wraped = 0;
07892
07893 if (!rr->port) {
07894 rr->port = misdn_cfg_get_next_port_spin(0);
07895 }
07896
07897 if (!rr->channel) {
07898 rr->channel = 1;
07899 }
07900
07901 bchan_start = rr->channel;
07902 port_start = rr->port;
07903 do {
07904 misdn_cfg_get(rr->port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07905 if (strcasecmp(cfg_group, group)) {
07906 wraped = 1;
07907 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07908 rr->channel = 1;
07909 continue;
07910 }
07911
07912 misdn_cfg_get(rr->port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07913 port_up = misdn_lib_port_up(rr->port, check);
07914
07915 if (!port_up) {
07916 chan_misdn_log(1, rr->port, "L1 is not Up on this Port\n");
07917 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07918 rr->channel = 1;
07919 } else if (port_up < 0) {
07920 ast_log(LOG_WARNING, "This port (%d) is blocked\n", rr->port);
07921 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07922 rr->channel = 1;
07923 } else {
07924 chan_misdn_log(4, rr->port, "portup\n");
07925 maxbchans = misdn_lib_get_maxchans(rr->port);
07926
07927 for (;rr->channel <= maxbchans;rr->channel++) {
07928
07929 if (wraped && (rr->port == port_start) && (rr->channel == bchan_start)) {
07930 break;
07931 }
07932
07933 chan_misdn_log(4, rr->port, "Checking channel %d\n", rr->channel);
07934
07935 if ((newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0))) {
07936 chan_misdn_log(4, rr->port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
07937 rr->channel++;
07938 break;
07939 }
07940 }
07941 if (wraped && (rr->port == port_start) && (rr->channel <= bchan_start)) {
07942 break;
07943 } else if (!newbc || (rr->channel == maxbchans)) {
07944 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07945 rr->channel = 1;
07946 }
07947
07948 }
07949 wraped = 1;
07950 } while (!newbc && (rr->port > 0));
07951 } else {
07952 for (port = misdn_cfg_get_next_port(0); port > 0;
07953 port = misdn_cfg_get_next_port(port)) {
07954 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07955
07956 chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
07957 if (!strcasecmp(cfg_group, group)) {
07958 int port_up;
07959 int check;
07960
07961 misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07962 port_up = misdn_lib_port_up(port, check);
07963
07964 chan_misdn_log(4, port, "portup:%d\n", port_up);
07965
07966 if (port_up > 0) {
07967 newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
07968 if (newbc) {
07969 break;
07970 }
07971 }
07972 }
07973 }
07974 }
07975
07976
07977 if (!newbc) {
07978 ast_log(LOG_WARNING,
07979 "Could not Dial out on group '%s'.\n"
07980 "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
07981 "\tOr there was no free channel on none of the ports\n\n",
07982 group);
07983 return NULL;
07984 }
07985 } else {
07986
07987 if (channel) {
07988 chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
07989 }
07990 newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
07991 if (!newbc) {
07992 ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str);
07993 return NULL;
07994 }
07995 }
07996
07997
07998 cl = chan_list_init(ORG_AST);
07999 if (!cl) {
08000 misdn_lib_release(newbc);
08001 ast_log(LOG_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
08002 return NULL;
08003 }
08004 cl->bc = newbc;
08005
08006 ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, requestor ? requestor->linkedid : NULL, port, channel);
08007 if (!ast) {
08008 chan_list_unref(cl, "Failed to create a new channel");
08009 misdn_lib_release(newbc);
08010 ast_log(LOG_ERROR, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
08011 return NULL;
08012 }
08013
08014 #if defined(AST_MISDN_ENHANCEMENTS)
08015 cl->record_id = record_id;
08016 #endif
08017
08018
08019 cl_queue_chan(cl);
08020
08021
08022 read_config(cl);
08023
08024
08025 cl->need_hangup = 0;
08026
08027 chan_list_unref(cl, "Successful misdn_request()");
08028 return ast;
08029 }
08030
08031
08032 static int misdn_send_text(struct ast_channel *chan, const char *text)
08033 {
08034 struct chan_list *tmp = MISDN_ASTERISK_TECH_PVT(chan);
08035
08036 if (tmp && tmp->bc) {
08037 ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
08038 misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
08039 } else {
08040 ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
08041 return -1;
08042 }
08043
08044 return 0;
08045 }
08046
08047 static struct ast_channel_tech misdn_tech = {
08048 .type = misdn_type,
08049 .description = "Channel driver for mISDN Support (Bri/Pri)",
08050 .capabilities = AST_FORMAT_ALAW ,
08051 .requester = misdn_request,
08052 .send_digit_begin = misdn_digit_begin,
08053 .send_digit_end = misdn_digit_end,
08054 .call = misdn_call,
08055 .bridge = misdn_bridge,
08056 .hangup = misdn_hangup,
08057 .answer = misdn_answer,
08058 .read = misdn_read,
08059 .write = misdn_write,
08060 .indicate = misdn_indication,
08061 .fixup = misdn_fixup,
08062 .send_text = misdn_send_text,
08063 .properties = 0,
08064 };
08065
08066 static struct ast_channel_tech misdn_tech_wo_bridge = {
08067 .type = misdn_type,
08068 .description = "Channel driver for mISDN Support (Bri/Pri)",
08069 .capabilities = AST_FORMAT_ALAW ,
08070 .requester = misdn_request,
08071 .send_digit_begin = misdn_digit_begin,
08072 .send_digit_end = misdn_digit_end,
08073 .call = misdn_call,
08074 .hangup = misdn_hangup,
08075 .answer = misdn_answer,
08076 .read = misdn_read,
08077 .write = misdn_write,
08078 .indicate = misdn_indication,
08079 .fixup = misdn_fixup,
08080 .send_text = misdn_send_text,
08081 .properties = 0,
08082 };
08083
08084
08085 static int glob_channel = 0;
08086
08087 static void update_name(struct ast_channel *tmp, int port, int c)
08088 {
08089 int chan_offset = 0;
08090 int tmp_port = misdn_cfg_get_next_port(0);
08091 char newname[255];
08092
08093 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08094 if (tmp_port == port) {
08095 break;
08096 }
08097 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08098 }
08099 if (c < 0) {
08100 c = 0;
08101 }
08102
08103 snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
08104 if (strncmp(tmp->name, newname, strlen(newname))) {
08105 snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
08106 ast_change_name(tmp, newname);
08107 chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
08108 }
08109 }
08110
08111 static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, int format, const char *linkedid, int port, int c)
08112 {
08113 struct ast_channel *tmp;
08114 char *cid_name = NULL;
08115 char *cid_num = NULL;
08116 int chan_offset = 0;
08117 int tmp_port = misdn_cfg_get_next_port(0);
08118 int bridging;
08119
08120 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08121 if (tmp_port == port) {
08122 break;
08123 }
08124 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08125 }
08126 if (c < 0) {
08127 c = 0;
08128 }
08129
08130 if (callerid) {
08131 ast_callerid_parse(callerid, &cid_name, &cid_num);
08132 }
08133
08134 tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", linkedid, 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
08135 if (tmp) {
08136 chan_misdn_log(2, port, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
08137
08138 tmp->nativeformats = prefformat;
08139
08140 tmp->readformat = format;
08141 tmp->rawreadformat = format;
08142 tmp->writeformat = format;
08143 tmp->rawwriteformat = format;
08144
08145
08146 chan_list_ref(chlist, "Give a reference to ast_channel");
08147 MISDN_ASTERISK_TECH_PVT(tmp) = chlist;
08148 chlist->ast = tmp;
08149
08150 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
08151 tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge;
08152
08153 tmp->writeformat = format;
08154 tmp->readformat = format;
08155 tmp->priority = 1;
08156
08157 if (exten) {
08158 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
08159 } else {
08160 chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
08161 }
08162
08163 if (!ast_strlen_zero(cid_num)) {
08164
08165
08166 tmp->caller.ani.number.valid = 1;
08167 tmp->caller.ani.number.str = ast_strdup(cid_num);
08168 }
08169
08170 if (pipe(chlist->pipe) < 0) {
08171 ast_log(LOG_ERROR, "Pipe failed\n");
08172 }
08173 ast_channel_set_fd(tmp, 0, chlist->pipe[0]);
08174
08175 tmp->rings = (state == AST_STATE_RING) ? 1 : 0;
08176
08177 ast_jb_configure(tmp, misdn_get_global_jbconf());
08178 } else {
08179 chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
08180 }
08181
08182 return tmp;
08183 }
08184
08185
08186 static struct chan_list *find_chan_by_bc(struct misdn_bchannel *bc)
08187 {
08188 struct chan_list *help;
08189
08190 ast_mutex_lock(&cl_te_lock);
08191 for (help = cl_te; help; help = help->next) {
08192 if (help->bc == bc) {
08193 chan_list_ref(help, "Found chan_list by bc");
08194 ast_mutex_unlock(&cl_te_lock);
08195 return help;
08196 }
08197 }
08198 ast_mutex_unlock(&cl_te_lock);
08199
08200 chan_misdn_log(6, bc->port,
08201 "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08202 bc->dialed.number,
08203 bc->caller.name,
08204 bc->caller.number);
08205
08206 return NULL;
08207 }
08208
08209
08210 static struct chan_list *find_hold_call(struct misdn_bchannel *bc)
08211 {
08212 struct chan_list *help;
08213
08214 if (bc->pri) {
08215 return NULL;
08216 }
08217
08218 chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d dialed:%s caller:\"%s\" <%s>\n",
08219 bc->channel,
08220 bc->dialed.number,
08221 bc->caller.name,
08222 bc->caller.number);
08223 ast_mutex_lock(&cl_te_lock);
08224 for (help = cl_te; help; help = help->next) {
08225 chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
08226 if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port) {
08227 chan_list_ref(help, "Found chan_list hold call");
08228 ast_mutex_unlock(&cl_te_lock);
08229 return help;
08230 }
08231 }
08232 ast_mutex_unlock(&cl_te_lock);
08233 chan_misdn_log(6, bc->port,
08234 "$$$ find_hold_call: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08235 bc->dialed.number,
08236 bc->caller.name,
08237 bc->caller.number);
08238
08239 return NULL;
08240 }
08241
08242
08243
08244 static struct chan_list *find_hold_call_l3(unsigned long l3_id)
08245 {
08246 struct chan_list *help;
08247
08248 ast_mutex_lock(&cl_te_lock);
08249 for (help = cl_te; help; help = help->next) {
08250 if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id) {
08251 chan_list_ref(help, "Found chan_list hold call l3");
08252 ast_mutex_unlock(&cl_te_lock);
08253 return help;
08254 }
08255 }
08256 ast_mutex_unlock(&cl_te_lock);
08257
08258 return NULL;
08259 }
08260
08261 #define TRANSFER_ON_HELD_CALL_HANGUP 1
08262 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
08263
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278 static struct chan_list *find_hold_active_call(struct misdn_bchannel *bc)
08279 {
08280 struct chan_list *list;
08281
08282 ast_mutex_lock(&cl_te_lock);
08283 for (list = cl_te; list; list = list->next) {
08284 if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
08285 && list->ast) {
08286 switch (list->state) {
08287 case MISDN_PROCEEDING:
08288 case MISDN_PROGRESS:
08289 case MISDN_ALERTING:
08290 case MISDN_CONNECTED:
08291 chan_list_ref(list, "Found chan_list hold active call");
08292 ast_mutex_unlock(&cl_te_lock);
08293 return list;
08294 default:
08295 break;
08296 }
08297 }
08298 }
08299 ast_mutex_unlock(&cl_te_lock);
08300 return NULL;
08301 }
08302 #endif
08303
08304 static void cl_queue_chan(struct chan_list *chan)
08305 {
08306 chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
08307
08308 chan_list_ref(chan, "Adding chan_list to list");
08309 ast_mutex_lock(&cl_te_lock);
08310 chan->next = NULL;
08311 if (!cl_te) {
08312
08313 cl_te = chan;
08314 } else {
08315 struct chan_list *help;
08316
08317
08318 for (help = cl_te; help->next; help = help->next) {
08319 }
08320 help->next = chan;
08321 }
08322 ast_mutex_unlock(&cl_te_lock);
08323 }
08324
08325 static int cl_dequeue_chan(struct chan_list *chan)
08326 {
08327 int found_it;
08328 struct chan_list *help;
08329
08330 ast_mutex_lock(&cl_te_lock);
08331 if (!cl_te) {
08332
08333 ast_mutex_unlock(&cl_te_lock);
08334 return 0;
08335 }
08336
08337 if (cl_te == chan) {
08338
08339 cl_te = cl_te->next;
08340 ast_mutex_unlock(&cl_te_lock);
08341 chan_list_unref(chan, "Removed chan_list from list head");
08342 return 1;
08343 }
08344
08345 found_it = 0;
08346 for (help = cl_te; help->next; help = help->next) {
08347 if (help->next == chan) {
08348
08349 help->next = help->next->next;
08350 found_it = 1;
08351 break;
08352 }
08353 }
08354
08355 ast_mutex_unlock(&cl_te_lock);
08356 if (found_it) {
08357 chan_list_unref(chan, "Removed chan_list from list");
08358 }
08359 return found_it;
08360 }
08361
08362
08363
08364
08365 static int pbx_start_chan(struct chan_list *ch)
08366 {
08367 int ret = ast_pbx_start(ch->ast);
08368
08369 ch->need_hangup = (ret >= 0) ? 0 : 1;
08370
08371 return ret;
08372 }
08373
08374 static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08375 {
08376 int port = bc->port;
08377
08378 if (!ch) {
08379 cb_log(1, port, "Cannot hangup chan, no ch\n");
08380 return;
08381 }
08382
08383 cb_log(5, port, "hangup_chan called\n");
08384
08385 if (ch->need_hangup) {
08386 cb_log(2, port, " --> hangup\n");
08387 ch->need_hangup = 0;
08388 ch->need_queue_hangup = 0;
08389 if (ch->ast && send_cause2ast(ch->ast, bc, ch)) {
08390 ast_hangup(ch->ast);
08391 }
08392 return;
08393 }
08394
08395 if (!ch->need_queue_hangup) {
08396 cb_log(2, port, " --> No need to queue hangup\n");
08397 return;
08398 }
08399
08400 ch->need_queue_hangup = 0;
08401 if (ch->ast) {
08402 if (send_cause2ast(ch->ast, bc, ch)) {
08403 ast_queue_hangup_with_cause(ch->ast, bc->cause);
08404 cb_log(2, port, " --> queue_hangup\n");
08405 }
08406 } else {
08407 cb_log(1, port, "Cannot hangup chan, no ast\n");
08408 }
08409 }
08410
08411
08412
08413
08414
08415
08416
08417
08418
08419
08420
08421
08422 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08423 {
08424 struct ast_channel *ast;
08425
08426 chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);
08427
08428 ast_mutex_lock(&release_lock);
08429 for (;;) {
08430 ast = ch->ast;
08431 if (!ast || !ast_channel_trylock(ast)) {
08432 break;
08433 }
08434 DEADLOCK_AVOIDANCE(&release_lock);
08435 }
08436 if (!cl_dequeue_chan(ch)) {
08437
08438 if (ast) {
08439 ast_channel_unlock(ast);
08440 }
08441 ast_mutex_unlock(&release_lock);
08442 return;
08443 }
08444 ch->state = MISDN_CLEANING;
08445 ch->ast = NULL;
08446 if (ast) {
08447 struct chan_list *ast_ch;
08448
08449 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08450 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08451 chan_misdn_log(1, bc->port,
08452 "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s>\n",
08453 bc->pid,
08454 ast->context,
08455 ast->exten,
08456 S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
08457 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""));
08458
08459 if (ast->_state != AST_STATE_RESERVED) {
08460 chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
08461 ast_setstate(ast, AST_STATE_DOWN);
08462 }
08463 ast_channel_unlock(ast);
08464 if (ast_ch) {
08465 chan_list_unref(ast_ch, "Release ast_channel reference.");
08466 }
08467 }
08468
08469 if (ch->originator == ORG_AST) {
08470 --misdn_out_calls[bc->port];
08471 } else {
08472 --misdn_in_calls[bc->port];
08473 }
08474
08475 ast_mutex_unlock(&release_lock);
08476 }
08477
08478
08479
08480
08481
08482
08483
08484
08485
08486
08487
08488 static void release_chan_early(struct chan_list *ch)
08489 {
08490 struct ast_channel *ast;
08491
08492 ast_mutex_lock(&release_lock);
08493 for (;;) {
08494 ast = ch->ast;
08495 if (!ast || !ast_channel_trylock(ast)) {
08496 break;
08497 }
08498 DEADLOCK_AVOIDANCE(&release_lock);
08499 }
08500 if (!cl_dequeue_chan(ch)) {
08501
08502 if (ast) {
08503 ast_channel_unlock(ast);
08504 }
08505 ast_mutex_unlock(&release_lock);
08506 return;
08507 }
08508 ch->state = MISDN_CLEANING;
08509 ch->ast = NULL;
08510 if (ast) {
08511 struct chan_list *ast_ch;
08512
08513 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08514 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08515
08516 if (ast->_state != AST_STATE_RESERVED) {
08517 ast_setstate(ast, AST_STATE_DOWN);
08518 }
08519 ast_channel_unlock(ast);
08520 if (ast_ch) {
08521 chan_list_unref(ast_ch, "Release ast_channel reference.");
08522 }
08523 }
08524
08525 if (ch->hold.state != MISDN_HOLD_IDLE) {
08526 if (ch->originator == ORG_AST) {
08527 --misdn_out_calls[ch->hold.port];
08528 } else {
08529 --misdn_in_calls[ch->hold.port];
08530 }
08531 }
08532
08533 ast_mutex_unlock(&release_lock);
08534 }
08535
08536
08537
08538
08539
08540
08541
08542
08543
08544
08545
08546 static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
08547 {
08548 int retval;
08549 struct ast_channel *target;
08550 struct ast_channel *transferee;
08551 struct ast_party_connected_line target_colp;
08552 struct ast_party_connected_line transferee_colp;
08553
08554 switch (active_ch->state) {
08555 case MISDN_PROCEEDING:
08556 case MISDN_PROGRESS:
08557 case MISDN_ALERTING:
08558 case MISDN_CONNECTED:
08559 break;
08560 default:
08561 return -1;
08562 }
08563
08564 ast_channel_lock(held_ch->ast);
08565 while (ast_channel_trylock(active_ch->ast)) {
08566 CHANNEL_DEADLOCK_AVOIDANCE(held_ch->ast);
08567 }
08568
08569 transferee = ast_bridged_channel(held_ch->ast);
08570 if (!transferee) {
08571
08572
08573
08574
08575 ast_channel_unlock(held_ch->ast);
08576 ast_channel_unlock(active_ch->ast);
08577 return -1;
08578 }
08579
08580 target = active_ch->ast;
08581 chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
08582 held_ch->ast->name, target->name);
08583
08584 ast_party_connected_line_init(&target_colp);
08585 ast_party_connected_line_copy(&target_colp, &target->connected);
08586 ast_party_connected_line_init(&transferee_colp);
08587 ast_party_connected_line_copy(&transferee_colp, &held_ch->ast->connected);
08588 held_ch->hold.state = MISDN_HOLD_TRANSFER;
08589
08590
08591
08592
08593
08594
08595
08596
08597
08598
08599
08600 ao2_ref(target, +1);
08601 ao2_ref(transferee, +1);
08602 ast_channel_unlock(held_ch->ast);
08603 ast_channel_unlock(active_ch->ast);
08604
08605
08606 retval = ast_channel_transfer_masquerade(target, &target_colp, 0,
08607 transferee, &transferee_colp, 1);
08608
08609 ast_party_connected_line_free(&target_colp);
08610 ast_party_connected_line_free(&transferee_colp);
08611 ao2_ref(target, -1);
08612 ao2_ref(transferee, -1);
08613 return retval;
08614 }
08615
08616
08617 static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
08618 {
08619 char *predial;
08620 struct ast_frame fr;
08621
08622 predial = ast_strdupa(ast->exten);
08623
08624 ch->state = MISDN_DIALING;
08625
08626 if (!ch->noautorespond_on_setup) {
08627 if (bc->nt) {
08628 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08629 } else {
08630 if (misdn_lib_is_ptp(bc->port)) {
08631 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08632 } else {
08633 misdn_lib_send_event(bc, EVENT_PROCEEDING);
08634 }
08635 }
08636 } else {
08637 ch->state = MISDN_INCOMING_SETUP;
08638 }
08639
08640 chan_misdn_log(1, bc->port,
08641 "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n",
08642 ast->context,
08643 ast->exten,
08644 (ast->caller.id.name.valid && ast->caller.id.name.str)
08645 ? ast->caller.id.name.str : "",
08646 (ast->caller.id.number.valid && ast->caller.id.number.str)
08647 ? ast->caller.id.number.str : "");
08648
08649 strcpy(ast->exten, "s");
08650
08651 if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->caller.number) || pbx_start_chan(ch) < 0) {
08652 ast = NULL;
08653 bc->out_cause = AST_CAUSE_UNALLOCATED;
08654 hangup_chan(ch, bc);
08655 hanguptone_indicate(ch);
08656
08657 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
08658 }
08659
08660
08661 while (!ast_strlen_zero(predial)) {
08662 fr.frametype = AST_FRAME_DTMF;
08663 fr.subclass.integer = *predial;
08664 fr.src = NULL;
08665 fr.data.ptr = NULL;
08666 fr.datalen = 0;
08667 fr.samples = 0;
08668 fr.mallocd = 0;
08669 fr.offset = 0;
08670 fr.delivery = ast_tv(0,0);
08671
08672 if (ch->ast && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
08673 ast_queue_frame(ch->ast, &fr);
08674 }
08675 predial++;
08676 }
08677 }
08678
08679
08680
08681
08682
08683 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch)
08684 {
08685 int can_hangup;
08686
08687 if (!ast) {
08688 chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
08689 return 0;
08690 }
08691 if (!bc) {
08692 chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
08693 return 0;
08694 }
08695 if (!ch) {
08696 chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
08697 return 0;
08698 }
08699
08700 ast->hangupcause = bc->cause;
08701
08702 can_hangup = -1;
08703 switch (bc->cause) {
08704 case AST_CAUSE_UNALLOCATED:
08705 case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
08706 case AST_CAUSE_NO_ROUTE_DESTINATION:
08707 case 4:
08708 case AST_CAUSE_NUMBER_CHANGED:
08709 case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
08710
08711
08712
08713
08714
08715
08716
08717
08718
08719
08720 break;
08721
08722 case AST_CAUSE_CALL_REJECTED:
08723 case AST_CAUSE_USER_BUSY:
08724 ch->state = MISDN_BUSY;
08725
08726 if (!ch->need_busy) {
08727 chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
08728 break;
08729 }
08730 ch->need_busy = 0;
08731
08732 chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
08733 ast_queue_control(ast, AST_CONTROL_BUSY);
08734
08735
08736 can_hangup = 0;
08737 break;
08738 }
08739 return can_hangup;
08740 }
08741
08742
08743
08744 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08745 {
08746 const char *tmp;
08747
08748 ast_channel_lock(chan);
08749 tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
08750 if (tmp && (atoi(tmp) == 1)) {
08751 bc->sending_complete = 1;
08752 }
08753
08754 tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
08755 if (tmp) {
08756 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
08757 ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
08758 bc->uulen = strlen(bc->uu);
08759 }
08760
08761 tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
08762 if (tmp) {
08763 ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
08764 }
08765 ast_channel_unlock(chan);
08766 }
08767
08768
08769 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08770 {
08771 char tmp[32];
08772
08773
08774
08775
08776
08777
08778
08779 chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
08780 snprintf(tmp, sizeof(tmp), "%d", bc->pid);
08781 pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
08782
08783 if (bc->sending_complete) {
08784 snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
08785 pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
08786 }
08787
08788 if (bc->urate) {
08789 snprintf(tmp, sizeof(tmp), "%d", bc->urate);
08790 pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
08791 }
08792
08793 if (bc->uulen) {
08794 pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
08795 }
08796
08797 if (!ast_strlen_zero(bc->keypad)) {
08798 pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
08799 }
08800 }
08801
08802 int add_in_calls(int port)
08803 {
08804 int max_in_calls;
08805
08806 misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
08807 misdn_in_calls[port]++;
08808
08809 if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
08810 ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
08811 return misdn_in_calls[port] - max_in_calls;
08812 }
08813
08814 return 0;
08815 }
08816
08817 int add_out_calls(int port)
08818 {
08819 int max_out_calls;
08820
08821 misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
08822
08823 if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
08824 ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
08825 return (misdn_out_calls[port] + 1) - max_out_calls;
08826 }
08827
08828 misdn_out_calls[port]++;
08829
08830 return 0;
08831 }
08832
08833 static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08834 {
08835 if (pbx_start_chan(ch) < 0) {
08836 hangup_chan(ch, bc);
08837 chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
08838 if (bc->nt) {
08839 hanguptone_indicate(ch);
08840 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
08841 } else {
08842 misdn_lib_send_event(bc, EVENT_RELEASE);
08843 }
08844 }
08845 }
08846
08847 static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08848 {
08849 ch->state = MISDN_WAITING4DIGS;
08850 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08851 if (bc->nt && !bc->dialed.number[0]) {
08852 dialtone_indicate(ch);
08853 }
08854 }
08855
08856 #if defined(AST_MISDN_ENHANCEMENTS)
08857
08858
08859
08860
08861
08862
08863
08864
08865
08866 static void misdn_cc_handle_ccbs_status_request(int port, const struct FacParm *facility)
08867 {
08868 struct misdn_cc_record *cc_record;
08869 struct misdn_bchannel dummy;
08870
08871 switch (facility->u.CCBSStatusRequest.ComponentType) {
08872 case FacComponent_Invoke:
08873
08874 misdn_make_dummy(&dummy, port, 0, misdn_lib_port_is_nt(port), 0);
08875 dummy.fac_out.Function = Fac_CCBSStatusRequest;
08876 dummy.fac_out.u.CCBSStatusRequest.InvokeID = facility->u.CCBSStatusRequest.InvokeID;
08877 dummy.fac_out.u.CCBSStatusRequest.ComponentType = FacComponent_Result;
08878
08879
08880 AST_LIST_LOCK(&misdn_cc_records_db);
08881 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSStatusRequest.Component.Invoke.CCBSReference);
08882 if (cc_record) {
08883 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = cc_record->party_a_free;
08884 } else {
08885
08886 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = 1;
08887 }
08888 AST_LIST_UNLOCK(&misdn_cc_records_db);
08889
08890
08891 print_facility(&dummy.fac_out, &dummy);
08892 misdn_lib_send_event(&dummy, EVENT_FACILITY);
08893 break;
08894
08895 default:
08896 chan_misdn_log(0, port, " --> not yet handled: facility type:0x%04X\n", facility->Function);
08897 break;
08898 }
08899 }
08900 #endif
08901
08902 #if defined(AST_MISDN_ENHANCEMENTS)
08903
08904
08905
08906
08907
08908
08909
08910
08911
08912 static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *notify)
08913 {
08914 struct ast_channel *chan;
08915 char id_str[32];
08916
08917 static unsigned short sequence = 0;
08918
08919
08920 snprintf(id_str, sizeof(id_str), "%ld", record_id);
08921 chan = ast_channel_alloc(0, AST_STATE_DOWN, id_str, NULL, NULL,
08922 notify->exten, notify->context, NULL, 0,
08923 "mISDN-CC/%ld-%X", record_id, (unsigned) ++sequence);
08924 if (!chan) {
08925 ast_log(LOG_ERROR, "Unable to allocate channel!\n");
08926 return;
08927 }
08928 chan->priority = notify->priority;
08929 ast_free(chan->dialed.number.str);
08930 chan->dialed.number.str = ast_strdup(notify->exten);
08931
08932 if (ast_pbx_start(chan)) {
08933 ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", chan->name);
08934 ast_channel_release(chan);
08935 } else {
08936 ast_verb(1, "Started pbx for call completion notify channel %s\n", chan->name);
08937 }
08938 }
08939 #endif
08940
08941 #if defined(AST_MISDN_ENHANCEMENTS)
08942
08943
08944
08945
08946
08947
08948
08949
08950 static void misdn_cc_handle_T_remote_user_free(struct misdn_bchannel *bc)
08951 {
08952 struct misdn_cc_record *cc_record;
08953 struct misdn_cc_notify notify;
08954 long record_id;
08955
08956 AST_LIST_LOCK(&misdn_cc_records_db);
08957 cc_record = misdn_cc_find_by_bc(bc);
08958 if (cc_record) {
08959 if (cc_record->party_a_free) {
08960 notify = cc_record->remote_user_free;
08961 } else {
08962
08963 bc->fac_out.Function = Fac_CCBS_T_Suspend;
08964 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
08965 print_facility(&bc->fac_out, bc);
08966 misdn_lib_send_event(bc, EVENT_FACILITY);
08967
08968 notify = cc_record->b_free;
08969 }
08970 record_id = cc_record->record_id;
08971 AST_LIST_UNLOCK(&misdn_cc_records_db);
08972 if (notify.context[0]) {
08973
08974 misdn_cc_pbx_notify(record_id, ¬ify);
08975 }
08976 } else {
08977 AST_LIST_UNLOCK(&misdn_cc_records_db);
08978 }
08979 }
08980 #endif
08981
08982 #if defined(AST_MISDN_ENHANCEMENTS)
08983
08984
08985
08986
08987
08988
08989
08990
08991
08992 static void misdn_cc_handle_remote_user_free(int port, const struct FacParm *facility)
08993 {
08994 struct misdn_cc_record *cc_record;
08995 struct misdn_cc_notify notify;
08996 long record_id;
08997
08998 AST_LIST_LOCK(&misdn_cc_records_db);
08999 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSRemoteUserFree.CCBSReference);
09000 if (cc_record) {
09001 notify = cc_record->remote_user_free;
09002 record_id = cc_record->record_id;
09003 AST_LIST_UNLOCK(&misdn_cc_records_db);
09004 misdn_cc_pbx_notify(record_id, ¬ify);
09005 } else {
09006 AST_LIST_UNLOCK(&misdn_cc_records_db);
09007 }
09008 }
09009 #endif
09010
09011 #if defined(AST_MISDN_ENHANCEMENTS)
09012
09013
09014
09015
09016
09017
09018
09019
09020
09021 static void misdn_cc_handle_b_free(int port, const struct FacParm *facility)
09022 {
09023 struct misdn_cc_record *cc_record;
09024 struct misdn_cc_notify notify;
09025 long record_id;
09026
09027 AST_LIST_LOCK(&misdn_cc_records_db);
09028 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSBFree.CCBSReference);
09029 if (cc_record && cc_record->b_free.context[0]) {
09030
09031 notify = cc_record->b_free;
09032 record_id = cc_record->record_id;
09033 AST_LIST_UNLOCK(&misdn_cc_records_db);
09034 misdn_cc_pbx_notify(record_id, ¬ify);
09035 } else {
09036 AST_LIST_UNLOCK(&misdn_cc_records_db);
09037 }
09038 }
09039 #endif
09040
09041
09042
09043
09044
09045
09046
09047
09048
09049
09050
09051 static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel *bc, struct chan_list *ch)
09052 {
09053 #if defined(AST_MISDN_ENHANCEMENTS)
09054 const char *diagnostic_msg;
09055 struct misdn_cc_record *cc_record;
09056 char buf[32];
09057 struct misdn_party_id party_id;
09058 long new_record_id;
09059 #endif
09060
09061 print_facility(&bc->fac_in, bc);
09062 switch (bc->fac_in.Function) {
09063 #if defined(AST_MISDN_ENHANCEMENTS)
09064 case Fac_ActivationDiversion:
09065 switch (bc->fac_in.u.ActivationDiversion.ComponentType) {
09066 case FacComponent_Result:
09067
09068
09069 break;
09070 default:
09071 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09072 bc->fac_in.Function);
09073 break;
09074 }
09075 break;
09076 case Fac_DeactivationDiversion:
09077 switch (bc->fac_in.u.DeactivationDiversion.ComponentType) {
09078 case FacComponent_Result:
09079
09080
09081 break;
09082 default:
09083 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09084 bc->fac_in.Function);
09085 break;
09086 }
09087 break;
09088 case Fac_ActivationStatusNotificationDiv:
09089
09090
09091
09092 break;
09093 case Fac_DeactivationStatusNotificationDiv:
09094
09095
09096 break;
09097 #if 0
09098 case Fac_InterrogationDiversion:
09099
09100 break;
09101 case Fac_InterrogateServedUserNumbers:
09102
09103 break;
09104 #endif
09105 case Fac_DiversionInformation:
09106
09107
09108 break;
09109 case Fac_CallDeflection:
09110 if (ch && ch->ast) {
09111 switch (bc->fac_in.u.CallDeflection.ComponentType) {
09112 case FacComponent_Invoke:
09113 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09114 sizeof(bc->redirecting.from.number));
09115 bc->redirecting.from.name[0] = 0;
09116 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09117 bc->redirecting.from.number_type = bc->dialed.number_type;
09118 bc->redirecting.from.screening = 0;
09119 if (bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
09120 bc->redirecting.from.presentation =
09121 bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser
09122 ? 0 : 1 ;
09123 } else {
09124 bc->redirecting.from.presentation = 0;
09125 }
09126
09127
09128 memset(&party_id, 0, sizeof(party_id));
09129 misdn_PartyNumber_extract(&party_id,
09130 &bc->fac_in.u.CallDeflection.Component.Invoke.Deflection.Party);
09131 misdn_add_number_prefix(bc->port, party_id.number_type,
09132 party_id.number, sizeof(party_id.number));
09133
09134
09135 bc->redirecting.to = party_id;
09136
09137 ++bc->redirecting.count;
09138 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09139
09140 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09141 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09142
09143
09144 #if 1
09145
09146
09147
09148
09149 bc->fac_out.Function = Fac_RESULT;
09150 bc->fac_out.u.RESULT.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09151 #else
09152 bc->fac_out.Function = Fac_CallDeflection;
09153 bc->fac_out.u.CallDeflection.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09154 bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Result;
09155 #endif
09156 print_facility(&bc->fac_out, bc);
09157 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09158
09159
09160 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09161 break;
09162
09163 case FacComponent_Result:
09164
09165
09166
09167
09168
09169
09170
09171 break;
09172
09173 default:
09174 break;
09175 }
09176 }
09177 break;
09178 #if 0
09179 case Fac_CallRerouteing:
09180
09181
09182 break;
09183 #endif
09184 case Fac_DivertingLegInformation1:
09185
09186 bc->div_leg_3_rx_wanted = 0;
09187 if (ch && ch->ast) {
09188 bc->redirecting.reason =
09189 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation1.DiversionReason);
09190 if (bc->fac_in.u.DivertingLegInformation1.DivertedToPresent) {
09191 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.to,
09192 &bc->fac_in.u.DivertingLegInformation1.DivertedTo);
09193
09194
09195 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09196 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09197 } else {
09198 bc->redirecting.to.number[0] = '\0';
09199 bc->redirecting.to.number_plan = NUMPLAN_ISDN;
09200 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09201 bc->redirecting.to.presentation = 1;
09202 bc->redirecting.to.screening = 0;
09203 }
09204 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09205 bc->div_leg_3_rx_wanted = 1;
09206 }
09207 break;
09208 case Fac_DivertingLegInformation2:
09209
09210 switch (event) {
09211 case EVENT_SETUP:
09212
09213 bc->div_leg_3_tx_pending = 1;
09214 if (ch && ch->ast) {
09215
09216
09217
09218
09219
09220
09221
09222
09223
09224
09225 ast_copy_string(bc->redirecting.to.number, bc->dialed.number,
09226 sizeof(bc->redirecting.to.number));
09227 bc->redirecting.to.number_plan = bc->dialed.number_plan;
09228 bc->redirecting.to.number_type = bc->dialed.number_type;
09229 bc->redirecting.to.presentation = 1;
09230 bc->redirecting.to.screening = 0;
09231
09232 bc->redirecting.reason =
09233 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation2.DiversionReason);
09234 bc->redirecting.count = bc->fac_in.u.DivertingLegInformation2.DiversionCounter;
09235 if (bc->fac_in.u.DivertingLegInformation2.DivertingPresent) {
09236
09237 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.from,
09238 &bc->fac_in.u.DivertingLegInformation2.Diverting);
09239
09240
09241 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type,
09242 bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
09243 }
09244 #if 0
09245 if (bc->fac_in.u.DivertingLegInformation2.OriginalCalledPresent) {
09246
09247 }
09248 #endif
09249 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09250 }
09251 break;
09252 default:
09253 chan_misdn_log(0, bc->port," --> Expected in a SETUP message: facility type:0x%04X\n",
09254 bc->fac_in.Function);
09255 break;
09256 }
09257 break;
09258 case Fac_DivertingLegInformation3:
09259
09260 if (bc->div_leg_3_rx_wanted) {
09261 bc->div_leg_3_rx_wanted = 0;
09262
09263 if (ch && ch->ast) {
09264 ch->ast->redirecting.to.number.presentation =
09265 bc->fac_in.u.DivertingLegInformation3.PresentationAllowedIndicator
09266 ? AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED
09267 : AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
09268 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
09269 }
09270 }
09271 break;
09272
09273 #else
09274
09275 case Fac_CD:
09276 if (ch && ch->ast) {
09277 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09278 sizeof(bc->redirecting.from.number));
09279 bc->redirecting.from.name[0] = 0;
09280 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09281 bc->redirecting.from.number_type = bc->dialed.number_type;
09282 bc->redirecting.from.screening = 0;
09283 bc->redirecting.from.presentation =
09284 bc->fac_in.u.CDeflection.PresentationAllowed
09285 ? 0 : 1 ;
09286
09287 ast_copy_string(bc->redirecting.to.number,
09288 (char *) bc->fac_in.u.CDeflection.DeflectedToNumber,
09289 sizeof(bc->redirecting.to.number));
09290 bc->redirecting.to.name[0] = 0;
09291 bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
09292 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09293 bc->redirecting.to.presentation = 0;
09294 bc->redirecting.to.screening = 0;
09295
09296 ++bc->redirecting.count;
09297 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09298
09299 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09300 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09301
09302 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09303
09304
09305 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09306 }
09307 break;
09308 #endif
09309 case Fac_AOCDCurrency:
09310 if (ch && ch->ast) {
09311 bc->AOCDtype = Fac_AOCDCurrency;
09312 memcpy(&bc->AOCD.currency, &bc->fac_in.u.AOCDcur, sizeof(bc->AOCD.currency));
09313 bc->AOCD_need_export = 1;
09314 export_aoc_vars(ch->originator, ch->ast, bc);
09315 }
09316 break;
09317 case Fac_AOCDChargingUnit:
09318 if (ch && ch->ast) {
09319 bc->AOCDtype = Fac_AOCDChargingUnit;
09320 memcpy(&bc->AOCD.chargingUnit, &bc->fac_in.u.AOCDchu, sizeof(bc->AOCD.chargingUnit));
09321 bc->AOCD_need_export = 1;
09322 export_aoc_vars(ch->originator, ch->ast, bc);
09323 }
09324 break;
09325 #if defined(AST_MISDN_ENHANCEMENTS)
09326 case Fac_ERROR:
09327 diagnostic_msg = misdn_to_str_error_code(bc->fac_in.u.ERROR.errorValue);
09328 chan_misdn_log(1, bc->port, " --> Facility error code: %s\n", diagnostic_msg);
09329 switch (event) {
09330 case EVENT_DISCONNECT:
09331 case EVENT_RELEASE:
09332 case EVENT_RELEASE_COMPLETE:
09333
09334 if (ch && ch->peer) {
09335 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09336 }
09337 break;
09338 default:
09339 break;
09340 }
09341 AST_LIST_LOCK(&misdn_cc_records_db);
09342 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.ERROR.invokeId);
09343 if (cc_record) {
09344 cc_record->outstanding_message = 0;
09345 cc_record->error_code = bc->fac_in.u.ERROR.errorValue;
09346 }
09347 AST_LIST_UNLOCK(&misdn_cc_records_db);
09348 break;
09349 case Fac_REJECT:
09350 diagnostic_msg = misdn_to_str_reject_code(bc->fac_in.u.REJECT.Code);
09351 chan_misdn_log(1, bc->port, " --> Facility reject code: %s\n", diagnostic_msg);
09352 switch (event) {
09353 case EVENT_DISCONNECT:
09354 case EVENT_RELEASE:
09355 case EVENT_RELEASE_COMPLETE:
09356
09357 if (ch && ch->peer) {
09358 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09359 }
09360 break;
09361 default:
09362 break;
09363 }
09364 if (bc->fac_in.u.REJECT.InvokeIDPresent) {
09365 AST_LIST_LOCK(&misdn_cc_records_db);
09366 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.REJECT.InvokeID);
09367 if (cc_record) {
09368 cc_record->outstanding_message = 0;
09369 cc_record->reject_code = bc->fac_in.u.REJECT.Code;
09370 }
09371 AST_LIST_UNLOCK(&misdn_cc_records_db);
09372 }
09373 break;
09374 case Fac_RESULT:
09375 AST_LIST_LOCK(&misdn_cc_records_db);
09376 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.RESULT.InvokeID);
09377 if (cc_record) {
09378 cc_record->outstanding_message = 0;
09379 }
09380 AST_LIST_UNLOCK(&misdn_cc_records_db);
09381 break;
09382 #if 0
09383 case Fac_EctExecute:
09384
09385 break;
09386 case Fac_ExplicitEctExecute:
09387
09388 break;
09389 case Fac_EctLinkIdRequest:
09390
09391 break;
09392 #endif
09393 case Fac_SubaddressTransfer:
09394
09395 break;
09396 case Fac_RequestSubaddress:
09397
09398
09399
09400
09401 if (bc->redirecting.to_changed) {
09402
09403 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09404 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09405 }
09406 switch (bc->notify_description_code) {
09407 case mISDN_NOTIFY_CODE_INVALID:
09408
09409 bc->redirecting.to_changed = 0;
09410 break;
09411 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
09412
09413
09414
09415
09416
09417
09418
09419
09420
09421 if (!bc->redirecting.to_changed) {
09422 break;
09423 }
09424 bc->redirecting.to_changed = 0;
09425 if (!ch || !ch->ast) {
09426 break;
09427 }
09428 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09429 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
09430 bc->incoming_cid_tag);
09431 break;
09432 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
09433 if (!bc->redirecting.to_changed) {
09434 break;
09435 }
09436 bc->redirecting.to_changed = 0;
09437 if (!ch || !ch->ast) {
09438 break;
09439 }
09440 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09441 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
09442 break;
09443 default:
09444 bc->redirecting.to_changed = 0;
09445 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
09446 bc->notify_description_code);
09447 break;
09448 }
09449 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
09450 break;
09451 case Fac_EctInform:
09452
09453 if (ch && ch->ast && bc->fac_in.u.EctInform.RedirectionPresent) {
09454
09455 memset(&party_id, 0, sizeof(party_id));
09456 misdn_PresentedNumberUnscreened_extract(&party_id,
09457 &bc->fac_in.u.EctInform.Redirection);
09458 misdn_add_number_prefix(bc->port, party_id.number_type,
09459 party_id.number, sizeof(party_id.number));
09460
09461
09462
09463
09464
09465
09466
09467
09468
09469
09470 misdn_update_remote_party(ch->ast, &party_id,
09471 (bc->fac_in.u.EctInform.Status == 0 )
09472 ? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
09473 : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
09474 bc->incoming_cid_tag);
09475 }
09476 break;
09477 #if 0
09478 case Fac_EctLoopTest:
09479
09480
09481 break;
09482 #endif
09483 case Fac_CallInfoRetain:
09484 switch (event) {
09485 case EVENT_ALERTING:
09486 case EVENT_DISCONNECT:
09487
09488 if (ch && ch->peer) {
09489 AST_LIST_LOCK(&misdn_cc_records_db);
09490 if (ch->record_id == -1) {
09491 cc_record = misdn_cc_new();
09492 } else {
09493
09494
09495
09496
09497
09498
09499
09500
09501
09502 cc_record = misdn_cc_find_by_id(ch->record_id);
09503 if (cc_record) {
09504 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09505
09506
09507
09508
09509
09510
09511
09512
09513 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09514 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09515 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09516 }
09517
09518
09519
09520
09521
09522 new_record_id = misdn_cc_record_id_new();
09523 if (new_record_id < 0) {
09524
09525 } else {
09526 cc_record->record_id = new_record_id;
09527 ch->record_id = new_record_id;
09528 }
09529 cc_record->ptp = 0;
09530 cc_record->port = bc->port;
09531 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09532 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09533 cc_record->invoke_id = ++misdn_invoke_id;
09534 cc_record->activated = 0;
09535 cc_record->outstanding_message = 0;
09536 cc_record->activation_requested = 0;
09537 cc_record->error_code = FacError_None;
09538 cc_record->reject_code = FacReject_None;
09539 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09540 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09541 cc_record->time_created = time(NULL);
09542
09543 cc_record = NULL;
09544 } else {
09545
09546
09547
09548
09549
09550 ch->record_id = -1;
09551 cc_record = misdn_cc_new();
09552 }
09553 }
09554 if (cc_record) {
09555 ch->record_id = cc_record->record_id;
09556 cc_record->ptp = 0;
09557 cc_record->port = bc->port;
09558 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09559
09560
09561 cc_record->redial.caller = bc->caller;
09562 cc_record->redial.dialed = bc->dialed;
09563 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09564 cc_record->redial.capability = bc->capability;
09565 cc_record->redial.hdlc = bc->hdlc;
09566 }
09567 AST_LIST_UNLOCK(&misdn_cc_records_db);
09568
09569
09570 if (ch->record_id != -1) {
09571 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09572 } else {
09573 buf[0] = 0;
09574 }
09575 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09576 }
09577 break;
09578 default:
09579 chan_misdn_log(0, bc->port,
09580 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09581 bc->fac_in.Function);
09582 break;
09583 }
09584 break;
09585 case Fac_CCBS_T_Call:
09586 case Fac_CCBSCall:
09587 switch (event) {
09588 case EVENT_SETUP:
09589
09590
09591
09592
09593 break;
09594 default:
09595 chan_misdn_log(0, bc->port, " --> Expected in a SETUP message: facility type:0x%04X\n",
09596 bc->fac_in.Function);
09597 break;
09598 }
09599 break;
09600 case Fac_CCBSDeactivate:
09601 switch (bc->fac_in.u.CCBSDeactivate.ComponentType) {
09602 case FacComponent_Result:
09603 AST_LIST_LOCK(&misdn_cc_records_db);
09604 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSDeactivate.InvokeID);
09605 if (cc_record) {
09606 cc_record->outstanding_message = 0;
09607 }
09608 AST_LIST_UNLOCK(&misdn_cc_records_db);
09609 break;
09610
09611 default:
09612 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09613 bc->fac_in.Function);
09614 break;
09615 }
09616 break;
09617 case Fac_CCBSErase:
09618 AST_LIST_LOCK(&misdn_cc_records_db);
09619 cc_record = misdn_cc_find_by_reference(bc->port, bc->fac_in.u.CCBSErase.CCBSReference);
09620 if (cc_record) {
09621 misdn_cc_delete(cc_record);
09622 }
09623 AST_LIST_UNLOCK(&misdn_cc_records_db);
09624 break;
09625 case Fac_CCBSRemoteUserFree:
09626 misdn_cc_handle_remote_user_free(bc->port, &bc->fac_in);
09627 break;
09628 case Fac_CCBSBFree:
09629 misdn_cc_handle_b_free(bc->port, &bc->fac_in);
09630 break;
09631 case Fac_CCBSStatusRequest:
09632 misdn_cc_handle_ccbs_status_request(bc->port, &bc->fac_in);
09633 break;
09634 case Fac_EraseCallLinkageID:
09635 AST_LIST_LOCK(&misdn_cc_records_db);
09636 cc_record = misdn_cc_find_by_linkage(bc->port,
09637 bc->fac_in.u.EraseCallLinkageID.CallLinkageID);
09638 if (cc_record && !cc_record->activation_requested) {
09639
09640
09641
09642
09643
09644 misdn_cc_delete(cc_record);
09645 }
09646 AST_LIST_UNLOCK(&misdn_cc_records_db);
09647 break;
09648 case Fac_CCBSStopAlerting:
09649
09650 break;
09651 case Fac_CCBSRequest:
09652 case Fac_CCNRRequest:
09653 switch (bc->fac_in.u.CCBSRequest.ComponentType) {
09654 case FacComponent_Result:
09655 AST_LIST_LOCK(&misdn_cc_records_db);
09656 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSRequest.InvokeID);
09657 if (cc_record && !cc_record->ptp) {
09658 cc_record->outstanding_message = 0;
09659 cc_record->activated = 1;
09660 cc_record->mode.ptmp.recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
09661 cc_record->mode.ptmp.reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
09662 }
09663 AST_LIST_UNLOCK(&misdn_cc_records_db);
09664 break;
09665
09666 default:
09667 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09668 bc->fac_in.Function);
09669 break;
09670 }
09671 break;
09672 #if 0
09673 case Fac_CCBSInterrogate:
09674 case Fac_CCNRInterrogate:
09675
09676 break;
09677 case Fac_StatusRequest:
09678
09679 break;
09680 #endif
09681 #if 0
09682 case Fac_CCBS_T_Suspend:
09683 case Fac_CCBS_T_Resume:
09684
09685 break;
09686 #endif
09687 case Fac_CCBS_T_RemoteUserFree:
09688 misdn_cc_handle_T_remote_user_free(bc);
09689 break;
09690 case Fac_CCBS_T_Available:
09691 switch (event) {
09692 case EVENT_ALERTING:
09693 case EVENT_DISCONNECT:
09694
09695 if (ch && ch->peer) {
09696 int set_id = 1;
09697
09698 AST_LIST_LOCK(&misdn_cc_records_db);
09699 if (ch->record_id == -1) {
09700 cc_record = misdn_cc_new();
09701 } else {
09702
09703
09704
09705
09706
09707 cc_record = misdn_cc_find_by_id(ch->record_id);
09708 if (cc_record) {
09709 if (cc_record->ptp && cc_record->mode.ptp.retention_enabled) {
09710
09711
09712
09713
09714 chan_misdn_log(1, bc->port, " --> Call-completion request retention option is enabled\n");
09715
09716 set_id = 0;
09717 } else {
09718 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09719
09720
09721
09722
09723
09724
09725
09726
09727
09728 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09729 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09730 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09731 }
09732
09733
09734
09735
09736
09737 new_record_id = misdn_cc_record_id_new();
09738 if (new_record_id < 0) {
09739
09740 } else {
09741 cc_record->record_id = new_record_id;
09742 ch->record_id = new_record_id;
09743 }
09744 cc_record->ptp = 1;
09745 cc_record->port = bc->port;
09746 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09747 cc_record->invoke_id = ++misdn_invoke_id;
09748 cc_record->activated = 0;
09749 cc_record->outstanding_message = 0;
09750 cc_record->activation_requested = 0;
09751 cc_record->error_code = FacError_None;
09752 cc_record->reject_code = FacReject_None;
09753 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09754 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09755 cc_record->time_created = time(NULL);
09756 }
09757 cc_record = NULL;
09758 } else {
09759
09760
09761
09762
09763
09764 ch->record_id = -1;
09765 cc_record = misdn_cc_new();
09766 }
09767 }
09768 if (cc_record) {
09769 ch->record_id = cc_record->record_id;
09770 cc_record->ptp = 1;
09771 cc_record->port = bc->port;
09772
09773
09774 cc_record->redial.caller = bc->caller;
09775 cc_record->redial.dialed = bc->dialed;
09776 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09777 cc_record->redial.capability = bc->capability;
09778 cc_record->redial.hdlc = bc->hdlc;
09779 }
09780 AST_LIST_UNLOCK(&misdn_cc_records_db);
09781
09782
09783 if (ch->record_id != -1 && set_id) {
09784 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09785 } else {
09786 buf[0] = 0;
09787 }
09788 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09789 }
09790 break;
09791 default:
09792 chan_misdn_log(0, bc->port,
09793 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09794 bc->fac_in.Function);
09795 break;
09796 }
09797 break;
09798 case Fac_CCBS_T_Request:
09799 case Fac_CCNR_T_Request:
09800 switch (bc->fac_in.u.CCBS_T_Request.ComponentType) {
09801 case FacComponent_Result:
09802 AST_LIST_LOCK(&misdn_cc_records_db);
09803 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBS_T_Request.InvokeID);
09804 if (cc_record && cc_record->ptp) {
09805 cc_record->outstanding_message = 0;
09806 cc_record->activated = 1;
09807 cc_record->mode.ptp.retention_enabled =
09808 cc_record->mode.ptp.requested_retention
09809 ? bc->fac_in.u.CCBS_T_Request.Component.Result.RetentionSupported
09810 ? 1 : 0
09811 : 0;
09812 }
09813 AST_LIST_UNLOCK(&misdn_cc_records_db);
09814 break;
09815
09816 case FacComponent_Invoke:
09817
09818 default:
09819 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09820 bc->fac_in.Function);
09821 break;
09822 }
09823 break;
09824
09825 #endif
09826 case Fac_None:
09827 break;
09828 default:
09829 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09830 bc->fac_in.Function);
09831 break;
09832 }
09833 }
09834
09835
09836
09837
09838
09839
09840
09841
09842
09843
09844
09845
09846 static int misdn_is_msn_valid(int port, const struct misdn_party_dialing *dialed)
09847 {
09848 char number[sizeof(dialed->number)];
09849
09850 ast_copy_string(number, dialed->number, sizeof(number));
09851 misdn_add_number_prefix(port, dialed->number_type, number, sizeof(number));
09852 return misdn_cfg_is_msn_valid(port, number);
09853 }
09854
09855
09856
09857
09858 static enum event_response_e
09859 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
09860 {
09861 #if defined(AST_MISDN_ENHANCEMENTS)
09862 struct misdn_cc_record *cc_record;
09863 #endif
09864 struct chan_list *held_ch;
09865 struct chan_list *ch = find_chan_by_bc(bc);
09866
09867 if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) {
09868 int debuglevel = 1;
09869
09870
09871 if (event == EVENT_CLEANUP && !user_data) {
09872 debuglevel = 5;
09873 }
09874
09875 chan_misdn_log(debuglevel, bc->port,
09876 "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n",
09877 manager_isdn_get_info(event),
09878 bc->caller.name,
09879 bc->caller.number,
09880 bc->dialed.number,
09881 bc->pid,
09882 ch ? misdn_get_ch_state(ch) : "none");
09883 if (debuglevel == 1) {
09884 misdn_lib_log_ies(bc);
09885 chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
09886 }
09887 }
09888
09889 if (!ch) {
09890 switch(event) {
09891 case EVENT_SETUP:
09892 case EVENT_DISCONNECT:
09893 case EVENT_RELEASE:
09894 case EVENT_RELEASE_COMPLETE:
09895 case EVENT_PORT_ALARM:
09896 case EVENT_RETRIEVE:
09897 case EVENT_NEW_BC:
09898 case EVENT_FACILITY:
09899 case EVENT_REGISTER:
09900 break;
09901 case EVENT_CLEANUP:
09902 case EVENT_TONE_GENERATE:
09903 case EVENT_BCHAN_DATA:
09904 return -1;
09905 default:
09906 chan_misdn_log(1, bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n", bc->l3_id, bc, manager_isdn_get_info(event), bc->port, bc->channel);
09907 return -1;
09908 }
09909 } else {
09910 switch (event) {
09911 case EVENT_TONE_GENERATE:
09912 break;
09913 case EVENT_DISCONNECT:
09914 case EVENT_RELEASE:
09915 case EVENT_RELEASE_COMPLETE:
09916 case EVENT_CLEANUP:
09917 case EVENT_TIMEOUT:
09918 if (!ch->ast) {
09919 chan_misdn_log(3, bc->port, "ast_hangup already called, so we have no ast ptr anymore in event(%s)\n", manager_isdn_get_info(event));
09920 }
09921 break;
09922 default:
09923 if (!ch->ast || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
09924 if (event != EVENT_BCHAN_DATA) {
09925 ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
09926 }
09927 chan_list_unref(ch, "No Ast or Ast private pointer");
09928 return -1;
09929 }
09930 break;
09931 }
09932 }
09933
09934
09935 switch (event) {
09936 case EVENT_PORT_ALARM:
09937 {
09938 int boa = 0;
09939 misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
09940 if (boa) {
09941 cb_log(1, bc->port, " --> blocking\n");
09942 misdn_lib_port_block(bc->port);
09943 }
09944 }
09945 break;
09946 case EVENT_BCHAN_ACTIVATED:
09947 break;
09948
09949 case EVENT_NEW_CHANNEL:
09950 update_name(ch->ast,bc->port,bc->channel);
09951 break;
09952
09953 case EVENT_NEW_L3ID:
09954 ch->l3id=bc->l3_id;
09955 ch->addr=bc->addr;
09956 break;
09957
09958 case EVENT_NEW_BC:
09959 if (!ch) {
09960 ch = find_hold_call(bc);
09961 }
09962
09963 if (!ch) {
09964 ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
09965 break;
09966 }
09967
09968 if (bc) {
09969 ch->bc = (struct misdn_bchannel *) user_data;
09970 }
09971 break;
09972
09973 case EVENT_DTMF_TONE:
09974 {
09975
09976 struct ast_frame fr;
09977
09978 memset(&fr, 0, sizeof(fr));
09979 fr.frametype = AST_FRAME_DTMF;
09980 fr.subclass.integer = bc->dtmf ;
09981 fr.src = NULL;
09982 fr.data.ptr = NULL;
09983 fr.datalen = 0;
09984 fr.samples = 0;
09985 fr.mallocd = 0;
09986 fr.offset = 0;
09987 fr.delivery = ast_tv(0,0);
09988
09989 if (!ch->ignore_dtmf) {
09990 chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
09991 ast_queue_frame(ch->ast, &fr);
09992 } else {
09993 chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
09994 }
09995 break;
09996 }
09997 case EVENT_STATUS:
09998 break;
09999
10000 case EVENT_INFORMATION:
10001 if (ch->state != MISDN_CONNECTED) {
10002 stop_indicate(ch);
10003 }
10004
10005 if (!ch->ast) {
10006 break;
10007 }
10008
10009 if (ch->state == MISDN_WAITING4DIGS) {
10010
10011 if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
10012 chan_misdn_log(1, bc->port, " --> using keypad as info\n");
10013 ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
10014 }
10015
10016 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10017 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10018
10019
10020 if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
10021 if (ast_pickup_call(ch->ast)) {
10022 hangup_chan(ch, bc);
10023 } else {
10024 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10025 hangup_chan(ch, bc);
10026 ch->ast = NULL;
10027 break;
10028 }
10029 }
10030
10031 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10032 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10033 ast_log(LOG_WARNING,
10034 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10035 bc->dialed.number, ch->context, bc->port);
10036 pbx_builtin_setvar_helper(ch->ast, "INVALID_EXTEN", bc->dialed.number);
10037 strcpy(ch->ast->exten, "i");
10038 ch->state = MISDN_DIALING;
10039 start_pbx(ch, bc, ch->ast);
10040 break;
10041 }
10042
10043 ast_log(LOG_WARNING,
10044 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10045 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10046 bc->dialed.number, ch->context, bc->port);
10047
10048 if (bc->nt) {
10049 hanguptone_indicate(ch);
10050 }
10051 ch->state = MISDN_EXTCANTMATCH;
10052 bc->out_cause = AST_CAUSE_UNALLOCATED;
10053
10054 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10055 break;
10056 }
10057
10058 if (ch->overlap_dial) {
10059 ast_mutex_lock(&ch->overlap_tv_lock);
10060 ch->overlap_tv = ast_tvnow();
10061 ast_mutex_unlock(&ch->overlap_tv_lock);
10062 if (ch->overlap_dial_task == -1) {
10063 ch->overlap_dial_task =
10064 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10065 }
10066 break;
10067 }
10068
10069 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10070 ch->state = MISDN_DIALING;
10071 start_pbx(ch, bc, ch->ast);
10072 }
10073 } else {
10074
10075 struct ast_frame fr;
10076 int digits;
10077
10078 memset(&fr, 0, sizeof(fr));
10079 fr.frametype = AST_FRAME_DTMF;
10080 fr.subclass.integer = bc->info_dad[0] ;
10081 fr.src = NULL;
10082 fr.data.ptr = NULL;
10083 fr.datalen = 0;
10084 fr.samples = 0;
10085 fr.mallocd = 0;
10086 fr.offset = 0;
10087 fr.delivery = ast_tv(0,0);
10088
10089 misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
10090 if (ch->state != MISDN_CONNECTED) {
10091 if (digits) {
10092 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10093 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10094 ast_cdr_update(ch->ast);
10095 }
10096
10097 ast_queue_frame(ch->ast, &fr);
10098 }
10099 }
10100 break;
10101 case EVENT_SETUP:
10102 {
10103 struct ast_channel *chan;
10104 int exceed;
10105 int ai;
10106 int im;
10107 int append_msn = 0;
10108
10109 if (ch) {
10110 switch (ch->state) {
10111 case MISDN_NOTHING:
10112 chan_list_unref(ch, "Ignore found ch. Is it for an outgoing call?");
10113 ch = NULL;
10114 break;
10115 default:
10116 chan_list_unref(ch, "Already have a call.");
10117 chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
10118 return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE;
10119 }
10120 }
10121
10122 if (!bc->nt && !misdn_is_msn_valid(bc->port, &bc->dialed)) {
10123 chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
10124 return RESPONSE_IGNORE_SETUP;
10125 }
10126
10127 if (bc->cw) {
10128 int cause;
10129 chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
10130 misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
10131 bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
10132 return RESPONSE_RELEASE_SETUP;
10133 }
10134
10135 print_bearer(bc);
10136
10137 ch = chan_list_init(ORG_MISDN);
10138 if (!ch) {
10139 chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
10140 return RESPONSE_RELEASE_SETUP;
10141 }
10142
10143 ch->bc = bc;
10144 ch->l3id = bc->l3_id;
10145 ch->addr = bc->addr;
10146
10147 chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, NULL, bc->port, bc->channel);
10148 if (!chan) {
10149 chan_list_unref(ch, "Failed to create a new channel");
10150 ast_log(LOG_ERROR, "cb_events: misdn_new failed!\n");
10151 return RESPONSE_RELEASE_SETUP;
10152 }
10153
10154 if ((exceed = add_in_calls(bc->port))) {
10155 char tmp[16];
10156 snprintf(tmp, sizeof(tmp), "%d", exceed);
10157 pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
10158 }
10159
10160 read_config(ch);
10161
10162 export_ch(chan, bc, ch);
10163
10164 ch->ast->rings = 1;
10165 ast_setstate(ch->ast, AST_STATE_RINGING);
10166
10167
10168 chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
10169 chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan);
10170 chan->caller.id.number.plan = misdn_to_ast_ton(bc->caller.number_type)
10171 | misdn_to_ast_plan(bc->caller.number_plan);
10172
10173 chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
10174 chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
10175 chan->caller.id.number.presentation = misdn_to_ast_pres(bc->caller.presentation)
10176 | misdn_to_ast_screen(bc->caller.screening);
10177
10178 ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
10179
10180 misdn_cfg_get(bc->port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
10181 if (append_msn) {
10182 strncat(bc->incoming_cid_tag, "_", sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10183 strncat(bc->incoming_cid_tag, bc->dialed.number, sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10184 }
10185
10186 ast_channel_lock(chan);
10187 chan->caller.id.tag = ast_strdup(bc->incoming_cid_tag);
10188 ast_channel_unlock(chan);
10189
10190 if (!ast_strlen_zero(bc->redirecting.from.number)) {
10191
10192 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
10193
10194
10195 misdn_copy_redirecting_to_ast(chan, &bc->redirecting, bc->incoming_cid_tag);
10196 }
10197
10198 pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
10199 chan->transfercapability = bc->capability;
10200
10201 switch (bc->capability) {
10202 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
10203 pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
10204 break;
10205 default:
10206 pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
10207 break;
10208 }
10209
10210 if (!strstr(ch->allowed_bearers, "all")) {
10211 int i;
10212
10213 for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
10214 if (allowed_bearers_array[i].cap == bc->capability) {
10215 if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
10216
10217 if (allowed_bearers_array[i].deprecated) {
10218 chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
10219 allowed_bearers_array[i].name);
10220 }
10221 break;
10222 }
10223 }
10224 }
10225 if (i == ARRAY_LEN(allowed_bearers_array)) {
10226
10227 chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
10228 bearer2str(bc->capability), bc->capability);
10229
10230 ch->state = MISDN_EXTCANTMATCH;
10231 chan_list_unref(ch, "BC not allowed, releasing call");
10232 bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
10233 return RESPONSE_RELEASE_SETUP;
10234 }
10235 }
10236
10237
10238 cl_queue_chan(ch);
10239
10240 if (bc->fac_in.Function != Fac_None) {
10241 misdn_facility_ie_handler(event, bc, ch);
10242 }
10243
10244
10245 if (!strcmp(chan->exten, ast_pickup_ext())) {
10246 if (!ch->noautorespond_on_setup) {
10247
10248 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10249 } else {
10250 ch->state = MISDN_INCOMING_SETUP;
10251 }
10252 if (ast_pickup_call(chan)) {
10253 hangup_chan(ch, bc);
10254 } else {
10255 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10256 hangup_chan(ch, bc);
10257 ch->ast = NULL;
10258 break;
10259 }
10260 }
10261
10262
10263
10264
10265
10266 misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
10267 if (ai) {
10268 do_immediate_setup(bc, ch, chan);
10269 break;
10270 }
10271
10272
10273 misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
10274 if (im && ast_strlen_zero(bc->dialed.number)) {
10275 do_immediate_setup(bc, ch, chan);
10276 break;
10277 }
10278
10279 chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
10280 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10281 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10282 ast_log(LOG_WARNING,
10283 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10284 bc->dialed.number, ch->context, bc->port);
10285 pbx_builtin_setvar_helper(ch->ast, "INVALID_EXTEN", bc->dialed.number);
10286 strcpy(ch->ast->exten, "i");
10287 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10288 ch->state = MISDN_DIALING;
10289 start_pbx(ch, bc, chan);
10290 break;
10291 }
10292
10293 ast_log(LOG_WARNING,
10294 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10295 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10296 bc->dialed.number, ch->context, bc->port);
10297 if (bc->nt) {
10298 hanguptone_indicate(ch);
10299 }
10300
10301 ch->state = MISDN_EXTCANTMATCH;
10302 bc->out_cause = AST_CAUSE_UNALLOCATED;
10303
10304 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE);
10305 break;
10306 }
10307
10308
10309
10310
10311 if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
10312 if (!ch->noautorespond_on_setup) {
10313 ch->state=MISDN_DIALING;
10314 misdn_lib_send_event(bc, EVENT_PROCEEDING);
10315 } else {
10316 ch->state = MISDN_INCOMING_SETUP;
10317 }
10318 start_pbx(ch, bc, chan);
10319 break;
10320 }
10321
10322
10323
10324
10325
10326
10327
10328 if (ch->overlap_dial && bc->nt && !bc->dialed.number[0]) {
10329 wait_for_digits(ch, bc, chan);
10330 break;
10331 }
10332
10333
10334
10335
10336
10337 if (ch->overlap_dial) {
10338 ast_mutex_lock(&ch->overlap_tv_lock);
10339 ch->overlap_tv = ast_tvnow();
10340 ast_mutex_unlock(&ch->overlap_tv_lock);
10341
10342 wait_for_digits(ch, bc, chan);
10343 if (ch->overlap_dial_task == -1) {
10344 ch->overlap_dial_task =
10345 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10346 }
10347 break;
10348 }
10349
10350
10351
10352
10353 if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10354 wait_for_digits(ch, bc, chan);
10355 break;
10356 }
10357
10358
10359
10360
10361 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10362 misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
10363 ch->state = MISDN_DIALING;
10364 start_pbx(ch, bc, chan);
10365 break;
10366 }
10367 break;
10368 }
10369 #if defined(AST_MISDN_ENHANCEMENTS)
10370 case EVENT_REGISTER:
10371 if (bc->fac_in.Function != Fac_None) {
10372 misdn_facility_ie_handler(event, bc, ch);
10373 }
10374
10375
10376
10377
10378
10379
10380
10381 bc->fac_out.Function = Fac_None;
10382 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10383 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10384 break;
10385 #endif
10386 case EVENT_SETUP_ACKNOWLEDGE:
10387 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10388
10389 if (bc->channel) {
10390 update_name(ch->ast,bc->port,bc->channel);
10391 }
10392
10393 if (bc->fac_in.Function != Fac_None) {
10394 misdn_facility_ie_handler(event, bc, ch);
10395 }
10396
10397 if (!ast_strlen_zero(bc->infos_pending)) {
10398
10399 strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10400
10401 if (!ch->ast) {
10402 break;
10403 }
10404 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10405 ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
10406 ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
10407
10408 misdn_lib_send_event(bc, EVENT_INFORMATION);
10409 }
10410 break;
10411 case EVENT_PROCEEDING:
10412 if (misdn_cap_is_speech(bc->capability) &&
10413 misdn_inband_avail(bc)) {
10414 start_bc_tones(ch);
10415 }
10416
10417 ch->state = MISDN_PROCEEDING;
10418
10419 if (bc->fac_in.Function != Fac_None) {
10420 misdn_facility_ie_handler(event, bc, ch);
10421 }
10422
10423 if (!ch->ast) {
10424 break;
10425 }
10426
10427 ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
10428 break;
10429 case EVENT_PROGRESS:
10430 if (bc->channel) {
10431 update_name(ch->ast, bc->port, bc->channel);
10432 }
10433
10434 if (bc->fac_in.Function != Fac_None) {
10435 misdn_facility_ie_handler(event, bc, ch);
10436 }
10437
10438 if (!bc->nt) {
10439 if (misdn_cap_is_speech(bc->capability) &&
10440 misdn_inband_avail(bc)) {
10441 start_bc_tones(ch);
10442 }
10443
10444 ch->state = MISDN_PROGRESS;
10445
10446 if (!ch->ast) {
10447 break;
10448 }
10449 ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
10450 }
10451 break;
10452 case EVENT_ALERTING:
10453 ch->state = MISDN_ALERTING;
10454
10455 if (!ch->ast) {
10456 break;
10457 }
10458
10459 if (bc->fac_in.Function != Fac_None) {
10460 misdn_facility_ie_handler(event, bc, ch);
10461 }
10462
10463 ast_queue_control(ch->ast, AST_CONTROL_RINGING);
10464 ast_setstate(ch->ast, AST_STATE_RINGING);
10465
10466 cb_log(7, bc->port, " --> Set State Ringing\n");
10467
10468 if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
10469 cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
10470 start_bc_tones(ch);
10471 } else {
10472 cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
10473 if (ch->far_alerting) {
10474 cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
10475 start_bc_tones(ch);
10476
10477 }
10478 }
10479 break;
10480 case EVENT_CONNECT:
10481 if (bc->fac_in.Function != Fac_None) {
10482 misdn_facility_ie_handler(event, bc, ch);
10483 }
10484 #if defined(AST_MISDN_ENHANCEMENTS)
10485 if (bc->div_leg_3_rx_wanted) {
10486 bc->div_leg_3_rx_wanted = 0;
10487
10488 if (ch->ast) {
10489 ch->ast->redirecting.to.number.presentation =
10490 AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
10491 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10492 }
10493 }
10494 #endif
10495
10496
10497 misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
10498
10499 if (!ch->ast) {
10500 break;
10501 }
10502
10503 stop_indicate(ch);
10504
10505 #if defined(AST_MISDN_ENHANCEMENTS)
10506 if (ch->record_id != -1) {
10507
10508
10509
10510
10511
10512
10513 AST_LIST_LOCK(&misdn_cc_records_db);
10514 cc_record = misdn_cc_find_by_id(ch->record_id);
10515 if (cc_record) {
10516 if (cc_record->ptp && cc_record->mode.ptp.bc) {
10517
10518 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
10519 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10520 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
10521 }
10522 misdn_cc_delete(cc_record);
10523 }
10524 AST_LIST_UNLOCK(&misdn_cc_records_db);
10525 ch->record_id = -1;
10526 if (ch->peer) {
10527 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, "");
10528
10529 ao2_ref(ch->peer, -1);
10530 ch->peer = NULL;
10531 }
10532 }
10533 #endif
10534
10535 if (!ast_strlen_zero(bc->connected.number)) {
10536
10537 misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
10538
10539
10540 misdn_update_remote_party(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
10541 }
10542
10543 ch->l3id = bc->l3_id;
10544 ch->addr = bc->addr;
10545
10546 start_bc_tones(ch);
10547
10548 ch->state = MISDN_CONNECTED;
10549
10550 ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
10551 break;
10552 case EVENT_CONNECT_ACKNOWLEDGE:
10553 ch->l3id = bc->l3_id;
10554 ch->addr = bc->addr;
10555
10556 start_bc_tones(ch);
10557
10558 ch->state = MISDN_CONNECTED;
10559 break;
10560 case EVENT_DISCONNECT:
10561
10562 if (ch) {
10563 if (bc->fac_in.Function != Fac_None) {
10564 misdn_facility_ie_handler(event, bc, ch);
10565 }
10566
10567 chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
10568 if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
10569
10570
10571
10572
10573
10574 chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
10575
10576 ch->state = MISDN_DISCONNECTED;
10577 start_bc_tones(ch);
10578
10579 if (ch->ast) {
10580 ch->ast->hangupcause = bc->cause;
10581 if (bc->cause == AST_CAUSE_USER_BUSY) {
10582 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
10583 }
10584 }
10585 ch->need_busy = 0;
10586 break;
10587 }
10588
10589 bc->need_disconnect = 0;
10590 stop_bc_tones(ch);
10591
10592
10593 held_ch = find_hold_call(bc);
10594 if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
10595 hangup_chan(ch, bc);
10596 }
10597 } else {
10598 held_ch = find_hold_call_l3(bc->l3_id);
10599 if (held_ch) {
10600 if (bc->fac_in.Function != Fac_None) {
10601 misdn_facility_ie_handler(event, bc, held_ch);
10602 }
10603
10604 if (held_ch->hold.state == MISDN_HOLD_ACTIVE) {
10605 bc->need_disconnect = 0;
10606
10607 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
10608
10609
10610
10611
10612
10613 ch = find_hold_active_call(bc);
10614 if (!ch || misdn_attempt_transfer(ch, held_ch)) {
10615 held_ch->hold.state = MISDN_HOLD_DISCONNECT;
10616 hangup_chan(held_ch, bc);
10617 }
10618 #else
10619 hangup_chan(held_ch, bc);
10620 #endif
10621 }
10622 }
10623 }
10624 if (held_ch) {
10625 chan_list_unref(held_ch, "Done with held call");
10626 }
10627 bc->out_cause = -1;
10628 if (bc->need_release) {
10629 misdn_lib_send_event(bc, EVENT_RELEASE);
10630 }
10631 break;
10632 case EVENT_RELEASE:
10633 if (!ch) {
10634 ch = find_hold_call_l3(bc->l3_id);
10635 if (!ch) {
10636 chan_misdn_log(1, bc->port,
10637 " --> no Ch, so we've already released. (%s)\n",
10638 manager_isdn_get_info(event));
10639 return -1;
10640 }
10641 }
10642 if (bc->fac_in.Function != Fac_None) {
10643 misdn_facility_ie_handler(event, bc, ch);
10644 }
10645
10646 bc->need_disconnect = 0;
10647 bc->need_release = 0;
10648
10649 hangup_chan(ch, bc);
10650 release_chan(ch, bc);
10651 break;
10652 case EVENT_RELEASE_COMPLETE:
10653 if (!ch) {
10654 ch = find_hold_call_l3(bc->l3_id);
10655 }
10656
10657 bc->need_disconnect = 0;
10658 bc->need_release = 0;
10659 bc->need_release_complete = 0;
10660
10661 if (ch) {
10662 if (bc->fac_in.Function != Fac_None) {
10663 misdn_facility_ie_handler(event, bc, ch);
10664 }
10665
10666 stop_bc_tones(ch);
10667 hangup_chan(ch, bc);
10668 release_chan(ch, bc);
10669 } else {
10670 #if defined(AST_MISDN_ENHANCEMENTS)
10671
10672
10673
10674
10675
10676 AST_LIST_LOCK(&misdn_cc_records_db);
10677 cc_record = misdn_cc_find_by_bc(bc);
10678 if (cc_record) {
10679
10680 misdn_cc_delete(cc_record);
10681 }
10682 AST_LIST_UNLOCK(&misdn_cc_records_db);
10683 #endif
10684
10685 chan_misdn_log(1, bc->port,
10686 " --> no Ch, so we've already released. (%s)\n",
10687 manager_isdn_get_info(event));
10688 }
10689 break;
10690 case EVENT_BCHAN_ERROR:
10691 case EVENT_CLEANUP:
10692 stop_bc_tones(ch);
10693
10694 switch (ch->state) {
10695 case MISDN_CALLING:
10696 bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
10697 break;
10698 default:
10699 break;
10700 }
10701
10702 hangup_chan(ch, bc);
10703 release_chan(ch, bc);
10704 break;
10705 case EVENT_TONE_GENERATE:
10706 {
10707 int tone_len = bc->tone_cnt;
10708 struct ast_channel *ast = ch->ast;
10709 void *tmp;
10710 int res;
10711 int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
10712
10713 chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);
10714
10715 if (!ast) {
10716 break;
10717 }
10718
10719 if (!ast->generator) {
10720 break;
10721 }
10722
10723 tmp = ast->generatordata;
10724 ast->generatordata = NULL;
10725 generate = ast->generator->generate;
10726
10727 if (tone_len < 0 || tone_len > 512) {
10728 ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
10729 tone_len = 128;
10730 }
10731
10732 res = generate(ast, tmp, tone_len, tone_len);
10733 ast->generatordata = tmp;
10734
10735 if (res) {
10736 ast_log(LOG_WARNING, "Auto-deactivating generator\n");
10737 ast_deactivate_generator(ast);
10738 } else {
10739 bc->tone_cnt = 0;
10740 }
10741 break;
10742 }
10743 case EVENT_BCHAN_DATA:
10744 if (ch->bc->AOCD_need_export) {
10745 export_aoc_vars(ch->originator, ch->ast, ch->bc);
10746 }
10747 if (!misdn_cap_is_speech(ch->bc->capability)) {
10748 struct ast_frame frame;
10749
10750
10751 memset(&frame, 0, sizeof(frame));
10752 frame.frametype = AST_FRAME_VOICE;
10753 frame.subclass.codec = AST_FORMAT_ALAW;
10754 frame.datalen = bc->bframe_len;
10755 frame.samples = bc->bframe_len;
10756 frame.mallocd = 0;
10757 frame.offset = 0;
10758 frame.delivery = ast_tv(0, 0);
10759 frame.src = NULL;
10760 frame.data.ptr = bc->bframe;
10761
10762 if (ch->ast) {
10763 ast_queue_frame(ch->ast, &frame);
10764 }
10765 } else {
10766 struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
10767 int t;
10768
10769 t = ast_poll(&pfd, 1, 0);
10770
10771 if (t < 0) {
10772 chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
10773 break;
10774 }
10775 if (!t) {
10776 chan_misdn_log(9, bc->port, "poll() timed out\n");
10777 break;
10778 }
10779
10780 if (pfd.revents & POLLOUT) {
10781 chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
10782 if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
10783 chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
10784
10785 stop_bc_tones(ch);
10786 hangup_chan(ch, bc);
10787 release_chan(ch, bc);
10788 }
10789 } else {
10790 chan_misdn_log(1, bc->port, "Write Pipe full!\n");
10791 }
10792 }
10793 break;
10794 case EVENT_TIMEOUT:
10795 if (ch && bc) {
10796 chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
10797 }
10798
10799 switch (ch->state) {
10800 case MISDN_DIALING:
10801 case MISDN_PROGRESS:
10802 if (bc->nt && !ch->nttimeout) {
10803 break;
10804 }
10805
10806 case MISDN_CALLING:
10807 case MISDN_ALERTING:
10808 case MISDN_PROCEEDING:
10809 case MISDN_CALLING_ACKNOWLEDGE:
10810 if (bc->nt) {
10811 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10812 hanguptone_indicate(ch);
10813 }
10814
10815 bc->out_cause = AST_CAUSE_UNALLOCATED;
10816 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10817 break;
10818 case MISDN_WAITING4DIGS:
10819 if (bc->nt) {
10820 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10821 bc->out_cause = AST_CAUSE_UNALLOCATED;
10822 hanguptone_indicate(ch);
10823 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10824 } else {
10825 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10826 misdn_lib_send_event(bc, EVENT_RELEASE);
10827 }
10828 break;
10829 case MISDN_CLEANING:
10830 chan_misdn_log(1, bc->port, " --> in state cleaning .. so ignoring, the stack should clean it for us\n");
10831 break;
10832 default:
10833 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10834 break;
10835 }
10836 break;
10837
10838
10839
10840
10841 case EVENT_RETRIEVE:
10842 if (!ch) {
10843 chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
10844 ch = find_hold_call_l3(bc->l3_id);
10845 if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
10846 ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
10847 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10848 break;
10849 }
10850 }
10851
10852
10853 ch->bc = bc;
10854
10855 ch->hold.state = MISDN_HOLD_IDLE;
10856 ch->hold.port = 0;
10857 ch->hold.channel = 0;
10858
10859 ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
10860
10861 if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
10862 chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
10863 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10864 }
10865 break;
10866 case EVENT_HOLD:
10867 {
10868 int hold_allowed;
10869 struct ast_channel *bridged;
10870
10871 misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
10872 if (!hold_allowed) {
10873 chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
10874 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10875 break;
10876 }
10877
10878 bridged = ast_bridged_channel(ch->ast);
10879 if (bridged) {
10880 chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
10881 ch->l3id = bc->l3_id;
10882
10883
10884 ch->bc = NULL;
10885 ch->hold.state = MISDN_HOLD_ACTIVE;
10886 ch->hold.port = bc->port;
10887 ch->hold.channel = bc->channel;
10888
10889 ast_queue_control(ch->ast, AST_CONTROL_HOLD);
10890
10891 misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
10892 } else {
10893 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10894 chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
10895 }
10896 break;
10897 }
10898 case EVENT_NOTIFY:
10899 if (bc->redirecting.to_changed) {
10900
10901 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
10902 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
10903 }
10904 switch (bc->notify_description_code) {
10905 case mISDN_NOTIFY_CODE_DIVERSION_ACTIVATED:
10906
10907 bc->redirecting.to_changed = 0;
10908 break;
10909 case mISDN_NOTIFY_CODE_CALL_IS_DIVERTING:
10910 if (!bc->redirecting.to_changed) {
10911 break;
10912 }
10913 bc->redirecting.to_changed = 0;
10914 if (!ch || !ch->ast) {
10915 break;
10916 }
10917 switch (ch->state) {
10918 case MISDN_ALERTING:
10919
10920 bc->redirecting.reason = mISDN_REDIRECTING_REASON_NO_REPLY;
10921 break;
10922 default:
10923
10924 bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
10925 break;
10926 }
10927 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
10928 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10929 break;
10930 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940 if (!bc->redirecting.to_changed) {
10941 break;
10942 }
10943 bc->redirecting.to_changed = 0;
10944 if (!ch || !ch->ast) {
10945 break;
10946 }
10947 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10948 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
10949 bc->incoming_cid_tag);
10950 break;
10951 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
10952 if (!bc->redirecting.to_changed) {
10953 break;
10954 }
10955 bc->redirecting.to_changed = 0;
10956 if (!ch || !ch->ast) {
10957 break;
10958 }
10959 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10960 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
10961 break;
10962 default:
10963 bc->redirecting.to_changed = 0;
10964 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
10965 bc->notify_description_code);
10966 break;
10967 }
10968 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10969 break;
10970 case EVENT_FACILITY:
10971 if (bc->fac_in.Function == Fac_None) {
10972
10973 chan_misdn_log(0, bc->port," --> Missing facility ie or unknown facility ie contents.\n");
10974 } else {
10975 misdn_facility_ie_handler(event, bc, ch);
10976 }
10977
10978
10979 bc->redirecting.to_changed = 0;
10980 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10981 break;
10982 case EVENT_RESTART:
10983 if (!bc->dummy) {
10984 stop_bc_tones(ch);
10985 release_chan(ch, bc);
10986 }
10987 break;
10988 default:
10989 chan_misdn_log(1, 0, "Got Unknown Event\n");
10990 break;
10991 }
10992
10993 if (ch) {
10994 chan_list_unref(ch, "cb_event complete OK");
10995 }
10996 return RESPONSE_OK;
10997 }
10998
10999
11000
11001 #if defined(AST_MISDN_ENHANCEMENTS)
11002
11003
11004
11005
11006
11007
11008
11009
11010
11011
11012
11013
11014
11015 static int misdn_cc_read(struct ast_channel *chan, const char *function_name,
11016 char *function_args, char *buf, size_t size)
11017 {
11018 char *parse;
11019 struct misdn_cc_record *cc_record;
11020
11021 AST_DECLARE_APP_ARGS(args,
11022 AST_APP_ARG(cc_id);
11023 AST_APP_ARG(get_name);
11024 AST_APP_ARG(other);
11025 );
11026
11027
11028 *buf = 0;
11029
11030 if (ast_strlen_zero(function_args)) {
11031 ast_log(LOG_ERROR, "Function '%s' requires arguments.\n", function_name);
11032 return -1;
11033 }
11034
11035 parse = ast_strdupa(function_args);
11036 AST_STANDARD_APP_ARGS(args, parse);
11037
11038 if (!args.argc || ast_strlen_zero(args.cc_id)) {
11039 ast_log(LOG_ERROR, "Function '%s' missing call completion record ID.\n",
11040 function_name);
11041 return -1;
11042 }
11043 if (!isdigit(*args.cc_id)) {
11044 ast_log(LOG_ERROR, "Function '%s' call completion record ID must be numeric.\n",
11045 function_name);
11046 return -1;
11047 }
11048
11049 if (ast_strlen_zero(args.get_name)) {
11050 ast_log(LOG_ERROR, "Function '%s' missing what-to-get parameter.\n",
11051 function_name);
11052 return -1;
11053 }
11054
11055 AST_LIST_LOCK(&misdn_cc_records_db);
11056 cc_record = misdn_cc_find_by_id(atoi(args.cc_id));
11057 if (cc_record) {
11058 if (!strcasecmp("a-all", args.get_name)) {
11059 snprintf(buf, size, "\"%s\" <%s>", cc_record->redial.caller.name,
11060 cc_record->redial.caller.number);
11061 } else if (!strcasecmp("a-name", args.get_name)) {
11062 ast_copy_string(buf, cc_record->redial.caller.name, size);
11063 } else if (!strncasecmp("a-num", args.get_name, 5)) {
11064 ast_copy_string(buf, cc_record->redial.caller.number, size);
11065 } else if (!strcasecmp("a-ton", args.get_name)) {
11066 snprintf(buf, size, "%d",
11067 misdn_to_ast_plan(cc_record->redial.caller.number_plan)
11068 | misdn_to_ast_ton(cc_record->redial.caller.number_type));
11069 } else if (!strncasecmp("a-pres", args.get_name, 6)) {
11070 ast_copy_string(buf, ast_named_caller_presentation(
11071 misdn_to_ast_pres(cc_record->redial.caller.presentation)
11072 | misdn_to_ast_screen(cc_record->redial.caller.screening)), size);
11073 } else if (!strcasecmp("a-busy", args.get_name)) {
11074 ast_copy_string(buf, cc_record->party_a_free ? "no" : "yes", size);
11075 } else if (!strncasecmp("b-num", args.get_name, 5)) {
11076 ast_copy_string(buf, cc_record->redial.dialed.number, size);
11077 } else if (!strcasecmp("b-ton", args.get_name)) {
11078 snprintf(buf, size, "%d",
11079 misdn_to_ast_plan(cc_record->redial.dialed.number_plan)
11080 | misdn_to_ast_ton(cc_record->redial.dialed.number_type));
11081 } else if (!strcasecmp("port", args.get_name)) {
11082 snprintf(buf, size, "%d", cc_record->port);
11083 } else if (!strcasecmp("available-notify-priority", args.get_name)) {
11084 snprintf(buf, size, "%d", cc_record->remote_user_free.priority);
11085 } else if (!strcasecmp("available-notify-exten", args.get_name)) {
11086 ast_copy_string(buf, cc_record->remote_user_free.exten, size);
11087 } else if (!strcasecmp("available-notify-context", args.get_name)) {
11088 ast_copy_string(buf, cc_record->remote_user_free.context, size);
11089 } else if (!strcasecmp("busy-notify-priority", args.get_name)) {
11090 snprintf(buf, size, "%d", cc_record->b_free.priority);
11091 } else if (!strcasecmp("busy-notify-exten", args.get_name)) {
11092 ast_copy_string(buf, cc_record->b_free.exten, size);
11093 } else if (!strcasecmp("busy-notify-context", args.get_name)) {
11094 ast_copy_string(buf, cc_record->b_free.context, size);
11095 } else {
11096 AST_LIST_UNLOCK(&misdn_cc_records_db);
11097 ast_log(LOG_ERROR, "Function '%s': Unknown what-to-get '%s'.\n", function_name, args.get_name);
11098 return -1;
11099 }
11100 }
11101 AST_LIST_UNLOCK(&misdn_cc_records_db);
11102
11103 return 0;
11104 }
11105 #endif
11106
11107 #if defined(AST_MISDN_ENHANCEMENTS)
11108 static struct ast_custom_function misdn_cc_function = {
11109 .name = "mISDN_CC",
11110 .synopsis = "Get call completion record information.",
11111 .syntax = "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)",
11112 .desc =
11113 "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)\n"
11114 "The following can be retrieved:\n"
11115 "\"a-num\", \"a-name\", \"a-all\", \"a-ton\", \"a-pres\", \"a-busy\",\n"
11116 "\"b-num\", \"b-ton\", \"port\",\n"
11117 " User-A is available for call completion:\n"
11118 " \"available-notify-priority\",\n"
11119 " \"available-notify-exten\",\n"
11120 " \"available-notify-context\",\n"
11121 " User-A is busy:\n"
11122 " \"busy-notify-priority\",\n"
11123 " \"busy-notify-exten\",\n"
11124 " \"busy-notify-context\"\n",
11125 .read = misdn_cc_read,
11126 };
11127 #endif
11128
11129
11130
11131
11132
11133
11134
11135
11136
11137
11138 static int unload_module(void)
11139 {
11140
11141 ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
11142
11143 misdn_tasks_destroy();
11144
11145 if (!g_config_initialized) {
11146 return 0;
11147 }
11148
11149 ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11150
11151
11152 ast_unregister_application("misdn_set_opt");
11153 ast_unregister_application("misdn_facility");
11154 ast_unregister_application("misdn_check_l2l1");
11155 #if defined(AST_MISDN_ENHANCEMENTS)
11156 ast_unregister_application(misdn_command_name);
11157 ast_custom_function_unregister(&misdn_cc_function);
11158 #endif
11159
11160 ast_channel_unregister(&misdn_tech);
11161
11162 free_robin_list();
11163 misdn_cfg_destroy();
11164 misdn_lib_destroy();
11165
11166 ast_free(misdn_out_calls);
11167 ast_free(misdn_in_calls);
11168 ast_free(misdn_debug_only);
11169 ast_free(misdn_ports);
11170 ast_free(misdn_debug);
11171
11172 #if defined(AST_MISDN_ENHANCEMENTS)
11173 misdn_cc_destroy();
11174 #endif
11175
11176 return 0;
11177 }
11178
11179 static int load_module(void)
11180 {
11181 int i, port;
11182 int ntflags = 0, ntkc = 0;
11183 char ports[256] = "";
11184 char tempbuf[BUFFERSIZE + 1];
11185 char ntfile[BUFFERSIZE + 1];
11186 struct misdn_lib_iface iface = {
11187 .cb_event = cb_events,
11188 .cb_log = chan_misdn_log,
11189 .cb_jb_empty = chan_misdn_jb_empty,
11190 };
11191
11192 max_ports = misdn_lib_maxports_get();
11193
11194 if (max_ports <= 0) {
11195 ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
11196 return AST_MODULE_LOAD_DECLINE;
11197 }
11198
11199 if (misdn_cfg_init(max_ports, 0)) {
11200 ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
11201 return AST_MODULE_LOAD_DECLINE;
11202 }
11203 g_config_initialized = 1;
11204
11205 #if defined(AST_MISDN_ENHANCEMENTS)
11206 misdn_cc_init();
11207 #endif
11208
11209 misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
11210 if (!misdn_debug) {
11211 ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
11212 return AST_MODULE_LOAD_DECLINE;
11213 }
11214 misdn_ports = ast_malloc(sizeof(int) * (max_ports + 1));
11215 if (!misdn_ports) {
11216 ast_free(misdn_debug);
11217 ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
11218 return AST_MODULE_LOAD_DECLINE;
11219 }
11220 misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(misdn_debug[0]));
11221 for (i = 1; i <= max_ports; i++) {
11222 misdn_debug[i] = misdn_debug[0];
11223 misdn_ports[i] = i;
11224 }
11225 *misdn_ports = 0;
11226 misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int));
11227 if (!misdn_debug_only) {
11228 ast_free(misdn_ports);
11229 ast_free(misdn_debug);
11230 ast_log(LOG_ERROR, "Out of memory for misdn_debug_only\n");
11231 return AST_MODULE_LOAD_DECLINE;
11232 }
11233
11234 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf));
11235 if (!ast_strlen_zero(tempbuf)) {
11236 tracing = 1;
11237 }
11238
11239 misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11240 if (!misdn_in_calls) {
11241 ast_free(misdn_debug_only);
11242 ast_free(misdn_ports);
11243 ast_free(misdn_debug);
11244 ast_log(LOG_ERROR, "Out of memory for misdn_in_calls\n");
11245 return AST_MODULE_LOAD_DECLINE;
11246 }
11247 misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11248 if (!misdn_out_calls) {
11249 ast_free(misdn_in_calls);
11250 ast_free(misdn_debug_only);
11251 ast_free(misdn_ports);
11252 ast_free(misdn_debug);
11253 ast_log(LOG_ERROR, "Out of memory for misdn_out_calls\n");
11254 return AST_MODULE_LOAD_DECLINE;
11255 }
11256
11257 for (i = 1; i <= max_ports; i++) {
11258 misdn_in_calls[i] = 0;
11259 misdn_out_calls[i] = 0;
11260 }
11261
11262 ast_mutex_init(&cl_te_lock);
11263 ast_mutex_init(&release_lock);
11264
11265 misdn_cfg_update_ptp();
11266 misdn_cfg_get_ports_string(ports);
11267
11268 if (!ast_strlen_zero(ports)) {
11269 chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
11270 }
11271 if (misdn_lib_init(ports, &iface, NULL)) {
11272 chan_misdn_log(0, 0, "No te ports initialized\n");
11273 }
11274
11275 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
11276 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
11277 misdn_cfg_get(0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
11278
11279 misdn_lib_nt_keepcalls(ntkc);
11280 misdn_lib_nt_debug_init(ntflags, ntfile);
11281
11282 if (ast_channel_register(&misdn_tech)) {
11283 ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
11284 unload_module();
11285 return AST_MODULE_LOAD_DECLINE;
11286 }
11287
11288 ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11289
11290 ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
11291 "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
11292 "Sets mISDN opts. and optargs\n"
11293 "\n"
11294 "The available options are:\n"
11295 " a - Have Asterisk detect DTMF tones on called channel\n"
11296 " c - Make crypted outgoing call, optarg is keyindex\n"
11297 " d - Send display text to called phone, text is the optarg\n"
11298 " e - Perform echo cancellation on this channel,\n"
11299 " takes taps as optarg (32,64,128,256)\n"
11300 " e! - Disable echo cancellation on this channel\n"
11301 " f - Enable fax detection\n"
11302 " h - Make digital outgoing call\n"
11303 " h1 - Make HDLC mode digital outgoing call\n"
11304 " i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
11305 " they will be transported inband.\n"
11306 " jb - Set jitter buffer length, optarg is length\n"
11307 " jt - Set jitter buffer upper threshold, optarg is threshold\n"
11308 " jn - Disable jitter buffer\n"
11309 " n - Disable mISDN DSP on channel.\n"
11310 " Disables: echo cancel, DTMF detection, and volume control.\n"
11311 " p - Caller ID presentation,\n"
11312 " optarg is either 'allowed' or 'restricted'\n"
11313 " s - Send Non-inband DTMF as inband\n"
11314 " vr - Rx gain control, optarg is gain\n"
11315 " vt - Tx gain control, optarg is gain\n"
11316 );
11317
11318
11319 ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
11320 "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
11321 "Sends the Facility Message FACILITY_TYPE with \n"
11322 "the given Arguments to the current ISDN Channel\n"
11323 "Supported Facilities are:\n"
11324 "\n"
11325 "type=calldeflect args=Nr where to deflect\n"
11326 #if defined(AST_MISDN_ENHANCEMENTS)
11327 "type=callrerouting args=Nr where to deflect\n"
11328 #endif
11329 );
11330
11331
11332 ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
11333 "misdn_check_l2l1(<port>||g:<groupname>,timeout)\n"
11334 "Checks if the L2 and L1 are up on either the given <port> or\n"
11335 "on the ports in the group with <groupname>\n"
11336 "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
11337 "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
11338 "\n"
11339 "This application, ensures the L1/L2 state of the Ports in a group\n"
11340 "it is intended to make the pmp_l1_check option redundant and to\n"
11341 "fix a buggy switch config from your provider\n"
11342 "\n"
11343 "a sample dialplan would look like:\n\n"
11344 "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
11345 "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
11346 );
11347
11348 #if defined(AST_MISDN_ENHANCEMENTS)
11349 ast_register_application(misdn_command_name, misdn_command_exec, misdn_command_name,
11350 "misdn_command(<command>[,<options>])\n"
11351 "The following commands are defined:\n"
11352 "cc-initialize\n"
11353 " Setup mISDN support for call completion\n"
11354 " Must call before doing any Dial() involving call completion.\n"
11355 "ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11356 " Request Call Completion No Reply activation\n"
11357 "ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11358 " Request Call Completion Busy Subscriber activation\n"
11359 "cc-b-free,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11360 " Set the dialplan location to notify when User-B is available but User-A is busy.\n"
11361 " Setting this dialplan location is optional.\n"
11362 "cc-a-busy,${MISDN_CC_RECORD_ID},<yes/no>\n"
11363 " Set the busy status of call completion User-A\n"
11364 "cc-deactivate,${MISDN_CC_RECORD_ID}\n"
11365 " Deactivate the identified call completion request\n"
11366 "\n"
11367 "MISDN_CC_RECORD_ID is set when Dial() returns and call completion is possible\n"
11368 "MISDN_CC_STATUS is set to ACTIVATED or ERROR after the call completion\n"
11369 "activation request.\n"
11370 "MISDN_ERROR_MSG is set to a descriptive message on error.\n"
11371 );
11372
11373 ast_custom_function_register(&misdn_cc_function);
11374 #endif
11375
11376 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
11377
11378
11379
11380 for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
11381 int l1timeout;
11382 misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
11383 if (l1timeout) {
11384 chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
11385 misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
11386 }
11387 }
11388
11389 chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");
11390
11391 return 0;
11392 }
11393
11394
11395
11396 static int reload(void)
11397 {
11398 reload_config();
11399
11400 return 0;
11401 }
11402
11403
11404
11405 #if defined(AST_MISDN_ENHANCEMENTS)
11406
11407
11408
11409 AST_DEFINE_APP_ARGS_TYPE(misdn_command_args,
11410 AST_APP_ARG(name);
11411 AST_APP_ARG(arg)[10 + 1];
11412 );
11413 #endif
11414
11415 #if defined(AST_MISDN_ENHANCEMENTS)
11416 static void misdn_cc_caller_destroy(void *obj)
11417 {
11418
11419 }
11420 #endif
11421
11422 #if defined(AST_MISDN_ENHANCEMENTS)
11423 static struct misdn_cc_caller *misdn_cc_caller_alloc(struct ast_channel *chan)
11424 {
11425 struct misdn_cc_caller *cc_caller;
11426
11427 if (!(cc_caller = ao2_alloc(sizeof(*cc_caller), misdn_cc_caller_destroy))) {
11428 return NULL;
11429 }
11430
11431 cc_caller->chan = chan;
11432
11433 return cc_caller;
11434 }
11435 #endif
11436
11437 #if defined(AST_MISDN_ENHANCEMENTS)
11438
11439
11440
11441
11442
11443
11444
11445
11446
11447
11448 static int misdn_command_cc_initialize(struct ast_channel *chan, struct misdn_command_args *subcommand)
11449 {
11450 struct misdn_cc_caller *cc_caller;
11451 struct ast_datastore *datastore;
11452
11453 if (!(cc_caller = misdn_cc_caller_alloc(chan))) {
11454 return -1;
11455 }
11456
11457 if (!(datastore = ast_datastore_alloc(&misdn_cc_ds_info, NULL))) {
11458 ao2_ref(cc_caller, -1);
11459 return -1;
11460 }
11461
11462 ast_channel_lock(chan);
11463
11464
11465 datastore->data = cc_caller;
11466 cc_caller = NULL;
11467
11468 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
11469
11470 ast_channel_datastore_add(chan, datastore);
11471
11472 ast_channel_unlock(chan);
11473
11474 return 0;
11475 }
11476 #endif
11477
11478 #if defined(AST_MISDN_ENHANCEMENTS)
11479
11480
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493 static int misdn_command_cc_deactivate(struct ast_channel *chan, struct misdn_command_args *subcommand)
11494 {
11495 long record_id;
11496 const char *error_str;
11497 struct misdn_cc_record *cc_record;
11498 struct misdn_bchannel *bc;
11499 struct misdn_bchannel dummy;
11500
11501 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID})\n";
11502
11503 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11504 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11505 return -1;
11506 }
11507 record_id = atol(subcommand->arg[0]);
11508
11509 AST_LIST_LOCK(&misdn_cc_records_db);
11510 cc_record = misdn_cc_find_by_id(record_id);
11511 if (cc_record && 0 <= cc_record->port) {
11512 if (cc_record->ptp) {
11513 if (cc_record->mode.ptp.bc) {
11514
11515 bc = cc_record->mode.ptp.bc;
11516 bc->fac_out.Function = Fac_None;
11517 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11518 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11519 }
11520 misdn_cc_delete(cc_record);
11521 } else if (cc_record->activated) {
11522 cc_record->error_code = FacError_None;
11523 cc_record->reject_code = FacReject_None;
11524 cc_record->invoke_id = ++misdn_invoke_id;
11525 cc_record->outstanding_message = 1;
11526
11527
11528 misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
11529 dummy.fac_out.Function = Fac_CCBSDeactivate;
11530 dummy.fac_out.u.CCBSDeactivate.InvokeID = cc_record->invoke_id;
11531 dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
11532 dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->mode.ptmp.reference_id;
11533
11534
11535 print_facility(&dummy.fac_out, &dummy);
11536 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11537 }
11538 }
11539 AST_LIST_UNLOCK(&misdn_cc_records_db);
11540
11541
11542 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11543
11544 AST_LIST_LOCK(&misdn_cc_records_db);
11545 cc_record = misdn_cc_find_by_id(record_id);
11546 if (cc_record) {
11547 if (cc_record->port < 0) {
11548
11549 error_str = NULL;
11550 } else if (cc_record->outstanding_message) {
11551 cc_record->outstanding_message = 0;
11552 error_str = misdn_no_response_from_network;
11553 } else if (cc_record->reject_code != FacReject_None) {
11554 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11555 } else if (cc_record->error_code != FacError_None) {
11556 error_str = misdn_to_str_error_code(cc_record->error_code);
11557 } else {
11558 error_str = NULL;
11559 }
11560
11561 misdn_cc_delete(cc_record);
11562 } else {
11563 error_str = NULL;
11564 }
11565 AST_LIST_UNLOCK(&misdn_cc_records_db);
11566 if (error_str) {
11567 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11568 misdn_command_name, subcommand->name, error_str, chan->name);
11569 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11570 }
11571
11572 return 0;
11573 }
11574 #endif
11575
11576 #if defined(AST_MISDN_ENHANCEMENTS)
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591 static int misdn_command_cc_a_busy(struct ast_channel *chan, struct misdn_command_args *subcommand)
11592 {
11593 long record_id;
11594 int party_a_free;
11595 struct misdn_cc_record *cc_record;
11596 struct misdn_bchannel *bc;
11597
11598 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<yes/no>)\n";
11599
11600 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11601 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11602 return -1;
11603 }
11604 record_id = atol(subcommand->arg[0]);
11605
11606 if (ast_true(subcommand->arg[1])) {
11607 party_a_free = 0;
11608 } else if (ast_false(subcommand->arg[1])) {
11609 party_a_free = 1;
11610 } else {
11611 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11612 return -1;
11613 }
11614
11615 AST_LIST_LOCK(&misdn_cc_records_db);
11616 cc_record = misdn_cc_find_by_id(record_id);
11617 if (cc_record && cc_record->party_a_free != party_a_free) {
11618
11619 cc_record->party_a_free = party_a_free;
11620
11621 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11622 cc_record->error_code = FacError_None;
11623 cc_record->reject_code = FacReject_None;
11624
11625
11626 bc = cc_record->mode.ptp.bc;
11627 if (cc_record->party_a_free) {
11628 bc->fac_out.Function = Fac_CCBS_T_Resume;
11629 bc->fac_out.u.CCBS_T_Resume.InvokeID = ++misdn_invoke_id;
11630 } else {
11631 bc->fac_out.Function = Fac_CCBS_T_Suspend;
11632 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
11633 }
11634
11635
11636 print_facility(&bc->fac_out, bc);
11637 misdn_lib_send_event(bc, EVENT_FACILITY);
11638 }
11639 }
11640 AST_LIST_UNLOCK(&misdn_cc_records_db);
11641
11642 return 0;
11643 }
11644 #endif
11645
11646 #if defined(AST_MISDN_ENHANCEMENTS)
11647
11648
11649
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659
11660
11661 static int misdn_command_cc_b_free(struct ast_channel *chan, struct misdn_command_args *subcommand)
11662 {
11663 unsigned index;
11664 long record_id;
11665 int priority;
11666 char *context;
11667 char *exten;
11668 struct misdn_cc_record *cc_record;
11669
11670 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11671
11672
11673 for (index = 0; index < 4; ++index) {
11674 if (ast_strlen_zero(subcommand->arg[index])) {
11675 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11676 return -1;
11677 }
11678 }
11679
11680
11681 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11682 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11683 return -1;
11684 }
11685
11686 record_id = atol(subcommand->arg[0]);
11687 context = subcommand->arg[1];
11688 exten = subcommand->arg[2];
11689 priority = atoi(subcommand->arg[3]);
11690
11691 AST_LIST_LOCK(&misdn_cc_records_db);
11692 cc_record = misdn_cc_find_by_id(record_id);
11693 if (cc_record) {
11694
11695 ast_copy_string(cc_record->b_free.context, context, sizeof(cc_record->b_free.context));
11696 ast_copy_string(cc_record->b_free.exten, exten, sizeof(cc_record->b_free.exten));
11697 cc_record->b_free.priority = priority;
11698 }
11699 AST_LIST_UNLOCK(&misdn_cc_records_db);
11700
11701 return 0;
11702 }
11703 #endif
11704
11705 #if defined(AST_MISDN_ENHANCEMENTS)
11706 struct misdn_cc_request {
11707 enum FacFunction ptmp;
11708 enum FacFunction ptp;
11709 };
11710 #endif
11711
11712 #if defined(AST_MISDN_ENHANCEMENTS)
11713
11714
11715
11716
11717
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729 static int misdn_command_cc_request(struct ast_channel *chan, struct misdn_command_args *subcommand, const struct misdn_cc_request *request)
11730 {
11731 unsigned index;
11732 int request_retention;
11733 long record_id;
11734 int priority;
11735 char *context;
11736 char *exten;
11737 const char *error_str;
11738 struct misdn_cc_record *cc_record;
11739 struct misdn_bchannel *bc;
11740 struct misdn_bchannel dummy;
11741 struct misdn_party_id id;
11742
11743 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11744
11745
11746 for (index = 0; index < 4; ++index) {
11747 if (ast_strlen_zero(subcommand->arg[index])) {
11748 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11749 return -1;
11750 }
11751 }
11752
11753
11754 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11755 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11756 return -1;
11757 }
11758
11759 record_id = atol(subcommand->arg[0]);
11760 context = subcommand->arg[1];
11761 exten = subcommand->arg[2];
11762 priority = atoi(subcommand->arg[3]);
11763
11764 AST_LIST_LOCK(&misdn_cc_records_db);
11765 cc_record = misdn_cc_find_by_id(record_id);
11766 if (cc_record) {
11767
11768 ast_copy_string(cc_record->remote_user_free.context, context,
11769 sizeof(cc_record->remote_user_free.context));
11770 ast_copy_string(cc_record->remote_user_free.exten, exten,
11771 sizeof(cc_record->remote_user_free.exten));
11772 cc_record->remote_user_free.priority = priority;
11773
11774 if (0 <= cc_record->port) {
11775 if (cc_record->ptp) {
11776 if (!cc_record->mode.ptp.bc) {
11777 bc = misdn_lib_get_register_bc(cc_record->port);
11778 if (bc) {
11779 cc_record->mode.ptp.bc = bc;
11780 cc_record->error_code = FacError_None;
11781 cc_record->reject_code = FacReject_None;
11782 cc_record->invoke_id = ++misdn_invoke_id;
11783 cc_record->outstanding_message = 1;
11784 cc_record->activation_requested = 1;
11785
11786 misdn_cfg_get(bc->port, MISDN_CFG_CC_REQUEST_RETENTION,
11787 &request_retention, sizeof(request_retention));
11788 cc_record->mode.ptp.requested_retention = request_retention ? 1 : 0;
11789
11790
11791 bc->fac_out.Function = request->ptp;
11792 bc->fac_out.u.CCBS_T_Request.InvokeID = cc_record->invoke_id;
11793 bc->fac_out.u.CCBS_T_Request.ComponentType = FacComponent_Invoke;
11794 bc->fac_out.u.CCBS_T_Request.Component.Invoke.Q931ie =
11795 cc_record->redial.setup_bc_hlc_llc;
11796 memset(&id, 0, sizeof(id));
11797 id.number_plan = cc_record->redial.dialed.number_plan;
11798 id.number_type = cc_record->redial.dialed.number_type;
11799 ast_copy_string(id.number, cc_record->redial.dialed.number,
11800 sizeof(id.number));
11801 misdn_Address_fill(
11802 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Destination,
11803 &id);
11804 misdn_Address_fill(
11805 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Originating,
11806 &cc_record->redial.caller);
11807 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1;
11808 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator =
11809 (cc_record->redial.caller.presentation != 0) ? 0 : 1;
11810 bc->fac_out.u.CCBS_T_Request.Component.Invoke.RetentionSupported =
11811 request_retention ? 1 : 0;
11812
11813
11814 print_facility(&bc->fac_out, bc);
11815 misdn_lib_send_event(bc, EVENT_REGISTER);
11816 }
11817 }
11818 } else {
11819 cc_record->error_code = FacError_None;
11820 cc_record->reject_code = FacReject_None;
11821 cc_record->invoke_id = ++misdn_invoke_id;
11822 cc_record->outstanding_message = 1;
11823 cc_record->activation_requested = 1;
11824
11825
11826 misdn_make_dummy(&dummy, cc_record->port, 0,
11827 misdn_lib_port_is_nt(cc_record->port), 0);
11828 dummy.fac_out.Function = request->ptmp;
11829 dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
11830 dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
11831 dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID =
11832 cc_record->mode.ptmp.linkage_id;
11833
11834
11835 print_facility(&dummy.fac_out, &dummy);
11836 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11837 }
11838 }
11839 }
11840 AST_LIST_UNLOCK(&misdn_cc_records_db);
11841
11842
11843 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11844
11845 AST_LIST_LOCK(&misdn_cc_records_db);
11846 cc_record = misdn_cc_find_by_id(record_id);
11847 if (cc_record) {
11848 if (!cc_record->activated) {
11849 if (cc_record->port < 0) {
11850
11851 error_str = "No port number";
11852 } else if (cc_record->outstanding_message) {
11853 cc_record->outstanding_message = 0;
11854 error_str = misdn_no_response_from_network;
11855 } else if (cc_record->reject_code != FacReject_None) {
11856 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11857 } else if (cc_record->error_code != FacError_None) {
11858 error_str = misdn_to_str_error_code(cc_record->error_code);
11859 } else if (cc_record->ptp) {
11860 if (cc_record->mode.ptp.bc) {
11861 error_str = "Call-completion already requested";
11862 } else {
11863 error_str = "Could not allocate call-completion signaling link";
11864 }
11865 } else {
11866
11867 error_str = "Unexpected error";
11868 }
11869
11870
11871 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11872
11873 bc = cc_record->mode.ptp.bc;
11874 bc->fac_out.Function = Fac_None;
11875 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11876 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11877 }
11878 misdn_cc_delete(cc_record);
11879 } else {
11880 error_str = NULL;
11881 }
11882 } else {
11883 error_str = misdn_cc_record_not_found;
11884 }
11885 AST_LIST_UNLOCK(&misdn_cc_records_db);
11886 if (error_str) {
11887 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11888 misdn_command_name, subcommand->name, error_str, chan->name);
11889 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11890 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ERROR");
11891 } else {
11892 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ACTIVATED");
11893 }
11894
11895 return 0;
11896 }
11897 #endif
11898
11899 #if defined(AST_MISDN_ENHANCEMENTS)
11900
11901
11902
11903
11904
11905
11906
11907
11908
11909
11910
11911
11912
11913
11914 static int misdn_command_ccbs_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11915 {
11916 static const struct misdn_cc_request request = {
11917 .ptmp = Fac_CCBSRequest,
11918 .ptp = Fac_CCBS_T_Request
11919 };
11920
11921 return misdn_command_cc_request(chan, subcommand, &request);
11922 }
11923 #endif
11924
11925 #if defined(AST_MISDN_ENHANCEMENTS)
11926
11927
11928
11929
11930
11931
11932
11933
11934
11935
11936
11937
11938
11939
11940 static int misdn_command_ccnr_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11941 {
11942 static const struct misdn_cc_request request = {
11943 .ptmp = Fac_CCNRRequest,
11944 .ptp = Fac_CCNR_T_Request
11945 };
11946
11947 return misdn_command_cc_request(chan, subcommand, &request);
11948 }
11949 #endif
11950
11951 #if defined(AST_MISDN_ENHANCEMENTS)
11952 struct misdn_command_table {
11953
11954 const char *name;
11955
11956
11957 int (*func)(struct ast_channel *chan, struct misdn_command_args *subcommand);
11958
11959
11960 int misdn_only;
11961 };
11962 static const struct misdn_command_table misdn_commands[] = {
11963
11964
11965 { "cc-initialize", misdn_command_cc_initialize, 0 },
11966 { "cc-deactivate", misdn_command_cc_deactivate, 0 },
11967 { "cc-a-busy", misdn_command_cc_a_busy, 0 },
11968 { "cc-b-free", misdn_command_cc_b_free, 0 },
11969 { "ccbs-request", misdn_command_ccbs_request, 0 },
11970 { "ccnr-request", misdn_command_ccnr_request, 0 },
11971
11972 };
11973 #endif
11974
11975 #if defined(AST_MISDN_ENHANCEMENTS)
11976
11977
11978
11979
11980
11981
11982
11983
11984
11985
11986 static int misdn_command_exec(struct ast_channel *chan, const char *data)
11987 {
11988 char *parse;
11989 unsigned index;
11990 struct misdn_command_args subcommand;
11991
11992 if (ast_strlen_zero((char *) data)) {
11993 ast_log(LOG_ERROR, "%s requires arguments\n", misdn_command_name);
11994 return -1;
11995 }
11996
11997 ast_log(LOG_DEBUG, "%s(%s)\n", misdn_command_name, (char *) data);
11998
11999 parse = ast_strdupa(data);
12000 AST_STANDARD_APP_ARGS(subcommand, parse);
12001 if (!subcommand.argc || ast_strlen_zero(subcommand.name)) {
12002 ast_log(LOG_ERROR, "%s requires a subcommand\n", misdn_command_name);
12003 return -1;
12004 }
12005
12006 for (index = 0; index < ARRAY_LEN(misdn_commands); ++index) {
12007 if (strcasecmp(misdn_commands[index].name, subcommand.name) == 0) {
12008 strcpy(subcommand.name, misdn_commands[index].name);
12009 if (misdn_commands[index].misdn_only
12010 && strcasecmp(chan->tech->type, misdn_type) != 0) {
12011 ast_log(LOG_WARNING,
12012 "%s(%s) only makes sense with %s channels!\n",
12013 misdn_command_name, subcommand.name, misdn_type);
12014 return -1;
12015 }
12016 return misdn_commands[index].func(chan, &subcommand);
12017 }
12018 }
12019
12020 ast_log(LOG_WARNING, "%s(%s) subcommand is unknown\n", misdn_command_name,
12021 subcommand.name);
12022 return -1;
12023 }
12024 #endif
12025
12026 static int misdn_facility_exec(struct ast_channel *chan, const char *data)
12027 {
12028 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12029 char *parse;
12030 unsigned max_len;
12031
12032 AST_DECLARE_APP_ARGS(args,
12033 AST_APP_ARG(facility_type);
12034 AST_APP_ARG(arg)[99];
12035 );
12036
12037 chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
12038
12039 if (strcasecmp(chan->tech->type, misdn_type)) {
12040 ast_log(LOG_WARNING, "misdn_facility only makes sense with %s channels!\n", misdn_type);
12041 return -1;
12042 }
12043
12044 if (ast_strlen_zero((char *) data)) {
12045 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12046 return -1;
12047 }
12048
12049 parse = ast_strdupa(data);
12050 AST_STANDARD_APP_ARGS(args, parse);
12051
12052 if (ast_strlen_zero(args.facility_type)) {
12053 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12054 return -1;
12055 }
12056
12057 if (!strcasecmp(args.facility_type, "calldeflect")) {
12058 if (ast_strlen_zero(args.arg[0])) {
12059 ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n");
12060 }
12061
12062 #if defined(AST_MISDN_ENHANCEMENTS)
12063 max_len = sizeof(ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
12064 if (max_len < strlen(args.arg[0])) {
12065 ast_log(LOG_WARNING,
12066 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12067 max_len);
12068 return 0;
12069 }
12070 ch->bc->fac_out.Function = Fac_CallDeflection;
12071 ch->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
12072 ch->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
12073 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
12074 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
12075 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;
12076 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(args.arg[0]);
12077 strcpy((char *) ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, args.arg[0]);
12078 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
12079
12080 #else
12081
12082 max_len = sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
12083 if (max_len < strlen(args.arg[0])) {
12084 ast_log(LOG_WARNING,
12085 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12086 max_len);
12087 return 0;
12088 }
12089 ch->bc->fac_out.Function = Fac_CD;
12090 ch->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
12091
12092 strcpy((char *) ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0]);
12093 #endif
12094
12095
12096 print_facility(&ch->bc->fac_out, ch->bc);
12097 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12098 #if defined(AST_MISDN_ENHANCEMENTS)
12099 } else if (!strcasecmp(args.facility_type, "callrerouteing")
12100 || !strcasecmp(args.facility_type, "callrerouting")) {
12101 if (ast_strlen_zero(args.arg[0])) {
12102 ast_log(LOG_WARNING, "Facility: Call rerouting requires an argument: Number\n");
12103 }
12104
12105 max_len = sizeof(ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
12106 if (max_len < strlen(args.arg[0])) {
12107 ast_log(LOG_WARNING,
12108 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12109 max_len);
12110 return 0;
12111 }
12112 ch->bc->fac_out.Function = Fac_CallRerouteing;
12113 ch->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
12114 ch->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
12115
12116 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;
12117 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
12118
12119 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;
12120 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(args.arg[0]);
12121 strcpy((char *) ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, args.arg[0]);
12122 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
12123
12124 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
12125
12126
12127 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
12128 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
12129 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
12130 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
12131 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
12132 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
12133 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
12134
12135 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;
12136 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;
12137
12138
12139 print_facility(&ch->bc->fac_out, ch->bc);
12140 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12141 #endif
12142 } else {
12143 chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type);
12144 }
12145
12146 return 0;
12147 }
12148
12149 static int misdn_check_l2l1(struct ast_channel *chan, const char *data)
12150 {
12151 char *parse;
12152 char group[BUFFERSIZE + 1];
12153 char *port_str;
12154 int port = 0;
12155 int timeout;
12156 int dowait = 0;
12157 int port_up;
12158
12159 AST_DECLARE_APP_ARGS(args,
12160 AST_APP_ARG(grouppar);
12161 AST_APP_ARG(timeout);
12162 );
12163
12164 if (ast_strlen_zero((char *) data)) {
12165 ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
12166 return -1;
12167 }
12168
12169 parse = ast_strdupa(data);
12170 AST_STANDARD_APP_ARGS(args, parse);
12171
12172 if (args.argc != 2) {
12173 ast_log(LOG_WARNING, "Wrong argument count\n");
12174 return 0;
12175 }
12176
12177
12178 timeout = atoi(args.timeout);
12179 port_str = args.grouppar;
12180
12181 if (port_str[0] == 'g' && port_str[1] == ':') {
12182
12183 port_str += 2;
12184 ast_copy_string(group, port_str, sizeof(group));
12185 chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
12186
12187 for (port = misdn_cfg_get_next_port(port);
12188 port > 0;
12189 port = misdn_cfg_get_next_port(port)) {
12190 char cfg_group[BUFFERSIZE + 1];
12191
12192 chan_misdn_log(2, 0, "trying port %d\n", port);
12193
12194 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
12195
12196 if (!strcasecmp(cfg_group, group)) {
12197 port_up = misdn_lib_port_up(port, 1);
12198 if (!port_up) {
12199 chan_misdn_log(2, 0, " --> port '%d'\n", port);
12200 misdn_lib_get_port_up(port);
12201 dowait = 1;
12202 }
12203 }
12204 }
12205 } else {
12206 port = atoi(port_str);
12207 chan_misdn_log(2, 0, "Checking Port: %d\n", port);
12208 port_up = misdn_lib_port_up(port, 1);
12209 if (!port_up) {
12210 misdn_lib_get_port_up(port);
12211 dowait = 1;
12212 }
12213 }
12214
12215 if (dowait) {
12216 chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
12217 ast_safe_sleep(chan, timeout * 1000);
12218 }
12219
12220 return 0;
12221 }
12222
12223 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data)
12224 {
12225 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12226 char *tok;
12227 char *tokb;
12228 char *parse;
12229 int keyidx = 0;
12230 int rxgain = 0;
12231 int txgain = 0;
12232 int change_jitter = 0;
12233
12234 if (strcasecmp(chan->tech->type, misdn_type)) {
12235 ast_log(LOG_WARNING, "misdn_set_opt makes sense only with %s channels!\n", misdn_type);
12236 return -1;
12237 }
12238
12239 if (ast_strlen_zero((char *) data)) {
12240 ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
12241 return -1;
12242 }
12243
12244 parse = ast_strdupa(data);
12245 for (tok = strtok_r(parse, ":", &tokb);
12246 tok;
12247 tok = strtok_r(NULL, ":", &tokb)) {
12248 int neglect = 0;
12249
12250 if (tok[0] == '!') {
12251 neglect = 1;
12252 tok++;
12253 }
12254
12255 switch(tok[0]) {
12256 case 'd' :
12257 ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
12258 chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
12259 break;
12260 case 'n':
12261 chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
12262 ch->bc->nodsp = 1;
12263 break;
12264 case 'j':
12265 chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
12266 tok++;
12267 change_jitter = 1;
12268
12269 switch (tok[0]) {
12270 case 'b':
12271 ch->jb_len = atoi(++tok);
12272 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
12273 break;
12274 case 't' :
12275 ch->jb_upper_threshold = atoi(++tok);
12276 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
12277 break;
12278 case 'n':
12279 ch->bc->nojitter = 1;
12280 chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
12281 break;
12282 default:
12283 ch->jb_len = 4000;
12284 ch->jb_upper_threshold = 0;
12285 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
12286 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
12287 break;
12288 }
12289 break;
12290 case 'v':
12291 tok++;
12292
12293 switch (tok[0]) {
12294 case 'r' :
12295 rxgain = atoi(++tok);
12296 if (rxgain < -8) {
12297 rxgain = -8;
12298 }
12299 if (rxgain > 8) {
12300 rxgain = 8;
12301 }
12302 ch->bc->rxgain = rxgain;
12303 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
12304 break;
12305 case 't':
12306 txgain = atoi(++tok);
12307 if (txgain < -8) {
12308 txgain = -8;
12309 }
12310 if (txgain > 8) {
12311 txgain = 8;
12312 }
12313 ch->bc->txgain = txgain;
12314 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
12315 break;
12316 }
12317 break;
12318 case 'c':
12319 keyidx = atoi(++tok);
12320 {
12321 char keys[4096];
12322 char *key = NULL;
12323 char *tmp = keys;
12324 int i;
12325
12326 misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
12327
12328 for (i = 0; i < keyidx; i++) {
12329 key = strsep(&tmp, ",");
12330 }
12331
12332 if (key) {
12333 ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
12334 }
12335
12336 chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
12337 break;
12338 }
12339 case 'e':
12340 chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
12341
12342 if (neglect) {
12343 chan_misdn_log(1, ch->bc->port, " --> disabled\n");
12344 #ifdef MISDN_1_2
12345 *ch->bc->pipeline = 0;
12346 #else
12347 ch->bc->ec_enable = 0;
12348 #endif
12349 } else {
12350 #ifdef MISDN_1_2
12351 update_pipeline_config(ch->bc);
12352 #else
12353 ch->bc->ec_enable = 1;
12354 ch->bc->orig = ch->originator;
12355 tok++;
12356 if (*tok) {
12357 ch->bc->ec_deftaps = atoi(tok);
12358 }
12359 #endif
12360 }
12361 break;
12362 case 'h':
12363 chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
12364
12365 if (strlen(tok) > 1 && tok[1] == '1') {
12366 chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
12367 if (!ch->bc->hdlc) {
12368 ch->bc->hdlc = 1;
12369 }
12370 }
12371 ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
12372 break;
12373 case 's':
12374 chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
12375 ch->bc->send_dtmf = 1;
12376 break;
12377 case 'f':
12378 chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
12379 ch->faxdetect = 1;
12380 misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
12381 break;
12382 case 'a':
12383 chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
12384 ch->ast_dsp = 1;
12385 break;
12386 case 'p':
12387 chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
12388
12389 if (strstr(tok, "allowed")) {
12390 ch->bc->presentation = 0;
12391 ch->bc->set_presentation = 1;
12392 } else if (strstr(tok, "restricted")) {
12393 ch->bc->presentation = 1;
12394 ch->bc->set_presentation = 1;
12395 } else if (strstr(tok, "not_screened")) {
12396 chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
12397 ch->bc->presentation = 1;
12398 ch->bc->set_presentation = 1;
12399 }
12400 break;
12401 case 'i' :
12402 chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
12403 ch->ignore_dtmf = 1;
12404 break;
12405 default:
12406 break;
12407 }
12408 }
12409
12410 if (change_jitter) {
12411 config_jitterbuffer(ch);
12412 }
12413
12414 if (ch->faxdetect || ch->ast_dsp) {
12415 if (!ch->dsp) {
12416 ch->dsp = ast_dsp_new();
12417 }
12418 if (ch->dsp) {
12419 ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
12420 }
12421 }
12422
12423 if (ch->ast_dsp) {
12424 chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
12425 ch->bc->nodsp = 1;
12426 }
12427
12428 return 0;
12429 }
12430
12431
12432 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len)
12433 {
12434 struct chan_list *ch;
12435 int res;
12436
12437 ch = find_chan_by_bc(bc);
12438 if (!ch) {
12439 return 0;
12440 }
12441
12442 if (ch->jb) {
12443 res = misdn_jb_empty(ch->jb, buf, len);
12444 } else {
12445 res = 0;
12446 }
12447 chan_list_unref(ch, "Done emptying jb");
12448
12449 return res;
12450 }
12451
12452
12453
12454
12455
12456
12457
12458
12459
12460 struct misdn_jb *misdn_jb_init(int size, int upper_threshold)
12461 {
12462 struct misdn_jb *jb;
12463
12464 jb = ast_calloc(1, sizeof(*jb));
12465 if (!jb) {
12466 chan_misdn_log(-1, 0, "No free Mem for jb\n");
12467 return NULL;
12468 }
12469 jb->size = size;
12470 jb->upper_threshold = upper_threshold;
12471
12472
12473
12474
12475
12476 jb->samples = ast_calloc(size, sizeof(*jb->samples));
12477 if (!jb->samples) {
12478 ast_free(jb);
12479 chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
12480 return NULL;
12481 }
12482
12483 jb->ok = ast_calloc(size, sizeof(*jb->ok));
12484 if (!jb->ok) {
12485 ast_free(jb->samples);
12486 ast_free(jb);
12487 chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
12488 return NULL;
12489 }
12490
12491 ast_mutex_init(&jb->mutexjb);
12492
12493 return jb;
12494 }
12495
12496
12497 void misdn_jb_destroy(struct misdn_jb *jb)
12498 {
12499 ast_mutex_destroy(&jb->mutexjb);
12500
12501 ast_free(jb->ok);
12502 ast_free(jb->samples);
12503 ast_free(jb);
12504 }
12505
12506
12507
12508 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
12509 {
12510 int i;
12511 int j;
12512 int rp;
12513 int wp;
12514
12515 if (!jb || ! data) {
12516 return 0;
12517 }
12518
12519 ast_mutex_lock(&jb->mutexjb);
12520
12521 wp = jb->wp;
12522 rp = jb->rp;
12523
12524 for (i = 0; i < len; i++) {
12525 jb->samples[wp] = data[i];
12526 jb->ok[wp] = 1;
12527 wp = (wp != jb->size - 1) ? wp + 1 : 0;
12528
12529 if (wp == jb->rp) {
12530 jb->state_full = 1;
12531 }
12532 }
12533
12534 if (wp >= rp) {
12535 jb->state_buffer = wp - rp;
12536 } else {
12537 jb->state_buffer = jb->size - rp + wp;
12538 }
12539 chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12540
12541 if (jb->state_full) {
12542 jb->wp = wp;
12543
12544 rp = wp;
12545 for (j = 0; j < jb->upper_threshold; j++) {
12546 rp = (rp != 0) ? rp - 1 : jb->size - 1;
12547 }
12548 jb->rp = rp;
12549 jb->state_full = 0;
12550 jb->state_empty = 1;
12551
12552 ast_mutex_unlock(&jb->mutexjb);
12553
12554 return -1;
12555 }
12556
12557 if (!jb->state_empty) {
12558 jb->bytes_wrote += len;
12559 if (jb->bytes_wrote >= jb->upper_threshold) {
12560 jb->state_empty = 1;
12561 jb->bytes_wrote = 0;
12562 }
12563 }
12564 jb->wp = wp;
12565
12566 ast_mutex_unlock(&jb->mutexjb);
12567
12568 return 0;
12569 }
12570
12571
12572
12573
12574 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
12575 {
12576 int i;
12577 int wp;
12578 int rp;
12579 int read = 0;
12580
12581 ast_mutex_lock(&jb->mutexjb);
12582
12583 rp = jb->rp;
12584 wp = jb->wp;
12585
12586 if (jb->state_empty) {
12587 for (i = 0; i < len; i++) {
12588 if (wp == rp) {
12589 jb->rp = rp;
12590 jb->state_empty = 0;
12591
12592 ast_mutex_unlock(&jb->mutexjb);
12593
12594 return read;
12595 } else {
12596 if (jb->ok[rp] == 1) {
12597 data[i] = jb->samples[rp];
12598 jb->ok[rp] = 0;
12599 rp = (rp != jb->size - 1) ? rp + 1 : 0;
12600 read += 1;
12601 }
12602 }
12603 }
12604
12605 if (wp >= rp) {
12606 jb->state_buffer = wp - rp;
12607 } else {
12608 jb->state_buffer = jb->size - rp + wp;
12609 }
12610 chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12611
12612 jb->rp = rp;
12613 } else {
12614 chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
12615 }
12616
12617 ast_mutex_unlock(&jb->mutexjb);
12618
12619 return read;
12620 }
12621
12622
12623
12624
12625
12626 static void chan_misdn_log(int level, int port, char *tmpl, ...)
12627 {
12628 va_list ap;
12629 char buf[1024];
12630 char port_buf[8];
12631
12632 if (!(0 <= port && port <= max_ports)) {
12633 ast_log(LOG_WARNING, "chan_misdn_log called with out-of-range port number! (%d)\n", port);
12634 port = 0;
12635 level = -1;
12636 } else if (!(level == -1
12637 || (misdn_debug_only[port]
12638 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12639 : level <= misdn_debug[port])
12640 || (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)))) {
12641
12642
12643
12644
12645 return;
12646 }
12647
12648 snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
12649 va_start(ap, tmpl);
12650 vsnprintf(buf, sizeof(buf), tmpl, ap);
12651 va_end(ap);
12652
12653 if (level == -1) {
12654 ast_log(LOG_WARNING, "%s", buf);
12655 } else if (misdn_debug_only[port]
12656 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12657 : level <= misdn_debug[port]) {
12658 ast_verbose("%s%s", port_buf, buf);
12659 }
12660
12661 if (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)) {
12662 char ctimebuf[30];
12663 time_t tm;
12664 char *tmp;
12665 char *p;
12666 FILE *fp;
12667
12668 fp = fopen(global_tracefile, "a+");
12669 if (!fp) {
12670 ast_verbose("Error opening Tracefile: [ %s ] %s\n", global_tracefile, strerror(errno));
12671 return;
12672 }
12673
12674 tm = time(NULL);
12675 tmp = ctime_r(&tm, ctimebuf);
12676 p = strchr(tmp, '\n');
12677 if (p) {
12678 *p = ':';
12679 }
12680 fputs(tmp, fp);
12681 fputs(" ", fp);
12682 fputs(port_buf, fp);
12683 fputs(" ", fp);
12684 fputs(buf, fp);
12685
12686 fclose(fp);
12687 }
12688 }
12689
12690 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Channel driver for mISDN Support (BRI/PRI)",
12691 .load = load_module,
12692 .unload = unload_module,
12693 .reload = reload,
12694 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
12695 );