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