From 99359a4b27b77060dea90e46978c8218c2ca0885 Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Thu, 21 Dec 2006 22:03:54 +0000 Subject: - 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 --- apps/app_sms.c | 193 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 70 deletions(-) (limited to 'apps/app_sms.c') diff --git a/apps/app_sms.c b/apps/app_sms.c index 44b7c52bb..c45508d5d 100644 --- a/apps/app_sms.c +++ b/apps/app_sms.c @@ -59,6 +59,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/alaw.h" #include "asterisk/callerid.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" /* #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 *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" "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n" "and Telecom Italia in Italy.\n" @@ -91,6 +94,10 @@ static char *descrip = " a: answer, i.e. send initial FSK packet.\n" " s: act as service centre talking to a phone.\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" "smsq (a separate software) is a command to generate message\n" "queues and send messages.\n" @@ -200,7 +207,7 @@ typedef struct sms_s { time_t scts; /*!< time stamp, UTC */ unsigned char pid; /*!< protocol ID */ 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 udhl; /*!< user data header length */ 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 */ /* 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 oseizure; /*!< protocol 2: channel seizure bits to send */ 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. */ 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->obitp = 0; 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) { int res = -1; struct ast_module_user *u; - struct ast_frame *f; sms_t h = { 0 }; - unsigned char *p; - unsigned char *d = data; - int answer = 0; - + /* argument parsing support */ + struct ast_flags sms_flags; + 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) { ast_log (LOG_ERROR, "Requires queue name at least\n"); 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); h.ipc0 = h.ipc1 = 20; /* phase for cosine */ h.dcs = 0xF1; /* default */ @@ -1714,43 +1769,35 @@ static int sms_exec (struct ast_channel *chan, void *data) if (chan->cid.cid_num) 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_module_user_remove(u); - return -1; + goto done; } - for (p = d; *p && *p != '|'; p++); - if (p - d >= sizeof (h.queue)) { + if (strlen(sms_args.queue) >= sizeof(h.queue)) { ast_log (LOG_ERROR, "Queue name too long\n"); - ast_module_user_remove(u); - return -1; + goto done; } - strncpy(h.queue, (char *)d, p - d); - if (*p == '|') - p++; - d = p; - for (p = (unsigned char *)h.queue; *p; p++) + ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue)); + + for (p = h.queue; *p; p++) if (!isalnum (*p)) *p = '-'; /* make very safe for filenames */ - while (*d && *d != '|') { - switch (*d) { - case 'a': /* we have to send the initial FSK sequence */ - answer = 1; - break; - case 's': /* we are acting as a service centre talking to a phone */ - h.smsc = 1; - break; - case 't': /* use protocol 2 ([t]wo)! couldn't use numbers *!* */ - h.protocol = 2; - break; - /* the following apply if there is an arg3/4 and apply to the created message file */ - case 'r': - h.srr = 1; - break; - case 'o': - h.dcs |= 4; /* octets */ - break; + h.smsc = ast_test_flag(&sms_flags, OPTION_BE_SMSC); + h.protocol = ast_test_flag(&sms_flags, OPTION_TWO) ? 2 : 1; + if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) + h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]); + if (h.opause_0 < 25 || h.opause_0 > 2000) + h.opause_0 = 300; /* default 300ms */ + ast_verbose("initial delay %dms\n", h.opause_0); + + + /* the following apply if there is an arg3/4 and apply to the created message file */ + if (ast_test_flag(&sms_flags, OPTION_SRR)) + h.srr = 1; + if (ast_test_flag(&sms_flags, OPTION_DCS)) + h.dcs = 1; +#if 0 case '1': case '2': case '3': @@ -1761,45 +1808,51 @@ static int sms_exec (struct ast_channel *chan, void *data) h.pid = 0x40 + (*d & 0xF); break; } - d++; - } - if (*d == '|') { +#endif + if (sms_args.argc > 2) { + unsigned char *up; + /* submitting a message, not taking call. */ /* deprecated, use smsq instead */ - d++; h.scts = time (0); - for (p = d; *p && *p != '|'; p++); - if (*p) - *p++ = 0; - if (strlen ((char *)d) >= sizeof (h.oa)) { - ast_log (LOG_ERROR, "Address too long %s\n", d); - return 0; + if (ast_strlen_zero(sms_args.addr) || strlen (sms_args.addr) >= sizeof (h.oa)) { + ast_log (LOG_ERROR, "Address too long %s\n", sms_args.addr); + goto done; } - if (h.smsc) { - ast_copy_string (h.oa, (char *)d, sizeof (h.oa)); - } else { - ast_copy_string (h.da, (char *)d, sizeof (h.da)); - } - if (!h.smsc) + if (h.smsc) + ast_copy_string (h.oa, sms_args.addr, sizeof (h.oa)); + else { + ast_copy_string (h.da, sms_args.addr, sizeof (h.da)); ast_copy_string (h.oa, h.cli, sizeof (h.oa)); - d = p; + } h.udl = 0; - while (*p && h.udl < SMSLEN) - h.ud[h.udl++] = utf8decode(&p); - if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0) + if (ast_strlen_zero(sms_args.body)) { + ast_log (LOG_ERROR, "Missing body for %s\n", sms_args.addr); + 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"); - 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"); - 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"); + goto done; + } h.rx = 0; /* sent message */ h.mr = -1; sms_writefile (&h); - ast_module_user_remove(u); - return 0; + res = h.err; + goto done; } - if (answer) { + if (ast_test_flag(&sms_flags, OPTION_ANSWER)) { h.framenumber = 1; /* Proto 2 */ /* set up SMS_EST initial message */ 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); if (res < 0) { ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n"); - ast_module_user_remove(u); - return -1; + goto done; } - 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_module_user_remove(u); - return -1; + goto done; } /* Do our thing here */ for (;;) { + struct ast_frame *f; int i = ast_waitfor(chan, -1); if (i < 0) { ast_log(LOG_NOTICE, "waitfor failed\n"); @@ -1852,11 +1904,12 @@ static int sms_exec (struct ast_channel *chan, void *data) ast_frfree (f); } + res = h.err; /* XXX */ sms_log (&h, '?'); /* log incomplete message */ - +done: ast_module_user_remove(u); - return (h.err); + return (res); } static int unload_module(void) -- cgit v1.2.3