Diffstat (limited to 'gammu/emb/common/service/sms/gsmems.c') (more/less context) (show whitespace changes)
-rw-r--r-- | gammu/emb/common/service/sms/gsmems.c | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/gammu/emb/common/service/sms/gsmems.c b/gammu/emb/common/service/sms/gsmems.c new file mode 100644 index 0000000..a7e20f4 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmems.c | |||
@@ -0,0 +1,765 @@ | |||
1 | /* (c) 2002-2004 by Marcin Wiacek */ | ||
2 | |||
3 | #include <ctype.h> | ||
4 | #include <string.h> | ||
5 | #include <time.h> | ||
6 | |||
7 | #include "../../gsmcomon.h" | ||
8 | #include "../../misc/coding/coding.h" | ||
9 | #include "../gsmcal.h" | ||
10 | #include "../gsmpbk.h" | ||
11 | #include "../gsmlogo.h" | ||
12 | #include "../gsmring.h" | ||
13 | #include "../gsmdata.h" | ||
14 | #include "../gsmnet.h" | ||
15 | #include "gsmsms.h" | ||
16 | #include "gsmmulti.h" | ||
17 | |||
18 | /* EMS Developers' Guidelines from www.sonyericsson.com | ||
19 | * docs from Alcatel | ||
20 | */ | ||
21 | GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
22 | GSM_MultiSMSMessage *SMS, | ||
23 | GSM_UDH UDHType) | ||
24 | { | ||
25 | unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
26 | int i,UsedText,j,Length,Width,Height,z,x,y; | ||
27 | unsigned int Len; | ||
28 | int Used,FreeText,FreeBytes,Width2,CopiedText,CopiedSMSText; | ||
29 | unsigned char UDHID; | ||
30 | GSM_Bitmap Bitmap,Bitmap2; | ||
31 | GSM_Ringtone Ring; | ||
32 | GSM_Coding_Type Coding = SMS_Coding_Default; | ||
33 | GSM_Phone_Bitmap_TypesBitmapType; | ||
34 | MultiPartSMSEntry *Entry; | ||
35 | bool start; | ||
36 | GSM_DateTime Date; | ||
37 | |||
38 | #ifdef DEBUG | ||
39 | if (UDHType != UDH_NoUDH) dbgprintf("linked EMS\n"); | ||
40 | #endif | ||
41 | |||
42 | if (Info->UnicodeCoding) Coding = SMS_Coding_Unicode; | ||
43 | |||
44 | /* Cleaning on the start */ | ||
45 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
46 | GSM_SetDefaultSMSData(&SMS->SMS[i]); | ||
47 | SMS->SMS[i].UDH.Type = UDHType; | ||
48 | GSM_EncodeUDHHeader(&SMS->SMS[i].UDH); | ||
49 | SMS->SMS[i].Coding = Coding; | ||
50 | } | ||
51 | |||
52 | /* Packing */ | ||
53 | for (i=0;i<Info->EntriesNum;i++) { | ||
54 | Entry = &Info->Entries[i]; | ||
55 | |||
56 | switch (Entry->ID) { | ||
57 | case SMS_ConcatenatedTextLong: | ||
58 | case SMS_ConcatenatedTextLong16bit: | ||
59 | Len = 0; | ||
60 | while(1) { | ||
61 | if (Entry->Left || Entry->Right || | ||
62 | Entry->Center || Entry->Large || | ||
63 | Entry->Small || Entry->Bold || | ||
64 | Entry->Italic || Entry->Underlined || | ||
65 | Entry->Strikethrough) { | ||
66 | Buffer[0] = 0x0A;/* ID for text format */ | ||
67 | Buffer[1] = 0x03; /* length of rest*/ | ||
68 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
69 | Buffer[3] = 0x00; /* how many chars */ | ||
70 | Buffer[4] = 0x00; /* formatting bits*/ | ||
71 | if (Entry->Left) { | ||
72 | } else if (Entry->Right) {Buffer[4] |= 1; | ||
73 | } else if (Entry->Center) {Buffer[4] |= 2; | ||
74 | } else Buffer[4] |= 3; | ||
75 | if (Entry->Large) { Buffer[4] |= 4; | ||
76 | } else if (Entry->Small) {Buffer[4] |= 8;} | ||
77 | if (Entry->Bold) Buffer[4] |= 16; | ||
78 | if (Entry->Italic) Buffer[4] |= 32; | ||
79 | if (Entry->Underlined) Buffer[4] |= 64; | ||
80 | if (Entry->Strikethrough) Buffer[4] |= 128; | ||
81 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
82 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
83 | if (FreeText == 0) continue; | ||
84 | } | ||
85 | GSM_AddSMS_Text_UDH(SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
86 | if (Entry->Left || Entry->Right || | ||
87 | Entry->Center || Entry->Large || | ||
88 | Entry->Small || Entry->Bold || | ||
89 | Entry->Italic || Entry->Underlined || | ||
90 | Entry->Strikethrough) { | ||
91 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText; | ||
92 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText; | ||
93 | } | ||
94 | Len += CopiedText; | ||
95 | if (Len == UnicodeLength(Entry->Buffer)) break; | ||
96 | dbgprintf("%i %i\n",Len,UnicodeLength(Entry->Buffer)); | ||
97 | } | ||
98 | break; | ||
99 | case SMS_EMSPredefinedSound: | ||
100 | case SMS_EMSPredefinedAnimation: | ||
101 | if (Entry->ID == SMS_EMSPredefinedSound) { | ||
102 | Buffer[0] = 0x0B; /* ID for def.sound*/ | ||
103 | } else { | ||
104 | Buffer[0] = 0x0D; /* ID for def.animation*/ | ||
105 | } | ||
106 | Buffer[1] = 0x02; /* Length of rest */ | ||
107 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
108 | Buffer[3] = Entry->Number; /* Number of anim.*/ | ||
109 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
110 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText; | ||
111 | break; | ||
112 | case SMS_EMSSonyEricssonSound: | ||
113 | case SMS_EMSSound10: | ||
114 | case SMS_EMSSound12: | ||
115 | if (Entry->Protected) { | ||
116 | Buffer[0] = 0x17; /* ID for ODI */ | ||
117 | Buffer[1] = 2; /* Length of rest */ | ||
118 | Buffer[2] = 1; /* Number of protected objects */ | ||
119 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
120 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
121 | } | ||
122 | |||
123 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
124 | switch (Entry->ID) { | ||
125 | case SMS_EMSSound10: | ||
126 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.0, true); | ||
127 | break; | ||
128 | case SMS_EMSSound12: | ||
129 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.2, true); | ||
130 | break; | ||
131 | case SMS_EMSSonyEricssonSound: | ||
132 | Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 0, true); | ||
133 | break; | ||
134 | default: | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
139 | Buffer[1] = Length+1; /* Length of rest */ | ||
140 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
141 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
142 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
143 | break; | ||
144 | case SMS_EMSSonyEricssonSoundLong: | ||
145 | case SMS_EMSSound10Long: | ||
146 | case SMS_EMSSound12Long: | ||
147 | Ring = *Entry->Ringtone; | ||
148 | |||
149 | /* First check if we can use classic format */ | ||
150 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
151 | switch (Entry->ID) { | ||
152 | case SMS_EMSSound10Long: | ||
153 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, true); | ||
154 | break; | ||
155 | case SMS_EMSSound12Long: | ||
156 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, true); | ||
157 | break; | ||
158 | case SMS_EMSSonyEricssonSoundLong: | ||
159 | Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, true); | ||
160 | break; | ||
161 | default: | ||
162 | break; | ||
163 | } | ||
164 | if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) { | ||
165 | if (Entry->Protected) { | ||
166 | Buffer[0] = 0x17; /* ID for ODI */ | ||
167 | Buffer[1] = 2; /* Length of rest */ | ||
168 | Buffer[2] = 1; /* Number of protected objects */ | ||
169 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
170 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
171 | } | ||
172 | |||
173 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
174 | Buffer[1] = Length+1; /* Length of rest */ | ||
175 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
176 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
177 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | /* Find free place in first SMS */ | ||
182 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
183 | Length = FreeBytes - 3; | ||
184 | if (Entry->Protected) Length = Length - 4; | ||
185 | if (Length < 0) Length = 128; | ||
186 | if (Length > 128) Length = 128; | ||
187 | |||
188 | Ring = *Entry->Ringtone; | ||
189 | |||
190 | /* Checking number of SMS */ | ||
191 | Used = 0; | ||
192 | FreeBytes = 0; | ||
193 | start = true; | ||
194 | while (1) { | ||
195 | if (FreeBytes != 0) { | ||
196 | z = 0; | ||
197 | for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { | ||
198 | Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; | ||
199 | z++; | ||
200 | } | ||
201 | Ring.NoteTone.NrCommands -= FreeBytes; | ||
202 | if (Ring.NoteTone.NrCommands == 0) break; | ||
203 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
204 | } | ||
205 | switch (Entry->ID) { | ||
206 | case SMS_EMSSound10Long: | ||
207 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); | ||
208 | break; | ||
209 | case SMS_EMSSound12Long: | ||
210 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); | ||
211 | break; | ||
212 | case SMS_EMSSonyEricssonSoundLong: | ||
213 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); | ||
214 | break; | ||
215 | default: | ||
216 | break; | ||
217 | } | ||
218 | start = false; | ||
219 | Used++; | ||
220 | } | ||
221 | dbgprintf("Used SMS: %i\n",Used); | ||
222 | |||
223 | if (Entry->Protected) { | ||
224 | Buffer[0] = 0x17; /* ID for ODI */ | ||
225 | Buffer[1] = 2; /* Length of rest */ | ||
226 | Buffer[2] = Used+1; /* Number of protected objects */ | ||
227 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
228 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
229 | } | ||
230 | |||
231 | /* Save UPI UDH */ | ||
232 | Buffer[0] = 0x13; /* ID for UPI */ | ||
233 | Buffer[1] = 1; /* Length of rest */ | ||
234 | Buffer[2] = Used; /* Number of used parts*/ | ||
235 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
236 | |||
237 | /* Find free place in first SMS */ | ||
238 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
239 | Length = FreeBytes - 3; | ||
240 | if (Length < 0) Length = 128; | ||
241 | if (Length > 128) Length = 128; | ||
242 | |||
243 | Ring = *Entry->Ringtone; | ||
244 | |||
245 | /* Saving */ | ||
246 | FreeBytes = 0; | ||
247 | start = true; | ||
248 | while (1) { | ||
249 | if (FreeBytes != 0) { | ||
250 | z = 0; | ||
251 | for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { | ||
252 | Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; | ||
253 | z++; | ||
254 | } | ||
255 | Ring.NoteTone.NrCommands -= FreeBytes; | ||
256 | if (Ring.NoteTone.NrCommands == 0) break; | ||
257 | Length = 128; /* 128 bytes is maximal length from specs */ | ||
258 | } | ||
259 | switch (Entry->ID) { | ||
260 | case SMS_EMSSound10Long: | ||
261 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); | ||
262 | break; | ||
263 | case SMS_EMSSound12Long: | ||
264 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); | ||
265 | break; | ||
266 | case SMS_EMSSonyEricssonSoundLong: | ||
267 | FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); | ||
268 | break; | ||
269 | default: | ||
270 | break; | ||
271 | } | ||
272 | Buffer[0] = 0x0C; /* ID for EMS sound */ | ||
273 | Buffer[1] = Length+1; /* Length of rest */ | ||
274 | Buffer[2] = 0x00; /* Position in EMS msg */ | ||
275 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
276 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; | ||
277 | start = false; | ||
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(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(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(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(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; | ||
334 | case SMS_EMSVariableBitmapLong: | ||
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(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 | ||
368 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
369 | #endif | ||
370 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); | ||
371 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
372 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | /* Find free place in first SMS */ | ||
377 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
378 | Used = 0; | ||
379 | Length = FreeBytes - 3; | ||
380 | if (Entry->Protected)Length = Length - 4; | ||
381 | if (Length < 0) Length = 128; | ||
382 | if (Length > 128) Length = 128; | ||
383 | |||
384 | /* Checking number of SMS */ | ||
385 | FreeBytes = 0; | ||
386 | while (FreeBytes != Width) { | ||
387 | Width2 = 8; | ||
388 | while (FreeBytes + Width2 != Width) { | ||
389 | if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; | ||
390 | |||
391 | Width2 = Width2 + 8; | ||
392 | } | ||
393 | FreeBytes = FreeBytes + Width2; | ||
394 | Length = 128; | ||
395 | Used ++; | ||
396 | } | ||
397 | dbgprintf("Used SMS: %i\n",Used); | ||
398 | |||
399 | if (Entry->Protected) { | ||
400 | Buffer[0] = 0x17; /* ID for ODI */ | ||
401 | Buffer[1] = 2; /* Length of rest */ | ||
402 | Buffer[2] = Used+1; /* Number of protected objects */ | ||
403 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
404 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
405 | } | ||
406 | |||
407 | /* Save UPI UDH */ | ||
408 | Buffer[0] = 0x13; /* ID for UPI */ | ||
409 | Buffer[1] = 1; /* Length of rest */ | ||
410 | Buffer[2] = Used; /* Number of used parts*/ | ||
411 | |||
412 | /* Find free place in first SMS */ | ||
413 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
414 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); | ||
415 | Length = FreeBytes - 3; | ||
416 | if (Length < 0) Length = 128; | ||
417 | if (Length > 128) Length = 128; | ||
418 | |||
419 | #ifdef DEBUG | ||
420 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
421 | #endif | ||
422 | |||
423 | /* Saving SMS */ | ||
424 | FreeBytes = 0; | ||
425 | while (FreeBytes != Width) { | ||
426 | Width2 = 8; | ||
427 | while (FreeBytes + Width2 != Width) { | ||
428 | if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; | ||
429 | |||
430 | Width2 = Width2 + 8; | ||
431 | } | ||
432 | |||
433 | /* Copying part of bitmap to new structure */ | ||
434 | Bitmap2.BitmapWidth = Width2; | ||
435 | Bitmap2.BitmapHeight = Height; | ||
436 | GSM_ClearBitmap(&Bitmap2); | ||
437 | for (x=0;x<Width2;x++) { | ||
438 | for (y=0;y<Height;y++) { | ||
439 | if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) { | ||
440 | GSM_SetPointBitmap(&Bitmap2, x, y); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | #ifdef DEBUG | ||
445 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap2); | ||
446 | #endif | ||
447 | |||
448 | /* Adding new bitmap to SMS */ | ||
449 | Length = PHONE_GetBitmapSize(BitmapType,Width2,Height); | ||
450 | Buffer[0] = 0x12; /* ID for EMS bitmap*/ | ||
451 | Buffer[1] = Length + 3; /* Length of rest */ | ||
452 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
453 | Buffer[3] = Width2/8; /* Bitmap width/8 */ | ||
454 | Buffer[4] = Height; /* Bitmap height */ | ||
455 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2); | ||
456 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
457 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
458 | |||
459 | FreeBytes = FreeBytes + Width2; | ||
460 | Length = 128; | ||
461 | } | ||
462 | break; | ||
463 | case SMS_EMSVariableBitmap: | ||
464 | if (Entry->Protected) { | ||
465 | Buffer[0] = 0x17; /* ID for ODI */ | ||
466 | Buffer[1] = 2; /* Length of rest */ | ||
467 | Buffer[2] = 1; /* Number of protected objects */ | ||
468 | Buffer[3] = 1; /* 1=Protected,0=Not protected */ | ||
469 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
470 | } | ||
471 | |||
472 | BitmapType = GSM_EMSVariablePicture; | ||
473 | Width = Entry->Bitmap->Bitmap[0].BitmapWidth; | ||
474 | Height = Entry->Bitmap->Bitmap[0].BitmapHeight; | ||
475 | |||
476 | while (1) { | ||
477 | /* Width should be multiply of 8 */ | ||
478 | while (Width % 8 != 0) Width--; | ||
479 | |||
480 | /* specs */ | ||
481 | if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break; | ||
482 | |||
483 | Height--; | ||
484 | } | ||
485 | |||
486 | Length = PHONE_GetBitmapSize(BitmapType,Width,Height); | ||
487 | |||
488 | Buffer[0] = 0x12; /* ID for EMS bitmap*/ | ||
489 | Buffer[1] = Length + 3; /* Length of rest */ | ||
490 | Buffer[2] = 0x00; /* Position in EMS msg*/ | ||
491 | Buffer[3] = Width/8; /* Bitmap width/8 */ | ||
492 | Buffer[4] = Height; /* Bitmap height */ | ||
493 | |||
494 | GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height); | ||
495 | #ifdef DEBUG | ||
496 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); | ||
497 | #endif | ||
498 | PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); | ||
499 | GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); | ||
500 | SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; | ||
501 | break; | ||
502 | default: | ||
503 | break; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | SMS->Number++; | ||
508 | |||
509 | if (UDHType == UDH_ConcatenatedMessages) { | ||
510 | UDHID = GSM_MakeSMSIDFromTime(); | ||
511 | for (i=0;i<SMS->Number;i++) { | ||
512 | SMS->SMS[i].UDH.Text[2+1] = UDHID; | ||
513 | SMS->SMS[i].UDH.Text[3+1] = SMS->Number; | ||
514 | SMS->SMS[i].UDH.Text[4+1] = i+1; | ||
515 | } | ||
516 | } | ||
517 | if (UDHType == UDH_ConcatenatedMessages16bit) { | ||
518 | UDHID = GSM_MakeSMSIDFromTime(); | ||
519 | GSM_GetCurrentDateTime (&Date); | ||
520 | for (i=0;i<SMS->Number;i++) { | ||
521 | SMS->SMS[i].UDH.Text[2+1] = Date.Hour; | ||
522 | SMS->SMS[i].UDH.Text[3+1] = UDHID; | ||
523 | SMS->SMS[i].UDH.Text[4+1] = SMS->Number; | ||
524 | SMS->SMS[i].UDH.Text[5+1] = i+1; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | #ifdef DEBUG | ||
529 | dbgprintf("SMS number is %i\n",SMS->Number); | ||
530 | for (i=0;i<SMS->Number;i++) { | ||
531 | dbgprintf("UDH length %i\n",SMS->SMS[i].UDH.Length); | ||
532 | DumpMessage(di.df, di.dl, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length); | ||
533 | dbgprintf("SMS length %i\n",UnicodeLength(SMS->SMS[i].Text)*2); | ||
534 | DumpMessage(di.df, di.dl, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2); | ||
535 | } | ||
536 | #endif | ||
537 | return ERR_NONE; | ||
538 | } | ||
539 | |||
540 | static bool AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len) | ||
541 | { | ||
542 | int BufferLen; | ||
543 | |||
544 | if (Len==0) return true; | ||
545 | |||
546 | if (Info->Entries[Info->EntriesNum].ID!=SMS_ConcatenatedTextLong && | ||
547 | Info->Entries[Info->EntriesNum].ID!=0) { | ||
548 | (Info->EntriesNum)++; | ||
549 | } | ||
550 | BufferLen = UnicodeLength(Info->Entries[Info->EntriesNum].Buffer)*2; | ||
551 | switch (SMS->Coding) { | ||
552 | case SMS_Coding_8bit: | ||
553 | // memcpy(Info->Entries[Info->EntriesNum].Buffer+BufferLen,SMS->Text+(*Pos),Len); | ||
554 | // BufferLen+=Len; | ||
555 | // (*Pos)+=Len; | ||
556 | break; | ||
557 | case SMS_Coding_Unicode: | ||
558 | case SMS_Coding_Default: | ||
559 | Info->Entries[Info->EntriesNum].Buffer = realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2) + 2); | ||
560 | if (Info->Entries[Info->EntriesNum].Buffer == NULL) return false; | ||
561 | memcpy(Info->Entries[Info->EntriesNum].Buffer + BufferLen, SMS->Text + (*Pos) *2, Len * 2); | ||
562 | BufferLen += Len * 2; | ||
563 | break; | ||
564 | } | ||
565 | (*Pos)+=Len; | ||
566 | Info->Entries[Info->EntriesNum].Buffer[BufferLen]= 0; | ||
567 | Info->Entries[Info->EntriesNum].Buffer[BufferLen+1]= 0; | ||
568 | Info->Entries[Info->EntriesNum].ID = SMS_ConcatenatedTextLong; | ||
569 | return true; | ||
570 | } | ||
571 | |||
572 | bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
573 | GSM_MultiSMSMessage *SMS) | ||
574 | { | ||
575 | int i, w, Pos, z, UPI = 1, width, height; | ||
576 | bool RetVal = false, NewPicture = true; | ||
577 | GSM_Phone_Bitmap_Types BitmapType; | ||
578 | GSM_Bitmap Bitmap,Bitmap2; | ||
579 | |||
580 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
581 | Info->Entries[i].ID = 0; | ||
582 | } | ||
583 | |||
584 | for (i=0;i<SMS->Number;i++) { | ||
585 | Pos = 0; | ||
586 | w= 1; | ||
587 | while (w < SMS->SMS[i].UDH.Length) { | ||
588 | if (Info->EntriesNum + 1 == MAX_MULTI_SMS) { | ||
589 | dbgprintf("Couldn't parse SMS, contains too many EMS parts!\n"); | ||
590 | return false; | ||
591 | } | ||
592 | switch(SMS->SMS[i].UDH.Text[w]) { | ||
593 | case 0x00: | ||
594 | dbgprintf("UDH part - linked SMS with 8 bit ID\n"); | ||
595 | break; | ||
596 | case 0x08: | ||
597 | dbgprintf("UDH part - linked SMS with 16 bit ID\n"); | ||
598 | break; | ||
599 | // case 0x0A: | ||
600 | // dbgprintf("UDH part - EMS text formatting\n"); | ||
601 | // break; | ||
602 | case 0x0B: | ||
603 | dbgprintf("UDH part - default EMS sound\n"); | ||
604 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
605 | z = Pos; | ||
606 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
607 | } | ||
608 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
609 | Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; | ||
610 | Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedSound; | ||
611 | RetVal = true; | ||
612 | break; | ||
613 | // case 0x0C: | ||
614 | // dbgprintf("UDH part - EMS sound\n"); | ||
615 | // break; | ||
616 | case 0x0D: | ||
617 | dbgprintf("UDH part - default EMS animation\n"); | ||
618 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
619 | z = Pos; | ||
620 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
621 | } | ||
622 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
623 | Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; | ||
624 | Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedAnimation; | ||
625 | RetVal = true; | ||
626 | break; | ||
627 | case 0x0E: | ||
628 | case 0x0F: | ||
629 | if (SMS->SMS[i].UDH.Text[w] == 0x0E) { | ||
630 | dbgprintf("UDH part - EMS 16x16 animation\n"); | ||
631 | BitmapType = GSM_EMSMediumPicture; | ||
632 | } else { | ||
633 | dbgprintf("UDH part - EMS 8x8 animation\n"); | ||
634 | BitmapType = GSM_EMSSmallPicture; | ||
635 | } | ||
636 | dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
637 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
638 | z = Pos; | ||
639 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
640 | } | ||
641 | (Info->EntriesNum)++; | ||
642 | Info->Entries[Info->EntriesNum].ID = SMS_EMSAnimation; | ||
643 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
644 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
645 | Info->Entries[Info->EntriesNum].Bitmap->Number = 0; | ||
646 | for (z=0;z<((SMS->SMS[i].UDH.Text[w+1]-1)/PHONE_GetBitmapSize(BitmapType,0,0));z++) { | ||
647 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z].Type = GSM_PictureImage; | ||
648 | PHONE_DecodeBitmap(BitmapType, | ||
649 | SMS->SMS[i].UDH.Text + w + 3 + PHONE_GetBitmapSize(BitmapType,0,0) * z, | ||
650 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z]); | ||
651 | Info->Entries[Info->EntriesNum].Bitmap->Number++; | ||
652 | } | ||
653 | RetVal = true; | ||
654 | break; | ||
655 | case 0x10: | ||
656 | case 0x11: | ||
657 | if (SMS->SMS[i].UDH.Text[w] == 0x10) { | ||
658 | dbgprintf("UDH part - EMS 32x32 picture\n"); | ||
659 | BitmapType = GSM_EMSBigPicture; | ||
660 | } else { | ||
661 | dbgprintf("UDH part - EMS 16x16 picture\n"); | ||
662 | BitmapType = GSM_EMSMediumPicture; | ||
663 | } | ||
664 | dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
665 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
666 | z = Pos; | ||
667 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
668 | } | ||
669 | if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; | ||
670 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
671 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
672 | PHONE_DecodeBitmap(BitmapType, | ||
673 | SMS->SMS[i].UDH.Text + w + 3, | ||
674 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); | ||
675 | Info->Entries[Info->EntriesNum].Bitmap->Number = 1; | ||
676 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; | ||
677 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; | ||
678 | Info->Entries[Info->EntriesNum].ID = SMS_EMSFixedBitmap; | ||
679 | RetVal = true; | ||
680 | break; | ||
681 | case 0x12: | ||
682 | dbgprintf("UDH part - EMS variable width bitmap\n"); | ||
683 | if (SMS->SMS[i].UDH.Text[w+2] > Pos) { | ||
684 | z = Pos; | ||
685 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; | ||
686 | } | ||
687 | if (NewPicture) { | ||
688 | (Info->EntriesNum)++; | ||
689 | Info->Entries[Info->EntriesNum].Bitmap->Number = 0; | ||
690 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = 0; | ||
691 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = 0; | ||
692 | } | ||
693 | Bitmap.BitmapWidth = SMS->SMS[i].UDH.Text[w+3]*8; | ||
694 | Bitmap.BitmapHeight = SMS->SMS[i].UDH.Text[w+4]; | ||
695 | Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
696 | if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; | ||
697 | if (NewPicture) { | ||
698 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth; | ||
699 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap.BitmapHeight; | ||
700 | PHONE_DecodeBitmap(GSM_EMSVariablePicture, | ||
701 | SMS->SMS[i].UDH.Text + w + 5, | ||
702 | &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); | ||
703 | } else { | ||
704 | PHONE_DecodeBitmap(GSM_EMSVariablePicture, | ||
705 | SMS->SMS[i].UDH.Text + w + 5, | ||
706 | &Bitmap); | ||
707 | Bitmap2 = Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]; | ||
708 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth+Bitmap2.BitmapWidth; | ||
709 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap2.BitmapHeight; | ||
710 | for (width=0;width<Bitmap2.BitmapWidth;width++) { | ||
711 | for (height=0;height<Bitmap2.BitmapHeight;height++) { | ||
712 | if (GSM_IsPointBitmap(&Bitmap2, width, height)) { | ||
713 | GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); | ||
714 | } else { | ||
715 | GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | for (width=0;width<Bitmap.BitmapWidth;width++) { | ||
720 | for (height=0;height<Bitmap2.BitmapHeight;height++) { | ||
721 | if (GSM_IsPointBitmap(&Bitmap, width, height)) { | ||
722 | GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); | ||
723 | } else { | ||
724 | GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | if (UPI == 1) { | ||
730 | Info->Entries[Info->EntriesNum].Bitmap->Number = 1; | ||
731 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; | ||
732 | Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; | ||
733 | Info->Entries[Info->EntriesNum].ID = SMS_EMSVariableBitmap; | ||
734 | RetVal = true; | ||
735 | NewPicture = true; | ||
736 | dbgprintf("New variable picture\n"); | ||
737 | } else { | ||
738 | NewPicture = false; | ||
739 | UPI--; | ||
740 | } | ||
741 | break; | ||
742 | case 0x13: | ||
743 | dbgprintf("UDH part - UPI\n"); | ||
744 | dbgprintf("Value %i\n",SMS->SMS[i].UDH.Text[w+2]); | ||
745 | UPI = SMS->SMS[i].UDH.Text[w+2]; | ||
746 | break; | ||
747 | case 0x17: | ||
748 | dbgprintf("UDH part - Object Distribution Indicator (Media Rights Protecting) ignored now\n"); | ||
749 | break; | ||
750 | default: | ||
751 | dbgprintf("UDH part - block %02x\n",SMS->SMS[i].UDH.Text[w]); | ||
752 | Info->Unknown = true; | ||
753 | } /* switch */ | ||
754 | w=w+SMS->SMS[i].UDH.Text[w+1]+2; | ||
755 | } /* while */ | ||
756 | if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return false; | ||
757 | RetVal = true; | ||
758 | } | ||
759 | if (RetVal) (Info->EntriesNum)++; | ||
760 | return RetVal; | ||
761 | } | ||
762 | |||
763 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
764 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
765 | */ | ||