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         if (str[count])
    357             count += 1;
    358     }
    359     return count;
    360 }
    361 
    362 int
    363 sms_address_from_bytes( SmsAddress  address, const unsigned char*  buf, int  buflen )
    364 {
    365     int   len = sizeof(address->data), num_digits;
    366 
    367     if (buflen < 2)
    368         return -1;
    369 
    370     address->len = num_digits = buf[0];
    371     address->toa = buf[1];
    372 
    373     len = (num_digits+1)/2;
    374     if ( len > sizeof(address->data) )
    375         return -1;
    376 
    377     memcpy( address->data, buf+2, len );
    378     return 0;
    379 }
    380 
    381 int
    382 sms_address_to_bytes( SmsAddress  address, unsigned char*  buf, int  bufsize )
    383 {
    384     int  len = (address->len + 1)/2 + 2;
    385 
    386     if (buf == NULL)
    387         bufsize = 0;
    388 
    389     if (bufsize < 1) goto Exit;
    390     buf[0] = address->len;
    391 
    392     if (bufsize < 2) goto Exit;
    393     buf[1] = address->toa;
    394 
    395     buf     += 2;
    396     bufsize -= 2;
    397     if (bufsize > len-2)
    398         bufsize = len - 2;
    399 
    400     memcpy( buf, address->data, bufsize );
    401 Exit:
    402     return len;
    403 }
    404 
    405 int
    406 sms_address_from_hex  ( SmsAddress  address, const char*  hex, int  hexlen )
    407 {
    408     const char*  hexend = hex + hexlen;
    409     int          nn, len, num_digits;
    410 
    411     if (hexlen < 4)
    412         return -1;
    413 
    414     address->len = num_digits = gsm_hex2_to_byte( hex );
    415     address->toa = gsm_hex2_to_byte( hex+2 );
    416     hex += 4;
    417 
    418     len = (num_digits + 1)/2;
    419     if (hex + len*2 > hexend)
    420         return -1;
    421 
    422     for ( nn = 0; nn < len; nn++ )
    423         address->data[nn] = gsm_hex2_to_byte( hex + nn*2 );
    424 
    425     return 0;
    426 }
    427 
    428 int
    429 sms_address_to_hex    ( SmsAddress  address, char*   hex, int  hexlen )
    430 {
    431     int  len = (address->len + 1)/2 + 2;
    432     int  nn;
    433 
    434     if (hex == NULL)
    435         hexlen = 0;
    436 
    437     if (hexlen < 2) goto Exit;
    438     gsm_hex_from_byte( hex, address->len );
    439     if (hexlen < 4) goto Exit;
    440     gsm_hex_from_byte( hex+2, address->toa );
    441     hex    += 4;
    442     hexlen -= 4;
    443     if ( hexlen > 2*(len - 2) )
    444         hexlen = (len - 2)/2;
    445 
    446     for ( nn = 0; nn < hexlen; nn += 2 )
    447         gsm_hex_from_byte( hex+nn, address->data[nn/2] );
    448 
    449 Exit:
    450     return len*2;
    451 }
    452 
    453 static void
    454 gsm_rope_add_address( GsmRope  rope, const SmsAddressRec*  addr )
    455 {
    456     gsm_rope_add_c( rope, addr->len );
    457     gsm_rope_add_c( rope, addr->toa );
    458     gsm_rope_add( rope, addr->data, (addr->len+1)/2 );
    459     if (addr->len & 1) {
    460         if (!rope->error && rope->data != NULL)
    461             rope->data[ rope->pos-1 ] |= 0xf0;
    462     }
    463 }
    464 
    465 static int
    466 sms_address_eq( const SmsAddressRec*  addr1, const SmsAddressRec*  addr2 )
    467 {
    468     if ( addr1->toa != addr2->toa ||
    469          addr1->len != addr2->len )
    470         return 0;
    471 
    472     return ( !memcmp( addr1->data, addr2->data, addr1->len ) );
    473 }
    474 
    475 /** SMS PARSER
    476  **/
    477 static int
    478 sms_get_byte( cbytes_t  *pcur, cbytes_t  end )
    479 {
    480     cbytes_t  cur    = *pcur;
    481     int       result = -1;
    482 
    483     if (cur < end) {
    484         result = cur[0];
    485         *pcur  = cur + 1;
    486     }
    487     return result;
    488 }
    489 
    490 /* parse a service center address, returns -1 in case of error */
    491 static int
    492 sms_get_sc_address( cbytes_t   *pcur,
    493                     cbytes_t    end,
    494                     SmsAddress  address )
    495 {
    496     cbytes_t  cur    = *pcur;
    497     int       result = -1;
    498 
    499     if (cur < end) {
    500         int  len = cur[0];
    501         int  dlen, adjust = 0;
    502 
    503         cur += 1;
    504 
    505         if (len == 0) {   /* empty address */
    506             address->len = 0;
    507             address->toa = 0x00;
    508             result       = 0;
    509             goto Exit;
    510         }
    511 
    512         if (cur + len > end) {
    513             goto Exit;
    514         }
    515 
    516         address->toa = *cur++;
    517         len         -= 1;
    518         result       = 0;
    519 
    520         for (dlen = 0; dlen < len; dlen+=1)
    521         {
    522             int  c = cur[dlen];
    523             int  v;
    524 
    525             adjust = 0;
    526             if (dlen >= sizeof(address->data)) {
    527                 result = -1;
    528                 break;
    529             }
    530 
    531             v = (c & 0xf);
    532             if (v >= 0xe)
    533                 break;
    534 
    535             adjust              = 1;
    536             address->data[dlen] = (byte_t) c;
    537 
    538             v = (c >> 4) & 0xf;
    539             if (v >= 0xe) {
    540                 break;
    541             }
    542         }
    543         address->len = 2*dlen + adjust;
    544     }
    545 Exit:
    546     if (!result)
    547         *pcur = cur;
    548 
    549     return result;
    550 }
    551 
    552 static int
    553 sms_skip_sc_address( cbytes_t   *pcur,
    554                      cbytes_t    end )
    555 {
    556     cbytes_t  cur    = *pcur;
    557     int       result = -1;
    558     int       len;
    559 
    560     if (cur >= end)
    561         goto Exit;
    562 
    563     len  = cur[0];
    564     cur += 1 + len;
    565     if (cur > end)
    566         goto Exit;
    567 
    568     *pcur  = cur;
    569     result = 0;
    570 Exit:
    571     return result;
    572 }
    573 
    574 /* parse a sender/receiver address, returns -1 in case of error */
    575 static int
    576 sms_get_address( cbytes_t   *pcur,
    577                  cbytes_t    end,
    578                  SmsAddress  address )
    579 {
    580     cbytes_t  cur    = *pcur;
    581     int       result = -1;
    582     int       len, dlen;
    583 
    584     if (cur >= end)
    585         goto Exit;
    586 
    587     dlen = *cur++;
    588 
    589     if (dlen == 0) {
    590         address->len = 0;
    591         address->toa = 0;
    592         result       = 0;
    593         goto Exit;
    594     }
    595 
    596     if (cur + 1 + (dlen+1)/2 > end)
    597         goto Exit;
    598 
    599     address->len = dlen;
    600     address->toa = *cur++;
    601 
    602     len = (dlen + 1)/2;
    603     if (len > sizeof(address->data))
    604         goto Exit;
    605 
    606     memcpy( address->data, cur, len );
    607     cur   += len;
    608     result = 0;
    609 
    610 Exit:
    611     if (!result)
    612         *pcur = cur;
    613 
    614     return result;
    615 }
    616 
    617 static int
    618 sms_skip_address( cbytes_t   *pcur,
    619                   cbytes_t    end  )
    620 {
    621     cbytes_t  cur    = *pcur;
    622     int       result = -1;
    623     int       dlen;
    624 
    625     if (cur + 2 > end)
    626         goto Exit;
    627 
    628     dlen = cur[0];
    629     cur += 2 + (dlen + 1)/2;
    630     if (cur > end)
    631         goto Exit;
    632 
    633     result = 0;
    634 Exit:
    635     return result;
    636 }
    637 
    638 /* parse a service center timestamp */
    639 static int
    640 sms_get_timestamp( cbytes_t     *pcur,
    641                    cbytes_t      end,
    642                    SmsTimeStamp  ts )
    643 {
    644     cbytes_t  cur = *pcur;
    645 
    646     if (cur + 7 > end)
    647         return -1;
    648 
    649     memcpy( ts->data, cur, 7 );
    650     *pcur = cur + 7;
    651     return 0;
    652 }
    653 
    654 static int
    655 sms_skip_timestamp( cbytes_t  *pcur,
    656                     cbytes_t   end )
    657 {
    658     cbytes_t  cur = *pcur;
    659 
    660     if (cur + 7 > end)
    661         return -1;
    662 
    663     *pcur = cur + 7;
    664     return 0;
    665 }
    666 
    667 
    668 static int
    669 sms_skip_validity_period( cbytes_t  *pcur,
    670                           cbytes_t   end,
    671                           int        mtiByte )
    672 {
    673     cbytes_t  cur = *pcur;
    674 
    675     switch ((mtiByte >> 3) & 3) {
    676         case 1:  /* relative format */
    677             cur += 1;
    678             break;
    679 
    680         case 2:  /* enhanced format */
    681         case 3:  /* absolute format */
    682             cur += 7;
    683     }
    684     if (cur > end)
    685         return -1;
    686 
    687     *pcur = cur;
    688     return 0;
    689 }
    690 
    691 /** SMS PDU
    692  **/
    693 
    694 typedef struct SmsPDURec {
    695     bytes_t  base;
    696     bytes_t  end;
    697     bytes_t  tpdu;
    698 } SmsPDURec;
    699 
    700 void
    701 smspdu_free( SmsPDU  pdu )
    702 {
    703     if (pdu) {
    704         free( pdu->base );
    705         pdu->base = NULL;
    706         pdu->end  = NULL;
    707         pdu->tpdu = NULL;
    708     }
    709 }
    710 
    711 SmsPduType
    712 smspdu_get_type( SmsPDU  pdu )
    713 {
    714     cbytes_t  data    = pdu->tpdu;
    715     cbytes_t  end     = pdu->end;
    716     int       mtiByte = sms_get_byte(&data, end);
    717 
    718     switch (mtiByte & 3) {
    719         case 0:  return SMS_PDU_DELIVER;
    720         case 1:  return SMS_PDU_SUBMIT;
    721         case 2:  return SMS_PDU_STATUS_REPORT;
    722         default: return SMS_PDU_INVALID;
    723     }
    724 }
    725 
    726 int
    727 smspdu_get_sender_address( SmsPDU  pdu, SmsAddress  address )
    728 {
    729     cbytes_t  data    = pdu->tpdu;
    730     cbytes_t  end     = pdu->end;
    731     int       mtiByte = sms_get_byte(&data, end);
    732 
    733     switch (mtiByte & 3) {
    734         case 0: /* SMS_PDU_DELIVER; */
    735             return sms_get_sc_address( &data, end, address );
    736 
    737         default: return -1;
    738     }
    739 }
    740 
    741 int
    742 smspdu_get_sc_timestamp( SmsPDU  pdu, SmsTimeStamp  ts )
    743 {
    744     cbytes_t  data    = pdu->tpdu;
    745     cbytes_t  end     = pdu->end;
    746     int       mtiByte = sms_get_byte( &data, end );
    747 
    748     switch (mtiByte & 3) {
    749         case 0:  /* SMS_PDU_DELIVER */
    750             {
    751                 SmsAddressRec  address;
    752 
    753                 if ( sms_get_sc_address( &data, end, &address ) < 0 )
    754                     return -1;
    755 
    756                 data += 2;  /* skip protocol identifer + coding scheme */
    757 
    758                 return sms_get_timestamp( &data, end, ts );
    759             }
    760 
    761         default: return -1;
    762     }
    763 }
    764 
    765 int
    766 smspdu_get_receiver_address( SmsPDU  pdu, SmsAddress  address )
    767 {
    768     cbytes_t  data    = pdu->tpdu;
    769     cbytes_t  end     = pdu->end;
    770     int       mtiByte = sms_get_byte( &data, end );
    771 
    772     switch (mtiByte & 3) {
    773         case 1:  /* SMS_PDU_SUBMIT */
    774             {
    775                 data += 1;  /* skip message reference */
    776                 return sms_get_address( &data, end, address );
    777             }
    778 
    779         default: return -1;
    780     }
    781 }
    782 
    783 typedef enum {
    784     SMS_CODING_SCHEME_UNKNOWN = 0,
    785     SMS_CODING_SCHEME_GSM7,
    786     SMS_CODING_SCHEME_UCS2
    787 
    788 } SmsCodingScheme;
    789 
    790 /* see TS 23.038 Section 5 for details */
    791 static SmsCodingScheme
    792 sms_get_coding_scheme( cbytes_t  *pcur,
    793                        cbytes_t   end )
    794 {
    795     cbytes_t  cur = *pcur;
    796     int       dataCoding;
    797 
    798     if (cur >= end)
    799         return SMS_CODING_SCHEME_UNKNOWN;
    800 
    801     dataCoding = *cur++;
    802     *pcur      = cur;
    803 
    804     switch (dataCoding >> 4) {
    805         case 0x00:
    806         case 0x02:
    807         case 0x03:
    808             return SMS_CODING_SCHEME_GSM7;
    809 
    810         case 0x01:
    811             if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7;
    812             if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2;
    813             break;
    814 
    815         case 0x04: case 0x05: case 0x06: case 0x07:
    816             if (dataCoding & 0x20)           return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */
    817             if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7;
    818             if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2;
    819             break;
    820 
    821         case 0xF:
    822             if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7;
    823             break;
    824     }
    825     return SMS_CODING_SCHEME_UNKNOWN;
    826 }
    827 
    828 
    829 /* see TS 23.040 section 9.2.3.24 for details */
    830 static int
    831 sms_get_text_utf8( cbytes_t        *pcur,
    832                    cbytes_t         end,
    833                    int              hasUDH,
    834                    SmsCodingScheme  coding,
    835                    GsmRope          rope )
    836 {
    837     cbytes_t  cur    = *pcur;
    838     int       result = -1;
    839     int       len;
    840 
    841     if (cur >= end)
    842         goto Exit;
    843 
    844     len = *cur++;
    845 
    846     /* skip user data header if any */
    847     if ( hasUDH )
    848     {
    849         int  hlen;
    850 
    851         if (cur >= end)
    852             goto Exit;
    853 
    854         hlen = *cur++;
    855         if (cur + hlen > end)
    856             goto Exit;
    857 
    858         cur += hlen;
    859 
    860         if (coding == SMS_CODING_SCHEME_GSM7)
    861             len -= 2*(hlen+1);
    862         else
    863             len -= hlen+1;
    864 
    865         if (len < 0)
    866             goto Exit;
    867     }
    868 
    869     /* switch the user data header if any */
    870     if (coding == SMS_CODING_SCHEME_GSM7)
    871     {
    872         int  count = utf8_from_gsm7( cur, 0, len, NULL );
    873 
    874         if (rope != NULL)
    875         {
    876             bytes_t  dst = gsm_rope_reserve( rope, count );
    877             if (dst != NULL)
    878                 utf8_from_gsm7( cur, 0, len, dst );
    879         }
    880         cur += (len+1)/2;
    881     }
    882     else if (coding == SMS_CODING_SCHEME_UCS2)
    883     {
    884         int  count = ucs2_to_utf8( cur, len/2, NULL );
    885 
    886         if (rope != NULL)
    887         {
    888             bytes_t  dst = gsm_rope_reserve( rope, count );
    889             if (dst != NULL)
    890                 ucs2_to_utf8( cur, len/2, dst );
    891         }
    892         cur += len;
    893     }
    894     result = 0;
    895 
    896 Exit:
    897     if (!result)
    898         *pcur = cur;
    899 
    900     return result;
    901 }
    902 
    903 /* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
    904 /* or -1 in case of error */
    905 int
    906 smspdu_get_text_message( SmsPDU  pdu, unsigned char*  utf8, int  utf8len )
    907 {
    908     cbytes_t  data    = pdu->tpdu;
    909     cbytes_t  end     = pdu->end;
    910     int       mtiByte = sms_get_byte( &data, end );
    911 
    912     switch (mtiByte & 3) {
    913         case 0:  /* SMS_PDU_DELIVER */
    914             {
    915                 SmsAddressRec    address;
    916                 SmsTimeStampRec  timestamp;
    917                 SmsCodingScheme  coding;
    918                 GsmRopeRec       rope[1];
    919                 int              result;
    920 
    921                 if ( sms_get_sc_address( &data, end, &address ) < 0 )
    922                     goto Fail;
    923 
    924                 data  += 1;  /* skip protocol identifier */
    925                 coding = sms_get_coding_scheme( &data, end );
    926                 if (coding == SMS_CODING_SCHEME_UNKNOWN)
    927                     goto Fail;
    928 
    929                 if ( sms_get_timestamp( &data, end, &timestamp ) < 0 )
    930                     goto Fail;
    931 
    932                 if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 )
    933                     goto Fail;
    934 
    935                 result = rope->pos;
    936                 if (utf8len > result)
    937                     utf8len = result;
    938 
    939                 if (utf8len > 0)
    940                     memcpy( utf8, rope->data, utf8len );
    941 
    942                 gsm_rope_done( rope );
    943                 return result;
    944             }
    945 
    946         case 1:  /* SMS_PDU_SUBMIT */
    947             {
    948                 SmsAddressRec    address;
    949                 SmsCodingScheme  coding;
    950                 GsmRopeRec       rope[1];
    951                 int              result;
    952 
    953                 data += 1;  /* message reference */
    954 
    955                 if ( sms_get_address( &data, end, &address ) < 0 )
    956                     goto Fail;
    957 
    958                 data  += 1;  /* skip protocol identifier */
    959                 coding = sms_get_coding_scheme( &data, end );
    960                 if (coding == SMS_CODING_SCHEME_UNKNOWN)
    961                     goto Fail;
    962 
    963                 gsm_rope_init_alloc( rope, 0 );
    964                 if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) {
    965                     gsm_rope_done( rope );
    966                     goto Fail;
    967                 }
    968 
    969                 result = rope->pos;
    970                 if (utf8len > result)
    971                     utf8len = result;
    972 
    973                 if (utf8len > 0)
    974                     memcpy( utf8, rope->data, utf8len );
    975 
    976                 gsm_rope_done( rope );
    977                 return result;
    978             }
    979     }
    980 Fail:
    981     return -1;
    982 }
    983 
    984 static cbytes_t
    985 smspdu_get_user_data_ref( SmsPDU  pdu )
    986 {
    987     cbytes_t  data    = pdu->tpdu;
    988     cbytes_t  end     = pdu->end;
    989     int       mtiByte = sms_get_byte( &data, end );
    990     int       len;
    991 
    992     /* if there is no user-data-header, there is no message reference here */
    993     if ((mtiByte & 0x40) == 0)
    994         goto Fail;
    995 
    996     switch (mtiByte & 3) {
    997         case 0:  /* SMS_PDU_DELIVER */
    998             if ( sms_skip_address( &data, end ) < 0 )
    999                 goto Fail;
   1000 
   1001             data  += 2;  /* skip protocol identifier + coding scheme */
   1002 
   1003             if ( sms_skip_timestamp( &data, end ) < 0 )
   1004                 goto Fail;
   1005 
   1006             break;
   1007 
   1008         case 1:  /* SMS_PDU_SUBMIT */
   1009             data += 1;  /* skip message reference */
   1010 
   1011             if ( sms_skip_address( &data, end ) < 0 )
   1012                 goto Fail;
   1013 
   1014             data += 2;  /* protocol identifier + oding schene */
   1015             if ( sms_skip_validity_period( &data, end, mtiByte ) < 0 )
   1016                 goto Fail;
   1017 
   1018             break;
   1019 
   1020         default:
   1021             goto Fail;
   1022     }
   1023 
   1024     /* skip user-data length */
   1025     if (data+1 >= end)
   1026         goto Fail;
   1027 
   1028     len   = data[1];
   1029     data += 2;
   1030 
   1031     while (len >= 2 && data + 2 <= end) {
   1032         int  htype = data[0];
   1033         int  hlen = data[1];
   1034 
   1035         if (htype == 00 && hlen == 3 && data + 5 <= end) {
   1036             return data + 2;
   1037         }
   1038 
   1039         data += hlen;
   1040         len  -= hlen - 2;
   1041     }
   1042 Fail:
   1043     return NULL;
   1044 }
   1045 
   1046 int
   1047 smspdu_get_ref( SmsPDU  pdu )
   1048 {
   1049     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1050 
   1051     if (user_ref != NULL)
   1052     {
   1053         return user_ref[0];
   1054     }
   1055     else
   1056     {
   1057         cbytes_t  data    = pdu->tpdu;
   1058         cbytes_t  end     = pdu->end;
   1059         int       mtiByte = sms_get_byte( &data, end );
   1060 
   1061         if ((mtiByte & 3) == 1) {
   1062             /* try to extract directly the reference for a SMS-SUBMIT */
   1063             if (data < end)
   1064                 return data[0];
   1065         }
   1066     }
   1067     return -1;
   1068 }
   1069 
   1070 int
   1071 smspdu_get_max_index( SmsPDU  pdu )
   1072 {
   1073     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1074 
   1075     if (user_ref != NULL) {
   1076         return user_ref[1];
   1077     } else {
   1078         return 1;
   1079     }
   1080 }
   1081 
   1082 int
   1083 smspdu_get_cur_index( SmsPDU  pdu )
   1084 {
   1085     cbytes_t  user_ref = smspdu_get_user_data_ref( pdu );
   1086 
   1087     if (user_ref != NULL) {
   1088         return user_ref[2] - 1;
   1089     } else {
   1090         return 0;
   1091     }
   1092 }
   1093 
   1094 
   1095 static void
   1096 gsm_rope_add_sms_user_header( GsmRope  rope,
   1097                               int      ref_number,
   1098                               int      pdu_count,
   1099                               int      pdu_index )
   1100 {
   1101     gsm_rope_add_c( rope, 0x05 );     /* total header length == 5 bytes */
   1102     gsm_rope_add_c( rope, 0x00 );     /* element id: concatenated message reference number */
   1103     gsm_rope_add_c( rope, 0x03 );     /* element len: 3 bytes */
   1104     gsm_rope_add_c( rope, (byte_t)ref_number );  /* reference number */
   1105     gsm_rope_add_c( rope, (byte_t)pdu_count );     /* max pdu index */
   1106     gsm_rope_add_c( rope, (byte_t)pdu_index+1 );   /* current pdu index */
   1107 }
   1108 
   1109 /* write a SMS-DELIVER PDU into a rope */
   1110 static void
   1111 gsm_rope_add_sms_deliver_pdu( GsmRope                 rope,
   1112                               cbytes_t                utf8,
   1113                               int                     utf8len,
   1114                               int                     use_gsm7,
   1115                               const SmsAddressRec*    sender_address,
   1116                               const SmsTimeStampRec*  timestamp,
   1117                               int                     ref_num,
   1118                               int                     pdu_count,
   1119                               int                     pdu_index)
   1120 {
   1121     int  coding;
   1122     int  mtiByte  = 0x20;  /* message type - SMS DELIVER */
   1123 
   1124     if (pdu_count > 1)
   1125         mtiByte |= 0x40;  /* user data header indicator */
   1126 
   1127     gsm_rope_add_c( rope, 0 );        /* no SC Address */
   1128     gsm_rope_add_c( rope, mtiByte );     /* message type - SMS-DELIVER */
   1129     gsm_rope_add_address( rope, sender_address );
   1130     gsm_rope_add_c( rope, 0 );        /* protocol identifier */
   1131 
   1132     /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */
   1133     coding = (use_gsm7 ? 0x00 : 0x09);
   1134 
   1135     gsm_rope_add_c( rope, coding );               /* data coding scheme       */
   1136     gsm_rope_add_timestamp( rope, timestamp );    /* service center timestamp */
   1137 
   1138     if (use_gsm7) {
   1139         bytes_t  dst;
   1140         int    count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
   1141         int    pad   = 0;
   1142 
   1143         assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE );
   1144 
   1145         if (pdu_count > 1)
   1146         {
   1147             int  headerBits    = 6*8;  /* 6 is size of header in bytes */
   1148             int  headerSeptets = headerBits / 7;
   1149             if (headerBits % 7 > 0)
   1150                 headerSeptets += 1;
   1151 
   1152             pad = headerSeptets*7 - headerBits;
   1153 
   1154             gsm_rope_add_c( rope, count + headerSeptets );
   1155             gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index);
   1156         }
   1157         else
   1158             gsm_rope_add_c( rope, count );
   1159 
   1160         count = (count*7+pad+7)/8;  /* convert to byte count */
   1161 
   1162         dst = gsm_rope_reserve( rope, count );
   1163         if (dst != NULL) {
   1164             utf8_to_gsm7( utf8, utf8len, dst, pad );
   1165         }
   1166     } else {
   1167         bytes_t  dst;
   1168         int      count = utf8_to_ucs2( utf8, utf8len, NULL );
   1169 
   1170         assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE );
   1171 
   1172         if (pdu_count > 1)
   1173         {
   1174             gsm_rope_add_c( rope, count*2 + 6 );
   1175             gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index );
   1176         }
   1177         else
   1178             gsm_rope_add_c( rope, count*2 );
   1179 
   1180         gsm_rope_add_c( rope, count*2 );
   1181         dst = gsm_rope_reserve( rope, count*2 );
   1182         if (dst != NULL) {
   1183             utf8_to_ucs2( utf8, utf8len, dst );
   1184         }
   1185     }
   1186 }
   1187 
   1188 
   1189 static SmsPDU
   1190 smspdu_create_deliver( cbytes_t               utf8,
   1191                        int                    utf8len,
   1192                        int                    use_gsm7,
   1193                        const SmsAddressRec*   sender_address,
   1194                        const SmsTimeStampRec* timestamp,
   1195                        int                    ref_num,
   1196                        int                    pdu_count,
   1197                        int                    pdu_index )
   1198 {
   1199     SmsPDU      p;
   1200     GsmRopeRec  rope[1];
   1201     int         size;
   1202 
   1203     p = calloc( sizeof(*p), 1 );
   1204     if (!p) goto Exit;
   1205 
   1206     gsm_rope_init( rope );
   1207     gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
   1208                                  sender_address, timestamp,
   1209                                  ref_num, pdu_count, pdu_index);
   1210     if (rope->error)
   1211         goto Fail;
   1212 
   1213     gsm_rope_init_alloc( rope, rope->pos );
   1214 
   1215     gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
   1216                                  sender_address, timestamp,
   1217                                  ref_num, pdu_count, pdu_index );
   1218 
   1219     p->base = gsm_rope_done_acquire( rope, &size );
   1220     if (p->base == NULL)
   1221         goto Fail;
   1222 
   1223     p->end  = p->base + size;
   1224     p->tpdu = p->base + 1;
   1225 Exit:
   1226     return p;
   1227 
   1228 Fail:
   1229     free(p);
   1230     return NULL;
   1231 }
   1232 
   1233 
   1234 void
   1235 smspdu_free_list( SmsPDU*  pdus )
   1236 {
   1237     if (pdus) {
   1238         int  nn;
   1239         for (nn = 0; pdus[nn] != NULL; nn++)
   1240             smspdu_free( pdus[nn] );
   1241 
   1242         free( pdus );
   1243     }
   1244 }
   1245 
   1246 
   1247 
   1248 SmsPDU*
   1249 smspdu_create_deliver_utf8( const unsigned char*   utf8,
   1250                             int                    utf8len,
   1251                             const SmsAddressRec*   sender_address,
   1252                             const SmsTimeStampRec* timestamp )
   1253 {
   1254     SmsTimeStampRec  ts0;
   1255     int              use_gsm7;
   1256     int              count, block;
   1257     int              num_pdus = 0;
   1258     int              leftover = 0;
   1259     SmsPDU*          list = NULL;
   1260 
   1261     static unsigned char  ref_num = 0;
   1262 
   1263     if (timestamp == NULL) {
   1264         sms_timestamp_now( &ts0 );
   1265         timestamp = &ts0;
   1266     }
   1267 
   1268     /* can we encode the message with the GSM 7-bit alphabet ? */
   1269     use_gsm7 = utf8_check_gsm7( utf8, utf8len );
   1270 
   1271     /* count the number of SMS PDUs we'll need */
   1272     block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE;
   1273 
   1274     if (use_gsm7) {
   1275         count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
   1276     } else {
   1277         count = utf8_to_ucs2( utf8, utf8len, NULL );
   1278         block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE;
   1279     }
   1280 
   1281     num_pdus = count / block;
   1282     leftover = count - num_pdus*block;
   1283     if (leftover > 0)
   1284         num_pdus += 1;
   1285 
   1286     list = calloc( sizeof(SmsPDU*), num_pdus + 1 );
   1287     if (list == NULL)
   1288         return NULL;
   1289 
   1290     /* now create each SMS PDU */
   1291     {
   1292         cbytes_t   src     = utf8;
   1293         cbytes_t   src_end = utf8 + utf8len;
   1294         int        nn;
   1295 
   1296         for (nn = 0; nn < num_pdus; nn++)
   1297         {
   1298             int       skip = block;
   1299             cbytes_t  src_next;
   1300 
   1301             if (leftover > 0 && nn == num_pdus-1)
   1302                 skip = leftover;
   1303 
   1304             src_next = utf8_skip_gsm7( src, src_end, skip );
   1305 
   1306             list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp,
   1307                                               ref_num, num_pdus, nn );
   1308             if (list[nn] == NULL)
   1309                 goto Fail;
   1310 
   1311             src = src_next;
   1312         }
   1313     }
   1314 
   1315     ref_num++;
   1316     return list;
   1317 
   1318 Fail:
   1319     smspdu_free_list(list);
   1320     return NULL;
   1321 }
   1322 
   1323 
   1324 SmsPDU
   1325 smspdu_create_from_hex( const char*  hex, int  hexlen )
   1326 {
   1327     SmsPDU    p;
   1328     cbytes_t  data;
   1329 
   1330     p = calloc( sizeof(*p), 1 );
   1331     if (!p) goto Exit;
   1332 
   1333     p->base = malloc( (hexlen+1)/2 );
   1334     if (p->base == NULL) {
   1335         free(p);
   1336         p = NULL;
   1337         goto Exit;
   1338     }
   1339 
   1340     if ( gsm_hex_to_bytes( (cbytes_t)hex, hexlen, p->base ) < 0 )
   1341         goto Fail;
   1342 
   1343     p->end = p->base + (hexlen+1)/2;
   1344 
   1345     data = p->base;
   1346     if ( sms_skip_sc_address( &data, p->end ) < 0 )
   1347         goto Fail;
   1348 
   1349     p->tpdu = (bytes_t) data;
   1350 
   1351 Exit:
   1352     return p;
   1353 
   1354 Fail:
   1355     free(p->base);
   1356     free(p);
   1357     return NULL;
   1358 }
   1359 
   1360 int
   1361 smspdu_to_hex( SmsPDU  pdu, char*  hex, int  hexlen )
   1362 {
   1363     int  result = (pdu->end - pdu->base)*2;
   1364     int  nn;
   1365 
   1366     if (hexlen > result)
   1367         hexlen = result;
   1368 
   1369     for (nn = 0; nn*2 < hexlen; nn++) {
   1370         gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] );
   1371     }
   1372     return result;
   1373 }
   1374 
   1375 
   1376 /** SMS SUBMIT RECEIVER
   1377  ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver
   1378  **/
   1379 
   1380 typedef struct SmsFragmentRec {
   1381     struct SmsFragmentRec*  next;
   1382     SmsAddressRec           from[1];
   1383     byte_t                  ref;
   1384     byte_t                  max;
   1385     byte_t                  count;
   1386     int                     index;
   1387     SmsPDU*                 pdus;
   1388 
   1389 } SmsFragmentRec, *SmsFragment;
   1390 
   1391 
   1392 typedef struct SmsReceiverRec {
   1393     int           last;
   1394     SmsFragment   fragments;
   1395 
   1396 } SmsReceiverRec;
   1397 
   1398 
   1399 static void
   1400 sms_fragment_free( SmsFragment  frag )
   1401 {
   1402     int  nn;
   1403 
   1404     for (nn = 0; nn < frag->max; nn++) {
   1405         if (frag->pdus[nn] != NULL) {
   1406             smspdu_free( frag->pdus[nn] );
   1407             frag->pdus[nn] = NULL;
   1408         }
   1409     }
   1410     frag->pdus  = NULL;
   1411     frag->count = 0;
   1412     frag->max   = 0;
   1413     frag->index = 0;
   1414     free( frag );
   1415 }
   1416 
   1417 static SmsFragment
   1418 sms_fragment_alloc( SmsReceiver  rec, const SmsAddressRec*  from, int   ref, int  max )
   1419 {
   1420     SmsFragment  frag = calloc(sizeof(*frag) + max*sizeof(SmsPDU), 1 );
   1421 
   1422     if (frag != NULL) {
   1423         frag->from[0] = from[0];
   1424         frag->ref     = ref;
   1425         frag->max     = max;
   1426         frag->pdus    = (SmsPDU*)(frag + 1);
   1427         frag->index   = ++rec->last;
   1428     }
   1429     return  frag;
   1430 }
   1431 
   1432 
   1433 
   1434 SmsReceiver   sms_receiver_create( void )
   1435 {
   1436     SmsReceiver  rec = calloc(sizeof(*rec),1);
   1437     return rec;
   1438 }
   1439 
   1440 void
   1441 sms_receiver_destroy( SmsReceiver  rec )
   1442 {
   1443     while (rec->fragments) {
   1444         SmsFragment  frag = rec->fragments;
   1445         rec->fragments = frag->next;
   1446         sms_fragment_free(frag);
   1447     }
   1448 }
   1449 
   1450 static SmsFragment*
   1451 sms_receiver_find_p( SmsReceiver  rec, const SmsAddressRec*  from, int  ref )
   1452 {
   1453     SmsFragment*  pnode = &rec->fragments;
   1454     SmsFragment   node;
   1455 
   1456     for (;;) {
   1457         node = *pnode;
   1458         if (node == NULL)
   1459             break;
   1460         if (node->ref == ref && sms_address_eq( node->from, from ))
   1461             break;
   1462         pnode = &node->next;
   1463     }
   1464     return  pnode;
   1465 }
   1466 
   1467 static SmsFragment*
   1468 sms_receiver_find_index_p( SmsReceiver  rec, int  index )
   1469 {
   1470     SmsFragment*  pnode = &rec->fragments;
   1471     SmsFragment   node;
   1472 
   1473     for (;;) {
   1474         node = *pnode;
   1475         if (node == NULL)
   1476             break;
   1477         if (node->index == index)
   1478             break;
   1479         pnode = &node->next;
   1480     }
   1481     return  pnode;
   1482 }
   1483 
   1484 int
   1485 sms_receiver_add_submit_pdu( SmsReceiver  rec, SmsPDU       submit_pdu )
   1486 {
   1487     SmsAddressRec  from[1];
   1488     int            ref, max, cur;
   1489     SmsFragment*   pnode;
   1490     SmsFragment    frag;
   1491 
   1492     if ( smspdu_get_receiver_address( submit_pdu, from ) < 0 ) {
   1493         D( "%s: could not extract receiver address\n", __FUNCTION__ );
   1494         return -1;
   1495     }
   1496 
   1497     ref = smspdu_get_ref( submit_pdu );
   1498     if (ref < 0) {
   1499         D( "%s: could not extract message reference from pdu\n", __FUNCTION__ );
   1500         return -1;
   1501     }
   1502     max = smspdu_get_max_index( submit_pdu );
   1503     if (max < 0) {
   1504         D( "%s: invalid max fragment value: %d should be >= 1\n",
   1505            __FUNCTION__, max );
   1506         return -1;
   1507     }
   1508     pnode = sms_receiver_find_p( rec, from, ref );
   1509     frag  = *pnode;
   1510     if (frag == NULL) {
   1511         frag = sms_fragment_alloc( rec, from, ref, max );
   1512         if (frag == NULL) {
   1513             D("%s: not enough memory to allocate new fragment\n", __FUNCTION__ );
   1514             return -1;
   1515         }
   1516         if (D_ACTIVE) {
   1517             char  tmp[32];
   1518             int   len;
   1519 
   1520             len = sms_address_to_str( from, tmp, sizeof(tmp) );
   1521             if (len < 0) {
   1522                 strcpy( tmp, "<unknown>" );
   1523                 len = strlen(tmp);
   1524             }
   1525             D("%s: created SMS index %d, from %.*s, ref %d, max %d\n", __FUNCTION__,
   1526                frag->index, len, tmp, frag->ref, frag->max);
   1527         }
   1528         *pnode = frag;
   1529     }
   1530 
   1531     cur = smspdu_get_cur_index( submit_pdu );
   1532     if (cur < 0) {
   1533         D("%s: SMS fragment index is too small: %d should be >= 1\n", __FUNCTION__, cur+1 );
   1534         return -1;
   1535     }
   1536     if (cur >= max) {
   1537         D("%s: SMS fragment index is too large (%d >= %d)\n", __FUNCTION__, cur, max);
   1538         return -1;
   1539     }
   1540     if ( frag->pdus[cur] != NULL ) {
   1541         D("%s: receiving duplicate SMS fragment for %d/%d, ref=%d, discarding old one\n",
   1542           __FUNCTION__, cur+1, max, ref);
   1543         smspdu_free( frag->pdus[cur] );
   1544         frag->count -= 1;
   1545     }
   1546     frag->pdus[cur] = submit_pdu;
   1547     frag->count    += 1;
   1548 
   1549     if (frag->count >= frag->max) {
   1550         /* yes, we received all fragments for this SMS */
   1551         D( "%s: SMS index %d, received all %d fragments\n", __FUNCTION__, frag->index, frag->count );
   1552         return frag->index;
   1553     }
   1554     else {
   1555         /* still waiting for more */
   1556         D( "%s: SMS index %d, received %d/%d, waiting for %d more\n", __FUNCTION__,
   1557             frag->index, cur+1, max, frag->max - frag->count );
   1558         return 0;
   1559     }
   1560 }
   1561 
   1562 
   1563 int
   1564 sms_receiver_get_text_message( SmsReceiver  rec, int  index, bytes_t  utf8, int  utf8len )
   1565 {
   1566     SmsFragment*  pnode = sms_receiver_find_index_p( rec, index );
   1567     SmsFragment   frag  = *pnode;
   1568     int           nn, total;
   1569 
   1570     if (frag == NULL) {
   1571         D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
   1572         return -1;
   1573     }
   1574     if (frag->count != frag->max) {
   1575         D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
   1576            frag->index, frag->max - frag->count );
   1577         return -1;
   1578     }
   1579     /* get the size of all combined text */
   1580     total = 0;
   1581     for ( nn = 0; nn < frag->count; nn++ ) {
   1582         int  partial;
   1583         if (utf8 && utf8len > 0) {
   1584             partial  = smspdu_get_text_message( frag->pdus[nn], utf8, utf8len );
   1585             utf8    += partial;
   1586             utf8len -= partial;
   1587         } else {
   1588             partial  = smspdu_get_text_message( frag->pdus[nn], NULL, 0 );
   1589         }
   1590         total += partial;
   1591     }
   1592     return total;
   1593 }
   1594 
   1595 
   1596 static void
   1597 sms_receiver_remove( SmsReceiver  rec, int  index )
   1598 {
   1599     SmsFragment*  pnode = sms_receiver_find_index_p( rec, index );
   1600     SmsFragment   frag  = *pnode;
   1601     if (frag != NULL) {
   1602         *pnode = frag->next;
   1603         sms_fragment_free(frag);
   1604     }
   1605 }
   1606 
   1607 
   1608 SmsPDU*
   1609 sms_receiver_create_deliver( SmsReceiver  rec, int  index, const SmsAddressRec*  from )
   1610 {
   1611     SmsPDU*          result = NULL;
   1612     SmsFragment*     pnode = sms_receiver_find_index_p( rec, index );
   1613     SmsFragment      frag  = *pnode;
   1614     SmsTimeStampRec  now[1];
   1615     int              nn, total;
   1616     bytes_t          utf8;
   1617     int              utf8len;
   1618 
   1619     if (frag == NULL) {
   1620         D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
   1621         return NULL;
   1622     }
   1623     if (frag->count != frag->max) {
   1624         D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
   1625            frag->index, frag->max - frag->count );
   1626         return NULL;
   1627     }
   1628 
   1629     /* get the combined text message */
   1630     utf8len = sms_receiver_get_text_message( rec, index, NULL, 0 );
   1631     if (utf8len < 0)
   1632         goto Exit;
   1633 
   1634     utf8 = malloc( utf8len + 1 );
   1635     if (utf8 == NULL) {
   1636         D( "%s: not enough memory to allocate %d bytes\n",
   1637            __FUNCTION__, utf8len+1 );
   1638         goto Exit;
   1639     }
   1640 
   1641     total = 0;
   1642     for ( nn = 0; nn < frag->count; nn++ ) {
   1643         total += smspdu_get_text_message( frag->pdus[nn], utf8 + total, utf8len - total );
   1644     }
   1645 
   1646     sms_timestamp_now( now );
   1647 
   1648     result = smspdu_create_deliver_utf8( utf8, utf8len, from, now );
   1649 
   1650     free(utf8);
   1651 
   1652 Exit:
   1653     sms_receiver_remove( rec, index );
   1654     return result;
   1655 }
   1656 
   1657