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