#include "asterisk.h"
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>
#include "asterisk/paths.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/alaw.h"
#include "asterisk/callerid.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
Go to the source code of this file.
Data Structures | |
struct | sms_s |
Defines | |
#define | __OUT_FMT AST_FORMAT_SLINEAR |
#define | DIR_RX 1 |
#define | DIR_TX 2 |
#define | DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1) |
#define | is16bit(dcs) ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) ) |
#define | is7bit(dcs) ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) ) |
#define | is8bit(dcs) ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) ) |
#define | MAX_DEBUG_LEN 300 |
#define | MAXSAMPLES (800) |
#define | OSYNC_BITS 80 |
#define | SMSLEN 160 |
#define | SMSLEN_8 140 |
Typedefs | |
typedef signed short | output_t |
typedef sms_s | sms_t |
Enumerations | |
enum | { OPTION_BE_SMSC = (1 << 0), OPTION_ANSWER = (1 << 1), OPTION_TWO = (1 << 2), OPTION_PAUSE = (1 << 3), OPTION_SRR = (1 << 4), OPTION_DCS = (1 << 5) } |
enum | { OPTION_ARG_PAUSE = 0, OPTION_ARG_ARRAY_SIZE } |
enum | message_types { DLL_SMS_MASK = 0x7f, DLL1_SMS_DATA = 0x11, DLL1_SMS_ERROR = 0x12, DLL1_SMS_EST = 0x13, DLL1_SMS_REL = 0x14, DLL1_SMS_ACK = 0x15, DLL1_SMS_NACK = 0x16, DLL1_SMS_COMPLETE = 0x80, DLL1_SMS_MORE = 0x00, DLL2_SMS_EST = 0x7f, DLL2_SMS_INFO_MO = 0x10, DLL2_SMS_INFO_MT = 0x11, DLL2_SMS_INFO_STA = 0x12, DLL2_SMS_NACK = 0x13, DLL2_SMS_ACK0 = 0x14, DLL2_SMS_ACK1 = 0x15, DLL2_SMS_ENQ = 0x16, DLL2_SMS_REL = 0x17, DLL2_SMS_COMPLETE = 0x00, DLL2_SMS_MORE = 0x80 } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | adddata_proto2 (sms_t *h, unsigned char msg, char *data, int size) |
static char * | isodate (time_t t, char *buf, int len) |
static, return a date/time in ISO format | |
static int | load_module (void) |
static void | numcpy (char *d, char *s) |
copy number, skipping non digits apart from leading + | |
static unsigned char | packaddress (unsigned char *o, char *i) |
store an address at o, and return number of bytes used | |
static void | packdate (unsigned char *o, time_t w) |
pack a date and return | |
static int | packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud) |
general pack, with length and data, returns number of bytes of target used | |
static int | packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud) |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes The return value is the number of bytes packed in to o, which is internally limited to 140 o can be null, in which case this is used to validate or count only if the input contains invalid characters then the return value is -1 | |
static int | packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud) |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes | |
static int | packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud) |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes. The return value is the number of bytes packed in to o, which is internally limited to 140. o can be null, in which case this is used to validate or count only. if the input contains invalid characters then the return value is -1 | |
static void | putdummydata_proto2 (sms_t *h) |
static struct dirent * | readdirqueue (DIR *d, char *queue) |
read dir skipping dot files... | |
static void * | sms_alloc (struct ast_channel *chan, void *sms_t_ptr) |
static void | sms_compose1 (sms_t *h, int more) |
compose a message for protocol 1 | |
static void | sms_compose2 (sms_t *h, int more) |
static void | sms_debug (int dir, sms_t *h) |
static int | sms_exec (struct ast_channel *chan, void *data) |
static int | sms_generate (struct ast_channel *chan, void *data, int len, int samples) |
static unsigned char | sms_handleincoming (sms_t *h) |
handle the incoming message | |
static int | sms_handleincoming_proto2 (sms_t *h) |
sms_handleincoming_proto2: handle the incoming message | |
static char * | sms_hexdump (unsigned char buf[], int size, char *s) |
static void | sms_log (sms_t *h, char status) |
Log the output, and remove file. | |
static void | sms_messagerx (sms_t *h) |
static void | sms_messagerx2 (sms_t *h) |
static void | sms_messagetx (sms_t *h) |
static void | sms_nextoutgoing (sms_t *h) |
find and fill in next message, or send a REL if none waiting | |
static void | sms_process (sms_t *h, int samples, signed short *data) |
static void | sms_readfile (sms_t *h, char *fn) |
parse and delete a file | |
static void | sms_release (struct ast_channel *chan, void *data) |
static void | sms_writefile (sms_t *h) |
white a received text message to a file | |
static int | unload_module (void) |
static unsigned char | unpackaddress (char *o, unsigned char *i) |
unpack an address from i, return byte length, unpack to o | |
static struct timeval | unpackdate (unsigned char *i) |
unpack a date and return | |
static int | unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi) |
general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length | |
static void | unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi) |
unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set | |
static void | unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi) |
unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set | |
static void | unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi) |
unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set. | |
static long | utf8decode (unsigned char **pp) |
Reads next UCS character from NUL terminated UTF-8 string and advance pointer. | |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SMS/PSTN handler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } |
static char * | app = "SMS" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static const unsigned short | defaultalphabet [] |
static char * | descrip |
static const unsigned short | escapes [] |
static char | log_file [255] |
static volatile unsigned char | message_ref |
static volatile unsigned int | seq |
enum { ... } | sms_flags |
enum { ... } | sms_opt_args |
static struct ast_app_option | sms_options [128] = { [ 's' ] = { .flag = OPTION_BE_SMSC }, [ 'a' ] = { .flag = OPTION_ANSWER }, [ 't' ] = { .flag = OPTION_TWO }, [ 'r' ] = { .flag = OPTION_SRR }, [ 'o' ] = { .flag = OPTION_DCS }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, } |
static struct ast_generator | smsgen |
static char * | synopsis = "Communicates with SMS service centres and SMS capable analogue phones" |
static signed short | wave [] |
static const output_t * | wave_out = wave |
Filippo Grassilli (Hyppo) - protocol 2 support Not fully tested, under development
Definition in file app_sms.c.
#define __OUT_FMT AST_FORMAT_SLINEAR |
#define DIR_RX 1 |
#define DIR_TX 2 |
#define DLL2_ACK | ( | h | ) | ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1) |
Referenced by sms_messagerx2().
#define is16bit | ( | dcs | ) | ( ((dcs) & 0xC0) ? 0 : (((dcs) & 0xc) == 8) ) |
#define is7bit | ( | dcs | ) | ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) ) |
#define is8bit | ( | dcs | ) | ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) ) |
#define MAX_DEBUG_LEN 300 |
Definition at line 1212 of file app_sms.c.
Referenced by sms_handleincoming_proto2(), and sms_hexdump().
#define MAXSAMPLES (800) |
Referenced by sms_generate().
#define OSYNC_BITS 80 |
#define SMSLEN 160 |
max SMS length
Definition at line 187 of file app_sms.c.
Referenced by packsms7(), and sms_readfile().
#define SMSLEN_8 140 |
max SMS length for 8-bit char
Definition at line 188 of file app_sms.c.
Referenced by packsms16(), and packsms8().
anonymous enum |
Definition at line 1813 of file app_sms.c.
01813 { 01814 OPTION_BE_SMSC = (1 << 0), /* act as sms center */ 01815 OPTION_ANSWER = (1 << 1), /* answer on incoming calls */ 01816 OPTION_TWO = (1 << 2), /* Use Protocol Two */ 01817 OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */ 01818 OPTION_SRR = (1 << 4), /* set srr */ 01819 OPTION_DCS = (1 << 5), /* set dcs */ 01820 } sms_flags;
anonymous enum |
Definition at line 1822 of file app_sms.c.
01822 { 01823 OPTION_ARG_PAUSE = 0, 01824 OPTION_ARG_ARRAY_SIZE 01825 } sms_opt_args;
enum message_types |
The SMS spec ETSI ES 201 912 defines two protocols with different message types. Also note that the high bit is used to indicate whether the message is complete or not, but in two opposite ways: for Protocol 1, 0x80 means that the message is complete; for Protocol 2, 0x00 means that the message is complete;
Definition at line 133 of file app_sms.c.
00133 { 00134 DLL_SMS_MASK = 0x7f, /* mask for the valid bits */ 00135 00136 /* Protocol 1 values */ 00137 DLL1_SMS_DATA = 0x11, /* data packet */ 00138 DLL1_SMS_ERROR = 0x12, 00139 DLL1_SMS_EST = 0x13, /* start the connection */ 00140 DLL1_SMS_REL = 0x14, /* end the connection */ 00141 DLL1_SMS_ACK = 0x15, 00142 DLL1_SMS_NACK = 0x16, 00143 00144 DLL1_SMS_COMPLETE = 0x80, /* packet is complete */ 00145 DLL1_SMS_MORE = 0x00, /* more data to follow */ 00146 00147 /* Protocol 2 values */ 00148 DLL2_SMS_EST = 0x7f, /* magic number. No message body */ 00149 DLL2_SMS_INFO_MO = 0x10, 00150 DLL2_SMS_INFO_MT = 0x11, 00151 DLL2_SMS_INFO_STA = 0x12, 00152 DLL2_SMS_NACK = 0x13, 00153 DLL2_SMS_ACK0 = 0x14, /* ack even-numbered frame */ 00154 DLL2_SMS_ACK1 = 0x15, /* ack odd-numbered frame */ 00155 DLL2_SMS_ENQ = 0x16, 00156 DLL2_SMS_REL = 0x17, /* end the connection */ 00157 00158 DLL2_SMS_COMPLETE = 0x00, /* packet is complete */ 00159 DLL2_SMS_MORE = 0x80, /* more data to follow */ 00160 };
static void adddata_proto2 | ( | sms_t * | h, | |
unsigned char | msg, | |||
char * | data, | |||
int | size | |||
) | [static] |
Add data to a protocol 2 message. Use the length field (h->omsg[1]) as a pointer to the next free position.
Definition at line 1152 of file app_sms.c.
References sms_s::omsg.
Referenced by putdummydata_proto2(), and sms_compose2().
01153 { 01154 int x = h->omsg[1] + 2; /* Get current position */ 01155 if (x == 2) { 01156 x += 2; /* First: skip Payload length (set later) */ 01157 } 01158 h->omsg[x++] = msg; /* Message code */ 01159 h->omsg[x++] = (unsigned char)size; /* Data size Low */ 01160 h->omsg[x++] = 0; /* Data size Hi */ 01161 for (; size > 0 ; size--) { 01162 h->omsg[x++] = *data++; 01163 } 01164 h->omsg[1] = x - 2; /* Frame size */ 01165 h->omsg[2] = x - 4; /* Payload length (Lo) */ 01166 h->omsg[3] = 0; /* Payload length (Hi) */ 01167 }
static char* isodate | ( | time_t | t, | |
char * | buf, | |||
int | len | |||
) | [static] |
static, return a date/time in ISO format
Definition at line 273 of file app_sms.c.
References ast_localtime(), and ast_strftime().
Referenced by sms_log(), and sms_writefile().
00274 { 00275 struct ast_tm tm; 00276 struct timeval local = { t, 0 }; 00277 ast_localtime(&local, &tm, NULL); 00278 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); 00279 return buf; 00280 }
static int load_module | ( | void | ) | [static] |
Definition at line 2030 of file app_sms.c.
References app, ast_config_AST_LOG_DIR, AST_LIN2A, ast_register_application, descrip, log_file, sms_exec(), synopsis, and wave.
02031 { 02032 #ifdef OUTALAW 02033 int p; 02034 for (p = 0; p < 80; p++) { 02035 wavea[p] = AST_LIN2A(wave[p]); 02036 } 02037 #endif 02038 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR); 02039 return ast_register_application(app, sms_exec, synopsis, descrip); 02040 }
static void numcpy | ( | char * | d, | |
char * | s | |||
) | [static] |
static unsigned char packaddress | ( | unsigned char * | o, | |
char * | i | |||
) | [static] |
store an address at o, and return number of bytes used
Definition at line 715 of file app_sms.c.
Referenced by sms_compose1().
00716 { 00717 unsigned char p = 2; 00718 o[0] = 0; /* number of bytes */ 00719 if (*i == '+') { /* record as bit 0 in byte 1 */ 00720 i++; 00721 o[1] = 0x91; 00722 } else { 00723 o[1] = 0x81; 00724 } 00725 for ( ; *i ; i++) { 00726 if (!isdigit(*i)) { /* ignore non-digits */ 00727 continue; 00728 } 00729 if (o[0] & 1) { 00730 o[p++] |= ((*i & 0xF) << 4); 00731 } else { 00732 o[p] = (*i & 0xF); 00733 } 00734 o[0]++; 00735 } 00736 if (o[0] & 1) { 00737 o[p++] |= 0xF0; /* pad */ 00738 } 00739 return p; 00740 }
static void packdate | ( | unsigned char * | o, | |
time_t | w | |||
) | [static] |
pack a date and return
Definition at line 523 of file app_sms.c.
References ast_localtime(), ast_tm::tm_gmtoff, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.
Referenced by sms_compose1().
00524 { 00525 struct ast_tm t; 00526 struct timeval topack = { w, 0 }; 00527 int z; 00528 00529 ast_localtime(&topack, &t, NULL); 00530 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__) 00531 z = -t.tm_gmtoff / 60 / 15; 00532 #else 00533 z = timezone / 60 / 15; 00534 #endif 00535 *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10; 00536 *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10; 00537 *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10; 00538 *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10; 00539 *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10; 00540 *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10; 00541 if (z < 0) { 00542 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08; 00543 } else { 00544 *o++ = ((z % 10) << 4) + z / 10; 00545 } 00546 }
static int packsms | ( | unsigned char | dcs, | |
unsigned char * | base, | |||
unsigned int | udhl, | |||
unsigned char * | udh, | |||
int | udl, | |||
unsigned short * | ud | |||
) | [static] |
general pack, with length and data, returns number of bytes of target used
Definition at line 490 of file app_sms.c.
References is7bit, is8bit, packsms16(), packsms7(), and packsms8().
Referenced by sms_compose1().
00491 { 00492 unsigned char *p = base; 00493 if (udl == 0) { 00494 *p++ = 0; /* no user data */ 00495 } else { 00496 00497 int l = 0; 00498 if (is7bit(dcs)) { /* 7 bit */ 00499 if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) { 00500 l = 0; 00501 } 00502 *p++ = l; 00503 p += (l * 7 + 7) / 8; 00504 } else if (is8bit(dcs)) { /* 8 bit */ 00505 if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) { 00506 l = 0; 00507 } 00508 *p++ = l; 00509 p += l; 00510 } else { /* UCS-2 */ 00511 if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) { 00512 l = 0; 00513 } 00514 *p++ = l; 00515 p += l; 00516 } 00517 } 00518 return p - base; 00519 }
static int packsms16 | ( | unsigned char * | o, | |
int | udhl, | |||
unsigned char * | udh, | |||
int | udl, | |||
unsigned short * | ud | |||
) | [static] |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes The return value is the number of bytes packed in to o, which is internally limited to 140 o can be null, in which case this is used to validate or count only if the input contains invalid characters then the return value is -1
Definition at line 455 of file app_sms.c.
References dummy(), and SMSLEN_8.
Referenced by packsms(), and sms_readfile().
00456 { 00457 unsigned char p = 0; 00458 unsigned char dummy[SMSLEN_8]; 00459 00460 if (o == NULL) { 00461 o = dummy; 00462 } 00463 /* header - no encoding */ 00464 if (udhl) { 00465 o[p++] = udhl; 00466 while (udhl--) { 00467 o[p++] = *udh++; 00468 if (p >= SMSLEN_8) { 00469 return p; 00470 } 00471 } 00472 } 00473 while (udl--) { 00474 long u; 00475 u = *ud++; 00476 o[p++] = (u >> 8); 00477 if (p >= SMSLEN_8) { 00478 return p - 1; /* could not fit last character */ 00479 } 00480 o[p++] = u; 00481 if (p >= SMSLEN_8) { 00482 return p; 00483 } 00484 } 00485 return p; 00486 }
static int packsms7 | ( | unsigned char * | o, | |
int | udhl, | |||
unsigned char * | udh, | |||
int | udl, | |||
unsigned short * | ud | |||
) | [static] |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes
Definition at line 339 of file app_sms.c.
References dummy(), and SMSLEN.
Referenced by packsms(), and sms_readfile().
00340 { 00341 unsigned char p = 0; /* output pointer (bytes) */ 00342 unsigned char b = 0; /* bit position */ 00343 unsigned char n = 0; /* output character count */ 00344 unsigned char dummy[SMSLEN]; 00345 00346 if (o == NULL) { /* output to a dummy buffer if o not set */ 00347 o = dummy; 00348 } 00349 00350 if (udhl) { /* header */ 00351 o[p++] = udhl; 00352 b = 1; 00353 n = 1; 00354 while (udhl--) { 00355 o[p++] = *udh++; 00356 b += 8; 00357 while (b >= 7) { 00358 b -= 7; 00359 n++; 00360 } 00361 if (n >= SMSLEN) 00362 return n; 00363 } 00364 if (b) { 00365 b = 7 - b; 00366 if (++n >= SMSLEN) 00367 return n; 00368 } /* filling to septet boundary */ 00369 } 00370 o[p] = 0; 00371 /* message */ 00372 while (udl--) { 00373 long u; 00374 unsigned char v; 00375 u = *ud++; 00376 /* XXX 0 is invalid ? */ 00377 /* look up in defaultalphabet[]. If found, v is the 7-bit code */ 00378 for (v = 0; v < 128 && defaultalphabet[v] != u; v++); 00379 if (v == 128 /* not found */ && u && n + 1 < SMSLEN) { 00380 /* if not found, look in the escapes table (we need 2 bytes) */ 00381 for (v = 0; v < 128 && escapes[v] != u; v++); 00382 if (v < 128) { /* escaped sequence, esc + v */ 00383 /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */ 00384 o[p] |= (27 << b); /* the low bits go into o[p] */ 00385 b += 7; 00386 if (b >= 8) { 00387 b -= 8; 00388 p++; 00389 o[p] = (27 >> (7 - b)); 00390 } 00391 n++; 00392 } 00393 } 00394 if (v == 128) 00395 return -1; /* invalid character */ 00396 /* store, same as above */ 00397 o[p] |= (v << b); 00398 b += 7; 00399 if (b >= 8) { 00400 b -= 8; 00401 p++; 00402 o[p] = (v >> (7 - b)); 00403 } 00404 if (++n >= SMSLEN) 00405 return n; 00406 } 00407 return n; 00408 }
static int packsms8 | ( | unsigned char * | o, | |
int | udhl, | |||
unsigned char * | udh, | |||
int | udl, | |||
unsigned short * | ud | |||
) | [static] |
takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes. The return value is the number of bytes packed in to o, which is internally limited to 140. o can be null, in which case this is used to validate or count only. if the input contains invalid characters then the return value is -1
Definition at line 416 of file app_sms.c.
References dummy(), and SMSLEN_8.
Referenced by packsms(), and sms_readfile().
00417 { 00418 unsigned char p = 0; 00419 unsigned char dummy[SMSLEN_8]; 00420 00421 if (o == NULL) 00422 o = dummy; 00423 /* header - no encoding */ 00424 if (udhl) { 00425 o[p++] = udhl; 00426 while (udhl--) { 00427 o[p++] = *udh++; 00428 if (p >= SMSLEN_8) { 00429 return p; 00430 } 00431 } 00432 } 00433 while (udl--) { 00434 long u; 00435 u = *ud++; 00436 if (u < 0 || u > 0xFF) { 00437 return -1; /* not valid */ 00438 } 00439 o[p++] = u; 00440 if (p >= SMSLEN_8) { 00441 return p; 00442 } 00443 } 00444 return p; 00445 }
static void putdummydata_proto2 | ( | sms_t * | h | ) | [static] |
Definition at line 1169 of file app_sms.c.
References adddata_proto2(), sms_s::udl, and sms_s::udtxt.
Referenced by sms_compose2().
01170 { 01171 adddata_proto2(h, 0x10, "\0", 1); /* Media Identifier > SMS */ 01172 adddata_proto2(h, 0x11, "\0\0\0\0\0\0", 6); /* Firmware version */ 01173 adddata_proto2(h, 0x12, "\2\0\4", 3); /* SMS provider ID */ 01174 adddata_proto2(h, 0x13, h->udtxt, h->udl); /* Body */ 01175 }
static struct dirent* readdirqueue | ( | DIR * | d, | |
char * | queue | |||
) | [static] |
read dir skipping dot files...
Definition at line 1066 of file app_sms.c.
References f.
Referenced by sms_nextoutgoing().
01067 { 01068 struct dirent *f; 01069 do { 01070 f = readdir(d); 01071 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.')); 01072 return f; 01073 }
static void* sms_alloc | ( | struct ast_channel * | chan, | |
void * | sms_t_ptr | |||
) | [static] |
static void sms_compose1 | ( | sms_t * | h, | |
int | more | |||
) | [static] |
compose a message for protocol 1
Definition at line 1364 of file app_sms.c.
References sms_s::da, sms_s::dcs, message_ref, sms_s::mr, sms_s::oa, sms_s::omsg, packaddress(), packdate(), packsms(), sms_s::pid, sms_s::rp, sms_s::scts, sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, and sms_s::vp.
Referenced by sms_nextoutgoing().
01365 { 01366 unsigned int p = 2; /* next byte to write. Skip type and len */ 01367 01368 h->omsg[0] = 0x91; /* SMS_DATA */ 01369 if (h->smsc) { /* deliver */ 01370 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0); 01371 p += packaddress(h->omsg + p, h->oa); 01372 h->omsg[p++] = h->pid; 01373 h->omsg[p++] = h->dcs; 01374 packdate(h->omsg + p, h->scts.tv_sec); 01375 p += 7; 01376 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud); 01377 } else { /* submit */ 01378 h->omsg[p++] = 01379 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0); 01380 if (h->mr < 0) { 01381 h->mr = message_ref++; 01382 } 01383 h->omsg[p++] = h->mr; 01384 p += packaddress(h->omsg + p, h->da); 01385 h->omsg[p++] = h->pid; 01386 h->omsg[p++] = h->dcs; 01387 if (h->vp) { /* relative VP */ 01388 if (h->vp < 720) { 01389 h->omsg[p++] = (h->vp + 4) / 5 - 1; 01390 } else if (h->vp < 1440) { 01391 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143; 01392 } else if (h->vp < 43200) { 01393 h->omsg[p++] = (h->vp + 1439) / 1440 + 166; 01394 } else if (h->vp < 635040) { 01395 h->omsg[p++] = (h->vp + 10079) / 10080 + 192; 01396 } else { 01397 h->omsg[p++] = 255; /* max */ 01398 } 01399 } 01400 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud); 01401 } 01402 h->omsg[1] = p - 2; 01403 }
static void sms_compose2 | ( | sms_t * | h, | |
int | more | |||
) | [static] |
Definition at line 1177 of file app_sms.c.
References adddata_proto2(), ast_localtime(), sms_s::da, sms_s::oa, sms_s::omsg, putdummydata_proto2(), sms_s::scts, sms_s::smsc, ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, and ast_tm::tm_mon.
Referenced by sms_nextoutgoing().
01178 { 01179 struct ast_tm tm; 01180 struct timeval now = h->scts; 01181 char stm[9]; 01182 01183 h->omsg[0] = 0x00; /* set later... */ 01184 h->omsg[1] = 0; 01185 putdummydata_proto2(h); 01186 if (h->smsc) { /* deliver */ 01187 h->omsg[0] = 0x11; /* SMS_DELIVERY */ 01188 /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */ 01189 ast_localtime(&now, &tm, NULL); 01190 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */ 01191 adddata_proto2(h, 0x14, stm, 8); /* Date */ 01192 if (*h->oa == 0) { 01193 strcpy(h->oa, "00000000"); 01194 } 01195 adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */ 01196 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */ 01197 } else { /* submit */ 01198 h->omsg[0] = 0x10; /* SMS_SUBMIT */ 01199 /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */ 01200 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */ 01201 if (*h->da == 0) { 01202 strcpy(h->da, "00000000"); 01203 } 01204 adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */ 01205 adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */ 01206 adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */ 01207 } 01208 }
static void sms_debug | ( | int | dir, | |
sms_t * | h | |||
) | [static] |
Definition at line 1448 of file app_sms.c.
References ast_verb, DIR_RX, sms_s::ibytep, sms_s::imsg, msg, and sms_s::omsg.
Referenced by sms_messagerx(), and sms_messagetx().
01449 { 01450 char txt[259 * 3 + 1]; 01451 char *p = txt; /* always long enough */ 01452 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg; 01453 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2; 01454 int q = 0; 01455 while (q < n && q < 30) { 01456 sprintf(p, " %02X", msg[q++]); 01457 p += 3; 01458 } 01459 if (q < n) { 01460 sprintf(p, "..."); 01461 } 01462 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt); 01463 }
static int sms_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1836 of file app_sms.c.
References AST_APP_ARG, ast_app_parse_options(), ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, chan, ast_channel::cid, ast_callerid::cid_num, sms_s::cli, sms_s::dcs, ast_flags::flags, sms_s::ipc0, sms_s::ipc1, LOG_ERROR, sms_s::opause_0, OPTION_ARG_ARRAY_SIZE, OPTION_ARG_PAUSE, OPTION_BE_SMSC, OPTION_DCS, OPTION_SRR, OPTION_TWO, parse(), sms_s::pid, sms_s::protocol, sms_s::queue, S_OR, sms_options, sms_s::smsc, and sms_s::srr.
Referenced by load_module().
01837 { 01838 int res = -1; 01839 sms_t h = { 0 }; 01840 /* argument parsing support */ 01841 struct ast_flags flags; 01842 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, }; 01843 char *p; 01844 AST_DECLARE_APP_ARGS(sms_args, 01845 AST_APP_ARG(queue); 01846 AST_APP_ARG(options); 01847 AST_APP_ARG(addr); 01848 AST_APP_ARG(body); 01849 ); 01850 01851 if (!data) { 01852 ast_log(LOG_ERROR, "Requires queue name at least\n"); 01853 return -1; 01854 } 01855 01856 parse = ast_strdupa(data); /* create a local copy */ 01857 AST_STANDARD_APP_ARGS(sms_args, parse); 01858 if (sms_args.argc > 1) { 01859 ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options); 01860 } 01861 01862 ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n", 01863 sms_args.argc, S_OR(sms_args.queue, ""), 01864 S_OR(sms_args.options, ""), 01865 S_OR(sms_args.addr, ""), 01866 S_OR(sms_args.body, "") ); 01867 01868 h.ipc0 = h.ipc1 = 20; /* phase for cosine */ 01869 h.dcs = 0xF1; /* default */ 01870 01871 if (chan->cid.cid_num) 01872 ast_copy_string(h.cli, chan->cid.cid_num, sizeof(h.cli)); 01873 01874 if (ast_strlen_zero(sms_args.queue)) { 01875 ast_log(LOG_ERROR, "Requires queue name\n"); 01876 goto done; 01877 } 01878 if (strlen(sms_args.queue) >= sizeof(h.queue)) { 01879 ast_log(LOG_ERROR, "Queue name too long\n"); 01880 goto done; 01881 } 01882 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue)); 01883 01884 for (p = h.queue; *p; p++) { 01885 if (!isalnum(*p)) { 01886 *p = '-'; /* make very safe for filenames */ 01887 } 01888 } 01889 01890 h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC); 01891 h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1; 01892 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) { 01893 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]); 01894 } 01895 if (h.opause_0 < 25 || h.opause_0 > 2000) { 01896 h.opause_0 = 300; /* default 300ms */ 01897 } 01898 ast_verb(1, "initial delay %dms\n", h.opause_0); 01899 01900 01901 /* the following apply if there is an arg3/4 and apply to the created message file */ 01902 if (ast_test_flag(&flags, OPTION_SRR)) { 01903 h.srr = 1; 01904 } 01905 if (ast_test_flag(&flags, OPTION_DCS)) { 01906 h.dcs = 1; 01907 } 01908 #if 0 01909 case '1': 01910 case '2': 01911 case '3': 01912 case '4': 01913 case '5': 01914 case '6': 01915 case '7': /* set the pid for saved local message */ 01916 h.pid = 0x40 + (*d & 0xF); 01917 break; 01918 } 01919 #endif 01920 if (sms_args.argc > 2) { 01921 unsigned char *up; 01922 01923 /* submitting a message, not taking call. */ 01924 /* deprecated, use smsq instead */ 01925 h.scts = ast_tvnow(); 01926 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) { 01927 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr); 01928 goto done; 01929 } 01930 if (h.smsc) { 01931 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa)); 01932 } else { 01933 ast_copy_string(h.da, sms_args.addr, sizeof(h.da)); 01934 ast_copy_string(h.oa, h.cli, sizeof(h.oa)); 01935 } 01936 h.udl = 0; 01937 if (ast_strlen_zero(sms_args.body)) { 01938 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr); 01939 goto done; 01940 } 01941 up = (unsigned char *)sms_args.body; 01942 while (*up && h.udl < SMSLEN) { 01943 h.ud[h.udl++] = utf8decode(&up); 01944 } 01945 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01946 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n"); 01947 goto done; 01948 } 01949 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01950 ast_log(LOG_WARNING, "Invalid 8 bit data\n"); 01951 goto done; 01952 } 01953 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01954 ast_log(LOG_WARNING, "Invalid 16 bit data\n"); 01955 goto done; 01956 } 01957 h.rx = 0; /* sent message */ 01958 h.mr = -1; 01959 sms_writefile(&h); 01960 res = h.err; 01961 goto done; 01962 } 01963 01964 if (chan->_state != AST_STATE_UP) { /* make sure channel is answered before any TX */ 01965 ast_answer(chan); 01966 } 01967 01968 if (ast_test_flag(&flags, OPTION_ANSWER)) { 01969 h.framenumber = 1; /* Proto 2 */ 01970 /* set up SMS_EST initial message */ 01971 if (h.protocol == 2) { 01972 h.omsg[0] = DLL2_SMS_EST; 01973 h.omsg[1] = 0; 01974 } else { 01975 h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE; 01976 h.omsg[1] = 0; 01977 } 01978 sms_messagetx(&h); 01979 } 01980 01981 res = ast_set_write_format(chan, __OUT_FMT); 01982 if (res >= 0) { 01983 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 01984 } 01985 if (res < 0) { 01986 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n"); 01987 goto done; 01988 } 01989 01990 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) { 01991 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name); 01992 goto done; 01993 } 01994 01995 /* Do our thing here */ 01996 for (;;) { 01997 struct ast_frame *f; 01998 int i = ast_waitfor(chan, -1); 01999 if (i < 0) { 02000 ast_log(LOG_NOTICE, "waitfor failed\n"); 02001 break; 02002 } 02003 if (h.hangup) { 02004 ast_log(LOG_NOTICE, "channel hangup\n"); 02005 break; 02006 } 02007 f = ast_read(chan); 02008 if (!f) { 02009 ast_log(LOG_NOTICE, "ast_read failed\n"); 02010 break; 02011 } 02012 if (f->frametype == AST_FRAME_VOICE) { 02013 sms_process(&h, f->samples, f->data.ptr); 02014 } 02015 02016 ast_frfree(f); 02017 } 02018 res = h.err; /* XXX */ 02019 02020 sms_log(&h, '?'); /* log incomplete message */ 02021 done: 02022 return (res); 02023 }
static int sms_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
outgoing data are produced by this generator function, that reads from the descriptor whether it has data to send and which ones.
Definition at line 1567 of file app_sms.c.
References __OUT_FMT, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), buf, f, LOG_WARNING, MAXSAMPLES, sms_s::obyte, sms_s::obyten, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::oseizure, sms_s::osync, and wave_out.
01568 { 01569 struct ast_frame f = { 0 }; 01570 #define MAXSAMPLES (800) 01571 output_t *buf; 01572 sms_t *h = data; 01573 int i; 01574 01575 if (samples > MAXSAMPLES) { 01576 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", 01577 MAXSAMPLES, samples); 01578 samples = MAXSAMPLES; 01579 } 01580 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET; 01581 buf = alloca(len); 01582 01583 f.frametype = AST_FRAME_VOICE; 01584 f.subclass = __OUT_FMT; 01585 f.datalen = samples * sizeof(*buf); 01586 f.offset = AST_FRIENDLY_OFFSET; 01587 f.mallocd = 0; 01588 f.data.ptr = buf; 01589 f.samples = samples; 01590 f.src = "app_sms"; 01591 /* create a buffer containing the digital sms pattern */ 01592 for (i = 0; i < samples; i++) { 01593 buf[i] = wave_out[0]; /* default is silence */ 01594 01595 if (h->opause) { 01596 h->opause--; 01597 } else if (h->obyten || h->osync) { /* sending data */ 01598 buf[i] = wave_out[h->ophase]; 01599 h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */ 01600 if (h->ophase >= 80) 01601 h->ophase -= 80; 01602 if ((h->ophasep += 12) >= 80) { /* time to send the next bit */ 01603 h->ophasep -= 80; 01604 if (h->oseizure > 0) { /* sending channel seizure (proto 2) */ 01605 h->oseizure--; 01606 h->obyte ^= 1; /* toggle low bit */ 01607 } else if (h->osync) { 01608 h->obyte = 1; /* send mark as sync bit */ 01609 h->osync--; /* sending sync bits */ 01610 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) { 01611 h->obytep = h->obyten = 0; /* we are done */ 01612 } 01613 } else { 01614 h->obitp++; 01615 if (h->obitp == 1) { 01616 h->obyte = 0; /* start bit; */ 01617 } else if (h->obitp == 2) { 01618 h->obyte = h->omsg[h->obytep]; 01619 } else if (h->obitp == 10) { 01620 h->obyte = 1; /* stop bit */ 01621 h->obitp = 0; 01622 h->obytep++; 01623 if (h->obytep == h->obyten) { 01624 h->obytep = h->obyten = 0; /* sent */ 01625 h->osync = 10; /* trailing marks */ 01626 } 01627 } else { 01628 h->obyte >>= 1; 01629 } 01630 } 01631 } 01632 } 01633 } 01634 if (ast_write(chan, &f) < 0) { 01635 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 01636 return -1; 01637 } 01638 return 0; 01639 #undef MAXSAMPLES 01640 }
static unsigned char sms_handleincoming | ( | sms_t * | h | ) | [static] |
handle the incoming message
Definition at line 1076 of file app_sms.c.
References ast_copy_string(), ast_log(), ast_tvnow(), sms_s::cli, sms_s::da, sms_s::dcs, sms_s::imsg, LOG_WARNING, sms_s::mr, sms_s::oa, sms_s::pid, sms_s::rp, sms_s::rx, sms_s::scts, sms_writefile(), sms_s::smsc, sms_s::srr, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, unpackaddress(), unpackdate(), unpacksms(), and sms_s::vp.
Referenced by sms_messagerx().
01077 { 01078 unsigned char p = 3; 01079 if (h->smsc) { /* SMSC */ 01080 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */ 01081 h->udhl = h->udl = 0; 01082 h->vp = 0; 01083 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0); 01084 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0); 01085 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0); 01086 ast_copy_string(h->oa, h->cli, sizeof(h->oa)); 01087 h->scts = ast_tvnow(); 01088 h->mr = h->imsg[p++]; 01089 p += unpackaddress(h->da, h->imsg + p); 01090 h->pid = h->imsg[p++]; 01091 h->dcs = h->imsg[p++]; 01092 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */ 01093 if (h->imsg[p] < 144) { 01094 h->vp = (h->imsg[p] + 1) * 5; 01095 } else if (h->imsg[p] < 168) { 01096 h->vp = 720 + (h->imsg[p] - 143) * 30; 01097 } else if (h->imsg[p] < 197) { 01098 h->vp = (h->imsg[p] - 166) * 1440; 01099 } else { 01100 h->vp = (h->imsg[p] - 192) * 10080; 01101 } 01102 p++; 01103 } else if (h->imsg[2] & 0x18) { 01104 p += 7; /* ignore enhanced / absolute VP */ 01105 } 01106 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi); 01107 h->rx = 1; /* received message */ 01108 sms_writefile(h); /* write the file */ 01109 if (p != h->imsg[1] + 2) { 01110 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2); 01111 return 0xFF; /* duh! */ 01112 } 01113 } else { 01114 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]); 01115 return 0xFF; 01116 } 01117 } else { /* client */ 01118 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */ 01119 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0; 01120 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0); 01121 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0); 01122 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0); 01123 h->mr = -1; 01124 p += unpackaddress(h->oa, h->imsg + p); 01125 h->pid = h->imsg[p++]; 01126 h->dcs = h->imsg[p++]; 01127 h->scts = unpackdate(h->imsg + p); 01128 p += 7; 01129 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi); 01130 h->rx = 1; /* received message */ 01131 sms_writefile(h); /* write the file */ 01132 if (p != h->imsg[1] + 2) { 01133 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2); 01134 return 0xFF; /* duh! */ 01135 } 01136 } else { 01137 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]); 01138 return 0xFF; 01139 } 01140 } 01141 return 0; /* no error */ 01142 }
static int sms_handleincoming_proto2 | ( | sms_t * | h | ) | [static] |
sms_handleincoming_proto2: handle the incoming message
Definition at line 1226 of file app_sms.c.
References ast_copy_string(), ast_localtime(), ast_mktime(), ast_tvnow(), ast_verb, sms_s::da, f, sms_s::imsg, MAX_DEBUG_LEN, msg, sms_s::oa, sms_s::scts, sms_hexdump(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, sms_s::ud, and sms_s::udl.
Referenced by sms_messagerx2().
01227 { 01228 int f, i, sz = 0; 01229 int msg, msgsz; 01230 struct ast_tm tm; 01231 struct timeval now = { 0, 0 }; 01232 char debug_buf[MAX_DEBUG_LEN * 3 + 1]; 01233 01234 sz = h->imsg[1] + 2; 01235 /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */ 01236 01237 /* Parse message body (called payload) */ 01238 now = h->scts = ast_tvnow(); 01239 for (f = 4; f < sz; ) { 01240 msg = h->imsg[f++]; 01241 msgsz = h->imsg[f++]; 01242 msgsz += (h->imsg[f++] * 256); 01243 switch (msg) { 01244 case 0x13: /* Body */ 01245 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01246 if (msgsz >= sizeof(h->imsg)) { 01247 msgsz = sizeof(h->imsg) - 1; 01248 } 01249 for (i = 0; i < msgsz; i++) { 01250 h->ud[i] = h->imsg[f + i]; 01251 } 01252 h->udl = msgsz; 01253 break; 01254 case 0x14: /* Date SCTS */ 01255 now = h->scts = ast_tvnow(); 01256 ast_localtime(&now, &tm, NULL); 01257 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1; 01258 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] ); 01259 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] ); 01260 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] ); 01261 tm.tm_sec = 0; 01262 h->scts = ast_mktime(&tm, NULL); 01263 ast_verb(3, "SMS-P2 Date#%02X=%02d/%02d %02d:%02d\n", msg, tm.tm_mday, tm.tm_mon + 1, tm.tm_hour, tm.tm_min); 01264 break; 01265 case 0x15: /* Calling line (from SMSC) */ 01266 if (msgsz >= 20) { 01267 msgsz = 20 - 1; 01268 } 01269 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01270 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1); 01271 break; 01272 case 0x18: /* Destination(from TE/phone) */ 01273 if (msgsz >= 20) { 01274 msgsz = 20 - 1; 01275 } 01276 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01277 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1); 01278 break; 01279 case 0x1C: /* Notify */ 01280 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf)); 01281 break; 01282 default: 01283 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf)); 01284 break; 01285 } 01286 f+=msgsz; /* Skip to next */ 01287 } 01288 h->rx = 1; /* received message */ 01289 sms_writefile(h); /* write the file */ 01290 return 0; /* no error */ 01291 }
static char* sms_hexdump | ( | unsigned char | buf[], | |
int | size, | |||
char * | s | |||
) | [static] |
Definition at line 1213 of file app_sms.c.
References f, and MAX_DEBUG_LEN.
Referenced by sms_handleincoming_proto2().
01214 { 01215 char *p; 01216 int f; 01217 01218 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) { 01219 sprintf(p, "%02X ", (unsigned char)buf[f]); 01220 } 01221 return(s); 01222 }
static void sms_log | ( | sms_t * | h, | |
char | status | |||
) | [static] |
Log the output, and remove file.
Definition at line 743 of file app_sms.c.
References AST_FILE_MODE, buf, sms_s::da, isodate(), sms_s::mr, sms_s::oa, sms_s::queue, sms_s::rx, S_OR, sms_s::smsc, sms_s::ud, and sms_s::udl.
Referenced by sms_messagerx(), and sms_messagerx2().
00744 { 00745 int o; 00746 00747 if (*h->oa == '\0' && *h->da == '\0') { 00748 return; 00749 } 00750 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE); 00751 if (o >= 0) { 00752 char line[1000], mrs[3] = "", *p; 00753 char buf[30]; 00754 unsigned char n; 00755 00756 if (h->mr >= 0) { 00757 snprintf(mrs, sizeof(mrs), "%02X", h->mr); 00758 } 00759 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ", 00760 isodate(time(NULL), buf, sizeof(buf)), 00761 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, 00762 S_OR(h->oa, "-"), S_OR(h->da, "-") ); 00763 p = line + strlen(line); 00764 for (n = 0; n < h->udl; n++) { 00765 if (h->ud[n] == '\\') { 00766 *p++ = '\\'; 00767 *p++ = '\\'; 00768 } else if (h->ud[n] == '\n') { 00769 *p++ = '\\'; 00770 *p++ = 'n'; 00771 } else if (h->ud[n] == '\r') { 00772 *p++ = '\\'; 00773 *p++ = 'r'; 00774 } else if (h->ud[n] < 32 || h->ud[n] == 127) { 00775 *p++ = 191; 00776 } else { 00777 *p++ = h->ud[n]; 00778 } 00779 } 00780 *p++ = '\n'; 00781 *p = 0; 00782 if (write(o, line, strlen(line)) < 0) { 00783 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 00784 } 00785 close(o); 00786 } 00787 *h->oa = *h->da = h->udl = 0; 00788 }
static void sms_messagerx | ( | sms_t * | h | ) | [static] |
Definition at line 1466 of file app_sms.c.
References DIR_RX, sms_s::err, sms_s::hangup, sms_s::imsg, sms_s::omsg, sms_s::protocol, sms_debug(), sms_handleincoming(), sms_log(), sms_messagerx2(), sms_messagetx(), and sms_nextoutgoing().
01467 { 01468 int cause; 01469 01470 sms_debug (DIR_RX, h); 01471 if (h->protocol == 2) { 01472 sms_messagerx2(h); 01473 return; 01474 } 01475 /* parse incoming message for Protocol 1 */ 01476 switch (h->imsg[0]) { 01477 case 0x91: /* SMS_DATA */ 01478 cause = sms_handleincoming (h); 01479 if (!cause) { 01480 sms_log(h, 'Y'); 01481 h->omsg[0] = 0x95; /* SMS_ACK */ 01482 h->omsg[1] = 0x02; 01483 h->omsg[2] = 0x00; /* deliver report */ 01484 h->omsg[3] = 0x00; /* no parameters */ 01485 } else { /* NACK */ 01486 sms_log(h, 'N'); 01487 h->omsg[0] = 0x96; /* SMS_NACK */ 01488 h->omsg[1] = 3; 01489 h->omsg[2] = 0; /* delivery report */ 01490 h->omsg[3] = cause; /* cause */ 01491 h->omsg[4] = 0; /* no parameters */ 01492 } 01493 sms_messagetx(h); 01494 break; 01495 01496 case 0x92: /* SMS_ERROR */ 01497 h->err = 1; 01498 sms_messagetx(h); /* send whatever we sent again */ 01499 break; 01500 case 0x93: /* SMS_EST */ 01501 sms_nextoutgoing (h); 01502 break; 01503 case 0x94: /* SMS_REL */ 01504 h->hangup = 1; /* hangup */ 01505 break; 01506 case 0x95: /* SMS_ACK */ 01507 sms_log(h, 'Y'); 01508 sms_nextoutgoing (h); 01509 break; 01510 case 0x96: /* SMS_NACK */ 01511 h->err = 1; 01512 sms_log(h, 'N'); 01513 sms_nextoutgoing (h); 01514 break; 01515 default: /* Unknown */ 01516 h->omsg[0] = 0x92; /* SMS_ERROR */ 01517 h->omsg[1] = 1; 01518 h->omsg[2] = 3; /* unknown message type */ 01519 sms_messagetx(h); 01520 break; 01521 } 01522 }
static void sms_messagerx2 | ( | sms_t * | h | ) | [static] |
Definition at line 1307 of file app_sms.c.
References ast_log(), DLL2_ACK, DLL2_SMS_ACK0, DLL2_SMS_ACK1, DLL2_SMS_EST, DLL2_SMS_INFO_MO, DLL2_SMS_INFO_MT, DLL2_SMS_NACK, DLL2_SMS_REL, DLL_SMS_MASK, sms_s::imsg, LOG_NOTICE, sms_handleincoming_proto2(), sms_log(), sms_messagetx(), and sms_nextoutgoing().
Referenced by sms_messagerx().
01308 { 01309 int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */ 01310 int cause; 01311 01312 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1) 01313 switch (p) { 01314 case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */ 01315 sms_nextoutgoing (h); 01316 /* smssend(h,"11 29 27 00 10 01 00 00 11 06 00 00 00 00 00 00 00 12 03 00 02 00 04 13 01 00 41 14 08 00 30 39 31 35 30 02 30 02 15 02 00 39 30 "); */ 01317 break; 01318 01319 case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */ 01320 case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */ 01321 cause = sms_handleincoming_proto2(h); 01322 if (!cause) { /* ACK */ 01323 sms_log(h, 'Y'); 01324 } 01325 h->omsg[0] = DLL2_ACK(h); 01326 h->omsg[1] = 0x06; /* msg len */ 01327 h->omsg[2] = 0x04; /* payload len */ 01328 h->omsg[3] = 0x00; /* payload len */ 01329 h->omsg[4] = 0x1f; /* Response type */ 01330 h->omsg[5] = 0x01; /* parameter len */ 01331 h->omsg[6] = 0x00; /* parameter len */ 01332 h->omsg[7] = cause; /* CONFIRM or error */ 01333 sms_messagetx(h); 01334 break; 01335 01336 case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */ 01337 h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */ 01338 h->omsg[1] = 0x00; /* msg len */ 01339 sms_messagetx(h); 01340 break; 01341 01342 case DLL2_SMS_ACK0: 01343 case DLL2_SMS_ACK1: 01344 /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */ 01345 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) { 01346 /* a response to our Release, just hangup */ 01347 h->hangup = 1; /* hangup */ 01348 } else { 01349 /* XXX depending on what we are.. */ 01350 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY"); 01351 sms_nextoutgoing (h); 01352 } 01353 break; 01354 01355 case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */ 01356 h->omsg[0] = DLL2_ACK(h); 01357 h->omsg[1] = 0; 01358 sms_messagetx(h); 01359 break; 01360 } 01361 }
static void sms_messagetx | ( | sms_t * | h | ) | [static] |
Definition at line 1524 of file app_sms.c.
References DIR_TX, sms_s::framenumber, len(), sms_s::obitp, sms_s::obyte, sms_s::obyten, sms_s::obytep, sms_s::omsg, sms_s::opause, sms_s::opause_0, sms_s::oseizure, sms_s::osync, OSYNC_BITS, sms_s::protocol, and sms_debug().
Referenced by sms_messagerx(), sms_messagerx2(), and sms_nextoutgoing().
01525 { 01526 unsigned char c = 0, p; 01527 int len = h->omsg[1] + 2; /* total message length excluding checksum */ 01528 01529 for (p = 0; p < len; p++) { /* compute checksum */ 01530 c += h->omsg[p]; 01531 } 01532 h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */ 01533 sms_debug(DIR_TX, h); 01534 h->framenumber++; /* Proto 2 */ 01535 h->obytep = 0; 01536 h->obitp = 0; 01537 if (h->protocol == 2) { /* Proto 2: */ 01538 h->oseizure = 300; /* 300bits (or more ?) */ 01539 h->obyte = 0; /* Seizure starts with space (0) */ 01540 if (h->omsg[0] == 0x7F) { 01541 h->opause = 8 * h->opause_0; /* initial message delay */ 01542 } else { 01543 h->opause = 400; 01544 } 01545 } else { /* Proto 1: */ 01546 h->oseizure = 0; /* No seizure */ 01547 h->obyte = 1; /* send mark ('1') at the beginning */ 01548 /* Change the initial message delay. BT requires 300ms, 01549 * but for others this might be way too much and the phone 01550 * could time out. XXX make it configurable. 01551 */ 01552 if (h->omsg[0] == 0x93) { 01553 h->opause = 8 * h->opause_0; /* initial message delay */ 01554 } else { 01555 h->opause = 200; 01556 } 01557 } 01558 /* Note - setting osync triggers the generator */ 01559 h->osync = OSYNC_BITS; /* 80 sync bits */ 01560 h->obyten = len + 1; /* bytes to send (including checksum) */ 01561 }
static void sms_nextoutgoing | ( | sms_t * | h | ) | [static] |
find and fill in next message, or send a REL if none waiting
Definition at line 1406 of file app_sms.c.
References ast_config_AST_SPOOL_DIR, ast_mkdir(), sms_s::da, sms_s::oa, sms_s::omsg, sms_s::protocol, sms_s::queue, readdirqueue(), sms_s::rx, sms_compose1(), sms_compose2(), sms_messagetx(), sms_readfile(), and sms_s::smsc.
Referenced by sms_messagerx(), and sms_messagerx2().
01407 { 01408 char fn[100 + NAME_MAX] = ""; 01409 DIR *d; 01410 char more = 0; 01411 01412 *h->da = *h->oa = '\0'; /* clear destinations */ 01413 h->rx = 0; /* outgoing message */ 01414 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx"); 01415 ast_mkdir(fn, 0777); /* ensure it exists */ 01416 d = opendir(fn); 01417 if (d) { 01418 struct dirent *f = readdirqueue(d, h->queue); 01419 if (f) { 01420 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name); 01421 sms_readfile(h, fn); 01422 if (readdirqueue(d, h->queue)) { 01423 more = 1; /* more to send */ 01424 } 01425 } 01426 closedir(d); 01427 } 01428 if (*h->da || *h->oa) { /* message to send */ 01429 if (h->protocol == 2) { 01430 sms_compose2(h, more); 01431 } else { 01432 sms_compose1(h, more); 01433 } 01434 } else { /* no message */ 01435 if (h->protocol == 2) { 01436 h->omsg[0] = 0x17; /* SMS_REL */ 01437 h->omsg[1] = 0; 01438 } else { 01439 h->omsg[0] = 0x94; /* SMS_REL */ 01440 h->omsg[1] = 0; 01441 } 01442 } 01443 sms_messagetx(h); 01444 }
static void sms_process | ( | sms_t * | h, | |
int | samples, | |||
signed short * | data | |||
) | [static] |
Process an incoming frame, trying to detect the carrier and decode the message. The two frequencies are 1300 and 2100 Hz. The decoder detects the amplitude of the signal over the last few samples, filtering the absolute values with a lowpass filter. If the magnitude (h->imag) is large enough, multiply the signal by the two carriers, and compute the amplitudes m0 and m1. Record the current sample as '0' or '1' depending on which one is greater. The last 3 bits are stored in h->ibith, with the count of '1' bits in h->ibitt. XXX the rest is to be determined.
Definition at line 1673 of file app_sms.c.
References ast_log(), sms_s::err, sms_s::hangup, sms_s::idle, sms_s::imag, LOG_NOTICE, m1, sms_s::obyten, and sms_s::osync.
01674 { 01675 int bit; 01676 01677 /* 01678 * Ignore incoming audio while a packet is being transmitted, 01679 * the protocol is half-duplex. 01680 * Unfortunately this means that if the outbound and incoming 01681 * transmission overlap (which is an error condition anyways), 01682 * we may miss some data and this makes debugging harder. 01683 */ 01684 if (h->obyten || h->osync) { 01685 return; 01686 } 01687 for ( ; samples-- ; data++) { 01688 unsigned long long m0, m1; 01689 if (abs(*data) > h->imag) { 01690 h->imag = abs(*data); 01691 } else { 01692 h->imag = h->imag * 7 / 8; 01693 } 01694 if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */ 01695 if (h->idle++ == 80000) { /* nothing happening */ 01696 ast_log(LOG_NOTICE, "No data, hanging up\n"); 01697 h->hangup = 1; 01698 h->err = 1; 01699 } 01700 if (h->ierr) { /* error */ 01701 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr); 01702 /* Protocol 1 */ 01703 h->err = 1; 01704 h->omsg[0] = 0x92; /* error */ 01705 h->omsg[1] = 1; 01706 h->omsg[2] = h->ierr; 01707 sms_messagetx(h); /* send error */ 01708 } 01709 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01710 continue; 01711 } 01712 h->idle = 0; 01713 01714 /* multiply signal by the two carriers. */ 01715 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7; 01716 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7; 01717 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7; 01718 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7; 01719 /* compute the amplitudes */ 01720 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0; 01721 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1; 01722 01723 /* advance the sin/cos pointers */ 01724 if ((h->ips0 += 21) >= 80) { 01725 h->ips0 -= 80; 01726 } 01727 if ((h->ipc0 += 21) >= 80) { 01728 h->ipc0 -= 80; 01729 } 01730 if ((h->ips1 += 13) >= 80) { 01731 h->ips1 -= 80; 01732 } 01733 if ((h->ipc1 += 13) >= 80) { 01734 h->ipc1 -= 80; 01735 } 01736 01737 /* set new bit to 1 or 0 depending on which value is stronger */ 01738 h->ibith <<= 1; 01739 if (m1 > m0) { 01740 h->ibith |= 1; 01741 } 01742 if (h->ibith & 8) { 01743 h->ibitt--; 01744 } 01745 if (h->ibith & 1) { 01746 h->ibitt++; 01747 } 01748 bit = ((h->ibitt > 1) ? 1 : 0); 01749 if (bit != h->ibitl) { 01750 h->ibitc = 1; 01751 } else { 01752 h->ibitc++; 01753 } 01754 h->ibitl = bit; 01755 if (!h->ibitn && h->ibitc == 4 && !bit) { 01756 h->ibitn = 1; 01757 h->iphasep = 0; 01758 } 01759 if (bit && h->ibitc == 200) { /* sync, restart message */ 01760 /* Protocol 2: empty connection ready (I am master) */ 01761 if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) { 01762 h->framenumber = 1; 01763 ast_verb(3, "SMS protocol 2 detected\n"); 01764 h->protocol = 2; 01765 h->imsg[0] = 0xff; /* special message (fake) */ 01766 h->imsg[1] = h->imsg[2] = 0x00; 01767 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01768 sms_messagerx(h); 01769 } 01770 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01771 } 01772 if (h->ibitn) { 01773 h->iphasep += 12; 01774 if (h->iphasep >= 80) { /* next bit */ 01775 h->iphasep -= 80; 01776 if (h->ibitn++ == 9) { /* end of byte */ 01777 if (!bit) { /* bad stop bit */ 01778 ast_log(LOG_NOTICE, "bad stop bit"); 01779 h->ierr = 0xFF; /* unknown error */ 01780 } else { 01781 if (h->ibytep < sizeof(h->imsg)) { 01782 h->imsg[h->ibytep] = h->ibytev; 01783 h->ibytec += h->ibytev; 01784 h->ibytep++; 01785 } else if (h->ibytep == sizeof(h->imsg)) { 01786 ast_log(LOG_NOTICE, "msg too large"); 01787 h->ierr = 2; /* bad message length */ 01788 } 01789 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) { 01790 if (!h->ibytec) { 01791 sms_messagerx(h); 01792 } else { 01793 ast_log(LOG_NOTICE, "bad checksum"); 01794 h->ierr = 1; /* bad checksum */ 01795 } 01796 } 01797 } 01798 h->ibitn = 0; 01799 } 01800 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0); 01801 } 01802 } 01803 } 01804 }
static void sms_readfile | ( | sms_t * | h, | |
char * | fn | |||
) | [static] |
parse and delete a file
Definition at line 791 of file app_sms.c.
References ast_log(), ast_mktime(), ast_tvnow(), sms_s::da, sms_s::dcs, is16bit, is7bit, is8bit, LOG_EVENT, LOG_WARNING, sms_s::mr, numcpy(), sms_s::oa, packsms16(), packsms7(), packsms8(), sms_s::pid, pp, sms_s::rp, sms_s::rx, S, s, sms_s::scts, SMSLEN, sms_s::srr, ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, ast_tm::tm_year, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, sms_s::udl, sms_s::udtxt, utf8decode(), and sms_s::vp.
Referenced by sms_nextoutgoing().
00792 { 00793 char line[1000]; 00794 FILE *s; 00795 char dcsset = 0; /* if DSC set */ 00796 ast_log(LOG_EVENT, "Sending %s\n", fn); 00797 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0; 00798 h->mr = -1; 00799 h->dcs = 0xF1; /* normal messages class 1 */ 00800 h->scts = ast_tvnow(); 00801 s = fopen(fn, "r"); 00802 if (s) { 00803 if (unlink(fn)) { /* concurrent access, we lost */ 00804 fclose(s); 00805 return; 00806 } 00807 while (fgets (line, sizeof(line), s)) { /* process line in file */ 00808 char *p; 00809 void *pp = &p; 00810 for (p = line; *p && *p != '\n' && *p != '\r'; p++); 00811 *p = 0; /* strip eoln */ 00812 p = line; 00813 if (!*p || *p == ';') { 00814 continue; /* blank line or comment, ignore */ 00815 } 00816 while (isalnum(*p)) { 00817 *p = tolower (*p); 00818 p++; 00819 } 00820 while (isspace (*p)) { 00821 *p++ = 0; 00822 } 00823 if (*p == '=') { 00824 *p++ = 0; 00825 if (!strcmp(line, "ud")) { /* parse message (UTF-8) */ 00826 unsigned char o = 0; 00827 memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */ 00828 while (*p && o < SMSLEN) { 00829 h->ud[o++] = utf8decode(pp); 00830 } 00831 h->udl = o; 00832 if (*p) { 00833 ast_log(LOG_WARNING, "UD too long in %s\n", fn); 00834 } 00835 } else { 00836 while (isspace (*p)) { 00837 p++; 00838 } 00839 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) { 00840 numcpy (h->oa, p); 00841 } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) { 00842 numcpy (h->da, p); 00843 } else if (!strcmp(line, "pid")) { 00844 h->pid = atoi(p); 00845 } else if (!strcmp(line, "dcs")) { 00846 h->dcs = atoi(p); 00847 dcsset = 1; 00848 } else if (!strcmp(line, "mr")) { 00849 h->mr = atoi(p); 00850 } else if (!strcmp(line, "srr")) { 00851 h->srr = (atoi(p) ? 1 : 0); 00852 } else if (!strcmp(line, "vp")) { 00853 h->vp = atoi(p); 00854 } else if (!strcmp(line, "rp")) { 00855 h->rp = (atoi(p) ? 1 : 0); 00856 } else if (!strcmp(line, "scts")) { /* get date/time */ 00857 int Y, m, d, H, M, S; 00858 /* XXX Why aren't we using ast_strptime here? */ 00859 if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) { 00860 struct ast_tm t = { 0, }; 00861 t.tm_year = Y - 1900; 00862 t.tm_mon = m - 1; 00863 t.tm_mday = d; 00864 t.tm_hour = H; 00865 t.tm_min = M; 00866 t.tm_sec = S; 00867 t.tm_isdst = -1; 00868 h->scts = ast_mktime(&t, NULL); 00869 if (h->scts.tv_sec == 0) { 00870 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p); 00871 } 00872 } 00873 } else { 00874 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p); 00875 } 00876 } 00877 } else if (*p == '#') { /* raw hex format */ 00878 *p++ = 0; 00879 if (*p == '#') { 00880 p++; 00881 if (!strcmp(line, "ud")) { /* user data */ 00882 int o = 0; 00883 while (*p && o < SMSLEN) { 00884 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) { 00885 h->ud[o++] = 00886 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) + 00887 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) + 00888 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF)); 00889 p += 4; 00890 } else 00891 break; 00892 } 00893 h->udl = o; 00894 if (*p) 00895 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn); 00896 } else 00897 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn); 00898 } else if (!strcmp(line, "ud")) { /* user data */ 00899 int o = 0; 00900 while (*p && o < SMSLEN) { 00901 if (isxdigit(*p) && isxdigit(p[1])) { 00902 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)); 00903 p += 2; 00904 } else { 00905 break; 00906 } 00907 } 00908 h->udl = o; 00909 if (*p) { 00910 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn); 00911 } 00912 } else if (!strcmp(line, "udh")) { /* user data header */ 00913 unsigned char o = 0; 00914 h->udhi = 1; 00915 while (*p && o < SMSLEN) { 00916 if (isxdigit(*p) && isxdigit(p[1])) { 00917 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)); 00918 o++; 00919 p += 2; 00920 } else { 00921 break; 00922 } 00923 } 00924 h->udhl = o; 00925 if (*p) { 00926 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn); 00927 } 00928 } else { 00929 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn); 00930 } 00931 } else { 00932 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line); 00933 } 00934 } 00935 fclose(s); 00936 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00937 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00938 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00939 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn); 00940 } else { 00941 h->dcs = 0x08; /* default to 16 bit */ 00942 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn); 00943 } 00944 } else { 00945 h->dcs = 0xF5; /* default to 8 bit */ 00946 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn); 00947 } 00948 } 00949 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00950 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn); 00951 } 00952 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00953 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn); 00954 } 00955 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00956 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn); 00957 } 00958 } 00959 }
static void sms_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static void sms_writefile | ( | sms_t * | h | ) | [static] |
white a received text message to a file
Definition at line 962 of file app_sms.c.
References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_mkdir(), ast_tvnow(), ast_tvzero(), buf, sms_s::da, isodate(), sms_s::oa, sms_s::queue, sms_s::rx, sms_s::scts, seq, sms_s::smsc, sms_s::ud, sms_s::udh, sms_s::udhi, sms_s::udhl, and sms_s::udl.
Referenced by sms_handleincoming().
00963 { 00964 char fn[200] = "", fn2[200] = ""; 00965 char buf[30]; 00966 FILE *o; 00967 00968 if (ast_tvzero(h->scts)) { 00969 h->scts = ast_tvnow(); 00970 } 00971 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx"); 00972 ast_mkdir(fn, 0777); /* ensure it exists */ 00973 ast_copy_string(fn2, fn, sizeof(fn2)); 00974 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++); 00975 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1); 00976 if ((o = fopen(fn, "w")) == NULL) { 00977 return; 00978 } 00979 00980 if (*h->oa) { 00981 fprintf(o, "oa=%s\n", h->oa); 00982 } 00983 if (*h->da) { 00984 fprintf(o, "da=%s\n", h->da); 00985 } 00986 if (h->udhi) { 00987 unsigned int p; 00988 fprintf(o, "udh#"); 00989 for (p = 0; p < h->udhl; p++) { 00990 fprintf(o, "%02X", h->udh[p]); 00991 } 00992 fprintf(o, "\n"); 00993 } 00994 if (h->udl) { 00995 unsigned int p; 00996 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++); 00997 if (p < h->udl) { 00998 fputc(';', o); /* cannot use ud=, but include as a comment for human readable */ 00999 } 01000 fprintf(o, "ud="); 01001 for (p = 0; p < h->udl; p++) { 01002 unsigned short v = h->ud[p]; 01003 if (v < 32) { 01004 fputc(191, o); 01005 } else if (v < 0x80) { 01006 fputc(v, o); 01007 } else if (v < 0x800) { 01008 fputc(0xC0 + (v >> 6), o); 01009 fputc(0x80 + (v & 0x3F), o); 01010 } else { 01011 fputc(0xE0 + (v >> 12), o); 01012 fputc(0x80 + ((v >> 6) & 0x3F), o); 01013 fputc(0x80 + (v & 0x3F), o); 01014 } 01015 } 01016 fprintf(o, "\n"); 01017 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++); 01018 if (p < h->udl) { 01019 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++); 01020 if (p == h->udl) { /* can write in ucs-1 hex */ 01021 fprintf(o, "ud#"); 01022 for (p = 0; p < h->udl; p++) { 01023 fprintf(o, "%02X", h->ud[p]); 01024 } 01025 fprintf(o, "\n"); 01026 } else { /* write in UCS-2 */ 01027 fprintf(o, "ud##"); 01028 for (p = 0; p < h->udl; p++) { 01029 fprintf(o, "%04X", h->ud[p]); 01030 } 01031 fprintf(o, "\n"); 01032 } 01033 } 01034 } 01035 if (h->scts.tv_sec) { 01036 char datebuf[30]; 01037 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf))); 01038 } 01039 if (h->pid) { 01040 fprintf(o, "pid=%d\n", h->pid); 01041 } 01042 if (h->dcs != 0xF1) { 01043 fprintf(o, "dcs=%d\n", h->dcs); 01044 } 01045 if (h->vp) { 01046 fprintf(o, "vp=%d\n", h->vp); 01047 } 01048 if (h->srr) { 01049 fprintf(o, "srr=1\n"); 01050 } 01051 if (h->mr >= 0) { 01052 fprintf(o, "mr=%d\n", h->mr); 01053 } 01054 if (h->rp) { 01055 fprintf(o, "rp=1\n"); 01056 } 01057 fclose(o); 01058 if (rename(fn, fn2)) { 01059 unlink(fn); 01060 } else { 01061 ast_log(LOG_EVENT, "Received to %s\n", fn2); 01062 } 01063 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2025 of file app_sms.c.
References app, and ast_unregister_application().
02026 { 02027 return ast_unregister_application(app); 02028 }
static unsigned char unpackaddress | ( | char * | o, | |
unsigned char * | i | |||
) | [static] |
unpack an address from i, return byte length, unpack to o
Definition at line 697 of file app_sms.c.
Referenced by sms_handleincoming().
00698 { 00699 unsigned char l = i[0], p; 00700 if (i[1] == 0x91) { 00701 *o++ = '+'; 00702 } 00703 for (p = 0; p < l; p++) { 00704 if (p & 1) { 00705 *o++ = (i[2 + p / 2] >> 4) + '0'; 00706 } else { 00707 *o++ = (i[2 + p / 2] & 0xF) + '0'; 00708 } 00709 } 00710 *o = 0; 00711 return (l + 5) / 2; 00712 }
static struct timeval unpackdate | ( | unsigned char * | i | ) | [static] |
unpack a date and return
Definition at line 549 of file app_sms.c.
References ast_mktime().
Referenced by sms_handleincoming().
00550 { 00551 struct ast_tm t; 00552 00553 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4); 00554 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1; 00555 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4); 00556 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4); 00557 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4); 00558 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4); 00559 t.tm_isdst = 0; 00560 if (i[6] & 0x08) { 00561 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4)); 00562 } else { 00563 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4)); 00564 } 00565 00566 return ast_mktime(&t, NULL); 00567 }
static int unpacksms | ( | unsigned char | dcs, | |
unsigned char * | i, | |||
unsigned char * | udh, | |||
int * | udhl, | |||
unsigned short * | ud, | |||
int * | udl, | |||
char | udhi | |||
) | [static] |
general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length
Definition at line 682 of file app_sms.c.
References is7bit, is8bit, unpacksms16(), unpacksms7(), and unpacksms8().
Referenced by sms_handleincoming().
00683 { 00684 int l = *i++; 00685 if (is7bit(dcs)) { 00686 unpacksms7(i, l, udh, udhl, ud, udl, udhi); 00687 l = (l * 7 + 7) / 8; /* adjust length to return */ 00688 } else if (is8bit(dcs)) { 00689 unpacksms8(i, l, udh, udhl, ud, udl, udhi); 00690 } else { 00691 unpacksms16(i, l, udh, udhl, ud, udl, udhi); 00692 } 00693 return l + 1; 00694 }
static void unpacksms16 | ( | unsigned char * | i, | |
unsigned char | l, | |||
unsigned char * | udh, | |||
int * | udhl, | |||
unsigned short * | ud, | |||
int * | udl, | |||
char | udhi | |||
) | [static] |
unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set
Definition at line 654 of file app_sms.c.
Referenced by unpacksms().
00655 { 00656 unsigned short *o = ud; 00657 *udhl = 0; 00658 if (udhi) { 00659 int n = *i; 00660 *udhl = n; 00661 if (n) { 00662 i++; 00663 l--; 00664 while (l && n) { 00665 l--; 00666 n--; 00667 *udh++ = *i++; 00668 } 00669 } 00670 } 00671 while (l--) { 00672 int v = *i++; 00673 if (l--) { 00674 v = (v << 8) + *i++; 00675 } 00676 *o++ = v; 00677 } 00678 *udl = (o - ud); 00679 }
static void unpacksms7 | ( | unsigned char * | i, | |
unsigned char | l, | |||
unsigned char * | udh, | |||
int * | udhl, | |||
unsigned short * | ud, | |||
int * | udl, | |||
char | udhi | |||
) | [static] |
unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set
Definition at line 572 of file app_sms.c.
Referenced by unpacksms().
00573 { 00574 unsigned char b = 0, p = 0; 00575 unsigned short *o = ud; 00576 *udhl = 0; 00577 if (udhi && l) { /* header */ 00578 int h = i[p]; 00579 *udhl = h; 00580 if (h) { 00581 b = 1; 00582 p++; 00583 l--; 00584 while (h-- && l) { 00585 *udh++ = i[p++]; 00586 b += 8; 00587 while (b >= 7) { 00588 b -= 7; 00589 l--; 00590 if (!l) { 00591 break; 00592 } 00593 } 00594 } 00595 /* adjust for fill, septets */ 00596 if (b) { 00597 b = 7 - b; 00598 l--; 00599 } 00600 } 00601 } 00602 while (l--) { 00603 unsigned char v; 00604 if (b < 2) { 00605 v = ((i[p] >> b) & 0x7F); /* everything in one byte */ 00606 } else { 00607 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F); 00608 } 00609 b += 7; 00610 if (b >= 8) { 00611 b -= 8; 00612 p++; 00613 } 00614 /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */ 00615 if (o > ud && o[-1] == 0x00A0 && escapes[v]) { 00616 o[-1] = escapes[v]; 00617 } else { 00618 *o++ = defaultalphabet[v]; 00619 } 00620 } 00621 *udl = (o - ud); 00622 }
static void unpacksms8 | ( | unsigned char * | i, | |
unsigned char | l, | |||
unsigned char * | udh, | |||
int * | udhl, | |||
unsigned short * | ud, | |||
int * | udl, | |||
char | udhi | |||
) | [static] |
unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set.
Definition at line 628 of file app_sms.c.
Referenced by unpacksms().
00629 { 00630 unsigned short *o = ud; 00631 *udhl = 0; 00632 if (udhi) { 00633 int n = *i; 00634 *udhl = n; 00635 if (n) { 00636 i++; 00637 l--; 00638 while (l && n) { 00639 l--; 00640 n--; 00641 *udh++ = *i++; 00642 } 00643 } 00644 } 00645 while (l--) { 00646 *o++ = *i++; /* not to UTF-8 as explicitly 8 bit coding in DCS */ 00647 } 00648 *udl = (o - ud); 00649 }
static long utf8decode | ( | unsigned char ** | pp | ) | [static] |
Reads next UCS character from NUL terminated UTF-8 string and advance pointer.
Definition at line 285 of file app_sms.c.
Referenced by sms_readfile().
00286 { 00287 unsigned char *p = *pp; 00288 if (!*p) { 00289 return 0; /* null termination of string */ 00290 } 00291 (*pp)++; 00292 if (*p < 0xC0) { 00293 return *p; /* ascii or continuation character */ 00294 } 00295 if (*p < 0xE0) { 00296 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) { 00297 return *p; /* not valid UTF-8 */ 00298 } 00299 (*pp)++; 00300 return ((*p & 0x1F) << 6) + (p[1] & 0x3F); 00301 } 00302 if (*p < 0xF0) { 00303 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) { 00304 return *p; /* not valid UTF-8 */ 00305 } 00306 (*pp) += 2; 00307 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F); 00308 } 00309 if (*p < 0xF8) { 00310 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) { 00311 return *p; /* not valid UTF-8 */ 00312 } 00313 (*pp) += 3; 00314 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F); 00315 } 00316 if (*p < 0xFC) { 00317 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80 00318 || (p[4] & 0xC0) != 0x80) { 00319 return *p; /* not valid UTF-8 */ 00320 } 00321 (*pp) += 4; 00322 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F); 00323 } 00324 if (*p < 0xFE) { 00325 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80 00326 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) { 00327 return *p; /* not valid UTF-8 */ 00328 } 00329 (*pp) += 5; 00330 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F); 00331 } 00332 return *p; /* not sensible */ 00333 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "SMS/PSTN handler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
const unsigned short defaultalphabet[] [static] |
char log_file[255] [static] |
volatile unsigned char message_ref [static] |
volatile unsigned int seq [static] |
Definition at line 65 of file app_sms.c.
Referenced by __manager_event(), append_event(), ast_udptl_write(), handle_link_data(), handle_remote_data(), parsing(), process_cisco_dtmf(), send_retransmit(), sms_writefile(), statpost(), and udptl_build_packet().
enum { ... } sms_flags |
enum { ... } sms_opt_args |
struct ast_app_option sms_options[128] = { [ 's' ] = { .flag = OPTION_BE_SMSC }, [ 'a' ] = { .flag = OPTION_ANSWER }, [ 't' ] = { .flag = OPTION_TWO }, [ 'r' ] = { .flag = OPTION_SRR }, [ 'o' ] = { .flag = OPTION_DCS }, [ 'p' ] = { .flag = OPTION_PAUSE , .arg_index = OPTION_ARG_PAUSE + 1 }, } [static] |
struct ast_generator smsgen [static] |
Initial value:
{ .alloc = sms_alloc, .release = sms_release, .generate = sms_generate, }
signed short wave[] [static] |