aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/smdi.txt148
-rw-r--r--res/res_smdi.c90
2 files changed, 204 insertions, 34 deletions
diff --git a/doc/smdi.txt b/doc/smdi.txt
index a4aa6bbd6..2181bc401 100644
--- a/doc/smdi.txt
+++ b/doc/smdi.txt
@@ -1,25 +1,137 @@
-Asterisk SMDI (Simple Message Desk Interface) integration
----------------------------------------------------------
+===============================================================================
+===============================================================================
+=== Asterisk SMDI (Simple Message Desk Interface) integration =================
+===============================================================================
+===============================================================================
-SMDI integration is configured in smdi.conf, zaptel.conf, and voicemail.conf.
-Various characteristics of the SMDI interfaces to be used (serial ports) are
-defined in smdi.conf. SMDI integration for callerid and MWI are defined in
-zaptel.conf and voicemail.conf respectively. SMDI only works with Zaptel
-interfaces configured for FXS signalling.
+===============================================================================
+===== 1) Accessing SMDI information in the dialplan. ==========================
+===============================================================================
-When SMDI is enabled and a call comes into Asterisk, the forwarding station
-number is used as the destination for the call and any callerid information
-present is used. This way you can configure your extensions.conf as follows to
-behave as a message desk.
+There are two dialplan functions that can be used to access the details of
+incoming SMDI messages.
-[default]
+*CLI> core show function SMDI_MSG_RETRIEVE
-exten => _XXXXXXX,1,VoiceMail(${EXTEN}|${SMDI_VM_TYPE})
-exten => _XXXXXXX,n,Hangup
+ -= Info about function 'SMDI_MSG_RETRIEVE' =-
-exten => s,1,VoiceMailMain(${CALLERID(num)})
-exten => s,n,Hangup
+[Syntax]
+SMDI_MSG_RETRIEVE(<smdi port>,<search key>[,timeout[,options]])
-The ${SMDI_VM_TYPE} variable will be set to u, b, or nothing depending on the
-contents of the type of SMDI message received.
+[Synopsis]
+Retrieve an SMDI message.
+[Description]
+ This function is used to retrieve an incoming SMDI message. It returns
+an ID which can be used with the SMDI_MSG() function to access details of
+the message. Note that this is a destructive function in the sense that
+once an SMDI message is retrieved using this function, it is no longer in
+the global SMDI message queue, and can not be accessed by any other Asterisk
+channels. The timeout for this function is optional, and the default is
+3 seconds. When providing a timeout, it should be in milliseconds.
+ The default search is done on the forwarding station ID. However, if
+you set one of the search key options in the options field, you can change
+this behavior.
+ Options:
+ t - Instead of searching on the forwarding station, search on the message
+ desk terminal.
+ n - Instead of searching on the forwarding station, search on the message
+ desk number.
+
+
+*CLI> core show function SMDI_MSG
+
+ -= Info about function 'SMDI_MSG' =-
+
+[Syntax]
+SMDI_MSG(<message_id>,<component>)
+
+[Synopsis]
+Retrieve details about an SMDI message.
+
+[Description]
+ This function is used to access details of an SMDI message that was
+pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()
+function.
+ Valid message components are:
+ station - The forwarding station
+ callerid - The callerID of the calling party that was forwarded
+ type - The call type. The value here is the exact character
+ that came in on the SMDI link. Typically, example values
+ are: D - Direct Calls, A - Forward All Calls,
+ B - Forward Busy Calls, N - Forward No Answer Calls
+
+
+Here is an example of how to use these functions:
+
+; Retrieve the SMDI message that is associated with the number that
+; was called in Asterisk.
+exten => _0XXX,1,Set(SMDI_MSG_ID=${SMDI_MSG_RETRIEVE(/dev/tty0,${EXTEN})})
+
+; Ensure that the message was retrieved.
+exten => _0XXX,n,GotoIf($["x${SMDI_MSG_ID}" != "x"]?processcall:hangup)
+exten => _0XXX,n(hangup),NoOp(No SMDI message retrieved for ${EXTEN})
+
+; Grab the details out of the SMDI message.
+exten => _0XXX,n(processcall),NoOp(Message found for ${EXTEN})
+exten => _0XXX,n,Set(SMDI_EXTEN=${SMDI_MSG(${SMDI_MSG_ID},station)})
+exten => _0XXX,n,Set(SMDI_CID=${SMDI_MSG(${SMDI_MSG_ID},callerid)})
+
+; Map SMDI message types to the right voicemail option. If it is "B", use the
+; busy option. Otherwise, use the unavailable option.
+exten => _0XXX,n,GotoIf($["${SMDI_MSG(${SMDI_MSG_ID},type)}" == "B"]?usebusy:useunavail)
+
+exten => _0XXX,n(usebusy),Set(SMDI_VM_TYPE=b)
+exten => _0XXX,n,Goto(continue)
+
+exten => _0XXX,n,(useunavil),Set(SMDI_VM_TYPE=u)
+
+exten => _0XXX,n(continue),NoOp( Process the rest of the call ... )
+
+
+===============================================================================
+===== 2) Ensuring complete MWI information over SMDI ==========================
+===============================================================================
+
+Another change has been made to ensure that MWI state is properly propagated
+over the SMDI link. This replaces the use of externnotify=smdi for
+voicemail.conf. The issue is that we have to poll mailboxes occasionally for
+changes that were made using an IMAP client. So, this ability was added to
+res_smdi. To configure this, there is a new section in smdi.conf. It looks
+like this:
+
+[mailboxes]
+; This section configures parameters related to MWI handling for the SMDI link.
+ ;
+; This option configures the polling interval used to check to see if the
+; mailboxes have any new messages. This option is specified in seconds.
+; The default value is 10 seconds.
+;
+;pollinginterval=10
+;
+; Before specifying mailboxes, you must specify an SMDI interface. All mailbox
+; definitions that follow will correspond to that SMDI interface. If you
+; specify another interface, then all definitions following that will correspond
+; to the new interface.
+;
+; Every other entry in this section of the configuration file is interpreted as
+; a mapping between the mailbox ID on the SMDI link, and the local Asterisk
+; mailbox name. In many cases, they are the same thing, but they still must be
+; listed here so that this module knows which mailboxes it needs to pay
+; attention to.
+;
+; Syntax:
+; <SMDI mailbox ID>=<Asterisk Mailbox Name>[@Asterisk Voicemail Context]
+;
+; If no Asterisk voicemail context is specified, "default" will be assumed.
+;
+;
+;smdiport=/dev/ttyS0
+;2565551234=1234@vmcontext1
+;2565555678=5678@vmcontext2
+;smdiport=/dev/ttyS1
+;2565559999=9999
+
+===============================================================================
+===============================================================================
+===============================================================================
diff --git a/res/res_smdi.c b/res/res_smdi.c
index b6a0b4593..83a5e1f7c 100644
--- a/res/res_smdi.c
+++ b/res/res_smdi.c
@@ -369,8 +369,13 @@ static void *smdi_msg_pop(struct ast_smdi_interface *iface, enum smdi_message_ty
return msg;
}
+enum {
+ OPT_SEARCH_TERMINAL = (1 << 0),
+ OPT_SEARCH_NUMBER = (1 << 1),
+};
+
static void *smdi_msg_find(struct ast_smdi_interface *iface,
- enum smdi_message_type type, const char *station)
+ enum smdi_message_type type, const char *search_key, struct ast_flags options)
{
void *msg = NULL;
@@ -378,10 +383,35 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface,
switch (type) {
case SMDI_MD:
- msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, station);
+ if (ast_test_flag(&options, OPT_SEARCH_TERMINAL)) {
+ struct ast_smdi_md_message *md_msg = NULL;
+
+ /* Searching by the message desk terminal */
+
+ ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+ if (!strcasecmp(iterator->mesg_desk_term, search_key))
+ md_msg = ASTOBJ_REF(iterator);
+ } while (0); );
+
+ msg = md_msg;
+ } else if (ast_test_flag(&options, OPT_SEARCH_NUMBER)) {
+ struct ast_smdi_md_message *md_msg = NULL;
+
+ /* Searching by the message desk number */
+
+ ASTOBJ_CONTAINER_TRAVERSE(&iface->md_q, !md_msg, do {
+ if (!strcasecmp(iterator->mesg_desk_num, search_key))
+ md_msg = ASTOBJ_REF(iterator);
+ } while (0); );
+
+ msg = md_msg;
+ } else {
+ /* Searching by the forwarding station */
+ msg = ASTOBJ_CONTAINER_FIND(&iface->md_q, search_key);
+ }
break;
case SMDI_MWI:
- msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, station);
+ msg = ASTOBJ_CONTAINER_FIND(&iface->mwi_q, search_key);
break;
}
@@ -389,7 +419,7 @@ static void *smdi_msg_find(struct ast_smdi_interface *iface,
}
static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout,
- enum smdi_message_type type, const char *station)
+ enum smdi_message_type type, const char *search_key, struct ast_flags options)
{
struct timeval start;
long diff = 0;
@@ -415,7 +445,7 @@ static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout,
lock_msg_q(iface, type);
- if ((msg = smdi_msg_find(iface, type, station))) {
+ if ((msg = smdi_msg_find(iface, type, search_key, options))) {
unlock_msg_q(iface, type);
return msg;
}
@@ -429,7 +459,7 @@ static void *smdi_message_wait(struct ast_smdi_interface *iface, int timeout,
ast_cond_timedwait(cond, lock, &ts);
- if ((msg = smdi_msg_find(iface, type, station))) {
+ if ((msg = smdi_msg_find(iface, type, search_key, options))) {
unlock_msg_q(iface, type);
return msg;
}
@@ -450,7 +480,8 @@ struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *i
struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
{
- return smdi_message_wait(iface, timeout, SMDI_MD, NULL);
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MD, NULL, options);
}
struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
@@ -460,13 +491,15 @@ struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface
struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
{
- return smdi_message_wait(iface, timeout, SMDI_MWI, NULL);
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MWI, NULL, options);
}
struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout,
const char *station)
{
- return smdi_message_wait(iface, timeout, SMDI_MWI, station);
+ struct ast_flags options = { 0 };
+ return smdi_message_wait(iface, timeout, SMDI_MWI, station, options);
}
struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
@@ -1059,14 +1092,21 @@ static int smdi_msg_id;
/*! In milliseconds */
#define SMDI_RETRIEVE_TIMEOUT_DEFAULT 3000
+AST_APP_OPTIONS(smdi_msg_ret_options, BEGIN_OPTIONS
+ AST_APP_OPTION('t', OPT_SEARCH_TERMINAL),
+ AST_APP_OPTION('n', OPT_SEARCH_NUMBER),
+END_OPTIONS );
+
static int smdi_msg_retrieve_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
struct ast_module_user *u;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(port);
- AST_APP_ARG(station);
+ AST_APP_ARG(search_key);
AST_APP_ARG(timeout);
+ AST_APP_ARG(options);
);
+ struct ast_flags options = { 0 };
unsigned int timeout = SMDI_RETRIEVE_TIMEOUT_DEFAULT;
int res = -1;
char *parse = NULL;
@@ -1092,7 +1132,7 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, char *cmd, char *dat
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
- if (ast_strlen_zero(args.port) || ast_strlen_zero(args.station)) {
+ if (ast_strlen_zero(args.port) || ast_strlen_zero(args.search_key)) {
ast_log(LOG_ERROR, "Invalid arguments provided to SMDI_MSG_RETRIEVE\n");
goto return_error;
}
@@ -1102,6 +1142,10 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, char *cmd, char *dat
goto return_error;
}
+ if (!ast_strlen_zero(args.options)) {
+ ast_app_parse_options(smdi_msg_ret_options, &options, NULL, args.options);
+ }
+
if (!ast_strlen_zero(args.timeout)) {
if (sscanf(args.timeout, "%u", &timeout) != 1) {
ast_log(LOG_ERROR, "'%s' is not a valid timeout\n", args.timeout);
@@ -1109,9 +1153,9 @@ static int smdi_msg_retrieve_read(struct ast_channel *chan, char *cmd, char *dat
}
}
- if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.station))) {
- ast_log(LOG_WARNING, "No SMDI message retrieved for station '%s' after "
- "waiting %u ms.\n", args.station, timeout);
+ if (!(md_msg = smdi_message_wait(iface, timeout, SMDI_MD, args.search_key, options))) {
+ ast_log(LOG_WARNING, "No SMDI message retrieved for search key '%s' after "
+ "waiting %u ms.\n", args.search_key, timeout);
goto return_error;
}
@@ -1200,7 +1244,11 @@ static int smdi_msg_read(struct ast_channel *chan, char *cmd, char *data, char *
smd = datastore->data;
- if (!strcasecmp(args.component, "station")) {
+ if (!strcasecmp(args.component, "number")) {
+ ast_copy_string(buf, smd->md_msg->mesg_desk_num, len);
+ } else if (!strcasecmp(args.component, "terminal")) {
+ ast_copy_string(buf, smd->md_msg->mesg_desk_term, len);
+ } else if (!strcasecmp(args.component, "station")) {
ast_copy_string(buf, smd->md_msg->fwd_st, len);
} else if (!strcasecmp(args.component, "callerid")) {
ast_copy_string(buf, smd->md_msg->calling_st, len);
@@ -1223,7 +1271,7 @@ return_error:
static struct ast_custom_function smdi_msg_retrieve_function = {
.name = "SMDI_MSG_RETRIEVE",
.synopsis = "Retrieve an SMDI message.",
- .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<station>[,timeout])",
+ .syntax = "SMDI_MSG_RETRIEVE(<smdi port>,<search key>[,timeout[,options]])",
.desc =
" This function is used to retrieve an incoming SMDI message. It returns\n"
"an ID which can be used with the SMDI_MSG() function to access details of\n"
@@ -1232,6 +1280,14 @@ static struct ast_custom_function smdi_msg_retrieve_function = {
"the global SMDI message queue, and can not be accessed by any other Asterisk\n"
"channels. The timeout for this function is optional, and the default is\n"
"3 seconds. When providing a timeout, it should be in milliseconds.\n"
+ " The default search is done on the forwarding station ID. However, if\n"
+ "you set one of the search key options in the options field, you can change\n"
+ "this behavior.\n"
+ " Options:\n"
+ " t - Instead of searching on the forwarding station, search on the message\n"
+ " desk terminal.\n"
+ " n - Instead of searching on the forwarding station, search on the message\n"
+ " desk number.\n"
"",
.read = smdi_msg_retrieve_read,
};
@@ -1245,6 +1301,8 @@ static struct ast_custom_function smdi_msg_function = {
"pulled from the incoming SMDI message queue using the SMDI_MSG_RETRIEVE()\n"
"function.\n"
" Valid message components are:\n"
+ " number - The message desk number\n"
+ " terminal - The message desk terminal\n"
" station - The forwarding station\n"
" callerid - The callerID of the calling party that was forwarded\n"
" type - The call type. The value here is the exact character\n"