- use the standard option parsing routines;

- document existing but undocumented parameters to send a message
  (untested but unchanged;

- ad a new option p(N) to set the initial message delay to N ms
  so this can be adapted from the dialplan to various countries;
 



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48825 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Luigi Rizzo
2006-12-21 22:03:54 +00:00
parent 8e9cdb10fd
commit 99359a4b27

View File

@@ -59,6 +59,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/alaw.h" #include "asterisk/alaw.h"
#include "asterisk/callerid.h" #include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
/* #define OUTALAW */ /* enable this to output Alaw rather than linear */ /* #define OUTALAW */ /* enable this to output Alaw rather than linear */
@@ -79,7 +81,8 @@ static char *app = "SMS";
static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones"; static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
static char *descrip = static char *descrip =
" SMS(name|[a][s][t]): SMS handles exchange of SMS data with a call to/from SMS capable\n" " SMS(name|[a][s][t][p(d)][r][o]|addr|body):\n"
"SMS handles exchange of SMS data with a call to/from SMS capable\n"
"phone or SMS PSTN service center. Can send and/or receive SMS messages.\n" "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
"Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n" "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
"and Telecom Italia in Italy.\n" "and Telecom Italia in Italy.\n"
@@ -91,6 +94,10 @@ static char *descrip =
" a: answer, i.e. send initial FSK packet.\n" " a: answer, i.e. send initial FSK packet.\n"
" s: act as service centre talking to a phone.\n" " s: act as service centre talking to a phone.\n"
" t: use protocol 2 (default used is protocol 1).\n" " t: use protocol 2 (default used is protocol 1).\n"
" p(N): set the initial delay to N ms (default is 300).\n"
"addr and body are a deprecated format to send messages out.\n"
" s: set the Status Report Request (SRR) bit.\n"
" o: the body should be coded as octets not 7-bit symbols.\n"
"Messages are processed as per text file message queues.\n" "Messages are processed as per text file message queues.\n"
"smsq (a separate software) is a command to generate message\n" "smsq (a separate software) is a command to generate message\n"
"queues and send messages.\n" "queues and send messages.\n"
@@ -200,7 +207,7 @@ typedef struct sms_s {
time_t scts; /*!< time stamp, UTC */ time_t scts; /*!< time stamp, UTC */
unsigned char pid; /*!< protocol ID */ unsigned char pid; /*!< protocol ID */
unsigned char dcs; /*!< data coding scheme */ unsigned char dcs; /*!< data coding scheme */
short mr; /*!< message reference - actually a byte, but usde -1 for not set */ short mr; /*!< message reference - actually a byte, but use -1 for not set */
int udl; /*!< user data length */ int udl; /*!< user data length */
int udhl; /*!< user data header length */ int udhl; /*!< user data header length */
unsigned char srr:1; /*!< Status Report request */ unsigned char srr:1; /*!< Status Report request */
@@ -242,6 +249,7 @@ typedef struct sms_s {
unsigned char ibitt; /*!< total of 1's in last 3 bytes */ unsigned char ibitt; /*!< total of 1's in last 3 bytes */
/* more to go here */ /* more to go here */
int opause_0; /*!< initial delay in ms, p() option */
int protocol; /*!< ETSI SMS protocol to use (passed at app call) */ int protocol; /*!< ETSI SMS protocol to use (passed at app call) */
int oseizure; /*!< protocol 2: channel seizure bits to send */ int oseizure; /*!< protocol 2: channel seizure bits to send */
int framenumber; /*!< protocol 2: frame number (for sending ACK0 or ACK1) */ int framenumber; /*!< protocol 2: frame number (for sending ACK0 or ACK1) */
@@ -1444,7 +1452,7 @@ static void sms_messagetx(sms_t * h)
* could time out. XXX make it configurable. * could time out. XXX make it configurable.
*/ */
if (h->omsg[0] == 0x93) if (h->omsg[0] == 0x93)
h->opause = 200; /* XXX initial message delay 300ms (for BT) */ h->opause = 8 * h->opause_0; /* initial message delay */
h->obytep = 0; h->obytep = 0;
h->obitp = 0; h->obitp = 0;
if (h->protocol == 2) { if (h->protocol == 2) {
@@ -1692,21 +1700,68 @@ static void sms_process(sms_t * h, int samples, signed short *data)
} }
} }
/*
* Standard argument parsing:
* - one enum for the flags we recognise,
* - one enum for argument indexes
* - AST_APP_OPTIONS() to drive the parsing routine
* - in the function, AST_DECLARE_APP_ARGS(...) for the arguments.
*/
enum {
OPTION_BE_SMSC = (1 << 0), /* act as sms center */
OPTION_ANSWER = (1 << 1), /* answer on incoming calls */
OPTION_TWO = (1 << 2), /* Use Protocol Two */
OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */
OPTION_SRR = (1 << 4), /* set srr */
OPTION_DCS = (1 << 5), /* set dcs */
} sms_flags;
enum {
OPTION_ARG_PAUSE = 0,
OPTION_ARG_ARRAY_SIZE
} sms_opt_args;
AST_APP_OPTIONS(sms_options, {
AST_APP_OPTION('s', OPTION_BE_SMSC),
AST_APP_OPTION('a', OPTION_ANSWER),
AST_APP_OPTION('t', OPTION_TWO),
AST_APP_OPTION('r', OPTION_SRR),
AST_APP_OPTION('o', OPTION_DCS),
AST_APP_OPTION_ARG('p', OPTION_PAUSE, OPTION_ARG_PAUSE),
} );
static int sms_exec (struct ast_channel *chan, void *data) static int sms_exec (struct ast_channel *chan, void *data)
{ {
int res = -1; int res = -1;
struct ast_module_user *u; struct ast_module_user *u;
struct ast_frame *f;
sms_t h = { 0 }; sms_t h = { 0 };
unsigned char *p; /* argument parsing support */
unsigned char *d = data; struct ast_flags sms_flags;
int answer = 0; char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE];
char *p;
AST_DECLARE_APP_ARGS(sms_args,
AST_APP_ARG(queue);
AST_APP_ARG(options);
AST_APP_ARG(addr);
AST_APP_ARG(body);
);
if (!data) { if (!data) {
ast_log (LOG_ERROR, "Requires queue name at least\n"); ast_log (LOG_ERROR, "Requires queue name at least\n");
return -1; return -1;
} }
parse = ast_strdupa(data); /* create a local copy */
AST_STANDARD_APP_ARGS(sms_args, parse);
if (sms_args.argc > 1)
ast_app_parse_options(sms_options, &sms_flags, sms_opts, sms_args.options);
ast_verbose("sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n",
sms_args.argc, S_OR(sms_args.queue, ""),
S_OR(sms_args.options, ""),
S_OR(sms_args.addr, ""),
S_OR(sms_args.body, "") );
u = ast_module_user_add(chan); u = ast_module_user_add(chan);
h.ipc0 = h.ipc1 = 20; /* phase for cosine */ h.ipc0 = h.ipc1 = 20; /* phase for cosine */
h.dcs = 0xF1; /* default */ h.dcs = 0xF1; /* default */
@@ -1714,43 +1769,35 @@ static int sms_exec (struct ast_channel *chan, void *data)
if (chan->cid.cid_num) if (chan->cid.cid_num)
ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli)); ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
if (!*d || *d == '|') { if (ast_strlen_zero(sms_args.queue)) {
ast_log (LOG_ERROR, "Requires queue name\n"); ast_log (LOG_ERROR, "Requires queue name\n");
ast_module_user_remove(u); goto done;
return -1;
} }
for (p = d; *p && *p != '|'; p++); if (strlen(sms_args.queue) >= sizeof(h.queue)) {
if (p - d >= sizeof (h.queue)) {
ast_log (LOG_ERROR, "Queue name too long\n"); ast_log (LOG_ERROR, "Queue name too long\n");
ast_module_user_remove(u); goto done;
return -1;
} }
strncpy(h.queue, (char *)d, p - d); ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue));
if (*p == '|')
p++; for (p = h.queue; *p; p++)
d = p;
for (p = (unsigned char *)h.queue; *p; p++)
if (!isalnum (*p)) if (!isalnum (*p))
*p = '-'; /* make very safe for filenames */ *p = '-'; /* make very safe for filenames */
while (*d && *d != '|') { h.smsc = ast_test_flag(&sms_flags, OPTION_BE_SMSC);
switch (*d) { h.protocol = ast_test_flag(&sms_flags, OPTION_TWO) ? 2 : 1;
case 'a': /* we have to send the initial FSK sequence */ if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE]))
answer = 1; h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]);
break; if (h.opause_0 < 25 || h.opause_0 > 2000)
case 's': /* we are acting as a service centre talking to a phone */ h.opause_0 = 300; /* default 300ms */
h.smsc = 1; ast_verbose("initial delay %dms\n", h.opause_0);
break;
case 't': /* use protocol 2 ([t]wo)! couldn't use numbers *!* */
h.protocol = 2; /* the following apply if there is an arg3/4 and apply to the created message file */
break; if (ast_test_flag(&sms_flags, OPTION_SRR))
/* the following apply if there is an arg3/4 and apply to the created message file */ h.srr = 1;
case 'r': if (ast_test_flag(&sms_flags, OPTION_DCS))
h.srr = 1; h.dcs = 1;
break; #if 0
case 'o':
h.dcs |= 4; /* octets */
break;
case '1': case '1':
case '2': case '2':
case '3': case '3':
@@ -1761,45 +1808,51 @@ static int sms_exec (struct ast_channel *chan, void *data)
h.pid = 0x40 + (*d & 0xF); h.pid = 0x40 + (*d & 0xF);
break; break;
} }
d++; #endif
} if (sms_args.argc > 2) {
if (*d == '|') { unsigned char *up;
/* submitting a message, not taking call. */ /* submitting a message, not taking call. */
/* deprecated, use smsq instead */ /* deprecated, use smsq instead */
d++;
h.scts = time (0); h.scts = time (0);
for (p = d; *p && *p != '|'; p++); if (ast_strlen_zero(sms_args.addr) || strlen (sms_args.addr) >= sizeof (h.oa)) {
if (*p) ast_log (LOG_ERROR, "Address too long %s\n", sms_args.addr);
*p++ = 0; goto done;
if (strlen ((char *)d) >= sizeof (h.oa)) {
ast_log (LOG_ERROR, "Address too long %s\n", d);
return 0;
} }
if (h.smsc) { if (h.smsc)
ast_copy_string (h.oa, (char *)d, sizeof (h.oa)); ast_copy_string (h.oa, sms_args.addr, sizeof (h.oa));
} else { else {
ast_copy_string (h.da, (char *)d, sizeof (h.da)); ast_copy_string (h.da, sms_args.addr, sizeof (h.da));
}
if (!h.smsc)
ast_copy_string (h.oa, h.cli, sizeof (h.oa)); ast_copy_string (h.oa, h.cli, sizeof (h.oa));
d = p; }
h.udl = 0; h.udl = 0;
while (*p && h.udl < SMSLEN) if (ast_strlen_zero(sms_args.body)) {
h.ud[h.udl++] = utf8decode(&p); ast_log (LOG_ERROR, "Missing body for %s\n", sms_args.addr);
if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0) goto done;
}
up = (unsigned char *)sms_args.body;
while (*up && h.udl < SMSLEN)
h.ud[h.udl++] = utf8decode(&up);
if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0) {
ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n"); ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0) goto done;
}
if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0) {
ast_log (LOG_WARNING, "Invalid 8 bit data\n"); ast_log (LOG_WARNING, "Invalid 8 bit data\n");
if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0) goto done;
}
if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0) {
ast_log (LOG_WARNING, "Invalid 16 bit data\n"); ast_log (LOG_WARNING, "Invalid 16 bit data\n");
goto done;
}
h.rx = 0; /* sent message */ h.rx = 0; /* sent message */
h.mr = -1; h.mr = -1;
sms_writefile (&h); sms_writefile (&h);
ast_module_user_remove(u); res = h.err;
return 0; goto done;
} }
if (answer) { if (ast_test_flag(&sms_flags, OPTION_ANSWER)) {
h.framenumber = 1; /* Proto 2 */ h.framenumber = 1; /* Proto 2 */
/* set up SMS_EST initial message */ /* set up SMS_EST initial message */
if (h.protocol == 2) { if (h.protocol == 2) {
@@ -1820,18 +1873,17 @@ static int sms_exec (struct ast_channel *chan, void *data)
res = ast_set_read_format (chan, AST_FORMAT_SLINEAR); res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
if (res < 0) { if (res < 0) {
ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n"); ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
ast_module_user_remove(u); goto done;
return -1;
} }
if (ast_activate_generator (chan, &smsgen, &h) < 0) { if ( (res = ast_activate_generator (chan, &smsgen, &h)) < 0) {
ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name); ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
ast_module_user_remove(u); goto done;
return -1;
} }
/* Do our thing here */ /* Do our thing here */
for (;;) { for (;;) {
struct ast_frame *f;
int i = ast_waitfor(chan, -1); int i = ast_waitfor(chan, -1);
if (i < 0) { if (i < 0) {
ast_log(LOG_NOTICE, "waitfor failed\n"); ast_log(LOG_NOTICE, "waitfor failed\n");
@@ -1852,11 +1904,12 @@ static int sms_exec (struct ast_channel *chan, void *data)
ast_frfree (f); ast_frfree (f);
} }
res = h.err; /* XXX */
sms_log (&h, '?'); /* log incomplete message */ sms_log (&h, '?'); /* log incomplete message */
done:
ast_module_user_remove(u); ast_module_user_remove(u);
return (h.err); return (res);
} }
static int unload_module(void) static int unload_module(void)