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