Diffstat (limited to 'gammu/emb/common/service/sms/gsmmulti.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | gammu/emb/common/service/sms/gsmmulti.c | 1148 |
1 files changed, 1148 insertions, 0 deletions
diff --git a/gammu/emb/common/service/sms/gsmmulti.c b/gammu/emb/common/service/sms/gsmmulti.c new file mode 100644 index 0000000..6c1cdcd --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmmulti.c | |||
@@ -0,0 +1,1148 @@ | |||
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 | #include "gsmems.h" | ||
18 | |||
19 | /* ----------------- Splitting SMS into parts ------------------------------ */ | ||
20 | |||
21 | unsigned char GSM_MakeSMSIDFromTime(void) | ||
22 | { | ||
23 | GSM_DateTime Date; | ||
24 | unsigned charretval; | ||
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_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes) | ||
38 | { | ||
39 | int UsedBytes; | ||
40 | |||
41 | switch (Coding) { | ||
42 | case SMS_Coding_Default: | ||
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; | ||
49 | case SMS_Coding_Unicode: | ||
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 | } | ||
61 | dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes); | ||
62 | } | ||
63 | |||
64 | GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, | ||
65 | GSM_Coding_Type Coding, | ||
66 | char *Buffer, | ||
67 | int BufferLen, | ||
68 | bool UDH, | ||
69 | int *UsedText, | ||
70 | int *CopiedText, | ||
71 | int *CopiedSMSText) | ||
72 | { | ||
73 | int FreeText,FreeBytes,Copy,i,j; | ||
74 | |||
75 | dbgprintf("Checking used\n"); | ||
76 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
77 | |||
78 | if (UDH) { | ||
79 | dbgprintf("Adding UDH\n"); | ||
80 | if (FreeBytes - BufferLen <= 0) { | ||
81 | dbgprintf("Going to the new SMS\n"); | ||
82 | SMS->Number++; | ||
83 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
84 | } | ||
85 | if (SMS->SMS[SMS->Number].UDH.Length == 0) { | ||
86 | SMS->SMS[SMS->Number].UDH.Length = 1; | ||
87 | SMS->SMS[SMS->Number].UDH.Text[0] = 0x00; | ||
88 | } | ||
89 | memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen); | ||
90 | SMS->SMS[SMS->Number].UDH.Length += BufferLen; | ||
91 | SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen; | ||
92 | SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH; | ||
93 | dbgprintf("UDH added %i\n",BufferLen); | ||
94 | } else { | ||
95 | dbgprintf("Adding text\n"); | ||
96 | if (FreeText == 0) { | ||
97 | dbgprintf("Going to the new SMS\n"); | ||
98 | SMS->Number++; | ||
99 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
100 | } | ||
101 | |||
102 | Copy = FreeText; | ||
103 | dbgprintf("copy %i\n",Copy); | ||
104 | if (BufferLen < Copy) Copy = BufferLen; | ||
105 | dbgprintf("copy %i\n",Copy); | ||
106 | |||
107 | switch (Coding) { | ||
108 | case SMS_Coding_Default: | ||
109 | FindDefaultAlphabetLen(Buffer,&i,&j,FreeText); | ||
110 | dbgprintf("def length %i %i\n",i,j); | ||
111 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0; | ||
112 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0; | ||
113 | memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2); | ||
114 | *CopiedText = i; | ||
115 | *CopiedSMSText = j; | ||
116 | SMS->SMS[SMS->Number].Length += i; | ||
117 | break; | ||
118 | case SMS_Coding_Unicode: | ||
119 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0; | ||
120 | SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0; | ||
121 | memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2); | ||
122 | *CopiedText = *CopiedSMSText = Copy; | ||
123 | SMS->SMS[SMS->Number].Length += Copy; | ||
124 | break; | ||
125 | case SMS_Coding_8bit: | ||
126 | memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy); | ||
127 | SMS->SMS[SMS->Number].Length += Copy; | ||
128 | *CopiedText = *CopiedSMSText = Copy; | ||
129 | break; | ||
130 | } | ||
131 | dbgprintf("Text added\n"); | ||
132 | } | ||
133 | |||
134 | dbgprintf("Checking on the end\n"); | ||
135 | GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); | ||
136 | |||
137 | return ERR_NONE; | ||
138 | } | ||
139 | |||
140 | void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage*SMS, | ||
141 | unsigned char *MessageBuffer, | ||
142 | int MessageLength, | ||
143 | GSM_UDH UDHType, | ||
144 | GSM_Coding_TypeCoding, | ||
145 | int Class, | ||
146 | unsigned char ReplaceMessage) | ||
147 | { | ||
148 | int j,Len,UsedText,CopiedText,CopiedSMSText; | ||
149 | unsigned char UDHID; | ||
150 | GSM_DateTime Date; | ||
151 | |||
152 | Len = 0; | ||
153 | while(1) { | ||
154 | GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]); | ||
155 | SMS->SMS[SMS->Number].Class = Class; | ||
156 | SMS->SMS[SMS->Number].Coding = Coding; | ||
157 | |||
158 | SMS->SMS[SMS->Number].UDH.Type = UDHType; | ||
159 | GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH); | ||
160 | |||
161 | if (Coding == SMS_Coding_8bit) { | ||
162 | GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
163 | } else { | ||
164 | GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); | ||
165 | } | ||
166 | Len += CopiedText; | ||
167 | dbgprintf("%i %i\n",Len,MessageLength); | ||
168 | if (Len == MessageLength) break; | ||
169 | if (SMS->Number == MAX_MULTI_SMS) break; | ||
170 | SMS->Number++; | ||
171 | } | ||
172 | |||
173 | SMS->Number++; | ||
174 | |||
175 | UDHID = GSM_MakeSMSIDFromTime(); | ||
176 | GSM_GetCurrentDateTime (&Date); | ||
177 | for (j=0;j<SMS->Number;j++) { | ||
178 | SMS->SMS[j].UDH.Type = UDHType; | ||
179 | SMS->SMS[j].UDH.ID8bit = UDHID; | ||
180 | SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour; | ||
181 | SMS->SMS[j].UDH.PartNumber = j+1; | ||
182 | SMS->SMS[j].UDH.AllParts = SMS->Number; | ||
183 | GSM_EncodeUDHHeader(&SMS->SMS[j].UDH); | ||
184 | } | ||
185 | if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage; | ||
186 | } | ||
187 | |||
188 | /* Calculates number of SMS and number of left chars in SMS */ | ||
189 | void GSM_SMSCounter(int MessageLength, | ||
190 | unsigned char *MessageBuffer, | ||
191 | GSM_UDH UDHType, | ||
192 | GSM_Coding_Type Coding, | ||
193 | int *SMSNum, | ||
194 | int *CharsLeft) | ||
195 | { | ||
196 | int UsedText,FreeBytes; | ||
197 | GSM_MultiSMSMessage MultiSMS; | ||
198 | |||
199 | MultiSMS.Number = 0; | ||
200 | GSM_MakeMultiPartSMS(&MultiSMS,MessageBuffer,MessageLength,UDHType,Coding,-1,false); | ||
201 | GSM_Find_Free_Used_SMS2(Coding,MultiSMS.SMS[MultiSMS.Number-1], &UsedText, CharsLeft, &FreeBytes); | ||
202 | *SMSNum = MultiSMS.Number; | ||
203 | } | ||
204 | |||
205 | /* Nokia Smart Messaging 3.0 */ | ||
206 | static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
207 | char *Buffer, int *Length) | ||
208 | { | ||
209 | int len; | ||
210 | |||
211 | /*SM version. Here 3.0*/ | ||
212 | Buffer[(*Length)++] = 0x30; | ||
213 | |||
214 | if (Info->Entries[0].ID == SMS_NokiaProfileLong) { | ||
215 | if (Info->Entries[0].Buffer != NULL) { | ||
216 | if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) { | ||
217 | Buffer[(*Length)++] = SM30_PROFILENAME; | ||
218 | Buffer[(*Length)++] = 0x00; | ||
219 | Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer); | ||
220 | CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer); | ||
221 | *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer); | ||
222 | } | ||
223 | } | ||
224 | if (Info->Entries[0].Ringtone != NULL) { | ||
225 | Buffer[(*Length)++] = SM30_RINGTONE; | ||
226 | /* Length for this part later will be changed */ | ||
227 | Buffer[(*Length)++] = 0x01; | ||
228 | Buffer[(*Length)++] = 0x00; | ||
229 | /* Smart Messaging 3.0 says: 16*9=144 bytes, | ||
230 | * but on 3310 4.02 it was possible to save about 196 chars | ||
231 | * (without cutting) */ | ||
232 | len = 196; | ||
233 | Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer+(*Length),&len); | ||
234 | Buffer[(*Length)-2] = len / 256; | ||
235 | Buffer[(*Length)-1] = len % 256; | ||
236 | *Length = *Length + len; | ||
237 | } | ||
238 | } | ||
239 | if (Info->Entries[0].Bitmap != NULL) { | ||
240 | if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) { | ||
241 | Buffer[(*Length)++] = SM30_OTA; | ||
242 | } else { | ||
243 | Buffer[(*Length)++] = SM30_SCREENSAVER; | ||
244 | } | ||
245 | Buffer[(*Length)++] = 0x01; | ||
246 | Buffer[(*Length)++] = 0x00; | ||
247 | NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length); | ||
248 | if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) { | ||
249 | if (Info->UnicodeCoding) { | ||
250 | Buffer[(*Length)++] = SM30_UNICODETEXT; | ||
251 | /* Length for text part */ | ||
252 | Buffer[(*Length)++] = 0x00; | ||
253 | Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; | ||
254 | memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2); | ||
255 | *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; | ||
256 | } else { | ||
257 | /*ID for ISO-8859-1 text*/ | ||
258 | Buffer[(*Length)++] = SM30_ISOTEXT; | ||
259 | Buffer[(*Length)++] = 0x00; | ||
260 | Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); | ||
261 | memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)); | ||
262 | *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | /* Alcatel docs from www.alcatel.com/wap/ahead */ | ||
269 | GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_MultiSMSMessage *SMS, | ||
270 | unsigned char *Data, | ||
271 | int Len, | ||
272 | unsigned char *Name, | ||
273 | int Type) | ||
274 | { | ||
275 | unsigned char buff[100],UDHID; | ||
276 | int p,i; | ||
277 | GSM_UDHHeaderMyUDH; | ||
278 | |||
279 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
280 | GSM_SetDefaultSMSData(&SMS->SMS[i]); | ||
281 | SMS->SMS[i].UDH.Type = UDH_UserUDH; | ||
282 | SMS->SMS[i].UDH.Text[1] = 0x80;/* Alcatel */ | ||
283 | p = UnicodeLength(Name); | ||
284 | EncodeDefault(buff, Name, &p, true, NULL); | ||
285 | SMS->SMS[i].UDH.Text[2]= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4; | ||
286 | SMS->SMS[i].UDH.Text[3]= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p); | ||
287 | SMS->SMS[i].UDH.Text[4] = Type; | ||
288 | SMS->SMS[i].UDH.Text[5] = Len / 256; | ||
289 | SMS->SMS[i].UDH.Text[6] = Len % 256; | ||
290 | SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3]; | ||
291 | SMS->SMS[i].UDH.Length = SMS->SMS[i].UDH.Text[0] + 1; | ||
292 | |||
293 | if (Len > 140 - SMS->SMS[i].UDH.Length) { | ||
294 | MyUDH.Type = UDH_ConcatenatedMessages; | ||
295 | GSM_EncodeUDHHeader(&MyUDH); | ||
296 | |||
297 | memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1); | ||
298 | SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1; | ||
299 | SMS->SMS[i].UDH.Length += MyUDH.Length-1; | ||
300 | } | ||
301 | |||
302 | SMS->SMS[i].Coding = SMS_Coding_8bit; | ||
303 | SMS->SMS[i].Class = 1; | ||
304 | } | ||
305 | |||
306 | p = 0; | ||
307 | while (p != Len) { | ||
308 | i = 140-SMS->SMS[SMS->Number].UDH.Length; | ||
309 | if (Len - p < i) i = Len - p; | ||
310 | memcpy(SMS->SMS[SMS->Number].Text,Data+p,i); | ||
311 | p += i; | ||
312 | SMS->SMS[SMS->Number].Length = i; | ||
313 | SMS->Number++; | ||
314 | |||
315 | } | ||
316 | |||
317 | /* Linked sms UDH */ | ||
318 | if (SMS->Number != 1) { | ||
319 | UDHID = GSM_MakeSMSIDFromTime(); | ||
320 | for (i=0;i<SMS->Number;i++) { | ||
321 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID; | ||
322 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number; | ||
323 | SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return ERR_NONE; | ||
328 | } | ||
329 | |||
330 | /* Alcatel docs from www.alcatel.com/wap/ahead and other */ | ||
331 | GSM_Error GSM_EncodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, | ||
332 | GSM_MultiSMSMessage *SMS) | ||
333 | { | ||
334 | unsigned charBuffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
335 | unsigned charBuffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
336 | int Length = 0,smslen,i, Class = -1, j,p; | ||
337 | GSM_Errorerror; | ||
338 | GSM_Coding_Type Coding = SMS_Coding_8bit; | ||
339 | GSM_UDH UDH= UDH_NoUDH; | ||
340 | GSM_UDHHeader UDHHeader; | ||
341 | bool EMS= false; | ||
342 | int textnum = 0; | ||
343 | |||
344 | SMS->Number = 0; | ||
345 | |||
346 | if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) { | ||
347 | Buffer[Length++] = 0x00; //number of elements | ||
348 | for (i=1;i<Info->EntriesNum;i++) { | ||
349 | switch (Info->Entries[i].ID) { | ||
350 | case SMS_EMSSound10: | ||
351 | case SMS_EMSSound12: | ||
352 | case SMS_EMSSonyEricssonSound: | ||
353 | case SMS_EMSSound10Long: | ||
354 | case SMS_EMSSound12Long: | ||
355 | case SMS_EMSSonyEricssonSoundLong: | ||
356 | case SMS_EMSVariableBitmap: | ||
357 | case SMS_EMSAnimation: | ||
358 | case SMS_EMSVariableBitmapLong: | ||
359 | break; | ||
360 | case SMS_EMSPredefinedSound: | ||
361 | Buffer[0]++; | ||
362 | Buffer[Length++] = 0x01; //type of data | ||
363 | Buffer[Length++] = 1 % 256;//len | ||
364 | Buffer[Length++] = 1 / 256; //len | ||
365 | Buffer[Length++] = Info->Entries[i].Number; | ||
366 | break; | ||
367 | case SMS_EMSPredefinedAnimation: | ||
368 | Buffer[0]++; | ||
369 | Buffer[Length++] = 0x02; //type of data | ||
370 | Buffer[Length++] = 1 % 256;//len | ||
371 | Buffer[Length++] = 1 / 256; //len | ||
372 | Buffer[Length++] = Info->Entries[i].Number; | ||
373 | break; | ||
374 | case SMS_ConcatenatedTextLong: | ||
375 | Buffer[0]++; | ||
376 | p = UnicodeLength(Info->Entries[i].Buffer); | ||
377 | EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, true, NULL); | ||
378 | Buffer[Length++] = 0x00; //type of data | ||
379 | Length = Length + 2; | ||
380 | smslen = GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p); | ||
381 | Buffer[Length-2] = smslen % 256; //len | ||
382 | Buffer[Length-1] = smslen / 256; //len | ||
383 | Length = Length + smslen; | ||
384 | break; | ||
385 | default: | ||
386 | return ERR_UNKNOWN; | ||
387 | } | ||
388 | } | ||
389 | Buffer[0] = Buffer[0] * 2; | ||
390 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE); | ||
391 | } | ||
392 | |||
393 | for (i=0;i<Info->EntriesNum;i++) { | ||
394 | switch (Info->Entries[i].ID) { | ||
395 | case SMS_EMSPredefinedAnimation: | ||
396 | case SMS_EMSPredefinedSound: | ||
397 | case SMS_EMSSound10: | ||
398 | case SMS_EMSSound12: | ||
399 | case SMS_EMSSonyEricssonSound: | ||
400 | case SMS_EMSSound10Long: | ||
401 | case SMS_EMSSound12Long: | ||
402 | case SMS_EMSSonyEricssonSoundLong: | ||
403 | case SMS_EMSFixedBitmap: | ||
404 | case SMS_EMSVariableBitmap: | ||
405 | case SMS_EMSAnimation: | ||
406 | case SMS_EMSVariableBitmapLong: | ||
407 | EMS = true; | ||
408 | break; | ||
409 | case SMS_ConcatenatedTextLong: | ||
410 | case SMS_ConcatenatedTextLong16bit: | ||
411 | |||
412 | /* This covers situation, when somebody will call function | ||
413 | * with two or more SMS_Concatenated.... entries only. | ||
414 | * It will be still only linked sms, but functions below | ||
415 | * will pack only first entry according to own limits. | ||
416 | * We redirect to EMS functions, because they are more generic | ||
417 | * here and will handle it correctly and produce linked sms | ||
418 | * from all entries | ||
419 | */ | ||
420 | textnum ++; | ||
421 | if (textnum > 1) EMS = true; | ||
422 | |||
423 | if (Info->Entries[i].Left || Info->Entries[i].Right || | ||
424 | Info->Entries[i].Center || Info->Entries[i].Large || | ||
425 | Info->Entries[i].Small || Info->Entries[i].Bold || | ||
426 | Info->Entries[i].Italic || Info->Entries[i].Underlined || | ||
427 | Info->Entries[i].Strikethrough) { | ||
428 | EMS = true; | ||
429 | } | ||
430 | default: | ||
431 | break; | ||
432 | } | ||
433 | if (EMS) break; | ||
434 | } | ||
435 | if (EMS) { | ||
436 | error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH); | ||
437 | if (error != ERR_NONE) return error; | ||
438 | if (SMS->Number != 1) { | ||
439 | SMS->Number = 0; | ||
440 | for (i=0;i<Info->EntriesNum;i++) { | ||
441 | if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) { | ||
442 | return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages); | ||
443 | } | ||
444 | } | ||
445 | return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit); | ||
446 | } | ||
447 | return error; | ||
448 | } | ||
449 | |||
450 | if (Info->EntriesNum != 1) return ERR_UNKNOWN; | ||
451 | |||
452 | switch (Info->Entries[0].ID) { | ||
453 | case SMS_AlcatelMonoBitmapLong: | ||
454 | Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth; | ||
455 | Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight; | ||
456 | PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+2, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
457 | Length = PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight)+2; | ||
458 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE); | ||
459 | case SMS_AlcatelMonoAnimationLong: | ||
460 | /* Number of sequence words */ | ||
461 | Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256; | ||
462 | Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256; | ||
463 | /* Picture display time 1 second (1 = 100ms) */ | ||
464 | Buffer[2] = 10 % 256; | ||
465 | Buffer[3] = 10 / 256 + 0xF0; | ||
466 | |||
467 | Length = 4; | ||
468 | j = 0; | ||
469 | |||
470 | /* Offsets to bitmaps */ | ||
471 | for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { | ||
472 | Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256; | ||
473 | Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256; | ||
474 | j += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight)+2; | ||
475 | } | ||
476 | |||
477 | /* Bitmaps */ | ||
478 | for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { | ||
479 | Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth; | ||
480 | Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight; | ||
481 | PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]); | ||
482 | Length += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight); | ||
483 | } | ||
484 | return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION); | ||
485 | case SMS_MMSIndicatorLong: | ||
486 | Class= 1; | ||
487 | UDH= UDH_MMSIndicatorLong; | ||
488 | GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator); | ||
489 | break; | ||
490 | case SMS_NokiaRingtoneLong: | ||
491 | case SMS_NokiaRingtone: | ||
492 | UDH= UDH_NokiaRingtone; | ||
493 | Class= 1; | ||
494 | /* 7 = length of UDH_NokiaRingtone UDH header */ | ||
495 | Length = GSM_MAX_8BIT_SMS_LENGTH-7; | ||
496 | Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); | ||
497 | if (Info->Entries[0].ID == SMS_NokiaRingtone) break; | ||
498 | if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) { | ||
499 | UDH = UDH_NokiaRingtoneLong; | ||
500 | Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3; | ||
501 | Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); | ||
502 | } | ||
503 | break; | ||
504 | case SMS_NokiaOperatorLogoLong: | ||
505 | if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) { | ||
506 | UDH= UDH_NokiaOperatorLogoLong; | ||
507 | Class = 1; | ||
508 | NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
509 | Length = Length + 3; | ||
510 | NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
511 | break; | ||
512 | } | ||
513 | case SMS_NokiaOperatorLogo: | ||
514 | UDH= UDH_NokiaOperatorLogo; | ||
515 | Class = 1; | ||
516 | NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
517 | Length = Length + 3; | ||
518 | NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
519 | break; | ||
520 | case SMS_NokiaCallerLogo: | ||
521 | UDH= UDH_NokiaCallerLogo; | ||
522 | Class = 1; | ||
523 | NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); | ||
524 | break; | ||
525 | case SMS_NokiaProfileLong: | ||
526 | case SMS_NokiaPictureImageLong: | ||
527 | case SMS_NokiaScreenSaverLong: | ||
528 | Class = 1; | ||
529 | UDH= UDH_NokiaProfileLong; | ||
530 | GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length); | ||
531 | break; | ||
532 | case SMS_NokiaWAPBookmarkLong: | ||
533 | Class= 1; | ||
534 | NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark); | ||
535 | /* 7 = length of UDH_NokiaWAP UDH header */ | ||
536 | if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) { | ||
537 | UDH=UDH_NokiaWAPLong; | ||
538 | } else { | ||
539 | UDH=UDH_NokiaWAP; | ||
540 | } | ||
541 | break; | ||
542 | case SMS_NokiaWAPSettingsLong: | ||
543 | Class= 1; | ||
544 | UDH= UDH_NokiaWAPLong; | ||
545 | NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false); | ||
546 | break; | ||
547 | case SMS_NokiaMMSSettingsLong: | ||
548 | Class= 1; | ||
549 | UDH= UDH_NokiaWAPLong; | ||
550 | NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true); | ||
551 | break; | ||
552 | case SMS_NokiaVCARD10Long: | ||
553 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
554 | /* is 1 SMS ? 8 = length of ..SCKE2 */ | ||
555 | if (Length<=GSM_MAX_SMS_LENGTH-8) { | ||
556 | sprintf(Buffer,"//SCKE2 "); | ||
557 | Length = 8; | ||
558 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
559 | } else { | ||
560 | /* FIXME: It wasn't checked */ | ||
561 | UDH = UDH_NokiaPhonebookLong; | ||
562 | } | ||
563 | Coding = SMS_Coding_Default; | ||
564 | memcpy(Buffer2,Buffer,Length); | ||
565 | EncodeUnicode(Buffer,Buffer2,Length); | ||
566 | break; | ||
567 | case SMS_NokiaVCARD21Long: | ||
568 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
569 | /* Is 1 SMS ? 12 = length of ..SCKL23F4 */ | ||
570 | if (Length<=GSM_MAX_SMS_LENGTH-12) { | ||
571 | sprintf(Buffer,"//SCKL23F4%c%c",13,10); | ||
572 | Length = 12; | ||
573 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
574 | } else { | ||
575 | UDH = UDH_NokiaPhonebookLong; | ||
576 | /* Here can be also 8 bit coding */ | ||
577 | } | ||
578 | Coding = SMS_Coding_Default; | ||
579 | memcpy(Buffer2,Buffer,Length); | ||
580 | EncodeUnicode(Buffer,Buffer2,Length); | ||
581 | break; | ||
582 | case SMS_VCARD10Long: | ||
583 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); | ||
584 | if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; | ||
585 | Coding = SMS_Coding_Default; | ||
586 | memcpy(Buffer2,Buffer,Length); | ||
587 | EncodeUnicode(Buffer,Buffer2,Length); | ||
588 | break; | ||
589 | case SMS_VCARD21Long: | ||
590 | GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); | ||
591 | if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; | ||
592 | Coding = SMS_Coding_Default; | ||
593 | memcpy(Buffer2,Buffer,Length); | ||
594 | EncodeUnicode(Buffer,Buffer2,Length); | ||
595 | break; | ||
596 | case SMS_NokiaVCALENDAR10Long: | ||
597 | error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); | ||
598 | if (error != ERR_NONE) return error; | ||
599 | /* Is 1 SMS ? 8 = length of ..SCKE4 */ | ||
600 | if (Length<=GSM_MAX_SMS_LENGTH-8) { | ||
601 | sprintf(Buffer,"//SCKE4 "); | ||
602 | Length = 8; | ||
603 | GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); | ||
604 | } else { | ||
605 | UDH = UDH_NokiaCalendarLong; | ||
606 | /* can be here 8 bit coding ? */ | ||
607 | } | ||
608 | Coding = SMS_Coding_Default; | ||
609 | memcpy(Buffer2,Buffer,Length); | ||
610 | EncodeUnicode(Buffer,Buffer2,Length); | ||
611 | break; | ||
612 | case SMS_NokiaVTODOLong: | ||
613 | error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo); | ||
614 | if (error != ERR_NONE) return error; | ||
615 | UDH = UDH_NokiaCalendarLong; | ||
616 | Coding = SMS_Coding_Default; | ||
617 | memcpy(Buffer2,Buffer,Length); | ||
618 | EncodeUnicode(Buffer,Buffer2,Length); | ||
619 | break; | ||
620 | case SMS_DisableVoice: | ||
621 | case SMS_DisableFax: | ||
622 | case SMS_DisableEmail: | ||
623 | case SMS_EnableVoice: | ||
624 | case SMS_EnableFax: | ||
625 | case SMS_EnableEmail: | ||
626 | case SMS_VoidSMS: | ||
627 | case SMS_Text: | ||
628 | Class = Info->Class; | ||
629 | switch (Info->Entries[0].ID) { | ||
630 | case SMS_DisableVoice: UDH = UDH_DisableVoice; break; | ||
631 | case SMS_DisableFax : UDH = UDH_DisableFax; break; | ||
632 | case SMS_DisableEmail: UDH = UDH_DisableEmail; break; | ||
633 | case SMS_EnableVoice: UDH = UDH_EnableVoice; break; | ||
634 | case SMS_EnableFax : UDH = UDH_EnableFax; break; | ||
635 | case SMS_EnableEmail: UDH = UDH_EnableEmail; break; | ||
636 | case SMS_VoidSMS : UDH = UDH_VoidSMS; break; | ||
637 | case SMS_Text : UDH = UDH_NoUDH; break; | ||
638 | default : break; | ||
639 | } | ||
640 | UDHHeader.Type = UDH; | ||
641 | GSM_EncodeUDHHeader(&UDHHeader); | ||
642 | memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); | ||
643 | if (Info->UnicodeCoding) { | ||
644 | Coding = SMS_Coding_Unicode; | ||
645 | Length = UnicodeLength(Info->Entries[0].Buffer); | ||
646 | if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2; | ||
647 | } else { | ||
648 | Coding = SMS_Coding_Default; | ||
649 | FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7); | ||
650 | } | ||
651 | break; | ||
652 | case SMS_ConcatenatedAutoTextLong: | ||
653 | case SMS_ConcatenatedAutoTextLong16bit: | ||
654 | smslen = UnicodeLength(Info->Entries[0].Buffer); | ||
655 | memcpy(Buffer,Info->Entries[0].Buffer,smslen*2); | ||
656 | EncodeDefault(Buffer2, Buffer, &smslen, true, NULL); | ||
657 | DecodeDefault(Buffer, Buffer2, smslen, true, NULL); | ||
658 | #ifdef DEBUG | ||
659 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) { | ||
660 | dbgprintf("Info->Entries[0].Buffer:\n"); | ||
661 | DumpMessage(di.df, di.dl, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2); | ||
662 | dbgprintf("Buffer:\n"); | ||
663 | DumpMessage(di.df, di.dl, Buffer, UnicodeLength(Buffer)*2); | ||
664 | } | ||
665 | #endif | ||
666 | Info->UnicodeCoding = false; | ||
667 | for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) { | ||
668 | if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) { | ||
669 | Info->UnicodeCoding = true; | ||
670 | dbgprintf("Setting to Unicode %i\n",smslen); | ||
671 | break; | ||
672 | } | ||
673 | } | ||
674 | /* No break here - we go to the SMS_ConcatenatedTextLong */ | ||
675 | case SMS_ConcatenatedTextLong: | ||
676 | case SMS_ConcatenatedTextLong16bit: | ||
677 | Class = Info->Class; | ||
678 | memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); | ||
679 | UDH = UDH_NoUDH; | ||
680 | if (Info->UnicodeCoding) { | ||
681 | Coding = SMS_Coding_Unicode; | ||
682 | Length = UnicodeLength(Info->Entries[0].Buffer); | ||
683 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || | ||
684 | Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { | ||
685 | if (Length>70) UDH=UDH_ConcatenatedMessages16bit; | ||
686 | } else { | ||
687 | if (Length>70) UDH=UDH_ConcatenatedMessages; | ||
688 | } | ||
689 | } else { | ||
690 | Coding = SMS_Coding_Default; | ||
691 | FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000); | ||
692 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || | ||
693 | Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { | ||
694 | if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit; | ||
695 | } else { | ||
696 | if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages; | ||
697 | } | ||
698 | } | ||
699 | default: | ||
700 | break; | ||
701 | } | ||
702 | GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage); | ||
703 | return ERR_NONE; | ||
704 | } | ||
705 | |||
706 | void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) | ||
707 | { | ||
708 | int i; | ||
709 | |||
710 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
711 | Info->Entries[i].Number = 0; | ||
712 | Info->Entries[i].Ringtone= NULL; | ||
713 | Info->Entries[i].Bitmap = NULL; | ||
714 | Info->Entries[i].Bookmark= NULL; | ||
715 | Info->Entries[i].Settings= NULL; | ||
716 | Info->Entries[i].MMSIndicator= NULL; | ||
717 | Info->Entries[i].Phonebook= NULL; | ||
718 | Info->Entries[i].Calendar= NULL; | ||
719 | Info->Entries[i].ToDo = NULL; | ||
720 | Info->Entries[i].Protected= false; | ||
721 | |||
722 | Info->Entries[i].Buffer = NULL; | ||
723 | Info->Entries[i].Left = false; | ||
724 | Info->Entries[i].Right = false; | ||
725 | Info->Entries[i].Center = false; | ||
726 | Info->Entries[i].Large = false; | ||
727 | Info->Entries[i].Small = false; | ||
728 | Info->Entries[i].Bold = false; | ||
729 | Info->Entries[i].Italic = false; | ||
730 | Info->Entries[i].Underlined= false; | ||
731 | Info->Entries[i].Strikethrough= false; | ||
732 | |||
733 | Info->Entries[i].RingtoneNotes= 0; | ||
734 | } | ||
735 | Info->Unknown = false; | ||
736 | Info->EntriesNum= 0; | ||
737 | Info->Class = -1; | ||
738 | Info->ReplaceMessage= 0; | ||
739 | Info->UnicodeCoding= false; | ||
740 | } | ||
741 | |||
742 | void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) | ||
743 | { | ||
744 | int i; | ||
745 | |||
746 | for (i=0;i<MAX_MULTI_SMS;i++) { | ||
747 | free(Info->Entries[i].Ringtone); | ||
748 | Info->Entries[i].Ringtone = NULL; | ||
749 | free(Info->Entries[i].Bitmap); | ||
750 | Info->Entries[i].Bitmap = NULL; | ||
751 | free(Info->Entries[i].Bookmark); | ||
752 | Info->Entries[i].Bookmark = NULL; | ||
753 | free(Info->Entries[i].Settings); | ||
754 | Info->Entries[i].Settings = NULL; | ||
755 | free(Info->Entries[i].MMSIndicator); | ||
756 | Info->Entries[i].MMSIndicator = NULL; | ||
757 | free(Info->Entries[i].Phonebook); | ||
758 | Info->Entries[i].Phonebook = NULL; | ||
759 | free(Info->Entries[i].Calendar); | ||
760 | Info->Entries[i].Calendar = NULL; | ||
761 | free(Info->Entries[i].ToDo); | ||
762 | Info->Entries[i].ToDo = NULL; | ||
763 | free(Info->Entries[i].Buffer); | ||
764 | Info->Entries[i].Buffer = NULL; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | /* ----------------- Joining SMS from parts -------------------------------- */ | ||
769 | |||
770 | bool GSM_DecodeMultiPartSMS(GSM_MultiPartSMSInfo*Info, | ||
771 | GSM_MultiSMSMessage *SMS, | ||
772 | bool ems) | ||
773 | { | ||
774 | int i, Length = 0; | ||
775 | charBuffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; | ||
776 | bool emsexist = false; | ||
777 | |||
778 | GSM_ClearMultiPartSMSInfo(Info); | ||
779 | if (ems) { | ||
780 | emsexist = true; | ||
781 | for (i=0;i<SMS->Number;i++) { | ||
782 | if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages && | ||
783 | SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
784 | SMS->SMS[i].UDH.Type != UDH_UserUDH) { | ||
785 | emsexist = false; | ||
786 | break; | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /* EMS decoding */ | ||
792 | if (emsexist) return GSM_DecodeEMSMultiPartSMS(Info,SMS); | ||
793 | |||
794 | /* Smart Messaging decoding */ | ||
795 | if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) { | ||
796 | Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone)); | ||
797 | if (Info->Entries[0].Ringtone == NULL) return false; | ||
798 | if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) { | ||
799 | Info->Entries[0].ID = SMS_NokiaRingtone; | ||
800 | Info->EntriesNum= 1; | ||
801 | return true; | ||
802 | } | ||
803 | } | ||
804 | if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) { | ||
805 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
806 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
807 | Info->Entries[0].Bitmap->Number = 1; | ||
808 | PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
809 | #ifdef DEBUG | ||
810 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
811 | #endif | ||
812 | Info->Entries[0].ID = SMS_NokiaCallerLogo; | ||
813 | Info->EntriesNum= 1; | ||
814 | return true; | ||
815 | } | ||
816 | if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) { | ||
817 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
818 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
819 | Info->Entries[0].Bitmap->Number = 1; | ||
820 | PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
821 | NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); | ||
822 | #ifdef DEBUG | ||
823 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
824 | #endif | ||
825 | Info->Entries[0].ID = SMS_NokiaOperatorLogo; | ||
826 | Info->EntriesNum= 1; | ||
827 | return true; | ||
828 | } | ||
829 | if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) { | ||
830 | for (i=0;i<SMS->Number;i++) { | ||
831 | if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong || | ||
832 | SMS->SMS[i].UDH.Text[11] != i+1 || | ||
833 | SMS->SMS[i].UDH.Text[10] != SMS->Number) { | ||
834 | return false; | ||
835 | } | ||
836 | memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length); | ||
837 | Length = Length + SMS->SMS[i].Length; | ||
838 | } | ||
839 | Info->EntriesNum = 1; | ||
840 | Info->Entries[0].ID = SMS_NokiaPictureImageLong; | ||
841 | Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); | ||
842 | if (Info->Entries[0].Bitmap == NULL) return false; | ||
843 | Info->Entries[0].Bitmap->Number = 1; | ||
844 | Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0; | ||
845 | Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0; | ||
846 | i=1; | ||
847 | while (i!=Length) { | ||
848 | switch (Buffer[i]) { | ||
849 | case SM30_ISOTEXT: | ||
850 | dbgprintf("ISO 8859-2 text\n"); | ||
851 | Info->Unknown = true; | ||
852 | break; | ||
853 | case SM30_UNICODETEXT: | ||
854 | dbgprintf("Unicode text\n"); | ||
855 | memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]); | ||
856 | Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0; | ||
857 | Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0; | ||
858 | dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text)); | ||
859 | break; | ||
860 | case SM30_OTA: | ||
861 | dbgprintf("OTA bitmap as Picture Image\n"); | ||
862 | PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
863 | #ifdef DEBUG | ||
864 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
865 | #endif | ||
866 | break; | ||
867 | case SM30_RINGTONE: | ||
868 | dbgprintf("RTTL ringtone\n"); | ||
869 | Info->Unknown = true; | ||
870 | break; | ||
871 | case SM30_PROFILENAME: | ||
872 | dbgprintf("Profile Name\n"); | ||
873 | Info->Entries[0].ID = SMS_NokiaProfileLong; | ||
874 | Info->Unknown = true; | ||
875 | break; | ||
876 | case SM30_SCREENSAVER: | ||
877 | dbgprintf("OTA bitmap as Screen Saver\n"); | ||
878 | PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); | ||
879 | #ifdef DEBUG | ||
880 | if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); | ||
881 | #endif | ||
882 | Info->Entries[0].ID = SMS_NokiaScreenSaverLong; | ||
883 | break; | ||
884 | } | ||
885 | i = i + Buffer[i+1]*256 + Buffer[i+2] + 3; | ||
886 | dbgprintf("%i %i\n",i,Length); | ||
887 | } | ||
888 | return true; | ||
889 | } | ||
890 | |||
891 | /* Linked sms */ | ||
892 | if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages || | ||
893 | SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { | ||
894 | Info->EntriesNum = 1; | ||
895 | Info->Entries[0].ID = SMS_ConcatenatedTextLong; | ||
896 | if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { | ||
897 | Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit; | ||
898 | } | ||
899 | |||
900 | for (i=0;i<SMS->Number;i++) { | ||
901 | switch (SMS->SMS[i].Coding) { | ||
902 | case SMS_Coding_8bit: | ||
903 | Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2); | ||
904 | if (Info->Entries[0].Buffer == NULL) return false; | ||
905 | |||
906 | memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length); | ||
907 | Length=Length+SMS->SMS[i].Length; | ||
908 | break; | ||
909 | case SMS_Coding_Unicode: | ||
910 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) { | ||
911 | Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong; | ||
912 | } | ||
913 | if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) { | ||
914 | Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit; | ||
915 | } | ||
916 | case SMS_Coding_Default: | ||
917 | Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2); | ||
918 | if (Info->Entries[0].Buffer == NULL) return false; | ||
919 | |||
920 | memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2); | ||
921 | Length=Length+UnicodeLength(SMS->SMS[i].Text)*2; | ||
922 | break; | ||
923 | } | ||
924 | } | ||
925 | Info->Entries[0].Buffer[Length] = 0; | ||
926 | Info->Entries[0].Buffer[Length+1] = 0; | ||
927 | return true; | ||
928 | } | ||
929 | |||
930 | return false; | ||
931 | } | ||
932 | |||
933 | GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems) | ||
934 | { | ||
935 | bool *INPUTSorted, copyit; | ||
936 | int i,OUTPUTNum,j,z,w; | ||
937 | |||
938 | i = 0; | ||
939 | while (INPUT[i] != NULL) i++; | ||
940 | |||
941 | INPUTSorted = calloc(i, sizeof(bool)); | ||
942 | if (INPUTSorted == NULL) return ERR_MOREMEMORY; | ||
943 | |||
944 | OUTPUTNum = 0; | ||
945 | OUTPUT[0] = NULL; | ||
946 | |||
947 | if (ems) { | ||
948 | i=0; | ||
949 | while (INPUT[i] != NULL) { | ||
950 | if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { | ||
951 | w=1; | ||
952 | while (w < INPUT[i]->SMS[0].UDH.Length) { | ||
953 | switch(INPUT[i]->SMS[0].UDH.Text[w]) { | ||
954 | case 0x00: | ||
955 | dbgprintf("Adding ID to user UDH - linked SMS with 8 bit ID\n"); | ||
956 | INPUT[i]->SMS[0].UDH.ID8bit= INPUT[i]->SMS[0].UDH.Text[w+2]; | ||
957 | INPUT[i]->SMS[0].UDH.AllParts= INPUT[i]->SMS[0].UDH.Text[w+3]; | ||
958 | INPUT[i]->SMS[0].UDH.PartNumber= INPUT[i]->SMS[0].UDH.Text[w+4]; | ||
959 | break; | ||
960 | case 0x08: | ||
961 | dbgprintf("Adding ID to user UDH - linked SMS with 16 bit ID\n"); | ||
962 | INPUT[i]->SMS[0].UDH.ID16bit= INPUT[i]->SMS[0].UDH.Text[w+2]*256+INPUT[i]->SMS[0].UDH.Text[w+3]; | ||
963 | INPUT[i]->SMS[0].UDH.AllParts= INPUT[i]->SMS[0].UDH.Text[w+4]; | ||
964 | INPUT[i]->SMS[0].UDH.PartNumber= INPUT[i]->SMS[0].UDH.Text[w+5]; | ||
965 | break; | ||
966 | default: | ||
967 | dbgprintf("Block %02x\n",INPUT[i]->SMS[0].UDH.Text[w]); | ||
968 | } | ||
969 | dbgprintf("%i %i %i %i\n", | ||
970 | INPUT[i]->SMS[0].UDH.ID8bit, | ||
971 | INPUT[i]->SMS[0].UDH.ID16bit, | ||
972 | INPUT[i]->SMS[0].UDH.PartNumber, | ||
973 | INPUT[i]->SMS[0].UDH.AllParts); | ||
974 | w=w+INPUT[i]->SMS[0].UDH.Text[w+1]+2; | ||
975 | } | ||
976 | } | ||
977 | i++; | ||
978 | } | ||
979 | } | ||
980 | |||
981 | i=0; | ||
982 | while (INPUT[i]!=NULL) { | ||
983 | /* If this one SMS was sorted earlier, do not touch */ | ||
984 | if (INPUTSorted[i]) { | ||
985 | i++; | ||
986 | continue; | ||
987 | } | ||
988 | copyit = false; | ||
989 | /* If we have: | ||
990 | * - linked sms returned by phone driver | ||
991 | * - sms without linking | ||
992 | * we copy it to OUTPUT | ||
993 | */ | ||
994 | if (INPUT[i]->Number != 1 || | ||
995 | INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH || | ||
996 | INPUT[i]->SMS[0].UDH.PartNumber == -1) { | ||
997 | copyit = true; | ||
998 | } | ||
999 | /* If we have unknown UDH, we copy it to OUTPUT */ | ||
1000 | if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { | ||
1001 | if (!ems) copyit = true; | ||
1002 | if (ems && INPUT[i]->SMS[0].UDH.PartNumber == -1) copyit = true; | ||
1003 | } | ||
1004 | if (copyit) { | ||
1005 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1006 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1007 | free(INPUTSorted); | ||
1008 | return ERR_MOREMEMORY; | ||
1009 | } | ||
1010 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1011 | |||
1012 | memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); | ||
1013 | INPUTSorted[i]=true; | ||
1014 | OUTPUTNum++; | ||
1015 | i = 0; | ||
1016 | continue; | ||
1017 | } | ||
1018 | /* We have 1'st part of linked sms. It's single. | ||
1019 | * We will try to find other parts | ||
1020 | */ | ||
1021 | if (INPUT[i]->SMS[0].UDH.PartNumber == 1) { | ||
1022 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1023 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1024 | free(INPUTSorted); | ||
1025 | return ERR_MOREMEMORY; | ||
1026 | } | ||
1027 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1028 | |||
1029 | memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage)); | ||
1030 | OUTPUT[OUTPUTNum]->Number = 1; | ||
1031 | INPUTSorted[i]= true; | ||
1032 | j = 1; | ||
1033 | /* We're searching for other parts in sequence */ | ||
1034 | while (j!=INPUT[i]->SMS[0].UDH.AllParts) { | ||
1035 | z=0; | ||
1036 | while(INPUT[z]!=NULL) { | ||
1037 | /* This was sorted earlier or is not single */ | ||
1038 | if (INPUTSorted[z] || INPUT[z]->Number != 1) { | ||
1039 | z++; | ||
1040 | continue; | ||
1041 | } | ||
1042 | if (ems && INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && | ||
1043 | INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
1044 | INPUT[i]->SMS[0].UDH.Type != UDH_UserUDH && | ||
1045 | INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && | ||
1046 | INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && | ||
1047 | INPUT[z]->SMS[0].UDH.Type != UDH_UserUDH) { | ||
1048 | if (INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { | ||
1049 | z++; | ||
1050 | continue; | ||
1051 | } | ||
1052 | } | ||
1053 | if (!ems && INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { | ||
1054 | z++; | ||
1055 | continue; | ||
1056 | } | ||
1057 | dbgprintf("compare %i %i %i %i %i", | ||
1058 | j+1, | ||
1059 | INPUT[i]->SMS[0].UDH.ID8bit, | ||
1060 | INPUT[i]->SMS[0].UDH.ID16bit, | ||
1061 | INPUT[i]->SMS[0].UDH.PartNumber, | ||
1062 | INPUT[i]->SMS[0].UDH.AllParts); | ||
1063 | dbgprintf(" %i %i %i %i\n", | ||
1064 | INPUT[z]->SMS[0].UDH.ID8bit, | ||
1065 | INPUT[z]->SMS[0].UDH.ID16bit, | ||
1066 | INPUT[z]->SMS[0].UDH.PartNumber, | ||
1067 | INPUT[z]->SMS[0].UDH.AllParts); | ||
1068 | if (INPUT[z]->SMS[0].UDH.ID8bit != INPUT[i]->SMS[0].UDH.ID8bit|| | ||
1069 | INPUT[z]->SMS[0].UDH.ID16bit != INPUT[i]->SMS[0].UDH.ID16bit|| | ||
1070 | INPUT[z]->SMS[0].UDH.AllParts != INPUT[i]->SMS[0].UDH.AllParts || | ||
1071 | INPUT[z]->SMS[0].UDH.PartNumber != j+1) { | ||
1072 | z++; | ||
1073 | continue; | ||
1074 | } | ||
1075 | /* For SMS_Deliver compare also SMSC and Sender number */ | ||
1076 | if (INPUT[z]->SMS[0].PDU == SMS_Deliver && | ||
1077 | (strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) || | ||
1078 | strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number)))) { | ||
1079 | z++; | ||
1080 | continue; | ||
1081 | } | ||
1082 | /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */ | ||
1083 | if (INPUT[z]->SMS[0].PDU == SMS_Deliver && | ||
1084 | UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)==0 && | ||
1085 | UnicodeLength(INPUT[z]->SMS[0].Number)==0 && | ||
1086 | (INPUT[z]->SMS[0].DateTime.Day != INPUT[i]->SMS[0].DateTime.Day || | ||
1087 | INPUT[z]->SMS[0].DateTime.Month != INPUT[i]->SMS[0].DateTime.Month || | ||
1088 | INPUT[z]->SMS[0].DateTime.Year != INPUT[i]->SMS[0].DateTime.Year || | ||
1089 | INPUT[z]->SMS[0].DateTime.Hour != INPUT[i]->SMS[0].DateTime.Hour || | ||
1090 | INPUT[z]->SMS[0].DateTime.Minute != INPUT[i]->SMS[0].DateTime.Minute || | ||
1091 | INPUT[z]->SMS[0].DateTime.Second != INPUT[i]->SMS[0].DateTime.Second)) { | ||
1092 | z++; | ||
1093 | continue; | ||
1094 | } | ||
1095 | /* We found correct sms. Copy it */ | ||
1096 | memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage)); | ||
1097 | OUTPUT[OUTPUTNum]->Number++; | ||
1098 | INPUTSorted[z]=true; | ||
1099 | break; | ||
1100 | } | ||
1101 | /* Incomplete sequence */ | ||
1102 | if (OUTPUT[OUTPUTNum]->Number==j) { | ||
1103 | dbgprintf("Incomplete sequence\n"); | ||
1104 | break; | ||
1105 | } | ||
1106 | j++; | ||
1107 | } | ||
1108 | OUTPUTNum++; | ||
1109 | i = 0; | ||
1110 | continue; | ||
1111 | } | ||
1112 | /* We have some next linked sms from sequence */ | ||
1113 | if (INPUT[i]->SMS[0].UDH.PartNumber > 1) { | ||
1114 | j = 0; | ||
1115 | while (INPUT[j]!=NULL) { | ||
1116 | if (INPUTSorted[j]) { | ||
1117 | j++; | ||
1118 | continue; | ||
1119 | } | ||
1120 | /* We have some not unassigned first sms from sequence. | ||
1121 | * We can't touch other sms from sequences | ||
1122 | */ | ||
1123 | if (INPUT[j]->SMS[0].UDH.PartNumber == 1) break; | ||
1124 | j++; | ||
1125 | } | ||
1126 | if (INPUT[j]==NULL) { | ||
1127 | OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); | ||
1128 | if (OUTPUT[OUTPUTNum] == NULL) { | ||
1129 | free(INPUTSorted); | ||
1130 | return ERR_MOREMEMORY; | ||
1131 | } | ||
1132 | OUTPUT[OUTPUTNum+1] = NULL; | ||
1133 | |||
1134 | memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); | ||
1135 | INPUTSorted[i]=true; | ||
1136 | OUTPUTNum++; | ||
1137 | i = 0; | ||
1138 | continue; | ||
1139 | } else i++; | ||
1140 | } | ||
1141 | } | ||
1142 | free(INPUTSorted); | ||
1143 | return ERR_NONE; | ||
1144 | } | ||
1145 | |||
1146 | /* How should editor hadle tabs in this file? Add editor commands here. | ||
1147 | * vim: noexpandtab sw=8 ts=8 sts=8: | ||
1148 | */ | ||