Imported gammu 0.90.7
[gammu.git] / common / service / sms / gsmmulti.c
blob7d6b5151cce89cac2c508b339edf57343648cbc2
2 #include <ctype.h>
3 #include <string.h>
4 #include <time.h>
6 #include "../../gsmcomon.h"
7 #include "../../misc/coding/coding.h"
8 #include "../gsmcal.h"
9 #include "../gsmpbk.h"
10 #include "../gsmlogo.h"
11 #include "../gsmring.h"
12 #include "../gsmwap.h"
13 #include "../gsmnet.h"
14 #include "gsmsms.h"
15 #include "gsmmulti.h"
16 #include "gsmems.h"
18 /* ----------------- Splitting SMS into parts ------------------------------ */
20 unsigned char GSM_MakeSMSIDFromTime()
22 GSM_DateTime Date;
23 unsigned char retval;
25 GSM_GetCurrentDateTime (&Date);
26 retval = Date.Second;
27 switch (Date.Minute/10) {
28 case 2: case 7: retval = retval + 60; break;
29 case 4: case 8: retval = retval + 120; break;
30 case 9: case 5: case 0: retval = retval + 180; break;
32 retval += Date.Minute/10;
33 return retval;
36 void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes)
38 int UsedBytes;
40 switch (Coding) {
41 case GSM_Coding_Default:
42 FindDefaultAlphabetLen(SMS.Text,&UsedBytes,UsedText,500);
43 UsedBytes = *UsedText * 7 / 8;
44 if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++;
45 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
46 *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length) * 8 / 7 - *UsedText;
47 break;
48 case GSM_Coding_Unicode:
49 *UsedText = UnicodeLength(SMS.Text);
50 UsedBytes = *UsedText * 2;
51 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
52 *FreeText = *FreeBytes / 2;
53 break;
54 case GSM_Coding_8bit:
55 *UsedText = UsedBytes = SMS.Length;
56 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
57 *FreeText = *FreeBytes;
58 break;
60 dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes);
63 GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS,
64 GSM_Coding_Type Coding,
65 char *Buffer,
66 int BufferLen,
67 bool UDH,
68 int *UsedText,
69 int *CopiedText,
70 int *CopiedSMSText)
72 int FreeText,FreeBytes,Copy,i,j;
74 dbgprintf("Checking used\n");
75 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
77 if (UDH) {
78 dbgprintf("Adding UDH\n");
79 if (FreeBytes - BufferLen <= 0) {
80 dbgprintf("Going to the new SMS\n");
81 SMS->Number++;
82 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
84 if (SMS->SMS[SMS->Number].UDH.Length == 0) {
85 SMS->SMS[SMS->Number].UDH.Length = 1;
86 SMS->SMS[SMS->Number].UDH.Text[0] = 0x00;
88 memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen);
89 SMS->SMS[SMS->Number].UDH.Length += BufferLen;
90 SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen;
91 SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH;
92 dbgprintf("UDH added %i\n",BufferLen);
93 } else {
94 dbgprintf("Adding text\n");
95 if (FreeText == 0) {
96 dbgprintf("Going to the new SMS\n");
97 SMS->Number++;
98 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
101 Copy = FreeText;
102 dbgprintf("copy %i\n",Copy);
103 if (BufferLen < Copy) Copy = BufferLen;
104 dbgprintf("copy %i\n",Copy);
106 switch (Coding) {
107 case GSM_Coding_Default:
108 FindDefaultAlphabetLen(Buffer,&i,&j,FreeText);
109 dbgprintf("def length %i %i\n",i,j);
110 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0;
111 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0;
112 memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2);
113 *CopiedText = i;
114 *CopiedSMSText = j;
115 SMS->SMS[SMS->Number].Length += i;
116 break;
117 case GSM_Coding_Unicode:
118 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0;
119 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0;
120 memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2);
121 *CopiedText = *CopiedSMSText = Copy;
122 SMS->SMS[SMS->Number].Length += Copy;
123 break;
124 case GSM_Coding_8bit:
125 memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy);
126 SMS->SMS[SMS->Number].Length += Copy;
127 *CopiedText = *CopiedSMSText = Copy;
128 break;
130 dbgprintf("Text added\n");
133 dbgprintf("Checking on the end\n");
134 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
136 return GE_NONE;
139 void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS,
140 unsigned char *MessageBuffer,
141 int MessageLength,
142 GSM_UDH UDHType,
143 GSM_Coding_Type Coding,
144 int Class,
145 unsigned char ReplaceMessage)
147 int j,Len,UsedText,CopiedText,CopiedSMSText;
148 unsigned char UDHID;
149 GSM_DateTime Date;
151 Len = 0;
152 while(1) {
153 GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]);
154 SMS->SMS[SMS->Number].Class = Class;
155 SMS->SMS[SMS->Number].Coding = Coding;
157 SMS->SMS[SMS->Number].UDH.Type = UDHType;
158 GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH);
160 if (Coding == GSM_Coding_8bit) {
161 GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
162 } else {
163 GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
165 Len += CopiedText;
166 dbgprintf("%i %i\n",Len,MessageLength);
167 if (Len == MessageLength) break;
168 if (SMS->Number == MAX_MULTI_SMS) break;
169 SMS->Number++;
172 SMS->Number++;
174 UDHID = GSM_MakeSMSIDFromTime();
175 GSM_GetCurrentDateTime (&Date);
176 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);
185 if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage;
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)
196 int UsedText,FreeBytes;
197 GSM_MultiSMSMessage MultiSMS;
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;
205 /* Nokia Smart Messaging 3.0 */
206 static void GSM_EncodeSMS30MultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
207 char *Buffer, int *Length)
209 int len;
211 /*SM version. Here 3.0*/
212 Buffer[(*Length)++] = 0x30;
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);
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;
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;
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);
268 GSM_Error GSM_EncodeMultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
269 GSM_MultiSMSMessage *SMS)
271 unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
272 unsigned char Buffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
273 int Length = 0,smslen,i, Class = -1;
274 GSM_Error error;
275 GSM_Coding_Type Coding = GSM_Coding_8bit;
276 GSM_UDH UDH = UDH_NoUDH;
277 GSM_UDHHeader UDHHeader;
278 bool EMS = false;
280 SMS->Number = 0;
282 for (i=0;i<Info->EntriesNum;i++) {
283 switch (Info->Entries[i].ID) {
284 case SMS_EMSPredefinedAnimation:
285 case SMS_EMSPredefinedSound:
286 case SMS_EMSSound10:
287 case SMS_EMSSound12:
288 case SMS_EMSSonyEricssonSound:
289 case SMS_EMSSound10Long:
290 case SMS_EMSSound12Long:
291 case SMS_EMSSonyEricssonSoundLong:
292 case SMS_EMSFixedBitmap:
293 case SMS_EMSVariableBitmap:
294 case SMS_EMSAnimation:
295 case SMS_EMSVariableBitmapLong:
296 EMS = true;
297 break;
298 case SMS_ConcatenatedTextLong:
299 case SMS_ConcatenatedTextLong16bit:
300 if (Info->Entries[i].Left || Info->Entries[i].Right ||
301 Info->Entries[i].Center || Info->Entries[i].Large ||
302 Info->Entries[i].Small || Info->Entries[i].Bold ||
303 Info->Entries[i].Italic || Info->Entries[i].Underlined ||
304 Info->Entries[i].Strikethrough) {
305 EMS = true;
307 default:
308 break;
310 if (EMS) break;
312 if (EMS) {
313 error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH);
314 if (error != GE_NONE) return error;
315 if (SMS->Number != 1) {
316 SMS->Number = 0;
317 for (i=0;i<Info->EntriesNum;i++) {
318 if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) {
319 return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages);
322 return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit);
324 return error;
326 if (Info->EntriesNum != 1) return GE_UNKNOWN;
328 switch (Info->Entries[0].ID) {
329 case SMS_MMSIndicatorLong:
330 Class = 1;
331 UDH = UDH_MMSIndicatorLong;
332 GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator);
333 break;
334 case SMS_NokiaRingtoneLong:
335 case SMS_NokiaRingtone:
336 UDH = UDH_NokiaRingtone;
337 Class = 1;
338 /* 7 = length of UDH_NokiaRingtone UDH header */
339 Length = GSM_MAX_8BIT_SMS_LENGTH-7;
340 Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length);
341 if (Info->Entries[0].ID == SMS_NokiaRingtone) break;
342 if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) {
343 UDH = UDH_NokiaRingtoneLong;
344 Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3;
345 Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length);
347 break;
348 case SMS_NokiaOperatorLogoLong:
349 if (Info->Entries[0].Bitmap->Bitmap[0].Width > 72 || Info->Entries[0].Bitmap->Bitmap[0].Height > 14) {
350 UDH = UDH_NokiaOperatorLogoLong;
351 Class = 1;
352 NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
353 Length = Length + 3;
354 NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
355 break;
357 case SMS_NokiaOperatorLogo:
358 UDH = UDH_NokiaOperatorLogo;
359 Class = 1;
360 NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
361 Length = Length + 3;
362 NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
363 break;
364 case SMS_NokiaCallerLogo:
365 UDH = UDH_NokiaCallerLogo;
366 Class = 1;
367 NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
368 break;
369 case SMS_NokiaProfileLong:
370 case SMS_NokiaPictureImageLong:
371 case SMS_NokiaScreenSaverLong:
372 Class = 1;
373 UDH = UDH_NokiaProfileLong;
374 GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length);
375 break;
376 case SMS_NokiaWAPBookmarkLong:
377 Class = 1;
378 NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark);
379 /* 7 = length of UDH_NokiaWAP UDH header */
380 if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) {
381 UDH=UDH_NokiaWAPLong;
382 } else {
383 UDH=UDH_NokiaWAP;
385 break;
386 case SMS_NokiaWAPSettingsLong:
387 Class = 1;
388 UDH = UDH_NokiaWAPLong;
389 NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false);
390 break;
391 case SMS_NokiaMMSSettingsLong:
392 Class = 1;
393 UDH = UDH_NokiaWAPLong;
394 NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true);
395 break;
396 case SMS_NokiaVCARD10Long:
397 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
398 /* is 1 SMS ? 8 = length of ..SCKE2 */
399 if (Length<=GSM_MAX_SMS_LENGTH-8) {
400 sprintf(Buffer,"//SCKE2 ");
401 Length = 8;
402 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
403 } else {
404 /* FIXME: It wasn't checked */
405 UDH = UDH_NokiaPhonebookLong;
407 Coding = GSM_Coding_Default;
408 memcpy(Buffer2,Buffer,Length);
409 EncodeUnicode(Buffer,Buffer2,Length);
410 break;
411 case SMS_NokiaVCARD21Long:
412 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
413 /* Is 1 SMS ? 12 = length of ..SCKL23F4 */
414 if (Length<=GSM_MAX_SMS_LENGTH-12) {
415 sprintf(Buffer,"//SCKL23F4%c%c",13,10);
416 Length = 12;
417 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
418 } else {
419 UDH = UDH_NokiaPhonebookLong;
420 /* Here can be also 8 bit coding */
422 Coding = GSM_Coding_Default;
423 memcpy(Buffer2,Buffer,Length);
424 EncodeUnicode(Buffer,Buffer2,Length);
425 break;
426 case SMS_VCARD10Long:
427 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
428 if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages;
429 Coding = GSM_Coding_Default;
430 memcpy(Buffer2,Buffer,Length);
431 EncodeUnicode(Buffer,Buffer2,Length);
432 break;
433 case SMS_VCARD21Long:
434 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
435 if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages;
436 Coding = GSM_Coding_Default;
437 memcpy(Buffer2,Buffer,Length);
438 EncodeUnicode(Buffer,Buffer2,Length);
439 break;
440 case SMS_NokiaVCALENDAR10Long:
441 error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar);
442 if (error != GE_NONE) return error;
443 /* Is 1 SMS ? 8 = length of ..SCKE4 */
444 if (Length<=GSM_MAX_SMS_LENGTH-8) {
445 sprintf(Buffer,"//SCKE4 ");
446 Length = 8;
447 GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar);
448 } else {
449 UDH = UDH_NokiaCalendarLong;
450 /* can be here 8 bit coding ? */
452 Coding = GSM_Coding_Default;
453 memcpy(Buffer2,Buffer,Length);
454 EncodeUnicode(Buffer,Buffer2,Length);
455 break;
456 case SMS_NokiaVTODOLong:
457 error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo);
458 if (error != GE_NONE) return error;
459 UDH = UDH_NokiaCalendarLong;
460 Coding = GSM_Coding_Default;
461 memcpy(Buffer2,Buffer,Length);
462 EncodeUnicode(Buffer,Buffer2,Length);
463 break;
464 case SMS_DisableVoice:
465 case SMS_DisableFax:
466 case SMS_DisableEmail:
467 case SMS_EnableVoice:
468 case SMS_EnableFax:
469 case SMS_EnableEmail:
470 case SMS_VoidSMS:
471 case SMS_Text:
472 Class = Info->Class;
473 switch (Info->Entries[0].ID) {
474 case SMS_DisableVoice : UDH = UDH_DisableVoice; break;
475 case SMS_DisableFax : UDH = UDH_DisableFax; break;
476 case SMS_DisableEmail : UDH = UDH_DisableEmail; break;
477 case SMS_EnableVoice : UDH = UDH_EnableVoice; break;
478 case SMS_EnableFax : UDH = UDH_EnableFax; break;
479 case SMS_EnableEmail : UDH = UDH_EnableEmail; break;
480 case SMS_VoidSMS : UDH = UDH_VoidSMS; break;
481 case SMS_Text : UDH = UDH_NoUDH; break;
482 default : break;
484 UDHHeader.Type = UDH;
485 GSM_EncodeUDHHeader(&UDHHeader);
486 memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
487 if (Info->UnicodeCoding) {
488 Coding = GSM_Coding_Unicode;
489 Length = UnicodeLength(Info->Entries[0].Buffer);
490 if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2;
491 } else {
492 Coding = GSM_Coding_Default;
493 FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7);
495 break;
496 case SMS_ConcatenatedAutoTextLong:
497 case SMS_ConcatenatedAutoTextLong16bit:
498 smslen = UnicodeLength(Info->Entries[0].Buffer);
499 memcpy(Buffer,Info->Entries[0].Buffer,smslen*2);
500 EncodeDefault(Buffer2, Buffer, &smslen, true, NULL);
501 DecodeDefault(Buffer, Buffer2, smslen, true, NULL);
502 #ifdef DEBUG
503 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) {
504 dbgprintf("Info->Entries[0].Buffer:\n");
505 DumpMessage(di.df, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2);
506 dbgprintf("Buffer:\n");
507 DumpMessage(di.df, Buffer, UnicodeLength(Buffer)*2);
509 #endif
510 Info->UnicodeCoding = false;
511 for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) {
512 if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) {
513 Info->UnicodeCoding = true;
514 dbgprintf("Setting to Unicode %i\n",smslen);
515 break;
518 /* No break here - we go to the SMS_ConcatenatedTextLong */
519 case SMS_ConcatenatedTextLong:
520 case SMS_ConcatenatedTextLong16bit:
521 Class = Info->Class;
522 memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
523 UDH = UDH_NoUDH;
524 if (Info->UnicodeCoding) {
525 Coding = GSM_Coding_Unicode;
526 Length = UnicodeLength(Info->Entries[0].Buffer);
527 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
528 Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
529 if (Length>70) UDH=UDH_ConcatenatedMessages16bit;
530 } else {
531 if (Length>70) UDH=UDH_ConcatenatedMessages;
533 } else {
534 Coding = GSM_Coding_Default;
535 FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000);
536 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
537 Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
538 if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit;
539 } else {
540 if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages;
543 default:
544 break;
546 GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage);
547 return GE_NONE;
550 void GSM_ClearMultiPartSMSInfo(GSM_EncodeMultiPartSMSInfo *Info)
552 int i;
554 for (i=0;i<MAX_MULTI_SMS;i++) {
555 Info->Entries[i].Buffer = NULL;
556 Info->Entries[i].Ringtone = NULL;
557 Info->Entries[i].Bitmap = NULL;
558 Info->Entries[i].Phonebook = NULL;
559 Info->Entries[i].Bookmark = NULL;
560 Info->Entries[i].Settings = NULL;
561 Info->Entries[i].Calendar = NULL;
562 Info->Entries[i].ToDo = NULL;
563 Info->Entries[i].MMSIndicator = NULL;
564 Info->Entries[i].Left = false;
565 Info->Entries[i].Right = false;
566 Info->Entries[i].Center = false;
567 Info->Entries[i].Large = false;
568 Info->Entries[i].Small = false;
569 Info->Entries[i].Bold = false;
570 Info->Entries[i].Italic = false;
571 Info->Entries[i].Underlined = false;
572 Info->Entries[i].Strikethrough = false;
574 Info->Entries[i].Protected = false;
576 Info->Unknown = false;
579 /* ----------------- Joining SMS from parts -------------------------------- */
581 bool GSM_DecodeMultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
582 GSM_MultiSMSMessage *SMS,
583 bool ems)
585 int i, Length = 0;
586 char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
587 bool emsexist = false;
589 Info->EntriesNum = 0;
590 if (ems) {
591 emsexist = true;
592 for (i=0;i<SMS->Number;i++) {
593 if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages &&
594 SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit &&
595 SMS->SMS[i].UDH.Type != UDH_UserUDH) {
596 emsexist = false;
597 break;
602 /* EMS decoding */
603 if (emsexist) return GSM_DecodeEMSMultiPartSMS(Info,SMS);
605 /* Smart Messaging decoding */
606 if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) {
607 if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==GE_NONE) {
608 Info->Entries[0].ID = SMS_NokiaRingtone;
609 Info->EntriesNum = 1;
610 return true;
613 if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) {
614 PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]);
615 #ifdef DEBUG
616 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
617 #endif
618 Info->Entries[0].ID = SMS_NokiaCallerLogo;
619 Info->EntriesNum = 1;
620 return true;
622 if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) {
623 PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]);
624 NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
625 #ifdef DEBUG
626 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
627 #endif
628 Info->Entries[0].ID = SMS_NokiaOperatorLogo;
629 Info->EntriesNum = 1;
630 return true;
632 if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) {
633 for (i=0;i<SMS->Number;i++) {
634 if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong ||
635 SMS->SMS[i].UDH.Text[11] != i+1 ||
636 SMS->SMS[i].UDH.Text[10] != SMS->Number) {
637 return false;
639 memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
640 Length = Length + SMS->SMS[i].Length;
642 Info->EntriesNum = 1;
643 Info->Entries[0].ID = SMS_NokiaPictureImageLong;
644 Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0;
645 Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0;
646 i=1;
647 while (i!=Length) {
648 switch (Buffer[i]) {
649 case SM30_ISOTEXT:
650 dbgprintf("ISO 8859-2 text\n");
651 Info->Unknown = true;
652 break;
653 case SM30_UNICODETEXT:
654 dbgprintf("Unicode text\n");
655 memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]);
656 Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0;
657 Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0;
658 dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
659 break;
660 case SM30_OTA:
661 dbgprintf("OTA bitmap as Picture Image\n");
662 PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]);
663 #ifdef DEBUG
664 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
665 #endif
666 break;
667 case SM30_RINGTONE:
668 dbgprintf("RTTL ringtone\n");
669 Info->Unknown = true;
670 break;
671 case SM30_PROFILENAME:
672 dbgprintf("Profile Name\n");
673 Info->Entries[0].ID = SMS_NokiaProfileLong;
674 Info->Unknown = true;
675 break;
676 case SM30_SCREENSAVER:
677 dbgprintf("OTA bitmap as Screen Saver\n");
678 PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]);
679 #ifdef DEBUG
680 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
681 #endif
682 Info->Entries[0].ID = SMS_NokiaScreenSaverLong;
683 break;
685 i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
686 dbgprintf("%i %i\n",i,Length);
688 return true;
691 /* Linked sms */
692 if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages ||
693 SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
694 Info->EntriesNum = 1;
695 Info->Entries[0].ID = SMS_ConcatenatedTextLong;
696 if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
697 Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit;
700 for (i=0;i<SMS->Number;i++) {
701 switch (SMS->SMS[i].Coding) {
702 case GSM_Coding_8bit:
703 memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
704 Length=Length+SMS->SMS[i].Length;
705 break;
706 case GSM_Coding_Unicode:
707 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) {
708 Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong;
710 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) {
711 Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit;
713 case GSM_Coding_Default:
714 memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2);
715 Length=Length+UnicodeLength(SMS->SMS[i].Text)*2;
716 break;
719 Info->Entries[0].Buffer[Length] = 0;
720 Info->Entries[0].Buffer[Length+1] = 0;
721 return true;
724 return false;
727 GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage *INPUT[150], GSM_MultiSMSMessage *OUTPUT[150], bool ems)
729 bool INPUTSorted[150],copyit;
730 int i,OUTPUTNum,j,z,w;
732 for (i=0;i<150;i++) INPUTSorted[i] = false;
734 OUTPUTNum = 0;
735 OUTPUT[0] = NULL;
737 if (ems) {
738 i=0;
739 while (INPUT[i] != NULL) {
740 if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) {
741 w=1;
742 while (1) {
743 if (w >= INPUT[i]->SMS[0].UDH.Length) break;
744 switch(INPUT[i]->SMS[0].UDH.Text[w]) {
745 case 0x00:
746 dbgprintf("Adding ID to user UDH - linked SMS with 8 bit ID\n");
747 INPUT[i]->SMS[0].UDH.ID8bit = INPUT[i]->SMS[0].UDH.Text[w+2];
748 INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+3];
749 INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+4];
750 break;
751 case 0x08:
752 dbgprintf("Adding ID to user UDH - linked SMS with 16 bit ID\n");
753 INPUT[i]->SMS[0].UDH.ID16bit = INPUT[i]->SMS[0].UDH.Text[w+2]*256+INPUT[i]->SMS[0].UDH.Text[w+3];
754 INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+4];
755 INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+5];
756 break;
757 default:
758 dbgprintf("Block %02x\n",INPUT[i]->SMS[0].UDH.Text[w]);
760 dbgprintf("%i %i %i %i\n",
761 INPUT[i]->SMS[0].UDH.ID8bit,
762 INPUT[i]->SMS[0].UDH.ID16bit,
763 INPUT[i]->SMS[0].UDH.PartNumber,
764 INPUT[i]->SMS[0].UDH.AllParts);
765 w=w+INPUT[i]->SMS[0].UDH.Text[w+1]+2;
768 i++;
772 i=0;
773 while (INPUT[i]!=NULL) {
774 /* If this one SMS was sorted earlier, do not touch */
775 if (INPUTSorted[i]) {
776 i++;
777 continue;
779 copyit = false;
780 /* If we have:
781 * - linked sms returned by phone driver
782 * - sms without linking
783 * we copy it to OUTPUT
785 if (INPUT[i]->Number != 1 ||
786 INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH ||
787 INPUT[i]->SMS[0].UDH.PartNumber == -1) {
788 copyit = true;
790 /* If we have unknown UDH, we copy it to OUTPUT */
791 if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) {
792 if (!ems) copyit = true;
793 if (ems && INPUT[i]->SMS[0].UDH.PartNumber == -1) copyit = true;
795 if (copyit) {
796 OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage));
797 if (OUTPUT[OUTPUTNum] == NULL) return GE_MOREMEMORY;
798 OUTPUT[OUTPUTNum+1] = NULL;
800 memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage));
801 INPUTSorted[i]=true;
802 OUTPUTNum++;
803 i = 0;
804 continue;
806 /* We have 1'st part of linked sms. It's single.
807 * We will try to find other parts
809 if (INPUT[i]->SMS[0].UDH.PartNumber == 1) {
810 OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage));
811 if (OUTPUT[OUTPUTNum] == NULL) return GE_MOREMEMORY;
812 OUTPUT[OUTPUTNum+1] = NULL;
814 memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage));
815 OUTPUT[OUTPUTNum]->Number = 1;
816 INPUTSorted[i] = true;
817 j = 1;
818 /* We're searching for other parts in sequence */
819 while (j!=INPUT[i]->SMS[0].UDH.AllParts) {
820 z=0;
821 while(INPUT[z]!=NULL) {
822 /* This was sorted earlier or is not single */
823 if (INPUTSorted[z] || INPUT[z]->Number != 1) {
824 z++;
825 continue;
827 if (ems && INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages &&
828 INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit &&
829 INPUT[i]->SMS[0].UDH.Type != UDH_UserUDH &&
830 INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages &&
831 INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit &&
832 INPUT[z]->SMS[0].UDH.Type != UDH_UserUDH) {
833 if (INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) {
834 z++;
835 continue;
838 if (!ems && INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) {
839 z++;
840 continue;
842 dbgprintf("compare %i %i %i %i %i",
843 j+1,
844 INPUT[i]->SMS[0].UDH.ID8bit,
845 INPUT[i]->SMS[0].UDH.ID16bit,
846 INPUT[i]->SMS[0].UDH.PartNumber,
847 INPUT[i]->SMS[0].UDH.AllParts);
848 dbgprintf(" %i %i %i %i\n",
849 INPUT[z]->SMS[0].UDH.ID8bit,
850 INPUT[z]->SMS[0].UDH.ID16bit,
851 INPUT[z]->SMS[0].UDH.PartNumber,
852 INPUT[z]->SMS[0].UDH.AllParts);
853 if (INPUT[z]->SMS[0].UDH.ID8bit != INPUT[i]->SMS[0].UDH.ID8bit ||
854 INPUT[z]->SMS[0].UDH.ID16bit != INPUT[i]->SMS[0].UDH.ID16bit ||
855 INPUT[z]->SMS[0].UDH.AllParts != INPUT[i]->SMS[0].UDH.AllParts ||
856 INPUT[z]->SMS[0].UDH.PartNumber != j+1) {
857 z++;
858 continue;
860 /* For SMS_Deliver compare also SMSC and Sender number */
861 if (INPUT[z]->SMS[0].PDU == SMS_Deliver &&
862 (strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) ||
863 strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number)))) {
864 z++;
865 continue;
867 /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */
868 if (INPUT[z]->SMS[0].PDU == SMS_Deliver &&
869 UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)==0 &&
870 UnicodeLength(INPUT[z]->SMS[0].Number)==0 &&
871 (INPUT[z]->SMS[0].DateTime.Day != INPUT[i]->SMS[0].DateTime.Day ||
872 INPUT[z]->SMS[0].DateTime.Month != INPUT[i]->SMS[0].DateTime.Month ||
873 INPUT[z]->SMS[0].DateTime.Year != INPUT[i]->SMS[0].DateTime.Year ||
874 INPUT[z]->SMS[0].DateTime.Hour != INPUT[i]->SMS[0].DateTime.Hour ||
875 INPUT[z]->SMS[0].DateTime.Minute != INPUT[i]->SMS[0].DateTime.Minute ||
876 INPUT[z]->SMS[0].DateTime.Second != INPUT[i]->SMS[0].DateTime.Second)) {
877 z++;
878 continue;
880 /* We found correct sms. Copy it */
881 memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage));
882 OUTPUT[OUTPUTNum]->Number++;
883 INPUTSorted[z]=true;
884 break;
886 /* Incomplete sequence */
887 if (OUTPUT[OUTPUTNum]->Number==j) {
888 dbgprintf("Incomplete sequence\n");
889 break;
891 j++;
893 OUTPUTNum++;
894 i = 0;
895 continue;
897 /* We have some next linked sms from sequence */
898 if (INPUT[i]->SMS[0].UDH.PartNumber > 1) {
899 j = 0;
900 while (INPUT[j]!=NULL) {
901 if (INPUTSorted[j]) {
902 j++;
903 continue;
905 /* We have some not unassigned first sms from sequence.
906 * We can't touch other sms from sequences
908 if (INPUT[j]->SMS[0].UDH.PartNumber == 1) break;
909 j++;
911 if (INPUT[j]==NULL) {
912 OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage));
913 if (OUTPUT[OUTPUTNum] == NULL) return GE_MOREMEMORY;
914 OUTPUT[OUTPUTNum+1] = NULL;
916 memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage));
917 INPUTSorted[i]=true;
918 OUTPUTNum++;
919 i = 0;
920 continue;
921 } else i++;
924 return GE_NONE;
927 /* How should editor hadle tabs in this file? Add editor commands here.
928 * vim: noexpandtab sw=8 ts=8 sts=8: