[asterisk-commits] trunk r9423 - in /trunk: ./ apps/ channels/
configs/ doc/ include/asterisk/ res/
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Fri Feb 10 14:50:58 MST 2006
Author: mattf
Date: Fri Feb 10 15:50:56 2006
New Revision: 9423
URL: http://svn.digium.com/view/asterisk?rev=9423&view=rev
Log:
Add smdi support for asterisk (see doc/smdi.txt for config info) (#5945)
Added:
trunk/configs/smdi.conf.sample
trunk/doc/smdi.txt
trunk/include/asterisk/smdi.h
trunk/res/res_smdi.c
Modified:
trunk/Makefile
trunk/apps/Makefile
trunk/apps/app_voicemail.c
trunk/channels/Makefile
trunk/channels/chan_zap.c
trunk/configs/voicemail.conf.sample
trunk/configs/zapata.conf.sample
trunk/include/asterisk/callerid.h
trunk/res/Makefile
Modified: trunk/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/Makefile?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Fri Feb 10 15:50:56 2006
@@ -72,6 +72,11 @@
#ifneq ($(CROSS_COMPILE),)
#OPTIONS += -DLOW_MEMORY
#endif
+
+#
+# Asterisk SMDI integration
+#
+WITH_SMDI = 1
# Optional debugging parameters
DEBUG_THREADS = #-DDUMP_SCHEDULER #-DDEBUG_SCHEDULER #-DDEBUG_THREADS #-DDO_CRASH #-DDETECT_DEADLOCKS
Modified: trunk/apps/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/apps/Makefile?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/apps/Makefile (original)
+++ trunk/apps/Makefile Fri Feb 10 15:50:56 2006
@@ -59,7 +59,12 @@
APPS+=app_sms.so
endif
+# Asterisk SMDI integration
#
+ifeq (${WITH_SMDI},1)
+CFLAGS+=-DWITH_SMDI
+endif
+
# If you have UnixODBC you can use ODBC voicemail
# storage
#
Modified: trunk/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/trunk/apps/app_voicemail.c?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Fri Feb 10 15:50:56 2006
@@ -73,6 +73,10 @@
#include "asterisk/cli.h"
#include "asterisk/utils.h"
#include "asterisk/stringfields.h"
+#ifdef WITH_SMDI
+#include "asterisk/smdi.h"
+#define SMDI_MWI_WAIT_TIMEOUT 1000 /* 1 second */
+#endif
#ifdef USE_ODBC_STORAGE
#include "asterisk/res_odbc.h"
#endif
@@ -393,7 +397,9 @@
static char serveremail[80];
static char mailcmd[160]; /* Configurable mail cmd */
static char externnotify[160];
-
+#ifdef WITH_SMDI
+static struct ast_smdi_interface *smdi_iface = NULL;
+#endif
static char vmfmts[80];
static int vmminmessage;
static int vmmaxmessage;
@@ -2318,13 +2324,39 @@
char arguments[255];
char ext_context[256] = "";
int newvoicemails = 0, oldvoicemails = 0;
+#ifdef WITH_SMDI
+ struct ast_smdi_mwi_message *mwi_msg;
+#endif
if (!ast_strlen_zero(context))
snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
else
ast_copy_string(ext_context, extension, sizeof(ext_context));
+#ifdef WITH_SMDI
+ if (!strcasecmp(externnotify, "smdi")) {
+
+ if (ast_app_has_voicemail(ext_context, NULL))
+ ast_smdi_mwi_set(smdi_iface, extension);
+ else
+ ast_smdi_mwi_unset(smdi_iface, extension);
+
+ mwi_msg = ast_smdi_mwi_message_wait(smdi_iface, SMDI_MWI_WAIT_TIMEOUT);
+ if (mwi_msg) {
+ ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s on %s\n", extension, smdi_iface->name);
+ if (!strncmp(mwi_msg->cause, "INV", 3))
+ ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
+ else if (!strncmp(mwi_msg->cause, "BLK", 3))
+ ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
+ ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
+ ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
+ } else {
+ ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s on %s\n", extension, smdi_iface->name);
+ }
+ } else if (!ast_strlen_zero(externnotify)) {
+#else
if (!ast_strlen_zero(externnotify)) {
+#endif
if (messagecount(ext_context, &newvoicemails, &oldvoicemails)) {
ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
} else {
@@ -5842,6 +5874,9 @@
char *cat;
struct ast_variable *var;
char *notifystr = NULL;
+#ifdef WITH_SMDI
+ char *smdistr = NULL;
+#endif
char *astattach;
char *astsearch;
char *astsaycid;
@@ -5951,6 +5986,25 @@
if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
ast_copy_string(externnotify, notifystr, sizeof(externnotify));
ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
+#ifdef WITH_SMDI
+ if(!strcasecmp(externnotify, "smdi")) {
+ ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
+
+ if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
+ smdi_iface = ast_smdi_interface_find(smdistr);
+ } else {
+ ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
+ smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
+ }
+
+ if(!smdi_iface) {
+ ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
+ externnotify[0] = '\0';
+ } else {
+ ast_log(LOG_DEBUG, "Using SMDI port %s\n", smdi_iface->name);
+ }
+ }
+#endif
} else {
externnotify[0] = '\0';
}
Modified: trunk/channels/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/channels/Makefile?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/channels/Makefile (original)
+++ trunk/channels/Makefile Fri Feb 10 15:50:56 2006
@@ -63,6 +63,13 @@
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/ixjuser.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/ixjuser.h),)
CHANNEL_LIBS+=chan_phone.so
+endif
+
+#
+# Asterisk SMDI integration
+#
+ifeq (${WITH_SMDI},1)
+CFLAGS+=-DWITH_SMDI
endif
ifneq ($(wildcard h323/libchanh323.a),)
Modified: trunk/channels/chan_zap.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_zap.c?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/channels/chan_zap.c (original)
+++ trunk/channels/chan_zap.c Fri Feb 10 15:50:56 2006
@@ -101,6 +101,11 @@
#include "asterisk/utils.h"
#include "asterisk/transcap.h"
#include "asterisk/stringfields.h"
+#ifdef WITH_SMDI
+#include "asterisk/smdi.h"
+#include "asterisk/astobj.h"
+#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
+#endif
#ifndef ZT_SIG_HARDHDLC
#error "Your zaptel is too old. please update"
@@ -279,7 +284,10 @@
static int amaflags = 0;
static int adsi = 0;
-
+#ifdef WITH_SMDI
+static int use_smdi = 0;
+static char smdi_port[SMDI_MAX_FILENAME_LEN] = "/dev/ttyS0";
+#endif
static int numbufs = 4;
static int cur_prewink = -1;
@@ -604,6 +612,10 @@
unsigned int hasr2call:1;
unsigned int r2blocked:1;
unsigned int sigchecked:1;
+#endif
+#ifdef WITH_SMDI
+ unsigned int use_smdi:1; /* Whether to use SMDI on this channel */
+ struct ast_smdi_interface *smdi_iface; /* The serial port to listen for SMDI data on */
#endif
struct zt_distRings drings;
@@ -2165,6 +2177,10 @@
p->prev->next = p->next;
if(p->next)
p->next->prev = p->prev;
+#ifdef WITH_SMDI
+ if(p->use_smdi)
+ ASTOBJ_UNREF(p->smdi_iface, ast_smdi_interface_destroy);
+#endif
ast_mutex_destroy(&p->lock);
free(p);
*pvt = NULL;
@@ -5274,7 +5290,7 @@
unsigned char buf[256];
char dtmfcid[300];
char dtmfbuf[300];
- struct callerid_state *cs;
+ struct callerid_state *cs=NULL;
char *name=NULL, *number=NULL;
int distMatches;
int curRingData[3];
@@ -5282,7 +5298,9 @@
int counter1;
int counter;
int samples = 0;
-
+#ifdef WITH_SMDI
+ struct ast_smdi_md_message *smdi_msg = NULL;
+#endif
int flags;
int i;
int timeout;
@@ -5928,10 +5946,35 @@
}
}
#endif
+#ifdef WITH_SMDI
+ /* check for SMDI messages */
+ if(p->use_smdi && p->smdi_iface) {
+ smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
+
+ if(smdi_msg != NULL) {
+ ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
+
+ if (smdi_msg->type == 'B')
+ pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
+ else if (smdi_msg->type == 'N')
+ pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
+
+ ast_log(LOG_DEBUG, "Recieved SMDI message on %s\n", chan->name);
+ } else {
+ ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
+ }
+ }
+
+ if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
+ number = smdi_msg->calling_st;
+
/* If we want caller id, we're in a prering state due to a polarity reversal
* and we're set to use a polarity reversal to trigger the start of caller id,
* grab the caller id and wait for ringing to start... */
+ } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && p->cid_start == CID_START_POLARITY)) {
+#else
if (p->use_callerid && (chan->_state == AST_STATE_PRERING && p->cid_start == CID_START_POLARITY)) {
+#endif
/* If set to use DTMF CID signalling, listen for DTMF */
if (p->cid_signalling == CID_SIG_DTMF) {
int i = 0;
@@ -6297,7 +6340,10 @@
ast_shrink_phone_number(number);
ast_set_callerid(chan, number, name, number);
-
+#ifdef WITH_SMDI
+ if (smdi_msg)
+ ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
+#endif
if (cs)
callerid_free(cs);
ast_setstate(chan, AST_STATE_RING);
@@ -7274,6 +7320,9 @@
tmp->callwaitingcallerid = callwaitingcallerid;
tmp->threewaycalling = threewaycalling;
tmp->adsi = adsi;
+#ifdef WITH_SMDI
+ tmp->use_smdi = use_smdi;
+#endif
tmp->permhidecallerid = hidecallerid;
tmp->callreturn = callreturn;
tmp->echocancel = echocancel;
@@ -7305,6 +7354,22 @@
tmp->use_callerid = 1;
}
}
+
+#ifdef WITH_SMDI
+ if (tmp->cid_signalling == CID_SIG_SMDI) {
+ if (!tmp->use_smdi) {
+ ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
+ tmp->use_smdi = 1;
+ }
+ }
+ if (tmp->use_smdi) {
+ tmp->smdi_iface = ast_smdi_interface_find(smdi_port);
+ if (!(tmp->smdi_iface)) {
+ ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
+ tmp->use_smdi = 0;
+ }
+ }
+#endif
ast_copy_string(tmp->accountcode, accountcode, sizeof(tmp->accountcode));
tmp->amaflags = amaflags;
@@ -10479,12 +10544,12 @@
cid_signalling = CID_SIG_V23;
else if (!strcasecmp(v->value, "dtmf"))
cid_signalling = CID_SIG_DTMF;
+#ifdef WITH_SMDI
+ else if (!strcasecmp(v->value, "smdi"))
+ cid_signalling = CID_SIG_SMDI;
+#endif
else if (!strcasecmp(v->value, "v23_jp"))
-#ifdef ZT_EVENT_RINGBEGIN
cid_signalling = CID_SIG_V23_JP;
-#else
- ast_log(LOG_WARNING, "Asterisk compiled aginst Zaptel version too old to support japanese CallerID!\n");
-#endif
else if (ast_true(v->value))
cid_signalling = CID_SIG_BELL;
} else if (!strcasecmp(v->name, "cidstart")) {
@@ -10507,6 +10572,12 @@
ast_copy_string(mailbox, v->value, sizeof(mailbox));
} else if (!strcasecmp(v->name, "adsi")) {
adsi = ast_true(v->value);
+#ifdef WITH_SMDI
+ } else if (!strcasecmp(v->name, "usesmdi")) {
+ use_smdi = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "smdiport")) {
+ ast_copy_string(smdi_port, v->value, sizeof(smdi_port));
+#endif
} else if (!strcasecmp(v->name, "transfer")) {
transfer = ast_true(v->value);
} else if (!strcasecmp(v->name, "canpark")) {
Added: trunk/configs/smdi.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/smdi.conf.sample?rev=9423&view=auto
==============================================================================
--- trunk/configs/smdi.conf.sample (added)
+++ trunk/configs/smdi.conf.sample Fri Feb 10 15:50:56 2006
@@ -1,0 +1,43 @@
+; Asterisk SMDI configuration
+
+[interfaces]
+; Specify serial ports to listen for SMDI messages on below. These will be
+; referenced later in zapata.conf. If you do not specify any interfaces then
+; SMDI will be disabled. Interfaces can have several different attributes
+; associated with them.
+
+; Set the number of stop bits to use per character here. The default is no,
+; in which case one stop bit will be used.
+
+;twostopbits = no
+
+; Character size or bit length is the size of each character sent accross the
+; link. Character size can be 7 or 8. The default is 7.
+
+;charsize = 7
+
+; If you need parity checking enabled you can turn it on here. Acceptable
+; values are even, odd, and none. The default is even.
+
+;paritybit = even
+
+; The baudrate to use for this port. Acceptable values are 1200, 2400, 4800,
+; and 9600. The default is 9600.
+
+;baudrate = 1200
+
+; Often the numbering scheme for a set of mailboxes or extensions will not be 7
+; or 10 digits (as SMDI requires). Use the msdstrip option to strip unused
+; digits from the start of numbers.
+
+;msdstrip = 0
+
+; Occasionally Asterisk and the SMDI switch may become out of sync. If this
+; happens, Asterisk will appear one or several calls behind as it processes
+; voicemail requests. To prevent this from hapening adjust the msgexpirytime.
+; This will make Asterisk discard old SMDI messages that have not yet been
+; processed. The default expiry time is 30000 milliseconds.
+
+;msgexpirytime = 30000
+
+;smdiport => /dev/ttyS0
Modified: trunk/configs/voicemail.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/voicemail.conf.sample?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/configs/voicemail.conf.sample (original)
+++ trunk/configs/voicemail.conf.sample Fri Feb 10 15:50:56 2006
@@ -49,12 +49,18 @@
silencethreshold=128
; Max number of failed login attempts
maxlogins=3
-; If you need to have an external program, i.e. /usr/bin/myapp called when a
-; voicemail is left, delivered, or your voicemailbox is checked, uncomment
-; this:
+
+; If you need to have an external program, i.e. /usr/bin/myapp
+; called when a voicemail is left, delivered, or your voicemailbox
+; is checked, uncomment this. It can also be set to 'smdi' to use
+; smdi for external notification. If it is 'smdi', smdiport should
+; be set to a valid port as specfied in smdi.conf.
+
;externnotify=/usr/bin/myapp
-; If you need to have an external program, i.e. /usr/bin/myapp called when a
-; voicemail password is changed, uncomment this:
+;smdiport=/dev/ttyS0
+
+; If you need to have an external program, i.e. /usr/bin/myapp
+; called when a voicemail password is changed, uncomment this:
;externpass=/usr/bin/myapp
; For the directory, you can override the intro file if you want
;directoryintro=dir-intro
Modified: trunk/configs/zapata.conf.sample
URL: http://svn.digium.com/view/asterisk/trunk/configs/zapata.conf.sample?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/configs/zapata.conf.sample (original)
+++ trunk/configs/zapata.conf.sample Fri Feb 10 15:50:56 2006
@@ -225,6 +225,7 @@
; v23 = v23 as used in the UK
; v23_jp = v23 as used in Japan
; dtmf = DTMF as used in Denmark, Sweden and Netherlands
+; smdi = Use SMDI for callerid. Requires SMDI to be enabled (usesmdi).
;
;cidsignalling=bell
;
@@ -379,6 +380,14 @@
; basis if you have (or may have) ADSI compatible CPE equipment
;
;adsi=yes
+;
+; SMDI (Simplified Message Desk Interface) can be enabled on a per-channel
+; basis if you would like that channel to behave like an SMDI message desk.
+; The SMDI port specfied should have already been defined in smdi.conf. The
+; default port is /dev/ttyS0.
+;
+;usesmdi=yes
+;smdiport=/dev/ttyS0
;
; On trunk interfaces (FXS) and E&M interfaces (E&M, Wink, Feature Group D
; etc, it can be useful to perform busy detection either in an effort to
Added: trunk/doc/smdi.txt
URL: http://svn.digium.com/view/asterisk/trunk/doc/smdi.txt?rev=9423&view=auto
==============================================================================
--- trunk/doc/smdi.txt (added)
+++ trunk/doc/smdi.txt Fri Feb 10 15:50:56 2006
@@ -1,0 +1,34 @@
+Asterisk SMDI (Simple Message Desk Interface) integration
+---------------------------------------------------------
+
+Support for using Asterisk as an SMDI message desk was developed by Matthew A.
+Nicholson <mnicholson at digium.com>. To enable SMDI support in asterisk edit the
+Makefile file and uncomment the line regarding SMDI so it reads like
+this:
+
+#
+# Asterisk SMDI integration
+#
+WITH_SMDI = 1
+
+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.
+
+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.
+
+[default]
+
+exten => _XXXXXXX,1,VoiceMail(${EXTEN}|${SMDI_VM_TYPE})
+exten => _XXXXXXX,n,Hangup
+
+exten => s,1,VoiceMailMain(${CALLERIDNUM})
+exten => s,n,Hangup
+
+The ${SMDI_VM_TYPE} variable will be set to u, b, or nothing depending on the
+contents of the type of SMDI message received.
+
Modified: trunk/include/asterisk/callerid.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/callerid.h?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/include/asterisk/callerid.h (original)
+++ trunk/include/asterisk/callerid.h Fri Feb 10 15:50:56 2006
@@ -42,6 +42,9 @@
#define CID_SIG_V23 2
#define CID_SIG_DTMF 3
#define CID_SIG_V23_JP 4
+#ifdef WITH_SMDI
+#define CID_SIG_SMDI 5
+#endif
#define CID_START_RING 1
#define CID_START_POLARITY 2
Added: trunk/include/asterisk/smdi.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/smdi.h?rev=9423&view=auto
==============================================================================
--- trunk/include/asterisk/smdi.h (added)
+++ trunk/include/asterisk/smdi.h Fri Feb 10 15:50:56 2006
@@ -1,0 +1,120 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * SMDI support for Asterisk.
+ *
+ * Copyright (C) 2005, Digium, Inc.
+ *
+ * Matthew A. Nicholson <mnicholson at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License.
+ */
+
+/*!
+ * \file
+ * \brief SMDI support for Asterisk.
+ * \author Matthew A. Nicholson <mnicholson at digium.com>
+ */
+
+
+/* C is simply a ego booster for those who want to do objects the hard way. */
+
+
+#ifndef AST_SMDI_H
+#define AST_SMDI_H
+
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/astobj.h"
+#include <termios.h>
+#include <time.h>
+
+#define SMDI_MESG_DESK_NUM_LEN 3
+#define SMDI_MESG_DESK_TERM_LEN 4
+#define SMDI_MWI_FAIL_CAUSE_LEN 3
+#define SMDI_MAX_STATION_NUM_LEN 10
+#define SMDI_MAX_FILENAME_LEN 256
+
+/*!
+ * \brief An SMDI message waiting indicator message.
+ *
+ * The ast_smdi_mwi_message structure contains the parsed out parts of an smdi
+ * message. Each ast_smdi_interface structure has a message queue consisting
+ * ast_smdi_mwi_message structures.
+ */
+struct ast_smdi_mwi_message {
+ ASTOBJ_COMPONENTS(struct ast_smdi_mwi_message);
+ char fwd_st[SMDI_MAX_STATION_NUM_LEN + 1]; /* forwarding station number */
+ char cause[SMDI_MWI_FAIL_CAUSE_LEN + 1]; /* the type of failure */
+ struct timeval timestamp; /* a timestamp for the message */
+};
+
+/*!
+ * \brief An SMDI message desk message.
+ *
+ * The ast_smdi_md_message structure contains the parsed out parts of an smdi
+ * message. Each ast_smdi_interface structure has a message queue consisting
+ * ast_smdi_md_message structures.
+ */
+struct ast_smdi_md_message {
+ ASTOBJ_COMPONENTS(struct ast_smdi_md_message);
+ char mesg_desk_num[SMDI_MESG_DESK_NUM_LEN + 1]; /* message desk number */
+ char mesg_desk_term[SMDI_MESG_DESK_TERM_LEN + 1]; /* message desk terminal */
+ char fwd_st[SMDI_MAX_STATION_NUM_LEN + 1]; /* forwarding station number */
+ char calling_st[SMDI_MAX_STATION_NUM_LEN + 1]; /* calling station number */
+ char type; /* the type of the call */
+ struct timeval timestamp; /* a timestamp for the message */
+};
+
+/*! \brief SMDI message desk message queue. */
+struct ast_smdi_md_queue {
+ ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_md_message);
+};
+
+/*! \brief SMDI message waiting indicator message queue. */
+struct ast_smdi_mwi_queue {
+ ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_mwi_message);
+};
+
+/*!
+ * \brief SMDI interface structure.
+ *
+ * The ast_smdi_interface structure holds information on a serial port that
+ * should be monitored for SMDI activity. The structure contains a message
+ * queue of messages that have been recieved on the interface.
+ */
+struct ast_smdi_interface {
+ ASTOBJ_COMPONENTS_FULL(struct ast_smdi_interface, SMDI_MAX_FILENAME_LEN, 1);
+ struct ast_smdi_md_queue md_q;
+ struct ast_smdi_mwi_queue mwi_q;
+ FILE *file;
+ int fd;
+ pthread_t thread;
+ struct termios mode;
+ int msdstrip;
+ long msg_expiry;
+};
+
+
+/* MD message queue functions */
+extern struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface);
+extern struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout);
+extern void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg);
+
+/* MWI message queue functions */
+extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface);
+extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout);
+extern void ast_smdi_mwi_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg);
+
+extern struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name);
+
+/* MWI functions */
+extern int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox);
+extern int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox);
+
+extern void ast_smdi_md_message_destroy(struct ast_smdi_md_message *msg);
+extern void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg);
+
+extern void ast_smdi_interface_destroy(struct ast_smdi_interface *iface);
+#endif
Modified: trunk/res/Makefile
URL: http://svn.digium.com/view/asterisk/trunk/res/Makefile?rev=9423&r1=9422&r2=9423&view=diff
==============================================================================
--- trunk/res/Makefile (original)
+++ trunk/res/Makefile Fri Feb 10 15:50:56 2006
@@ -64,6 +64,13 @@
CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC
endif
+#
+# Asterisk SMDI integration
+#
+ifeq (${WITH_SMDI},1)
+MODS+=res_smdi.so
+endif
+
all: depend $(MODS)
install: all
Added: trunk/res/res_smdi.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_smdi.c?rev=9423&view=auto
==============================================================================
--- trunk/res/res_smdi.c (added)
+++ trunk/res/res_smdi.c Fri Feb 10 15:50:56 2006
@@ -1,0 +1,794 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * SMDI support for Asterisk.
+ *
+ * Copyright (C) 2005, Digium, Inc.
+ *
+ * Matthew A. Nicholson <mnicholson at digium.com>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <sys/time.h>
+#include <time.h>
+#include <ctype.h>
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/utils.h"
+#include "asterisk/smdi.h"
+#include "asterisk/config.h"
+#include "asterisk/astobj.h"
+#include "asterisk/io.h"
+#include "asterisk/logger.h"
+#include "asterisk/utils.h"
+#include "asterisk/options.h"
+
+/*!
+ * \file
+ * \brief SMDI support for Asterisk.
+ * \author Matthew A. Nicholson <mnicholson at digium.com>
+ */
+
+/* Message expiry time in milliseconds */
+#define SMDI_MSG_EXPIRY_TIME 30000 /* 30 seconds */
+
+static const char tdesc[] = "Asterisk Simplified Message Desk Interface (SMDI) Module";
+static const char config_file[] = "smdi.conf";
+
+static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg);
+static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg);
+
+static void *smdi_read(void *iface_p);
+static int smdi_load(int reload);
+
+/* Use count stuff */
+
+AST_MUTEX_DEFINE_STATIC(localuser_lock);
+static int localusecnt = 0;
+
+/*! \brief SMDI interface container. */
+struct ast_smdi_interface_container {
+ ASTOBJ_CONTAINER_COMPONENTS(struct ast_smdi_interface);
+} smdi_ifaces;
+
+/*!
+ * \internal
+ * \brief Push an SMDI message to the back of an interface's message queue.
+ * \param iface a pointer to the interface to use.
+ * \param md_msg a pointer to the message to use.
+ */
+static void ast_smdi_md_message_push(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
+{
+ ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
+}
+
+/*!
+ * \internal
+ * \brief Push an SMDI message to the back of an interface's message queue.
+ * \param iface a pointer to the interface to use.
+ * \param mwi_msg a pointer to the message to use.
+ */
+static void ast_smdi_mwi_message_push(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
+{
+ ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
+}
+
+/*!
+ * \brief Set the MWI indicator for a mailbox.
+ * \param iface the interface to use.
+ * \param mailbox the mailbox to use.
+ */
+extern int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
+{
+ FILE *file;
+ int i;
+
+ file = fopen(iface->name, "w");
+ if(!file) {
+ ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
+ return 1;
+ }
+
+ ASTOBJ_WRLOCK(iface);
+
+ fprintf(file, "OP:MWI ");
+
+ for(i = 0; i < iface->msdstrip; i++)
+ fprintf(file, "0");
+
+ fprintf(file, "%s!\x04", mailbox);
+ fclose(file);
+
+ ASTOBJ_UNLOCK(iface);
+ ast_log(LOG_DEBUG, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
+ return 0;
+}
+
+/*!
+ * \brief Unset the MWI indicator for a mailbox.
+ * \param iface the interface to use.
+ * \param mailbox the mailbox to use.
+ */
+extern int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
+{
+ FILE *file;
+ int i;
+
+ file = fopen(iface->name, "w");
+ if(!file) {
+ ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
+ return 1;
+ }
+
+ ASTOBJ_WRLOCK(iface);
+
+ fprintf(file, "RMV:MWI ");
+
+ for(i = 0; i < iface->msdstrip; i++)
+ fprintf(file, "0");
+
+ fprintf(file, "%s!\x04", mailbox);
+ fclose(file);
+
+ ASTOBJ_UNLOCK(iface);
+ ast_log(LOG_DEBUG, "Sent MWI unset message for %s on %s", mailbox, iface->name);
+ return 0;
+}
+
+/*!
+ * \brief Put an SMDI message back in the front of the queue.
+ * \param iface a pointer to the interface to use.
+ * \param msg a pointer to the message to use.
+ *
+ * This function puts a message back in the front of the specified queue. It
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+extern void ast_smdi_md_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
+{
+ ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
+}
+
+/*!
+ * \brief Put an SMDI message back in the front of the queue.
+ * \param iface a pointer to the interface to use.
+ * \param msg a pointer to the message to use.
+ *
+ * This function puts a message back in the front of the specified queue. It
+ * should be used if a message was popped but is not going to be processed for
+ * some reason, and the message needs to be returned to the queue.
+ */
+extern void ast_smdi_mwi_message_putback(struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
+{
+ ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
+}
+
+/*!
+ * \brief Get the next SMDI message from the queue.
+ * \param iface a pointer to the interface to use.
+ *
+ * This function pulls the first unexpired message from the SMDI message queue
+ * on the specified interface. It will purge all expired SMDI messages before
+ * returning.
+ *
+ * \return the next SMDI message, or NULL if there were no pending messages.
+ */
+extern struct ast_smdi_md_message *ast_smdi_md_message_pop(struct ast_smdi_interface *iface)
+{
+ struct ast_smdi_md_message *md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
+ struct timeval now;
+ long elapsed = 0;
+
+ /* purge old messages */
+ gettimeofday(&now, NULL);
+ while(md_msg)
+ {
+ /* calculate the elapsed time since this message was recieved ( in milliseconds) */
+ elapsed = (now.tv_sec - md_msg->timestamp.tv_sec) * 1000;
+ elapsed += (now.tv_usec - md_msg->timestamp.tv_usec) / 1000;
+
+ if(elapsed > iface->msg_expiry)
+ { /* found an expired message */
+ ASTOBJ_UNREF(md_msg,ast_smdi_md_message_destroy);
+ ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MD message queue. Message was %ld milliseconds too old.", iface->name, elapsed - iface->msg_expiry);
+ md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
+ }
+ else /* good message, return it */
+ {
+ break;
+ }
+ }
+
+ return md_msg;
+}
+
+/*!
+ * \brief Get the next SMDI message from the queue.
+ * \param iface a pointer to the interface to use.
+ * \param timeout the time to wait before returning in milliseconds.
+ *
+ * This function pulls a message from the SMDI message queue on the specified
+ * interface. If no message is available this function will wait the specified
+ * amount of time before returning.
+ *
+ * \return the next SMDI message, or NULL if there were no pending messages and
+ * the timeout has expired.
+ */
+extern struct ast_smdi_md_message *ast_smdi_md_message_wait(struct ast_smdi_interface *iface, int timeout)
+{
+ struct timeval start, end;
+ long diff = 0;
+ struct ast_smdi_md_message *msg;
+
+ gettimeofday(&start, NULL);
+ while(diff < timeout) {
+
+ if((msg = ast_smdi_md_message_pop(iface)))
+ return msg;
+
+ /* check timeout */
+ gettimeofday(&end, NULL);
+ diff = (end.tv_sec - start.tv_sec) * 1000;
+ diff += (end.tv_usec - start.tv_usec) / 1000;
+ }
+ return (ast_smdi_md_message_pop(iface));
+}
+
+/*!
+ * \brief Get the next SMDI message from the queue.
+ * \param iface a pointer to the interface to use.
+ *
+ * This function pulls the first unexpired message from the SMDI message queue
+ * on the specified interface. It will purge all expired SMDI messages before
+ * returning.
+ *
+ * \return the next SMDI message, or NULL if there were no pending messages.
+ */
+extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_pop(struct ast_smdi_interface *iface)
+{
+ struct ast_smdi_mwi_message *mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
+ struct timeval now;
+ long elapsed = 0;
+
+ /* purge old messages */
+ gettimeofday(&now, NULL);
+ while(mwi_msg)
+ {
+ /* calculate the elapsed time since this message was recieved ( in milliseconds) */
+ elapsed = (now.tv_sec - mwi_msg->timestamp.tv_sec) * 1000;
+ elapsed += (now.tv_usec - mwi_msg->timestamp.tv_usec) / 1000;
+
+ if(elapsed > iface->msg_expiry)
+ { /* found an expired message */
+ ASTOBJ_UNREF(mwi_msg,ast_smdi_mwi_message_destroy);
+ ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MWI message queue. Message was %ld milliseconds too old.", iface->name, elapsed - iface->msg_expiry);
+ mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
+ }
+ else /* good message, return it */
+ {
+ break;
+ }
+ }
+
+ return mwi_msg;
+ return (ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q));
+}
+
+/*!
+ * \brief Get the next SMDI message from the queue.
+ * \param iface a pointer to the interface to use.
+ * \param timeout the time to wait before returning in milliseconds.
+ *
+ * This function pulls a message from the SMDI message queue on the specified
+ * interface. If no message is available this function will wait the specified
+ * amount of time before returning.
+ *
+ * \return the next SMDI message, or NULL if there were no pending messages and
+ * the timeout has expired.
+ */
+extern struct ast_smdi_mwi_message *ast_smdi_mwi_message_wait(struct ast_smdi_interface *iface, int timeout)
+{
+ struct timeval start, end;
+ long diff = 0;
+ struct ast_smdi_mwi_message *msg;
+
+ gettimeofday(&start, NULL);
+ while(diff < timeout) {
+
+ if((msg = ast_smdi_mwi_message_pop(iface)))
+ return msg;
+
+ /* check timeout */
+ gettimeofday(&end, NULL);
+ diff = (end.tv_sec - start.tv_sec) * 1000;
+ diff += (end.tv_usec - start.tv_usec) / 1000;
+ }
+ return (ast_smdi_mwi_message_pop(iface));
+}
+
+/*!
+ * \brief Find an SMDI interface with the specified name.
+ * \param iface_name the name/port of the interface to search for.
+ *
+ * \return a pointer to the interface located or NULL if none was found. This
+ * actually returns an ASTOBJ reference and should be released using
+ * #ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).
+ */
+extern struct ast_smdi_interface *ast_smdi_interface_find(const char *iface_name)
+{
+ return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces,iface_name));
+}
+
+/*! \brief Read an SMDI message.
+ *
+ * \param iface the SMDI interface to read from.
+ *
+ * This function loops and reads from and SMDI interface. It must be stopped
+ * using pthread_cancel().
+ */
+static void *smdi_read(void *iface_p)
+{
+ struct ast_smdi_interface *iface = iface_p;
+ struct ast_smdi_md_message *md_msg;
+ struct ast_smdi_mwi_message *mwi_msg;
+ char c = '\0';
+ char *cp = NULL;
+ int i;
+ int start = 0;
+
+ /* read an smdi message */
+ while((c = fgetc(iface->file))) {
+
+ /* check if this is the start of a message */
+ if(!start)
+ {
+ if(c == 'M')
+ start = 1;
+ }
+ else /* Determine if this is a MD or MWI message */
+ {
+ if(c == 'D') { /* MD message */
+ start = 0;
+
+ md_msg = malloc(sizeof(struct ast_smdi_md_message));
+ if(!md_msg) {
+ ast_log(LOG_ERROR, "Error allocating memory for ast_smdi_md_message. Stopping listner thread.\n");
+ ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
+ return NULL;
+ }
+ memset(md_msg, 0, sizeof(struct ast_smdi_md_message));
+
+ ASTOBJ_INIT(md_msg);
+
+ /* read the message desk number */
+ for(i = 0; i < SMDI_MESG_DESK_NUM_LEN; i++) {
+ md_msg->mesg_desk_num[i] = fgetc(iface->file);
+ }
+ md_msg->mesg_desk_num[SMDI_MESG_DESK_NUM_LEN] = '\0';
+
+ /* read the message desk terminal number */
+ for(i = 0; i < SMDI_MESG_DESK_TERM_LEN; i++) {
+ md_msg->mesg_desk_term[i] = fgetc(iface->file);
+ }
+ md_msg->mesg_desk_term[SMDI_MESG_DESK_TERM_LEN] = '\0';
+
+ /* read the message type */
+ md_msg->type = fgetc(iface->file);
+
+ /* read the forwarding station number (may be blank) */
+ cp = &md_msg->fwd_st[0];
+ for(i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
+ if((c = fgetc(iface->file)) == ' ') {
+ *cp = '\0';
+ break;
+ }
+
+ /* store c in md_msg->fwd_st */
+ if( i >= iface->msdstrip) {
+ *cp = c;
+ cp++;
+ }
+ }
+ /* make sure the value is null terminated, even if this truncates it */
+ md_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
+ cp = NULL;
+
+ /* read the calling station number (may be blank) */
+ cp = &md_msg->calling_st[0];
+ for(i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
+ if(!isdigit( (c = fgetc(iface->file)) )) {
+ *cp = '\0';
+ break;
+ }
+
+ /* store c in md_msg->calling_st */
+ if( i >= iface->msdstrip) {
+ *cp = c;
+ cp++;
+ }
+ }
+ /* make sure the value is null terminated, even if this truncates it */
+ md_msg->calling_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
+ cp = NULL;
+
+ /* add the message to the message queue */
+ gettimeofday(&md_msg->timestamp, NULL);
+ ast_smdi_md_message_push(iface, md_msg);
+ ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name);
+
+ ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
+
+ } else if(c == 'W') { /* MWI message */
+ start = 0;
+
+ mwi_msg = malloc(sizeof(struct ast_smdi_mwi_message));
+ if(!mwi_msg) {
+ ast_log(LOG_ERROR, "Error allocating memory for ast_smdi_mwi_message. Stopping listner thread.\n");
+ ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
+ return NULL;
+ }
+ memset(mwi_msg, 0, sizeof(struct ast_smdi_mwi_message));
+
+ ASTOBJ_INIT(mwi_msg);
+
+ /* discard the 'I' (from 'MWI') */
+ fgetc(iface->file);
+
+ /* read the forwarding station number (may be blank) */
+ cp = &mwi_msg->fwd_st[0];
+ for(i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
+ if((c = fgetc(iface->file)) == ' ') {
+ *cp = '\0';
+ break;
+ }
+
+ /* store c in md_msg->fwd_st */
+ if( i >= iface->msdstrip) {
+ *cp = c;
+ cp++;
+ }
+ }
+ /* make sure the station number is null terminated, even if this will truncate it */
+ mwi_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
+ cp = NULL;
+
+ /* read the mwi failure cause */
+ for(i = 0; i < SMDI_MWI_FAIL_CAUSE_LEN; i++) {
+ mwi_msg->cause[i] = fgetc(iface->file);
+ }
+ mwi_msg->cause[SMDI_MWI_FAIL_CAUSE_LEN] = '\0';
+
+ /* add the message to the message queue */
+ gettimeofday(&mwi_msg->timestamp, NULL);
+ ast_smdi_mwi_message_push(iface, mwi_msg);
+ ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name);
+
+ ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
+ } else {
+ ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c);
+ start = 0;
+ }
+ }
+ }
+
+ ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
+ ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
+ return NULL;
+}
+
+/*! \brief ast_smdi_md_message destructor. */
+void ast_smdi_md_message_destroy(struct ast_smdi_md_message *msg)
+{
+ free(msg);
+}
+
+/*! \brief ast_smdi_mwi_message destructor. */
+void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg)
+{
+ free(msg);
+}
+
+/*! \brief ast_smdi_interface destructor. */
+void ast_smdi_interface_destroy(struct ast_smdi_interface *iface)
+{
+ if(iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
+ pthread_cancel(iface->thread);
+ pthread_join(iface->thread, NULL);
+ }
+
+ iface->thread = AST_PTHREADT_STOP;
+
+ if(iface->file)
+ fclose(iface->file);
+
+ ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
+ ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
+ ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
+ ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
+ free(iface);
+
+ ast_mutex_lock(&localuser_lock);
+ localusecnt--;
+ ast_mutex_unlock(&localuser_lock);
+ ast_update_use_count();
+}
+
+/*!
+ * \internal
+ * \brief Load and reload SMDI configuration.
+ * \param reload this should be 1 if we are reloading and 0 if not.
+ *
+ * This function loads/reloads the SMDI configuration and starts and stops
+ * interfaces accordingly.
+ *
+ * \return zero on success, -1 on failure, and 1 if no smdi interfaces were started.
+ */
+static int smdi_load(int reload)
+{
+ struct ast_config *conf;
+ struct ast_variable *v;
+ struct ast_smdi_interface *iface = NULL;
+ int res = 0;
+
+ /* Config options */
+ speed_t baud_rate = B9600; /* 9600 baud rate */
+ tcflag_t paritybit = PARENB; /* even parity checking */
+ tcflag_t charsize = CS7; /* seven bit characters */
[... 253 lines stripped ...]
More information about the asterisk-commits
mailing list