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