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 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 150124 $")
00040
00041 #include <stdio.h>
00042 #include <pthread.h>
00043 #include <string.h>
00044 #include <sys/socket.h>
00045 #include <sys/time.h>
00046 #include <errno.h>
00047 #include <unistd.h>
00048 #include <stdlib.h>
00049 #include <arpa/inet.h>
00050 #include <fcntl.h>
00051 #include <sys/ioctl.h>
00052 #include <signal.h>
00053 #include <sys/file.h>
00054 #include <semaphore.h>
00055
00056 #include "asterisk/channel.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/logger.h"
00059 #include "asterisk/module.h"
00060 #include "asterisk/pbx.h"
00061 #include "asterisk/options.h"
00062 #include "asterisk/io.h"
00063 #include "asterisk/frame.h"
00064 #include "asterisk/translate.h"
00065 #include "asterisk/cli.h"
00066 #include "asterisk/musiconhold.h"
00067 #include "asterisk/dsp.h"
00068 #include "asterisk/translate.h"
00069 #include "asterisk/config.h"
00070 #include "asterisk/file.h"
00071 #include "asterisk/callerid.h"
00072 #include "asterisk/indications.h"
00073 #include "asterisk/app.h"
00074 #include "asterisk/features.h"
00075 #include "asterisk/term.h"
00076 #include "asterisk/sched.h"
00077 #include "asterisk/stringfields.h"
00078 #include "asterisk/causes.h"
00079
00080 #include "chan_misdn_config.h"
00081 #include "isdn_lib.h"
00082
00083 char global_tracefile[BUFFERSIZE + 1];
00084
00085 static int g_config_initialized = 0;
00086
00087 struct misdn_jb{
00088 int size;
00089 int upper_threshold;
00090 char *samples, *ok;
00091 int wp,rp;
00092 int state_empty;
00093 int state_full;
00094 int state_buffer;
00095 int bytes_wrote;
00096 ast_mutex_t mutexjb;
00097 };
00098
00099
00100
00101
00102 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
00103
00104
00105 void misdn_jb_destroy(struct misdn_jb *jb);
00106
00107
00108
00109 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
00110
00111
00112
00113
00114 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
00115
00116
00117
00118
00119 ast_mutex_t release_lock;
00120
00121 enum misdn_chan_state {
00122 MISDN_NOTHING=0,
00123 MISDN_WAITING4DIGS,
00124 MISDN_EXTCANTMATCH,
00125 MISDN_INCOMING_SETUP,
00126 MISDN_DIALING,
00127 MISDN_PROGRESS,
00128 MISDN_PROCEEDING,
00129 MISDN_CALLING,
00130 MISDN_CALLING_ACKNOWLEDGE,
00131 MISDN_ALERTING,
00132 MISDN_BUSY,
00133 MISDN_CONNECTED,
00134 MISDN_PRECONNECTED,
00135 MISDN_DISCONNECTED,
00136 MISDN_RELEASED,
00137 MISDN_BRIDGED,
00138 MISDN_CLEANING,
00139 MISDN_HUNGUP_FROM_MISDN,
00140 MISDN_HUNGUP_FROM_AST,
00141 MISDN_HOLDED,
00142 MISDN_HOLD_DISCONNECT,
00143
00144 };
00145
00146 #define ORG_AST 1
00147 #define ORG_MISDN 2
00148
00149 struct hold_info {
00150 int port;
00151 int channel;
00152 };
00153
00154 struct chan_list {
00155
00156 char allowed_bearers[BUFFERSIZE + 1];
00157
00158 enum misdn_chan_state state;
00159 int need_queue_hangup;
00160 int need_hangup;
00161 int need_busy;
00162
00163 int originator;
00164 int noautorespond_on_setup;
00165
00166 int norxtone;
00167 int notxtone;
00168
00169 int toggle_ec;
00170
00171 int incoming_early_audio;
00172
00173 int ignore_dtmf;
00174
00175 int pipe[2];
00176 char ast_rd_buf[4096];
00177 struct ast_frame frame;
00178
00179 int faxdetect;
00180 int faxdetect_timeout;
00181 struct timeval faxdetect_tv;
00182 int faxhandled;
00183
00184 int ast_dsp;
00185
00186 int jb_len;
00187 int jb_upper_threshold;
00188 struct misdn_jb *jb;
00189
00190 struct ast_dsp *dsp;
00191 struct ast_trans_pvt *trans;
00192
00193 struct ast_channel * ast;
00194
00195 int dummy;
00196
00197 struct misdn_bchannel *bc;
00198
00199 struct hold_info hold_info;
00200
00201 unsigned int l3id;
00202 int addr;
00203
00204 char context[BUFFERSIZE];
00205
00206 int zero_read_cnt;
00207 int dropped_frame_cnt;
00208
00209 int far_alerting;
00210
00211 int nttimeout;
00212
00213 int other_pid;
00214 struct chan_list *other_ch;
00215
00216 const struct ind_tone_zone_sound *ts;
00217
00218 int overlap_dial;
00219 int overlap_dial_task;
00220 ast_mutex_t overlap_tv_lock;
00221 struct timeval overlap_tv;
00222
00223 struct chan_list *peer;
00224 struct chan_list *next;
00225 struct chan_list *prev;
00226 struct chan_list *first;
00227 };
00228
00229
00230
00231 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00232 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00233
00234 struct robin_list {
00235 char *group;
00236 int port;
00237 int channel;
00238 struct robin_list *next;
00239 struct robin_list *prev;
00240 };
00241 static struct robin_list *robin = NULL;
00242
00243
00244
00245 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
00246
00247
00248
00249 static inline void free_robin_list_r (struct robin_list *r)
00250 {
00251 if (r) {
00252 if (r->next)
00253 free_robin_list_r(r->next);
00254 if (r->group)
00255 free(r->group);
00256 free(r);
00257 }
00258 }
00259
00260 static void free_robin_list ( void )
00261 {
00262 free_robin_list_r(robin);
00263 robin = NULL;
00264 }
00265
00266 static struct robin_list* get_robin_position (char *group)
00267 {
00268 struct robin_list *new;
00269 struct robin_list *iter = robin;
00270 for (; iter; iter = iter->next) {
00271 if (!strcasecmp(iter->group, group))
00272 return iter;
00273 }
00274 new = (struct robin_list *) calloc(1, sizeof(struct robin_list));
00275 new->group = strndup(group, strlen(group));
00276 new->port = 0;
00277 new->channel = 0;
00278 if (robin) {
00279 new->next = robin;
00280 robin->prev = new;
00281 }
00282 robin = new;
00283 return robin;
00284 }
00285
00286
00287
00288 static struct sched_context *misdn_tasks = NULL;
00289 static pthread_t misdn_tasks_thread;
00290
00291 static int *misdn_ports;
00292
00293 static void chan_misdn_log(int level, int port, char *tmpl, ...)
00294 __attribute__ ((format (printf, 3, 4)));
00295
00296 static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
00297 static void send_digit_to_chan(struct chan_list *cl, char digit );
00298
00299 static void hangup_chan(struct chan_list *ch);
00300 static int pbx_start_chan(struct chan_list *ch);
00301
00302 #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
00303 #define MISDN_ASTERISK_PVT(ast) 1
00304
00305 #include "asterisk/strings.h"
00306
00307
00308
00309 static const char misdn_type[] = "mISDN";
00310
00311 static int tracing = 0 ;
00312
00313
00314 static int prefformat = AST_FORMAT_ALAW ;
00315
00316 static int *misdn_debug;
00317 static int *misdn_debug_only;
00318 static int max_ports;
00319
00320 static int *misdn_in_calls;
00321 static int *misdn_out_calls;
00322
00323
00324 struct chan_list dummy_cl;
00325
00326 struct chan_list *cl_te=NULL;
00327 ast_mutex_t cl_te_lock;
00328
00329 static enum event_response_e
00330 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
00331
00332 static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
00333
00334 static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
00335 static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
00336 static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
00337 static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
00338
00339
00340
00341 static int dialtone_indicate(struct chan_list *cl);
00342 static int hanguptone_indicate(struct chan_list *cl);
00343 static int stop_indicate(struct chan_list *cl);
00344
00345 static int start_bc_tones(struct chan_list *cl);
00346 static int stop_bc_tones(struct chan_list *cl);
00347 static void release_chan(struct misdn_bchannel *bc);
00348
00349 static int misdn_check_l2l1(struct ast_channel *chan, void *data);
00350 static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
00351 static int misdn_facility_exec(struct ast_channel *chan, void *data);
00352
00353 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
00354
00355
00356 void debug_numplan(int port, int numplan, char *type);
00357
00358
00359 int add_out_calls(int port);
00360 int add_in_calls(int port);
00361
00362
00363 #ifdef MISDN_1_2
00364 static int update_pipeline_config(struct misdn_bchannel *bc);
00365 #else
00366 static int update_ec_config(struct misdn_bchannel *bc);
00367 #endif
00368
00369
00370
00371
00372
00373 static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
00374 {
00375 struct chan_list *tmp;
00376
00377 for (tmp=cl_te; tmp; tmp = tmp->next) {
00378 if ( tmp->ast == ast ) return tmp;
00379 }
00380
00381 return NULL;
00382 }
00383
00384 static struct chan_list * get_chan_by_ast_name(char *name)
00385 {
00386 struct chan_list *tmp;
00387
00388 for (tmp=cl_te; tmp; tmp = tmp->next) {
00389 if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp;
00390 }
00391
00392 return NULL;
00393 }
00394
00395
00396
00397 struct allowed_bearers {
00398 char *name;
00399 char *display;
00400 int cap;
00401 int deprecated;
00402 };
00403
00404
00405 static const struct allowed_bearers allowed_bearers_array[]= {
00406
00407 { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
00408 { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
00409 { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
00410 { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
00411 { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 },
00412 { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
00413 };
00414
00415
00416 static const char *bearer2str(int cap)
00417 {
00418 unsigned index;
00419
00420 for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
00421 if (allowed_bearers_array[index].cap == cap) {
00422 return allowed_bearers_array[index].display;
00423 }
00424 }
00425
00426 return "Unknown Bearer";
00427 }
00428
00429
00430 static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
00431 {
00432 switch (fac->Function) {
00433 case Fac_CD:
00434 chan_misdn_log(1,bc->port," --> calldeflect to: %s, screened: %s\n", fac->u.CDeflection.DeflectedToNumber,
00435 fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
00436 break;
00437 case Fac_AOCDCurrency:
00438 if (fac->u.AOCDcur.chargeNotAvailable)
00439 chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n");
00440 else if (fac->u.AOCDcur.freeOfCharge)
00441 chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n");
00442 else if (fac->u.AOCDchu.billingId >= 0)
00443 chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
00444 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
00445 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
00446 else
00447 chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
00448 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
00449 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
00450 break;
00451 case Fac_AOCDChargingUnit:
00452 if (fac->u.AOCDchu.chargeNotAvailable)
00453 chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n");
00454 else if (fac->u.AOCDchu.freeOfCharge)
00455 chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n");
00456 else if (fac->u.AOCDchu.billingId >= 0)
00457 chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
00458 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
00459 else
00460 chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
00461 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
00462 break;
00463 default:
00464 chan_misdn_log(1,bc->port," --> unknown facility\n");
00465 break;
00466 }
00467 }
00468
00469 static void print_bearer(struct misdn_bchannel *bc)
00470 {
00471
00472 chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability));
00473
00474 switch(bc->law) {
00475 case INFO_CODEC_ALAW:
00476 chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
00477 break;
00478 case INFO_CODEC_ULAW:
00479 chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
00480 break;
00481 }
00482 }
00483
00484 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
00485 {
00486 char buf[128];
00487
00488 if (!ast)
00489 return;
00490
00491 if (originator == ORG_AST) {
00492 ast = ast_bridged_channel(ast);
00493 if (!ast)
00494 return;
00495 }
00496
00497 switch (bc->AOCDtype) {
00498 case Fac_AOCDCurrency:
00499 pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
00500 if (bc->AOCD.currency.chargeNotAvailable)
00501 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
00502 else {
00503 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
00504 if (bc->AOCD.currency.freeOfCharge)
00505 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
00506 else {
00507 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
00508 if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
00509 pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
00510 if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf))
00511 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
00512 }
00513 }
00514 }
00515 break;
00516 case Fac_AOCDChargingUnit:
00517 pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
00518 if (bc->AOCD.chargingUnit.chargeNotAvailable)
00519 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
00520 else {
00521 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
00522 if (bc->AOCD.chargingUnit.freeOfCharge)
00523 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
00524 else {
00525 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
00526 if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
00527 pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
00528 if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf))
00529 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
00530 }
00531 }
00532 }
00533 break;
00534 default:
00535 break;
00536 }
00537 }
00538
00539
00540
00541 static void sighandler(int sig)
00542 {}
00543
00544 static void* misdn_tasks_thread_func (void *data)
00545 {
00546 int wait;
00547 struct sigaction sa;
00548
00549 sa.sa_handler = sighandler;
00550 sa.sa_flags = SA_NODEFER;
00551 sigemptyset(&sa.sa_mask);
00552 sigaddset(&sa.sa_mask, SIGUSR1);
00553 sigaction(SIGUSR1, &sa, NULL);
00554
00555 sem_post((sem_t *)data);
00556
00557 while (1) {
00558 wait = ast_sched_wait(misdn_tasks);
00559 if (wait < 0)
00560 wait = 8000;
00561 if (poll(NULL, 0, wait) < 0)
00562 chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
00563 ast_sched_runq(misdn_tasks);
00564 }
00565 return NULL;
00566 }
00567
00568 static void misdn_tasks_init (void)
00569 {
00570 sem_t blocker;
00571 int i = 5;
00572
00573 if (sem_init(&blocker, 0, 0)) {
00574 perror("chan_misdn: Failed to initialize semaphore!");
00575 exit(1);
00576 }
00577
00578 chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
00579
00580 misdn_tasks = sched_context_create();
00581 pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
00582
00583 while (sem_wait(&blocker) && --i);
00584 sem_destroy(&blocker);
00585 }
00586
00587 static void misdn_tasks_destroy (void)
00588 {
00589 if (misdn_tasks) {
00590 chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
00591 if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
00592 cb_log(4, 0, "Joining misdn_tasks thread\n");
00593 pthread_join(misdn_tasks_thread, NULL);
00594 }
00595 sched_context_destroy(misdn_tasks);
00596 }
00597 }
00598
00599 static inline void misdn_tasks_wakeup (void)
00600 {
00601 pthread_kill(misdn_tasks_thread, SIGUSR1);
00602 }
00603
00604 static inline int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable)
00605 {
00606 int task_id;
00607
00608 if (!misdn_tasks) {
00609 misdn_tasks_init();
00610 }
00611 task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
00612 misdn_tasks_wakeup();
00613
00614 return task_id;
00615 }
00616
00617 static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data)
00618 {
00619 return _misdn_tasks_add_variable(timeout, callback, data, 0);
00620 }
00621
00622 static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data)
00623 {
00624 return _misdn_tasks_add_variable(timeout, callback, data, 1);
00625 }
00626
00627 static void misdn_tasks_remove (int task_id)
00628 {
00629 AST_SCHED_DEL(misdn_tasks, task_id);
00630 }
00631
00632 static int misdn_l1_task (const void *data)
00633 {
00634 misdn_lib_isdn_l1watcher(*(int *)data);
00635 chan_misdn_log(5, *(int *)data, "L1watcher timeout\n");
00636 return 1;
00637 }
00638
00639 static int misdn_overlap_dial_task (const void *data)
00640 {
00641 struct timeval tv_end, tv_now;
00642 int diff;
00643 struct chan_list *ch = (struct chan_list *)data;
00644
00645 chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
00646
00647 if (ch->state != MISDN_WAITING4DIGS) {
00648 ch->overlap_dial_task = -1;
00649 return 0;
00650 }
00651
00652 ast_mutex_lock(&ch->overlap_tv_lock);
00653 tv_end = ch->overlap_tv;
00654 ast_mutex_unlock(&ch->overlap_tv_lock);
00655
00656 tv_end.tv_sec += ch->overlap_dial;
00657 tv_now = ast_tvnow();
00658
00659 diff = ast_tvdiff_ms(tv_end, tv_now);
00660
00661 if (diff <= 100) {
00662 char *dad=ch->bc->dad, sexten[]="s";
00663
00664 stop_indicate(ch);
00665
00666 if (ast_strlen_zero(ch->bc->dad)) {
00667 dad=sexten;
00668 strcpy(ch->ast->exten, sexten);
00669 }
00670
00671 if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
00672 ch->state=MISDN_DIALING;
00673 if (pbx_start_chan(ch) < 0) {
00674 chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
00675 goto misdn_overlap_dial_task_disconnect;
00676 }
00677 } else {
00678 misdn_overlap_dial_task_disconnect:
00679 hanguptone_indicate(ch);
00680 ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
00681 ch->state=MISDN_CLEANING;
00682 misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
00683 }
00684 ch->overlap_dial_task = -1;
00685 return 0;
00686 } else
00687 return diff;
00688 }
00689
00690 static void send_digit_to_chan(struct chan_list *cl, char digit )
00691 {
00692 static const char* dtmf_tones[] = {
00693 "!941+1336/100,!0/100",
00694 "!697+1209/100,!0/100",
00695 "!697+1336/100,!0/100",
00696 "!697+1477/100,!0/100",
00697 "!770+1209/100,!0/100",
00698 "!770+1336/100,!0/100",
00699 "!770+1477/100,!0/100",
00700 "!852+1209/100,!0/100",
00701 "!852+1336/100,!0/100",
00702 "!852+1477/100,!0/100",
00703 "!697+1633/100,!0/100",
00704 "!770+1633/100,!0/100",
00705 "!852+1633/100,!0/100",
00706 "!941+1633/100,!0/100",
00707 "!941+1209/100,!0/100",
00708 "!941+1477/100,!0/100" };
00709 struct ast_channel *chan=cl->ast;
00710
00711 if (digit >= '0' && digit <='9')
00712 ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
00713 else if (digit >= 'A' && digit <= 'D')
00714 ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
00715 else if (digit == '*')
00716 ast_playtones_start(chan,0,dtmf_tones[14], 0);
00717 else if (digit == '#')
00718 ast_playtones_start(chan,0,dtmf_tones[15], 0);
00719 else {
00720
00721 ast_log(LOG_DEBUG, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
00722 }
00723 }
00724
00725
00726 static int misdn_set_debug(int fd, int argc, char *argv[])
00727 {
00728 int level;
00729
00730 if (argc != 4 && argc != 5 && argc != 6 && argc != 7)
00731 return RESULT_SHOWUSAGE;
00732
00733 level = atoi(argv[3]);
00734
00735 switch (argc) {
00736 case 4:
00737 case 5:
00738 {
00739 int i;
00740 int only = 0;
00741 if (argc == 5) {
00742 if (strncasecmp(argv[4], "only", strlen(argv[4])))
00743 return RESULT_SHOWUSAGE;
00744 else
00745 only = 1;
00746 }
00747
00748 for (i = 0; i <= max_ports; i++) {
00749 misdn_debug[i] = level;
00750 misdn_debug_only[i] = only;
00751 }
00752 ast_cli(fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":"");
00753 }
00754 break;
00755 case 6:
00756 case 7:
00757 {
00758 int port;
00759 if (strncasecmp(argv[4], "port", strlen(argv[4])))
00760 return RESULT_SHOWUSAGE;
00761 port = atoi(argv[5]);
00762 if (port <= 0 || port > max_ports) {
00763 switch (max_ports) {
00764 case 0:
00765 ast_cli(fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
00766 break;
00767 case 1:
00768 ast_cli(fd, "port number not valid! only port 1 is available.\n");
00769 break;
00770 default:
00771 ast_cli(fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
00772 }
00773 return 0;
00774 }
00775 if (argc == 7) {
00776 if (strncasecmp(argv[6], "only", strlen(argv[6])))
00777 return RESULT_SHOWUSAGE;
00778 else
00779 misdn_debug_only[port] = 1;
00780 } else
00781 misdn_debug_only[port] = 0;
00782 misdn_debug[port] = level;
00783 ast_cli(fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port);
00784 }
00785 }
00786 return 0;
00787 }
00788
00789 static int misdn_set_crypt_debug(int fd, int argc, char *argv[])
00790 {
00791 if (argc != 5) return RESULT_SHOWUSAGE;
00792
00793 return 0;
00794 }
00795
00796 static int misdn_port_block(int fd, int argc, char *argv[])
00797 {
00798 int port;
00799
00800 if (argc != 4)
00801 return RESULT_SHOWUSAGE;
00802
00803 port = atoi(argv[3]);
00804
00805 misdn_lib_port_block(port);
00806
00807 return 0;
00808 }
00809
00810 static int misdn_port_unblock(int fd, int argc, char *argv[])
00811 {
00812 int port;
00813
00814 if (argc != 4)
00815 return RESULT_SHOWUSAGE;
00816
00817 port = atoi(argv[3]);
00818
00819 misdn_lib_port_unblock(port);
00820
00821 return 0;
00822 }
00823
00824
00825 static int misdn_restart_port (int fd, int argc, char *argv[])
00826 {
00827 int port;
00828
00829 if (argc != 4)
00830 return RESULT_SHOWUSAGE;
00831
00832 port = atoi(argv[3]);
00833
00834 misdn_lib_port_restart(port);
00835
00836 return 0;
00837 }
00838
00839 static int misdn_restart_pid (int fd, int argc, char *argv[])
00840 {
00841 int pid;
00842
00843 if (argc != 4)
00844 return RESULT_SHOWUSAGE;
00845
00846 pid = atoi(argv[3]);
00847
00848 misdn_lib_pid_restart(pid);
00849
00850 return 0;
00851 }
00852
00853 static int misdn_port_up (int fd, int argc, char *argv[])
00854 {
00855 int port;
00856
00857 if (argc != 4)
00858 return RESULT_SHOWUSAGE;
00859
00860 port = atoi(argv[3]);
00861
00862 misdn_lib_get_port_up(port);
00863
00864 return 0;
00865 }
00866
00867 static int misdn_port_down (int fd, int argc, char *argv[])
00868 {
00869 int port;
00870
00871 if (argc != 4)
00872 return RESULT_SHOWUSAGE;
00873
00874 port = atoi(argv[3]);
00875
00876 misdn_lib_get_port_down(port);
00877
00878 return 0;
00879 }
00880
00881 static inline void show_config_description (int fd, enum misdn_cfg_elements elem)
00882 {
00883 char section[BUFFERSIZE];
00884 char name[BUFFERSIZE];
00885 char desc[BUFFERSIZE];
00886 char def[BUFFERSIZE];
00887 char tmp[BUFFERSIZE];
00888
00889 misdn_cfg_get_name(elem, tmp, sizeof(tmp));
00890 term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
00891 misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
00892
00893 if (elem < MISDN_CFG_LAST)
00894 term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
00895 else
00896 term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
00897
00898 if (*def)
00899 ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc);
00900 else
00901 ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
00902 }
00903
00904 static int misdn_show_config (int fd, int argc, char *argv[])
00905 {
00906 char buffer[