SMS application - ETSI ES 201 912 protocol 1 implementation. More...
#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 struct sms_s | sms_t |
Enumerations | |
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 } |
enum | sms_flags { 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 | sms_opt_args { OPTION_ARG_PAUSE = 0, OPTION_ARG_ARRAY_SIZE } |
Functions | |
static void | adddata_proto2 (sms_t *h, unsigned char msg, char *data, int size) |
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),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"SMS/PSTN handler") | |
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, const char *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 char * | app = "SMS" |
static const unsigned short | defaultalphabet [] |
static const unsigned short | escapes [] |
static char | log_file [255] |
static volatile unsigned char | message_ref |
static volatile unsigned int | seq |
static struct ast_generator | smsgen |
static const signed short | wave [] |
static const output_t * | wave_out = wave |
SMS application - ETSI ES 201 912 protocol 1 implementation.
ES 201 912 SMS for PSTN/ISDN TS 123 040 Technical realization of SMS
Definition in file app_sms.c.
#define __OUT_FMT AST_FORMAT_SLINEAR |
Definition at line 147 of file app_sms.c.
Referenced by sms_generate().
#define DIR_RX 1 |
Definition at line 1472 of file app_sms.c.
Referenced by sms_debug(), and sms_messagerx().
#define DIR_TX 2 |
Definition at line 1473 of file app_sms.c.
Referenced by sms_messagetx().
#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) ) |
Definition at line 279 of file app_sms.c.
Referenced by sms_readfile().
#define is7bit | ( | dcs | ) | ( ((dcs) & 0xC0) ? (!((dcs) & 4) ) : (((dcs) & 0xc) == 0) ) |
Definition at line 277 of file app_sms.c.
Referenced by packsms(), sms_readfile(), and unpacksms().
#define is8bit | ( | dcs | ) | ( ((dcs) & 0xC0) ? ( ((dcs) & 4) ) : (((dcs) & 0xc) == 4) ) |
Definition at line 278 of file app_sms.c.
Referenced by packsms(), sms_readfile(), and unpacksms().
#define MAX_DEBUG_LEN 300 |
Definition at line 1238 of file app_sms.c.
Referenced by sms_handleincoming_proto2(), and sms_hexdump().
#define MAXSAMPLES (800) |
Referenced by sms_generate().
#define OSYNC_BITS 80 |
Definition at line 150 of file app_sms.c.
Referenced by sms_messagetx().
#define SMSLEN 160 |
max SMS length
Definition at line 213 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 214 of file app_sms.c.
Referenced by packsms16(), and packsms8().
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 159 of file app_sms.c.
00159 { 00160 DLL_SMS_MASK = 0x7f, /* mask for the valid bits */ 00161 00162 /* Protocol 1 values */ 00163 DLL1_SMS_DATA = 0x11, /* data packet */ 00164 DLL1_SMS_ERROR = 0x12, 00165 DLL1_SMS_EST = 0x13, /* start the connection */ 00166 DLL1_SMS_REL = 0x14, /* end the connection */ 00167 DLL1_SMS_ACK = 0x15, 00168 DLL1_SMS_NACK = 0x16, 00169 00170 DLL1_SMS_COMPLETE = 0x80, /* packet is complete */ 00171 DLL1_SMS_MORE = 0x00, /* more data to follow */ 00172 00173 /* Protocol 2 values */ 00174 DLL2_SMS_EST = 0x7f, /* magic number. No message body */ 00175 DLL2_SMS_INFO_MO = 0x10, 00176 DLL2_SMS_INFO_MT = 0x11, 00177 DLL2_SMS_INFO_STA = 0x12, 00178 DLL2_SMS_NACK = 0x13, 00179 DLL2_SMS_ACK0 = 0x14, /* ack even-numbered frame */ 00180 DLL2_SMS_ACK1 = 0x15, /* ack odd-numbered frame */ 00181 DLL2_SMS_ENQ = 0x16, 00182 DLL2_SMS_REL = 0x17, /* end the connection */ 00183 00184 DLL2_SMS_COMPLETE = 0x00, /* packet is complete */ 00185 DLL2_SMS_MORE = 0x80, /* more data to follow */ 00186 };
enum sms_flags |
Definition at line 1839 of file app_sms.c.
01839 { 01840 OPTION_BE_SMSC = (1 << 0), /* act as sms center */ 01841 OPTION_ANSWER = (1 << 1), /* answer on incoming calls */ 01842 OPTION_TWO = (1 << 2), /* Use Protocol Two */ 01843 OPTION_PAUSE = (1 << 3), /* pause before sending data, in ms */ 01844 OPTION_SRR = (1 << 4), /* set srr */ 01845 OPTION_DCS = (1 << 5), /* set dcs */ 01846 };
enum sms_opt_args |
Definition at line 1848 of file app_sms.c.
01848 { 01849 OPTION_ARG_PAUSE = 0, 01850 OPTION_ARG_ARRAY_SIZE 01851 };
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 1178 of file app_sms.c.
References sms_s::omsg.
Referenced by sms_compose2().
01179 { 01180 int x = h->omsg[1] + 2; /* Get current position */ 01181 if (x == 2) { 01182 x += 2; /* First: skip Payload length (set later) */ 01183 } 01184 h->omsg[x++] = msg; /* Message code */ 01185 h->omsg[x++] = (unsigned char)size; /* Data size Low */ 01186 h->omsg[x++] = 0; /* Data size Hi */ 01187 for (; size > 0 ; size--) { 01188 h->omsg[x++] = *data++; 01189 } 01190 h->omsg[1] = x - 2; /* Frame size */ 01191 h->omsg[2] = x - 4; /* Payload length (Lo) */ 01192 h->omsg[3] = 0; /* Payload length (Hi) */ 01193 }
AST_APP_OPTIONS | ( | sms_options | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"SMS/PSTN handler" | ||||
) |
static char* isodate | ( | time_t | t, | |
char * | buf, | |||
int | len | |||
) | [static] |
static, return a date/time in ISO format
Definition at line 299 of file app_sms.c.
References ast_localtime(), and ast_strftime().
Referenced by sms_log(), and sms_writefile().
00300 { 00301 struct ast_tm tm; 00302 struct timeval local = { t, 0 }; 00303 ast_localtime(&local, &tm, NULL); 00304 ast_strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); 00305 return buf; 00306 }
static int load_module | ( | void | ) | [static] |
Definition at line 2063 of file app_sms.c.
References ast_config_AST_LOG_DIR, AST_LIN2A, ast_register_application_xml, and sms_exec().
02064 { 02065 #ifdef OUTALAW 02066 int p; 02067 for (p = 0; p < 80; p++) { 02068 wavea[p] = AST_LIN2A(wave[p]); 02069 } 02070 #endif 02071 snprintf(log_file, sizeof(log_file), "%s/sms", ast_config_AST_LOG_DIR); 02072 return ast_register_application_xml(app, sms_exec); 02073 }
static void numcpy | ( | char * | d, | |
char * | s | |||
) | [static] |
copy number, skipping non digits apart from leading +
Definition at line 284 of file app_sms.c.
Referenced by sms_readfile().
static unsigned char packaddress | ( | unsigned char * | o, | |
char * | i | |||
) | [static] |
store an address at o, and return number of bytes used
Definition at line 741 of file app_sms.c.
Referenced by sms_compose1().
00742 { 00743 unsigned char p = 2; 00744 o[0] = 0; /* number of bytes */ 00745 if (*i == '+') { /* record as bit 0 in byte 1 */ 00746 i++; 00747 o[1] = 0x91; 00748 } else { 00749 o[1] = 0x81; 00750 } 00751 for ( ; *i ; i++) { 00752 if (!isdigit(*i)) { /* ignore non-digits */ 00753 continue; 00754 } 00755 if (o[0] & 1) { 00756 o[p++] |= ((*i & 0xF) << 4); 00757 } else { 00758 o[p] = (*i & 0xF); 00759 } 00760 o[0]++; 00761 } 00762 if (o[0] & 1) { 00763 o[p++] |= 0xF0; /* pad */ 00764 } 00765 return p; 00766 }
static void packdate | ( | unsigned char * | o, | |
time_t | w | |||
) | [static] |
pack a date and return
Definition at line 549 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().
00550 { 00551 struct ast_tm t; 00552 struct timeval topack = { w, 0 }; 00553 int z; 00554 00555 ast_localtime(&topack, &t, NULL); 00556 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__) || defined(__CYGWIN__) 00557 z = -t.tm_gmtoff / 60 / 15; 00558 #else 00559 z = timezone / 60 / 15; 00560 #endif 00561 *o++ = ((t.tm_year % 10) << 4) + (t.tm_year % 100) / 10; 00562 *o++ = (((t.tm_mon + 1) % 10) << 4) + (t.tm_mon + 1) / 10; 00563 *o++ = ((t.tm_mday % 10) << 4) + t.tm_mday / 10; 00564 *o++ = ((t.tm_hour % 10) << 4) + t.tm_hour / 10; 00565 *o++ = ((t.tm_min % 10) << 4) + t.tm_min / 10; 00566 *o++ = ((t.tm_sec % 10) << 4) + t.tm_sec / 10; 00567 if (z < 0) { 00568 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08; 00569 } else { 00570 *o++ = ((z % 10) << 4) + z / 10; 00571 } 00572 }
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 516 of file app_sms.c.
References is7bit, is8bit, packsms16(), packsms7(), and packsms8().
Referenced by sms_compose1().
00517 { 00518 unsigned char *p = base; 00519 if (udl == 0) { 00520 *p++ = 0; /* no user data */ 00521 } else { 00522 00523 int l = 0; 00524 if (is7bit(dcs)) { /* 7 bit */ 00525 if ((l = packsms7(p + 1, udhl, udh, udl, ud)) < 0) { 00526 l = 0; 00527 } 00528 *p++ = l; 00529 p += (l * 7 + 7) / 8; 00530 } else if (is8bit(dcs)) { /* 8 bit */ 00531 if ((l = packsms8(p + 1, udhl, udh, udl, ud)) < 0) { 00532 l = 0; 00533 } 00534 *p++ = l; 00535 p += l; 00536 } else { /* UCS-2 */ 00537 if ((l = packsms16(p + 1, udhl, udh, udl, ud)) < 0) { 00538 l = 0; 00539 } 00540 *p++ = l; 00541 p += l; 00542 } 00543 } 00544 return p - base; 00545 }
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 481 of file app_sms.c.
References dummy(), and SMSLEN_8.
Referenced by packsms(), and sms_readfile().
00482 { 00483 unsigned char p = 0; 00484 unsigned char dummy[SMSLEN_8]; 00485 00486 if (o == NULL) { 00487 o = dummy; 00488 } 00489 /* header - no encoding */ 00490 if (udhl) { 00491 o[p++] = udhl; 00492 while (udhl--) { 00493 o[p++] = *udh++; 00494 if (p >= SMSLEN_8) { 00495 return p; 00496 } 00497 } 00498 } 00499 while (udl--) { 00500 long u; 00501 u = *ud++; 00502 o[p++] = (u >> 8); 00503 if (p >= SMSLEN_8) { 00504 return p - 1; /* could not fit last character */ 00505 } 00506 o[p++] = u; 00507 if (p >= SMSLEN_8) { 00508 return p; 00509 } 00510 } 00511 return p; 00512 }
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 365 of file app_sms.c.
References dummy(), and SMSLEN.
Referenced by packsms(), and sms_readfile().
00366 { 00367 unsigned char p = 0; /* output pointer (bytes) */ 00368 unsigned char b = 0; /* bit position */ 00369 unsigned char n = 0; /* output character count */ 00370 unsigned char dummy[SMSLEN]; 00371 00372 if (o == NULL) { /* output to a dummy buffer if o not set */ 00373 o = dummy; 00374 } 00375 00376 if (udhl) { /* header */ 00377 o[p++] = udhl; 00378 b = 1; 00379 n = 1; 00380 while (udhl--) { 00381 o[p++] = *udh++; 00382 b += 8; 00383 while (b >= 7) { 00384 b -= 7; 00385 n++; 00386 } 00387 if (n >= SMSLEN) 00388 return n; 00389 } 00390 if (b) { 00391 b = 7 - b; 00392 if (++n >= SMSLEN) 00393 return n; 00394 } /* filling to septet boundary */ 00395 } 00396 o[p] = 0; 00397 /* message */ 00398 while (udl--) { 00399 long u; 00400 unsigned char v; 00401 u = *ud++; 00402 /* XXX 0 is invalid ? */ 00403 /* look up in defaultalphabet[]. If found, v is the 7-bit code */ 00404 for (v = 0; v < 128 && defaultalphabet[v] != u; v++); 00405 if (v == 128 /* not found */ && u && n + 1 < SMSLEN) { 00406 /* if not found, look in the escapes table (we need 2 bytes) */ 00407 for (v = 0; v < 128 && escapes[v] != u; v++); 00408 if (v < 128) { /* escaped sequence, esc + v */ 00409 /* store the low (8-b) bits in o[p], the remaining bits in o[p+1] */ 00410 o[p] |= (27 << b); /* the low bits go into o[p] */ 00411 b += 7; 00412 if (b >= 8) { 00413 b -= 8; 00414 p++; 00415 o[p] = (27 >> (7 - b)); 00416 } 00417 n++; 00418 } 00419 } 00420 if (v == 128) 00421 return -1; /* invalid character */ 00422 /* store, same as above */ 00423 o[p] |= (v << b); 00424 b += 7; 00425 if (b >= 8) { 00426 b -= 8; 00427 p++; 00428 o[p] = (v >> (7 - b)); 00429 } 00430 if (++n >= SMSLEN) 00431 return n; 00432 } 00433 return n; 00434 }
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 442 of file app_sms.c.
References dummy(), and SMSLEN_8.
Referenced by packsms(), and sms_readfile().
00443 { 00444 unsigned char p = 0; 00445 unsigned char dummy[SMSLEN_8]; 00446 00447 if (o == NULL) 00448 o = dummy; 00449 /* header - no encoding */ 00450 if (udhl) { 00451 o[p++] = udhl; 00452 while (udhl--) { 00453 o[p++] = *udh++; 00454 if (p >= SMSLEN_8) { 00455 return p; 00456 } 00457 } 00458 } 00459 while (udl--) { 00460 long u; 00461 u = *ud++; 00462 if (u < 0 || u > 0xFF) { 00463 return -1; /* not valid */ 00464 } 00465 o[p++] = u; 00466 if (p >= SMSLEN_8) { 00467 return p; 00468 } 00469 } 00470 return p; 00471 }
static void putdummydata_proto2 | ( | sms_t * | h | ) | [static] |
Referenced by sms_compose2().
static struct dirent* readdirqueue | ( | DIR * | d, | |
char * | queue | |||
) | [static, read] |
read dir skipping dot files...
Definition at line 1092 of file app_sms.c.
References f.
Referenced by sms_nextoutgoing().
01093 { 01094 struct dirent *f; 01095 do { 01096 f = readdir(d); 01097 } while (f && (*f->d_name == '.' || strncmp(f->d_name, queue, strlen(queue)) || f->d_name[strlen(queue)] != '.')); 01098 return f; 01099 }
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 1390 of file app_sms.c.
References sms_s::da, sms_s::dcs, 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().
01391 { 01392 unsigned int p = 2; /* next byte to write. Skip type and len */ 01393 01394 h->omsg[0] = 0x91; /* SMS_DATA */ 01395 if (h->smsc) { /* deliver */ 01396 h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0); 01397 p += packaddress(h->omsg + p, h->oa); 01398 h->omsg[p++] = h->pid; 01399 h->omsg[p++] = h->dcs; 01400 packdate(h->omsg + p, h->scts.tv_sec); 01401 p += 7; 01402 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud); 01403 } else { /* submit */ 01404 h->omsg[p++] = 01405 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0); 01406 if (h->mr < 0) { 01407 h->mr = message_ref++; 01408 } 01409 h->omsg[p++] = h->mr; 01410 p += packaddress(h->omsg + p, h->da); 01411 h->omsg[p++] = h->pid; 01412 h->omsg[p++] = h->dcs; 01413 if (h->vp) { /* relative VP */ 01414 if (h->vp < 720) { 01415 h->omsg[p++] = (h->vp + 4) / 5 - 1; 01416 } else if (h->vp < 1440) { 01417 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143; 01418 } else if (h->vp < 43200) { 01419 h->omsg[p++] = (h->vp + 1439) / 1440 + 166; 01420 } else if (h->vp < 635040) { 01421 h->omsg[p++] = (h->vp + 10079) / 10080 + 192; 01422 } else { 01423 h->omsg[p++] = 255; /* max */ 01424 } 01425 } 01426 p += packsms(h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud); 01427 } 01428 h->omsg[1] = p - 2; 01429 }
static void sms_compose2 | ( | sms_t * | h, | |
int | more | |||
) | [static] |
Definition at line 1203 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().
01204 { 01205 struct ast_tm tm; 01206 struct timeval now = h->scts; 01207 char stm[9]; 01208 01209 h->omsg[0] = 0x00; /* set later... */ 01210 h->omsg[1] = 0; 01211 putdummydata_proto2(h); 01212 if (h->smsc) { /* deliver */ 01213 h->omsg[0] = 0x11; /* SMS_DELIVERY */ 01214 /* Required: 10 11 12 13 14 15 17 (seems they must be ordered!) */ 01215 ast_localtime(&now, &tm, NULL); 01216 sprintf(stm, "%02d%02d%02d%02d", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min); /* Date mmddHHMM */ 01217 adddata_proto2(h, 0x14, stm, 8); /* Date */ 01218 if (*h->oa == 0) { 01219 strcpy(h->oa, "00000000"); 01220 } 01221 adddata_proto2(h, 0x15, h->oa, strlen(h->oa)); /* Originator */ 01222 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */ 01223 } else { /* submit */ 01224 h->omsg[0] = 0x10; /* SMS_SUBMIT */ 01225 /* Required: 10 11 12 13 17 18 1B 1C (seems they must be ordered!) */ 01226 adddata_proto2(h, 0x17, "\1", 1); /* Calling Terminal ID */ 01227 if (*h->da == 0) { 01228 strcpy(h->da, "00000000"); 01229 } 01230 adddata_proto2(h, 0x18, h->da, strlen(h->da)); /* Originator */ 01231 adddata_proto2(h, 0x1B, "\1", 1); /* Called Terminal ID */ 01232 adddata_proto2(h, 0x1C, "\0\0\0", 3); /* Notification */ 01233 } 01234 }
static void sms_debug | ( | int | dir, | |
sms_t * | h | |||
) | [static] |
Definition at line 1474 of file app_sms.c.
References ast_verb, DIR_RX, sms_s::ibytep, sms_s::imsg, and sms_s::omsg.
Referenced by sms_messagerx(), and sms_messagetx().
01475 { 01476 char txt[259 * 3 + 1]; 01477 char *p = txt; /* always long enough */ 01478 unsigned char *msg = (dir == DIR_RX) ? h->imsg : h->omsg; 01479 int n = (dir == DIR_RX) ? h->ibytep : msg[1] + 2; 01480 int q = 0; 01481 while (q < n && q < 30) { 01482 sprintf(p, " %02X", msg[q++]); 01483 p += 3; 01484 } 01485 if (q < n) { 01486 sprintf(p, "..."); 01487 } 01488 ast_verb(3, "SMS %s%s\n", dir == DIR_RX ? "RX" : "TX", txt); 01489 }
static int sms_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1862 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, ast_channel::caller, sms_s::cli, sms_s::dcs, ast_party_caller::id, sms_s::ipc0, sms_s::ipc1, LOG_ERROR, ast_party_id::number, 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_COR, S_OR, sms_s::smsc, sms_s::srr, ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
01863 { 01864 int res = -1; 01865 sms_t h = { 0 }; 01866 /* argument parsing support */ 01867 struct ast_flags flags; 01868 char *parse, *sms_opts[OPTION_ARG_ARRAY_SIZE] = { 0, }; 01869 char *p; 01870 AST_DECLARE_APP_ARGS(sms_args, 01871 AST_APP_ARG(queue); 01872 AST_APP_ARG(options); 01873 AST_APP_ARG(addr); 01874 AST_APP_ARG(body); 01875 ); 01876 01877 if (!data) { 01878 ast_log(LOG_ERROR, "Requires queue name at least\n"); 01879 return -1; 01880 } 01881 01882 parse = ast_strdupa(data); /* create a local copy */ 01883 AST_STANDARD_APP_ARGS(sms_args, parse); 01884 if (sms_args.argc > 1) { 01885 ast_app_parse_options(sms_options, &flags, sms_opts, sms_args.options); 01886 } 01887 01888 ast_verb(1, "sms argc %d queue <%s> opts <%s> addr <%s> body <%s>\n", 01889 sms_args.argc, S_OR(sms_args.queue, ""), 01890 S_OR(sms_args.options, ""), 01891 S_OR(sms_args.addr, ""), 01892 S_OR(sms_args.body, "") ); 01893 01894 h.ipc0 = h.ipc1 = 20; /* phase for cosine */ 01895 h.dcs = 0xF1; /* default */ 01896 01897 ast_copy_string(h.cli, 01898 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""), 01899 sizeof(h.cli)); 01900 01901 if (ast_strlen_zero(sms_args.queue)) { 01902 ast_log(LOG_ERROR, "Requires queue name\n"); 01903 goto done; 01904 } 01905 if (strlen(sms_args.queue) >= sizeof(h.queue)) { 01906 ast_log(LOG_ERROR, "Queue name too long\n"); 01907 goto done; 01908 } 01909 ast_copy_string(h.queue, sms_args.queue, sizeof(h.queue)); 01910 01911 for (p = h.queue; *p; p++) { 01912 if (!isalnum(*p)) { 01913 *p = '-'; /* make very safe for filenames */ 01914 } 01915 } 01916 01917 h.smsc = ast_test_flag(&flags, OPTION_BE_SMSC); 01918 h.protocol = ast_test_flag(&flags, OPTION_TWO) ? 2 : 1; 01919 if (!ast_strlen_zero(sms_opts[OPTION_ARG_PAUSE])) { 01920 h.opause_0 = atoi(sms_opts[OPTION_ARG_PAUSE]); 01921 } 01922 if (h.opause_0 < 25 || h.opause_0 > 2000) { 01923 h.opause_0 = 300; /* default 300ms */ 01924 } 01925 ast_verb(1, "initial delay %dms\n", h.opause_0); 01926 01927 01928 /* the following apply if there is an arg3/4 and apply to the created message file */ 01929 if (ast_test_flag(&flags, OPTION_SRR)) { 01930 h.srr = 1; 01931 } 01932 if (ast_test_flag(&flags, OPTION_DCS)) { 01933 h.dcs = 1; 01934 } 01935 #if 0 01936 case '1': 01937 case '2': 01938 case '3': 01939 case '4': 01940 case '5': 01941 case '6': 01942 case '7': /* set the pid for saved local message */ 01943 h.pid = 0x40 + (*d & 0xF); 01944 break; 01945 } 01946 #endif 01947 if (sms_args.argc > 2) { 01948 unsigned char *up; 01949 01950 /* submitting a message, not taking call. */ 01951 /* deprecated, use smsq instead */ 01952 h.scts = ast_tvnow(); 01953 if (ast_strlen_zero(sms_args.addr) || strlen(sms_args.addr) >= sizeof(h.oa)) { 01954 ast_log(LOG_ERROR, "Address too long %s\n", sms_args.addr); 01955 goto done; 01956 } 01957 if (h.smsc) { 01958 ast_copy_string(h.oa, sms_args.addr, sizeof(h.oa)); 01959 } else { 01960 ast_copy_string(h.da, sms_args.addr, sizeof(h.da)); 01961 ast_copy_string(h.oa, h.cli, sizeof(h.oa)); 01962 } 01963 h.udl = 0; 01964 if (ast_strlen_zero(sms_args.body)) { 01965 ast_log(LOG_ERROR, "Missing body for %s\n", sms_args.addr); 01966 goto done; 01967 } 01968 up = (unsigned char *)sms_args.body; 01969 while (*up && h.udl < SMSLEN) { 01970 h.ud[h.udl++] = utf8decode(&up); 01971 } 01972 if (is7bit(h.dcs) && packsms7(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01973 ast_log(LOG_WARNING, "Invalid 7 bit GSM data\n"); 01974 goto done; 01975 } 01976 if (is8bit(h.dcs) && packsms8(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01977 ast_log(LOG_WARNING, "Invalid 8 bit data\n"); 01978 goto done; 01979 } 01980 if (is16bit(h.dcs) && packsms16(0, h.udhl, h.udh, h.udl, h.ud) < 0) { 01981 ast_log(LOG_WARNING, "Invalid 16 bit data\n"); 01982 goto done; 01983 } 01984 h.rx = 0; /* sent message */ 01985 h.mr = -1; 01986 sms_writefile(&h); 01987 res = h.err; 01988 goto done; 01989 } 01990 01991 if (chan->_state != AST_STATE_UP) { /* make sure channel is answered before any TX */ 01992 ast_answer(chan); 01993 } 01994 01995 if (ast_test_flag(&flags, OPTION_ANSWER)) { 01996 h.framenumber = 1; /* Proto 2 */ 01997 /* set up SMS_EST initial message */ 01998 if (h.protocol == 2) { 01999 h.omsg[0] = DLL2_SMS_EST; 02000 h.omsg[1] = 0; 02001 } else { 02002 h.omsg[0] = DLL1_SMS_EST | DLL1_SMS_COMPLETE; 02003 h.omsg[1] = 0; 02004 } 02005 sms_messagetx(&h); 02006 } 02007 02008 res = ast_set_write_format(chan, __OUT_FMT); 02009 if (res >= 0) { 02010 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 02011 } 02012 if (res < 0) { 02013 ast_log(LOG_ERROR, "Unable to set to linear mode, giving up\n"); 02014 goto done; 02015 } 02016 02017 if ( (res = ast_activate_generator(chan, &smsgen, &h)) < 0) { 02018 ast_log(LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name); 02019 goto done; 02020 } 02021 02022 /* Do our thing here */ 02023 for (;;) { 02024 struct ast_frame *f; 02025 int i = ast_waitfor(chan, -1); 02026 if (i < 0) { 02027 ast_log(LOG_NOTICE, "waitfor failed\n"); 02028 break; 02029 } 02030 if (h.hangup) { 02031 ast_log(LOG_NOTICE, "channel hangup\n"); 02032 break; 02033 } 02034 f = ast_read(chan); 02035 if (!f) { 02036 ast_log(LOG_NOTICE, "ast_read failed\n"); 02037 break; 02038 } 02039 if (f->frametype == AST_FRAME_VOICE) { 02040 sms_process(&h, f->samples, f->data.ptr); 02041 } 02042 02043 ast_frfree(f); 02044 } 02045 res = h.err; /* XXX */ 02046 02047 /* 02048 * The SMS generator data is on the stack. We _MUST_ make sure the generator 02049 * is stopped before returning from this function. 02050 */ 02051 ast_deactivate_generator(chan); 02052 02053 sms_log(&h, '?'); /* log incomplete message */ 02054 done: 02055 return (res); 02056 }
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 1593 of file app_sms.c.
References __OUT_FMT, ast_alloca, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, DLL2_SMS_EST, errno, ast_frame::frametype, LOG_WARNING, ast_frame::mallocd, MAXSAMPLES, sms_s::obitp, sms_s::obyte, sms_s::obyten, sms_s::obytep, ast_frame::offset, sms_s::omsg, sms_s::opause, sms_s::ophase, sms_s::ophasep, sms_s::oseizure, sms_s::osync, sms_s::protocol, ast_frame::ptr, ast_frame::samples, ast_frame::src, and ast_frame::subclass.
01594 { 01595 struct ast_frame f = { 0 }; 01596 #define MAXSAMPLES (800) 01597 output_t *buf; 01598 sms_t *h = data; 01599 int i; 01600 01601 if (samples > MAXSAMPLES) { 01602 ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", 01603 MAXSAMPLES, samples); 01604 samples = MAXSAMPLES; 01605 } 01606 len = samples * sizeof(*buf) + AST_FRIENDLY_OFFSET; 01607 buf = ast_alloca(len); 01608 01609 f.frametype = AST_FRAME_VOICE; 01610 f.subclass.codec = __OUT_FMT; 01611 f.datalen = samples * sizeof(*buf); 01612 f.offset = AST_FRIENDLY_OFFSET; 01613 f.mallocd = 0; 01614 f.data.ptr = buf; 01615 f.samples = samples; 01616 f.src = "app_sms"; 01617 /* create a buffer containing the digital sms pattern */ 01618 for (i = 0; i < samples; i++) { 01619 buf[i] = wave_out[0]; /* default is silence */ 01620 01621 if (h->opause) { 01622 h->opause--; 01623 } else if (h->obyten || h->osync) { /* sending data */ 01624 buf[i] = wave_out[h->ophase]; 01625 h->ophase += (h->obyte & 1) ? 13 : 21; /* compute next phase */ 01626 if (h->ophase >= 80) 01627 h->ophase -= 80; 01628 if ((h->ophasep += 12) >= 80) { /* time to send the next bit */ 01629 h->ophasep -= 80; 01630 if (h->oseizure > 0) { /* sending channel seizure (proto 2) */ 01631 h->oseizure--; 01632 h->obyte ^= 1; /* toggle low bit */ 01633 } else if (h->osync) { 01634 h->obyte = 1; /* send mark as sync bit */ 01635 h->osync--; /* sending sync bits */ 01636 if (h->osync == 0 && h->protocol == 2 && h->omsg[0] == DLL2_SMS_EST) { 01637 h->obytep = h->obyten = 0; /* we are done */ 01638 } 01639 } else { 01640 h->obitp++; 01641 if (h->obitp == 1) { 01642 h->obyte = 0; /* start bit; */ 01643 } else if (h->obitp == 2) { 01644 h->obyte = h->omsg[h->obytep]; 01645 } else if (h->obitp == 10) { 01646 h->obyte = 1; /* stop bit */ 01647 h->obitp = 0; 01648 h->obytep++; 01649 if (h->obytep == h->obyten) { 01650 h->obytep = h->obyten = 0; /* sent */ 01651 h->osync = 10; /* trailing marks */ 01652 } 01653 } else { 01654 h->obyte >>= 1; 01655 } 01656 } 01657 } 01658 } 01659 } 01660 if (ast_write(chan, &f) < 0) { 01661 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 01662 return -1; 01663 } 01664 return 0; 01665 #undef MAXSAMPLES 01666 }
static unsigned char sms_handleincoming | ( | sms_t * | h | ) | [static] |
handle the incoming message
Definition at line 1102 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().
01103 { 01104 unsigned char p = 3; 01105 if (h->smsc) { /* SMSC */ 01106 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */ 01107 h->udhl = h->udl = 0; 01108 h->vp = 0; 01109 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0); 01110 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0); 01111 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0); 01112 ast_copy_string(h->oa, h->cli, sizeof(h->oa)); 01113 h->scts = ast_tvnow(); 01114 h->mr = h->imsg[p++]; 01115 p += unpackaddress(h->da, h->imsg + p); 01116 h->pid = h->imsg[p++]; 01117 h->dcs = h->imsg[p++]; 01118 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */ 01119 if (h->imsg[p] < 144) { 01120 h->vp = (h->imsg[p] + 1) * 5; 01121 } else if (h->imsg[p] < 168) { 01122 h->vp = 720 + (h->imsg[p] - 143) * 30; 01123 } else if (h->imsg[p] < 197) { 01124 h->vp = (h->imsg[p] - 166) * 1440; 01125 } else { 01126 h->vp = (h->imsg[p] - 192) * 10080; 01127 } 01128 p++; 01129 } else if (h->imsg[2] & 0x18) { 01130 p += 7; /* ignore enhanced / absolute VP */ 01131 } 01132 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi); 01133 h->rx = 1; /* received message */ 01134 sms_writefile(h); /* write the file */ 01135 if (p != h->imsg[1] + 2) { 01136 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2); 01137 return 0xFF; /* duh! */ 01138 } 01139 } else { 01140 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]); 01141 return 0xFF; 01142 } 01143 } else { /* client */ 01144 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */ 01145 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0; 01146 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0); 01147 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0); 01148 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0); 01149 h->mr = -1; 01150 p += unpackaddress(h->oa, h->imsg + p); 01151 h->pid = h->imsg[p++]; 01152 h->dcs = h->imsg[p++]; 01153 h->scts = unpackdate(h->imsg + p); 01154 p += 7; 01155 p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi); 01156 h->rx = 1; /* received message */ 01157 sms_writefile(h); /* write the file */ 01158 if (p != h->imsg[1] + 2) { 01159 ast_log(LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2); 01160 return 0xFF; /* duh! */ 01161 } 01162 } else { 01163 ast_log(LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]); 01164 return 0xFF; 01165 } 01166 } 01167 return 0; /* no error */ 01168 }
static int sms_handleincoming_proto2 | ( | sms_t * | h | ) | [static] |
sms_handleincoming_proto2: handle the incoming message
Definition at line 1252 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, sms_s::oa, sms_s::rx, sms_s::scts, sms_hexdump(), sms_writefile(), 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().
01253 { 01254 int f, i, sz = 0; 01255 int msg, msgsz; 01256 struct ast_tm tm; 01257 struct timeval now = { 0, 0 }; 01258 char debug_buf[MAX_DEBUG_LEN * 3 + 1]; 01259 01260 sz = h->imsg[1] + 2; 01261 /* ast_verb(3, "SMS-P2 Frame: %s\n", sms_hexdump(h->imsg, sz, debug_buf)); */ 01262 01263 /* Parse message body (called payload) */ 01264 now = h->scts = ast_tvnow(); 01265 for (f = 4; f < sz; ) { 01266 msg = h->imsg[f++]; 01267 msgsz = h->imsg[f++]; 01268 msgsz += (h->imsg[f++] * 256); 01269 switch (msg) { 01270 case 0x13: /* Body */ 01271 ast_verb(3, "SMS-P2 Body#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01272 if (msgsz >= sizeof(h->ud)) { 01273 msgsz = sizeof(h->ud) - 1; 01274 } 01275 for (i = 0; i < msgsz; i++) { 01276 h->ud[i] = h->imsg[f + i]; 01277 } 01278 h->udl = msgsz; 01279 break; 01280 case 0x14: /* Date SCTS */ 01281 now = h->scts = ast_tvnow(); 01282 ast_localtime(&now, &tm, NULL); 01283 tm.tm_mon = ( (h->imsg[f] * 10) + h->imsg[f + 1] ) - 1; 01284 tm.tm_mday = ( (h->imsg[f + 2] * 10) + h->imsg[f + 3] ); 01285 tm.tm_hour = ( (h->imsg[f + 4] * 10) + h->imsg[f + 5] ); 01286 tm.tm_min = ( (h->imsg[f + 6] * 10) + h->imsg[f + 7] ); 01287 tm.tm_sec = 0; 01288 h->scts = ast_mktime(&tm, NULL); 01289 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); 01290 break; 01291 case 0x15: /* Calling line (from SMSC) */ 01292 if (msgsz >= 20) { 01293 msgsz = 20 - 1; 01294 } 01295 ast_verb(3, "SMS-P2 Origin#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01296 ast_copy_string(h->oa, (char *)(&h->imsg[f]), msgsz + 1); 01297 break; 01298 case 0x18: /* Destination(from TE/phone) */ 01299 if (msgsz >= 20) { 01300 msgsz = 20 - 1; 01301 } 01302 ast_verb(3, "SMS-P2 Destination#%02X=[%.*s]\n", msg, msgsz, &h->imsg[f]); 01303 ast_copy_string(h->da, (char *)(&h->imsg[f]), msgsz + 1); 01304 break; 01305 case 0x1C: /* Notify */ 01306 ast_verb(3, "SMS-P2 Notify#%02X=%s\n", msg, sms_hexdump(&h->imsg[f], 3, debug_buf)); 01307 break; 01308 default: 01309 ast_verb(3, "SMS-P2 Par#%02X [%d]: %s\n", msg, msgsz, sms_hexdump(&h->imsg[f], msgsz, debug_buf)); 01310 break; 01311 } 01312 f+=msgsz; /* Skip to next */ 01313 } 01314 h->rx = 1; /* received message */ 01315 sms_writefile(h); /* write the file */ 01316 return 0; /* no error */ 01317 }
static char* sms_hexdump | ( | unsigned char | buf[], | |
int | size, | |||
char * | s | |||
) | [static] |
Definition at line 1239 of file app_sms.c.
References f, and MAX_DEBUG_LEN.
Referenced by sms_handleincoming_proto2().
01240 { 01241 char *p; 01242 int f; 01243 01244 for (p = s, f = 0; f < size && f < MAX_DEBUG_LEN; f++, p += 3) { 01245 sprintf(p, "%02X ", (unsigned char)buf[f]); 01246 } 01247 return(s); 01248 }
static void sms_log | ( | sms_t * | h, | |
char | status | |||
) | [static] |
Log the output, and remove file.
Definition at line 769 of file app_sms.c.
References AST_FILE_MODE, ast_log(), sms_s::da, errno, isodate(), LOG_WARNING, 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().
00770 { 00771 int o; 00772 00773 if (*h->oa == '\0' && *h->da == '\0') { 00774 return; 00775 } 00776 o = open(log_file, O_CREAT | O_APPEND | O_WRONLY, AST_FILE_MODE); 00777 if (o >= 0) { 00778 char line[1000], mrs[3] = "", *p; 00779 char buf[30]; 00780 unsigned char n; 00781 00782 if (h->mr >= 0) { 00783 snprintf(mrs, sizeof(mrs), "%02X", h->mr); 00784 } 00785 snprintf(line, sizeof(line), "%s %c%c%c%s %s %s %s ", 00786 isodate(time(NULL), buf, sizeof(buf)), 00787 status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, 00788 S_OR(h->oa, "-"), S_OR(h->da, "-") ); 00789 p = line + strlen(line); 00790 for (n = 0; n < h->udl; n++) { 00791 if (h->ud[n] == '\\') { 00792 *p++ = '\\'; 00793 *p++ = '\\'; 00794 } else if (h->ud[n] == '\n') { 00795 *p++ = '\\'; 00796 *p++ = 'n'; 00797 } else if (h->ud[n] == '\r') { 00798 *p++ = '\\'; 00799 *p++ = 'r'; 00800 } else if (h->ud[n] < 32 || h->ud[n] == 127) { 00801 *p++ = 191; 00802 } else { 00803 *p++ = h->ud[n]; 00804 } 00805 } 00806 *p++ = '\n'; 00807 *p = 0; 00808 if (write(o, line, strlen(line)) < 0) { 00809 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 00810 } 00811 close(o); 00812 } 00813 *h->oa = *h->da = h->udl = 0; 00814 }
static void sms_messagerx | ( | sms_t * | h | ) | [static] |
Definition at line 1492 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().
Referenced by sms_process().
01493 { 01494 int cause; 01495 01496 sms_debug (DIR_RX, h); 01497 if (h->protocol == 2) { 01498 sms_messagerx2(h); 01499 return; 01500 } 01501 /* parse incoming message for Protocol 1 */ 01502 switch (h->imsg[0]) { 01503 case 0x91: /* SMS_DATA */ 01504 cause = sms_handleincoming (h); 01505 if (!cause) { 01506 sms_log(h, 'Y'); 01507 h->omsg[0] = 0x95; /* SMS_ACK */ 01508 h->omsg[1] = 0x02; 01509 h->omsg[2] = 0x00; /* deliver report */ 01510 h->omsg[3] = 0x00; /* no parameters */ 01511 } else { /* NACK */ 01512 sms_log(h, 'N'); 01513 h->omsg[0] = 0x96; /* SMS_NACK */ 01514 h->omsg[1] = 3; 01515 h->omsg[2] = 0; /* delivery report */ 01516 h->omsg[3] = cause; /* cause */ 01517 h->omsg[4] = 0; /* no parameters */ 01518 } 01519 sms_messagetx(h); 01520 break; 01521 01522 case 0x92: /* SMS_ERROR */ 01523 h->err = 1; 01524 sms_messagetx(h); /* send whatever we sent again */ 01525 break; 01526 case 0x93: /* SMS_EST */ 01527 sms_nextoutgoing (h); 01528 break; 01529 case 0x94: /* SMS_REL */ 01530 h->hangup = 1; /* hangup */ 01531 break; 01532 case 0x95: /* SMS_ACK */ 01533 sms_log(h, 'Y'); 01534 sms_nextoutgoing (h); 01535 break; 01536 case 0x96: /* SMS_NACK */ 01537 h->err = 1; 01538 sms_log(h, 'N'); 01539 sms_nextoutgoing (h); 01540 break; 01541 default: /* Unknown */ 01542 h->omsg[0] = 0x92; /* SMS_ERROR */ 01543 h->omsg[1] = 1; 01544 h->omsg[2] = 3; /* unknown message type */ 01545 sms_messagetx(h); 01546 break; 01547 } 01548 }
static void sms_messagerx2 | ( | sms_t * | h | ) | [static] |
Definition at line 1333 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::hangup, sms_s::imsg, LOG_NOTICE, sms_s::omsg, sms_handleincoming_proto2(), sms_log(), sms_messagetx(), and sms_nextoutgoing().
Referenced by sms_messagerx().
01334 { 01335 int p = h->imsg[0] & DLL_SMS_MASK ; /* mask the high bit */ 01336 int cause; 01337 01338 #define DLL2_ACK(h) ((h->framenumber & 1) ? DLL2_SMS_ACK1: DLL2_SMS_ACK1) 01339 switch (p) { 01340 case DLL2_SMS_EST: /* Protocol 2: Connection ready (fake): send message */ 01341 sms_nextoutgoing (h); 01342 /* 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 "); */ 01343 break; 01344 01345 case DLL2_SMS_INFO_MO: /* transport SMS_SUBMIT */ 01346 case DLL2_SMS_INFO_MT: /* transport SMS_DELIVERY */ 01347 cause = sms_handleincoming_proto2(h); 01348 if (!cause) { /* ACK */ 01349 sms_log(h, 'Y'); 01350 } 01351 h->omsg[0] = DLL2_ACK(h); 01352 h->omsg[1] = 0x06; /* msg len */ 01353 h->omsg[2] = 0x04; /* payload len */ 01354 h->omsg[3] = 0x00; /* payload len */ 01355 h->omsg[4] = 0x1f; /* Response type */ 01356 h->omsg[5] = 0x01; /* parameter len */ 01357 h->omsg[6] = 0x00; /* parameter len */ 01358 h->omsg[7] = cause; /* CONFIRM or error */ 01359 sms_messagetx(h); 01360 break; 01361 01362 case DLL2_SMS_NACK: /* Protocol 2: SMS_NAK */ 01363 h->omsg[0] = DLL2_SMS_REL; /* SMS_REL */ 01364 h->omsg[1] = 0x00; /* msg len */ 01365 sms_messagetx(h); 01366 break; 01367 01368 case DLL2_SMS_ACK0: 01369 case DLL2_SMS_ACK1: 01370 /* SMS_ACK also transport SMS_SUBMIT or SMS_DELIVERY */ 01371 if ( (h->omsg[0] & DLL_SMS_MASK) == DLL2_SMS_REL) { 01372 /* a response to our Release, just hangup */ 01373 h->hangup = 1; /* hangup */ 01374 } else { 01375 /* XXX depending on what we are.. */ 01376 ast_log(LOG_NOTICE, "SMS_SUBMIT or SMS_DELIVERY\n"); 01377 sms_nextoutgoing (h); 01378 } 01379 break; 01380 01381 case DLL2_SMS_REL: /* Protocol 2: SMS_REL (hangup req) */ 01382 h->omsg[0] = DLL2_ACK(h); 01383 h->omsg[1] = 0; 01384 sms_messagetx(h); 01385 break; 01386 } 01387 }
static void sms_messagetx | ( | sms_t * | h | ) | [static] |
Definition at line 1550 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(), sms_nextoutgoing(), and sms_process().
01551 { 01552 unsigned char c = 0, p; 01553 int len = h->omsg[1] + 2; /* total message length excluding checksum */ 01554 01555 for (p = 0; p < len; p++) { /* compute checksum */ 01556 c += h->omsg[p]; 01557 } 01558 h->omsg[len] = 0 - c; /* actually, (256 - (c & 0fxx)) & 0xff) */ 01559 sms_debug(DIR_TX, h); 01560 h->framenumber++; /* Proto 2 */ 01561 h->obytep = 0; 01562 h->obitp = 0; 01563 if (h->protocol == 2) { /* Proto 2: */ 01564 h->oseizure = 300; /* 300bits (or more ?) */ 01565 h->obyte = 0; /* Seizure starts with space (0) */ 01566 if (h->omsg[0] == 0x7F) { 01567 h->opause = 8 * h->opause_0; /* initial message delay */ 01568 } else { 01569 h->opause = 400; 01570 } 01571 } else { /* Proto 1: */ 01572 h->oseizure = 0; /* No seizure */ 01573 h->obyte = 1; /* send mark ('1') at the beginning */ 01574 /* Change the initial message delay. BT requires 300ms, 01575 * but for others this might be way too much and the phone 01576 * could time out. XXX make it configurable. 01577 */ 01578 if (h->omsg[0] == 0x93) { 01579 h->opause = 8 * h->opause_0; /* initial message delay */ 01580 } else { 01581 h->opause = 200; 01582 } 01583 } 01584 /* Note - setting osync triggers the generator */ 01585 h->osync = OSYNC_BITS; /* 80 sync bits */ 01586 h->obyten = len + 1; /* bytes to send (including checksum) */ 01587 }
static void sms_nextoutgoing | ( | sms_t * | h | ) | [static] |
find and fill in next message, or send a REL if none waiting
Definition at line 1432 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().
01433 { 01434 char fn[100 + NAME_MAX] = ""; 01435 DIR *d; 01436 char more = 0; 01437 01438 *h->da = *h->oa = '\0'; /* clear destinations */ 01439 h->rx = 0; /* outgoing message */ 01440 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? "mttx" : "motx"); 01441 ast_mkdir(fn, 0777); /* ensure it exists */ 01442 d = opendir(fn); 01443 if (d) { 01444 struct dirent *f = readdirqueue(d, h->queue); 01445 if (f) { 01446 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name); 01447 sms_readfile(h, fn); 01448 if (readdirqueue(d, h->queue)) { 01449 more = 1; /* more to send */ 01450 } 01451 } 01452 closedir(d); 01453 } 01454 if (*h->da || *h->oa) { /* message to send */ 01455 if (h->protocol == 2) { 01456 sms_compose2(h, more); 01457 } else { 01458 sms_compose1(h, more); 01459 } 01460 } else { /* no message */ 01461 if (h->protocol == 2) { 01462 h->omsg[0] = 0x17; /* SMS_REL */ 01463 h->omsg[1] = 0; 01464 } else { 01465 h->omsg[0] = 0x94; /* SMS_REL */ 01466 h->omsg[1] = 0; 01467 } 01468 } 01469 sms_messagetx(h); 01470 }
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 1699 of file app_sms.c.
References ast_log(), ast_verb, sms_s::err, sms_s::framenumber, sms_s::hangup, sms_s::ibitc, sms_s::ibith, sms_s::ibitl, sms_s::ibitn, sms_s::ibitt, sms_s::ibytec, sms_s::ibytep, sms_s::ibytev, sms_s::idle, sms_s::ierr, sms_s::imag, sms_s::imc0, sms_s::imc1, sms_s::ims0, sms_s::ims1, sms_s::imsg, sms_s::ipc0, sms_s::ipc1, sms_s::iphasep, sms_s::ips0, sms_s::ips1, LOG_NOTICE, sms_s::obyten, sms_s::omsg, sms_s::osync, sms_s::protocol, sms_messagerx(), and sms_messagetx().
01700 { 01701 int bit; 01702 01703 /* 01704 * Ignore incoming audio while a packet is being transmitted, 01705 * the protocol is half-duplex. 01706 * Unfortunately this means that if the outbound and incoming 01707 * transmission overlap (which is an error condition anyways), 01708 * we may miss some data and this makes debugging harder. 01709 */ 01710 if (h->obyten || h->osync) { 01711 return; 01712 } 01713 for ( ; samples-- ; data++) { 01714 unsigned long long m0, m1; 01715 if (abs(*data) > h->imag) { 01716 h->imag = abs(*data); 01717 } else { 01718 h->imag = h->imag * 7 / 8; 01719 } 01720 if (h->imag <= 500) { /* below [arbitrary] threahold: lost carrier */ 01721 if (h->idle++ == 80000) { /* nothing happening */ 01722 ast_log(LOG_NOTICE, "No data, hanging up\n"); 01723 h->hangup = 1; 01724 h->err = 1; 01725 } 01726 if (h->ierr) { /* error */ 01727 ast_log(LOG_NOTICE, "Error %d, hanging up\n", h->ierr); 01728 /* Protocol 1 */ 01729 h->err = 1; 01730 h->omsg[0] = 0x92; /* error */ 01731 h->omsg[1] = 1; 01732 h->omsg[2] = h->ierr; 01733 sms_messagetx(h); /* send error */ 01734 } 01735 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01736 continue; 01737 } 01738 h->idle = 0; 01739 01740 /* multiply signal by the two carriers. */ 01741 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7; 01742 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7; 01743 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7; 01744 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7; 01745 /* compute the amplitudes */ 01746 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0; 01747 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1; 01748 01749 /* advance the sin/cos pointers */ 01750 if ((h->ips0 += 21) >= 80) { 01751 h->ips0 -= 80; 01752 } 01753 if ((h->ipc0 += 21) >= 80) { 01754 h->ipc0 -= 80; 01755 } 01756 if ((h->ips1 += 13) >= 80) { 01757 h->ips1 -= 80; 01758 } 01759 if ((h->ipc1 += 13) >= 80) { 01760 h->ipc1 -= 80; 01761 } 01762 01763 /* set new bit to 1 or 0 depending on which value is stronger */ 01764 h->ibith <<= 1; 01765 if (m1 > m0) { 01766 h->ibith |= 1; 01767 } 01768 if (h->ibith & 8) { 01769 h->ibitt--; 01770 } 01771 if (h->ibith & 1) { 01772 h->ibitt++; 01773 } 01774 bit = ((h->ibitt > 1) ? 1 : 0); 01775 if (bit != h->ibitl) { 01776 h->ibitc = 1; 01777 } else { 01778 h->ibitc++; 01779 } 01780 h->ibitl = bit; 01781 if (!h->ibitn && h->ibitc == 4 && !bit) { 01782 h->ibitn = 1; 01783 h->iphasep = 0; 01784 } 01785 if (bit && h->ibitc == 200) { /* sync, restart message */ 01786 /* Protocol 2: empty connection ready (I am master) */ 01787 if (h->framenumber < 0 && h->ibytec >= 160 && !memcmp(h->imsg, "UUUUUUUUUUUUUUUUUUUU", 20)) { 01788 h->framenumber = 1; 01789 ast_verb(3, "SMS protocol 2 detected\n"); 01790 h->protocol = 2; 01791 h->imsg[0] = 0xff; /* special message (fake) */ 01792 h->imsg[1] = h->imsg[2] = 0x00; 01793 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01794 sms_messagerx(h); 01795 } 01796 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0; 01797 } 01798 if (h->ibitn) { 01799 h->iphasep += 12; 01800 if (h->iphasep >= 80) { /* next bit */ 01801 h->iphasep -= 80; 01802 if (h->ibitn++ == 9) { /* end of byte */ 01803 if (!bit) { /* bad stop bit */ 01804 ast_log(LOG_NOTICE, "bad stop bit\n"); 01805 h->ierr = 0xFF; /* unknown error */ 01806 } else { 01807 if (h->ibytep < sizeof(h->imsg)) { 01808 h->imsg[h->ibytep] = h->ibytev; 01809 h->ibytec += h->ibytev; 01810 h->ibytep++; 01811 } else if (h->ibytep == sizeof(h->imsg)) { 01812 ast_log(LOG_NOTICE, "msg too large\n"); 01813 h->ierr = 2; /* bad message length */ 01814 } 01815 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) { 01816 if (!h->ibytec) { 01817 sms_messagerx(h); 01818 } else { 01819 ast_log(LOG_NOTICE, "bad checksum\n"); 01820 h->ierr = 1; /* bad checksum */ 01821 } 01822 } 01823 } 01824 h->ibitn = 0; 01825 } 01826 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0); 01827 } 01828 } 01829 } 01830 }
static void sms_readfile | ( | sms_t * | h, | |
char * | fn | |||
) | [static] |
parse and delete a file
Definition at line 817 of file app_sms.c.
References ast_log(), ast_mktime(), ast_tvnow(), sms_s::da, sms_s::dcs, is16bit, is7bit, is8bit, LOG_NOTICE, LOG_WARNING, sms_s::mr, numcpy(), sms_s::oa, packsms16(), packsms7(), packsms8(), sms_s::pid, sms_s::rp, sms_s::rx, 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().
00818 { 00819 char line[1000]; 00820 FILE *s; 00821 char dcsset = 0; /* if DSC set */ 00822 ast_log(LOG_NOTICE, "Sending %s\n", fn); 00823 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0; 00824 h->mr = -1; 00825 h->dcs = 0xF1; /* normal messages class 1 */ 00826 h->scts = ast_tvnow(); 00827 s = fopen(fn, "r"); 00828 if (s) { 00829 if (unlink(fn)) { /* concurrent access, we lost */ 00830 fclose(s); 00831 return; 00832 } 00833 while (fgets (line, sizeof(line), s)) { /* process line in file */ 00834 char *p; 00835 void *pp = &p; 00836 for (p = line; *p && *p != '\n' && *p != '\r'; p++); 00837 *p = 0; /* strip eoln */ 00838 p = line; 00839 if (!*p || *p == ';') { 00840 continue; /* blank line or comment, ignore */ 00841 } 00842 while (isalnum(*p)) { 00843 *p = tolower (*p); 00844 p++; 00845 } 00846 while (isspace (*p)) { 00847 *p++ = 0; 00848 } 00849 if (*p == '=') { 00850 *p++ = 0; 00851 if (!strcmp(line, "ud")) { /* parse message (UTF-8) */ 00852 unsigned char o = 0; 00853 memcpy(h->udtxt, p, SMSLEN); /* for protocol 2 */ 00854 while (*p && o < SMSLEN) { 00855 h->ud[o++] = utf8decode(pp); 00856 } 00857 h->udl = o; 00858 if (*p) { 00859 ast_log(LOG_WARNING, "UD too long in %s\n", fn); 00860 } 00861 } else { 00862 while (isspace (*p)) { 00863 p++; 00864 } 00865 if (!strcmp(line, "oa") && strlen(p) < sizeof(h->oa)) { 00866 numcpy (h->oa, p); 00867 } else if (!strcmp(line, "da") && strlen(p) < sizeof(h->oa)) { 00868 numcpy (h->da, p); 00869 } else if (!strcmp(line, "pid")) { 00870 h->pid = atoi(p); 00871 } else if (!strcmp(line, "dcs")) { 00872 h->dcs = atoi(p); 00873 dcsset = 1; 00874 } else if (!strcmp(line, "mr")) { 00875 h->mr = atoi(p); 00876 } else if (!strcmp(line, "srr")) { 00877 h->srr = (atoi(p) ? 1 : 0); 00878 } else if (!strcmp(line, "vp")) { 00879 h->vp = atoi(p); 00880 } else if (!strcmp(line, "rp")) { 00881 h->rp = (atoi(p) ? 1 : 0); 00882 } else if (!strcmp(line, "scts")) { /* get date/time */ 00883 int Y, m, d, H, M, S; 00884 /* XXX Why aren't we using ast_strptime here? */ 00885 if (sscanf(p, "%4d-%2d-%2dT%2d:%2d:%2d", &Y, &m, &d, &H, &M, &S) == 6) { 00886 struct ast_tm t = { 0, }; 00887 t.tm_year = Y - 1900; 00888 t.tm_mon = m - 1; 00889 t.tm_mday = d; 00890 t.tm_hour = H; 00891 t.tm_min = M; 00892 t.tm_sec = S; 00893 t.tm_isdst = -1; 00894 h->scts = ast_mktime(&t, NULL); 00895 if (h->scts.tv_sec == 0) { 00896 ast_log(LOG_WARNING, "Bad date/timein %s: %s", fn, p); 00897 } 00898 } 00899 } else { 00900 ast_log(LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p); 00901 } 00902 } 00903 } else if (*p == '#') { /* raw hex format */ 00904 *p++ = 0; 00905 if (*p == '#') { 00906 p++; 00907 if (!strcmp(line, "ud")) { /* user data */ 00908 int o = 0; 00909 while (*p && o < SMSLEN) { 00910 if (isxdigit(*p) && isxdigit(p[1]) && isxdigit(p[2]) && isxdigit(p[3])) { 00911 h->ud[o++] = 00912 (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 12) + 00913 (((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) + 00914 (((isalpha(p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha(p[3]) ? 9 : 0) + (p[3] & 0xF)); 00915 p += 4; 00916 } else 00917 break; 00918 } 00919 h->udl = o; 00920 if (*p) 00921 ast_log(LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn); 00922 } else 00923 ast_log(LOG_WARNING, "Only ud can use ## format, %s\n", fn); 00924 } else if (!strcmp(line, "ud")) { /* user data */ 00925 int o = 0; 00926 while (*p && o < SMSLEN) { 00927 if (isxdigit(*p) && isxdigit(p[1])) { 00928 h->ud[o++] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)); 00929 p += 2; 00930 } else { 00931 break; 00932 } 00933 } 00934 h->udl = o; 00935 if (*p) { 00936 ast_log(LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn); 00937 } 00938 } else if (!strcmp(line, "udh")) { /* user data header */ 00939 unsigned char o = 0; 00940 h->udhi = 1; 00941 while (*p && o < SMSLEN) { 00942 if (isxdigit(*p) && isxdigit(p[1])) { 00943 h->udh[o] = (((isalpha(*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha(p[1]) ? 9 : 0) + (p[1] & 0xF)); 00944 o++; 00945 p += 2; 00946 } else { 00947 break; 00948 } 00949 } 00950 h->udhl = o; 00951 if (*p) { 00952 ast_log(LOG_WARNING, "UDH too long / invalid hex in %s\n", fn); 00953 } 00954 } else { 00955 ast_log(LOG_WARNING, "Only ud and udh can use # format, %s\n", fn); 00956 } 00957 } else { 00958 ast_log(LOG_WARNING, "Cannot parse in %s: %s\n", fn, line); 00959 } 00960 } 00961 fclose(s); 00962 if (!dcsset && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00963 if (packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00964 if (packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00965 ast_log(LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn); 00966 } else { 00967 h->dcs = 0x08; /* default to 16 bit */ 00968 ast_log(LOG_WARNING, "Sending in 16 bit format(%s)\n", fn); 00969 } 00970 } else { 00971 h->dcs = 0xF5; /* default to 8 bit */ 00972 ast_log(LOG_WARNING, "Sending in 8 bit format(%s)\n", fn); 00973 } 00974 } 00975 if (is7bit(h->dcs) && packsms7(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00976 ast_log(LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn); 00977 } 00978 if (is8bit(h->dcs) && packsms8(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00979 ast_log(LOG_WARNING, "Invalid 8 bit data %s\n", fn); 00980 } 00981 if (is16bit(h->dcs) && packsms16(0, h->udhl, h->udh, h->udl, h->ud) < 0) { 00982 ast_log(LOG_WARNING, "Invalid 16 bit data %s\n", fn); 00983 } 00984 } 00985 }
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 988 of file app_sms.c.
References ast_config_AST_SPOOL_DIR, ast_copy_string(), ast_log(), ast_mkdir(), ast_tvnow(), ast_tvzero(), sms_s::da, sms_s::dcs, isodate(), LOG_NOTICE, sms_s::mr, sms_s::oa, sms_s::pid, sms_s::queue, sms_s::rp, sms_s::rx, 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_handleincoming(), and sms_handleincoming_proto2().
00989 { 00990 char fn[200] = "", fn2[200] = ""; 00991 char buf[30]; 00992 FILE *o; 00993 00994 if (ast_tvzero(h->scts)) { 00995 h->scts = ast_tvnow(); 00996 } 00997 snprintf(fn, sizeof(fn), "%s/sms/%s", ast_config_AST_SPOOL_DIR, h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx"); 00998 ast_mkdir(fn, 0777); /* ensure it exists */ 00999 ast_copy_string(fn2, fn, sizeof(fn2)); 01000 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%s.%s-%d", h->queue, isodate(h->scts.tv_sec, buf, sizeof(buf)), seq++); 01001 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1); 01002 if ((o = fopen(fn, "w")) == NULL) { 01003 return; 01004 } 01005 01006 if (*h->oa) { 01007 fprintf(o, "oa=%s\n", h->oa); 01008 } 01009 if (*h->da) { 01010 fprintf(o, "da=%s\n", h->da); 01011 } 01012 if (h->udhi) { 01013 unsigned int p; 01014 fprintf(o, "udh#"); 01015 for (p = 0; p < h->udhl; p++) { 01016 fprintf(o, "%02X", h->udh[p]); 01017 } 01018 fprintf(o, "\n"); 01019 } 01020 if (h->udl) { 01021 unsigned int p; 01022 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++); 01023 if (p < h->udl) { 01024 fputc(';', o); /* cannot use ud=, but include as a comment for human readable */ 01025 } 01026 fprintf(o, "ud="); 01027 for (p = 0; p < h->udl; p++) { 01028 unsigned short v = h->ud[p]; 01029 if (v < 32) { 01030 fputc(191, o); 01031 } else if (v < 0x80) { 01032 fputc(v, o); 01033 } else if (v < 0x800) { 01034 fputc(0xC0 + (v >> 6), o); 01035 fputc(0x80 + (v & 0x3F), o); 01036 } else { 01037 fputc(0xE0 + (v >> 12), o); 01038 fputc(0x80 + ((v >> 6) & 0x3F), o); 01039 fputc(0x80 + (v & 0x3F), o); 01040 } 01041 } 01042 fprintf(o, "\n"); 01043 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++); 01044 if (p < h->udl) { 01045 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++); 01046 if (p == h->udl) { /* can write in ucs-1 hex */ 01047 fprintf(o, "ud#"); 01048 for (p = 0; p < h->udl; p++) { 01049 fprintf(o, "%02X", h->ud[p]); 01050 } 01051 fprintf(o, "\n"); 01052 } else { /* write in UCS-2 */ 01053 fprintf(o, "ud##"); 01054 for (p = 0; p < h->udl; p++) { 01055 fprintf(o, "%04X", h->ud[p]); 01056 } 01057 fprintf(o, "\n"); 01058 } 01059 } 01060 } 01061 if (h->scts.tv_sec) { 01062 char datebuf[30]; 01063 fprintf(o, "scts=%s\n", isodate(h->scts.tv_sec, datebuf, sizeof(datebuf))); 01064 } 01065 if (h->pid) { 01066 fprintf(o, "pid=%d\n", h->pid); 01067 } 01068 if (h->dcs != 0xF1) { 01069 fprintf(o, "dcs=%d\n", h->dcs); 01070 } 01071 if (h->vp) { 01072 fprintf(o, "vp=%d\n", h->vp); 01073 } 01074 if (h->srr) { 01075 fprintf(o, "srr=1\n"); 01076 } 01077 if (h->mr >= 0) { 01078 fprintf(o, "mr=%d\n", h->mr); 01079 } 01080 if (h->rp) { 01081 fprintf(o, "rp=1\n"); 01082 } 01083 fclose(o); 01084 if (rename(fn, fn2)) { 01085 unlink(fn); 01086 } else { 01087 ast_log(LOG_NOTICE, "Received to %s\n", fn2); 01088 } 01089 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2058 of file app_sms.c.
References ast_unregister_application().
02059 { 02060 return ast_unregister_application(app); 02061 }
static unsigned char unpackaddress | ( | char * | o, | |
unsigned char * | i | |||
) | [static] |
unpack an address from i, return byte length, unpack to o
Definition at line 723 of file app_sms.c.
Referenced by sms_handleincoming().
00724 { 00725 unsigned char l = i[0], p; 00726 if (i[1] == 0x91) { 00727 *o++ = '+'; 00728 } 00729 for (p = 0; p < l; p++) { 00730 if (p & 1) { 00731 *o++ = (i[2 + p / 2] >> 4) + '0'; 00732 } else { 00733 *o++ = (i[2 + p / 2] & 0xF) + '0'; 00734 } 00735 } 00736 *o = 0; 00737 return (l + 5) / 2; 00738 }
static struct timeval unpackdate | ( | unsigned char * | i | ) | [static, read] |
unpack a date and return
Definition at line 575 of file app_sms.c.
References ast_mktime(), ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.
Referenced by sms_handleincoming().
00576 { 00577 struct ast_tm t; 00578 00579 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4); 00580 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1; 00581 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4); 00582 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4); 00583 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4); 00584 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4); 00585 t.tm_isdst = 0; 00586 if (i[6] & 0x08) { 00587 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4)); 00588 } else { 00589 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4)); 00590 } 00591 00592 return ast_mktime(&t, NULL); 00593 }
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 708 of file app_sms.c.
References is7bit, is8bit, unpacksms16(), unpacksms7(), and unpacksms8().
Referenced by sms_handleincoming().
00709 { 00710 int l = *i++; 00711 if (is7bit(dcs)) { 00712 unpacksms7(i, l, udh, udhl, ud, udl, udhi); 00713 l = (l * 7 + 7) / 8; /* adjust length to return */ 00714 } else if (is8bit(dcs)) { 00715 unpacksms8(i, l, udh, udhl, ud, udl, udhi); 00716 } else { 00717 unpacksms16(i, l, udh, udhl, ud, udl, udhi); 00718 } 00719 return l + 1; 00720 }
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 680 of file app_sms.c.
Referenced by unpacksms().
00681 { 00682 unsigned short *o = ud; 00683 *udhl = 0; 00684 if (udhi) { 00685 int n = *i; 00686 *udhl = n; 00687 if (n) { 00688 i++; 00689 l--; 00690 while (l && n) { 00691 l--; 00692 n--; 00693 *udh++ = *i++; 00694 } 00695 } 00696 } 00697 while (l--) { 00698 int v = *i++; 00699 if (l--) { 00700 v = (v << 8) + *i++; 00701 } 00702 *o++ = v; 00703 } 00704 *udl = (o - ud); 00705 }
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 598 of file app_sms.c.
Referenced by unpacksms().
00599 { 00600 unsigned char b = 0, p = 0; 00601 unsigned short *o = ud; 00602 *udhl = 0; 00603 if (udhi && l) { /* header */ 00604 int h = i[p]; 00605 *udhl = h; 00606 if (h) { 00607 b = 1; 00608 p++; 00609 l--; 00610 while (h-- && l) { 00611 *udh++ = i[p++]; 00612 b += 8; 00613 while (b >= 7) { 00614 b -= 7; 00615 l--; 00616 if (!l) { 00617 break; 00618 } 00619 } 00620 } 00621 /* adjust for fill, septets */ 00622 if (b) { 00623 b = 7 - b; 00624 l--; 00625 } 00626 } 00627 } 00628 while (l--) { 00629 unsigned char v; 00630 if (b < 2) { 00631 v = ((i[p] >> b) & 0x7F); /* everything in one byte */ 00632 } else { 00633 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F); 00634 } 00635 b += 7; 00636 if (b >= 8) { 00637 b -= 8; 00638 p++; 00639 } 00640 /* 0x00A0 is the encoding of ESC (27) in defaultalphabet */ 00641 if (o > ud && o[-1] == 0x00A0 && escapes[v]) { 00642 o[-1] = escapes[v]; 00643 } else { 00644 *o++ = defaultalphabet[v]; 00645 } 00646 } 00647 *udl = (o - ud); 00648 }
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 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 *o++ = *i++; /* not to UTF-8 as explicitly 8 bit coding in DCS */ 00673 } 00674 *udl = (o - ud); 00675 }
static long utf8decode | ( | unsigned char ** | pp | ) | [static] |
Reads next UCS character from NUL terminated UTF-8 string and advance pointer.
Definition at line 311 of file app_sms.c.
Referenced by sms_readfile().
00312 { 00313 unsigned char *p = *pp; 00314 if (!*p) { 00315 return 0; /* null termination of string */ 00316 } 00317 (*pp)++; 00318 if (*p < 0xC0) { 00319 return *p; /* ascii or continuation character */ 00320 } 00321 if (*p < 0xE0) { 00322 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80) { 00323 return *p; /* not valid UTF-8 */ 00324 } 00325 (*pp)++; 00326 return ((*p & 0x1F) << 6) + (p[1] & 0x3F); 00327 } 00328 if (*p < 0xF0) { 00329 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) { 00330 return *p; /* not valid UTF-8 */ 00331 } 00332 (*pp) += 2; 00333 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F); 00334 } 00335 if (*p < 0xF8) { 00336 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) { 00337 return *p; /* not valid UTF-8 */ 00338 } 00339 (*pp) += 3; 00340 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F); 00341 } 00342 if (*p < 0xFC) { 00343 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80 00344 || (p[4] & 0xC0) != 0x80) { 00345 return *p; /* not valid UTF-8 */ 00346 } 00347 (*pp) += 4; 00348 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F); 00349 } 00350 if (*p < 0xFE) { 00351 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80 00352 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80) { 00353 return *p; /* not valid UTF-8 */ 00354 } 00355 (*pp) += 5; 00356 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F); 00357 } 00358 return *p; /* not sensible */ 00359 }
const unsigned short defaultalphabet[] [static] |
volatile unsigned char message_ref [static] |
volatile unsigned int seq [static] |
Definition at line 118 of file app_sms.c.
Referenced by ast_udptl_write(), parsing(), process_dtmf_cisco(), send_client(), send_retransmit(), and udptl_build_packet().
struct ast_generator smsgen [static] |
{ .alloc = sms_alloc, .release = sms_release, .generate = sms_generate, }