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