Imported gammu 0.90.0
[gammu.git] / common / service / gsmsms.c
blob3e23795363f6a54df19b924133671ee1f40793d9
2 #include <ctype.h>
3 #include <string.h>
4 #include <time.h>
6 #include "../gsmcomon.h"
7 #include "../misc/coding/coding.h"
8 #include "gsmsms.h"
9 #include "gsmcal.h"
10 #include "gsmpbk.h"
11 #include "gsmlogo.h"
12 #include "gsmring.h"
13 #include "gsmwap.h"
14 #include "gsmnet.h"
16 /* User data headers */
17 static GSM_UDHHeader UDHHeaders[] = {
18 /* See GSM 03.40 section 9.2.3.24.1
19 * 1 byte 0x00
20 * 1 byte 0x03
21 * 1 byte 0x01: unique ID for message series
22 * 1 byte 0x00: how many SMS in sequence
23 * 1 byte 0x00: number of current SMS in sequence */
24 { UDH_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00",2,-1,4,3},
26 /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */
27 { UDH_DisableVoice, 0x04, "\x01\x02\x00\x00",-1,-1,-1,-1},
28 { UDH_DisableFax, 0x04, "\x01\x02\x01\x00",-1,-1,-1,-1},
29 { UDH_DisableEmail, 0x04, "\x01\x02\x02\x00",-1,-1,-1,-1},
30 { UDH_EnableVoice, 0x04, "\x01\x02\x00\x01",-1,-1,-1,-1},
31 { UDH_EnableFax, 0x04, "\x01\x02\x01\x01",-1,-1,-1,-1},
32 { UDH_EnableEmail, 0x04, "\x01\x02\x02\x01",-1,-1,-1,-1},
34 /* When send such SMS to some phones, they don't display anything,
35 * only beep and enable vibra/light
37 { UDH_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00",-1,-1,-1,-1},
39 /* Nokia Smart Messaging (short version) UDH
40 * General format :
41 * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address
42 * 1 byte 0x04 : IEI length
43 * 2 bytes : destination address : high & low byte
44 * 2 bytes 0x00 0x00 : originator address : high & low byte */
45 { UDH_NokiaRingtone, 0x06, "\x05\x04\x15\x81\x00\x00",-1,-1,-1,-1},
46 { UDH_NokiaOperatorLogo, 0x06, "\x05\x04\x15\x82\x00\x00",-1,-1,-1,-1},
47 { UDH_NokiaCallerLogo, 0x06, "\x05\x04\x15\x83\x00\x00",-1,-1,-1,-1},
48 { UDH_NokiaWAP, 0x06, "\x05\x04\xc3\x4f\x00\x00",-1,-1,-1,-1},
50 /* Nokia Smart Messaging (long version) UDH and other
51 * General format:
52 * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address
53 * 1 byte 0x04 : IEI length
54 * 2 bytes 0x00 0x00 : destination address : high & low byte
55 * 2 bytes 0x00 0x00 : originator address : high & low byte
56 * 1 byte 0x00 : SAR
57 * 1 byte 0x03 : SAR length
58 * 1 byte : diagram reference number (unique ID for message series)
59 * 1 byte : number of all SMS
60 * 1 byte : number of current SMS */
61 { UDH_NokiaCalendarLong, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00",8,-1,10,9},
62 { UDH_MMSIndicatorLong, 0x0b, "\x05\x04\x0b\x84\x23\xf0\x00\x03\xe5\x00\x00",8,-1,10,9},
63 { UDH_NokiaRingtoneLong, 0x0b, "\x05\x04\x15\x81\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9},
64 { UDH_NokiaOperatorLogoLong, 0x0b, "\x05\x04\x15\x82\x00\x00\x00\x03\x02\x00\x00",8,-1,10,9},
65 { UDH_NokiaProfileLong, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00",8,-1,10,9},
66 { UDH_NokiaPhonebookLong, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9},
67 { UDH_NokiaWAPLong, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00",8,-1,10,9},
69 { UDH_ConcatenatedMessages16bit,0x06, "\x08\x04\x00\x00\x00\x00",-1,2,5,4},
71 { UDH_NoUDH, 0x00, "",-1,-1,-1,-1}
74 /* --------------------------- Unpacking SMS ------------------------------- */
76 /* See GSM 03.40 section 9.2.3.11 */
77 static GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req)
79 DT->Year = DecodeWithBCDAlphabet(req[0]);
80 if (DT->Year<90) DT->Year=DT->Year+2000; else DT->Year=DT->Year+1990;
81 DT->Month = DecodeWithBCDAlphabet(req[1]);
82 DT->Day = DecodeWithBCDAlphabet(req[2]);
83 DT->Hour = DecodeWithBCDAlphabet(req[3]);
84 DT->Minute = DecodeWithBCDAlphabet(req[4]);
85 DT->Second = DecodeWithBCDAlphabet(req[5]);
87 /* The timezone is given in quarters. The base is GMT. */
88 DT->Timezone=(10*(req[6]&0x07)+(req[6]>>4))/4;
90 if (req[6]&0x08) DT->Timezone = -DT->Timezone;
92 dbgprintf("Decoding date & time: ");
93 dbgprintf("%s %4d/%02d/%02d ", DayOfWeek(DT->Year, DT->Month, DT->Day),
94 DT->Year, DT->Month, DT->Day);
95 dbgprintf("%02d:%02d:%02d %02d00\n", DT->Hour, DT->Minute, DT->Second, DT->Timezone);
97 return GE_NONE;
100 void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH)
102 int i, tmp, w;
103 bool UDHOK;
105 UDH->Type = UDH_UserUDH;
106 UDH->ID8bit = -1;
107 UDH->ID16bit = -1;
108 UDH->PartNumber = -1;
109 UDH->AllParts = -1;
111 i=-1;
112 while (true) {
113 i++;
114 if (UDHHeaders[i].Type==UDH_NoUDH) break;
116 tmp=UDHHeaders[i].Length;
117 /* if length is the same */
118 if (tmp==UDH->Text[0]) {
120 if (tmp==0x05) tmp=tmp-3;/*three last bytes can be different for such UDH*/
121 if (tmp==0x0b) tmp=tmp-3;/*three last bytes can be different for such UDH*/
122 if (tmp==0x06 && UDH->Text[1] == 0x08) tmp=tmp-4;
124 UDHOK=true;
125 for (w=0;w<tmp;w++) {
126 if (UDHHeaders[i].Text[w]!=UDH->Text[w+1]) {
127 UDHOK=false;
128 break;
131 if (UDHOK) {
132 UDH->Type=UDHHeaders[i].Type;
134 if (UDHHeaders[i].ID8bit !=-1) UDH->ID8bit = UDH->Text[UDHHeaders[i].ID8bit+1];
135 if (UDHHeaders[i].ID16bit !=-1) UDH->ID16bit = UDH->Text[UDHHeaders[i].ID16bit+1]*256+UDH->Text[UDHHeaders[i].ID16bit+2];
136 if (UDHHeaders[i].PartNumber !=-1) UDH->PartNumber = UDH->Text[UDHHeaders[i].PartNumber+1];
137 if (UDHHeaders[i].AllParts !=-1) UDH->AllParts = UDH->Text[UDHHeaders[i].AllParts+1];
138 break;
143 #ifdef DEBUG
144 dbgprintf("Type of UDH: ");
145 switch (UDH->Type) {
146 case UDH_ConcatenatedMessages : dbgprintf("Concatenated (linked) message"); break;
147 case UDH_ConcatenatedMessages16bit : dbgprintf("Concatenated (linked) message"); break;
148 case UDH_DisableVoice : dbgprintf("Disables voice indicator"); break;
149 case UDH_EnableVoice : dbgprintf("Enables voice indicator"); break;
150 case UDH_DisableFax : dbgprintf("Disables fax indicator"); break;
151 case UDH_EnableFax : dbgprintf("Enables fax indicator"); break;
152 case UDH_DisableEmail : dbgprintf("Disables email indicator"); break;
153 case UDH_EnableEmail : dbgprintf("Enables email indicator"); break;
154 case UDH_VoidSMS : dbgprintf("Void SMS"); break;
155 case UDH_NokiaWAP : dbgprintf("Nokia WAP Bookmark"); break;
156 case UDH_NokiaOperatorLogoLong : dbgprintf("Nokia operator logo"); break;
157 case UDH_NokiaWAPLong : dbgprintf("Nokia WAP Bookmark or WAP/MMS Settings"); break;
158 case UDH_NokiaRingtone : dbgprintf("Nokia ringtone"); break;
159 case UDH_NokiaRingtoneLong : dbgprintf("Nokia ringtone"); break;
160 case UDH_NokiaOperatorLogo : dbgprintf("Nokia GSM operator logo"); break;
161 case UDH_NokiaCallerLogo : dbgprintf("Nokia caller logo"); break;
162 case UDH_NokiaProfileLong : dbgprintf("Nokia profile"); break;
163 case UDH_NokiaCalendarLong : dbgprintf("Nokia calendar note"); break;
164 case UDH_NokiaPhonebookLong : dbgprintf("Nokia phonebook entry"); break;
165 case UDH_UserUDH : dbgprintf("User UDH"); break;
166 case UDH_MMSIndicatorLong : dbgprintf("MMS indicator"); break;
167 case UDH_NoUDH: break;
169 if (UDH->ID8bit != -1) dbgprintf(", ID 8 bit %i",UDH->ID8bit);
170 if (UDH->ID16bit != -1) dbgprintf(", ID 16 bit %i",UDH->ID16bit);
171 if (UDH->PartNumber != -1 && UDH->AllParts != -1) {
172 dbgprintf(", part %i of %i",UDH->PartNumber,UDH->AllParts);
174 dbgprintf("\n");
175 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, UDH->Text, UDH->Length);
176 #endif
179 GSM_Error GSM_DecodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
181 int off=0; /* off - length of the user data header */
182 int w,i,tmp=0;
183 unsigned char output[161];
185 SMS->UDH.Length = 0;
186 /* UDH header available */
187 if (buffer[Layout.firstbyte] & 64) {
188 /* Length of UDH header */
189 off = (buffer[Layout.Text] + 1);
190 SMS->UDH.Length = off;
191 dbgprintf("UDH header available (length %i)\n",off);
193 /* Copy UDH header into SMS->UDH */
194 for (i = 0; i < off; i++) SMS->UDH.Text[i] = buffer[Layout.Text + i];
196 GSM_DecodeUDHHeader(&SMS->UDH);
199 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
200 if ((buffer[Layout.TPDCS] & 0xf4) == 0xf4) SMS->Coding=GSM_Coding_8bit;
201 if ((buffer[Layout.TPDCS] & 0x08) == 0x08) SMS->Coding=GSM_Coding_Unicode;
203 switch (SMS->Coding) {
204 case GSM_Coding_Default:
205 i = 0;
206 do {
207 i+=7;
208 w=(i-off)%i;
209 } while (w<0);
210 SMS->Length=buffer[Layout.TPUDL] - (off*8 + w) / 7;
211 tmp=GSM_UnpackEightBitsToSeven(w, buffer[Layout.TPUDL]-off, SMS->Length, buffer+(Layout.Text+off), output);
212 dbgprintf("7 bit SMS, length %i\n",SMS->Length);
213 DecodeDefault (SMS->Text, output, SMS->Length, true, NULL);
214 dbgprintf("%s\n",DecodeUnicodeString(SMS->Text));
215 break;
216 case GSM_Coding_8bit:
217 SMS->Length=buffer[Layout.TPUDL] - off;
218 memcpy(SMS->Text,buffer+(Layout.Text+off),SMS->Length);
219 #ifdef DEBUG
220 dbgprintf("8 bit SMS, length %i\n",SMS->Length);
221 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, SMS->Text, SMS->Length);
222 #endif
223 break;
224 case GSM_Coding_Unicode:
225 SMS->Length=(buffer[Layout.TPUDL] - off) / 2;
226 DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(Layout.Text+off), SMS->Length);
227 #ifdef DEBUG
228 dbgprintf("Unicode SMS, length %i\n",SMS->Length);
229 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df,buffer+(Layout.Text+off), SMS->Length*2);
230 dbgprintf("%s\n",DecodeUnicodeString(SMS->Text));
231 #endif
232 break;
235 return GE_NONE;
238 GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
240 SMS->DeliveryStatus = buffer[Layout.TPStatus];
242 if (buffer[Layout.TPStatus] < 0x03) {
243 EncodeUnicode(SMS->Text,"Delivered",9);
244 SMS->Length = 9;
245 } else if (buffer[Layout.TPStatus] & 0x40) {
246 EncodeUnicode(SMS->Text,"Failed",6);
247 SMS->Length = 6;
248 } else if (buffer[Layout.TPStatus] & 0x20) {
249 EncodeUnicode(SMS->Text,"Pending",7);
250 SMS->Length = 7;
251 } else {
252 EncodeUnicode(SMS->Text,"Unknown",7);
253 SMS->Length = 7;
256 #ifdef DEBUG
257 /* See GSM 03.40 section 9.2.3.15 (TP-Status) */
258 if (buffer[Layout.TPStatus] & 0x40) {
259 if (buffer[Layout.TPStatus] & 0x20) {
260 /* 0x60, 0x61, ... */
261 dbgprintf("Temporary error, SC is not making any more transfer attempts\n");
262 } else {
263 /* 0x40, 0x41, ... */
264 dbgprintf("Permanent error, SC is not making any more transfer attempts\n");
266 } else if (buffer[Layout.TPStatus] & 0x20) {
267 /* 0x20, 0x21, ... */
268 dbgprintf("Temporary error, SC still trying to transfer SM\n");
270 switch (buffer[Layout.TPStatus]) {
271 case 0x00: dbgprintf("SM received by the SME"); break;
272 case 0x01: dbgprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");break;
273 case 0x02: dbgprintf("SM replaced by the SC"); break;
274 case 0x20: dbgprintf("Congestion"); break;
275 case 0x21: dbgprintf("SME busy"); break;
276 case 0x22: dbgprintf("No response from SME"); break;
277 case 0x23: dbgprintf("Service rejected"); break;
278 case 0x24: dbgprintf("Quality of service not aviable"); break;
279 case 0x25: dbgprintf("Error in SME"); break;
280 case 0x40: dbgprintf("Remote procedure error"); break;
281 case 0x41: dbgprintf("Incompatibile destination"); break;
282 case 0x42: dbgprintf("Connection rejected by SME"); break;
283 case 0x43: dbgprintf("Not obtainable"); break;
284 case 0x44: dbgprintf("Quality of service not available"); break;
285 case 0x45: dbgprintf("No internetworking available"); break;
286 case 0x46: dbgprintf("SM Validity Period Expired"); break;
287 case 0x47: dbgprintf("SM deleted by originating SME"); break;
288 case 0x48: dbgprintf("SM Deleted by SC Administration"); break;
289 case 0x49: dbgprintf("SM does not exist"); break;
290 case 0x60: dbgprintf("Congestion"); break;
291 case 0x61: dbgprintf("SME busy"); break;
292 case 0x62: dbgprintf("No response from SME"); break;
293 case 0x63: dbgprintf("Service rejected"); break;
294 case 0x64: dbgprintf("Quality of service not available"); break;
295 case 0x65: dbgprintf("Error in SME"); break;
296 default : dbgprintf("Reserved/Specific to SC: %x",buffer[Layout.TPStatus]); break;
298 dbgprintf("\n");
299 #endif /* DEBUG */
301 return GE_NONE;
304 GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
306 #ifdef DEBUG
307 if (Layout.firstbyte == 255) {
308 dbgprintf("ERROR: firstbyte in SMS layout not set\n");
309 return GE_UNKNOWN;
311 if (Layout.TPDCS != 255) dbgprintf("TPDCS : %02x %i\n",buffer[Layout.TPDCS] ,buffer[Layout.TPDCS]);
312 if (Layout.TPMR != 255) dbgprintf("TPMR : %02x %i\n",buffer[Layout.TPMR] ,buffer[Layout.TPMR]);
313 if (Layout.TPPID != 255) dbgprintf("TPPID : %02x %i\n",buffer[Layout.TPPID] ,buffer[Layout.TPPID]);
314 if (Layout.TPUDL != 255) dbgprintf("TPUDL : %02x %i\n",buffer[Layout.TPUDL] ,buffer[Layout.TPUDL]);
315 if (Layout.firstbyte != 255) dbgprintf("FirstByte : %02x %i\n",buffer[Layout.firstbyte],buffer[Layout.firstbyte]);
316 if (Layout.Text != 255) dbgprintf("Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]);
317 #endif
319 SMS->UDH.Type = UDH_NoUDH;
320 SMS->Coding = GSM_Coding_Default;
321 SMS->Length = 0;
322 SMS->SMSC.Number[0] = 0;
323 SMS->SMSC.Number[1] = 0;
324 SMS->Number[0] = 0;
325 SMS->Number[1] = 0;
326 SMS->Name[0] = 0;
327 SMS->Name[1] = 0;
328 SMS->ReplyViaSameSMSC = false;
329 if (Layout.SMSCNumber!=255) {
330 GSM_UnpackSemiOctetNumber(SMS->SMSC.Number,buffer+Layout.SMSCNumber,false);
331 dbgprintf("SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number));
333 if ((buffer[Layout.firstbyte] & 0x80)!=0) SMS->ReplyViaSameSMSC=true;
334 #ifdef DEBUG
335 if (SMS->ReplyViaSameSMSC) dbgprintf("SMS centre set for reply\n");
336 #endif
337 if (Layout.Number!=255) {
338 GSM_UnpackSemiOctetNumber(SMS->Number,buffer+Layout.Number,true);
339 dbgprintf("Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number));
341 if (Layout.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255) {
342 GSM_DecodeSMSFrameText(SMS, buffer, Layout);
344 if (Layout.DateTime != 255) {
345 GSM_DecodeSMSDateTime(&SMS->DateTime,buffer+(Layout.DateTime));
347 if (Layout.SMSCTime != 255 && Layout.TPStatus != 255) {
348 /* See GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */
349 dbgprintf("SMSC response date: ");
350 GSM_DecodeSMSDateTime(&SMS->SMSCTime, buffer+(Layout.SMSCTime));
351 GSM_DecodeSMSFrameStatusReportData(SMS,buffer,Layout);
353 SMS->Class = -1;
354 if (Layout.TPDCS != 255) {
355 if ((buffer[Layout.TPDCS] & 0xF3)==0xF0) SMS->Class = 0;
356 if ((buffer[Layout.TPDCS] & 0xF3)==0xF1) SMS->Class = 1;
357 if ((buffer[Layout.TPDCS] & 0xF3)==0xF2) SMS->Class = 2;
358 if ((buffer[Layout.TPDCS] & 0xF3)==0xF3) SMS->Class = 3;
360 dbgprintf("SMS class: %i\n",SMS->Class);
361 SMS->MessageReference = 0;
362 if (Layout.TPMR != 255) {
363 SMS->MessageReference = buffer[Layout.TPMR];
365 SMS->ReplaceMessage = 0;
366 if (Layout.TPPID != 255) {
367 if (buffer[Layout.TPPID] > 0x40 && buffer[Layout.TPPID] < 0x48) {
368 SMS->ReplaceMessage = buffer[Layout.TPPID] - 0x40;
371 SMS->RejectDuplicates = false;
372 if ((buffer[Layout.firstbyte] & 0x04)==0x04) SMS->RejectDuplicates = true;
374 return GE_NONE;
377 /* ----------------------------- Packing SMS ------------------------------- */
379 /* See GSM 03.40 section 9.2.3.11 */
380 static GSM_Error GSM_EncodeSMSDateTime(GSM_DateTime *DT, unsigned char *req)
382 int Year;
384 dbgprintf("Encoding SMS datetime: %02i/%02i/%04i %02i:%02i:%02i\n",
385 DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second);
387 /* We need to have only two last digits of year */
388 if (DT->Year>1900)
390 if (DT->Year<2000) Year = DT->Year-1900;
391 else Year = DT->Year-2000;
392 } else Year = DT->Year;
394 req[0]=EncodeWithBCDAlphabet(Year);
395 req[1]=EncodeWithBCDAlphabet(DT->Month);
396 req[2]=EncodeWithBCDAlphabet(DT->Day);
397 req[3]=EncodeWithBCDAlphabet(DT->Hour);
398 req[4]=EncodeWithBCDAlphabet(DT->Minute);
399 req[5]=EncodeWithBCDAlphabet(DT->Second);
401 /* FIXME: do it */
402 req[6]=0; /* TimeZone = +-0 */
404 return GE_NONE;
407 static int GSM_EncodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout)
409 int off = 0; /* off - length of the user data header */
410 int size = 0, size2 = 0, w,p;
411 char buff[200];
413 if (SMS->UDH.Type!=UDH_NoUDH) {
414 buffer[Layout.firstbyte] |= 0x40; /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */
415 off = 1 + SMS->UDH.Text[0]; /* off - length of the user data header */
416 memcpy(buffer+Layout.Text, SMS->UDH.Text, off); /* we copy the udh */
417 #ifdef DEBUG
418 dbgprintf("UDH, length %i\n",off);
419 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, SMS->UDH.Text, off);
420 #endif
422 switch (SMS->Coding) {
423 case GSM_Coding_8bit:
424 /* the mask for the 8-bit data */
425 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme)
426 * and GSM 03.38 section 4 */
427 buffer[Layout.TPDCS] |= 0xf4;
428 memcpy(buffer+(Layout.Text+off), SMS->Text, SMS->Length);
429 size2 = size = SMS->Length+off;
430 #ifdef DEBUG
431 dbgprintf("8 bit SMS, length %i\n",SMS->Length);
432 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df,SMS->Text,SMS->Length);
433 #endif
434 break;
435 case GSM_Coding_Default:
436 p = 0;
437 do {
438 p+=7;
439 w=(p-off)%p;
440 } while (w<0);
441 p = UnicodeLength(SMS->Text);
442 EncodeDefault(buff, SMS->Text, &p, true, NULL);
443 size = GSM_PackSevenBitsToEight(w, buff, buffer+(Layout.Text+off), p);
444 size += off;
445 size2 = (off*8 + w) / 7 + p;
446 dbgprintf("7 bit SMS, length %i, %i\n",size,size2);
447 dbgprintf("%s\n",DecodeUnicodeString(SMS->Text));
448 if (size > GSM_MAX_8BIT_SMS_LENGTH) {
449 size = 0; size2 = 0;
451 break;
452 case GSM_Coding_Unicode:
453 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme)
454 * and GSM 03.38 section 4 */
455 buffer[Layout.TPDCS] |= 0x08;
456 EncodeUnicodeSpecialNOKIAChars(buffer+(Layout.Text+off), SMS->Text, UnicodeLength(SMS->Text));
457 size=size2=UnicodeLength(buffer+(Layout.Text+off))*2+off;
458 #ifdef DEBUG
459 dbgprintf("Unicode SMS, length %i\n",(size2-off)/2);
460 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df,buffer+(Layout.Text+off), size2-off);
461 dbgprintf("%s\n",DecodeUnicodeString(buffer+(Layout.Text+off)));
462 #endif
463 break;
466 /* SMS->Length is:
467 - integer representation of the number od octets within the user data
468 when UD is coded using 8bit data
469 - the sum of the number of septets in UDH including any padding
470 and number of septets in UD in other case */
471 /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length) */
472 buffer[Layout.TPUDL] = size2;
473 return size;
476 GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear)
478 int i;
480 if (clear) {
481 /* Cleaning up to the SMS text */
482 for (i=0;i<Layout.Text;i++) buffer[i] = 0;
485 /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */
486 switch (SMS->PDU) {
487 case SMS_Submit:
488 buffer[Layout.firstbyte] |= 0x01;
489 break;
490 /* SMS_Status_Report when Submit sms should have delivery report */
491 /* We DON'T CREATE FRAME FOR REAL SMS_STATUS_REPORT */
492 case SMS_Status_Report:
493 buffer[Layout.firstbyte] |= 0x01;
494 /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */
495 /* Mask for request for delivery report from SMSC */
496 buffer[Layout.firstbyte] |= 0x20;
497 break;
498 case SMS_Deliver:
499 buffer[Layout.firstbyte] |= 0x00;
502 /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */
503 if (SMS->ReplyViaSameSMSC) buffer[Layout.firstbyte] |= 0x80;
505 if (Layout.Number!=255) {
506 buffer[Layout.Number] = GSM_PackSemiOctetNumber(SMS->Number,buffer+(Layout.Number+1),true);
507 dbgprintf("Recipient number \"%s\"\n",DecodeUnicodeString(SMS->Number));
509 if (Layout.SMSCNumber!=255) {
510 buffer[Layout.SMSCNumber]=GSM_PackSemiOctetNumber(SMS->SMSC.Number,buffer+(Layout.SMSCNumber+1), false);
511 dbgprintf("SMSC number \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number));
514 /* Message Class*/
515 /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */
516 if (Layout.TPDCS != 255) {
517 if (SMS->Class>=0 && SMS->Class<5) buffer[Layout.TPDCS] |= (240+SMS->Class);
520 if (Layout.TPVP != 255) {
521 /* GSM 03.40 section 9.2.3.3 (TP-Validity-Period-Format) */
522 /* Bits 4 and 3: 10. TP-VP field present and integer represent (relative) */
523 buffer[Layout.firstbyte] |= 0x10;
524 buffer[Layout.TPVP]=((unsigned char)SMS->SMSC.Validity.Relative);
525 dbgprintf("SMS validity %02x\n",SMS->SMSC.Validity.Relative);
528 if (Layout.DateTime != 255) {
529 GSM_EncodeSMSDateTime(&SMS->DateTime, buffer+Layout.DateTime);
532 if (Layout.TPMR != 255) {
533 buffer[Layout.TPMR] = SMS->MessageReference;
536 if (SMS->RejectDuplicates) {
537 /* GSM 03.40 section 9.2.3.25 (TP Reject Duplicates) */
538 buffer[Layout.firstbyte] |= 0x04;
541 if (Layout.TPPID != 255) {
542 buffer[Layout.TPPID] = 0;
543 if (SMS->ReplaceMessage > 0 && SMS->ReplaceMessage < 8) {
544 buffer[Layout.TPPID] = 0x40 + SMS->ReplaceMessage;
548 /* size is the length of the data in octets including udh */
549 *length=GSM_EncodeSMSFrameText(SMS,buffer,Layout);
550 // if (*length == 0) return GE_UNKNOWN;
551 *length += Layout.Text;
553 return GE_NONE;
556 /* ----------------- Some help functions ----------------------------------- */
558 void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS)
560 SMS->Class = -1;
561 SMS->SMSC.Location = 1;
562 SMS->SMSC.Validity.VPF = GSM_RelativeFormat;
563 SMS->SMSC.Validity.Relative = GSMV_Max_Time;
564 SMS->ReplyViaSameSMSC = false;
565 SMS->UDH.Type = UDH_NoUDH;
566 SMS->UDH.Length = 0;
567 SMS->UDH.Text[0] = 0;
568 SMS->UDH.ID8bit = 0;
569 SMS->UDH.ID16bit = 0;
570 SMS->UDH.PartNumber = 0;
571 SMS->UDH.AllParts = 0;
572 SMS->Coding = GSM_Coding_Default;
573 SMS->Text[0] = 0;
574 SMS->Text[1] = 0;
575 SMS->PDU = SMS_Submit;
576 SMS->RejectDuplicates = false;
577 SMS->MessageReference = 0;
578 SMS->ReplaceMessage = 0;
579 SMS->Length = 0;
581 /* This part is required to save SMS */
582 SMS->State = GSM_UnSent;
583 SMS->Location = 0;
584 SMS->Folder = 0x02; /*Outbox*/
585 GSM_GetCurrentDateTime (&SMS->DateTime);
586 SMS->Name[0] = 0;
587 SMS->Name[1] = 0;
590 /* This function encodes the UserDataHeader as described in:
591 * - GSM 03.40 version 6.1.0 Release 1997, section 9.2.3.24
592 * - Smart Messaging Specification, Revision 1.0.0, September 15, 1997
594 void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH)
596 int i=0;
598 switch (UDH->Type) {
599 case UDH_NoUDH:
600 UDH->Length = 0;
601 break;
602 case UDH_UserUDH:
603 UDH->Length = UDH->Text[0] + 1;
604 break;
605 default:
606 while (true) {
607 if (UDHHeaders[i].Type==UDH_NoUDH)
609 dbgprintf("Not supported UDH type\n");
610 break;
612 if (UDHHeaders[i].Type==UDH->Type)
614 /* UDH Length */
615 UDH->Text[0] = UDHHeaders[i].Length;
616 memcpy(UDH->Text+1, UDHHeaders[i].Text, UDHHeaders[i].Length);
617 UDH->Length = UDH->Text[0] + 1;
619 if (UDHHeaders[i].ID8bit != -1) {
620 UDH->Text[UDHHeaders[i].ID8bit+1] = UDH->ID8bit % 256;
621 } else {
622 UDH->ID8bit = -1;
624 if (UDHHeaders[i].ID16bit != -1) {
625 UDH->Text[UDHHeaders[i].ID16bit+1] = UDH->ID16bit / 256;
626 UDH->Text[UDHHeaders[i].ID16bit+2] = UDH->ID16bit % 256;
627 } else {
628 UDH->ID16bit = -1;
630 if (UDHHeaders[i].PartNumber != -1) {
631 UDH->Text[UDHHeaders[i].PartNumber+1] = UDH->PartNumber;
632 } else {
633 UDH->PartNumber = -1;
635 if (UDHHeaders[i].AllParts != -1) {
636 UDH->Text[UDHHeaders[i].AllParts+1] = UDH->AllParts;
637 } else {
638 UDH->AllParts = -1;
640 break;
642 i++;
647 /* ----------------- Splitting SMS into parts ------------------------------ */
649 static unsigned char GSM_MakeSMSIDFromTime()
651 GSM_DateTime Date;
652 unsigned char retval;
654 GSM_GetCurrentDateTime (&Date);
655 retval = Date.Second;
656 switch (Date.Minute/10) {
657 case 2: case 7: retval = retval + 60; break;
658 case 4: case 8: retval = retval + 120; break;
659 case 9: case 5: case 0: retval = retval + 180; break;
661 retval += Date.Minute/10;
662 return retval;
665 static void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes)
667 int UsedBytes;
669 switch (Coding) {
670 case GSM_Coding_Default:
671 FindDefaultAlphabetLen(SMS.Text,&UsedBytes,UsedText,500);
672 UsedBytes = *UsedText * 7 / 8;
673 if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++;
674 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
675 *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length) * 8 / 7 - *UsedText;
676 break;
677 case GSM_Coding_Unicode:
678 *UsedText = UnicodeLength(SMS.Text);
679 UsedBytes = *UsedText * 2;
680 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
681 *FreeText = *FreeBytes / 2;
682 break;
683 case GSM_Coding_8bit:
684 *UsedText = UsedBytes = SMS.Length;
685 *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes;
686 *FreeText = *FreeBytes;
687 break;
689 dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes);
692 GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS,
693 GSM_Coding_Type Coding,
694 char *Buffer,
695 int BufferLen,
696 bool UDH,
697 int *UsedText,
698 int *CopiedText,
699 int *CopiedSMSText)
701 int FreeText,FreeBytes,Copy,i,j;
703 dbgprintf("Checking used\n");
704 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
706 if (UDH) {
707 dbgprintf("Adding UDH\n");
708 if (FreeBytes - BufferLen <= 0) {
709 dbgprintf("Going to the new SMS\n");
710 SMS->Number++;
711 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
713 if (SMS->SMS[SMS->Number].UDH.Length == 0) {
714 SMS->SMS[SMS->Number].UDH.Length = 1;
715 SMS->SMS[SMS->Number].UDH.Text[0] = 0x00;
717 memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen);
718 SMS->SMS[SMS->Number].UDH.Length += BufferLen;
719 SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen;
720 SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH;
721 dbgprintf("UDH added %i\n",BufferLen);
722 } else {
723 dbgprintf("Adding text\n");
724 if (FreeText == 0) {
725 dbgprintf("Going to the new SMS\n");
726 SMS->Number++;
727 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
730 Copy = FreeText;
731 dbgprintf("copy %i\n",Copy);
732 if (BufferLen < Copy) Copy = BufferLen;
733 dbgprintf("copy %i\n",Copy);
735 switch (Coding) {
736 case GSM_Coding_Default:
737 FindDefaultAlphabetLen(Buffer,&i,&j,FreeText);
738 dbgprintf("def length %i %i\n",i,j);
739 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0;
740 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0;
741 memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2);
742 *CopiedText = i;
743 *CopiedSMSText = j;
744 SMS->SMS[SMS->Number].Length += i;
745 break;
746 case GSM_Coding_Unicode:
747 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0;
748 SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0;
749 memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2);
750 *CopiedText = *CopiedSMSText = Copy;
751 SMS->SMS[SMS->Number].Length += Copy;
752 break;
753 case GSM_Coding_8bit:
754 memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy);
755 SMS->SMS[SMS->Number].Length += Copy;
756 *CopiedText = *CopiedSMSText = Copy;
757 break;
759 dbgprintf("Text added\n");
762 dbgprintf("Checking on the end\n");
763 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes);
765 return GE_NONE;
768 void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS,
769 unsigned char *MessageBuffer,
770 int MessageLength,
771 GSM_UDH UDHType,
772 GSM_Coding_Type Coding,
773 int Class,
774 unsigned char ReplaceMessage)
776 int j,Len,UsedText,CopiedText,CopiedSMSText;
777 unsigned char UDHID;
778 GSM_DateTime Date;
780 Len = 0;
781 while(1) {
782 GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]);
783 SMS->SMS[SMS->Number].Class = Class;
784 SMS->SMS[SMS->Number].Coding = Coding;
786 SMS->SMS[SMS->Number].UDH.Type = UDHType;
787 GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH);
789 if (Coding == GSM_Coding_8bit) {
790 GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
791 } else {
792 GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
794 Len += CopiedText;
795 dbgprintf("%i %i\n",Len,MessageLength);
796 if (Len == MessageLength) break;
797 if (SMS->Number == MAX_MULTI_SMS) break;
798 SMS->Number++;
801 SMS->Number++;
803 UDHID = GSM_MakeSMSIDFromTime();
804 GSM_GetCurrentDateTime (&Date);
805 for (j=0;j<SMS->Number;j++)
807 SMS->SMS[j].UDH.Type = UDHType;
808 SMS->SMS[j].UDH.ID8bit = UDHID;
809 SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour;
810 SMS->SMS[j].UDH.PartNumber = j+1;
811 SMS->SMS[j].UDH.AllParts = SMS->Number;
812 GSM_EncodeUDHHeader(&SMS->SMS[j].UDH);
814 if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage;
817 /* Calculates number of SMS and number of left chars in SMS */
818 void GSM_SMSCounter(int MessageLength,
819 unsigned char *MessageBuffer,
820 GSM_UDH UDHType,
821 GSM_Coding_Type Coding,
822 int *SMSNum,
823 int *CharsLeft)
825 int UsedText,FreeBytes;
826 GSM_MultiSMSMessage MultiSMS;
828 MultiSMS.Number = 0;
829 GSM_MakeMultiPartSMS(&MultiSMS,MessageBuffer,MessageLength,UDHType,Coding,-1,false);
830 GSM_Find_Free_Used_SMS2(Coding,MultiSMS.SMS[MultiSMS.Number-1], &UsedText, CharsLeft, &FreeBytes);
831 *SMSNum = MultiSMS.Number;
834 /* Nokia Smart Messaging 3.0 */
835 static void GSM_EncodeSMS30MultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
836 char *Buffer, int *Length)
838 int len;
840 /*SM version. Here 3.0*/
841 Buffer[(*Length)++] = 0x30;
843 if (Info->Entries[0].ID == SMS_NokiaProfileLong) {
844 if (Info->Entries[0].Buffer != NULL) {
845 if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) {
846 Buffer[(*Length)++] = SM30_PROFILENAME;
847 Buffer[(*Length)++] = 0x00;
848 Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer);
849 CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer);
850 *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer);
853 if (Info->Entries[0].Ringtone != NULL) {
854 Buffer[(*Length)++] = SM30_RINGTONE;
855 /* Length for this part later will be changed */
856 Buffer[(*Length)++] = 0x01;
857 Buffer[(*Length)++] = 0x00;
858 /* Smart Messaging 3.0 says: 16*9=144 bytes,
859 * but on 3310 4.02 it was possible to save about 196 chars
860 * (without cutting) */
861 len = 196;
862 Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer+(*Length),&len);
863 Buffer[(*Length)-2] = len / 256;
864 Buffer[(*Length)-1] = len % 256;
865 *Length = *Length + len;
868 if (Info->Entries[0].Bitmap != NULL) {
869 if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) {
870 Buffer[(*Length)++] = SM30_OTA;
871 } else {
872 Buffer[(*Length)++] = SM30_SCREENSAVER;
874 Buffer[(*Length)++] = 0x01;
875 Buffer[(*Length)++] = 0x00;
876 NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length);
877 if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) {
878 if (Info->UnicodeCoding) {
879 Buffer[(*Length)++] = SM30_UNICODETEXT;
880 /* Length for text part */
881 Buffer[(*Length)++] = 0x00;
882 Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
883 memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2);
884 *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
885 } else {
886 /*ID for ISO-8859-1 text*/
887 Buffer[(*Length)++] = SM30_ISOTEXT;
888 Buffer[(*Length)++] = 0x00;
889 Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
890 memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text));
891 *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
897 /* EMS Developers' Guidelines from www.sonyericsson.com
898 * docs from Alcatel
900 static GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
901 GSM_MultiSMSMessage *SMS,
902 GSM_UDH UDHType)
904 unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
905 int i,UsedText,j,Length,Width,Height,z,x,y;
906 unsigned int Len;
907 int Used,FreeText,FreeBytes,Width2,CopiedText,CopiedSMSText;
908 unsigned char UDHID;
909 GSM_Bitmap Bitmap,Bitmap2;
910 GSM_Ringtone Ring;
911 GSM_Coding_Type Coding = GSM_Coding_Default;
912 GSM_Phone_Bitmap_Types BitmapType;
913 EncodeMultiPartSMSEntry *Entry;
914 bool start;
915 GSM_DateTime Date;
917 #ifdef DEBUG
918 if (UDHType != UDH_NoUDH) dbgprintf("linked EMS\n");
919 #endif
921 if (Info->UnicodeCoding) Coding = GSM_Coding_Unicode;
923 /* Cleaning on the start */
924 for (i=0;i<MAX_MULTI_SMS;i++) {
925 GSM_SetDefaultSMSData(&SMS->SMS[i]);
926 SMS->SMS[i].UDH.Type = UDHType;
927 GSM_EncodeUDHHeader(&SMS->SMS[i].UDH);
928 SMS->SMS[i].Coding = Coding;
931 /* Packing */
932 for (i=0;i<Info->EntriesNum;i++) {
933 Entry = &Info->Entries[i];
935 switch (Entry->ID) {
936 case SMS_ConcatenatedTextLong:
937 case SMS_ConcatenatedTextLong16bit:
938 Len = 0;
939 while(1) {
940 if (Entry->Left || Entry->Right ||
941 Entry->Center || Entry->Large ||
942 Entry->Small || Entry->Bold ||
943 Entry->Italic || Entry->Underlined ||
944 Entry->Strikethrough) {
945 Buffer[0] = 0x0A; /* ID for text format */
946 Buffer[1] = 0x03; /* length of rest */
947 Buffer[2] = 0x00; /* Position in EMS msg */
948 Buffer[3] = 0x00; /* how many chars */
949 Buffer[4] = 0x00; /* formatting bits */
950 if (Entry->Left) {
951 } else if (Entry->Right) { Buffer[4] |= 1;
952 } else if (Entry->Center) { Buffer[4] |= 2;
953 } else Buffer[4] |= 3;
954 if (Entry->Large) { Buffer[4] |= 4;
955 } else if (Entry->Small) { Buffer[4] |= 8;}
956 if (Entry->Bold) Buffer[4] |= 16;
957 if (Entry->Italic) Buffer[4] |= 32;
958 if (Entry->Underlined) Buffer[4] |= 64;
959 if (Entry->Strikethrough) Buffer[4] |= 128;
960 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5,true,&UsedText,&CopiedText,&CopiedSMSText);
961 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
962 if (FreeText == 0) continue;
964 GSM_AddSMS_Text_UDH(SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,false,&UsedText,&CopiedText,&CopiedSMSText);
965 if (Entry->Left || Entry->Right ||
966 Entry->Center || Entry->Large ||
967 Entry->Small || Entry->Bold ||
968 Entry->Italic || Entry->Underlined ||
969 Entry->Strikethrough) {
970 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText;
971 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText;
973 Len += CopiedText;
974 if (Len == UnicodeLength(Entry->Buffer)) break;
975 dbgprintf("%i %i\n",Len,UnicodeLength(Entry->Buffer));
977 break;
978 case SMS_EMSPredefinedSound:
979 case SMS_EMSPredefinedAnimation:
980 if (Entry->ID == SMS_EMSPredefinedSound) {
981 Buffer[0] = 0x0B; /* ID for def.sound */
982 } else {
983 Buffer[0] = 0x0D; /* ID for def.animation */
985 Buffer[1] = 0x02; /* Length of rest */
986 Buffer[2] = 0x00; /* Position in EMS msg */
987 Buffer[3] = Entry->Number; /* Number of anim. */
988 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
989 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText;
990 break;
991 case SMS_EMSSonyEricssonSound:
992 case SMS_EMSSound10:
993 case SMS_EMSSound12:
994 if (Entry->Protected) {
995 Buffer[0] = 0x17; /* ID for ODI */
996 Buffer[1] = 2; /* Length of rest */
997 Buffer[2] = 1; /* Number of protected objects */
998 Buffer[3] = 1; /* 1=Protected,0=Not protected */
999 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1002 Length = 128; /* 128 bytes is maximal length from specs */
1003 switch (Entry->ID) {
1004 case SMS_EMSSound10:
1005 Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.0, true);
1006 break;
1007 case SMS_EMSSound12:
1008 Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.2, true);
1009 break;
1010 case SMS_EMSSonyEricssonSound:
1011 Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 0, true);
1012 break;
1013 default:
1014 break;
1017 Buffer[0] = 0x0C; /* ID for EMS sound */
1018 Buffer[1] = Length+1; /* Length of rest */
1019 Buffer[2] = 0x00; /* Position in EMS msg */
1020 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
1021 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
1022 break;
1023 case SMS_EMSSonyEricssonSoundLong:
1024 case SMS_EMSSound10Long:
1025 case SMS_EMSSound12Long:
1026 memcpy(&Ring,Entry->Ringtone,sizeof(GSM_Ringtone));
1028 /* First check if we can use classic format */
1029 Length = 128; /* 128 bytes is maximal length from specs */
1030 switch (Entry->ID) {
1031 case SMS_EMSSound10Long:
1032 Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, true);
1033 break;
1034 case SMS_EMSSound12Long:
1035 Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, true);
1036 break;
1037 case SMS_EMSSonyEricssonSoundLong:
1038 Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, true);
1039 break;
1040 default:
1041 break;
1043 if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) {
1044 if (Entry->Protected) {
1045 Buffer[0] = 0x17; /* ID for ODI */
1046 Buffer[1] = 2; /* Length of rest */
1047 Buffer[2] = 1; /* Number of protected objects */
1048 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1049 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1052 Buffer[0] = 0x0C; /* ID for EMS sound */
1053 Buffer[1] = Length+1; /* Length of rest */
1054 Buffer[2] = 0x00; /* Position in EMS msg */
1055 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
1056 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
1057 break;
1060 /* Find free place in first SMS */
1061 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
1062 Length = FreeBytes - 3;
1063 if (Entry->Protected) Length = Length - 4;
1064 if (Length < 0) Length = 128;
1065 if (Length > 128) Length = 128;
1067 memcpy(&Ring,Entry->Ringtone,sizeof(GSM_Ringtone));
1069 /* Checking number of SMS */
1070 Used = 0;
1071 FreeBytes = 0;
1072 start = true;
1073 while (1) {
1074 if (FreeBytes != 0) {
1075 z = 0;
1076 for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
1077 memcpy(&Ring.NoteTone.Commands[z],&Ring.NoteTone.Commands[j],sizeof(GSM_RingCommand));
1078 z++;
1080 Ring.NoteTone.NrCommands -= FreeBytes;
1081 if (Ring.NoteTone.NrCommands == 0) break;
1082 Length = 128; /* 128 bytes is maximal length from specs */
1084 switch (Entry->ID) {
1085 case SMS_EMSSound10Long:
1086 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start);
1087 break;
1088 case SMS_EMSSound12Long:
1089 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start);
1090 break;
1091 case SMS_EMSSonyEricssonSoundLong:
1092 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start);
1093 break;
1094 default:
1095 break;
1097 start = false;
1098 Used++;
1100 dbgprintf("Used SMS: %i\n",Used);
1102 if (Entry->Protected) {
1103 Buffer[0] = 0x17; /* ID for ODI */
1104 Buffer[1] = 2; /* Length of rest */
1105 Buffer[2] = Used+1; /* Number of protected objects */
1106 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1107 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1110 /* Save UPI UDH */
1111 Buffer[0] = 0x13; /* ID for UPI */
1112 Buffer[1] = 1; /* Length of rest */
1113 Buffer[2] = Used; /* Number of used parts */
1114 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText);
1116 /* Find free place in first SMS */
1117 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
1118 Length = FreeBytes - 3;
1119 if (Length < 0) Length = 128;
1120 if (Length > 128) Length = 128;
1122 memcpy(&Ring,Entry->Ringtone,sizeof(GSM_Ringtone));
1124 /* Saving */
1125 FreeBytes = 0;
1126 start = true;
1127 while (1) {
1128 if (FreeBytes != 0) {
1129 z = 0;
1130 for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) {
1131 memcpy(&Ring.NoteTone.Commands[z],&Ring.NoteTone.Commands[j],sizeof(GSM_RingCommand));
1132 z++;
1134 Ring.NoteTone.NrCommands -= FreeBytes;
1135 if (Ring.NoteTone.NrCommands == 0) break;
1136 Length = 128; /* 128 bytes is maximal length from specs */
1138 switch (Entry->ID) {
1139 case SMS_EMSSound10Long:
1140 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start);
1141 break;
1142 case SMS_EMSSound12Long:
1143 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start);
1144 break;
1145 case SMS_EMSSonyEricssonSoundLong:
1146 FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start);
1147 break;
1148 default:
1149 break;
1151 Buffer[0] = 0x0C; /* ID for EMS sound */
1152 Buffer[1] = Length+1; /* Length of rest */
1153 Buffer[2] = 0x00; /* Position in EMS msg */
1154 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText);
1155 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText;
1156 start = false;
1159 Entry->RingtoneNotes = Entry->Ringtone->NoteTone.NrCommands;
1161 break;
1162 case SMS_EMSAnimation:
1163 if (Entry->Protected) {
1164 Buffer[0] = 0x17; /* ID for ODI */
1165 Buffer[1] = 2; /* Length of rest */
1166 Buffer[2] = 1; /* Number of protected objects */
1167 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1168 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1171 if (Entry->Bitmap->Bitmap[0].Width > 8 || Entry->Bitmap->Bitmap[0].Height > 8) {
1172 BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
1173 Buffer[0] = 0x0E; /* ID for 16x16 animation */
1174 } else {
1175 BitmapType = GSM_EMSSmallPicture; /* Bitmap 8x8 */
1176 Buffer[0] = 0x0F; /* ID for 8x8 animation */
1178 Length = PHONE_GetBitmapSize(BitmapType,0,0);
1180 Buffer[1] = Length*Entry->Bitmap->Number + 1; /* Length of rest */
1181 Buffer[2] = 0x00; /* Position in EMS msg */
1182 for (j=0;j<Entry->Bitmap->Number;j++) {
1183 PHONE_EncodeBitmap(BitmapType, Buffer+3+j*Length, &Entry->Bitmap->Bitmap[j]);
1185 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length*Entry->Bitmap->Number,true,&UsedText,&CopiedText,&CopiedSMSText);
1186 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length*Entry->Bitmap->Number] = UsedText;
1187 break;
1188 case SMS_EMSFixedBitmap:
1189 if (Entry->Protected) {
1190 Buffer[0] = 0x17; /* ID for ODI */
1191 Buffer[1] = 2; /* Length of rest */
1192 Buffer[2] = 1; /* Number of protected objects */
1193 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1194 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1197 if (Entry->Bitmap->Bitmap[0].Width > 16 || Entry->Bitmap->Bitmap[0].Height > 16) {
1198 BitmapType = GSM_EMSBigPicture; /* Bitmap 32x32 */
1199 Buffer[0] = 0x10; /* ID for EMS bitmap */
1200 } else {
1201 BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */
1202 Buffer[0] = 0x11; /* ID for EMS bitmap */
1204 Length = PHONE_GetBitmapSize(BitmapType,0,0);
1205 PHONE_GetBitmapWidthHeight(BitmapType, &Width, &Height);
1207 Buffer[1] = Length + 1; /* Length of rest */
1208 Buffer[2] = 0x00; /* Position in EMS msg */
1209 PHONE_EncodeBitmap(BitmapType,Buffer+3, &Entry->Bitmap->Bitmap[0]);
1210 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
1211 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length] = UsedText;
1212 break;
1213 case SMS_EMSVariableBitmapLong:
1214 BitmapType = GSM_EMSVariablePicture;
1215 Width = Entry->Bitmap->Bitmap[0].Width;
1216 Height = Entry->Bitmap->Bitmap[0].Height;
1217 memcpy(&Bitmap,&Entry->Bitmap->Bitmap[0],sizeof(GSM_Bitmap));
1219 /* First check if we can use classical format */
1220 while (1) {
1221 /* Width should be multiply of 8 */
1222 while (Width % 8 != 0) Width--;
1224 /* specs */
1225 if (Width <= 96 && Height <= 128) break;
1227 Height--;
1229 Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
1230 if (Length <= 128) {
1231 if (Entry->Protected) {
1232 Buffer[0] = 0x17; /* ID for ODI */
1233 Buffer[1] = 2; /* Length of rest */
1234 Buffer[2] = 1; /* Number of protected objects */
1235 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1236 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1239 Buffer[0] = 0x12; /* ID for EMS bitmap */
1240 Buffer[1] = Length + 3; /* Length of rest */
1241 Buffer[2] = 0x00; /* Position in EMS msg */
1242 Buffer[3] = Width/8; /* Bitmap width/8 */
1243 Buffer[4] = Height; /* Bitmap height */
1245 GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
1246 #ifdef DEBUG
1247 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
1248 #endif
1249 PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
1250 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
1251 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
1252 break;
1255 /* Find free place in first SMS */
1256 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
1257 Used = 0;
1258 Length = FreeBytes - 3;
1259 if (Entry->Protected) Length = Length - 4;
1260 if (Length < 0) Length = 128;
1261 if (Length > 128) Length = 128;
1263 /* Checking number of SMS */
1264 FreeBytes = 0;
1265 while (FreeBytes != Width) {
1266 Width2 = 8;
1267 while(1) {
1268 if (FreeBytes+Width2 == Width) break;
1270 if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break;
1272 Width2 = Width2 + 8;
1274 FreeBytes = FreeBytes + Width2;
1275 Length = 128;
1276 Used ++;
1278 dbgprintf("Used SMS: %i\n",Used);
1280 if (Entry->Protected) {
1281 Buffer[0] = 0x17; /* ID for ODI */
1282 Buffer[1] = 2; /* Length of rest */
1283 Buffer[2] = Used+1; /* Number of protected objects */
1284 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1285 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1288 /* Save UPI UDH */
1289 Buffer[0] = 0x13; /* ID for UPI */
1290 Buffer[1] = 1; /* Length of rest */
1291 Buffer[2] = Used; /* Number of used parts */
1293 /* Find free place in first SMS */
1294 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText);
1295 GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes);
1296 Length = FreeBytes - 3;
1297 if (Length < 0) Length = 128;
1298 if (Length > 128) Length = 128;
1300 #ifdef DEBUG
1301 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
1302 #endif
1304 /* Saving SMS */
1305 FreeBytes = 0;
1306 while (FreeBytes != Width) {
1307 Width2 = 8;
1308 while(1) {
1309 if (FreeBytes+Width2 == Width) break;
1311 if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break;
1313 Width2 = Width2 + 8;
1316 /* Copying part of bitmap to new structure */
1317 Bitmap2.Width = Width2;
1318 Bitmap2.Height = Height;
1319 GSM_ClearBitmap(&Bitmap2);
1320 for (x=0;x<Width2;x++) {
1321 for (y=0;y<Height;y++) {
1322 if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) {
1323 GSM_SetPointBitmap(&Bitmap2, x, y);
1327 #ifdef DEBUG
1328 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap2);
1329 #endif
1331 /* Adding new bitmap to SMS */
1332 Length = PHONE_GetBitmapSize(BitmapType,Width2,Height);
1333 Buffer[0] = 0x12; /* ID for EMS bitmap */
1334 Buffer[1] = Length + 3; /* Length of rest */
1335 Buffer[2] = 0x00; /* Position in EMS msg */
1336 Buffer[3] = Width2/8; /* Bitmap width/8 */
1337 Buffer[4] = Height; /* Bitmap height */
1338 PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2);
1339 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
1340 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
1342 FreeBytes = FreeBytes + Width2;
1343 Length = 128;
1345 break;
1346 case SMS_EMSVariableBitmap:
1347 if (Entry->Protected) {
1348 Buffer[0] = 0x17; /* ID for ODI */
1349 Buffer[1] = 2; /* Length of rest */
1350 Buffer[2] = 1; /* Number of protected objects */
1351 Buffer[3] = 1; /* 1=Protected,0=Not protected */
1352 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText);
1355 BitmapType = GSM_EMSVariablePicture;
1356 Width = Entry->Bitmap->Bitmap[0].Width;
1357 Height = Entry->Bitmap->Bitmap[0].Height;
1359 while (1) {
1360 /* Width should be multiply of 8 */
1361 while (Width % 8 != 0) Width--;
1363 /* specs */
1364 if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break;
1366 Height--;
1369 Length = PHONE_GetBitmapSize(BitmapType,Width,Height);
1371 Buffer[0] = 0x12; /* ID for EMS bitmap */
1372 Buffer[1] = Length + 3; /* Length of rest */
1373 Buffer[2] = 0x00; /* Position in EMS msg */
1374 Buffer[3] = Width/8; /* Bitmap width/8 */
1375 Buffer[4] = Height; /* Bitmap height */
1377 GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height);
1378 #ifdef DEBUG
1379 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap);
1380 #endif
1381 PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap);
1382 GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText);
1383 SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText;
1384 break;
1385 default:
1386 break;
1390 SMS->Number++;
1392 if (UDHType == UDH_ConcatenatedMessages) {
1393 UDHID = GSM_MakeSMSIDFromTime();
1394 for (i=0;i<SMS->Number;i++) {
1395 SMS->SMS[i].UDH.Text[2+1] = UDHID;
1396 SMS->SMS[i].UDH.Text[3+1] = SMS->Number;
1397 SMS->SMS[i].UDH.Text[4+1] = i+1;
1400 if (UDHType == UDH_ConcatenatedMessages16bit) {
1401 UDHID = GSM_MakeSMSIDFromTime();
1402 GSM_GetCurrentDateTime (&Date);
1403 for (i=0;i<SMS->Number;i++) {
1404 SMS->SMS[i].UDH.Text[2+1] = Date.Hour;
1405 SMS->SMS[i].UDH.Text[3+1] = UDHID;
1406 SMS->SMS[i].UDH.Text[4+1] = SMS->Number;
1407 SMS->SMS[i].UDH.Text[5+1] = i+1;
1411 #ifdef DEBUG
1412 dbgprintf("SMS number is %i\n",SMS->Number);
1413 for (i=0;i<SMS->Number;i++) {
1414 dbgprintf("UDH length %i\n",SMS->SMS[i].UDH.Length);
1415 DumpMessage(di.df, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length);
1416 dbgprintf("SMS length %i\n",UnicodeLength(SMS->SMS[i].Text)*2);
1417 DumpMessage(di.df, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2);
1419 #endif
1420 return GE_NONE;
1423 GSM_Error GSM_EncodeMultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
1424 GSM_MultiSMSMessage *SMS)
1426 unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
1427 unsigned char Buffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
1428 int Length = 0,smslen,i, Class = -1;
1429 GSM_Error error;
1430 GSM_Coding_Type Coding = GSM_Coding_8bit;
1431 GSM_UDH UDH = UDH_NoUDH;
1432 GSM_UDHHeader UDHHeader;
1433 bool EMS = false;
1435 SMS->Number = 0;
1437 for (i=0;i<Info->EntriesNum;i++) {
1438 switch (Info->Entries[i].ID) {
1439 case SMS_EMSPredefinedAnimation:
1440 case SMS_EMSPredefinedSound:
1441 case SMS_EMSSound10:
1442 case SMS_EMSSound12:
1443 case SMS_EMSSonyEricssonSound:
1444 case SMS_EMSSound10Long:
1445 case SMS_EMSSound12Long:
1446 case SMS_EMSSonyEricssonSoundLong:
1447 case SMS_EMSFixedBitmap:
1448 case SMS_EMSVariableBitmap:
1449 case SMS_EMSAnimation:
1450 case SMS_EMSVariableBitmapLong:
1451 EMS = true;
1452 break;
1453 case SMS_ConcatenatedTextLong:
1454 case SMS_ConcatenatedTextLong16bit:
1455 if (Info->Entries[i].Left || Info->Entries[i].Right ||
1456 Info->Entries[i].Center || Info->Entries[i].Large ||
1457 Info->Entries[i].Small || Info->Entries[i].Bold ||
1458 Info->Entries[i].Italic || Info->Entries[i].Underlined ||
1459 Info->Entries[i].Strikethrough) {
1460 EMS = true;
1462 default:
1463 break;
1465 if (EMS) break;
1467 if (EMS) {
1468 error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH);
1469 if (error != GE_NONE) return error;
1470 if (SMS->Number != 1) {
1471 SMS->Number = 0;
1472 for (i=0;i<Info->EntriesNum;i++) {
1473 if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) {
1474 return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages);
1477 return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit);
1479 return error;
1481 if (Info->EntriesNum != 1) return GE_UNKNOWN;
1483 switch (Info->Entries[0].ID) {
1484 case SMS_MMSIndicatorLong:
1485 Class = 1;
1486 UDH = UDH_MMSIndicatorLong;
1487 GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator);
1488 break;
1489 case SMS_NokiaRingtoneLong:
1490 case SMS_NokiaRingtone:
1491 UDH = UDH_NokiaRingtone;
1492 Class = 1;
1493 /* 7 = length of UDH_NokiaRingtone UDH header */
1494 Length = GSM_MAX_8BIT_SMS_LENGTH-7;
1495 Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length);
1496 if (Info->Entries[0].ID == SMS_NokiaRingtone) break;
1497 if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) {
1498 UDH = UDH_NokiaRingtoneLong;
1499 Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3;
1500 Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length);
1502 break;
1503 case SMS_NokiaOperatorLogoLong:
1504 if (Info->Entries[0].Bitmap->Bitmap[0].Width > 72 || Info->Entries[0].Bitmap->Bitmap[0].Height > 14) {
1505 UDH = UDH_NokiaOperatorLogoLong;
1506 Class = 1;
1507 NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
1508 Length = Length + 3;
1509 NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
1510 break;
1512 case SMS_NokiaOperatorLogo:
1513 UDH = UDH_NokiaOperatorLogo;
1514 Class = 1;
1515 NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
1516 Length = Length + 3;
1517 NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
1518 break;
1519 case SMS_NokiaCallerLogo:
1520 UDH = UDH_NokiaCallerLogo;
1521 Class = 1;
1522 NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
1523 break;
1524 case SMS_NokiaProfileLong:
1525 case SMS_NokiaPictureImageLong:
1526 case SMS_NokiaScreenSaverLong:
1527 Class = 1;
1528 UDH = UDH_NokiaProfileLong;
1529 GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length);
1530 break;
1531 case SMS_NokiaWAPBookmarkLong:
1532 Class = 1;
1533 NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark);
1534 /* 7 = length of UDH_NokiaWAP UDH header */
1535 if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) {
1536 UDH=UDH_NokiaWAPLong;
1537 } else {
1538 UDH=UDH_NokiaWAP;
1540 break;
1541 case SMS_NokiaWAPSettingsLong:
1542 Class = 1;
1543 UDH = UDH_NokiaWAPLong;
1544 NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false);
1545 break;
1546 case SMS_NokiaMMSSettingsLong:
1547 Class = 1;
1548 UDH = UDH_NokiaWAPLong;
1549 NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true);
1550 break;
1551 case SMS_NokiaVCARD10Long:
1552 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
1553 /* is 1 SMS ? 8 = length of ..SCKE2 */
1554 if (Length<=GSM_MAX_SMS_LENGTH-8) {
1555 sprintf(Buffer,"//SCKE2 ");
1556 Length = 8;
1557 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
1558 } else {
1559 /* FIXME: It wasn't checked */
1560 UDH = UDH_NokiaPhonebookLong;
1562 Coding = GSM_Coding_Default;
1563 memcpy(Buffer2,Buffer,Length);
1564 EncodeUnicode(Buffer,Buffer2,Length);
1565 break;
1566 case SMS_NokiaVCARD21Long:
1567 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
1568 /* Is 1 SMS ? 12 = length of ..SCKL23F4 */
1569 if (Length<=GSM_MAX_SMS_LENGTH-12) {
1570 sprintf(Buffer,"//SCKL23F4%c%c",13,10);
1571 Length = 12;
1572 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
1573 } else {
1574 UDH = UDH_NokiaPhonebookLong;
1575 /* Here can be also 8 bit coding */
1577 Coding = GSM_Coding_Default;
1578 memcpy(Buffer2,Buffer,Length);
1579 EncodeUnicode(Buffer,Buffer2,Length);
1580 break;
1581 case SMS_VCARD10Long:
1582 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10);
1583 if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages;
1584 Coding = GSM_Coding_Default;
1585 memcpy(Buffer2,Buffer,Length);
1586 EncodeUnicode(Buffer,Buffer2,Length);
1587 break;
1588 case SMS_VCARD21Long:
1589 GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21);
1590 if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages;
1591 Coding = GSM_Coding_Default;
1592 memcpy(Buffer2,Buffer,Length);
1593 EncodeUnicode(Buffer,Buffer2,Length);
1594 break;
1595 case SMS_NokiaVCALENDAR10Long:
1596 error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar);
1597 if (error != GE_NONE) return error;
1598 /* Is 1 SMS ? 8 = length of ..SCKE4 */
1599 if (Length<=GSM_MAX_SMS_LENGTH-8) {
1600 sprintf(Buffer,"//SCKE4 ");
1601 Length = 8;
1602 GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar);
1603 } else {
1604 UDH = UDH_NokiaCalendarLong;
1605 /* can be here 8 bit coding ? */
1607 Coding = GSM_Coding_Default;
1608 memcpy(Buffer2,Buffer,Length);
1609 EncodeUnicode(Buffer,Buffer2,Length);
1610 break;
1611 case SMS_NokiaVTODOLong:
1612 error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo);
1613 if (error != GE_NONE) return error;
1614 UDH = UDH_NokiaCalendarLong;
1615 Coding = GSM_Coding_Default;
1616 memcpy(Buffer2,Buffer,Length);
1617 EncodeUnicode(Buffer,Buffer2,Length);
1618 break;
1619 case SMS_DisableVoice:
1620 case SMS_DisableFax:
1621 case SMS_DisableEmail:
1622 case SMS_EnableVoice:
1623 case SMS_EnableFax:
1624 case SMS_EnableEmail:
1625 case SMS_VoidSMS:
1626 case SMS_Text:
1627 Class = Info->Class;
1628 switch (Info->Entries[0].ID) {
1629 case SMS_DisableVoice : UDH = UDH_DisableVoice; break;
1630 case SMS_DisableFax : UDH = UDH_DisableFax; break;
1631 case SMS_DisableEmail : UDH = UDH_DisableEmail; break;
1632 case SMS_EnableVoice : UDH = UDH_EnableVoice; break;
1633 case SMS_EnableFax : UDH = UDH_EnableFax; break;
1634 case SMS_EnableEmail : UDH = UDH_EnableEmail; break;
1635 case SMS_VoidSMS : UDH = UDH_VoidSMS; break;
1636 case SMS_Text : UDH = UDH_NoUDH; break;
1637 default : break;
1639 UDHHeader.Type = UDH;
1640 GSM_EncodeUDHHeader(&UDHHeader);
1641 memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
1642 if (Info->UnicodeCoding) {
1643 Coding = GSM_Coding_Unicode;
1644 Length = UnicodeLength(Info->Entries[0].Buffer);
1645 if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2;
1646 } else {
1647 Coding = GSM_Coding_Default;
1648 FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7);
1650 break;
1651 case SMS_ConcatenatedAutoTextLong:
1652 case SMS_ConcatenatedAutoTextLong16bit:
1653 smslen = UnicodeLength(Info->Entries[0].Buffer);
1654 memcpy(Buffer,Info->Entries[0].Buffer,smslen*2);
1655 EncodeDefault(Buffer2, Buffer, &smslen, true, NULL);
1656 DecodeDefault(Buffer, Buffer2, smslen, true, NULL);
1657 #ifdef DEBUG
1658 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) {
1659 dbgprintf("Info->Entries[0].Buffer:\n");
1660 DumpMessage(di.df, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2);
1661 dbgprintf("Buffer:\n");
1662 DumpMessage(di.df, Buffer, UnicodeLength(Buffer)*2);
1664 #endif
1665 Info->UnicodeCoding = false;
1666 for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) {
1667 if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) {
1668 Info->UnicodeCoding = true;
1669 dbgprintf("Setting to Unicode %i\n",smslen);
1670 break;
1673 /* No break here - we go to the SMS_ConcatenatedTextLong */
1674 case SMS_ConcatenatedTextLong:
1675 case SMS_ConcatenatedTextLong16bit:
1676 Class = Info->Class;
1677 memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
1678 UDH = UDH_NoUDH;
1679 if (Info->UnicodeCoding) {
1680 Coding = GSM_Coding_Unicode;
1681 Length = UnicodeLength(Info->Entries[0].Buffer);
1682 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
1683 Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
1684 if (Length>70) UDH=UDH_ConcatenatedMessages16bit;
1685 } else {
1686 if (Length>70) UDH=UDH_ConcatenatedMessages;
1688 } else {
1689 Coding = GSM_Coding_Default;
1690 FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000);
1691 if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
1692 Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
1693 if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit;
1694 } else {
1695 if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages;
1698 default:
1699 break;
1701 GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage);
1702 return GE_NONE;
1705 void GSM_ClearMultiPartSMSInfo(GSM_EncodeMultiPartSMSInfo *Info)
1707 int i;
1709 for (i=0;i<MAX_MULTI_SMS;i++) {
1710 Info->Entries[i].Buffer = NULL;
1711 Info->Entries[i].Ringtone = NULL;
1712 Info->Entries[i].Bitmap = NULL;
1713 Info->Entries[i].Phonebook = NULL;
1714 Info->Entries[i].Bookmark = NULL;
1715 Info->Entries[i].Settings = NULL;
1716 Info->Entries[i].Calendar = NULL;
1717 Info->Entries[i].ToDo = NULL;
1718 Info->Entries[i].MMSIndicator = NULL;
1719 Info->Entries[i].Left = false;
1720 Info->Entries[i].Right = false;
1721 Info->Entries[i].Center = false;
1722 Info->Entries[i].Large = false;
1723 Info->Entries[i].Small = false;
1724 Info->Entries[i].Bold = false;
1725 Info->Entries[i].Italic = false;
1726 Info->Entries[i].Underlined = false;
1727 Info->Entries[i].Strikethrough = false;
1729 Info->Entries[i].Protected = false;
1733 /* ----------------- Joining SMS from parts -------------------------------- */
1735 bool GSM_DecodeMultiPartSMS(GSM_EncodeMultiPartSMSInfo *Info,
1736 GSM_MultiSMSMessage *SMS)
1738 int i;
1739 char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS];
1740 int Length = 0;
1741 bool RetVal = false, Bitmap = false, Ringtone = false, TextBuffer = false;
1743 if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) {
1744 if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==GE_NONE)
1746 RetVal = true;
1747 Ringtone = true;
1750 if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) {
1751 PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]);
1752 #ifdef DEBUG
1753 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
1754 #endif
1755 Bitmap = true;
1756 RetVal = true;
1758 if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) {
1759 PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]);
1760 NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
1761 #ifdef DEBUG
1762 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
1763 #endif
1764 Bitmap = true;
1765 RetVal = true;
1768 if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages ||
1769 SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
1770 for (i=0;i<SMS->Number;i++) {
1771 switch (SMS->SMS[i].Coding) {
1772 case GSM_Coding_8bit:
1773 memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
1774 Length=Length+SMS->SMS[i].Length;
1775 break;
1776 case GSM_Coding_Unicode:
1777 case GSM_Coding_Default:
1778 memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2);
1779 Length=Length+UnicodeLength(SMS->SMS[i].Text)*2;
1780 break;
1783 Info->Entries[0].Buffer[Length] = 0;
1784 Info->Entries[0].Buffer[Length+1] = 0;
1785 TextBuffer = true;
1786 RetVal = true;
1789 /* Generally Smart Messaging 3.0 decoding */
1790 if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) {
1791 RetVal = true;
1792 for (i=0;i<SMS->Number;i++) {
1793 if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong ||
1794 SMS->SMS[i].UDH.Text[11] != i+1 ||
1795 SMS->SMS[i].UDH.Text[10] != SMS->Number)
1797 return false;
1799 memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
1800 Length = Length + SMS->SMS[i].Length;
1802 Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0;
1803 Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0;
1804 i=1;
1805 while (i!=Length) {
1806 switch (Buffer[i]) {
1807 case SM30_ISOTEXT:
1808 dbgprintf("ISO 8859-2 text\n");
1809 break;
1810 case SM30_UNICODETEXT:
1811 dbgprintf("Unicode text\n");
1812 memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]);
1813 Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0;
1814 Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0;
1815 dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
1816 break;
1817 case SM30_OTA:
1818 dbgprintf("OTA bitmap as Picture Image\n");
1819 PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]);
1820 #ifdef DEBUG
1821 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
1822 #endif
1823 Bitmap = true;
1824 break;
1825 case SM30_RINGTONE:
1826 dbgprintf("RTTL ringtone\n");
1827 break;
1828 case SM30_PROFILENAME:
1829 dbgprintf("Profile Name\n");
1830 break;
1831 case SM30_SCREENSAVER:
1832 dbgprintf("OTA bitmap as Screen Saver\n");
1833 PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]);
1834 #ifdef DEBUG
1835 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]);
1836 #endif
1837 Bitmap = true;
1838 break;
1840 i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
1841 dbgprintf("%i %i\n",i,Length);
1844 if (!Bitmap) Info->Entries[0].Bitmap = NULL;
1845 if (!TextBuffer) Info->Entries[0].Buffer = NULL;
1846 if (!Ringtone) Info->Entries[0].Ringtone = NULL;
1847 return RetVal;
1850 GSM_Error GSM_SortSMS(GSM_MultiSMSMessage *INPUT[150], GSM_MultiSMSMessage *OUTPUT[150])
1852 bool INPUTSorted[150],copyit;
1853 int i,OUTPUTNum,j,z,loop;
1855 for (i=0;i<150;i++) INPUTSorted[i] = false;
1857 OUTPUTNum = 0;
1858 OUTPUT[0] = NULL;
1860 i=0;
1861 while (INPUT[i]!=NULL) {
1862 loop = true;
1863 /* If this one SMS was sorted earlier, do not touch */
1864 if (INPUTSorted[i]) {
1865 i++;
1866 loop=false;
1868 if (loop) {
1869 /* If we have:
1870 * - linked sms returned by phone driver
1871 * - sms without linking
1872 * - unknown sms
1873 * we copy it to OUTPUT
1875 if (INPUT[i]->Number != 1 ||
1876 INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH ||
1877 INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH ||
1878 INPUT[i]->SMS[0].UDH.PartNumber == -1) {
1879 OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage));
1880 if (OUTPUT[OUTPUTNum] == NULL) return GE_MOREMEMORY;
1881 OUTPUT[OUTPUTNum+1] = NULL;
1883 memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage));
1884 INPUTSorted[i]=true;
1885 OUTPUTNum++;
1886 i=0;
1887 loop = false;
1890 if (loop) {
1891 /* We have 1'st part of linked sms. It's single.
1892 * We will try to find other parts
1894 if (INPUT[i]->SMS[0].UDH.PartNumber == 1) {
1895 OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage));
1896 if (OUTPUT[OUTPUTNum] == NULL) return GE_MOREMEMORY;
1897 OUTPUT[OUTPUTNum+1] = NULL;
1899 memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage));
1900 OUTPUT[OUTPUTNum]->Number = 1;
1901 INPUTSorted[i]=true;
1902 j=1;
1903 while (j!=INPUT[i]->SMS[0].UDH.AllParts) {
1904 z=0;
1905 while(INPUT[z]!=NULL) {
1906 copyit=false;
1907 /* Look for
1908 * - non sorted earlier
1909 * - single
1910 * - with the same UDH (with the same ID, etc.) to the first sms
1912 if (!INPUTSorted[z] &&
1913 INPUT[z]->Number == 1 &&
1914 INPUT[z]->SMS[0].UDH.Type == INPUT[i]->SMS[0].UDH.Type &&
1915 INPUT[z]->SMS[0].UDH.ID8bit == INPUT[i]->SMS[0].UDH.ID8bit &&
1916 INPUT[z]->SMS[0].UDH.ID16bit == INPUT[i]->SMS[0].UDH.ID16bit &&
1917 INPUT[z]->SMS[0].UDH.AllParts == INPUT[i]->SMS[0].UDH.AllParts &&
1918 INPUT[z]->SMS[0].UDH.PartNumber == j+1) {
1919 /* For SMS_Deliver compare also SMSC and Sender number */
1920 if (INPUT[z]->SMS[0].PDU == SMS_Deliver) {
1921 if (!strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) &&
1922 !strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number))) {
1923 if (UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)!=0 || UnicodeLength(INPUT[z]->SMS[0].Number)!=0) {
1924 copyit=true;
1925 } else {
1926 if (INPUT[z]->SMS[0].DateTime.Day == INPUT[i]->SMS[0].DateTime.Day &&
1927 INPUT[z]->SMS[0].DateTime.Month == INPUT[i]->SMS[0].DateTime.Month &&
1928 INPUT[z]->SMS[0].DateTime.Year == INPUT[i]->SMS[0].DateTime.Year &&
1929 INPUT[z]->SMS[0].DateTime.Hour == INPUT[i]->SMS[0].DateTime.Hour &&
1930 INPUT[z]->SMS[0].DateTime.Minute == INPUT[i]->SMS[0].DateTime.Minute &&
1931 INPUT[z]->SMS[0].DateTime.Second == INPUT[i]->SMS[0].DateTime.Second) {
1932 copyit=true;
1937 } else copyit=true;
1939 /* We found correct sms. Copy it */
1940 if (copyit) {
1941 memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage));
1942 OUTPUT[OUTPUTNum]->Number++;
1943 INPUTSorted[z]=true;
1944 break;
1946 z++;
1948 /* Incomplete sequence */
1949 if (OUTPUT[OUTPUTNum]->Number==j) break;
1950 j++;
1952 OUTPUTNum++;
1953 i=0;
1957 return GE_NONE;
1960 /* How should editor hadle tabs in this file? Add editor commands here.
1961 * vim: noexpandtab sw=8 ts=8 sts=8: