Gammu internals  1.38.0
gsmems.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 "../../misc/coding/coding.h"
11 #include "../../debug.h"
12 #include "../gsmlogo.h"
13 #include "gsmmulti.h"
14 #include "gsmems.h"
15 #include "../gsmring.h"
16 
17 /* EMS Developers' Guidelines from www.sonyericsson.com
18  * docs from Alcatel
19  */
23  GSM_UDH UDHType)
24 {
25  unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*GSM_MAX_MULTI_SMS];
26  int i,j,z;
27  ssize_t Length;
28  size_t EncodeLength;
29  unsigned int Len;
30  size_t FreeText=0,FreeBytes=0,UsedText=0,Width,Height,x,y,Width2;
31  size_t Used,CopiedText,CopiedSMSText;
32  unsigned char UDHID;
33  GSM_Bitmap Bitmap,Bitmap2;
34  GSM_Ringtone Ring;
36  GSM_Phone_Bitmap_Types BitmapType;
37  GSM_MultiPartSMSEntry *Entry;
38  GSM_DateTime Date;
39 
40 #ifdef DEBUG
41  if (UDHType != UDH_NoUDH) smfprintf(di, "linked EMS\n");
42 #endif
43 
45 
46  /* Cleaning on the start */
47  for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
48  GSM_SetDefaultSMSData(&SMS->SMS[i]);
49  SMS->SMS[i].UDH.Type = UDHType;
50  GSM_EncodeUDHHeader(di, &SMS->SMS[i].UDH);
51  SMS->SMS[i].Coding = Coding;
52  }
53 
54  /* Packing */
55  for (i=0;i<Info->EntriesNum;i++) {
56  Entry = &Info->Entries[i];
57 
58  switch (Entry->ID) {
61  Len = 0;
62  while(1) {
63  if (Entry->Left || Entry->Right ||
64  Entry->Center || Entry->Large ||
65  Entry->Small || Entry->Bold ||
66  Entry->Italic || Entry->Underlined ||
67  Entry->Strikethrough) {
68  Buffer[0] = 0x0A; /* ID for text format */
69  Buffer[1] = 0x03; /* length of rest */
70  Buffer[2] = 0x00; /* Position in EMS msg */
71  Buffer[3] = 0x00; /* how many chars */
72  Buffer[4] = 0x00; /* formatting bits */
73  if (Entry->Left) {
74  } else if (Entry->Right) { Buffer[4] |= 1;
75  } else if (Entry->Center) { Buffer[4] |= 2;
76  } else Buffer[4] |= 3;
77  if (Entry->Large) { Buffer[4] |= 4;
78  } else if (Entry->Small) { Buffer[4] |= 8;}
79  if (Entry->Bold) Buffer[4] |= 16;
80  if (Entry->Italic) Buffer[4] |= 32;
81  if (Entry->Underlined) Buffer[4] |= 64;
82  if (Entry->Strikethrough) Buffer[4] |= 128;
83  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,5,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
84  GSM_Find_Free_Used_SMS2(di, Coding, &(SMS->SMS[SMS->Number]), &UsedText, &FreeText, &FreeBytes);
85  if (FreeText == 0) continue;
86  }
87  GSM_AddSMS_Text_UDH(di, SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,FALSE,&UsedText,&CopiedText,&CopiedSMSText);
88  if (Entry->Left || Entry->Right ||
89  Entry->Center || Entry->Large ||
90  Entry->Small || Entry->Bold ||
91  Entry->Italic || Entry->Underlined ||
92  Entry->Strikethrough) {
93  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText;
94  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText;
95  }
96  Len += CopiedText;
97  if (Len == UnicodeLength(Entry->Buffer)) break;
98  smfprintf(di, "%u %ld\n", Len, (long)UnicodeLength(Entry->Buffer));
99  }
100  break;
103  if (Entry->ID == SMS_EMSPredefinedSound) {
104  Buffer[0] = 0x0B; /* ID for def.sound */
105  } else {
106  Buffer[0] = 0x0D; /* ID for def.animation */
107  }
108  Buffer[1] = 0x02; /* Length of rest */
109  Buffer[2] = 0x00; /* Position in EMS msg */
110  Buffer[3] = Entry->Number; /* Number of anim. */
111  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
112  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText;
113  break;
115  case SMS_EMSSound10:
116  case SMS_EMSSound12:
117  if (Entry->Protected) {
118  Buffer[0] = 0x17; /* ID for ODI */
119  Buffer[1] = 2; /* Length of rest */
120  Buffer[2] = 1; /* Number of protected objects */
121  Buffer[3] = 1; /* 1=Protected,0=Not protected */
122  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
123  }
124 
125  EncodeLength = 128; /* 128 bytes is maximum length from specs */
126  switch (Entry->ID) {
127  case SMS_EMSSound10:
128  Entry->RingtoneNotes = GSM_EncodeEMSSound(Entry->Ringtone, Buffer+3, &EncodeLength, GSM_Ring_IMelody10, TRUE);
129  break;
130  case SMS_EMSSound12:
131  Entry->RingtoneNotes = GSM_EncodeEMSSound(Entry->Ringtone, Buffer+3, &EncodeLength, GSM_Ring_IMelody12, TRUE);
132  break;
134  Entry->RingtoneNotes = GSM_EncodeEMSSound(Entry->Ringtone, Buffer+3, &EncodeLength, GSM_Ring_NoHeader, TRUE);
135  break;
136  default:
137  break;
138  }
139 
140  Buffer[0] = 0x0C; /* ID for EMS sound */
141  Buffer[1] = EncodeLength+1; /* Length of rest */
142  Buffer[2] = 0x00; /* Position in EMS msg */
143  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,EncodeLength+3,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
144  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-EncodeLength-1] = UsedText;
145  break;
147  case SMS_EMSSound10Long:
148  case SMS_EMSSound12Long:
149  Ring = *Entry->Ringtone;
150 
151  /* First check if we can use classic format */
152  EncodeLength = 128; /* 128 bytes is maximum length from specs */
153  switch (Entry->ID) {
154  case SMS_EMSSound10Long:
155  Entry->RingtoneNotes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody10, TRUE);
156  break;
157  case SMS_EMSSound12Long:
158  Entry->RingtoneNotes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody12, TRUE);
159  break;
161  Entry->RingtoneNotes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_NoHeader, TRUE);
162  break;
163  default:
164  break;
165  }
166  if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) {
167  if (Entry->Protected) {
168  Buffer[0] = 0x17; /* ID for ODI */
169  Buffer[1] = 2; /* Length of rest */
170  Buffer[2] = 1; /* Number of protected objects */
171  Buffer[3] = 1; /* 1=Protected,0=Not protected */
172  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
173  }
174 
175  Buffer[0] = 0x0C; /* ID for EMS sound */
176  Buffer[1] = EncodeLength+1; /* Length of rest */
177  Buffer[2] = 0x00; /* Position in EMS msg */
178  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,EncodeLength+3,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
179  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-EncodeLength-1] = UsedText;
180  break;
181  }
182 
183  /* Find free place in first SMS */
184  GSM_Find_Free_Used_SMS2(di, Coding, &(SMS->SMS[SMS->Number]), &UsedText, &FreeText, &FreeBytes);
185  Length = FreeBytes - 3;
186  if (Entry->Protected) Length = Length - 4;
187  if (Length < 0) Length = 128;
188  if (Length > 128) Length = 128;
189 
190  Ring = *Entry->Ringtone;
191 
192  /* Checking number of SMS */
193  Used = 0;
194  FreeBytes = 0;
195  EncodeLength = Length;
196  while (1) {
197  if (FreeBytes != 0) {
198  z = 0;
199  for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
200  Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j];
201  z++;
202  }
203  Ring.NoteTone.NrCommands -= FreeBytes;
204  if (Ring.NoteTone.NrCommands == 0) break;
205  EncodeLength = 128; /* 128 bytes is maximum length from specs */
206  }
207  switch (Entry->ID) {
208  case SMS_EMSSound10Long:
209  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody10, TRUE);
210  break;
211  case SMS_EMSSound12Long:
212  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody12, TRUE);
213  break;
215  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_NoHeader, TRUE);
216  break;
217  default:
218  break;
219  }
220  Used++;
221  }
222  smfprintf(di, "Used SMS: %ld\n", (long)Used);
223 
224  if (Entry->Protected) {
225  Buffer[0] = 0x17; /* ID for ODI */
226  Buffer[1] = 2; /* Length of rest */
227  Buffer[2] = Used+1; /* Number of protected objects */
228  Buffer[3] = 1; /* 1=Protected,0=Not protected */
229  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
230  }
231 
232  /* Save UPI UDH */
233  Buffer[0] = 0x13; /* ID for UPI */
234  Buffer[1] = 1; /* Length of rest */
235  Buffer[2] = Used; /* Number of used parts */
236  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,3,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
237 
238  /* Find free place in first SMS */
239  GSM_Find_Free_Used_SMS2(di, Coding, &(SMS->SMS[SMS->Number]), &UsedText, &FreeText, &FreeBytes);
240  Length = FreeBytes - 3;
241  if (Length < 0) Length = 128;
242  if (Length > 128) Length = 128;
243 
244  Ring = *Entry->Ringtone;
245 
246  /* Saving */
247  FreeBytes = 0;
248  EncodeLength = Length;
249  while (1) {
250  if (FreeBytes != 0) {
251  z = 0;
252  for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
253  Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j];
254  z++;
255  }
256  Ring.NoteTone.NrCommands -= FreeBytes;
257  if (Ring.NoteTone.NrCommands == 0) break;
258  EncodeLength = 128; /* 128 bytes is maximum length from specs */
259  }
260  switch (Entry->ID) {
261  case SMS_EMSSound10Long:
262  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody10, TRUE);
263  break;
264  case SMS_EMSSound12Long:
265  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_IMelody12, TRUE);
266  break;
268  FreeBytes = GSM_EncodeEMSSound(&Ring, Buffer+3, &EncodeLength, GSM_Ring_NoHeader, TRUE);
269  break;
270  default:
271  break;
272  }
273  Buffer[0] = 0x0C; /* ID for EMS sound */
274  Buffer[1] = EncodeLength+1; /* Length of rest */
275  Buffer[2] = 0x00; /* Position in EMS msg */
276  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,EncodeLength+3,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
277  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-EncodeLength-1] = UsedText;
278  }
279 
280  Entry->RingtoneNotes = Entry->Ringtone->NoteTone.NrCommands;
281 
282  break;
283  case SMS_EMSAnimation:
284  if (Entry->Protected) {
285  Buffer[0] = 0x17; /* ID for ODI */
286  Buffer[1] = 2; /* Length of rest */
287  Buffer[2] = 1; /* Number of protected objects */
288  Buffer[3] = 1; /* 1=Protected,0=Not protected */
289  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
290  }
291 
292  if (Entry->Bitmap->Bitmap[0].BitmapWidth > 8 || Entry->Bitmap->Bitmap[0].BitmapHeight > 8) {
293  BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
294  Buffer[0] = 0x0E; /* ID for 16x16 animation */
295  } else {
296  BitmapType = GSM_EMSSmallPicture; /* Bitmap 8x8 */
297  Buffer[0] = 0x0F; /* ID for 8x8 animation */
298  }
299  Length = PHONE_GetBitmapSize(BitmapType,0,0);
300 
301  Buffer[1] = Length*Entry->Bitmap->Number + 1; /* Length of rest */
302  Buffer[2] = 0x00; /* Position in EMS msg */
303  for (j=0;j<Entry->Bitmap->Number;j++) {
304  PHONE_EncodeBitmap(BitmapType, Buffer+3+j*Length, &Entry->Bitmap->Bitmap[j]);
305  }
306  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,3+Length*Entry->Bitmap->Number,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
307  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length*Entry->Bitmap->Number] = UsedText;
308  break;
309  case SMS_EMSFixedBitmap:
310  if (Entry->Protected) {
311  Buffer[0] = 0x17; /* ID for ODI */
312  Buffer[1] = 2; /* Length of rest */
313  Buffer[2] = 1; /* Number of protected objects */
314  Buffer[3] = 1; /* 1=Protected,0=Not protected */
315  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
316  }
317 
318  if (Entry->Bitmap->Bitmap[0].BitmapWidth > 16 || Entry->Bitmap->Bitmap[0].BitmapHeight > 16) {
319  BitmapType = GSM_EMSBigPicture; /* Bitmap 32x32 */
320  Buffer[0] = 0x10; /* ID for EMS bitmap */
321  } else {
322  BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
323  Buffer[0] = 0x11; /* ID for EMS bitmap */
324  }
325  Length = PHONE_GetBitmapSize(BitmapType,0,0);
326  PHONE_GetBitmapWidthHeight(BitmapType, &Width, &Height);
327 
328  Buffer[1] = Length + 1; /* Length of rest */
329  Buffer[2] = 0x00; /* Position in EMS msg */
330  PHONE_EncodeBitmap(BitmapType,Buffer+3, &Entry->Bitmap->Bitmap[0]);
331  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,3+Length,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
332  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length] = UsedText;
333  break;
335  BitmapType = GSM_EMSVariablePicture;
336  Width = Entry->Bitmap->Bitmap[0].BitmapWidth;
337  Height = Entry->Bitmap->Bitmap[0].BitmapHeight;
338  Bitmap = Entry->Bitmap->Bitmap[0];
339 
340  /* First check if we can use classical format */
341  while (1) {
342  /* Width should be multiply of 8 */
343  while (Width % 8 != 0) Width--;
344 
345  /* specs */
346  if (Width <= 96 && Height <= 128) break;
347 
348  Height--;
349  }
350  Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
351  if (Length <= 128) {
352  if (Entry->Protected) {
353  Buffer[0] = 0x17; /* ID for ODI */
354  Buffer[1] = 2; /* Length of rest */
355  Buffer[2] = 1; /* Number of protected objects */
356  Buffer[3] = 1; /* 1=Protected,0=Not protected */
357  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
358  }
359 
360  Buffer[0] = 0x12; /* ID for EMS bitmap */
361  Buffer[1] = Length + 3; /* Length of rest */
362  Buffer[2] = 0x00; /* Position in EMS msg */
363  Buffer[3] = Width/8; /* Bitmap width/8 */
364  Buffer[4] = Height; /* Bitmap height */
365 
366  GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
367 #ifdef DEBUG
370 #endif
371  PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
372  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,5+Length,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
373  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
374  break;
375  }
376 
377  /* Find free place in first SMS */
378  GSM_Find_Free_Used_SMS2(di, Coding, &(SMS->SMS[SMS->Number]), &UsedText, &FreeText, &FreeBytes);
379  Used = 0;
380  Length = FreeBytes - 3;
381  if (Entry->Protected) Length = Length - 4;
382  if (Length < 0) Length = 128;
383  if (Length > 128) Length = 128;
384 
385  /* Checking number of SMS */
386  FreeBytes = 0;
387  while (FreeBytes != Width) {
388  Width2 = 8;
389  while (FreeBytes + Width2 != Width) {
390  if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > (size_t)Length) break;
391 
392  Width2 = Width2 + 8;
393  }
394  FreeBytes = FreeBytes + Width2;
395  Length = 128;
396  Used ++;
397  }
398  smfprintf(di, "Used SMS: %ld\n", (long)Used);
399 
400  if (Entry->Protected) {
401  Buffer[0] = 0x17; /* ID for ODI */
402  Buffer[1] = 2; /* Length of rest */
403  Buffer[2] = Used+1; /* Number of protected objects */
404  Buffer[3] = 1; /* 1=Protected,0=Not protected */
405  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
406  }
407 
408  /* Save UPI UDH */
409  Buffer[0] = 0x13; /* ID for UPI */
410  Buffer[1] = 1; /* Length of rest */
411  Buffer[2] = Used; /* Number of used parts */
412 
413  /* Find free place in first SMS */
414  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,3,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
415  GSM_Find_Free_Used_SMS2(di, Coding, &(SMS->SMS[SMS->Number]), &UsedText, &FreeText, &FreeBytes);
416  Length = FreeBytes - 3;
417  if (Length < 0) Length = 128;
418  if (Length > 128) Length = 128;
419 
420 #ifdef DEBUG
423 #endif
424 
425  /* Saving SMS */
426  FreeBytes = 0;
427  while (FreeBytes != Width) {
428  Width2 = 8;
429  while (FreeBytes + Width2 != Width) {
430  if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > (size_t)Length) break;
431 
432  Width2 = Width2 + 8;
433  }
434 
435  /* Copying part of bitmap to new structure */
436  Bitmap2.BitmapWidth = Width2;
437  Bitmap2.BitmapHeight = Height;
438  GSM_ClearBitmap(&Bitmap2);
439  for (x=0;x<Width2;x++) {
440  for (y=0;y<Height;y++) {
441  if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) {
442  GSM_SetPointBitmap(&Bitmap2, x, y);
443  }
444  }
445  }
446 #ifdef DEBUG
449 #endif
450 
451  /* Adding new bitmap to SMS */
452  Length = PHONE_GetBitmapSize(BitmapType,Width2,Height);
453  Buffer[0] = 0x12; /* ID for EMS bitmap */
454  Buffer[1] = Length + 3; /* Length of rest */
455  Buffer[2] = 0x00; /* Position in EMS msg */
456  Buffer[3] = Width2/8; /* Bitmap width/8 */
457  Buffer[4] = Height; /* Bitmap height */
458  PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2);
459  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,5+Length,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
460  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
461 
462  FreeBytes = FreeBytes + Width2;
463  Length = 128;
464  }
465  break;
467  if (Entry->Protected) {
468  Buffer[0] = 0x17; /* ID for ODI */
469  Buffer[1] = 2; /* Length of rest */
470  Buffer[2] = 1; /* Number of protected objects */
471  Buffer[3] = 1; /* 1=Protected,0=Not protected */
472  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,4,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
473  }
474 
475  BitmapType = GSM_EMSVariablePicture;
476  Width = Entry->Bitmap->Bitmap[0].BitmapWidth;
477  Height = Entry->Bitmap->Bitmap[0].BitmapHeight;
478 
479  while (1) {
480  /* Width should be multiply of 8 */
481  while (Width % 8 != 0) Width--;
482 
483  /* specs */
484  if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break;
485 
486  Height--;
487  }
488 
489  Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
490 
491  Buffer[0] = 0x12; /* ID for EMS bitmap */
492  Buffer[1] = Length + 3; /* Length of rest */
493  Buffer[2] = 0x00; /* Position in EMS msg */
494  Buffer[3] = Width/8; /* Bitmap width/8 */
495  Buffer[4] = Height; /* Bitmap height */
496 
497  GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
498 #ifdef DEBUG
501 #endif
502  PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
503  GSM_AddSMS_Text_UDH(di, SMS,Coding,Buffer,5+Length,TRUE,&UsedText,&CopiedText,&CopiedSMSText);
504  SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
505  break;
506  default:
507  break;
508  }
509  }
510 
511  SMS->Number++;
512 
513  if (UDHType == UDH_ConcatenatedMessages) {
514  UDHID = GSM_MakeSMSIDFromTime();
515  for (i=0;i<SMS->Number;i++) {
516  SMS->SMS[i].UDH.Text[2+1] = UDHID;
517  SMS->SMS[i].UDH.Text[3+1] = SMS->Number;
518  SMS->SMS[i].UDH.Text[4+1] = i+1;
519  }
520  }
521  if (UDHType == UDH_ConcatenatedMessages16bit) {
522  UDHID = GSM_MakeSMSIDFromTime();
523  GSM_GetCurrentDateTime (&Date);
524  for (i=0;i<SMS->Number;i++) {
525  SMS->SMS[i].UDH.Text[2+1] = Date.Hour;
526  SMS->SMS[i].UDH.Text[3+1] = UDHID;
527  SMS->SMS[i].UDH.Text[4+1] = SMS->Number;
528  SMS->SMS[i].UDH.Text[5+1] = i+1;
529  }
530  }
531 
532 #ifdef DEBUG
533  smfprintf(di, "SMS number is %i\n",SMS->Number);
534  for (i=0;i<SMS->Number;i++) {
535  smfprintf(di, "UDH length %i\n",SMS->SMS[i].UDH.Length);
536  DumpMessage(&GSM_global_debug, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length);
537  smfprintf(di, "SMS length %ld\n", (long)UnicodeLength(SMS->SMS[i].Text)*2);
538  DumpMessage(&GSM_global_debug, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2);
539  }
540 #endif
541  return ERR_NONE;
542 }
543 
544 static gboolean AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len)
545 {
546  int BufferLen;
547 
548  if (Len==0) return TRUE;
549 
550  if (Info->Entries[Info->EntriesNum].ID!=SMS_ConcatenatedTextLong &&
551  Info->Entries[Info->EntriesNum].ID!=0) {
552  (Info->EntriesNum)++;
553  }
554  BufferLen = UnicodeLength(Info->Entries[Info->EntriesNum].Buffer) * 2 + 2;
555  switch (SMS->Coding) {
556 #if 0
557  case -1:
558  /* We will convert the text */
560 #endif
561  case SMS_Coding_8bit:
562  Info->Entries[Info->EntriesNum].Buffer = (unsigned char *)realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2));
563  if (Info->Entries[Info->EntriesNum].Buffer == NULL) return FALSE;
564  EncodeUnicode(Info->Entries[Info->EntriesNum].Buffer + BufferLen - 2, SMS->Text + (*Pos) *2, Len);
565  BufferLen += Len * 2;
566  break;
569  Info->Entries[Info->EntriesNum].Buffer = (unsigned char *)realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2));
570  if (Info->Entries[Info->EntriesNum].Buffer == NULL) return FALSE;
571  memcpy(Info->Entries[Info->EntriesNum].Buffer + BufferLen - 2, SMS->Text + (*Pos) *2, Len * 2);
572  BufferLen += Len * 2;
573  break;
574  default:
575  break;
576  }
577  if (Info->Entries[Info->EntriesNum].Buffer != NULL) {
578  (*Pos)+=Len;
579  Info->Entries[Info->EntriesNum].Buffer[BufferLen - 2] = 0;
580  Info->Entries[Info->EntriesNum].Buffer[BufferLen - 1] = 0;
582  }
583  return TRUE;
584 }
585 
587  GSM_MultiPartSMSInfo *Info,
588  GSM_MultiSMSMessage *SMS)
589 {
590  int i, w, Pos, UPI = 1, fmt;
591  size_t width, height;
592  size_t z;
593  gboolean NewPicture = TRUE;
594  GSM_Phone_Bitmap_Types BitmapType;
595  GSM_Bitmap Bitmap,Bitmap2;
596 
597  for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
598  Info->Entries[i].ID = 0;
599  }
600 
601  for (i=0;i<SMS->Number;i++) {
602  Pos = 0;
603  w = 1;
604  while (w < SMS->SMS[i].UDH.Length) {
605  if (Info->EntriesNum + 1 == GSM_MAX_MULTI_SMS) {
606  smfprintf(di, "Couldn't parse SMS, contains too many EMS parts!\n");
607  return FALSE;
608  }
609  switch(SMS->SMS[i].UDH.Text[w]) {
610  case 0x00:
611  smfprintf(di, "UDH part - linked SMS with 8 bit ID\n");
612  break;
613  case 0x05:
614  /* Application data */
615  SMS->SMS[i].Coding = -1;
616  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return FALSE;
617  Info->Entries[Info->EntriesNum].Number =
618  ((0x00ff & SMS->SMS[i].UDH.Text[w + 2]) << 8) | ( 0x00ff &SMS->SMS[i].UDH.Text[w + 3]);
619  switch (Info->Entries[Info->EntriesNum].Number) {
620  case 0x23f4:
621  smfprintf(di, "UDH part - vCard\n");
622  Info->Entries[Info->EntriesNum].ID = SMS_NokiaVCARD21Long;
623  break;
624  case 0x23f5:
625  smfprintf(di, "UDH part - vCalendar\n");
627  break;
628  case 0x0b84:
629  smfprintf(di, "UDH part - MMS notification\n");
630  return GSM_DecodeMMSIndication(di, Info, SMS);
631  default:
632  smfprintf(di, "UDH part - unknown application data - 0x%04x\n", Info->Entries[Info->EntriesNum].Number);
633  break;
634  }
635  break;
636  case 0x08:
637  smfprintf(di, "UDH part - linked SMS with 16 bit ID\n");
638  break;
639  case 0x0A:
640  smfprintf(di, "UDH part - EMS text formatting\n");
641  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
642  z = Pos;
643  if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
644  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
645  }
646  fmt = SMS->SMS[i].UDH.Text[w+4];
647  switch (fmt & 3) {
648  case 0:
649  Info->Entries[Info->EntriesNum].Left = TRUE;
650  break;
651  case 1:
652  Info->Entries[Info->EntriesNum].Right = TRUE;
653  break;
654  case 2:
655  Info->Entries[Info->EntriesNum].Center = TRUE;
656  break;
657  case 3:
658  break;
659 
660  }
661  if ((fmt & 4) == 4) {
662  Info->Entries[Info->EntriesNum].Large = TRUE;
663  }
664  if ((fmt & 8) == 8) {
665  Info->Entries[Info->EntriesNum].Small = TRUE;
666  }
667  if ((fmt & 16) == 16) {
668  Info->Entries[Info->EntriesNum].Bold = TRUE;
669  }
670  if ((fmt & 32) == 32) {
671  Info->Entries[Info->EntriesNum].Italic= TRUE;
672  }
673  if ((fmt & 64) == 64) {
674  Info->Entries[Info->EntriesNum].Underlined = TRUE;
675  }
676  if ((fmt & 128) == 128) {
677  Info->Entries[Info->EntriesNum].Strikethrough = TRUE;
678  }
679  Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3];
681  break;
682  case 0x0B:
683  smfprintf(di, "UDH part - default EMS sound\n");
684  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
685  z = Pos;
686  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
687  }
688  if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
689  Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3];
691  break;
692 #if 0
693  case 0x0C:
694  smfprintf(di, "UDH part - EMS sound\n");
695  break;
696 #endif
697  case 0x0D:
698  smfprintf(di, "UDH part - default EMS animation\n");
699  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
700  z = Pos;
701  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
702  }
703  if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
704  Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3];
706  break;
707  case 0x0E:
708  case 0x0F:
709  if (SMS->SMS[i].UDH.Text[w] == 0x0E) {
710  smfprintf(di, "UDH part - EMS 16x16 animation\n");
711  BitmapType = GSM_EMSMediumPicture;
712  } else {
713  smfprintf(di, "UDH part - EMS 8x8 animation\n");
714  BitmapType = GSM_EMSSmallPicture;
715  }
716  smfprintf(di, "Position - %i\n",SMS->SMS[i].UDH.Text[w+2]);
717  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
718  z = Pos;
719  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
720  }
721  (Info->EntriesNum)++;
722  Info->Entries[Info->EntriesNum].ID = SMS_EMSAnimation;
723  Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
724  if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return FALSE;
725  Info->Entries[Info->EntriesNum].Bitmap->Number = 0;
726  for (z=0;z<((SMS->SMS[i].UDH.Text[w+1]-1)/PHONE_GetBitmapSize(BitmapType,0,0));z++) {
728  PHONE_DecodeBitmap(BitmapType,
729  SMS->SMS[i].UDH.Text + w + 3 + PHONE_GetBitmapSize(BitmapType,0,0) * z,
730  &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z]);
731  Info->Entries[Info->EntriesNum].Bitmap->Number++;
732  }
733  break;
734  case 0x10:
735  case 0x11:
736  if (SMS->SMS[i].UDH.Text[w] == 0x10) {
737  smfprintf(di, "UDH part - EMS 32x32 picture\n");
738  BitmapType = GSM_EMSBigPicture;
739  } else {
740  smfprintf(di, "UDH part - EMS 16x16 picture\n");
741  BitmapType = GSM_EMSMediumPicture;
742  }
743  smfprintf(di, "Position - %i\n",SMS->SMS[i].UDH.Text[w+2]);
744  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
745  z = Pos;
746  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
747  }
748  if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++;
749  Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
750  if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return FALSE;
751  PHONE_DecodeBitmap(BitmapType,
752  SMS->SMS[i].UDH.Text + w + 3,
753  &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]);
754  Info->Entries[Info->EntriesNum].Bitmap->Number = 1;
755  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0;
756  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0;
757  Info->Entries[Info->EntriesNum].ID = SMS_EMSFixedBitmap;
758  break;
759  case 0x12:
760  smfprintf(di, "UDH part - EMS variable width bitmap\n");
761  if (SMS->SMS[i].UDH.Text[w+2] > Pos) {
762  z = Pos;
763  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return FALSE;
764  }
765  Bitmap.BitmapWidth = SMS->SMS[i].UDH.Text[w+3]*8;
766  Bitmap.BitmapHeight = SMS->SMS[i].UDH.Text[w+4];
767  Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
768  if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return FALSE;
769  if (NewPicture) {
770  Info->Entries[Info->EntriesNum].Bitmap->Number = 0;
771  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth;
772  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap.BitmapHeight;
774  SMS->SMS[i].UDH.Text + w + 5,
775  &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]);
776  } else {
778  SMS->SMS[i].UDH.Text + w + 5,
779  &Bitmap);
780  Bitmap2 = Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0];
781  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth+Bitmap2.BitmapWidth;
782  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap2.BitmapHeight;
783  for (width=0;width<Bitmap2.BitmapWidth;width++) {
784  for (height=0;height<Bitmap2.BitmapHeight;height++) {
785  if (GSM_IsPointBitmap(&Bitmap2, width, height)) {
786  GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height);
787  } else {
788  GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height);
789  }
790  }
791  }
792  for (width=0;width<Bitmap.BitmapWidth;width++) {
793  for (height=0;height<Bitmap2.BitmapHeight;height++) {
794  if (GSM_IsPointBitmap(&Bitmap, width, height)) {
795  GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height);
796  } else {
797  GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height);
798  }
799  }
800  }
801  }
802  if (UPI == 1) {
803  Info->Entries[Info->EntriesNum].Bitmap->Number = 1;
804  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0;
805  Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0;
807  NewPicture = TRUE;
808  smfprintf(di, "New variable picture\n");
809  } else {
810  NewPicture = FALSE;
811  UPI--;
812  }
813  break;
814  case 0x13:
815  smfprintf(di, "UDH part - UPI\n");
816  smfprintf(di, "Value %i\n",SMS->SMS[i].UDH.Text[w+2]);
817  UPI = SMS->SMS[i].UDH.Text[w+2];
818  break;
819  case 0x17:
820  smfprintf(di, "UDH part - Object Distribution Indicator (Media Rights Protecting) ignored now\n");
821  break;
822  default:
823  smfprintf(di, "UDH part - unknown block %02x\n",SMS->SMS[i].UDH.Text[w]);
824  Info->Unknown = TRUE;
825  } /* switch */
826  w=w+SMS->SMS[i].UDH.Text[w+1]+2;
827  } /* while */
828  if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return FALSE;
829  }
830  if (SMS->Number > 0) (Info->EntriesNum)++;
831  return TRUE;
832 }
833 
834 /* How should editor hadle tabs in this file? Add editor commands here.
835  * vim: noexpandtab sw=8 ts=8 sts=8:
836  */
GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, GSM_UDH UDHType)
Definition: gsmems.c:20
GSM_RingCommand Commands[GSM_MAX_RINGTONE_NOTES]
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
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
GSM_MultiBitmap * Bitmap
static gboolean AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len)
Definition: gsmems.c:544
GSM_Bitmap_Types Type
Definition: gammu-bitmap.h:107
GSM_Error
Definition: gammu-error.h:23
void PHONE_EncodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap)
Definition: gsmlogo.c:197
FILE * df
Definition: debug.h:36
void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS)
Definition: gsmsms.c:1129
size_t UnicodeLength(const unsigned char *str)
Definition: coding.c:186
GSM_UDHHeader UDH
void PHONE_DecodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap)
Definition: gsmlogo.c:141
GSM_Ringtone * Ringtone
GSM_MultiPartSMSEntry Entries[GSM_MAX_MULTI_SMS]
GSM_Phone_Bitmap_Types
Definition: gsmlogo.h:9
GSM_Coding_Type Coding
#define GSM_MAX_SMS_LENGTH
Definition: gammu-limits.h:176
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
unsigned char Text[GSM_MAX_UDH_LENGTH]
void GSM_ResizeBitmap(GSM_Bitmap *dest, GSM_Bitmap *src, size_t width, size_t height)
Definition: gsmlogo.c:288
int gboolean
Definition: gammu-types.h:23
void GSM_PrintBitmap(FILE *file, GSM_Bitmap *bitmap)
Definition: gsmlogo.c:257
GSM_Debug_Info GSM_global_debug
Definition: debug.c:33
void EncodeUnicode(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:301
#define FALSE
Definition: gammu-types.h:25
gboolean GSM_IsPointBitmap(GSM_Bitmap *bmp, int x, int y)
Definition: gsmlogo.c:238
gboolean GSM_DecodeEMSMultiPartSMS(GSM_Debug_Info *di, GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS)
Definition: gsmems.c:586
GSM_SMSMessage SMS[GSM_MAX_MULTI_SMS]
EncodeMultiPartSMSID ID
GSM_Bitmap Bitmap[GSM_MAX_MULTI_BITMAP]
Definition: gammu-bitmap.h:192
#define GSM_MAX_MULTI_SMS
Definition: gammu-limits.h:162
GSM_UDH
GSM_Coding_Type
unsigned char * Buffer
unsigned char Number
Definition: gammu-bitmap.h:188
void GSM_GetCurrentDateTime(GSM_DateTime *Date)
Definition: misc.c:184
void GSM_ClearBitmap(GSM_Bitmap *bmp)
Definition: gsmlogo.c:247
void PHONE_GetBitmapWidthHeight(GSM_Phone_Bitmap_Types Type, size_t *width, size_t *height)
Definition: gsmlogo.c:23
size_t BitmapHeight
Definition: gammu-bitmap.h:152
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
void GSM_ClearPointBitmap(GSM_Bitmap *bmp, int x, int y)
Definition: gsmlogo.c:233
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
void GSM_SetPointBitmap(GSM_Bitmap *bmp, int x, int y)
Definition: gsmlogo.c:228
#define TRUE
Definition: gammu-types.h:28
unsigned char GSM_EncodeEMSSound(GSM_Ringtone *ringtone, unsigned char *package, size_t *maxlength, GSM_RingtoneVersion version, gboolean start)
Definition: gsmring.c:1565
Debug_Level dl
Definition: debug.h:35