• 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 <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, &timestamp ) < 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