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
sms_utf8_from_message_str(const char * str,int strlen,unsigned char * utf8,int utf8len)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 */
sms_utf8_to_message_str(const unsigned char * utf8,int utf8len,char * str,int strlen)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
sms_timestamp_now(SmsTimeStamp stamp)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
sms_timestamp_to_tm(SmsTimeStamp stamp,struct tm * tm)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
gsm_rope_add_timestamp(GsmRope rope,const SmsTimeStampRec * ts)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
sms_address_from_str(SmsAddress address,const char * src,int srclen)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
sms_address_to_str(SmsAddress address,char * str,int strlen)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
sms_address_from_bytes(SmsAddress address,const unsigned char * buf,int buflen)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
sms_address_to_bytes(SmsAddress address,unsigned char * buf,int bufsize)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
sms_address_from_hex(SmsAddress address,const char * hex,int hexlen)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
sms_address_to_hex(SmsAddress address,char * hex,int hexlen)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
gsm_rope_add_address(GsmRope rope,const SmsAddressRec * addr)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
sms_address_eq(const SmsAddressRec * addr1,const SmsAddressRec * addr2)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
sms_get_byte(cbytes_t * pcur,cbytes_t end)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
sms_get_sc_address(cbytes_t * pcur,cbytes_t end,SmsAddress address)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
sms_skip_sc_address(cbytes_t * pcur,cbytes_t end)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
sms_get_address(cbytes_t * pcur,cbytes_t end,SmsAddress address)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
sms_skip_address(cbytes_t * pcur,cbytes_t end)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
sms_get_timestamp(cbytes_t * pcur,cbytes_t end,SmsTimeStamp ts)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
sms_skip_timestamp(cbytes_t * pcur,cbytes_t end)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
sms_skip_validity_period(cbytes_t * pcur,cbytes_t end,int mtiByte)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
smspdu_free(SmsPDU pdu)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
smspdu_get_type(SmsPDU pdu)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
smspdu_get_sender_address(SmsPDU pdu,SmsAddress address)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
smspdu_get_sc_timestamp(SmsPDU pdu,SmsTimeStamp ts)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
smspdu_get_receiver_address(SmsPDU pdu,SmsAddress address)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
sms_get_coding_scheme(cbytes_t * pcur,cbytes_t end)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
sms_get_text_utf8(cbytes_t * pcur,cbytes_t end,int hasUDH,SmsCodingScheme coding,GsmRope rope)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
smspdu_get_text_message(SmsPDU pdu,unsigned char * utf8,int utf8len)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
smspdu_get_user_data_ref(SmsPDU pdu)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
smspdu_get_ref(SmsPDU pdu)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
smspdu_get_max_index(SmsPDU pdu)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
smspdu_get_cur_index(SmsPDU pdu)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
gsm_rope_add_sms_user_header(GsmRope rope,int ref_number,int pdu_count,int pdu_index)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
gsm_rope_add_sms_deliver_pdu(GsmRope rope,cbytes_t utf8,int utf8len,int use_gsm7,const SmsAddressRec * sender_address,const SmsTimeStampRec * timestamp,int ref_num,int pdu_count,int pdu_index)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
smspdu_create_deliver(cbytes_t utf8,int utf8len,int use_gsm7,const SmsAddressRec * sender_address,const SmsTimeStampRec * timestamp,int ref_num,int pdu_count,int pdu_index)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
smspdu_free_list(SmsPDU * pdus)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*
smspdu_create_deliver_utf8(const unsigned char * utf8,int utf8len,const SmsAddressRec * sender_address,const SmsTimeStampRec * timestamp)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
smspdu_create_from_hex(const char * hex,int hexlen)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
smspdu_to_hex(SmsPDU pdu,char * hex,int hexlen)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
sms_fragment_free(SmsFragment frag)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
sms_fragment_alloc(SmsReceiver rec,const SmsAddressRec * from,int ref,int max)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
sms_receiver_create(void)1433 SmsReceiver sms_receiver_create( void )
1434 {
1435 SmsReceiver rec = calloc(sizeof(*rec),1);
1436 return rec;
1437 }
1438
1439 void
sms_receiver_destroy(SmsReceiver rec)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*
sms_receiver_find_p(SmsReceiver rec,const SmsAddressRec * from,int ref)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*
sms_receiver_find_index_p(SmsReceiver rec,int index)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
sms_receiver_add_submit_pdu(SmsReceiver rec,SmsPDU submit_pdu)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
sms_receiver_get_text_message(SmsReceiver rec,int index,bytes_t utf8,int utf8len)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
sms_receiver_remove(SmsReceiver rec,int index)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*
sms_receiver_create_deliver(SmsReceiver rec,int index,const SmsAddressRec * from)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