aboutsummaryrefslogtreecommitdiffstats
path: root/telephony/sms.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:35 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:35 -0800
commitf721e3ac031f892af46f255a47d7f54a91317b30 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /telephony/sms.c
parentbae1bc39312d5019bd9a5b8d840a529213a69a17 (diff)
downloadexternal_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.zip
external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.gz
external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'telephony/sms.c')
-rw-r--r--telephony/sms.c1655
1 files changed, 0 insertions, 1655 deletions
diff --git a/telephony/sms.c b/telephony/sms.c
deleted file mode 100644
index 448eab4..0000000
--- a/telephony/sms.c
+++ /dev/null
@@ -1,1655 +0,0 @@
-/* Copyright (C) 2007-2008 The Android Open Source Project
-**
-** This software is licensed under the terms of the GNU General Public
-** License version 2, as published by the Free Software Foundation, and
-** may be copied, distributed, and modified under those terms.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-*/
-#include "sms.h"
-#include "gsm.h"
-#include <memory.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define DEBUG 1
-
-#if 1
-# include "android/utils/debug.h"
-# define D_ACTIVE VERBOSE_CHECK(modem)
-#else
-# define D_ACTIVE DEBUG
-#endif
-
-#if DEBUG
-# define D(...) VERBOSE_PRINT(modem,__VA_ARGS__)
-#else
-# define D(...) ((void)0)
-#endif
-
-/* maximum number of data bytes in a SMS data message */
-#define MAX_USER_DATA_BYTES 140
-
-/* maximum number of 7-bit septets in a SMS text message */
-#define MAX_USER_DATA_SEPTETS 160
-
-/* size of the user data header in bytes */
-#define USER_DATA_HEADER_SIZE 6
-
-/** MESSAGE TEXT
- **/
-int
-sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len )
-{
- cbytes_t p = (cbytes_t)str;
- cbytes_t end = p + strlen;
- int count = 0;
- int escaped = 0;
-
- while (p < end)
- {
- int c = p[0];
-
- /* read the value from the string */
- p += 1;
- if (c >= 128) {
- if ((c & 0xe0) == 0xc0)
- c &= 0x1f;
- else if ((c & 0xf0) == 0xe0)
- c &= 0x0f;
- else
- c &= 0x07;
- p++;
- while (p < end && (p[0] & 0xc0) == 0x80) {
- c = (c << 6) | (p[0] & 0x3f);
- p++;
- }
- }
- if (escaped) {
- switch (c) {
- case '\\':
- break;
- case 'n': /* \n is line feed */
- c = 10;
- break;
-
- case 'x': /* \xNN, where NN is a 2-digit hexadecimal value */
- if (p+2 > end)
- return -1;
- c = gsm_hex2_to_byte( (const char*)p );
- if (c < 0)
- return -1;
- p += 2;
- break;
-
- case 'u': /* \uNNNN where NNNN is a 4-digiti hexadecimal value */
- if (p + 4 > end)
- return -1;
- c = gsm_hex4_to_short( (const char*)p );
- if (c < 0)
- return -1;
- p += 4;
- break;
-
- default: /* invalid escape, return -1 */
- return -1;
- }
- escaped = 0;
- }
- else if (c == '\\')
- {
- escaped = 1;
- continue;
- }
-
- /* now, try to write it to the destination */
- if (c < 128) {
- if (count < utf8len)
- utf8[count] = (byte_t) c;
- count += 1;
- }
- else if (c < 0x800) {
- if (count < utf8len)
- utf8[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
- if (count+1 < utf8len)
- utf8[count+1] = (byte_t)(0x80 | (c & 0x3f));
- count += 2;
- }
- else {
- if (count < utf8len)
- utf8[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf));
- if (count+1 < utf8len)
- utf8[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
- if (count+2 < utf8len)
- utf8[count+2] = (byte_t)(0x80 | (c & 0x3f));
- count += 3;
- }
- }
-
- if (escaped) /* bad final escape */
- return -1;
-
- return count;
-}
-
-/* to convert utf-8 to a message string, we only need to deal with control characters
- * and that's it */
-int sms_utf8_to_message_str( const unsigned char* utf8, int utf8len, char* str, int strlen )
-{
- cbytes_t p = utf8;
- cbytes_t end = p + utf8len;
- int count = 0;
-
- while (p < end)
- {
- int c = p[0];
- int escape = 0;
-
- /* read the value from the string */
- p += 1;
- if (c >= 128) {
- if ((c & 0xe0) == 0xc0)
- c &= 0x1f;
- else if ((c & 0xf0) == 0xe0)
- c &= 0x0f;
- else
- c &= 0x07;
- p++;
- while (p < end && (p[0] & 0xc0) == 0x80) {
- c = (c << 6) | (p[0] & 0x3f);
- p++;
- }
- }
-
- if (c < ' ') {
- escape = 1;
- if (c == '\n') {
- c = 'n';
- escape = 2;
- }
- }
- else if (c == '\\')
- escape = 2;
-
- switch (escape) {
- case 0:
- if (c < 128) {
- if (count < strlen)
- str[count] = (char) c;
- count += 1;
- }
- else if (c < 0x800) {
- if (count < strlen)
- str[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
- if (count+1 < strlen)
- str[count+1] = (byte_t)(0x80 | (c & 0x3f));
- count += 2;
- }
- else {
- if (count < strlen)
- str[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf));
- if (count+1 < strlen)
- str[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
- if (count+2 < strlen)
- str[count+2] = (byte_t)(0x80 | (c & 0x3f));
- count += 3;
- }
- break;
-
- case 1:
- if (count+3 < strlen) {
- str[count+0] = '\\';
- str[count+1] = 'x';
- gsm_hex_from_byte(str + count + 2, c);
- }
- count += 4;
- break;
-
- default:
- if (count+2 < strlen) {
- str[count+0] = '\\';
- str[count+1] = (char) c;
- }
- count += 2;
- }
- }
- return count;
-}
-
-
-/** TIMESTAMPS
- **/
-void
-sms_timestamp_now( SmsTimeStamp stamp )
-{
- time_t now_time = time(NULL);
- struct tm gm = *(gmtime(&now_time));
- struct tm local = *(localtime(&now_time));
- int tzdiff = 0;
-
- stamp->data[0] = gsm_int_to_bcdi( local.tm_year % 100 );
- stamp->data[1] = gsm_int_to_bcdi( local.tm_mon+1 );
- stamp->data[2] = gsm_int_to_bcdi( local.tm_mday );
- stamp->data[3] = gsm_int_to_bcdi( local.tm_hour );
- stamp->data[4] = gsm_int_to_bcdi( local.tm_min );
- stamp->data[5] = gsm_int_to_bcdi( local.tm_sec );
-
- tzdiff = (local.tm_hour*4 + local.tm_min/15) - (gm.tm_hour*4 + gm.tm_min/15);
- if (local.tm_yday > gm.tm_yday)
- tzdiff += 24*4;
- else if (local.tm_yday < gm.tm_yday)
- tzdiff -= 24*4;
-
- stamp->data[6] = gsm_int_to_bcdi( tzdiff >= 0 ? tzdiff : -tzdiff );
- if (tzdiff < 0)
- stamp->data[6] |= 0x08;
-}
-
-int
-sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm )
-{
- int tzdiff;
-
- tm->tm_year = gsm_int_from_bcdi( stamp->data[0] );
- if (tm->tm_year < 50)
- tm->tm_year += 100;
- tm->tm_mon = gsm_int_from_bcdi( stamp->data[1] ) -1;
- tm->tm_mday = gsm_int_from_bcdi( stamp->data[2] );
- tm->tm_hour = gsm_int_from_bcdi( stamp->data[3] );
- tm->tm_min = gsm_int_from_bcdi( stamp->data[4] );
- tm->tm_sec = gsm_int_from_bcdi( stamp->data[5] );
-
- tm->tm_isdst = -1;
-
- tzdiff = gsm_int_from_bcdi( stamp->data[6] & 0xf7 );
- if (stamp->data[6] & 0x8)
- tzdiff = -tzdiff;
-
- return tzdiff;
-}
-
-static void
-gsm_rope_add_timestamp( GsmRope rope, const SmsTimeStampRec* ts )
-{
- gsm_rope_add( rope, ts->data, 7 );
-}
-
-
-/** SMS ADDRESSES
- **/
-
-int
-sms_address_from_str( SmsAddress address, const char* src, int srclen )
-{
- const char* end = src + srclen;
- int shift = 0, len = 0;
- bytes_t data = address->data;
-
- address->len = 0;
- address->toa = 0x81;
-
- if (src >= end)
- return -1;
-
- if ( src[0] == '+' ) {
- address->toa = 0x91;
- if (++src == end)
- goto Fail;
- }
-
- memset( address->data, 0, sizeof(address->data) );
-
- shift = 0;
-
- while (src < end) {
- int c = *src++ - '0';
-
- if ( (unsigned)c >= 10 ||
- data >= address->data + sizeof(address->data) )
- goto Fail;
-
- data[0] |= c << shift;
- len += 1;
- shift += 4;
- if (shift == 8) {
- shift = 0;
- data += 1;
- }
- }
- if (shift != 0)
- data[0] |= 0xf0;
-
- address->len = len;
- return 0;
-
-Fail:
- return -1;
-}
-
-int
-sms_address_to_str( SmsAddress address, char* str, int strlen )
-{
- static const char dialdigits[16] = "0123456789*#,N%";
- int n, count = 0;
-
- if (address->toa == 0x91) {
- if (count < strlen)
- str[count] = '+';
- count++;
- }
- for (n = 0; n < address->len; n += 2)
- {
- int c = address->data[n/2];
-
- if (count < strlen)
- str[count] = dialdigits[c & 0xf];
- count += 1;
-
- if (n+1 > address->len)
- break;
-
- if (count < strlen)
- str[count] = dialdigits[(c >> 4) & 0xf];
- count += 1;
- }
- return count;
-}
-
-int
-sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen )
-{
- int len = sizeof(address->data), num_digits;
-
- if (buflen < 2)
- return -1;
-
- address->len = num_digits = buf[0];
- address->toa = buf[1];
-
- len = (num_digits+1)/2;
- if ( len > sizeof(address->data) )
- return -1;
-
- memcpy( address->data, buf+2, len );
- return 0;
-}
-
-int
-sms_address_to_bytes( SmsAddress address, unsigned char* buf, int bufsize )
-{
- int len = (address->len + 1)/2 + 2;
-
- if (buf == NULL)
- bufsize = 0;
-
- if (bufsize < 1) goto Exit;
- buf[0] = address->len;
-
- if (bufsize < 2) goto Exit;
- buf[1] = address->toa;
-
- buf += 2;
- bufsize -= 2;
- if (bufsize > len-2)
- bufsize = len - 2;
-
- memcpy( buf, address->data, bufsize );
-Exit:
- return len;
-}
-
-int
-sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen )
-{
- const char* hexend = hex + hexlen;
- int nn, len, num_digits;
-
- if (hexlen < 4)
- return -1;
-
- address->len = num_digits = gsm_hex2_to_byte( hex );
- address->toa = gsm_hex2_to_byte( hex+2 );
- hex += 4;
-
- len = (num_digits + 1)/2;
- if (hex + len*2 > hexend)
- return -1;
-
- for ( nn = 0; nn < len; nn++ )
- address->data[nn] = gsm_hex2_to_byte( hex + nn*2 );
-
- return 0;
-}
-
-int
-sms_address_to_hex ( SmsAddress address, char* hex, int hexlen )
-{
- int len = (address->len + 1)/2 + 2;
- int nn;
-
- if (hex == NULL)
- hexlen = 0;
-
- if (hexlen < 2) goto Exit;
- gsm_hex_from_byte( hex, address->len );
- if (hexlen < 4) goto Exit;
- gsm_hex_from_byte( hex+2, address->toa );
- hex += 4;
- hexlen -= 4;
- if ( hexlen > 2*(len - 2) )
- hexlen = (len - 2)/2;
-
- for ( nn = 0; nn < hexlen; nn += 2 )
- gsm_hex_from_byte( hex+nn, address->data[nn/2] );
-
-Exit:
- return len*2;
-}
-
-static void
-gsm_rope_add_address( GsmRope rope, const SmsAddressRec* addr )
-{
- gsm_rope_add_c( rope, addr->len );
- gsm_rope_add_c( rope, addr->toa );
- gsm_rope_add( rope, addr->data, (addr->len+1)/2 );
- if (addr->len & 1) {
- if (!rope->error && rope->data != NULL)
- rope->data[ rope->pos-1 ] |= 0xf0;
- }
-}
-
-static int
-sms_address_eq( const SmsAddressRec* addr1, const SmsAddressRec* addr2 )
-{
- if ( addr1->toa != addr2->toa ||
- addr1->len != addr2->len )
- return 0;
-
- return ( !memcmp( addr1->data, addr2->data, addr1->len ) );
-}
-
-/** SMS PARSER
- **/
-static int
-sms_get_byte( cbytes_t *pcur, cbytes_t end )
-{
- cbytes_t cur = *pcur;
- int result = -1;
-
- if (cur < end) {
- result = cur[0];
- *pcur = cur + 1;
- }
- return result;
-}
-
-/* parse a service center address, returns -1 in case of error */
-static int
-sms_get_sc_address( cbytes_t *pcur,
- cbytes_t end,
- SmsAddress address )
-{
- cbytes_t cur = *pcur;
- int result = -1;
-
- if (cur < end) {
- int len = cur[0];
- int dlen, adjust = 0;
-
- cur += 1;
-
- if (len == 0) { /* empty address */
- address->len = 0;
- address->toa = 0x00;
- result = 0;
- goto Exit;
- }
-
- if (cur + len > end) {
- goto Exit;
- }
-
- address->toa = *cur++;
- len -= 1;
- result = 0;
-
- for (dlen = 0; dlen < len; dlen+=1)
- {
- int c = cur[dlen];
- int v;
-
- adjust = 0;
- if (dlen >= sizeof(address->data)) {
- result = -1;
- break;
- }
-
- v = (c & 0xf);
- if (v >= 0xe)
- break;
-
- adjust = 1;
- address->data[dlen] = (byte_t) c;
-
- v = (c >> 4) & 0xf;
- if (v >= 0xe) {
- break;
- }
- }
- address->len = 2*dlen + adjust;
- }
-Exit:
- if (!result)
- *pcur = cur;
-
- return result;
-}
-
-static int
-sms_skip_sc_address( cbytes_t *pcur,
- cbytes_t end )
-{
- cbytes_t cur = *pcur;
- int result = -1;
- int len;
-
- if (cur >= end)
- goto Exit;
-
- len = cur[0];
- cur += 1 + len;
- if (cur > end)
- goto Exit;
-
- *pcur = cur;
- result = 0;
-Exit:
- return result;
-}
-
-/* parse a sender/receiver address, returns -1 in case of error */
-static int
-sms_get_address( cbytes_t *pcur,
- cbytes_t end,
- SmsAddress address )
-{
- cbytes_t cur = *pcur;
- int result = -1;
- int len, dlen;
-
- if (cur >= end)
- goto Exit;
-
- dlen = *cur++;
-
- if (dlen == 0) {
- address->len = 0;
- address->toa = 0;
- result = 0;
- goto Exit;
- }
-
- if (cur + 1 + (dlen+1)/2 > end)
- goto Exit;
-
- address->len = dlen;
- address->toa = *cur++;
-
- len = (dlen + 1)/2;
- if (len > sizeof(address->data))
- goto Exit;
-
- memcpy( address->data, cur, len );
- cur += len;
- result = 0;
-
-Exit:
- if (!result)
- *pcur = cur;
-
- return result;
-}
-
-static int
-sms_skip_address( cbytes_t *pcur,
- cbytes_t end )
-{
- cbytes_t cur = *pcur;
- int result = -1;
- int dlen;
-
- if (cur + 2 > end)
- goto Exit;
-
- dlen = cur[0];
- cur += 2 + (dlen + 1)/2;
- if (cur > end)
- goto Exit;
-
- result = 0;
-Exit:
- return result;
-}
-
-/* parse a service center timestamp */
-static int
-sms_get_timestamp( cbytes_t *pcur,
- cbytes_t end,
- SmsTimeStamp ts )
-{
- cbytes_t cur = *pcur;
-
- if (cur + 7 > end)
- return -1;
-
- memcpy( ts->data, cur, 7 );
- *pcur = cur + 7;
- return 0;
-}
-
-static int
-sms_skip_timestamp( cbytes_t *pcur,
- cbytes_t end )
-{
- cbytes_t cur = *pcur;
-
- if (cur + 7 > end)
- return -1;
-
- *pcur = cur + 7;
- return 0;
-}
-
-
-static int
-sms_skip_validity_period( cbytes_t *pcur,
- cbytes_t end,
- int mtiByte )
-{
- cbytes_t cur = *pcur;
-
- switch ((mtiByte >> 3) & 3) {
- case 1: /* relative format */
- cur += 1;
- break;
-
- case 2: /* enhanced format */
- case 3: /* absolute format */
- cur += 7;
- }
- if (cur > end)
- return -1;
-
- *pcur = cur;
- return 0;
-}
-
-/** SMS PDU
- **/
-
-typedef struct SmsPDURec {
- bytes_t base;
- bytes_t end;
- bytes_t tpdu;
-} SmsPDURec;
-
-void
-smspdu_free( SmsPDU pdu )
-{
- if (pdu) {
- free( pdu->base );
- pdu->base = NULL;
- pdu->end = NULL;
- pdu->tpdu = NULL;
- }
-}
-
-SmsPduType
-smspdu_get_type( SmsPDU pdu )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte(&data, end);
-
- switch (mtiByte & 3) {
- case 0: return SMS_PDU_DELIVER;
- case 1: return SMS_PDU_SUBMIT;
- case 2: return SMS_PDU_STATUS_REPORT;
- default: return SMS_PDU_INVALID;
- }
-}
-
-int
-smspdu_get_sender_address( SmsPDU pdu, SmsAddress address )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte(&data, end);
-
- switch (mtiByte & 3) {
- case 0: /* SMS_PDU_DELIVER; */
- return sms_get_sc_address( &data, end, address );
-
- default: return -1;
- }
-}
-
-int
-smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp ts )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte( &data, end );
-
- switch (mtiByte & 3) {
- case 0: /* SMS_PDU_DELIVER */
- {
- SmsAddressRec address;
-
- if ( sms_get_sc_address( &data, end, &address ) < 0 )
- return -1;
-
- data += 2; /* skip protocol identifer + coding scheme */
-
- return sms_get_timestamp( &data, end, ts );
- }
-
- default: return -1;
- }
-}
-
-int
-smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte( &data, end );
-
- switch (mtiByte & 3) {
- case 1: /* SMS_PDU_SUBMIT */
- {
- data += 1; /* skip message reference */
- return sms_get_address( &data, end, address );
- }
-
- default: return -1;
- }
-}
-
-typedef enum {
- SMS_CODING_SCHEME_UNKNOWN = 0,
- SMS_CODING_SCHEME_GSM7,
- SMS_CODING_SCHEME_UCS2
-
-} SmsCodingScheme;
-
-/* see TS 23.038 Section 5 for details */
-static SmsCodingScheme
-sms_get_coding_scheme( cbytes_t *pcur,
- cbytes_t end )
-{
- cbytes_t cur = *pcur;
- int dataCoding;
-
- if (cur >= end)
- return SMS_CODING_SCHEME_UNKNOWN;
-
- dataCoding = *cur++;
- *pcur = cur;
-
- switch (dataCoding >> 4) {
- case 0x00:
- case 0x02:
- case 0x03:
- return SMS_CODING_SCHEME_GSM7;
-
- case 0x01:
- if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7;
- if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2;
- break;
-
- case 0x04: case 0x05: case 0x06: case 0x07:
- if (dataCoding & 0x20) return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */
- if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7;
- if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2;
- break;
-
- case 0xF:
- if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7;
- break;
- }
- return SMS_CODING_SCHEME_UNKNOWN;
-}
-
-
-/* see TS 23.040 section 9.2.3.24 for details */
-static int
-sms_get_text_utf8( cbytes_t *pcur,
- cbytes_t end,
- int hasUDH,
- SmsCodingScheme coding,
- GsmRope rope )
-{
- cbytes_t cur = *pcur;
- int result = -1;
- int len;
-
- if (cur >= end)
- goto Exit;
-
- len = *cur++;
-
- /* skip user data header if any */
- if ( hasUDH )
- {
- int hlen;
-
- if (cur >= end)
- goto Exit;
-
- hlen = *cur++;
- if (cur + hlen > end)
- goto Exit;
-
- cur += hlen;
-
- if (coding == SMS_CODING_SCHEME_GSM7)
- len -= 2*(hlen+1);
- else
- len -= hlen+1;
-
- if (len < 0)
- goto Exit;
- }
-
- /* switch the user data header if any */
- if (coding == SMS_CODING_SCHEME_GSM7)
- {
- int count = utf8_from_gsm7( cur, 0, len, NULL );
-
- if (rope != NULL)
- {
- bytes_t dst = gsm_rope_reserve( rope, count );
- if (dst != NULL)
- utf8_from_gsm7( cur, 0, len, dst );
- }
- cur += (len+1)/2;
- }
- else if (coding == SMS_CODING_SCHEME_UCS2)
- {
- int count = ucs2_to_utf8( cur, len/2, NULL );
-
- if (rope != NULL)
- {
- bytes_t dst = gsm_rope_reserve( rope, count );
- if (dst != NULL)
- ucs2_to_utf8( cur, len/2, dst );
- }
- cur += len;
- }
- result = 0;
-
-Exit:
- if (!result)
- *pcur = cur;
-
- return result;
-}
-
-/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
-/* or -1 in case of error */
-int
-smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte( &data, end );
-
- switch (mtiByte & 3) {
- case 0: /* SMS_PDU_DELIVER */
- {
- SmsAddressRec address;
- SmsTimeStampRec timestamp;
- SmsCodingScheme coding;
- GsmRopeRec rope[1];
- int result;
-
- if ( sms_get_sc_address( &data, end, &address ) < 0 )
- goto Fail;
-
- data += 1; /* skip protocol identifier */
- coding = sms_get_coding_scheme( &data, end );
- if (coding == SMS_CODING_SCHEME_UNKNOWN)
- goto Fail;
-
- if ( sms_get_timestamp( &data, end, &timestamp ) < 0 )
- goto Fail;
-
- if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 )
- goto Fail;
-
- result = rope->pos;
- if (utf8len > result)
- utf8len = result;
-
- if (utf8len > 0)
- memcpy( utf8, rope->data, utf8len );
-
- gsm_rope_done( rope );
- return result;
- }
-
- case 1: /* SMS_PDU_SUBMIT */
- {
- SmsAddressRec address;
- SmsCodingScheme coding;
- GsmRopeRec rope[1];
- int result;
-
- data += 1; /* message reference */
-
- if ( sms_get_address( &data, end, &address ) < 0 )
- goto Fail;
-
- data += 1; /* skip protocol identifier */
- coding = sms_get_coding_scheme( &data, end );
- if (coding == SMS_CODING_SCHEME_UNKNOWN)
- goto Fail;
-
- gsm_rope_init_alloc( rope, 0 );
- if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) {
- gsm_rope_done( rope );
- goto Fail;
- }
-
- result = rope->pos;
- if (utf8len > result)
- utf8len = result;
-
- if (utf8len > 0)
- memcpy( utf8, rope->data, utf8len );
-
- gsm_rope_done( rope );
- return result;
- }
- }
-Fail:
- return -1;
-}
-
-static cbytes_t
-smspdu_get_user_data_ref( SmsPDU pdu )
-{
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte( &data, end );
- int len;
-
- /* if there is no user-data-header, there is no message reference here */
- if ((mtiByte & 0x40) == 0)
- goto Fail;
-
- switch (mtiByte & 3) {
- case 0: /* SMS_PDU_DELIVER */
- if ( sms_skip_address( &data, end ) < 0 )
- goto Fail;
-
- data += 2; /* skip protocol identifier + coding scheme */
-
- if ( sms_skip_timestamp( &data, end ) < 0 )
- goto Fail;
-
- break;
-
- case 1: /* SMS_PDU_SUBMIT */
- data += 1; /* skip message reference */
-
- if ( sms_skip_address( &data, end ) < 0 )
- goto Fail;
-
- data += 2; /* protocol identifier + oding schene */
- if ( sms_skip_validity_period( &data, end, mtiByte ) < 0 )
- goto Fail;
-
- break;
-
- default:
- goto Fail;
- }
-
- /* skip user-data length */
- if (data+1 >= end)
- goto Fail;
-
- len = data[1];
- data += 2;
-
- while (len >= 2 && data + 2 <= end) {
- int htype = data[0];
- int hlen = data[1];
-
- if (htype == 00 && hlen == 3 && data + 5 <= end) {
- return data + 2;
- }
-
- data += hlen;
- len -= hlen - 2;
- }
-Fail:
- return NULL;
-}
-
-int
-smspdu_get_ref( SmsPDU pdu )
-{
- cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
-
- if (user_ref != NULL)
- {
- return user_ref[0];
- }
- else
- {
- cbytes_t data = pdu->tpdu;
- cbytes_t end = pdu->end;
- int mtiByte = sms_get_byte( &data, end );
-
- if ((mtiByte & 3) == 1) {
- /* try to extract directly the reference for a SMS-SUBMIT */
- if (data < end)
- return data[0];
- }
- }
- return -1;
-}
-
-int
-smspdu_get_max_index( SmsPDU pdu )
-{
- cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
-
- if (user_ref != NULL) {
- return user_ref[1];
- } else {
- return 1;
- }
-}
-
-int
-smspdu_get_cur_index( SmsPDU pdu )
-{
- cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
-
- if (user_ref != NULL) {
- return user_ref[2] - 1;
- } else {
- return 0;
- }
-}
-
-
-static void
-gsm_rope_add_sms_user_header( GsmRope rope,
- int ref_number,
- int pdu_count,
- int pdu_index )
-{
- gsm_rope_add_c( rope, 0x05 ); /* total header length == 5 bytes */
- gsm_rope_add_c( rope, 0x00 ); /* element id: concatenated message reference number */
- gsm_rope_add_c( rope, 0x03 ); /* element len: 3 bytes */
- gsm_rope_add_c( rope, (byte_t)ref_number ); /* reference number */
- gsm_rope_add_c( rope, (byte_t)pdu_count ); /* max pdu index */
- gsm_rope_add_c( rope, (byte_t)pdu_index+1 ); /* current pdu index */
-}
-
-/* write a SMS-DELIVER PDU into a rope */
-static void
-gsm_rope_add_sms_deliver_pdu( GsmRope rope,
- cbytes_t utf8,
- int utf8len,
- int use_gsm7,
- const SmsAddressRec* sender_address,
- const SmsTimeStampRec* timestamp,
- int ref_num,
- int pdu_count,
- int pdu_index)
-{
- int coding;
- int mtiByte = 0x20; /* message type - SMS DELIVER */
-
- if (pdu_count > 1)
- mtiByte |= 0x40; /* user data header indicator */
-
- gsm_rope_add_c( rope, 0 ); /* no SC Address */
- gsm_rope_add_c( rope, mtiByte ); /* message type - SMS-DELIVER */
- gsm_rope_add_address( rope, sender_address );
- gsm_rope_add_c( rope, 0 ); /* protocol identifier */
-
- /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */
- coding = (use_gsm7 ? 0x00 : 0x09);
-
- gsm_rope_add_c( rope, coding ); /* data coding scheme */
- gsm_rope_add_timestamp( rope, timestamp ); /* service center timestamp */
-
- if (use_gsm7) {
- bytes_t dst;
- int count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
- int pad = 0;
-
- assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE );
-
- if (pdu_count > 1)
- {
- int headerBits = 6*8; /* 6 is size of header in bytes */
- int headerSeptets = headerBits / 7;
- if (headerBits % 7 > 0)
- headerSeptets += 1;
-
- pad = headerSeptets*7 - headerBits;
-
- gsm_rope_add_c( rope, count + headerSeptets );
- gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index);
- }
- else
- gsm_rope_add_c( rope, count );
-
- count = (count*7+pad+7)/8; /* convert to byte count */
-
- dst = gsm_rope_reserve( rope, count );
- if (dst != NULL) {
- utf8_to_gsm7( utf8, utf8len, dst, pad );
- }
- } else {
- bytes_t dst;
- int count = utf8_to_ucs2( utf8, utf8len, NULL );
-
- assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE );
-
- if (pdu_count > 1)
- {
- gsm_rope_add_c( rope, count*2 + 6 );
- gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index );
- }
- else
- gsm_rope_add_c( rope, count*2 );
-
- gsm_rope_add_c( rope, count*2 );
- dst = gsm_rope_reserve( rope, count*2 );
- if (dst != NULL) {
- utf8_to_ucs2( utf8, utf8len, dst );
- }
- }
-}
-
-
-static SmsPDU
-smspdu_create_deliver( cbytes_t utf8,
- int utf8len,
- int use_gsm7,
- const SmsAddressRec* sender_address,
- const SmsTimeStampRec* timestamp,
- int ref_num,
- int pdu_count,
- int pdu_index )
-{
- SmsPDU p;
- GsmRopeRec rope[1];
- int size;
-
- p = calloc( sizeof(*p), 1 );
- if (!p) goto Exit;
-
- gsm_rope_init( rope );
- gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
- sender_address, timestamp,
- ref_num, pdu_count, pdu_index);
- if (rope->error)
- goto Fail;
-
- gsm_rope_init_alloc( rope, rope->pos );
-
- gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
- sender_address, timestamp,
- ref_num, pdu_count, pdu_index );
-
- p->base = gsm_rope_done_acquire( rope, &size );
- if (p->base == NULL)
- goto Fail;
-
- p->end = p->base + size;
- p->tpdu = p->base + 1;
-Exit:
- return p;
-
-Fail:
- free(p);
- return NULL;
-}
-
-
-void
-smspdu_free_list( SmsPDU* pdus )
-{
- if (pdus) {
- int nn;
- for (nn = 0; pdus[nn] != NULL; nn++)
- smspdu_free( pdus[nn] );
-
- free( pdus );
- }
-}
-
-
-
-SmsPDU*
-smspdu_create_deliver_utf8( const unsigned char* utf8,
- int utf8len,
- const SmsAddressRec* sender_address,
- const SmsTimeStampRec* timestamp )
-{
- SmsTimeStampRec ts0;
- int use_gsm7;
- int count, block;
- int num_pdus = 0;
- int leftover = 0;
- SmsPDU* list = NULL;
-
- static unsigned char ref_num = 0;
-
- if (timestamp == NULL) {
- sms_timestamp_now( &ts0 );
- timestamp = &ts0;
- }
-
- /* can we encode the message with the GSM 7-bit alphabet ? */
- use_gsm7 = utf8_check_gsm7( utf8, utf8len );
-
- /* count the number of SMS PDUs we'll need */
- block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE;
-
- if (use_gsm7) {
- count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
- } else {
- count = utf8_to_ucs2( utf8, utf8len, NULL );
- block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE;
- }
-
- num_pdus = count / block;
- leftover = count - num_pdus*block;
- if (leftover > 0)
- num_pdus += 1;
-
- list = calloc( sizeof(SmsPDU*), num_pdus + 1 );
- if (list == NULL)
- return NULL;
-
- /* now create each SMS PDU */
- {
- cbytes_t src = utf8;
- cbytes_t src_end = utf8 + utf8len;
- int nn;
-
- for (nn = 0; nn < num_pdus; nn++)
- {
- int skip = block;
- cbytes_t src_next;
-
- if (leftover > 0 && nn == num_pdus-1)
- skip = leftover;
-
- src_next = utf8_skip_gsm7( src, src_end, skip );
-
- list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp,
- ref_num, num_pdus, nn );
- if (list[nn] == NULL)
- goto Fail;
-
- src = src_next;
- }
- }
-
- ref_num++;
- return list;
-
-Fail:
- smspdu_free_list(list);
- return NULL;
-}
-
-
-SmsPDU
-smspdu_create_from_hex( const char* hex, int hexlen )
-{
- SmsPDU p;
- cbytes_t data;
-
- p = calloc( sizeof(*p), 1 );
- if (!p) goto Exit;
-
- p->base = malloc( (hexlen+1)/2 );
- if (p->base == NULL) {
- free(p);
- p = NULL;
- goto Exit;
- }
-
- if ( gsm_hex_to_bytes( (cbytes_t)hex, hexlen, p->base ) < 0 )
- goto Fail;
-
- p->end = p->base + (hexlen+1)/2;
-
- data = p->base;
- if ( sms_skip_sc_address( &data, p->end ) < 0 )
- goto Fail;
-
- p->tpdu = (bytes_t) data;
-
-Exit:
- return p;
-
-Fail:
- free(p->base);
- free(p);
- return NULL;
-}
-
-int
-smspdu_to_hex( SmsPDU pdu, char* hex, int hexlen )
-{
- int result = (pdu->end - pdu->base)*2;
- int nn;
-
- if (hexlen > result)
- hexlen = result;
-
- for (nn = 0; nn*2 < hexlen; nn++) {
- gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] );
- }
- return result;
-}
-
-
-/** SMS SUBMIT RECEIVER
- ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver
- **/
-
-typedef struct SmsFragmentRec {
- struct SmsFragmentRec* next;
- SmsAddressRec from[1];
- byte_t ref;
- byte_t max;
- byte_t count;
- int index;
- SmsPDU* pdus;
-
-} SmsFragmentRec, *SmsFragment;
-
-
-typedef struct SmsReceiverRec {
- int last;
- SmsFragment fragments;
-
-} SmsReceiverRec;
-
-
-static void
-sms_fragment_free( SmsFragment frag )
-{
- int nn;
-
- for (nn = 0; nn < frag->max; nn++) {
- if (frag->pdus[nn] != NULL) {
- smspdu_free( frag->pdus[nn] );
- frag->pdus[nn] = NULL;
- }
- }
- frag->pdus = NULL;
- frag->count = 0;
- frag->max = 0;
- frag->index = 0;
- free( frag );
-}
-
-static SmsFragment
-sms_fragment_alloc( SmsReceiver rec, const SmsAddressRec* from, int ref, int max )
-{
- SmsFragment frag = calloc(sizeof(*frag) + max*sizeof(SmsPDU), 1 );
-
- if (frag != NULL) {
- frag->from[0] = from[0];
- frag->ref = ref;
- frag->max = max;
- frag->pdus = (SmsPDU*)(frag + 1);
- frag->index = ++rec->last;
- }
- return frag;
-}
-
-
-
-SmsReceiver sms_receiver_create( void )
-{
- SmsReceiver rec = calloc(sizeof(*rec),1);
- return rec;
-}
-
-void
-sms_receiver_destroy( SmsReceiver rec )
-{
- while (rec->fragments) {
- SmsFragment frag = rec->fragments;
- rec->fragments = frag->next;
- sms_fragment_free(frag);
- }
-}
-
-static SmsFragment*
-sms_receiver_find_p( SmsReceiver rec, const SmsAddressRec* from, int ref )
-{
- SmsFragment* pnode = &rec->fragments;
- SmsFragment node;
-
- for (;;) {
- node = *pnode;
- if (node == NULL)
- break;
- if (node->ref == ref && sms_address_eq( node->from, from ))
- break;
- pnode = &node->next;
- }
- return pnode;
-}
-
-static SmsFragment*
-sms_receiver_find_index_p( SmsReceiver rec, int index )
-{
- SmsFragment* pnode = &rec->fragments;
- SmsFragment node;
-
- for (;;) {
- node = *pnode;
- if (node == NULL)
- break;
- if (node->index == index)
- break;
- pnode = &node->next;
- }
- return pnode;
-}
-
-int
-sms_receiver_add_submit_pdu( SmsReceiver rec, SmsPDU submit_pdu )
-{
- SmsAddressRec from[1];
- int ref, max, cur;
- SmsFragment* pnode;
- SmsFragment frag;
-
- if ( smspdu_get_receiver_address( submit_pdu, from ) < 0 ) {
- D( "%s: could not extract receiver address\n", __FUNCTION__ );
- return -1;
- }
-
- ref = smspdu_get_ref( submit_pdu );
- if (ref < 0) {
- D( "%s: could not extract message reference from pdu\n", __FUNCTION__ );
- return -1;
- }
- max = smspdu_get_max_index( submit_pdu );
- if (max < 0) {
- D( "%s: invalid max fragment value: %d should be >= 1\n",
- __FUNCTION__, max );
- return -1;
- }
- pnode = sms_receiver_find_p( rec, from, ref );
- frag = *pnode;
- if (frag == NULL) {
- frag = sms_fragment_alloc( rec, from, ref, max );
- if (frag == NULL) {
- D("%s: not enough memory to allocate new fragment\n", __FUNCTION__ );
- return -1;
- }
- if (D_ACTIVE) {
- char tmp[32];
- int len;
-
- len = sms_address_to_str( from, tmp, sizeof(tmp) );
- if (len < 0) {
- strcpy( tmp, "<unknown>" );
- len = strlen(tmp);
- }
- D("%s: created SMS index %d, from %.*s, ref %d, max %d\n", __FUNCTION__,
- frag->index, len, tmp, frag->ref, frag->max);
- }
- *pnode = frag;
- }
-
- cur = smspdu_get_cur_index( submit_pdu );
- if (cur < 0) {
- D("%s: SMS fragment index is too small: %d should be >= 1\n", __FUNCTION__, cur+1 );
- return -1;
- }
- if (cur >= max) {
- D("%s: SMS fragment index is too large (%d >= %d)\n", __FUNCTION__, cur, max);
- return -1;
- }
- if ( frag->pdus[cur] != NULL ) {
- D("%s: receiving duplicate SMS fragment for %d/%d, ref=%d, discarding old one\n",
- __FUNCTION__, cur+1, max, ref);
- smspdu_free( frag->pdus[cur] );
- frag->count -= 1;
- }
- frag->pdus[cur] = submit_pdu;
- frag->count += 1;
-
- if (frag->count >= frag->max) {
- /* yes, we received all fragments for this SMS */
- D( "%s: SMS index %d, received all %d fragments\n", __FUNCTION__, frag->index, frag->count );
- return frag->index;
- }
- else {
- /* still waiting for more */
- D( "%s: SMS index %d, received %d/%d, waiting for %d more\n", __FUNCTION__,
- frag->index, cur+1, max, frag->max - frag->count );
- return 0;
- }
-}
-
-
-int
-sms_receiver_get_text_message( SmsReceiver rec, int index, bytes_t utf8, int utf8len )
-{
- SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
- SmsFragment frag = *pnode;
- int nn, total;
-
- if (frag == NULL) {
- D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
- return -1;
- }
- if (frag->count != frag->max) {
- D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
- frag->index, frag->max - frag->count );
- return -1;
- }
- /* get the size of all combined text */
- total = 0;
- for ( nn = 0; nn < frag->count; nn++ ) {
- int partial;
- if (utf8 && utf8len > 0) {
- partial = smspdu_get_text_message( frag->pdus[nn], utf8, utf8len );
- utf8 += partial;
- utf8len -= partial;
- } else {
- partial = smspdu_get_text_message( frag->pdus[nn], NULL, 0 );
- }
- total += partial;
- }
- return total;
-}
-
-
-static void
-sms_receiver_remove( SmsReceiver rec, int index )
-{
- SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
- SmsFragment frag = *pnode;
- if (frag != NULL) {
- *pnode = frag->next;
- sms_fragment_free(frag);
- }
-}
-
-
-SmsPDU*
-sms_receiver_create_deliver( SmsReceiver rec, int index, const SmsAddressRec* from )
-{
- SmsPDU* result = NULL;
- SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
- SmsFragment frag = *pnode;
- SmsTimeStampRec now[1];
- int nn, total;
- bytes_t utf8;
- int utf8len;
-
- if (frag == NULL) {
- D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
- return NULL;
- }
- if (frag->count != frag->max) {
- D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
- frag->index, frag->max - frag->count );
- return NULL;
- }
-
- /* get the combined text message */
- utf8len = sms_receiver_get_text_message( rec, index, NULL, 0 );
- if (utf8len < 0)
- goto Exit;
-
- utf8 = malloc( utf8len + 1 );
- if (utf8 == NULL) {
- D( "%s: not enough memory to allocate %d bytes\n",
- __FUNCTION__, utf8len+1 );
- goto Exit;
- }
-
- total = 0;
- for ( nn = 0; nn < frag->count; nn++ ) {
- total += smspdu_get_text_message( frag->pdus[nn], utf8 + total, utf8len - total );
- }
-
- sms_timestamp_now( now );
-
- result = smspdu_create_deliver_utf8( utf8, utf8len, from, now );
-
- free(utf8);
-
-Exit:
- sms_receiver_remove( rec, index );
- return result;
-}
-