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