Home | History | Annotate | Download | only in telephony
      1 /* Copyright (C) 2007-2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "sms.h"
     13 #include "gsm.h"
     14 #include <memory.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include <assert.h>
     18 
     19 #define  DEBUG  1
     20 
     21 #if 1
     22 #  include "android/utils/debug.h"
     23 #  define  D_ACTIVE  VERBOSE_CHECK(modem)
     24 #else
     25 #  define  D_ACTIVE  DEBUG
     26 #endif
     27 
     28 #if DEBUG
     29 #  define  D(...)  VERBOSE_PRINT(modem,__VA_ARGS__)
     30 #else
     31 #  define  D(...)  ((void)0)
     32 #endif
     33 
     34 /* maximum number of data bytes in a SMS data message */
     35 #define  MAX_USER_DATA_BYTES   140
     36 
     37 /* maximum number of 7-bit septets in a SMS text message */
     38 #define  MAX_USER_DATA_SEPTETS  160
     39 
     40 /* size of the user data header in bytes */
     41 #define  USER_DATA_HEADER_SIZE   6
     42 
     43 /** MESSAGE TEXT
     44  **/
     45 int
     46 sms_utf8_from_message_str( const char*  str, int  strlen, unsigned char*  utf8, int  utf8len )
     47 {
     48     cbytes_t  p       = (cbytes_t)str;
     49     cbytes_t  end     = p + strlen;
     50     int       count   = 0;
     51     int       escaped = 0;
     52 
     53     while (p < end)
     54     {
     55         int  c = p[0];
     56 
     57         /* read the value from the string */
     58         p += 1;
     59         if (c >= 128) {
     60             if ((c & 0xe0) == 0xc0)
     61                 c &= 0x1f;
     62             else if ((c & 0xf0) == 0xe0)
     63                 c &= 0x0f;
     64             else
     65                 c &= 0x07;
     66             p++;
     67             while (p < end && (p[0] & 0xc0) == 0x80) {
     68                 c = (c << 6) | (p[0] & 0x3f);
     69                 p++;
     70             }
     71         }
     72         if (escaped) {
     73             switch (c) {
     74                 case '\\':
     75                     break;
     76                 case 'n':  /* \n is line feed */
     77                     c = 10;
     78                     break;
     79 
     80                 case 'x':  /* \xNN, where NN is a 2-digit hexadecimal value */
     81                     if (p+2 > end)
     82                         return -1;
     83                     c = gsm_hex2_to_byte( (const char*)p );
     84                     if (c < 0)
     85                         return -1;
     86                     p += 2;
     87                     break;
     88 
     89                 case 'u':  /* \uNNNN where NNNN is a 4-digiti hexadecimal value */
     90                     if (p + 4 > end)
     91                         return -1;
     92                     c = gsm_hex4_to_short( (const char*)p );
     93                     if (c < 0)
     94                         return -1;
     95                     p += 4;
     96                     break;
     97 
     98                 default:  /* invalid escape, return -1 */
     99                     return -1;
    100             }
    101             escaped = 0;
    102         }
    103         else if (c == '\\')
    104         {
    105             escaped = 1;
    106             continue;
    107         }
    108 
    109         /* now, try to write it to the destination */
    110         if (c < 128) {
    111             if (count < utf8len)
    112                 utf8[count] = (byte_t) c;
    113             count += 1;
    114         }
    115         else if (c < 0x800) {
    116             if (count < utf8len)
    117                 utf8[count]   = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
    118             if (count+1 < utf8len)
    119                 utf8[count+1] = (byte_t)(0x80 | (c & 0x3f));
    120             count += 2;
    121         }
    122         else {
    123             if (count < utf8len)
    124                 utf8[count]   = (byte_t)(0xc0 | ((c >> 12) & 0xf));
    125             if (count+1 < utf8len)
    126                 utf8[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
    127             if (count+2 < utf8len)
    128                 utf8[count+2] = (byte_t)(0x80 | (c & 0x3f));
    129             count += 3;
    130         }
    131     }
    132 
    133     if (escaped)   /* bad final escape */
    134         return -1;
    135 
    136     return count;
    137 }
    138 
    139 /* to convert utf-8 to a message string, we only need to deal with control characters
    140  * and that's it */
    141 int  sms_utf8_to_message_str( const unsigned char*  utf8, int  utf8len, char*  str, int  strlen )
    142 {
    143     cbytes_t  p = utf8;
    144     cbytes_t  end = p + utf8len;
    145     int       count   = 0;
    146 
    147     while (p < end)
    148     {
    149         int  c      = p[0];
    150         int  escape = 0;
    151 
    152         /* read the value from the string */
    153         p += 1;
    154         if (c >= 128) {
    155             if ((c & 0xe0) == 0xc0)
    156                 c &= 0x1f;
    157             else if ((c & 0xf0) == 0xe0)
    158                 c &= 0x0f;
    159             else
    160                 c &= 0x07;
    161             p++;
    162             while (p < end && (p[0] & 0xc0) == 0x80) {
    163                 c = (c << 6) | (p[0] & 0x3f);
    164                 p++;
    165             }
    166         }
    167 
    168         if (c < ' ') {
    169             escape = 1;
    170             if (c == '\n') {
    171                 c      = 'n';
    172                 escape = 2;
    173             }
    174         }
    175         else if (c == '\\')
    176             escape = 2;
    177 
    178         switch (escape) {
    179             case 0:
    180                 if (c < 128) {
    181                     if (count < strlen)
    182                         str[count] = (char) c;
    183                     count += 1;
    184                 }
    185                 else if (c < 0x800) {
    186                     if (count < strlen)
    187                         str[count]   = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
    188                     if (count+1 < strlen)
    189                         str[count+1] = (byte_t)(0x80 | (c & 0x3f));
    190                     count += 2;
    191                 }
    192                 else {
    193                     if (count < strlen)
    194                         str[count]   = (byte_t)(0xc0 | ((c >> 12) & 0xf));
    195                     if (count+1 < strlen)
    196                         str[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
    197                     if (count+2 < strlen)
    198                         str[count+2] = (byte_t)(0x80 | (c & 0x3f));
    199                     count += 3;
    200                 }
    201                 break;
    202 
    203             case 1:
    204                 if (count+3 < strlen) {
    205                     str[count+0] = '\\';
    206                     str[count+1] = 'x';
    207                     gsm_hex_from_byte(str + count + 2, c);
    208                 }
    209                 count += 4;
    210                 break;
    211 
    212             default:
    213                 if (count+2 < strlen) {
    214                     str[count+0] = '\\';
    215                     str[count+1] = (char) c;
    216                 }
    217                 count += 2;
    218         }
    219     }
    220     return count;
    221 }
    222 
    223 
    224 /** TIMESTAMPS
    225  **/
    226 void
    227 sms_timestamp_now( SmsTimeStamp  stamp )
    228 {
    229     time_t     now_time = time(NULL);
    230     struct tm  gm       = *(gmtime(&now_time));
    231     struct tm  local    = *(localtime(&now_time));
    232     int        tzdiff   = 0;
    233 
    234     stamp->data[0] = gsm_int_to_bcdi( local.tm_year % 100 );
    235     stamp->data[1] = gsm_int_to_bcdi( local.tm_mon+1 );
    236     stamp->data[2] = gsm_int_to_bcdi( local.tm_mday );
    237     stamp->data[3] = gsm_int_to_bcdi( local.tm_hour );
    238     stamp->data[4] = gsm_int_to_bcdi( local.tm_min );
    239     stamp->data[5] = gsm_int_to_bcdi( local.tm_sec );
    240 
    241     tzdiff = (local.tm_hour*4 + local.tm_min/15) - (gm.tm_hour*4 + gm.tm_min/15);
    242     if (local.tm_yday > gm.tm_yday)
    243         tzdiff += 24*4;
    244     else if (local.tm_yday < gm.tm_yday)
    245         tzdiff -= 24*4;
    246 
    247     stamp->data[6] = gsm_int_to_bcdi( tzdiff >= 0 ? tzdiff : -tzdiff );
    248     if (tzdiff < 0)
    249         stamp->data[6] |= 0x08;
    250 }
    251 
    252 int
    253 sms_timestamp_to_tm( SmsTimeStamp  stamp, struct tm*  tm )
    254 {
    255     int  tzdiff;
    256 
    257     tm->tm_year = gsm_int_from_bcdi( stamp->data[0] );
    258     if (tm->tm_year < 50)
    259         tm->tm_year += 100;
    260     tm->tm_mon  = gsm_int_from_bcdi( stamp->data[1] ) -1;
    261     tm->tm_mday = gsm_int_from_bcdi( stamp->data[2] );
    262     tm->tm_hour = gsm_int_from_bcdi( stamp->data[3] );
    263     tm->tm_min  = gsm_int_from_bcdi( stamp->data[4] );
    264     tm->tm_sec  = gsm_int_from_bcdi( stamp->data[5] );
    265 
    266     tm->tm_isdst = -1;
    267 
    268     tzdiff = gsm_int_from_bcdi( stamp->data[6] & 0xf7 );
    269     if (stamp->data[6] & 0x8)
    270         tzdiff = -tzdiff;
    271 
    272     return tzdiff;
    273 }
    274 
    275 static void
    276 gsm_rope_add_timestamp( GsmRope  rope, const SmsTimeStampRec*  ts )
    277 {
    278     gsm_rope_add( rope, ts->data, 7 );
    279 }
    280 
    281 
    282 /** SMS ADDRESSES
    283  **/
    284 
    285 int
    286 sms_address_from_str( SmsAddress  address, const char*  src, int  srclen )
    287 {
    288     const char*  end   = src + srclen;
    289     int          shift = 0, len = 0;
    290     bytes_t      data = address->data;
    291 
    292     address->len = 0;
    293     address->toa = 0x81;
    294 
    295     if (src >= end)
    296         return -1;
    297 
    298     if ( src[0] == '+' ) {
    299         address->toa = 0x91;
    300         if (++src == end)
    301             goto Fail;
    302     }
    303 
    304     memset( address->data, 0, sizeof(address->data) );
    305 
    306     shift = 0;
    307 
    308     while (src < end) {
    309         int  c = *src++ - '0';
    310 
    311         if ( (unsigned)c >= 10 ||
    312               data >= address->data + sizeof(address->data) )
    313             goto Fail;
    314 
    315         data[0] |= c << shift;
    316         len   += 1;
    317         shift += 4;
    318         if (shift == 8) {
    319             shift = 0;
    320             data += 1;
    321         }
    322     }
    323     if (shift != 0)
    324         data[0] |= 0xf0;
    325 
    326     address->len = len;
    327     return 0;
    328 
    329 Fail:
    330     return -1;
    331 }
    332 
    333 int
    334 sms_address_to_str( SmsAddress address, char*  str, int  strlen )
    335 {
    336     static const char  dialdigits[16] = "0123456789*#,N%";
    337     int                n, count = 0;
    338 
    339     if (address->toa == 0x91) {
    340         if (count < strlen)
    341             str[count] = '+';
    342         count++;
    343     }
    344     for (n = 0; n < address->len; n += 2)
    345     {
    346         int   c = address->data[n/2];
    347 
    348         if (count < strlen)
    349             str[count] = dialdigits[c & 0xf];
    350         count += 1;
    351 
    352         if (n+1 > address->len)
    353             break;
    354 
    355         if (count < strlen)
    356             str[count] = dialdigits[(c >> 4) & 0xf];
    357         if (str[count])
    358             count += 1;
    359     }
    360     return count;
    361 }
    362 
    363 int
    364 sms_address_from_bytes( SmsAddress  address, const unsigned char*  buf, int  buflen )
    365 {
    366     int   len = sizeof(address->data), num_digits;
    367 
    368     if (buflen < 2)
    369         return -1;
    370 
    371     address->len = num_digits = buf[0];
    372     address->toa = buf[1];
    373 
    374     len = (num_digits+1)/2;
    375     if ( len > sizeof(address->data) )
    376         return -1;
    377 
    378     memcpy( address->data, buf+2, len );
    379     return 0;
    380 }
    381 
    382 int
    383 sms_address_to_bytes( SmsAddress  address, unsigned char*  buf, int  bufsize )
    384 {
    385     int  len = (address->len + 1)/2 + 2;
    386 
    387     if (buf == NULL)
    388         bufsize = 0;
    389 
    390     if (bufsize < 1) goto Exit;
    391     buf[0] = address->len;
    392 
    393     if (bufsize < 2) goto Exit;
    394     buf[1] = address->toa;
    395 
    396     buf     += 2;
    397     bufsize -= 2;
    398     if (bufsize > len-2)
    399         bufsize = len - 2;
    400 
    401     memcpy( buf, address->data, bufsize );
    402 Exit:
    403     return len;
    404 }
    405 
    406 int
    407 sms_address_from_hex  ( SmsAddress  address, const char*  hex, int  hexlen )
    408 {
    409     const char*  hexend = hex + hexlen;
    410     int          nn, len, num_digits;
    411 
    412     if (hexlen < 4)
    413         return -1;
    414 
    415     address->len = num_digits = gsm_hex2_to_byte( hex );
    416     address->toa = gsm_hex2_to_byte( hex+2 );
    417     hex += 4;
    418 
    419     len = (num_digits + 1)/2;
    420     if (hex + len*2 > hexend)
    421         return -1;
    422 
    423     for ( nn = 0; nn < len; nn++ )
    424         address->data[nn] = gsm_hex2_to_byte( hex + nn*2 );
    425 
    426     return 0;
    427 }
    428 
    429 int
    430 sms_address_to_hex    ( SmsAddress  address, char*   hex, int  hexlen )
    431 {
    432     int  len = (address->len + 1)/2 + 2;
    433     int  nn;
    434 
    435     if (hex == NULL)
    436         hexlen = 0;
    437 
    438     if (hexlen < 2) goto Exit;
    439     gsm_hex_from_byte( hex, address->len );
    440     if (hexlen < 4) goto Exit;
    441     gsm_hex_from_byte( hex+2, address->toa );
    442     hex    += 4;
    443     hexlen -= 4;
    444     if ( hexlen > 2*(len - 2) )
    445         hexlen = (len - 2)/2;
    446 
    447     for ( nn = 0; nn < hexlen; nn += 2 )
    448         gsm_hex_from_byte( hex+nn, address->data[nn/2] );
    449 
    450 Exit:
    451     return len*2;
    452 }
    453 
    454 static void
    455 gsm_rope_add_address( GsmRope  rope, const SmsAddressRec*  addr )
    456 {
    457     gsm_rope_add_c( rope, addr->len );
    458     gsm_rope_add_c( rope, addr->toa );
    459     gsm_rope_add( rope, addr->data, (addr->len+1)/2 );
    460     if (addr->len & 1) {
    461         if (!rope->error && rope->data != NULL)
    462             rope->data[ rope->pos-1 ] |= 0xf0;
    463     }
    464 }
    465 
    466 static int
    467 sms_address_eq( const SmsAddressRec*  addr1, const SmsAddressRec*  addr2 )
    468 {
    469     if ( addr1->toa != addr2->toa ||
    470          addr1->len != addr2->len )
    471         return 0;
    472 
    473     return ( !memcmp( addr1->data, addr2->data, addr1->len ) );
    474 }
    475 
    476 /** SMS PARSER
    477  **/
    478 static int
    479 sms_get_byte( cbytes_t  *pcur, cbytes_t  end )
    480 {
    481     cbytes_t  cur    = *pcur;
    482     int       result = -1;
    483 
    484     if (cur < end) {
    485         result = cur[0];
    486         *pcur  = cur + 1;
    487     }
    488     return result;
    489 }
    490 
    491 /* parse a service center address, returns -1 in case of error */
    492 static int
    493 sms_get_sc_address( cbytes_t   *pcur,
    494                     cbytes_t    end,
    495                     SmsAddress  address )
    496 {
    497     cbytes_t  cur    = *pcur;
    498     int       result = -1;
    499 
    500     if (cur < end) {
    501         int  len = cur[0];
    502         int  dlen, adjust = 0;
    503 
    504         cur += 1;
    505 
    506         if (len == 0) {   /* empty address */
    507             address->len = 0;
    508             address->toa = 0x00;
    509             result       = 0;
    510             goto Exit;
    511         }
    512 
    513         if (cur + len > end) {
    514             goto Exit;
    515         }
    516 
    517         address->toa = *cur++;
    518         len         -= 1;
    519         result       = 0;
    520 
    521         for (dlen = 0; dlen < len; dlen+=1)
    522         {
    523             int  c = cur[dlen];
    524             int  v;
    525 
    526             adjust = 0;
    527             if (dlen >= sizeof(address->data)) {
    528                 result = -1;
    529                 break;
    530             }
    531 
    532             v = (c & 0xf);
    533             if (v >= 0xe)
    534                 break;
    535 
    536             adjust              = 1;
    537             address->data[dlen] = (byte_t) c;
    538 
    539             v = (c >> 4) & 0xf;
    540             if (v >= 0xe) {
    541                 break;
    542             }
    543         }
    544         address->len = 2*dlen + adjust;
    545     }
    546 Exit:
    547     if (!result)
    548         *pcur = cur;
    549 
    550     return result;
    551 }
    552 
    553 static int
    554 sms_skip_sc_address( cbytes_t   *pcur,
    555                      cbytes_t    end )
    556 {
    557     cbytes_t  cur    = *pcur;
    558     int       result = -1;
    559     int       len;
    560 
    561     if (cur >= end)
    562         goto Exit;
    563 
    564     len  = cur[0];
    565     cur += 1 + len;
    566     if (cur > end)
    567         goto Exit;
    568 
    569     *pcur  = cur;
    570     result = 0;
    571 Exit:
    572     return result;
    573 }
    574 
    575 /* parse a sender/receiver address, returns -1 in case of error */
    576 static int
    577 sms_get_address( cbytes_t   *pcur,
    578                  cbytes_t    end,
    579                  SmsAddress  address )
    580 {
    581     cbytes_t  cur    = *pcur;
    582     int       result = -1;
    583     int       len, dlen;
    584 
    585     if (cur >= end)
    586         goto Exit;
    587 
    588     dlen = *cur++;
    589 
    590     if (dlen == 0) {
    591         address->len = 0;
    592         address->toa = 0;
    593         result       = 0;
    594         goto Exit;
    595     }
    596 
    597     if (cur + 1 + (dlen+1)/2 > end)
    598         goto Exit;
    599 
    600     address->len = dlen;
    601     address->toa = *cur++;
    602 
    603     len = (dlen + 1)/2;
    604     if (len > sizeof(address->data))
    605         goto Exit;
    606 
    607     memcpy( address->data, cur, len );
    608     cur   += len;
    609     result = 0;
    610 
    611 Exit:
    612     if (!result)
    613         *pcur = cur;
    614 
    615     return result;
    616 }
    617 
    618 static int
    619 sms_skip_address( cbytes_t   *pcur,
    620                   cbytes_t    end  )
    621 {
    622     cbytes_t  cur    = *pcur;
    623     int       result = -1;
    624     int       dlen;
    625 
    626     if (cur + 2 > end)
    627         goto Exit;
    628 
    629     dlen = cur[0];
    630     cur += 2 + (dlen + 1)/2;
    631     if (cur > end)
    632         goto Exit;
    633 
    634     result = 0;
    635 Exit:
    636     return result;
    637 }
    638 
    639 /* parse a service center timestamp */
    640 static int
    641 sms_get_timestamp( cbytes_t     *pcur,
    642                    cbytes_t      end,
    643                    SmsTimeStamp  ts )
    644 {
    645     cbytes_t  cur = *pcur;
    646 
    647     if (cur + 7 > end)
    648         return -1;
    649 
    650     memcpy( ts->data, cur, 7 );
    651     *pcur = cur + 7;
    652     return 0;
    653 }
    654 
    655 static int
    656 sms_skip_timestamp( cbytes_t  *pcur,
    657                     cbytes_t   end )
    658 {
    659     cbytes_t  cur = *pcur;
    660 
    661     if (cur + 7 > end)
    662         return -1;
    663 
    664     *pcur = cur + 7;
    665     return 0;
    666 }
    667 
    668 
    669 static int
    670 sms_skip_validity_period( cbytes_t  *pcur,
    671                           cbytes_t   end,
    672                           int        mtiByte )
    673 {
    674     cbytes_t  cur = *pcur;
    675 
    676     switch ((mtiByte >> 3) & 3) {
    677         case 1:  /* relative format */
    678             cur += 1;
    679             break;
    680 
    681         case 2:  /* enhanced format */
    682         case 3:  /* absolute format */
    683             cur += 7;
    684     }
    685     if (cur > end)
    686         return -1;
    687 
    688     *pcur = cur;
    689     return 0;
    690 }
    691 
    692 /** SMS PDU
    693  **/
    694 
    695 typedef struct SmsPDURec {
    696     bytes_t  base;
    697     bytes_t  end;
    698     bytes_t  tpdu;
    699 } SmsPDURec;
    700 
    701 void
    702 smspdu_free( SmsPDU  pdu )
    703 {
    704     if (pdu) {
    705         free( pdu->base );
    706         pdu->base = NULL;
    707         pdu->end  = NULL;
    708         pdu->tpdu = NULL;
    709     }
    710 }
    711 
    712 SmsPduType
    713 smspdu_get_type( SmsPDU  pdu )
    714 {
    715     cbytes_t  data    = pdu->tpdu;
    716     cbytes_t  end     = pdu->end;
    717     int       mtiByte = sms_get_byte(&data, end);
    718 
    719     switch (mtiByte & 3) {
    720         case 0:  return SMS_PDU_DELIVER;
    721         case 1:  return SMS_PDU_SUBMIT;
    722         case 2:  return SMS_PDU_STATUS_REPORT;
    723         default: return SMS_PDU_INVALID;
    724     }
    725 }
    726 
    727 int
    728 smspdu_get_sender_address( SmsPDU  pdu, SmsAddress  address )
    729 {
    730     cbytes_t  data    = pdu->tpdu;
    731     cbytes_t  end     = pdu->end;
    732     int       mtiByte = sms_get_byte(&data, end);
    733 
    734     switch (mtiByte & 3) {
    735         case 0: /* SMS_PDU_DELIVER; */
    736             return sms_get_sc_address( &data, end, address );
    737 
    738         default: return -1;
    739     }
    740 }
    741 
    742 int
    743 smspdu_get_sc_timestamp( SmsPDU  pdu, SmsTimeStamp  ts )
    744 {
    745     cbytes_t  data    = pdu->tpdu;
    746     cbytes_t  end     = pdu->end;
    747     int       mtiByte = sms_get_byte( &data, end );
    748 
    749     switch (mtiByte & 3) {
    750         case 0:  /* SMS_PDU_DELIVER */
    751             {
    752                 SmsAddressRec  address;
    753 
    754                 if ( sms_get_sc_address( &data, end, &address ) < 0 )
    755                     return -1;
    756 
    757                 data += 2;  /* skip protocol identifer + coding scheme */
    758 
    759                 return sms_get_timestamp( &data, end, ts );
    760             }
    761 
    762         default: return -1;
    763     }
    764 }
    765 
    766 int
    767 smspdu_get_receiver_address( SmsPDU  pdu, SmsAddress  address )
    768 {
    769     cbytes_t  data    = pdu->tpdu;
    770     cbytes_t  end     = pdu->end;
    771     int       mtiByte = sms_get_byte( &data, end );
    772 
    773     switch (mtiByte & 3) {
    774         case 1:  /* SMS_PDU_SUBMIT */
    775             {
    776                 data += 1;  /* skip message reference */
    777                 return sms_get_address( &data, end, address );
    778             }
    779 
    780         default: return -1;
    781     }
    782 }
    783 
    784 typedef enum {
    785     SMS_CODING_SCHEME_UNKNOWN = 0,
    786     SMS_CODING_SCHEME_GSM7,
    787     SMS_CODING_SCHEME_UCS2
    788 
    789 } SmsCodingScheme;
    790 
    791 /* see TS 23.038 Section 5 for details */
    792 static SmsCodingScheme
    793 sms_get_coding_scheme( cbytes_t  *pcur,
    794                        cbytes_t   end )
    795 {
    796     cbytes_t  cur = *pcur;
    797     int       dataCoding;
    798 
    799     if (cur >= end)
    800         return SMS_CODING_SCHEME_UNKNOWN;
    801 
    802     dataCoding = *cur++;
    803     *pcur      = cur;
    804 
    805     switch (dataCoding >> 4) {
    806         case 0x00:
    807         case 0x02:
    808         case 0x03:
    809             return SMS_CODING_SCHEME_GSM7;
    810 
    811         case 0x01:
    812             if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7;
    813             if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2;
    814             break;
    815 
    816         case 0x04: case 0x05: case 0x06: case 0x07:
    817             if (dataCoding & 0x20)           return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */
    818             if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7;
    819             if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2;
    820             break;
    821 
    822         case 0xF:
    823             if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7;
    824             break;
    825     }
    826     return SMS_CODING_SCHEME_UNKNOWN;
    827 }
    828 
    829 
    830 /* see TS 23.040 section 9.2.3.24 for details */
    831 static int
    832 sms_get_text_utf8( cbytes_t        *pcur,
    833                    cbytes_t         end,
    834                    int              hasUDH,
    835                    SmsCodingScheme  coding,
    836                    GsmRope          rope )
    837 {
    838     cbytes_t  cur    = *pcur;
    839     int       result = -1;
    840     int       len;
    841 
    842     if (cur >= end)
    843         goto Exit;
    844 
    845     len = *cur++;
    846 
    847     /* skip user data header if any */
    848     if ( hasUDH )
    849     {
    850         int  hlen;
    851 
    852         if (cur >= end)
    853             goto Exit;
    854 
    855         hlen = *cur++;
    856         if (cur + hlen > end)
    857             goto Exit;
    858 
    859         cur += hlen;
    860 
    861         if (coding == SMS_CODING_SCHEME_GSM7)
    862             len -= 2*(hlen+1);
    863         else
    864             len -= hlen+1;
    865 
    866         if (len < 0)
    867             goto Exit;
    868     }
    869 
    870     /* switch the user data header if any */
    871     if (coding == SMS_CODING_SCHEME_GSM7)
    872     {
    873         int  count = utf8_from_gsm7( cur, 0, len, NULL );
    874 
    875         if (rope != NULL)
    876         {
    877             bytes_t  dst = gsm_rope_reserve( rope, count );
    878             if (dst != NULL)
    879                 utf8_from_gsm7( cur, 0, len, dst );
    880         }
    881         cur += (len+1)/2;
    882     }
    883     else if (coding == SMS_CODING_SCHEME_UCS2)
    884     {
    885         int  count = ucs2_to_utf8( cur, len/2, NULL );
    886 
    887         if (rope != NULL)
    888         {
    889             bytes_t  dst = gsm_rope_reserve( rope, count );
    890             if (dst != NULL)
    891                 ucs2_to_utf8( cur, len/2, dst );
    892         }
    893         cur += len;
    894     }
    895     result = 0;
    896 
    897 Exit:
    898     if (!result)
    899         *pcur = cur;
    900 
    901     return result;
    902 }
    903 
    904 /* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
    905 /* or -1 in case of error */
    906 int
    907 smspdu_get_text_message( SmsPDU  pdu, unsigned char*  utf8, int  utf8len )
    908 {
    909     cbytes_t  data    = pdu->tpdu;
    910     cbytes_t  end     = pdu->end;
    911     int       mtiByte = sms_get_byte( &data, end );
    912 
    913     switch (mtiByte & 3) {
    914         case 0:  /* SMS_PDU_DELIVER */
    915             {
    916                 SmsAddressRec    address;
    917                 SmsTimeStampRec  timestamp;
    918                 SmsCodingScheme  coding;
    919                 GsmRopeRec       rope[1];
    920                 int              result;
    921 
    922                 if ( sms_get_sc_address( &data, end, &address ) < 0 )
    923                     goto Fail;
    924 
    925                 data  += 1;  /* skip protocol identifier */
    926                 coding = sms_get_coding_scheme( &data, end );
    927                 if (coding == SMS_CODING_SCHEME_UNKNOWN)
    928                     goto Fail;
    929 
    930                 if ( sms_get_timestamp( &data, end, &timestamp ) < 0 )
    931                     goto Fail;
    932 
    933                 if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 )
    934                     goto Fail;
    935 
    936                 result = rope->pos;
    937                 if (utf8len > result)
    938                     utf8len = result;
    939 
    940                 if (utf8len > 0)
    941                     memcpy( utf8, rope->data, utf8len );
    942 
    943                 gsm_rope_done( rope );
    944                 return result;
    945             }
    946 
    947         case 1:  /* SMS_PDU_SUBMIT */
    948             {
    949                 SmsAddressRec    address;
    950                 SmsCodingScheme  coding;
    951                 GsmRopeRec       rope[1];
    952                 int              result;
    953 
    954                 data += 1;  /* message reference */
    955 
    956                 if ( sms_get_address( &data, end, &address ) < 0 )
    957                     goto Fail;
    958 
    959                 data  += 1;  /* skip protocol identifier */
    960                 coding = sms_get_coding_scheme( &data, end );
    961                 if (coding == SMS_CODING_SCHEME_UNKNOWN)
    962                     goto Fail;
    963 
    964                 gsm_rope_init_alloc( rope, 0 );
    965                 if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) {
    966                     gsm_rope_done( rope );
    967                     goto Fail;
    968                 }
    969 
    970                 result = rope->pos;
    971                 if (utf8len > result)
    972                     utf8len = result;
    973 
    974                 if (utf8len > 0)
    975                     memcpy( utf8, rope->data, utf8len );
    976 
    977                 gsm_rope_done( rope );
    978                 return result;
    979             }
    980     }
    981 Fail:
    982     return -1;
    983 }
    984 
    985 static cbytes_t
    986 smspdu_get_user_data_ref( SmsPDU  pdu )
    987 {
    988     cbytes_t  data    = pdu->tpdu;
    989     cbytes_t  end     = pdu->end;
    990     int       mtiByte = sms_get_byte( &data, end );
    991     int       len;
    992 
    993     /* if there is no user-data-header, there is no message reference here */
    994     if ((mtiByte & 0x40) == 0)
    995         goto Fail;
    996 
    997     switch (mtiByte & 3) {
    998         case 0:  /* SMS_PDU_DELIVER */
    999             if ( sms_skip_address( &data, end ) < 0 )
   1000                 goto Fail;
   1001 
   1002             data  += 2;  /* skip protocol identifier + coding scheme */
   1003 
   1004             if ( sms_skip_timestamp( &data, end ) < 0 )
   1005                 goto Fail;
   1006 
   1007             break;
   1008 
   1009         case 1:  /* SMS_PDU_SUBMIT */
   1010             data += 1;  /* skip message reference */
   1011 
   1012             if ( sms_skip_address( &data, end ) < 0 )
   1013                 goto Fail;
   1014 
   1015             data += 2;  /* protocol identifier + oding schene */
   1016             if ( sms_skip_validity_period( &data, end, mtiByte ) < 0 )
   1017                 goto Fail;
   1018 
   1019             break;
   1020 
   1021         default:
   1022             goto Fail;
   1023     }
   1024 
   1025     /* skip user-data length */
   1026     if (data+1 >= end)
   1027         goto Fail;
   1028 
   1029     len   = data[1];
   1030     data += 2;
   1031 
   1032     while (len >= 2 && data + 2 <= end) {
   1033         int  htype = data[0];
   1034         int  hlen = data[1];
   1035 
   1036         if (htype == 00 && hlen == 3 && data + 5 <= end) {
   1037             return data + 2;
   1038         }
   1039 
   1040         data += hlen;
   1041         len  -= hlen - 2;
   1042     }
   1043 Fail:
   1044     return NULL;
   1045 }
   1046 
   1047 int
   1048 smspdu_get_ref( SmsPDU  pdu )
   1049 {
   1050     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1051 
   1052     if (user_ref != NULL)
   1053     {
   1054         return user_ref[0];
   1055     }
   1056     else
   1057     {
   1058         cbytes_t  data    = pdu->tpdu;
   1059         cbytes_t  end     = pdu->end;
   1060         int       mtiByte = sms_get_byte( &data, end );
   1061 
   1062         if ((mtiByte & 3) == 1) {
   1063             /* try to extract directly the reference for a SMS-SUBMIT */
   1064             if (data < end)
   1065                 return data[0];
   1066         }
   1067     }
   1068     return -1;
   1069 }
   1070 
   1071 int
   1072 smspdu_get_max_index( SmsPDU  pdu )
   1073 {
   1074     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1075 
   1076     if (user_ref != NULL) {
   1077         return user_ref[1];
   1078     } else {
   1079         return 1;
   1080     }
   1081 }
   1082 
   1083 int
   1084 smspdu_get_cur_index( SmsPDU  pdu )
   1085 {
   1086     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1087 
   1088     if (user_ref != NULL) {
   1089         return user_ref[2] - 1;
   1090     } else {
   1091         return 0;
   1092     }
   1093 }
   1094 
   1095 
   1096 static void
   1097 gsm_rope_add_sms_user_header( GsmRope  rope,
   1098                               int      ref_number,
   1099                               int      pdu_count,
   1100                               int      pdu_index )
   1101 {
   1102     gsm_rope_add_c( rope, 0x05 );     /* total header length == 5 bytes */
   1103     gsm_rope_add_c( rope, 0x00 );     /* element id: concatenated message reference number */
   1104     gsm_rope_add_c( rope, 0x03 );     /* element len: 3 bytes */
   1105     gsm_rope_add_c( rope, (byte_t)ref_number );  /* reference number */
   1106     gsm_rope_add_c( rope, (byte_t)pdu_count );     /* max pdu index */
   1107     gsm_rope_add_c( rope, (byte_t)pdu_index+1 );   /* current pdu index */
   1108 }
   1109 
   1110 /* write a SMS-DELIVER PDU into a rope */
   1111 static void
   1112 gsm_rope_add_sms_deliver_pdu( GsmRope                 rope,
   1113                               cbytes_t                utf8,
   1114                               int                     utf8len,
   1115                               int                     use_gsm7,
   1116                               const SmsAddressRec*    sender_address,
   1117                               const SmsTimeStampRec*  timestamp,
   1118                               int                     ref_num,
   1119                               int                     pdu_count,
   1120                               int                     pdu_index)
   1121 {
   1122     int  coding;
   1123     int  mtiByte  = 0x20;  /* message type - SMS DELIVER */
   1124 
   1125     if (pdu_count > 1)
   1126         mtiByte |= 0x40;  /* user data header indicator */
   1127 
   1128     gsm_rope_add_c( rope, 0 );        /* no SC Address */
   1129     gsm_rope_add_c( rope, mtiByte );     /* message type - SMS-DELIVER */
   1130     gsm_rope_add_address( rope, sender_address );
   1131     gsm_rope_add_c( rope, 0 );        /* protocol identifier */
   1132 
   1133     /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */
   1134     coding = (use_gsm7 ? 0x00 : 0x09);
   1135 
   1136     gsm_rope_add_c( rope, coding );               /* data coding scheme       */
   1137     gsm_rope_add_timestamp( rope, timestamp );    /* service center timestamp */
   1138 
   1139     if (use_gsm7) {
   1140         bytes_t  dst;
   1141         int    count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
   1142         int    pad   = 0;
   1143 
   1144         assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE );
   1145 
   1146         if (pdu_count > 1)
   1147         {
   1148             int  headerBits    = 6*8;  /* 6 is size of header in bytes */
   1149             int  headerSeptets = headerBits / 7;
   1150             if (headerBits % 7 > 0)
   1151                 headerSeptets += 1;
   1152 
   1153             pad = headerSeptets*7 - headerBits;
   1154 
   1155             gsm_rope_add_c( rope, count + headerSeptets );
   1156             gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index);
   1157         }
   1158         else
   1159             gsm_rope_add_c( rope, count );
   1160 
   1161         count = (count*7+pad+7)/8;  /* convert to byte count */
   1162 
   1163         dst = gsm_rope_reserve( rope, count );
   1164         if (dst != NULL) {
   1165             utf8_to_gsm7( utf8, utf8len, dst, pad );
   1166         }
   1167     } else {
   1168         bytes_t  dst;
   1169         int      count = utf8_to_ucs2( utf8, utf8len, NULL );
   1170 
   1171         assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE );
   1172 
   1173         if (pdu_count > 1)
   1174         {
   1175             gsm_rope_add_c( rope, count*2 + 6 );
   1176             gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index );
   1177         }
   1178         else
   1179             gsm_rope_add_c( rope, count*2 );
   1180 
   1181         gsm_rope_add_c( rope, count*2 );
   1182         dst = gsm_rope_reserve( rope, count*2 );
   1183         if (dst != NULL) {
   1184             utf8_to_ucs2( utf8, utf8len, dst );
   1185         }
   1186     }
   1187 }
   1188 
   1189 
   1190 static SmsPDU
   1191 smspdu_create_deliver( cbytes_t               utf8,
   1192                        int                    utf8len,
   1193                        int                    use_gsm7,
   1194                        const SmsAddressRec*   sender_address,
   1195                        const SmsTimeStampRec* timestamp,
   1196                        int                    ref_num,
   1197                        int                    pdu_count,
   1198                        int                    pdu_index )
   1199 {
   1200     SmsPDU      p;
   1201     GsmRopeRec  rope[1];
   1202     int         size;
   1203 
   1204     p = calloc( sizeof(*p), 1 );
   1205     if (!p) goto Exit;
   1206 
   1207     gsm_rope_init( rope );
   1208     gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
   1209                                  sender_address, timestamp,
   1210                                  ref_num, pdu_count, pdu_index);
   1211     if (rope->error)
   1212         goto Fail;
   1213 
   1214     gsm_rope_init_alloc( rope, rope->pos );
   1215 
   1216     gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
   1217                                  sender_address, timestamp,
   1218                                  ref_num, pdu_count, pdu_index );
   1219 
   1220     p->base = gsm_rope_done_acquire( rope, &size );
   1221     if (p->base == NULL)
   1222         goto Fail;
   1223 
   1224     p->end  = p->base + size;
   1225     p->tpdu = p->base + 1;
   1226 Exit:
   1227     return p;
   1228 
   1229 Fail:
   1230     free(p);
   1231     return NULL;
   1232 }
   1233 
   1234 
   1235 void
   1236 smspdu_free_list( SmsPDU*  pdus )
   1237 {
   1238     if (pdus) {
   1239         int  nn;
   1240         for (nn = 0; pdus[nn] != NULL; nn++)
   1241             smspdu_free( pdus[nn] );
   1242 
   1243         free( pdus );
   1244     }
   1245 }
   1246 
   1247 
   1248 
   1249 SmsPDU*
   1250 smspdu_create_deliver_utf8( const unsigned char*   utf8,
   1251                             int                    utf8len,
   1252                             const SmsAddressRec*   sender_address,
   1253                             const SmsTimeStampRec* timestamp )
   1254 {
   1255     SmsTimeStampRec  ts0;
   1256     int              use_gsm7;
   1257     int              count, block;
   1258     int              num_pdus = 0;
   1259     int              leftover = 0;
   1260     SmsPDU*          list = NULL;
   1261 
   1262     static unsigned char  ref_num = 0;
   1263 
   1264     if (timestamp == NULL) {
   1265         sms_timestamp_now( &ts0 );
   1266         timestamp = &ts0;
   1267     }
   1268 
   1269     /* can we encode the message with the GSM 7-bit alphabet ? */
   1270     use_gsm7 = utf8_check_gsm7( utf8, utf8len );
   1271 
   1272     /* count the number of SMS PDUs we'll need */
   1273     block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE;
   1274 
   1275     if (use_gsm7) {
   1276         count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
   1277     } else {
   1278         count = utf8_to_ucs2( utf8, utf8len, NULL );
   1279         block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE;
   1280     }
   1281 
   1282     num_pdus = count / block;
   1283     leftover = count - num_pdus*block;
   1284     if (leftover > 0)
   1285         num_pdus += 1;
   1286 
   1287     list = calloc( sizeof(SmsPDU*), num_pdus + 1 );
   1288     if (list == NULL)
   1289         return NULL;
   1290 
   1291     /* now create each SMS PDU */
   1292     {
   1293         cbytes_t   src     = utf8;
   1294         cbytes_t   src_end = utf8 + utf8len;
   1295         int        nn;
   1296 
   1297         for (nn = 0; nn < num_pdus; nn++)
   1298         {
   1299             int       skip = block;
   1300             cbytes_t  src_next;
   1301 
   1302             if (leftover > 0 && nn == num_pdus-1)
   1303                 skip = leftover;
   1304 
   1305             src_next = utf8_skip_gsm7( src, src_end, skip );
   1306 
   1307             list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp,
   1308                                               ref_num, num_pdus, nn );
   1309             if (list[nn] == NULL)
   1310                 goto Fail;
   1311 
   1312             src = src_next;
   1313         }
   1314     }
   1315 
   1316     ref_num++;
   1317     return list;
   1318 
   1319 Fail:
   1320     smspdu_free_list(list);
   1321     return NULL;
   1322 }
   1323 
   1324 
   1325 SmsPDU
   1326 smspdu_create_from_hex( const char*  hex, int  hexlen )
   1327 {
   1328     SmsPDU    p;
   1329     cbytes_t  data;
   1330 
   1331     p = calloc( sizeof(*p), 1 );
   1332     if (!p) goto Exit;
   1333 
   1334     p->base = malloc( (hexlen+1)/2 );
   1335     if (p->base == NULL) {
   1336         free(p);
   1337         p = NULL;
   1338         goto Exit;
   1339     }
   1340 
   1341     if ( gsm_hex_to_bytes( (cbytes_t)hex, hexlen, p->base ) < 0 )
   1342         goto Fail;
   1343 
   1344     p->end = p->base + (hexlen+1)/2;
   1345 
   1346     data = p->base;
   1347     if ( sms_skip_sc_address( &data, p->end ) < 0 )
   1348         goto Fail;
   1349 
   1350     p->tpdu = (bytes_t) data;
   1351 
   1352 Exit:
   1353     return p;
   1354 
   1355 Fail:
   1356     free(p->base);
   1357     free(p);
   1358     return NULL;
   1359 }
   1360 
   1361 int
   1362 smspdu_to_hex( SmsPDU  pdu, char*  hex, int  hexlen )
   1363 {
   1364     int  result = (pdu->end - pdu->base)*2;
   1365     int  nn;
   1366 
   1367     if (hexlen > result)
   1368         hexlen = result;
   1369 
   1370     for (nn = 0; nn*2 < hexlen; nn++) {
   1371         gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] );
   1372     }
   1373     return result;
   1374 }
   1375 
   1376 
   1377 /** SMS SUBMIT RECEIVER
   1378  ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver
   1379  **/
   1380 
   1381 typedef struct SmsFragmentRec {
   1382     struct SmsFragmentRec*  next;
   1383     SmsAddressRec           from[1];
   1384     byte_t                  ref;
   1385     byte_t                  max;
   1386     byte_t                  count;
   1387     int                     index;
   1388     SmsPDU*                 pdus;
   1389 
   1390 } SmsFragmentRec, *SmsFragment;
   1391 
   1392 
   1393 typedef struct SmsReceiverRec {
   1394     int           last;
   1395     SmsFragment   fragments;
   1396 
   1397 } SmsReceiverRec;
   1398 
   1399 
   1400 static void
   1401 sms_fragment_free( SmsFragment  frag )
   1402 {
   1403     int  nn;
   1404 
   1405     for (nn = 0; nn < frag->max; nn++) {
   1406         if (frag->pdus[nn] != NULL) {
   1407             smspdu_free( frag->pdus[nn] );
   1408             frag->pdus[nn] = NULL;
   1409         }
   1410     }
   1411     frag->pdus  = NULL;
   1412     frag->count = 0;
   1413     frag->max   = 0;
   1414     frag->index = 0;
   1415     free( frag );
   1416 }
   1417 
   1418 static SmsFragment
   1419 sms_fragment_alloc( SmsReceiver  rec, const SmsAddressRec*  from, int   ref, int  max )
   1420 {
   1421     SmsFragment  frag = calloc(sizeof(*frag) + max*sizeof(SmsPDU), 1 );
   1422 
   1423     if (frag != NULL) {
   1424         frag->from[0] = from[0];
   1425         frag->ref     = ref;
   1426         frag->max     = max;
   1427         frag->pdus    = (SmsPDU*)(frag + 1);
   1428         frag->index   = ++rec->last;
   1429     }
   1430     return  frag;
   1431 }
   1432 
   1433 
   1434 
   1435 SmsReceiver   sms_receiver_create( void )
   1436 {
   1437     SmsReceiver  rec = calloc(sizeof(*rec),1);
   1438     return rec;
   1439 }
   1440 
   1441 void
   1442 sms_receiver_destroy( SmsReceiver  rec )
   1443 {
   1444     while (rec->fragments) {
   1445         SmsFragment  frag = rec->fragments;
   1446         rec->fragments = frag->next;
   1447         sms_fragment_free(frag);
   1448     }
   1449 }
   1450 
   1451 static SmsFragment*
   1452 sms_receiver_find_p( SmsReceiver  rec, const SmsAddressRec*  from, int  ref )
   1453 {
   1454     SmsFragment*  pnode = &rec->fragments;
   1455     SmsFragment   node;
   1456 
   1457     for (;;) {
   1458         node = *pnode;
   1459         if (node == NULL)
   1460             break;
   1461         if (node->ref == ref && sms_address_eq( node->from, from ))
   1462             break;
   1463         pnode = &node->next;
   1464     }
   1465     return  pnode;
   1466 }
   1467 
   1468 static SmsFragment*
   1469 sms_receiver_find_index_p( SmsReceiver  rec, int  index )
   1470 {
   1471     SmsFragment*  pnode = &rec->fragments;
   1472     SmsFragment   node;
   1473 
   1474     for (;;) {
   1475         node = *pnode;
   1476         if (node == NULL)
   1477             break;
   1478         if (node->index == index)
   1479             break;
   1480         pnode = &node->next;
   1481     }
   1482     return  pnode;
   1483 }
   1484 
   1485 int
   1486 sms_receiver_add_submit_pdu( SmsReceiver  rec, SmsPDU       submit_pdu )
   1487 {
   1488     SmsAddressRec  from[1];
   1489     int            ref, max, cur;
   1490     SmsFragment*   pnode;
   1491     SmsFragment    frag;
   1492 
   1493     if ( smspdu_get_receiver_address( submit_pdu, from ) < 0 ) {
   1494         D( "%s: could not extract receiver address\n", __FUNCTION__ );
   1495         return -1;
   1496     }
   1497 
   1498     ref = smspdu_get_ref( submit_pdu );
   1499     if (ref < 0) {
   1500         D( "%s: could not extract message reference from pdu\n", __FUNCTION__ );
   1501         return -1;
   1502     }
   1503     max = smspdu_get_max_index( submit_pdu );
   1504     if (max < 0) {
   1505         D( "%s: invalid max fragment value: %d should be >= 1\n",
   1506            __FUNCTION__, max );
   1507         return -1;
   1508     }
   1509     pnode = sms_receiver_find_p( rec, from, ref );
   1510     frag  = *pnode;
   1511     if (frag == NULL) {
   1512         frag = sms_fragment_alloc( rec, from, ref, max );
   1513         if (frag == NULL) {
   1514             D("%s: not enough memory to allocate new fragment\n", __FUNCTION__ );
   1515             return -1;
   1516         }
   1517         if (D_ACTIVE) {
   1518             char  tmp[32];
   1519             int   len;
   1520 
   1521             len = sms_address_to_str( from, tmp, sizeof(tmp) );
   1522             if (len < 0) {
   1523                 strcpy( tmp, "<unknown>" );
   1524                 len = strlen(tmp);
   1525             }
   1526             D("%s: created SMS index %d, from %.*s, ref %d, max %d\n", __FUNCTION__,
   1527                frag->index, len, tmp, frag->ref, frag->max);
   1528         }
   1529         *pnode = frag;
   1530     }
   1531 
   1532     cur = smspdu_get_cur_index( submit_pdu );
   1533     if (cur < 0) {
   1534         D("%s: SMS fragment index is too small: %d should be >= 1\n", __FUNCTION__, cur+1 );
   1535         return -1;
   1536     }
   1537     if (cur >= max) {
   1538         D("%s: SMS fragment index is too large (%d >= %d)\n", __FUNCTION__, cur, max);
   1539         return -1;
   1540     }
   1541     if ( frag->pdus[cur] != NULL ) {
   1542         D("%s: receiving duplicate SMS fragment for %d/%d, ref=%d, discarding old one\n",
   1543           __FUNCTION__, cur+1, max, ref);
   1544         smspdu_free( frag->pdus[cur] );
   1545         frag->count -= 1;
   1546     }
   1547     frag->pdus[cur] = submit_pdu;
   1548     frag->count    += 1;
   1549 
   1550     if (frag->count >= frag->max) {
   1551         /* yes, we received all fragments for this SMS */
   1552         D( "%s: SMS index %d, received all %d fragments\n", __FUNCTION__, frag->index, frag->count );
   1553         return frag->index;
   1554     }
   1555     else {
   1556         /* still waiting for more */
   1557         D( "%s: SMS index %d, received %d/%d, waiting for %d more\n", __FUNCTION__,
   1558             frag->index, cur+1, max, frag->max - frag->count );
   1559         return 0;
   1560     }
   1561 }
   1562 
   1563 
   1564 int
   1565 sms_receiver_get_text_message( SmsReceiver  rec, int  index, bytes_t  utf8, int  utf8len )
   1566 {
   1567     SmsFragment*  pnode = sms_receiver_find_index_p( rec, index );
   1568     SmsFragment   frag  = *pnode;
   1569     int           nn, total;
   1570 
   1571     if (frag == NULL) {
   1572         D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
   1573         return -1;
   1574     }
   1575     if (frag->count != frag->max) {
   1576         D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
   1577            frag->index, frag->max - frag->count );
   1578         return -1;
   1579     }
   1580     /* get the size of all combined text */
   1581     total = 0;
   1582     for ( nn = 0; nn < frag->count; nn++ ) {
   1583         int  partial;
   1584         if (utf8 && utf8len > 0) {
   1585             partial  = smspdu_get_text_message( frag->pdus[nn], utf8, utf8len );
   1586             utf8    += partial;
   1587             utf8len -= partial;
   1588         } else {
   1589             partial  = smspdu_get_text_message( frag->pdus[nn], NULL, 0 );
   1590         }
   1591         total += partial;
   1592     }
   1593     return total;
   1594 }
   1595 
   1596 
   1597 static void
   1598 sms_receiver_remove( SmsReceiver  rec, int  index )
   1599 {
   1600     SmsFragment*  pnode = sms_receiver_find_index_p( rec, index );
   1601     SmsFragment   frag  = *pnode;
   1602     if (frag != NULL) {
   1603         *pnode = frag->next;
   1604         sms_fragment_free(frag);
   1605     }
   1606 }
   1607 
   1608 
   1609 SmsPDU*
   1610 sms_receiver_create_deliver( SmsReceiver  rec, int  index, const SmsAddressRec*  from )
   1611 {
   1612     SmsPDU*          result = NULL;
   1613     SmsFragment*     pnode = sms_receiver_find_index_p( rec, index );
   1614     SmsFragment      frag  = *pnode;
   1615     SmsTimeStampRec  now[1];
   1616     int              nn, total;
   1617     bytes_t          utf8;
   1618     int              utf8len;
   1619 
   1620     if (frag == NULL) {
   1621         D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
   1622         return NULL;
   1623     }
   1624     if (frag->count != frag->max) {
   1625         D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
   1626            frag->index, frag->max - frag->count );
   1627         return NULL;
   1628     }
   1629 
   1630     /* get the combined text message */
   1631     utf8len = sms_receiver_get_text_message( rec, index, NULL, 0 );
   1632     if (utf8len < 0)
   1633         goto Exit;
   1634 
   1635     utf8 = malloc( utf8len + 1 );
   1636     if (utf8 == NULL) {
   1637         D( "%s: not enough memory to allocate %d bytes\n",
   1638            __FUNCTION__, utf8len+1 );
   1639         goto Exit;
   1640     }
   1641 
   1642     total = 0;
   1643     for ( nn = 0; nn < frag->count; nn++ ) {
   1644         total += smspdu_get_text_message( frag->pdus[nn], utf8 + total, utf8len - total );
   1645     }
   1646 
   1647     sms_timestamp_now( now );
   1648 
   1649     result = smspdu_create_deliver_utf8( utf8, utf8len, from, now );
   1650 
   1651     free(utf8);
   1652 
   1653 Exit:
   1654     sms_receiver_remove( rec, index );
   1655     return result;
   1656 }
   1657 
   1658