summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/service/sms/gsmmulti.c
Unidiff
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.c1148
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
21unsigned 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
37void 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 */
206static 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
706void 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
742void 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
933GSM_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 */