From 9c2db6ff405bec6bb748cdfbdb9e5c23d7602250 Mon Sep 17 00:00:00 2001 From: rmudgett Date: Thu, 3 Jun 2010 00:02:14 +0000 Subject: Add ETSI Message Waiting Indication (MWI) support. Add the ability to report waiting messages to ISDN endpoints (phones). Relevant specification: EN 300 650 and EN 300 745 Review: https://reviewboard.asterisk.org/r/599/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@267399 f38db490-d61c-443f-a65b-d21fe96a405b --- channels/chan_dahdi.c | 11 +++ channels/sig_pri.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++- channels/sig_pri.h | 42 +++++++++++ 3 files changed, 252 insertions(+), 1 deletion(-) (limited to 'channels') diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 17de19dcb..af1b871f5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -11895,6 +11895,11 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup; #endif /* defined(HAVE_PRI_AOC_EVENTS) */ ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list)); +#if defined(HAVE_PRI_MWI) + ast_copy_string(pris[span].pri.mwi_mailboxes, + conf->pri.pri.mwi_mailboxes, + sizeof(pris[span].pri.mwi_mailboxes)); +#endif /* defined(HAVE_PRI_MWI) */ ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial)); ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext)); ast_copy_string(pris[span].pri.internationalprefix, conf->pri.pri.internationalprefix, sizeof(pris[span].pri.internationalprefix)); @@ -16586,6 +16591,7 @@ static int __unload_module(void) for (j = 0; j < SIG_PRI_NUM_DCHANS; j++) { dahdi_close_pri_fd(&(pris[i]), j); } + sig_pri_stop_pri(&pris[i].pri); } #if defined(HAVE_PRI_CCSS) ast_cc_agent_unregister(&dahdi_pri_cc_agent_callbacks); @@ -17450,6 +17456,11 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct } else if (!strcasecmp(v->name, "allow_call_waiting_calls")) { confp->pri.pri.allow_call_waiting_calls = ast_true(v->value); #endif /* defined(HAVE_PRI_CALL_WAITING) */ +#if defined(HAVE_PRI_MWI) + } else if (!strcasecmp(v->name, "mwi_mailboxes")) { + ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value, + sizeof(confp->pri.pri.mwi_mailboxes)); +#endif /* defined(HAVE_PRI_MWI) */ #endif /* HAVE_PRI */ #ifdef HAVE_SS7 } else if (!strcasecmp(v->name, "ss7type")) { diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 8955c670b..8e7c73c22 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -6423,6 +6423,130 @@ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char return 1; } +#if defined(HAVE_PRI_MWI) +/*! + * \internal + * \brief Send a MWI indication to the given span. + * \since 1.8 + * + * \param pri Asterisk D channel control structure. + * \param mbox_number Mailbox number + * \param mbox_context Mailbox context + * \param num_messages Number of messages waiting. + * + * \return Nothing + */ +static void sig_pri_send_mwi_indication(struct sig_pri_pri *pri, const char *mbox_number, const char *mbox_context, int num_messages) +{ + struct pri_party_id mailbox; + + ast_debug(1, "Send MWI indication for %s@%s num_messages:%d\n", mbox_number, + mbox_context, num_messages); + + memset(&mailbox, 0, sizeof(mailbox)); + mailbox.number.valid = 1; + mailbox.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN; + ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str)); + + ast_mutex_lock(&pri->lock); + pri_mwi_indicate(pri->pri, &mailbox, 1 /* speech */, num_messages, NULL, NULL, -1, 0); + ast_mutex_unlock(&pri->lock); +} +#endif /* defined(HAVE_PRI_MWI) */ + +#if defined(HAVE_PRI_MWI) +/*! + * \internal + * \brief MWI subscription event callback. + * \since 1.8 + * + * \param event the event being passed to the subscriber + * \param userdata the data provider in the call to ast_event_subscribe() + * + * \return Nothing + */ +static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata) +{ + struct sig_pri_pri *pri = userdata; + const char *mbox_context; + const char *mbox_number; + int num_messages; + + mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX); + if (ast_strlen_zero(mbox_number)) { + return; + } + mbox_context = ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT); + if (ast_strlen_zero(mbox_context)) { + return; + } + num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); + sig_pri_send_mwi_indication(pri, mbox_number, mbox_context, num_messages); +} +#endif /* defined(HAVE_PRI_MWI) */ + +#if defined(HAVE_PRI_MWI) +/*! + * \internal + * \brief Send update MWI indications from the event cache. + * \since 1.8 + * + * \param pri Asterisk D channel control structure. + * + * \return Nothing + */ +static void sig_pri_mwi_cache_update(struct sig_pri_pri *pri) +{ + int idx; + int num_messages; + struct ast_event *event; + + for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) { + if (!pri->mbox[idx].sub) { + /* There are no more mailboxes on this span. */ + break; + } + + event = ast_event_get_cached(AST_EVENT_MWI, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].number, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, pri->mbox[idx].context, + AST_EVENT_IE_END); + if (!event) { + /* No cached event for this mailbox. */ + continue; + } + num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); + sig_pri_send_mwi_indication(pri, pri->mbox[idx].number, pri->mbox[idx].context, + num_messages); + ast_event_destroy(event); + } +} +#endif /* defined(HAVE_PRI_MWI) */ + +/*! + * \brief Stop PRI span. + * \since 1.8 + * + * \param pri Asterisk D channel control structure. + * + * \return Nothing + */ +void sig_pri_stop_pri(struct sig_pri_pri *pri) +{ +#if defined(HAVE_PRI_MWI) + int idx; +#endif /* defined(HAVE_PRI_MWI) */ + +#if defined(HAVE_PRI_MWI) + for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) { + if (pri->mbox[idx].sub) { + pri->mbox[idx].sub = ast_event_unsubscribe(pri->mbox[idx].sub); + } + } +#endif /* defined(HAVE_PRI_MWI) */ +} + /*! * \internal * \brief qsort comparison function. @@ -6477,11 +6601,72 @@ int sig_pri_start_pri(struct sig_pri_pri *pri) { int x; int i; +#if defined(HAVE_PRI_MWI) + char *saveptr; + char *mbox_number; + char *mbox_context; + struct ast_str *mwi_description = ast_str_alloca(64); +#endif /* defined(HAVE_PRI_MWI) */ + +#if defined(HAVE_PRI_MWI) + /* Prepare the mbox[] for use. */ + for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) { + if (pri->mbox[i].sub) { + pri->mbox[i].sub = ast_event_unsubscribe(pri->mbox[i].sub); + } + } +#endif /* defined(HAVE_PRI_MWI) */ ast_mutex_init(&pri->lock); - sig_pri_sort_pri_chans(pri); +#if defined(HAVE_PRI_MWI) + /* + * Split the mwi_mailboxes configuration string into the mbox[]: + * mailbox_number[@context]{,mailbox_number[@context]} + */ + i = 0; + saveptr = pri->mwi_mailboxes; + while (i < ARRAY_LEN(pri->mbox)) { + mbox_number = strsep(&saveptr, ","); + if (!mbox_number) { + break; + } + /* Split the mailbox_number and context */ + mbox_context = strchr(mbox_number, '@'); + if (mbox_context) { + *mbox_context++ = '\0'; + mbox_context = ast_strip(mbox_context); + } + mbox_number = ast_strip(mbox_number); + if (ast_strlen_zero(mbox_number)) { + /* There is no mailbox number. Skip it. */ + continue; + } + if (ast_strlen_zero(mbox_context)) { + /* There was no context so use the default. */ + mbox_context = "default"; + } + + /* Fill the mbox[] element. */ + ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s", + sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context); + pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb, + ast_str_buffer(mwi_description), pri, + AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox_number, + AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, mbox_context, + AST_EVENT_IE_END); + if (!pri->mbox[i].sub) { + ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.", + sig_pri_cc_type_name, pri->span, mbox_number, mbox_context); + continue; + } + pri->mbox[i].number = mbox_number; + pri->mbox[i].context = mbox_context; + ++i; + } +#endif /* defined(HAVE_PRI_MWI) */ + for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) { if (pri->fds[i] == -1) { break; @@ -6574,6 +6759,19 @@ int sig_pri_start_pri(struct sig_pri_pri *pri) ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno)); return -1; } + +#if defined(HAVE_PRI_MWI) + /* + * Send the initial MWI indications from the event cache for this span. + * + * If we were loaded after app_voicemail the event would already be in + * the cache. If we were loaded before app_voicemail the event would not + * be in the cache yet and app_voicemail will send the event when it + * gets loaded. + */ + sig_pri_mwi_cache_update(pri); +#endif /* defined(HAVE_PRI_MWI) */ + return 0; } diff --git a/channels/sig_pri.h b/channels/sig_pri.h index 450a36eec..e7f424f5f 100644 --- a/channels/sig_pri.h +++ b/channels/sig_pri.h @@ -27,6 +27,7 @@ #include "asterisk/channel.h" #include "asterisk/frame.h" +#include "asterisk/event.h" #include "asterisk/ccss.h" #include #include @@ -251,6 +252,35 @@ struct sig_pri_chan { #endif }; +#if defined(HAVE_PRI_MWI) +/*! Maximum number of mailboxes per span. */ +#define SIG_PRI_MAX_MWI_MAILBOXES 8 +/*! Typical maximum length of mwi mailbox number */ +#define SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN 10 /* digits in number */ +/*! Typical maximum length of mwi mailbox context */ +#define SIG_PRI_MAX_MWI_CONTEXT_LEN 10 +/*! + * \brief Maximum mwi_mailbox string length. + * \details + * max_length = #mailboxes * (mbox_number + '@' + context + ',') + * The last ',' is a null terminator instead. + */ +#define SIG_PRI_MAX_MWI_MAILBOX_STR (SIG_PRI_MAX_MWI_MAILBOXES \ + * (SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN + 1 + SIG_PRI_MAX_MWI_CONTEXT_LEN + 1)) + +struct sig_pri_mbox { + /*! + * \brief MWI mailbox event subscription. + * \note NULL if mailbox not configured. + */ + struct ast_event_sub *sub; + /*! \brief Mailbox number */ + const char *number; + /*! \brief Mailbox context. */ + const char *context; +}; +#endif /* defined(HAVE_PRI_MWI) */ + struct sig_pri_pri { /* Should be set by user */ struct ast_cc_config_params *cc_params; /*!< CC config parameters for each new call. */ @@ -294,6 +324,17 @@ struct sig_pri_pri { char privateprefix[20]; /*!< for private dialplans */ char unknownprefix[20]; /*!< for unknown dialplans */ long resetinterval; /*!< Interval (in seconds) for resetting unused channels */ +#if defined(HAVE_PRI_MWI) + /*! \brief Active MWI mailboxes */ + struct sig_pri_mbox mbox[SIG_PRI_MAX_MWI_MAILBOXES]; + /*! + * \brief Comma separated list of mailboxes to indicate MWI. + * \note Empty if disabled. + * \note Format: mailbox_number[@context]{,mailbox_number[@context]} + * \note String is split apart when span is started. + */ + char mwi_mailboxes[SIG_PRI_MAX_MWI_MAILBOX_STR]; +#endif /* defined(HAVE_PRI_MWI) */ char msn_list[AST_MAX_EXTENSION]; /*!< Comma separated list of MSNs to handle. Empty if disabled. */ char idleext[AST_MAX_EXTENSION]; /*!< Where to idle extra calls */ char idlecontext[AST_MAX_CONTEXT]; /*!< What context to use for idle */ @@ -412,6 +453,7 @@ void sig_pri_init_pri(struct sig_pri_pri *pri); * functions should handle it normally (generate inband DTMF) */ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char digit); +void sig_pri_stop_pri(struct sig_pri_pri *pri); int sig_pri_start_pri(struct sig_pri_pri *pri); void sig_pri_chan_alarm_notify(struct sig_pri_chan *p, int noalarm); -- cgit v1.2.3