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, ×tamp ) < 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