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: 328209 $")
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_CONGESTION:
06987 chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc->pid);
06988
06989 p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
06990 start_bc_tones(p);
06991 misdn_lib_send_event(p->bc, EVENT_DISCONNECT);
06992
06993 if (p->bc->nt) {
06994 hanguptone_indicate(p);
06995 }
06996 break;
06997 case -1 :
06998 chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc->pid);
06999
07000 stop_indicate(p);
07001
07002 if (p->state == MISDN_CONNECTED) {
07003 start_bc_tones(p);
07004 }
07005 break;
07006 case AST_CONTROL_HOLD:
07007 ast_moh_start(ast, data, p->mohinterpret);
07008 chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc->pid);
07009 break;
07010 case AST_CONTROL_UNHOLD:
07011 ast_moh_stop(ast);
07012 chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc->pid);
07013 break;
07014 case AST_CONTROL_CONNECTED_LINE:
07015 chan_misdn_log(1, p->bc->port, "* IND :\tconnected line update pid:%d\n", p->bc->pid);
07016 misdn_update_connected_line(ast, p->bc, p->originator);
07017 break;
07018 case AST_CONTROL_REDIRECTING:
07019 chan_misdn_log(1, p->bc->port, "* IND :\tredirecting info update pid:%d\n", p->bc->pid);
07020 misdn_update_redirecting(ast, p->bc, p->originator);
07021 break;
07022 default:
07023 chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc->pid);
07024 return -1;
07025 }
07026
07027 return 0;
07028 }
07029
07030 static int misdn_hangup(struct ast_channel *ast)
07031 {
07032 struct chan_list *p;
07033 struct misdn_bchannel *bc;
07034 const char *var;
07035
07036 if (!ast) {
07037 return -1;
07038 }
07039
07040 ast_debug(1, "misdn_hangup(%s)\n", ast->name);
07041
07042
07043 ast_mutex_lock(&release_lock);
07044 p = MISDN_ASTERISK_TECH_PVT(ast);
07045 if (!p) {
07046 ast_mutex_unlock(&release_lock);
07047 return -1;
07048 }
07049 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
07050
07051 if (!misdn_chan_is_valid(p)) {
07052 ast_mutex_unlock(&release_lock);
07053 chan_list_unref(p, "Release ast_channel reference. Was not active?");
07054 return 0;
07055 }
07056
07057 if (p->hold.state == MISDN_HOLD_IDLE) {
07058 bc = p->bc;
07059 } else {
07060 p->hold.state = MISDN_HOLD_DISCONNECT;
07061 bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
07062 if (!bc) {
07063 chan_misdn_log(4, p->hold.port,
07064 "misdn_hangup: Could not find held bc for (%s)\n", ast->name);
07065 release_chan_early(p);
07066 ast_mutex_unlock(&release_lock);
07067 chan_list_unref(p, "Release ast_channel reference");
07068 return 0;
07069 }
07070 }
07071
07072 if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
07073
07074 ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
07075 release_chan_early(p);
07076 if (bc) {
07077 misdn_lib_release(bc);
07078 }
07079 ast_mutex_unlock(&release_lock);
07080 chan_list_unref(p, "Release ast_channel reference");
07081 return 0;
07082 }
07083 if (!bc) {
07084 ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
07085 misdn_get_ch_state(p), p->l3id);
07086 release_chan_early(p);
07087 ast_mutex_unlock(&release_lock);
07088 chan_list_unref(p, "Release ast_channel reference");
07089 return 0;
07090 }
07091
07092 p->ast = NULL;
07093 p->need_hangup = 0;
07094 p->need_queue_hangup = 0;
07095 p->need_busy = 0;
07096
07097 if (!bc->nt) {
07098 stop_bc_tones(p);
07099 }
07100
07101 bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
07102
07103
07104
07105 var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
07106 if (!var) {
07107 var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
07108 }
07109 if (var) {
07110 int tmpcause;
07111
07112 tmpcause = atoi(var);
07113 bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
07114 }
07115
07116 var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
07117 if (var) {
07118 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
07119 ast_copy_string(bc->uu, var, sizeof(bc->uu));
07120 bc->uulen = strlen(bc->uu);
07121 }
07122
07123
07124 chan_misdn_log(1, bc->port,
07125 "* IND : HANGUP\tpid:%d context:%s dialed:%s caller:\"%s\" <%s> State:%s\n",
07126 bc->pid,
07127 ast->context,
07128 ast->exten,
07129 (ast->caller.id.name.valid && ast->caller.id.name.str)
07130 ? ast->caller.id.name.str : "",
07131 (ast->caller.id.number.valid && ast->caller.id.number.str)
07132 ? ast->caller.id.number.str : "",
07133 misdn_get_ch_state(p));
07134 chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
07135 chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
07136 chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
07137
07138 switch (p->state) {
07139 case MISDN_INCOMING_SETUP:
07140
07141
07142
07143
07144 ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
07145 release_chan(p, bc);
07146 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
07147 ast_mutex_unlock(&release_lock);
07148 chan_list_unref(p, "Release ast_channel reference");
07149 return 0;
07150 case MISDN_DIALING:
07151 if (p->hold.state == MISDN_HOLD_IDLE) {
07152 start_bc_tones(p);
07153 hanguptone_indicate(p);
07154 }
07155
07156 if (bc->need_disconnect) {
07157 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07158 }
07159 break;
07160 case MISDN_CALLING_ACKNOWLEDGE:
07161 if (p->hold.state == MISDN_HOLD_IDLE) {
07162 start_bc_tones(p);
07163 hanguptone_indicate(p);
07164 }
07165
07166 if (bc->need_disconnect) {
07167 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07168 }
07169 break;
07170
07171 case MISDN_CALLING:
07172 case MISDN_ALERTING:
07173 case MISDN_PROGRESS:
07174 case MISDN_PROCEEDING:
07175 if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
07176 hanguptone_indicate(p);
07177 }
07178
07179 if (bc->need_disconnect) {
07180 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07181 }
07182 break;
07183 case MISDN_CONNECTED:
07184
07185 if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
07186 start_bc_tones(p);
07187 hanguptone_indicate(p);
07188 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
07189 }
07190 if (bc->need_disconnect) {
07191 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07192 }
07193 break;
07194 case MISDN_DISCONNECTED:
07195 if (bc->need_release) {
07196 misdn_lib_send_event(bc, EVENT_RELEASE);
07197 }
07198 break;
07199
07200 case MISDN_CLEANING:
07201 ast_mutex_unlock(&release_lock);
07202 chan_list_unref(p, "Release ast_channel reference");
07203 return 0;
07204
07205 case MISDN_BUSY:
07206 break;
07207 default:
07208 if (bc->nt) {
07209 bc->out_cause = -1;
07210 if (bc->need_release) {
07211 misdn_lib_send_event(bc, EVENT_RELEASE);
07212 }
07213 } else {
07214 if (bc->need_disconnect) {
07215 misdn_lib_send_event(bc, EVENT_DISCONNECT);
07216 }
07217 }
07218 break;
07219 }
07220
07221 p->state = MISDN_CLEANING;
07222 chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
07223 misdn_get_ch_state(p));
07224
07225 ast_mutex_unlock(&release_lock);
07226 chan_list_unref(p, "Release ast_channel reference");
07227 return 0;
07228 }
07229
07230
07231 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
07232 {
07233 struct ast_frame *f;
07234
07235 if (tmp->dsp) {
07236 f = ast_dsp_process(tmp->ast, tmp->dsp, frame);
07237 } else {
07238 chan_misdn_log(0, tmp->bc->port, "No DSP-Path found\n");
07239 return NULL;
07240 }
07241
07242 if (!f || (f->frametype != AST_FRAME_DTMF)) {
07243 return f;
07244 }
07245
07246 ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass.integer);
07247
07248 if (tmp->faxdetect && (f->subclass.integer == 'f')) {
07249
07250 if (!tmp->faxhandled) {
07251 struct ast_channel *ast = tmp->ast;
07252 tmp->faxhandled++;
07253 chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
07254 tmp->bc->rxgain = 0;
07255 isdn_lib_update_rxgain(tmp->bc);
07256 tmp->bc->txgain = 0;
07257 isdn_lib_update_txgain(tmp->bc);
07258 #ifdef MISDN_1_2
07259 *tmp->bc->pipeline = 0;
07260 #else
07261 tmp->bc->ec_enable = 0;
07262 #endif
07263 isdn_lib_update_ec(tmp->bc);
07264 isdn_lib_stop_dtmf(tmp->bc);
07265 switch (tmp->faxdetect) {
07266 case 1:
07267 if (strcmp(ast->exten, "fax")) {
07268 char *context;
07269 char context_tmp[BUFFERSIZE];
07270 misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
07271 context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
07272 if (ast_exists_extension(ast, context, "fax", 1,
07273 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
07274 ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
07275
07276 pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
07277 if (ast_async_goto(ast, context, "fax", 1)) {
07278 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
07279 }
07280 } else {
07281 ast_log(LOG_NOTICE, "Fax detected but no fax extension, context:%s exten:%s\n", context, ast->exten);
07282 }
07283 } else {
07284 ast_debug(1, "Already in a fax extension, not redirecting\n");
07285 }
07286 break;
07287 case 2:
07288 ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
07289 break;
07290 default:
07291 break;
07292 }
07293 } else {
07294 ast_debug(1, "Fax already handled\n");
07295 }
07296 }
07297
07298 if (tmp->ast_dsp && (f->subclass.integer != 'f')) {
07299 chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass.integer);
07300 }
07301
07302 return f;
07303 }
07304
07305
07306 static struct ast_frame *misdn_read(struct ast_channel *ast)
07307 {
07308 struct chan_list *tmp;
07309 int len, t;
07310 struct pollfd pfd = { .fd = -1, .events = POLLIN };
07311
07312 if (!ast) {
07313 chan_misdn_log(1, 0, "misdn_read called without ast\n");
07314 return NULL;
07315 }
07316 if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
07317 chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
07318 return NULL;
07319 }
07320
07321 if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
07322 chan_misdn_log(1, 0, "misdn_read called without bc\n");
07323 return NULL;
07324 }
07325
07326 pfd.fd = tmp->pipe[0];
07327 t = ast_poll(&pfd, 1, 20);
07328
07329 if (t < 0) {
07330 chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
07331 return NULL;
07332 }
07333
07334 if (!t) {
07335 chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
07336 len = 160;
07337 } else if (pfd.revents & POLLIN) {
07338 len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
07339
07340 if (len <= 0) {
07341
07342 chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
07343 return NULL;
07344 }
07345 } else {
07346 return NULL;
07347 }
07348
07349 tmp->frame.frametype = AST_FRAME_VOICE;
07350 tmp->frame.subclass.codec = AST_FORMAT_ALAW;
07351 tmp->frame.datalen = len;
07352 tmp->frame.samples = len;
07353 tmp->frame.mallocd = 0;
07354 tmp->frame.offset = 0;
07355 tmp->frame.delivery = ast_tv(0, 0);
07356 tmp->frame.src = NULL;
07357 tmp->frame.data.ptr = tmp->ast_rd_buf;
07358
07359 if (tmp->faxdetect && !tmp->faxhandled) {
07360 if (tmp->faxdetect_timeout) {
07361 if (ast_tvzero(tmp->faxdetect_tv)) {
07362 tmp->faxdetect_tv = ast_tvnow();
07363 chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
07364 return process_ast_dsp(tmp, &tmp->frame);
07365 } else {
07366 struct timeval tv_now = ast_tvnow();
07367 int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
07368 if (diff <= (tmp->faxdetect_timeout * 1000)) {
07369 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
07370 return process_ast_dsp(tmp, &tmp->frame);
07371 } else {
07372 chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
07373 tmp->faxdetect = 0;
07374 return &tmp->frame;
07375 }
07376 }
07377 } else {
07378 chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
07379 return process_ast_dsp(tmp, &tmp->frame);
07380 }
07381 } else {
07382 if (tmp->ast_dsp) {
07383 return process_ast_dsp(tmp, &tmp->frame);
07384 } else {
07385 return &tmp->frame;
07386 }
07387 }
07388 }
07389
07390
07391 static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
07392 {
07393 struct chan_list *ch;
07394 int i = 0;
07395
07396 if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
07397 return -1;
07398 }
07399
07400 if (ch->hold.state != MISDN_HOLD_IDLE) {
07401 chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
07402 return 0;
07403 }
07404
07405 if (!ch->bc) {
07406 ast_log(LOG_WARNING, "private but no bc\n");
07407 return -1;
07408 }
07409
07410 if (ch->notxtone) {
07411 chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
07412 return 0;
07413 }
07414
07415
07416 if (!frame->subclass.codec) {
07417 chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
07418 return 0;
07419 }
07420
07421 if (!(frame->subclass.codec & prefformat)) {
07422 chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%s\n", ast_getformatname(frame->subclass.codec));
07423 return 0;
07424 }
07425
07426
07427 if (!frame->samples) {
07428 chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
07429
07430 if (!strcmp(frame->src,"ast_prod")) {
07431 chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
07432
07433 if (ch->ts) {
07434 chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
07435 misdn_lib_tone_generator_start(ch->bc);
07436 }
07437 return 0;
07438 }
07439
07440 return -1;
07441 }
07442
07443 if (!ch->bc->addr) {
07444 chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
07445 return 0;
07446 }
07447
07448 #ifdef MISDN_DEBUG
07449 {
07450 int i;
07451 int max = 5 > frame->samples ? frame->samples : 5;
07452
07453 ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
07454
07455 for (i = 0; i < max; i++) {
07456 ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]);
07457 }
07458 }
07459 #endif
07460
07461 switch (ch->bc->bc_state) {
07462 case BCHAN_ACTIVATED:
07463 case BCHAN_BRIDGED:
07464 break;
07465 default:
07466 if (!ch->dropped_frame_cnt) {
07467 chan_misdn_log(5, ch->bc->port,
07468 "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n",
07469 frame->samples, ch->bc->addr, ast->exten,
07470 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
07471 misdn_get_ch_state(ch), ch->bc->bc_state, ch->bc->l3_id);
07472 }
07473
07474 if (++ch->dropped_frame_cnt > 100) {
07475 ch->dropped_frame_cnt = 0;
07476 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);
07477 }
07478
07479 return 0;
07480 }
07481
07482 chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
07483 if (!ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability)) {
07484
07485 if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) {
07486 if (ch->bc->active) {
07487 cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
07488 }
07489 }
07490
07491 } else {
07492
07493 i = misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
07494 }
07495
07496 return 0;
07497 }
07498
07499 static enum ast_bridge_result misdn_bridge(struct ast_channel *c0,
07500 struct ast_channel *c1, int flags,
07501 struct ast_frame **fo,
07502 struct ast_channel **rc,
07503 int timeoutms)
07504 {
07505 struct chan_list *ch1, *ch2;
07506 struct ast_channel *carr[2], *who;
07507 int to = -1;
07508 struct ast_frame *f;
07509 int p1_b, p2_b;
07510 int bridging;
07511
07512 ch1 = get_chan_by_ast(c0);
07513 if (!ch1) {
07514 return -1;
07515 }
07516 ch2 = get_chan_by_ast(c1);
07517 if (!ch2) {
07518 chan_list_unref(ch1, "Failed to find ch2");
07519 return -1;
07520 }
07521
07522 carr[0] = c0;
07523 carr[1] = c1;
07524
07525 misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
07526 misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));
07527
07528 if (! p1_b || ! p2_b) {
07529 ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
07530 chan_list_unref(ch1, "Bridge fallback ch1");
07531 chan_list_unref(ch2, "Bridge fallback ch2");
07532 return AST_BRIDGE_FAILED;
07533 }
07534
07535 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
07536 if (bridging) {
07537
07538 chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
07539 misdn_lib_bridge(ch1->bc, ch2->bc);
07540 }
07541
07542 ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
07543
07544 chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between \"%s\" <%s> and \"%s\" <%s>\n",
07545 ch1->bc->caller.name,
07546 ch1->bc->caller.number,
07547 ch2->bc->caller.name,
07548 ch2->bc->caller.number);
07549
07550 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
07551 ch1->ignore_dtmf = 1;
07552 }
07553
07554 if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
07555 ch2->ignore_dtmf = 1;
07556 }
07557
07558 for (;;) {
07559 to = -1;
07560 who = ast_waitfor_n(carr, 2, &to);
07561
07562 if (!who) {
07563 ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
07564 break;
07565 }
07566 f = ast_read(who);
07567
07568 if (!f || f->frametype == AST_FRAME_CONTROL) {
07569
07570
07571 if (!f) {
07572 chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
07573 } else {
07574 chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass.integer);
07575 }
07576
07577 *fo = f;
07578 *rc = who;
07579 break;
07580 }
07581
07582 if (f->frametype == AST_FRAME_DTMF) {
07583 chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass.integer, who->exten);
07584
07585 *fo = f;
07586 *rc = who;
07587 break;
07588 }
07589
07590 #if 0
07591 if (f->frametype == AST_FRAME_VOICE) {
07592 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
07593
07594 continue;
07595 }
07596 #endif
07597
07598 ast_write((who == c0) ? c1 : c0, f);
07599 }
07600
07601 chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
07602
07603 misdn_lib_split_bridge(ch1->bc, ch2->bc);
07604
07605 chan_list_unref(ch1, "Bridge complete ch1");
07606 chan_list_unref(ch2, "Bridge complete ch2");
07607 return AST_BRIDGE_COMPLETE;
07608 }
07609
07610
07611
07612 static int dialtone_indicate(struct chan_list *cl)
07613 {
07614 struct ast_channel *ast = cl->ast;
07615 int nd = 0;
07616
07617 if (!ast) {
07618 chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
07619 return -1;
07620 }
07621
07622 misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));
07623
07624 if (nd) {
07625 chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
07626 return 0;
07627 }
07628
07629 chan_misdn_log(3, cl->bc->port, " --> Dial\n");
07630
07631 cl->ts = ast_get_indication_tone(ast->zone, "dial");
07632
07633 if (cl->ts) {
07634 cl->notxtone = 0;
07635 cl->norxtone = 0;
07636
07637 ast_playtones_start(ast, 0, cl->ts->data, 0);
07638 }
07639
07640 return 0;
07641 }
07642
07643 static void hanguptone_indicate(struct chan_list *cl)
07644 {
07645 misdn_lib_send_tone(cl->bc, TONE_HANGUP);
07646 }
07647
07648 static int stop_indicate(struct chan_list *cl)
07649 {
07650 struct ast_channel *ast = cl->ast;
07651
07652 if (!ast) {
07653 chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
07654 return -1;
07655 }
07656
07657 chan_misdn_log(3, cl->bc->port, " --> None\n");
07658 misdn_lib_tone_generator_stop(cl->bc);
07659 ast_playtones_stop(ast);
07660
07661 if (cl->ts) {
07662 cl->ts = ast_tone_zone_sound_unref(cl->ts);
07663 }
07664
07665 return 0;
07666 }
07667
07668
07669 static int start_bc_tones(struct chan_list* cl)
07670 {
07671 misdn_lib_tone_generator_stop(cl->bc);
07672 cl->notxtone = 0;
07673 cl->norxtone = 0;
07674 return 0;
07675 }
07676
07677 static int stop_bc_tones(struct chan_list *cl)
07678 {
07679 if (!cl) {
07680 return -1;
07681 }
07682
07683 cl->notxtone = 1;
07684 cl->norxtone = 1;
07685
07686 return 0;
07687 }
07688
07689
07690
07691
07692
07693
07694
07695
07696
07697 static void chan_list_destructor(void *obj)
07698 {
07699 struct chan_list *ch = obj;
07700
07701 #if defined(AST_MISDN_ENHANCEMENTS)
07702 if (ch->peer) {
07703 ao2_ref(ch->peer, -1);
07704 ch->peer = NULL;
07705 }
07706 #endif
07707
07708 if (ch->dsp) {
07709 ast_dsp_free(ch->dsp);
07710 ch->dsp = NULL;
07711 }
07712
07713
07714 if (ch->jb) {
07715 misdn_jb_destroy(ch->jb);
07716 ch->jb = NULL;
07717 }
07718
07719 if (ch->overlap_dial) {
07720 if (ch->overlap_dial_task != -1) {
07721 misdn_tasks_remove(ch->overlap_dial_task);
07722 ch->overlap_dial_task = -1;
07723 }
07724 ast_mutex_destroy(&ch->overlap_tv_lock);
07725 }
07726
07727 if (-1 < ch->pipe[0]) {
07728 close(ch->pipe[0]);
07729 }
07730 if (-1 < ch->pipe[1]) {
07731 close(ch->pipe[1]);
07732 }
07733 }
07734
07735
07736 static struct chan_list *chan_list_init(int orig)
07737 {
07738 struct chan_list *cl;
07739
07740 cl = ao2_alloc(sizeof(*cl), chan_list_destructor);
07741 if (!cl) {
07742 chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
07743 return NULL;
07744 }
07745
07746 cl->originator = orig;
07747 cl->need_queue_hangup = 1;
07748 cl->need_hangup = 1;
07749 cl->need_busy = 1;
07750 cl->overlap_dial_task = -1;
07751 #if defined(AST_MISDN_ENHANCEMENTS)
07752 cl->record_id = -1;
07753 #endif
07754 cl->pipe[0] = -1;
07755 cl->pipe[1] = -1;
07756
07757 return cl;
07758 }
07759
07760 static struct ast_channel *misdn_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
07761 {
07762 struct ast_channel *ast;
07763 char group[BUFFERSIZE + 1] = "";
07764 char dial_str[128];
07765 char *dest_cp;
07766 char *p = NULL;
07767 int channel = 0;
07768 int port = 0;
07769 struct misdn_bchannel *newbc = NULL;
07770 int dec = 0;
07771 #if defined(AST_MISDN_ENHANCEMENTS)
07772 int cc_retry_call = 0;
07773 long record_id = -1;
07774 struct misdn_cc_record *cc_record;
07775 const char *err_msg;
07776 #endif
07777 struct chan_list *cl;
07778
07779 AST_DECLARE_APP_ARGS(args,
07780 AST_APP_ARG(intf);
07781 AST_APP_ARG(ext);
07782 AST_APP_ARG(opts);
07783 );
07784
07785 snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
07786
07787
07788
07789
07790
07791
07792
07793
07794
07795
07796 dest_cp = ast_strdupa(data);
07797 AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
07798 if (!args.ext) {
07799 args.ext = "";
07800 }
07801
07802 if (!ast_strlen_zero(args.intf)) {
07803 if (args.intf[0] == 'g' && args.intf[1] == ':') {
07804
07805 args.intf += 2;
07806 ast_copy_string(group, args.intf, sizeof(group));
07807 chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
07808 #if defined(AST_MISDN_ENHANCEMENTS)
07809 } else if (strcmp(args.intf, "cc") == 0) {
07810 cc_retry_call = 1;
07811 #endif
07812 } else if ((p = strchr(args.intf, ':'))) {
07813
07814 *p++ = 0;
07815 channel = atoi(p);
07816 port = atoi(args.intf);
07817 chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
07818 } else {
07819 port = atoi(args.intf);
07820 }
07821 } else {
07822 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
07823 return NULL;
07824 }
07825
07826 #if defined(AST_MISDN_ENHANCEMENTS)
07827 if (cc_retry_call) {
07828 if (ast_strlen_zero(args.ext)) {
07829 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT cc-record-id, check extensions.conf\n", dial_str);
07830 return NULL;
07831 }
07832 if (!isdigit(*args.ext)) {
07833 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) cc-record-id must be a number.\n", dial_str);
07834 return NULL;
07835 }
07836 record_id = atol(args.ext);
07837
07838 AST_LIST_LOCK(&misdn_cc_records_db);
07839 cc_record = misdn_cc_find_by_id(record_id);
07840 if (!cc_record) {
07841 AST_LIST_UNLOCK(&misdn_cc_records_db);
07842 err_msg = misdn_cc_record_not_found;
07843 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07844 return NULL;
07845 }
07846 if (!cc_record->activated) {
07847 AST_LIST_UNLOCK(&misdn_cc_records_db);
07848 err_msg = "Call completion has not been activated";
07849 ast_log(LOG_WARNING, " --> ! IND : Dial(%s) %s.\n", dial_str, err_msg);
07850 return NULL;
07851 }
07852 port = cc_record->port;
07853 AST_LIST_UNLOCK(&misdn_cc_records_db);
07854 }
07855 #endif
07856
07857 if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
07858 chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
07859 dec = 1;
07860 }
07861
07862 if (!ast_strlen_zero(group)) {
07863 char cfg_group[BUFFERSIZE + 1];
07864 struct robin_list *rr = NULL;
07865
07866
07867
07868 if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
07869 chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
07870 rr = get_robin_position(group);
07871 }
07872
07873 if (rr) {
07874 int robin_channel = rr->channel;
07875 int port_start;
07876 int next_chan = 1;
07877
07878 do {
07879 port_start = 0;
07880 for (port = misdn_cfg_get_next_port_spin(rr->port); port > 0 && port != port_start;
07881 port = misdn_cfg_get_next_port_spin(port)) {
07882
07883 if (!port_start) {
07884 port_start = port;
07885 }
07886
07887 if (port >= port_start) {
07888 next_chan = 1;
07889 }
07890
07891 if (port <= port_start && next_chan) {
07892 int maxbchans = misdn_lib_get_maxchans(port);
07893
07894 if (++robin_channel >= maxbchans) {
07895 robin_channel = 1;
07896 }
07897 next_chan = 0;
07898 }
07899
07900 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07901
07902 if (!strcasecmp(cfg_group, group)) {
07903 int port_up;
07904 int check;
07905
07906 misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07907 port_up = misdn_lib_port_up(port, check);
07908
07909 if (check && !port_up) {
07910 chan_misdn_log(1, port, "L1 is not Up on this Port\n");
07911 }
07912
07913 if (check && port_up < 0) {
07914 ast_log(LOG_WARNING, "This port (%d) is blocked\n", port);
07915 }
07916
07917 if (port_up > 0) {
07918 newbc = misdn_lib_get_free_bc(port, robin_channel, 0, 0);
07919 if (newbc) {
07920 chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
07921 if (port_up) {
07922 chan_misdn_log(4, port, "portup:%d\n", port_up);
07923 }
07924 rr->port = newbc->port;
07925 rr->channel = newbc->channel;
07926 break;
07927 }
07928 }
07929 }
07930 }
07931 } while (!newbc && robin_channel != rr->channel);
07932 } else {
07933 for (port = misdn_cfg_get_next_port(0); port > 0;
07934 port = misdn_cfg_get_next_port(port)) {
07935 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
07936
07937 chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
07938 if (!strcasecmp(cfg_group, group)) {
07939 int port_up;
07940 int check;
07941
07942 misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
07943 port_up = misdn_lib_port_up(port, check);
07944
07945 chan_misdn_log(4, port, "portup:%d\n", port_up);
07946
07947 if (port_up > 0) {
07948 newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
07949 if (newbc) {
07950 break;
07951 }
07952 }
07953 }
07954 }
07955 }
07956
07957
07958 if (!newbc) {
07959 ast_log(LOG_WARNING,
07960 "Could not Dial out on group '%s'.\n"
07961 "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
07962 "\tOr there was no free channel on none of the ports\n\n",
07963 group);
07964 return NULL;
07965 }
07966 } else {
07967
07968 if (channel) {
07969 chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
07970 }
07971 newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
07972 if (!newbc) {
07973 ast_log(LOG_WARNING, "Could not create channel on port:%d for Dial(%s)\n", port, dial_str);
07974 return NULL;
07975 }
07976 }
07977
07978
07979 cl = chan_list_init(ORG_AST);
07980 if (!cl) {
07981 ast_log(LOG_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
07982 return NULL;
07983 }
07984 cl->bc = newbc;
07985
07986 ast = misdn_new(cl, AST_STATE_RESERVED, args.ext, NULL, format, requestor ? requestor->linkedid : NULL, port, channel);
07987 if (!ast) {
07988 chan_list_unref(cl, "Failed to create a new channel");
07989 ast_log(LOG_ERROR, "Could not create Asterisk channel for Dial(%s)\n", dial_str);
07990 return NULL;
07991 }
07992
07993 #if defined(AST_MISDN_ENHANCEMENTS)
07994 cl->record_id = record_id;
07995 #endif
07996
07997
07998 cl_queue_chan(cl);
07999
08000
08001 read_config(cl);
08002
08003
08004 cl->need_hangup = 0;
08005
08006 chan_list_unref(cl, "Successful misdn_request()");
08007 return ast;
08008 }
08009
08010
08011 static int misdn_send_text(struct ast_channel *chan, const char *text)
08012 {
08013 struct chan_list *tmp = MISDN_ASTERISK_TECH_PVT(chan);
08014
08015 if (tmp && tmp->bc) {
08016 ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
08017 misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
08018 } else {
08019 ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
08020 return -1;
08021 }
08022
08023 return 0;
08024 }
08025
08026 static struct ast_channel_tech misdn_tech = {
08027 .type = misdn_type,
08028 .description = "Channel driver for mISDN Support (Bri/Pri)",
08029 .capabilities = AST_FORMAT_ALAW ,
08030 .requester = misdn_request,
08031 .send_digit_begin = misdn_digit_begin,
08032 .send_digit_end = misdn_digit_end,
08033 .call = misdn_call,
08034 .bridge = misdn_bridge,
08035 .hangup = misdn_hangup,
08036 .answer = misdn_answer,
08037 .read = misdn_read,
08038 .write = misdn_write,
08039 .indicate = misdn_indication,
08040 .fixup = misdn_fixup,
08041 .send_text = misdn_send_text,
08042 .properties = 0,
08043 };
08044
08045 static struct ast_channel_tech misdn_tech_wo_bridge = {
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 .hangup = misdn_hangup,
08054 .answer = misdn_answer,
08055 .read = misdn_read,
08056 .write = misdn_write,
08057 .indicate = misdn_indication,
08058 .fixup = misdn_fixup,
08059 .send_text = misdn_send_text,
08060 .properties = 0,
08061 };
08062
08063
08064 static int glob_channel = 0;
08065
08066 static void update_name(struct ast_channel *tmp, int port, int c)
08067 {
08068 int chan_offset = 0;
08069 int tmp_port = misdn_cfg_get_next_port(0);
08070 char newname[255];
08071
08072 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08073 if (tmp_port == port) {
08074 break;
08075 }
08076 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08077 }
08078 if (c < 0) {
08079 c = 0;
08080 }
08081
08082 snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
08083 if (strncmp(tmp->name, newname, strlen(newname))) {
08084 snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
08085 ast_change_name(tmp, newname);
08086 chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
08087 }
08088 }
08089
08090 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)
08091 {
08092 struct ast_channel *tmp;
08093 char *cid_name = NULL;
08094 char *cid_num = NULL;
08095 int chan_offset = 0;
08096 int tmp_port = misdn_cfg_get_next_port(0);
08097 int bridging;
08098
08099 for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
08100 if (tmp_port == port) {
08101 break;
08102 }
08103 chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
08104 }
08105 if (c < 0) {
08106 c = 0;
08107 }
08108
08109 if (callerid) {
08110 ast_callerid_parse(callerid, &cid_name, &cid_num);
08111 }
08112
08113 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++);
08114 if (tmp) {
08115 chan_misdn_log(2, 0, " --> * NEW CHANNEL dialed:%s caller:%s\n", exten, callerid);
08116
08117 tmp->nativeformats = prefformat;
08118
08119 tmp->readformat = format;
08120 tmp->rawreadformat = format;
08121 tmp->writeformat = format;
08122 tmp->rawwriteformat = format;
08123
08124
08125 chan_list_ref(chlist, "Give a reference to ast_channel");
08126 MISDN_ASTERISK_TECH_PVT(tmp) = chlist;
08127 chlist->ast = tmp;
08128
08129 misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
08130 tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge;
08131
08132 tmp->writeformat = format;
08133 tmp->readformat = format;
08134 tmp->priority = 1;
08135
08136 if (exten) {
08137 ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
08138 } else {
08139 chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
08140 }
08141
08142 if (!ast_strlen_zero(cid_num)) {
08143
08144
08145 tmp->caller.ani.number.valid = 1;
08146 tmp->caller.ani.number.str = ast_strdup(cid_num);
08147 }
08148
08149 if (pipe(chlist->pipe) < 0) {
08150 ast_log(LOG_ERROR, "Pipe failed\n");
08151 }
08152 ast_channel_set_fd(tmp, 0, chlist->pipe[0]);
08153
08154 tmp->rings = (state == AST_STATE_RING) ? 1 : 0;
08155
08156 ast_jb_configure(tmp, misdn_get_global_jbconf());
08157 } else {
08158 chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
08159 }
08160
08161 return tmp;
08162 }
08163
08164
08165 static struct chan_list *find_chan_by_bc(struct misdn_bchannel *bc)
08166 {
08167 struct chan_list *help;
08168
08169 ast_mutex_lock(&cl_te_lock);
08170 for (help = cl_te; help; help = help->next) {
08171 if (help->bc == bc) {
08172 chan_list_ref(help, "Found chan_list by bc");
08173 ast_mutex_unlock(&cl_te_lock);
08174 return help;
08175 }
08176 }
08177 ast_mutex_unlock(&cl_te_lock);
08178
08179 chan_misdn_log(6, bc->port,
08180 "$$$ find_chan_by_bc: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08181 bc->dialed.number,
08182 bc->caller.name,
08183 bc->caller.number);
08184
08185 return NULL;
08186 }
08187
08188
08189 static struct chan_list *find_hold_call(struct misdn_bchannel *bc)
08190 {
08191 struct chan_list *help;
08192
08193 if (bc->pri) {
08194 return NULL;
08195 }
08196
08197 chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d dialed:%s caller:\"%s\" <%s>\n",
08198 bc->channel,
08199 bc->dialed.number,
08200 bc->caller.name,
08201 bc->caller.number);
08202 ast_mutex_lock(&cl_te_lock);
08203 for (help = cl_te; help; help = help->next) {
08204 chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
08205 if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port) {
08206 chan_list_ref(help, "Found chan_list hold call");
08207 ast_mutex_unlock(&cl_te_lock);
08208 return help;
08209 }
08210 }
08211 ast_mutex_unlock(&cl_te_lock);
08212 chan_misdn_log(6, bc->port,
08213 "$$$ find_hold_call: No channel found for dialed:%s caller:\"%s\" <%s>\n",
08214 bc->dialed.number,
08215 bc->caller.name,
08216 bc->caller.number);
08217
08218 return NULL;
08219 }
08220
08221
08222
08223 static struct chan_list *find_hold_call_l3(unsigned long l3_id)
08224 {
08225 struct chan_list *help;
08226
08227 ast_mutex_lock(&cl_te_lock);
08228 for (help = cl_te; help; help = help->next) {
08229 if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id) {
08230 chan_list_ref(help, "Found chan_list hold call l3");
08231 ast_mutex_unlock(&cl_te_lock);
08232 return help;
08233 }
08234 }
08235 ast_mutex_unlock(&cl_te_lock);
08236
08237 return NULL;
08238 }
08239
08240 #define TRANSFER_ON_HELD_CALL_HANGUP 1
08241 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251
08252
08253
08254
08255
08256
08257 static struct chan_list *find_hold_active_call(struct misdn_bchannel *bc)
08258 {
08259 struct chan_list *list;
08260
08261 ast_mutex_lock(&cl_te_lock);
08262 for (list = cl_te; list; list = list->next) {
08263 if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
08264 && list->ast) {
08265 switch (list->state) {
08266 case MISDN_PROCEEDING:
08267 case MISDN_PROGRESS:
08268 case MISDN_ALERTING:
08269 case MISDN_CONNECTED:
08270 chan_list_ref(list, "Found chan_list hold active call");
08271 ast_mutex_unlock(&cl_te_lock);
08272 return list;
08273 default:
08274 break;
08275 }
08276 }
08277 }
08278 ast_mutex_unlock(&cl_te_lock);
08279 return NULL;
08280 }
08281 #endif
08282
08283 static void cl_queue_chan(struct chan_list *chan)
08284 {
08285 chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
08286
08287 chan_list_ref(chan, "Adding chan_list to list");
08288 ast_mutex_lock(&cl_te_lock);
08289 chan->next = NULL;
08290 if (!cl_te) {
08291
08292 cl_te = chan;
08293 } else {
08294 struct chan_list *help;
08295
08296
08297 for (help = cl_te; help->next; help = help->next) {
08298 }
08299 help->next = chan;
08300 }
08301 ast_mutex_unlock(&cl_te_lock);
08302 }
08303
08304 static int cl_dequeue_chan(struct chan_list *chan)
08305 {
08306 int found_it;
08307 struct chan_list *help;
08308
08309 ast_mutex_lock(&cl_te_lock);
08310 if (!cl_te) {
08311
08312 ast_mutex_unlock(&cl_te_lock);
08313 return 0;
08314 }
08315
08316 if (cl_te == chan) {
08317
08318 cl_te = cl_te->next;
08319 ast_mutex_unlock(&cl_te_lock);
08320 chan_list_unref(chan, "Removed chan_list from list head");
08321 return 1;
08322 }
08323
08324 found_it = 0;
08325 for (help = cl_te; help->next; help = help->next) {
08326 if (help->next == chan) {
08327
08328 help->next = help->next->next;
08329 found_it = 1;
08330 break;
08331 }
08332 }
08333
08334 ast_mutex_unlock(&cl_te_lock);
08335 if (found_it) {
08336 chan_list_unref(chan, "Removed chan_list from list");
08337 }
08338 return found_it;
08339 }
08340
08341
08342
08343
08344 static int pbx_start_chan(struct chan_list *ch)
08345 {
08346 int ret = ast_pbx_start(ch->ast);
08347
08348 ch->need_hangup = (ret >= 0) ? 0 : 1;
08349
08350 return ret;
08351 }
08352
08353 static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08354 {
08355 int port;
08356
08357 if (!ch) {
08358 cb_log(1, 0, "Cannot hangup chan, no ch\n");
08359 return;
08360 }
08361
08362 port = bc->port;
08363 cb_log(5, port, "hangup_chan called\n");
08364
08365 if (ch->need_hangup) {
08366 cb_log(2, port, " --> hangup\n");
08367 ch->need_hangup = 0;
08368 ch->need_queue_hangup = 0;
08369 if (ch->ast && send_cause2ast(ch->ast, bc, ch)) {
08370 ast_hangup(ch->ast);
08371 }
08372 return;
08373 }
08374
08375 if (!ch->need_queue_hangup) {
08376 cb_log(2, port, " --> No need to queue hangup\n");
08377 return;
08378 }
08379
08380 ch->need_queue_hangup = 0;
08381 if (ch->ast) {
08382 if (send_cause2ast(ch->ast, bc, ch)) {
08383 ast_queue_hangup_with_cause(ch->ast, bc->cause);
08384 cb_log(2, port, " --> queue_hangup\n");
08385 }
08386 } else {
08387 cb_log(1, port, "Cannot hangup chan, no ast\n");
08388 }
08389 }
08390
08391
08392
08393
08394
08395
08396
08397
08398
08399
08400
08401
08402 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc)
08403 {
08404 struct ast_channel *ast;
08405
08406 chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);
08407
08408 ast_mutex_lock(&release_lock);
08409 for (;;) {
08410 ast = ch->ast;
08411 if (!ast || !ast_channel_trylock(ast)) {
08412 break;
08413 }
08414 DEADLOCK_AVOIDANCE(&release_lock);
08415 }
08416 if (!cl_dequeue_chan(ch)) {
08417
08418 if (ast) {
08419 ast_channel_unlock(ast);
08420 }
08421 ast_mutex_unlock(&release_lock);
08422 return;
08423 }
08424 ch->state = MISDN_CLEANING;
08425 ch->ast = NULL;
08426 if (ast) {
08427 struct chan_list *ast_ch;
08428
08429 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08430 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08431 chan_misdn_log(1, bc->port,
08432 "* RELEASING CHANNEL pid:%d context:%s dialed:%s caller:\"%s\" <%s>\n",
08433 bc->pid,
08434 ast->context,
08435 ast->exten,
08436 S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
08437 S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""));
08438
08439 if (ast->_state != AST_STATE_RESERVED) {
08440 chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
08441 ast_setstate(ast, AST_STATE_DOWN);
08442 }
08443 ast_channel_unlock(ast);
08444 if (ast_ch) {
08445 chan_list_unref(ast_ch, "Release ast_channel reference.");
08446 }
08447 }
08448
08449 if (ch->originator == ORG_AST) {
08450 --misdn_out_calls[bc->port];
08451 } else {
08452 --misdn_in_calls[bc->port];
08453 }
08454
08455 ast_mutex_unlock(&release_lock);
08456 }
08457
08458
08459
08460
08461
08462
08463
08464
08465
08466
08467
08468 static void release_chan_early(struct chan_list *ch)
08469 {
08470 struct ast_channel *ast;
08471
08472 ast_mutex_lock(&release_lock);
08473 for (;;) {
08474 ast = ch->ast;
08475 if (!ast || !ast_channel_trylock(ast)) {
08476 break;
08477 }
08478 DEADLOCK_AVOIDANCE(&release_lock);
08479 }
08480 if (!cl_dequeue_chan(ch)) {
08481
08482 if (ast) {
08483 ast_channel_unlock(ast);
08484 }
08485 ast_mutex_unlock(&release_lock);
08486 return;
08487 }
08488 ch->state = MISDN_CLEANING;
08489 ch->ast = NULL;
08490 if (ast) {
08491 struct chan_list *ast_ch;
08492
08493 ast_ch = MISDN_ASTERISK_TECH_PVT(ast);
08494 MISDN_ASTERISK_TECH_PVT(ast) = NULL;
08495
08496 if (ast->_state != AST_STATE_RESERVED) {
08497 ast_setstate(ast, AST_STATE_DOWN);
08498 }
08499 ast_channel_unlock(ast);
08500 if (ast_ch) {
08501 chan_list_unref(ast_ch, "Release ast_channel reference.");
08502 }
08503 }
08504
08505 if (ch->hold.state != MISDN_HOLD_IDLE) {
08506 if (ch->originator == ORG_AST) {
08507 --misdn_out_calls[ch->hold.port];
08508 } else {
08509 --misdn_in_calls[ch->hold.port];
08510 }
08511 }
08512
08513 ast_mutex_unlock(&release_lock);
08514 }
08515
08516
08517
08518
08519
08520
08521
08522
08523
08524
08525
08526 static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
08527 {
08528 int retval;
08529 struct ast_channel *target;
08530 struct ast_channel *transferee;
08531 struct ast_party_connected_line target_colp;
08532 struct ast_party_connected_line transferee_colp;
08533
08534 switch (active_ch->state) {
08535 case MISDN_PROCEEDING:
08536 case MISDN_PROGRESS:
08537 case MISDN_ALERTING:
08538 case MISDN_CONNECTED:
08539 break;
08540 default:
08541 return -1;
08542 }
08543
08544 ast_channel_lock(held_ch->ast);
08545 while (ast_channel_trylock(active_ch->ast)) {
08546 CHANNEL_DEADLOCK_AVOIDANCE(held_ch->ast);
08547 }
08548
08549 transferee = ast_bridged_channel(held_ch->ast);
08550 if (!transferee) {
08551
08552
08553
08554
08555 ast_channel_unlock(held_ch->ast);
08556 ast_channel_unlock(active_ch->ast);
08557 return -1;
08558 }
08559
08560 target = active_ch->ast;
08561 chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
08562 held_ch->ast->name, target->name);
08563
08564 ast_party_connected_line_init(&target_colp);
08565 ast_party_connected_line_copy(&target_colp, &target->connected);
08566 ast_party_connected_line_init(&transferee_colp);
08567 ast_party_connected_line_copy(&transferee_colp, &held_ch->ast->connected);
08568 held_ch->hold.state = MISDN_HOLD_TRANSFER;
08569
08570
08571
08572
08573
08574
08575
08576
08577
08578
08579
08580 ao2_ref(target, +1);
08581 ao2_ref(transferee, +1);
08582 ast_channel_unlock(held_ch->ast);
08583 ast_channel_unlock(active_ch->ast);
08584
08585
08586 retval = ast_channel_transfer_masquerade(target, &target_colp, 0,
08587 transferee, &transferee_colp, 1);
08588
08589 ast_party_connected_line_free(&target_colp);
08590 ast_party_connected_line_free(&transferee_colp);
08591 ao2_ref(target, -1);
08592 ao2_ref(transferee, -1);
08593 return retval;
08594 }
08595
08596
08597 static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
08598 {
08599 char *predial;
08600 struct ast_frame fr;
08601
08602 predial = ast_strdupa(ast->exten);
08603
08604 ch->state = MISDN_DIALING;
08605
08606 if (!ch->noautorespond_on_setup) {
08607 if (bc->nt) {
08608 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08609 } else {
08610 if (misdn_lib_is_ptp(bc->port)) {
08611 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08612 } else {
08613 misdn_lib_send_event(bc, EVENT_PROCEEDING);
08614 }
08615 }
08616 } else {
08617 ch->state = MISDN_INCOMING_SETUP;
08618 }
08619
08620 chan_misdn_log(1, bc->port,
08621 "* Starting Ast context:%s dialed:%s caller:\"%s\" <%s> with 's' extension\n",
08622 ast->context,
08623 ast->exten,
08624 (ast->caller.id.name.valid && ast->caller.id.name.str)
08625 ? ast->caller.id.name.str : "",
08626 (ast->caller.id.number.valid && ast->caller.id.number.str)
08627 ? ast->caller.id.number.str : "");
08628
08629 strcpy(ast->exten, "s");
08630
08631 if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->caller.number) || pbx_start_chan(ch) < 0) {
08632 ast = NULL;
08633 bc->out_cause = AST_CAUSE_UNALLOCATED;
08634 hangup_chan(ch, bc);
08635 hanguptone_indicate(ch);
08636
08637 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
08638 }
08639
08640
08641 while (!ast_strlen_zero(predial)) {
08642 fr.frametype = AST_FRAME_DTMF;
08643 fr.subclass.integer = *predial;
08644 fr.src = NULL;
08645 fr.data.ptr = NULL;
08646 fr.datalen = 0;
08647 fr.samples = 0;
08648 fr.mallocd = 0;
08649 fr.offset = 0;
08650 fr.delivery = ast_tv(0,0);
08651
08652 if (ch->ast && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
08653 ast_queue_frame(ch->ast, &fr);
08654 }
08655 predial++;
08656 }
08657 }
08658
08659
08660
08661
08662
08663 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch)
08664 {
08665 int can_hangup;
08666
08667 if (!ast) {
08668 chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
08669 return 0;
08670 }
08671 if (!bc) {
08672 chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
08673 return 0;
08674 }
08675 if (!ch) {
08676 chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
08677 return 0;
08678 }
08679
08680 ast->hangupcause = bc->cause;
08681
08682 can_hangup = -1;
08683 switch (bc->cause) {
08684 case AST_CAUSE_UNALLOCATED:
08685 case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
08686 case AST_CAUSE_NO_ROUTE_DESTINATION:
08687 case 4:
08688 case AST_CAUSE_NUMBER_CHANGED:
08689 case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
08690
08691
08692
08693
08694
08695
08696
08697
08698
08699
08700 break;
08701
08702 case AST_CAUSE_CALL_REJECTED:
08703 case AST_CAUSE_USER_BUSY:
08704 ch->state = MISDN_BUSY;
08705
08706 if (!ch->need_busy) {
08707 chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
08708 break;
08709 }
08710 ch->need_busy = 0;
08711
08712 chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
08713 ast_queue_control(ast, AST_CONTROL_BUSY);
08714
08715
08716 can_hangup = 0;
08717 break;
08718 }
08719 return can_hangup;
08720 }
08721
08722
08723
08724 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08725 {
08726 const char *tmp;
08727
08728 ast_channel_lock(chan);
08729 tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
08730 if (tmp && (atoi(tmp) == 1)) {
08731 bc->sending_complete = 1;
08732 }
08733
08734 tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
08735 if (tmp) {
08736 ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
08737 ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
08738 bc->uulen = strlen(bc->uu);
08739 }
08740
08741 tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
08742 if (tmp) {
08743 ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
08744 }
08745 ast_channel_unlock(chan);
08746 }
08747
08748
08749 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
08750 {
08751 char tmp[32];
08752
08753
08754
08755
08756
08757
08758
08759 chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
08760 snprintf(tmp, sizeof(tmp), "%d", bc->pid);
08761 pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
08762
08763 if (bc->sending_complete) {
08764 snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
08765 pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
08766 }
08767
08768 if (bc->urate) {
08769 snprintf(tmp, sizeof(tmp), "%d", bc->urate);
08770 pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
08771 }
08772
08773 if (bc->uulen) {
08774 pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
08775 }
08776
08777 if (!ast_strlen_zero(bc->keypad)) {
08778 pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
08779 }
08780 }
08781
08782 int add_in_calls(int port)
08783 {
08784 int max_in_calls;
08785
08786 misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
08787 misdn_in_calls[port]++;
08788
08789 if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
08790 ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
08791 return misdn_in_calls[port] - max_in_calls;
08792 }
08793
08794 return 0;
08795 }
08796
08797 int add_out_calls(int port)
08798 {
08799 int max_out_calls;
08800
08801 misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
08802
08803 if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
08804 ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
08805 return (misdn_out_calls[port] + 1) - max_out_calls;
08806 }
08807
08808 misdn_out_calls[port]++;
08809
08810 return 0;
08811 }
08812
08813 static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08814 {
08815 if (pbx_start_chan(ch) < 0) {
08816 hangup_chan(ch, bc);
08817 chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
08818 if (bc->nt) {
08819 hanguptone_indicate(ch);
08820 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
08821 } else {
08822 misdn_lib_send_event(bc, EVENT_RELEASE);
08823 }
08824 }
08825 }
08826
08827 static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
08828 {
08829 ch->state = MISDN_WAITING4DIGS;
08830 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
08831 if (bc->nt && !bc->dialed.number[0]) {
08832 dialtone_indicate(ch);
08833 }
08834 }
08835
08836 #if defined(AST_MISDN_ENHANCEMENTS)
08837
08838
08839
08840
08841
08842
08843
08844
08845
08846 static void misdn_cc_handle_ccbs_status_request(int port, const struct FacParm *facility)
08847 {
08848 struct misdn_cc_record *cc_record;
08849 struct misdn_bchannel dummy;
08850
08851 switch (facility->u.CCBSStatusRequest.ComponentType) {
08852 case FacComponent_Invoke:
08853
08854 misdn_make_dummy(&dummy, port, 0, misdn_lib_port_is_nt(port), 0);
08855 dummy.fac_out.Function = Fac_CCBSStatusRequest;
08856 dummy.fac_out.u.CCBSStatusRequest.InvokeID = facility->u.CCBSStatusRequest.InvokeID;
08857 dummy.fac_out.u.CCBSStatusRequest.ComponentType = FacComponent_Result;
08858
08859
08860 AST_LIST_LOCK(&misdn_cc_records_db);
08861 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSStatusRequest.Component.Invoke.CCBSReference);
08862 if (cc_record) {
08863 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = cc_record->party_a_free;
08864 } else {
08865
08866 dummy.fac_out.u.CCBSStatusRequest.Component.Result.Free = 1;
08867 }
08868 AST_LIST_UNLOCK(&misdn_cc_records_db);
08869
08870
08871 print_facility(&dummy.fac_out, &dummy);
08872 misdn_lib_send_event(&dummy, EVENT_FACILITY);
08873 break;
08874
08875 default:
08876 chan_misdn_log(0, port, " --> not yet handled: facility type:0x%04X\n", facility->Function);
08877 break;
08878 }
08879 }
08880 #endif
08881
08882 #if defined(AST_MISDN_ENHANCEMENTS)
08883
08884
08885
08886
08887
08888
08889
08890
08891
08892 static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *notify)
08893 {
08894 struct ast_channel *chan;
08895 char id_str[32];
08896
08897 static unsigned short sequence = 0;
08898
08899
08900 snprintf(id_str, sizeof(id_str), "%ld", record_id);
08901 chan = ast_channel_alloc(0, AST_STATE_DOWN, id_str, NULL, NULL,
08902 notify->exten, notify->context, NULL, 0,
08903 "mISDN-CC/%ld-%X", record_id, (unsigned) ++sequence);
08904 if (!chan) {
08905 ast_log(LOG_ERROR, "Unable to allocate channel!\n");
08906 return;
08907 }
08908 chan->priority = notify->priority;
08909 ast_free(chan->dialed.number.str);
08910 chan->dialed.number.str = ast_strdup(notify->exten);
08911
08912 if (ast_pbx_start(chan)) {
08913 ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", chan->name);
08914 ast_channel_release(chan);
08915 } else {
08916 ast_verb(1, "Started pbx for call completion notify channel %s\n", chan->name);
08917 }
08918 }
08919 #endif
08920
08921 #if defined(AST_MISDN_ENHANCEMENTS)
08922
08923
08924
08925
08926
08927
08928
08929
08930 static void misdn_cc_handle_T_remote_user_free(struct misdn_bchannel *bc)
08931 {
08932 struct misdn_cc_record *cc_record;
08933 struct misdn_cc_notify notify;
08934 long record_id;
08935
08936 AST_LIST_LOCK(&misdn_cc_records_db);
08937 cc_record = misdn_cc_find_by_bc(bc);
08938 if (cc_record) {
08939 if (cc_record->party_a_free) {
08940 notify = cc_record->remote_user_free;
08941 } else {
08942
08943 bc->fac_out.Function = Fac_CCBS_T_Suspend;
08944 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
08945 print_facility(&bc->fac_out, bc);
08946 misdn_lib_send_event(bc, EVENT_FACILITY);
08947
08948 notify = cc_record->b_free;
08949 }
08950 record_id = cc_record->record_id;
08951 AST_LIST_UNLOCK(&misdn_cc_records_db);
08952 if (notify.context[0]) {
08953
08954 misdn_cc_pbx_notify(record_id, ¬ify);
08955 }
08956 } else {
08957 AST_LIST_UNLOCK(&misdn_cc_records_db);
08958 }
08959 }
08960 #endif
08961
08962 #if defined(AST_MISDN_ENHANCEMENTS)
08963
08964
08965
08966
08967
08968
08969
08970
08971
08972 static void misdn_cc_handle_remote_user_free(int port, const struct FacParm *facility)
08973 {
08974 struct misdn_cc_record *cc_record;
08975 struct misdn_cc_notify notify;
08976 long record_id;
08977
08978 AST_LIST_LOCK(&misdn_cc_records_db);
08979 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSRemoteUserFree.CCBSReference);
08980 if (cc_record) {
08981 notify = cc_record->remote_user_free;
08982 record_id = cc_record->record_id;
08983 AST_LIST_UNLOCK(&misdn_cc_records_db);
08984 misdn_cc_pbx_notify(record_id, ¬ify);
08985 } else {
08986 AST_LIST_UNLOCK(&misdn_cc_records_db);
08987 }
08988 }
08989 #endif
08990
08991 #if defined(AST_MISDN_ENHANCEMENTS)
08992
08993
08994
08995
08996
08997
08998
08999
09000
09001 static void misdn_cc_handle_b_free(int port, const struct FacParm *facility)
09002 {
09003 struct misdn_cc_record *cc_record;
09004 struct misdn_cc_notify notify;
09005 long record_id;
09006
09007 AST_LIST_LOCK(&misdn_cc_records_db);
09008 cc_record = misdn_cc_find_by_reference(port, facility->u.CCBSBFree.CCBSReference);
09009 if (cc_record && cc_record->b_free.context[0]) {
09010
09011 notify = cc_record->b_free;
09012 record_id = cc_record->record_id;
09013 AST_LIST_UNLOCK(&misdn_cc_records_db);
09014 misdn_cc_pbx_notify(record_id, ¬ify);
09015 } else {
09016 AST_LIST_UNLOCK(&misdn_cc_records_db);
09017 }
09018 }
09019 #endif
09020
09021
09022
09023
09024
09025
09026
09027
09028
09029
09030
09031 static void misdn_facility_ie_handler(enum event_e event, struct misdn_bchannel *bc, struct chan_list *ch)
09032 {
09033 #if defined(AST_MISDN_ENHANCEMENTS)
09034 const char *diagnostic_msg;
09035 struct misdn_cc_record *cc_record;
09036 char buf[32];
09037 struct misdn_party_id party_id;
09038 long new_record_id;
09039 #endif
09040
09041 print_facility(&bc->fac_in, bc);
09042 switch (bc->fac_in.Function) {
09043 #if defined(AST_MISDN_ENHANCEMENTS)
09044 case Fac_ActivationDiversion:
09045 switch (bc->fac_in.u.ActivationDiversion.ComponentType) {
09046 case FacComponent_Result:
09047
09048
09049 break;
09050 default:
09051 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09052 bc->fac_in.Function);
09053 break;
09054 }
09055 break;
09056 case Fac_DeactivationDiversion:
09057 switch (bc->fac_in.u.DeactivationDiversion.ComponentType) {
09058 case FacComponent_Result:
09059
09060
09061 break;
09062 default:
09063 chan_misdn_log(0, bc->port," --> not yet handled: facility type:0x%04X\n",
09064 bc->fac_in.Function);
09065 break;
09066 }
09067 break;
09068 case Fac_ActivationStatusNotificationDiv:
09069
09070
09071
09072 break;
09073 case Fac_DeactivationStatusNotificationDiv:
09074
09075
09076 break;
09077 #if 0
09078 case Fac_InterrogationDiversion:
09079
09080 break;
09081 case Fac_InterrogateServedUserNumbers:
09082
09083 break;
09084 #endif
09085 case Fac_DiversionInformation:
09086
09087
09088 break;
09089 case Fac_CallDeflection:
09090 if (ch && ch->ast) {
09091 switch (bc->fac_in.u.CallDeflection.ComponentType) {
09092 case FacComponent_Invoke:
09093 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09094 sizeof(bc->redirecting.from.number));
09095 bc->redirecting.from.name[0] = 0;
09096 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09097 bc->redirecting.from.number_type = bc->dialed.number_type;
09098 bc->redirecting.from.screening = 0;
09099 if (bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
09100 bc->redirecting.from.presentation =
09101 bc->fac_in.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser
09102 ? 0 : 1 ;
09103 } else {
09104 bc->redirecting.from.presentation = 0;
09105 }
09106
09107
09108 memset(&party_id, 0, sizeof(party_id));
09109 misdn_PartyNumber_extract(&party_id,
09110 &bc->fac_in.u.CallDeflection.Component.Invoke.Deflection.Party);
09111 misdn_add_number_prefix(bc->port, party_id.number_type,
09112 party_id.number, sizeof(party_id.number));
09113
09114
09115 bc->redirecting.to = party_id;
09116
09117 ++bc->redirecting.count;
09118 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09119
09120 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09121 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09122
09123
09124 #if 1
09125
09126
09127
09128
09129 bc->fac_out.Function = Fac_RESULT;
09130 bc->fac_out.u.RESULT.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09131 #else
09132 bc->fac_out.Function = Fac_CallDeflection;
09133 bc->fac_out.u.CallDeflection.InvokeID = bc->fac_in.u.CallDeflection.InvokeID;
09134 bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Result;
09135 #endif
09136 print_facility(&bc->fac_out, bc);
09137 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09138
09139
09140 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09141 break;
09142
09143 case FacComponent_Result:
09144
09145
09146
09147
09148
09149
09150
09151 break;
09152
09153 default:
09154 break;
09155 }
09156 }
09157 break;
09158 #if 0
09159 case Fac_CallRerouteing:
09160
09161
09162 break;
09163 #endif
09164 case Fac_DivertingLegInformation1:
09165
09166 bc->div_leg_3_rx_wanted = 0;
09167 if (ch && ch->ast) {
09168 bc->redirecting.reason =
09169 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation1.DiversionReason);
09170 if (bc->fac_in.u.DivertingLegInformation1.DivertedToPresent) {
09171 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.to,
09172 &bc->fac_in.u.DivertingLegInformation1.DivertedTo);
09173
09174
09175 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09176 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09177 } else {
09178 bc->redirecting.to.number[0] = '\0';
09179 bc->redirecting.to.number_plan = NUMPLAN_ISDN;
09180 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09181 bc->redirecting.to.presentation = 1;
09182 bc->redirecting.to.screening = 0;
09183 }
09184 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09185 bc->div_leg_3_rx_wanted = 1;
09186 }
09187 break;
09188 case Fac_DivertingLegInformation2:
09189
09190 switch (event) {
09191 case EVENT_SETUP:
09192
09193 bc->div_leg_3_tx_pending = 1;
09194 if (ch && ch->ast) {
09195
09196
09197
09198
09199
09200
09201
09202
09203
09204
09205 ast_copy_string(bc->redirecting.to.number, bc->dialed.number,
09206 sizeof(bc->redirecting.to.number));
09207 bc->redirecting.to.number_plan = bc->dialed.number_plan;
09208 bc->redirecting.to.number_type = bc->dialed.number_type;
09209 bc->redirecting.to.presentation = 1;
09210 bc->redirecting.to.screening = 0;
09211
09212 bc->redirecting.reason =
09213 diversion_reason_to_misdn(bc->fac_in.u.DivertingLegInformation2.DiversionReason);
09214 bc->redirecting.count = bc->fac_in.u.DivertingLegInformation2.DiversionCounter;
09215 if (bc->fac_in.u.DivertingLegInformation2.DivertingPresent) {
09216
09217 misdn_PresentedNumberUnscreened_extract(&bc->redirecting.from,
09218 &bc->fac_in.u.DivertingLegInformation2.Diverting);
09219
09220
09221 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type,
09222 bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
09223 }
09224 #if 0
09225 if (bc->fac_in.u.DivertingLegInformation2.OriginalCalledPresent) {
09226
09227 }
09228 #endif
09229 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09230 }
09231 break;
09232 default:
09233 chan_misdn_log(0, bc->port," --> Expected in a SETUP message: facility type:0x%04X\n",
09234 bc->fac_in.Function);
09235 break;
09236 }
09237 break;
09238 case Fac_DivertingLegInformation3:
09239
09240 if (bc->div_leg_3_rx_wanted) {
09241 bc->div_leg_3_rx_wanted = 0;
09242
09243 if (ch && ch->ast) {
09244 ch->ast->redirecting.to.number.presentation =
09245 bc->fac_in.u.DivertingLegInformation3.PresentationAllowedIndicator
09246 ? AST_PRES_ALLOWED | AST_PRES_USER_NUMBER_UNSCREENED
09247 : AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
09248 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
09249 }
09250 }
09251 break;
09252
09253 #else
09254
09255 case Fac_CD:
09256 if (ch && ch->ast) {
09257 ast_copy_string(bc->redirecting.from.number, bc->dialed.number,
09258 sizeof(bc->redirecting.from.number));
09259 bc->redirecting.from.name[0] = 0;
09260 bc->redirecting.from.number_plan = bc->dialed.number_plan;
09261 bc->redirecting.from.number_type = bc->dialed.number_type;
09262 bc->redirecting.from.screening = 0;
09263 bc->redirecting.from.presentation =
09264 bc->fac_in.u.CDeflection.PresentationAllowed
09265 ? 0 : 1 ;
09266
09267 ast_copy_string(bc->redirecting.to.number,
09268 (char *) bc->fac_in.u.CDeflection.DeflectedToNumber,
09269 sizeof(bc->redirecting.to.number));
09270 bc->redirecting.to.name[0] = 0;
09271 bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
09272 bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
09273 bc->redirecting.to.presentation = 0;
09274 bc->redirecting.to.screening = 0;
09275
09276 ++bc->redirecting.count;
09277 bc->redirecting.reason = mISDN_REDIRECTING_REASON_DEFLECTION;
09278
09279 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
09280 ast_string_field_set(ch->ast, call_forward, bc->redirecting.to.number);
09281
09282 misdn_lib_send_event(bc, EVENT_DISCONNECT);
09283
09284
09285 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
09286 }
09287 break;
09288 #endif
09289 case Fac_AOCDCurrency:
09290 if (ch && ch->ast) {
09291 bc->AOCDtype = Fac_AOCDCurrency;
09292 memcpy(&bc->AOCD.currency, &bc->fac_in.u.AOCDcur, sizeof(bc->AOCD.currency));
09293 bc->AOCD_need_export = 1;
09294 export_aoc_vars(ch->originator, ch->ast, bc);
09295 }
09296 break;
09297 case Fac_AOCDChargingUnit:
09298 if (ch && ch->ast) {
09299 bc->AOCDtype = Fac_AOCDChargingUnit;
09300 memcpy(&bc->AOCD.chargingUnit, &bc->fac_in.u.AOCDchu, sizeof(bc->AOCD.chargingUnit));
09301 bc->AOCD_need_export = 1;
09302 export_aoc_vars(ch->originator, ch->ast, bc);
09303 }
09304 break;
09305 #if defined(AST_MISDN_ENHANCEMENTS)
09306 case Fac_ERROR:
09307 diagnostic_msg = misdn_to_str_error_code(bc->fac_in.u.ERROR.errorValue);
09308 chan_misdn_log(1, bc->port, " --> Facility error code: %s\n", diagnostic_msg);
09309 switch (event) {
09310 case EVENT_DISCONNECT:
09311 case EVENT_RELEASE:
09312 case EVENT_RELEASE_COMPLETE:
09313
09314 if (ch && ch->peer) {
09315 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09316 }
09317 break;
09318 default:
09319 break;
09320 }
09321 AST_LIST_LOCK(&misdn_cc_records_db);
09322 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.ERROR.invokeId);
09323 if (cc_record) {
09324 cc_record->outstanding_message = 0;
09325 cc_record->error_code = bc->fac_in.u.ERROR.errorValue;
09326 }
09327 AST_LIST_UNLOCK(&misdn_cc_records_db);
09328 break;
09329 case Fac_REJECT:
09330 diagnostic_msg = misdn_to_str_reject_code(bc->fac_in.u.REJECT.Code);
09331 chan_misdn_log(1, bc->port, " --> Facility reject code: %s\n", diagnostic_msg);
09332 switch (event) {
09333 case EVENT_DISCONNECT:
09334 case EVENT_RELEASE:
09335 case EVENT_RELEASE_COMPLETE:
09336
09337 if (ch && ch->peer) {
09338 misdn_cc_set_peer_var(ch->peer, MISDN_ERROR_MSG, diagnostic_msg);
09339 }
09340 break;
09341 default:
09342 break;
09343 }
09344 if (bc->fac_in.u.REJECT.InvokeIDPresent) {
09345 AST_LIST_LOCK(&misdn_cc_records_db);
09346 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.REJECT.InvokeID);
09347 if (cc_record) {
09348 cc_record->outstanding_message = 0;
09349 cc_record->reject_code = bc->fac_in.u.REJECT.Code;
09350 }
09351 AST_LIST_UNLOCK(&misdn_cc_records_db);
09352 }
09353 break;
09354 case Fac_RESULT:
09355 AST_LIST_LOCK(&misdn_cc_records_db);
09356 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.RESULT.InvokeID);
09357 if (cc_record) {
09358 cc_record->outstanding_message = 0;
09359 }
09360 AST_LIST_UNLOCK(&misdn_cc_records_db);
09361 break;
09362 #if 0
09363 case Fac_EctExecute:
09364
09365 break;
09366 case Fac_ExplicitEctExecute:
09367
09368 break;
09369 case Fac_EctLinkIdRequest:
09370
09371 break;
09372 #endif
09373 case Fac_SubaddressTransfer:
09374
09375 break;
09376 case Fac_RequestSubaddress:
09377
09378
09379
09380
09381 if (bc->redirecting.to_changed) {
09382
09383 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
09384 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
09385 }
09386 switch (bc->notify_description_code) {
09387 case mISDN_NOTIFY_CODE_INVALID:
09388
09389 bc->redirecting.to_changed = 0;
09390 break;
09391 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
09392
09393
09394
09395
09396
09397
09398
09399
09400
09401 if (!bc->redirecting.to_changed) {
09402 break;
09403 }
09404 bc->redirecting.to_changed = 0;
09405 if (!ch || !ch->ast) {
09406 break;
09407 }
09408 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09409 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
09410 bc->incoming_cid_tag);
09411 break;
09412 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
09413 if (!bc->redirecting.to_changed) {
09414 break;
09415 }
09416 bc->redirecting.to_changed = 0;
09417 if (!ch || !ch->ast) {
09418 break;
09419 }
09420 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
09421 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
09422 break;
09423 default:
09424 bc->redirecting.to_changed = 0;
09425 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
09426 bc->notify_description_code);
09427 break;
09428 }
09429 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
09430 break;
09431 case Fac_EctInform:
09432
09433 if (ch && ch->ast && bc->fac_in.u.EctInform.RedirectionPresent) {
09434
09435 memset(&party_id, 0, sizeof(party_id));
09436 misdn_PresentedNumberUnscreened_extract(&party_id,
09437 &bc->fac_in.u.EctInform.Redirection);
09438 misdn_add_number_prefix(bc->port, party_id.number_type,
09439 party_id.number, sizeof(party_id.number));
09440
09441
09442
09443
09444
09445
09446
09447
09448
09449
09450 misdn_update_remote_party(ch->ast, &party_id,
09451 (bc->fac_in.u.EctInform.Status == 0 )
09452 ? AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING
09453 : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER,
09454 bc->incoming_cid_tag);
09455 }
09456 break;
09457 #if 0
09458 case Fac_EctLoopTest:
09459
09460
09461 break;
09462 #endif
09463 case Fac_CallInfoRetain:
09464 switch (event) {
09465 case EVENT_ALERTING:
09466 case EVENT_DISCONNECT:
09467
09468 if (ch && ch->peer) {
09469 AST_LIST_LOCK(&misdn_cc_records_db);
09470 if (ch->record_id == -1) {
09471 cc_record = misdn_cc_new();
09472 } else {
09473
09474
09475
09476
09477
09478
09479
09480
09481
09482 cc_record = misdn_cc_find_by_id(ch->record_id);
09483 if (cc_record) {
09484 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09485
09486
09487
09488
09489
09490
09491
09492
09493 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09494 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09495 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09496 }
09497
09498
09499
09500
09501
09502 new_record_id = misdn_cc_record_id_new();
09503 if (new_record_id < 0) {
09504
09505 } else {
09506 cc_record->record_id = new_record_id;
09507 ch->record_id = new_record_id;
09508 }
09509 cc_record->ptp = 0;
09510 cc_record->port = bc->port;
09511 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09512 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09513 cc_record->invoke_id = ++misdn_invoke_id;
09514 cc_record->activated = 0;
09515 cc_record->outstanding_message = 0;
09516 cc_record->activation_requested = 0;
09517 cc_record->error_code = FacError_None;
09518 cc_record->reject_code = FacReject_None;
09519 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09520 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09521 cc_record->time_created = time(NULL);
09522
09523 cc_record = NULL;
09524 } else {
09525
09526
09527
09528
09529
09530 ch->record_id = -1;
09531 cc_record = misdn_cc_new();
09532 }
09533 }
09534 if (cc_record) {
09535 ch->record_id = cc_record->record_id;
09536 cc_record->ptp = 0;
09537 cc_record->port = bc->port;
09538 cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
09539
09540
09541 cc_record->redial.caller = bc->caller;
09542 cc_record->redial.dialed = bc->dialed;
09543 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09544 cc_record->redial.capability = bc->capability;
09545 cc_record->redial.hdlc = bc->hdlc;
09546 }
09547 AST_LIST_UNLOCK(&misdn_cc_records_db);
09548
09549
09550 if (ch->record_id != -1) {
09551 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09552 } else {
09553 buf[0] = 0;
09554 }
09555 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09556 }
09557 break;
09558 default:
09559 chan_misdn_log(0, bc->port,
09560 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09561 bc->fac_in.Function);
09562 break;
09563 }
09564 break;
09565 case Fac_CCBS_T_Call:
09566 case Fac_CCBSCall:
09567 switch (event) {
09568 case EVENT_SETUP:
09569
09570
09571
09572
09573 break;
09574 default:
09575 chan_misdn_log(0, bc->port, " --> Expected in a SETUP message: facility type:0x%04X\n",
09576 bc->fac_in.Function);
09577 break;
09578 }
09579 break;
09580 case Fac_CCBSDeactivate:
09581 switch (bc->fac_in.u.CCBSDeactivate.ComponentType) {
09582 case FacComponent_Result:
09583 AST_LIST_LOCK(&misdn_cc_records_db);
09584 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSDeactivate.InvokeID);
09585 if (cc_record) {
09586 cc_record->outstanding_message = 0;
09587 }
09588 AST_LIST_UNLOCK(&misdn_cc_records_db);
09589 break;
09590
09591 default:
09592 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09593 bc->fac_in.Function);
09594 break;
09595 }
09596 break;
09597 case Fac_CCBSErase:
09598 AST_LIST_LOCK(&misdn_cc_records_db);
09599 cc_record = misdn_cc_find_by_reference(bc->port, bc->fac_in.u.CCBSErase.CCBSReference);
09600 if (cc_record) {
09601 misdn_cc_delete(cc_record);
09602 }
09603 AST_LIST_UNLOCK(&misdn_cc_records_db);
09604 break;
09605 case Fac_CCBSRemoteUserFree:
09606 misdn_cc_handle_remote_user_free(bc->port, &bc->fac_in);
09607 break;
09608 case Fac_CCBSBFree:
09609 misdn_cc_handle_b_free(bc->port, &bc->fac_in);
09610 break;
09611 case Fac_CCBSStatusRequest:
09612 misdn_cc_handle_ccbs_status_request(bc->port, &bc->fac_in);
09613 break;
09614 case Fac_EraseCallLinkageID:
09615 AST_LIST_LOCK(&misdn_cc_records_db);
09616 cc_record = misdn_cc_find_by_linkage(bc->port,
09617 bc->fac_in.u.EraseCallLinkageID.CallLinkageID);
09618 if (cc_record && !cc_record->activation_requested) {
09619
09620
09621
09622
09623
09624 misdn_cc_delete(cc_record);
09625 }
09626 AST_LIST_UNLOCK(&misdn_cc_records_db);
09627 break;
09628 case Fac_CCBSStopAlerting:
09629
09630 break;
09631 case Fac_CCBSRequest:
09632 case Fac_CCNRRequest:
09633 switch (bc->fac_in.u.CCBSRequest.ComponentType) {
09634 case FacComponent_Result:
09635 AST_LIST_LOCK(&misdn_cc_records_db);
09636 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSRequest.InvokeID);
09637 if (cc_record && !cc_record->ptp) {
09638 cc_record->outstanding_message = 0;
09639 cc_record->activated = 1;
09640 cc_record->mode.ptmp.recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
09641 cc_record->mode.ptmp.reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
09642 }
09643 AST_LIST_UNLOCK(&misdn_cc_records_db);
09644 break;
09645
09646 default:
09647 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09648 bc->fac_in.Function);
09649 break;
09650 }
09651 break;
09652 #if 0
09653 case Fac_CCBSInterrogate:
09654 case Fac_CCNRInterrogate:
09655
09656 break;
09657 case Fac_StatusRequest:
09658
09659 break;
09660 #endif
09661 #if 0
09662 case Fac_CCBS_T_Suspend:
09663 case Fac_CCBS_T_Resume:
09664
09665 break;
09666 #endif
09667 case Fac_CCBS_T_RemoteUserFree:
09668 misdn_cc_handle_T_remote_user_free(bc);
09669 break;
09670 case Fac_CCBS_T_Available:
09671 switch (event) {
09672 case EVENT_ALERTING:
09673 case EVENT_DISCONNECT:
09674
09675 if (ch && ch->peer) {
09676 int set_id = 1;
09677
09678 AST_LIST_LOCK(&misdn_cc_records_db);
09679 if (ch->record_id == -1) {
09680 cc_record = misdn_cc_new();
09681 } else {
09682
09683
09684
09685
09686
09687 cc_record = misdn_cc_find_by_id(ch->record_id);
09688 if (cc_record) {
09689 if (cc_record->ptp && cc_record->mode.ptp.retention_enabled) {
09690
09691
09692
09693
09694 chan_misdn_log(1, bc->port, " --> Call-completion request retention option is enabled\n");
09695
09696 set_id = 0;
09697 } else {
09698 if (cc_record->ptp && cc_record->mode.ptp.bc) {
09699
09700
09701
09702
09703
09704
09705
09706
09707
09708 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
09709 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
09710 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
09711 }
09712
09713
09714
09715
09716
09717 new_record_id = misdn_cc_record_id_new();
09718 if (new_record_id < 0) {
09719
09720 } else {
09721 cc_record->record_id = new_record_id;
09722 ch->record_id = new_record_id;
09723 }
09724 cc_record->ptp = 1;
09725 cc_record->port = bc->port;
09726 memset(&cc_record->mode, 0, sizeof(cc_record->mode));
09727 cc_record->invoke_id = ++misdn_invoke_id;
09728 cc_record->activated = 0;
09729 cc_record->outstanding_message = 0;
09730 cc_record->activation_requested = 0;
09731 cc_record->error_code = FacError_None;
09732 cc_record->reject_code = FacReject_None;
09733 memset(&cc_record->remote_user_free, 0, sizeof(cc_record->remote_user_free));
09734 memset(&cc_record->b_free, 0, sizeof(cc_record->b_free));
09735 cc_record->time_created = time(NULL);
09736 }
09737 cc_record = NULL;
09738 } else {
09739
09740
09741
09742
09743
09744 ch->record_id = -1;
09745 cc_record = misdn_cc_new();
09746 }
09747 }
09748 if (cc_record) {
09749 ch->record_id = cc_record->record_id;
09750 cc_record->ptp = 1;
09751 cc_record->port = bc->port;
09752
09753
09754 cc_record->redial.caller = bc->caller;
09755 cc_record->redial.dialed = bc->dialed;
09756 cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
09757 cc_record->redial.capability = bc->capability;
09758 cc_record->redial.hdlc = bc->hdlc;
09759 }
09760 AST_LIST_UNLOCK(&misdn_cc_records_db);
09761
09762
09763 if (ch->record_id != -1 && set_id) {
09764 snprintf(buf, sizeof(buf), "%ld", ch->record_id);
09765 } else {
09766 buf[0] = 0;
09767 }
09768 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, buf);
09769 }
09770 break;
09771 default:
09772 chan_misdn_log(0, bc->port,
09773 " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
09774 bc->fac_in.Function);
09775 break;
09776 }
09777 break;
09778 case Fac_CCBS_T_Request:
09779 case Fac_CCNR_T_Request:
09780 switch (bc->fac_in.u.CCBS_T_Request.ComponentType) {
09781 case FacComponent_Result:
09782 AST_LIST_LOCK(&misdn_cc_records_db);
09783 cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBS_T_Request.InvokeID);
09784 if (cc_record && cc_record->ptp) {
09785 cc_record->outstanding_message = 0;
09786 cc_record->activated = 1;
09787 cc_record->mode.ptp.retention_enabled =
09788 cc_record->mode.ptp.requested_retention
09789 ? bc->fac_in.u.CCBS_T_Request.Component.Result.RetentionSupported
09790 ? 1 : 0
09791 : 0;
09792 }
09793 AST_LIST_UNLOCK(&misdn_cc_records_db);
09794 break;
09795
09796 case FacComponent_Invoke:
09797
09798 default:
09799 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09800 bc->fac_in.Function);
09801 break;
09802 }
09803 break;
09804
09805 #endif
09806 case Fac_None:
09807 break;
09808 default:
09809 chan_misdn_log(0, bc->port, " --> not yet handled: facility type:0x%04X\n",
09810 bc->fac_in.Function);
09811 break;
09812 }
09813 }
09814
09815
09816
09817
09818
09819
09820
09821
09822
09823
09824
09825
09826 static int misdn_is_msn_valid(int port, const struct misdn_party_dialing *dialed)
09827 {
09828 char number[sizeof(dialed->number)];
09829
09830 ast_copy_string(number, dialed->number, sizeof(number));
09831 misdn_add_number_prefix(port, dialed->number_type, number, sizeof(number));
09832 return misdn_cfg_is_msn_valid(port, number);
09833 }
09834
09835
09836
09837
09838 static enum event_response_e
09839 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
09840 {
09841 #if defined(AST_MISDN_ENHANCEMENTS)
09842 struct misdn_cc_record *cc_record;
09843 #endif
09844 struct chan_list *held_ch;
09845 struct chan_list *ch = find_chan_by_bc(bc);
09846
09847 if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) {
09848 int debuglevel = 1;
09849
09850
09851 if (event == EVENT_CLEANUP && !user_data) {
09852 debuglevel = 5;
09853 }
09854
09855 chan_misdn_log(debuglevel, bc->port,
09856 "I IND :%s caller:\"%s\" <%s> dialed:%s pid:%d state:%s\n",
09857 manager_isdn_get_info(event),
09858 bc->caller.name,
09859 bc->caller.number,
09860 bc->dialed.number,
09861 bc->pid,
09862 ch ? misdn_get_ch_state(ch) : "none");
09863 if (debuglevel == 1) {
09864 misdn_lib_log_ies(bc);
09865 chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
09866 }
09867 }
09868
09869 if (!ch) {
09870 switch(event) {
09871 case EVENT_SETUP:
09872 case EVENT_DISCONNECT:
09873 case EVENT_RELEASE:
09874 case EVENT_RELEASE_COMPLETE:
09875 case EVENT_PORT_ALARM:
09876 case EVENT_RETRIEVE:
09877 case EVENT_NEW_BC:
09878 case EVENT_FACILITY:
09879 case EVENT_REGISTER:
09880 break;
09881 case EVENT_CLEANUP:
09882 case EVENT_TONE_GENERATE:
09883 case EVENT_BCHAN_DATA:
09884 return -1;
09885 default:
09886 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);
09887 return -1;
09888 }
09889 } else {
09890 switch (event) {
09891 case EVENT_TONE_GENERATE:
09892 break;
09893 case EVENT_DISCONNECT:
09894 case EVENT_RELEASE:
09895 case EVENT_RELEASE_COMPLETE:
09896 case EVENT_CLEANUP:
09897 case EVENT_TIMEOUT:
09898 if (!ch->ast) {
09899 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));
09900 }
09901 break;
09902 default:
09903 if (!ch->ast || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
09904 if (event != EVENT_BCHAN_DATA) {
09905 ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
09906 }
09907 chan_list_unref(ch, "No Ast or Ast private pointer");
09908 return -1;
09909 }
09910 break;
09911 }
09912 }
09913
09914
09915 switch (event) {
09916 case EVENT_PORT_ALARM:
09917 {
09918 int boa = 0;
09919 misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
09920 if (boa) {
09921 cb_log(1, bc->port, " --> blocking\n");
09922 misdn_lib_port_block(bc->port);
09923 }
09924 }
09925 break;
09926 case EVENT_BCHAN_ACTIVATED:
09927 break;
09928
09929 case EVENT_NEW_CHANNEL:
09930 update_name(ch->ast,bc->port,bc->channel);
09931 break;
09932
09933 case EVENT_NEW_L3ID:
09934 ch->l3id=bc->l3_id;
09935 ch->addr=bc->addr;
09936 break;
09937
09938 case EVENT_NEW_BC:
09939 if (!ch) {
09940 ch = find_hold_call(bc);
09941 }
09942
09943 if (!ch) {
09944 ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
09945 break;
09946 }
09947
09948 if (bc) {
09949 ch->bc = (struct misdn_bchannel *) user_data;
09950 }
09951 break;
09952
09953 case EVENT_DTMF_TONE:
09954 {
09955
09956 struct ast_frame fr;
09957
09958 memset(&fr, 0, sizeof(fr));
09959 fr.frametype = AST_FRAME_DTMF;
09960 fr.subclass.integer = bc->dtmf ;
09961 fr.src = NULL;
09962 fr.data.ptr = NULL;
09963 fr.datalen = 0;
09964 fr.samples = 0;
09965 fr.mallocd = 0;
09966 fr.offset = 0;
09967 fr.delivery = ast_tv(0,0);
09968
09969 if (!ch->ignore_dtmf) {
09970 chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
09971 ast_queue_frame(ch->ast, &fr);
09972 } else {
09973 chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
09974 }
09975 break;
09976 }
09977 case EVENT_STATUS:
09978 break;
09979
09980 case EVENT_INFORMATION:
09981 if (ch->state != MISDN_CONNECTED) {
09982 stop_indicate(ch);
09983 }
09984
09985 if (!ch->ast) {
09986 break;
09987 }
09988
09989 if (ch->state == MISDN_WAITING4DIGS) {
09990
09991 if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
09992 chan_misdn_log(1, bc->port, " --> using keypad as info\n");
09993 ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
09994 }
09995
09996 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
09997 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
09998
09999
10000 if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
10001 if (ast_pickup_call(ch->ast)) {
10002 hangup_chan(ch, bc);
10003 } else {
10004 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10005 hangup_chan(ch, bc);
10006 ch->ast = NULL;
10007 break;
10008 }
10009 }
10010
10011 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10012 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10013 ast_log(LOG_WARNING,
10014 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10015 bc->dialed.number, ch->context, bc->port);
10016 strcpy(ch->ast->exten, "i");
10017
10018 ch->state = MISDN_DIALING;
10019 start_pbx(ch, bc, ch->ast);
10020 break;
10021 }
10022
10023 ast_log(LOG_WARNING,
10024 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10025 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10026 bc->dialed.number, ch->context, bc->port);
10027
10028 if (bc->nt) {
10029 hanguptone_indicate(ch);
10030 }
10031 ch->state = MISDN_EXTCANTMATCH;
10032 bc->out_cause = AST_CAUSE_UNALLOCATED;
10033
10034 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10035 break;
10036 }
10037
10038 if (ch->overlap_dial) {
10039 ast_mutex_lock(&ch->overlap_tv_lock);
10040 ch->overlap_tv = ast_tvnow();
10041 ast_mutex_unlock(&ch->overlap_tv_lock);
10042 if (ch->overlap_dial_task == -1) {
10043 ch->overlap_dial_task =
10044 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10045 }
10046 break;
10047 }
10048
10049 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10050 ch->state = MISDN_DIALING;
10051 start_pbx(ch, bc, ch->ast);
10052 }
10053 } else {
10054
10055 struct ast_frame fr;
10056 int digits;
10057
10058 memset(&fr, 0, sizeof(fr));
10059 fr.frametype = AST_FRAME_DTMF;
10060 fr.subclass.integer = bc->info_dad[0] ;
10061 fr.src = NULL;
10062 fr.data.ptr = NULL;
10063 fr.datalen = 0;
10064 fr.samples = 0;
10065 fr.mallocd = 0;
10066 fr.offset = 0;
10067 fr.delivery = ast_tv(0,0);
10068
10069 misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
10070 if (ch->state != MISDN_CONNECTED) {
10071 if (digits) {
10072 strncat(bc->dialed.number, bc->info_dad, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10073 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10074 ast_cdr_update(ch->ast);
10075 }
10076
10077 ast_queue_frame(ch->ast, &fr);
10078 }
10079 }
10080 break;
10081 case EVENT_SETUP:
10082 {
10083 struct ast_channel *chan;
10084 int exceed;
10085 int ai;
10086 int im;
10087 int append_msn = 0;
10088
10089 if (ch) {
10090 switch (ch->state) {
10091 case MISDN_NOTHING:
10092 chan_list_unref(ch, "Ignore found ch. Is it for an outgoing call?");
10093 ch = NULL;
10094 break;
10095 default:
10096 chan_list_unref(ch, "Already have a call.");
10097 chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
10098 return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE;
10099 }
10100 }
10101
10102 if (!bc->nt && !misdn_is_msn_valid(bc->port, &bc->dialed)) {
10103 chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
10104 return RESPONSE_IGNORE_SETUP;
10105 }
10106
10107 if (bc->cw) {
10108 int cause;
10109 chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
10110 misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
10111 bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
10112 return RESPONSE_RELEASE_SETUP;
10113 }
10114
10115 print_bearer(bc);
10116
10117 ch = chan_list_init(ORG_MISDN);
10118 if (!ch) {
10119 chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
10120 return 0;
10121 }
10122
10123 ch->bc = bc;
10124 ch->l3id = bc->l3_id;
10125 ch->addr = bc->addr;
10126
10127 chan = misdn_new(ch, AST_STATE_RESERVED, bc->dialed.number, bc->caller.number, AST_FORMAT_ALAW, NULL, bc->port, bc->channel);
10128 if (!chan) {
10129 chan_list_unref(ch, "Failed to create a new channel");
10130 misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
10131 ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
10132 return 0;
10133 }
10134
10135 if ((exceed = add_in_calls(bc->port))) {
10136 char tmp[16];
10137 snprintf(tmp, sizeof(tmp), "%d", exceed);
10138 pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
10139 }
10140
10141 read_config(ch);
10142
10143 export_ch(chan, bc, ch);
10144
10145 ch->ast->rings = 1;
10146 ast_setstate(ch->ast, AST_STATE_RINGING);
10147
10148
10149 chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type);
10150 chan_misdn_log(2, bc->port, " --> PLAN: %s(%d)\n", misdn_to_str_plan(bc->caller.number_plan), bc->caller.number_plan);
10151 chan->caller.id.number.plan = misdn_to_ast_ton(bc->caller.number_type)
10152 | misdn_to_ast_plan(bc->caller.number_plan);
10153
10154 chan_misdn_log(2, bc->port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
10155 chan_misdn_log(2, bc->port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
10156 chan->caller.id.number.presentation = misdn_to_ast_pres(bc->caller.presentation)
10157 | misdn_to_ast_screen(bc->caller.screening);
10158
10159 ast_set_callerid(chan, bc->caller.number, NULL, bc->caller.number);
10160
10161 misdn_cfg_get(bc->port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
10162 if (append_msn) {
10163 strncat(bc->incoming_cid_tag, "_", sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10164 strncat(bc->incoming_cid_tag, bc->dialed.number, sizeof(bc->incoming_cid_tag) - strlen(bc->incoming_cid_tag) - 1);
10165 }
10166
10167 ast_channel_lock(chan);
10168 chan->caller.id.tag = ast_strdup(bc->incoming_cid_tag);
10169 ast_channel_unlock(chan);
10170
10171 if (!ast_strlen_zero(bc->redirecting.from.number)) {
10172
10173 misdn_add_number_prefix(bc->port, bc->redirecting.from.number_type, bc->redirecting.from.number, sizeof(bc->redirecting.from.number));
10174
10175
10176 misdn_copy_redirecting_to_ast(chan, &bc->redirecting, bc->incoming_cid_tag);
10177 }
10178
10179 pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
10180 chan->transfercapability = bc->capability;
10181
10182 switch (bc->capability) {
10183 case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
10184 pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
10185 break;
10186 default:
10187 pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
10188 break;
10189 }
10190
10191
10192 cl_queue_chan(ch);
10193
10194 if (!strstr(ch->allowed_bearers, "all")) {
10195 int i;
10196
10197 for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
10198 if (allowed_bearers_array[i].cap == bc->capability) {
10199 if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
10200
10201 if (allowed_bearers_array[i].deprecated) {
10202 chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
10203 allowed_bearers_array[i].name);
10204 }
10205 break;
10206 }
10207 }
10208 }
10209 if (i == ARRAY_LEN(allowed_bearers_array)) {
10210
10211 chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
10212 bearer2str(bc->capability), bc->capability);
10213 bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
10214
10215 ch->state = MISDN_EXTCANTMATCH;
10216 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10217 chan_list_unref(ch, "BC not allowed, releasing call");
10218 return RESPONSE_OK;
10219 }
10220 }
10221
10222 if (bc->fac_in.Function != Fac_None) {
10223 misdn_facility_ie_handler(event, bc, ch);
10224 }
10225
10226
10227 if (!strcmp(chan->exten, ast_pickup_ext())) {
10228 if (!ch->noautorespond_on_setup) {
10229
10230 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10231 } else {
10232 ch->state = MISDN_INCOMING_SETUP;
10233 }
10234 if (ast_pickup_call(chan)) {
10235 hangup_chan(ch, bc);
10236 } else {
10237 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10238 hangup_chan(ch, bc);
10239 ch->ast = NULL;
10240 break;
10241 }
10242 }
10243
10244
10245
10246
10247
10248 misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
10249 if (ai) {
10250 do_immediate_setup(bc, ch, chan);
10251 break;
10252 }
10253
10254
10255 misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
10256 if (im && ast_strlen_zero(bc->dialed.number)) {
10257 do_immediate_setup(bc, ch, chan);
10258 break;
10259 }
10260
10261 chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
10262 if (!ast_canmatch_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10263 if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->caller.number)) {
10264 ast_log(LOG_WARNING,
10265 "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
10266 bc->dialed.number, ch->context, bc->port);
10267 strcpy(ch->ast->exten, "i");
10268 misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
10269 ch->state = MISDN_DIALING;
10270 start_pbx(ch, bc, chan);
10271 break;
10272 }
10273
10274 ast_log(LOG_WARNING,
10275 "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
10276 "\tMaybe you want to add an 'i' extension to catch this case.\n",
10277 bc->dialed.number, ch->context, bc->port);
10278 if (bc->nt) {
10279 hanguptone_indicate(ch);
10280 }
10281
10282 ch->state = MISDN_EXTCANTMATCH;
10283 bc->out_cause = AST_CAUSE_UNALLOCATED;
10284
10285 misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE);
10286 break;
10287 }
10288
10289
10290
10291
10292 if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
10293 if (!ch->noautorespond_on_setup) {
10294 ch->state=MISDN_DIALING;
10295 misdn_lib_send_event(bc, EVENT_PROCEEDING);
10296 } else {
10297 ch->state = MISDN_INCOMING_SETUP;
10298 }
10299 start_pbx(ch, bc, chan);
10300 break;
10301 }
10302
10303
10304
10305
10306
10307
10308
10309 if (ch->overlap_dial && bc->nt && !bc->dialed.number[0]) {
10310 wait_for_digits(ch, bc, chan);
10311 break;
10312 }
10313
10314
10315
10316
10317
10318 if (ch->overlap_dial) {
10319 ast_mutex_lock(&ch->overlap_tv_lock);
10320 ch->overlap_tv = ast_tvnow();
10321 ast_mutex_unlock(&ch->overlap_tv_lock);
10322
10323 wait_for_digits(ch, bc, chan);
10324 if (ch->overlap_dial_task == -1) {
10325 ch->overlap_dial_task =
10326 misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
10327 }
10328 break;
10329 }
10330
10331
10332
10333
10334 if (!ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10335 wait_for_digits(ch, bc, chan);
10336 break;
10337 }
10338
10339
10340
10341
10342 if (ast_exists_extension(ch->ast, ch->context, bc->dialed.number, 1, bc->caller.number)) {
10343 misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
10344 ch->state = MISDN_DIALING;
10345 start_pbx(ch, bc, chan);
10346 break;
10347 }
10348 break;
10349 }
10350 #if defined(AST_MISDN_ENHANCEMENTS)
10351 case EVENT_REGISTER:
10352 if (bc->fac_in.Function != Fac_None) {
10353 misdn_facility_ie_handler(event, bc, ch);
10354 }
10355
10356
10357
10358
10359
10360
10361
10362 bc->fac_out.Function = Fac_None;
10363 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10364 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10365 break;
10366 #endif
10367 case EVENT_SETUP_ACKNOWLEDGE:
10368 ch->state = MISDN_CALLING_ACKNOWLEDGE;
10369
10370 if (bc->channel) {
10371 update_name(ch->ast,bc->port,bc->channel);
10372 }
10373
10374 if (bc->fac_in.Function != Fac_None) {
10375 misdn_facility_ie_handler(event, bc, ch);
10376 }
10377
10378 if (!ast_strlen_zero(bc->infos_pending)) {
10379
10380 strncat(bc->dialed.number, bc->infos_pending, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
10381
10382 if (!ch->ast) {
10383 break;
10384 }
10385 ast_copy_string(ch->ast->exten, bc->dialed.number, sizeof(ch->ast->exten));
10386 ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
10387 ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
10388
10389 misdn_lib_send_event(bc, EVENT_INFORMATION);
10390 }
10391 break;
10392 case EVENT_PROCEEDING:
10393 if (misdn_cap_is_speech(bc->capability) &&
10394 misdn_inband_avail(bc)) {
10395 start_bc_tones(ch);
10396 }
10397
10398 ch->state = MISDN_PROCEEDING;
10399
10400 if (bc->fac_in.Function != Fac_None) {
10401 misdn_facility_ie_handler(event, bc, ch);
10402 }
10403
10404 if (!ch->ast) {
10405 break;
10406 }
10407
10408 ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
10409 break;
10410 case EVENT_PROGRESS:
10411 if (bc->channel) {
10412 update_name(ch->ast, bc->port, bc->channel);
10413 }
10414
10415 if (bc->fac_in.Function != Fac_None) {
10416 misdn_facility_ie_handler(event, bc, ch);
10417 }
10418
10419 if (!bc->nt) {
10420 if (misdn_cap_is_speech(bc->capability) &&
10421 misdn_inband_avail(bc)) {
10422 start_bc_tones(ch);
10423 }
10424
10425 ch->state = MISDN_PROGRESS;
10426
10427 if (!ch->ast) {
10428 break;
10429 }
10430 ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
10431 }
10432 break;
10433 case EVENT_ALERTING:
10434 ch->state = MISDN_ALERTING;
10435
10436 if (!ch->ast) {
10437 break;
10438 }
10439
10440 if (bc->fac_in.Function != Fac_None) {
10441 misdn_facility_ie_handler(event, bc, ch);
10442 }
10443
10444 ast_queue_control(ch->ast, AST_CONTROL_RINGING);
10445 ast_setstate(ch->ast, AST_STATE_RINGING);
10446
10447 cb_log(7, bc->port, " --> Set State Ringing\n");
10448
10449 if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
10450 cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
10451 start_bc_tones(ch);
10452 } else {
10453 cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
10454 if (ch->far_alerting) {
10455 cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
10456 start_bc_tones(ch);
10457
10458 }
10459 }
10460 break;
10461 case EVENT_CONNECT:
10462 if (bc->fac_in.Function != Fac_None) {
10463 misdn_facility_ie_handler(event, bc, ch);
10464 }
10465 #if defined(AST_MISDN_ENHANCEMENTS)
10466 if (bc->div_leg_3_rx_wanted) {
10467 bc->div_leg_3_rx_wanted = 0;
10468
10469 if (ch->ast) {
10470 ch->ast->redirecting.to.number.presentation =
10471 AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED;
10472 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10473 }
10474 }
10475 #endif
10476
10477
10478 misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
10479
10480 if (!ch->ast) {
10481 break;
10482 }
10483
10484 stop_indicate(ch);
10485
10486 #if defined(AST_MISDN_ENHANCEMENTS)
10487 if (ch->record_id != -1) {
10488
10489
10490
10491
10492
10493
10494 AST_LIST_LOCK(&misdn_cc_records_db);
10495 cc_record = misdn_cc_find_by_id(ch->record_id);
10496 if (cc_record) {
10497 if (cc_record->ptp && cc_record->mode.ptp.bc) {
10498
10499 cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
10500 cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10501 misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
10502 }
10503 misdn_cc_delete(cc_record);
10504 }
10505 AST_LIST_UNLOCK(&misdn_cc_records_db);
10506 ch->record_id = -1;
10507 if (ch->peer) {
10508 misdn_cc_set_peer_var(ch->peer, MISDN_CC_RECORD_ID, "");
10509
10510 ao2_ref(ch->peer, -1);
10511 ch->peer = NULL;
10512 }
10513 }
10514 #endif
10515
10516 if (!ast_strlen_zero(bc->connected.number)) {
10517
10518 misdn_add_number_prefix(bc->port, bc->connected.number_type, bc->connected.number, sizeof(bc->connected.number));
10519
10520
10521 misdn_update_remote_party(ch->ast, &bc->connected, AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, bc->incoming_cid_tag);
10522 }
10523
10524 ch->l3id = bc->l3_id;
10525 ch->addr = bc->addr;
10526
10527 start_bc_tones(ch);
10528
10529 ch->state = MISDN_CONNECTED;
10530
10531 ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
10532 break;
10533 case EVENT_CONNECT_ACKNOWLEDGE:
10534 ch->l3id = bc->l3_id;
10535 ch->addr = bc->addr;
10536
10537 start_bc_tones(ch);
10538
10539 ch->state = MISDN_CONNECTED;
10540 break;
10541 case EVENT_DISCONNECT:
10542
10543 if (ch) {
10544 if (bc->fac_in.Function != Fac_None) {
10545 misdn_facility_ie_handler(event, bc, ch);
10546 }
10547
10548 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);
10549 if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
10550
10551
10552
10553
10554
10555 chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
10556
10557 ch->state = MISDN_DISCONNECTED;
10558 start_bc_tones(ch);
10559
10560 if (ch->ast) {
10561 ch->ast->hangupcause = bc->cause;
10562 if (bc->cause == AST_CAUSE_USER_BUSY) {
10563 ast_queue_control(ch->ast, AST_CONTROL_BUSY);
10564 }
10565 }
10566 ch->need_busy = 0;
10567 break;
10568 }
10569
10570 bc->need_disconnect = 0;
10571 stop_bc_tones(ch);
10572
10573
10574 held_ch = find_hold_call(bc);
10575 if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
10576 hangup_chan(ch, bc);
10577 }
10578 } else {
10579 held_ch = find_hold_call_l3(bc->l3_id);
10580 if (held_ch) {
10581 if (bc->fac_in.Function != Fac_None) {
10582 misdn_facility_ie_handler(event, bc, held_ch);
10583 }
10584
10585 if (held_ch->hold.state == MISDN_HOLD_ACTIVE) {
10586 bc->need_disconnect = 0;
10587
10588 #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
10589
10590
10591
10592
10593
10594 ch = find_hold_active_call(bc);
10595 if (!ch || misdn_attempt_transfer(ch, held_ch)) {
10596 held_ch->hold.state = MISDN_HOLD_DISCONNECT;
10597 hangup_chan(held_ch, bc);
10598 }
10599 #else
10600 hangup_chan(held_ch, bc);
10601 #endif
10602 }
10603 }
10604 }
10605 if (held_ch) {
10606 chan_list_unref(held_ch, "Done with held call");
10607 }
10608 bc->out_cause = -1;
10609 if (bc->need_release) {
10610 misdn_lib_send_event(bc, EVENT_RELEASE);
10611 }
10612 break;
10613 case EVENT_RELEASE:
10614 if (!ch) {
10615 ch = find_hold_call_l3(bc->l3_id);
10616 if (!ch) {
10617 chan_misdn_log(1, bc->port,
10618 " --> no Ch, so we've already released. (%s)\n",
10619 manager_isdn_get_info(event));
10620 return -1;
10621 }
10622 }
10623 if (bc->fac_in.Function != Fac_None) {
10624 misdn_facility_ie_handler(event, bc, ch);
10625 }
10626
10627 bc->need_disconnect = 0;
10628 bc->need_release = 0;
10629
10630 hangup_chan(ch, bc);
10631 release_chan(ch, bc);
10632 break;
10633 case EVENT_RELEASE_COMPLETE:
10634 if (!ch) {
10635 ch = find_hold_call_l3(bc->l3_id);
10636 }
10637
10638 bc->need_disconnect = 0;
10639 bc->need_release = 0;
10640 bc->need_release_complete = 0;
10641
10642 if (ch) {
10643 if (bc->fac_in.Function != Fac_None) {
10644 misdn_facility_ie_handler(event, bc, ch);
10645 }
10646
10647 stop_bc_tones(ch);
10648 hangup_chan(ch, bc);
10649 release_chan(ch, bc);
10650 } else {
10651 #if defined(AST_MISDN_ENHANCEMENTS)
10652
10653
10654
10655
10656
10657 AST_LIST_LOCK(&misdn_cc_records_db);
10658 cc_record = misdn_cc_find_by_bc(bc);
10659 if (cc_record) {
10660
10661 misdn_cc_delete(cc_record);
10662 }
10663 AST_LIST_UNLOCK(&misdn_cc_records_db);
10664 #endif
10665
10666 chan_misdn_log(1, bc->port,
10667 " --> no Ch, so we've already released. (%s)\n",
10668 manager_isdn_get_info(event));
10669 }
10670 break;
10671 case EVENT_BCHAN_ERROR:
10672 case EVENT_CLEANUP:
10673 stop_bc_tones(ch);
10674
10675 switch (ch->state) {
10676 case MISDN_CALLING:
10677 bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
10678 break;
10679 default:
10680 break;
10681 }
10682
10683 hangup_chan(ch, bc);
10684 release_chan(ch, bc);
10685 break;
10686 case EVENT_TONE_GENERATE:
10687 {
10688 int tone_len = bc->tone_cnt;
10689 struct ast_channel *ast = ch->ast;
10690 void *tmp;
10691 int res;
10692 int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
10693
10694 chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);
10695
10696 if (!ast) {
10697 break;
10698 }
10699
10700 if (!ast->generator) {
10701 break;
10702 }
10703
10704 tmp = ast->generatordata;
10705 ast->generatordata = NULL;
10706 generate = ast->generator->generate;
10707
10708 if (tone_len < 0 || tone_len > 512) {
10709 ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
10710 tone_len = 128;
10711 }
10712
10713 res = generate(ast, tmp, tone_len, tone_len);
10714 ast->generatordata = tmp;
10715
10716 if (res) {
10717 ast_log(LOG_WARNING, "Auto-deactivating generator\n");
10718 ast_deactivate_generator(ast);
10719 } else {
10720 bc->tone_cnt = 0;
10721 }
10722 break;
10723 }
10724 case EVENT_BCHAN_DATA:
10725 if (ch->bc->AOCD_need_export) {
10726 export_aoc_vars(ch->originator, ch->ast, ch->bc);
10727 }
10728 if (!misdn_cap_is_speech(ch->bc->capability)) {
10729 struct ast_frame frame;
10730
10731
10732 memset(&frame, 0, sizeof(frame));
10733 frame.frametype = AST_FRAME_VOICE;
10734 frame.subclass.codec = AST_FORMAT_ALAW;
10735 frame.datalen = bc->bframe_len;
10736 frame.samples = bc->bframe_len;
10737 frame.mallocd = 0;
10738 frame.offset = 0;
10739 frame.delivery = ast_tv(0, 0);
10740 frame.src = NULL;
10741 frame.data.ptr = bc->bframe;
10742
10743 if (ch->ast) {
10744 ast_queue_frame(ch->ast, &frame);
10745 }
10746 } else {
10747 struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
10748 int t;
10749
10750 t = ast_poll(&pfd, 1, 0);
10751
10752 if (t < 0) {
10753 chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
10754 break;
10755 }
10756 if (!t) {
10757 chan_misdn_log(9, bc->port, "poll() timed out\n");
10758 break;
10759 }
10760
10761 if (pfd.revents & POLLOUT) {
10762 chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
10763 if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
10764 chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
10765
10766 stop_bc_tones(ch);
10767 hangup_chan(ch, bc);
10768 release_chan(ch, bc);
10769 }
10770 } else {
10771 chan_misdn_log(1, bc->port, "Write Pipe full!\n");
10772 }
10773 }
10774 break;
10775 case EVENT_TIMEOUT:
10776 if (ch && bc) {
10777 chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
10778 }
10779
10780 switch (ch->state) {
10781 case MISDN_DIALING:
10782 case MISDN_PROGRESS:
10783 if (bc->nt && !ch->nttimeout) {
10784 break;
10785 }
10786
10787 case MISDN_CALLING:
10788 case MISDN_ALERTING:
10789 case MISDN_PROCEEDING:
10790 case MISDN_CALLING_ACKNOWLEDGE:
10791 if (bc->nt) {
10792 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10793 hanguptone_indicate(ch);
10794 }
10795
10796 bc->out_cause = AST_CAUSE_UNALLOCATED;
10797 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10798 break;
10799 case MISDN_WAITING4DIGS:
10800 if (bc->nt) {
10801 bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
10802 bc->out_cause = AST_CAUSE_UNALLOCATED;
10803 hanguptone_indicate(ch);
10804 misdn_lib_send_event(bc, EVENT_DISCONNECT);
10805 } else {
10806 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
10807 misdn_lib_send_event(bc, EVENT_RELEASE);
10808 }
10809 break;
10810 case MISDN_CLEANING:
10811 chan_misdn_log(1, bc->port, " --> in state cleaning .. so ignoring, the stack should clean it for us\n");
10812 break;
10813 default:
10814 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
10815 break;
10816 }
10817 break;
10818
10819
10820
10821
10822 case EVENT_RETRIEVE:
10823 if (!ch) {
10824 chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
10825 ch = find_hold_call_l3(bc->l3_id);
10826 if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
10827 ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
10828 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10829 break;
10830 }
10831 }
10832
10833
10834 ch->bc = bc;
10835
10836 ch->hold.state = MISDN_HOLD_IDLE;
10837 ch->hold.port = 0;
10838 ch->hold.channel = 0;
10839
10840 ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
10841
10842 if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
10843 chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
10844 misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
10845 }
10846 break;
10847 case EVENT_HOLD:
10848 {
10849 int hold_allowed;
10850 struct ast_channel *bridged;
10851
10852 misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
10853 if (!hold_allowed) {
10854 chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
10855 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10856 break;
10857 }
10858
10859 bridged = ast_bridged_channel(ch->ast);
10860 if (bridged) {
10861 chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
10862 ch->l3id = bc->l3_id;
10863
10864
10865 ch->bc = NULL;
10866 ch->hold.state = MISDN_HOLD_ACTIVE;
10867 ch->hold.port = bc->port;
10868 ch->hold.channel = bc->channel;
10869
10870 ast_queue_control(ch->ast, AST_CONTROL_HOLD);
10871
10872 misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
10873 } else {
10874 misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
10875 chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
10876 }
10877 break;
10878 }
10879 case EVENT_NOTIFY:
10880 if (bc->redirecting.to_changed) {
10881
10882 misdn_add_number_prefix(bc->port, bc->redirecting.to.number_type,
10883 bc->redirecting.to.number, sizeof(bc->redirecting.to.number));
10884 }
10885 switch (bc->notify_description_code) {
10886 case mISDN_NOTIFY_CODE_DIVERSION_ACTIVATED:
10887
10888 bc->redirecting.to_changed = 0;
10889 break;
10890 case mISDN_NOTIFY_CODE_CALL_IS_DIVERTING:
10891 if (!bc->redirecting.to_changed) {
10892 break;
10893 }
10894 bc->redirecting.to_changed = 0;
10895 if (!ch || !ch->ast) {
10896 break;
10897 }
10898 switch (ch->state) {
10899 case MISDN_ALERTING:
10900
10901 bc->redirecting.reason = mISDN_REDIRECTING_REASON_NO_REPLY;
10902 break;
10903 default:
10904
10905 bc->redirecting.reason = mISDN_REDIRECTING_REASON_UNKNOWN;
10906 break;
10907 }
10908 misdn_copy_redirecting_to_ast(ch->ast, &bc->redirecting, bc->incoming_cid_tag);
10909 ast_channel_queue_redirecting_update(ch->ast, &ch->ast->redirecting, NULL);
10910 break;
10911 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ALERTING:
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921 if (!bc->redirecting.to_changed) {
10922 break;
10923 }
10924 bc->redirecting.to_changed = 0;
10925 if (!ch || !ch->ast) {
10926 break;
10927 }
10928 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10929 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING,
10930 bc->incoming_cid_tag);
10931 break;
10932 case mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE:
10933 if (!bc->redirecting.to_changed) {
10934 break;
10935 }
10936 bc->redirecting.to_changed = 0;
10937 if (!ch || !ch->ast) {
10938 break;
10939 }
10940 misdn_update_remote_party(ch->ast, &bc->redirecting.to,
10941 AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, bc->incoming_cid_tag);
10942 break;
10943 default:
10944 bc->redirecting.to_changed = 0;
10945 chan_misdn_log(0, bc->port," --> not yet handled: notify code:0x%02X\n",
10946 bc->notify_description_code);
10947 break;
10948 }
10949 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10950 break;
10951 case EVENT_FACILITY:
10952 if (bc->fac_in.Function == Fac_None) {
10953
10954 chan_misdn_log(0, bc->port," --> Missing facility ie or unknown facility ie contents.\n");
10955 } else {
10956 misdn_facility_ie_handler(event, bc, ch);
10957 }
10958
10959
10960 bc->redirecting.to_changed = 0;
10961 bc->notify_description_code = mISDN_NOTIFY_CODE_INVALID;
10962 break;
10963 case EVENT_RESTART:
10964 if (!bc->dummy) {
10965 stop_bc_tones(ch);
10966 release_chan(ch, bc);
10967 }
10968 break;
10969 default:
10970 chan_misdn_log(1, 0, "Got Unknown Event\n");
10971 break;
10972 }
10973
10974 if (ch) {
10975 chan_list_unref(ch, "cb_event complete OK");
10976 }
10977 return RESPONSE_OK;
10978 }
10979
10980
10981
10982 #if defined(AST_MISDN_ENHANCEMENTS)
10983
10984
10985
10986
10987
10988
10989
10990
10991
10992
10993
10994
10995
10996 static int misdn_cc_read(struct ast_channel *chan, const char *function_name,
10997 char *function_args, char *buf, size_t size)
10998 {
10999 char *parse;
11000 struct misdn_cc_record *cc_record;
11001
11002 AST_DECLARE_APP_ARGS(args,
11003 AST_APP_ARG(cc_id);
11004 AST_APP_ARG(get_name);
11005 AST_APP_ARG(other);
11006 );
11007
11008
11009 *buf = 0;
11010
11011 if (ast_strlen_zero(function_args)) {
11012 ast_log(LOG_ERROR, "Function '%s' requires arguments.\n", function_name);
11013 return -1;
11014 }
11015
11016 parse = ast_strdupa(function_args);
11017 AST_STANDARD_APP_ARGS(args, parse);
11018
11019 if (!args.argc || ast_strlen_zero(args.cc_id)) {
11020 ast_log(LOG_ERROR, "Function '%s' missing call completion record ID.\n",
11021 function_name);
11022 return -1;
11023 }
11024 if (!isdigit(*args.cc_id)) {
11025 ast_log(LOG_ERROR, "Function '%s' call completion record ID must be numeric.\n",
11026 function_name);
11027 return -1;
11028 }
11029
11030 if (ast_strlen_zero(args.get_name)) {
11031 ast_log(LOG_ERROR, "Function '%s' missing what-to-get parameter.\n",
11032 function_name);
11033 return -1;
11034 }
11035
11036 AST_LIST_LOCK(&misdn_cc_records_db);
11037 cc_record = misdn_cc_find_by_id(atoi(args.cc_id));
11038 if (cc_record) {
11039 if (!strcasecmp("a-all", args.get_name)) {
11040 snprintf(buf, size, "\"%s\" <%s>", cc_record->redial.caller.name,
11041 cc_record->redial.caller.number);
11042 } else if (!strcasecmp("a-name", args.get_name)) {
11043 ast_copy_string(buf, cc_record->redial.caller.name, size);
11044 } else if (!strncasecmp("a-num", args.get_name, 5)) {
11045 ast_copy_string(buf, cc_record->redial.caller.number, size);
11046 } else if (!strcasecmp("a-ton", args.get_name)) {
11047 snprintf(buf, size, "%d",
11048 misdn_to_ast_plan(cc_record->redial.caller.number_plan)
11049 | misdn_to_ast_ton(cc_record->redial.caller.number_type));
11050 } else if (!strncasecmp("a-pres", args.get_name, 6)) {
11051 ast_copy_string(buf, ast_named_caller_presentation(
11052 misdn_to_ast_pres(cc_record->redial.caller.presentation)
11053 | misdn_to_ast_screen(cc_record->redial.caller.screening)), size);
11054 } else if (!strcasecmp("a-busy", args.get_name)) {
11055 ast_copy_string(buf, cc_record->party_a_free ? "no" : "yes", size);
11056 } else if (!strncasecmp("b-num", args.get_name, 5)) {
11057 ast_copy_string(buf, cc_record->redial.dialed.number, size);
11058 } else if (!strcasecmp("b-ton", args.get_name)) {
11059 snprintf(buf, size, "%d",
11060 misdn_to_ast_plan(cc_record->redial.dialed.number_plan)
11061 | misdn_to_ast_ton(cc_record->redial.dialed.number_type));
11062 } else if (!strcasecmp("port", args.get_name)) {
11063 snprintf(buf, size, "%d", cc_record->port);
11064 } else if (!strcasecmp("available-notify-priority", args.get_name)) {
11065 snprintf(buf, size, "%d", cc_record->remote_user_free.priority);
11066 } else if (!strcasecmp("available-notify-exten", args.get_name)) {
11067 ast_copy_string(buf, cc_record->remote_user_free.exten, size);
11068 } else if (!strcasecmp("available-notify-context", args.get_name)) {
11069 ast_copy_string(buf, cc_record->remote_user_free.context, size);
11070 } else if (!strcasecmp("busy-notify-priority", args.get_name)) {
11071 snprintf(buf, size, "%d", cc_record->b_free.priority);
11072 } else if (!strcasecmp("busy-notify-exten", args.get_name)) {
11073 ast_copy_string(buf, cc_record->b_free.exten, size);
11074 } else if (!strcasecmp("busy-notify-context", args.get_name)) {
11075 ast_copy_string(buf, cc_record->b_free.context, size);
11076 } else {
11077 AST_LIST_UNLOCK(&misdn_cc_records_db);
11078 ast_log(LOG_ERROR, "Function '%s': Unknown what-to-get '%s'.\n", function_name, args.get_name);
11079 return -1;
11080 }
11081 }
11082 AST_LIST_UNLOCK(&misdn_cc_records_db);
11083
11084 return 0;
11085 }
11086 #endif
11087
11088 #if defined(AST_MISDN_ENHANCEMENTS)
11089 static struct ast_custom_function misdn_cc_function = {
11090 .name = "mISDN_CC",
11091 .synopsis = "Get call completion record information.",
11092 .syntax = "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)",
11093 .desc =
11094 "mISDN_CC(${MISDN_CC_RECORD_ID},<what-to-get>)\n"
11095 "The following can be retrieved:\n"
11096 "\"a-num\", \"a-name\", \"a-all\", \"a-ton\", \"a-pres\", \"a-busy\",\n"
11097 "\"b-num\", \"b-ton\", \"port\",\n"
11098 " User-A is available for call completion:\n"
11099 " \"available-notify-priority\",\n"
11100 " \"available-notify-exten\",\n"
11101 " \"available-notify-context\",\n"
11102 " User-A is busy:\n"
11103 " \"busy-notify-priority\",\n"
11104 " \"busy-notify-exten\",\n"
11105 " \"busy-notify-context\"\n",
11106 .read = misdn_cc_read,
11107 };
11108 #endif
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119 static int unload_module(void)
11120 {
11121
11122 ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
11123
11124 misdn_tasks_destroy();
11125
11126 if (!g_config_initialized) {
11127 return 0;
11128 }
11129
11130 ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11131
11132
11133 ast_unregister_application("misdn_set_opt");
11134 ast_unregister_application("misdn_facility");
11135 ast_unregister_application("misdn_check_l2l1");
11136 #if defined(AST_MISDN_ENHANCEMENTS)
11137 ast_unregister_application(misdn_command_name);
11138 ast_custom_function_unregister(&misdn_cc_function);
11139 #endif
11140
11141 ast_channel_unregister(&misdn_tech);
11142
11143 free_robin_list();
11144 misdn_cfg_destroy();
11145 misdn_lib_destroy();
11146
11147 ast_free(misdn_out_calls);
11148 ast_free(misdn_in_calls);
11149 ast_free(misdn_debug_only);
11150 ast_free(misdn_ports);
11151 ast_free(misdn_debug);
11152
11153 #if defined(AST_MISDN_ENHANCEMENTS)
11154 misdn_cc_destroy();
11155 #endif
11156
11157 return 0;
11158 }
11159
11160 static int load_module(void)
11161 {
11162 int i, port;
11163 int ntflags = 0, ntkc = 0;
11164 char ports[256] = "";
11165 char tempbuf[BUFFERSIZE + 1];
11166 char ntfile[BUFFERSIZE + 1];
11167 struct misdn_lib_iface iface = {
11168 .cb_event = cb_events,
11169 .cb_log = chan_misdn_log,
11170 .cb_jb_empty = chan_misdn_jb_empty,
11171 };
11172
11173 max_ports = misdn_lib_maxports_get();
11174
11175 if (max_ports <= 0) {
11176 ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
11177 return AST_MODULE_LOAD_DECLINE;
11178 }
11179
11180 if (misdn_cfg_init(max_ports, 0)) {
11181 ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
11182 return AST_MODULE_LOAD_DECLINE;
11183 }
11184 g_config_initialized = 1;
11185
11186 #if defined(AST_MISDN_ENHANCEMENTS)
11187 misdn_cc_init();
11188 #endif
11189
11190 misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
11191 if (!misdn_debug) {
11192 ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
11193 return AST_MODULE_LOAD_DECLINE;
11194 }
11195 misdn_ports = ast_malloc(sizeof(int) * (max_ports + 1));
11196 if (!misdn_ports) {
11197 ast_free(misdn_debug);
11198 ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
11199 return AST_MODULE_LOAD_DECLINE;
11200 }
11201 misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(misdn_debug[0]));
11202 for (i = 1; i <= max_ports; i++) {
11203 misdn_debug[i] = misdn_debug[0];
11204 misdn_ports[i] = i;
11205 }
11206 *misdn_ports = 0;
11207 misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int));
11208 if (!misdn_debug_only) {
11209 ast_free(misdn_ports);
11210 ast_free(misdn_debug);
11211 ast_log(LOG_ERROR, "Out of memory for misdn_debug_only\n");
11212 return AST_MODULE_LOAD_DECLINE;
11213 }
11214
11215 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf));
11216 if (!ast_strlen_zero(tempbuf)) {
11217 tracing = 1;
11218 }
11219
11220 misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11221 if (!misdn_in_calls) {
11222 ast_free(misdn_debug_only);
11223 ast_free(misdn_ports);
11224 ast_free(misdn_debug);
11225 ast_log(LOG_ERROR, "Out of memory for misdn_in_calls\n");
11226 return AST_MODULE_LOAD_DECLINE;
11227 }
11228 misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1));
11229 if (!misdn_out_calls) {
11230 ast_free(misdn_in_calls);
11231 ast_free(misdn_debug_only);
11232 ast_free(misdn_ports);
11233 ast_free(misdn_debug);
11234 ast_log(LOG_ERROR, "Out of memory for misdn_out_calls\n");
11235 return AST_MODULE_LOAD_DECLINE;
11236 }
11237
11238 for (i = 1; i <= max_ports; i++) {
11239 misdn_in_calls[i] = 0;
11240 misdn_out_calls[i] = 0;
11241 }
11242
11243 ast_mutex_init(&cl_te_lock);
11244 ast_mutex_init(&release_lock);
11245
11246 misdn_cfg_update_ptp();
11247 misdn_cfg_get_ports_string(ports);
11248
11249 if (!ast_strlen_zero(ports)) {
11250 chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
11251 }
11252 if (misdn_lib_init(ports, &iface, NULL)) {
11253 chan_misdn_log(0, 0, "No te ports initialized\n");
11254 }
11255
11256 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
11257 misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
11258 misdn_cfg_get(0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
11259
11260 misdn_lib_nt_keepcalls(ntkc);
11261 misdn_lib_nt_debug_init(ntflags, ntfile);
11262
11263 if (ast_channel_register(&misdn_tech)) {
11264 ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
11265 unload_module();
11266 return AST_MODULE_LOAD_DECLINE;
11267 }
11268
11269 ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
11270
11271 ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
11272 "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
11273 "Sets mISDN opts. and optargs\n"
11274 "\n"
11275 "The available options are:\n"
11276 " a - Have Asterisk detect DTMF tones on called channel\n"
11277 " c - Make crypted outgoing call, optarg is keyindex\n"
11278 " d - Send display text to called phone, text is the optarg\n"
11279 " e - Perform echo cancellation on this channel,\n"
11280 " takes taps as optarg (32,64,128,256)\n"
11281 " e! - Disable echo cancellation on this channel\n"
11282 " f - Enable fax detection\n"
11283 " h - Make digital outgoing call\n"
11284 " h1 - Make HDLC mode digital outgoing call\n"
11285 " i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
11286 " they will be transported inband.\n"
11287 " jb - Set jitter buffer length, optarg is length\n"
11288 " jt - Set jitter buffer upper threshold, optarg is threshold\n"
11289 " jn - Disable jitter buffer\n"
11290 " n - Disable mISDN DSP on channel.\n"
11291 " Disables: echo cancel, DTMF detection, and volume control.\n"
11292 " p - Caller ID presentation,\n"
11293 " optarg is either 'allowed' or 'restricted'\n"
11294 " s - Send Non-inband DTMF as inband\n"
11295 " vr - Rx gain control, optarg is gain\n"
11296 " vt - Tx gain control, optarg is gain\n"
11297 );
11298
11299
11300 ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
11301 "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
11302 "Sends the Facility Message FACILITY_TYPE with \n"
11303 "the given Arguments to the current ISDN Channel\n"
11304 "Supported Facilities are:\n"
11305 "\n"
11306 "type=calldeflect args=Nr where to deflect\n"
11307 #if defined(AST_MISDN_ENHANCEMENTS)
11308 "type=callrerouting args=Nr where to deflect\n"
11309 #endif
11310 );
11311
11312
11313 ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
11314 "misdn_check_l2l1(<port>||g:<groupname>,timeout)\n"
11315 "Checks if the L2 and L1 are up on either the given <port> or\n"
11316 "on the ports in the group with <groupname>\n"
11317 "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
11318 "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
11319 "\n"
11320 "This application, ensures the L1/L2 state of the Ports in a group\n"
11321 "it is intended to make the pmp_l1_check option redundant and to\n"
11322 "fix a buggy switch config from your provider\n"
11323 "\n"
11324 "a sample dialplan would look like:\n\n"
11325 "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
11326 "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
11327 );
11328
11329 #if defined(AST_MISDN_ENHANCEMENTS)
11330 ast_register_application(misdn_command_name, misdn_command_exec, misdn_command_name,
11331 "misdn_command(<command>[,<options>])\n"
11332 "The following commands are defined:\n"
11333 "cc-initialize\n"
11334 " Setup mISDN support for call completion\n"
11335 " Must call before doing any Dial() involving call completion.\n"
11336 "ccnr-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11337 " Request Call Completion No Reply activation\n"
11338 "ccbs-request,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11339 " Request Call Completion Busy Subscriber activation\n"
11340 "cc-b-free,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>\n"
11341 " Set the dialplan location to notify when User-B is available but User-A is busy.\n"
11342 " Setting this dialplan location is optional.\n"
11343 "cc-a-busy,${MISDN_CC_RECORD_ID},<yes/no>\n"
11344 " Set the busy status of call completion User-A\n"
11345 "cc-deactivate,${MISDN_CC_RECORD_ID}\n"
11346 " Deactivate the identified call completion request\n"
11347 "\n"
11348 "MISDN_CC_RECORD_ID is set when Dial() returns and call completion is possible\n"
11349 "MISDN_CC_STATUS is set to ACTIVATED or ERROR after the call completion\n"
11350 "activation request.\n"
11351 "MISDN_ERROR_MSG is set to a descriptive message on error.\n"
11352 );
11353
11354 ast_custom_function_register(&misdn_cc_function);
11355 #endif
11356
11357 misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
11358
11359
11360
11361 for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
11362 int l1timeout;
11363 misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
11364 if (l1timeout) {
11365 chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
11366 misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
11367 }
11368 }
11369
11370 chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");
11371
11372 return 0;
11373 }
11374
11375
11376
11377 static int reload(void)
11378 {
11379 reload_config();
11380
11381 return 0;
11382 }
11383
11384
11385
11386 #if defined(AST_MISDN_ENHANCEMENTS)
11387
11388
11389
11390 AST_DEFINE_APP_ARGS_TYPE(misdn_command_args,
11391 AST_APP_ARG(name);
11392 AST_APP_ARG(arg)[10 + 1];
11393 );
11394 #endif
11395
11396 #if defined(AST_MISDN_ENHANCEMENTS)
11397 static void misdn_cc_caller_destroy(void *obj)
11398 {
11399
11400 }
11401 #endif
11402
11403 #if defined(AST_MISDN_ENHANCEMENTS)
11404 static struct misdn_cc_caller *misdn_cc_caller_alloc(struct ast_channel *chan)
11405 {
11406 struct misdn_cc_caller *cc_caller;
11407
11408 if (!(cc_caller = ao2_alloc(sizeof(*cc_caller), misdn_cc_caller_destroy))) {
11409 return NULL;
11410 }
11411
11412 cc_caller->chan = chan;
11413
11414 return cc_caller;
11415 }
11416 #endif
11417
11418 #if defined(AST_MISDN_ENHANCEMENTS)
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429 static int misdn_command_cc_initialize(struct ast_channel *chan, struct misdn_command_args *subcommand)
11430 {
11431 struct misdn_cc_caller *cc_caller;
11432 struct ast_datastore *datastore;
11433
11434 if (!(cc_caller = misdn_cc_caller_alloc(chan))) {
11435 return -1;
11436 }
11437
11438 if (!(datastore = ast_datastore_alloc(&misdn_cc_ds_info, NULL))) {
11439 ao2_ref(cc_caller, -1);
11440 return -1;
11441 }
11442
11443 ast_channel_lock(chan);
11444
11445
11446 datastore->data = cc_caller;
11447 cc_caller = NULL;
11448
11449 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
11450
11451 ast_channel_datastore_add(chan, datastore);
11452
11453 ast_channel_unlock(chan);
11454
11455 return 0;
11456 }
11457 #endif
11458
11459 #if defined(AST_MISDN_ENHANCEMENTS)
11460
11461
11462
11463
11464
11465
11466
11467
11468
11469
11470
11471
11472
11473
11474 static int misdn_command_cc_deactivate(struct ast_channel *chan, struct misdn_command_args *subcommand)
11475 {
11476 long record_id;
11477 const char *error_str;
11478 struct misdn_cc_record *cc_record;
11479 struct misdn_bchannel *bc;
11480 struct misdn_bchannel dummy;
11481
11482 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID})\n";
11483
11484 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11485 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11486 return -1;
11487 }
11488 record_id = atol(subcommand->arg[0]);
11489
11490 AST_LIST_LOCK(&misdn_cc_records_db);
11491 cc_record = misdn_cc_find_by_id(record_id);
11492 if (cc_record && 0 <= cc_record->port) {
11493 if (cc_record->ptp) {
11494 if (cc_record->mode.ptp.bc) {
11495
11496 bc = cc_record->mode.ptp.bc;
11497 bc->fac_out.Function = Fac_None;
11498 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11499 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11500 }
11501 misdn_cc_delete(cc_record);
11502 } else if (cc_record->activated) {
11503 cc_record->error_code = FacError_None;
11504 cc_record->reject_code = FacReject_None;
11505 cc_record->invoke_id = ++misdn_invoke_id;
11506 cc_record->outstanding_message = 1;
11507
11508
11509 misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
11510 dummy.fac_out.Function = Fac_CCBSDeactivate;
11511 dummy.fac_out.u.CCBSDeactivate.InvokeID = cc_record->invoke_id;
11512 dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
11513 dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->mode.ptmp.reference_id;
11514
11515
11516 print_facility(&dummy.fac_out, &dummy);
11517 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11518 }
11519 }
11520 AST_LIST_UNLOCK(&misdn_cc_records_db);
11521
11522
11523 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11524
11525 AST_LIST_LOCK(&misdn_cc_records_db);
11526 cc_record = misdn_cc_find_by_id(record_id);
11527 if (cc_record) {
11528 if (cc_record->port < 0) {
11529
11530 error_str = NULL;
11531 } else if (cc_record->outstanding_message) {
11532 cc_record->outstanding_message = 0;
11533 error_str = misdn_no_response_from_network;
11534 } else if (cc_record->reject_code != FacReject_None) {
11535 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11536 } else if (cc_record->error_code != FacError_None) {
11537 error_str = misdn_to_str_error_code(cc_record->error_code);
11538 } else {
11539 error_str = NULL;
11540 }
11541
11542 misdn_cc_delete(cc_record);
11543 } else {
11544 error_str = NULL;
11545 }
11546 AST_LIST_UNLOCK(&misdn_cc_records_db);
11547 if (error_str) {
11548 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11549 misdn_command_name, subcommand->name, error_str, chan->name);
11550 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11551 }
11552
11553 return 0;
11554 }
11555 #endif
11556
11557 #if defined(AST_MISDN_ENHANCEMENTS)
11558
11559
11560
11561
11562
11563
11564
11565
11566
11567
11568
11569
11570
11571
11572 static int misdn_command_cc_a_busy(struct ast_channel *chan, struct misdn_command_args *subcommand)
11573 {
11574 long record_id;
11575 int party_a_free;
11576 struct misdn_cc_record *cc_record;
11577 struct misdn_bchannel *bc;
11578
11579 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<yes/no>)\n";
11580
11581 if (ast_strlen_zero(subcommand->arg[0]) || !isdigit(*subcommand->arg[0])) {
11582 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11583 return -1;
11584 }
11585 record_id = atol(subcommand->arg[0]);
11586
11587 if (ast_true(subcommand->arg[1])) {
11588 party_a_free = 0;
11589 } else if (ast_false(subcommand->arg[1])) {
11590 party_a_free = 1;
11591 } else {
11592 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11593 return -1;
11594 }
11595
11596 AST_LIST_LOCK(&misdn_cc_records_db);
11597 cc_record = misdn_cc_find_by_id(record_id);
11598 if (cc_record && cc_record->party_a_free != party_a_free) {
11599
11600 cc_record->party_a_free = party_a_free;
11601
11602 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11603 cc_record->error_code = FacError_None;
11604 cc_record->reject_code = FacReject_None;
11605
11606
11607 bc = cc_record->mode.ptp.bc;
11608 if (cc_record->party_a_free) {
11609 bc->fac_out.Function = Fac_CCBS_T_Resume;
11610 bc->fac_out.u.CCBS_T_Resume.InvokeID = ++misdn_invoke_id;
11611 } else {
11612 bc->fac_out.Function = Fac_CCBS_T_Suspend;
11613 bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
11614 }
11615
11616
11617 print_facility(&bc->fac_out, bc);
11618 misdn_lib_send_event(bc, EVENT_FACILITY);
11619 }
11620 }
11621 AST_LIST_UNLOCK(&misdn_cc_records_db);
11622
11623 return 0;
11624 }
11625 #endif
11626
11627 #if defined(AST_MISDN_ENHANCEMENTS)
11628
11629
11630
11631
11632
11633
11634
11635
11636
11637
11638
11639
11640
11641
11642 static int misdn_command_cc_b_free(struct ast_channel *chan, struct misdn_command_args *subcommand)
11643 {
11644 unsigned index;
11645 long record_id;
11646 int priority;
11647 char *context;
11648 char *exten;
11649 struct misdn_cc_record *cc_record;
11650
11651 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11652
11653
11654 for (index = 0; index < 4; ++index) {
11655 if (ast_strlen_zero(subcommand->arg[index])) {
11656 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11657 return -1;
11658 }
11659 }
11660
11661
11662 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11663 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11664 return -1;
11665 }
11666
11667 record_id = atol(subcommand->arg[0]);
11668 context = subcommand->arg[1];
11669 exten = subcommand->arg[2];
11670 priority = atoi(subcommand->arg[3]);
11671
11672 AST_LIST_LOCK(&misdn_cc_records_db);
11673 cc_record = misdn_cc_find_by_id(record_id);
11674 if (cc_record) {
11675
11676 ast_copy_string(cc_record->b_free.context, context, sizeof(cc_record->b_free.context));
11677 ast_copy_string(cc_record->b_free.exten, exten, sizeof(cc_record->b_free.exten));
11678 cc_record->b_free.priority = priority;
11679 }
11680 AST_LIST_UNLOCK(&misdn_cc_records_db);
11681
11682 return 0;
11683 }
11684 #endif
11685
11686 #if defined(AST_MISDN_ENHANCEMENTS)
11687 struct misdn_cc_request {
11688 enum FacFunction ptmp;
11689 enum FacFunction ptp;
11690 };
11691 #endif
11692
11693 #if defined(AST_MISDN_ENHANCEMENTS)
11694
11695
11696
11697
11698
11699
11700
11701
11702
11703
11704
11705
11706
11707
11708
11709
11710 static int misdn_command_cc_request(struct ast_channel *chan, struct misdn_command_args *subcommand, const struct misdn_cc_request *request)
11711 {
11712 unsigned index;
11713 int request_retention;
11714 long record_id;
11715 int priority;
11716 char *context;
11717 char *exten;
11718 const char *error_str;
11719 struct misdn_cc_record *cc_record;
11720 struct misdn_bchannel *bc;
11721 struct misdn_bchannel dummy;
11722 struct misdn_party_id id;
11723
11724 static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
11725
11726
11727 for (index = 0; index < 4; ++index) {
11728 if (ast_strlen_zero(subcommand->arg[index])) {
11729 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11730 return -1;
11731 }
11732 }
11733
11734
11735 if (!isdigit(*subcommand->arg[0]) || !isdigit(*subcommand->arg[3])) {
11736 ast_log(LOG_WARNING, cmd_help, misdn_command_name, subcommand->name);
11737 return -1;
11738 }
11739
11740 record_id = atol(subcommand->arg[0]);
11741 context = subcommand->arg[1];
11742 exten = subcommand->arg[2];
11743 priority = atoi(subcommand->arg[3]);
11744
11745 AST_LIST_LOCK(&misdn_cc_records_db);
11746 cc_record = misdn_cc_find_by_id(record_id);
11747 if (cc_record) {
11748
11749 ast_copy_string(cc_record->remote_user_free.context, context,
11750 sizeof(cc_record->remote_user_free.context));
11751 ast_copy_string(cc_record->remote_user_free.exten, exten,
11752 sizeof(cc_record->remote_user_free.exten));
11753 cc_record->remote_user_free.priority = priority;
11754
11755 if (0 <= cc_record->port) {
11756 if (cc_record->ptp) {
11757 if (!cc_record->mode.ptp.bc) {
11758 bc = misdn_lib_get_register_bc(cc_record->port);
11759 if (bc) {
11760 cc_record->mode.ptp.bc = bc;
11761 cc_record->error_code = FacError_None;
11762 cc_record->reject_code = FacReject_None;
11763 cc_record->invoke_id = ++misdn_invoke_id;
11764 cc_record->outstanding_message = 1;
11765 cc_record->activation_requested = 1;
11766
11767 misdn_cfg_get(bc->port, MISDN_CFG_CC_REQUEST_RETENTION,
11768 &request_retention, sizeof(request_retention));
11769 cc_record->mode.ptp.requested_retention = request_retention ? 1 : 0;
11770
11771
11772 bc->fac_out.Function = request->ptp;
11773 bc->fac_out.u.CCBS_T_Request.InvokeID = cc_record->invoke_id;
11774 bc->fac_out.u.CCBS_T_Request.ComponentType = FacComponent_Invoke;
11775 bc->fac_out.u.CCBS_T_Request.Component.Invoke.Q931ie =
11776 cc_record->redial.setup_bc_hlc_llc;
11777 memset(&id, 0, sizeof(id));
11778 id.number_plan = cc_record->redial.dialed.number_plan;
11779 id.number_type = cc_record->redial.dialed.number_type;
11780 ast_copy_string(id.number, cc_record->redial.dialed.number,
11781 sizeof(id.number));
11782 misdn_Address_fill(
11783 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Destination,
11784 &id);
11785 misdn_Address_fill(
11786 &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Originating,
11787 &cc_record->redial.caller);
11788 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1;
11789 bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator =
11790 (cc_record->redial.caller.presentation != 0) ? 0 : 1;
11791 bc->fac_out.u.CCBS_T_Request.Component.Invoke.RetentionSupported =
11792 request_retention ? 1 : 0;
11793
11794
11795 print_facility(&bc->fac_out, bc);
11796 misdn_lib_send_event(bc, EVENT_REGISTER);
11797 }
11798 }
11799 } else {
11800 cc_record->error_code = FacError_None;
11801 cc_record->reject_code = FacReject_None;
11802 cc_record->invoke_id = ++misdn_invoke_id;
11803 cc_record->outstanding_message = 1;
11804 cc_record->activation_requested = 1;
11805
11806
11807 misdn_make_dummy(&dummy, cc_record->port, 0,
11808 misdn_lib_port_is_nt(cc_record->port), 0);
11809 dummy.fac_out.Function = request->ptmp;
11810 dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
11811 dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
11812 dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID =
11813 cc_record->mode.ptmp.linkage_id;
11814
11815
11816 print_facility(&dummy.fac_out, &dummy);
11817 misdn_lib_send_event(&dummy, EVENT_FACILITY);
11818 }
11819 }
11820 }
11821 AST_LIST_UNLOCK(&misdn_cc_records_db);
11822
11823
11824 misdn_cc_response_wait(chan, MISDN_CC_REQUEST_WAIT_MAX, record_id);
11825
11826 AST_LIST_LOCK(&misdn_cc_records_db);
11827 cc_record = misdn_cc_find_by_id(record_id);
11828 if (cc_record) {
11829 if (!cc_record->activated) {
11830 if (cc_record->port < 0) {
11831
11832 error_str = "No port number";
11833 } else if (cc_record->outstanding_message) {
11834 cc_record->outstanding_message = 0;
11835 error_str = misdn_no_response_from_network;
11836 } else if (cc_record->reject_code != FacReject_None) {
11837 error_str = misdn_to_str_reject_code(cc_record->reject_code);
11838 } else if (cc_record->error_code != FacError_None) {
11839 error_str = misdn_to_str_error_code(cc_record->error_code);
11840 } else if (cc_record->ptp) {
11841 if (cc_record->mode.ptp.bc) {
11842 error_str = "Call-completion already requested";
11843 } else {
11844 error_str = "Could not allocate call-completion signaling link";
11845 }
11846 } else {
11847
11848 error_str = "Unexpected error";
11849 }
11850
11851
11852 if (cc_record->ptp && cc_record->mode.ptp.bc) {
11853
11854 bc = cc_record->mode.ptp.bc;
11855 bc->fac_out.Function = Fac_None;
11856 bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
11857 misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
11858 }
11859 misdn_cc_delete(cc_record);
11860 } else {
11861 error_str = NULL;
11862 }
11863 } else {
11864 error_str = misdn_cc_record_not_found;
11865 }
11866 AST_LIST_UNLOCK(&misdn_cc_records_db);
11867 if (error_str) {
11868 ast_verb(1, "%s(%s) diagnostic '%s' on channel %s\n",
11869 misdn_command_name, subcommand->name, error_str, chan->name);
11870 pbx_builtin_setvar_helper(chan, MISDN_ERROR_MSG, error_str);
11871 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ERROR");
11872 } else {
11873 pbx_builtin_setvar_helper(chan, MISDN_CC_STATUS, "ACTIVATED");
11874 }
11875
11876 return 0;
11877 }
11878 #endif
11879
11880 #if defined(AST_MISDN_ENHANCEMENTS)
11881
11882
11883
11884
11885
11886
11887
11888
11889
11890
11891
11892
11893
11894
11895 static int misdn_command_ccbs_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11896 {
11897 static const struct misdn_cc_request request = {
11898 .ptmp = Fac_CCBSRequest,
11899 .ptp = Fac_CCBS_T_Request
11900 };
11901
11902 return misdn_command_cc_request(chan, subcommand, &request);
11903 }
11904 #endif
11905
11906 #if defined(AST_MISDN_ENHANCEMENTS)
11907
11908
11909
11910
11911
11912
11913
11914
11915
11916
11917
11918
11919
11920
11921 static int misdn_command_ccnr_request(struct ast_channel *chan, struct misdn_command_args *subcommand)
11922 {
11923 static const struct misdn_cc_request request = {
11924 .ptmp = Fac_CCNRRequest,
11925 .ptp = Fac_CCNR_T_Request
11926 };
11927
11928 return misdn_command_cc_request(chan, subcommand, &request);
11929 }
11930 #endif
11931
11932 #if defined(AST_MISDN_ENHANCEMENTS)
11933 struct misdn_command_table {
11934
11935 const char *name;
11936
11937
11938 int (*func)(struct ast_channel *chan, struct misdn_command_args *subcommand);
11939
11940
11941 int misdn_only;
11942 };
11943 static const struct misdn_command_table misdn_commands[] = {
11944
11945
11946 { "cc-initialize", misdn_command_cc_initialize, 0 },
11947 { "cc-deactivate", misdn_command_cc_deactivate, 0 },
11948 { "cc-a-busy", misdn_command_cc_a_busy, 0 },
11949 { "cc-b-free", misdn_command_cc_b_free, 0 },
11950 { "ccbs-request", misdn_command_ccbs_request, 0 },
11951 { "ccnr-request", misdn_command_ccnr_request, 0 },
11952
11953 };
11954 #endif
11955
11956 #if defined(AST_MISDN_ENHANCEMENTS)
11957
11958
11959
11960
11961
11962
11963
11964
11965
11966
11967 static int misdn_command_exec(struct ast_channel *chan, const char *data)
11968 {
11969 char *parse;
11970 unsigned index;
11971 struct misdn_command_args subcommand;
11972
11973 if (ast_strlen_zero((char *) data)) {
11974 ast_log(LOG_ERROR, "%s requires arguments\n", misdn_command_name);
11975 return -1;
11976 }
11977
11978 ast_log(LOG_DEBUG, "%s(%s)\n", misdn_command_name, (char *) data);
11979
11980 parse = ast_strdupa(data);
11981 AST_STANDARD_APP_ARGS(subcommand, parse);
11982 if (!subcommand.argc || ast_strlen_zero(subcommand.name)) {
11983 ast_log(LOG_ERROR, "%s requires a subcommand\n", misdn_command_name);
11984 return -1;
11985 }
11986
11987 for (index = 0; index < ARRAY_LEN(misdn_commands); ++index) {
11988 if (strcasecmp(misdn_commands[index].name, subcommand.name) == 0) {
11989 strcpy(subcommand.name, misdn_commands[index].name);
11990 if (misdn_commands[index].misdn_only
11991 && strcasecmp(chan->tech->type, misdn_type) != 0) {
11992 ast_log(LOG_WARNING,
11993 "%s(%s) only makes sense with %s channels!\n",
11994 misdn_command_name, subcommand.name, misdn_type);
11995 return -1;
11996 }
11997 return misdn_commands[index].func(chan, &subcommand);
11998 }
11999 }
12000
12001 ast_log(LOG_WARNING, "%s(%s) subcommand is unknown\n", misdn_command_name,
12002 subcommand.name);
12003 return -1;
12004 }
12005 #endif
12006
12007 static int misdn_facility_exec(struct ast_channel *chan, const char *data)
12008 {
12009 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12010 char *parse;
12011 unsigned max_len;
12012
12013 AST_DECLARE_APP_ARGS(args,
12014 AST_APP_ARG(facility_type);
12015 AST_APP_ARG(arg)[99];
12016 );
12017
12018 chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
12019
12020 if (strcasecmp(chan->tech->type, misdn_type)) {
12021 ast_log(LOG_WARNING, "misdn_facility only makes sense with %s channels!\n", misdn_type);
12022 return -1;
12023 }
12024
12025 if (ast_strlen_zero((char *) data)) {
12026 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12027 return -1;
12028 }
12029
12030 parse = ast_strdupa(data);
12031 AST_STANDARD_APP_ARGS(args, parse);
12032
12033 if (ast_strlen_zero(args.facility_type)) {
12034 ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
12035 return -1;
12036 }
12037
12038 if (!strcasecmp(args.facility_type, "calldeflect")) {
12039 if (ast_strlen_zero(args.arg[0])) {
12040 ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n");
12041 }
12042
12043 #if defined(AST_MISDN_ENHANCEMENTS)
12044 max_len = sizeof(ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
12045 if (max_len < strlen(args.arg[0])) {
12046 ast_log(LOG_WARNING,
12047 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12048 max_len);
12049 return 0;
12050 }
12051 ch->bc->fac_out.Function = Fac_CallDeflection;
12052 ch->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
12053 ch->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
12054 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
12055 ch->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
12056 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;
12057 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(args.arg[0]);
12058 strcpy((char *) ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, args.arg[0]);
12059 ch->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
12060
12061 #else
12062
12063 max_len = sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber) - 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_CD;
12071 ch->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
12072
12073 strcpy((char *) ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0]);
12074 #endif
12075
12076
12077 print_facility(&ch->bc->fac_out, ch->bc);
12078 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12079 #if defined(AST_MISDN_ENHANCEMENTS)
12080 } else if (!strcasecmp(args.facility_type, "callrerouteing")
12081 || !strcasecmp(args.facility_type, "callrerouting")) {
12082 if (ast_strlen_zero(args.arg[0])) {
12083 ast_log(LOG_WARNING, "Facility: Call rerouting requires an argument: Number\n");
12084 }
12085
12086 max_len = sizeof(ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
12087 if (max_len < strlen(args.arg[0])) {
12088 ast_log(LOG_WARNING,
12089 "Facility: Number argument too long (up to %u digits are allowed). Ignoring.\n",
12090 max_len);
12091 return 0;
12092 }
12093 ch->bc->fac_out.Function = Fac_CallRerouteing;
12094 ch->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
12095 ch->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
12096
12097 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;
12098 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
12099
12100 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;
12101 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(args.arg[0]);
12102 strcpy((char *) ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, args.arg[0]);
12103 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
12104
12105 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
12106
12107
12108 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
12109 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
12110 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
12111 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
12112 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
12113 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
12114 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
12115
12116 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;
12117 ch->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;
12118
12119
12120 print_facility(&ch->bc->fac_out, ch->bc);
12121 misdn_lib_send_event(ch->bc, EVENT_FACILITY);
12122 #endif
12123 } else {
12124 chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type);
12125 }
12126
12127 return 0;
12128 }
12129
12130 static int misdn_check_l2l1(struct ast_channel *chan, const char *data)
12131 {
12132 char *parse;
12133 char group[BUFFERSIZE + 1];
12134 char *port_str;
12135 int port = 0;
12136 int timeout;
12137 int dowait = 0;
12138 int port_up;
12139
12140 AST_DECLARE_APP_ARGS(args,
12141 AST_APP_ARG(grouppar);
12142 AST_APP_ARG(timeout);
12143 );
12144
12145 if (ast_strlen_zero((char *) data)) {
12146 ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
12147 return -1;
12148 }
12149
12150 parse = ast_strdupa(data);
12151 AST_STANDARD_APP_ARGS(args, parse);
12152
12153 if (args.argc != 2) {
12154 ast_log(LOG_WARNING, "Wrong argument count\n");
12155 return 0;
12156 }
12157
12158
12159 timeout = atoi(args.timeout);
12160 port_str = args.grouppar;
12161
12162 if (port_str[0] == 'g' && port_str[1] == ':') {
12163
12164 port_str += 2;
12165 ast_copy_string(group, port_str, sizeof(group));
12166 chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
12167
12168 for (port = misdn_cfg_get_next_port(port);
12169 port > 0;
12170 port = misdn_cfg_get_next_port(port)) {
12171 char cfg_group[BUFFERSIZE + 1];
12172
12173 chan_misdn_log(2, 0, "trying port %d\n", port);
12174
12175 misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
12176
12177 if (!strcasecmp(cfg_group, group)) {
12178 port_up = misdn_lib_port_up(port, 1);
12179 if (!port_up) {
12180 chan_misdn_log(2, 0, " --> port '%d'\n", port);
12181 misdn_lib_get_port_up(port);
12182 dowait = 1;
12183 }
12184 }
12185 }
12186 } else {
12187 port = atoi(port_str);
12188 chan_misdn_log(2, 0, "Checking Port: %d\n", port);
12189 port_up = misdn_lib_port_up(port, 1);
12190 if (!port_up) {
12191 misdn_lib_get_port_up(port);
12192 dowait = 1;
12193 }
12194 }
12195
12196 if (dowait) {
12197 chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
12198 ast_safe_sleep(chan, timeout * 1000);
12199 }
12200
12201 return 0;
12202 }
12203
12204 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data)
12205 {
12206 struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
12207 char *tok;
12208 char *tokb;
12209 char *parse;
12210 int keyidx = 0;
12211 int rxgain = 0;
12212 int txgain = 0;
12213 int change_jitter = 0;
12214
12215 if (strcasecmp(chan->tech->type, misdn_type)) {
12216 ast_log(LOG_WARNING, "misdn_set_opt makes sense only with %s channels!\n", misdn_type);
12217 return -1;
12218 }
12219
12220 if (ast_strlen_zero((char *) data)) {
12221 ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
12222 return -1;
12223 }
12224
12225 parse = ast_strdupa(data);
12226 for (tok = strtok_r(parse, ":", &tokb);
12227 tok;
12228 tok = strtok_r(NULL, ":", &tokb)) {
12229 int neglect = 0;
12230
12231 if (tok[0] == '!') {
12232 neglect = 1;
12233 tok++;
12234 }
12235
12236 switch(tok[0]) {
12237 case 'd' :
12238 ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
12239 chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
12240 break;
12241 case 'n':
12242 chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
12243 ch->bc->nodsp = 1;
12244 break;
12245 case 'j':
12246 chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
12247 tok++;
12248 change_jitter = 1;
12249
12250 switch (tok[0]) {
12251 case 'b':
12252 ch->jb_len = atoi(++tok);
12253 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
12254 break;
12255 case 't' :
12256 ch->jb_upper_threshold = atoi(++tok);
12257 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
12258 break;
12259 case 'n':
12260 ch->bc->nojitter = 1;
12261 chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
12262 break;
12263 default:
12264 ch->jb_len = 4000;
12265 ch->jb_upper_threshold = 0;
12266 chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
12267 chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
12268 break;
12269 }
12270 break;
12271 case 'v':
12272 tok++;
12273
12274 switch (tok[0]) {
12275 case 'r' :
12276 rxgain = atoi(++tok);
12277 if (rxgain < -8) {
12278 rxgain = -8;
12279 }
12280 if (rxgain > 8) {
12281 rxgain = 8;
12282 }
12283 ch->bc->rxgain = rxgain;
12284 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
12285 break;
12286 case 't':
12287 txgain = atoi(++tok);
12288 if (txgain < -8) {
12289 txgain = -8;
12290 }
12291 if (txgain > 8) {
12292 txgain = 8;
12293 }
12294 ch->bc->txgain = txgain;
12295 chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
12296 break;
12297 }
12298 break;
12299 case 'c':
12300 keyidx = atoi(++tok);
12301 {
12302 char keys[4096];
12303 char *key = NULL;
12304 char *tmp = keys;
12305 int i;
12306
12307 misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
12308
12309 for (i = 0; i < keyidx; i++) {
12310 key = strsep(&tmp, ",");
12311 }
12312
12313 if (key) {
12314 ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
12315 }
12316
12317 chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
12318 break;
12319 }
12320 case 'e':
12321 chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
12322
12323 if (neglect) {
12324 chan_misdn_log(1, ch->bc->port, " --> disabled\n");
12325 #ifdef MISDN_1_2
12326 *ch->bc->pipeline = 0;
12327 #else
12328 ch->bc->ec_enable = 0;
12329 #endif
12330 } else {
12331 #ifdef MISDN_1_2
12332 update_pipeline_config(ch->bc);
12333 #else
12334 ch->bc->ec_enable = 1;
12335 ch->bc->orig = ch->originator;
12336 tok++;
12337 if (*tok) {
12338 ch->bc->ec_deftaps = atoi(tok);
12339 }
12340 #endif
12341 }
12342 break;
12343 case 'h':
12344 chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
12345
12346 if (strlen(tok) > 1 && tok[1] == '1') {
12347 chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
12348 if (!ch->bc->hdlc) {
12349 ch->bc->hdlc = 1;
12350 }
12351 }
12352 ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
12353 break;
12354 case 's':
12355 chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
12356 ch->bc->send_dtmf = 1;
12357 break;
12358 case 'f':
12359 chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
12360 ch->faxdetect = 1;
12361 misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
12362 break;
12363 case 'a':
12364 chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
12365 ch->ast_dsp = 1;
12366 break;
12367 case 'p':
12368 chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
12369
12370 if (strstr(tok, "allowed")) {
12371 ch->bc->presentation = 0;
12372 ch->bc->set_presentation = 1;
12373 } else if (strstr(tok, "restricted")) {
12374 ch->bc->presentation = 1;
12375 ch->bc->set_presentation = 1;
12376 } else if (strstr(tok, "not_screened")) {
12377 chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
12378 ch->bc->presentation = 1;
12379 ch->bc->set_presentation = 1;
12380 }
12381 break;
12382 case 'i' :
12383 chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
12384 ch->ignore_dtmf = 1;
12385 break;
12386 default:
12387 break;
12388 }
12389 }
12390
12391 if (change_jitter) {
12392 config_jitterbuffer(ch);
12393 }
12394
12395 if (ch->faxdetect || ch->ast_dsp) {
12396 if (!ch->dsp) {
12397 ch->dsp = ast_dsp_new();
12398 }
12399 if (ch->dsp) {
12400 ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
12401 }
12402 }
12403
12404 if (ch->ast_dsp) {
12405 chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
12406 ch->bc->nodsp = 1;
12407 }
12408
12409 return 0;
12410 }
12411
12412
12413 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len)
12414 {
12415 struct chan_list *ch;
12416 int res;
12417
12418 ch = find_chan_by_bc(bc);
12419 if (!ch) {
12420 return 0;
12421 }
12422
12423 if (ch->jb) {
12424 res = misdn_jb_empty(ch->jb, buf, len);
12425 } else {
12426 res = 0;
12427 }
12428 chan_list_unref(ch, "Done emptying jb");
12429
12430 return res;
12431 }
12432
12433
12434
12435
12436
12437
12438
12439
12440
12441 struct misdn_jb *misdn_jb_init(int size, int upper_threshold)
12442 {
12443 struct misdn_jb *jb;
12444
12445 jb = ast_calloc(1, sizeof(*jb));
12446 if (!jb) {
12447 chan_misdn_log(-1, 0, "No free Mem for jb\n");
12448 return NULL;
12449 }
12450 jb->size = size;
12451 jb->upper_threshold = upper_threshold;
12452
12453
12454
12455
12456
12457 jb->samples = ast_calloc(size, sizeof(*jb->samples));
12458 if (!jb->samples) {
12459 ast_free(jb);
12460 chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
12461 return NULL;
12462 }
12463
12464 jb->ok = ast_calloc(size, sizeof(*jb->ok));
12465 if (!jb->ok) {
12466 ast_free(jb->samples);
12467 ast_free(jb);
12468 chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
12469 return NULL;
12470 }
12471
12472 ast_mutex_init(&jb->mutexjb);
12473
12474 return jb;
12475 }
12476
12477
12478 void misdn_jb_destroy(struct misdn_jb *jb)
12479 {
12480 ast_mutex_destroy(&jb->mutexjb);
12481
12482 ast_free(jb->ok);
12483 ast_free(jb->samples);
12484 ast_free(jb);
12485 }
12486
12487
12488
12489 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
12490 {
12491 int i;
12492 int j;
12493 int rp;
12494 int wp;
12495
12496 if (!jb || ! data) {
12497 return 0;
12498 }
12499
12500 ast_mutex_lock(&jb->mutexjb);
12501
12502 wp = jb->wp;
12503 rp = jb->rp;
12504
12505 for (i = 0; i < len; i++) {
12506 jb->samples[wp] = data[i];
12507 jb->ok[wp] = 1;
12508 wp = (wp != jb->size - 1) ? wp + 1 : 0;
12509
12510 if (wp == jb->rp) {
12511 jb->state_full = 1;
12512 }
12513 }
12514
12515 if (wp >= rp) {
12516 jb->state_buffer = wp - rp;
12517 } else {
12518 jb->state_buffer = jb->size - rp + wp;
12519 }
12520 chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12521
12522 if (jb->state_full) {
12523 jb->wp = wp;
12524
12525 rp = wp;
12526 for (j = 0; j < jb->upper_threshold; j++) {
12527 rp = (rp != 0) ? rp - 1 : jb->size - 1;
12528 }
12529 jb->rp = rp;
12530 jb->state_full = 0;
12531 jb->state_empty = 1;
12532
12533 ast_mutex_unlock(&jb->mutexjb);
12534
12535 return -1;
12536 }
12537
12538 if (!jb->state_empty) {
12539 jb->bytes_wrote += len;
12540 if (jb->bytes_wrote >= jb->upper_threshold) {
12541 jb->state_empty = 1;
12542 jb->bytes_wrote = 0;
12543 }
12544 }
12545 jb->wp = wp;
12546
12547 ast_mutex_unlock(&jb->mutexjb);
12548
12549 return 0;
12550 }
12551
12552
12553
12554
12555 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
12556 {
12557 int i;
12558 int wp;
12559 int rp;
12560 int read = 0;
12561
12562 ast_mutex_lock(&jb->mutexjb);
12563
12564 rp = jb->rp;
12565 wp = jb->wp;
12566
12567 if (jb->state_empty) {
12568 for (i = 0; i < len; i++) {
12569 if (wp == rp) {
12570 jb->rp = rp;
12571 jb->state_empty = 0;
12572
12573 ast_mutex_unlock(&jb->mutexjb);
12574
12575 return read;
12576 } else {
12577 if (jb->ok[rp] == 1) {
12578 data[i] = jb->samples[rp];
12579 jb->ok[rp] = 0;
12580 rp = (rp != jb->size - 1) ? rp + 1 : 0;
12581 read += 1;
12582 }
12583 }
12584 }
12585
12586 if (wp >= rp) {
12587 jb->state_buffer = wp - rp;
12588 } else {
12589 jb->state_buffer = jb->size - rp + wp;
12590 }
12591 chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
12592
12593 jb->rp = rp;
12594 } else {
12595 chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
12596 }
12597
12598 ast_mutex_unlock(&jb->mutexjb);
12599
12600 return read;
12601 }
12602
12603
12604
12605
12606
12607 static void chan_misdn_log(int level, int port, char *tmpl, ...)
12608 {
12609 va_list ap;
12610 char buf[1024];
12611 char port_buf[8];
12612
12613 if (!(0 <= port && port <= max_ports)) {
12614 ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
12615 port = 0;
12616 level = -1;
12617 } else if (!(level == -1
12618 || (misdn_debug_only[port]
12619 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12620 : level <= misdn_debug[port])
12621 || (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)))) {
12622
12623
12624
12625
12626 return;
12627 }
12628
12629 snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
12630 va_start(ap, tmpl);
12631 vsnprintf(buf, sizeof(buf), tmpl, ap);
12632 va_end(ap);
12633
12634 if (level == -1) {
12635 ast_log(LOG_WARNING, "%s", buf);
12636 } else if (misdn_debug_only[port]
12637 ? (level == 1 && misdn_debug[port]) || level == misdn_debug[port]
12638 : level <= misdn_debug[port]) {
12639 ast_console_puts(port_buf);
12640 ast_console_puts(buf);
12641 }
12642
12643 if (level <= misdn_debug[0] && !ast_strlen_zero(global_tracefile)) {
12644 char ctimebuf[30];
12645 time_t tm;
12646 char *tmp;
12647 char *p;
12648 FILE *fp;
12649
12650 fp = fopen(global_tracefile, "a+");
12651 if (!fp) {
12652 ast_console_puts("Error opening Tracefile: [ ");
12653 ast_console_puts(global_tracefile);
12654 ast_console_puts(" ] ");
12655
12656 ast_console_puts(strerror(errno));
12657 ast_console_puts("\n");
12658 return;
12659 }
12660
12661 tm = time(NULL);
12662 tmp = ctime_r(&tm, ctimebuf);
12663 p = strchr(tmp, '\n');
12664 if (p) {
12665 *p = ':';
12666 }
12667 fputs(tmp, fp);
12668 fputs(" ", fp);
12669 fputs(port_buf, fp);
12670 fputs(" ", fp);
12671 fputs(buf, fp);
12672
12673 fclose(fp);
12674 }
12675 }
12676
12677 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Channel driver for mISDN Support (BRI/PRI)",
12678 .load = load_module,
12679 .unload = unload_module,
12680 .reload = reload,
12681 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
12682 );