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