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