Upgrade ofono to 1.11 and merge to 2.0alpha
[profile/ivi/ofono.git] / src / smsutil.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34
35 #include <glib.h>
36
37 #include "util.h"
38 #include "storage.h"
39 #include "smsutil.h"
40
41 #define uninitialized_var(x) x = x
42
43 #define SMS_BACKUP_MODE 0600
44 #define SMS_BACKUP_PATH STORAGEDIR "/%s/sms_assembly"
45 #define SMS_BACKUP_PATH_DIR SMS_BACKUP_PATH "/%s-%i-%i"
46 #define SMS_BACKUP_PATH_FILE SMS_BACKUP_PATH_DIR "/%03i"
47
48 #define SMS_SR_BACKUP_PATH STORAGEDIR "/%s/sms_sr"
49 #define SMS_SR_BACKUP_PATH_FILE SMS_SR_BACKUP_PATH "/%s-%s"
50
51 #define SMS_TX_BACKUP_PATH STORAGEDIR "/%s/tx_queue"
52 #define SMS_TX_BACKUP_PATH_DIR SMS_TX_BACKUP_PATH "/%lu-%lu-%s"
53 #define SMS_TX_BACKUP_PATH_FILE SMS_TX_BACKUP_PATH_DIR "/%03i"
54
55 #define SMS_ADDR_FMT "%24[0-9A-F]"
56 #define SMS_MSGID_FMT "%40[0-9A-F]"
57
58 /*
59  * Time zone accounts for daylight saving time, and the two extreme time
60  * zones on earth are UTC-12 and UTC+14.
61  */
62 #define MAX_TIMEZONE 56
63 #define MIN_TIMEZONE -48
64
65 static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
66                                         const struct sms *sms, time_t ts,
67                                         const struct sms_address *addr,
68                                         guint16 ref, guint8 max, guint8 seq,
69                                         gboolean backup);
70
71 /*
72  * This function uses the meanings of digits 10..15 according to the rules
73  * defined in 23.040 Section 9.1.2.3 and 24.008 Table 10.5.118
74  */
75 void extract_bcd_number(const unsigned char *buf, int len, char *out)
76 {
77         static const char digit_lut[] = "0123456789*#abc\0";
78         unsigned char oct;
79         int i;
80
81         for (i = 0; i < len; i++) {
82                 oct = buf[i];
83
84                 out[i*2] = digit_lut[oct & 0x0f];
85                 out[i*2+1] = digit_lut[(oct & 0xf0) >> 4];
86         }
87
88         out[i*2] = '\0';
89 }
90
91 static inline int to_semi_oct(char in)
92 {
93         int digit;
94
95         switch (in) {
96         case '0':
97         case '1':
98         case '2':
99         case '3':
100         case '4':
101         case '5':
102         case '6':
103         case '7':
104         case '8':
105         case '9':
106                 digit = in - '0';
107                 break;
108         case '*':
109                 digit = 10;
110                 break;
111         case '#':
112                 digit = 11;
113                 break;
114         case 'A':
115         case 'a':
116                 digit = 12;
117                 break;
118         case 'B':
119         case 'b':
120                 digit = 13;
121                 break;
122         case 'C':
123         case 'c':
124                 digit = 14;
125                 break;
126         default:
127                 digit = -1;
128                 break;
129         }
130
131         return digit;
132 }
133
134 void encode_bcd_number(const char *number, unsigned char *out)
135 {
136         while (number[0] != '\0' && number[1] != '\0') {
137                 *out = to_semi_oct(*number++);
138                 *out++ |= to_semi_oct(*number++) << 4;
139         }
140
141         if (*number)
142                 *out = to_semi_oct(*number) | 0xf0;
143 }
144
145 /*
146  * Returns whether the DCS could be parsed successfully, e.g. no reserved
147  * values were used
148  */
149 gboolean sms_dcs_decode(guint8 dcs, enum sms_class *cls,
150                         enum sms_charset *charset,
151                         gboolean *compressed, gboolean *autodelete)
152 {
153         guint8 upper = (dcs & 0xf0) >> 4;
154         enum sms_charset ch;
155         enum sms_class cl;
156         gboolean comp;
157         gboolean autodel;
158
159         /* MWI DCS types are handled in sms_mwi_dcs_decode */
160         if (upper >= 0x8 && upper <= 0xE)
161                 return FALSE;
162
163         upper = (dcs & 0xc0) >> 6;
164
165         switch (upper) {
166         case 0:
167         case 1:
168                 autodel = upper;
169                 comp = (dcs & 0x20) ? TRUE : FALSE;
170
171                 if (dcs & 0x10)
172                         cl = (enum sms_class) (dcs & 0x03);
173                 else
174                         cl = SMS_CLASS_UNSPECIFIED;
175
176                 if (((dcs & 0x0c) >> 2) < 3)
177                         ch = (enum sms_charset) ((dcs & 0x0c) >> 2);
178                 else
179                         return FALSE;
180
181                 break;
182         case 3:
183                 comp = FALSE;
184                 autodel = FALSE;
185
186                 if (dcs & 0x4)
187                         ch = SMS_CHARSET_8BIT;
188                 else
189                         ch = SMS_CHARSET_7BIT;
190
191                 cl = (enum sms_class) (dcs & 0x03);
192
193                 break;
194         default:
195                 return FALSE;
196         };
197
198         if (compressed)
199                 *compressed = comp;
200
201         if (autodelete)
202                 *autodelete = autodel;
203
204         if (cls)
205                 *cls = cl;
206
207         if (charset)
208                 *charset = ch;
209
210         return TRUE;
211 }
212
213 gboolean sms_mwi_dcs_decode(guint8 dcs, enum sms_mwi_type *type,
214                                 enum sms_charset *charset,
215                                 gboolean *active, gboolean *discard)
216 {
217         guint8 upper = (dcs & 0xf0) >> 4;
218         enum sms_mwi_type t;
219         enum sms_charset ch;
220         gboolean dis;
221         gboolean act;
222
223         if (upper < 0xC || upper > 0xE)
224                 return FALSE;
225
226         upper = (dcs & 0x30) >> 4;
227
228         if (upper == 0)
229                 dis = TRUE;
230         else
231                 dis = FALSE;
232
233         /*
234          * As per 3GPP TS 23.038 specification, if bits 7..4 set to 1110,
235          * text included in the user data is coded in the uncompresssed
236          * UCS2 character set.
237          */
238         if (upper == 2)
239                 ch = SMS_CHARSET_UCS2;
240         else
241                 ch = SMS_CHARSET_7BIT;
242
243         act = dcs & 0x8;
244
245         t = (enum sms_mwi_type) (dcs & 0x3);
246
247         if (type)
248                 *type = t;
249
250         if (charset)
251                 *charset = ch;
252
253         if (active)
254                 *active = act;
255
256         if (discard)
257                 *discard = dis;
258
259         return TRUE;
260 }
261
262 int sms_udl_in_bytes(guint8 ud_len, guint8 dcs)
263 {
264         int len_7bit = (ud_len + 1) * 7 / 8;
265         int len_8bit = ud_len;
266         guint8 upper;
267
268         if (dcs == 0)
269                 return len_7bit;
270
271         upper = (dcs & 0xc0) >> 6;
272
273         switch (upper) {
274         case 0:
275         case 1:
276                 if (dcs & 0x20) /* compressed */
277                         return len_8bit;
278
279                 switch ((dcs & 0x0c) >> 2) {
280                 case 0:
281                         return len_7bit;
282                 case 1:
283                         return len_8bit;
284                 case 2:
285                         return len_8bit;
286                 }
287
288                 return 0;
289         case 2:
290                 return 0;
291         case 3:
292                 switch ((dcs & 0x30) >> 4) {
293                 case 0:
294                 case 1:
295                         return len_7bit;
296                 case 2:
297                         return len_8bit;
298                 case 3:
299                         if (dcs & 0x4)
300                                 return len_8bit;
301                         else
302                                 return len_7bit;
303                 }
304
305                 break;
306         default:
307                 break;
308         };
309
310         return 0;
311 }
312
313 static inline gboolean next_octet(const unsigned char *pdu, int len,
314                                         int *offset, unsigned char *oct)
315 {
316         if (len == *offset)
317                 return FALSE;
318
319         *oct = pdu[*offset];
320
321         *offset = *offset + 1;
322
323         return TRUE;
324 }
325
326 static inline gboolean set_octet(unsigned char *pdu, int *offset,
327                                         unsigned char oct)
328 {
329         pdu[*offset] = oct;
330         *offset = *offset + 1;
331
332         return TRUE;
333 }
334
335 gboolean sms_encode_scts(const struct sms_scts *in, unsigned char *pdu,
336                                 int *offset)
337 {
338         guint timezone;
339
340         if (in->year > 99)
341                 return FALSE;
342
343         if (in->month > 12)
344                 return FALSE;
345
346         if (in->day > 31)
347                 return FALSE;
348
349         if (in->hour > 23)
350                 return FALSE;
351
352         if (in->minute > 59)
353                 return FALSE;
354
355         if (in->second > 59)
356                 return FALSE;
357
358         if ((in->timezone > MAX_TIMEZONE || in->timezone < MIN_TIMEZONE) &&
359                         in->has_timezone == TRUE)
360                 return FALSE;
361
362         pdu = pdu + *offset;
363
364         pdu[0] = ((in->year / 10) & 0x0f) | (((in->year % 10) & 0x0f) << 4);
365         pdu[1] = ((in->month / 10) & 0x0f) | (((in->month % 10) & 0x0f) << 4);
366         pdu[2] = ((in->day / 10) & 0x0f) | (((in->day % 10) & 0x0f) << 4);
367         pdu[3] = ((in->hour / 10) & 0x0f) | (((in->hour % 10) & 0x0f) << 4);
368         pdu[4] = ((in->minute / 10) & 0x0f) | (((in->minute % 10) & 0x0f) << 4);
369         pdu[5] = ((in->second / 10) & 0x0f) | (((in->second % 10) & 0x0f) << 4);
370
371         if (in->has_timezone == FALSE) {
372                 pdu[6] = 0xff;
373                 goto out;
374         }
375
376         timezone = abs(in->timezone);
377
378         pdu[6] = ((timezone / 10) & 0x07) | (((timezone % 10) & 0x0f) << 4);
379
380         if (in->timezone < 0)
381                 pdu[6] |= 0x8;
382
383 out:
384         *offset += 7;
385
386         return TRUE;
387 }
388
389 guint8 sms_decode_semi_octet(guint8 in)
390 {
391         return (in & 0x0f) * 10 + (in >> 4);
392 }
393
394 gboolean sms_decode_scts(const unsigned char *pdu, int len,
395                                 int *offset, struct sms_scts *out)
396 {
397         unsigned char oct = 0;
398
399         if ((len - *offset) < 7)
400                 return FALSE;
401
402         next_octet(pdu, len, offset, &oct);
403         out->year = sms_decode_semi_octet(oct);
404
405         if (out->year > 99)
406                 return FALSE;
407
408         next_octet(pdu, len, offset, &oct);
409         out->month = sms_decode_semi_octet(oct);
410
411         if (out->month > 12)
412                 return FALSE;
413
414         next_octet(pdu, len, offset, &oct);
415         out->day = sms_decode_semi_octet(oct);
416
417         if (out->day > 31)
418                 return FALSE;
419
420         next_octet(pdu, len, offset, &oct);
421         out->hour = sms_decode_semi_octet(oct);
422
423         if (out->hour > 23)
424                 return FALSE;
425
426         next_octet(pdu, len, offset, &oct);
427         out->minute = sms_decode_semi_octet(oct);
428
429         if (out->minute > 59)
430                 return FALSE;
431
432         next_octet(pdu, len, offset, &oct);
433         out->second = sms_decode_semi_octet(oct);
434
435         if (out->second > 59)
436                 return FALSE;
437
438         next_octet(pdu, len, offset, &oct);
439
440         /*
441          * Time Zone indicates the difference, expressed in quarters
442          * of an hour, between the local time and GMT. In the first of the two
443          * semi‑octets, the first bit (bit 3 of the seventh octet of the
444          * TP‑Service‑Centre‑Time‑Stamp field) represents the algebraic
445          * sign of this difference (0: positive, 1: negative).
446          */
447         out->timezone = (oct & 0x07) * 10 + ((oct & 0xf0) >> 4);
448
449         if (oct & 0x08)
450                 out->timezone = out->timezone * -1;
451
452         if ((out->timezone > MAX_TIMEZONE) || (out->timezone < MIN_TIMEZONE))
453                 return FALSE;
454
455         out->has_timezone = TRUE;
456
457         return TRUE;
458 }
459
460 static gboolean decode_validity_period(const unsigned char *pdu, int len,
461                                         int *offset,
462                                         enum sms_validity_period_format vpf,
463                                         struct sms_validity_period *vp)
464 {
465         switch (vpf) {
466         case SMS_VALIDITY_PERIOD_FORMAT_ABSENT:
467                 return TRUE;
468         case SMS_VALIDITY_PERIOD_FORMAT_RELATIVE:
469                 if (!next_octet(pdu, len, offset, &vp->relative))
470                         return FALSE;
471
472                 return TRUE;
473         case SMS_VALIDITY_PERIOD_FORMAT_ABSOLUTE:
474                 if (!sms_decode_scts(pdu, len, offset, &vp->absolute))
475                         return FALSE;
476
477                 return TRUE;
478         case SMS_VALIDITY_PERIOD_FORMAT_ENHANCED:
479                 /*
480                  * TODO: Parse out enhanced structure properly
481                  * 23.040 Section 9.2.3.12.3
482                  */
483                 if ((len - *offset) < 7)
484                         return FALSE;
485
486                 memcpy(vp->enhanced, pdu + *offset, 7);
487
488                 *offset = *offset + 7;
489
490                 return TRUE;
491         default:
492                 break;
493         }
494
495         return FALSE;
496 }
497
498 static gboolean encode_validity_period(const struct sms_validity_period *vp,
499                                         enum sms_validity_period_format vpf,
500                                         unsigned char *pdu, int *offset)
501 {
502         switch (vpf) {
503         case SMS_VALIDITY_PERIOD_FORMAT_ABSENT:
504                 return TRUE;
505         case SMS_VALIDITY_PERIOD_FORMAT_RELATIVE:
506                 set_octet(pdu, offset, vp->relative);
507                 return TRUE;
508         case SMS_VALIDITY_PERIOD_FORMAT_ABSOLUTE:
509                 return sms_encode_scts(&vp->absolute, pdu, offset);
510         case SMS_VALIDITY_PERIOD_FORMAT_ENHANCED:
511                 /* TODO: Write out proper enhanced VP structure */
512                 memcpy(pdu + *offset, vp->enhanced, 7);
513
514                 *offset = *offset + 7;
515
516                 return TRUE;
517         default:
518                 break;
519         }
520
521         return FALSE;
522 }
523
524 gboolean sms_encode_address_field(const struct sms_address *in, gboolean sc,
525                                         unsigned char *pdu, int *offset)
526 {
527         size_t len = strlen(in->address);
528         unsigned char addr_len = 0;
529         unsigned char p[10];
530
531         pdu = pdu + *offset;
532
533         if (len == 0 && sc) {
534                 pdu[0] = 0;
535                 *offset = *offset + 1;
536
537                 return TRUE;
538         }
539
540         if (len == 0)
541                 goto out;
542
543         if (in->number_type == SMS_NUMBER_TYPE_ALPHANUMERIC) {
544                 long written;
545                 long packed;
546                 unsigned char *gsm;
547                 unsigned char *r;
548
549                 if (len > 11)
550                         return FALSE;
551
552                 gsm = convert_utf8_to_gsm(in->address, len, NULL, &written, 0);
553                 if (gsm == NULL)
554                         return FALSE;
555
556                 r = pack_7bit_own_buf(gsm, written, 0, FALSE, &packed, 0, p);
557
558                 g_free(gsm);
559
560                 if (r == NULL)
561                         return FALSE;
562
563                 if (sc)
564                         addr_len = packed + 1;
565                 else
566                         addr_len = (written * 7 + 3) / 4;
567         } else {
568                 int j = 0;
569                 int i;
570                 int c;
571
572                 if (len > 20)
573                         return FALSE;
574
575                 for (i = 0; in->address[i]; i++) {
576                         c = to_semi_oct(in->address[i]);
577
578                         if (c < 0)
579                                 return FALSE;
580
581                         if ((i % 2) == 0) {
582                                 p[j] = c;
583                         } else {
584                                 p[j] |= c << 4;
585                                 j++;
586                         }
587                 }
588
589                 if ((i % 2) == 1) {
590                         p[j] |= 0xf0;
591                         j++;
592                 }
593
594                 if (sc)
595                         addr_len = j + 1;
596                 else
597                         addr_len = i;
598         }
599
600 out:
601         pdu[0] = addr_len;
602         pdu[1] = (in->number_type << 4) | in->numbering_plan | 0x80;
603         memcpy(pdu+2, p, (sc ? addr_len - 1 : (addr_len + 1) / 2));
604
605         *offset = *offset + 2 + (sc ? addr_len - 1 : (addr_len + 1) / 2);
606
607         return TRUE;
608 }
609
610 gboolean sms_decode_address_field(const unsigned char *pdu, int len,
611                                         int *offset, gboolean sc,
612                                         struct sms_address *out)
613 {
614         unsigned char addr_len;
615         unsigned char addr_type;
616         int byte_len;
617
618         if (!next_octet(pdu, len, offset, &addr_len))
619                 return FALSE;
620
621         if (sc && addr_len == 0) {
622                 out->address[0] = '\0';
623                 return TRUE;
624         }
625
626         if (!next_octet(pdu, len, offset, &addr_type))
627                 return FALSE;
628
629         if (sc)
630                 byte_len = addr_len - 1;
631         else
632                 byte_len = (addr_len + 1) / 2;
633
634         if ((len - *offset) < byte_len)
635                 return FALSE;
636
637         out->number_type = bit_field(addr_type, 4, 3);
638         out->numbering_plan = bit_field(addr_type, 0, 4);
639
640         if (out->number_type != SMS_NUMBER_TYPE_ALPHANUMERIC) {
641                 extract_bcd_number(pdu + *offset, byte_len, out->address);
642                 *offset += byte_len;
643         } else {
644                 int chars;
645                 long written;
646                 unsigned char *res;
647                 char *utf8;
648
649                 if (sc)
650                         chars = byte_len * 8 / 7;
651                 else
652                         chars = addr_len * 4 / 7;
653
654                 /*
655                  * This cannot happen according to 24.011, however
656                  * nothing is said in 23.040
657                  */
658                 if (chars == 0) {
659                         out->address[0] = '\0';
660                         return TRUE;
661                 }
662
663                 res = unpack_7bit(pdu + *offset, byte_len, 0, FALSE, chars,
664                                         &written, 0);
665
666                 *offset = *offset + (addr_len + 1) / 2;
667
668                 if (res == NULL)
669                         return FALSE;
670
671                 utf8 = convert_gsm_to_utf8(res, written, NULL, NULL, 0);
672
673                 g_free(res);
674
675                 if (utf8 == NULL)
676                         return FALSE;
677
678                 if (strlen(utf8) > 20) {
679                         g_free(utf8);
680                         return FALSE;
681                 }
682
683                 strcpy(out->address, utf8);
684
685                 g_free(utf8);
686         }
687
688         return TRUE;
689 }
690
691 static gboolean encode_deliver(const struct sms_deliver *in, unsigned char *pdu,
692                                 int *offset)
693 {
694         int ud_oct_len;
695         unsigned char oct;
696
697         oct = 0;
698
699         if (!in->mms)
700                 oct |= 1 << 2;
701
702         if (in->sri)
703                 oct |= 1 << 5;
704
705         if (in->rp)
706                 oct |= 1 << 7;
707
708         if (in->udhi)
709                 oct |= 1 << 6;
710
711         set_octet(pdu, offset, oct);
712
713         if (sms_encode_address_field(&in->oaddr, FALSE, pdu, offset) == FALSE)
714                 return FALSE;
715
716         set_octet(pdu, offset, in->pid);
717         set_octet(pdu, offset, in->dcs);
718
719         if (sms_encode_scts(&in->scts, pdu, offset) == FALSE)
720                 return FALSE;
721
722         set_octet(pdu, offset, in->udl);
723
724         ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
725
726         memcpy(pdu + *offset, in->ud, ud_oct_len);
727
728         *offset = *offset + ud_oct_len;
729
730         return TRUE;
731 }
732
733 static gboolean decode_deliver(const unsigned char *pdu, int len,
734                                 struct sms *out)
735 {
736         int offset = 0;
737         int expected;
738         unsigned char octet;
739
740         out->type = SMS_TYPE_DELIVER;
741
742         if (!next_octet(pdu, len, &offset, &octet))
743                 return FALSE;
744
745         out->deliver.mms = !is_bit_set(octet, 2);
746         out->deliver.sri = is_bit_set(octet, 5);
747         out->deliver.udhi = is_bit_set(octet, 6);
748         out->deliver.rp = is_bit_set(octet, 7);
749
750         if (!sms_decode_address_field(pdu, len, &offset,
751                                         FALSE, &out->deliver.oaddr))
752                 return FALSE;
753
754         if (!next_octet(pdu, len, &offset, &out->deliver.pid))
755                 return FALSE;
756
757         if (!next_octet(pdu, len, &offset, &out->deliver.dcs))
758                 return FALSE;
759
760         if (!sms_decode_scts(pdu, len, &offset, &out->deliver.scts))
761                 return FALSE;
762
763         if (!next_octet(pdu, len, &offset, &out->deliver.udl))
764                 return FALSE;
765
766         expected = sms_udl_in_bytes(out->deliver.udl, out->deliver.dcs);
767
768         if ((len - offset) < expected)
769                 return FALSE;
770
771         memcpy(out->deliver.ud, pdu+offset, expected);
772
773         return TRUE;
774 }
775
776 static gboolean encode_submit_ack_report(const struct sms_submit_ack_report *in,
777                                                 unsigned char *pdu, int *offset)
778 {
779         unsigned char oct;
780
781         oct = 1;
782
783         if (in->udhi)
784                 oct |= 1 << 6;
785
786         set_octet(pdu, offset, oct);
787
788         set_octet(pdu, offset, in->pi);
789
790         if (!sms_encode_scts(&in->scts, pdu, offset))
791                 return FALSE;
792
793         if (in->pi & 0x1)
794                 set_octet(pdu, offset, in->pid);
795
796         if (in->pi & 0x2)
797                 set_octet(pdu, offset, in->dcs);
798
799         if (in->pi & 0x4) {
800                 int ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
801
802                 set_octet(pdu, offset, in->udl);
803                 memcpy(pdu + *offset, in->ud, ud_oct_len);
804                 *offset = *offset + ud_oct_len;
805         }
806
807         return TRUE;
808 }
809
810 static gboolean encode_submit_err_report(const struct sms_submit_err_report *in,
811                                                 unsigned char *pdu, int *offset)
812 {
813         unsigned char oct;
814
815         oct = 0x1;
816
817         if (in->udhi)
818                 oct |= 1 << 6;
819
820         set_octet(pdu, offset, oct);
821
822         set_octet(pdu, offset, in->fcs);
823
824         set_octet(pdu, offset, in->pi);
825
826         if (!sms_encode_scts(&in->scts, pdu, offset))
827                 return FALSE;
828
829         if (in->pi & 0x1)
830                 set_octet(pdu, offset, in->pid);
831
832         if (in->pi & 0x2)
833                 set_octet(pdu, offset, in->dcs);
834
835         if (in->pi & 0x4) {
836                 int ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
837
838                 set_octet(pdu, offset, in->udl);
839                 memcpy(pdu + *offset, in->ud, ud_oct_len);
840                 *offset = *offset + ud_oct_len;
841         }
842
843         return TRUE;
844 }
845
846 static gboolean decode_submit_report(const unsigned char *pdu, int len,
847                                         struct sms *out)
848 {
849         int offset = 0;
850         unsigned char octet;
851         gboolean udhi;
852         guint8 uninitialized_var(fcs);
853         guint8 pi;
854         struct sms_scts *scts;
855         guint8 pid = 0;
856         guint8 dcs = 0;
857         guint8 udl = 0;
858
859         if (!next_octet(pdu, len, &offset, &octet))
860                 return FALSE;
861
862         udhi = is_bit_set(octet, 6);
863
864         if (!next_octet(pdu, len, &offset, &octet))
865                 return FALSE;
866
867         /*
868          * At this point we don't know whether this is an ACK or an ERROR.
869          * FCS can only have values 0x80 and above, as 0x00 - 0x7F are reserved
870          * according to 3GPP 23.040.  For PI, the values can be only in
871          * bit 0, 1, 2 with the 7th bit reserved as an extension.  Since
872          * bits 3-6 are not used, assume no extension is feasible, so if the
873          * value of this octet is >= 0x80, this is an FCS and thus an error
874          * report tpdu.
875          */
876
877         if (octet >= 0x80) {
878                 out->type = SMS_TYPE_SUBMIT_REPORT_ERROR;
879                 fcs = octet;
880
881                 if (!next_octet(pdu, len, &offset, &octet))
882                         return FALSE;
883
884                 scts = &out->submit_err_report.scts;
885         } else {
886                 scts = &out->submit_ack_report.scts;
887                 out->type = SMS_TYPE_SUBMIT_REPORT_ACK;
888         }
889
890         pi = octet & 0x07;
891
892         if (!sms_decode_scts(pdu, len, &offset, scts))
893                 return FALSE;
894
895         if (pi & 0x01) {
896                 if (!next_octet(pdu, len, &offset, &pid))
897                         return FALSE;
898         }
899
900         if (pi & 0x02) {
901                 if (!next_octet(pdu, len, &offset, &dcs))
902                         return FALSE;
903         }
904
905         if (out->type == SMS_TYPE_SUBMIT_REPORT_ERROR) {
906                 out->submit_err_report.udhi = udhi;
907                 out->submit_err_report.fcs = fcs;
908                 out->submit_err_report.pi = pi;
909                 out->submit_err_report.pid = pid;
910                 out->submit_err_report.dcs = dcs;
911         } else {
912                 out->submit_ack_report.udhi = udhi;
913                 out->submit_ack_report.pi = pi;
914                 out->submit_ack_report.pid = pid;
915                 out->submit_ack_report.dcs = dcs;
916         }
917
918         if (pi & 0x04) {
919                 int expected;
920
921                 if (!next_octet(pdu, len, &offset, &udl))
922                         return FALSE;
923
924                 expected = sms_udl_in_bytes(udl, dcs);
925
926                 if ((len - offset) < expected)
927                         return FALSE;
928
929                 if (out->type == SMS_TYPE_SUBMIT_REPORT_ERROR) {
930                         out->submit_err_report.udl = udl;
931                         memcpy(out->submit_err_report.ud,
932                                         pdu+offset, expected);
933                 } else {
934                         out->submit_ack_report.udl = udl;
935                         memcpy(out->submit_ack_report.ud,
936                                         pdu+offset, expected);
937                 }
938         }
939
940         return TRUE;
941 }
942
943 static gboolean encode_status_report(const struct sms_status_report *in,
944                                         unsigned char *pdu, int *offset)
945 {
946         unsigned char octet;
947
948         octet = 0x2;
949
950         if (!in->mms)
951                 octet |= 1 << 2;
952
953         if (!in->srq)
954                 octet |= 1 << 5;
955
956         if (!in->udhi)
957                 octet |= 1 << 6;
958
959         set_octet(pdu, offset, octet);
960
961         set_octet(pdu, offset, in->mr);
962
963         if (!sms_encode_address_field(&in->raddr, FALSE, pdu, offset))
964                 return FALSE;
965
966         if (!sms_encode_scts(&in->scts, pdu, offset))
967                 return FALSE;
968
969         if (!sms_encode_scts(&in->dt, pdu, offset))
970                 return FALSE;
971
972         octet = in->st;
973         set_octet(pdu, offset, octet);
974
975         if (in->pi == 0)
976                 return TRUE;
977
978         set_octet(pdu, offset, in->pi);
979
980         if (in->pi & 0x01)
981                 set_octet(pdu, offset, in->pid);
982
983         if (in->pi & 0x02)
984                 set_octet(pdu, offset, in->dcs);
985
986         if (in->pi & 0x4) {
987                 int ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
988
989                 set_octet(pdu, offset, in->udl);
990                 memcpy(pdu + *offset, in->ud, ud_oct_len);
991                 *offset = *offset + ud_oct_len;
992         }
993
994         return TRUE;
995 }
996
997 static gboolean decode_status_report(const unsigned char *pdu, int len,
998                                         struct sms *out)
999 {
1000         int offset = 0;
1001         unsigned char octet;
1002
1003         out->type = SMS_TYPE_STATUS_REPORT;
1004
1005         if (!next_octet(pdu, len, &offset, &octet))
1006                 return FALSE;
1007
1008         out->status_report.mms = !is_bit_set(octet, 2);
1009         out->status_report.srq = is_bit_set(octet, 5);
1010         out->status_report.udhi = is_bit_set(octet, 6);
1011
1012         if (!next_octet(pdu, len, &offset, &out->status_report.mr))
1013                 return FALSE;
1014
1015         if (!sms_decode_address_field(pdu, len, &offset, FALSE,
1016                                         &out->status_report.raddr))
1017                 return FALSE;
1018
1019         if (!sms_decode_scts(pdu, len, &offset, &out->status_report.scts))
1020                 return FALSE;
1021
1022         if (!sms_decode_scts(pdu, len, &offset, &out->status_report.dt))
1023                 return FALSE;
1024
1025         if (!next_octet(pdu, len, &offset, &octet))
1026                 return FALSE;
1027
1028         out->status_report.st = octet;
1029
1030         /*
1031          * We have to be careful here, PI is labeled as Optional in 23.040
1032          * which is different from RP-ERR & RP-ACK for both Deliver & Submit
1033          * reports
1034          */
1035
1036         if ((len - offset) == 0)
1037                 return TRUE;
1038
1039         if (!next_octet(pdu, len, &offset, &octet))
1040                 return FALSE;
1041
1042         out->status_report.pi = octet & 0x07;
1043
1044         if (out->status_report.pi & 0x01) {
1045                 if (!next_octet(pdu, len, &offset, &out->status_report.pid))
1046                         return FALSE;
1047         }
1048
1049         if (out->status_report.pi & 0x02) {
1050                 if (!next_octet(pdu, len, &offset, &out->status_report.dcs))
1051                         return FALSE;
1052         }
1053
1054         if (out->status_report.pi & 0x04) {
1055                 int expected;
1056
1057                 if (!next_octet(pdu, len, &offset, &out->status_report.udl))
1058                         return FALSE;
1059
1060                 expected = sms_udl_in_bytes(out->status_report.udl,
1061                                                 out->status_report.dcs);
1062
1063                 if ((len - offset) < expected)
1064                         return FALSE;
1065
1066                 memcpy(out->status_report.ud, pdu+offset, expected);
1067         }
1068
1069         return TRUE;
1070 }
1071
1072 static gboolean encode_deliver_ack_report(const struct sms_deliver_ack_report *in,
1073                                                 unsigned char *pdu,
1074                                                 int *offset)
1075 {
1076         unsigned char oct;
1077
1078         oct = 0;
1079
1080         if (in->udhi)
1081                 oct |= 1 << 6;
1082
1083         set_octet(pdu, offset, oct);
1084
1085         set_octet(pdu, offset, in->pi);
1086
1087         if (in->pi & 0x1)
1088                 set_octet(pdu, offset, in->pid);
1089
1090         if (in->pi & 0x2)
1091                 set_octet(pdu, offset, in->dcs);
1092
1093         if (in->pi & 0x4) {
1094                 int ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
1095
1096                 set_octet(pdu, offset, in->udl);
1097                 memcpy(pdu + *offset, in->ud, ud_oct_len);
1098                 *offset = *offset + ud_oct_len;
1099         }
1100
1101         return TRUE;
1102 }
1103
1104 static gboolean encode_deliver_err_report(const struct sms_deliver_err_report *in,
1105                                                 unsigned char *pdu,
1106                                                 int *offset)
1107 {
1108         unsigned char oct;
1109
1110         oct = 0;
1111
1112         if (in->udhi)
1113                 oct |= 1 << 6;
1114
1115         set_octet(pdu, offset, oct);
1116
1117         set_octet(pdu, offset, in->fcs);
1118
1119         set_octet(pdu, offset, in->pi);
1120
1121         if (in->pi & 0x1)
1122                 set_octet(pdu, offset, in->pid);
1123
1124         if (in->pi & 0x2)
1125                 set_octet(pdu, offset, in->dcs);
1126
1127         if (in->pi & 0x4) {
1128                 int ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
1129
1130                 set_octet(pdu, offset, in->udl);
1131                 memcpy(pdu + *offset, in->ud, ud_oct_len);
1132                 *offset = *offset + ud_oct_len;
1133         }
1134
1135         return TRUE;
1136 }
1137
1138 static gboolean decode_deliver_report(const unsigned char *pdu, int len,
1139                                         struct sms *out)
1140 {
1141         int offset = 0;
1142         unsigned char octet;
1143         gboolean udhi;
1144         guint8 uninitialized_var(fcs);
1145         guint8 pi;
1146         guint8 pid = 0;
1147         guint8 dcs = 0;
1148         guint8 udl = 0;
1149
1150         if (!next_octet(pdu, len, &offset, &octet))
1151                 return FALSE;
1152
1153         udhi = is_bit_set(octet, 6);
1154
1155         if (!next_octet(pdu, len, &offset, &octet))
1156                 return FALSE;
1157
1158         /*
1159          * At this point we don't know whether this is an ACK or an ERROR.
1160          * FCS can only have values 0x80 and above, as 0x00 - 0x7F are reserved
1161          * according to 3GPP 23.040.  For PI, the values can be only in
1162          * bit 0, 1, 2 with the 7th bit reserved as an extension.  Since
1163          * bits 3-6 are not used, assume no extension is feasible, so if the
1164          * value of this octet is >= 0x80, this is an FCS and thus an error
1165          * report tpdu.
1166          */
1167
1168         if (octet >= 0x80) {
1169                 out->type = SMS_TYPE_DELIVER_REPORT_ERROR;
1170                 fcs = octet;
1171
1172                 if (!next_octet(pdu, len, &offset, &octet))
1173                         return FALSE;
1174         } else {
1175                 out->type = SMS_TYPE_DELIVER_REPORT_ACK;
1176         }
1177
1178         pi = octet & 0x07;
1179
1180         if (pi & 0x01) {
1181                 if (!next_octet(pdu, len, &offset, &pid))
1182                         return FALSE;
1183         }
1184
1185         if (pi & 0x02) {
1186                 if (!next_octet(pdu, len, &offset, &dcs))
1187                         return FALSE;
1188         }
1189
1190         if (out->type == SMS_TYPE_DELIVER_REPORT_ERROR) {
1191                 out->deliver_err_report.udhi = udhi;
1192                 out->deliver_err_report.fcs = fcs;
1193                 out->deliver_err_report.pi = pi;
1194                 out->deliver_err_report.pid = pid;
1195                 out->deliver_err_report.dcs = dcs;
1196         } else {
1197                 out->deliver_ack_report.udhi = udhi;
1198                 out->deliver_ack_report.pi = pi;
1199                 out->deliver_ack_report.pid = pid;
1200                 out->deliver_ack_report.dcs = dcs;
1201         }
1202
1203         if (pi & 0x04) {
1204                 int expected;
1205
1206                 if (!next_octet(pdu, len, &offset, &udl))
1207                         return FALSE;
1208
1209                 expected = sms_udl_in_bytes(udl, dcs);
1210
1211                 if ((len - offset) < expected)
1212                         return FALSE;
1213
1214                 if (out->type == SMS_TYPE_DELIVER_REPORT_ERROR) {
1215                         out->deliver_err_report.udl = udl;
1216                         memcpy(out->deliver_err_report.ud,
1217                                         pdu+offset, expected);
1218                 } else {
1219                         out->deliver_ack_report.udl = udl;
1220                         memcpy(out->deliver_ack_report.ud,
1221                                         pdu+offset, expected);
1222                 }
1223         }
1224
1225         return TRUE;
1226 }
1227
1228 static gboolean encode_submit(const struct sms_submit *in,
1229                                         unsigned char *pdu, int *offset)
1230 {
1231         unsigned char octet;
1232         int ud_oct_len;
1233
1234         /* SMS Submit */
1235         octet = 0x1;
1236
1237         if (in->rd)
1238                 octet |= 1 << 2;
1239
1240         if (in->rp)
1241                 octet |= 1 << 7;
1242
1243         octet |= in->vpf << 3;
1244
1245         if (in->udhi)
1246                 octet |= 1 << 6;
1247
1248         if (in->srr)
1249                 octet |= 1 << 5;
1250
1251         set_octet(pdu, offset, octet);
1252
1253         set_octet(pdu, offset, in->mr);
1254
1255         if (sms_encode_address_field(&in->daddr, FALSE, pdu, offset) == FALSE)
1256                 return FALSE;
1257
1258         set_octet(pdu, offset, in->pid);
1259
1260         set_octet(pdu, offset, in->dcs);
1261
1262         if (!encode_validity_period(&in->vp, in->vpf, pdu, offset))
1263                 return FALSE;
1264
1265         set_octet(pdu, offset, in->udl);
1266
1267         ud_oct_len = sms_udl_in_bytes(in->udl, in->dcs);
1268
1269         memcpy(pdu + *offset, in->ud, ud_oct_len);
1270
1271         *offset = *offset + ud_oct_len;
1272
1273         return TRUE;
1274 }
1275
1276 gboolean sms_decode_unpacked_stk_pdu(const unsigned char *pdu, int len,
1277                                         struct sms *out)
1278 {
1279         unsigned char octet;
1280         int offset = 0;
1281
1282         if (!next_octet(pdu, len, &offset, &octet))
1283                 return FALSE;
1284
1285         if ((octet & 0x3) != 1)
1286                 return FALSE;
1287
1288         out->type = SMS_TYPE_SUBMIT;
1289
1290         out->submit.rd = is_bit_set(octet, 2);
1291         out->submit.vpf = bit_field(octet, 3, 2);
1292         out->submit.rp = is_bit_set(octet, 7);
1293         out->submit.udhi = is_bit_set(octet, 6);
1294         out->submit.srr = is_bit_set(octet, 5);
1295
1296         if (!next_octet(pdu, len, &offset, &out->submit.mr))
1297                 return FALSE;
1298
1299         if (!sms_decode_address_field(pdu, len, &offset,
1300                                         FALSE, &out->submit.daddr))
1301                 return FALSE;
1302
1303         if (!next_octet(pdu, len, &offset, &out->submit.pid))
1304                 return FALSE;
1305
1306         if (!next_octet(pdu, len, &offset, &out->submit.dcs))
1307                 return FALSE;
1308
1309         /* Now we override the DCS */
1310         out->submit.dcs = 0xF0;
1311
1312         if (!decode_validity_period(pdu, len, &offset, out->submit.vpf,
1313                                         &out->submit.vp))
1314                 return FALSE;
1315
1316         if (!next_octet(pdu, len, &offset, &out->submit.udl))
1317                 return FALSE;
1318
1319         if ((len - offset) < out->submit.udl)
1320                 return FALSE;
1321
1322         pack_7bit_own_buf(pdu + offset, out->submit.udl, 0, FALSE,
1323                                 NULL, 0, out->submit.ud);
1324
1325         return TRUE;
1326 }
1327
1328 static gboolean decode_submit(const unsigned char *pdu, int len,
1329                                         struct sms *out)
1330 {
1331         unsigned char octet;
1332         int offset = 0;
1333         int expected;
1334
1335         out->type = SMS_TYPE_SUBMIT;
1336
1337         if (!next_octet(pdu, len, &offset, &octet))
1338                 return FALSE;
1339
1340         out->submit.rd = is_bit_set(octet, 2);
1341         out->submit.vpf = bit_field(octet, 3, 2);
1342         out->submit.rp = is_bit_set(octet, 7);
1343         out->submit.udhi = is_bit_set(octet, 6);
1344         out->submit.srr = is_bit_set(octet, 5);
1345
1346         if (!next_octet(pdu, len, &offset, &out->submit.mr))
1347                 return FALSE;
1348
1349         if (!sms_decode_address_field(pdu, len, &offset,
1350                                         FALSE, &out->submit.daddr))
1351                 return FALSE;
1352
1353         if (!next_octet(pdu, len, &offset, &out->submit.pid))
1354                 return FALSE;
1355
1356         if (!next_octet(pdu, len, &offset, &out->submit.dcs))
1357                 return FALSE;
1358
1359         if (!decode_validity_period(pdu, len, &offset, out->submit.vpf,
1360                                         &out->submit.vp))
1361                 return FALSE;
1362
1363         if (!next_octet(pdu, len, &offset, &out->submit.udl))
1364                 return FALSE;
1365
1366         expected = sms_udl_in_bytes(out->submit.udl, out->submit.dcs);
1367
1368         if ((len - offset) < expected)
1369                 return FALSE;
1370
1371         if (expected > (int) sizeof(out->submit.ud))
1372                 return FALSE;
1373
1374         memcpy(out->submit.ud, pdu+offset, expected);
1375
1376         return TRUE;
1377 }
1378
1379 static gboolean encode_command(const struct sms_command *in,
1380                                         unsigned char *pdu, int *offset)
1381 {
1382         unsigned char octet;
1383
1384         octet = 0x2;
1385
1386         if (in->udhi)
1387                 octet |= 1 << 6;
1388
1389         if (in->srr)
1390                 octet |= 1 << 5;
1391
1392         set_octet(pdu, offset, octet);
1393
1394         set_octet(pdu, offset, in->mr);
1395
1396         set_octet(pdu, offset, in->pid);
1397
1398         octet = in->ct;
1399         set_octet(pdu, offset, octet);
1400
1401         set_octet(pdu, offset, in->mn);
1402
1403         if (!sms_encode_address_field(&in->daddr, FALSE, pdu, offset))
1404                 return FALSE;
1405
1406         set_octet(pdu, offset, in->cdl);
1407
1408         memcpy(pdu + *offset, in->cd, in->cdl);
1409
1410         *offset = *offset + in->cdl;
1411
1412         return TRUE;
1413 }
1414
1415 static gboolean decode_command(const unsigned char *pdu, int len,
1416                                         struct sms *out)
1417 {
1418         unsigned char octet;
1419         int offset = 0;
1420
1421         out->type = SMS_TYPE_COMMAND;
1422
1423         if (!next_octet(pdu, len, &offset, &octet))
1424                 return FALSE;
1425
1426         out->command.udhi = is_bit_set(octet, 6);
1427         out->command.srr = is_bit_set(octet, 5);
1428
1429         if (!next_octet(pdu, len, &offset, &out->command.mr))
1430                 return FALSE;
1431
1432         if (!next_octet(pdu, len, &offset, &out->command.pid))
1433                 return FALSE;
1434
1435         if (!next_octet(pdu, len, &offset, &octet))
1436                 return FALSE;
1437
1438         out->command.ct = octet;
1439
1440         if (!next_octet(pdu, len, &offset, &out->command.mn))
1441                 return FALSE;
1442
1443         if (!sms_decode_address_field(pdu, len, &offset,
1444                                         FALSE, &out->command.daddr))
1445                 return FALSE;
1446
1447         if (!next_octet(pdu, len, &offset, &out->command.cdl))
1448                 return FALSE;
1449
1450         if ((len - offset) < out->command.cdl)
1451                 return FALSE;
1452
1453         memcpy(out->command.cd, pdu+offset, out->command.cdl);
1454
1455         return TRUE;
1456 }
1457
1458 /* Buffer must be at least 164 (tpud) + 12 (SC address) bytes long */
1459 gboolean sms_encode(const struct sms *in, int *len, int *tpdu_len,
1460                         unsigned char *pdu)
1461 {
1462         int offset = 0;
1463         int tpdu_start;
1464
1465         if (in->type == SMS_TYPE_DELIVER || in->type == SMS_TYPE_SUBMIT ||
1466                         in->type == SMS_TYPE_COMMAND ||
1467                         in->type == SMS_TYPE_STATUS_REPORT)
1468                 if (!sms_encode_address_field(&in->sc_addr, TRUE, pdu, &offset))
1469                         return FALSE;
1470
1471         tpdu_start = offset;
1472
1473         switch (in->type) {
1474         case SMS_TYPE_DELIVER:
1475                 if (encode_deliver(&in->deliver, pdu, &offset) == FALSE)
1476                         return FALSE;
1477                 break;
1478         case SMS_TYPE_DELIVER_REPORT_ACK:
1479                 if (!encode_deliver_ack_report(&in->deliver_ack_report, pdu,
1480                                                 &offset))
1481                         return FALSE;
1482                 break;
1483         case SMS_TYPE_DELIVER_REPORT_ERROR:
1484                 if (!encode_deliver_err_report(&in->deliver_err_report, pdu,
1485                                                 &offset))
1486                         return FALSE;
1487                 break;
1488         case SMS_TYPE_STATUS_REPORT:
1489                 if (!encode_status_report(&in->status_report, pdu, &offset))
1490                         return FALSE;
1491                 break;
1492         case SMS_TYPE_SUBMIT:
1493                 if (!encode_submit(&in->submit, pdu, &offset))
1494                         return FALSE;
1495                 break;
1496         case SMS_TYPE_SUBMIT_REPORT_ACK:
1497                 if (!encode_submit_ack_report(&in->submit_ack_report, pdu,
1498                                                 &offset))
1499                         return FALSE;
1500                 break;
1501         case SMS_TYPE_SUBMIT_REPORT_ERROR:
1502                 if (!encode_submit_err_report(&in->submit_err_report, pdu,
1503                                                 &offset))
1504                         return FALSE;
1505                 break;
1506         case SMS_TYPE_COMMAND:
1507                 if (!encode_command(&in->command, pdu, &offset))
1508                         return FALSE;
1509                 break;
1510         default:
1511                 return FALSE;
1512         };
1513
1514         if (tpdu_len)
1515                 *tpdu_len = offset - tpdu_start;
1516
1517         if (len)
1518                 *len = offset;
1519
1520         return TRUE;
1521 }
1522
1523 gboolean sms_decode(const unsigned char *pdu, int len, gboolean outgoing,
1524                         int tpdu_len, struct sms *out)
1525 {
1526         unsigned char type;
1527         int offset = 0;
1528
1529         if (out == NULL)
1530                 return FALSE;
1531
1532         if (len == 0)
1533                 return FALSE;
1534
1535         memset(out, 0, sizeof(*out));
1536
1537         if (tpdu_len < len) {
1538                 if (!sms_decode_address_field(pdu, len, &offset,
1539                                                 TRUE, &out->sc_addr))
1540                         return FALSE;
1541         }
1542
1543         if ((len - offset) < tpdu_len)
1544                 return FALSE;
1545
1546         /* 23.040 9.2.3.1 */
1547         type = pdu[offset] & 0x3;
1548
1549         if (outgoing)
1550                 type |= 0x4;
1551
1552         pdu = pdu + offset;
1553
1554         switch (type) {
1555         case 0:
1556                 return decode_deliver(pdu, tpdu_len, out);
1557         case 1:
1558                 return decode_submit_report(pdu, tpdu_len, out);
1559         case 2:
1560                 return decode_status_report(pdu, tpdu_len, out);
1561         case 3:
1562                 /* According to 9.2.3.1, Reserved treated as deliver */
1563                 return decode_deliver(pdu, tpdu_len, out);
1564         case 4:
1565                 return decode_deliver_report(pdu, tpdu_len, out);
1566         case 5:
1567                 return decode_submit(pdu, tpdu_len, out);
1568         case 6:
1569                 return decode_command(pdu, tpdu_len, out);
1570         }
1571
1572         return FALSE;
1573 }
1574
1575 const guint8 *sms_extract_common(const struct sms *sms, gboolean *out_udhi,
1576                                         guint8 *out_dcs, guint8 *out_udl,
1577                                         guint8 *out_max)
1578 {
1579         const guint8 *ud = NULL;
1580         guint8 uninitialized_var(udl);
1581         guint8 uninitialized_var(max);
1582         gboolean uninitialized_var(udhi);
1583         guint8 uninitialized_var(dcs);
1584
1585         switch (sms->type) {
1586         case SMS_TYPE_DELIVER:
1587                 udhi = sms->deliver.udhi;
1588                 ud = sms->deliver.ud;
1589                 udl = sms->deliver.udl;
1590                 dcs = sms->deliver.dcs;
1591                 max = sizeof(sms->deliver.ud);
1592                 break;
1593         case SMS_TYPE_DELIVER_REPORT_ACK:
1594                 udhi = sms->deliver_ack_report.udhi;
1595                 ud = sms->deliver_ack_report.ud;
1596                 udl = sms->deliver_ack_report.udl;
1597                 dcs = sms->deliver_ack_report.dcs;
1598                 max = sizeof(sms->deliver_ack_report.ud);
1599                 break;
1600         case SMS_TYPE_DELIVER_REPORT_ERROR:
1601                 udhi = sms->deliver_err_report.udhi;
1602                 ud = sms->deliver_err_report.ud;
1603                 udl = sms->deliver_err_report.udl;
1604                 dcs = sms->deliver_err_report.dcs;
1605                 max = sizeof(sms->deliver_err_report.ud);
1606                 break;
1607         case SMS_TYPE_STATUS_REPORT:
1608                 udhi = sms->status_report.udhi;
1609                 ud = sms->status_report.ud;
1610                 udl = sms->status_report.udl;
1611                 dcs = sms->status_report.dcs;
1612                 max = sizeof(sms->status_report.ud);
1613                 break;
1614         case SMS_TYPE_SUBMIT:
1615                 udhi = sms->submit.udhi;
1616                 ud = sms->submit.ud;
1617                 udl = sms->submit.udl;
1618                 dcs = sms->submit.dcs;
1619                 max = sizeof(sms->submit.ud);
1620                 break;
1621         case SMS_TYPE_SUBMIT_REPORT_ACK:
1622                 udhi = sms->submit_ack_report.udhi;
1623                 ud = sms->submit_ack_report.ud;
1624                 udl = sms->submit_ack_report.udl;
1625                 dcs = sms->submit_ack_report.dcs;
1626                 max = sizeof(sms->submit_ack_report.ud);
1627                 break;
1628         case SMS_TYPE_SUBMIT_REPORT_ERROR:
1629                 udhi = sms->submit_err_report.udhi;
1630                 ud = sms->submit_err_report.ud;
1631                 udl = sms->submit_err_report.udl;
1632                 dcs = sms->submit_err_report.dcs;
1633                 max = sizeof(sms->submit_err_report.ud);
1634                 break;
1635         case SMS_TYPE_COMMAND:
1636                 udhi = sms->command.udhi;
1637                 ud = sms->command.cd;
1638                 udl = sms->command.cdl;
1639                 dcs = 0;
1640                 max = sizeof(sms->command.cd);
1641                 break;
1642         };
1643
1644         if (ud == NULL)
1645                 return NULL;
1646
1647         if (out_udhi)
1648                 *out_udhi = udhi;
1649
1650         if (out_dcs)
1651                 *out_dcs = dcs;
1652
1653         if (out_udl)
1654                 *out_udl = udl;
1655
1656         if (out_max)
1657                 *out_max = max;
1658
1659         return ud;
1660 }
1661
1662 static gboolean verify_udh(const guint8 *hdr, guint8 max_len)
1663 {
1664         guint8 max_offset;
1665         guint8 offset;
1666
1667         /* Must have at least one information-element if udhi is true */
1668         if (hdr[0] < 2)
1669                 return FALSE;
1670
1671         if (hdr[0] >= max_len)
1672                 return FALSE;
1673
1674         /*
1675          * According to 23.040: If the length of the User Data Header is
1676          * such that there are too few or too many octets in the final
1677          * Information Element then the whole User Data Header shall be
1678          * ignored.
1679          */
1680
1681         max_offset = hdr[0] + 1;
1682         offset = 1;
1683         do {
1684                 if ((offset + 2) > max_offset)
1685                         return FALSE;
1686
1687                 if ((offset + 2 + hdr[offset + 1]) > max_offset)
1688                         return FALSE;
1689
1690                 offset = offset + 2 + hdr[offset + 1];
1691         } while (offset < max_offset);
1692
1693         if (offset != max_offset)
1694                 return FALSE;
1695
1696         return TRUE;
1697 }
1698
1699 gboolean sms_udh_iter_init(const struct sms *sms, struct sms_udh_iter *iter)
1700 {
1701         gboolean udhi = FALSE;
1702         const guint8 *hdr;
1703         guint8 udl;
1704         guint8 dcs;
1705         guint8 max_len;
1706         guint8 max_ud_len;
1707
1708         hdr = sms_extract_common(sms, &udhi, &dcs, &udl, &max_ud_len);
1709         if (hdr == NULL)
1710                 return FALSE;
1711
1712         if (!udhi)
1713                 return FALSE;
1714
1715         if (sms->type == SMS_TYPE_COMMAND)
1716                 max_len = udl;
1717         else
1718                 max_len = sms_udl_in_bytes(udl, dcs);
1719
1720         /* Can't actually store the HDL + IEI / IEL */
1721         if (max_len < 3)
1722                 return FALSE;
1723
1724         if (max_len > max_ud_len)
1725                 return FALSE;
1726
1727         if (!verify_udh(hdr, max_len))
1728                 return FALSE;
1729
1730         iter->data = hdr;
1731         iter->offset = 1;
1732
1733         return TRUE;
1734 }
1735
1736 gboolean sms_udh_iter_init_from_cbs(const struct cbs *cbs,
1737                                         struct sms_udh_iter *iter)
1738 {
1739         gboolean udhi = FALSE;
1740         const guint8 *hdr;
1741         guint8 max_ud_len;
1742
1743         cbs_dcs_decode(cbs->dcs, &udhi, NULL, NULL, NULL, NULL, NULL);
1744
1745         if (!udhi)
1746                 return FALSE;
1747
1748         hdr = cbs->ud;
1749         max_ud_len = 82;
1750
1751         /* Must have at least one information-element if udhi is true */
1752         if (hdr[0] < 2)
1753                 return FALSE;
1754
1755         if (hdr[0] >= max_ud_len)
1756                 return FALSE;
1757
1758         if (!verify_udh(hdr, max_ud_len))
1759                 return FALSE;
1760
1761         iter->data = hdr;
1762         iter->offset = 1;
1763
1764         return TRUE;
1765 }
1766 guint8 sms_udh_iter_get_udh_length(struct sms_udh_iter *iter)
1767 {
1768         return iter->data[0];
1769 }
1770
1771 const guint8 *sms_udh_iter_get_ud_after_header(struct sms_udh_iter *iter)
1772 {
1773         return iter->data + iter->data[0] + 1;
1774 }
1775
1776 enum sms_iei sms_udh_iter_get_ie_type(struct sms_udh_iter *iter)
1777 {
1778         if (iter->offset > iter->data[0])
1779                 return SMS_IEI_INVALID;
1780
1781         return (enum sms_iei) iter->data[iter->offset];
1782 }
1783
1784 guint8 sms_udh_iter_get_ie_length(struct sms_udh_iter *iter)
1785 {
1786         guint8 ie_len;
1787
1788         ie_len = iter->data[iter->offset + 1];
1789
1790         return ie_len;
1791 }
1792
1793 void sms_udh_iter_get_ie_data(struct sms_udh_iter *iter, guint8 *data)
1794 {
1795         guint8 ie_len;
1796
1797         ie_len = iter->data[iter->offset + 1];
1798
1799         memcpy(data, &iter->data[iter->offset + 2], ie_len);
1800 }
1801
1802 gboolean sms_udh_iter_has_next(struct sms_udh_iter *iter)
1803 {
1804         guint8 total_len = iter->data[0];
1805         guint8 cur_ie_len = iter->data[iter->offset + 1];
1806
1807         if ((iter->offset + 2 + cur_ie_len) > total_len)
1808                 return FALSE;
1809
1810         return TRUE;
1811 }
1812
1813 gboolean sms_udh_iter_next(struct sms_udh_iter *iter)
1814 {
1815         if (iter->offset > iter->data[0])
1816                 return FALSE;
1817
1818         iter->offset = iter->offset + 2 + iter->data[iter->offset + 1];
1819
1820         if (iter->offset > iter->data[0])
1821                 return FALSE;
1822
1823         return TRUE;
1824 }
1825
1826 /*
1827  * Returns both forms of time.  The time_t value returns the time in local
1828  * timezone.  The struct tm is filled out with the remote time information
1829  */
1830 time_t sms_scts_to_time(const struct sms_scts *scts, struct tm *remote)
1831 {
1832         struct tm t;
1833         time_t ret;
1834
1835         t.tm_sec = scts->second;
1836         t.tm_min = scts->minute;
1837         t.tm_hour = scts->hour;
1838         t.tm_mday = scts->day;
1839         t.tm_mon = scts->month - 1;
1840         t.tm_isdst = -1;
1841
1842         if (scts->year > 80)
1843                 t.tm_year = scts->year;
1844         else
1845                 t.tm_year = scts->year + 100;
1846
1847         ret = mktime(&t);
1848
1849         /* Adjust local time by the local timezone information */
1850         ret += t.tm_gmtoff;
1851
1852         /* Set the proper timezone on the remote side */
1853         t.tm_gmtoff = scts->timezone * 15 * 60;
1854
1855         /* Now adjust by the remote timezone information */
1856         ret -= t.tm_gmtoff;
1857
1858         if (remote)
1859                 memcpy(remote, &t, sizeof(struct tm));
1860
1861         return ret;
1862 }
1863
1864 void sms_address_from_string(struct sms_address *addr, const char *str)
1865 {
1866         addr->numbering_plan = SMS_NUMBERING_PLAN_ISDN;
1867         if (str[0] == '+') {
1868                 addr->number_type = SMS_NUMBER_TYPE_INTERNATIONAL;
1869                 strcpy(addr->address, str+1);
1870         } else {
1871                 addr->number_type = SMS_NUMBER_TYPE_UNKNOWN;
1872                 strcpy(addr->address, str);
1873         }
1874 }
1875
1876 const char *sms_address_to_string(const struct sms_address *addr)
1877 {
1878         static char buffer[64];
1879
1880         if (addr->number_type == SMS_NUMBER_TYPE_INTERNATIONAL &&
1881                         (strlen(addr->address) > 0) &&
1882                                 addr->address[0] != '+') {
1883                 buffer[0] = '+';
1884                 strcpy(buffer + 1, addr->address);
1885         } else {
1886                 strcpy(buffer, addr->address);
1887         }
1888
1889         return buffer;
1890 }
1891
1892 static gboolean extract_app_port_common(struct sms_udh_iter *iter, int *dst,
1893                                         int *src, gboolean *is_8bit)
1894 {
1895         enum sms_iei iei;
1896         guint8 addr_hdr[4];
1897         int srcport = -1;
1898         int dstport = -1;
1899         gboolean uninitialized_var(is_addr_8bit);
1900
1901         /*
1902          * According to the specification, we have to use the last
1903          * useable header.  Also, we have to ignore ports that are reserved:
1904          * A receiving entity shall ignore (i.e. skip over and commence
1905          * processing at the next information element) any information element
1906          * where the value of the Information-Element-Data is Reserved or not
1907          * supported.
1908          */
1909         while ((iei = sms_udh_iter_get_ie_type(iter)) !=
1910                         SMS_IEI_INVALID) {
1911                 switch (iei) {
1912                 case SMS_IEI_APPLICATION_ADDRESS_8BIT:
1913                         if (sms_udh_iter_get_ie_length(iter) != 2)
1914                                 break;
1915
1916                         sms_udh_iter_get_ie_data(iter, addr_hdr);
1917
1918                         if (addr_hdr[0] < 240)
1919                                 break;
1920
1921                         if (addr_hdr[1] < 240)
1922                                 break;
1923
1924                         dstport = addr_hdr[0];
1925                         srcport = addr_hdr[1];
1926                         is_addr_8bit = TRUE;
1927                         break;
1928
1929                 case SMS_IEI_APPLICATION_ADDRESS_16BIT:
1930                         if (sms_udh_iter_get_ie_length(iter) != 4)
1931                                 break;
1932
1933                         sms_udh_iter_get_ie_data(iter, addr_hdr);
1934
1935                         if (((addr_hdr[0] << 8) | addr_hdr[1]) > 49151)
1936                                 break;
1937
1938                         if (((addr_hdr[2] << 8) | addr_hdr[3]) > 49151)
1939                                 break;
1940
1941                         dstport = (addr_hdr[0] << 8) | addr_hdr[1];
1942                         srcport = (addr_hdr[2] << 8) | addr_hdr[3];
1943                         is_addr_8bit = FALSE;
1944                         break;
1945
1946                 default:
1947                         break;
1948                 }
1949
1950                 sms_udh_iter_next(iter);
1951         }
1952
1953         if (dstport == -1 || srcport == -1)
1954                 return FALSE;
1955
1956         if (dst)
1957                 *dst = dstport;
1958
1959         if (src)
1960                 *src = srcport;
1961
1962         if (is_8bit)
1963                 *is_8bit = is_addr_8bit;
1964
1965         return TRUE;
1966
1967 }
1968
1969 gboolean sms_extract_app_port(const struct sms *sms, int *dst, int *src,
1970                                 gboolean *is_8bit)
1971 {
1972         struct sms_udh_iter iter;
1973
1974         if (!sms_udh_iter_init(sms, &iter))
1975                 return FALSE;
1976
1977         return extract_app_port_common(&iter, dst, src, is_8bit);
1978 }
1979
1980 gboolean sms_extract_concatenation(const struct sms *sms, guint16 *ref_num,
1981                                         guint8 *max_msgs, guint8 *seq_num)
1982 {
1983         struct sms_udh_iter iter;
1984         enum sms_iei iei;
1985         guint8 concat_hdr[4];
1986         guint16 uninitialized_var(rn);
1987         guint8 uninitialized_var(max), uninitialized_var(seq);
1988         gboolean concatenated = FALSE;
1989
1990         /*
1991          * We must ignore the entire user_data header here:
1992          * If the length of the User Data Header is such that there
1993          * are too few or too many octets in the final Information
1994          * Element then the whole User Data Header shall be ignored.
1995          */
1996         if (!sms_udh_iter_init(sms, &iter))
1997                 return FALSE;
1998
1999         /*
2000          * According to the specification, we have to use the last
2001          * useable header:
2002          * In the event that IEs determined as not repeatable are
2003          * duplicated, the last occurrence of the IE shall be used.
2004          * In the event that two or more IEs occur which have mutually
2005          * exclusive meanings (e.g. an 8bit port address and a 16bit
2006          * port address), then the last occurring IE shall be used.
2007          */
2008         while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
2009                         SMS_IEI_INVALID) {
2010                 switch (iei) {
2011                 case SMS_IEI_CONCATENATED_8BIT:
2012                         if (sms_udh_iter_get_ie_length(&iter) != 3)
2013                                 break;
2014
2015                         sms_udh_iter_get_ie_data(&iter, concat_hdr);
2016
2017                         if (concat_hdr[1] == 0)
2018                                 break;
2019
2020                         if (concat_hdr[2] == 0 || concat_hdr[2] > concat_hdr[1])
2021                                 break;
2022
2023                         rn = concat_hdr[0];
2024                         max = concat_hdr[1];
2025                         seq = concat_hdr[2];
2026                         concatenated = TRUE;
2027                         break;
2028
2029                 case SMS_IEI_CONCATENATED_16BIT:
2030                         if (sms_udh_iter_get_ie_length(&iter) != 4)
2031                                 break;
2032
2033                         sms_udh_iter_get_ie_data(&iter, concat_hdr);
2034
2035                         if (concat_hdr[2] == 0)
2036                                 break;
2037
2038                         if (concat_hdr[3] == 0 ||
2039                                         concat_hdr[3] > concat_hdr[2])
2040                                 break;
2041
2042                         rn = (concat_hdr[0] << 8) | concat_hdr[1];
2043                         max = concat_hdr[2];
2044                         seq = concat_hdr[3];
2045                         concatenated = TRUE;
2046                         break;
2047                 default:
2048                         break;
2049                 }
2050
2051                 sms_udh_iter_next(&iter);
2052         }
2053
2054         if (!concatenated)
2055                 return FALSE;
2056
2057         if (ref_num)
2058                 *ref_num = rn;
2059
2060         if (max_msgs)
2061                 *max_msgs = max;
2062
2063         if (seq_num)
2064                 *seq_num = seq;
2065
2066         return TRUE;
2067 }
2068
2069 gboolean sms_extract_language_variant(const struct sms *sms, guint8 *locking,
2070                                         guint8 *single)
2071 {
2072         struct sms_udh_iter iter;
2073         enum sms_iei iei;
2074         guint8 variant;
2075
2076         /*
2077          * We must ignore the entire user_data header here:
2078          * If the length of the User Data Header is such that there
2079          * are too few or too many octets in the final Information
2080          * Element then the whole User Data Header shall be ignored.
2081          */
2082         if (!sms_udh_iter_init(sms, &iter))
2083                 return FALSE;
2084
2085         /*
2086          * According to the specification, we have to use the last
2087          * useable header:
2088          * In the event that IEs determined as not repeatable are
2089          * duplicated, the last occurrence of the IE shall be used.
2090          * In the event that two or more IEs occur which have mutually
2091          * exclusive meanings (e.g. an 8bit port address and a 16bit
2092          * port address), then the last occurring IE shall be used.
2093          */
2094         while ((iei = sms_udh_iter_get_ie_type(&iter)) !=
2095                         SMS_IEI_INVALID) {
2096                 switch (iei) {
2097                 case SMS_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT:
2098                         if (sms_udh_iter_get_ie_length(&iter) != 1)
2099                                 break;
2100
2101                         sms_udh_iter_get_ie_data(&iter, &variant);
2102                         if (single)
2103                                 *single = variant;
2104                         break;
2105
2106                 case SMS_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT:
2107                         if (sms_udh_iter_get_ie_length(&iter) != 1)
2108                                 break;
2109
2110                         sms_udh_iter_get_ie_data(&iter, &variant);
2111                         if (locking)
2112                                 *locking = variant;
2113                         break;
2114                 default:
2115                         break;
2116                 }
2117
2118                 sms_udh_iter_next(&iter);
2119         }
2120
2121         return TRUE;
2122 }
2123
2124 /*!
2125  * Decodes a list of SMSes that contain a datagram.  The list must be
2126  * sorted in order of the sequence number.  This function assumes that
2127  * all fragments are coded using 8-bit character set.
2128  *
2129  * Returns a pointer to a newly allocated array or NULL if the
2130  * conversion could not be performed
2131  */
2132 unsigned char *sms_decode_datagram(GSList *sms_list, long *out_len)
2133 {
2134         GSList *l;
2135         const struct sms *sms;
2136         unsigned char *buf;
2137         long len = 0;
2138
2139         for (l = sms_list; l; l = l->next) {
2140                 guint8 taken = 0;
2141                 guint8 udl;
2142                 const guint8 *ud;
2143                 struct sms_udh_iter iter;
2144
2145                 sms = l->data;
2146
2147                 ud = sms_extract_common(sms, NULL, NULL, &udl, NULL);
2148                 if (ud == NULL)
2149                         return NULL;
2150
2151                 /*
2152                  * Note we do this because we must check whether the UDH
2153                  * is properly formatted.  If not, the entire UDH is ignored
2154                  */
2155                 if (sms_udh_iter_init(sms, &iter))
2156                         taken = sms_udh_iter_get_udh_length(&iter) + 1;
2157
2158                 len += udl - taken;
2159         }
2160
2161         /* Data is probably in headers we can't understand */
2162         if (len == 0)
2163                 return NULL;
2164
2165         buf = g_try_new(unsigned char, len);
2166         if (buf == NULL)
2167                 return NULL;
2168
2169         len = 0;
2170         for (l = sms_list; l; l = l->next) {
2171                 guint8 taken = 0;
2172                 guint8 udl;
2173                 const guint8 *ud;
2174                 struct sms_udh_iter iter;
2175
2176                 sms = l->data;
2177
2178                 ud = sms_extract_common(sms, NULL, NULL, &udl, NULL);
2179
2180                 if (sms_udh_iter_init(sms, &iter))
2181                         taken = sms_udh_iter_get_udh_length(&iter) + 1;
2182
2183                 memcpy(buf + len, ud + taken, udl - taken);
2184                 len += udl - taken;
2185         }
2186
2187         if (out_len)
2188                 *out_len = len;
2189
2190         return buf;
2191 }
2192
2193 static inline int sms_text_capacity_gsm(int max, int offset)
2194 {
2195         return max - (offset * 8 + 6) / 7;
2196 }
2197
2198 /*!
2199  * Decodes a list of SMSes that contain a text in either 7bit or UCS2 encoding.
2200  * The list must be sorted in order of the sequence number.  This function
2201  * assumes that all fragments have a proper DCS.
2202  *
2203  * Returns a pointer to a newly allocated string or NULL if the conversion
2204  * failed.
2205  */
2206 char *sms_decode_text(GSList *sms_list)
2207 {
2208         GSList *l;
2209         GString *str;
2210         const struct sms *sms;
2211         int guess_size = g_slist_length(sms_list);
2212         char *utf8;
2213
2214         if (guess_size == 1)
2215                 guess_size = 160;
2216         else
2217                 guess_size = (guess_size - 1) * 160;
2218
2219         str = g_string_sized_new(guess_size);
2220
2221         for (l = sms_list; l; l = l->next) {
2222                 guint8 taken = 0;
2223                 guint8 dcs;
2224                 guint8 udl;
2225                 enum sms_charset charset;
2226                 int udl_in_bytes;
2227                 const guint8 *ud;
2228                 struct sms_udh_iter iter;
2229                 char *converted;
2230
2231                 sms = l->data;
2232
2233                 ud = sms_extract_common(sms, NULL, &dcs, &udl, NULL);
2234
2235                 if (!sms_mwi_dcs_decode(dcs, NULL, &charset, NULL, NULL) &&
2236                         !sms_dcs_decode(dcs, NULL, &charset, NULL, NULL))
2237                         continue;
2238
2239                 if (charset == SMS_CHARSET_8BIT)
2240                         continue;
2241
2242                 if (sms_udh_iter_init(sms, &iter))
2243                         taken = sms_udh_iter_get_udh_length(&iter) + 1;
2244
2245                 udl_in_bytes = sms_udl_in_bytes(udl, dcs);
2246
2247                 if (udl_in_bytes == taken)
2248                         continue;
2249
2250                 if (charset == SMS_CHARSET_7BIT) {
2251                         unsigned char buf[160];
2252                         long written;
2253                         guint8 locking_shift = 0;
2254                         guint8 single_shift = 0;
2255                         int max_chars = sms_text_capacity_gsm(udl, taken);
2256
2257                         if (unpack_7bit_own_buf(ud + taken,
2258                                                 udl_in_bytes - taken,
2259                                                 taken, FALSE, max_chars,
2260                                                 &written, 0, buf) == NULL)
2261                                 continue;
2262
2263                         /* Take care of improperly split fragments */
2264                         if (buf[written-1] == 0x1b)
2265                                 written = written - 1;
2266
2267                         sms_extract_language_variant(sms, &locking_shift,
2268                                                                 &single_shift);
2269
2270                         /*
2271                          * If language is not defined in 3GPP TS 23.038,
2272                          * implementations are instructed to ignore it
2273                          */
2274                         if (locking_shift > SMS_ALPHABET_PORTUGUESE)
2275                                 locking_shift = GSM_DIALECT_DEFAULT;
2276
2277                         if (single_shift > SMS_ALPHABET_PORTUGUESE)
2278                                 single_shift = GSM_DIALECT_DEFAULT;
2279
2280                         converted = convert_gsm_to_utf8_with_lang(buf, written,
2281                                                                 NULL, NULL, 0,
2282                                                                 locking_shift,
2283                                                                 single_shift);
2284                 } else {
2285                         const gchar *from = (const gchar *) (ud + taken);
2286                         /*
2287                          * According to the spec: A UCS2 character shall not be
2288                          * split in the middle; if the length of the User Data
2289                          * Header is odd, the maximum length of the whole TP-UD
2290                          * field is 139 octets
2291                          */
2292                         gssize num_ucs2_chars = (udl_in_bytes - taken) >> 1;
2293                         num_ucs2_chars = num_ucs2_chars << 1;
2294
2295                         converted = g_convert(from, num_ucs2_chars,
2296                                                 "UTF-8//TRANSLIT", "UCS-2BE",
2297                                                 NULL, NULL, NULL);
2298                 }
2299
2300                 if (converted) {
2301                         g_string_append(str, converted);
2302                         g_free(converted);
2303                 }
2304         }
2305
2306         utf8 = g_string_free(str, FALSE);
2307
2308         return utf8;
2309 }
2310
2311 static int sms_serialize(unsigned char *buf, const struct sms *sms)
2312 {
2313         int len, tpdu_len;
2314
2315         sms_encode(sms, &len, &tpdu_len, buf + 1);
2316         buf[0] = tpdu_len;
2317
2318         return len + 1;
2319 }
2320
2321 static gboolean sms_deserialize(const unsigned char *buf,
2322                 struct sms *sms, int len)
2323 {
2324         if (len < 1)
2325                 return FALSE;
2326
2327         return sms_decode(buf + 1, len - 1, FALSE, buf[0], sms);
2328 }
2329
2330 static gboolean sms_deserialize_outgoing(const unsigned char *buf,
2331                 struct sms *sms, int len)
2332 {
2333         if (len < 1)
2334                 return FALSE;
2335
2336         return sms_decode(buf + 1, len - 1, TRUE, buf[0], sms);
2337 }
2338
2339 static gboolean sms_assembly_extract_address(const char *straddr,
2340                                                 struct sms_address *out)
2341 {
2342         unsigned char pdu[12];
2343         long len;
2344         int offset = 0;
2345
2346         if (decode_hex_own_buf(straddr, -1, &len, 0, pdu) == NULL)
2347                 return FALSE;
2348
2349         return sms_decode_address_field(pdu, len, &offset, FALSE, out);
2350 }
2351
2352 gboolean sms_address_to_hex_string(const struct sms_address *in, char *straddr)
2353 {
2354         unsigned char pdu[12];
2355         int offset = 0;
2356
2357         if (sms_encode_address_field(in, FALSE, pdu, &offset) == FALSE)
2358                 return FALSE;
2359
2360         if (encode_hex_own_buf(pdu, offset, 0, straddr) == NULL)
2361                 return FALSE;
2362
2363         straddr[offset * 2 + 1] = '\0';
2364
2365         return TRUE;
2366 }
2367
2368 static void sms_assembly_load(struct sms_assembly *assembly,
2369                                 const struct dirent *dir)
2370 {
2371         struct sms_address addr;
2372         DECLARE_SMS_ADDR_STR(straddr);
2373         guint16 ref;
2374         guint8 max;
2375         guint8 seq;
2376         char *path;
2377         int len;
2378         struct stat segment_stat;
2379         struct dirent **segments;
2380         char *endp;
2381         int r;
2382         int i;
2383         unsigned char buf[177];
2384         struct sms segment;
2385
2386         if (dir->d_type != DT_DIR)
2387                 return;
2388
2389         /* Max of SMS address size is 12 bytes, hex encoded */
2390         if (sscanf(dir->d_name, SMS_ADDR_FMT "-%hi-%hhi",
2391                                 straddr, &ref, &max) < 3)
2392                 return;
2393
2394         if (sms_assembly_extract_address(straddr, &addr) == FALSE)
2395                 return;
2396
2397         path = g_strdup_printf(SMS_BACKUP_PATH "/%s",
2398                         assembly->imsi, dir->d_name);
2399         len = scandir(path, &segments, NULL, versionsort);
2400         g_free(path);
2401
2402         if (len < 0)
2403                 return;
2404
2405         for (i = 0; i < len; i++) {
2406                 if (segments[i]->d_type != DT_REG)
2407                         continue;
2408
2409                 seq = strtol(segments[i]->d_name, &endp, 10);
2410                 if (*endp != '\0')
2411                         continue;
2412
2413                 r = read_file(buf, sizeof(buf), SMS_BACKUP_PATH "/%s/%s",
2414                                 assembly->imsi,
2415                                 dir->d_name, segments[i]->d_name);
2416                 if (r < 0)
2417                         continue;
2418
2419                 if (!sms_deserialize(buf, &segment, r))
2420                         continue;
2421
2422                 path = g_strdup_printf(SMS_BACKUP_PATH "/%s/%s",
2423                                 assembly->imsi,
2424                                 dir->d_name, segments[i]->d_name);
2425                 r = stat(path, &segment_stat);
2426                 g_free(path);
2427
2428                 if (r != 0)
2429                         continue;
2430
2431                 /* Errors cannot occur here */
2432                 sms_assembly_add_fragment_backup(assembly, &segment,
2433                                                 segment_stat.st_mtime,
2434                                                 &addr, ref, max, seq, FALSE);
2435         }
2436
2437         for (i = 0; i < len; i++)
2438                 free(segments[i]);
2439
2440         free(segments);
2441 }
2442
2443 static gboolean sms_assembly_store(struct sms_assembly *assembly,
2444                                 struct sms_assembly_node *node,
2445                                 const struct sms *sms, guint8 seq)
2446 {
2447         unsigned char buf[177];
2448         int len;
2449         DECLARE_SMS_ADDR_STR(straddr);
2450
2451         if (assembly->imsi == NULL)
2452                 return FALSE;
2453
2454         if (sms_address_to_hex_string(&node->addr, straddr) == FALSE)
2455                 return FALSE;
2456
2457         len = sms_serialize(buf, sms);
2458
2459         if (write_file(buf, len, SMS_BACKUP_MODE,
2460                                 SMS_BACKUP_PATH_FILE, assembly->imsi, straddr,
2461                                 node->ref, node->max_fragments, seq) != len)
2462                 return FALSE;
2463
2464         return TRUE;
2465 }
2466
2467 static void sms_assembly_backup_free(struct sms_assembly *assembly,
2468                                         struct sms_assembly_node *node)
2469 {
2470         char *path;
2471         int seq;
2472         DECLARE_SMS_ADDR_STR(straddr);
2473
2474         if (assembly->imsi == NULL)
2475                 return;
2476
2477         if (sms_address_to_hex_string(&node->addr, straddr) == FALSE)
2478                 return;
2479
2480         for (seq = 0; seq < node->max_fragments; seq++) {
2481                 int offset = seq / 32;
2482                 int bit = 1 << (seq % 32);
2483
2484                 if (node->bitmap[offset] & bit) {
2485                         path = g_strdup_printf(SMS_BACKUP_PATH_FILE,
2486                                         assembly->imsi, straddr,
2487                                         node->ref, node->max_fragments, seq);
2488                         unlink(path);
2489                         g_free(path);
2490                 }
2491         }
2492
2493         path = g_strdup_printf(SMS_BACKUP_PATH_DIR, assembly->imsi, straddr,
2494                                 node->ref, node->max_fragments);
2495         rmdir(path);
2496         g_free(path);
2497 }
2498
2499 struct sms_assembly *sms_assembly_new(const char *imsi)
2500 {
2501         struct sms_assembly *ret = g_new0(struct sms_assembly, 1);
2502         char *path;
2503         struct dirent **entries;
2504         int len;
2505
2506         if (imsi) {
2507                 ret->imsi = imsi;
2508
2509                 /* Restore state from backup */
2510
2511                 path = g_strdup_printf(SMS_BACKUP_PATH, imsi);
2512                 len = scandir(path, &entries, NULL, alphasort);
2513                 g_free(path);
2514
2515                 if (len < 0)
2516                         return ret;
2517
2518                 while (len--) {
2519                         sms_assembly_load(ret, entries[len]);
2520                         free(entries[len]);
2521                 }
2522
2523                 free(entries);
2524         }
2525
2526         return ret;
2527 }
2528
2529 void sms_assembly_free(struct sms_assembly *assembly)
2530 {
2531         GSList *l;
2532
2533         for (l = assembly->assembly_list; l; l = l->next) {
2534                 struct sms_assembly_node *node = l->data;
2535
2536                 g_slist_foreach(node->fragment_list, (GFunc) g_free, 0);
2537                 g_slist_free(node->fragment_list);
2538                 g_free(node);
2539         }
2540
2541         g_slist_free(assembly->assembly_list);
2542         g_free(assembly);
2543 }
2544
2545 GSList *sms_assembly_add_fragment(struct sms_assembly *assembly,
2546                                         const struct sms *sms, time_t ts,
2547                                         const struct sms_address *addr,
2548                                         guint16 ref, guint8 max, guint8 seq)
2549 {
2550         return sms_assembly_add_fragment_backup(assembly, sms,
2551                                                 ts, addr, ref, max, seq, TRUE);
2552 }
2553
2554 static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
2555                                         const struct sms *sms, time_t ts,
2556                                         const struct sms_address *addr,
2557                                         guint16 ref, guint8 max, guint8 seq,
2558                                         gboolean backup)
2559 {
2560         unsigned int offset = seq / 32;
2561         unsigned int bit = 1 << (seq % 32);
2562         GSList *l;
2563         GSList *prev;
2564         struct sms *newsms;
2565         struct sms_assembly_node *node;
2566         GSList *completed;
2567         unsigned int position;
2568         unsigned int i;
2569         unsigned int j;
2570
2571         prev = NULL;
2572
2573         for (l = assembly->assembly_list; l; prev = l, l = l->next) {
2574                 node = l->data;
2575
2576                 if (node->addr.number_type != addr->number_type)
2577                         continue;
2578
2579                 if (node->addr.numbering_plan != addr->numbering_plan)
2580                         continue;
2581
2582                 if (strcmp(node->addr.address, addr->address))
2583                         continue;
2584
2585                 if (ref != node->ref)
2586                         continue;
2587
2588                 /*
2589                  * Message Reference and address the same, but max is not
2590                  * ignore the SMS completely
2591                  */
2592                 if (max != node->max_fragments)
2593                         return NULL;
2594
2595                 /* Now check if we already have this seq number */
2596                 if (node->bitmap[offset] & bit)
2597                         return NULL;
2598
2599                 /*
2600                  * Iterate over the bitmap to find in which position
2601                  * should the fragment be inserted -- basically we
2602                  * walk each bit in the bitmap until the bit we care
2603                  * about (offset:bit) and count which are stored --
2604                  * that gives us in which position we have to insert.
2605                  */
2606                 position = 0;
2607                 for (i = 0; i < offset; i++)
2608                         for (j = 0; j < 32; j++)
2609                                 if (node->bitmap[i] & (1 << j))
2610                                         position += 1;
2611
2612                 for (j = 1; j < bit; j = j << 1)
2613                         if (node->bitmap[offset] & j)
2614                                 position += 1;
2615
2616                 goto out;
2617         }
2618
2619         node = g_new0(struct sms_assembly_node, 1);
2620         memcpy(&node->addr, addr, sizeof(struct sms_address));
2621         node->ts = ts;
2622         node->ref = ref;
2623         node->max_fragments = max;
2624
2625         assembly->assembly_list = g_slist_prepend(assembly->assembly_list,
2626                                                         node);
2627
2628         prev = NULL;
2629         l = assembly->assembly_list;
2630         position = 0;
2631
2632 out:
2633         newsms = g_new(struct sms, 1);
2634
2635         memcpy(newsms, sms, sizeof(struct sms));
2636         node->fragment_list = g_slist_insert(node->fragment_list,
2637                                                 newsms, position);
2638         node->bitmap[offset] |= bit;
2639         node->num_fragments += 1;
2640
2641         if (node->num_fragments < node->max_fragments) {
2642                 if (backup)
2643                         sms_assembly_store(assembly, node, sms, seq);
2644
2645                 return NULL;
2646         }
2647
2648         completed = node->fragment_list;
2649
2650         sms_assembly_backup_free(assembly, node);
2651
2652         if (prev)
2653                 prev->next = l->next;
2654         else
2655                 assembly->assembly_list = l->next;
2656
2657         g_free(node);
2658         g_slist_free_1(l);
2659         return completed;
2660 }
2661
2662 /*!
2663  * Expires all incomplete messages that have been received at time prior
2664  * to one given by before argument.  The fragment list is freed and the
2665  * SMSes are vaporized.
2666  */
2667 void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
2668 {
2669         GSList *cur;
2670         GSList *prev;
2671         GSList *tmp;
2672
2673         prev = NULL;
2674         cur = assembly->assembly_list;
2675
2676         while (cur) {
2677                 struct sms_assembly_node *node = cur->data;
2678
2679                 if (node->ts > before) {
2680                         prev = cur;
2681                         cur = cur->next;
2682                         continue;
2683                 }
2684
2685                 sms_assembly_backup_free(assembly, node);
2686
2687                 g_slist_foreach(node->fragment_list, (GFunc) g_free, 0);
2688                 g_slist_free(node->fragment_list);
2689                 g_free(node);
2690
2691                 if (prev)
2692                         prev->next = cur->next;
2693                 else
2694                         assembly->assembly_list = cur->next;
2695
2696                 tmp = cur;
2697                 cur = cur->next;
2698                 g_slist_free_1(tmp);
2699         }
2700 }
2701
2702 static gboolean sha1_equal(gconstpointer v1, gconstpointer v2)
2703 {
2704         return memcmp(v1, v2, SMS_MSGID_LEN) == 0;
2705 }
2706
2707 static guint sha1_hash(gconstpointer v)
2708 {
2709         guint h;
2710
2711         memcpy(&h, v, sizeof(h));
2712
2713         return h;
2714 }
2715
2716 static void sr_assembly_load_backup(GHashTable *assembly_table,
2717                                         const char *imsi,
2718                                         const struct dirent *addr_dir)
2719 {
2720         struct sms_address addr;
2721         DECLARE_SMS_ADDR_STR(straddr);
2722         struct id_table_node *node;
2723         GHashTable *id_table;
2724         int r;
2725         char *assembly_table_key;
2726         unsigned int *id_table_key;
2727         char msgid_str[SMS_MSGID_LEN * 2 + 1];
2728         unsigned char msgid[SMS_MSGID_LEN];
2729         char endc;
2730
2731         if (addr_dir->d_type != DT_REG)
2732                 return;
2733
2734         /*
2735          * All SMS-messages under the same IMSI-code are
2736          * included in the same directory.
2737          * So, SMS-address and message ID are included in the same file name
2738          * Max of SMS address size is 12 bytes, hex encoded
2739          * Max of SMS SHA1 hash is 20 bytes, hex encoded
2740          */
2741         if (sscanf(addr_dir->d_name, SMS_ADDR_FMT "-" SMS_MSGID_FMT "%c",
2742                                 straddr, msgid_str, &endc) != 2)
2743                 return;
2744
2745         if (sms_assembly_extract_address(straddr, &addr) == FALSE)
2746                 return;
2747
2748         if (strlen(msgid_str) != 2 * SMS_MSGID_LEN)
2749                 return;
2750
2751         if (decode_hex_own_buf(msgid_str, 2 * SMS_MSGID_LEN,
2752                                 NULL, 0, msgid) == NULL)
2753                 return;
2754
2755         node = g_new0(struct id_table_node, 1);
2756
2757         r = read_file((unsigned char *) node,
2758                         sizeof(struct id_table_node),
2759                         SMS_SR_BACKUP_PATH "/%s",
2760                         imsi, addr_dir->d_name);
2761
2762         if (r < 0) {
2763                 g_free(node);
2764                 return;
2765         }
2766
2767         id_table = g_hash_table_lookup(assembly_table,
2768                                         sms_address_to_string(&addr));
2769
2770         /* Create hashtable keyed by the to address if required */
2771         if (id_table == NULL) {
2772                 id_table = g_hash_table_new_full(sha1_hash, sha1_equal,
2773                                                         g_free, g_free);
2774
2775                 assembly_table_key = g_strdup(sms_address_to_string(&addr));
2776                 g_hash_table_insert(assembly_table, assembly_table_key,
2777                                         id_table);
2778         }
2779
2780         /* Node ready, create key and add them to the table */
2781         id_table_key = g_memdup(msgid, SMS_MSGID_LEN);
2782
2783         g_hash_table_insert(id_table, id_table_key, node);
2784 }
2785
2786 struct status_report_assembly *status_report_assembly_new(const char *imsi)
2787 {
2788         char *path;
2789         int len;
2790         struct dirent **addresses;
2791         struct status_report_assembly *ret =
2792                                 g_new0(struct status_report_assembly, 1);
2793
2794         ret->assembly_table = g_hash_table_new_full(g_str_hash, g_str_equal,
2795                                 g_free, (GDestroyNotify) g_hash_table_destroy);
2796
2797         if (imsi) {
2798                 ret->imsi = imsi;
2799
2800                 /* Restore state from backup */
2801                 path = g_strdup_printf(SMS_SR_BACKUP_PATH, imsi);
2802                 len = scandir(path, &addresses, NULL, alphasort);
2803
2804                 g_free(path);
2805
2806                 if (len < 0)
2807                         return ret;
2808
2809                 /*
2810                  * Go through different addresses. Each address can relate to
2811                  * 1-n msg_ids.
2812                  */
2813
2814                 while (len--) {
2815                         sr_assembly_load_backup(ret->assembly_table, imsi,
2816                                                                 addresses[len]);
2817                         g_free(addresses[len]);
2818                 }
2819
2820                 g_free(addresses);
2821         }
2822
2823         return ret;
2824 }
2825
2826 static gboolean sr_assembly_add_fragment_backup(const char *imsi,
2827                                         const struct id_table_node *node,
2828                                         const struct sms_address *addr,
2829                                         const unsigned char *msgid)
2830 {
2831         int len = sizeof(struct id_table_node);
2832         DECLARE_SMS_ADDR_STR(straddr);
2833         char msgid_str[SMS_MSGID_LEN * 2 + 1];
2834
2835         if (imsi == NULL)
2836                 return FALSE;
2837
2838         if (sms_address_to_hex_string(addr, straddr) == FALSE)
2839                 return FALSE;
2840
2841         if (encode_hex_own_buf(msgid, SMS_MSGID_LEN, 0, msgid_str) == NULL)
2842                 return FALSE;
2843
2844         /* storagedir/%s/sms_sr/%s-%s */
2845         if (write_file((unsigned char *) node, len, SMS_BACKUP_MODE,
2846                         SMS_SR_BACKUP_PATH_FILE, imsi,
2847                         straddr, msgid_str) != len)
2848                 return FALSE;
2849
2850         return TRUE;
2851 }
2852
2853 static gboolean sr_assembly_remove_fragment_backup(const char *imsi,
2854                                         const struct sms_address *addr,
2855                                         const unsigned char *sha1)
2856 {
2857         char *path;
2858         DECLARE_SMS_ADDR_STR(straddr);
2859         char msgid_str[SMS_MSGID_LEN * 2 + 1];
2860
2861         if (imsi == NULL)
2862                 return FALSE;
2863
2864         if (sms_address_to_hex_string(addr, straddr) == FALSE)
2865                 return FALSE;
2866
2867         if (encode_hex_own_buf(sha1, SMS_MSGID_LEN, 0, msgid_str) == FALSE)
2868                 return FALSE;
2869
2870         path = g_strdup_printf(SMS_SR_BACKUP_PATH_FILE,
2871                                         imsi, straddr, msgid_str);
2872
2873         unlink(path);
2874         g_free(path);
2875
2876         return TRUE;
2877 }
2878
2879 void status_report_assembly_free(struct status_report_assembly *assembly)
2880 {
2881         g_hash_table_destroy(assembly->assembly_table);
2882         g_free(assembly);
2883 }
2884
2885 static gboolean sr_st_to_delivered(enum sms_st st, gboolean *delivered)
2886 {
2887         if (st >= SMS_ST_TEMPFINAL_CONGESTION && st <= SMS_ST_TEMPFINAL_LAST)
2888                 return FALSE;
2889
2890         if (st >= SMS_ST_TEMPORARY_CONGESTION && st <= SMS_ST_TEMPORARY_LAST)
2891                 return FALSE;
2892
2893         if (st <= SMS_ST_COMPLETED_LAST) {
2894                 *delivered = TRUE;
2895                 return TRUE;
2896         }
2897
2898         if (st >= SMS_ST_PERMANENT_RP_ERROR && st <= SMS_ST_PERMANENT_LAST) {
2899                 *delivered = FALSE;
2900                 return TRUE;
2901         }
2902
2903         return FALSE;
2904 }
2905
2906 static struct id_table_node *find_by_mr_and_mark(GHashTable *id_table,
2907                                                 unsigned char mr,
2908                                                 GHashTableIter *out_iter,
2909                                                 unsigned char **out_id)
2910 {
2911         unsigned int offset = mr / 32;
2912         unsigned int bit = 1 << (mr % 32);
2913         gpointer key, value;
2914         struct id_table_node *node;
2915
2916         g_hash_table_iter_init(out_iter, id_table);
2917         while (g_hash_table_iter_next(out_iter, &key, &value)) {
2918                 node = value;
2919
2920                 /* Address and MR matched */
2921                 if (node->mrs[offset] & bit) {
2922                         node->mrs[offset] ^= bit;
2923                         *out_id = key;
2924
2925                         return node;
2926                 }
2927         }
2928
2929         return NULL;
2930 }
2931
2932 /*
2933  * Key (receiver address) does not exist in assembly. Some networks can change
2934  * address to international format, although address is sent in the national
2935  * format. Handle also change from national to international format.
2936  * Notify these special cases by comparing only last six digits of the assembly
2937  * addresses and received address. If address contains less than six digits,
2938  * compare only existing digits.
2939  */
2940 static struct id_table_node *fuzzy_lookup(struct status_report_assembly *assy,
2941                                                 const struct sms *sr,
2942                                                 const char **out_addr,
2943                                                 GHashTableIter *out_iter,
2944                                                 unsigned char **out_msgid)
2945 {
2946         GHashTableIter iter_addr;
2947         gpointer key, value;
2948         const char *r_addr;
2949
2950         r_addr = sms_address_to_string(&sr->status_report.raddr);
2951         g_hash_table_iter_init(&iter_addr, assy->assembly_table);
2952
2953         while (g_hash_table_iter_next(&iter_addr, &key, &value)) {
2954                 const char *s_addr = key;
2955                 GHashTable *id_table = value;
2956                 unsigned int len, r_len, s_len;
2957                 unsigned int i;
2958                 struct id_table_node *node;
2959
2960                 if (r_addr[0] == '+' && s_addr[0] == '+')
2961                         continue;
2962
2963                 if (r_addr[0] != '+' && s_addr[0] != '+')
2964                         continue;
2965
2966                 r_len = strlen(r_addr);
2967                 s_len = strlen(s_addr);
2968
2969                 len = MIN(6, MIN(r_len, s_len));
2970
2971                 for (i = 0; i < len; i++)
2972                         if (s_addr[s_len - i - 1] != r_addr[r_len - i - 1])
2973                                 break;
2974
2975                 /* Not all digits matched. */
2976                 if (i < len)
2977                         continue;
2978
2979                 /* Address matched. Check message reference. */
2980                 node = find_by_mr_and_mark(id_table, sr->status_report.mr,
2981                                                 out_iter, out_msgid);
2982                 if (node != NULL) {
2983                         *out_addr = s_addr;
2984                         return node;
2985                 }
2986         }
2987
2988         return NULL;
2989 }
2990
2991 gboolean status_report_assembly_report(struct status_report_assembly *assembly,
2992                                         const struct sms *sr,
2993                                         unsigned char *out_msgid,
2994                                         gboolean *out_delivered)
2995 {
2996         const char *straddr;
2997         GHashTable *id_table;
2998         GHashTableIter iter;
2999         struct sms_address addr;
3000         struct id_table_node *node;
3001         gboolean delivered;
3002         gboolean pending;
3003         unsigned char *msgid;
3004         int i;
3005
3006         /* We ignore temporary or tempfinal status reports */
3007         if (sr_st_to_delivered(sr->status_report.st, &delivered) == FALSE)
3008                 return FALSE;
3009
3010         straddr = sms_address_to_string(&sr->status_report.raddr);
3011         id_table = g_hash_table_lookup(assembly->assembly_table, straddr);
3012
3013         if (id_table != NULL)
3014                 node = find_by_mr_and_mark(id_table, sr->status_report.mr,
3015                                                 &iter, &msgid);
3016         else
3017                 node = fuzzy_lookup(assembly, sr, &straddr, &iter, &msgid);
3018
3019         /* Unable to find a message reference belonging to this address */
3020         if (node == NULL)
3021                 return FALSE;
3022
3023         node->deliverable = node->deliverable && delivered;
3024
3025         /* If we haven't sent the entire message yet, wait until sent */
3026         if (node->sent_mrs < node->total_mrs)
3027                 return FALSE;
3028
3029         /* Figure out if we are expecting more status reports */
3030         for (i = 0, pending = FALSE; i < 8; i++) {
3031                 /* There are still pending mr(s). */
3032                 if (node->mrs[i] != 0) {
3033                         pending = TRUE;
3034                         break;
3035                 }
3036         }
3037
3038         sms_address_from_string(&addr, straddr);
3039
3040         if (pending == TRUE && node->deliverable == TRUE) {
3041                 /*
3042                  * More status reports expected, and already received
3043                  * reports completed. Update backup file.
3044                  */
3045                 sr_assembly_add_fragment_backup(assembly->imsi, node,
3046                                                 &addr, msgid);
3047
3048                 return FALSE;
3049         }
3050
3051         if (out_delivered)
3052                 *out_delivered = node->deliverable;
3053
3054         if (out_msgid)
3055                 memcpy(out_msgid, msgid, SMS_MSGID_LEN);
3056
3057         sr_assembly_remove_fragment_backup(assembly->imsi, &addr, msgid);
3058         id_table = g_hash_table_iter_get_hash_table(&iter);
3059         g_hash_table_iter_remove(&iter);
3060
3061         if (g_hash_table_size(id_table) == 0)
3062                 g_hash_table_remove(assembly->assembly_table, straddr);
3063
3064         return TRUE;
3065 }
3066
3067 void status_report_assembly_add_fragment(
3068                                         struct status_report_assembly *assembly,
3069                                         const unsigned char *msgid,
3070                                         const struct sms_address *to,
3071                                         unsigned char mr, time_t expiration,
3072                                         unsigned char total_mrs)
3073 {
3074         unsigned int offset = mr / 32;
3075         unsigned int bit = 1 << (mr % 32);
3076         GHashTable *id_table;
3077         struct id_table_node *node;
3078         unsigned char *id_table_key;
3079
3080         id_table = g_hash_table_lookup(assembly->assembly_table,
3081                                         sms_address_to_string(to));
3082
3083         /* Create hashtable keyed by the to address if required */
3084         if (id_table == NULL) {
3085                 id_table = g_hash_table_new_full(sha1_hash, sha1_equal,
3086                                                                 g_free, g_free);
3087                 g_hash_table_insert(assembly->assembly_table,
3088                                         g_strdup(sms_address_to_string(to)),
3089                                         id_table);
3090         }
3091
3092         node = g_hash_table_lookup(id_table, msgid);
3093
3094         /* Create node in the message id hashtable if required */
3095         if (node == NULL) {
3096                 id_table_key = g_memdup(msgid, SMS_MSGID_LEN);
3097
3098                 node = g_new0(struct id_table_node, 1);
3099                 node->total_mrs = total_mrs;
3100                 node->deliverable = TRUE;
3101
3102                 g_hash_table_insert(id_table, id_table_key, node);
3103         }
3104
3105         /* id_table and node both exists */
3106         node->mrs[offset] |= bit;
3107         node->expiration = expiration;
3108         node->sent_mrs++;
3109         sr_assembly_add_fragment_backup(assembly->imsi, node, to, msgid);
3110 }
3111
3112 void status_report_assembly_expire(struct status_report_assembly *assembly,
3113                                         time_t before)
3114 {
3115         GHashTable *id_table;
3116         GHashTableIter iter_addr, iter_node;
3117         struct sms_address addr;
3118         char *straddr;
3119         gpointer key;
3120         struct id_table_node *node;
3121
3122         g_hash_table_iter_init(&iter_addr, assembly->assembly_table);
3123
3124         /*
3125          * Go through different addresses. Each address can relate to
3126          * 1-n msg_ids.
3127          */
3128         while (g_hash_table_iter_next(&iter_addr, (gpointer) &straddr,
3129                                         (gpointer) &id_table)) {
3130
3131                 sms_address_from_string(&addr, straddr);
3132                 g_hash_table_iter_init(&iter_node, id_table);
3133
3134                 /* Go through different messages. */
3135                 while (g_hash_table_iter_next(&iter_node, &key,
3136                                                 (gpointer) &node)) {
3137                         /*
3138                          * If message is expired, removed it from the
3139                          * hash-table and remove the backup-file
3140                          */
3141                         if (node->expiration <= before) {
3142                                 g_hash_table_iter_remove(&iter_node);
3143
3144                                 sr_assembly_remove_fragment_backup(
3145                                                                 assembly->imsi,
3146                                                                 &addr,
3147                                                                 key);
3148                         }
3149                 }
3150
3151                 /*
3152                  * If all messages are removed, remove address
3153                  * from the hash-table.
3154                  */
3155                 if (g_hash_table_size(id_table) == 0)
3156                         g_hash_table_iter_remove(&iter_addr);
3157         }
3158 }
3159
3160 static int sms_tx_load_filter(const struct dirent *dent)
3161 {
3162         char *endp;
3163         guint8 seq __attribute__ ((unused));
3164
3165         if (dent->d_type != DT_REG)
3166                 return 0;
3167
3168         seq = strtol(dent->d_name, &endp, 10);
3169         if (*endp != '\0')
3170                 return 0;
3171
3172         return 1;
3173 }
3174
3175 /*
3176  * Each directory contains a file per pdu.
3177  */
3178 static GSList *sms_tx_load(const char *imsi, const struct dirent *dir)
3179 {
3180         GSList *list = NULL;
3181         struct dirent **pdus;
3182         char *path;
3183         int len, r;
3184         unsigned char buf[177];
3185         struct sms s;
3186
3187         if (dir->d_type != DT_DIR)
3188                 return NULL;
3189
3190         path = g_strdup_printf(SMS_TX_BACKUP_PATH "/%s", imsi, dir->d_name);
3191         len = scandir(path, &pdus, sms_tx_load_filter, versionsort);
3192         g_free(path);
3193
3194         if (len < 0)
3195                 return NULL;
3196
3197         while (len--) {
3198                 r = read_file(buf, sizeof(buf), SMS_TX_BACKUP_PATH "/%s/%s",
3199                                         imsi, dir->d_name, pdus[len]->d_name);
3200
3201                 if (r < 0)
3202                         goto free_pdu;
3203
3204                 if (sms_deserialize_outgoing(buf, &s, r) == FALSE)
3205                         goto free_pdu;
3206
3207                 list = g_slist_prepend(list, g_memdup(&s, sizeof(s)));
3208
3209 free_pdu:
3210                 g_free(pdus[len]);
3211         }
3212
3213         g_free(pdus);
3214
3215         return list;
3216 }
3217
3218 static int sms_tx_queue_filter(const struct dirent *dirent)
3219 {
3220         if (dirent->d_type != DT_DIR)
3221                 return 0;
3222
3223         if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
3224                 return 0;
3225
3226         return 1;
3227 }
3228
3229 /*
3230  * populate the queue with tx_backup_entry from stored backup
3231  * data.
3232  */
3233 GQueue *sms_tx_queue_load(const char *imsi)
3234 {
3235         GQueue *retq = 0;
3236         char *path;
3237         struct dirent **entries;
3238         int len;
3239         int i;
3240         unsigned long id;
3241
3242         if (imsi == NULL)
3243                 return NULL;
3244
3245         path = g_strdup_printf(SMS_TX_BACKUP_PATH, imsi);
3246
3247         len = scandir(path, &entries, sms_tx_queue_filter, versionsort);
3248         if (len < 0)
3249                 goto nodir_exit;
3250
3251         retq = g_queue_new();
3252
3253         for (i = 0, id = 0; i < len; i++) {
3254                 char uuid[SMS_MSGID_LEN * 2 + 1];
3255                 GSList *msg_list;
3256                 unsigned long oldid;
3257                 unsigned long flags;
3258                 char *oldpath, *newpath;
3259                 struct txq_backup_entry *entry;
3260                 struct dirent *dir = entries[i];
3261                 char endc;
3262
3263                 if (sscanf(dir->d_name, "%lu-%lu-" SMS_MSGID_FMT "%c",
3264                                         &oldid, &flags, uuid, &endc) != 3)
3265                         continue;
3266
3267                 if (strlen(uuid) !=  2 * SMS_MSGID_LEN)
3268                         continue;
3269
3270                 msg_list = sms_tx_load(imsi, dir);
3271                 if (msg_list == NULL)
3272                         continue;
3273
3274                 entry = g_new0(struct txq_backup_entry, 1);
3275                 entry->msg_list = msg_list;
3276                 entry->flags = flags;
3277                 decode_hex_own_buf(uuid, -1, NULL, 0, entry->uuid);
3278
3279                 g_queue_push_tail(retq, entry);
3280
3281                 /* Don't bother re-shuffling the ids if they are the same */
3282                 if (oldid == id) {
3283                         id++;
3284                         continue;
3285                 }
3286
3287                 oldpath = g_strdup_printf("%s/%s", path, dir->d_name);
3288                 newpath = g_strdup_printf(SMS_TX_BACKUP_PATH_DIR,
3289                                                 imsi, id++, flags, uuid);
3290
3291                 /* rename directory to reflect new position in queue */
3292                 rename(oldpath, newpath);
3293
3294                 g_free(newpath);
3295                 g_free(oldpath);
3296         }
3297
3298         for (i = 0; i < len; i++)
3299                 g_free(entries[i]);
3300
3301         g_free(entries);
3302
3303 nodir_exit:
3304         g_free(path);
3305         return retq;
3306 }
3307
3308 gboolean sms_tx_backup_store(const char *imsi, unsigned long id,
3309                                 unsigned long flags, const char *uuid,
3310                                 guint8 seq, const unsigned char *pdu,
3311                                 int pdu_len, int tpdu_len)
3312 {
3313         unsigned char buf[177];
3314         int len;
3315
3316         if (!imsi)
3317                 return FALSE;
3318
3319         memcpy(buf + 1, pdu, pdu_len);
3320         buf[0] = tpdu_len;
3321         len = pdu_len + 1;
3322
3323         /*
3324          * file name is: imsi/tx_queue/order-flags-uuid/pdu
3325          */
3326         if (write_file(buf, len, SMS_BACKUP_MODE, SMS_TX_BACKUP_PATH_FILE,
3327                                         imsi, id, flags, uuid, seq) != len)
3328                 return FALSE;
3329
3330         return TRUE;
3331 }
3332
3333 void sms_tx_backup_free(const char *imsi, unsigned long id,
3334                                 unsigned long flags, const char *uuid)
3335 {
3336         char *path;
3337         struct dirent **entries;
3338         int len;
3339
3340         path = g_strdup_printf(SMS_TX_BACKUP_PATH_DIR,
3341                                         imsi, id, flags, uuid);
3342
3343         len = scandir(path, &entries, NULL, versionsort);
3344
3345         if (len < 0)
3346                 goto nodir_exit;
3347
3348         /* skip '..' and '.' entries */
3349         while (len-- > 2) {
3350                 struct dirent *dir = entries[len];
3351                 char *file = g_strdup_printf("%s/%s", path, dir->d_name);
3352
3353                 unlink(file);
3354                 g_free(file);
3355
3356                 g_free(entries[len]);
3357         }
3358
3359         g_free(entries[1]);
3360         g_free(entries[0]);
3361         g_free(entries);
3362
3363         rmdir(path);
3364
3365 nodir_exit:
3366         g_free(path);
3367 }
3368
3369 void sms_tx_backup_remove(const char *imsi, unsigned long id,
3370                                 unsigned long flags, const char *uuid,
3371                                 guint8 seq)
3372 {
3373         char *path;
3374
3375         path = g_strdup_printf(SMS_TX_BACKUP_PATH_FILE,
3376                                         imsi, id, flags, uuid, seq);
3377         unlink(path);
3378
3379         g_free(path);
3380 }
3381
3382 static inline GSList *sms_list_append(GSList *l, const struct sms *in)
3383 {
3384         struct sms *sms;
3385
3386         sms = g_new(struct sms, 1);
3387         memcpy(sms, in, sizeof(struct sms));
3388         l = g_slist_prepend(l, sms);
3389
3390         return l;
3391 }
3392
3393 /*
3394  * Prepares a datagram for transmission.  Breaks up into fragments if
3395  * necessary using ref as the concatenated message reference number.
3396  * Returns a list of sms messages in order.
3397  *
3398  * @use_delivery_reports: value for the Status-Report-Request field
3399  *     (23.040 3.2.9, 9.2.2.2)
3400  */
3401 GSList *sms_datagram_prepare(const char *to,
3402                                 const unsigned char *data, unsigned int len,
3403                                 guint16 ref, gboolean use_16bit_ref,
3404                                 unsigned short src, unsigned short dst,
3405                                 gboolean use_16bit_port,
3406                                 gboolean use_delivery_reports)
3407 {
3408         struct sms template;
3409         unsigned int offset;
3410         unsigned int written;
3411         unsigned int left;
3412         guint8 seq;
3413         GSList *r = NULL;
3414
3415         memset(&template, 0, sizeof(struct sms));
3416         template.type = SMS_TYPE_SUBMIT;
3417         template.submit.rd = FALSE;
3418         template.submit.vpf = SMS_VALIDITY_PERIOD_FORMAT_RELATIVE;
3419         template.submit.rp = FALSE;
3420         template.submit.srr = use_delivery_reports;
3421         template.submit.mr = 0;
3422         template.submit.vp.relative = 0xA7; /* 24 Hours */
3423         template.submit.dcs = 0x04; /* Class Unspecified, 8 Bit */
3424         template.submit.udhi = TRUE;
3425         sms_address_from_string(&template.submit.daddr, to);
3426
3427         offset = 1;
3428
3429         if (use_16bit_port) {
3430                 template.submit.ud[0] += 6;
3431                 template.submit.ud[offset] = SMS_IEI_APPLICATION_ADDRESS_16BIT;
3432                 template.submit.ud[offset + 1] = 4;
3433                 template.submit.ud[offset + 2] = (dst & 0xff00) >> 8;
3434                 template.submit.ud[offset + 3] = dst & 0xff;
3435                 template.submit.ud[offset + 4] = (src & 0xff00) >> 8;
3436                 template.submit.ud[offset + 5] = src & 0xff;
3437
3438                 offset += 6;
3439         } else {
3440                 template.submit.ud[0] += 4;
3441                 template.submit.ud[offset] = SMS_IEI_APPLICATION_ADDRESS_8BIT;
3442                 template.submit.ud[offset + 1] = 2;
3443                 template.submit.ud[offset + 2] = dst & 0xff;
3444                 template.submit.ud[offset + 3] = src & 0xff;
3445
3446                 offset += 4;
3447         }
3448
3449         if (len <= (140 - offset)) {
3450                 template.submit.udl = len + offset;
3451                 memcpy(template.submit.ud + offset, data, len);
3452
3453                 return sms_list_append(NULL, &template);
3454         }
3455
3456         if (use_16bit_ref) {
3457                 template.submit.ud[0] += 6;
3458                 template.submit.ud[offset] = SMS_IEI_CONCATENATED_16BIT;
3459                 template.submit.ud[offset + 1] = 4;
3460                 template.submit.ud[offset + 2] = (ref & 0xff00) >> 8;
3461                 template.submit.ud[offset + 3] = ref & 0xff;
3462
3463                 offset += 6;
3464         } else {
3465                 template.submit.ud[0] += 5;
3466                 template.submit.ud[offset] = SMS_IEI_CONCATENATED_8BIT;
3467                 template.submit.ud[offset + 1] = 3;
3468                 template.submit.ud[offset + 2] = ref & 0xff;
3469
3470                 offset += 5;
3471         }
3472
3473         seq = 0;
3474         left = len;
3475         written = 0;
3476
3477         while (left > 0) {
3478                 unsigned int chunk;
3479
3480                 seq += 1;
3481
3482                 chunk = 140 - offset;
3483                 if (left < chunk)
3484                         chunk = left;
3485
3486                 template.submit.udl = chunk + offset;
3487                 memcpy(template.submit.ud + offset, data + written, chunk);
3488
3489                 written += chunk;
3490                 left -= chunk;
3491
3492                 template.submit.ud[offset - 1] = seq;
3493
3494                 r = sms_list_append(r, &template);
3495
3496                 if (seq == 255)
3497                         break;
3498         }
3499
3500         if (left > 0) {
3501                 g_slist_foreach(r, (GFunc) g_free, NULL);
3502                 g_slist_free(r);
3503
3504                 return NULL;
3505         } else {
3506                 GSList *l;
3507
3508                 for (l = r; l; l = l->next) {
3509                         struct sms *sms = l->data;
3510
3511                         sms->submit.ud[offset - 2] = seq;
3512                 }
3513         }
3514
3515         r = g_slist_reverse(r);
3516
3517         return r;
3518 }
3519
3520 /*
3521  * Prepares the text for transmission.  Breaks up into fragments if
3522  * necessary using ref as the concatenated message reference number.
3523  * Returns a list of sms messages in order.
3524  *
3525  * @use_delivery_reports: value for the Status-Report-Request field
3526  *     (23.040 3.2.9, 9.2.2.2)
3527  */
3528 GSList *sms_text_prepare_with_alphabet(const char *to, const char *utf8,
3529                                         guint16 ref, gboolean use_16bit,
3530                                         gboolean use_delivery_reports,
3531                                         enum sms_alphabet alphabet)
3532 {
3533         struct sms template;
3534         int offset = 0;
3535         unsigned char *gsm_encoded = NULL;
3536         char *ucs2_encoded = NULL;
3537         long written;
3538         long left;
3539         guint8 seq;
3540         GSList *r = NULL;
3541         enum gsm_dialect used_locking;
3542         enum gsm_dialect used_single;
3543
3544         memset(&template, 0, sizeof(struct sms));
3545         template.type = SMS_TYPE_SUBMIT;
3546         template.submit.rd = FALSE;
3547         template.submit.vpf = SMS_VALIDITY_PERIOD_FORMAT_RELATIVE;
3548         template.submit.rp = FALSE;
3549         template.submit.srr = use_delivery_reports;
3550         template.submit.mr = 0;
3551         template.submit.vp.relative = 0xA7; /* 24 Hours */
3552         sms_address_from_string(&template.submit.daddr, to);
3553
3554         /*
3555          * UDHI, UDL, UD and DCS actually depend on the contents of
3556          * the text, and also on the GSM dialect we use to encode it.
3557          */
3558         gsm_encoded = convert_utf8_to_gsm_best_lang(utf8, -1, NULL, &written, 0,
3559                                                         alphabet, &used_locking,
3560                                                         &used_single);
3561         if (gsm_encoded == NULL) {
3562                 gsize converted;
3563
3564                 ucs2_encoded = g_convert(utf8, -1, "UCS-2BE//TRANSLIT", "UTF-8",
3565                                                 NULL, &converted, NULL);
3566                 written = converted;
3567         }
3568
3569         if (gsm_encoded == NULL && ucs2_encoded == NULL)
3570                 return NULL;
3571
3572         if (gsm_encoded != NULL)
3573                 template.submit.dcs = 0x00; /* Class Unspecified, 7 Bit */
3574         else
3575                 template.submit.dcs = 0x08; /* Class Unspecified, UCS2 */
3576
3577         if (gsm_encoded != NULL && used_single != GSM_DIALECT_DEFAULT) {
3578                 if (!offset)
3579                         offset = 1;
3580
3581                 template.submit.ud[0] += 3;
3582                 template.submit.ud[offset] = SMS_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT;
3583                 template.submit.ud[offset + 1] = 1;
3584                 template.submit.ud[offset + 2] = used_single;
3585                 offset += 3;
3586         }
3587
3588         if (gsm_encoded != NULL && used_locking != GSM_DIALECT_DEFAULT) {
3589                 if (!offset)
3590                         offset = 1;
3591
3592                 template.submit.ud[0] += 3;
3593                 template.submit.ud[offset] = SMS_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT;
3594                 template.submit.ud[offset + 1] = 1;
3595                 template.submit.ud[offset + 2] = used_locking;
3596                 offset += 3;
3597         }
3598
3599         if (offset != 0)
3600                 template.submit.udhi = TRUE;
3601
3602         if (gsm_encoded && (written <= sms_text_capacity_gsm(160, offset))) {
3603                 template.submit.udl = written + (offset * 8 + 6) / 7;
3604                 pack_7bit_own_buf(gsm_encoded, written, offset, FALSE, NULL,
3605                                         0, template.submit.ud + offset);
3606
3607                 g_free(gsm_encoded);
3608                 return sms_list_append(NULL, &template);
3609         }
3610
3611         if (ucs2_encoded && (written <= (140 - offset))) {
3612                 template.submit.udl = written + offset;
3613                 memcpy(template.submit.ud + offset, ucs2_encoded, written);
3614
3615                 g_free(ucs2_encoded);
3616                 return sms_list_append(NULL, &template);
3617         }
3618
3619         template.submit.udhi = TRUE;
3620
3621         if (!offset)
3622                 offset = 1;
3623
3624         if (use_16bit) {
3625                 template.submit.ud[0] += 6;
3626                 template.submit.ud[offset] = SMS_IEI_CONCATENATED_16BIT;
3627                 template.submit.ud[offset + 1] = 4;
3628                 template.submit.ud[offset + 2] = (ref & 0xff00) >> 8;
3629                 template.submit.ud[offset + 3] = ref & 0xff;
3630
3631                 offset += 6;
3632         } else {
3633                 template.submit.ud[0] += 5;
3634                 template.submit.ud[offset] = SMS_IEI_CONCATENATED_8BIT;
3635                 template.submit.ud[offset + 1] = 3;
3636                 template.submit.ud[offset + 2] = ref & 0xff;
3637
3638                 offset += 5;
3639         }
3640
3641         seq = 0;
3642         left = written;
3643         written = 0;
3644
3645         while (left > 0) {
3646                 long chunk;
3647
3648                 seq += 1;
3649
3650                 if (gsm_encoded) {
3651                         chunk = sms_text_capacity_gsm(160, offset);
3652
3653                         if (left < chunk)
3654                                 chunk = left;
3655
3656                         if (gsm_encoded[written + chunk - 1] == 0x1b)
3657                                 chunk -= 1;
3658
3659                         template.submit.udl = chunk + (offset * 8 + 6) / 7;
3660                         pack_7bit_own_buf(gsm_encoded + written, chunk,
3661                                                 offset, FALSE, NULL, 0,
3662                                                 template.submit.ud + offset);
3663                 } else {
3664                         chunk = 140 - offset;
3665                         chunk &= ~0x1;
3666
3667                         if (left < chunk)
3668                                 chunk = left;
3669
3670                         template.submit.udl = chunk + offset;
3671                         memcpy(template.submit.ud + offset,
3672                                 ucs2_encoded + written, chunk);
3673                 }
3674
3675                 written += chunk;
3676                 left -= chunk;
3677
3678                 template.submit.ud[offset - 1] = seq;
3679
3680                 r = sms_list_append(r, &template);
3681
3682                 if (seq == 255)
3683                         break;
3684         }
3685
3686         if (gsm_encoded)
3687                 g_free(gsm_encoded);
3688
3689         if (ucs2_encoded)
3690                 g_free(ucs2_encoded);
3691
3692         if (left > 0) {
3693                 g_slist_foreach(r, (GFunc) g_free, NULL);
3694                 g_slist_free(r);
3695
3696                 return NULL;
3697         } else {
3698                 GSList *l;
3699
3700                 for (l = r; l; l = l->next) {
3701                         struct sms *sms = l->data;
3702
3703                         sms->submit.ud[offset - 2] = seq;
3704                 }
3705         }
3706
3707         r = g_slist_reverse(r);
3708
3709         return r;
3710 }
3711
3712 GSList *sms_text_prepare(const char *to, const char *utf8, guint16 ref,
3713                                 gboolean use_16bit,
3714                                 gboolean use_delivery_reports)
3715 {
3716         return sms_text_prepare_with_alphabet(to, utf8, ref, use_16bit,
3717                                                 use_delivery_reports,
3718                                                 SMS_ALPHABET_DEFAULT);
3719 }
3720
3721 gboolean cbs_dcs_decode(guint8 dcs, gboolean *udhi, enum sms_class *cls,
3722                         enum sms_charset *charset, gboolean *compressed,
3723                         enum cbs_language *language, gboolean *iso639)
3724 {
3725         guint8 upper = (dcs & 0xf0) >> 4;
3726         guint8 lower = dcs & 0xf;
3727         enum sms_charset ch;
3728         enum sms_class cl;
3729         enum cbs_language lang = CBS_LANGUAGE_UNSPECIFIED;
3730         gboolean iso = FALSE;
3731         gboolean comp = FALSE;
3732         gboolean udh = FALSE;
3733
3734         if (upper == 0x3 || upper == 0x8 || (upper >= 0xA && upper <= 0xE))
3735                 return FALSE;
3736
3737         switch (upper) {
3738         case 0:
3739                 ch = SMS_CHARSET_7BIT;
3740                 cl = SMS_CLASS_UNSPECIFIED;
3741                 lang = (enum cbs_language) lower;
3742                 break;
3743         case 1:
3744                 if (lower > 1)
3745                         return FALSE;
3746
3747                 if (lower == 0)
3748                         ch = SMS_CHARSET_7BIT;
3749                 else
3750                         ch = SMS_CHARSET_UCS2;
3751
3752                 cl = SMS_CLASS_UNSPECIFIED;
3753                 iso = TRUE;
3754
3755                 break;
3756         case 2:
3757                 if (lower > 4)
3758                         return FALSE;
3759
3760                 ch = SMS_CHARSET_7BIT;
3761                 cl = SMS_CLASS_UNSPECIFIED;
3762                 lang = (enum cbs_language) dcs;
3763                 break;
3764         case 4:
3765         case 5:
3766         case 6:
3767         case 7:
3768                 comp = (dcs & 0x20) ? TRUE : FALSE;
3769
3770                 if (dcs & 0x10)
3771                         cl = (enum sms_class) (dcs & 0x03);
3772                 else
3773                         cl = SMS_CLASS_UNSPECIFIED;
3774
3775                 if (((dcs & 0x0c) >> 2) < 3)
3776                         ch = (enum sms_charset) ((dcs & 0x0c) >> 2);
3777                 else
3778                         return FALSE;
3779
3780                 break;
3781         case 9:
3782                 udh = TRUE;
3783                 cl = (enum sms_class) (dcs & 0x03);
3784                 if (((dcs & 0x0c) >> 2) < 3)
3785                         ch = (enum sms_charset) ((dcs & 0x0c) >> 2);
3786                 else
3787                         return FALSE;
3788
3789                 break;
3790         case 15:
3791                 if (lower & 0x8)
3792                         return FALSE;
3793
3794                 if (lower & 0x4)
3795                         ch = SMS_CHARSET_8BIT;
3796                 else
3797                         ch = SMS_CHARSET_7BIT;
3798
3799                 if (lower & 0x3)
3800                         cl = (enum sms_class) (lower & 0x3);
3801                 else
3802                         cl = SMS_CLASS_UNSPECIFIED;
3803
3804                 break;
3805         default:
3806                 return FALSE;
3807         };
3808
3809         if (udhi)
3810                 *udhi = udh;
3811
3812         if (cls)
3813                 *cls = cl;
3814
3815         if (charset)
3816                 *charset = ch;
3817
3818         if (compressed)
3819                 *compressed = comp;
3820
3821         if (language)
3822                 *language = lang;
3823
3824         if (iso639)
3825                 *iso639 = iso;
3826
3827         return TRUE;
3828 }
3829
3830 gboolean cbs_decode(const unsigned char *pdu, int len, struct cbs *out)
3831 {
3832         /* CBS is always a fixed length of 88 bytes */
3833         if (len != 88)
3834                 return FALSE;
3835
3836         out->gs = (enum cbs_geo_scope) ((pdu[0] >> 6) & 0x03);
3837         out->message_code = ((pdu[0] & 0x3f) << 4) | ((pdu[1] >> 4) & 0xf);
3838         out->update_number = (pdu[1] & 0xf);
3839         out->message_identifier = (pdu[2] << 8) | pdu[3];
3840         out->dcs = pdu[4];
3841         out->max_pages = pdu[5] & 0xf;
3842         out->page = (pdu[5] >> 4) & 0xf;
3843
3844         /*
3845          * If a mobile receives the code 0000 in either the first field or
3846          * the second field then it shall treat the CBS message exactly the
3847          * same as a CBS message with page parameter 0001 0001 (i.e. a single
3848          * page message).
3849          */
3850         if (out->max_pages == 0 || out->page == 0) {
3851                 out->max_pages = 1;
3852                 out->page = 1;
3853         }
3854
3855         memcpy(out->ud, pdu + 6, 82);
3856
3857         return TRUE;
3858 }
3859
3860 gboolean cbs_encode(const struct cbs *cbs, int *len, unsigned char *pdu)
3861 {
3862         pdu[0] = (cbs->gs << 6) | ((cbs->message_code >> 4) & 0x3f);
3863         pdu[1] = ((cbs->message_code & 0xf) << 4) | cbs->update_number;
3864         pdu[2] = cbs->message_identifier >> 8;
3865         pdu[3] = cbs->message_identifier & 0xff;
3866         pdu[4] = cbs->dcs;
3867         pdu[5] = cbs->max_pages | (cbs->page << 4);
3868
3869         memcpy(pdu + 6, cbs->ud, 82);
3870
3871         if (len)
3872                 *len = 88;
3873
3874         return TRUE;
3875 }
3876
3877 gboolean cbs_extract_app_port(const struct cbs *cbs, int *dst, int *src,
3878                                 gboolean *is_8bit)
3879 {
3880         struct sms_udh_iter iter;
3881
3882         if (!sms_udh_iter_init_from_cbs(cbs, &iter))
3883                 return FALSE;
3884
3885         return extract_app_port_common(&iter, dst, src, is_8bit);
3886 }
3887
3888 gboolean iso639_2_from_language(enum cbs_language lang, char *iso639)
3889 {
3890         switch (lang) {
3891         case CBS_LANGUAGE_GERMAN:
3892                 iso639[0] = 'd';
3893                 iso639[1] = 'e';
3894                 iso639[2] = '\0';
3895                 return TRUE;
3896         case CBS_LANGUAGE_ENGLISH:
3897                 iso639[0] = 'e';
3898                 iso639[1] = 'n';
3899                 iso639[2] = '\0';
3900                 return TRUE;
3901         case CBS_LANGUAGE_ITALIAN:
3902                 iso639[0] = 'i';
3903                 iso639[1] = 't';
3904                 iso639[2] = '\0';
3905                 return TRUE;
3906         case CBS_LANGUAGE_FRENCH:
3907                 iso639[0] = 'f';
3908                 iso639[1] = 'r';
3909                 iso639[2] = '\0';
3910                 return TRUE;
3911         case CBS_LANGUAGE_SPANISH:
3912                 iso639[0] = 'e';
3913                 iso639[1] = 's';
3914                 iso639[2] = '\0';
3915                 return TRUE;
3916         case CBS_LANGUAGE_DUTCH:
3917                 iso639[0] = 'n';
3918                 iso639[1] = 'l';
3919                 iso639[2] = '\0';
3920                 return TRUE;
3921         case CBS_LANGUAGE_SWEDISH:
3922                 iso639[0] = 's';
3923                 iso639[1] = 'v';
3924                 iso639[2] = '\0';
3925                 return TRUE;
3926         case CBS_LANGUAGE_DANISH:
3927                 iso639[0] = 'd';
3928                 iso639[1] = 'a';
3929                 iso639[2] = '\0';
3930                 return TRUE;
3931         case CBS_LANGUAGE_PORTUGESE:
3932                 iso639[0] = 'p';
3933                 iso639[1] = 't';
3934                 iso639[2] = '\0';
3935                 return TRUE;
3936         case CBS_LANGUAGE_FINNISH:
3937                 iso639[0] = 'f';
3938                 iso639[1] = 'i';
3939                 iso639[2] = '\0';
3940                 return TRUE;
3941         case CBS_LANGUAGE_NORWEGIAN:
3942                 iso639[0] = 'n';
3943                 iso639[1] = 'o';
3944                 iso639[2] = '\0';
3945                 return TRUE;
3946         case CBS_LANGUAGE_GREEK:
3947                 iso639[0] = 'e';
3948                 iso639[1] = 'l';
3949                 iso639[2] = '\0';
3950                 return TRUE;
3951         case CBS_LANGUAGE_TURKISH:
3952                 iso639[0] = 't';
3953                 iso639[1] = 'r';
3954                 iso639[2] = '\0';
3955                 return TRUE;
3956         case CBS_LANGUAGE_HUNGARIAN:
3957                 iso639[0] = 'h';
3958                 iso639[1] = 'u';
3959                 iso639[2] = '\0';
3960                 return TRUE;
3961         case CBS_LANGUAGE_POLISH:
3962                 iso639[0] = 'p';
3963                 iso639[1] = 'l';
3964                 iso639[2] = '\0';
3965                 return TRUE;
3966         case CBS_LANGUAGE_CZECH:
3967                 iso639[0] = 'c';
3968                 iso639[1] = 's';
3969                 iso639[2] = '\0';
3970                 return TRUE;
3971         case CBS_LANGUAGE_HEBREW:
3972                 iso639[0] = 'h';
3973                 iso639[1] = 'e';
3974                 iso639[2] = '\0';
3975                 return TRUE;
3976         case CBS_LANGUAGE_ARABIC:
3977                 iso639[0] = 'a';
3978                 iso639[1] = 'r';
3979                 iso639[2] = '\0';
3980                 return TRUE;
3981         case CBS_LANGUAGE_RUSSIAN:
3982                 iso639[0] = 'r';
3983                 iso639[1] = 'u';
3984                 iso639[2] = '\0';
3985                 return TRUE;
3986         case CBS_LANGUAGE_ICELANDIC:
3987                 iso639[0] = 'i';
3988                 iso639[1] = 's';
3989                 iso639[2] = '\0';
3990                 return TRUE;
3991         default:
3992                 iso639[0] = '\0';
3993                 break;
3994         }
3995
3996         return FALSE;
3997 }
3998
3999 char *cbs_decode_text(GSList *cbs_list, char *iso639_lang)
4000 {
4001         GSList *l;
4002         const struct cbs *cbs;
4003         enum sms_charset uninitialized_var(charset);
4004         enum cbs_language lang;
4005         gboolean uninitialized_var(iso639);
4006         int bufsize = 0;
4007         unsigned char *buf;
4008         char *utf8;
4009
4010         if (cbs_list == NULL)
4011                 return NULL;
4012
4013         /*
4014          * CBS can only come from the network, so we're much less lenient
4015          * on what we support.  Namely we require the same charset to be
4016          * used across all pages.
4017          */
4018         for (l = cbs_list; l; l = l->next) {
4019                 enum sms_charset curch;
4020                 gboolean curiso;
4021
4022                 cbs = l->data;
4023
4024                 if (!cbs_dcs_decode(cbs->dcs, NULL, NULL,
4025                                         &curch, NULL, &lang, &curiso))
4026                         return NULL;
4027
4028                 if (l == cbs_list) {
4029                         iso639 = curiso;
4030                         charset = curch;
4031                 }
4032
4033                 if (curch != charset)
4034                         return NULL;
4035
4036                 if (curiso != iso639)
4037                         return NULL;
4038
4039                 if (curch == SMS_CHARSET_8BIT)
4040                         return NULL;
4041
4042                 if (curch == SMS_CHARSET_7BIT) {
4043                         bufsize += CBS_MAX_GSM_CHARS;
4044
4045                         if (iso639)
4046                                 bufsize -= 3;
4047                 } else {
4048                         bufsize += 82;
4049
4050                         if (iso639)
4051                                 bufsize -= 2;
4052                 }
4053         }
4054
4055         if (lang) {
4056                 cbs = cbs_list->data;
4057
4058                 if (iso639) {
4059                         struct sms_udh_iter iter;
4060                         int taken = 0;
4061
4062                         if (sms_udh_iter_init_from_cbs(cbs, &iter))
4063                                 taken = sms_udh_iter_get_udh_length(&iter) + 1;
4064
4065                         unpack_7bit_own_buf(cbs->ud + taken, 82 - taken,
4066                                                 taken, FALSE, 2,
4067                                                 NULL, 0,
4068                                                 (unsigned char *)iso639_lang);
4069                         iso639_lang[2] = '\0';
4070                 } else {
4071                         iso639_2_from_language(lang, iso639_lang);
4072                 }
4073         }
4074
4075         buf = g_new(unsigned char, bufsize);
4076         bufsize = 0;
4077
4078         for (l = cbs_list; l; l = l->next) {
4079                 const guint8 *ud;
4080                 struct sms_udh_iter iter;
4081                 int taken = 0;
4082
4083                 cbs = l->data;
4084                 ud = cbs->ud;
4085
4086                 if (sms_udh_iter_init_from_cbs(cbs, &iter))
4087                         taken = sms_udh_iter_get_udh_length(&iter) + 1;
4088
4089                 if (charset == SMS_CHARSET_7BIT) {
4090                         unsigned char unpacked[CBS_MAX_GSM_CHARS];
4091                         long written;
4092                         int max_chars;
4093                         int i;
4094
4095                         max_chars =
4096                                 sms_text_capacity_gsm(CBS_MAX_GSM_CHARS, taken);
4097
4098                         unpack_7bit_own_buf(ud + taken, 82 - taken,
4099                                                 taken, FALSE, max_chars,
4100                                                 &written, 0, unpacked);
4101
4102                         i = iso639 ? 3 : 0;
4103
4104                         /*
4105                          * CR is a padding character, which means we can
4106                          * safely discard everything afterwards
4107                          */
4108                         for (; i < written; i++, bufsize++) {
4109                                 if (unpacked[i] == '\r')
4110                                         break;
4111
4112                                 buf[bufsize] = unpacked[i];
4113                         }
4114
4115                         /*
4116                          * It isn't clear whether extension sequences
4117                          * (2 septets) must be wholly present in the page
4118                          * and not broken over multiple pages.  The behavior
4119                          * is probably the same as SMS, but we don't make
4120                          * the check here since the specification isn't clear
4121                          */
4122                 } else {
4123                         int num_ucs2_chars = (82 - taken) >> 1;
4124                         int i = taken;
4125                         int max_offset = taken + num_ucs2_chars * 2;
4126
4127                         /*
4128                          * It is completely unclear how UCS2 chars are handled
4129                          * especially across pages or when the UDH is present.
4130                          * For now do the best we can.
4131                          */
4132                         if (iso639) {
4133                                 i += 2;
4134                                 num_ucs2_chars -= 1;
4135                         }
4136
4137                         while (i < max_offset) {
4138                                 if (ud[i] == 0x00 && ud[i+1] == '\r')
4139                                         break;
4140
4141                                 buf[bufsize] = ud[i];
4142                                 buf[bufsize + 1] = ud[i+1];
4143
4144                                 bufsize += 2;
4145                                 i += 2;
4146                         }
4147                 }
4148         }
4149
4150         if (charset == SMS_CHARSET_7BIT)
4151                 utf8 = convert_gsm_to_utf8(buf, bufsize, NULL, NULL, 0);
4152         else
4153                 utf8 = g_convert((char *) buf, bufsize, "UTF-8//TRANSLIT",
4154                                         "UCS-2BE", NULL, NULL, NULL);
4155
4156         g_free(buf);
4157         return utf8;
4158 }
4159
4160 static inline gboolean cbs_is_update_newer(unsigned int n, unsigned int o)
4161 {
4162         unsigned int old_update = o & 0xf;
4163         unsigned int new_update = n & 0xf;
4164
4165         if (new_update == old_update)
4166                 return FALSE;
4167
4168         /*
4169          * Any Update Number eight or less higher (modulo 16) than the last
4170          * received Update Number will be considered more recent, and shall be
4171          * treated as a new CBS message, provided the mobile has not been
4172          * switched off.
4173          */
4174         if (new_update <= ((old_update + 8) % 16))
4175                 return TRUE;
4176
4177         return FALSE;
4178 }
4179
4180 struct cbs_assembly *cbs_assembly_new(void)
4181 {
4182         return g_new0(struct cbs_assembly, 1);
4183 }
4184
4185 void cbs_assembly_free(struct cbs_assembly *assembly)
4186 {
4187         GSList *l;
4188
4189         for (l = assembly->assembly_list; l; l = l->next) {
4190                 struct cbs_assembly_node *node = l->data;
4191
4192                 g_slist_foreach(node->pages, (GFunc) g_free, 0);
4193                 g_slist_free(node->pages);
4194                 g_free(node);
4195         }
4196
4197         g_slist_free(assembly->assembly_list);
4198         g_slist_free(assembly->recv_plmn);
4199         g_slist_free(assembly->recv_loc);
4200         g_slist_free(assembly->recv_cell);
4201
4202         g_free(assembly);
4203 }
4204
4205 static gint cbs_compare_node_by_gs(gconstpointer a, gconstpointer b)
4206 {
4207         const struct cbs_assembly_node *node = a;
4208         unsigned int gs = GPOINTER_TO_UINT(b);
4209
4210         if (((node->serial >> 14) & 0x3) == gs)
4211                 return 0;
4212
4213         return 1;
4214 }
4215
4216 static gint cbs_compare_node_by_update(gconstpointer a, gconstpointer b)
4217 {
4218         const struct cbs_assembly_node *node = a;
4219         unsigned int serial = GPOINTER_TO_UINT(b);
4220
4221         if ((serial & (~0xf)) != (node->serial & (~0xf)))
4222                 return 1;
4223
4224         if (cbs_is_update_newer(node->serial, serial))
4225                 return 1;
4226
4227         return 0;
4228 }
4229
4230 static gint cbs_compare_recv_by_serial(gconstpointer a, gconstpointer b)
4231 {
4232         unsigned int old_serial = GPOINTER_TO_UINT(a);
4233         unsigned int new_serial = GPOINTER_TO_UINT(b);
4234
4235         if ((old_serial & (~0xf)) == (new_serial & (~0xf)))
4236                 return 0;
4237
4238         return 1;
4239 }
4240
4241 static void cbs_assembly_expire(struct cbs_assembly *assembly,
4242                                 GCompareFunc func, gconstpointer *userdata)
4243 {
4244         GSList *l;
4245         GSList *prev;
4246         GSList *tmp;
4247
4248         /*
4249          * Take care of the case where several updates are being
4250          * reassembled at the same time. If the newer one is assembled
4251          * first, then the subsequent old update is discarded, make
4252          * sure that we're also discarding the assembly node for the
4253          * partially assembled ones
4254          */
4255         prev = NULL;
4256         l = assembly->assembly_list;
4257
4258         while (l) {
4259                 struct cbs_assembly_node *node = l->data;
4260
4261                 if (func(node, userdata) != 0) {
4262                         prev = l;
4263                         l = l->next;
4264                         continue;
4265                 }
4266
4267                 if (prev)
4268                         prev->next = l->next;
4269                 else
4270                         assembly->assembly_list = l->next;
4271
4272                 g_slist_foreach(node->pages, (GFunc) g_free, NULL);
4273                 g_slist_free(node->pages);
4274                 g_free(node->pages);
4275                 tmp = l;
4276                 l = l->next;
4277                 g_slist_free_1(tmp);
4278         }
4279 }
4280
4281 void cbs_assembly_location_changed(struct cbs_assembly *assembly, gboolean plmn,
4282                                         gboolean lac, gboolean ci)
4283 {
4284         /*
4285          * Location Area wide (in GSM) (which means that a CBS message with the
4286          * same Message Code and Update Number may or may not be "new" in the
4287          * next cell according to whether the next cell is in the same Location
4288          * Area as the current cell), or
4289          *
4290          * Service Area Wide (in UMTS) (which means that a CBS message with the
4291          * same Message Code and Update Number may or may not be "new" in the
4292          * next cell according to whether the next cell is in the same Service
4293          * Area as the current cell)
4294          *
4295          * NOTE 4: According to 3GPP TS 23.003 [2] a Service Area consists of
4296          * one cell only.
4297          */
4298
4299         if (plmn) {
4300                 lac = TRUE;
4301                 g_slist_free(assembly->recv_plmn);
4302                 assembly->recv_plmn = NULL;
4303
4304                 cbs_assembly_expire(assembly, cbs_compare_node_by_gs,
4305                                 GUINT_TO_POINTER(CBS_GEO_SCOPE_PLMN));
4306         }
4307
4308         if (lac) {
4309                 /* If LAC changed, then cell id has changed */
4310                 ci = TRUE;
4311                 g_slist_free(assembly->recv_loc);
4312                 assembly->recv_loc = NULL;
4313
4314                 cbs_assembly_expire(assembly, cbs_compare_node_by_gs,
4315                                 GUINT_TO_POINTER(CBS_GEO_SCOPE_SERVICE_AREA));
4316         }
4317
4318         if (ci) {
4319                 g_slist_free(assembly->recv_cell);
4320                 assembly->recv_cell = NULL;
4321                 cbs_assembly_expire(assembly, cbs_compare_node_by_gs,
4322                                 GUINT_TO_POINTER(CBS_GEO_SCOPE_CELL_IMMEDIATE));
4323                 cbs_assembly_expire(assembly, cbs_compare_node_by_gs,
4324                                 GUINT_TO_POINTER(CBS_GEO_SCOPE_CELL_NORMAL));
4325         }
4326 }
4327
4328 GSList *cbs_assembly_add_page(struct cbs_assembly *assembly,
4329                                 const struct cbs *cbs)
4330 {
4331         struct cbs *newcbs;
4332         struct cbs_assembly_node *node;
4333         GSList *completed;
4334         unsigned int new_serial;
4335         GSList **recv;
4336         GSList *l;
4337         GSList *prev;
4338         int position;
4339
4340         new_serial = cbs->gs << 14;
4341         new_serial |= cbs->message_code << 4;
4342         new_serial |= cbs->update_number;
4343         new_serial |= cbs->message_identifier << 16;
4344
4345         if (cbs->gs == CBS_GEO_SCOPE_PLMN)
4346                 recv = &assembly->recv_plmn;
4347         else if (cbs->gs == CBS_GEO_SCOPE_SERVICE_AREA)
4348                 recv = &assembly->recv_loc;
4349         else
4350                 recv = &assembly->recv_cell;
4351
4352         /* Have we seen this message before? */
4353         l = g_slist_find_custom(*recv, GUINT_TO_POINTER(new_serial),
4354                                 cbs_compare_recv_by_serial);
4355
4356         /* If we have, is the message newer? */
4357         if (l && !cbs_is_update_newer(new_serial, GPOINTER_TO_UINT(l->data)))
4358                 return NULL;
4359
4360         /* Easy case first, page 1 of 1 */
4361         if (cbs->max_pages == 1 && cbs->page == 1) {
4362                 if (l)
4363                         l->data = GUINT_TO_POINTER(new_serial);
4364                 else
4365                         *recv = g_slist_prepend(*recv,
4366                                                 GUINT_TO_POINTER(new_serial));
4367
4368                 newcbs = g_new(struct cbs, 1);
4369                 memcpy(newcbs, cbs, sizeof(struct cbs));
4370                 completed = g_slist_append(NULL, newcbs);
4371
4372                 return completed;
4373         }
4374
4375         prev = NULL;
4376         position = 0;
4377
4378         for (l = assembly->assembly_list; l; prev = l, l = l->next) {
4379                 int j;
4380                 node = l->data;
4381
4382                 if (new_serial != node->serial)
4383                         continue;
4384
4385                 if (node->bitmap & (1 << cbs->page))
4386                         return NULL;
4387
4388                 for (j = 1; j < cbs->page; j++)
4389                         if (node->bitmap & (1 << j))
4390                                 position += 1;
4391
4392                 goto out;
4393         }
4394
4395         node = g_new0(struct cbs_assembly_node, 1);
4396         node->serial = new_serial;
4397
4398         assembly->assembly_list = g_slist_prepend(assembly->assembly_list,
4399                                                         node);
4400
4401         prev = NULL;
4402         l = assembly->assembly_list;
4403         position = 0;
4404
4405 out:
4406         newcbs = g_new(struct cbs, 1);
4407         memcpy(newcbs, cbs, sizeof(struct cbs));
4408         node->pages = g_slist_insert(node->pages, newcbs, position);
4409         node->bitmap |= 1 << cbs->page;
4410
4411         if (g_slist_length(node->pages) < cbs->max_pages)
4412                 return NULL;
4413
4414         completed = node->pages;
4415
4416         if (prev)
4417                 prev->next = l->next;
4418         else
4419                 assembly->assembly_list = l->next;
4420
4421         g_free(node);
4422         g_slist_free_1(l);
4423
4424         cbs_assembly_expire(assembly, cbs_compare_node_by_update,
4425                                 GUINT_TO_POINTER(new_serial));
4426         *recv = g_slist_prepend(*recv, GUINT_TO_POINTER(new_serial));
4427
4428         return completed;
4429 }
4430
4431 static inline int skip_to_next_field(const char *str, int pos, int len)
4432 {
4433         if (pos < len && str[pos] == ',')
4434                 pos += 1;
4435
4436         while (pos < len && str[pos] == ' ')
4437                 pos += 1;
4438
4439         return pos;
4440 }
4441
4442 static gboolean next_range(const char *str, int *offset, gint *min, gint *max)
4443 {
4444         int pos;
4445         int end;
4446         int len;
4447         int low = 0;
4448         int high = 0;
4449
4450         len = strlen(str);
4451
4452         pos = *offset;
4453
4454         while (pos < len && str[pos] == ' ')
4455                 pos += 1;
4456
4457         end = pos;
4458
4459         while (str[end] >= '0' && str[end] <= '9') {
4460                 low = low * 10 + (int)(str[end] - '0');
4461                 end += 1;
4462         }
4463
4464         if (pos == end)
4465                 return FALSE;
4466
4467         if (str[end] != '-') {
4468                 high = low;
4469                 goto out;
4470         }
4471
4472         pos = end = end + 1;
4473
4474         while (str[end] >= '0' && str[end] <= '9') {
4475                 high = high * 10 + (int)(str[end] - '0');
4476                 end += 1;
4477         }
4478
4479         if (pos == end)
4480                 return FALSE;
4481
4482 out:
4483         *offset = skip_to_next_field(str, end, len);
4484
4485         if (min)
4486                 *min = low;
4487
4488         if (max)
4489                 *max = high;
4490
4491         return TRUE;
4492 }
4493
4494 GSList *cbs_optimize_ranges(GSList *ranges)
4495 {
4496         struct cbs_topic_range *range;
4497         unsigned char bitmap[125];
4498         GSList *l;
4499         unsigned short i;
4500         GSList *ret = NULL;
4501
4502         memset(bitmap, 0, sizeof(bitmap));
4503
4504         for (l = ranges; l; l = l->next) {
4505                 range = l->data;
4506
4507                 for (i = range->min; i <= range->max; i++) {
4508                         int byte_offset = i / 8;
4509                         int bit = i % 8;
4510
4511                         bitmap[byte_offset] |= 1 << bit;
4512                 }
4513         }
4514
4515         range = NULL;
4516
4517         for (i = 0; i <= 999; i++) {
4518                 int byte_offset = i / 8;
4519                 int bit = i % 8;
4520
4521                 if (is_bit_set(bitmap[byte_offset], bit) == FALSE) {
4522                         if (range) {
4523                                 ret = g_slist_prepend(ret, range);
4524                                 range = NULL;
4525                         }
4526
4527                         continue;
4528                 }
4529
4530                 if (range) {
4531                         range->max = i;
4532                         continue;
4533                 }
4534
4535                 range = g_new0(struct cbs_topic_range, 1);
4536                 range->min = i;
4537                 range->max = i;
4538         }
4539
4540         if (range != NULL)
4541                 ret = g_slist_prepend(ret, range);
4542
4543         ret = g_slist_reverse(ret);
4544
4545         return ret;
4546 }
4547
4548 GSList *cbs_extract_topic_ranges(const char *ranges)
4549 {
4550         int min;
4551         int max;
4552         int offset = 0;
4553         GSList *ret = NULL;
4554         GSList *tmp;
4555
4556         while (next_range(ranges, &offset, &min, &max) == TRUE) {
4557                 if (min < 0 || min > 999)
4558                         return NULL;
4559
4560                 if (max < 0 || max > 999)
4561                         return NULL;
4562
4563                 if (max < min)
4564                         return NULL;
4565         }
4566
4567         if (ranges[offset] != '\0')
4568                 return NULL;
4569
4570         offset = 0;
4571
4572         while (next_range(ranges, &offset, &min, &max) == TRUE) {
4573                 struct cbs_topic_range *range = g_new0(struct cbs_topic_range, 1);
4574
4575                 range->min = min;
4576                 range->max = max;
4577
4578                 ret = g_slist_prepend(ret, range);
4579         }
4580
4581         tmp = cbs_optimize_ranges(ret);
4582         g_slist_foreach(ret, (GFunc) g_free, NULL);
4583         g_slist_free(ret);
4584
4585         return tmp;
4586 }
4587
4588 static inline int element_length(unsigned short element)
4589 {
4590         if (element <= 9)
4591                 return 1;
4592
4593         if (element <= 99)
4594                 return 2;
4595
4596         if (element <= 999)
4597                 return 3;
4598
4599         if (element <= 9999)
4600                 return 4;
4601
4602         return 5;
4603 }
4604
4605 static inline int range_length(struct cbs_topic_range *range)
4606 {
4607         if (range->min == range->max)
4608                 return element_length(range->min);
4609
4610         return element_length(range->min) + element_length(range->max) + 1;
4611 }
4612
4613 char *cbs_topic_ranges_to_string(GSList *ranges)
4614 {
4615         int len = 0;
4616         int nelem = 0;
4617         struct cbs_topic_range *range;
4618         GSList *l;
4619         char *ret;
4620
4621         if (ranges == NULL)
4622                 return g_new0(char, 1);
4623
4624         for (l = ranges; l; l = l->next) {
4625                 range = l->data;
4626
4627                 len += range_length(range);
4628                 nelem += 1;
4629         }
4630
4631         /* Space for ranges, commas and terminator null */
4632         ret = g_new(char, len + nelem);
4633
4634         len = 0;
4635
4636         for (l = ranges; l; l = l->next) {
4637                 range = l->data;
4638
4639                 if (range->min != range->max)
4640                         len += sprintf(ret + len, "%hu-%hu",
4641                                         range->min, range->max);
4642                 else
4643                         len += sprintf(ret + len, "%hu", range->min);
4644
4645                 if (l->next != NULL)
4646                         ret[len++] = ',';
4647         }
4648
4649         return ret;
4650 }
4651
4652 static gint cbs_topic_compare(gconstpointer a, gconstpointer b)
4653 {
4654         const struct cbs_topic_range *range = a;
4655         unsigned short topic = GPOINTER_TO_UINT(b);
4656
4657         if (topic >= range->min && topic <= range->max)
4658                 return 0;
4659
4660         return 1;
4661 }
4662
4663 gboolean cbs_topic_in_range(unsigned int topic, GSList *ranges)
4664 {
4665         if (ranges == NULL)
4666                 return FALSE;
4667
4668         return g_slist_find_custom(ranges, GUINT_TO_POINTER(topic),
4669                                         cbs_topic_compare) != NULL;
4670 }
4671
4672 char *ussd_decode(int dcs, int len, const unsigned char *data)
4673 {
4674         gboolean udhi;
4675         enum sms_charset charset;
4676         gboolean compressed;
4677         gboolean iso639;
4678         char *utf8;
4679
4680         if (!cbs_dcs_decode(dcs, &udhi, NULL, &charset,
4681                                 &compressed, NULL, &iso639))
4682                 return NULL;
4683
4684         if (udhi || compressed || iso639)
4685                 return NULL;
4686
4687         switch (charset) {
4688         case SMS_CHARSET_7BIT:
4689         {
4690                 long written;
4691                 unsigned char *unpacked = unpack_7bit(data, len, 0, TRUE, 0,
4692                                                         &written, 0);
4693                 if (unpacked == NULL)
4694                         return NULL;
4695
4696                 utf8 = convert_gsm_to_utf8(unpacked, written, NULL, NULL, 0);
4697                 g_free(unpacked);
4698
4699                 break;
4700         }
4701         case SMS_CHARSET_8BIT:
4702                 utf8 = convert_gsm_to_utf8(data, len, NULL, NULL, 0);
4703                 break;
4704         case SMS_CHARSET_UCS2:
4705                 utf8 = g_convert((const gchar *) data, len,
4706                                         "UTF-8//TRANSLIT", "UCS-2BE",
4707                                         NULL, NULL, NULL);
4708                 break;
4709         default:
4710                 utf8 = NULL;
4711         }
4712
4713         return utf8;
4714 }
4715
4716 gboolean ussd_encode(const char *str, long *items_written, unsigned char *pdu)
4717 {
4718         unsigned char *converted = NULL;
4719         long written;
4720         long num_packed;
4721
4722         if (pdu == NULL)
4723                 return FALSE;
4724
4725         converted = convert_utf8_to_gsm(str, -1, NULL, &written, 0);
4726         if (converted == NULL || written > 182) {
4727                 g_free(converted);
4728                 return FALSE;
4729         }
4730
4731         pack_7bit_own_buf(converted, written, 0, TRUE, &num_packed, 0, pdu);
4732         g_free(converted);
4733
4734         if (num_packed < 1)
4735                 return FALSE;
4736
4737         if (items_written)
4738                 *items_written = num_packed;
4739
4740         return TRUE;
4741 }