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: 370563 $")
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 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 help->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 continue;
04237 }
04238
04239 if (misdn_debug[0] > 2) {
04240 ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
04241 }
04242 if (bc) {
04243 print_bc_info(a->fd, help, bc);
04244 } else {
04245 if (help->hold.state != MISDN_HOLD_IDLE) {
04246 ast_cli(a->fd, "ITS A HELD CALL BC:\n");
04247 ast_cli(a->fd, " --> l3_id: %x\n"
04248 " --> dialed:%s\n"
04249 " --> caller:\"%s\" <%s>\n"
04250 " --> hold_port: %d\n"
04251 " --> hold_channel: %d\n",
04252 help->l3id,
04253 ast->exten,
04254 S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
04255 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
04256 help->hold.port,
04257 help->hold.channel
04258 );
04259 } else {
04260 ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n",
04261 ast->exten,
04262 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""));
04263 }
04264 }
04265 }
04266 ast_mutex_unlock(&cl_te_lock);
04267
04268 misdn_dump_chanlist();
04269
04270 return CLI_SUCCESS;
04271 }
04272
04273 static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04274 {
04275 struct chan_list *help;
04276
04277 switch (cmd) {
04278 case CLI_INIT:
04279 e->command = "misdn show channel";
04280 e->usage =
04281 "Usage: misdn show channel <channel>\n"
04282 " Show an internal mISDN channel\n.";
04283 return NULL;
04284 case CLI_GENERATE:
04285 return complete_ch(a);
04286 }
04287
04288 if (a->argc != 4) {
04289 return CLI_SHOWUSAGE;
04290 }
04291
04292 ast_mutex_lock(&cl_te_lock);
04293 for (help = cl_te; help; help = help->next) {
04294 struct misdn_bchannel *bc = help->bc;
04295 struct ast_channel *ast = help->ast;
04296
04297 if (bc && ast) {
04298 if (!strcasecmp(ast->name, a->argv[3])) {
04299 print_bc_info(a->fd, help, bc);
04300 break;
04301 }
04302 }
04303 }
04304 ast_mutex_unlock(&cl_te_lock);
04305
04306 return CLI_SUCCESS;
04307 }
04308
04309 static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04310 {
04311 switch (cmd) {
04312 case CLI_INIT:
04313 e->command = "misdn set tics";
04314 e->usage =
04315 "Usage: misdn set tics <value>\n";
04316 return NULL;
04317 case CLI_GENERATE:
04318 return NULL;
04319 }
04320
04321 if (a->argc != 4) {
04322 return CLI_SHOWUSAGE;
04323 }
04324
04325
04326 MAXTICS = atoi(a->argv[3]);
04327
04328 return CLI_SUCCESS;
04329 }
04330
04331 static char *handle_cli_misdn_show_stacks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04332 {
04333 int port;
04334
04335 switch (cmd) {
04336 case CLI_INIT:
04337 e->command = "misdn show stacks";
04338 e->usage =
04339 "Usage: misdn show stacks\n"
04340 " Show internal mISDN stack_list.\n";
04341 return NULL;
04342 case CLI_GENERATE:
04343 return NULL;
04344 }
04345
04346 if (a->argc != 3) {
04347 return CLI_SHOWUSAGE;
04348 }
04349
04350 ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04351 for (port = misdn_cfg_get_next_port(0); port > 0;
04352 port = misdn_cfg_get_next_port(port)) {
04353 char buf[128];
04354
04355 get_show_stack_details(port, buf);
04356 ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04357 }
04358
04359 return CLI_SUCCESS;
04360 }
04361
04362 static char *handle_cli_misdn_show_ports_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04363 {
04364 int port;
04365
04366 switch (cmd) {
04367 case CLI_INIT:
04368 e->command = "misdn show ports stats";
04369 e->usage =
04370 "Usage: misdn show ports stats\n"
04371 " Show mISDNs channel's call statistics per port.\n";
04372 return NULL;
04373 case CLI_GENERATE:
04374 return NULL;
04375 }
04376
04377 if (a->argc != 4) {
04378 return CLI_SHOWUSAGE;
04379 }
04380
04381 ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
04382 for (port = misdn_cfg_get_next_port(0); port > 0;
04383 port = misdn_cfg_get_next_port(port)) {
04384 ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
04385 }
04386 ast_cli(a->fd, "\n");
04387
04388 return CLI_SUCCESS;
04389 }
04390
04391 static char *handle_cli_misdn_show_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04392 {
04393 int port;
04394 char buf[128];
04395
04396 switch (cmd) {
04397 case CLI_INIT:
04398 e->command = "misdn show port";
04399 e->usage =
04400 "Usage: misdn show port <port>\n"
04401 " Show detailed information for given port.\n";
04402 return NULL;
04403 case CLI_GENERATE:
04404 return NULL;
04405 }
04406
04407 if (a->argc != 4) {
04408 return CLI_SHOWUSAGE;
04409 }
04410
04411 port = atoi(a->argv[3]);
04412
04413 ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04414 get_show_stack_details(port, buf);
04415 ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04416
04417 return CLI_SUCCESS;
04418 }
04419
04420 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
04421 static const struct FacParm Fac_Msgs[] = {
04422
04423 [0].Function = Fac_ERROR,
04424 [0].u.ERROR.invokeId = 8,
04425 [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
04426
04427 [1].Function = Fac_RESULT,
04428 [1].u.RESULT.InvokeID = 9,
04429
04430 [2].Function = Fac_REJECT,
04431 [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
04432
04433 [3].Function = Fac_REJECT,
04434 [3].u.REJECT.InvokeIDPresent = 1,
04435 [3].u.REJECT.InvokeID = 10,
04436 [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
04437
04438 [4].Function = Fac_REJECT,
04439 [4].u.REJECT.InvokeIDPresent = 1,
04440 [4].u.REJECT.InvokeID = 11,
04441 [4].u.REJECT.Code = FacReject_Res_MistypedResult,
04442
04443 [5].Function = Fac_REJECT,
04444 [5].u.REJECT.InvokeIDPresent = 1,
04445 [5].u.REJECT.InvokeID = 12,
04446 [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
04447
04448 [6].Function = Fac_StatusRequest,
04449 [6].u.StatusRequest.InvokeID = 13,
04450 [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
04451 [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04452 [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
04453 [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
04454 [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
04455 [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
04456 [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
04457 [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
04458
04459 [7].Function = Fac_StatusRequest,
04460 [7].u.StatusRequest.InvokeID = 14,
04461 [7].u.StatusRequest.ComponentType = FacComponent_Result,
04462 [7].u.StatusRequest.Component.Result.Status = 2,
04463
04464 [8].Function = Fac_CallInfoRetain,
04465 [8].u.CallInfoRetain.InvokeID = 15,
04466 [8].u.CallInfoRetain.CallLinkageID = 115,
04467
04468 [9].Function = Fac_EraseCallLinkageID,
04469 [9].u.EraseCallLinkageID.InvokeID = 16,
04470 [9].u.EraseCallLinkageID.CallLinkageID = 105,
04471
04472 [10].Function = Fac_CCBSDeactivate,
04473 [10].u.CCBSDeactivate.InvokeID = 17,
04474 [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
04475 [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
04476
04477 [11].Function = Fac_CCBSDeactivate,
04478 [11].u.CCBSDeactivate.InvokeID = 18,
04479 [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
04480
04481 [12].Function = Fac_CCBSErase,
04482 [12].u.CCBSErase.InvokeID = 19,
04483 [12].u.CCBSErase.Q931ie.Bc.Length = 2,
04484 [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04485 [12].u.CCBSErase.AddressOfB.Party.Type = 0,
04486 [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
04487 [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
04488 [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04489 [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04490 [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04491 [12].u.CCBSErase.RecallMode = 1,
04492 [12].u.CCBSErase.CCBSReference = 102,
04493 [12].u.CCBSErase.Reason = 3,
04494
04495 [13].Function = Fac_CCBSErase,
04496 [13].u.CCBSErase.InvokeID = 20,
04497 [13].u.CCBSErase.Q931ie.Bc.Length = 2,
04498 [13].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04499 [13].u.CCBSErase.AddressOfB.Party.Type = 1,
04500 [13].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04501 [13].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 1,
04502 [13].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04503 [13].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04504 [13].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04505 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCountPresent = 1,
04506 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCount = 1,
04507 [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04508 [13].u.CCBSErase.RecallMode = 1,
04509 [13].u.CCBSErase.CCBSReference = 102,
04510 [13].u.CCBSErase.Reason = 3,
04511
04512 [14].Function = Fac_CCBSErase,
04513 [14].u.CCBSErase.InvokeID = 21,
04514 [14].u.CCBSErase.Q931ie.Bc.Length = 2,
04515 [14].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04516 [14].u.CCBSErase.AddressOfB.Party.Type = 2,
04517 [14].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04518 [14].u.CCBSErase.AddressOfB.Party.Number = "1803",
04519 [14].u.CCBSErase.AddressOfB.Subaddress.Type = 1,
04520 [14].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04521 [14].u.CCBSErase.AddressOfB.Subaddress.u.Nsap = "6492",
04522 [14].u.CCBSErase.RecallMode = 1,
04523 [14].u.CCBSErase.CCBSReference = 102,
04524 [14].u.CCBSErase.Reason = 3,
04525
04526 [15].Function = Fac_CCBSErase,
04527 [15].u.CCBSErase.InvokeID = 22,
04528 [15].u.CCBSErase.Q931ie.Bc.Length = 2,
04529 [15].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04530 [15].u.CCBSErase.AddressOfB.Party.Type = 3,
04531 [15].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04532 [15].u.CCBSErase.AddressOfB.Party.Number = "1803",
04533 [15].u.CCBSErase.RecallMode = 1,
04534 [15].u.CCBSErase.CCBSReference = 102,
04535 [15].u.CCBSErase.Reason = 3,
04536
04537 [16].Function = Fac_CCBSErase,
04538 [16].u.CCBSErase.InvokeID = 23,
04539 [16].u.CCBSErase.Q931ie.Bc.Length = 2,
04540 [16].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04541 [16].u.CCBSErase.AddressOfB.Party.Type = 4,
04542 [16].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04543 [16].u.CCBSErase.AddressOfB.Party.Number = "1803",
04544 [16].u.CCBSErase.RecallMode = 1,
04545 [16].u.CCBSErase.CCBSReference = 102,
04546 [16].u.CCBSErase.Reason = 3,
04547
04548 [17].Function = Fac_CCBSErase,
04549 [17].u.CCBSErase.InvokeID = 24,
04550 [17].u.CCBSErase.Q931ie.Bc.Length = 2,
04551 [17].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04552 [17].u.CCBSErase.AddressOfB.Party.Type = 5,
04553 [17].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04554 [17].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 4,
04555 [17].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04556 [17].u.CCBSErase.RecallMode = 1,
04557 [17].u.CCBSErase.CCBSReference = 102,
04558 [17].u.CCBSErase.Reason = 3,
04559
04560 [18].Function = Fac_CCBSErase,
04561 [18].u.CCBSErase.InvokeID = 25,
04562 [18].u.CCBSErase.Q931ie.Bc.Length = 2,
04563 [18].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04564 [18].u.CCBSErase.AddressOfB.Party.Type = 8,
04565 [18].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04566 [18].u.CCBSErase.AddressOfB.Party.Number = "1803",
04567 [18].u.CCBSErase.RecallMode = 1,
04568 [18].u.CCBSErase.CCBSReference = 102,
04569 [18].u.CCBSErase.Reason = 3,
04570
04571 [19].Function = Fac_CCBSRemoteUserFree,
04572 [19].u.CCBSRemoteUserFree.InvokeID = 26,
04573 [19].u.CCBSRemoteUserFree.Q931ie.Bc.Length = 2,
04574 [19].u.CCBSRemoteUserFree.Q931ie.Bc.Contents = "JK",
04575 [19].u.CCBSRemoteUserFree.AddressOfB.Party.Type = 8,
04576 [19].u.CCBSRemoteUserFree.AddressOfB.Party.LengthOfNumber = 4,
04577 [19].u.CCBSRemoteUserFree.AddressOfB.Party.Number = "1803",
04578 [19].u.CCBSRemoteUserFree.RecallMode = 1,
04579 [19].u.CCBSRemoteUserFree.CCBSReference = 102,
04580
04581 [20].Function = Fac_CCBSCall,
04582 [20].u.CCBSCall.InvokeID = 27,
04583 [20].u.CCBSCall.CCBSReference = 115,
04584
04585 [21].Function = Fac_CCBSStatusRequest,
04586 [21].u.CCBSStatusRequest.InvokeID = 28,
04587 [21].u.CCBSStatusRequest.ComponentType = FacComponent_Invoke,
04588 [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04589 [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Contents = "JK",
04590 [21].u.CCBSStatusRequest.Component.Invoke.RecallMode = 1,
04591 [21].u.CCBSStatusRequest.Component.Invoke.CCBSReference = 102,
04592
04593 [22].Function = Fac_CCBSStatusRequest,
04594 [22].u.CCBSStatusRequest.InvokeID = 29,
04595 [22].u.CCBSStatusRequest.ComponentType = FacComponent_Result,
04596 [22].u.CCBSStatusRequest.Component.Result.Free = 1,
04597
04598 [23].Function = Fac_CCBSBFree,
04599 [23].u.CCBSBFree.InvokeID = 30,
04600 [23].u.CCBSBFree.Q931ie.Bc.Length = 2,
04601 [23].u.CCBSBFree.Q931ie.Bc.Contents = "JK",
04602 [23].u.CCBSBFree.AddressOfB.Party.Type = 8,
04603 [23].u.CCBSBFree.AddressOfB.Party.LengthOfNumber = 4,
04604 [23].u.CCBSBFree.AddressOfB.Party.Number = "1803",
04605 [23].u.CCBSBFree.RecallMode = 1,
04606 [23].u.CCBSBFree.CCBSReference = 14,
04607
04608 [24].Function = Fac_CCBSStopAlerting,
04609 [24].u.CCBSStopAlerting.InvokeID = 31,
04610 [24].u.CCBSStopAlerting.CCBSReference = 37,
04611
04612 [25].Function = Fac_CCBSRequest,
04613 [25].u.CCBSRequest.InvokeID = 32,
04614 [25].u.CCBSRequest.ComponentType = FacComponent_Invoke,
04615 [25].u.CCBSRequest.Component.Invoke.CallLinkageID = 57,
04616
04617 [26].Function = Fac_CCBSRequest,
04618 [26].u.CCBSRequest.InvokeID = 33,
04619 [26].u.CCBSRequest.ComponentType = FacComponent_Result,
04620 [26].u.CCBSRequest.Component.Result.RecallMode = 1,
04621 [26].u.CCBSRequest.Component.Result.CCBSReference = 102,
04622
04623 [27].Function = Fac_CCBSInterrogate,
04624 [27].u.CCBSInterrogate.InvokeID = 34,
04625 [27].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04626 [27].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04627 [27].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04628 [27].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04629 [27].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04630 [27].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04631
04632 [28].Function = Fac_CCBSInterrogate,
04633 [28].u.CCBSInterrogate.InvokeID = 35,
04634 [28].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04635 [28].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04636 [28].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04637 [28].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04638
04639 [29].Function = Fac_CCBSInterrogate,
04640 [29].u.CCBSInterrogate.InvokeID = 36,
04641 [29].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04642 [29].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04643 [29].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04644
04645 [30].Function = Fac_CCBSInterrogate,
04646 [30].u.CCBSInterrogate.InvokeID = 37,
04647 [30].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04648
04649 [31].Function = Fac_CCBSInterrogate,
04650 [31].u.CCBSInterrogate.InvokeID = 38,
04651 [31].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04652 [31].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04653
04654 [32].Function = Fac_CCBSInterrogate,
04655 [32].u.CCBSInterrogate.InvokeID = 39,
04656 [32].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04657 [32].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04658 [32].u.CCBSInterrogate.Component.Result.NumRecords = 1,
04659 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04660 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04661 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04662 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04663 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04664 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04665 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Type = 1,
04666 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Length = 4,
04667 [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.u.Nsap = "6492",
04668
04669 [33].Function = Fac_CCBSInterrogate,
04670 [33].u.CCBSInterrogate.InvokeID = 40,
04671 [33].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04672 [33].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04673 [33].u.CCBSInterrogate.Component.Result.NumRecords = 2,
04674 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04675 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04676 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04677 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04678 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04679 [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04680 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].CCBSReference = 102,
04681 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Length = 2,
04682 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Contents = "LM",
04683 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Type = 8,
04684 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.LengthOfNumber = 4,
04685 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Number = "6229",
04686 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Type = 1,
04687 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Length = 4,
04688 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.u.Nsap = "8592",
04689 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Type = 1,
04690 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Length = 4,
04691 [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.u.Nsap = "6492",
04692
04693 [34].Function = Fac_CCNRRequest,
04694 [34].u.CCNRRequest.InvokeID = 512,
04695 [34].u.CCNRRequest.ComponentType = FacComponent_Invoke,
04696 [34].u.CCNRRequest.Component.Invoke.CallLinkageID = 57,
04697
04698 [35].Function = Fac_CCNRRequest,
04699 [35].u.CCNRRequest.InvokeID = 150,
04700 [35].u.CCNRRequest.ComponentType = FacComponent_Result,
04701 [35].u.CCNRRequest.Component.Result.RecallMode = 1,
04702 [35].u.CCNRRequest.Component.Result.CCBSReference = 102,
04703
04704 [36].Function = Fac_CCNRInterrogate,
04705 [36].u.CCNRInterrogate.InvokeID = -129,
04706 [36].u.CCNRInterrogate.ComponentType = FacComponent_Invoke,
04707
04708 [37].Function = Fac_CCNRInterrogate,
04709 [37].u.CCNRInterrogate.InvokeID = -3,
04710 [37].u.CCNRInterrogate.ComponentType = FacComponent_Result,
04711 [37].u.CCNRInterrogate.Component.Result.RecallMode = 1,
04712
04713 [38].Function = Fac_CCBS_T_Call,
04714 [38].u.EctExecute.InvokeID = 41,
04715
04716 [39].Function = Fac_CCBS_T_Suspend,
04717 [39].u.EctExecute.InvokeID = 42,
04718
04719 [40].Function = Fac_CCBS_T_Resume,
04720 [40].u.EctExecute.InvokeID = 43,
04721
04722 [41].Function = Fac_CCBS_T_RemoteUserFree,
04723 [41].u.EctExecute.InvokeID = 44,
04724
04725 [42].Function = Fac_CCBS_T_Available,
04726 [42].u.EctExecute.InvokeID = 45,
04727
04728 [43].Function = Fac_CCBS_T_Request,
04729 [43].u.CCBS_T_Request.InvokeID = 46,
04730 [43].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04731 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04732 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04733 [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04734 [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04735 [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04736 [43].u.CCBS_T_Request.Component.Invoke.RetentionSupported = 1,
04737 [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04738 [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04739 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04740 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04741 [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04742
04743 [44].Function = Fac_CCBS_T_Request,
04744 [44].u.CCBS_T_Request.InvokeID = 47,
04745 [44].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04746 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04747 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04748 [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04749 [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04750 [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04751 [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04752 [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04753 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04754 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04755 [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04756
04757 [45].Function = Fac_CCBS_T_Request,
04758 [45].u.CCBS_T_Request.InvokeID = 48,
04759 [45].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04760 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04761 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04762 [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04763 [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04764 [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04765 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04766 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04767 [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04768
04769 [46].Function = Fac_CCBS_T_Request,
04770 [46].u.CCBS_T_Request.InvokeID = 49,
04771 [46].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04772 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04773 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04774 [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04775 [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04776 [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04777 [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04778 [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04779
04780 [47].Function = Fac_CCBS_T_Request,
04781 [47].u.CCBS_T_Request.InvokeID = 50,
04782 [47].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04783 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04784 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04785 [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04786 [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04787 [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04788
04789 [48].Function = Fac_CCBS_T_Request,
04790 [48].u.CCBS_T_Request.InvokeID = 51,
04791 [48].u.CCBS_T_Request.ComponentType = FacComponent_Result,
04792 [48].u.CCBS_T_Request.Component.Result.RetentionSupported = 1,
04793
04794 [49].Function = Fac_CCNR_T_Request,
04795 [49].u.CCNR_T_Request.InvokeID = 52,
04796 [49].u.CCNR_T_Request.ComponentType = FacComponent_Invoke,
04797 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Type = 8,
04798 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04799 [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04800 [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04801 [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04802
04803 [50].Function = Fac_CCNR_T_Request,
04804 [50].u.CCNR_T_Request.InvokeID = 53,
04805 [50].u.CCNR_T_Request.ComponentType = FacComponent_Result,
04806 [50].u.CCNR_T_Request.Component.Result.RetentionSupported = 1,
04807
04808 [51].Function = Fac_EctExecute,
04809 [51].u.EctExecute.InvokeID = 54,
04810
04811 [52].Function = Fac_ExplicitEctExecute,
04812 [52].u.ExplicitEctExecute.InvokeID = 55,
04813 [52].u.ExplicitEctExecute.LinkID = 23,
04814
04815 [53].Function = Fac_RequestSubaddress,
04816 [53].u.RequestSubaddress.InvokeID = 56,
04817
04818 [54].Function = Fac_SubaddressTransfer,
04819 [54].u.SubaddressTransfer.InvokeID = 57,
04820 [54].u.SubaddressTransfer.Subaddress.Type = 1,
04821 [54].u.SubaddressTransfer.Subaddress.Length = 4,
04822 [54].u.SubaddressTransfer.Subaddress.u.Nsap = "6492",
04823
04824 [55].Function = Fac_EctLinkIdRequest,
04825 [55].u.EctLinkIdRequest.InvokeID = 58,
04826 [55].u.EctLinkIdRequest.ComponentType = FacComponent_Invoke,
04827
04828 [56].Function = Fac_EctLinkIdRequest,
04829 [56].u.EctLinkIdRequest.InvokeID = 59,
04830 [56].u.EctLinkIdRequest.ComponentType = FacComponent_Result,
04831 [56].u.EctLinkIdRequest.Component.Result.LinkID = 76,
04832
04833 [57].Function = Fac_EctInform,
04834 [57].u.EctInform.InvokeID = 60,
04835 [57].u.EctInform.Status = 1,
04836 [57].u.EctInform.RedirectionPresent = 1,
04837 [57].u.EctInform.Redirection.Type = 0,
04838 [57].u.EctInform.Redirection.Unscreened.Type = 8,
04839 [57].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04840 [57].u.EctInform.Redirection.Unscreened.Number = "6229",
04841
04842 [58].Function = Fac_EctInform,
04843 [58].u.EctInform.InvokeID = 61,
04844 [58].u.EctInform.Status = 1,
04845 [58].u.EctInform.RedirectionPresent = 1,
04846 [58].u.EctInform.Redirection.Type = 1,
04847
04848 [59].Function = Fac_EctInform,
04849 [59].u.EctInform.InvokeID = 62,
04850 [59].u.EctInform.Status = 1,
04851 [59].u.EctInform.RedirectionPresent = 1,
04852 [59].u.EctInform.Redirection.Type = 2,
04853
04854 [60].Function = Fac_EctInform,
04855 [60].u.EctInform.InvokeID = 63,
04856 [60].u.EctInform.Status = 1,
04857 [60].u.EctInform.RedirectionPresent = 1,
04858 [60].u.EctInform.Redirection.Type = 3,
04859 [60].u.EctInform.Redirection.Unscreened.Type = 8,
04860 [60].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04861 [60].u.EctInform.Redirection.Unscreened.Number = "3340",
04862
04863 [61].Function = Fac_EctInform,
04864 [61].u.EctInform.InvokeID = 64,
04865 [61].u.EctInform.Status = 1,
04866 [61].u.EctInform.RedirectionPresent = 0,
04867
04868 [62].Function = Fac_EctLoopTest,
04869 [62].u.EctLoopTest.InvokeID = 65,
04870 [62].u.EctLoopTest.ComponentType = FacComponent_Invoke,
04871 [62].u.EctLoopTest.Component.Invoke.CallTransferID = 7,
04872
04873 [63].Function = Fac_EctLoopTest,
04874 [63].u.EctLoopTest.InvokeID = 66,
04875 [63].u.EctLoopTest.ComponentType = FacComponent_Result,
04876 [63].u.EctLoopTest.Component.Result.LoopResult = 2,
04877
04878 [64].Function = Fac_ActivationDiversion,
04879 [64].u.ActivationDiversion.InvokeID = 67,
04880 [64].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04881 [64].u.ActivationDiversion.Component.Invoke.Procedure = 2,
04882 [64].u.ActivationDiversion.Component.Invoke.BasicService = 3,
04883 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04884 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04885 [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04886 [64].u.ActivationDiversion.Component.Invoke.ServedUser.Type = 4,
04887 [64].u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber = 4,
04888 [64].u.ActivationDiversion.Component.Invoke.ServedUser.Number = "5398",
04889
04890 [65].Function = Fac_ActivationDiversion,
04891 [65].u.ActivationDiversion.InvokeID = 68,
04892 [65].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04893 [65].u.ActivationDiversion.Component.Invoke.Procedure = 1,
04894 [65].u.ActivationDiversion.Component.Invoke.BasicService = 5,
04895 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04896 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04897 [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04898
04899 [66].Function = Fac_ActivationDiversion,
04900 [66].u.ActivationDiversion.InvokeID = 69,
04901 [66].u.ActivationDiversion.ComponentType = FacComponent_Result,
04902
04903 [67].Function = Fac_DeactivationDiversion,
04904 [67].u.DeactivationDiversion.InvokeID = 70,
04905 [67].u.DeactivationDiversion.ComponentType = FacComponent_Invoke,
04906 [67].u.DeactivationDiversion.Component.Invoke.Procedure = 1,
04907 [67].u.DeactivationDiversion.Component.Invoke.BasicService = 5,
04908
04909 [68].Function = Fac_DeactivationDiversion,
04910 [68].u.DeactivationDiversion.InvokeID = 71,
04911 [68].u.DeactivationDiversion.ComponentType = FacComponent_Result,
04912
04913 [69].Function = Fac_ActivationStatusNotificationDiv,
04914 [69].u.ActivationStatusNotificationDiv.InvokeID = 72,
04915 [69].u.ActivationStatusNotificationDiv.Procedure = 1,
04916 [69].u.ActivationStatusNotificationDiv.BasicService = 5,
04917 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Type = 4,
04918 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.LengthOfNumber = 4,
04919 [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Number = "1803",
04920
04921 [70].Function = Fac_DeactivationStatusNotificationDiv,
04922 [70].u.DeactivationStatusNotificationDiv.InvokeID = 73,
04923 [70].u.DeactivationStatusNotificationDiv.Procedure = 1,
04924 [70].u.DeactivationStatusNotificationDiv.BasicService = 5,
04925
04926 [71].Function = Fac_InterrogationDiversion,
04927 [71].u.InterrogationDiversion.InvokeID = 74,
04928 [71].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04929 [71].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04930 [71].u.InterrogationDiversion.Component.Invoke.BasicService = 5,
04931
04932 [72].Function = Fac_InterrogationDiversion,
04933 [72].u.InterrogationDiversion.InvokeID = 75,
04934 [72].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04935 [72].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04936
04937 [73].Function = Fac_InterrogationDiversion,
04938 [73].u.InterrogationDiversion.InvokeID = 76,
04939 [73].u.InterrogationDiversion.ComponentType = FacComponent_Result,
04940 [73].u.InterrogationDiversion.Component.Result.NumRecords = 2,
04941 [73].u.InterrogationDiversion.Component.Result.List[0].Procedure = 2,
04942 [73].u.InterrogationDiversion.Component.Result.List[0].BasicService = 5,
04943 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Type = 4,
04944 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.LengthOfNumber = 4,
04945 [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Number = "1803",
04946 [73].u.InterrogationDiversion.Component.Result.List[1].Procedure = 1,
04947 [73].u.InterrogationDiversion.Component.Result.List[1].BasicService = 3,
04948 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Type = 4,
04949 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.LengthOfNumber = 4,
04950 [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Number = "1903",
04951 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Type = 4,
04952 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.LengthOfNumber = 4,
04953 [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Number = "5398",
04954
04955 [74].Function = Fac_DiversionInformation,
04956 [74].u.DiversionInformation.InvokeID = 77,
04957 [74].u.DiversionInformation.DiversionReason = 3,
04958 [74].u.DiversionInformation.BasicService = 5,
04959 [74].u.DiversionInformation.ServedUserSubaddress.Type = 1,
04960 [74].u.DiversionInformation.ServedUserSubaddress.Length = 4,
04961 [74].u.DiversionInformation.ServedUserSubaddress.u.Nsap = "6492",
04962 [74].u.DiversionInformation.CallingAddressPresent = 1,
04963 [74].u.DiversionInformation.CallingAddress.Type = 0,
04964 [74].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 3,
04965 [74].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
04966 [74].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
04967 [74].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
04968 [74].u.DiversionInformation.OriginalCalledPresent = 1,
04969 [74].u.DiversionInformation.OriginalCalled.Type = 1,
04970 [74].u.DiversionInformation.LastDivertingPresent = 1,
04971 [74].u.DiversionInformation.LastDiverting.Type = 2,
04972 [74].u.DiversionInformation.LastDivertingReasonPresent = 1,
04973 [74].u.DiversionInformation.LastDivertingReason = 3,
04974 [74].u.DiversionInformation.UserInfo.Length = 5,
04975 [74].u.DiversionInformation.UserInfo.Contents = "79828",
04976
04977 [75].Function = Fac_DiversionInformation,
04978 [75].u.DiversionInformation.InvokeID = 78,
04979 [75].u.DiversionInformation.DiversionReason = 3,
04980 [75].u.DiversionInformation.BasicService = 5,
04981 [75].u.DiversionInformation.CallingAddressPresent = 1,
04982 [75].u.DiversionInformation.CallingAddress.Type = 1,
04983 [75].u.DiversionInformation.OriginalCalledPresent = 1,
04984 [75].u.DiversionInformation.OriginalCalled.Type = 2,
04985 [75].u.DiversionInformation.LastDivertingPresent = 1,
04986 [75].u.DiversionInformation.LastDiverting.Type = 1,
04987
04988 [76].Function = Fac_DiversionInformation,
04989 [76].u.DiversionInformation.InvokeID = 79,
04990 [76].u.DiversionInformation.DiversionReason = 2,
04991 [76].u.DiversionInformation.BasicService = 3,
04992 [76].u.DiversionInformation.CallingAddressPresent = 1,
04993 [76].u.DiversionInformation.CallingAddress.Type = 2,
04994
04995 [77].Function = Fac_DiversionInformation,
04996 [77].u.DiversionInformation.InvokeID = 80,
04997 [77].u.DiversionInformation.DiversionReason = 3,
04998 [77].u.DiversionInformation.BasicService = 5,
04999 [77].u.DiversionInformation.CallingAddressPresent = 1,
05000 [77].u.DiversionInformation.CallingAddress.Type = 3,
05001 [77].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 2,
05002 [77].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
05003 [77].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
05004 [77].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
05005
05006 [78].Function = Fac_DiversionInformation,
05007 [78].u.DiversionInformation.InvokeID = 81,
05008 [78].u.DiversionInformation.DiversionReason = 2,
05009 [78].u.DiversionInformation.BasicService = 4,
05010 [78].u.DiversionInformation.UserInfo.Length = 5,
05011 [78].u.DiversionInformation.UserInfo.Contents = "79828",
05012
05013 [79].Function = Fac_DiversionInformation,
05014 [79].u.DiversionInformation.InvokeID = 82,
05015 [79].u.DiversionInformation.DiversionReason = 2,
05016 [79].u.DiversionInformation.BasicService = 4,
05017
05018 [80].Function = Fac_CallDeflection,
05019 [80].u.CallDeflection.InvokeID = 83,
05020 [80].u.CallDeflection.ComponentType = FacComponent_Invoke,
05021 [80].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05022 [80].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05023 [80].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05024 [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05025 [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 1,
05026
05027 [81].Function = Fac_CallDeflection,
05028 [81].u.CallDeflection.InvokeID = 84,
05029 [81].u.CallDeflection.ComponentType = FacComponent_Invoke,
05030 [81].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05031 [81].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05032 [81].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05033 [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05034 [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0,
05035
05036 [82].Function = Fac_CallDeflection,
05037 [82].u.CallDeflection.InvokeID = 85,
05038 [82].u.CallDeflection.ComponentType = FacComponent_Invoke,
05039 [82].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05040 [82].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05041 [82].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05042
05043 [83].Function = Fac_CallDeflection,
05044 [83].u.CallDeflection.InvokeID = 86,
05045 [83].u.CallDeflection.ComponentType = FacComponent_Result,
05046
05047 [84].Function = Fac_CallRerouteing,
05048 [84].u.CallRerouteing.InvokeID = 87,
05049 [84].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05050 [84].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05051 [84].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05052 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05053 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05054 [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05055 [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05056 [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05057 [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 3,
05058 [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Contents = "RTG",
05059 [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 2,
05060 [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Contents = "MY",
05061 [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 5,
05062 [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Contents = "YEHAW",
05063 [84].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05064 [84].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05065 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Type = 1,
05066 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 4,
05067 [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.u.Nsap = "6492",
05068
05069 [85].Function = Fac_CallRerouteing,
05070 [85].u.CallRerouteing.InvokeID = 88,
05071 [85].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05072 [85].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05073 [85].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05074 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05075 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05076 [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05077 [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05078 [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05079 [85].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05080 [85].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05081
05082 [86].Function = Fac_CallRerouteing,
05083 [86].u.CallRerouteing.InvokeID = 89,
05084 [86].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05085 [86].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05086 [86].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05087 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05088 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05089 [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05090 [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05091 [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05092 [86].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 2,
05093
05094 [87].Function = Fac_CallRerouteing,
05095 [87].u.CallRerouteing.InvokeID = 90,
05096 [87].u.CallRerouteing.ComponentType = FacComponent_Result,
05097
05098 [88].Function = Fac_InterrogateServedUserNumbers,
05099 [88].u.InterrogateServedUserNumbers.InvokeID = 91,
05100 [88].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Invoke,
05101
05102 [89].Function = Fac_InterrogateServedUserNumbers,
05103 [89].u.InterrogateServedUserNumbers.InvokeID = 92,
05104 [89].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Result,
05105 [89].u.InterrogateServedUserNumbers.Component.Result.NumRecords = 2,
05106 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Type = 4,
05107 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].LengthOfNumber = 4,
05108 [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Number = "1803",
05109 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Type = 4,
05110 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].LengthOfNumber = 4,
05111 [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Number = "5786",
05112
05113 [90].Function = Fac_DivertingLegInformation1,
05114 [90].u.DivertingLegInformation1.InvokeID = 93,
05115 [90].u.DivertingLegInformation1.DiversionReason = 4,
05116 [90].u.DivertingLegInformation1.SubscriptionOption = 1,
05117 [90].u.DivertingLegInformation1.DivertedToPresent = 1,
05118 [90].u.DivertingLegInformation1.DivertedTo.Type = 2,
05119
05120 [91].Function = Fac_DivertingLegInformation1,
05121 [91].u.DivertingLegInformation1.InvokeID = 94,
05122 [91].u.DivertingLegInformation1.DiversionReason = 4,
05123 [91].u.DivertingLegInformation1.SubscriptionOption = 1,
05124
05125 [92].Function = Fac_DivertingLegInformation2,
05126 [92].u.DivertingLegInformation2.InvokeID = 95,
05127 [92].u.DivertingLegInformation2.DiversionCounter = 3,
05128 [92].u.DivertingLegInformation2.DiversionReason = 2,
05129 [92].u.DivertingLegInformation2.DivertingPresent = 1,
05130 [92].u.DivertingLegInformation2.Diverting.Type = 2,
05131 [92].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05132 [92].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05133
05134 [93].Function = Fac_DivertingLegInformation2,
05135 [93].u.DivertingLegInformation2.InvokeID = 96,
05136 [93].u.DivertingLegInformation2.DiversionCounter = 3,
05137 [93].u.DivertingLegInformation2.DiversionReason = 2,
05138 [93].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05139 [93].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05140
05141 [94].Function = Fac_DivertingLegInformation2,
05142 [94].u.DivertingLegInformation2.InvokeID = 97,
05143 [94].u.DivertingLegInformation2.DiversionCounter = 1,
05144 [94].u.DivertingLegInformation2.DiversionReason = 2,
05145
05146 [95].Function = Fac_DivertingLegInformation3,
05147 [95].u.DivertingLegInformation3.InvokeID = 98,
05148 [95].u.DivertingLegInformation3.PresentationAllowedIndicator = 1,
05149
05150 };
05151 #endif
05152
05153 static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05154 {
05155 const char *channame;
05156 const char *nr;
05157 struct chan_list *tmp;
05158 int port;
05159 const char *served_nr;
05160 struct misdn_bchannel dummy, *bc=&dummy;
05161 unsigned max_len;
05162
05163 switch (cmd) {
05164 case CLI_INIT:
05165 e->command = "misdn send facility";
05166 e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
05167 "\t type is one of:\n"
05168 "\t - calldeflect\n"
05169 #if defined(AST_MISDN_ENHANCEMENTS)
05170 "\t - callrerouting\n"
05171 #endif
05172 "\t - CFActivate\n"
05173 "\t - CFDeactivate\n";
05174
05175 return NULL;
05176 case CLI_GENERATE:
05177 return complete_ch(a);
05178 }
05179
05180 if (a->argc < 5) {
05181 return CLI_SHOWUSAGE;
05182 }
05183
05184 if (strstr(a->argv[3], "calldeflect")) {
05185 if (a->argc < 6) {
05186 ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
05187 return 0;
05188 }
05189 channame = a->argv[4];
05190 nr = a->argv[5];
05191
05192 ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
05193 tmp = get_chan_by_ast_name(channame);
05194 if (!tmp) {
05195 ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05196 return 0;
05197 }
05198 ao2_lock(tmp);
05199
05200 #if defined(AST_MISDN_ENHANCEMENTS)
05201 max_len = sizeof(tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
05202 if (max_len < strlen(nr)) {
05203 ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05204 nr, channame, max_len);
05205 ao2_unlock(tmp);
05206 chan_list_unref(tmp, "Number too long");
05207 return 0;
05208 }
05209 tmp->bc->fac_out.Function = Fac_CallDeflection;
05210 tmp->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
05211 tmp->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
05212 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
05213 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
05214 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;
05215 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(nr);
05216 strcpy((char *) tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, nr);
05217 tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
05218
05219 #else
05220
05221 max_len = sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
05222 if (max_len < strlen(nr)) {
05223 ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05224 nr, channame, max_len);
05225 ao2_unlock(tmp);
05226 chan_list_unref(tmp, "Number too long");
05227 return 0;
05228 }
05229 tmp->bc->fac_out.Function = Fac_CD;
05230 tmp->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
05231
05232 strcpy((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr);
05233 #endif
05234
05235
05236 print_facility(&tmp->bc->fac_out, tmp->bc);
05237 ao2_unlock(tmp);
05238 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05239 chan_list_unref(tmp, "Send facility complete");
05240 #if defined(AST_MISDN_ENHANCEMENTS)
05241 } else if (strstr(a->argv[3], "callrerouteing") || strstr(a->argv[3], "callrerouting")) {
05242 if (a->argc < 6) {
05243 ast_verbose("callrerouting requires 1 arg: ToNumber\n\n");
05244 return 0;
05245 }
05246 channame = a->argv[4];
05247 nr = a->argv[5];
05248
05249 ast_verbose("Sending Callrerouting (%s) to %s\n", nr, channame);
05250 tmp = get_chan_by_ast_name(channame);
05251 if (!tmp) {
05252 ast_verbose("Sending Call Rerouting with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05253 return 0;
05254 }
05255 ao2_lock(tmp);
05256
05257 max_len = sizeof(tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
05258 if (max_len < strlen(nr)) {
05259 ast_verbose("Sending Call Rerouting with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05260 nr, channame, max_len);
05261 ao2_unlock(tmp);
05262 chan_list_unref(tmp, "Number too long");
05263 return 0;
05264 }
05265 tmp->bc->fac_out.Function = Fac_CallRerouteing;
05266 tmp->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
05267 tmp->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
05268
05269 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;
05270 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
05271
05272 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;
05273 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(nr);
05274 strcpy((char *) tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, nr);
05275 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
05276
05277 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
05278
05279
05280 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
05281 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
05282 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
05283 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
05284 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
05285 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
05286 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
05287
05288 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;
05289 tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;
05290
05291
05292 print_facility(&tmp->bc->fac_out, tmp->bc);
05293 ao2_unlock(tmp);
05294 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05295 chan_list_unref(tmp, "Send facility complete");
05296 #endif
05297 } else if (strstr(a->argv[3], "CFActivate")) {
05298 if (a->argc < 7) {
05299 ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
05300 return 0;
05301 }
05302 port = atoi(a->argv[4]);
05303 served_nr = a->argv[5];
05304 nr = a->argv[6];
05305
05306 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05307
05308 ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
05309
05310 #if defined(AST_MISDN_ENHANCEMENTS)
05311 bc->fac_out.Function = Fac_ActivationDiversion;
05312 bc->fac_out.u.ActivationDiversion.InvokeID = ++misdn_invoke_id;
05313 bc->fac_out.u.ActivationDiversion.ComponentType = FacComponent_Invoke;
05314 bc->fac_out.u.ActivationDiversion.Component.Invoke.BasicService = 0;
05315 bc->fac_out.u.ActivationDiversion.Component.Invoke.Procedure = 0;
05316 ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number,
05317 served_nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number));
05318 bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05319 strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number);
05320 bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Type = 0;
05321 ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number,
05322 nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number));
05323 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber =
05324 strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number);
05325 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 0;
05326 bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Subaddress.Length = 0;
05327
05328 #else
05329
05330 bc->fac_out.Function = Fac_CFActivate;
05331 bc->fac_out.u.CFActivate.BasicService = 0;
05332 bc->fac_out.u.CFActivate.Procedure = 0;
05333 ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05334 ast_copy_string((char *) bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));
05335 #endif
05336
05337
05338 print_facility(&bc->fac_out, bc);
05339 misdn_lib_send_event(bc, EVENT_FACILITY);
05340 } else if (strstr(a->argv[3], "CFDeactivate")) {
05341 if (a->argc < 6) {
05342 ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
05343 return 0;
05344 }
05345 port = atoi(a->argv[4]);
05346 served_nr = a->argv[5];
05347
05348 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05349 ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr);
05350
05351 #if defined(AST_MISDN_ENHANCEMENTS)
05352 bc->fac_out.Function = Fac_DeactivationDiversion;
05353 bc->fac_out.u.DeactivationDiversion.InvokeID = ++misdn_invoke_id;
05354 bc->fac_out.u.DeactivationDiversion.ComponentType = FacComponent_Invoke;
05355 bc->fac_out.u.DeactivationDiversion.Component.Invoke.BasicService = 0;
05356 bc->fac_out.u.DeactivationDiversion.Component.Invoke.Procedure = 0;
05357 ast_copy_string((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number,
05358 served_nr, sizeof(bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number));
05359 bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05360 strlen((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number);
05361 bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Type = 0;
05362
05363 #else
05364
05365 bc->fac_out.Function = Fac_CFDeactivate;
05366 bc->fac_out.u.CFDeactivate.BasicService = 0;
05367 bc->fac_out.u.CFDeactivate.Procedure = 0;
05368 ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05369 #endif
05370
05371
05372 print_facility(&bc->fac_out, bc);
05373 misdn_lib_send_event(bc, EVENT_FACILITY);
05374 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
05375 } else if (strstr(a->argv[3], "test")) {
05376 int msg_number;
05377
05378 if (a->argc < 5) {
05379 ast_verbose("test (<port> [<msg#>]) | (<channel-name> <msg#>)\n\n");
05380 return 0;
05381 }
05382 port = atoi(a->argv[4]);
05383
05384 channame = a->argv[4];
05385 tmp = get_chan_by_ast_name(channame);
05386 if (tmp) {
05387
05388 msg_number = atoi(a->argv[5]);
05389 if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05390 ao2_lock(tmp);
05391 tmp->bc->fac_out = Fac_Msgs[msg_number];
05392
05393
05394 print_facility(&tmp->bc->fac_out, tmp->bc);
05395 ao2_unlock(tmp);
05396 misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05397 } else {
05398 ast_verbose("test <channel-name> <msg#>\n\n");
05399 }
05400 chan_list_unref(tmp, "Facility test done");
05401 } else if (a->argc < 6) {
05402 for (msg_number = 0; msg_number < ARRAY_LEN(Fac_Msgs); ++msg_number) {
05403 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05404 bc->fac_out = Fac_Msgs[msg_number];
05405
05406
05407 print_facility(&bc->fac_out, bc);
05408 misdn_lib_send_event(bc, EVENT_FACILITY);
05409 sleep(1);
05410 }
05411 } else {
05412 msg_number = atoi(a->argv[5]);
05413 if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05414 misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05415 bc->fac_out = Fac_Msgs[msg_number];
05416
05417
05418 print_facility(&bc->fac_out, bc);
05419 misdn_lib_send_event(bc, EVENT_FACILITY);
05420 } else {
05421 ast_verbose("test <port> [<msg#>]\n\n");
05422 }
05423 }
05424 } else if (strstr(a->argv[3], "register")) {
05425 if (a->argc < 5) {
05426 ast_verbose("register <port>\n\n");
05427 return 0;
05428 }
05429 port = atoi(a->argv[4]);
05430
05431 bc = misdn_lib_get_register_bc(port);
05432 if (!bc) {
05433 ast_verbose("Could not allocate REGISTER bc struct\n\n");
05434 return 0;
05435 }
05436 bc->fac_out = Fac_Msgs[45];
05437
05438
05439 print_facility(&bc->fac_out, bc);
05440 misdn_lib_send_event(bc, EVENT_REGISTER);
05441 #endif
05442 }
05443
05444 return CLI_SUCCESS;
05445 }
05446
05447 static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05448 {
05449 int port;
05450 int channel;
05451
05452 switch (cmd) {
05453 case CLI_INIT:
05454 e->command = "misdn send restart";
05455 e->usage =
05456 "Usage: misdn send restart [port [channel]]\n"
05457 " Send a restart for every bchannel on the given port.\n";
05458 return NULL;
05459 case CLI_GENERATE:
05460 return NULL;
05461 }
05462
05463 if (a->argc < 4 || a->argc > 5) {
05464 return CLI_SHOWUSAGE;
05465 }
05466
05467 port = atoi(a->argv[3]);
05468
05469 if (a->argc == 5) {
05470 channel = atoi(a->argv[4]);
05471 misdn_lib_send_restart(port, channel);
05472 } else {
05473 misdn_lib_send_restart(port, -1);
05474 }
05475
05476 return CLI_SUCCESS;
05477 }
05478
05479 static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05480 {
05481 const char *channame;
05482 const char *msg;
05483 struct chan_list *tmp;
05484 int i, msglen;
05485
05486 switch (cmd) {
05487 case CLI_INIT:
05488 e->command = "misdn send digit";
05489 e->usage =
05490 "Usage: misdn send digit <channel> \"<msg>\" \n"
05491 " Send <digit> to <channel> as DTMF Tone\n"
05492 " when channel is a mISDN channel\n";
05493 return NULL;
05494 case CLI_GENERATE:
05495 return complete_ch(a);
05496 }
05497
05498 if (a->argc != 5) {
05499 return CLI_SHOWUSAGE;
05500 }
05501
05502 channame = a->argv[3];
05503 msg = a->argv[4];
05504 msglen = strlen(msg);
05505
05506 ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05507
05508 tmp = get_chan_by_ast_name(channame);
05509 if (!tmp) {
05510 ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
05511 return CLI_SUCCESS;
05512 }
05513 #if 1
05514 for (i = 0; i < msglen; i++) {
05515 if (!tmp->ast) {
05516 break;
05517 }
05518 ast_cli(a->fd, "Sending: %c\n", msg[i]);
05519 send_digit_to_chan(tmp, msg[i]);
05520
05521 usleep(250000);
05522
05523 }
05524 #else
05525 if (tmp->ast) {
05526 ast_dtmf_stream(tmp->ast, NULL, msg, 250);
05527 }
05528 #endif
05529 chan_list_unref(tmp, "Digit(s) sent");
05530
05531 return CLI_SUCCESS;
05532 }
05533
05534 static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05535 {
05536 const char *channame;
05537 struct chan_list *tmp;
05538
05539 switch (cmd) {
05540 case CLI_INIT:
05541 e->command = "misdn toggle echocancel";
05542 e->usage =
05543 "Usage: misdn toggle echocancel <channel>\n"
05544 " Toggle EchoCancel on mISDN Channel.\n";
05545 return NULL;
05546 case CLI_GENERATE:
05547 return complete_ch(a);
05548 }
05549
05550 if (a->argc != 4) {
05551 return CLI_SHOWUSAGE;
05552 }
05553
05554 channame = a->argv[3];
05555
05556 ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
05557
05558 tmp = get_chan_by_ast_name(channame);
05559 if (!tmp) {
05560 ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
05561 return CLI_SUCCESS;
05562 }
05563
05564 tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
05565
05566 if (tmp->toggle_ec) {
05567 #ifdef MISDN_1_2
05568 update_pipeline_config(tmp->bc);
05569 #else
05570 update_ec_config(tmp->bc);
05571 #endif
05572 manager_ec_enable(tmp->bc);
05573 } else {
05574 manager_ec_disable(tmp->bc);
05575 }
05576 chan_list_unref(tmp, "Done toggling echo cancel");
05577
05578 return CLI_SUCCESS;
05579 }
05580
05581 static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05582 {
05583 const char *channame;
05584 const char *msg;
05585 struct chan_list *tmp;
05586
05587 switch (cmd) {
05588 case CLI_INIT:
05589 e->command = "misdn send display";
05590 e->usage =
05591 "Usage: misdn send display <channel> \"<msg>\" \n"
05592 " Send <msg> to <channel> as Display Message\n"
05593 " when channel is a mISDN channel\n";
05594 return NULL;
05595 case CLI_GENERATE:
05596 return complete_ch(a);
05597 }
05598
05599 if (a->argc != 5) {
05600 return CLI_SHOWUSAGE;
05601 }
05602
05603 channame = a->argv[3];
05604 msg = a->argv[4];
05605
05606 ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05607
05608 tmp = get_chan_by_ast_name(channame);
05609 if (tmp && tmp->bc) {
05610 ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
05611 misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
05612 chan_list_unref(tmp, "Done sending display");
05613 } else {
05614 if (tmp) {
05615 chan_list_unref(tmp, "Display failed");
05616 }
05617 ast_cli(a->fd, "No such channel %s\n", channame);
05618 return CLI_SUCCESS;
05619 }
05620
05621 return CLI_SUCCESS;
05622 }
05623
05624 static char *complete_ch(struct ast_cli_args *a)
05625 {
05626 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05627 }
05628
05629 static char *complete_debug_port(struct ast_cli_args *a)
05630 {
05631 if (a->n) {
05632 return NULL;
05633 }
05634
05635 switch (a->pos) {
05636 case 4:
05637 if (a->word[0] == 'p') {
05638 return ast_strdup("port");
05639 } else if (a->word[0] == 'o') {
05640 return ast_strdup("only");
05641 }
05642 break;
05643 case 6:
05644 if (a->word[0] == 'o') {
05645 return ast_strdup("only");
05646 }
05647 break;
05648 }
05649 return NULL;
05650 }
05651
05652 static char *complete_show_config(struct ast_cli_args *a)
05653 {
05654 char buffer[BUFFERSIZE];
05655 enum misdn_cfg_elements elem;
05656 int wordlen = strlen(a->word);
05657 int which = 0;
05658 int port = 0;
05659
05660 switch (a->pos) {
05661 case 3:
05662 if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) {
05663 return ast_strdup("description");
05664 }
05665 if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) {
05666 return ast_strdup("descriptions");
05667 }
05668 if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) {
05669 return ast_strdup("0");
05670 }
05671 while ((port = misdn_cfg_get_next_port(port)) != -1) {
05672 snprintf(buffer, sizeof(buffer), "%d", port);
05673 if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
05674 return ast_strdup(buffer);
05675 }
05676 }
05677 break;
05678 case 4:
05679 if (strstr(a->line, "description ")) {
05680 for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
05681 if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) {
05682 continue;
05683 }
05684 misdn_cfg_get_name(elem, buffer, sizeof(buffer));
05685 if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
05686 if (++which > a->n) {
05687 return ast_strdup(buffer);
05688 }
05689 }
05690 }
05691 } else if (strstr(a->line, "descriptions ")) {
05692 if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) {
05693 return ast_strdup("general");
05694 }
05695 if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) {
05696 return ast_strdup("ports");
05697 }
05698 }
05699 break;
05700 }
05701 return NULL;
05702 }
05703
05704 static struct ast_cli_entry chan_misdn_clis[] = {
05705
05706 AST_CLI_DEFINE(handle_cli_misdn_port_block, "Block the given port"),
05707 AST_CLI_DEFINE(handle_cli_misdn_port_down, "Try to deactivate the L1 on the given port"),
05708 AST_CLI_DEFINE(handle_cli_misdn_port_unblock, "Unblock the given port"),
05709 AST_CLI_DEFINE(handle_cli_misdn_port_up, "Try to establish L1 on the given port"),
05710 AST_CLI_DEFINE(handle_cli_misdn_reload, "Reload internal mISDN config, read from the config file"),
05711 AST_CLI_DEFINE(handle_cli_misdn_restart_pid, "Restart the given pid"),
05712 AST_CLI_DEFINE(handle_cli_misdn_restart_port, "Restart the given port"),
05713 AST_CLI_DEFINE(handle_cli_misdn_show_channel, "Show an internal mISDN channel"),
05714 AST_CLI_DEFINE(handle_cli_misdn_show_channels, "Show the internal mISDN channel list"),
05715 AST_CLI_DEFINE(handle_cli_misdn_show_config, "Show internal mISDN config, read from the config file"),
05716 AST_CLI_DEFINE(handle_cli_misdn_show_port, "Show detailed information for given port"),
05717 AST_CLI_DEFINE(handle_cli_misdn_show_ports_stats, "Show mISDNs channel's call statistics per port"),
05718 AST_CLI_DEFINE(handle_cli_misdn_show_stacks, "Show internal mISDN stack_list"),
05719 AST_CLI_DEFINE(handle_cli_misdn_send_facility, "Sends a Facility Message to the mISDN Channel"),
05720 AST_CLI_DEFINE(handle_cli_misdn_send_digit, "Send DTMF digit to mISDN Channel"),
05721 AST_CLI_DEFINE(handle_cli_misdn_send_display, "Send Text to mISDN Channel"),
05722 AST_CLI_DEFINE(handle_cli_misdn_send_restart, "Send a restart for every bchannel on the given port"),
05723 AST_CLI_DEFINE(handle_cli_misdn_set_crypt_debug, "Set CryptDebuglevel of chan_misdn, at the moment, level={1,2}"),
05724 AST_CLI_DEFINE(handle_cli_misdn_set_debug, "Set Debuglevel of chan_misdn"),
05725 AST_CLI_DEFINE(handle_cli_misdn_set_tics, "???"),
05726 AST_CLI_DEFINE(handle_cli_misdn_toggle_echocancel, "Toggle EchoCancel on mISDN Channel"),
05727
05728 };
05729
05730
05731 static void update_config(struct chan_list *ch)
05732 {
05733 struct ast_channel *ast;
05734 struct misdn_bchannel *bc;
05735 int port;
05736 int hdlc = 0;
05737 int pres;
05738 int screen;
05739
05740 if (!ch) {
05741 ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05742 return;
05743 }
05744
05745 ast = ch->ast;
05746 bc = ch->bc;
05747 if (! ast || ! bc) {
05748 ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05749 return;
05750 }
05751
05752 port = bc->port;
05753
05754 chan_misdn_log(7, port, "update_config: Getting Config\n");
05755
05756 misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
05757 if (hdlc) {
05758 switch (bc->capability) {
05759 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05760 case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05761 chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05762 bc->hdlc = 1;
05763 break;
05764 }
05765 }
05766
05767
05768 misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
05769 misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
05770 chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
05771
05772 if (pres < 0 || screen < 0) {
05773 chan_misdn_log(2, port, " --> pres: %x\n", ast->connected.id.number.presentation);
05774
05775 bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
05776 chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
05777
05778 bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
05779 chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
05780 } else {
05781 bc->caller.screening = screen;
05782 bc->caller.presentation = pres;
05783 }
05784 }
05785
05786
05787 static void config_jitterbuffer(struct chan_list *ch)
05788 {
05789 struct misdn_bchannel *bc = ch->bc;
05790 int len = ch->jb_len;
05791 int threshold = ch->jb_upper_threshold;
05792
05793 chan_misdn_log(5, bc->port, "config_jb: Called\n");
05794
05795 if (!len) {
05796 chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
05797 bc->nojitter = 1;
05798 } else {
05799 if (len <= 100 || len > 8000) {
05800 chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
05801 len = 1000;
05802 }
05803
05804 if (threshold > len) {
05805 chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
05806 }
05807
05808 if (ch->jb) {
05809 cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
05810 misdn_jb_destroy(ch->jb);
05811 ch->jb = NULL;
05812 }
05813
05814 ch->jb = misdn_jb_init(len, threshold);
05815
05816 if (!ch->jb) {
05817 bc->nojitter = 1;
05818 }
05819 }
05820 }
05821
05822
05823 void debug_numtype(int port, int numtype, char *type)
05824 {
05825 switch (numtype) {
05826 case NUMTYPE_UNKNOWN:
05827 chan_misdn_log(2, port, " --> %s: Unknown\n", type);
05828 break;
05829 case NUMTYPE_INTERNATIONAL:
05830 chan_misdn_log(2, port, " --> %s: International\n", type);
05831 break;
05832 case NUMTYPE_NATIONAL:
05833 chan_misdn_log(2, port, " --> %s: National\n", type);
05834 break;
05835 case NUMTYPE_NETWORK_SPECIFIC:
05836 chan_misdn_log(2, port, " --> %s: Network Specific\n", type);
05837 break;
05838 case NUMTYPE_SUBSCRIBER:
05839 chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
05840 break;
05841 case NUMTYPE_ABBREVIATED:
05842 chan_misdn_log(2, port, " --> %s: Abbreviated\n", type);
05843 break;
05844
05845 default:
05846 chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
05847 break;
05848 }
05849 }
05850
05851
05852 #ifdef MISDN_1_2
05853 static int update_pipeline_config(struct misdn_bchannel *bc)
05854 {
05855 int ec;
05856
05857 misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline));
05858
05859 if (*bc->pipeline) {
05860 return 0;
05861 }
05862
05863 misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05864 if (ec == 1) {
05865 ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline));
05866 } else if (ec > 1) {
05867 snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec);
05868 }
05869
05870 return 0;
05871 }
05872 #else
05873 static int update_ec_config(struct misdn_bchannel *bc)
05874 {
05875 int ec;
05876 int port = bc->port;
05877
05878 misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05879
05880 if (ec == 1) {
05881 bc->ec_enable = 1;
05882 } else if (ec > 1) {
05883 bc->ec_enable = 1;
05884 bc->ec_deftaps = ec;
05885 }
05886
05887 return 0;
05888 }
05889 #endif
05890
05891
05892 static int read_config(struct chan_list *ch)
05893 {
05894 struct ast_channel *ast;
05895 struct misdn_bchannel *bc;
05896 int port;
05897 int hdlc = 0;
05898 char lang[BUFFERSIZE + 1];
05899 char faxdetect[BUFFERSIZE + 1];
05900 char buf[256];
05901 char buf2[256];
05902 ast_group_t pg;
05903 ast_group_t cg;
05904
05905 if (!ch) {
05906 ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05907 return -1;
05908 }
05909
05910 ast = ch->ast;
05911 bc = ch->bc;
05912 if (! ast || ! bc) {
05913 ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05914 return -1;
05915 }
05916
05917 port = bc->port;
05918 chan_misdn_log(1, port, "read_config: Getting Config\n");
05919
05920 misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
05921 ast_string_field_set(ast, language, lang);
05922
05923 misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
05924
05925 misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(bc->txgain));
05926 misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(bc->rxgain));
05927
05928 misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));
05929
05930 misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
05931
05932 misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
05933 if (ch->ast_dsp) {
05934 ch->ignore_dtmf = 1;
05935 }
05936
05937 misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos));
05938 misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(ch->nttimeout));
05939
05940 misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(ch->noautorespond_on_setup));
05941
05942 misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(ch->far_alerting));
05943
05944 misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, sizeof(ch->allowed_bearers));
05945
05946 misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
05947
05948 misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
05949 if (hdlc) {
05950 switch (bc->capability) {
05951 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05952 case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05953 chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05954 bc->hdlc = 1;
05955 break;
05956 }
05957
05958 }
05959
05960 misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
05961 misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(ch->jb_upper_threshold));
05962
05963 config_jitterbuffer(ch);
05964
05965 misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
05966
05967 ast_copy_string(ast->context, ch->context, sizeof(ast->context));
05968
05969 #ifdef MISDN_1_2
05970 update_pipeline_config(bc);
05971 #else
05972 update_ec_config(bc);
05973 #endif
05974
05975 misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
05976
05977 misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected));
05978 misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup));
05979 misdn_cfg_get(port, MISDN_CFG_OUTGOING_COLP, &bc->outgoing_colp, sizeof(bc->outgoing_colp));
05980
05981 misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
05982 misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
05983 chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
05984 ast->pickupgroup = pg;
05985 ast->callgroup = cg;
05986
05987 if (ch->originator == ORG_AST) {
05988 char callerid[BUFFERSIZE + 1];
05989
05990
05991
05992 misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel));
05993
05994 if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
05995 ch->faxdetect = strstr(faxdetect, "nojump") ? 2 : 1;
05996 }
05997
05998 misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
05999 if (!ast_strlen_zero(callerid)) {
06000 char *cid_name = NULL;
06001 char *cid_num = NULL;
06002
06003 ast_callerid_parse(callerid, &cid_name, &cid_num);
06004 if (cid_name) {
06005 ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name));
06006 } else {
06007 bc->caller.name[0] = '\0';
06008 }
06009 if (cid_num) {
06010 ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number));
06011 } else {
06012 bc->caller.number[0] = '\0';
06013 }
06014 chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number);
06015 }
06016
06017 misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type));
06018 bc->dialed.number_plan = NUMPLAN_ISDN;
06019 debug_numtype(port, bc->dialed.number_type, "TON");
06020
06021 ch->overlap_dial = 0;
06022 } else {
06023
06024
06025 if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
06026 ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
06027 }
06028
06029
06030 misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number));
06031
06032 if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) {
06033 ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number));
06034 }
06035
06036
06037 misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
06038
06039 ast_copy_string(ast->exten, bc->dialed.number, sizeof(ast->exten));
06040
06041 misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
06042 ast_mutex_init(&ch->overlap_tv_lock);
06043 }
06044
06045 misdn_cfg_get(port, MISDN_CFG_INCOMING_CALLERID_TAG, bc->incoming_cid_tag, sizeof(bc->incoming_cid_tag));
06046 if (!ast_strlen_zero(bc->incoming_cid_tag)) {
06047 chan_misdn_log(1, port, " --> * Setting incoming caller id tag to \"%s\"\n", bc->incoming_cid_tag);
06048 }
06049 ch->overlap_dial_task = -1;
06050
06051 if (ch->faxdetect || ch->ast_dsp) {
06052 misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
06053 if (!ch->dsp) {
06054 ch->dsp = ast_dsp_new();
06055 }
06056 if (ch->dsp) {
06057 ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | (ch->faxdetect ? DSP_FEATURE_FAX_DETECT : 0));
06058 }
06059 }
06060
06061
06062 bc->AOCDtype = Fac_None;
06063
06064 return 0;
06065 }
06066
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077
06078 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)
06079 {
06080 struct ast_party_connected_line connected;
06081 struct ast_set_party_connected_line update_connected;
06082
06083 ast_party_connected_line_init(&connected);
06084 memset(&update_connected, 0, sizeof(update_connected));
06085 update_connected.id.number = 1;
06086 connected.id.number.valid = 1;
06087 connected.id.number.str = (char *) id->number;
06088 connected.id.number.plan = misdn_to_ast_ton(id->number_type)
06089 | misdn_to_ast_plan(id->number_plan);
06090 connected.id.number.presentation = misdn_to_ast_pres(id->presentation)
06091 | misdn_to_ast_screen(id->screening);
06092 connected.id.tag = cid_tag;
06093 connected.source = source;
06094 ast_channel_queue_connected_line_update(ast, &connected, &update_connected);
06095 }
06096
06097
06098
06099
06100
06101
06102
06103
06104
06105
06106
06107 static void misdn_update_caller_id(struct ast_channel *ast, const struct misdn_party_id *id, char *cid_tag)
06108 {
06109 struct ast_party_caller caller;
06110 struct ast_set_party_caller update_caller;
06111
06112 memset(&update_caller, 0, sizeof(update_caller));
06113 update_caller.id.number = 1;
06114 update_caller.ani.number = 1;
06115
06116 ast_channel_lock(ast);
06117 ast_party_caller_set_init(&caller, &ast->caller);
06118
06119 caller.id.number.valid = 1;
06120 caller.id.number.str = (char *) id->number;
06121 caller.id.number.plan = misdn_to_ast_ton(id->number_type)
06122 | misdn_to_ast_plan(id->number_plan);
06123 caller.id.number.presentation = misdn_to_ast_pres(id->presentation)
06124 | misdn_to_ast_screen(id->screening);
06125
06126 caller.ani.number = caller.id.number;
06127
06128 caller.id.tag = cid_tag;
06129 caller.ani.tag = cid_tag;
06130
06131 ast_channel_set_caller_event(ast, &caller, &update_caller);
06132 ast_channel_unlock(ast);
06133 }
06134
06135
06136
06137
06138
06139
06140
06141
06142
06143
06144
06145
06146 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)
06147 {
06148 misdn_update_caller_id(ast, id, cid_tag);
06149 misdn_queue_connected_line_update(ast, id, source, cid_tag);
06150 }
06151
06152
06153
06154
06155
06156
06157
06158
06159
06160
06161
06162 static void misdn_get_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06163 {
06164 int number_type;
06165
06166 if (originator == ORG_MISDN) {
06167
06168
06169 ast_copy_string(bc->connected.name,
06170 S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
06171 sizeof(bc->connected.name));
06172 if (ast->connected.id.number.valid) {
06173 ast_copy_string(bc->connected.number, S_OR(ast->connected.id.number.str, ""),
06174 sizeof(bc->connected.number));
06175 bc->connected.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
06176 bc->connected.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
06177 bc->connected.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06178 bc->connected.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06179 } else {
06180 bc->connected.number[0] = '\0';
06181 bc->connected.presentation = 0;
06182 bc->connected.screening = 0;
06183 bc->connected.number_type = NUMTYPE_UNKNOWN;
06184 bc->connected.number_plan = NUMPLAN_UNKNOWN;
06185 }
06186
06187 misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type));
06188 if (0 <= number_type) {
06189
06190 bc->connected.number_type = number_type;
06191 bc->connected.number_plan = NUMPLAN_ISDN;
06192 }
06193 debug_numtype(bc->port, bc->connected.number_type, "CTON");
06194 } else {
06195
06196
06197 ast_copy_string(bc->caller.name,
06198 S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
06199 sizeof(bc->caller.name));
06200 if (ast->connected.id.number.valid) {
06201 ast_copy_string(bc->caller.number, S_OR(ast->connected.id.number.str, ""),
06202 sizeof(bc->caller.number));
06203 bc->caller.presentation = ast_to_misdn_pres(ast->connected.id.number.presentation);
06204 bc->caller.screening = ast_to_misdn_screen(ast->connected.id.number.presentation);
06205 bc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06206 bc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06207 } else {
06208 bc->caller.number[0] = '\0';
06209 bc->caller.presentation = 0;
06210 bc->caller.screening = 0;
06211 bc->caller.number_type = NUMTYPE_UNKNOWN;
06212 bc->caller.number_plan = NUMPLAN_UNKNOWN;
06213 }
06214
06215 misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06216 if (0 <= number_type) {
06217
06218 bc->caller.number_type = number_type;
06219 bc->caller.number_plan = NUMPLAN_ISDN;
06220 }
06221 debug_numtype(bc->port, bc->caller.number_type, "LTON");
06222 }
06223 }
06224
06225
06226
06227
06228
06229
06230
06231
06232
06233
06234
06235 static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06236 {
06237 struct chan_list *ch;
06238
06239 misdn_get_connected_line(ast, bc, originator);
06240 if (originator == ORG_MISDN) {
06241 bc->redirecting.to = bc->connected;
06242 } else {
06243 bc->redirecting.to = bc->caller;
06244 }
06245 switch (bc->outgoing_colp) {
06246 case 1:
06247 bc->redirecting.to.presentation = 1;
06248 break;
06249 case 2:
06250
06251 return;
06252 default:
06253 break;
06254 }
06255
06256 ch = MISDN_ASTERISK_TECH_PVT(ast);
06257 if (ch->state == MISDN_CONNECTED
06258 || originator != ORG_MISDN) {
06259 int is_ptmp;
06260
06261 is_ptmp = !misdn_lib_is_ptp(bc->port);
06262 if (is_ptmp) {
06263
06264
06265
06266
06267
06268
06269 if (!misdn_lib_port_is_nt(bc->port)) {
06270 return;
06271 }
06272 if (ch->state != MISDN_CONNECTED) {
06273
06274 bc->redirecting.to_changed = 1;
06275 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06276 misdn_lib_send_event(bc, EVENT_NOTIFY);
06277 #if defined(AST_MISDN_ENHANCEMENTS)
06278 } else {
06279
06280 bc->redirecting.to_changed = 1;
06281 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06282 bc->fac_out.Function = Fac_RequestSubaddress;
06283 bc->fac_out.u.RequestSubaddress.InvokeID = ++misdn_invoke_id;
06284
06285
06286 print_facility(&bc->fac_out, bc);
06287 misdn_lib_send_event(bc, EVENT_FACILITY);
06288 #endif
06289 }
06290 #if defined(AST_MISDN_ENHANCEMENTS)
06291 } else {
06292
06293 bc->fac_out.Function = Fac_EctInform;
06294 bc->fac_out.u.EctInform.InvokeID = ++misdn_invoke_id;
06295 bc->fac_out.u.EctInform.Status = 1;
06296 bc->fac_out.u.EctInform.RedirectionPresent = 1;
06297 misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.EctInform.Redirection,
06298 &bc->redirecting.to);
06299
06300
06301 print_facility(&bc->fac_out, bc);
06302 misdn_lib_send_event(bc, EVENT_FACILITY);
06303 #endif
06304 }
06305 }
06306 }
06307
06308
06309
06310
06311
06312
06313
06314
06315
06316
06317 static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast)
06318 {
06319 ast_copy_string(bc->redirecting.from.name,
06320 S_COR(ast->redirecting.from.name.valid, ast->redirecting.from.name.str, ""),
06321 sizeof(bc->redirecting.from.name));
06322 if (ast->redirecting.from.number.valid) {
06323 ast_copy_string(bc->redirecting.from.number, S_OR(ast->redirecting.from.number.str, ""),
06324 sizeof(bc->redirecting.from.number));
06325 bc->redirecting.from.presentation = ast_to_misdn_pres(ast->redirecting.from.number.presentation);
06326 bc->redirecting.from.screening = ast_to_misdn_screen(ast->redirecting.from.number.presentation);
06327 bc->redirecting.from.number_type = ast_to_misdn_ton(ast->redirecting.from.number.plan);
06328 bc->redirecting.from.number_plan = ast_to_misdn_plan(ast->redirecting.from.number.plan);
06329 } else {
06330 bc->redirecting.from.number[0] = '\0';
06331 bc->redirecting.from.presentation = 0;
06332 bc->redirecting.from.screening = 0;
06333 bc->redirecting.from.number_type = NUMTYPE_UNKNOWN;
06334 bc->redirecting.from.number_plan = NUMPLAN_UNKNOWN;
06335 }
06336
06337 ast_copy_string(bc->redirecting.to.name,
06338 S_COR(ast->redirecting.to.name.valid, ast->redirecting.to.name.str, ""),
06339 sizeof(bc->redirecting.to.name));
06340 if (ast->redirecting.to.number.valid) {
06341 ast_copy_string(bc->redirecting.to.number, S_OR(ast->redirecting.to.number.str, ""),
06342 sizeof(bc->redirecting.to.number));
06343 bc->redirecting.to.presentation = ast_to_misdn_pres(ast->redirecting.to.number.presentation);
06344 bc->redirecting.to.screening = ast_to_misdn_screen(ast->redirecting.to.number.presentation);
06345 bc->redirecting.to.number_type = ast_to_misdn_ton(ast->redirecting.to.number.plan);
06346 bc->redirecting.to.number_plan = ast_to_misdn_plan(ast->redirecting.to.number.plan);
06347 } else {
06348 bc->redirecting.to.number[0] = '\0';
06349 bc->redirecting.to.presentation = 0;
06350 bc->redirecting.to.screening = 0;
06351 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
06352 bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
06353 }
06354
06355 bc->redirecting.reason = ast_to_misdn_reason(ast->redirecting.reason);
06356 bc->redirecting.count = ast->redirecting.count;
06357 }
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369 static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect, char *tag)
06370 {
06371 struct ast_party_redirecting redirecting;
06372 struct ast_set_party_redirecting update_redirecting;
06373
06374 ast_party_redirecting_set_init(&redirecting, &ast->redirecting);
06375 memset(&update_redirecting, 0, sizeof(update_redirecting));
06376
06377 update_redirecting.from.number = 1;
06378 redirecting.from.number.valid = 1;
06379 redirecting.from.number.str = (char *) redirect->from.number;
06380 redirecting.from.number.plan =
06381 misdn_to_ast_ton(redirect->from.number_type)
06382 | misdn_to_ast_plan(redirect->from.number_plan);
06383 redirecting.from.number.presentation =
06384 misdn_to_ast_pres(redirect->from.presentation)
06385 | misdn_to_ast_screen(redirect->from.screening);
06386 redirecting.from.tag = tag;
06387
06388 update_redirecting.to.number = 1;
06389 redirecting.to.number.valid = 1;
06390 redirecting.to.number.str = (char *) redirect->to.number;
06391 redirecting.to.number.plan =
06392 misdn_to_ast_ton(redirect->to.number_type)
06393 | misdn_to_ast_plan(redirect->to.number_plan);
06394 redirecting.to.number.presentation =
06395 misdn_to_ast_pres(redirect->to.presentation)
06396 | misdn_to_ast_screen(redirect->to.screening);
06397 redirecting.to.tag = tag;
06398
06399 redirecting.reason = misdn_to_ast_reason(redirect->reason);
06400 redirecting.count = redirect->count;
06401
06402 ast_channel_set_redirecting(ast, &redirecting, &update_redirecting);
06403 }
06404
06405
06406
06407
06408
06409
06410
06411
06412
06413
06414
06415 static void misdn_update_redirecting(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06416 {
06417 int is_ptmp;
06418
06419 misdn_copy_redirecting_from_ast(bc, ast);
06420 switch (bc->outgoing_colp) {
06421 case 1:
06422 bc->redirecting.to.presentation = 1;
06423 break;
06424 case 2:
06425
06426 return;
06427 default:
06428 break;
06429 }
06430
06431 if (originator != ORG_MISDN) {
06432 return;
06433 }
06434
06435 is_ptmp = !misdn_lib_is_ptp(bc->port);
06436 if (is_ptmp) {
06437
06438
06439
06440
06441
06442
06443 if (!misdn_lib_port_is_nt(bc->port)) {
06444 return;
06445 }
06446
06447 bc->redirecting.to_changed = 1;
06448 bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_IS_DIVERTING;
06449 misdn_lib_send_event(bc, EVENT_NOTIFY);
06450 #if defined(AST_MISDN_ENHANCEMENTS)
06451 } else {
06452 int match;
06453
06454 match = (strcmp(ast->exten, bc->redirecting.to.number) == 0) ? 1 : 0;
06455 if (!bc->div_leg_3_tx_pending
06456 || !match) {
06457
06458 bc->fac_out.Function = Fac_DivertingLegInformation1;
06459 bc->fac_out.u.DivertingLegInformation1.InvokeID = ++misdn_invoke_id;
06460 bc->fac_out.u.DivertingLegInformation1.DiversionReason =
06461 misdn_to_diversion_reason(bc->redirecting.reason);
06462 bc->fac_out.u.DivertingLegInformation1.SubscriptionOption = 2;
06463 bc->fac_out.u.DivertingLegInformation1.DivertedToPresent = 1;
06464 misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.DivertingLegInformation1.DivertedTo, &bc->redirecting.to);
06465 print_facility(&bc->fac_out, bc);
06466 misdn_lib_send_event(bc, EVENT_FACILITY);
06467 }
06468 bc->div_leg_3_tx_pending = 0;
06469
06470
06471 bc->fac_out.Function = Fac_DivertingLegInformation3;
06472 bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06473 bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06474 bc->redirecting.to.presentation == 0 ? 1 : 0;
06475 print_facility(&bc->fac_out, bc);
06476 misdn_lib_send_event(bc, EVENT_FACILITY);
06477 #endif
06478 }
06479 }
06480
06481
06482
06483
06484
06485
06486 static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
06487 {
06488 int port = 0;
06489 int r;
06490 int exceed;
06491 int number_type;
06492 struct chan_list *ch;
06493 struct misdn_bchannel *newbc;
06494 char *dest_cp;
06495 int append_msn = 0;
06496
06497 AST_DECLARE_APP_ARGS(args,
06498 AST_APP_ARG(intf);
06499 AST_APP_ARG(ext);
06500 AST_APP_ARG(opts);
06501 );
06502
06503 if (!ast) {
06504 ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
06505 return -1;
06506 }
06507
06508 if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest) {
06509 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
06510 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06511 ast_setstate(ast, AST_STATE_DOWN);
06512 return -1;
06513 }
06514
06515 ch = MISDN_ASTERISK_TECH_PVT(ast);
06516 if (!ch) {
06517 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast->name);
06518 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06519 ast_setstate(ast, AST_STATE_DOWN);
06520 return -1;
06521 }
06522
06523 newbc = ch->bc;
06524 if (!newbc) {
06525 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast->name);
06526 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06527 ast_setstate(ast, AST_STATE_DOWN);
06528 return -1;
06529 }
06530
06531 port = newbc->port;
06532
06533 #if defined(AST_MISDN_ENHANCEMENTS)
06534 if ((ch->peer = misdn_cc_caller_get(ast))) {
06535 chan_misdn_log(3, port, " --> Found CC caller data, peer:%s\n",
06536 ch->peer->chan ? "available" : "NULL");
06537 }
06538
06539 if (ch->record_id != -1) {
06540 struct misdn_cc_record *cc_record;
06541
06542
06543 AST_LIST_LOCK(&misdn_cc_records_db);
06544 cc_record = misdn_cc_find_by_id(ch->record_id);
06545 if (!cc_record) {
06546 AST_LIST_UNLOCK(&misdn_cc_records_db);
06547 ast_log(LOG_WARNING, " --> ! misdn_call called on %s, cc_record==NULL\n", ast->name);
06548 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06549 ast_setstate(ast, AST_STATE_DOWN);
06550 return -1;
06551 }
06552
06553
06554 newbc->dialed = cc_record->redial.dialed;
06555 newbc->caller = cc_record->redial.caller;
06556 memset(&newbc->redirecting, 0, sizeof(newbc->redirecting));
06557 newbc->capability = cc_record->redial.capability;
06558 newbc->hdlc = cc_record->redial.hdlc;
06559 newbc->sending_complete = 1;
06560
06561 if (cc_record->ptp) {
06562 newbc->fac_out.Function = Fac_CCBS_T_Call;
06563 newbc->fac_out.u.CCBS_T_Call.InvokeID = ++misdn_invoke_id;
06564 } else {
06565 newbc->fac_out.Function = Fac_CCBSCall;
06566 newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
06567 newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->mode.ptmp.reference_id;
06568 }
06569 AST_LIST_UNLOCK(&misdn_cc_records_db);
06570
06571 ast_copy_string(ast->exten, newbc->dialed.number, sizeof(ast->exten));
06572
06573 chan_misdn_log(1, port, "* Call completion to: %s\n", newbc->dialed.number);
06574 chan_misdn_log(2, port, " --> * tech:%s context:%s\n", ast->name, ast->context);
06575 } else
06576 #endif
06577 {
06578
06579
06580
06581
06582
06583
06584
06585
06586 dest_cp = ast_strdupa(dest);
06587 AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
06588 if (!args.ext) {
06589 args.ext = "";
06590 }
06591
06592 chan_misdn_log(1, port, "* CALL: %s\n", dest);
06593 chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast->name, ast->context);
06594
06595 ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
06596 ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
06597
06598 if (ast_strlen_zero(newbc->caller.name)
06599 && ast->connected.id.name.valid
06600 && !ast_strlen_zero(ast->connected.id.name.str)) {
06601 ast_copy_string(newbc->caller.name, ast->connected.id.name.str, sizeof(newbc->caller.name));
06602 chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06603 }
06604 if (ast_strlen_zero(newbc->caller.number)
06605 && ast->connected.id.number.valid
06606 && !ast_strlen_zero(ast->connected.id.number.str)) {
06607 ast_copy_string(newbc->caller.number, ast->connected.id.number.str, sizeof(newbc->caller.number));
06608 chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06609 }
06610
06611 misdn_cfg_get(port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
06612 if (append_msn) {
06613 strncat(newbc->incoming_cid_tag, "_", sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06614 strncat(newbc->incoming_cid_tag, newbc->caller.number, sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06615 }
06616
06617 ast->caller.id.tag = ast_strdup(newbc->incoming_cid_tag);
06618
06619 misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06620 if (number_type < 0) {
06621 if (ast->connected.id.number.valid) {
06622 newbc->caller.number_type = ast_to_misdn_ton(ast->connected.id.number.plan);
06623 newbc->caller.number_plan = ast_to_misdn_plan(ast->connected.id.number.plan);
06624 } else {
06625 newbc->caller.number_type = NUMTYPE_UNKNOWN;
06626 newbc->caller.number_plan = NUMPLAN_ISDN;
06627 }
06628 } else {
06629
06630 newbc->caller.number_type = number_type;
06631 newbc->caller.number_plan = NUMPLAN_ISDN;
06632 }
06633 debug_numtype(port, newbc->caller.number_type, "LTON");
06634
06635 newbc->capability = ast->transfercapability;
06636 pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
06637 if (ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
06638 chan_misdn_log(2, port, " --> * Call with flag Digital\n");
06639 }
06640
06641
06642 update_config(ch);
06643
06644
06645 import_ch(ast, newbc, ch);
06646
06647
06648 if (!ast_strlen_zero(args.opts)) {
06649 misdn_set_opt_exec(ast, args.opts);
06650 } else {
06651 chan_misdn_log(2, port, "NO OPTS GIVEN\n");
06652 }
06653 if (newbc->set_presentation) {
06654 newbc->caller.presentation = newbc->presentation;
06655 }
06656
06657 misdn_copy_redirecting_from_ast(newbc, ast);
06658 switch (newbc->outgoing_colp) {
06659 case 1:
06660 case 2:
06661 newbc->redirecting.from.presentation = 1;
06662 break;
06663 default:
06664 break;
06665 }
06666 #if defined(AST_MISDN_ENHANCEMENTS)
06667 if (newbc->redirecting.from.number[0] && misdn_lib_is_ptp(port)) {
06668 if (newbc->redirecting.count < 1) {
06669 newbc->redirecting.count = 1;
06670 }
06671
06672
06673 newbc->fac_out.Function = Fac_DivertingLegInformation2;
06674 newbc->fac_out.u.DivertingLegInformation2.InvokeID = ++misdn_invoke_id;
06675 newbc->fac_out.u.DivertingLegInformation2.DivertingPresent = 1;
06676 misdn_PresentedNumberUnscreened_fill(
06677 &newbc->fac_out.u.DivertingLegInformation2.Diverting,
06678 &newbc->redirecting.from);
06679 switch (newbc->outgoing_colp) {
06680 case 2:
06681
06682 newbc->fac_out.u.DivertingLegInformation2.Diverting.Type = 1;
06683
06684
06685 newbc->fac_out.u.DivertingLegInformation2.DiversionCounter = 1;
06686 newbc->fac_out.u.DivertingLegInformation2.DiversionReason = 0;
06687 break;
06688 default:
06689 newbc->fac_out.u.DivertingLegInformation2.DiversionCounter =
06690 newbc->redirecting.count;
06691 newbc->fac_out.u.DivertingLegInformation2.DiversionReason =
06692 misdn_to_diversion_reason(newbc->redirecting.reason);
06693 break;
06694 }
06695 newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 0;
06696 if (1 < newbc->fac_out.u.DivertingLegInformation2.DiversionCounter) {
06697 newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 1;
06698 newbc->fac_out.u.DivertingLegInformation2.OriginalCalled.Type = 2;
06699 }
06700
06701
06702
06703
06704
06705 newbc->div_leg_3_rx_wanted = 1;
06706 }
06707 #endif
06708 }
06709
06710 exceed = add_out_calls(port);
06711 if (exceed != 0) {
06712 char tmp[16];
06713
06714 snprintf(tmp, sizeof(tmp), "%d", exceed);
06715 pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
06716 ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
06717 ast_setstate(ast, AST_STATE_DOWN);
06718 return -1;
06719 }
06720
06721 #if defined(AST_MISDN_ENHANCEMENTS)
06722 if (newbc->fac_out.Function != Fac_None) {
06723 print_facility(&newbc->fac_out, newbc);
06724 }
06725 #endif
06726 r = misdn_lib_send_event(newbc, EVENT_SETUP);
06727
06728
06729 ch->l3id = newbc->l3_id;
06730
06731 if (r == -ENOCHAN) {
06732 chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
06733 chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
06734 ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
06735 ast_setstate(ast, AST_STATE_DOWN);
06736 return -1;
06737 }
06738
06739 chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);
06740
06741 ast_setstate(ast, AST_STATE_DIALING);
06742 ast->hangupcause = AST_CAUSE_NORMAL_CLEARING;
06743
06744 if (newbc->nt) {
06745 stop_bc_tones(ch);
06746 }
06747
06748 ch->state = MISDN_CALLING;
06749
06750 return 0;
06751 }
06752
06753
06754 static int misdn_answer(struct ast_channel *ast)
06755 {
06756 struct chan_list *p;
06757 const char *tmp;
06758
06759 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06760 return -1;
06761 }
06762
06763 chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
06764
06765 if (!p) {
06766 ast_log(LOG_WARNING, " --> Channel not connected ??\n");
06767 ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
06768 }
06769
06770 if (!p->bc) {
06771 chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");
06772
06773 ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR);
06774 }
06775
06776 ast_channel_lock(ast);
06777 tmp = pbx_builtin_getvar_helper(ast, "CRYPT_KEY");
06778 if (!ast_strlen_zero(tmp)) {
06779 chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
06780 ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
06781 } else {
06782 chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
06783 }
06784
06785 tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
06786 if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
06787 chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
06788 p->bc->nodsp = 1;
06789 p->bc->hdlc = 0;
06790 p->bc->nojitter = 1;
06791 }
06792 ast_channel_unlock(ast);
06793
06794 p->state = MISDN_CONNECTED;
06795 stop_indicate(p);
06796
06797 if (ast_strlen_zero(p->bc->connected.number)) {
06798 chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n");
06799 ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number));
06800
06801
06802
06803
06804
06805
06806 p->bc->connected.presentation = p->bc->presentation;
06807 p->bc->connected.screening = 0;
06808 p->bc->connected.number_type = p->bc->dialed.number_type;
06809 p->bc->connected.number_plan = p->bc->dialed.number_plan;
06810 }
06811
06812 switch (p->bc->outgoing_colp) {
06813 case 1:
06814 case 2:
06815 p->bc->connected.presentation = 1;
06816 break;
06817 default:
06818 break;
06819 }
06820
06821 #if defined(AST_MISDN_ENHANCEMENTS)
06822 if (p->bc->div_leg_3_tx_pending) {
06823 p->bc->div_leg_3_tx_pending = 0;
06824
06825
06826 p->bc->fac_out.Function = Fac_DivertingLegInformation3;
06827 p->bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06828 p->bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06829 (p->bc->connected.presentation == 0) ? 1 : 0;
06830 print_facility(&p->bc->fac_out, p->bc);
06831 }
06832 #endif
06833 misdn_lib_send_event(p->bc, EVENT_CONNECT);
06834 start_bc_tones(p);
06835
06836 return 0;
06837 }
06838
06839 static int misdn_digit_begin(struct ast_channel *chan, char digit)
06840 {
06841
06842 return 0;
06843 }
06844
06845 static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
06846 {
06847 struct chan_list *p;
06848 struct misdn_bchannel *bc;
06849 char buf[2] = { digit, 0 };
06850
06851 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06852 return -1;
06853 }
06854
06855 bc = p->bc;
06856 chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
06857
06858 if (!bc) {
06859 ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
06860 return -1;
06861 }
06862
06863 switch (p->state) {
06864 case MISDN_CALLING:
06865 if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
06866 strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
06867 }
06868 break;
06869 case MISDN_CALLING_ACKNOWLEDGE:
06870 ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
06871 if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) {
06872 strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
06873 }
06874 ast_copy_string(p->ast->exten, bc->dialed.number, sizeof(p->ast->exten));
06875 misdn_lib_send_event(bc, EVENT_INFORMATION);
06876 break;
06877 default:
06878 if (bc->send_dtmf) {
06879 send_digit_to_chan(p, digit);
06880 }
06881 break;
06882 }
06883
06884 return 0;
06885 }
06886
06887
06888 static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast)
06889 {
06890 struct chan_list *p;
06891
06892 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06893 return -1;
06894 }
06895
06896 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);
06897
06898 p->ast = ast;
06899
06900 return 0;
06901 }
06902
06903
06904
06905 static int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen)
06906 {
06907 struct chan_list *p;
06908
06909 if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06910 ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
06911 return -1;
06912 }
06913
06914 if (!p->bc) {
06915 if (p->hold.state == MISDN_HOLD_IDLE) {
06916 chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
06917 ast->name);
06918 ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
06919 } else {
06920 chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
06921 cond, ast->name);
06922 }
06923 return -1;
06924 }
06925
06926 chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n\n", cond, ast->name);
06927
06928 switch (cond) {
06929 case AST_CONTROL_BUSY:
06930 chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid);
06931 ast_setstate(ast, AST_STATE_BUSY);
06932
06933 p->bc->out_cause = AST_CAUSE_USER_BUSY;
06934 if (p->state != MISDN_CONNECTED) {
06935 start_bc_tones(p);
06936 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
06937 }
06938 return -1;
06939 case AST_CONTROL_RING:
06940 chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc->pid);
06941 return -1;
06942 case AST_CONTROL_RINGING:
06943 chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc->pid);
06944 switch (p->state) {
06945 case MISDN_ALERTING:
06946 chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc->pid);
06947 break;
06948 case MISDN_CONNECTED:
06949 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);
06950 return -1;
06951 default:
06952 p->state = MISDN_ALERTING;
06953 chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc->pid);
06954 misdn_lib_send_event(p->bc, EVENT_ALERTING);
06955
06956 chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc->pid);
06957 ast_setstate(ast, AST_STATE_RING);
06958
06959 if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) {
06960 chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n");
06961 } else {
06962 return -1;
06963 }
06964 }
06965 break;
06966 case AST_CONTROL_ANSWER:
06967 chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc->pid);
06968 start_bc_tones(p);
06969 break;
06970 case AST_CONTROL_TAKEOFFHOOK:
06971 chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc->pid);
06972 return -1;
06973 case AST_CONTROL_OFFHOOK:
06974 chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc->pid);
06975 return -1;
06976 case AST_CONTROL_FLASH:
06977 chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc->pid);
06978 break;
06979 case AST_CONTROL_PROGRESS:
06980 chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc->pid);
06981 misdn_lib_send_event(p->bc, EVENT_PROGRESS);
06982 break;
06983 case AST_CONTROL_PROCEEDING:
06984 chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc->pid);
06985 misdn_lib_send_event(p->bc, EVENT_PROCEEDING);
06986 break;
06987 case AST_CONTROL_INCOMPLETE:
06988 chan_misdn_log(1, p->bc->port, " --> *\tincomplete pid:%d\n", p->bc->pid);
06989 if (!p->overlap_dial) {
06990
06991 p->bc->out_cause = AST_CAUSE_INVALID_NUMBER_FORMAT;
06992 start_bc_tones(p);
06993 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
06994
06995 if (p->bc->nt) {
06996 hanguptone_indicate(p);
06997 }
06998 }
06999 break;
07000 case AST_CONTROL_CONGESTION:
07001 chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid);
07002
07003 p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
07004 start_bc_tones(p);
07005 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
07006
07007 if (p->bc->nt) {
07008 hanguptone_indicate(p);
07009 }
07010 break;
07011 case -1 :
07012 chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid);
07013
07014 stop_indicate(p);
07015
07016 if (p->state == MISDN_CONNECTED) {
07017 start_bc_tones(p);
07018 }
07019 break;
07020 case AST_CONTROL_HOLD:
07021 ast_moh_start(ast, data, p->mohinterpret);
07022 chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid);
07023 break;
07024 case AST_CONTROL_UNHOLD:
07025 ast_moh_stop(ast);
07026 chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid);
07027 break;
07028 case AST_CONTROL_CONNECTED_LINE:
07029 chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid);
07030 misdn_update_connected_line(ast, p->bc, p->originator);
07031 break;
07032 case AST_CONTROL_REDIRECTING:
07033 chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid);
07034 misdn_update_redirecting(ast, p->bc, p->originator);
07035 break;
07036 default:
07037 chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
07038 return -1;
07039 }
07040
07041 return 0;
07042 }
07043
07044 static int misdn_hangup(struct ast_channel *ast)
07045 {
07046 struct chan_list *p;
07047 struct misdn_bchannel *bc;
07048 const char *var;
07049
07050 if (!ast) {
07051 return -1;
07052 }
07053
07054 ast_debug(1, "misdn_hangup(%s)\n", ast->name);
07055
07056
07057 ast_mutex_lock(&release_lock);
07058 p = MISDN_ASTERISK_TECH_PVT(ast);
07059 if (!p) {
07060 ast_mutex_unlock(&release_lock);
07061 return -1;
07062 }
07063 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
07064
07065 if (!misdn_chan_is_valid(p)) {
07066 ast_mutex_unlock(&release_lock);
07067 chan_list_unref(p, "Release ast_channel reference. Was not active?");
07068 return 0;
07069 }
07070
07071 if (p->hold.state == MISDN_HOLD_IDLE) {
07072 bc = p->bc;
07073 } else {
07074 p->hold.state = MISDN_HOLD_DISCONNECT;
07075 bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
07076 if (!bc) {
07077 chan_misdn_log(4, p->hold.port,
07078 "misdn_hangup: Could not find held bc for (%s)\n", ast->name);
07079 release_chan_early(p);
07080 ast_mutex_unlock(&release_lock);
07081 chan_list_unref(p, "Release ast_channel reference");
07082 return 0;
07083 }
07084 }
07085
07086 if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
07087
07088 ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
07089 release_chan_early(p);
07090 if (bc) {
07091 misdn_lib_release(bc);
07092 }
07093 ast_mutex_unlock(&release_lock);
07094 chan_list_unref(p, "Release ast_channel reference");
07095 return 0;
07096 }
07097 if (!bc) {
07098 ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
07099 misdn_get_ch_state(p), p->l3id);
07100 release_chan_early(p);
07101 ast_mutex_unlock(&release_lock);
07102 chan_list_unref(p, "Release ast_channel reference");
07103 return 0;
07104 }
07105
07106 p->ast = NULL;
07107 p->need_hangup = 0;
07108 p->need_queue_hangup = 0;
07109 p->need_busy = 0;
07110
07111 if (!bc->nt) {
07112 stop_bc_tones(p);
07113 }
07114
07115 bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
07116
07117
07118
07119 var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
07120 if (!var) {
07121 var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
07122 }
07123 if (var) {
07124 int tmpcause;
07125
07126 tmpcause = atoi(var);
07127 bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
07128 }
07129
07130 var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
07131 if (var) {
07132 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
07133 ast_copy_string(bc->uu, var, sizeof(bc->uu));
07134 bc->uulen = strlen(bc->uu);
07135 }
07136
07137
07138 chan_misdn_log(1, bc->port,
07139 "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n",
07140 bc->pid,
07141 ast->context,
07142 ast->exten,
07143 (ast->caller.id.name.valid && ast->caller.id.name.str)
07144 ? ast->caller.id.name.str : "",
07145 (ast->caller.id.number.valid && ast->caller.id.number.str)
07146 ? ast->caller.id.number.str : "",
07147 misdn_get_ch_state(p));
07148 chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
07149 chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
07150 chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
07151
07152 switch (p->state) {
07153 case MISDN_INCOMING_SETUP:
07154
07155
07156
07157
07158 ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
07159 release_chan(p, bc);
07160 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
07161 ast_mutex_unlock(&release_lock);
07162 chan_list_unref(p, "Release ast_channel reference");
07163 return 0;
07164 case MISDN_DIALING:
07165 if (p->hold.state == MISDN_HOLD_IDLE) {
07166 start_bc_tones(p);
07167 hanguptone_indicate(p);
07168 }
07169
07170 if (bc->need_disconnect) {
07171 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07172 }
07173 break;
07174 case MISDN_CALLING_ACKNOWLEDGE:
07175 if (p->hold.state == MISDN_HOLD_IDLE) {
07176 start_bc_tones(p);
07177 hanguptone_indicate(p);
07178 }
07179
07180 if (bc->need_disconnect) {
07181 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07182 }
07183 break;
07184
07185 case MISDN_CALLING:
07186 case MISDN_ALERTING:
07187 case MISDN_PROGRESS:
07188 case MISDN_PROCEEDING:
07189 if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
07190 hanguptone_indicate(p);
07191 }
07192
07193 if (bc->need_disconnect) {
07194 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07195 }
07196 break;
07197 case MISDN_CONNECTED:
07198
07199 if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
07200 start_bc_tones(p);
07201 hanguptone_indicate(p);
07202 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
07203 }
07204 if (bc->need_disconnect) {
07205 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07206 }
07207 break;
07208 case MISDN_DISCONNECTED:
07209 if (bc->need_release) {
07210 misdn_lib_send_event(bc, EVENT_RELEASE);
07211 }
07212 break;
07213
07214 case MISDN_CLEANING:
07215 ast_mutex_unlock(&release_lock);
07216 chan_list_unref(p, "Release ast_channel reference");
07217 return 0;
07218
07219 case MISDN_BUSY:
07220 break;
07221 default:
07222 if (bc->nt) {
07223 bc->out_cause = -1;
07224 if (bc->need_release) {
07225 misdn_lib_send_event(bc, EVENT_RELEASE);
07226 }
07227 } else {
07228 if (bc->need_disconnect) {
07229 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07230 }
07231 }
07232 break;
07233 }
07234
07235 p->state = MISDN_CLEANING;
07236 chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
07237 misdn_get_ch_state(p));
07238
07239 ast_mutex_unlock(&release_lock);
07240 chan_list_unref(p, "Release ast_channel reference");
07241 return 0;
07242 }
07243
07244
07245 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
07246 {
07247 struct ast_frame *f;
07248
07249 if (tmp->dsp) {
07250 f = ast_dsp_process(tmp->ast, tmp->dsp, frame);
07251 } else {
07252 chan_misdn_log(0, tmp->bc->port, "No DSP-Path found\n");
07253 return NULL;
07254 }
07255
07256 if (!f || (f->frametype != AST_FRAME_DTMF)) {
07257 return f;
07258 }
07259
07260 ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass.integer);
07261
07262 if (tmp->faxdetect && (f->subclass.integer == 'f')) {
07263
07264 if (!tmp->faxhandled) {
07265 struct ast_channel *ast = tmp->ast;
07266 tmp->faxhandled++;
07267 chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
07268 tmp->bc->rxgain = 0;
07269 isdn_lib_update_rxgain(tmp->bc);
07270 tmp->bc->txgain = 0;
07271 isdn_lib_update_txgain(tmp->bc);
07272 #ifdef MISDN_1_2
07273 *tmp->bc->pipeline = 0;
07274 #else
07275 tmp->bc->ec_enable = 0;
07276 #endif
07277 isdn_lib_update_ec(tmp->bc);
07278 isdn_lib_stop_dtmf(tmp->bc);
07279 switch (tmp->faxdetect) {
07280 case 1:
07281 if (strcmp(ast->exten, "fax")) {
07282 char *context;
07283 char context_tmp[BUFFERSIZE];
07284 misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
07285 context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
07286 if (ast_exists_extension(ast, context, "fax", 1,
07287 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
07288 ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
07289
07290 pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
07291 if (ast_async_goto(ast, context, "fax", 1)) {
07292 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
07293 }
07294 } else {
07295 ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten);
07296 }
07297 } else {
07298 ast_debug(1, "Already in a fax extension, not redirecting\n");
07299 }
07300 break;
07301 case 2:
07302 ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
07303 break;
07304 default:
07305 break;
07306 }
07307 } else {
07308 ast_debug(1, "Fax already handled\n");
07309 }
07310 }
07311
07312 if (tmp->ast_dsp && (f->subclass.integer != 'f')) {
07313 chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass.integer);
07314 }
07315
07316 return f;
07317 }
07318
07319
07320 static struct ast_frame *misdn_read(struct ast_channel *ast)
07321 {
07322 struct chan_list *tmp;
07323 int len, t;
07324 struct pollfd pfd = { .fd = -1, .events = POLLIN };
07325
07326 if (!ast) {
07327 chan_misdn_log(1, 0, "misdn_read called without ast\n");
07328 return NULL;
07329 }
07330 if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
07331 chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
07332 return NULL;
07333 }
07334
07335 if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
07336 chan_misdn_log(1, 0, "misdn_read called without bc\n");
07337 return NULL;
07338 }
07339
07340 pfd.fd = tmp->pipe[0];
07341 t = ast_poll(&pfd, 1, 20);
07342
07343 if (t < 0) {
07344 chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
07345 return NULL;
07346 }
07347
07348 if (!t) {
07349 chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
07350 len = 160;
07351 } else if (pfd.revents & POLLIN) {
07352 len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
07353
07354 if (len <= 0) {
07355
07356 chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
07357 return NULL;
07358 }
07359 } else {
07360 return NULL;
07361 }
07362
07363 tmp->frame.frametype = AST_FRAME_VOICE;
07364 tmp->frame.subclass.codec = AST_FORMAT_ALAW;
07365 tmp->frame.datalen = len;
07366 tmp->frame.samples = len;
07367 tmp->frame.mallocd = 0;
07368 tmp->frame.offset = 0;
07369 tmp->frame.delivery = ast_tv(0, 0);
07370 tmp->frame.src = NULL;
07371 tmp->frame.data.ptr = tmp->ast_rd_buf;
07372
07373 if (tmp->faxdetect && !tmp->faxhandled) {
07374 if (tmp->faxdetect_timeout) {
07375 if (ast_tvzero(tmp->faxdetect_tv)) {
07376 tmp->faxdetect_tv = ast_tvnow();
07377 chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
07378 return process_ast_dsp(tmp, &tmp->frame);
07379 } else {
07380 struct timeval tv_now = ast_tvnow();
07381 int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
07382 if (diff <= (tmp->faxdetect_timeout * 1000)) {
07383 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
07384 return process_ast_dsp(tmp, &tmp->frame);
07385 } else {
07386 chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
07387 tmp->faxdetect = 0;
07388 return &tmp->frame;
07389 }
07390 }
07391 } else {
07392 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
07393 return process_ast_dsp(tmp, &tmp->frame);
07394 }
07395 } else {
07396 if (tmp->ast_dsp) {
07397 return process_ast_dsp(tmp, &tmp->frame);
07398 } else {
07399 return &tmp->frame;
07400 }
07401 }
07402 }
07403
07404
07405 static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
07406 {
07407 struct chan_list *ch;
07408
07409 if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
07410 return -1;
07411 }
07412
07413 if (ch->hold.state != MISDN_HOLD_IDLE) {
07414 chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
07415 return 0;
07416 }
07417
07418 if (!ch->bc) {
07419 ast_log(LOG_WARNING, "private but no bc\n");
07420 return -1;
07421 }
07422
07423 if (ch->notxtone) {
07424 chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
07425 return 0;
07426 }
07427
07428
07429 if (!frame->subclass.codec) {
07430 chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
07431 return 0;
07432 }
07433
07434 if (!(frame->subclass.codec & prefformat)) {
07435 chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", ast_getformatname(frame->subclass.codec));
07436 return 0;
07437 }
07438
07439
07440 if (!frame->samples) {
07441 chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
07442
07443 if (!strcmp(frame->src,"ast_prod")) {
07444 chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
07445
07446 if (ch->ts) {
07447 chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
07448 misdn_lib_tone_generator_start(ch->bc);
07449 }
07450 return 0;
07451 }
07452
07453 return -1;
07454 }
07455
07456 if (!ch->bc->addr) {
07457 chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
07458 return 0;
07459 }
07460
07461 #ifdef MISDN_DEBUG
07462 {
07463 int i;
07464 int max = 5 > frame->samples ? frame->samples : 5;
07465
07466 ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
07467
07468 for (i = 0; i < max; i++) {
07469 ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]);
07470 }
07471 }
07472 #endif
07473
07474 switch (ch->bc->bc_state) {
07475 case BCHAN_ACTIVATED:
07476 case BCHAN_BRIDGED:
07477 break;
07478 default:
07479 if (!ch->dropped_frame_cnt) {
07480 chan_misdn_log(5, ch->bc->port,
07481 "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n",
07482 frame->samples, ch->bc->addr, ast->exten,
07483 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
07484 misdn_get_ch_state(ch), ch->bc->bc_state, ch->bc->l3_id);
07485 }
07486
07487 if (++ch->dropped_frame_cnt > 100) {
07488 ch->dropped_frame_cnt = 0;
07489 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);
07490 }
07491
07492 return 0;
07493 }
07494
07495 chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
07496 if (!ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability)) {
07497
07498 if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) {
07499 if (ch->bc->active) {
07500 cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
07501 }
07502 }
07503
07504 } else {
07505
07506 misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
07507 }
07508
07509 return 0;
07510 }
07511
07512 static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
07513 struct ast_channel *c1, int flags,
07514 struct ast_frame **fo,
07515 struct ast_channel **rc,
07516 int timeoutms)
07517 {
07518 struct chan_list *ch1, *ch2;
07519 struct ast_channel *carr[2], *who;
07520 int to = -1;
07521 struct ast_frame *f;
07522 int p1_b, p2_b;
07523 int bridging;
07524
07525 ch1 = get_chan_by_ast(c0);
07526 if (!ch1) {
07527 return -1;
07528 }
07529 ch2 = get_chan_by_ast(c1);
07530 if (!ch2) {
07531 chan_list_unref(ch1, "Failed to find ch2");
07532 return -1;
07533 }
07534
07535 carr[0] = c0;
07536 carr[1] = c1;
07537
07538 misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
07539 misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));
07540
07541 if (! p1_b || ! p2_b) {
07542 ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
07543 chan_list_unref(ch1, "Bridge fallback ch1");
07544 chan_list_unref(ch2, "Bridge fallback ch2");
07545 return AST_BRIDGE_FAILED;
07546 }
07547
07548 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
07549 if (bridging) {
07550
07551 chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
07552 misdn_lib_bridge(ch1->bc, ch2->bc);
07553 }
07554
07555 ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
07556
07557 chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n",
07558 ch1->bc->caller.name,
07559 ch1->bc->caller.number,
07560 ch2->bc->caller.name,
07561 ch2->bc->caller.number);
07562
07563 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
07564 ch1->ignore_dtmf = 1;
07565 }
07566
07567 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
07568 ch2->ignore_dtmf = 1;
07569 }
07570
07571 for (;;) {
07572 to = -1;
07573 who = ast_waitfor_n(carr, 2, &to);
07574
07575 if (!who) {
07576 ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
07577 break;
07578 }
07579 f = ast_read(who);
07580
07581 if (!f || f->frametype == AST_FRAME_CONTROL) {
07582
07583
07584 if (!f) {
07585 chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
07586 } else {
07587 chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass.integer);
07588 }
07589
07590 *fo = f;
07591 *rc = who;
07592 break;
07593 }
07594
07595 if (f->frametype == AST_FRAME_DTMF) {
07596 chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass.integer, who->exten);
07597
07598 *fo = f;
07599 *rc = who;
07600 break;
07601 }
07602
07603 #if 0
07604 if (f->frametype == AST_FRAME_VOICE) {
07605 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
07606
07607 continue;
07608 }
07609 #endif
07610
07611 ast_write((who == c0) ? c1 : c0, f);
07612 }
07613
07614 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
07615
07616 misdn_lib_split_bridge(ch1->bc, ch2->bc);
07617
07618 chan_list_unref(ch1, "Bridge complete ch1");
07619 chan_list_unref(ch2, "Bridge complete ch2");
07620 return AST_BRIDGE_COMPLETE;
07621 }
07622
07623
07624
07625 static int dialtone_indicate(struct chan_list *cl)
07626 {
07627 struct ast_channel *ast = cl->ast;
07628 int nd = 0;
07629
07630 if (!ast) {
07631 chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
07632 return -1;
07633 }
07634
07635 misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));
07636
07637 if (nd) {
07638 chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
07639 return 0;
07640 }
07641
07642 chan_misdn_log(3, cl->bc->port, " --> Dial\n");
07643
07644 cl->ts = ast_get_indication_tone(ast->zone, "dial");
07645
07646 if (cl->ts) {
07647 cl->notxtone = 0;
07648 cl->norxtone = 0;
07649
07650 ast_playtones_start(ast, 0, cl->ts->data, 0);
07651 }
07652
07653 return 0;
07654 }
07655
07656 static void hanguptone_indicate(struct chan_list *cl)
07657 {
07658 misdn_lib_send_tone(cl->bc, TONE_HANGUP);
07659 }
07660
07661 static int stop_indicate(struct chan_list *cl)
07662 {
07663 struct ast_channel *ast = cl->ast;
07664
07665 if (!ast) {
07666 chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
07667 return -1;
07668 }
07669
07670 chan_misdn_log(3, cl->bc->port, " --> None\n");
07671 misdn_lib_tone_generator_stop(cl->bc);
07672 ast_playtones_stop(ast);
07673
07674 if (cl->ts) {
07675 cl->ts = ast_tone_zone_sound_unref(cl->ts);
07676 }
07677
07678 return 0;
07679 }
07680
07681
07682 static int start_bc_tones(struct chan_list* cl)
07683 {
07684 misdn_lib_tone_generator_stop(cl->bc);
07685 cl->notxtone = 0;
07686 cl->norxtone = 0;
07687 return 0;
07688 }
07689
07690 static int stop_bc_tones(struct chan_list *cl)
07691 {
07692 if (!cl) {
07693 return -1;
07694 }
07695
07696 cl->notxtone = 1;
07697 cl->norxtone = 1;
07698
07699 return 0;
07700 }
07701
07702
07703
07704
07705
07706
07707
07708
07709
07710 static void chan_list_destructor(void *obj)
07711 {
07712 struct chan_list *ch = obj;
07713
07714 #if defined(AST_MISDN_ENHANCEMENTS)
07715 if (ch->peer) {
07716 ao2_ref(ch->peer, -1);
07717 ch->peer = NULL;
07718 }
07719 #endif
07720
07721 if (ch->dsp) {
07722 ast_dsp_free(ch->dsp);
07723 ch->dsp = NULL;
07724 }
07725
07726
07727 if (ch->jb) {
07728 misdn_jb_destroy(ch->jb);
07729 ch->jb = NULL;
07730 }
07731
07732 if (ch->overlap_dial) {
07733 if (ch->overlap_dial_task != -1) {
07734 misdn_tasks_remove(ch->overlap_dial_task);
07735 ch->overlap_dial_task = -1;
07736 }
07737 ast_mutex_destroy(&ch->overlap_tv_lock);
07738 }
07739
07740 if (-1 < ch->pipe[0]) {
07741 close(ch->pipe[0]);
07742 }
07743 if (-1 < ch->pipe[1]) {
07744 close(ch->pipe[1]);
07745 }
07746 }
07747
07748
07749 static struct chan_list *chan_list_init(int orig)
07750 {
07751 struct chan_list *cl;
07752
07753 cl = ao2_alloc(sizeof(*cl), chan_list_destructor);
07754 if (!cl) {
07755 chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
07756 return NULL;
07757 }
07758
07759 cl->originator = orig;
07760 cl->need_queue_hangup = 1;
07761 cl->need_hangup = 1;
07762 cl->need_busy = 1;
07763 cl->overlap_dial_task = -1;
07764 #if defined(AST_MISDN_ENHANCEMENTS)
07765 cl->record_id = -1;
07766 #endif
07767 cl->pipe[0] = -1;
07768 cl->pipe[1] = -1;
07769
07770 return cl;
07771 }
07772
07773 static struct ast_channel *misdn_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
07774 {
07775 struct ast_channel *ast;
07776 char group[BUFFERSIZE + 1] = "";
07777 char dial_str[128];
07778 char *dest_cp;
07779 char *p = NULL;
07780 int channel = 0;
07781 int port = 0;
07782 struct misdn_bchannel *newbc = NULL;
07783 int dec = 0;
07784 #if defined(AST_MISDN_ENHANCEMENTS)
07785 int cc_retry_call = 0;
07786 long record_id = -1;
07787 struct misdn_cc_record *cc_record;
07788 const char *err_msg;
07789 #endif
07790 struct chan_list *cl;
07791
07792 AST_DECLARE_APP_ARGS(args,
07793 AST_APP_ARG(intf);
07794 AST_APP_ARG(ext);
07795 AST_APP_ARG(opts);
07796 );
07797
07798 snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
07799
07800
07801
07802
07803
07804
07805
07806
07807
07808
07809 dest_cp = ast_strdupa(data);
07810 AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
07811 if (!args.ext) {
07812 args.ext = "";
07813 }
07814
07815 if (!ast_strlen_zero(args.intf)) {
07816 if (args.intf[0] == 'g' && args.intf[1] == ':') {
07817
07818 args.intf += 2;
07819 ast_copy_string(group, args.intf, sizeof(group));
07820 chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
07821 #if defined(AST_MISDN_ENHANCEMENTS)
07822 } else if (strcmp(args.intf, "cc") == 0) {
07823 cc_retry_call = 1;
07824 #endif
07825 } else if ((p = strchr(args.intf, ':'))) {
07826
07827 *p++ = 0;
07828 channel = atoi(p);
07829 port = atoi(args.intf);
07830 chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
07831 } else {
07832 port = atoi(args.intf);
07833 }
07834 } else {
07835 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
07836 return NULL;
07837 }
07838
07839 #if defined(AST_MISDN_ENHANCEMENTS)
07840 if (cc_retry_call) {
07841 if (ast_strlen_zero(args.ext)) {
07842 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT cc-record-id, check extensions.conf\n", dial_str);
07843 return NULL;
07844 }
07845 if (!isdigit(*args.ext)) {
07846 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) cc-record-id must be a number.\n", dial_str);
07847 return NULL;
07848 }
07849 record_id = atol(args.ext);
07850
07851 AST_LIST_LOCK(&misdn_cc_records_db);
07852 cc_record = misdn_cc_find_by_id(record_id);
07853 if (!cc_record) {
07854 AST_LIST_UNLOCK(&misdn_cc_records_db);
07855 err_msg = misdn_cc_record_not_found;
07856 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07857 return NULL;
07858 }
07859 if (!cc_record->activated) {
07860 AST_LIST_UNLOCK(&misdn_cc_records_db);
07861 err_msg = "Call completion has not been activated";
07862 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07863 return NULL;
07864 }
07865 port = cc_record->port;
07866 AST_LIST_UNLOCK(&misdn_cc_records_db);
07867 }
07868 #endif
07869
07870 if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
07871 chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
07872 dec = 1;
07873 }
07874
07875 if (!ast_strlen_zero(group)) {
07876 char cfg_group[BUFFERSIZE + 1];
07877 struct robin_list *rr = NULL;
07878
07879
07880
07881 if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
07882 chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
07883 rr = get_robin_position(group);
07884 }
07885
07886 if (rr) {
07887 int port_start;
07888 int bchan_start;
07889 int port_up;
07890 int check;
07891 int maxbchans;
07892 int wraped = 0;
07893
07894 if (!rr->port) {
07895 rr->port = misdn_cfg_get_next_port_spin(0);
07896 }
07897
07898 if (!rr->channel) {
07899 rr->channel = 1;
07900 }
07901
07902 bchan_start = rr->channel;
07903 port_start = rr->port;
07904 do {
07905 misdn_cfg_get(rr->port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07906 if (strcasecmp(cfg_group, group)) {
07907 wraped = 1;
07908 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07909 rr->channel = 1;
07910 continue;
07911 }
07912
07913 misdn_cfg_get(rr->port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07914 port_up = misdn_lib_port_up(rr->port, check);
07915
07916 if (!port_up) {
07917 chan_misdn_log(1, rr->port, "L1 is not Up on this Port\n");
07918 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07919 rr->channel = 1;
07920 } else if (port_up < 0) {
07921 ast_log(LOG_WARNING, "This port (%d) is blocked\n", rr->port);
07922 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07923 rr->channel = 1;
07924 } else {
07925 chan_misdn_log(4, rr->port, "portup\n");
07926 maxbchans = misdn_lib_get_maxchans(rr->port);
07927
07928 for (;rr->channel <= maxbchans;rr->channel++) {
07929
07930 if (wraped && (rr->port == port_start) && (rr->channel == bchan_start)) {
07931 break;
07932 }
07933
07934 chan_misdn_log(4, rr->port, "Checking channel %d\n", rr->channel);
07935
07936 if ((newbc = misdn_lib_get_free_bc(rr->port, rr->channel, 0, 0))) {
07937 chan_misdn_log(4, rr->port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
07938 rr->channel++;
07939 break;
07940 }
07941 }
07942 if (wraped && (rr->port == port_start) && (rr->channel <= bchan_start)) {
07943 break;
07944 } else if (!newbc || (rr->channel == maxbchans)) {
07945 rr->port = misdn_cfg_get_next_port_spin(rr->port);
07946 rr->channel = 1;
07947 }
07948
07949 }
07950 wraped = 1;
07951 } while (!newbc && (rr->port > 0));
07952 } else {
07953 for (port = misdn_cfg_get_next_port(0); port > 0;
07954 port = misdn_cfg_get_next_port(port)) {
07955 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07956
07957 chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
07958 if (!strcasecmp(cfg_group, group)) {
07959 int port_up;
07960 int check;
07961
07962 misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07963 port_up = misdn_lib_port_up(port, check);
07964
07965 chan_misdn_log(4, port, "portup:%d\n", port_up);
07966
07967 if (port_up > 0) {
07968 newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
07969 if (newbc) {
07970 break;
07971 }
07972 }
07973 }
07974 }
07975 }
07976
07977
07978 if (!newbc) {
07979 ast_log(LOG_WARNING,
07980 "Could not Dial out on group '%s'.\n"
07981 "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
07982 "\tOr there was no free channel on none of the ports\n\n",
07983 group);
07984 return NULL;
07985 }
07986 } else {
07987
07988 if (channel) {
07989 chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
07990 }
07991 newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
07992 if (!newbc) {
07993 ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str);
07994 return NULL;
07995 }
07996 }
07997
07998
07999 cl = chan_list_init(ORG_AST);
08000 if (!cl) {
08001 misdn_lib_release(newbc);
08002 ast_log(LOG_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
08003 return NULL;
08004 }
08005 cl->bc = newbc;
08006
08007 ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, requestor ? requestor->linkedid : NULL, port, channel);
08008 if (!ast) {
08009 chan_list_unref(cl, "Failed to create a new channel");
08010 misdn_lib_release(newbc);
08011 ast_log(LOG_ERROR, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
08012 return NULL;
08013 }
08014
08015 #if defined(AST_MISDN_ENHANCEMENTS)
08016 cl->record_id = record_id;
08017 #endif
08018
08019
08020 cl_queue_chan(cl);
08021
08022
08023 read_config(cl);
08024
08025
08026 cl->need_hangup = 0;
08027
08028 chan_list_unref(cl, "Successful misdn_request()");
08029 return ast;
08030 }
08031
08032
08033 static int misdn_send_text(struct ast_channel *chan, const char *text)
08034 {
08035 struct chan_list *tmp = MISDN_ASTERISK_TECH_PVT(chan);
08036
08037 if (tmp && tmp->bc) {
08038 ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
08039 misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
08040 } else {
08041 ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
08042 return -1;
08043 }
08044
08045 return 0;
08046 }
08047
08048 static struct ast_channel_tech misdn_tech = {
08049 .type = misdn_type,
08050 .description = "Channel driver for mISDN Support (Bri/Pri)",
08051 .capabilities = AST_FORMAT_ALAW ,
08052 .requester = misdn_request,
08053 .send_digit_begin = misdn_digit_begin,
08054 .send_digit_end = misdn_digit_end,
08055 .call = misdn_call,
08056 .bridge = misdn_bridge,
08057 .hangup = misdn_hangup,
08058 .answer = misdn_answer,
08059 .read = misdn_read,
08060 .write = misdn_write,
08061 .indicate = misdn_indication,
08062 .fixup = misdn_fixup,
08063 .send_text = misdn_send_text,
08064 .properties = 0,
08065 };
08066
08067 static struct ast_channel_tech misdn_tech_wo_bridge = {
08068 .type = misdn_type,
08069 .description = "Channel driver for mISDN Support (Bri/Pri)",
08070 .capabilities = AST_FORMAT_ALAW ,
08071 .requester = misdn_request,
08072 .send_digit_begin = misdn_digit_begin,
08073 .send_digit_end = misdn_digit_end,
08074 .call = misdn_call,
08075 .hangup = misdn_hangup,
08076 .answer = misdn_answer,
08077 .read = misdn_read,
08078 .write = misdn_write,
08079 .indicate = misdn_indication,
08080 .fixup = misdn_fixup,
08081 .send_text = misdn_send_text,
08082 .properties = 0,
08083 };
08084
08085
08086 static int glob_channel = 0;
08087
08088 static void update_name(struct ast_channel *tmp, int port, int c)
08089 {
08090 int chan_offset = 0;
08091 int tmp_port = misdn_cfg_get_next_port(0);
08092 char newname[255];
08093
08094 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08095 if (tmp_port == port) {
08096 break;
08097 }
08098 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08099 }
08100 if (c < 0) {
08101 c = 0;
08102 }
08103
08104 snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
08105 if (strncmp(tmp->name, newname, strlen(newname))) {
08106 snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
08107 ast_change_name(tmp, newname);
08108 chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
08109 }
08110 }
08111
08112 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)
08113 {
08114 struct ast_channel *tmp;
08115 char *cid_name = NULL;
08116 char *cid_num = NULL;
08117 int chan_offset = 0;
08118 int tmp_port = misdn_cfg_get_next_port(0);
08119 int bridging;
08120
08121 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08122 if (tmp_port == port) {
08123 break;
08124 }
08125 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08126 }
08127 if (c < 0) {
08128 c = 0;
08129 }
08130
08131 if (callerid) {
08132 ast_callerid_parse(callerid, &cid_name, &cid_num);
08133 }
08134
08135 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++);
08136 if (tmp) {
08137 chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
08138
08139 tmp->nativeformats = prefformat;
08140
08141 tmp->readformat = format;
08142 tmp->rawreadformat = format;
08143 tmp->writeformat = format;
08144 tmp->rawwriteformat = format;
08145
08146
08147 chan_list_ref(chlist, "Give a reference to ast_channel");
08148 MISDN_ASTERISK_TECH_PVT(tmp) = chlist;
08149 chlist->ast = tmp;
08150
08151 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
08152 tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge;
08153
08154 tmp->writeformat = format;
08155 tmp->readformat = format;
08156 tmp->priority = 1;
08157
08158 if (exten) {
08159 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
08160 } else {
08161 chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
08162 }
08163
08164 if (!ast_strlen_zero(cid_num)) {
08165
08166
08167 tmp->caller.ani.number.valid = 1;
08168 tmp->caller.ani.number.str = ast_strdup(cid_num);
08169 }
08170
08171 if (pipe(chlist->pipe) < 0) {
08172 ast_log(LOG_ERROR, "Pipe failed\n");
08173 }
08174 ast_channel_set_fd(tmp, 0, chlist->pipe[0]);
08175
08176 tmp->rings = (state == AST_STATE_RING) ? 1 : 0;
08177
08178 ast_jb_configure(tmp, misdn_get_global_jbconf());
08179 } else {
08180 chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
08181 }
08182
08183 return tmp;
08184 }
08185
08186
08187 static struct chan_list *find_chan_by_bc(struct misdn_bchannel *bc)
08188 {
08189 struct chan_list *help;
08190
08191 ast_mutex_lock(&cl_te_lock);
08192 for (help = cl_te; help; help = help->next) {
08193 if (help->bc == bc) {
08194 chan_list_ref(help, "Found chan_list by bc");
08195 ast_mutex_unlock(&cl_te_lock);
08196 return help;
08197 }
08198 }
08199 ast_mutex_unlock(&cl_te_lock);
08200
08201 chan_misdn_log(6, bc->port,
08202 "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08203 bc->dialed.number,
08204 bc->caller.name,
08205 bc->caller.number);
08206
08207 return NULL;
08208 }
08209
08210
08211 static struct chan_list *find_hold_call(struct misdn_bchannel *bc)
08212 {
08213 struct chan_list *help;
08214
08215 if (bc->pri) {
08216 return NULL;
08217 }
08218
08219 chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d dialed:%s caller:\"%s\" <%s>\n",
08220 bc->channel,
08221 bc->dialed.number,
08222 bc->caller.name,
08223 bc->caller.number);
08224 ast_mutex_lock(&cl_te_lock);
08225 for (help = cl_te; help; help = help->next) {
08226 chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
08227 if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port) {
08228 chan_list_ref(help, "Found chan_list hold call");
08229 ast_mutex_unlock(&cl_te_lock);
08230 return help;
08231 }
08232 }
08233 ast_mutex_unlock(&cl_te_lock);
08234 chan_misdn_log(6, bc->port,
08235 "$$$ find_hold_call: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08236 bc->dialed.number,
08237 bc->caller.name,
08238 bc->caller.number);
08239
08240 return NULL;
08241 }
08242
08243
08244
08245 static struct chan_list *find_hold_call_l3(unsigned long l3_id)
08246 {
08247 struct chan_list *help;
08248
08249 ast_mutex_lock(&cl_te_lock);
08250 for (help = cl_te; help; help = help->next) {
08251 if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id) {
08252 chan_list_ref(help, "Found chan_list hold call l3");
08253 ast_mutex_unlock(&cl_te_lock);
08254 return help;
08255 }
08256 }
08257 ast_mutex_unlock(&cl_te_lock);
08258
08259 return NULL;
08260 }
08261
08262 #define TRANSFER_ON_HELD_CALL_HANGUP 1
08263 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
08264
08265
08266
08267
08268
08269
08270
08271
08272
08273
08274
08275
08276
08277
08278
08279 static struct chan_list *find_hold_active_call(struct misdn_bchannel *bc)
08280 {
08281 struct chan_list *list;
08282
08283 ast_mutex_lock(&cl_te_lock);
08284 for (list = cl_te; list; list = list->next) {
08285 if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
08286 && list->ast) {
08287 switch (list->state) {
08288 case MISDN_PROCEEDING:
08289 case MISDN_PROGRESS:
08290 case MISDN_ALERTING:
08291 case MISDN_CONNECTED:
08292 chan_list_ref(list, "Found chan_list hold active call");
08293 ast_mutex_unlock(&cl_te_lock);
08294 return list;
08295 default:
08296 break;
08297 }
08298 }
08299 }
08300 ast_mutex_unlock(&cl_te_lock);
08301 return NULL;
08302 }
08303 #endif
08304
08305 static void cl_queue_chan(struct chan_list *chan)
08306 {
08307 chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
08308
08309 chan_list_ref(chan, "Adding chan_list to list");
08310 ast_mutex_lock(&cl_te_lock);
08311 chan->next = NULL;
08312 if (!cl_te) {
08313
08314 cl_te = chan;
08315 } else {
08316 struct chan_list *help;
08317
08318
08319 for (help = cl_te; help->next; help = help->next) {
08320 }
08321 help->next = chan;
08322 }
08323 ast_mutex_unlock(&cl_te_lock);
08324 }
08325
08326 static int cl_dequeue_chan(struct chan_list *chan)
08327 {
08328 int found_it;
08329 struct chan_list *help;
08330
08331 ast_mutex_lock(&cl_te_lock);
08332 if (!cl_te) {
08333
08334 ast_mutex_unlock(&cl_te_lock);
08335 return 0;
08336 }
08337
08338 if (cl_te == chan) {
08339
08340 cl_te = cl_te->next;
08341 ast_mutex_unlock(&cl_te_lock);
08342 chan_list_unref(chan, "Removed chan_list from list head");
08343 return 1;
08344 }
08345
08346 found_it = 0;
08347 for (help = cl_te; help->next; help = help->next) {
08348 if (help->next == chan) {
08349
08350 help->next = help->next->next;
08351 found_it = 1;
08352 break;
08353 }
08354 }
08355
08356 ast_mutex_unlock(&cl_te_lock);
08357 if (found_it) {
08358 chan_list_unref(chan, "Removed chan_list from list");
08359 }
08360 return found_it;
08361 }
08362
08363
08364
08365
08366 static int pbx_start_chan(struct chan_list *ch)
08367 {
08368 int ret = ast_pbx_start(ch->ast);
08369
08370 ch->need_hangup = (ret >= 0) ? 0 : 1;
08371
08372 return ret;
08373 }
08374
08375 static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08376 {
08377 int port;
08378
08379 if (!ch) {
08380 cb_log(1, 0, "Cannot hangup chan, no ch\n");
08381 return;
08382 }
08383
08384 port = bc->port;
08385 cb_log(5, port, "hangup_chan called\n");
08386
08387 if (ch->need_hangup) {
08388 cb_log(2, port, " --> hangup\n");
08389 ch->need_hangup = 0;
08390 ch->need_queue_hangup = 0;
08391 if (ch->ast && send_cause2ast(ch->ast, bc, ch)) {
08392 ast_hangup(ch->ast);
08393 }
08394 return;
08395 }
08396
08397 if (!ch->need_queue_hangup) {
08398 cb_log(2, port, " --> No need to queue hangup\n");
08399 return;
08400 }
08401
08402 ch->need_queue_hangup = 0;
08403 if (ch->ast) {
08404 if (send_cause2ast(ch->ast, bc, ch)) {
08405 ast_queue_hangup_with_cause(ch->ast, bc->cause);
08406 cb_log(2, port, " --> queue_hangup\n");
08407 }
08408 } else {
08409 cb_log(1, port, "Cannot hangup chan, no ast\n");
08410 }
08411 }
08412
08413
08414
08415
08416
08417
08418
08419
08420
08421
08422
08423
08424 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08425 {
08426 struct ast_channel *ast;
08427
08428 chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);
08429
08430 ast_mutex_lock(&release_lock);
08431 for (;;) {
08432 ast = ch->ast;
08433 if (!ast || !ast_channel_trylock(ast)) {
08434 break;
08435 }
08436 DEADLOCK_AVOIDANCE(&release_lock);
08437 }
08438 if (!cl_dequeue_chan(ch)) {
08439
08440 if (ast) {
08441 ast_channel_unlock(ast);
08442 }
08443 ast_mutex_unlock(&release_lock);
08444 return;
08445 }
08446 ch->state = MISDN_CLEANING;
08447 ch->ast = NULL;
08448 if (ast) {
08449 struct chan_list *ast_ch;
08450
08451 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08452 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08453 chan_misdn_log(1, bc->port,
08454 "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s>\n",
08455 bc->pid,
08456 ast->context,
08457 ast->exten,
08458 S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
08459 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""));
08460
08461 if (ast->_state != AST_STATE_RESERVED) {
08462 chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
08463 ast_setstate(ast, AST_STATE_DOWN);
08464 }
08465 ast_channel_unlock(ast);
08466 if (ast_ch) {
08467 chan_list_unref(ast_ch, "Release ast_channel reference.");
08468 }
08469 }
08470
08471 if (ch->originator == ORG_AST) {
08472 --misdn_out_calls[bc->port];
08473 } else {
08474 --misdn_in_calls[bc->port];
08475 }
08476
08477 ast_mutex_unlock(&release_lock);
08478 }
08479
08480
08481
08482
08483
08484
08485
08486
08487
08488
08489
08490 static void release_chan_early(struct chan_list *ch)
08491 {
08492 struct ast_channel *ast;
08493
08494 ast_mutex_lock(&release_lock);
08495 for (;;) {
08496 ast = ch->ast;
08497 if (!ast || !ast_channel_trylock(ast)) {
08498 break;
08499 }
08500 DEADLOCK_AVOIDANCE(&release_lock);
08501 }
08502 if (!cl_dequeue_chan(ch)) {
08503
08504 if (ast) {
08505 ast_channel_unlock(ast);
08506 }
08507 ast_mutex_unlock(&release_lock);
08508 return;
08509 }
08510 ch->state = MISDN_CLEANING;
08511 ch->ast = NULL;
08512 if (ast) {
08513 struct chan_list *ast_ch;
08514
08515 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08516 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08517
08518 if (ast->_state != AST_STATE_RESERVED) {
08519 ast_setstate(ast, AST_STATE_DOWN);
08520 }
08521 ast_channel_unlock(ast);
08522 if (ast_ch) {
08523 chan_list_unref(ast_ch, "Release ast_channel reference.");
08524 }
08525 }
08526
08527 if (ch->hold.state != MISDN_HOLD_IDLE) {
08528 if (ch->originator == ORG_AST) {
08529 --misdn_out_calls[ch->hold.port];
08530 } else {
08531 --misdn_in_calls[ch->hold.port];
08532 }
08533 }
08534
08535 ast_mutex_unlock(&release_lock);
08536 }
08537
08538
08539
08540
08541
08542
08543
08544
08545
08546
08547
08548 static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
08549 {
08550 int retval;
08551 struct ast_channel *target;
08552 struct ast_channel *transferee;
08553 struct ast_party_connected_line target_colp;
08554 struct ast_party_connected_line transferee_colp;
08555
08556 switch (active_ch->state) {
08557 case MISDN_PROCEEDING:
08558 case MISDN_PROGRESS:
08559 case MISDN_ALERTING:
08560 case MISDN_CONNECTED:
08561 break;
08562 default:
08563 return -1;
08564 }
08565
08566 ast_channel_lock(held_ch->ast);
08567 while (ast_channel_trylock(active_ch->ast)) {
08568 CHANNEL_DEADLOCK_AVOIDANCE(held_ch->ast);
08569 }
08570
08571 transferee = ast_bridged_channel(held_ch->ast);
08572 if (!transferee) {
08573
08574
08575
08576
08577 ast_channel_unlock(held_ch->ast);
08578 ast_channel_unlock(active_ch->ast);
08579 return -1;
08580 }
08581
08582 target = active_ch->ast;
08583 chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
08584 held_ch->ast->name, target->name);
08585
08586 ast_party_connected_line_init(&target_colp);
08587 ast_party_connected_line_copy(&target_colp, &target->connected);
08588 ast_party_connected_line_init(&transferee_colp);
08589 ast_party_connected_line_copy(&transferee_colp, &held_ch->ast->connected);
08590 held_ch->hold.state = MISDN_HOLD_TRANSFER;
08591
08592
08593
08594
08595
08596
08597
08598
08599
08600
08601
08602 ao2_ref(target, +1);
08603 ao2_ref(transferee, +1);
08604 ast_channel_unlock(held_ch->ast);
08605 ast_channel_unlock(active_ch->ast);
08606
08607
08608 retval = ast_channel_transfer_masquerade(target, &target_colp, 0,
08609 transferee, &transferee_colp, 1);
08610
08611 ast_party_connected_line_free(&target_colp);
08612 ast_party_connected_line_free(&transferee_colp);
08613 ao2_ref(target, -1);
08614 ao2_ref(transferee, -1);
08615 return retval;
08616 }
08617
08618
08619 static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
08620 {
08621 char *predial;
08622 struct ast_frame fr;
08623
08624 predial = ast_strdupa(ast->exten);
08625
08626 ch->state = MISDN_DIALING;
08627
08628 if (!ch->noautorespond_on_setup) {
08629 if (bc->nt) {
08630 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08631 } else {
08632 if (misdn_lib_is_ptp(bc->port)) {
08633 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08634 } else {
08635 misdn_lib_send_event(bc, EVENT_PROCEEDING);
08636 }
08637 }
08638 } else {
08639 ch->state = MISDN_INCOMING_SETUP;
08640 }
08641
08642 chan_misdn_log(1, bc->port,
08643 "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n",
08644 ast->context,
08645 ast->exten,
08646 (ast->caller.id.name.valid && ast->caller.id.name.str)
08647 ? ast->caller.id.name.str : "",
08648 (ast->caller.id.number.valid && ast->caller.id.number.str)
08649 ? ast->caller.id.number.str : "");
08650
08651 strcpy(ast->exten, "s");
08652
08653 if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->caller.number) || pbx_start_chan(ch) < 0) {
08654 ast = NULL;
08655 bc->out_cause = AST_CAUSE_UNALLOCATED;
08656 hangup_chan(ch, bc);
08657 hanguptone_indicate(ch);
08658
08659 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
08660 }
08661
08662
08663 while (!ast_strlen_zero(predial)) {
08664 fr.frametype = AST_FRAME_DTMF;
08665 fr.subclass.integer = *predial;
08666 fr.src = NULL;
08667 fr.data.ptr = NULL;
08668 fr.datalen = 0;
08669 fr.samples = 0;
08670 fr.mallocd = 0;
08671 fr.offset = 0;
08672 fr.delivery = ast_tv(0,0);
08673
08674 if (ch->ast && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
08675 ast_queue_frame(ch->ast, &fr);
08676 }
08677 predial++;
08678 }
08679 }
08680
08681
08682
08683
08684
08685 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch)
08686 {
08687 int can_hangup;
08688
08689 if (!ast) {
08690 chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
08691 return 0;
08692 }
08693 if (!bc) {
08694 chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
08695 return 0;
08696 }
08697 if (!ch) {
08698 chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
08699 return 0;
08700 }
08701
08702 ast->hangupcause = bc->cause;
08703
08704 can_hangup = -1;
08705 switch (bc->cause) {
08706 case AST_CAUSE_UNALLOCATED:
08707 case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
08708 case AST_CAUSE_NO_ROUTE_DESTINATION:
08709 case 4:
08710 case AST_CAUSE_NUMBER_CHANGED:
08711 case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
08712
08713
08714
08715
08716
08717
08718
08719
08720
08721
08722 break;
08723
08724 case AST_CAUSE_CALL_REJECTED:
08725 case AST_CAUSE_USER_BUSY:
08726 ch->state = MISDN_BUSY;
08727
08728 if (!ch->need_busy) {
08729 chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
08730 break;
08731 }
08732 ch->need_busy = 0;
08733
08734 chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
08735 ast_queue_control(ast, AST_CONTROL_BUSY);
08736
08737
08738 can_hangup = 0;
08739 break;
08740 }
08741 return can_hangup;
08742 }
08743
08744
08745
08746 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08747 {
08748 const char *tmp;
08749
08750 ast_channel_lock(chan);
08751 tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
08752 if (tmp && (atoi(tmp) == 1)) {
08753 bc->sending_complete = 1;
08754 }
08755
08756 tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
08757 if (tmp) {
08758 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
08759 ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
08760 bc->uulen = strlen(bc->uu);
08761 }
08762
08763 tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
08764 if (tmp) {
08765 ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
08766 }
08767 ast_channel_unlock(chan);
08768 }
08769
08770
08771 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08772 {
08773 char tmp[32];
08774
08775
08776
08777
08778
08779
08780
08781 chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
08782 snprintf(tmp, sizeof(tmp), "%d", bc->pid);
08783 pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
08784
08785 if (bc->sending_complete) {
08786 snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
08787 pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
08788 }
08789
08790 if (bc->urate) {
08791 snprintf(tmp, sizeof(tmp), "%d", bc->urate);
08792 pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
08793 }
08794
08795 if (bc->uulen) {
08796 pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
08797 }
08798
08799 if (!ast_strlen_zero(bc->keypad)) {
08800 pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
08801 }
08802 }
08803
08804 int add_in_calls(int port)
08805 {
08806 int max_in_calls;
08807
08808 misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
08809 misdn_in_calls[port]++;
08810
08811 if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
08812 ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
08813 return misdn_in_calls[port] - max_in_calls;
08814 }
08815
08816 return 0;
08817 }
08818
08819 int add_out_calls(int port)
08820 {
08821 int max_out_calls;
08822
08823 misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
08824
08825 if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
08826 ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
08827 return (misdn_out_calls[port] + 1) - max_out_calls;
08828 }
08829
08830 misdn_out_calls[port]++;
08831
08832 return 0;
08833 }
08834
08835 static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08836 {
08837 if (pbx_start_chan(ch) < 0) {
08838 hangup_chan(ch, bc);
08839 chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
08840 if (bc->nt) {
08841 hanguptone_indicate(ch);
08842 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
08843 } else {
08844 misdn_lib_send_event(bc, EVENT_RELEASE);
08845 }
08846 }
08847 }
08848
08849 static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08850 {
08851 ch->state = MISDN_WAITING4DIGS;
08852 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08853 if (bc->nt && !bc->dialed.number[0]) {
08854 dialtone_indicate(ch);
08855 }
08856 }
08857
08858 #if defined(AST_MISDN_ENHANCEMENTS)
08859
08860
08861
08862
08863
08864
08865
08866
08867
08868 static void misdn_cc_handle_ccbs_status_request(int port, const struct FacParm *facility)
08869 {
08870 struct misdn_cc_record *cc_record;
08871 struct misdn_bchannel dummy;
08872
08873 switch (facility->u.CCBSStatusRequest.ComponentType) {
08874 case FacComponent_Invoke:
08875
08876 misdn_make_dummy(&dummy, port, 0, misdn_lib_port_is_nt(port), 0);
08877 dummy.fac_out.Function = Fac_CCBSStatusRequest;
08878 dummy.fac_out.u.CCBSStatusRequest.InvokeID = facility->u.CCBSStatusRequest.InvokeID;
08879 dummy.fac_out.u.CCBSStatusRequest.ComponentType = FacComponent_Result;
08880
08881
08882 AST_LIST_LOCK(&misdn_cc_records_db);
08883 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSStatusRequest.Component.Invoke.CCBSReference);
08884 if (cc_record) {
08885 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = cc_record->party_a_free;
08886 } else {
08887
08888 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = 1;
08889 }
08890 AST_LIST_UNLOCK(&misdn_cc_records_db);
08891
08892
08893 print_facility(&dummy.fac_out, &dummy);
08894 misdn_lib_send_event(&dummy, EVENT_FACILITY);
08895 break;
08896
08897 default:
08898 chan_misdn_log(0, port, " --> not yet handled: facility type:0x%04X\n", facility->Function);
08899 break;
08900 }
08901 }
08902 #endif
08903
08904 #if defined(AST_MISDN_ENHANCEMENTS)
08905
08906
08907
08908
08909
08910
08911
08912
08913
08914 static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *notify)
08915 {
08916 struct ast_channel *chan;
08917 char id_str[32];
08918
08919 static unsigned short sequence = 0;
08920
08921
08922 snprintf(id_str, sizeof(id_str), "%ld", record_id);
08923 chan = ast_channel_alloc(0, AST_STATE_DOWN, id_str, NULL, NULL,
08924 notify->exten, notify->context, NULL, 0,
08925 "mISDN-CC/%ld-%X", record_id, (unsigned) ++sequence);
08926 if (!chan) {
08927 ast_log(LOG_ERROR, "Unable to allocate channel!\n");
08928 return;
08929 }
08930 chan->priority = notify->priority;
08931 ast_free(chan->dialed.number.str);
08932 chan->dialed.number.str = ast_strdup(notify->exten);
08933
08934 if (ast_pbx_start(chan)) {
08935 ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", chan->name);
08936 ast_channel_release(chan);
08937 } else {
08938 ast_verb(1, "Started pbx for call completion notify channel %s\n", chan->name);
08939 }
08940 }
08941 #endif
08942
08943 #if defined(AST_MISDN_ENHANCEMENTS)
08944
08945
08946
08947
08948
08949
08950
08951
08952 static void misdn_cc_handle_T_remote_user_free(struct misdn_bchannel *bc)
08953 {
08954 struct misdn_cc_record *cc_record;
08955 struct misdn_cc_notify notify;
08956 long record_id;
08957
08958 AST_LIST_LOCK(&misdn_cc_records_db);
08959 cc_record = misdn_cc_find_by_bc(bc);
08960 if (cc_record) {
08961 if (cc_record->party_a_free) {
08962 notify = cc_record->remote_user_free;
08963 } else {
08964
08965 bc->fac_out.Function = Fac_CCBS_T_Suspend;
08966 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
08967 print_facility(&bc->fac_out, bc);
08968 misdn_lib_send_event(bc, EVENT_FACILITY);
08969
08970 notify = cc_record->b_free;
08971 }
08972 record_id = cc_record->record_id;
08973 AST_LIST_UNLOCK(&misdn_cc_records_db);
08974 if (notify.context[0]) {
08975
08976 misdn_cc_pbx_notify(record_id, ¬ify);
08977 }
08978 } else {
08979 AST_LIST_UNLOCK(&misdn_cc_records_db);
08980 }
08981 }
08982 #endif
08983
08984 #if defined(AST_MISDN_ENHANCEMENTS)
08985
08986
08987
08988
08989
08990
08991
08992
08993
08994 static void misdn_cc_handle_remote_user_free(int port, const struct FacParm *facility)
08995 {
08996 struct misdn_cc_record *cc_record;
08997 struct misdn_cc_notify notify;
08998 long record_id;
08999
09000 AST_LIST_LOCK(&misdn_cc_records_db);
09001 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSRemoteUserFree.CCBSReference);
09002 if (cc_record) {
09003 notify = cc_record->remote_user_free;
09004 record_id = cc_record->record_id;
09005 AST_LIST_UNLOCK(&misdn_cc_records_db);
09006 misdn_cc_pbx_notify(record_id, ¬ify);
09007 } else {
09008 AST_LIST_UNLOCK(&misdn_cc_records_db);
09009 }
09010 }
09011 #endif
09012
09013 #if defined(AST_MISDN_ENHANCEMENTS)
09014
09015
09016
09017
09018
09019
09020
09021
09022
09023 static void misdn_cc_handle_b_free(int port, const struct FacParm *facility)
09024 {
09025 struct misdn_cc_record *cc_record;
09026 struct misdn_cc_notify notify;
09027 long record_id;
09028
09029 AST_LIST_LOCK(&misdn_cc_records_db);
09030 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSBFree.CCBSReference);
09031 if (cc_record && cc_record->b_free.context[0]) {
09032
09033 notify = cc_record->b_free;
09034 record_id = cc_record->record_id;
09035 AST_LIST_UNLOCK(&misdn_cc_records_db);
09036 misdn_cc_pbx_notify(record_id, ¬ify);
09037 } else {
09038 AST_LIST_UNLOCK(&misdn_cc_records_db);
09039 }
09040 }
09041 #endif
09042
09043
09044
09045
09046
09047
09048
09049
09050
09051
09052
09053 static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel *bc, struct chan_list *ch)
09054 {
09055 #if defined(AST_MISDN_ENHANCEMENTS)
09056 const char *diagnostic_msg;
09057 struct misdn_cc_record *cc_record;
09058 char buf[32];
09059 struct misdn_party_id party_id;
09060 long new_record_id;
09061 #endif
09062
09063 print_facility(&bc->fac_in, bc);
09064 switch (bc->fac_in.Function) {
09065 #if defined(AST_MISDN_ENHANCEMENTS)
09066 case Fac_ActivationDiversion:
09067 switch (bc->fac_in.u.ActivationDiversion.ComponentType) {
09068 case FacComponent_Result:
09069
09070
09071 break;
09072 default:
09073 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09074 bc->fac_in.Function);
09075 break;
09076 }
09077 break;
09078 case Fac_DeactivationDiversion:
09079 switch (bc->fac_in.u.DeactivationDiversion.ComponentType) {
09080 case FacComponent_Result:
09081
09082
09083 break;
09084 default:
09085 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09086 bc->fac_in.Function);
09087 break;
09088 }
09089 break;
09090 case Fac_ActivationStatusNotificationDiv:
09091
09092
09093
09094 break;
09095 case Fac_DeactivationStatusNotificationDiv:
09096
09097
09098 break;
09099 #if 0
09100 case Fac_InterrogationDiversion:
09101
09102 break;
09103 case Fac_InterrogateServedUserNumbers:
09104
09105 break;
09106 #endif
09107 case Fac_DiversionInformation:
09108
09109
09110 break;
09111 case Fac_CallDeflection:
09112 if (ch && ch->ast) {
09113 switch (bc->fac_in.u.CallDeflection.ComponentType) {
09114 case FacComponent_Invoke:
09115 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09116 sizeof(bc->redirecting.from.number));
09117 bc->redirecting.from.name[0] = 0;
09118 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09119 bc->redirecting.from.number_type = bc->dialed.number_type;
09120 bc->redirecting.from.screening = 0;
09121 if (bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
09122 bc->redirecting.from.presentation =
09123 bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser
09124 ? 0 : 1 ;
09125 } else {
09126 bc->redirecting.from.presentation = 0;
09127 }
09128
09129
09130 memset(&party_id, 0, sizeof(party_id));
09131 misdn_PartyNumber_extract(&party_id,
09132 &bc->fac_in.u.CallDeflection.Component.Invoke.Deflection.Party);
09133 misdn_add_number_prefix(bc->port, party_id.number_type,
09134 party_id.number, sizeof(party_id.number));
09135
09136
09137 bc->redirecting.to = party_id;
09138
09139 ++bc->redirecting.count;
09140 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09141
09142 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09143 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09144
09145
09146 #if 1
09147
09148
09149
09150
09151 bc->fac_out.Function = Fac_RESULT;
09152 bc->fac_out.u.RESULT.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09153 #else
09154 bc->fac_out.Function = Fac_CallDeflection;
09155 bc->fac_out.u.CallDeflection.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09156 bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Result;
09157 #endif
09158 print_facility(&bc->fac_out, bc);
09159 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09160
09161
09162 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09163 break;
09164
09165 case FacComponent_Result:
09166
09167
09168
09169
09170
09171
09172
09173 break;
09174
09175 default:
09176 break;
09177 }
09178 }
09179 break;
09180 #if 0
09181 case Fac_CallRerouteing:
09182
09183
09184 break;
09185 #endif
09186 case Fac_DivertingLegInformation1:
09187
09188 bc->div_leg_3_rx_wanted = 0;
09189 if (ch && ch->ast) {
09190 bc->redirecting.reason =
09191 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation1.DiversionReason);
09192 if (bc->fac_in.u.DivertingLegInformation1.DivertedToPresent) {
09193 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.to,
09194 &bc->fac_in.u.DivertingLegInformation1.DivertedTo);
09195
09196
09197 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09198 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09199 } else {
09200 bc->redirecting.to.number[0] = '\0';
09201 bc->redirecting.to.number_plan = NUMPLAN_ISDN;
09202 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09203 bc->redirecting.to.presentation = 1;
09204 bc->redirecting.to.screening = 0;
09205 }
09206 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09207 bc->div_leg_3_rx_wanted = 1;
09208 }
09209 break;
09210 case Fac_DivertingLegInformation2:
09211
09212 switch (event) {
09213 case EVENT_SETUP:
09214
09215 bc->div_leg_3_tx_pending = 1;
09216 if (ch && ch->ast) {
09217
09218
09219
09220
09221
09222
09223
09224
09225
09226
09227 ast_copy_string(bc->redirecting.to.number, bc->dialed.number,
09228 sizeof(bc->redirecting.to.number));
09229 bc->redirecting.to.number_plan = bc->dialed.number_plan;
09230 bc->redirecting.to.number_type = bc->dialed.number_type;
09231 bc->redirecting.to.presentation = 1;
09232 bc->redirecting.to.screening = 0;
09233
09234 bc->redirecting.reason =
09235 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation2.DiversionReason);
09236 bc->redirecting.count = bc->fac_in.u.DivertingLegInformation2.DiversionCounter;
09237 if (bc->fac_in.u.DivertingLegInformation2.DivertingPresent) {
09238
09239 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.from,
09240 &bc->fac_in.u.DivertingLegInformation2.Diverting);
09241
09242
09243 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type,
09244 bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
09245 }
09246 #if 0
09247 if (bc->fac_in.u.DivertingLegInformation2.OriginalCalledPresent) {
09248
09249 }
09250 #endif
09251 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09252 }
09253 break;
09254 default:
09255 chan_misdn_log(0, bc->port," --> Expected in a SETUP message: facility type:0x%04X\n",
09256 bc->fac_in.Function);
09257 break;
09258 }
09259 break;
09260 case Fac_DivertingLegInformation3:
09261
09262 if (bc->div_leg_3_rx_wanted) {
09263 bc->div_leg_3_rx_wanted = 0;
09264
09265 if (ch && ch->ast) {
09266 ch->ast->redirecting.to.number.presentation =
09267 bc->fac_in.u.DivertingLegInformation3.PresentationAllowedIndicator
09268 ? AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED
09269 : AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
09270 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
09271 }
09272 }
09273 break;
09274
09275 #else
09276
09277 case Fac_CD:
09278 if (ch && ch->ast) {
09279 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09280 sizeof(bc->redirecting.from.number));
09281 bc->redirecting.from.name[0] = 0;
09282 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09283 bc->redirecting.from.number_type = bc->dialed.number_type;
09284 bc->redirecting.from.screening = 0;
09285 bc->redirecting.from.presentation =
09286 bc->fac_in.u.CDeflection.PresentationAllowed
09287 ? 0 : 1 ;
09288
09289 ast_copy_string(bc->redirecting.to.number,
09290 (char *) bc->fac_in.u.CDeflection.DeflectedToNumber,
09291 sizeof(bc->redirecting.to.number));
09292 bc->redirecting.to.name[0] = 0;
09293 bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
09294 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09295 bc->redirecting.to.presentation = 0;
09296 bc->redirecting.to.screening = 0;
09297
09298 ++bc->redirecting.count;
09299 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09300
09301 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09302 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09303
09304 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09305
09306
09307 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09308 }
09309 break;
09310 #endif
09311 case Fac_AOCDCurrency:
09312 if (ch && ch->ast) {
09313 bc->AOCDtype = Fac_AOCDCurrency;
09314 memcpy(&bc->AOCD.currency, &bc->fac_in.u.AOCDcur, sizeof(bc->AOCD.currency));
09315 bc->AOCD_need_export = 1;
09316 export_aoc_vars(ch->originator, ch->ast, bc);
09317 }
09318 break;
09319 case Fac_AOCDChargingUnit:
09320 if (ch && ch->ast) {
09321 bc->AOCDtype = Fac_AOCDChargingUnit;
09322 memcpy(&bc->AOCD.chargingUnit, &bc->fac_in.u.AOCDchu, sizeof(bc->AOCD.chargingUnit));
09323 bc->AOCD_need_export = 1;
09324 export_aoc_vars(ch->originator, ch->ast, bc);
09325 }
09326 break;
09327 #if defined(AST_MISDN_ENHANCEMENTS)
09328 case Fac_ERROR:
09329 diagnostic_msg = misdn_to_str_error_code(bc->fac_in.u.ERROR.errorValue);
09330 chan_misdn_log(1, bc->port, " --> Facility error code: %s\n", diagnostic_msg);
09331 switch (event) {
09332 case EVENT_DISCONNECT:
09333 case EVENT_RELEASE:
09334 case EVENT_RELEASE_COMPLETE:
09335
09336 if (ch && ch->peer) {
09337 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09338 }
09339 break;
09340 default:
09341 break;
09342 }
09343 AST_LIST_LOCK(&misdn_cc_records_db);
09344 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.ERROR.invokeId);
09345 if (cc_record) {
09346 cc_record->outstanding_message = 0;
09347 cc_record->error_code = bc->fac_in.u.ERROR.errorValue;
09348 }
09349 AST_LIST_UNLOCK(&misdn_cc_records_db);
09350 break;
09351 case Fac_REJECT:
09352 diagnostic_msg = misdn_to_str_reject_code(bc->fac_in.u.REJECT.Code);
09353 chan_misdn_log(1, bc->port, " --> Facility reject code: %s\n", diagnostic_msg);
09354 switch (event) {
09355 case EVENT_DISCONNECT:
09356 case EVENT_RELEASE:
09357 case EVENT_RELEASE_COMPLETE:
09358
09359 if (ch && ch->peer) {
09360 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09361 }
09362 break;
09363 default:
09364 break;
09365 }
09366 if (bc->fac_in.u.REJECT.InvokeIDPresent) {
09367 AST_LIST_LOCK(&misdn_cc_records_db);
09368 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.REJECT.InvokeID);
09369 if (cc_record) {
09370 cc_record->outstanding_message = 0;
09371 cc_record->reject_code = bc->fac_in.u.REJECT.Code;
09372 }
09373 AST_LIST_UNLOCK(&misdn_cc_records_db);
09374 }
09375 break;
09376 case Fac_RESULT:
09377 AST_LIST_LOCK(&misdn_cc_records_db);
09378 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.RESULT.InvokeID);
09379 if (cc_record) {
09380 cc_record->outstanding_message = 0;
09381 }
09382 AST_LIST_UNLOCK(&misdn_cc_records_db);
09383 break;
09384 #if 0
09385 case Fac_EctExecute:
09386
09387 break;
09388 case Fac_ExplicitEctExecute:
09389
09390 break;
09391 case Fac_EctLinkIdRequest:
09392
09393 break;
09394 #endif
09395 case Fac_SubaddressTransfer:
09396
09397 break;
09398 case Fac_RequestSubaddress:
09399
09400
09401
09402
09403 if (bc->redirecting.to_changed) {
09404
09405 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09406 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09407 }
09408 switch (bc->notify_description_code) {
09409 case mISDN_NOTIFY_CODE_INVALID:
09410
09411 bc->redirecting.to_changed = 0;
09412 break;
09413 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
09414
09415
09416
09417
09418
09419
09420
09421
09422
09423 if (!bc->redirecting.to_changed) {
09424 break;
09425 }
09426 bc->redirecting.to_changed = 0;
09427 if (!ch || !ch->ast) {
09428 break;
09429 }
09430 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09431 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
09432 bc->incoming_cid_tag);
09433 break;
09434 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
09435 if (!bc->redirecting.to_changed) {
09436 break;
09437 }
09438 bc->redirecting.to_changed = 0;
09439 if (!ch || !ch->ast) {
09440 break;
09441 }
09442 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09443 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
09444 break;
09445 default:
09446 bc->redirecting.to_changed = 0;
09447 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
09448 bc->notify_description_code);
09449 break;
09450 }
09451 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
09452 break;
09453 case Fac_EctInform:
09454
09455 if (ch && ch->ast && bc->fac_in.u.EctInform.RedirectionPresent) {
09456
09457 memset(&party_id, 0, sizeof(party_id));
09458 misdn_PresentedNumberUnscreened_extract(&party_id,
09459 &bc->fac_in.u.EctInform.Redirection);
09460 misdn_add_number_prefix(bc->port, party_id.number_type,
09461 party_id.number, sizeof(party_id.number));
09462
09463
09464
09465
09466
09467
09468
09469
09470
09471
09472 misdn_update_remote_party(ch->ast, &party_id,
09473 (bc->fac_in.u.EctInform.Status == 0 )
09474 ? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
09475 : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
09476 bc->incoming_cid_tag);
09477 }
09478 break;
09479 #if 0
09480 case Fac_EctLoopTest:
09481
09482
09483 break;
09484 #endif
09485 case Fac_CallInfoRetain:
09486 switch (event) {
09487 case EVENT_ALERTING:
09488 case EVENT_DISCONNECT:
09489
09490 if (ch && ch->peer) {
09491 AST_LIST_LOCK(&misdn_cc_records_db);
09492 if (ch->record_id == -1) {
09493 cc_record = misdn_cc_new();
09494 } else {
09495
09496
09497
09498
09499
09500
09501
09502
09503
09504 cc_record = misdn_cc_find_by_id(ch->record_id);
09505 if (cc_record) {
09506 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09507
09508
09509
09510
09511
09512
09513
09514
09515 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09516 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09517 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09518 }
09519
09520
09521
09522
09523
09524 new_record_id = misdn_cc_record_id_new();
09525 if (new_record_id < 0) {
09526
09527 } else {
09528 cc_record->record_id = new_record_id;
09529 ch->record_id = new_record_id;
09530 }
09531 cc_record->ptp = 0;
09532 cc_record->port = bc->port;
09533 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09534 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09535 cc_record->invoke_id = ++misdn_invoke_id;
09536 cc_record->activated = 0;
09537 cc_record->outstanding_message = 0;
09538 cc_record->activation_requested = 0;
09539 cc_record->error_code = FacError_None;
09540 cc_record->reject_code = FacReject_None;
09541 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09542 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09543 cc_record->time_created = time(NULL);
09544
09545 cc_record = NULL;
09546 } else {
09547
09548
09549
09550
09551
09552 ch->record_id = -1;
09553 cc_record = misdn_cc_new();
09554 }
09555 }
09556 if (cc_record) {
09557 ch->record_id = cc_record->record_id;
09558 cc_record->ptp = 0;
09559 cc_record->port = bc->port;
09560 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09561
09562
09563 cc_record->redial.caller = bc->caller;
09564 cc_record->redial.dialed = bc->dialed;
09565 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09566 cc_record->redial.capability = bc->capability;
09567 cc_record->redial.hdlc = bc->hdlc;
09568 }
09569 AST_LIST_UNLOCK(&misdn_cc_records_db);
09570
09571
09572 if (ch->record_id != -1) {
09573 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09574 } else {
09575 buf[0] = 0;
09576 }
09577 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09578 }
09579 break;
09580 default:
09581 chan_misdn_log(0, bc->port,
09582 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09583 bc->fac_in.Function);
09584 break;
09585 }
09586 break;
09587 case Fac_CCBS_T_Call:
09588 case Fac_CCBSCall:
09589 switch (event) {
09590 case EVENT_SETUP:
09591
09592
09593
09594
09595 break;
09596 default:
09597 chan_misdn_log(0, bc->port, " --> Expected in a SETUP message: facility type:0x%04X\n",
09598 bc->fac_in.Function);
09599 break;
09600 }
09601 break;
09602 case Fac_CCBSDeactivate:
09603 switch (bc->fac_in.u.CCBSDeactivate.ComponentType) {
09604 case FacComponent_Result:
09605 AST_LIST_LOCK(&misdn_cc_records_db);
09606 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSDeactivate.InvokeID);
09607 if (cc_record) {
09608 cc_record->outstanding_message = 0;
09609 }
09610 AST_LIST_UNLOCK(&misdn_cc_records_db);
09611 break;
09612
09613 default:
09614 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09615 bc->fac_in.Function);
09616 break;
09617 }
09618 break;
09619 case Fac_CCBSErase:
09620 AST_LIST_LOCK(&misdn_cc_records_db);
09621 cc_record = misdn_cc_find_by_reference(bc->port, bc->fac_in.u.CCBSErase.CCBSReference);
09622 if (cc_record) {
09623 misdn_cc_delete(cc_record);
09624 }
09625 AST_LIST_UNLOCK(&misdn_cc_records_db);
09626 break;
09627 case Fac_CCBSRemoteUserFree:
09628 misdn_cc_handle_remote_user_free(bc->port, &bc->fac_in);
09629 break;
09630 case Fac_CCBSBFree:
09631 misdn_cc_handle_b_free(bc->port, &bc->fac_in);
09632 break;
09633 case Fac_CCBSStatusRequest:
09634 misdn_cc_handle_ccbs_status_request(bc->port, &bc->fac_in);
09635 break;
09636 case Fac_EraseCallLinkageID:
09637 AST_LIST_LOCK(&misdn_cc_records_db);
09638 cc_record = misdn_cc_find_by_linkage(bc->port,
09639 bc->fac_in.u.EraseCallLinkageID.CallLinkageID);
09640 if (cc_record && !cc_record->activation_requested) {
09641
09642
09643
09644
09645
09646 misdn_cc_delete(cc_record);
09647 }
09648 AST_LIST_UNLOCK(&misdn_cc_records_db);
09649 break;
09650 case Fac_CCBSStopAlerting:
09651
09652 break;
09653 case Fac_CCBSRequest:
09654 case Fac_CCNRRequest:
09655 switch (bc->fac_in.u.CCBSRequest.ComponentType) {
09656 case FacComponent_Result:
09657 AST_LIST_LOCK(&misdn_cc_records_db);
09658 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSRequest.InvokeID);
09659 if (cc_record && !cc_record->ptp) {
09660 cc_record->outstanding_message = 0;
09661 cc_record->activated = 1;
09662 cc_record->mode.ptmp.recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
09663 cc_record->mode.ptmp.reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
09664 }
09665 AST_LIST_UNLOCK(&misdn_cc_records_db);
09666 break;
09667
09668 default:
09669 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09670 bc->fac_in.Function);
09671 break;
09672 }
09673 break;
09674 #if 0
09675 case Fac_CCBSInterrogate:
09676 case Fac_CCNRInterrogate:
09677
09678 break;
09679 case Fac_StatusRequest:
09680
09681 break;
09682 #endif
09683 #if 0
09684 case Fac_CCBS_T_Suspend:
09685 case Fac_CCBS_T_Resume:
09686
09687 break;
09688 #endif
09689 case Fac_CCBS_T_RemoteUserFree:
09690 misdn_cc_handle_T_remote_user_free(bc);
09691 break;
09692 case Fac_CCBS_T_Available:
09693 switch (event) {
09694 case EVENT_ALERTING:
09695 case EVENT_DISCONNECT:
09696
09697 if (ch && ch->peer) {
09698 int set_id = 1;
09699
09700 AST_LIST_LOCK(&misdn_cc_records_db);
09701 if (ch->record_id == -1) {
09702 cc_record = misdn_cc_new();
09703 } else {
09704
09705
09706
09707
09708
09709 cc_record = misdn_cc_find_by_id(ch->record_id);
09710 if (cc_record) {
09711 if (cc_record->ptp && cc_record->mode.ptp.retention_enabled) {
09712
09713
09714
09715
09716 chan_misdn_log(1, bc->port, " --> Call-completion request retention option is enabled\n");
09717
09718 set_id = 0;
09719 } else {
09720 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09721
09722
09723
09724
09725
09726
09727
09728
09729
09730 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09731 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09732 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09733 }
09734
09735
09736
09737
09738
09739 new_record_id = misdn_cc_record_id_new();
09740 if (new_record_id < 0) {
09741
09742 } else {
09743 cc_record->record_id = new_record_id;
09744 ch->record_id = new_record_id;
09745 }
09746 cc_record->ptp = 1;
09747 cc_record->port = bc->port;
09748 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09749 cc_record->invoke_id = ++misdn_invoke_id;
09750 cc_record->activated = 0;
09751 cc_record->outstanding_message = 0;
09752 cc_record->activation_requested = 0;
09753 cc_record->error_code = FacError_None;
09754 cc_record->reject_code = FacReject_None;
09755 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09756 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09757 cc_record->time_created = time(NULL);
09758 }
09759 cc_record = NULL;
09760 } else {
09761
09762
09763
09764
09765
09766 ch->record_id = -1;
09767 cc_record = misdn_cc_new();
09768 }
09769 }
09770 if (cc_record) {
09771 ch->record_id = cc_record->record_id;
09772 cc_record->ptp = 1;
09773 cc_record->port = bc->port;
09774
09775
09776 cc_record->redial.caller = bc->caller;
09777 cc_record->redial.dialed = bc->dialed;
09778 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09779 cc_record->redial.capability = bc->capability;
09780 cc_record->redial.hdlc = bc->hdlc;
09781 }
09782 AST_LIST_UNLOCK(&misdn_cc_records_db);
09783
09784
09785 if (ch->record_id != -1 && set_id) {
09786 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09787 } else {
09788 buf[0] = 0;
09789 }
09790 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09791 }
09792 break;
09793 default:
09794 chan_misdn_log(0, bc->port,
09795 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09796 bc->fac_in.Function);
09797 break;
09798 }
09799 break;
09800 case Fac_CCBS_T_Request:
09801 case Fac_CCNR_T_Request:
09802 switch (bc->fac_in.u.CCBS_T_Request.ComponentType) {
09803 case FacComponent_Result:
09804 AST_LIST_LOCK(&misdn_cc_records_db);
09805 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBS_T_Request.InvokeID);
09806 if (cc_record && cc_record->ptp) {
09807 cc_record->outstanding_message = 0;
09808 cc_record->activated = 1;
09809 cc_record->mode.ptp.retention_enabled =
09810 cc_record->mode.ptp.requested_retention
09811 ? bc->fac_in.u.CCBS_T_Request.Component.Result.RetentionSupported
09812 ? 1 : 0
09813 : 0;
09814 }
09815 AST_LIST_UNLOCK(&misdn_cc_records_db);
09816 break;
09817
09818 case FacComponent_Invoke:
09819
09820 default:
09821 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09822 bc->fac_in.Function);
09823 break;
09824 }
09825 break;
09826
09827 #endif
09828 case Fac_None:
09829 break;
09830 default:
09831 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09832 bc->fac_in.Function);
09833 break;
09834 }
09835 }
09836
09837
09838
09839
09840
09841
09842
09843
09844
09845
09846
09847
09848 static int misdn_is_msn_valid(int port, const struct misdn_party_dialing *dialed)
09849 {
09850 char number[sizeof(dialed->number)];
09851
09852 ast_copy_string(number, dialed->number, sizeof(number));
09853 misdn_add_number_prefix(port, dialed->number_type, number, sizeof(number));
09854 return misdn_cfg_is_msn_valid(port, number);
09855 }
09856
09857
09858
09859
09860 static enum event_response_e
09861 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
09862 {
09863 #if defined(AST_MISDN_ENHANCEMENTS)
09864 struct misdn_cc_record *cc_record;
09865 #endif
09866 struct chan_list *held_ch;
09867 struct chan_list *ch = find_chan_by_bc(bc);
09868
09869 if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) {
09870 int debuglevel = 1;
09871
09872
09873 if (event == EVENT_CLEANUP && !user_data) {
09874 debuglevel = 5;
09875 }
09876
09877 chan_misdn_log(debuglevel, bc->port,
09878 "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n",
09879 manager_isdn_get_info(event),
09880 bc->caller.name,
09881 bc->caller.number,
09882 bc->dialed.number,
09883 bc->pid,
09884 ch ? misdn_get_ch_state(ch) : "none");
09885 if (debuglevel == 1) {
09886 misdn_lib_log_ies(bc);
09887 chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
09888 }
09889 }
09890
09891 if (!ch) {
09892 switch(event) {
09893 case EVENT_SETUP:
09894 case EVENT_DISCONNECT:
09895 case EVENT_RELEASE:
09896 case EVENT_RELEASE_COMPLETE:
09897 case EVENT_PORT_ALARM:
09898 case EVENT_RETRIEVE:
09899 case EVENT_NEW_BC:
09900 case EVENT_FACILITY:
09901 case EVENT_REGISTER:
09902 break;
09903 case EVENT_CLEANUP:
09904 case EVENT_TONE_GENERATE:
09905 case EVENT_BCHAN_DATA:
09906 return -1;
09907 default:
09908 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);
09909 return -1;
09910 }
09911 } else {
09912 switch (event) {
09913 case EVENT_TONE_GENERATE:
09914 break;
09915 case EVENT_DISCONNECT:
09916 case EVENT_RELEASE:
09917 case EVENT_RELEASE_COMPLETE:
09918 case EVENT_CLEANUP:
09919 case EVENT_TIMEOUT:
09920 if (!ch->ast) {
09921 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));
09922 }
09923 break;
09924 default:
09925 if (!ch->ast || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
09926 if (event != EVENT_BCHAN_DATA) {
09927 ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
09928 }
09929 chan_list_unref(ch, "No Ast or Ast private pointer");
09930 return -1;
09931 }
09932 break;
09933 }
09934 }
09935
09936
09937 switch (event) {
09938 case EVENT_PORT_ALARM:
09939 {
09940 int boa = 0;
09941 misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
09942 if (boa) {
09943 cb_log(1, bc->port, " --> blocking\n");
09944 misdn_lib_port_block(bc->port);
09945 }
09946 }
09947 break;
09948 case EVENT_BCHAN_ACTIVATED:
09949 break;
09950
09951 case EVENT_NEW_CHANNEL:
09952 update_name(ch->ast,bc->port,bc->channel);
09953 break;
09954
09955 case EVENT_NEW_L3ID:
09956 ch->l3id=bc->l3_id;
09957 ch->addr=bc->addr;
09958 break;
09959
09960 case EVENT_NEW_BC:
09961 if (!ch) {
09962 ch = find_hold_call(bc);
09963 }
09964
09965 if (!ch) {
09966 ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
09967 break;
09968 }
09969
09970 if (bc) {
09971 ch->bc = (struct misdn_bchannel *) user_data;
09972 }
09973 break;
09974
09975 case EVENT_DTMF_TONE:
09976 {
09977
09978 struct ast_frame fr;
09979
09980 memset(&fr, 0, sizeof(fr));
09981 fr.frametype = AST_FRAME_DTMF;
09982 fr.subclass.integer = bc->dtmf ;
09983 fr.src = NULL;
09984 fr.data.ptr = NULL;
09985 fr.datalen = 0;
09986 fr.samples = 0;
09987 fr.mallocd = 0;
09988 fr.offset = 0;
09989 fr.delivery = ast_tv(0,0);
09990
09991 if (!ch->ignore_dtmf) {
09992 chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
09993 ast_queue_frame(ch->ast, &fr);
09994 } else {
09995 chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
09996 }
09997 break;
09998 }
09999 case EVENT_STATUS:
10000 break;
10001
10002 case EVENT_INFORMATION:
10003 if (ch->state != MISDN_CONNECTED) {
10004 stop_indicate(ch);
10005 }
10006
10007 if (!ch->ast) {
10008 break;
10009 }
10010
10011 if (ch->state == MISDN_WAITING4DIGS) {
10012
10013 if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
10014 chan_misdn_log(1, bc->port, " --> using keypad as info\n");
10015 ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
10016 }
10017
10018 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10019 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10020
10021
10022 if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
10023 if (ast_pickup_call(ch->ast)) {
10024 hangup_chan(ch, bc);
10025 } else {
10026 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10027 hangup_chan(ch, bc);
10028 ch->ast = NULL;
10029 break;
10030 }
10031 }
10032
10033 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10034 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10035 ast_log(LOG_WARNING,
10036 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10037 bc->dialed.number, ch->context, bc->port);
10038 strcpy(ch->ast->exten, "i");
10039
10040 ch->state = MISDN_DIALING;
10041 start_pbx(ch, bc, ch->ast);
10042 break;
10043 }
10044
10045 ast_log(LOG_WARNING,
10046 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10047 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10048 bc->dialed.number, ch->context, bc->port);
10049
10050 if (bc->nt) {
10051 hanguptone_indicate(ch);
10052 }
10053 ch->state = MISDN_EXTCANTMATCH;
10054 bc->out_cause = AST_CAUSE_UNALLOCATED;
10055
10056 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10057 break;
10058 }
10059
10060 if (ch->overlap_dial) {
10061 ast_mutex_lock(&ch->overlap_tv_lock);
10062 ch->overlap_tv = ast_tvnow();
10063 ast_mutex_unlock(&ch->overlap_tv_lock);
10064 if (ch->overlap_dial_task == -1) {
10065 ch->overlap_dial_task =
10066 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10067 }
10068 break;
10069 }
10070
10071 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10072 ch->state = MISDN_DIALING;
10073 start_pbx(ch, bc, ch->ast);
10074 }
10075 } else {
10076
10077 struct ast_frame fr;
10078 int digits;
10079
10080 memset(&fr, 0, sizeof(fr));
10081 fr.frametype = AST_FRAME_DTMF;
10082 fr.subclass.integer = bc->info_dad[0] ;
10083 fr.src = NULL;
10084 fr.data.ptr = NULL;
10085 fr.datalen = 0;
10086 fr.samples = 0;
10087 fr.mallocd = 0;
10088 fr.offset = 0;
10089 fr.delivery = ast_tv(0,0);
10090
10091 misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
10092 if (ch->state != MISDN_CONNECTED) {
10093 if (digits) {
10094 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10095 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10096 ast_cdr_update(ch->ast);
10097 }
10098
10099 ast_queue_frame(ch->ast, &fr);
10100 }
10101 }
10102 break;
10103 case EVENT_SETUP:
10104 {
10105 struct ast_channel *chan;
10106 int exceed;
10107 int ai;
10108 int im;
10109 int append_msn = 0;
10110
10111 if (ch) {
10112 switch (ch->state) {
10113 case MISDN_NOTHING:
10114 chan_list_unref(ch, "Ignore found ch. Is it for an outgoing call?");
10115 ch = NULL;
10116 break;
10117 default:
10118 chan_list_unref(ch, "Already have a call.");
10119 chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
10120 return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE;
10121 }
10122 }
10123
10124 if (!bc->nt && !misdn_is_msn_valid(bc->port, &bc->dialed)) {
10125 chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
10126 return RESPONSE_IGNORE_SETUP;
10127 }
10128
10129 if (bc->cw) {
10130 int cause;
10131 chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
10132 misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
10133 bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
10134 return RESPONSE_RELEASE_SETUP;
10135 }
10136
10137 print_bearer(bc);
10138
10139 ch = chan_list_init(ORG_MISDN);
10140 if (!ch) {
10141 chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
10142 return 0;
10143 }
10144
10145 ch->bc = bc;
10146 ch->l3id = bc->l3_id;
10147 ch->addr = bc->addr;
10148
10149 chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, NULL, bc->port, bc->channel);
10150 if (!chan) {
10151 chan_list_unref(ch, "Failed to create a new channel");
10152 misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
10153 ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
10154 return 0;
10155 }
10156
10157 if ((exceed = add_in_calls(bc->port))) {
10158 char tmp[16];
10159 snprintf(tmp, sizeof(tmp), "%d", exceed);
10160 pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
10161 }
10162
10163 read_config(ch);
10164
10165 export_ch(chan, bc, ch);
10166
10167 ch->ast->rings = 1;
10168 ast_setstate(ch->ast, AST_STATE_RINGING);
10169
10170
10171 chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
10172 chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan);
10173 chan->caller.id.number.plan = misdn_to_ast_ton(bc->caller.number_type)
10174 | misdn_to_ast_plan(bc->caller.number_plan);
10175
10176 chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
10177 chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
10178 chan->caller.id.number.presentation = misdn_to_ast_pres(bc->caller.presentation)
10179 | misdn_to_ast_screen(bc->caller.screening);
10180
10181 ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
10182
10183 misdn_cfg_get(bc->port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
10184 if (append_msn) {
10185 strncat(bc->incoming_cid_tag, "_", sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10186 strncat(bc->incoming_cid_tag, bc->dialed.number, sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10187 }
10188
10189 ast_channel_lock(chan);
10190 chan->caller.id.tag = ast_strdup(bc->incoming_cid_tag);
10191 ast_channel_unlock(chan);
10192
10193 if (!ast_strlen_zero(bc->redirecting.from.number)) {
10194
10195 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
10196
10197
10198 misdn_copy_redirecting_to_ast(chan, &bc->redirecting, bc->incoming_cid_tag);
10199 }
10200
10201 pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
10202 chan->transfercapability = bc->capability;
10203
10204 switch (bc->capability) {
10205 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
10206 pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
10207 break;
10208 default:
10209 pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
10210 break;
10211 }
10212
10213
10214 cl_queue_chan(ch);
10215
10216 if (!strstr(ch->allowed_bearers, "all")) {
10217 int i;
10218
10219 for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
10220 if (allowed_bearers_array[i].cap == bc->capability) {
10221 if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
10222
10223 if (allowed_bearers_array[i].deprecated) {
10224 chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
10225 allowed_bearers_array[i].name);
10226 }
10227 break;
10228 }
10229 }
10230 }
10231 if (i == ARRAY_LEN(allowed_bearers_array)) {
10232
10233 chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
10234 bearer2str(bc->capability), bc->capability);
10235 bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
10236
10237 ch->state = MISDN_EXTCANTMATCH;
10238 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10239 chan_list_unref(ch, "BC not allowed, releasing call");
10240 return RESPONSE_OK;
10241 }
10242 }
10243
10244 if (bc->fac_in.Function != Fac_None) {
10245 misdn_facility_ie_handler(event, bc, ch);
10246 }
10247
10248
10249 if (!strcmp(chan->exten, ast_pickup_ext())) {
10250 if (!ch->noautorespond_on_setup) {
10251
10252 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10253 } else {
10254 ch->state = MISDN_INCOMING_SETUP;
10255 }
10256 if (ast_pickup_call(chan)) {
10257 hangup_chan(ch, bc);
10258 } else {
10259 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10260 hangup_chan(ch, bc);
10261 ch->ast = NULL;
10262 break;
10263 }
10264 }
10265
10266
10267
10268
10269
10270 misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
10271 if (ai) {
10272 do_immediate_setup(bc, ch, chan);
10273 break;
10274 }
10275
10276
10277 misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
10278 if (im && ast_strlen_zero(bc->dialed.number)) {
10279 do_immediate_setup(bc, ch, chan);
10280 break;
10281 }
10282
10283 chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
10284 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10285 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10286 ast_log(LOG_WARNING,
10287 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10288 bc->dialed.number, ch->context, bc->port);
10289 strcpy(ch->ast->exten, "i");
10290 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10291 ch->state = MISDN_DIALING;
10292 start_pbx(ch, bc, chan);
10293 break;
10294 }
10295
10296 ast_log(LOG_WARNING,
10297 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10298 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10299 bc->dialed.number, ch->context, bc->port);
10300 if (bc->nt) {
10301 hanguptone_indicate(ch);
10302 }
10303
10304 ch->state = MISDN_EXTCANTMATCH;
10305 bc->out_cause = AST_CAUSE_UNALLOCATED;
10306
10307 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE);
10308 break;
10309 }
10310
10311
10312
10313
10314 if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
10315 if (!ch->noautorespond_on_setup) {
10316 ch->state=MISDN_DIALING;
10317 misdn_lib_send_event(bc, EVENT_PROCEEDING);
10318 } else {
10319 ch->state = MISDN_INCOMING_SETUP;
10320 }
10321 start_pbx(ch, bc, chan);
10322 break;
10323 }
10324
10325
10326
10327
10328
10329
10330
10331 if (ch->overlap_dial && bc->nt && !bc->dialed.number[0]) {
10332 wait_for_digits(ch, bc, chan);
10333 break;
10334 }
10335
10336
10337
10338
10339
10340 if (ch->overlap_dial) {
10341 ast_mutex_lock(&ch->overlap_tv_lock);
10342 ch->overlap_tv = ast_tvnow();
10343 ast_mutex_unlock(&ch->overlap_tv_lock);
10344
10345 wait_for_digits(ch, bc, chan);
10346 if (ch->overlap_dial_task == -1) {
10347 ch->overlap_dial_task =
10348 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10349 }
10350 break;
10351 }
10352
10353
10354
10355
10356 if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10357 wait_for_digits(ch, bc, chan);
10358 break;
10359 }
10360
10361
10362
10363
10364 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10365 misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
10366 ch->state = MISDN_DIALING;
10367 start_pbx(ch, bc, chan);
10368 break;
10369 }
10370 break;
10371 }
10372 #if defined(AST_MISDN_ENHANCEMENTS)
10373 case EVENT_REGISTER:
10374 if (bc->fac_in.Function != Fac_None) {
10375 misdn_facility_ie_handler(event, bc, ch);
10376 }
10377
10378
10379
10380
10381
10382
10383
10384 bc->fac_out.Function = Fac_None;
10385 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10386 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10387 break;
10388 #endif
10389 case EVENT_SETUP_ACKNOWLEDGE:
10390 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10391
10392 if (bc->channel) {
10393 update_name(ch->ast,bc->port,bc->channel);
10394 }
10395
10396 if (bc->fac_in.Function != Fac_None) {
10397 misdn_facility_ie_handler(event, bc, ch);
10398 }
10399
10400 if (!ast_strlen_zero(bc->infos_pending)) {
10401
10402 strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10403
10404 if (!ch->ast) {
10405 break;
10406 }
10407 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10408 ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
10409 ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
10410
10411 misdn_lib_send_event(bc, EVENT_INFORMATION);
10412 }
10413 break;
10414 case EVENT_PROCEEDING:
10415 if (misdn_cap_is_speech(bc->capability) &&
10416 misdn_inband_avail(bc)) {
10417 start_bc_tones(ch);
10418 }
10419
10420 ch->state = MISDN_PROCEEDING;
10421
10422 if (bc->fac_in.Function != Fac_None) {
10423 misdn_facility_ie_handler(event, bc, ch);
10424 }
10425
10426 if (!ch->ast) {
10427 break;
10428 }
10429
10430 ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
10431 break;
10432 case EVENT_PROGRESS:
10433 if (bc->channel) {
10434 update_name(ch->ast, bc->port, bc->channel);
10435 }
10436
10437 if (bc->fac_in.Function != Fac_None) {
10438 misdn_facility_ie_handler(event, bc, ch);
10439 }
10440
10441 if (!bc->nt) {
10442 if (misdn_cap_is_speech(bc->capability) &&
10443 misdn_inband_avail(bc)) {
10444 start_bc_tones(ch);
10445 }
10446
10447 ch->state = MISDN_PROGRESS;
10448
10449 if (!ch->ast) {
10450 break;
10451 }
10452 ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
10453 }
10454 break;
10455 case EVENT_ALERTING:
10456 ch->state = MISDN_ALERTING;
10457
10458 if (!ch->ast) {
10459 break;
10460 }
10461
10462 if (bc->fac_in.Function != Fac_None) {
10463 misdn_facility_ie_handler(event, bc, ch);
10464 }
10465
10466 ast_queue_control(ch->ast, AST_CONTROL_RINGING);
10467 ast_setstate(ch->ast, AST_STATE_RINGING);
10468
10469 cb_log(7, bc->port, " --> Set State Ringing\n");
10470
10471 if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
10472 cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
10473 start_bc_tones(ch);
10474 } else {
10475 cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
10476 if (ch->far_alerting) {
10477 cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
10478 start_bc_tones(ch);
10479
10480 }
10481 }
10482 break;
10483 case EVENT_CONNECT:
10484 if (bc->fac_in.Function != Fac_None) {
10485 misdn_facility_ie_handler(event, bc, ch);
10486 }
10487 #if defined(AST_MISDN_ENHANCEMENTS)
10488 if (bc->div_leg_3_rx_wanted) {
10489 bc->div_leg_3_rx_wanted = 0;
10490
10491 if (ch->ast) {
10492 ch->ast->redirecting.to.number.presentation =
10493 AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
10494 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10495 }
10496 }
10497 #endif
10498
10499
10500 misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
10501
10502 if (!ch->ast) {
10503 break;
10504 }
10505
10506 stop_indicate(ch);
10507
10508 #if defined(AST_MISDN_ENHANCEMENTS)
10509 if (ch->record_id != -1) {
10510
10511
10512
10513
10514
10515
10516 AST_LIST_LOCK(&misdn_cc_records_db);
10517 cc_record = misdn_cc_find_by_id(ch->record_id);
10518 if (cc_record) {
10519 if (cc_record->ptp && cc_record->mode.ptp.bc) {
10520
10521 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
10522 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10523 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
10524 }
10525 misdn_cc_delete(cc_record);
10526 }
10527 AST_LIST_UNLOCK(&misdn_cc_records_db);
10528 ch->record_id = -1;
10529 if (ch->peer) {
10530 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, "");
10531
10532 ao2_ref(ch->peer, -1);
10533 ch->peer = NULL;
10534 }
10535 }
10536 #endif
10537
10538 if (!ast_strlen_zero(bc->connected.number)) {
10539
10540 misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
10541
10542
10543 misdn_update_remote_party(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
10544 }
10545
10546 ch->l3id = bc->l3_id;
10547 ch->addr = bc->addr;
10548
10549 start_bc_tones(ch);
10550
10551 ch->state = MISDN_CONNECTED;
10552
10553 ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
10554 break;
10555 case EVENT_CONNECT_ACKNOWLEDGE:
10556 ch->l3id = bc->l3_id;
10557 ch->addr = bc->addr;
10558
10559 start_bc_tones(ch);
10560
10561 ch->state = MISDN_CONNECTED;
10562 break;
10563 case EVENT_DISCONNECT:
10564
10565 if (ch) {
10566 if (bc->fac_in.Function != Fac_None) {
10567 misdn_facility_ie_handler(event, bc, ch);
10568 }
10569
10570 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);
10571 if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
10572
10573
10574
10575
10576
10577 chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
10578
10579 ch->state = MISDN_DISCONNECTED;
10580 start_bc_tones(ch);
10581
10582 if (ch->ast) {
10583 ch->ast->hangupcause = bc->cause;
10584 if (bc->cause == AST_CAUSE_USER_BUSY) {
10585 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
10586 }
10587 }
10588 ch->need_busy = 0;
10589 break;
10590 }
10591
10592 bc->need_disconnect = 0;
10593 stop_bc_tones(ch);
10594
10595
10596 held_ch = find_hold_call(bc);
10597 if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
10598 hangup_chan(ch, bc);
10599 }
10600 } else {
10601 held_ch = find_hold_call_l3(bc->l3_id);
10602 if (held_ch) {
10603 if (bc->fac_in.Function != Fac_None) {
10604 misdn_facility_ie_handler(event, bc, held_ch);
10605 }
10606
10607 if (held_ch->hold.state == MISDN_HOLD_ACTIVE) {
10608 bc->need_disconnect = 0;
10609
10610 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
10611
10612
10613
10614
10615
10616 ch = find_hold_active_call(bc);
10617 if (!ch || misdn_attempt_transfer(ch, held_ch)) {
10618 held_ch->hold.state = MISDN_HOLD_DISCONNECT;
10619 hangup_chan(held_ch, bc);
10620 }
10621 #else
10622 hangup_chan(held_ch, bc);
10623 #endif
10624 }
10625 }
10626 }
10627 if (held_ch) {
10628 chan_list_unref(held_ch, "Done with held call");
10629 }
10630 bc->out_cause = -1;
10631 if (bc->need_release) {
10632 misdn_lib_send_event(bc, EVENT_RELEASE);
10633 }
10634 break;
10635 case EVENT_RELEASE:
10636 if (!ch) {
10637 ch = find_hold_call_l3(bc->l3_id);
10638 if (!ch) {
10639 chan_misdn_log(1, bc->port,
10640 " --> no Ch, so we've already released. (%s)\n",
10641 manager_isdn_get_info(event));
10642 return -1;
10643 }
10644 }
10645 if (bc->fac_in.Function != Fac_None) {
10646 misdn_facility_ie_handler(event, bc, ch);
10647 }
10648
10649 bc->need_disconnect = 0;
10650 bc->need_release = 0;
10651
10652 hangup_chan(ch, bc);
10653 release_chan(ch, bc);
10654 break;
10655 case EVENT_RELEASE_COMPLETE:
10656 if (!ch) {
10657 ch = find_hold_call_l3(bc->l3_id);
10658 }
10659
10660 bc->need_disconnect = 0;
10661 bc->need_release = 0;
10662 bc->need_release_complete = 0;
10663
10664 if (ch) {
10665 if (bc->fac_in.Function != Fac_None) {
10666 misdn_facility_ie_handler(event, bc, ch);
10667 }
10668
10669 stop_bc_tones(ch);
10670 hangup_chan(ch, bc);
10671 release_chan(ch, bc);
10672 } else {
10673 #if defined(AST_MISDN_ENHANCEMENTS)
10674
10675
10676
10677
10678
10679 AST_LIST_LOCK(&misdn_cc_records_db);
10680 cc_record = misdn_cc_find_by_bc(bc);
10681 if (cc_record) {
10682
10683 misdn_cc_delete(cc_record);
10684 }
10685 AST_LIST_UNLOCK(&misdn_cc_records_db);
10686 #endif
10687
10688 chan_misdn_log(1, bc->port,
10689 " --> no Ch, so we've already released. (%s)\n",
10690 manager_isdn_get_info(event));
10691 }
10692 break;
10693 case EVENT_BCHAN_ERROR:
10694 case EVENT_CLEANUP:
10695 stop_bc_tones(ch);
10696
10697 switch (ch->state) {
10698 case MISDN_CALLING:
10699 bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
10700 break;
10701 default:
10702 break;
10703 }
10704
10705 hangup_chan(ch, bc);
10706 release_chan(ch, bc);
10707 break;
10708 case EVENT_TONE_GENERATE:
10709 {
10710 int tone_len = bc->tone_cnt;
10711 struct ast_channel *ast = ch->ast;
10712 void *tmp;
10713 int res;
10714 int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
10715
10716 chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);
10717
10718 if (!ast) {
10719 break;
10720 }
10721
10722 if (!ast->generator) {
10723 break;
10724 }
10725
10726 tmp = ast->generatordata;
10727 ast->generatordata = NULL;
10728 generate = ast->generator->generate;
10729
10730 if (tone_len < 0 || tone_len > 512) {
10731 ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
10732 tone_len = 128;
10733 }
10734
10735 res = generate(ast, tmp, tone_len, tone_len);
10736 ast->generatordata = tmp;
10737
10738 if (res) {
10739 ast_log(LOG_WARNING, "Auto-deactivating generator\n");
10740 ast_deactivate_generator(ast);
10741 } else {
10742 bc->tone_cnt = 0;
10743 }
10744 break;
10745 }
10746 case EVENT_BCHAN_DATA:
10747 if (ch->bc->AOCD_need_export) {
10748 export_aoc_vars(ch->originator, ch->ast, ch->bc);
10749 }
10750 if (!misdn_cap_is_speech(ch->bc->capability)) {
10751 struct ast_frame frame;
10752
10753
10754 memset(&frame, 0, sizeof(frame));
10755 frame.frametype = AST_FRAME_VOICE;
10756 frame.subclass.codec = AST_FORMAT_ALAW;
10757 frame.datalen = bc->bframe_len;
10758 frame.samples = bc->bframe_len;
10759 frame.mallocd = 0;
10760 frame.offset = 0;
10761 frame.delivery = ast_tv(0, 0);
10762 frame.src = NULL;
10763 frame.data.ptr = bc->bframe;
10764
10765 if (ch->ast) {
10766 ast_queue_frame(ch->ast, &frame);
10767 }
10768 } else {
10769 struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
10770 int t;
10771
10772 t = ast_poll(&pfd, 1, 0);
10773
10774 if (t < 0) {
10775 chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
10776 break;
10777 }
10778 if (!t) {
10779 chan_misdn_log(9, bc->port, "poll() timed out\n");
10780 break;
10781 }
10782
10783 if (pfd.revents & POLLOUT) {
10784 chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
10785 if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
10786 chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
10787
10788 stop_bc_tones(ch);
10789 hangup_chan(ch, bc);
10790 release_chan(ch, bc);
10791 }
10792 } else {
10793 chan_misdn_log(1, bc->port, "Write Pipe full!\n");
10794 }
10795 }
10796 break;
10797 case EVENT_TIMEOUT:
10798 if (ch && bc) {
10799 chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
10800 }
10801
10802 switch (ch->state) {
10803 case MISDN_DIALING:
10804 case MISDN_PROGRESS:
10805 if (bc->nt && !ch->nttimeout) {
10806 break;
10807 }
10808
10809 case MISDN_CALLING:
10810 case MISDN_ALERTING:
10811 case MISDN_PROCEEDING:
10812 case MISDN_CALLING_ACKNOWLEDGE:
10813 if (bc->nt) {
10814 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10815 hanguptone_indicate(ch);
10816 }
10817
10818 bc->out_cause = AST_CAUSE_UNALLOCATED;
10819 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10820 break;
10821 case MISDN_WAITING4DIGS:
10822 if (bc->nt) {
10823 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10824 bc->out_cause = AST_CAUSE_UNALLOCATED;
10825 hanguptone_indicate(ch);
10826 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10827 } else {
10828 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10829 misdn_lib_send_event(bc, EVENT_RELEASE);
10830 }
10831 break;
10832 case MISDN_CLEANING:
10833 chan_misdn_log(1, bc->port, " --> in state cleaning .. so ignoring, the stack should clean it for us\n");
10834 break;
10835 default:
10836 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10837 break;
10838 }
10839 break;
10840
10841
10842
10843
10844 case EVENT_RETRIEVE:
10845 if (!ch) {
10846 chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
10847 ch = find_hold_call_l3(bc->l3_id);
10848 if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
10849 ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
10850 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10851 break;
10852 }
10853 }
10854
10855
10856 ch->bc = bc;
10857
10858 ch->hold.state = MISDN_HOLD_IDLE;
10859 ch->hold.port = 0;
10860 ch->hold.channel = 0;
10861
10862 ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
10863
10864 if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
10865 chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
10866 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10867 }
10868 break;
10869 case EVENT_HOLD:
10870 {
10871 int hold_allowed;
10872 struct ast_channel *bridged;
10873
10874 misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
10875 if (!hold_allowed) {
10876 chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
10877 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10878 break;
10879 }
10880
10881 bridged = ast_bridged_channel(ch->ast);
10882 if (bridged) {
10883 chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
10884 ch->l3id = bc->l3_id;
10885
10886
10887 ch->bc = NULL;
10888 ch->hold.state = MISDN_HOLD_ACTIVE;
10889 ch->hold.port = bc->port;
10890 ch->hold.channel = bc->channel;
10891
10892 ast_queue_control(ch->ast, AST_CONTROL_HOLD);
10893
10894 misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
10895 } else {
10896 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10897 chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
10898 }
10899 break;
10900 }
10901 case EVENT_NOTIFY:
10902 if (bc->redirecting.to_changed) {
10903
10904 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
10905 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
10906 }
10907 switch (bc->notify_description_code) {
10908 case mISDN_NOTIFY_CODE_DIVERSION_ACTIVATED:
10909
10910 bc->redirecting.to_changed = 0;
10911 break;
10912 case mISDN_NOTIFY_CODE_CALL_IS_DIVERTING:
10913 if (!bc->redirecting.to_changed) {
10914 break;
10915 }
10916 bc->redirecting.to_changed = 0;
10917 if (!ch || !ch->ast) {
10918 break;
10919 }
10920 switch (ch->state) {
10921 case MISDN_ALERTING:
10922
10923 bc->redirecting.reason = mISDN_REDIRECTING_REASON_NO_REPLY;
10924 break;
10925 default:
10926
10927 bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
10928 break;
10929 }
10930 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
10931 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10932 break;
10933 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943 if (!bc->redirecting.to_changed) {
10944 break;
10945 }
10946 bc->redirecting.to_changed = 0;
10947 if (!ch || !ch->ast) {
10948 break;
10949 }
10950 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10951 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
10952 bc->incoming_cid_tag);
10953 break;
10954 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
10955 if (!bc->redirecting.to_changed) {
10956 break;
10957 }
10958 bc->redirecting.to_changed = 0;
10959 if (!ch || !ch->ast) {
10960 break;
10961 }
10962 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10963 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
10964 break;
10965 default:
10966 bc->redirecting.to_changed = 0;
10967 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
10968 bc->notify_description_code);
10969 break;
10970 }
10971 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10972 break;
10973 case EVENT_FACILITY:
10974 if (bc->fac_in.Function == Fac_None) {
10975
10976 chan_misdn_log(0, bc->port," --> Missing facility ie or unknown facility ie contents.\n");
10977 } else {
10978 misdn_facility_ie_handler(event, bc, ch);
10979 }
10980
10981
10982 bc->redirecting.to_changed = 0;
10983 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10984 break;
10985 case EVENT_RESTART:
10986 if (!bc->dummy) {
10987 stop_bc_tones(ch);
10988 release_chan(ch, bc);
10989 }
10990 break;
10991 default:
10992 chan_misdn_log(1, 0, "Got Unknown Event\n");
10993 break;
10994 }
10995
10996 if (ch) {
10997 chan_list_unref(ch, "cb_event complete OK");
10998 }
10999 return RESPONSE_OK;
11000 }
11001
11002
11003
11004 #if defined(AST_MISDN_ENHANCEMENTS)
11005
11006
11007
11008
11009
11010
11011
11012
11013
11014
11015
11016
11017
11018 static int misdn_cc_read(struct ast_channel *chan, const char *function_name,
11019 char *function_args, char *buf, size_t size)
11020 {
11021 char *parse;
11022 struct misdn_cc_record *cc_record;
11023
11024 AST_DECLARE_APP_ARGS(args,
11025 AST_APP_ARG(cc_id);
11026 AST_APP_ARG(get_name);
11027 AST_APP_ARG(other);
11028 );
11029
11030
11031 *buf = 0;
11032
11033 if (ast_strlen_zero(function_args)) {
11034 ast_log(LOG_ERROR, "Function '%s' requires arguments.\n", function_name);
11035 return -1;
11036 }
11037
11038 parse = ast_strdupa(function_args);
11039 AST_STANDARD_APP_ARGS(args, parse);
11040
11041 if (!args.argc || ast_strlen_zero(args.cc_id)) {
11042 ast_log(LOG_ERROR, "Function '%s' missing call completion record ID.\n",
11043 function_name);
11044 return -1;
11045 }
11046 if (!isdigit(*args.cc_id)) {
11047 ast_log(LOG_ERROR, "Function '%s' call completion record ID must be numeric.\n",
11048 function_name);
11049 return -1;
11050 }
11051
11052 if (ast_strlen_zero(args.get_name)) {
11053 ast_log(LOG_ERROR, "Function '%s' missing what-to-get parameter.\n",
11054 function_name);
11055 return -1;
11056 }
11057
11058 AST_LIST_LOCK(&misdn_cc_records_db);
11059 cc_record = misdn_cc_find_by_id(atoi(args.cc_id));
11060 if (cc_record) {
11061 if (!strcasecmp("a-all", args.get_name)) {
11062 snprintf(buf, size, "\"%s\" <%s>", cc_record->redial.caller.name,
11063 cc_record->redial.caller.number);
11064 } else if (!strcasecmp("a-name", args.get_name)) {
11065 ast_copy_string(buf, cc_record->redial.caller.name, size);
11066 } else if (!strncasecmp("a-num", args.get_name, 5)) {
11067 ast_copy_string(buf, cc_record->redial.caller.number, size);
11068 } else if (!strcasecmp("a-ton", args.get_name)) {
11069 snprintf(buf, size, "%d",
11070 misdn_to_ast_plan(cc_record->redial.caller.number_plan)
11071 | misdn_to_ast_ton(cc_record->redial.caller.number_type));
11072 } else if (!strncasecmp("a-pres", args.get_name, 6)) {
11073 ast_copy_string(buf, ast_named_caller_presentation(
11074 misdn_to_ast_pres(cc_record->redial.caller.presentation)
11075 | misdn_to_ast_screen(cc_record->redial.caller.screening)), size);
11076 } else if (!strcasecmp("a-busy", args.get_name)) {
11077 ast_copy_string(buf, cc_record->party_a_free ? "no" : "yes", size);
11078 } else if (!strncasecmp("b-num", args.get_name, 5)) {
11079 ast_copy_string(buf, cc_record->redial.dialed.number, size);
11080 } else if (!strcasecmp("b-ton", args.get_name)) {
11081 snprintf(buf, size, "%d",
11082 misdn_to_ast_plan(cc_record->redial.dialed.number_plan)
11083 | misdn_to_ast_ton(cc_record->redial.dialed.number_type));
11084 } else if (!strcasecmp("port", args.get_name)) {
11085 snprintf(buf, size, "%d", cc_record->port);
11086 } else if (!strcasecmp("available-notify-priority", args.get_name)) {
11087 snprintf(buf, size, "%d", cc_record->remote_user_free.priority);
11088 } else if (!strcasecmp("available-notify-exten", args.get_name)) {
11089 ast_copy_string(buf, cc_record->remote_user_free.exten, size);
11090 } else if (!strcasecmp("available-notify-context", args.get_name)) {
11091 ast_copy_string(buf, cc_record->remote_user_free.context, size);
11092 } else if (!strcasecmp("busy-notify-priority", args.get_name)) {
11093 snprintf(buf, size, "%d", cc_record->b_free.priority);
11094 } else if (!strcasecmp("busy-notify-exten", args.get_name)) {
11095 ast_copy_string(buf, cc_record->b_free.exten, size);
11096 } else if (!strcasecmp("busy-notify-context", args.get_name)) {
11097 ast_copy_string(buf, cc_record->b_free.context, size);
11098 } else {
11099 AST_LIST_UNLOCK(&misdn_cc_records_db);
11100 ast_log(LOG_ERROR, "Function '%s': Unknown what-to-get '%s'.\n", function_name, args.get_name);
11101 return -1;
11102 }
11103 }
11104 AST_LIST_UNLOCK(&misdn_cc_records_db);
11105
11106 return 0;
11107 }
11108 #endif
11109
11110 #if defined(AST_MISDN_ENHANCEMENTS)
11111 static struct ast_custom_function misdn_cc_function = {
11112 .name = "mISDN_CC",
11113 .synopsis = "Get call completion record information.",
11114 .syntax = "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)",
11115 .desc =
11116 "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)\n"
11117 "The following can be retrieved:\n"
11118 "\"a-num\", \"a-name\", \"a-all\", \"a-ton\", \"a-pres\", \"a-busy\",\n"
11119 "\"b-num\", \"b-ton\", \"port\",\n"
11120 " User-A is available for call completion:\n"
11121 " \"available-notify-priority\",\n"
11122 " \"available-notify-exten\",\n"
11123 " \"available-notify-context\",\n"
11124 " User-A is busy:\n"
11125 " \"busy-notify-priority\",\n"
11126 " \"busy-notify-exten\",\n"
11127 " \"busy-notify-context\"\n",
11128 .read = misdn_cc_read,
11129 };
11130 #endif
11131
11132
11133
11134
11135
11136
11137
11138
11139
11140
11141 static int unload_module(void)
11142 {
11143
11144 ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
11145
11146 misdn_tasks_destroy();
11147
11148 if (!g_config_initialized) {
11149 return 0;
11150 }
11151
11152 ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11153
11154
11155 ast_unregister_application("misdn_set_opt");
11156 ast_unregister_application("misdn_facility");
11157 ast_unregister_application("misdn_check_l2l1");
11158 #if defined(AST_MISDN_ENHANCEMENTS)
11159 ast_unregister_application(misdn_command_name);
11160 ast_custom_function_unregister(&misdn_cc_function);
11161 #endif
11162
11163 ast_channel_unregister(&misdn_tech);
11164
11165 free_robin_list();
11166 misdn_cfg_destroy();
11167 misdn_lib_destroy();
11168
11169 ast_free(misdn_out_calls);
11170 ast_free(misdn_in_calls);
11171 ast_free(misdn_debug_only);
11172 ast_free(misdn_ports);
11173 ast_free(misdn_debug);
11174
11175 #if defined(AST_MISDN_ENHANCEMENTS)
11176 misdn_cc_destroy();
11177 #endif
11178
11179 return 0;
11180 }
11181
11182 static int load_module(void)
11183 {
11184 int i, port;
11185 int ntflags = 0, ntkc = 0;
11186 char ports[256] = "";
11187 char tempbuf[BUFFERSIZE + 1];
11188 char ntfile[BUFFERSIZE + 1];
11189 struct misdn_lib_iface iface = {
11190 .cb_event = cb_events,
11191 .cb_log = chan_misdn_log,
11192 .cb_jb_empty = chan_misdn_jb_empty,
11193 };
11194
11195 max_ports = misdn_lib_maxports_get();
11196
11197 if (max_ports <= 0) {
11198 ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
11199 return AST_MODULE_LOAD_DECLINE;
11200 }
11201
11202 if (misdn_cfg_init(max_ports, 0)) {
11203 ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
11204 return AST_MODULE_LOAD_DECLINE;
11205 }
11206 g_config_initialized = 1;
11207
11208 #if defined(AST_MISDN_ENHANCEMENTS)
11209 misdn_cc_init();
11210 #endif
11211
11212 misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
11213 if (!misdn_debug) {
11214 ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
11215 return AST_MODULE_LOAD_DECLINE;
11216 }
11217 misdn_ports = ast_malloc(sizeof(int) * (max_ports + 1));
11218 if (!misdn_ports) {
11219 ast_free(misdn_debug);
11220 ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
11221 return AST_MODULE_LOAD_DECLINE;
11222 }
11223 misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(misdn_debug[0]));
11224 for (i = 1; i <= max_ports; i++) {
11225 misdn_debug[i] = misdn_debug[0];
11226 misdn_ports[i] = i;
11227 }
11228 *misdn_ports = 0;
11229 misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int));
11230 if (!misdn_debug_only) {
11231 ast_free(misdn_ports);
11232 ast_free(misdn_debug);
11233 ast_log(LOG_ERROR, "Out of memory for misdn_debug_only\n");
11234 return AST_MODULE_LOAD_DECLINE;
11235 }
11236
11237 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf));
11238 if (!ast_strlen_zero(tempbuf)) {
11239 tracing = 1;
11240 }
11241
11242 misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11243 if (!misdn_in_calls) {
11244 ast_free(misdn_debug_only);
11245 ast_free(misdn_ports);
11246 ast_free(misdn_debug);
11247 ast_log(LOG_ERROR, "Out of memory for misdn_in_calls\n");
11248 return AST_MODULE_LOAD_DECLINE;
11249 }
11250 misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11251 if (!misdn_out_calls) {
11252 ast_free(misdn_in_calls);
11253 ast_free(misdn_debug_only);
11254 ast_free(misdn_ports);
11255 ast_free(misdn_debug);
11256 ast_log(LOG_ERROR, "Out of memory for misdn_out_calls\n");
11257 return AST_MODULE_LOAD_DECLINE;
11258 }
11259
11260 for (i = 1; i <= max_ports; i++) {
11261 misdn_in_calls[i] = 0;
11262 misdn_out_calls[i] = 0;
11263 }
11264
11265 ast_mutex_init(&cl_te_lock);
11266 ast_mutex_init(&release_lock);
11267
11268 misdn_cfg_update_ptp();
11269 misdn_cfg_get_ports_string(ports);
11270
11271 if (!ast_strlen_zero(ports)) {
11272 chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
11273 }
11274 if (misdn_lib_init(ports, &iface, NULL)) {
11275 chan_misdn_log(0, 0, "No te ports initialized\n");
11276 }
11277
11278 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
11279 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
11280 misdn_cfg_get(0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
11281
11282 misdn_lib_nt_keepcalls(ntkc);
11283 misdn_lib_nt_debug_init(ntflags, ntfile);
11284
11285 if (ast_channel_register(&misdn_tech)) {
11286 ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
11287 unload_module();
11288 return AST_MODULE_LOAD_DECLINE;
11289 }
11290
11291 ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11292
11293 ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
11294 "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
11295 "Sets mISDN opts. and optargs\n"
11296 "\n"
11297 "The available options are:\n"
11298 " a - Have Asterisk detect DTMF tones on called channel\n"
11299 " c - Make crypted outgoing call, optarg is keyindex\n"
11300 " d - Send display text to called phone, text is the optarg\n"
11301 " e - Perform echo cancellation on this channel,\n"
11302 " takes taps as optarg (32,64,128,256)\n"
11303 " e! - Disable echo cancellation on this channel\n"
11304 " f - Enable fax detection\n"
11305 " h - Make digital outgoing call\n"
11306 " h1 - Make HDLC mode digital outgoing call\n"
11307 " i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
11308 " they will be transported inband.\n"
11309 " jb - Set jitter buffer length, optarg is length\n"
11310 " jt - Set jitter buffer upper threshold, optarg is threshold\n"
11311 " jn - Disable jitter buffer\n"
11312 " n - Disable mISDN DSP on channel.\n"
11313 " Disables: echo cancel, DTMF detection, and volume control.\n"
11314 " p - Caller ID presentation,\n"
11315 " optarg is either 'allowed' or 'restricted'\n"
11316 " s - Send Non-inband DTMF as inband\n"
11317 " vr - Rx gain control, optarg is gain\n"
11318 " vt - Tx gain control, optarg is gain\n"
11319 );
11320
11321
11322 ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
11323 "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
11324 "Sends the Facility Message FACILITY_TYPE with \n"
11325 "the given Arguments to the current ISDN Channel\n"
11326 "Supported Facilities are:\n"
11327 "\n"
11328 "type=calldeflect args=Nr where to deflect\n"
11329 #if defined(AST_MISDN_ENHANCEMENTS)
11330 "type=callrerouting args=Nr where to deflect\n"
11331 #endif
11332 );
11333
11334
11335 ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
11336 "misdn_check_l2l1(<port>||g:<groupname>,timeout)\n"
11337 "Checks if the L2 and L1 are up on either the given <port> or\n"
11338 "on the ports in the group with <groupname>\n"
11339 "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
11340 "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
11341 "\n"
11342 "This application, ensures the L1/L2 state of the Ports in a group\n"
11343 "it is intended to make the pmp_l1_check option redundant and to\n"
11344 "fix a buggy switch config from your provider\n"
11345 "\n"
11346 "a sample dialplan would look like:\n\n"
11347 "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
11348 "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
11349 );
11350
11351 #if defined(AST_MISDN_ENHANCEMENTS)
11352 ast_register_application(misdn_command_name, misdn_command_exec, misdn_command_name,
11353 "misdn_command(<command>[,<options>])\n"
11354 "The following commands are defined:\n"
11355 "cc-initialize\n"
11356 " Setup mISDN support for call completion\n"
11357 " Must call before doing any Dial() involving call completion.\n"
11358 "ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11359 " Request Call Completion No Reply activation\n"
11360 "ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11361 " Request Call Completion Busy Subscriber activation\n"
11362 "cc-b-free,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11363 " Set the dialplan location to notify when User-B is available but User-A is busy.\n"
11364 " Setting this dialplan location is optional.\n"
11365 "cc-a-busy,${MISDN_CC_RECORD_ID},<yes/no>\n"
11366 " Set the busy status of call completion User-A\n"
11367 "cc-deactivate,${MISDN_CC_RECORD_ID}\n"
11368 " Deactivate the identified call completion request\n"
11369 "\n"
11370 "MISDN_CC_RECORD_ID is set when Dial() returns and call completion is possible\n"
11371 "MISDN_CC_STATUS is set to ACTIVATED or ERROR after the call completion\n"
11372 "activation request.\n"
11373 "MISDN_ERROR_MSG is set to a descriptive message on error.\n"
11374 );
11375
11376 ast_custom_function_register(&misdn_cc_function);
11377 #endif
11378
11379 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
11380
11381
11382
11383 for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
11384 int l1timeout;
11385 misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
11386 if (l1timeout) {
11387 chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
11388 misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
11389 }
11390 }
11391
11392 chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");
11393
11394 return 0;
11395 }
11396
11397
11398
11399 static int reload(void)
11400 {
11401 reload_config();
11402
11403 return 0;
11404 }
11405
11406
11407
11408 #if defined(AST_MISDN_ENHANCEMENTS)
11409
11410
11411
11412 AST_DEFINE_APP_ARGS_TYPE(misdn_command_args,
11413 AST_APP_ARG(name);
11414 AST_APP_ARG(arg)[10 + 1];
11415 );
11416 #endif
11417
11418 #if defined(AST_MISDN_ENHANCEMENTS)
11419 static void misdn_cc_caller_destroy(void *obj)
11420 {
11421
11422 }
11423 #endif
11424
11425 #if defined(AST_MISDN_ENHANCEMENTS)
11426 static struct misdn_cc_caller *misdn_cc_caller_alloc(struct ast_channel *chan)
11427 {
11428 struct misdn_cc_caller *cc_caller;
11429
11430 if (!(cc_caller = ao2_alloc(sizeof(*cc_caller), misdn_cc_caller_destroy))) {
11431 return NULL;
11432 }
11433
11434 cc_caller->chan = chan;
11435
11436 return cc_caller;
11437 }
11438 #endif
11439
11440 #if defined(AST_MISDN_ENHANCEMENTS)
11441
11442
11443
11444
11445
11446
11447
11448
11449
11450
11451 static int misdn_command_cc_initialize(struct ast_channel *chan, struct misdn_command_args *subcommand)
11452 {
11453 struct misdn_cc_caller *cc_caller;
11454 struct ast_datastore *datastore;
11455
11456 if (!(cc_caller = misdn_cc_caller_alloc(chan))) {
11457 return -1;
11458 }
11459
11460 if (!(datastore = ast_datastore_alloc(&misdn_cc_ds_info, NULL))) {
11461 ao2_ref(cc_caller, -1);
11462 return -1;
11463 }
11464
11465 ast_channel_lock(chan);
11466
11467
11468 datastore->data = cc_caller;
11469 cc_caller = NULL;
11470
11471 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
11472
11473 ast_channel_datastore_add(chan, datastore);
11474
11475 ast_channel_unlock(chan);
11476
11477 return 0;
11478 }
11479 #endif
11480
11481 #if defined(AST_MISDN_ENHANCEMENTS)
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493
11494
11495
11496 static int misdn_command_cc_deactivate(struct ast_channel *chan, struct misdn_command_args *subcommand)
11497 {
11498 long record_id;
11499 const char *error_str;
11500 struct misdn_cc_record *cc_record;
11501 struct misdn_bchannel *bc;
11502 struct misdn_bchannel dummy;
11503
11504 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID})\n";
11505
11506 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11507 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11508 return -1;
11509 }
11510 record_id = atol(subcommand->arg[0]);
11511
11512 AST_LIST_LOCK(&misdn_cc_records_db);
11513 cc_record = misdn_cc_find_by_id(record_id);
11514 if (cc_record && 0 <= cc_record->port) {
11515 if (cc_record->ptp) {
11516 if (cc_record->mode.ptp.bc) {
11517
11518 bc = cc_record->mode.ptp.bc;
11519 bc->fac_out.Function = Fac_None;
11520 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11521 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11522 }
11523 misdn_cc_delete(cc_record);
11524 } else if (cc_record->activated) {
11525 cc_record->error_code = FacError_None;
11526 cc_record->reject_code = FacReject_None;
11527 cc_record->invoke_id = ++misdn_invoke_id;
11528 cc_record->outstanding_message = 1;
11529
11530
11531 misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
11532 dummy.fac_out.Function = Fac_CCBSDeactivate;
11533 dummy.fac_out.u.CCBSDeactivate.InvokeID = cc_record->invoke_id;
11534 dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
11535 dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->mode.ptmp.reference_id;
11536
11537
11538 print_facility(&dummy.fac_out, &dummy);
11539 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11540 }
11541 }
11542 AST_LIST_UNLOCK(&misdn_cc_records_db);
11543
11544
11545 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11546
11547 AST_LIST_LOCK(&misdn_cc_records_db);
11548 cc_record = misdn_cc_find_by_id(record_id);
11549 if (cc_record) {
11550 if (cc_record->port < 0) {
11551
11552 error_str = NULL;
11553 } else if (cc_record->outstanding_message) {
11554 cc_record->outstanding_message = 0;
11555 error_str = misdn_no_response_from_network;
11556 } else if (cc_record->reject_code != FacReject_None) {
11557 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11558 } else if (cc_record->error_code != FacError_None) {
11559 error_str = misdn_to_str_error_code(cc_record->error_code);
11560 } else {
11561 error_str = NULL;
11562 }
11563
11564 misdn_cc_delete(cc_record);
11565 } else {
11566 error_str = NULL;
11567 }
11568 AST_LIST_UNLOCK(&misdn_cc_records_db);
11569 if (error_str) {
11570 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11571 misdn_command_name, subcommand->name, error_str, chan->name);
11572 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11573 }
11574
11575 return 0;
11576 }
11577 #endif
11578
11579 #if defined(AST_MISDN_ENHANCEMENTS)
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594 static int misdn_command_cc_a_busy(struct ast_channel *chan, struct misdn_command_args *subcommand)
11595 {
11596 long record_id;
11597 int party_a_free;
11598 struct misdn_cc_record *cc_record;
11599 struct misdn_bchannel *bc;
11600
11601 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<yes/no>)\n";
11602
11603 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11604 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11605 return -1;
11606 }
11607 record_id = atol(subcommand->arg[0]);
11608
11609 if (ast_true(subcommand->arg[1])) {
11610 party_a_free = 0;
11611 } else if (ast_false(subcommand->arg[1])) {
11612 party_a_free = 1;
11613 } else {
11614 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11615 return -1;
11616 }
11617
11618 AST_LIST_LOCK(&misdn_cc_records_db);
11619 cc_record = misdn_cc_find_by_id(record_id);
11620 if (cc_record && cc_record->party_a_free != party_a_free) {
11621
11622 cc_record->party_a_free = party_a_free;
11623
11624 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11625 cc_record->error_code = FacError_None;
11626 cc_record->reject_code = FacReject_None;
11627
11628
11629 bc = cc_record->mode.ptp.bc;
11630 if (cc_record->party_a_free) {
11631 bc->fac_out.Function = Fac_CCBS_T_Resume;
11632 bc->fac_out.u.CCBS_T_Resume.InvokeID = ++misdn_invoke_id;
11633 } else {
11634 bc->fac_out.Function = Fac_CCBS_T_Suspend;
11635 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
11636 }
11637
11638
11639 print_facility(&bc->fac_out, bc);
11640 misdn_lib_send_event(bc, EVENT_FACILITY);
11641 }
11642 }
11643 AST_LIST_UNLOCK(&misdn_cc_records_db);
11644
11645 return 0;
11646 }
11647 #endif
11648
11649 #if defined(AST_MISDN_ENHANCEMENTS)
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659
11660
11661
11662
11663
11664 static int misdn_command_cc_b_free(struct ast_channel *chan, struct misdn_command_args *subcommand)
11665 {
11666 unsigned index;
11667 long record_id;
11668 int priority;
11669 char *context;
11670 char *exten;
11671 struct misdn_cc_record *cc_record;
11672
11673 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11674
11675
11676 for (index = 0; index < 4; ++index) {
11677 if (ast_strlen_zero(subcommand->arg[index])) {
11678 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11679 return -1;
11680 }
11681 }
11682
11683
11684 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11685 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11686 return -1;
11687 }
11688
11689 record_id = atol(subcommand->arg[0]);
11690 context = subcommand->arg[1];
11691 exten = subcommand->arg[2];
11692 priority = atoi(subcommand->arg[3]);
11693
11694 AST_LIST_LOCK(&misdn_cc_records_db);
11695 cc_record = misdn_cc_find_by_id(record_id);
11696 if (cc_record) {
11697
11698 ast_copy_string(cc_record->b_free.context, context, sizeof(cc_record->b_free.context));
11699 ast_copy_string(cc_record->b_free.exten, exten, sizeof(cc_record->b_free.exten));
11700 cc_record->b_free.priority = priority;
11701 }
11702 AST_LIST_UNLOCK(&misdn_cc_records_db);
11703
11704 return 0;
11705 }
11706 #endif
11707
11708 #if defined(AST_MISDN_ENHANCEMENTS)
11709 struct misdn_cc_request {
11710 enum FacFunction ptmp;
11711 enum FacFunction ptp;
11712 };
11713 #endif
11714
11715 #if defined(AST_MISDN_ENHANCEMENTS)
11716
11717
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729
11730
11731
11732 static int misdn_command_cc_request(struct ast_channel *chan, struct misdn_command_args *subcommand, const struct misdn_cc_request *request)
11733 {
11734 unsigned index;
11735 int request_retention;
11736 long record_id;
11737 int priority;
11738 char *context;
11739 char *exten;
11740 const char *error_str;
11741 struct misdn_cc_record *cc_record;
11742 struct misdn_bchannel *bc;
11743 struct misdn_bchannel dummy;
11744 struct misdn_party_id id;
11745
11746 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11747
11748
11749 for (index = 0; index < 4; ++index) {
11750 if (ast_strlen_zero(subcommand->arg[index])) {
11751 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11752 return -1;
11753 }
11754 }
11755
11756
11757 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11758 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11759 return -1;
11760 }
11761
11762 record_id = atol(subcommand->arg[0]);
11763 context = subcommand->arg[1];
11764 exten = subcommand->arg[2];
11765 priority = atoi(subcommand->arg[3]);
11766
11767 AST_LIST_LOCK(&misdn_cc_records_db);
11768 cc_record = misdn_cc_find_by_id(record_id);
11769 if (cc_record) {
11770
11771 ast_copy_string(cc_record->remote_user_free.context, context,
11772 sizeof(cc_record->remote_user_free.context));
11773 ast_copy_string(cc_record->remote_user_free.exten, exten,
11774 sizeof(cc_record->remote_user_free.exten));
11775 cc_record->remote_user_free.priority = priority;
11776
11777 if (0 <= cc_record->port) {
11778 if (cc_record->ptp) {
11779 if (!cc_record->mode.ptp.bc) {
11780 bc = misdn_lib_get_register_bc(cc_record->port);
11781 if (bc) {
11782 cc_record->mode.ptp.bc = bc;
11783 cc_record->error_code = FacError_None;
11784 cc_record->reject_code = FacReject_None;
11785 cc_record->invoke_id = ++misdn_invoke_id;
11786 cc_record->outstanding_message = 1;
11787 cc_record->activation_requested = 1;
11788
11789 misdn_cfg_get(bc->port, MISDN_CFG_CC_REQUEST_RETENTION,
11790 &request_retention, sizeof(request_retention));
11791 cc_record->mode.ptp.requested_retention = request_retention ? 1 : 0;
11792
11793
11794 bc->fac_out.Function = request->ptp;
11795 bc->fac_out.u.CCBS_T_Request.InvokeID = cc_record->invoke_id;
11796 bc->fac_out.u.CCBS_T_Request.ComponentType = FacComponent_Invoke;
11797 bc->fac_out.u.CCBS_T_Request.Component.Invoke.Q931ie =
11798 cc_record->redial.setup_bc_hlc_llc;
11799 memset(&id, 0, sizeof(id));
11800 id.number_plan = cc_record->redial.dialed.number_plan;
11801 id.number_type = cc_record->redial.dialed.number_type;
11802 ast_copy_string(id.number, cc_record->redial.dialed.number,
11803 sizeof(id.number));
11804 misdn_Address_fill(
11805 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Destination,
11806 &id);
11807 misdn_Address_fill(
11808 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Originating,
11809 &cc_record->redial.caller);
11810 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1;
11811 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator =
11812 (cc_record->redial.caller.presentation != 0) ? 0 : 1;
11813 bc->fac_out.u.CCBS_T_Request.Component.Invoke.RetentionSupported =
11814 request_retention ? 1 : 0;
11815
11816
11817 print_facility(&bc->fac_out, bc);
11818 misdn_lib_send_event(bc, EVENT_REGISTER);
11819 }
11820 }
11821 } else {
11822 cc_record->error_code = FacError_None;
11823 cc_record->reject_code = FacReject_None;
11824 cc_record->invoke_id = ++misdn_invoke_id;
11825 cc_record->outstanding_message = 1;
11826 cc_record->activation_requested = 1;
11827
11828
11829 misdn_make_dummy(&dummy, cc_record->port, 0,
11830 misdn_lib_port_is_nt(cc_record->port), 0);
11831 dummy.fac_out.Function = request->ptmp;
11832 dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
11833 dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
11834 dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID =
11835 cc_record->mode.ptmp.linkage_id;
11836
11837
11838 print_facility(&dummy.fac_out, &dummy);
11839 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11840 }
11841 }
11842 }
11843 AST_LIST_UNLOCK(&misdn_cc_records_db);
11844
11845
11846 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11847
11848 AST_LIST_LOCK(&misdn_cc_records_db);
11849 cc_record = misdn_cc_find_by_id(record_id);
11850 if (cc_record) {
11851 if (!cc_record->activated) {
11852 if (cc_record->port < 0) {
11853
11854 error_str = "No port number";
11855 } else if (cc_record->outstanding_message) {
11856 cc_record->outstanding_message = 0;
11857 error_str = misdn_no_response_from_network;
11858 } else if (cc_record->reject_code != FacReject_None) {
11859 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11860 } else if (cc_record->error_code != FacError_None) {
11861 error_str = misdn_to_str_error_code(cc_record->error_code);
11862 } else if (cc_record->ptp) {
11863 if (cc_record->mode.ptp.bc) {
11864 error_str = "Call-completion already requested";
11865 } else {
11866 error_str = "Could not allocate call-completion signaling link";
11867 }
11868 } else {
11869
11870 error_str = "Unexpected error";
11871 }
11872
11873
11874 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11875
11876 bc = cc_record->mode.ptp.bc;
11877 bc->fac_out.Function = Fac_None;
11878 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11879 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11880 }
11881 misdn_cc_delete(cc_record);
11882 } else {
11883 error_str = NULL;
11884 }
11885 } else {
11886 error_str = misdn_cc_record_not_found;
11887 }
11888 AST_LIST_UNLOCK(&misdn_cc_records_db);
11889 if (error_str) {
11890 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11891 misdn_command_name, subcommand->name, error_str, chan->name);
11892 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11893 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ERROR");
11894 } else {
11895 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ACTIVATED");
11896 }
11897
11898 return 0;
11899 }
11900 #endif
11901
11902 #if defined(AST_MISDN_ENHANCEMENTS)
11903
11904
11905
11906
11907
11908
11909
11910
11911
11912
11913
11914
11915
11916
11917 static int misdn_command_ccbs_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11918 {
11919 static const struct misdn_cc_request request = {
11920 .ptmp = Fac_CCBSRequest,
11921 .ptp = Fac_CCBS_T_Request
11922 };
11923
11924 return misdn_command_cc_request(chan, subcommand, &request);
11925 }
11926 #endif
11927
11928 #if defined(AST_MISDN_ENHANCEMENTS)
11929
11930
11931
11932
11933
11934
11935
11936
11937
11938
11939
11940
11941
11942
11943 static int misdn_command_ccnr_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11944 {
11945 static const struct misdn_cc_request request = {
11946 .ptmp = Fac_CCNRRequest,
11947 .ptp = Fac_CCNR_T_Request
11948 };
11949
11950 return misdn_command_cc_request(chan, subcommand, &request);
11951 }
11952 #endif
11953
11954 #if defined(AST_MISDN_ENHANCEMENTS)
11955 struct misdn_command_table {
11956
11957 const char *name;
11958
11959
11960 int (*func)(struct ast_channel *chan, struct misdn_command_args *subcommand);
11961
11962
11963 int misdn_only;
11964 };
11965 static const struct misdn_command_table misdn_commands[] = {
11966
11967
11968 { "cc-initialize", misdn_command_cc_initialize, 0 },
11969 { "cc-deactivate", misdn_command_cc_deactivate, 0 },
11970 { "cc-a-busy", misdn_command_cc_a_busy, 0 },
11971 { "cc-b-free", misdn_command_cc_b_free, 0 },
11972 { "ccbs-request", misdn_command_ccbs_request, 0 },
11973 { "ccnr-request", misdn_command_ccnr_request, 0 },
11974
11975 };
11976 #endif
11977
11978 #if defined(AST_MISDN_ENHANCEMENTS)
11979
11980
11981
11982
11983
11984
11985
11986
11987
11988
11989 static int misdn_command_exec(struct ast_channel *chan, const char *data)
11990 {
11991 char *parse;
11992 unsigned index;
11993 struct misdn_command_args subcommand;
11994
11995 if (ast_strlen_zero((char *) data)) {
11996 ast_log(LOG_ERROR, "%s requires arguments\n", misdn_command_name);
11997 return -1;
11998 }
11999
12000 ast_log(LOG_DEBUG, "%s(%s)\n", misdn_command_name, (char *) data);
12001
12002 parse = ast_strdupa(data);
12003 AST_STANDARD_APP_ARGS(subcommand, parse);
12004 if (!subcommand.argc || ast_strlen_zero(subcommand.name)) {
12005 ast_log(LOG_ERROR, "%s requires a subcommand\n", misdn_command_name);
12006 return -1;
12007 }
12008
12009 for (index = 0; index < ARRAY_LEN(misdn_commands); ++index) {
12010 if (strcasecmp(misdn_commands[index].name, subcommand.name) == 0) {
12011 strcpy(subcommand.name, misdn_commands[index].name);
12012 if (misdn_commands[index].misdn_only
12013 && strcasecmp(chan->tech->type, misdn_type) != 0) {
12014 ast_log(LOG_WARNING,
12015 "%s(%s) only makes sense with %s channels!\n",
12016 misdn_command_name, subcommand.name, misdn_type);
12017 return -1;
12018 }
12019 return misdn_commands[index].func(chan, &subcommand);
12020 }
12021 }
12022
12023 ast_log(LOG_WARNING, "%s(%s) subcommand is unknown\n", misdn_command_name,
12024 subcommand.name);
12025 return -1;
12026 }
12027 #endif
12028
12029 static int misdn_facility_exec(struct ast_channel *chan, const char *data)
12030 {
12031 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12032 char *parse;
12033 unsigned max_len;
12034
12035 AST_DECLARE_APP_ARGS(args,
12036 AST_APP_ARG(facility_type);
12037 AST_APP_ARG(arg)[99];
12038 );
12039
12040 chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
12041
12042 if (strcasecmp(chan->tech->type, misdn_type)) {
12043 ast_log(LOG_WARNING, "misdn_facility only makes sense with %s channels!\n", misdn_type);
12044 return -1;
12045 }
12046
12047 if (ast_strlen_zero((char *) data)) {
12048 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12049 return -1;
12050 }
12051
12052 parse = ast_strdupa(data);
12053 AST_STANDARD_APP_ARGS(args, parse);
12054
12055 if (ast_strlen_zero(args.facility_type)) {
12056 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12057 return -1;
12058 }
12059
12060 if (!strcasecmp(args.facility_type, "calldeflect")) {
12061 if (ast_strlen_zero(args.arg[0])) {
12062 ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n");
12063 }
12064
12065 #if defined(AST_MISDN_ENHANCEMENTS)
12066 max_len = sizeof(ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
12067 if (max_len < strlen(args.arg[0])) {
12068 ast_log(LOG_WARNING,
12069 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12070 max_len);
12071 return 0;
12072 }
12073 ch->bc->fac_out.Function = Fac_CallDeflection;
12074 ch->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
12075 ch->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
12076 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
12077 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
12078 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;
12079 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(args.arg[0]);
12080 strcpy((char *) ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, args.arg[0]);
12081 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
12082
12083 #else
12084
12085 max_len = sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
12086 if (max_len < strlen(args.arg[0])) {
12087 ast_log(LOG_WARNING,
12088 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12089 max_len);
12090 return 0;
12091 }
12092 ch->bc->fac_out.Function = Fac_CD;
12093 ch->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
12094
12095 strcpy((char *) ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0]);
12096 #endif
12097
12098
12099 print_facility(&ch->bc->fac_out, ch->bc);
12100 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12101 #if defined(AST_MISDN_ENHANCEMENTS)
12102 } else if (!strcasecmp(args.facility_type, "callrerouteing")
12103 || !strcasecmp(args.facility_type, "callrerouting")) {
12104 if (ast_strlen_zero(args.arg[0])) {
12105 ast_log(LOG_WARNING, "Facility: Call rerouting requires an argument: Number\n");
12106 }
12107
12108 max_len = sizeof(ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
12109 if (max_len < strlen(args.arg[0])) {
12110 ast_log(LOG_WARNING,
12111 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12112 max_len);
12113 return 0;
12114 }
12115 ch->bc->fac_out.Function = Fac_CallRerouteing;
12116 ch->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
12117 ch->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
12118
12119 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;
12120 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
12121
12122 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;
12123 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(args.arg[0]);
12124 strcpy((char *) ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, args.arg[0]);
12125 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
12126
12127 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
12128
12129
12130 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
12131 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
12132 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
12133 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
12134 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
12135 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
12136 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
12137
12138 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;
12139 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;
12140
12141
12142 print_facility(&ch->bc->fac_out, ch->bc);
12143 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12144 #endif
12145 } else {
12146 chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type);
12147 }
12148
12149 return 0;
12150 }
12151
12152 static int misdn_check_l2l1(struct ast_channel *chan, const char *data)
12153 {
12154 char *parse;
12155 char group[BUFFERSIZE + 1];
12156 char *port_str;
12157 int port = 0;
12158 int timeout;
12159 int dowait = 0;
12160 int port_up;
12161
12162 AST_DECLARE_APP_ARGS(args,
12163 AST_APP_ARG(grouppar);
12164 AST_APP_ARG(timeout);
12165 );
12166
12167 if (ast_strlen_zero((char *) data)) {
12168 ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
12169 return -1;
12170 }
12171
12172 parse = ast_strdupa(data);
12173 AST_STANDARD_APP_ARGS(args, parse);
12174
12175 if (args.argc != 2) {
12176 ast_log(LOG_WARNING, "Wrong argument count\n");
12177 return 0;
12178 }
12179
12180
12181 timeout = atoi(args.timeout);
12182 port_str = args.grouppar;
12183
12184 if (port_str[0] == 'g' && port_str[1] == ':') {
12185
12186 port_str += 2;
12187 ast_copy_string(group, port_str, sizeof(group));
12188 chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
12189
12190 for (port = misdn_cfg_get_next_port(port);
12191 port > 0;
12192 port = misdn_cfg_get_next_port(port)) {
12193 char cfg_group[BUFFERSIZE + 1];
12194
12195 chan_misdn_log(2, 0, "trying port %d\n", port);
12196
12197 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
12198
12199 if (!strcasecmp(cfg_group, group)) {
12200 port_up = misdn_lib_port_up(port, 1);
12201 if (!port_up) {
12202 chan_misdn_log(2, 0, " --> port '%d'\n", port);
12203 misdn_lib_get_port_up(port);
12204 dowait = 1;
12205 }
12206 }
12207 }
12208 } else {
12209 port = atoi(port_str);
12210 chan_misdn_log(2, 0, "Checking Port: %d\n", port);
12211 port_up = misdn_lib_port_up(port, 1);
12212 if (!port_up) {
12213 misdn_lib_get_port_up(port);
12214 dowait = 1;
12215 }
12216 }
12217
12218 if (dowait) {
12219 chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
12220 ast_safe_sleep(chan, timeout * 1000);
12221 }
12222
12223 return 0;
12224 }
12225
12226 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data)
12227 {
12228 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12229 char *tok;
12230 char *tokb;
12231 char *parse;
12232 int keyidx = 0;
12233 int rxgain = 0;
12234 int txgain = 0;
12235 int change_jitter = 0;
12236
12237 if (strcasecmp(chan->tech->type, misdn_type)) {
12238 ast_log(LOG_WARNING, "misdn_set_opt makes sense only with %s channels!\n", misdn_type);
12239 return -1;
12240 }
12241
12242 if (ast_strlen_zero((char *) data)) {
12243 ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
12244 return -1;
12245 }
12246
12247 parse = ast_strdupa(data);
12248 for (tok = strtok_r(parse, ":", &tokb);
12249 tok;
12250 tok = strtok_r(NULL, ":", &tokb)) {
12251 int neglect = 0;
12252
12253 if (tok[0] == '!') {
12254 neglect = 1;
12255 tok++;
12256 }
12257
12258 switch(tok[0]) {
12259 case 'd' :
12260 ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
12261 chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
12262 break;
12263 case 'n':
12264 chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
12265 ch->bc->nodsp = 1;
12266 break;
12267 case 'j':
12268 chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
12269 tok++;
12270 change_jitter = 1;
12271
12272 switch (tok[0]) {
12273 case 'b':
12274 ch->jb_len = atoi(++tok);
12275 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
12276 break;
12277 case 't' :
12278 ch->jb_upper_threshold = atoi(++tok);
12279 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
12280 break;
12281 case 'n':
12282 ch->bc->nojitter = 1;
12283 chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
12284 break;
12285 default:
12286 ch->jb_len = 4000;
12287 ch->jb_upper_threshold = 0;
12288 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
12289 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
12290 break;
12291 }
12292 break;
12293 case 'v':
12294 tok++;
12295
12296 switch (tok[0]) {
12297 case 'r' :
12298 rxgain = atoi(++tok);
12299 if (rxgain < -8) {
12300 rxgain = -8;
12301 }
12302 if (rxgain > 8) {
12303 rxgain = 8;
12304 }
12305 ch->bc->rxgain = rxgain;
12306 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
12307 break;
12308 case 't':
12309 txgain = atoi(++tok);
12310 if (txgain < -8) {
12311 txgain = -8;
12312 }
12313 if (txgain > 8) {
12314 txgain = 8;
12315 }
12316 ch->bc->txgain = txgain;
12317 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
12318 break;
12319 }
12320 break;
12321 case 'c':
12322 keyidx = atoi(++tok);
12323 {
12324 char keys[4096];
12325 char *key = NULL;
12326 char *tmp = keys;
12327 int i;
12328
12329 misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
12330
12331 for (i = 0; i < keyidx; i++) {
12332 key = strsep(&tmp, ",");
12333 }
12334
12335 if (key) {
12336 ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
12337 }
12338
12339 chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
12340 break;
12341 }
12342 case 'e':
12343 chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
12344
12345 if (neglect) {
12346 chan_misdn_log(1, ch->bc->port, " --> disabled\n");
12347 #ifdef MISDN_1_2
12348 *ch->bc->pipeline = 0;
12349 #else
12350 ch->bc->ec_enable = 0;
12351 #endif
12352 } else {
12353 #ifdef MISDN_1_2
12354 update_pipeline_config(ch->bc);
12355 #else
12356 ch->bc->ec_enable = 1;
12357 ch->bc->orig = ch->originator;
12358 tok++;
12359 if (*tok) {
12360 ch->bc->ec_deftaps = atoi(tok);
12361 }
12362 #endif
12363 }
12364 break;
12365 case 'h':
12366 chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
12367
12368 if (strlen(tok) > 1 && tok[1] == '1') {
12369 chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
12370 if (!ch->bc->hdlc) {
12371 ch->bc->hdlc = 1;
12372 }
12373 }
12374 ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
12375 break;
12376 case 's':
12377 chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
12378 ch->bc->send_dtmf = 1;
12379 break;
12380 case 'f':
12381 chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
12382 ch->faxdetect = 1;
12383 misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
12384 break;
12385 case 'a':
12386 chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
12387 ch->ast_dsp = 1;
12388 break;
12389 case 'p':
12390 chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
12391
12392 if (strstr(tok, "allowed")) {
12393 ch->bc->presentation = 0;
12394 ch->bc->set_presentation = 1;
12395 } else if (strstr(tok, "restricted")) {
12396 ch->bc->presentation = 1;
12397 ch->bc->set_presentation = 1;
12398 } else if (strstr(tok, "not_screened")) {
12399 chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
12400 ch->bc->presentation = 1;
12401 ch->bc->set_presentation = 1;
12402 }
12403 break;
12404 case 'i' :
12405 chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
12406 ch->ignore_dtmf = 1;
12407 break;
12408 default:
12409 break;
12410 }
12411 }
12412
12413 if (change_jitter) {
12414 config_jitterbuffer(ch);
12415 }
12416
12417 if (ch->faxdetect || ch->ast_dsp) {
12418 if (!ch->dsp) {
12419 ch->dsp = ast_dsp_new();
12420 }
12421 if (ch->dsp) {
12422 ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
12423 }
12424 }
12425
12426 if (ch->ast_dsp) {
12427 chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
12428 ch->bc->nodsp = 1;
12429 }
12430
12431 return 0;
12432 }
12433
12434
12435 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len)
12436 {
12437 struct chan_list *ch;
12438 int res;
12439
12440 ch = find_chan_by_bc(bc);
12441 if (!ch) {
12442 return 0;
12443 }
12444
12445 if (ch->jb) {
12446 res = misdn_jb_empty(ch->jb, buf, len);
12447 } else {
12448 res = 0;
12449 }
12450 chan_list_unref(ch, "Done emptying jb");
12451
12452 return res;
12453 }
12454
12455
12456
12457
12458
12459
12460
12461
12462
12463 struct misdn_jb *misdn_jb_init(int size, int upper_threshold)
12464 {
12465 struct misdn_jb *jb;
12466
12467 jb = ast_calloc(1, sizeof(*jb));
12468 if (!jb) {
12469 chan_misdn_log(-1, 0, "No free Mem for jb\n");
12470 return NULL;
12471 }
12472 jb->size = size;
12473 jb->upper_threshold = upper_threshold;
12474
12475
12476
12477
12478
12479 jb->samples = ast_calloc(size, sizeof(*jb->samples));
12480 if (!jb->samples) {
12481 ast_free(jb);
12482 chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
12483 return NULL;
12484 }
12485
12486 jb->ok = ast_calloc(size, sizeof(*jb->ok));
12487 if (!jb->ok) {
12488 ast_free(jb->samples);
12489 ast_free(jb);
12490 chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
12491 return NULL;
12492 }
12493
12494 ast_mutex_init(&jb->mutexjb);
12495
12496 return jb;
12497 }
12498
12499
12500 void misdn_jb_destroy(struct misdn_jb *jb)
12501 {
12502 ast_mutex_destroy(&jb->mutexjb);
12503
12504 ast_free(jb->ok);
12505 ast_free(jb->samples);
12506 ast_free(jb);
12507 }
12508
12509
12510
12511 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
12512 {
12513 int i;
12514 int j;
12515 int rp;
12516 int wp;
12517
12518 if (!jb || ! data) {
12519 return 0;
12520 }
12521
12522 ast_mutex_lock(&jb->mutexjb);
12523
12524 wp = jb->wp;
12525 rp = jb->rp;
12526
12527 for (i = 0; i < len; i++) {
12528 jb->samples[wp] = data[i];
12529 jb->ok[wp] = 1;
12530 wp = (wp != jb->size - 1) ? wp + 1 : 0;
12531
12532 if (wp == jb->rp) {
12533 jb->state_full = 1;
12534 }
12535 }
12536
12537 if (wp >= rp) {
12538 jb->state_buffer = wp - rp;
12539 } else {
12540 jb->state_buffer = jb->size - rp + wp;
12541 }
12542 chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12543
12544 if (jb->state_full) {
12545 jb->wp = wp;
12546
12547 rp = wp;
12548 for (j = 0; j < jb->upper_threshold; j++) {
12549 rp = (rp != 0) ? rp - 1 : jb->size - 1;
12550 }
12551 jb->rp = rp;
12552 jb->state_full = 0;
12553 jb->state_empty = 1;
12554
12555 ast_mutex_unlock(&jb->mutexjb);
12556
12557 return -1;
12558 }
12559
12560 if (!jb->state_empty) {
12561 jb->bytes_wrote += len;
12562 if (jb->bytes_wrote >= jb->upper_threshold) {
12563 jb->state_empty = 1;
12564 jb->bytes_wrote = 0;
12565 }
12566 }
12567 jb->wp = wp;
12568
12569 ast_mutex_unlock(&jb->mutexjb);
12570
12571 return 0;
12572 }
12573
12574
12575
12576
12577 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
12578 {
12579 int i;
12580 int wp;
12581 int rp;
12582 int read = 0;
12583
12584 ast_mutex_lock(&jb->mutexjb);
12585
12586 rp = jb->rp;
12587 wp = jb->wp;
12588
12589 if (jb->state_empty) {
12590 for (i = 0; i < len; i++) {
12591 if (wp == rp) {
12592 jb->rp = rp;
12593 jb->state_empty = 0;
12594
12595 ast_mutex_unlock(&jb->mutexjb);
12596
12597 return read;
12598 } else {
12599 if (jb->ok[rp] == 1) {
12600 data[i] = jb->samples[rp];
12601 jb->ok[rp] = 0;
12602 rp = (rp != jb->size - 1) ? rp + 1 : 0;
12603 read += 1;
12604 }
12605 }
12606 }
12607
12608 if (wp >= rp) {
12609 jb->state_buffer = wp - rp;
12610 } else {
12611 jb->state_buffer = jb->size - rp + wp;
12612 }
12613 chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12614
12615 jb->rp = rp;
12616 } else {
12617 chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
12618 }
12619
12620 ast_mutex_unlock(&jb->mutexjb);
12621
12622 return read;
12623 }
12624
12625
12626
12627
12628
12629 static void chan_misdn_log(int level, int port, char *tmpl, ...)
12630 {
12631 va_list ap;
12632 char buf[1024];
12633 char port_buf[8];
12634
12635 if (!(0 <= port && port <= max_ports)) {
12636 ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
12637 port = 0;
12638 level = -1;
12639 } else if (!(level == -1
12640 || (misdn_debug_only[port]
12641 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12642 : level <= misdn_debug[port])
12643 || (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)))) {
12644
12645
12646
12647
12648 return;
12649 }
12650
12651 snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
12652 va_start(ap, tmpl);
12653 vsnprintf(buf, sizeof(buf), tmpl, ap);
12654 va_end(ap);
12655
12656 if (level == -1) {
12657 ast_log(LOG_WARNING, "%s", buf);
12658 } else if (misdn_debug_only[port]
12659 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12660 : level <= misdn_debug[port]) {
12661 ast_console_puts(port_buf);
12662 ast_console_puts(buf);
12663 }
12664
12665 if (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)) {
12666 char ctimebuf[30];
12667 time_t tm;
12668 char *tmp;
12669 char *p;
12670 FILE *fp;
12671
12672 fp = fopen(global_tracefile, "a+");
12673 if (!fp) {
12674 ast_console_puts("Error opening Tracefile: [ ");
12675 ast_console_puts(global_tracefile);
12676 ast_console_puts(" ] ");
12677
12678 ast_console_puts(strerror(errno));
12679 ast_console_puts("\n");
12680 return;
12681 }
12682
12683 tm = time(NULL);
12684 tmp = ctime_r(&tm, ctimebuf);
12685 p = strchr(tmp, '\n');
12686 if (p) {
12687 *p = ':';
12688 }
12689 fputs(tmp, fp);
12690 fputs(" ", fp);
12691 fputs(port_buf, fp);
12692 fputs(" ", fp);
12693 fputs(buf, fp);
12694
12695 fclose(fp);
12696 }
12697 }
12698
12699 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Channel driver for mISDN Support (BRI/PRI)",
12700 .load = load_module,
12701 .unload = unload_module,
12702 .reload = reload,
12703 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
12704 );