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