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