Gammu internals  1.38.0
gsmsms.c
Go to the documentation of this file.
1 /* (c) 2001-2006 by Marcin Wiacek */
2 /* Based on some Pawel Kot and others work from Gnokii (www.gnokii.org)
3  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
4  * GNU GPL version 2 or later
5  */
6 /* Due to a problem in the source code management, the names of some of
7  * the authors have unfortunately been lost. We do not mean to belittle
8  * their efforts and hope they will contact us to see their names
9  * properly added to the Copyright notice above.
10  * Having published their contributions under the terms of the GNU
11  * General Public License (GPL) [version 2], the Copyright of these
12  * authors will remain respected by adhering to the license they chose
13  * to publish their code under.
14  */
15 
16 #include <ctype.h>
17 #include <string.h>
18 #include <time.h>
19 
20 #include <gammu-calendar.h>
21 #include <gammu-message.h>
22 #include <gammu-unicode.h>
23 #include <gammu-debug.h>
24 
25 #include "../../misc/coding/coding.h"
26 #include "../../debug.h"
27 
28 /* User data headers */
30  /* See GSM 03.40 section 9.2.3.24.1
31  * 1 byte 0x00
32  * 1 byte 0x03
33  * 1 byte 0x01: unique ID for message series
34  * 1 byte 0x00: how many SMS in sequence
35  * 1 byte 0x00: number of current SMS in sequence */
36  { UDH_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00",2,-1,4,3},
37 
38  /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */
39  { UDH_DisableVoice, 0x04, "\x01\x02\x00\x00",-1,-1,-1,-1},
40  { UDH_DisableFax, 0x04, "\x01\x02\x01\x00",-1,-1,-1,-1},
41  { UDH_DisableEmail, 0x04, "\x01\x02\x02\x00",-1,-1,-1,-1},
42  { UDH_EnableVoice, 0x04, "\x01\x02\x00\x01",-1,-1,-1,-1},
43  { UDH_EnableFax, 0x04, "\x01\x02\x01\x01",-1,-1,-1,-1},
44  { UDH_EnableEmail, 0x04, "\x01\x02\x02\x01",-1,-1,-1,-1},
45 
46  /* When send such SMS to some phones, they don't display anything,
47  * only beep and enable vibra/light
48  */
49  { UDH_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00",-1,-1,-1,-1},
50 
51  /* Nokia Smart Messaging (short version) UDH
52  * General format :
53  * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address
54  * 1 byte 0x04 : IEI length
55  * 2 bytes : destination address : high & low byte
56  * 2 bytes 0x00 0x00 : originator address : high & low byte */
57  { UDH_NokiaRingtone, 0x06, "\x05\x04\x15\x81\x00\x00",-1,-1,-1,-1},
58  { UDH_NokiaOperatorLogo, 0x06, "\x05\x04\x15\x82\x00\x00",-1,-1,-1,-1},
59  { UDH_NokiaCallerLogo, 0x06, "\x05\x04\x15\x83\x00\x00",-1,-1,-1,-1},
60  { UDH_NokiaWAP, 0x06, "\x05\x04\xc3\x4f\x00\x00",-1,-1,-1,-1},
61 
62  /* Nokia Smart Messaging (long version) UDH and other
63  * General format:
64  * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address
65  * 1 byte 0x04 : IEI length
66  * 2 bytes 0x00 0x00 : destination address : high & low byte
67  * 2 bytes 0x00 0x00 : originator address : high & low byte
68  * 1 byte 0x00 : SAR
69  * 1 byte 0x03 : SAR length
70  * 1 byte : diagram reference number (unique ID for message series)
71  * 1 byte : number of all SMS
72  * 1 byte : number of current SMS */
73  { UDH_NokiaCalendarLong, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00",8,-1,10,9},
74  { UDH_MMSIndicatorLong, 0x0b, "\x05\x04\x0b\x84\x23\xf0\x00\x03\xe5\x00\x00",8,-1,10,9},
75  { UDH_NokiaRingtoneLong, 0x0b, "\x05\x04\x15\x81\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9},
76  { UDH_NokiaOperatorLogoLong, 0x0b, "\x05\x04\x15\x82\x00\x00\x00\x03\x02\x00\x00",8,-1,10,9},
77  { UDH_NokiaProfileLong, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00",8,-1,10,9},
78  { UDH_NokiaPhonebookLong, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9},
79  { UDH_NokiaWAPLong, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00",8,-1,10,9},
80 
81  { UDH_ConcatenatedMessages16bit,0x06, "\x08\x04\x00\x00\x00\x00",-1,2,5,4},
82 
83  { UDH_NoUDH, 0x00, "",-1,-1,-1,-1}
84 };
85 
86 /* --------------------------- Unpacking SMS ------------------------------- */
87 
88 /* See GSM 03.40 section 9.2.3.11 */
89 static GSM_Error GSM_DecodeSMSDateTime(GSM_Debug_Info *di, GSM_DateTime *DT, const unsigned char *req)
90 {
91  DT->Year = DecodeWithBCDAlphabet(req[0]);
92  if (DT->Year < 90) {
93  DT->Year = DT->Year + 2000;
94  } else {
95  DT->Year = DT->Year + 1990;
96  }
97  DT->Month = DecodeWithBCDAlphabet(req[1]);
98  DT->Day = DecodeWithBCDAlphabet(req[2]);
99  DT->Hour = DecodeWithBCDAlphabet(req[3]);
100  DT->Minute = DecodeWithBCDAlphabet(req[4]);
101  DT->Second = DecodeWithBCDAlphabet(req[5]);
102 
103  /* Base for timezone is GMT. It's in quarters */
104  DT->Timezone = (10 * (req[6] & 0x07) + (req[6] >> 4)) *3600 / 4;
105 
106  if (req[6] & 0x08) {
107  DT->Timezone = -DT->Timezone;
108  }
109 
110  if (!CheckDate(DT) || !CheckTime(DT)) {
111  smfprintf(di, "Invalid date & time!\n");
112  DT->Year = 0;
113  return ERR_NONE;
114  }
115 
116  smfprintf(di, "Decoding date & time: %s\n", OSDateTime(*DT, TRUE));
117 
118  return ERR_NONE;
119 }
120 
122 {
123  int i, tmp, w;
124  gboolean UDHOK;
125 
126  UDH->Type = UDH_UserUDH;
127  UDH->ID8bit = -1;
128  UDH->ID16bit = -1;
129  UDH->PartNumber = -1;
130  UDH->AllParts = -1;
131 
132  i=-1;
133  while (UDHHeaders[++i].Type != UDH_NoUDH) {
134 
135  tmp=UDHHeaders[i].Length;
136  /* if length is the same */
137  if (tmp==UDH->Text[0]) {
138 
139  if (tmp == 0x05) {
140  /* three last bytes can be different for such UDH */
141  tmp = tmp - 3;
142  }
143  if (tmp == 0x0b) {
144  /* three last bytes can be different for such UDH */
145  tmp = tmp - 3;
146  }
147  if (tmp == 0x06 && UDH->Text[1] == 0x08) {
148  tmp=tmp-4;
149  }
150 
151  UDHOK = TRUE;
152  for (w = 0; w < tmp; w++) {
153  if (UDHHeaders[i].Text[w] != UDH->Text[w + 1]) {
154  UDHOK = FALSE;
155  break;
156  }
157  }
158  if (UDHOK) {
159  UDH->Type=UDHHeaders[i].Type;
160 
161  if (UDHHeaders[i].ID8bit !=-1) {
162  UDH->ID8bit = UDH->Text[UDHHeaders[i].ID8bit+1];
163  }
164  if (UDHHeaders[i].ID16bit !=-1) {
165  UDH->ID16bit = UDH->Text[UDHHeaders[i].ID16bit+1]*256+UDH->Text[UDHHeaders[i].ID16bit+2];
166  }
167  if (UDHHeaders[i].PartNumber !=-1) {
168  UDH->PartNumber = UDH->Text[UDHHeaders[i].PartNumber+1];
169  }
170  if (UDHHeaders[i].AllParts !=-1) {
171  UDH->AllParts = UDH->Text[UDHHeaders[i].AllParts+1];
172  }
173  break;
174  }
175  }
176  }
177 
178 #ifdef DEBUG
179  smfprintf(di, "Type of UDH: ");
180  switch (UDH->Type) {
182  smfprintf(di, "Concatenated (linked) message");
183  break;
185  smfprintf(di, "Concatenated (linked) message");
186  break;
187  case UDH_DisableVoice:
188  smfprintf(di, "Disables voice indicator");
189  break;
190  case UDH_EnableVoice:
191  smfprintf(di, "Enables voice indicator");
192  break;
193  case UDH_DisableFax:
194  smfprintf(di, "Disables fax indicator");
195  break;
196  case UDH_EnableFax:
197  smfprintf(di, "Enables fax indicator");
198  break;
199  case UDH_DisableEmail:
200  smfprintf(di, "Disables email indicator");
201  break;
202  case UDH_EnableEmail:
203  smfprintf(di, "Enables email indicator");
204  break;
205  case UDH_VoidSMS:
206  smfprintf(di, "Void SMS");
207  break;
208  case UDH_NokiaWAP:
209  smfprintf(di, "Nokia WAP Bookmark");
210  break;
212  smfprintf(di, "Nokia operator logo");
213  break;
214  case UDH_NokiaWAPLong:
215  smfprintf(di, "Nokia WAP Bookmark or WAP/MMS Settings");
216  break;
217  case UDH_NokiaRingtone:
218  smfprintf(di, "Nokia ringtone");
219  break;
221  smfprintf(di, "Nokia ringtone");
222  break;
224  smfprintf(di, "Nokia GSM operator logo");
225  break;
226  case UDH_NokiaCallerLogo:
227  smfprintf(di, "Nokia caller logo");
228  break;
230  smfprintf(di, "Nokia profile");
231  break;
233  smfprintf(di, "Nokia calendar note");
234  break;
236  smfprintf(di, "Nokia phonebook entry");
237  break;
238  case UDH_UserUDH:
239  smfprintf(di, "User UDH");
240  break;
242  smfprintf(di, "MMS indicator");
243  break;
244  case UDH_NoUDH:
245  break;
246  }
247  if (UDH->ID8bit != -1) {
248  smfprintf(di, ", ID 8 bit %i", UDH->ID8bit);
249  }
250  if (UDH->ID16bit != -1) {
251  smfprintf(di, ", ID 16 bit %i", UDH->ID16bit);
252  }
253  if (UDH->PartNumber != -1 && UDH->AllParts != -1) {
254  smfprintf(di, ", part %i of %i",UDH->PartNumber,UDH->AllParts);
255  }
256  smfprintf(di, "\n");
257  DumpMessageText(di, UDH->Text, UDH->Length);
258 #endif
259 }
260 
262 
263  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
264  if ((TPDCS & 0xC0) == 0 || (TPDCS & 0xC0) == 0x40) {
265  /* 0x40 is marked for automatic deletion, we ignore that bit */
266  /* bits 7..4 set to 00xx */
267  if ((TPDCS & 0xC) == 0xC) {
268  smfprintf(di, "WARNING: reserved alphabet value in TPDCS\n");
269  } else {
270  if (TPDCS == 0) {
272  }
273  if ((TPDCS & 0x2C) == 0x00) {
275  }
276  if ((TPDCS & 0x2C) == 0x20) {
278  }
279  if ((TPDCS & 0x2C) == 0x08) {
281  }
282  if ((TPDCS & 0x2C) == 0x28) {
284  }
285  }
286  } else if ((TPDCS & 0xF0) >= 0x40 &&
287  (TPDCS & 0xF0) <= 0xB0) {
288  /* bits 7..4 set to 0100 ... 1011 */
289  smfprintf(di, "WARNING: reserved coding group in TPDCS\n");
290  } else if (((TPDCS & 0xF0) == 0xC0) ||
291  ((TPDCS & 0xF0) == 0xD0)) {
292  /* bits 7..4 set to 1100 or 1101 */
293  if ((TPDCS & 4) == 4) {
294  smfprintf(di, "WARNING: set reserved bit 2 in TPDCS\n");
295  } else {
297  }
298  } else if ((TPDCS & 0xF0) == 0xE0) {
299  /* bits 7..4 set to 1110 */
300  if ((TPDCS & 4) == 4) {
301  smfprintf(di, "WARNING: set reserved bit 2 in TPDCS\n");
302  } else {
304  }
305  } else if ((TPDCS & 0xF0) == 0xF0) {
306  /* bits 7..4 set to 1111 */
307  if ((TPDCS & 8) == 8) {
308  smfprintf(di, "WARNING: set reserved bit 3 in TPDCS\n");
309  } else {
310  if ((TPDCS & 4) == 0) return SMS_Coding_Default_No_Compression;
311  }
312  }
313  return SMS_Coding_8bit;
314 }
315 
317 {
318  int off=0; /* length of the User Data Header */
319  int w,i;
320  unsigned char output[1024];
321 
322  SMS->UDH.Length = 0;
323  /* UDH header available */
324  if (buffer[Layout.firstbyte] & 64) {
325  /* Length of UDH header */
326  off = (buffer[Layout.Text] + 1);
327  if (off > buffer[Layout.TPUDL]) {
328  return ERR_CORRUPTED;
329  }
330  SMS->UDH.Length = off;
331  smfprintf(di, "UDH header available (length %i)\n",off);
332 
333  /* Copy UDH header into SMS->UDH */
334  for (i = 0; i < off; i++) {
335  SMS->UDH.Text[i] = buffer[Layout.Text + i];
336  }
337 
338  GSM_DecodeUDHHeader(di, &SMS->UDH);
339  }
340 
341  switch (SMS->Coding) {
343  i = 0;
344  do {
345  i+=7;
346  w=(i-off)%i;
347  } while (w<0);
348  SMS->Length=buffer[Layout.TPUDL] - (off*8 + w) / 7;
349  if (SMS->Length < 0) {
350  smfprintf(di, "No SMS text!\n");
351  SMS->Length = 0;
352  break;
353  }
354  GSM_UnpackEightBitsToSeven(w, buffer[Layout.TPUDL]-off, SMS->Length, buffer+(Layout.Text+off), output);
355  smfprintf(di, "7 bit SMS, length %i\n",SMS->Length);
356  DecodeDefault (SMS->Text, output, SMS->Length, TRUE, NULL);
357  smfprintf(di, "%s\n",DecodeUnicodeString(SMS->Text));
358  break;
359  case SMS_Coding_8bit:
360  SMS->Length=buffer[Layout.TPUDL] - off;
361  memcpy(SMS->Text,buffer+(Layout.Text+off),SMS->Length);
362 #ifdef DEBUG
363  smfprintf(di, "8 bit SMS, length %i\n",SMS->Length);
364  DumpMessageText(di, SMS->Text, SMS->Length);
365 #endif
366  break;
368  SMS->Length=(buffer[Layout.TPUDL] - off) / 2;
369  DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(Layout.Text+off), SMS->Length);
370 #ifdef DEBUG
371  smfprintf(di, "Unicode SMS, length %i\n",SMS->Length);
372  DumpMessageText(di, buffer+(Layout.Text+off), SMS->Length*2);
373  smfprintf(di, "%s\n",DecodeUnicodeString(SMS->Text));
374 #endif
375  break;
376  default:
377  SMS->Length=0;
378  break;
379  }
380 
381  return ERR_NONE;
382 }
383 
385 {
386  SMS->DeliveryStatus = TP_ST;
388 
389  if (TP_ST < 0x03) {
390  EncodeUnicode(SMS->Text,"Delivered",9);
391  SMS->Length = 9;
392  } else if (TP_ST & 0x40) {
393  EncodeUnicode(SMS->Text,"Failed",6);
394  SMS->Length = 6;
395  } else if (TP_ST & 0x20) {
396  EncodeUnicode(SMS->Text,"Pending",7);
397  SMS->Length = 7;
398  } else {
399  EncodeUnicode(SMS->Text,"Unknown",7);
400  SMS->Length = 7;
401  }
402 
403 #ifdef DEBUG
404  /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
405  if (TP_ST & 0x40) {
406  if (TP_ST & 0x20) {
407  /* 0x60, 0x61, ... */
408  smfprintf(di, "Temporary error, SC is not making any more transfer attempts\n");
409  } else {
410  /* 0x40, 0x41, ... */
411  smfprintf(di, "Permanent error, SC is not making any more transfer attempts\n");
412  }
413  } else if (TP_ST & 0x20) {
414  /* 0x20, 0x21, ... */
415  smfprintf(di, "Temporary error, SC still trying to transfer SM\n");
416  }
417  switch (TP_ST) {
418  case 0x00:
419  smfprintf(di, "SM received by the SME");
420  break;
421  case 0x01:
422  smfprintf(di, "SM forwarded by the SC to the SME but the SC is unable to confirm delivery");
423  break;
424  case 0x02:
425  smfprintf(di, "SM replaced by the SC");
426  break;
427  case 0x20:
428  smfprintf(di, "Congestion");
429  break;
430  case 0x21:
431  smfprintf(di, "SME busy");
432  break;
433  case 0x22:
434  smfprintf(di, "No response from SME");
435  break;
436  case 0x23:
437  smfprintf(di, "Service rejected");
438  break;
439  case 0x24:
440  smfprintf(di, "Quality of service not available");
441  break;
442  case 0x25:
443  smfprintf(di, "Error in SME");
444  break;
445  case 0x40:
446  smfprintf(di, "Remote procedure error");
447  break;
448  case 0x41:
449  smfprintf(di, "Incompatible destination");
450  break;
451  case 0x42:
452  smfprintf(di, "Connection rejected by SME");
453  break;
454  case 0x43:
455  smfprintf(di, "Not obtainable");
456  break;
457  case 0x44:
458  smfprintf(di, "Quality of service not available");
459  break;
460  case 0x45:
461  smfprintf(di, "No internetworking available");
462  break;
463  case 0x46:
464  smfprintf(di, "SM Validity Period Expired");
465  break;
466  case 0x47:
467  smfprintf(di, "SM deleted by originating SME");
468  break;
469  case 0x48:
470  smfprintf(di, "SM Deleted by SC Administration");
471  break;
472  case 0x49:
473  smfprintf(di, "SM does not exist");
474  break;
475  case 0x60:
476  smfprintf(di, "Congestion");
477  break;
478  case 0x61:
479  smfprintf(di, "SME busy");
480  break;
481  case 0x62:
482  smfprintf(di, "No response from SME");
483  break;
484  case 0x63:
485  smfprintf(di, "Service rejected");
486  break;
487  case 0x64:
488  smfprintf(di, "Quality of service not available");
489  break;
490  case 0x65:
491  smfprintf(di, "Error in SME");
492  break;
493  default:
494  smfprintf(di, "Reserved/Specific to SC: %x",TP_ST);
495  break;
496  }
497  smfprintf(di, "\n");
498 #endif
499 
500  return ERR_NONE;
501 }
502 
504 {
505  return GSM_DecodeSMSStatusReportData(di, SMS, buffer[Layout.TPStatus]);
506 }
507 
508 GSM_Error GSM_DecodePDUFrame(GSM_Debug_Info *di, GSM_SMSMessage *SMS, const unsigned char *buffer, size_t length, size_t *final_pos, gboolean SMSC)
509 {
510  size_t pos = 0;
511  int type, tp_pi;
512  int vpf = 0;
513  int udh = 0;
514  int i,w;
515  unsigned char output[161];
516  int datalength;
517  gboolean have_data = FALSE;
518  GSM_Error error;
519 
520  /* Set some sane data */
522 
523  /* Parse SMSC if it is included */
524  if (SMSC) {
525  error = GSM_UnpackSemiOctetNumber(di, SMS->SMSC.Number, buffer, &pos, length, FALSE);
526  if (error != ERR_NONE) {
527  return error;
528  }
529  smfprintf(di, "SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number));
530  }
531 
532  /* Message type */
533  type = buffer[pos];
534  pos++;
535  switch (type & 0x3) {
536  case 0:
537  smfprintf(di, "SMS type: Deliver");
538  SMS->PDU = SMS_Deliver;
539  break;
540  case 1:
541  smfprintf(di, "SMS type: Submit");
542  SMS->PDU = SMS_Submit;
543  break;
544  case 2:
545  smfprintf(di, "SMS type: Status report");
546  SMS->PDU = SMS_Status_Report;
547  break;
548  case 3:
549  smfprintf(di, "SMS type: Reserved message type, aborting!\n");
550  return ERR_UNKNOWN;;
551  }
552 
553  if (SMS->PDU == SMS_Submit || SMS->PDU == SMS_Deliver) {
554  if (type & (1 << 7)) {
555  smfprintf(di, ", Reply path set");
556  }
557  if (type & (1 << 6)) {
558  smfprintf(di, ", UDH included");
559  udh = 1;
560  }
561  if (type & (1 << 5)) {
562  smfprintf(di, ", Delivery report requested");
563  }
564  }
565  if (SMS->PDU == SMS_Submit) {
566  vpf = (type & (0x3 << 3)) >> 3;
567  switch (vpf) {
568  case 0:
569  smfprintf(di, ", No VP");
570  break;
571  case 1:
572  smfprintf(di, ", Reserved VP!\n");
573  return ERR_UNKNOWN;
574  case 2:
575  smfprintf(di, ", Relative VP");
576  break;
577  case 3:
578  smfprintf(di, ", Absolute VP");
579  break;
580  }
581  }
582  smfprintf(di, "\n");
583 
584  /* Message reference */
585  if (SMS->PDU == SMS_Submit || SMS->PDU == SMS_Status_Report) {
586  SMS->MessageReference = buffer[pos];
587  smfprintf(di, "SMS MR: 0x%02X\n", SMS->MessageReference);
588  pos++;
589  if (pos >= length) {
590  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
591  return ERR_CORRUPTED;
592  }
593  }
594 
595  /* Remote number */
596  error = GSM_UnpackSemiOctetNumber(di, SMS->Number, buffer, &pos, length, TRUE);
597  if (error != ERR_NONE) {
598  return error;
599  }
600  smfprintf(di, "Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number));
601  if (pos >= length) {
602  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
603  return ERR_CORRUPTED;
604  }
605 
606 
607  if (SMS->PDU == SMS_Submit || SMS->PDU == SMS_Deliver) {
608  /* Protocol identifier */
609  smfprintf(di, "SMS PID: 0x%02X\n", buffer[pos]);
610  if (buffer[pos] > 0x40 && buffer[pos] < 0x48) {
611  SMS->ReplaceMessage = buffer[pos] - 0x40;
612  }
613  pos++;
614  if (pos >= length) {
615  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
616  return ERR_CORRUPTED;
617  }
618 
619  /* Data coding scheme */
620  smfprintf(di, "SMS DCS: 0x%02X\n", buffer[pos]);
621  SMS->Coding = GSM_GetMessageCoding(di, buffer[pos]);
622 
623  /* Message class */
624  SMS->Class = -1;
625  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
626  if ((buffer[pos] & 0xD0) == 0x10 || (buffer[pos] & 0xF0) == 0xF0) {
627  SMS->Class = buffer[pos] & 3;
628  }
629  smfprintf(di, "SMS class: %i\n", SMS->Class);
630 
631  pos++;
632  if (pos >= length) {
633  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
634  return ERR_CORRUPTED;
635  }
636  }
637 
638  /* SMSC time stamp */
639  if (SMS->PDU == SMS_Status_Report || SMS->PDU == SMS_Deliver) {
640  if (pos + 7 >= length) {
641  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
642  return ERR_CORRUPTED;
643  }
644  GSM_DecodeSMSDateTime(di, &SMS->DateTime, buffer + pos);
645  pos += 7;
646  }
647 
648  if (SMS->PDU == SMS_Status_Report) {
649  /* Discharge Time */
650  if (pos + 7 >= length) {
651  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
652  return ERR_CORRUPTED;
653  }
654  GSM_DecodeSMSDateTime(di, &SMS->SMSCTime, buffer + pos);
655  pos += 7;
656 
657  /* Status */
658  GSM_DecodeSMSStatusReportData(di, SMS, buffer[pos]);
659  pos++;
660 
661  /* Optional part coming from ETSI 123 040, section 9.2.2.3 */
662  /* We ignore 0xff, because some buggy phones pad SMS with it */
663  if (pos < length && buffer[pos] != 0xff) {
664  /* TP-Parameter-Indicator */
665  tp_pi = buffer[pos];
666  pos++;
667 
668  /* We have TP-PID */
669  if (tp_pi & 1) {
670  smfprintf(di, "SMS PID: 0x%02X\n", buffer[pos]);
671  if (buffer[pos] > 0x40 && buffer[pos] < 0x48) {
672  SMS->ReplaceMessage = buffer[pos] - 0x40;
673  }
674  pos++;
675  }
676 
677  /* We have TP-DCS */
678  if (tp_pi & 2) {
679  smfprintf(di, "SMS DCS: 0x%02X\n", buffer[pos]);
680  SMS->Coding = GSM_GetMessageCoding(di, buffer[pos]);
681  pos++;
682  } else {
683  SMS->Coding = GSM_GetMessageCoding(di, 0);
684  }
685 
686  /* We have TP-UDL */
687  if (tp_pi & 4) {
688  have_data = TRUE;
689  }
690  }
691  }
692 
693  /* Validity period */
694  if (SMS->PDU == SMS_Submit) {
695  if (vpf == 2) {
697  SMS->SMSC.Validity.Relative = buffer[pos];
698  smfprintf(di, "Relative validity: 0x%02X\n", buffer[pos]);
699  pos++;
700  if (pos >= length) {
701  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
702  return ERR_CORRUPTED;
703  }
704  } else if (vpf == 3) {
705  /* @todo TODO: handle absolute validity */
706  smfprintf(di, "Absolute validity not handled!\n");
707  pos += 7;
708  if (pos >= length) {
709  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
710  return ERR_CORRUPTED;
711  }
712  }
713  }
714 
715  /* Data */
716  if (SMS->PDU == SMS_Submit || SMS->PDU == SMS_Deliver || have_data) {
717  datalength = buffer[pos];
719  datalength = (datalength * 7) / 8;
720  if ((buffer[pos] * 7) % 8 != 0) {
721  datalength++;
722  }
723  } else if (SMS->Coding == SMS_Coding_Unicode_Compression) {
724  smfprintf(di, "Compressed unicode messages not yet supported!\n");
725  return ERR_NOTSUPPORTED;
726  } else if (SMS->Coding == SMS_Coding_Default_Compression) {
727  smfprintf(di, "Compressed 7-bit messages not yet supported!\n");
728  return ERR_NOTSUPPORTED;
729  }
730 
731  if (pos + datalength >= length) {
732  smfprintf(di, "Ran out of buffer when parsing PDU!\n");
733  return ERR_CORRUPTED;
734  }
735  if (final_pos != NULL) {
736  *final_pos = pos + datalength + 1;
737  }
738  SMS->UDH.Length = 0;
739  /* UDH header available */
740  if (udh) {
741  /* Length of UDH header */
742  SMS->UDH.Length = (buffer[pos + 1] + 1);
743  smfprintf(di, "UDH header available (length %i)\n",SMS->UDH.Length);
744 
745  /* Copy UDH header into SMS->UDH */
746  for (i = 0; i < SMS->UDH.Length; i++) SMS->UDH.Text[i] = buffer[pos + 1 + i];
747 
748  GSM_DecodeUDHHeader(di, &SMS->UDH);
749  }
750 
751  switch (SMS->Coding) {
753  i = 0;
754  do {
755  i+=7;
756  w=(i-SMS->UDH.Length)%i;
757  } while (w<0);
758  SMS->Length=buffer[pos] - (SMS->UDH.Length*8 + w) / 7;
759  if (SMS->Length < 0) {
760  smfprintf(di, "No SMS text!\n");
761  SMS->Length = 0;
762  break;
763  }
764  GSM_UnpackEightBitsToSeven(w, buffer[pos]-SMS->UDH.Length, SMS->Length, buffer+(pos + 1+SMS->UDH.Length), output);
765  smfprintf(di, "7 bit SMS, length %i\n",SMS->Length);
766  DecodeDefault (SMS->Text, output, SMS->Length, TRUE, NULL);
767  smfprintf(di, "%s\n",DecodeUnicodeString(SMS->Text));
768  break;
769  case SMS_Coding_8bit:
770  SMS->Length=buffer[pos] - SMS->UDH.Length;
771  if (SMS->Length < 0) {
772  smfprintf(di, "Invalid message length!\n");
773  return ERR_CORRUPTED;
774  }
775  memcpy(SMS->Text,buffer+(pos + 1+SMS->UDH.Length),SMS->Length);
776 #ifdef DEBUG
777  smfprintf(di, "8 bit SMS, length %i\n",SMS->Length);
778  DumpMessageText(di, SMS->Text, SMS->Length);
779 #endif
780  break;
782  SMS->Length=(buffer[pos] - SMS->UDH.Length) / 2;
783  if (SMS->Length < 0) {
784  smfprintf(di, "Invalid message length!\n");
785  return ERR_CORRUPTED;
786  }
787  DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(pos + 1+SMS->UDH.Length), SMS->Length);
788 #ifdef DEBUG
789  smfprintf(di, "Unicode SMS, length %i\n",SMS->Length);
790  DumpMessageText(di, buffer+(pos + 1+SMS->UDH.Length), SMS->Length*2);
791  smfprintf(di, "%s\n",DecodeUnicodeString(SMS->Text));
792 #endif
793  break;
794  default:
795  SMS->Length=0;
796  break;
797  }
798  } else {
799  if (final_pos != NULL) {
800  *final_pos = pos;
801  }
802  }
803 
804  return ERR_NONE;
805 }
806 
808 {
809  GSM_DateTime zerodt = {0,0,0,0,0,0,0};
810  size_t pos;
811  GSM_Error error;
812 
813 #ifdef DEBUG
814  if (Layout.firstbyte == 255) {
815  smfprintf(di, "ERROR: firstbyte in SMS layout not set\n");
816  return ERR_UNKNOWN;
817  }
818  if (Layout.TPDCS != 255) smfprintf(di, "TPDCS : %02x %i\n",buffer[Layout.TPDCS] ,buffer[Layout.TPDCS]);
819  if (Layout.TPMR != 255) smfprintf(di, "TPMR : %02x %i\n",buffer[Layout.TPMR] ,buffer[Layout.TPMR]);
820  if (Layout.TPPID != 255) smfprintf(di, "TPPID : %02x %i\n",buffer[Layout.TPPID] ,buffer[Layout.TPPID]);
821  if (Layout.TPUDL != 255) smfprintf(di, "TPUDL : %02x %i\n",buffer[Layout.TPUDL] ,buffer[Layout.TPUDL]);
822  if (Layout.firstbyte != 255) smfprintf(di, "FirstByte : %02x %i\n",buffer[Layout.firstbyte],buffer[Layout.firstbyte]);
823  if (Layout.Text != 255 && Layout.TPUDL != 255 && buffer[Layout.TPUDL] > 0) {
824  smfprintf(di, "Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]);
825  }
826 #endif
827 
829 
830  if (Layout.SMSCNumber!=255) {
831  pos = Layout.SMSCNumber;
832  error = GSM_UnpackSemiOctetNumber(di, SMS->SMSC.Number, buffer, &pos, 1000, FALSE);
833  if (error != ERR_NONE) {
834  return error;
835  }
836  smfprintf(di, "SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number));
837  }
838  if ((buffer[Layout.firstbyte] & 0x80)!=0) SMS->ReplyViaSameSMSC=TRUE;
839 #ifdef DEBUG
840  if (SMS->ReplyViaSameSMSC) smfprintf(di, "SMS centre set for reply\n");
841 #endif
842  if (Layout.Number!=255) {
843  pos = Layout.Number;
844  error = GSM_UnpackSemiOctetNumber(di, SMS->Number, buffer, &pos, 1000, TRUE);
845  if (error != ERR_NONE) {
846  return error;
847  }
848  smfprintf(di, "Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number));
849  }
850  if (Layout.TPDCS != 255) {
851  /* Get message coding */
852  SMS->Coding = GSM_GetMessageCoding(di, buffer[Layout.TPDCS]);
853  }
854  if (Layout.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255 && buffer[Layout.TPUDL] > 0) {
855  GSM_DecodeSMSFrameText(di, SMS, buffer, Layout);
856  }
857  if (Layout.DateTime != 255) {
858  GSM_DecodeSMSDateTime(di, &SMS->DateTime,buffer+(Layout.DateTime));
859  } else {
860  SMS->DateTime = zerodt;
861  }
862  if (Layout.SMSCTime != 255 && Layout.TPStatus != 255) {
863  /* GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */
864  smfprintf(di, "SMSC response date: ");
865  GSM_DecodeSMSDateTime(di, &SMS->SMSCTime, buffer+(Layout.SMSCTime));
866  GSM_DecodeSMSFrameStatusReportData(di, SMS,buffer,Layout);
867  } else {
868  SMS->SMSCTime = zerodt;
869  }
870  SMS->Class = -1;
871  if (Layout.TPDCS != 255) {
872  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
873  if ((buffer[Layout.TPDCS] & 0xD0) == 0x10) {
874  /* bits 7..4 set to 00x1 */
875  if ((buffer[Layout.TPDCS] & 0xC) == 0xC) {
876  smfprintf(di, "WARNING: reserved alphabet value in TPDCS\n");
877  } else {
878  SMS->Class = (buffer[Layout.TPDCS] & 3);
879  }
880  } else if ((buffer[Layout.TPDCS] & 0xF0) == 0xF0) {
881  /* bits 7..4 set to 1111 */
882  if ((buffer[Layout.TPDCS] & 8) == 8) {
883  smfprintf(di, "WARNING: set reserved bit 3 in TPDCS\n");
884  } else {
885  SMS->Class = (buffer[Layout.TPDCS] & 3);
886  }
887  }
888  }
889  smfprintf(di, "SMS class: %i\n",SMS->Class);
890 
891  SMS->MessageReference = 0;
892  if (Layout.TPMR != 255) SMS->MessageReference = buffer[Layout.TPMR];
893 
894  SMS->ReplaceMessage = 0;
895  if (Layout.TPPID != 255) {
896  if (buffer[Layout.TPPID] > 0x40 && buffer[Layout.TPPID] < 0x48) {
897  SMS->ReplaceMessage = buffer[Layout.TPPID] - 0x40;
898  }
899  }
900  SMS->RejectDuplicates = FALSE;
901  if ((buffer[Layout.firstbyte] & 0x04)==0x04) SMS->RejectDuplicates = TRUE;
902 
903  return ERR_NONE;
904 }
905 
906 /* ----------------------------- Packing SMS ------------------------------- */
907 
908 /* See GSM 03.40 section 9.2.3.11 */
909 static GSM_Error GSM_EncodeSMSDateTime(GSM_Debug_Info *di, GSM_DateTime *DT, unsigned char *req)
910 {
911  int Year;
912 
913  smfprintf(di, "Encoding SMS datetime: %s\n", OSDate(*DT));
914 
915  /* We need to have only two last digits of year */
916  if (DT->Year>1900) {
917  if (DT->Year<2000) Year = DT->Year-1900;
918  else Year = DT->Year-2000;
919  } else Year = DT->Year;
920 
921  req[0]=EncodeWithBCDAlphabet(Year);
922  req[1]=EncodeWithBCDAlphabet(DT->Month);
923  req[2]=EncodeWithBCDAlphabet(DT->Day);
924  req[3]=EncodeWithBCDAlphabet(DT->Hour);
925  req[4]=EncodeWithBCDAlphabet(DT->Minute);
926  req[5]=EncodeWithBCDAlphabet(DT->Second);
927 
928  /* FIXME: do it */
929  req[6]=0; /* TimeZone = +-0 */
930 
931  return ERR_NONE;
932 }
933 
934 static int GSM_EncodeSMSFrameText(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
935 {
936  int off = 0; /* length of the User Data Header */
937  int size = 0, size2 = 0, w;
938  size_t p;
939  char buff[200];
940 
941  if (SMS->UDH.Type!=UDH_NoUDH) {
942  buffer[Layout.firstbyte] |= 0x40; /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */
943  if (SMS->UDH.Length == 0) {
944  /* off - length of the User Data Header w/o data */
945  off = 1 + SMS->UDH.Text[0];
946  smfprintf(di, "UDL passed from API is 0, using UDHL+1 (%i)\n", off);
947  } else {
948  off = SMS->UDH.Length;
949  smfprintf(di, "UDL: %i, UDHL: %i\n", off, SMS->UDH.Text[0]);
950  }
951  memcpy(buffer+Layout.Text, SMS->UDH.Text, off); /* we copy the udh */
952  smfprintf(di, "UDH, length %i\n",off);
953  DumpMessageText(di, SMS->UDH.Text, off);
954  }
955  switch (SMS->Coding) {
956  case SMS_Coding_8bit:
957  /* the mask for the 8-bit data */
958  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme)
959  * and GSM 03.38 section 4 */
960  buffer[Layout.TPDCS] |= (1 << 2);
961  memcpy(buffer+(Layout.Text+off), SMS->Text, MIN(SMS->Length, 140));
962  size2 = size = SMS->Length+off;
963  smfprintf(di, "8 bit SMS, length %i\n",SMS->Length);
964  DumpMessageText(di, SMS->Text, SMS->Length);
965  break;
967  p = 0;
968  do {
969  p+=7;
970  w=(p-off)%p;
971  } while (w<0);
972  p = MIN(UnicodeLength(SMS->Text), 160);
973  EncodeDefault(buff, SMS->Text, &p, TRUE, NULL);
974  size = GSM_PackSevenBitsToEight(w, buff, buffer+(Layout.Text+off), p);
975  size += off;
976  size2 = (off*8 + w) / 7 + p;
977  smfprintf(di, "7 bit SMS, length %i, %i\n",size,size2);
978  smfprintf(di, "%s\n",DecodeUnicodeString(SMS->Text));
979  if (size > GSM_MAX_8BIT_SMS_LENGTH) {
980  size = 0; size2 = 0;
981  }
982  break;
984  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme)
985  * and GSM 03.38 section 4 */
986  buffer[Layout.TPDCS] |= (1 << 3);
987  EncodeUnicodeSpecialNOKIAChars(buffer+(Layout.Text+off), SMS->Text, MIN(UnicodeLength(SMS->Text), 70));
988  size=size2=UnicodeLength(buffer+(Layout.Text+off))*2+off;
989  smfprintf(di, "Unicode SMS, length %i\n",(size2-off)/2);
990  DumpMessageText(di, buffer+(Layout.Text+off), size2-off);
991  smfprintf(di, "%s\n",DecodeUnicodeString(buffer+(Layout.Text+off)));
992  break;
993  default:
994  break;
995  }
996 
997  /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length)
998  * SMS->Length is:
999  - integer representation of the number od octets within the
1000  user data when TP-User-Data is coded using 8 bit data
1001  - the sum of the number of septets in UDH including any padding
1002  and the number of septets in TP-User-Data in other case
1003  */
1004  buffer[Layout.TPUDL] = size2;
1005  return size;
1006 }
1007 
1008 GSM_Error GSM_EncodeSMSFrame(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, gboolean clear)
1009 {
1010  int i;
1011 
1012  if (clear) {
1013  /* Cleaning up to the SMS text */
1014  for (i=0;i<Layout.Text;i++) buffer[i] = 0;
1015  }
1016 
1017  /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */
1018  switch (SMS->PDU) {
1019  case SMS_Submit:
1020  buffer[Layout.firstbyte] |= 0x01;
1021  break;
1022  /* SMS_Status_Report when Submit sms should have delivery report */
1023  /* We DON'T CREATE FRAME FOR REAL SMS_STATUS_REPORT */
1024  case SMS_Status_Report:
1025  buffer[Layout.firstbyte] |= 0x01;
1026  /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */
1027  /* Set when want delivery report from SMSC */
1028  buffer[Layout.firstbyte] |= 0x20;
1029  break;
1030  case SMS_Deliver:
1031  buffer[Layout.firstbyte] |= 0x00;
1032  }
1033 
1034  /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */
1035  if (SMS->ReplyViaSameSMSC) buffer[Layout.firstbyte] |= 0x80;
1036 
1037  if (Layout.Number!=255) {
1038  buffer[Layout.Number] = GSM_PackSemiOctetNumber(SMS->Number,buffer+(Layout.Number+1),TRUE);
1039  smfprintf(di, "Recipient number \"%s\"\n",DecodeUnicodeString(SMS->Number));
1040  }
1041  if (Layout.SMSCNumber!=255) {
1042  buffer[Layout.SMSCNumber]=GSM_PackSemiOctetNumber(SMS->SMSC.Number,buffer+(Layout.SMSCNumber+1), FALSE);
1043  smfprintf(di, "SMSC number \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number));
1044  }
1045 
1046  /* Message Class*/
1047  /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
1048  if (Layout.TPDCS != 255) {
1049  if (SMS->Class >= 0 && SMS->Class <= 3) buffer[Layout.TPDCS] |= SMS->Class | (1 << 4);
1050  smfprintf(di, "SMS class %i\n",SMS->Class);
1051  }
1052 
1053  if (Layout.TPVP != 255) {
1054  /* GSM 03.40 section 9.2.3.3 (TP-Validity-Period-Format) */
1055  /* Bits 4 and 3: 10. TP-VP field present and integer represent (relative) */
1056  buffer[Layout.firstbyte] |= 0x10;
1057  buffer[Layout.TPVP]=((unsigned char)SMS->SMSC.Validity.Relative);
1058  smfprintf(di, "SMS validity %02x\n",SMS->SMSC.Validity.Relative);
1059  }
1060 
1061  if (Layout.DateTime != 255) {
1062  GSM_EncodeSMSDateTime(di, &SMS->DateTime, buffer+Layout.DateTime);
1063  }
1064 
1065  if (Layout.TPMR != 255) {
1066  smfprintf(di, "TPMR: %02x %i\n",SMS->MessageReference,SMS->MessageReference);
1067  buffer[Layout.TPMR] = SMS->MessageReference;
1068  }
1069 
1070  if (SMS->RejectDuplicates) {
1071  /* GSM 03.40 section 9.2.3.25 (TP Reject Duplicates) */
1072  buffer[Layout.firstbyte] |= 0x04;
1073  }
1074 
1075  if (Layout.TPPID != 255) {
1076  buffer[Layout.TPPID] = 0;
1077  if (SMS->ReplaceMessage > 0 && SMS->ReplaceMessage < 8) {
1078  buffer[Layout.TPPID] = 0x40 + SMS->ReplaceMessage;
1079  }
1080  }
1081 
1082  /* size is the length of the data in octets including UDH */
1083  *length=GSM_EncodeSMSFrameText(di, SMS,buffer,Layout);
1084 /* if (*length == 0) return GE_UNKNOWN; */
1085  *length += Layout.Text;
1086 
1087  return ERR_NONE;
1088 }
1089 
1090 /* ----------------- Some help functions ----------------------------------- */
1091 
1093 {
1094  SMS->UDH.Type = UDH_NoUDH;
1095  SMS->UDH.Length = 0;
1096  SMS->UDH.Text[0] = 0;
1097  SMS->UDH.ID8bit = 0;
1098  SMS->UDH.ID16bit = 0;
1099  SMS->UDH.PartNumber = -1;
1100  SMS->UDH.AllParts = 0;
1101  SMS->Coding = SMS_Coding_8bit;
1102  SMS->Length = 0;
1103  SMS->SMSC.Location = 0;
1104  SMS->SMSC.DefaultNumber[0] = 0;
1105  SMS->SMSC.DefaultNumber[1] = 0;
1106  SMS->SMSC.Number[0] = 0;
1107  SMS->SMSC.Number[1] = 0;
1108  SMS->SMSC.Name[0] = 0;
1109  SMS->SMSC.Name[1] = 0;
1112  SMS->SMSC.Format = SMS_FORMAT_Text;
1113  SMS->Number[0] = 0;
1114  SMS->Number[1] = 0;
1115  SMS->OtherNumbersNum = 0;
1116  SMS->Name[0] = 0;
1117  SMS->Name[1] = 0;
1118  SMS->ReplyViaSameSMSC = FALSE;
1119  SMS->Class = 0;
1120  SMS->Text[0] = 0;
1121  SMS->Text[1] = 0;
1122  SMS->RejectDuplicates = FALSE;
1123  SMS->MessageReference = 0;
1124  SMS->ReplaceMessage = 0;
1125  SMS->DeliveryStatus = 0;
1126  SMS->DateTime.Year = 0;
1127 }
1128 
1130 {
1132 
1135  SMS->SMSC.Location = 1;
1136 
1137  /* This part is required to save SMS */
1138  SMS->State = SMS_UnSent;
1139  SMS->PDU = SMS_Submit;
1140  SMS->Location = 0;
1141  SMS->Memory = 0;
1142  SMS->Folder = 0x02; /*Outbox*/
1143  SMS->InboxFolder = FALSE;
1146 }
1147 
1152 {
1153  int i=0;
1154 
1155  if (UDH->Type == UDH_NoUDH) {
1156  UDH->Length = 0;
1157  return;
1158  }
1159  if (UDH->Type == UDH_UserUDH) {
1160  UDH->Length = UDH->Text[0] + 1;
1161  return;
1162  }
1163  while (TRUE) {
1164  if (UDHHeaders[i].Type==UDH_NoUDH) {
1165  smfprintf(di, "Not supported UDH type\n");
1166  break;
1167  }
1168  if (UDHHeaders[i].Type!=UDH->Type) {
1169  i++;
1170  continue;
1171  }
1172  /* UDH Length */
1173  UDH->Text[0] = UDHHeaders[i].Length;
1174  memcpy(UDH->Text+1, UDHHeaders[i].Text, UDHHeaders[i].Length);
1175  UDH->Length = UDH->Text[0] + 1;
1176 
1177  if (UDHHeaders[i].ID8bit != -1) {
1178  UDH->Text[UDHHeaders[i].ID8bit+1] = UDH->ID8bit % 256;
1179  } else {
1180  UDH->ID8bit = -1;
1181  }
1182  if (UDHHeaders[i].ID16bit != -1) {
1183  UDH->Text[UDHHeaders[i].ID16bit+1] = UDH->ID16bit / 256;
1184  UDH->Text[UDHHeaders[i].ID16bit+2] = UDH->ID16bit % 256;
1185  } else {
1186  UDH->ID16bit = -1;
1187  }
1188  if (UDHHeaders[i].PartNumber != -1) {
1189  UDH->Text[UDHHeaders[i].PartNumber+1] = UDH->PartNumber;
1190  } else {
1191  UDH->PartNumber = -1;
1192  }
1193  if (UDHHeaders[i].AllParts != -1) {
1194  UDH->Text[UDHHeaders[i].AllParts+1] = UDH->AllParts;
1195  } else {
1196  UDH->AllParts = -1;
1197  }
1198  break;
1199  }
1200 }
1201 
1203  GSM_SMSMessage *SMS)
1204 {
1205  int current;
1206 
1207  if (SMS->PDU != SMS_Deliver) {
1208  return FALSE;
1209  }
1210  if (SMS->Coding != SMS_Coding_8bit) {
1211  return FALSE;
1212  }
1213  if (SMS->Class != 1) {
1214  return FALSE;
1215  }
1216  if (SMS->UDH.Type != UDH_NoUDH) {
1217  return FALSE;
1218  }
1219  if (SMS->Length < 22) {
1220  return FALSE;
1221  }
1222 
1223  if (strncmp(SMS->Text, "//SEO",5) != 0) {
1224  return FALSE; /* Siemens Exchange Object */
1225  }
1226  if (SMS->Text[5] != 1) {
1227  return FALSE; /* version 1 */
1228  }
1229  Info->DataLen = SMS->Text[6] + SMS->Text[7]*256;
1230  Info->SequenceID = SMS->Text[8] + SMS->Text[9]*256 +
1231  SMS->Text[10]*256*256 + SMS->Text[11]*256*256*256;
1232  Info->PacketNum = SMS->Text[12] + SMS->Text[13]*256;
1233  Info->PacketsNum = SMS->Text[14] + SMS->Text[15]*256;
1234  smfprintf(di, "Packet %i/%i\n",Info->PacketNum,Info->PacketsNum);
1235  Info->AllDataLen = SMS->Text[16] + SMS->Text[17]*256 +
1236  SMS->Text[18]*256*256 + SMS->Text[19]*256*256*256;
1237  smfprintf(di, "DataLen %i/%lu\n",Info->DataLen,Info->AllDataLen);
1238 
1239  if (SMS->Text[20] > 9) {
1240  return FALSE;
1241  }
1242  memcpy(Info->DataType,SMS->Text+21,SMS->Text[20]);
1243  Info->DataType[SMS->Text[20]] = 0;
1244  smfprintf(di, "DataType '%s'\n",Info->DataType);
1245 
1246  current = 21+SMS->Text[20];
1247  if (SMS->Text[current] > 39) {
1248  return FALSE;
1249  }
1250  memcpy(Info->DataName,SMS->Text+current+1,SMS->Text[current]);
1251  Info->DataName[SMS->Text[current]] = 0;
1252  smfprintf(di, "DataName '%s'\n",Info->DataName);
1253 
1254  current += SMS->Text[current]+1;
1255  memcpy(Info->Data,SMS->Text+current,Info->DataLen);
1256 
1257  return TRUE;
1258 }
1259 
1261 {
1262  /* Maintain those without compression for backward compatibility */
1263  if (s == NULL) {
1265  } else if (strcmp("Unicode", s) == 0) {
1267  } else if (strcmp("Unicode_No_Compression", s) == 0) {
1269  } else if (strcmp("Unicode_Compression", s) == 0) {
1271  } else if (strcmp("Default", s) == 0) {
1273  } else if (strcmp("Default_No_Compression", s) == 0) {
1275  } else if (strcmp("Default_Compression", s) == 0) {
1277  } else if (strcmp("8bit", s) == 0) {
1278  return SMS_Coding_8bit;
1279  }
1280 
1281  return 0;
1282 }
1283 
1285 {
1286  switch (type) {
1288  return "Unicode_No_Compression";
1290  return "Unicode_Compression";
1292  return "Default_No_Compression";
1294  return "Default_Compression";
1295  case SMS_Coding_8bit:
1296  return "8bit";
1297  }
1298 
1299  return NULL;
1300 }
1301 
1302 /* How should editor hadle tabs in this file? Add editor commands here.
1303  * vim: noexpandtab sw=8 ts=8 sts=8:
1304  */
unsigned char Text
GSM_SMSMessageType PDU
GSM_DateTime DateTime
unsigned char TPUDL
void GSM_SetDefaultReceivedSMSData(GSM_SMSMessage *SMS)
Definition: gsmsms.c:1092
GSM_Error GSM_DecodeSMSStatusReportData(GSM_Debug_Info *di, GSM_SMSMessage *SMS, int TP_ST)
Definition: gsmsms.c:384
unsigned char Text[(GSM_MAX_SMS_LENGTH+1) *2]
char * DecodeUnicodeString(const unsigned char *src)
Definition: coding.c:245
unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1) *2]
static GSM_Error GSM_DecodeSMSDateTime(GSM_Debug_Info *di, GSM_DateTime *DT, const unsigned char *req)
Definition: gsmsms.c:89
unsigned char TPDCS
void DecodeDefault(unsigned char *dest, const unsigned char *src, size_t len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
Definition: coding.c:498
char * OSDate(GSM_DateTime dt)
Definition: misc.c:305
unsigned char ReplaceMessage
GSM_SMS_State State
const char * GSM_SMSCodingToString(GSM_Coding_Type type)
Definition: gsmsms.c:1284
int GSM_PackSemiOctetNumber(const unsigned char *Number, unsigned char *Output, gboolean semioctet)
Definition: coding.c:1125
unsigned char SMSCTime
void DumpMessageText(GSM_Debug_Info *d, const unsigned char *message, const size_t messagesize)
Definition: debug.c:371
GSM_Error GSM_DecodeSMSFrame(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
Definition: gsmsms.c:807
int GSM_PackSevenBitsToEight(size_t offset, const unsigned char *input, unsigned char *output, size_t length)
Definition: coding.c:993
GSM_Error
Definition: gammu-error.h:23
gboolean RejectDuplicates
GSM_Error GSM_DecodePDUFrame(GSM_Debug_Info *di, GSM_SMSMessage *SMS, const unsigned char *buffer, size_t length, size_t *final_pos, gboolean SMSC)
Definition: gsmsms.c:508
signed char Class
static GSM_UDHHeader UDHHeaders[]
Definition: gsmsms.c:29
void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS)
Definition: gsmsms.c:1129
size_t UnicodeLength(const unsigned char *str)
Definition: coding.c:186
GSM_UDHHeader UDH
static GSM_Error GSM_EncodeSMSDateTime(GSM_Debug_Info *di, GSM_DateTime *DT, unsigned char *req)
Definition: gsmsms.c:909
unsigned char DataName[40]
unsigned char DeliveryStatus
GSM_Coding_Type Coding
unsigned char SMSCNumber
GSM_SMSFormat Format
unsigned long AllDataLen
#define GSM_MAX_8BIT_SMS_LENGTH
Definition: gammu-limits.h:190
unsigned char EncodeWithBCDAlphabet(int value)
Definition: coding.c:315
gboolean GSM_DecodeSiemensOTASMS(GSM_Debug_Info *di, GSM_SiemensOTASMSInfo *Info, GSM_SMSMessage *SMS)
Definition: gsmsms.c:1202
unsigned char Text[GSM_MAX_UDH_LENGTH]
unsigned char Data[140]
unsigned char DefaultNumber[(GSM_MAX_NUMBER_LENGTH+1) *2]
int gboolean
Definition: gammu-types.h:23
GSM_ValidityPeriodFormat Format
void EncodeUnicode(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:301
unsigned char Name[(GSM_MAX_SMS_NAME_LENGTH+1) *2]
gboolean InboxFolder
GSM_Error GSM_DecodeSMSFrameText(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
Definition: gsmsms.c:316
#define FALSE
Definition: gammu-types.h:25
GSM_SMSValidity Validity
unsigned int PacketNum
GSM_Coding_Type GSM_StringToSMSCoding(const char *s)
Definition: gsmsms.c:1260
unsigned int PacketsNum
unsigned char TPVP
GSM_Coding_Type GSM_GetMessageCoding(GSM_Debug_Info *di, const char TPDCS)
Definition: gsmsms.c:261
gboolean CheckTime(GSM_DateTime *date)
Definition: misc.c:363
int DecodeWithBCDAlphabet(unsigned char value)
Definition: coding.c:323
char * OSDateTime(GSM_DateTime dt, gboolean TimeZone)
Definition: misc.c:264
unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1) *2]
unsigned char firstbyte
static int GSM_EncodeSMSFrameText(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
Definition: gsmsms.c:934
void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
Definition: coding.c:1401
GSM_Coding_Type
GSM_Error GSM_UnpackSemiOctetNumber(GSM_Debug_Info *di, unsigned char *retval, const unsigned char *Number, size_t *pos, size_t bufferlength, gboolean semioctet)
Definition: coding.c:1028
int GSM_UnpackEightBitsToSeven(size_t offset, size_t in_length, size_t out_length, const unsigned char *input, unsigned char *output)
Definition: coding.c:953
void GSM_GetCurrentDateTime(GSM_DateTime *Date)
Definition: misc.c:184
unsigned char TPStatus
void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
Definition: coding.c:1367
GSM_Error GSM_EncodeSMSFrame(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, gboolean clear)
Definition: gsmsms.c:1008
void GSM_DecodeUDHHeader(GSM_Debug_Info *di, GSM_UDHHeader *UDH)
Definition: gsmsms.c:121
int smfprintf(GSM_Debug_Info *d, const char *format,...)
Definition: debug.c:240
void GSM_EncodeUDHHeader(GSM_Debug_Info *di, GSM_UDHHeader *UDH)
Definition: gsmsms.c:1151
#define MIN(a, b)
Definition: gammu-misc.h:70
#define TRUE
Definition: gammu-types.h:28
unsigned char MessageReference
gboolean ReplyViaSameSMSC
GSM_DateTime SMSCTime
unsigned char DateTime
unsigned char Number
void EncodeDefault(unsigned char *dest, const unsigned char *src, size_t *len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
Definition: coding.c:831
unsigned char TPMR
GSM_ValidityPeriod Relative
gboolean CheckDate(GSM_DateTime *date)
Definition: misc.c:349
GSM_MemoryType Memory
unsigned long SequenceID
GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_Debug_Info *di, GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
Definition: gsmsms.c:503
unsigned char DataType[10]
unsigned char TPPID
unsigned char Name[(GSM_MAX_SMSC_NAME_LENGTH+1) *2]