Gammu internals  1.38.0
gsmmulti.c
Go to the documentation of this file.
1 /* (c) 2002-2006 by Marcin Wiacek */
2 
3 #include <ctype.h>
4 #include <string.h>
5 #include <time.h>
6 
7 #include <gammu-unicode.h>
8 #include <gammu-debug.h>
9 
10 #include "gsmmulti.h"
11 #include "../gsmring.h"
12 #include "../gsmlogo.h"
13 #include "../../misc/coding/coding.h"
14 #include "../../debug.h"
15 #include "gsmems.h"
16 #include "../gsmdata.h"
17 #include "../gsmnet.h"
18 
19 /* ----------------- Splitting SMS into parts ------------------------------ */
20 
21 unsigned char GSM_MakeSMSIDFromTime(void)
22 {
23  GSM_DateTime Date;
24  unsigned char retval;
25 
26  GSM_GetCurrentDateTime (&Date);
27  retval = Date.Second;
28  switch (Date.Minute/10) {
29  case 2: case 7: retval = retval + 60; break;
30  case 4: case 8: retval = retval + 120; break;
31  case 9: case 5: case 0: retval = retval + 180; break;
32  }
33  retval += Date.Minute/10;
34  return retval;
35 }
36 
37 void GSM_Find_Free_Used_SMS2(GSM_Debug_Info *di, GSM_Coding_Type Coding,GSM_SMSMessage *SMS, size_t *UsedText, size_t *FreeText, size_t *FreeBytes)
38 {
39  size_t UsedBytes = 0;
40 
41  switch (Coding) {
43  FindDefaultAlphabetLen(SMS->Text,&UsedBytes,UsedText,500);
44  UsedBytes = *UsedText * 7 / 8;
45  if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++;
46  *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
47  *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length) * 8 / 7 - *UsedText;
48  break;
50  *UsedText = UnicodeLength(SMS->Text);
51  UsedBytes = *UsedText * 2;
52  *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
53  *FreeText = *FreeBytes / 2;
54  break;
55  case SMS_Coding_8bit:
56  *UsedText = UsedBytes = SMS->Length;
57  *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
58  *FreeText = *FreeBytes;
59  break;
60  default:
61  break;
62  }
63  smfprintf(di, "UDH len %i, UsedBytes %ld, FreeText %ld, UsedText %ld, FreeBytes %ld\n",
64  SMS->UDH.Length,
65  (long)UsedBytes,
66  (long)*FreeText,
67  (long)*UsedText,
68  (long)*FreeBytes);
69 }
70 
71 unsigned int ReassembleCharacter(char *Buffer, size_t character_index)
72 {
73  size_t offset = character_index * 2;
74 
75  return (
76  (unsigned int) ((unsigned char) Buffer[offset] << 8)
77  + (unsigned char) Buffer[offset + 1]
78  );
79 }
80 
82  size_t *Copy,
83  char *Buffer,
84  size_t BufferLen)
85 {
86  int rv = 0;
87  unsigned int n;
88 
89  /* Precondition:
90  * Resulting copy must always be non-zero. */
91 
92  if (*Copy <= 1) {
93  return rv;
94  }
95 
96  /* Don't split a UTF-16 surrogate pair:
97  * If the final code unit to be copied is a lead surrogate, save
98  * it for the next message segment. This allows recipients to view
99  * the proper four-byte UTF-16 character even if they're unable to
100  * reassemble the message (e.g. if a telecom strips off the UDH). */
101 
102  n = ReassembleCharacter(Buffer, *Copy - 1);
103 
104  /* UTF-16 leading surrogate:
105  * First character in pair is always between U+D800 and U+DBFF */
106 
107  if (n >= 0xd800 && n <= 0xdbff) {
108  *Copy -= 1;
109  ++rv;
110  }
111 
112  return rv;
113 }
114 
116  size_t *Copy,
117  char *Buffer,
118  size_t BufferLen)
119 {
120  int rv = 0;
121  unsigned int n;
122 
123  /* Precondition:
124  * If we only have one character to copy, or if there isn't any
125  * code unit following our copy window, don't change anything. */
126 
127  if (*Copy <= 1 || *Copy >= BufferLen) {
128  return rv;
129  }
130 
131  /* Don't split up a combining sequence:
132  * Peek at the next message segment to see if it begins with
133  * a combining character (e.g. a discritical mark). If it does,
134  * push the final character of this message segment in to the
135  * next message segment. This ensures that the recipient can
136  * visually combine the sequence, even if reassembly fails. */
137 
138  n = ReassembleCharacter(Buffer, *Copy);
139 
140  /* Unicode combining characters:
141  * Combining Half Marks (U+FE20 - U+FE2F)
142  * Combining Diacritical Marks (U+300 - U+36F)
143  * Combining Diacritical Marks Extended (U+1AB0 - U+1AFF)
144  * Combining Diacritical Marks Supplement (U+1DC0 - U+1DFF)
145  * Combining Diacritical Marks for Symbols (U+20D0 - U+20FF) */
146 
147  if ((n >= 0xfe20 && n <= 0xfe2f) ||
148  (n >= 0x300 && n <= 0x36f) || (n >= 0x1ab0 && n <= 0x1aff) ||
149  (n >= 0x1dc0 && n <= 0x1dff) || (n >= 0x20d0 && n <= 0x20ff)) {
150  *Copy -= 1;
151  ++rv;
152  }
153 
154  return rv;
155 }
156 
158  size_t *Copy,
159  char *Buffer,
160  size_t BufferLen)
161 {
162  int rv = 0;
163  unsigned int l1, l2, r1, r2;
164 
165  /* Precondition:
166  * If we have two or fewer characters to copy, omitting two
167  * of them would cause us to send empty message segments. If
168  * there aren't at least two characters remaining *after* the
169  * copy boundary, then there can't possibly be space for a
170  * second surrogate pair there. In either case, send as-is. */
171 
172  if (*Copy <= 2 || (*Copy + 2) >= BufferLen) {
173  return rv;
174  }
175 
176  /* Fetch characters:
177  * We retrieve two UTF-16 characters directly preceeding the
178  * copy boundary, and two directly following the copy boundary. */
179 
180  l1 = ReassembleCharacter(Buffer, *Copy - 2);
181  l2 = ReassembleCharacter(Buffer, *Copy - 1);
182  r1 = ReassembleCharacter(Buffer, *Copy);
183  r2 = ReassembleCharacter(Buffer, *Copy + 1);
184 
185  /* Regional Indicator Symbol (U+1F1E6 - U+1F1FF)
186  * UTF-16 surrogate pairs: 0xd83c 0xdde6 - 0xd83c 0xddff */
187 
188  if (l1 == 0xd83c && r1 == 0xd83c &&
189  l2 >= 0xdde6 && l2 <= 0xddff && r2 >= 0xdde6 && r2 <= 0xddff) {
190  *Copy -= 2;
191  rv += 2;
192  }
193 
194  return rv;
195 }
196 
198  size_t *Copy,
199  char *Buffer,
200  size_t BufferLen)
201 {
202  int rv = 0;
203 
204  if (!(rv += AlignIfSurrogatePair(di, Copy, Buffer, BufferLen))) {
205  rv += AlignIfCombinedCharacter(di, Copy, Buffer, BufferLen);
206  }
207 
208  rv += AlignIfCombinedSurrogate(di, Copy, Buffer, BufferLen);
209  return rv;
210 }
211 
213  GSM_MultiSMSMessage *SMS,
214  GSM_Coding_Type Coding,
215  char *Buffer,
216  size_t BufferLen,
217  gboolean UDH,
218  size_t *UsedText,
219  size_t *CopiedText,
220  size_t *CopiedSMSText)
221 {
222  size_t FreeText=0,FreeBytes=0,Copy,i,j;
223 
224  smfprintf(di, "Checking used: ");
226  di, Coding, &(SMS->SMS[SMS->Number]),
227  UsedText, &FreeText, &FreeBytes
228  );
229 
230  if (UDH) {
231  smfprintf(di, "Adding UDH\n");
232  if (FreeBytes - BufferLen <= 0) {
233  smfprintf(di, "Going to the new SMS\n");
234  SMS->Number++;
236  di, Coding, &(SMS->SMS[SMS->Number]),
237  UsedText, &FreeText, &FreeBytes
238  );
239  }
240  if (SMS->SMS[SMS->Number].UDH.Length == 0) {
241  SMS->SMS[SMS->Number].UDH.Length = 1;
242  SMS->SMS[SMS->Number].UDH.Text[0] = 0x00;
243  }
244  memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen);
245  SMS->SMS[SMS->Number].UDH.Length += BufferLen;
246  SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen;
247  SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH;
248  smfprintf(di, "UDH added %ld\n", (long)BufferLen);
249  } else {
250  smfprintf(di, "Adding text\n");
251  if (FreeText == 0) {
252  smfprintf(di, "Going to the new SMS\n");
253  SMS->Number++;
255  di, Coding, &(SMS->SMS[SMS->Number]),
256  UsedText, &FreeText, &FreeBytes
257  );
258  }
259 
260  Copy = FreeText;
261  smfprintf(di, "Copy %ld (max %ld)\n", (long)Copy, (long)BufferLen);
262  if (BufferLen < Copy) {
263  Copy = BufferLen;
264  }
265 
266  switch (Coding) {
268  FindDefaultAlphabetLen(Buffer,&i,&j,FreeText);
269  smfprintf(di, "Defalt text, length %ld %ld\n", (long)i, (long)j);
270  SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0;
271  SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0;
272  memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2);
273  *CopiedText = i;
274  *CopiedSMSText = j;
275  SMS->SMS[SMS->Number].Length += i;
276  break;
278  AlignSegmentForContent(di, &Copy, Buffer, BufferLen);
279  SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0;
280  SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0;
281  memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2);
282  *CopiedText = *CopiedSMSText = Copy;
283  SMS->SMS[SMS->Number].Length += Copy;
284  break;
285  case SMS_Coding_8bit:
286  memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy);
287  SMS->SMS[SMS->Number].Length += Copy;
288  *CopiedText = *CopiedSMSText = Copy;
289  break;
290  default:
291  break;
292  }
293  smfprintf(di, "Text added\n");
294  }
295 
296  smfprintf(di, "Checking at the end: ");
298  di, Coding, &(SMS->SMS[SMS->Number]),
299  UsedText, &FreeText, &FreeBytes
300  );
301 
302  return ERR_NONE;
303 }
304 
306  unsigned char *MessageBuffer,
307  size_t MessageLength,
308  GSM_UDH UDHType,
309  GSM_Coding_Type Coding,
310  int Class,
311  unsigned char ReplaceMessage)
312 {
313  size_t Len,UsedText = 0,CopiedText = 0,CopiedSMSText = 0;
314  int j;
315  unsigned char UDHID;
316  GSM_DateTime Date;
317 
318  Len = 0;
319  while(1) {
320  if (SMS->Number >= GSM_MAX_MULTI_SMS) {
321  break;
322  }
323  GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]);
324  SMS->SMS[SMS->Number].Class = Class;
325  SMS->SMS[SMS->Number].Coding = Coding;
326 
327  SMS->SMS[SMS->Number].UDH.Type = UDHType;
328  GSM_EncodeUDHHeader(di, &SMS->SMS[SMS->Number].UDH);
329 
330  if (Coding == SMS_Coding_8bit) {
331  GSM_AddSMS_Text_UDH(di, SMS,Coding,MessageBuffer+Len,MessageLength - Len,FALSE,&UsedText,&CopiedText,&CopiedSMSText);
332  } else {
333  GSM_AddSMS_Text_UDH(di, SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,FALSE,&UsedText,&CopiedText,&CopiedSMSText);
334  }
335  Len += CopiedText;
336  smfprintf(di, "%ld %ld\n", (long)Len, (long)MessageLength);
337  SMS->Number++;
338  if (Len == MessageLength) break;
339  }
340 
341  UDHID = GSM_MakeSMSIDFromTime();
342  GSM_GetCurrentDateTime (&Date);
343  for (j=0;j<SMS->Number;j++) {
344  SMS->SMS[j].UDH.Type = UDHType;
345  SMS->SMS[j].UDH.ID8bit = UDHID;
346  SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour;
347  SMS->SMS[j].UDH.PartNumber = j+1;
348  SMS->SMS[j].UDH.AllParts = SMS->Number;
349  GSM_EncodeUDHHeader(di, &SMS->SMS[j].UDH);
350  }
351  if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage;
352 }
353 
354 /* Calculates number of SMS and number of left chars in SMS */
356  unsigned char *MessageBuffer,
357  GSM_UDH UDHType,
358  GSM_Coding_Type Coding,
359  int *SMSNum,
360  size_t *CharsLeft)
361 {
362  size_t UsedText=0,FreeBytes=0;
363  GSM_MultiSMSMessage MultiSMS;
364 
365  MultiSMS.Number = 0;
366  GSM_MakeMultiPartSMS(di, &MultiSMS,MessageBuffer,UnicodeLength(MessageBuffer),UDHType,Coding,-1,FALSE);
368  di, Coding, &(MultiSMS.SMS[MultiSMS.Number-1]),
369  &UsedText, CharsLeft, &FreeBytes
370  );
371  *SMSNum = MultiSMS.Number;
372 }
373 
374 /* Nokia Smart Messaging 3.0 */
376  char *Buffer, size_t *Length)
377 {
378  size_t len;
379 
380  /*SM version. Here 3.0*/
381  Buffer[(*Length)++] = 0x30;
382 
383  if (Info->Entries[0].ID == SMS_NokiaProfileLong) {
384  if (Info->Entries[0].Buffer != NULL) {
385  if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) {
386  Buffer[(*Length)++] = SM30_PROFILENAME;
387  Buffer[(*Length)++] = 0x00;
388  Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer);
389  CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer);
390  *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer);
391  }
392  }
393  if (Info->Entries[0].Ringtone != NULL) {
394  Buffer[(*Length)++] = SM30_RINGTONE;
395  /* Length for this part later will be changed */
396  Buffer[(*Length)++] = 0x01;
397  Buffer[(*Length)++] = 0x00;
398  /* Smart Messaging 3.0 says: 16*9=144 bytes,
399  * but on 3310 4.02 it was possible to save about 196 chars
400  * (without cutting) */
401  len = 196;
402  Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer+(*Length),&len);
403  Buffer[(*Length)-2] = len / 256;
404  Buffer[(*Length)-1] = len % 256;
405  *Length = *Length + len;
406  }
407  }
408  if (Info->Entries[0].Bitmap != NULL) {
409  if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) {
410  Buffer[(*Length)++] = SM30_OTA;
411  } else {
412  Buffer[(*Length)++] = SM30_SCREENSAVER;
413  }
414  Buffer[(*Length)++] = 0x01;
415  Buffer[(*Length)++] = 0x00;
416  NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length);
417  if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) {
418  if (Info->UnicodeCoding) {
419  Buffer[(*Length)++] = SM30_UNICODETEXT;
420  /* Length for text part */
421  Buffer[(*Length)++] = 0x00;
422  Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
423  memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2);
424  *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
425  } else {
426  /*ID for ISO-8859-1 text*/
427  Buffer[(*Length)++] = SM30_ISOTEXT;
428  Buffer[(*Length)++] = 0x00;
429  Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
430  memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text));
431  *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
432  }
433  }
434  }
435 }
436 
437 /* Alcatel docs from www.alcatel.com/wap/ahead */
439  unsigned char *Data,
440  size_t Len,
441  unsigned char *Name,
442  size_t Type)
443 {
444  unsigned char buff[100],UDHID;
445  size_t i, p;
446  GSM_UDHHeader MyUDH;
447 
448  for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
449  GSM_SetDefaultSMSData(&SMS->SMS[i]);
450  SMS->SMS[i].UDH.Type = UDH_UserUDH;
451  SMS->SMS[i].UDH.Text[1] = 0x80; /* Alcatel */
452  p = UnicodeLength(Name);
453  EncodeDefault(buff, Name, &p, TRUE, NULL);
454  SMS->SMS[i].UDH.Text[2] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4;
455  SMS->SMS[i].UDH.Text[3] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p);
456  SMS->SMS[i].UDH.Text[4] = Type;
457  SMS->SMS[i].UDH.Text[5] = Len / 256;
458  SMS->SMS[i].UDH.Text[6] = Len % 256;
459  SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3];
460  SMS->SMS[i].UDH.Length = SMS->SMS[i].UDH.Text[0] + 1;
461 
462  if (Len > (size_t)(140 - SMS->SMS[i].UDH.Length)) {
464  GSM_EncodeUDHHeader(di, &MyUDH);
465 
466  memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1);
467  SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1;
468  SMS->SMS[i].UDH.Length += MyUDH.Length-1;
469  }
470 
471  SMS->SMS[i].Coding = SMS_Coding_8bit;
472  SMS->SMS[i].Class = 1;
473  }
474 
475  p = 0;
476  while (p != Len) {
477  i = 140-SMS->SMS[SMS->Number].UDH.Length;
478  if (Len - p < i) i = Len - p;
479  memcpy(SMS->SMS[SMS->Number].Text,Data+p,i);
480  p += i;
481  SMS->SMS[SMS->Number].Length = i;
482  SMS->Number++;
483 
484  }
485 
486  /* Linked sms UDH */
487  if (SMS->Number != 1) {
488  UDHID = GSM_MakeSMSIDFromTime();
489  for (i = 0; i < (size_t)SMS->Number; i++) {
490  SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID;
491  SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number;
492  SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1;
493  }
494  }
495 
496  return ERR_NONE;
497 }
498 
499 /* Alcatel docs from www.alcatel.com/wap/ahead and other */
501  GSM_MultiPartSMSInfo *Info,
502  GSM_MultiSMSMessage *SMS)
503 {
504  unsigned char *Buffer;
505  unsigned char *Buffer2;
506  size_t buffer_size = GSM_MAX_SMS_LENGTH * 2 * GSM_MAX_MULTI_SMS;
507  int i, Class = -1, j;
508  size_t p;
509  size_t Length = 0, smslen;
510  GSM_Error error;
512  GSM_UDH UDH = UDH_NoUDH;
513  GSM_UDHHeader UDHHeader;
514  gboolean EMS = FALSE;
515  int textnum = 0;
516 
517  if (Info->EntriesNum == 0) return ERR_EMPTY;
518 
519  Buffer = malloc(buffer_size);
520  if (Buffer == NULL) {
521  return ERR_MOREMEMORY;
522  }
523  Buffer2 = malloc(buffer_size);
524  if (Buffer2 == NULL) {
525  free(Buffer);
526  return ERR_MOREMEMORY;
527  }
528 
529  SMS->Number = 0;
530 
531  if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) {
532  Buffer[Length++] = 0x00; /* number of elements */
533  for (i=1;i<Info->EntriesNum;i++) {
534  switch (Info->Entries[i].ID) {
535  case SMS_EMSSound10:
536  case SMS_EMSSound12:
538  case SMS_EMSSound10Long:
539  case SMS_EMSSound12Long:
542  case SMS_EMSAnimation:
544  break;
546  Buffer[0]++;
547  Buffer[Length++] = 0x01; /* type of data */
548  Buffer[Length++] = 1 % 256; /* len */
549  Buffer[Length++] = 1 / 256; /* len */
550  Buffer[Length++] = Info->Entries[i].Number;
551  break;
553  Buffer[0]++;
554  Buffer[Length++] = 0x02; /* type of data */
555  Buffer[Length++] = 1 % 256; /* len */
556  Buffer[Length++] = 1 / 256; /* len */
557  Buffer[Length++] = Info->Entries[i].Number;
558  break;
560  Buffer[0]++;
561  p = UnicodeLength(Info->Entries[i].Buffer);
562  EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, TRUE, NULL);
563  Buffer[Length++] = 0x00; /* type of data */
564  Length = Length + 2;
565  smslen = GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p);
566  Buffer[Length-2] = smslen % 256; /* len */
567  Buffer[Length-1] = smslen / 256; /* len */
568  Length = Length + smslen;
569  break;
570  default:
571  error = ERR_UNKNOWN;
572  goto out;
573  }
574  }
575  Buffer[0] = Buffer[0] * 2;
576  error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE);
577  goto out;
578  }
579 
580  for (i=0;i<Info->EntriesNum;i++) {
581  switch (Info->Entries[i].ID) {
584  case SMS_EMSSound10:
585  case SMS_EMSSound12:
587  case SMS_EMSSound10Long:
588  case SMS_EMSSound12Long:
590  case SMS_EMSFixedBitmap:
592  case SMS_EMSAnimation:
594  EMS = TRUE;
595  break;
598 
599  /* This covers situation, when somebody will call function
600  * with two or more SMS_Concatenated.... entries only.
601  * It will be still only linked sms, but functions below
602  * will pack only first entry according to own limits.
603  * We redirect to EMS functions, because they are more generic
604  * here and will handle it correctly and produce linked sms
605  * from all entries
606  */
607  textnum ++;
608  if (textnum > 1) EMS = TRUE;
609 
610  if (Info->Entries[i].Left || Info->Entries[i].Right ||
611  Info->Entries[i].Center || Info->Entries[i].Large ||
612  Info->Entries[i].Small || Info->Entries[i].Bold ||
613  Info->Entries[i].Italic || Info->Entries[i].Underlined ||
614  Info->Entries[i].Strikethrough) {
615  EMS = TRUE;
616  }
617  default:
618  break;
619  }
620  if (EMS) break;
621  }
622  if (EMS) {
623  error=GSM_EncodeEMSMultiPartSMS(di, Info,SMS,UDH_NoUDH);
624  if (error != ERR_NONE) {
625  goto out;
626  }
627  if (SMS->Number != 1) {
628  SMS->Number = 0;
629  for (i=0;i<Info->EntriesNum;i++) {
630  if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) {
632  goto out;
633  }
634  }
636  }
637  goto out;
638  }
639 
640  if (Info->EntriesNum != 1) {
641  error = ERR_UNKNOWN;
642  goto out;
643  }
644 
645  switch (Info->Entries[0].ID) {
647  Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth;
648  Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight;
651  error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE);
652  goto out;
654  /* Number of sequence words */
655  Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256;
656  Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256;
657  /* Picture display time 1 second (1 = 100ms) */
658  Buffer[2] = 10 % 256;
659  Buffer[3] = 10 / 256 + 0xF0;
660 
661  Length = 4;
662  j = 0;
663 
664  /* Offsets to bitmaps */
665  for (i=0;i<Info->Entries[0].Bitmap->Number;i++) {
666  Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256;
667  Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256;
669  }
670 
671  /* Bitmaps */
672  for (i=0;i<Info->Entries[0].Bitmap->Number;i++) {
673  Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth;
674  Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight;
675  PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]);
677  }
678  error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION);
679  goto out;
681  Class = 1;
682  UDH = UDH_MMSIndicatorLong;
683  GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,Info->Entries[0].MMSIndicator);
684  break;
686  Class = 1;
687  UDH = UDH_MMSIndicatorLong;
689  break;
691  case SMS_NokiaRingtone:
692  UDH = UDH_NokiaRingtone;
693  Class = 1;
694  /* 7 = length of UDH_NokiaRingtone UDH header */
695  Length = GSM_MAX_8BIT_SMS_LENGTH-7;
696  Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer,&Length);
697  if (Info->Entries[0].ID == SMS_NokiaRingtone) break;
698  if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) {
699  UDH = UDH_NokiaRingtoneLong;
700  Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3;
701  Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer,&Length);
702  }
703  break;
705  if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) {
707  Class = 1;
709  Length = Length + 3;
710  NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
711  break;
712  }
714  UDH = UDH_NokiaOperatorLogo;
715  Class = 1;
717  Length = Length + 3;
718  NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
719  break;
720  case SMS_NokiaCallerLogo:
721  UDH = UDH_NokiaCallerLogo;
722  Class = 1;
723  NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
724  break;
728  Class = 1;
729  UDH = UDH_NokiaProfileLong;
730  GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length);
731  break;
733  Class = 1;
734  NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark);
735  /* 7 = length of UDH_NokiaWAP UDH header */
736  if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) {
737  UDH=UDH_NokiaWAPLong;
738  } else {
739  UDH=UDH_NokiaWAP;
740  }
741  break;
743  Class = 1;
744  UDH = UDH_NokiaWAPLong;
745  NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,FALSE);
746  break;
748  Class = 1;
749  UDH = UDH_NokiaWAPLong;
750  NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,TRUE);
751  break;
755  error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length, Info->Entries[0].Phonebook, TRUE, Nokia_VCard10);
756  if (error != ERR_NONE) {
757  goto out;
758  }
759  memcpy(Buffer2,Buffer,Length);
760  EncodeUnicode(Buffer,Buffer2,Length);
761  break;
763  error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length, Info->Entries[0].Phonebook, TRUE, Nokia_VCard21);
764  if (error != ERR_NONE) {
765  goto out;
766  }
769  memcpy(Buffer2,Buffer,Length);
770  EncodeUnicode(Buffer,Buffer2,Length);
771  break;
772  case SMS_VCARD10Long:
773  error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length,Info->Entries[0].Phonebook,TRUE,Nokia_VCard10);
774  if (error != ERR_NONE) {
775  goto out;
776  }
779  memcpy(Buffer2,Buffer,Length);
780  EncodeUnicode(Buffer,Buffer2,Length);
781  break;
782  case SMS_VCARD21Long:
783  error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length,Info->Entries[0].Phonebook,TRUE,Nokia_VCard21);
784  if (error != ERR_NONE) {
785  goto out;
786  }
789  memcpy(Buffer2,Buffer,Length);
790  EncodeUnicode(Buffer,Buffer2,Length);
791  break;
793  error=GSM_EncodeVCALENDAR(Buffer, buffer_size,&Length,Info->Entries[0].Calendar,TRUE,Nokia_VCalendar);
794  if (error != ERR_NONE) {
795  goto out;
796  }
798  /* Is 1 SMS ? 8 = length of ..SCKE4 */
799  if (Length <= GSM_MAX_SMS_CHARS_LENGTH - 8) {
800  sprintf(Buffer,"//SCKE4 ");
801  Length = 8;
802  } else {
803  UDH = UDH_NokiaCalendarLong;
804  }
805  memcpy(Buffer2,Buffer,Length);
806  EncodeUnicode(Buffer,Buffer2,Length);
807  break;
808  case SMS_NokiaVTODOLong:
809  error=GSM_EncodeVTODO(Buffer, buffer_size,&Length,Info->Entries[0].ToDo,TRUE,Nokia_VToDo);
810  if (error != ERR_NONE) {
811  goto out;
812  }
813  UDH = UDH_NokiaCalendarLong;
815  memcpy(Buffer2,Buffer,Length);
816  EncodeUnicode(Buffer,Buffer2,Length);
817  break;
818  case SMS_DisableVoice:
819  case SMS_DisableFax:
820  case SMS_DisableEmail:
821  case SMS_EnableVoice:
822  case SMS_EnableFax:
823  case SMS_EnableEmail:
824  case SMS_VoidSMS:
825  case SMS_Text:
826  Class = Info->Class;
827  switch (Info->Entries[0].ID) {
828  case SMS_DisableVoice : UDH = UDH_DisableVoice; break;
829  case SMS_DisableFax : UDH = UDH_DisableFax; break;
830  case SMS_DisableEmail : UDH = UDH_DisableEmail; break;
831  case SMS_EnableVoice : UDH = UDH_EnableVoice; break;
832  case SMS_EnableFax : UDH = UDH_EnableFax; break;
833  case SMS_EnableEmail : UDH = UDH_EnableEmail; break;
834  case SMS_VoidSMS : UDH = UDH_VoidSMS; break;
835  case SMS_Text : UDH = UDH_NoUDH; break;
836  default : break;
837  }
838  UDHHeader.Type = UDH;
839  GSM_EncodeUDHHeader(di, &UDHHeader);
840  memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
841  if (Info->UnicodeCoding) {
843  Length = UnicodeLength(Info->Entries[0].Buffer);
844  if (Length > (size_t)(140 - UDHHeader.Length) / 2) {
845  Length = (140 - UDHHeader.Length) / 2;
846  }
847  } else {
849  FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7);
850  }
851  break;
854  smslen = UnicodeLength(Info->Entries[0].Buffer);
855  memcpy(Buffer,Info->Entries[0].Buffer,smslen*2);
856  EncodeDefault(Buffer2, Buffer, &smslen, TRUE, NULL);
857  DecodeDefault(Buffer, Buffer2, smslen, TRUE, NULL);
858 #ifdef DEBUG
859  if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
860  smfprintf(di, "Info->Entries[0].Buffer:\n");
861  DumpMessage(di, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2);
862  smfprintf(di, "Buffer:\n");
863  DumpMessage(di, Buffer, UnicodeLength(Buffer)*2);
864  }
865 #endif
866  Info->UnicodeCoding = FALSE;
867  for (smslen = 0; smslen < UnicodeLength(Info->Entries[0].Buffer) * 2; smslen++) {
868  if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) {
869  Info->UnicodeCoding = TRUE;
870  smfprintf(di, "Setting to Unicode %ld\n", (long)smslen);
871  break;
872  }
873  }
874  /* No break here - we go to the SMS_ConcatenatedTextLong */
877  Class = Info->Class;
878  if (Info->Entries[0].Buffer == NULL) {
879  Buffer[0] = 0;
880  Buffer[1] = 0;
881  } else {
882  memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
883  }
884  UDH = UDH_NoUDH;
885  if (Info->UnicodeCoding) {
887  Length = UnicodeLength(Buffer);
888  if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
890  if (Length>70) UDH=UDH_ConcatenatedMessages16bit;
891  } else {
892  if (Length>70) UDH=UDH_ConcatenatedMessages;
893  }
894  } else {
896  FindDefaultAlphabetLen(Buffer,&Length,&smslen,5000);
897  if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
900  } else {
902  }
903  }
904  default:
905  break;
906  }
907  GSM_MakeMultiPartSMS(di, SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage);
908  error = ERR_NONE;
909 out:
910  free(Buffer);
911  free(Buffer2);
912  return error;
913 }
914 
916 {
917  int i;
918 
919  for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
920  Info->Entries[i].Number = 0;
921  Info->Entries[i].Ringtone = NULL;
922  Info->Entries[i].Bitmap = NULL;
923  Info->Entries[i].Bookmark = NULL;
924  Info->Entries[i].File = NULL;
925  Info->Entries[i].Settings = NULL;
926  Info->Entries[i].MMSIndicator = NULL;
927  Info->Entries[i].Phonebook = NULL;
928  Info->Entries[i].Calendar = NULL;
929  Info->Entries[i].ToDo = NULL;
930  Info->Entries[i].Protected = FALSE;
931 
932  Info->Entries[i].Buffer = NULL;
933  Info->Entries[i].Left = FALSE;
934  Info->Entries[i].Right = FALSE;
935  Info->Entries[i].Center = FALSE;
936  Info->Entries[i].Large = FALSE;
937  Info->Entries[i].Small = FALSE;
938  Info->Entries[i].Bold = FALSE;
939  Info->Entries[i].Italic = FALSE;
940  Info->Entries[i].Underlined = FALSE;
941  Info->Entries[i].Strikethrough = FALSE;
942 
943  Info->Entries[i].RingtoneNotes = 0;
944  }
945  Info->Unknown = FALSE;
946  Info->EntriesNum = 0;
947  Info->Class = -1;
948  Info->ReplaceMessage = 0;
949  Info->UnicodeCoding = FALSE;
950 }
951 
953 {
954  int i;
955 
956  for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
957  free(Info->Entries[i].Ringtone);
958  Info->Entries[i].Ringtone = NULL;
959  free(Info->Entries[i].Bitmap);
960  Info->Entries[i].Bitmap = NULL;
961  free(Info->Entries[i].Bookmark);
962  Info->Entries[i].Bookmark = NULL;
963  free(Info->Entries[i].Settings);
964  Info->Entries[i].Settings = NULL;
965  free(Info->Entries[i].MMSIndicator);
966  Info->Entries[i].MMSIndicator = NULL;
967  free(Info->Entries[i].Phonebook);
968  Info->Entries[i].Phonebook = NULL;
969  free(Info->Entries[i].Calendar);
970  Info->Entries[i].Calendar = NULL;
971  free(Info->Entries[i].ToDo);
972  Info->Entries[i].ToDo = NULL;
973  free(Info->Entries[i].Buffer);
974  Info->Entries[i].Buffer = NULL;
975  }
976 }
977 
982  GSM_MultiPartSMSInfo *Info,
983  GSM_MultiSMSMessage *SMS)
984 {
985  int i, Length = 0, j;
986  unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*GSM_MAX_MULTI_SMS];
987 
988  /* Concatenate data */
989  for (i = 0; i < SMS->Number; i++) {
990  if (SMS->SMS[i].UDH.Type == UDH_MMSIndicatorLong) {
991  if (SMS->SMS[i].UDH.Text[11] != i+1 ||
992  SMS->SMS[i].UDH.Text[10] != SMS->Number) {
993  return FALSE;
994  }
995  } else if (SMS->SMS[i].UDH.Type != UDH_UserUDH) {
996  return FALSE;
997  }
998  memcpy(Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length);
999  Length = Length + SMS->SMS[i].Length;
1000  }
1001 
1002  dbgprintf(di, "MMS data of length %d:\n", Length);
1003  DumpMessage(di, Buffer, Length);
1004  Info->Entries[0].MMSIndicator = (GSM_MMSIndicator *)malloc(sizeof(GSM_MMSIndicator));
1005  if (Info->Entries[0].MMSIndicator == NULL) {
1006  return FALSE;
1007  }
1008  Info->EntriesNum = 1;
1009  Info->Entries[0].ID = SMS_MMSIndicatorLong;
1010  Info->Entries[0].MMSIndicator->Class = GSM_MMS_None;
1011  Info->Entries[0].MMSIndicator->MessageSize = 0;
1012  Info->Entries[0].MMSIndicator->Title[0] = 0;
1013  Info->Entries[0].MMSIndicator->Sender[0] = 0;
1014  Info->Entries[0].MMSIndicator->Address[0] = 0;
1015 
1016  /* First byte is transaction ID */
1017  /* PUSH */
1018  if (Buffer[1] != 0x06) {
1019  dbgprintf(di, "Unsupported transaction id: 0x%02x\n", Buffer[1]);
1020  return FALSE;
1021  }
1022  /* Process payload */
1023  for (i = 3 + Buffer[2]; i < Length; i++) {
1024  switch(Buffer[i]) {
1025  case 0x8c:
1026  /* Transaction type */
1027  i++;
1028  if (Buffer[i] != 0x82) {
1029  dbgprintf(di, "Unsupported transaction type: 0x%02x\n", Buffer[i]);
1030  return FALSE;
1031  }
1032  break;
1033  case 0x98:
1034  /* Message ID */
1035  while (Buffer[i] != 0 && i < Length) i++;
1036  break;
1037  case 0x8d:
1038  /* MMS version */
1039  i++;
1040  if (Buffer[i] < 0x90 || Buffer[i] > 0x92) {
1041  dbgprintf(di, "Unsupported MMS version: 0x%02x\n", Buffer[i]);
1042  return FALSE;
1043  }
1044  break;
1045  case 0x89:
1046  /* Sender */
1047  i++;
1048  if (Buffer[i] == 0) continue;
1049  if (Buffer[i + 1] == 0x80) {
1050  if (Buffer[i + 2] < 32) {
1051  /* String with length + encoding, we just ignore it for now */
1052  strcpy(Info->Entries[0].MMSIndicator->Sender, Buffer + i + 4);
1053  } else {
1054  strcpy(Info->Entries[0].MMSIndicator->Sender, Buffer + i + 2);
1055  }
1056  }
1057  i += Buffer[i];
1058  break;
1059  case 0x96:
1060  /* Title */
1061  if (Buffer[i + 1] == 0x0a && Buffer[i + 2] == 0xea) {
1062  /* UTF-8 */
1063  strcpy(Info->Entries[0].MMSIndicator->Title, Buffer + i + 3);
1064  i += strlen(Info->Entries[0].MMSIndicator->Title) + 3;
1065  } else {
1066  strcpy(Info->Entries[0].MMSIndicator->Title, Buffer + i + 1);
1067  i += strlen(Info->Entries[0].MMSIndicator->Title) + 1;
1068  }
1069  break;
1070  case 0x8a:
1071  /* Class */
1072  i++;
1073  switch (Buffer[i]) {
1074  case 0x80:
1076  break;
1077  case 0x81:
1079  break;
1080  case 0x82:
1081  Info->Entries[0].MMSIndicator->Class = GSM_MMS_Info;
1082  break;
1083  case 0x83:
1084  Info->Entries[0].MMSIndicator->Class = GSM_MMS_Auto;
1085  break;
1086  default:
1087  dbgprintf(di, "Unsupported MMS class: 0x%02x\n", Buffer[i]);
1088  break;
1089  }
1090  break;
1091  case 0x8e:
1092  /* Message size */
1093  i++;
1094  for (j = i + 1; j < i + 1 + Buffer[i]; j++) {
1095  Info->Entries[0].MMSIndicator->MessageSize = (Info->Entries[0].MMSIndicator->MessageSize << 8) + Buffer[j];
1096  }
1097  i += Buffer[i];
1098  break;
1099  case 0x88:
1100  /* Don't know */
1101  i++;
1102  break;
1103  case 0x81:
1104  /* Don't know */
1105  i++;
1106  i += Buffer[i];
1107  break;
1108  case 0x83:
1109  /* URL */
1110  strcpy(Info->Entries[0].MMSIndicator->Address, Buffer + i + 1);
1111  i += strlen(Info->Entries[0].MMSIndicator->Address) + 1;
1112  break;
1113  case 0x87:
1114  default:
1115  dbgprintf(di, "Unknown MMS tag: 0x%02x\n", Buffer[i]);
1116  break;
1117  }
1118  }
1119 
1120  return TRUE;
1121 }
1122 
1127  GSM_MultiPartSMSInfo *Info,
1128  GSM_MultiSMSMessage *SMS)
1129 {
1130  int i, Length = 0;
1131  char Buffer[GSM_MAX_SMS_LENGTH*2*GSM_MAX_MULTI_SMS];
1132 
1133  for (i=0;i<SMS->Number;i++) {
1134  if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong ||
1135  SMS->SMS[i].UDH.Text[11] != i+1 ||
1136  SMS->SMS[i].UDH.Text[10] != SMS->Number) {
1137  return FALSE;
1138  }
1139  memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
1140  Length = Length + SMS->SMS[i].Length;
1141  }
1142  Info->EntriesNum = 1;
1144  Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1145  if (Info->Entries[0].Bitmap == NULL) return FALSE;
1146  Info->Entries[0].Bitmap->Number = 0;
1147  Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0;
1148  Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0;
1149  i=1;
1150  while (i < Length) {
1151  switch (Buffer[i]) {
1152  case SM30_ISOTEXT:
1153  smfprintf(di, "ISO 8859-2 text\n");
1154  break;
1155  case SM30_UNICODETEXT:
1156  smfprintf(di, "Unicode text\n");
1157  break;
1158  case SM30_OTA:
1159  smfprintf(di, "OTA bitmap as Picture Image\n");
1160  PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[Info->Entries[0].Bitmap->Number]);
1161  Info->Entries[0].Bitmap->Number += 1;
1162 #ifdef DEBUG
1163  if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
1164  GSM_PrintBitmap(di->df, &Info->Entries[0].Bitmap->Bitmap[0]);
1165  }
1166 #endif
1167  break;
1168  case SM30_RINGTONE:
1169  smfprintf(di, "RTTL ringtone\n");
1170  Info->Unknown = TRUE;
1171  break;
1172  case SM30_PROFILENAME:
1173  smfprintf(di, "Profile Name\n");
1174  Info->Entries[0].ID = SMS_NokiaProfileLong;
1175  Info->Unknown = TRUE;
1176  break;
1177  case SM30_SCREENSAVER:
1178  smfprintf(di, "OTA bitmap as Screen Saver\n");
1179  PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[Info->Entries[0].Bitmap->Number]);
1180  Info->Entries[0].Bitmap->Number += 1;
1181 #ifdef DEBUG
1182  if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
1183  GSM_PrintBitmap(di->df, &Info->Entries[0].Bitmap->Bitmap[0]);
1184  }
1185 #endif
1186  Info->Entries[0].ID = SMS_NokiaScreenSaverLong;
1187  break;
1188  }
1189  i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
1190  smfprintf(di, "Profile: pos=%i length=%i\n", i, Length);
1191  }
1192  i=1;
1193  while (i < Length) {
1194  switch (Buffer[i]) {
1195  case SM30_ISOTEXT:
1196  smfprintf(di, "ISO 8859-2 text\n");
1197  EncodeUnicode (Info->Entries[0].Bitmap->Bitmap[0].Text, Buffer+i+3, Buffer[i+2]);
1198  smfprintf(di, "ISO Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
1199  break;
1200  case SM30_UNICODETEXT:
1201  smfprintf(di, "Unicode text\n");
1202  memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]);
1203  Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0;
1204  Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0;
1205  smfprintf(di, "Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
1206  break;
1207  case SM30_OTA:
1208  smfprintf(di, "OTA bitmap as Picture Image\n");
1209  break;
1210  case SM30_RINGTONE:
1211  smfprintf(di, "RTTL ringtone\n");
1212  break;
1213  case SM30_PROFILENAME:
1214  smfprintf(di, "Profile Name\n");
1215  break;
1216  case SM30_SCREENSAVER:
1217  smfprintf(di, "OTA bitmap as Screen Saver\n");
1218  break;
1219  }
1220  i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
1221  smfprintf(di, "Profile: pos=%i length=%i\n", i, Length);
1222  }
1223  return TRUE;
1224 }
1225 
1230  GSM_MultiPartSMSInfo *Info,
1231  GSM_MultiSMSMessage *SMS)
1232 {
1233  int i, Length = 0;
1234 
1235  Info->EntriesNum = 1;
1236  Info->Entries[0].ID = SMS_ConcatenatedTextLong;
1237  if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
1239  }
1240 
1241  for (i=0;i<SMS->Number;i++) {
1242  switch (SMS->SMS[i].Coding) {
1243  case SMS_Coding_8bit:
1244  Info->Entries[0].Buffer = (unsigned char *)realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2);
1245  if (Info->Entries[0].Buffer == NULL) return FALSE;
1246 
1247  memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length);
1248  Length=Length+SMS->SMS[i].Length;
1249  break;
1251  if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) {
1253  }
1254  if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) {
1256  }
1258  Info->Entries[0].Buffer = (unsigned char *)realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2);
1259  if (Info->Entries[0].Buffer == NULL) return FALSE;
1260 
1261  memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2);
1262  Length=Length+UnicodeLength(SMS->SMS[i].Text)*2;
1263  break;
1264  default:
1265  break;
1266  }
1267  }
1268  Info->Entries[0].Buffer[Length] = 0;
1269  Info->Entries[0].Buffer[Length+1] = 0;
1270  return TRUE;
1271 }
1272 
1273 /* ----------------- Joining SMS from parts -------------------------------- */
1274 
1276  GSM_MultiPartSMSInfo *Info,
1277  GSM_MultiSMSMessage *SMS,
1278  gboolean ems)
1279 {
1280  int i;
1281  unsigned int j;
1282  gboolean emsexist = FALSE, result;
1283  GSM_SiemensOTASMSInfo SiemensInfo;
1284 
1286  if (ems) {
1287  emsexist = TRUE;
1288  for (i=0;i<SMS->Number;i++) {
1289  if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages &&
1291  SMS->SMS[i].UDH.Type != UDH_UserUDH) {
1292  emsexist = FALSE;
1293  break;
1294  }
1295  }
1296  }
1297 
1298  /* EMS decoding */
1299  if (emsexist) {
1300  return GSM_DecodeEMSMultiPartSMS(di, Info,SMS);
1301  }
1302 
1303  /* Siemens OTA */
1304  if (GSM_DecodeSiemensOTASMS(di, &SiemensInfo,&SMS->SMS[0])) {
1305  Info->Entries[0].File = (GSM_File *)malloc(sizeof(GSM_File));
1306  if (Info->Entries[0].File == NULL) return FALSE;
1307  Info->Entries[0].File->Buffer = NULL;
1308  Info->Entries[0].File->Used = 0;
1309  for (i=0;i<SMS->Number;i++) {
1310  if (GSM_DecodeSiemensOTASMS(di, &SiemensInfo,&SMS->SMS[i])) {
1311  j = SiemensInfo.AllDataLen - Info->Entries[0].File->Used;
1312  if (j>SiemensInfo.DataLen) j = SiemensInfo.DataLen;
1313  Info->Entries[0].File->Buffer = (unsigned char *)realloc(Info->Entries[0].File->Buffer,j+Info->Entries[0].File->Used);
1314  memcpy(Info->Entries[0].File->Buffer+Info->Entries[0].File->Used,SiemensInfo.Data,j);
1315  Info->Entries[0].File->Used += j;
1316  }
1317  }
1318  if (SiemensInfo.AllDataLen == Info->Entries[0].File->Used) {
1319  Info->Entries[0].ID = SMS_SiemensFile;
1320  Info->EntriesNum = 1;
1321  EncodeUnicode(Info->Entries[0].File->Name,SiemensInfo.DataName,strlen(SiemensInfo.DataName));
1322  return TRUE;
1323  }
1324  free(Info->Entries[0].File->Buffer);
1325  Info->Entries[0].File->Buffer=NULL;
1326  }
1327 
1328  /* Smart Messaging decoding */
1329  if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) {
1330  Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone));
1331  if (Info->Entries[0].Ringtone == NULL) return FALSE;
1332  if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) {
1333  Info->Entries[0].ID = SMS_NokiaRingtone;
1334  Info->EntriesNum = 1;
1335  return TRUE;
1336  }
1337  }
1338  if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) {
1339  Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1340  if (Info->Entries[0].Bitmap == NULL) return FALSE;
1341  Info->Entries[0].Bitmap->Number = 1;
1342  PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]);
1343 #ifdef DEBUG
1344  if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE)
1345  GSM_PrintBitmap(di->df,&Info->Entries[0].Bitmap->Bitmap[0]);
1346 #endif
1347  Info->Entries[0].ID = SMS_NokiaCallerLogo;
1348  Info->EntriesNum = 1;
1349  return TRUE;
1350  }
1351  if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) {
1352  Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1353  if (Info->Entries[0].Bitmap == NULL) return FALSE;
1354  Info->Entries[0].Bitmap->Number = 1;
1357 #ifdef DEBUG
1358  if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE)
1359  GSM_PrintBitmap(di->df,&Info->Entries[0].Bitmap->Bitmap[0]);
1360 #endif
1361  Info->Entries[0].ID = SMS_NokiaOperatorLogo;
1362  Info->EntriesNum = 1;
1363  return TRUE;
1364  }
1365  if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) {
1366  return GSM_DecodeNokiaProfile(di, Info, SMS);
1367  }
1368 
1369  /* Linked sms */
1370  if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages ||
1372  return GSM_DecodeLinkedText(di, Info, SMS);
1373  }
1374  /* Nokia vCard/vCalendar */
1375  if (SMS->SMS[0].UDH.Type == UDH_NokiaCalendarLong ||
1376  SMS->SMS[0].UDH.Type == UDH_NokiaPhonebookLong) {
1377  result = GSM_DecodeLinkedText(di, Info, SMS);
1378  if (result) {
1379  if (SMS->SMS[0].UDH.Type == UDH_NokiaPhonebookLong) {
1380  Info->Entries[0].ID = SMS_NokiaVCARD10Long;
1381  } else {
1382  Info->Entries[0].ID = SMS_NokiaVCALENDAR10Long;
1383  }
1384  }
1385  return result;
1386  }
1387  /* MMS indication */
1388  if (SMS->SMS[0].UDH.Type == UDH_MMSIndicatorLong) {
1389  return GSM_DecodeMMSIndication(di, Info, SMS);
1390  }
1391 
1392  return FALSE;
1393 }
1394 
1396 {
1397  gboolean *InputMessagesSorted, copyit,OtherNumbers[GSM_SMS_OTHER_NUMBERS+1],wrong=FALSE;
1398  int i,OutputMessagesNum,z,w,m,p;
1399  int j;
1400  GSM_SiemensOTASMSInfo SiemensOTA,SiemensOTA2;
1401 
1402  i = 0;
1403  while (InputMessages[i] != NULL) i++;
1404 
1405  OutputMessagesNum = 0;
1406  OutputMessages[0] = NULL;
1407 
1408  if (i == 0) {
1409  return ERR_NONE;
1410  }
1411 
1412  InputMessagesSorted = calloc(i, sizeof(gboolean));
1413  if (InputMessagesSorted == NULL) return ERR_MOREMEMORY;
1414 
1415  if (ems) {
1416  for (i = 0; InputMessages[i] != NULL; i++) {
1417  if (InputMessages[i]->SMS[0].UDH.Type == UDH_UserUDH) {
1418  w=1;
1419  while (w < InputMessages[i]->SMS[0].UDH.Length) {
1420  switch(InputMessages[i]->SMS[0].UDH.Text[w]) {
1421  case 0x00:
1422  smfprintf(di, "Adding ID to user UDH - linked SMS with 8 bit ID\n");
1423  InputMessages[i]->SMS[0].UDH.ID8bit = InputMessages[i]->SMS[0].UDH.Text[w+2];
1424  InputMessages[i]->SMS[0].UDH.ID16bit = -1;
1425  InputMessages[i]->SMS[0].UDH.AllParts = InputMessages[i]->SMS[0].UDH.Text[w+3];
1426  InputMessages[i]->SMS[0].UDH.PartNumber = InputMessages[i]->SMS[0].UDH.Text[w+4];
1427  break;
1428  case 0x08:
1429  smfprintf(di, "Adding ID to user UDH - linked SMS with 16 bit ID\n");
1430  InputMessages[i]->SMS[0].UDH.ID8bit = -1;
1431  InputMessages[i]->SMS[0].UDH.ID16bit = InputMessages[i]->SMS[0].UDH.Text[w+2]*256+InputMessages[i]->SMS[0].UDH.Text[w+3];
1432  InputMessages[i]->SMS[0].UDH.AllParts = InputMessages[i]->SMS[0].UDH.Text[w+4];
1433  InputMessages[i]->SMS[0].UDH.PartNumber = InputMessages[i]->SMS[0].UDH.Text[w+5];
1434  break;
1435  default:
1436  smfprintf(di, "Block %02x\n",InputMessages[i]->SMS[0].UDH.Text[w]);
1437  }
1438  smfprintf(di, "id8: %i, id16: %i, part: %i, parts count: %i\n",
1439  InputMessages[i]->SMS[0].UDH.ID8bit,
1440  InputMessages[i]->SMS[0].UDH.ID16bit,
1441  InputMessages[i]->SMS[0].UDH.PartNumber,
1442  InputMessages[i]->SMS[0].UDH.AllParts);
1443  w=w+InputMessages[i]->SMS[0].UDH.Text[w+1]+2;
1444  }
1445  }
1446  }
1447  }
1448 
1449  i=0;
1450  while (InputMessages[i]!=NULL) {
1451  /* If this one SMS was sorted earlier, do not touch */
1452  if (InputMessagesSorted[i]) {
1453  i++;
1454  continue;
1455  }
1456  /* We have 1'st part of SIEMENS sms. It's single.
1457  * We will try to find other parts
1458  */
1459  if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[i]->SMS[0]) &&
1460  SiemensOTA.PacketNum == 1) {
1461  OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1462  if (OutputMessages[OutputMessagesNum] == NULL) {
1463  free(InputMessagesSorted);
1464  InputMessagesSorted=NULL;
1465  return ERR_MOREMEMORY;
1466  }
1467  OutputMessages[OutputMessagesNum+1] = NULL;
1468 
1469  memcpy(&OutputMessages[OutputMessagesNum]->SMS[0],&InputMessages[i]->SMS[0],sizeof(GSM_SMSMessage));
1470  OutputMessages[OutputMessagesNum]->Number = 1;
1471  InputMessagesSorted[i] = TRUE;
1472  j = 1;
1473  /* We're searching for other parts in sequence */
1474  while (j!=(int)SiemensOTA.PacketsNum) {
1475  z=0;
1476  while(InputMessages[z]!=NULL) {
1477  /* This was sorted earlier or is not single */
1478  if (InputMessagesSorted[z] || InputMessages[z]->Number != 1) {
1479  z++;
1480  continue;
1481  }
1482  if (!GSM_DecodeSiemensOTASMS(di, &SiemensOTA2,&InputMessages[z]->SMS[0])) {
1483  z++;
1484  continue;
1485  }
1486  if (SiemensOTA2.SequenceID != SiemensOTA.SequenceID ||
1487  (int)SiemensOTA2.PacketNum != j+1 ||
1488  SiemensOTA2.PacketsNum != SiemensOTA.PacketsNum ||
1489  strcmp(SiemensOTA2.DataType,SiemensOTA.DataType) ||
1490  strcmp(SiemensOTA2.DataName,SiemensOTA.DataName)) {
1491  z++;
1492  continue;
1493  }
1494  /* For SMS_Deliver compare also SMSC and Sender numbers */
1495  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1496  strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].SMSC.Number),DecodeUnicodeString(InputMessages[i]->SMS[0].SMSC.Number))) {
1497  z++;
1498  continue;
1499  }
1500  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1501  InputMessages[z]->SMS[0].OtherNumbersNum!=InputMessages[i]->SMS[0].OtherNumbersNum) {
1502  z++;
1503  continue;
1504  }
1505  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver) {
1506  for (m=0;m<GSM_SMS_OTHER_NUMBERS+1;m++) {
1507  OtherNumbers[m]=FALSE;
1508  }
1509  for (m=0;m<InputMessages[z]->SMS[0].OtherNumbersNum+1;m++) {
1510  wrong=TRUE;
1511  for (p=0;p<InputMessages[i]->SMS[0].OtherNumbersNum+1;p++) {
1512  if (OtherNumbers[p]) continue;
1513  if (m==0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1514  OtherNumbers[0]=TRUE;
1515  wrong=FALSE;
1516  break;
1517  }
1518  if (m==0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1519  OtherNumbers[p]=TRUE;
1520  wrong=FALSE;
1521  break;
1522  }
1523  if (m!=0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1524  OtherNumbers[0]=TRUE;
1525  wrong=FALSE;
1526  break;
1527  }
1528  if (m!=0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1529  OtherNumbers[p]=TRUE;
1530  wrong=FALSE;
1531  break;
1532  }
1533  }
1534  if (wrong) break;
1535  }
1536  if (wrong) {
1537  z++;
1538  continue;
1539  }
1540  }
1541  /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */
1542  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1543  UnicodeLength(InputMessages[z]->SMS[0].SMSC.Number)==0 &&
1544  UnicodeLength(InputMessages[z]->SMS[0].Number)==0 &&
1545  (InputMessages[z]->SMS[0].DateTime.Day != InputMessages[i]->SMS[0].DateTime.Day ||
1546  InputMessages[z]->SMS[0].DateTime.Month != InputMessages[i]->SMS[0].DateTime.Month ||
1547  InputMessages[z]->SMS[0].DateTime.Year != InputMessages[i]->SMS[0].DateTime.Year ||
1548  InputMessages[z]->SMS[0].DateTime.Hour != InputMessages[i]->SMS[0].DateTime.Hour ||
1549  InputMessages[z]->SMS[0].DateTime.Minute != InputMessages[i]->SMS[0].DateTime.Minute ||
1550  InputMessages[z]->SMS[0].DateTime.Second != InputMessages[i]->SMS[0].DateTime.Second)) {
1551  z++;
1552  continue;
1553  }
1554  smfprintf(di, "Found Siemens SMS %i\n",j);
1555  /* We found correct sms. Copy it */
1556  memcpy(&OutputMessages[OutputMessagesNum]->SMS[j],&InputMessages[z]->SMS[0],sizeof(GSM_SMSMessage));
1557  OutputMessages[OutputMessagesNum]->Number++;
1558  InputMessagesSorted[z]=TRUE;
1559  break;
1560  }
1561  /* Incomplete sequence */
1562  if (OutputMessages[OutputMessagesNum]->Number==j) {
1563  smfprintf(di, "Incomplete sequence\n");
1564  break;
1565  }
1566  j++;
1567  }
1568  OutputMessagesNum++;
1569  i = 0;
1570  continue;
1571  }
1572  /* We have some next Siemens sms from sequence */
1573  if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[i]->SMS[0]) &&
1574  SiemensOTA.PacketNum > 1) {
1575  j = 0;
1576  while (InputMessages[j]!=NULL) {
1577  if (InputMessagesSorted[j]) {
1578  j++;
1579  continue;
1580  }
1581  /* We have some not unassigned first sms from sequence.
1582  * We can't touch other sms from sequences
1583  */
1584  if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[j]->SMS[0]) &&
1585  SiemensOTA.PacketNum == 1) {
1586  break;
1587  }
1588  j++;
1589  }
1590  if (InputMessages[j]==NULL) {
1591  OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1592  if (OutputMessages[OutputMessagesNum] == NULL) {
1593  free(InputMessagesSorted);
1594  InputMessagesSorted=NULL;
1595  return ERR_MOREMEMORY;
1596  }
1597  OutputMessages[OutputMessagesNum+1] = NULL;
1598 
1599  memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1600  InputMessagesSorted[i]=TRUE;
1601  OutputMessagesNum++;
1602  i = 0;
1603  continue;
1604  } else i++;
1605  }
1606  copyit = FALSE;
1607  /* If we have:
1608  * - linked sms returned by phone driver
1609  * - sms without linking
1610  * we copy it to OutputMessages
1611  */
1612  if (InputMessages[i]->Number != 1 ||
1613  InputMessages[i]->SMS[0].UDH.Type == UDH_NoUDH ||
1614  InputMessages[i]->SMS[0].UDH.PartNumber == -1) {
1615  copyit = TRUE;
1616  }
1617  /* If we have unknown UDH, we copy it to OutputMessages */
1618  if (InputMessages[i]->SMS[0].UDH.Type == UDH_UserUDH) {
1619  if (!ems) copyit = TRUE;
1620  if (ems && InputMessages[i]->SMS[0].UDH.PartNumber == -1) copyit = TRUE;
1621  }
1622  if (copyit) {
1623  OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1624  if (OutputMessages[OutputMessagesNum] == NULL) {
1625  free(InputMessagesSorted);
1626  InputMessagesSorted=NULL;
1627  return ERR_MOREMEMORY;
1628  }
1629  OutputMessages[OutputMessagesNum+1] = NULL;
1630 
1631  memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1632  InputMessagesSorted[i]=TRUE;
1633  OutputMessagesNum++;
1634  i = 0;
1635  continue;
1636  }
1637  /* We have 1'st part of linked sms. It's single.
1638  * We will try to find other parts
1639  */
1640  if (InputMessages[i]->SMS[0].UDH.PartNumber == 1) {
1641  OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1642  if (OutputMessages[OutputMessagesNum] == NULL) {
1643  free(InputMessagesSorted);
1644  InputMessagesSorted=NULL;
1645  return ERR_MOREMEMORY;
1646  }
1647  OutputMessages[OutputMessagesNum+1] = NULL;
1648 
1649  memcpy(&OutputMessages[OutputMessagesNum]->SMS[0],&InputMessages[i]->SMS[0],sizeof(GSM_SMSMessage));
1650  OutputMessages[OutputMessagesNum]->Number = 1;
1651  InputMessagesSorted[i] = TRUE;
1652  j = 1;
1653  /* We're searching for other parts in sequence */
1654  while (j != InputMessages[i]->SMS[0].UDH.AllParts) {
1655  z=0;
1656  while(InputMessages[z]!=NULL) {
1657  /* This was sorted earlier or is not single */
1658  if (InputMessagesSorted[z] || InputMessages[z]->Number != 1) {
1659  z++;
1660  continue;
1661  }
1662  if (ems && InputMessages[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages &&
1663  InputMessages[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit &&
1664  InputMessages[i]->SMS[0].UDH.Type != UDH_UserUDH &&
1665  InputMessages[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages &&
1666  InputMessages[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit &&
1667  InputMessages[z]->SMS[0].UDH.Type != UDH_UserUDH) {
1668  if (InputMessages[z]->SMS[0].UDH.Type != InputMessages[i]->SMS[0].UDH.Type) {
1669  z++;
1670  continue;
1671  }
1672  }
1673  if (!ems && InputMessages[z]->SMS[0].UDH.Type != InputMessages[i]->SMS[0].UDH.Type) {
1674  z++;
1675  continue;
1676  }
1677  smfprintf(di, "compare %i %i %i %i %i",
1678  j+1,
1679  InputMessages[i]->SMS[0].UDH.ID8bit,
1680  InputMessages[i]->SMS[0].UDH.ID16bit,
1681  InputMessages[i]->SMS[0].UDH.PartNumber,
1682  InputMessages[i]->SMS[0].UDH.AllParts);
1683  smfprintf(di, " %i %i %i %i\n",
1684  InputMessages[z]->SMS[0].UDH.ID8bit,
1685  InputMessages[z]->SMS[0].UDH.ID16bit,
1686  InputMessages[z]->SMS[0].UDH.PartNumber,
1687  InputMessages[z]->SMS[0].UDH.AllParts);
1688  if (InputMessages[z]->SMS[0].UDH.ID8bit != InputMessages[i]->SMS[0].UDH.ID8bit ||
1689  InputMessages[z]->SMS[0].UDH.ID16bit != InputMessages[i]->SMS[0].UDH.ID16bit ||
1690  InputMessages[z]->SMS[0].UDH.AllParts != InputMessages[i]->SMS[0].UDH.AllParts ||
1691  (InputMessages[z]->SMS[0].UDH.PartNumber) != j + 1) {
1692  z++;
1693  continue;
1694  }
1695  /* For SMS_Deliver compare also SMSC and Sender numbers */
1696  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1697  strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].SMSC.Number),DecodeUnicodeString(InputMessages[i]->SMS[0].SMSC.Number))) {
1698  z++;
1699  continue;
1700  }
1701  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1702  InputMessages[z]->SMS[0].OtherNumbersNum!=InputMessages[i]->SMS[0].OtherNumbersNum) {
1703  z++;
1704  continue;
1705  }
1706  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver) {
1707  for (m=0;m<GSM_SMS_OTHER_NUMBERS+1;m++) {
1708  OtherNumbers[m]=FALSE;
1709  }
1710  for (m=0;m<InputMessages[z]->SMS[0].OtherNumbersNum+1;m++) {
1711  wrong=TRUE;
1712  for (p=0;p<InputMessages[i]->SMS[0].OtherNumbersNum+1;p++) {
1713  if (OtherNumbers[p]) continue;
1714  if (m==0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1715  OtherNumbers[0]=TRUE;
1716  wrong=FALSE;
1717  break;
1718  }
1719  if (m==0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1720  OtherNumbers[p]=TRUE;
1721  wrong=FALSE;
1722  break;
1723  }
1724  if (m!=0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1725  OtherNumbers[0]=TRUE;
1726  wrong=FALSE;
1727  break;
1728  }
1729  if (m!=0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1730  OtherNumbers[p]=TRUE;
1731  wrong=FALSE;
1732  break;
1733  }
1734  }
1735  if (wrong) break;
1736  }
1737  if (wrong) {
1738  z++;
1739  continue;
1740  }
1741  }
1742  /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */
1743  if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1744  UnicodeLength(InputMessages[z]->SMS[0].SMSC.Number)==0 &&
1745  UnicodeLength(InputMessages[z]->SMS[0].Number)==0 &&
1746  (InputMessages[z]->SMS[0].DateTime.Day != InputMessages[i]->SMS[0].DateTime.Day ||
1747  InputMessages[z]->SMS[0].DateTime.Month != InputMessages[i]->SMS[0].DateTime.Month ||
1748  InputMessages[z]->SMS[0].DateTime.Year != InputMessages[i]->SMS[0].DateTime.Year ||
1749  InputMessages[z]->SMS[0].DateTime.Hour != InputMessages[i]->SMS[0].DateTime.Hour ||
1750  InputMessages[z]->SMS[0].DateTime.Minute != InputMessages[i]->SMS[0].DateTime.Minute ||
1751  InputMessages[z]->SMS[0].DateTime.Second != InputMessages[i]->SMS[0].DateTime.Second)) {
1752  z++;
1753  continue;
1754  }
1755  /* We found correct sms. Copy it */
1756  memcpy(&OutputMessages[OutputMessagesNum]->SMS[j],&InputMessages[z]->SMS[0],sizeof(GSM_SMSMessage));
1757  OutputMessages[OutputMessagesNum]->Number++;
1758  InputMessagesSorted[z]=TRUE;
1759  break;
1760  }
1761  /* Incomplete sequence */
1762  if (OutputMessages[OutputMessagesNum]->Number==j) {
1763  smfprintf(di, "Incomplete sequence\n");
1764  break;
1765  }
1766  j++;
1767  }
1768  OutputMessagesNum++;
1769  i = 0;
1770  continue;
1771  }
1772  /* We have some next linked sms from sequence */
1773  if (InputMessages[i]->SMS[0].UDH.PartNumber > 1) {
1774  j = 0;
1775  while (InputMessages[j]!=NULL) {
1776  if (InputMessagesSorted[j]) {
1777  j++;
1778  continue;
1779  }
1780  /* We have some not unassigned first sms from sequence.
1781  * We can't touch other sms from sequences
1782  */
1783  if (InputMessages[j]->SMS[0].UDH.PartNumber == 1) break;
1784  j++;
1785  }
1786  if (InputMessages[j]==NULL) {
1787  OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1788  if (OutputMessages[OutputMessagesNum] == NULL) {
1789  free(InputMessagesSorted);
1790  InputMessagesSorted=NULL;
1791  return ERR_MOREMEMORY;
1792  }
1793  OutputMessages[OutputMessagesNum+1] = NULL;
1794 
1795  memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1796  InputMessagesSorted[i]=TRUE;
1797  OutputMessagesNum++;
1798  i = 0;
1799  continue;
1800  } else i++;
1801  }
1802  }
1803  free(InputMessagesSorted);
1804  InputMessagesSorted=NULL;
1805  return ERR_NONE;
1806 }
1807 
1808 /* How should editor hadle tabs in this file? Add editor commands here.
1809  * vim: noexpandtab sw=8 ts=8 sts=8:
1810  */
GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, GSM_UDH UDHType)
Definition: gsmems.c:20
GSM_DateTime DateTime
GSM_Error GSM_EncodeVCALENDAR(char *Buffer, const size_t buff_len, size_t *Length, GSM_CalendarEntry *note, const gboolean header, const GSM_VCalendarVersion Version)
Definition: gsmcal.c:814
#define SM30_PROFILENAME
Definition: gsmmulti.h:20
unsigned int ReassembleCharacter(char *Buffer, size_t character_index)
Definition: gsmmulti.c:71
gboolean GSM_DecodeMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, gboolean ems)
Definition: gsmmulti.c:1275
unsigned char Name[2 *(GSM_MAX_FILENAME_LENGTH+1)]
Definition: gammu-file.h:74
GSM_MemoryEntry * Phonebook
unsigned char Text[(GSM_MAX_SMS_LENGTH+1) *2]
gboolean GSM_DecodeMMSIndication(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmmulti.c:981
GSM_Error GSM_EncodeVCARD(GSM_Debug_Info *di, char *Buffer, const size_t buff_len, size_t *Length, GSM_MemoryEntry *pbk, const gboolean header, const GSM_VCardVersion Version)
Definition: gsmpbk.c:126
char * DecodeUnicodeString(const unsigned char *src)
Definition: coding.c:245
void DumpMessage(GSM_Debug_Info *d, const unsigned char *message, const size_t messagesize)
Definition: debug.c:314
size_t PHONE_GetBitmapSize(GSM_Phone_Bitmap_Types Type, size_t Width, size_t Height)
Definition: gsmlogo.c:44
GSM_Error GSM_AddSMS_Text_UDH(GSM_Debug_Info *di, GSM_MultiSMSMessage *SMS, GSM_Coding_Type Coding, char *Buffer, size_t BufferLen, gboolean UDH, size_t *UsedText, size_t *CopiedText, size_t *CopiedSMSText)
Definition: gsmmulti.c:212
void CopyUnicodeString(unsigned char *Dest, const unsigned char *Source)
Definition: coding.c:1192
GSM_MultiBitmap * Bitmap
GSM_WAPSettings * Settings
void DecodeDefault(unsigned char *dest, const unsigned char *src, size_t len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
Definition: coding.c:498
unsigned char ReplaceMessage
#define SM30_RINGTONE
Definition: gsmmulti.h:19
void FindDefaultAlphabetLen(const unsigned char *src, size_t *srclen, size_t *smslen, size_t maxlen)
Definition: coding.c:914
unsigned char ReplaceMessage
char Address[500]
Definition: gammu-message.h:90
void GSM_EncodeMMSIndicatorSMSText(unsigned char *Buffer, size_t *Length, GSM_MMSIndicator *Indicator)
Definition: gsmdata.c:307
#define GSM_MAX_SMS_CHARS_LENGTH
Definition: gammu-limits.h:183
GSM_MMSIndicator * MMSIndicator
void GSM_SMSCounter(GSM_Debug_Info *di, unsigned char *MessageBuffer, GSM_UDH UDHType, GSM_Coding_Type Coding, int *SMSNum, size_t *CharsLeft)
Definition: gsmmulti.c:355
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
void PHONE_EncodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap)
Definition: gsmlogo.c:197
void NOKIA_EncodeWAPMMSSettingsSMSText(unsigned char *Buffer, size_t *Length, GSM_WAPSettings *settings, gboolean MMS)
Definition: gsmdata.c:41
FILE * df
Definition: debug.h:36
signed char Class
void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS)
Definition: gsmsms.c:1129
size_t UnicodeLength(const unsigned char *str)
Definition: coding.c:186
GSM_UDHHeader UDH
int AlignIfCombinedSurrogate(GSM_Debug_Info *di, size_t *Copy, char *Buffer, size_t BufferLen)
Definition: gsmmulti.c:157
void PHONE_DecodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap)
Definition: gsmlogo.c:141
GSM_MMS_Class Class
GSM_ToDoEntry * ToDo
unsigned char DataName[40]
void NOKIA_EncodeWAPBookmarkSMSText(unsigned char *Buffer, size_t *Length, GSM_WAPBookmark *bookmark)
Definition: gsmdata.c:190
GSM_Ringtone * Ringtone
unsigned char * Buffer
Definition: gammu-file.h:94
GSM_MultiPartSMSEntry Entries[GSM_MAX_MULTI_SMS]
#define ALCATELTDD_ANIMATION
Definition: gsmmulti.h:26
GSM_Coding_Type Coding
unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength)
Definition: gsmring.c:992
unsigned long AllDataLen
int AlignSegmentForContent(GSM_Debug_Info *di, size_t *Copy, char *Buffer, size_t BufferLen)
Definition: gsmmulti.c:197
#define GSM_MAX_SMS_LENGTH
Definition: gammu-limits.h:176
#define GSM_MAX_8BIT_SMS_LENGTH
Definition: gammu-limits.h:190
GSM_NoteRingtone NoteTone
void GSM_Find_Free_Used_SMS2(GSM_Debug_Info *di, GSM_Coding_Type Coding, GSM_SMSMessage *SMS, size_t *UsedText, size_t *FreeText, size_t *FreeBytes)
Definition: gsmmulti.c:37
void NOKIA_CopyBitmap(GSM_Phone_Bitmap_Types Type, GSM_Bitmap *Bitmap, char *Buffer, size_t *Length)
Definition: gsmlogo.c:1132
gboolean GSM_DecodeSiemensOTASMS(GSM_Debug_Info *di, GSM_SiemensOTASMSInfo *Info, GSM_SMSMessage *SMS)
Definition: gsmsms.c:1202
size_t Used
Definition: gammu-file.h:70
unsigned char Text[GSM_MAX_UDH_LENGTH]
char NetworkCode[10]
Definition: gammu-bitmap.h:160
unsigned char Data[140]
void NOKIA_DecodeNetworkCode(const unsigned char *buffer, char *output)
Definition: gsmnet.c:2473
int gboolean
Definition: gammu-types.h:23
void GSM_MakeMultiPartSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage *SMS, unsigned char *MessageBuffer, size_t MessageLength, GSM_UDH UDHType, GSM_Coding_Type Coding, int Class, unsigned char ReplaceMessage)
Definition: gsmmulti.c:305
#define GSM_SMS_OTHER_NUMBERS
Definition: gammu-limits.h:145
void GSM_PrintBitmap(FILE *file, GSM_Bitmap *bitmap)
Definition: gsmlogo.c:257
void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info)
Definition: gsmmulti.c:915
void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info)
Definition: gsmmulti.c:952
void EncodeUnicode(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:301
#define FALSE
Definition: gammu-types.h:25
#define SM30_UNICODETEXT
Definition: gsmmulti.h:17
unsigned int PacketNum
GSM_Error GSM_EncodeVTODO(char *Buffer, const size_t buff_len, size_t *Length, const GSM_ToDoEntry *note, const gboolean header, const GSM_VToDoVersion Version)
Definition: gsmcal.c:1038
gboolean GSM_DecodeEMSMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmems.c:586
unsigned int PacketsNum
#define SM30_ISOTEXT
Definition: gsmmulti.h:16
int AlignIfCombinedCharacter(GSM_Debug_Info *di, size_t *Copy, char *Buffer, size_t BufferLen)
Definition: gsmmulti.c:115
GSM_WAPBookmark * Bookmark
GSM_SMSMessage SMS[GSM_MAX_MULTI_SMS]
GSM_Error GSM_EncodeMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmmulti.c:500
char Sender[200]
Definition: gammu-message.h:98
EncodeMultiPartSMSID ID
GSM_Bitmap Bitmap[GSM_MAX_MULTI_BITMAP]
Definition: gammu-bitmap.h:192
void GSM_EncodeWAPIndicatorSMSText(unsigned char *Buffer, size_t *Length, char *Text, char *URL)
Definition: gsmdata.c:233
#define GSM_MAX_MULTI_SMS
Definition: gammu-limits.h:162
void NOKIA_EncodeNetworkCode(unsigned char *buffer, const char *input)
Definition: gsmnet.c:2467
GSM_UDH
GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, size_t maxlength UNUSED)
Definition: gsmring.c:1128
GSM_Coding_Type
#define dbgprintf
Definition: debug.h:72
unsigned char * Buffer
int AlignIfSurrogatePair(GSM_Debug_Info *di, size_t *Copy, char *Buffer, size_t BufferLen)
Definition: gsmmulti.c:81
unsigned char Number
Definition: gammu-bitmap.h:188
void GSM_GetCurrentDateTime(GSM_DateTime *Date)
Definition: misc.c:184
size_t BitmapHeight
Definition: gammu-bitmap.h:152
int smfprintf(GSM_Debug_Info *d, const char *format,...)
Definition: debug.c:240
#define ALCATELTDD_SMSTEMPLATE
Definition: gsmmulti.h:27
void GSM_EncodeUDHHeader(GSM_Debug_Info *di, GSM_UDHHeader *UDH)
Definition: gsmsms.c:1151
unsigned char GSM_MakeSMSIDFromTime(void)
Definition: gsmmulti.c:21
size_t BitmapWidth
Definition: gammu-bitmap.h:156
unsigned char Text[2 *(GSM_BITMAP_TEXT_LENGTH+1)]
Definition: gammu-bitmap.h:118
GSM_CalendarEntry * Calendar
gboolean GSM_DecodeNokiaProfile(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmmulti.c:1126
#define TRUE
Definition: gammu-types.h:28
#define ALCATELTDD_PICTURE
Definition: gsmmulti.h:25
GSM_Error GSM_LinkSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage **InputMessages, GSM_MultiSMSMessage **OutputMessages, gboolean ems)
Definition: gsmmulti.c:1395
void EncodeDefault(unsigned char *dest, const unsigned char *src, size_t *len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
Definition: coding.c:831
#define SM30_SCREENSAVER
Definition: gsmmulti.h:22
Debug_Level dl
Definition: debug.h:35
GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage *SMS, unsigned char *Data, size_t Len, unsigned char *Name, size_t Type)
Definition: gsmmulti.c:438
static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info, char *Buffer, size_t *Length)
Definition: gsmmulti.c:375
unsigned long SequenceID
gboolean GSM_DecodeLinkedText(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmmulti.c:1229
unsigned char DataType[10]
#define SM30_OTA
Definition: gsmmulti.h:18