diff --git a/src/pstn/main.c b/src/pstn/main.c index 15e6c12..7605363 100644 --- a/src/pstn/main.c +++ b/src/pstn/main.c @@ -104,6 +104,12 @@ static void print_help() printf(" Enable en-block dialing, to collect number before setup. The value\n"); printf(" given is the number of seconds to wait for more digits to be dialed.\n"); printf(" (default = %d)\n", enblock); + printf(" -D --dial-hint xxxx | xxxx-yyyy\n"); + printf(" The given one or multpiple hits for numbers with a fixed length. This\n"); + printf(" can be a single number or a range of number. If a range is given, xxxx\n"); + printf(" and yyyy must have equal length. If one of the given numbers are dialed,\n"); + printf(" the en-block dialing is complete and there is no need to wait for the\n"); + printf(" timeout.\n"); printf(" --recall\n"); printf(" Enable recall / call waiting. (disabled by default)\n"); printf(" -R --ringing-type-incoming \n"); @@ -166,6 +172,7 @@ static void add_options(void) option_add(OPT_TX_CID_BELL, "cid-bell", 0); option_add(OPT_TX_CID_DTMF, "cid-dtmf", 1); option_add(OPT_TX_ENBLOCK, "enblock", 1); + option_add('D', "dial-hint", 1); option_add(OPT_TX_RECALL, "recall", 0); option_add(OPT_TX_RING_I, "ringing-type-incoming", 1); option_add(OPT_TX_RING_H, "ringing-type-hold", 1); @@ -245,6 +252,13 @@ static int handle_options(int short_option, int argi, char **argv) case OPT_TX_RECALL: recall = 1; break; + case 'D': + rc = add_dial_hint(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Given dial hint '%s' is not valid, please use -h for help.\n", argv[argi]); + return rc; + } + break; case OPT_TX_RING_I: if (ringing_type_incoming_num == SUBSCRIBER_MAX) { fprintf(stderr, "Cannot define more than %d ringing types.\n", SUBSCRIBER_MAX); @@ -425,6 +439,8 @@ error: pstn_destroy(pstn_ep); } + purge_dial_hints(); + options_free(); /* exit fm */ diff --git a/src/pstn/pstn.c b/src/pstn/pstn.c index 52e4263..bc93f80 100644 --- a/src/pstn/pstn.c +++ b/src/pstn/pstn.c @@ -159,6 +159,112 @@ static const char *timer_ident_name(enum timer_ident ident) } }; +/* + * dial hints + */ + +static struct dial_hint *dial_hints = NULL; + +int add_dial_hint(const char *arg) +{ + struct dial_hint *hint; + int i, dash; + + hint = calloc(1, sizeof(*hint)); + if (!hint) + return -ENOMEM; + + for (i = 0, dash = -1; arg[i]; i++) { + if (arg[i] == '-') { + /* only single dash is allowed */ + if (dash >= 0) + goto error; + dash = i; + continue; + } + /* only digits 0..9 are allowd */ + if (arg[i] < '0' || arg[i] > '9') + goto error; + } + + if (dash < 0) { + /* number must have at least one digit */ + if (i < 1) + goto error; + hint->length = i; + hint->from = calloc(1, i + 1); + if (!hint->from) + goto error; + strcpy(hint->from, arg); + PDEBUG(DTEL, DEBUG_INFO, "Added dial hint '%s'\n", hint->from); + } else { + /* both numbers must have same lenth */ + if (dash != i - dash - 1) + goto error; + /* there must be digits at all */ + if (dash < 1) + goto error; + hint->length = dash; + hint->from = calloc(1, dash + 1); + if (!hint->from) + goto error; + strncpy(hint->from, arg, dash); + hint->to = calloc(1, dash + 1); + if (!hint->to) + goto error; + strcpy(hint->to, arg + dash + 1); + /* second string must be greater than first string */ + if (strcmp(hint->from, hint->to) > 0) + goto error; + PDEBUG(DTEL, DEBUG_INFO, "Added dial hint '%s' - '%s'\n", hint->from, hint->to); + } + + hint->next = dial_hints; + dial_hints = hint; + + return 0; + +error: + free(hint->from); + free(hint->to); + free(hint); + + return -EINVAL; +} + +static int check_dial_hint(const char *number) +{ + struct dial_hint *hint; + size_t length = strlen(number); + + for (hint = dial_hints; hint; hint = hint->next) { + if (hint->length != length) + continue; + if (hint->from && !hint->to) { + if (strncmp(number, hint->from, hint->length) == 0) + return 1; + } + if (hint->from && hint->to) { + if (strncmp(number, hint->from, hint->length) >= 0 + && strncmp(number, hint->to, hint->length) <= 0) + return 1; + } + } + return 0; +} + +void purge_dial_hints(void) +{ + struct dial_hint *hint; + + while ((hint = dial_hints)) { + dial_hints = hint->next; + free(hint->from); + free(hint->to); + free(hint); + } +} + /* * Endpoint instance */ @@ -521,7 +627,7 @@ void recv_dtmf(void *priv, char digit, dtmf_meas_t __attribute__((unused)) *meas /* if we are receiving digits en block */ if (pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ENBLOCK) { if (digit == '#') { - PDEBUG(DTEL, DEBUG_DEBUG, "Number is complete, send setup\n"); + PDEBUG(DTEL, DEBUG_DEBUG, "Digit '#' received, number is complete, send setup\n"); /* setup (en block) */ setup_ind(pstn, PSTN_CALL_ACTIVE, pstn->dialing, 1); return; @@ -531,6 +637,12 @@ void recv_dtmf(void *priv, char digit, dtmf_meas_t __attribute__((unused)) *meas char called[2] = { digit, '\0' }; strncat(pstn->dialing, called, sizeof(pstn->dialing) - 1); PDEBUG(DTEL, DEBUG_DEBUG, "Appending digit, so dial string is now: '%s'.\n", pstn->dialing); + if (check_dial_hint(pstn->dialing)) { + PDEBUG(DTEL, DEBUG_DEBUG, "Number in list of dial hints received, number is complete, send setup\n"); + /* setup (en block) */ + setup_ind(pstn, PSTN_CALL_ACTIVE, pstn->dialing, 1); + return; + } /* start dial timer */ timer_on(pstn, (double)pstn->enblock, TIMER_IDENT_DIALING); return; @@ -1492,6 +1604,12 @@ static void v5_sig_ind(pstn_t *pstn, uint8_t *data, int len) /* append digit */ strncat(pstn->dialing, called, sizeof(pstn->dialing) - 1); PDEBUG(DTEL, DEBUG_DEBUG, "Appending digit, so dial string is now: '%s'.\n", pstn->dialing); + if (check_dial_hint(pstn->dialing)) { + PDEBUG(DTEL, DEBUG_DEBUG, "Number in list of dial hints received, number is complete, send setup\n"); + /* setup (en block) */ + setup_ind(pstn, PSTN_CALL_ACTIVE, pstn->dialing, 1); + break; + } /* start dial timer */ timer_on(pstn, (double)pstn->enblock, TIMER_IDENT_DIALING); break; diff --git a/src/pstn/pstn.h b/src/pstn/pstn.h index 4107328..a1fd35b 100644 --- a/src/pstn/pstn.h +++ b/src/pstn/pstn.h @@ -104,6 +104,12 @@ struct call { int on_hold; /* track hold/retrieval notification */ }; +struct dial_hint { + struct dial_hint *next; + size_t length; + char *from, *to; +}; + typedef struct pstn { osmo_cc_endpoint_t cc_ep; @@ -119,6 +125,7 @@ typedef struct pstn { int cid_bell; /* use V.23 or Bell 202 FSK tones */ int cid_dtmf; /* use DTMF instead of FSK caller ID */ int enblock; /* receive digits before transmitting them via SETUP message (timeout as given) */ + struct dial_hint dial_hints; /* list of numbers that are complete */ int recall; /* support recall / waiting call */ int *ringing_types_incoming;/* cadenced rining on incoming call */ int ringing_type_hold; /* cadenced rining on waiting call */ @@ -153,9 +160,10 @@ typedef struct pstn { int tx_buffer_pos; /* current position in transmit audio buffer */ } pstn_t; +int add_dial_hint(const char *arg); +void purge_dial_hints(void); void pstn_destroy(pstn_t *pstn_ep); pstn_t *pstn_create(void); int pstn_init(pstn_t *pstn, const char *name, const char *socketname, const char **subscribers, int subscriber_num, uint8_t serving_location, int tx_delay, enum pstn_cid_method clip, int cid_bell, int cid_dtmf, int clip_date, int enblock, int recall, int *ringing_types_incoming, int ringing_type_hold, enum tones_type tones_type, char law); void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg); void rtp_work(pstn_t *pstn_ep); -