1 /* (c) 2002-2006 by Marcin Wiacek */
2 
3 #include <ctype.h>
4 #include <string.h>
5 #include <time.h>
6 
7 #include <gammu-unicode.h>
8 #include <gammu-debug.h>
9 
10 #include "gsmmulti.h"
11 #include "../gsmring.h"
12 #include "../gsmlogo.h"
13 #include "../../misc/coding/coding.h"
14 #include "../../debug.h"
15 #include "gsmems.h"
16 #include "../gsmdata.h"
17 #include "../gsmnet.h"
18 
19 /* ----------------- Splitting SMS into parts ------------------------------ */
20 
GSM_MakeSMSIDFromTime(void)21 unsigned char GSM_MakeSMSIDFromTime(void)
22 {
23 	GSM_DateTime 	Date;
24 	unsigned char	retval;
25 
26 	GSM_GetCurrentDateTime (&Date);
27 	retval = Date.Second;
28 	switch (Date.Minute/10) {
29 		case 2: case 7: 	retval = retval +  60; break;
30 		case 4: case 8: 	retval = retval + 120; break;
31 		case 9: case 5: case 0: retval = retval + 180; break;
32 	}
33 	retval += Date.Minute/10;
34 	return retval;
35 }
36 
GSM_Find_Free_Used_SMS2(GSM_Debug_Info * di,GSM_Coding_Type Coding,GSM_SMSMessage * SMS,size_t * UsedText,size_t * FreeText,size_t * FreeBytes)37 void GSM_Find_Free_Used_SMS2(GSM_Debug_Info *di, GSM_Coding_Type Coding,GSM_SMSMessage *SMS, size_t *UsedText, size_t *FreeText, size_t *FreeBytes)
38 {
39 	size_t UsedBytes = 0;
40 
41 	switch (Coding) {
42 	case SMS_Coding_Default_No_Compression:
43 		FindDefaultAlphabetLen(SMS->Text,&UsedBytes,UsedText,500);
44 		UsedBytes = *UsedText * 7 / 8;
45 		if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++;
46 		*FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
47 		*FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length) * 8 / 7 - *UsedText;
48 		break;
49 	case SMS_Coding_Unicode_No_Compression:
50 		*UsedText = UnicodeLength(SMS->Text);
51 		UsedBytes = *UsedText * 2;
52 		*FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
53 		*FreeText = *FreeBytes / 2;
54 		break;
55 	case SMS_Coding_8bit:
56 		*UsedText = UsedBytes = SMS->Length;
57 		*FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS->UDH.Length - UsedBytes;
58 		*FreeText = *FreeBytes;
59 		break;
60 	default:
61 		break;
62 	}
63 	smfprintf(di, "UDH len %i, UsedBytes %ld, FreeText %ld, UsedText %ld, FreeBytes %ld\n",
64 		SMS->UDH.Length,
65 		(long)UsedBytes,
66 		(long)*FreeText,
67 		(long)*UsedText,
68 		(long)*FreeBytes);
69 }
70 
ReassembleCharacter(char * Buffer,size_t character_index)71 unsigned int ReassembleCharacter(char *Buffer, size_t character_index)
72 {
73 	size_t offset = character_index * 2;
74 
75 	return (
76 	  (unsigned int) ((unsigned char) Buffer[offset] << 8)
77 	    + (unsigned char) Buffer[offset + 1]
78 	);
79 }
80 
AlignIfSurrogatePair(GSM_Debug_Info * di,size_t * Copy,char * Buffer,size_t BufferLen)81 int AlignIfSurrogatePair(GSM_Debug_Info	*di,
82 			 size_t		*Copy,
83 			 char		*Buffer,
84 			 size_t		BufferLen)
85 {
86 	int rv = 0;
87 	unsigned int n;
88 
89 	/* Precondition:
90 	 *   Resulting copy must always be non-zero. */
91 
92 	if (*Copy <= 1) {
93 		return rv;
94 	}
95 
96 	/* Don't split a UTF-16 surrogate pair:
97 	 *   If the final code unit to be copied is a lead surrogate, save
98 	 *   it for the next message segment. This allows recipients to view
99 	 *   the proper four-byte UTF-16 character even if they're unable to
100 	 *   reassemble the message (e.g. if a telecom strips off the UDH). */
101 
102 	n = ReassembleCharacter(Buffer, *Copy - 1);
103 
104 	/* UTF-16 leading surrogate:
105 	 *   First character in pair is always between U+D800 and U+DBFF */
106 
107 	if (n >= 0xd800 && n <= 0xdbff) {
108 		*Copy -= 1;
109 		++rv;
110 	}
111 
112 	return rv;
113 }
114 
AlignIfCombinedCharacter(GSM_Debug_Info * di,size_t * Copy,char * Buffer,size_t BufferLen)115 int AlignIfCombinedCharacter(GSM_Debug_Info	*di,
116 			      size_t		*Copy,
117 			      char		*Buffer,
118 			      size_t		BufferLen)
119 {
120 	int rv = 0;
121 	unsigned int n;
122 
123 	/* Precondition:
124 	 *   If we only have one character to copy, or if there isn't any
125 	 *   code unit following our copy window, don't change anything. */
126 
127 	if (*Copy <= 1 || *Copy >= BufferLen) {
128 		return rv;
129 	}
130 
131 	/* Don't split up a combining sequence:
132 	 *   Peek at the next message segment to see if it begins with
133 	 *   a combining character (e.g. a discritical mark). If it does,
134 	 *   push the final character of this message segment in to the
135 	 *   next message segment. This ensures that the recipient can
136 	 *   visually combine the sequence, even if reassembly fails. */
137 
138 	n = ReassembleCharacter(Buffer, *Copy);
139 
140 	/* Unicode combining characters:
141 	 *   Combining Half Marks (U+FE20 - U+FE2F)
142 	 *   Combining Diacritical Marks (U+300 - U+36F)
143 	 *   Combining Diacritical Marks Extended (U+1AB0 - U+1AFF)
144 	 *   Combining Diacritical Marks Supplement (U+1DC0 - U+1DFF)
145 	 *   Combining Diacritical Marks for Symbols (U+20D0 - U+20FF) */
146 
147 	if ((n >= 0xfe20 && n <= 0xfe2f) ||
148 	    (n >= 0x300 && n <= 0x36f) || (n >= 0x1ab0 && n <= 0x1aff) ||
149 	    (n >= 0x1dc0 && n <= 0x1dff) || (n >= 0x20d0 && n <= 0x20ff)) {
150 		*Copy -= 1;
151 		++rv;
152 	}
153 
154 	return rv;
155 }
156 
AlignIfCombinedSurrogate(GSM_Debug_Info * di,size_t * Copy,char * Buffer,size_t BufferLen)157 int AlignIfCombinedSurrogate(GSM_Debug_Info	*di,
158 			     size_t		*Copy,
159 			     char		*Buffer,
160 			     size_t		BufferLen)
161 {
162 	int rv = 0;
163 	unsigned int l1, l2, r1, r2;
164 
165 	/* Precondition:
166 	 *   If we have two or fewer characters to copy, omitting two
167 	 *   of them would cause us to send empty message segments. If
168 	 *   there aren't at least two characters remaining *after* the
169 	 *   copy boundary, then there can't possibly be space for a
170 	 *   second surrogate pair there. In either case, send as-is. */
171 
172 	if (*Copy <= 2 || (*Copy + 2) >= BufferLen) {
173 		return rv;
174 	}
175 
176 	/* Fetch characters:
177 	 *   We retrieve two UTF-16 characters directly preceeding the
178 	 *   copy boundary, and two directly following the copy boundary. */
179 
180 	l1 = ReassembleCharacter(Buffer, *Copy - 2);
181 	l2 = ReassembleCharacter(Buffer, *Copy - 1);
182 	r1 = ReassembleCharacter(Buffer, *Copy);
183 	r2 = ReassembleCharacter(Buffer, *Copy + 1);
184 
185 	/* Regional Indicator Symbol (U+1F1E6 - U+1F1FF)
186 	 *   UTF-16 surrogate pairs: 0xd83c 0xdde6 - 0xd83c 0xddff */
187 
188 	if (l1 == 0xd83c && r1 == 0xd83c &&
189 	    l2 >= 0xdde6 && l2 <= 0xddff && r2 >= 0xdde6 && r2 <= 0xddff) {
190 		*Copy -= 2;
191 		rv += 2;
192 	}
193 
194 	return rv;
195 }
196 
AlignSegmentForContent(GSM_Debug_Info * di,size_t * Copy,char * Buffer,size_t BufferLen)197 int AlignSegmentForContent(GSM_Debug_Info	*di,
198 			   size_t		*Copy,
199 			   char			*Buffer,
200 			   size_t		BufferLen)
201 {
202 	int rv = 0;
203 
204 	if (!(rv += AlignIfSurrogatePair(di, Copy, Buffer, BufferLen))) {
205 		rv += AlignIfCombinedCharacter(di, Copy, Buffer, BufferLen);
206 	}
207 
208 	rv += AlignIfCombinedSurrogate(di, Copy, Buffer, BufferLen);
209 	return rv;
210 }
211 
GSM_AddSMS_Text_UDH(GSM_Debug_Info * di,GSM_MultiSMSMessage * SMS,GSM_Coding_Type Coding,char * Buffer,size_t BufferLen,gboolean UDH,size_t * UsedText,size_t * CopiedText,size_t * CopiedSMSText)212 GSM_Error GSM_AddSMS_Text_UDH(GSM_Debug_Info *di,
213 				GSM_MultiSMSMessage 	*SMS,
214 		      		GSM_Coding_Type		Coding,
215 		      		char 			*Buffer,
216 		      		size_t			BufferLen,
217 		      		gboolean 			UDH,
218 		      		size_t 			*UsedText,
219 		      		size_t			*CopiedText,
220 		      		size_t			*CopiedSMSText)
221 {
222 	size_t FreeText=0,FreeBytes=0,Copy,i,j;
223 
224 	smfprintf(di, "Checking used: ");
225 	GSM_Find_Free_Used_SMS2(
226 		di, Coding, &(SMS->SMS[SMS->Number]),
227 		UsedText, &FreeText, &FreeBytes
228 	);
229 
230 	if (UDH) {
231 		smfprintf(di, "Adding UDH\n");
232 		if (FreeBytes - BufferLen <= 0) {
233 			smfprintf(di, "Going to the new SMS\n");
234 			SMS->Number++;
235 			GSM_Find_Free_Used_SMS2(
236 				di, Coding, &(SMS->SMS[SMS->Number]),
237 				UsedText, &FreeText, &FreeBytes
238 			);
239 		}
240 		if (SMS->SMS[SMS->Number].UDH.Length == 0) {
241 			SMS->SMS[SMS->Number].UDH.Length  = 1;
242 			SMS->SMS[SMS->Number].UDH.Text[0] = 0x00;
243 		}
244 		memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen);
245 		SMS->SMS[SMS->Number].UDH.Length  	+= BufferLen;
246 		SMS->SMS[SMS->Number].UDH.Text[0] 	+= BufferLen;
247 		SMS->SMS[SMS->Number].UDH.Type 		=  UDH_UserUDH;
248 		smfprintf(di, "UDH added %ld\n", (long)BufferLen);
249 	} else {
250 		smfprintf(di, "Adding text\n");
251 		if (FreeText == 0) {
252 			smfprintf(di, "Going to the new SMS\n");
253 			SMS->Number++;
254 			GSM_Find_Free_Used_SMS2(
255 				di, Coding, &(SMS->SMS[SMS->Number]),
256 				UsedText, &FreeText, &FreeBytes
257 			);
258 		}
259 
260 		Copy = FreeText;
261 		smfprintf(di, "Copy %ld (max %ld)\n", (long)Copy, (long)BufferLen);
262 		if (BufferLen < Copy) {
263 			Copy = BufferLen;
264 		}
265 
266 		switch (Coding) {
267 		case SMS_Coding_Default_No_Compression:
268 			FindDefaultAlphabetLen(Buffer,&i,&j,FreeText);
269 			smfprintf(di, "Defalt text, length %ld %ld\n", (long)i, (long)j);
270 			SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2]   = 0;
271 			SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0;
272 			memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2);
273 			*CopiedText 	= i;
274 			*CopiedSMSText 	= j;
275 			SMS->SMS[SMS->Number].Length += i;
276 			break;
277 		case SMS_Coding_Unicode_No_Compression:
278 			AlignSegmentForContent(di, &Copy, Buffer, BufferLen);
279 			SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2]   = 0;
280 			SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0;
281 			memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2);
282 			*CopiedText = *CopiedSMSText = Copy;
283 			SMS->SMS[SMS->Number].Length += Copy;
284 			break;
285 		case SMS_Coding_8bit:
286 			memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy);
287 			SMS->SMS[SMS->Number].Length += Copy;
288 			*CopiedText = *CopiedSMSText = Copy;
289 			break;
290 		default:
291 			break;
292 		}
293 		smfprintf(di, "Text added\n");
294 	}
295 
296 	smfprintf(di, "Checking at the end: ");
297 	GSM_Find_Free_Used_SMS2(
298 		di, Coding, &(SMS->SMS[SMS->Number]),
299 		UsedText, &FreeText, &FreeBytes
300 	);
301 
302 	return ERR_NONE;
303 }
304 
GSM_MakeMultiPartSMS(GSM_Debug_Info * di,GSM_MultiSMSMessage * SMS,unsigned char * MessageBuffer,size_t MessageLength,GSM_UDH UDHType,GSM_Coding_Type Coding,int Class,unsigned char ReplaceMessage)305 void GSM_MakeMultiPartSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage	*SMS,
306 			  unsigned char		*MessageBuffer,
307 			  size_t		MessageLength,
308 			  GSM_UDH		UDHType,
309 			  GSM_Coding_Type	Coding,
310 			  int			Class,
311 			  unsigned char		ReplaceMessage)
312 {
313 	size_t 		Len,UsedText = 0,CopiedText = 0,CopiedSMSText = 0;
314 	int		j;
315 	unsigned char 	UDHID;
316 	GSM_DateTime 	Date;
317 
318 	Len = 0;
319 	while(1) {
320 		if (SMS->Number >= GSM_MAX_MULTI_SMS) {
321 			break;
322 		}
323 		GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]);
324 		SMS->SMS[SMS->Number].Class    = Class;
325 		SMS->SMS[SMS->Number].Coding   = Coding;
326 
327 		SMS->SMS[SMS->Number].UDH.Type = UDHType;
328 		GSM_EncodeUDHHeader(di, &SMS->SMS[SMS->Number].UDH);
329 
330 		if (Coding == SMS_Coding_8bit) {
331 			GSM_AddSMS_Text_UDH(di, SMS,Coding,MessageBuffer+Len,MessageLength - Len,FALSE,&UsedText,&CopiedText,&CopiedSMSText);
332 		} else {
333 			GSM_AddSMS_Text_UDH(di, SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,FALSE,&UsedText,&CopiedText,&CopiedSMSText);
334 		}
335 		Len += CopiedText;
336 		smfprintf(di, "%ld %ld\n", (long)Len, (long)MessageLength);
337 		SMS->Number++;
338 		if (Len == MessageLength) break;
339 	}
340 
341 	UDHID = GSM_MakeSMSIDFromTime();
342 	GSM_GetCurrentDateTime (&Date);
343 	for (j=0;j<SMS->Number;j++) {
344 		SMS->SMS[j].UDH.Type 		= UDHType;
345 		SMS->SMS[j].UDH.ID8bit 		= UDHID;
346 		SMS->SMS[j].UDH.ID16bit		= UDHID + 256 * Date.Hour;
347 		SMS->SMS[j].UDH.PartNumber 	= j+1;
348 		SMS->SMS[j].UDH.AllParts 	= SMS->Number;
349 		GSM_EncodeUDHHeader(di, &SMS->SMS[j].UDH);
350 	}
351 	if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage;
352 }
353 
354 /* Calculates number of SMS and number of left chars in SMS */
GSM_SMSCounter(GSM_Debug_Info * di,unsigned char * MessageBuffer,GSM_UDH UDHType,GSM_Coding_Type Coding,int * SMSNum,size_t * CharsLeft)355 void GSM_SMSCounter(GSM_Debug_Info *di,
356 		    unsigned char 	*MessageBuffer,
357 		    GSM_UDH	 	UDHType,
358 		    GSM_Coding_Type 	Coding,
359 		    int 		*SMSNum,
360 		    size_t 		*CharsLeft)
361 {
362 	size_t			UsedText=0,FreeBytes=0;
363 	GSM_MultiSMSMessage 	MultiSMS;
364 
365 	MultiSMS.Number = 0;
366 	GSM_MakeMultiPartSMS(di, &MultiSMS,MessageBuffer,UnicodeLength(MessageBuffer),UDHType,Coding,-1,FALSE);
367 	GSM_Find_Free_Used_SMS2(
368 		di, Coding, &(MultiSMS.SMS[MultiSMS.Number-1]),
369 		&UsedText, CharsLeft, &FreeBytes
370 	);
371 	*SMSNum = MultiSMS.Number;
372 }
373 
374 /* Nokia Smart Messaging 3.0 */
GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo * Info,char * Buffer,size_t * Length)375 static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info,
376 					char *Buffer, size_t *Length)
377 {
378 	size_t len;
379 
380 	/*SM version. Here 3.0*/
381 	Buffer[(*Length)++] = 0x30;
382 
383 	if (Info->Entries[0].ID == SMS_NokiaProfileLong) {
384 		if (Info->Entries[0].Buffer != NULL) {
385 			if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) {
386 				Buffer[(*Length)++] = SM30_PROFILENAME;
387 				Buffer[(*Length)++] = 0x00;
388 				Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer);
389 				CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer);
390 				*Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer);
391 			}
392 		}
393 		if (Info->Entries[0].Ringtone != NULL) {
394 			Buffer[(*Length)++] = SM30_RINGTONE;
395 			/* Length for this part later will be changed */
396 			Buffer[(*Length)++] = 0x01;
397 			Buffer[(*Length)++] = 0x00;
398 			/* Smart Messaging 3.0 says: 16*9=144 bytes,
399 			 * but on 3310 4.02 it was possible to save about 196 chars
400 			 * (without cutting) */
401 			len = 196;
402 			Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer+(*Length),&len);
403 			Buffer[(*Length)-2] = len / 256;
404 			Buffer[(*Length)-1] = len % 256;
405 			*Length = *Length + len;
406 		}
407 	}
408 	if (Info->Entries[0].Bitmap != NULL) {
409 		if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) {
410 			Buffer[(*Length)++] = SM30_OTA;
411 		} else {
412 			Buffer[(*Length)++] = SM30_SCREENSAVER;
413 		}
414 		Buffer[(*Length)++] = 0x01;
415 		Buffer[(*Length)++] = 0x00;
416 		NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length);
417 		if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) {
418 			if (Info->UnicodeCoding) {
419 				Buffer[(*Length)++] = SM30_UNICODETEXT;
420 				/* Length for text part */
421 				Buffer[(*Length)++] = 0x00;
422 				Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
423 				memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2);
424 				*Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2;
425 			} else {
426 				/*ID for ISO-8859-1 text*/
427 				Buffer[(*Length)++] = SM30_ISOTEXT;
428 				Buffer[(*Length)++] = 0x00;
429 				Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
430 				memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text));
431 				*Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text);
432 			}
433 		}
434 	}
435 }
436 
437 /* Alcatel docs from www.alcatel.com/wap/ahead */
GSM_EncodeAlcatelMultiPartSMS(GSM_Debug_Info * di,GSM_MultiSMSMessage * SMS,unsigned char * Data,size_t Len,unsigned char * Name,size_t Type)438 GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage 	*SMS,
439 					unsigned char 		*Data,
440 					size_t			Len,
441 					unsigned char		*Name,
442 					size_t			Type)
443 {
444 	unsigned char 	buff[100],UDHID;
445 	size_t		i, p;
446 	GSM_UDHHeader	MyUDH;
447 
448 	for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
449 		GSM_SetDefaultSMSData(&SMS->SMS[i]);
450 		SMS->SMS[i].UDH.Type    = UDH_UserUDH;
451 		SMS->SMS[i].UDH.Text[1] = 0x80;	/* Alcatel */
452 		p 			= UnicodeLength(Name);
453 		EncodeDefault(buff, Name, &p, TRUE, NULL);
454 		SMS->SMS[i].UDH.Text[2]	= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4;
455 		SMS->SMS[i].UDH.Text[3]	= GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p);
456 		SMS->SMS[i].UDH.Text[4] = Type;
457 		SMS->SMS[i].UDH.Text[5] = Len / 256;
458 		SMS->SMS[i].UDH.Text[6] = Len % 256;
459 		SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3];
460 		SMS->SMS[i].UDH.Length  = SMS->SMS[i].UDH.Text[0] + 1;
461 
462 		if (Len > (size_t)(140 - SMS->SMS[i].UDH.Length)) {
463 			MyUDH.Type = UDH_ConcatenatedMessages;
464 			GSM_EncodeUDHHeader(di, &MyUDH);
465 
466 			memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1);
467 			SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1;
468 			SMS->SMS[i].UDH.Length  += MyUDH.Length-1;
469 		}
470 
471 		SMS->SMS[i].Coding = SMS_Coding_8bit;
472 		SMS->SMS[i].Class  = 1;
473 	}
474 
475 	p = 0;
476 	while (p != Len) {
477 		i = 140-SMS->SMS[SMS->Number].UDH.Length;
478 		if (Len - p < i) i = Len - p;
479 		memcpy(SMS->SMS[SMS->Number].Text,Data+p,i);
480 		p += i;
481 		SMS->SMS[SMS->Number].Length = i;
482 		SMS->Number++;
483 
484 	}
485 
486 	/* Linked sms UDH */
487 	if (SMS->Number != 1) {
488 		UDHID = GSM_MakeSMSIDFromTime();
489 		for (i = 0; i < (size_t)SMS->Number; i++) {
490 			SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID;
491 			SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number;
492 			SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1;
493 		}
494 	}
495 
496         return ERR_NONE;
497 }
498 
499 /* Alcatel docs from www.alcatel.com/wap/ahead and other */
GSM_EncodeMultiPartSMS(GSM_Debug_Info * di,GSM_MultiPartSMSInfo * Info,GSM_MultiSMSMessage * SMS)500 GSM_Error GSM_EncodeMultiPartSMS(GSM_Debug_Info *di,
501 				 GSM_MultiPartSMSInfo		*Info,
502 			    	 GSM_MultiSMSMessage		*SMS)
503 {
504 	unsigned char	*Buffer;
505 	unsigned char	*Buffer2;
506 	size_t		buffer_size = GSM_MAX_SMS_LENGTH * 2 * GSM_MAX_MULTI_SMS;
507 	int		i, Class = -1, j;
508 	size_t p;
509 	size_t Length = 0, smslen;
510 	GSM_Error	error;
511 	GSM_Coding_Type Coding 	= SMS_Coding_8bit;
512 	GSM_UDH		UDH	= UDH_NoUDH;
513 	GSM_UDHHeader 	UDHHeader;
514 	gboolean		EMS	= FALSE;
515 	int		textnum = 0;
516 
517 	if (Info->EntriesNum == 0) return ERR_EMPTY;
518 
519 	Buffer = malloc(buffer_size);
520 	if (Buffer == NULL) {
521 		return ERR_MOREMEMORY;
522 	}
523 	Buffer2 = malloc(buffer_size);
524 	if (Buffer2 == NULL) {
525 		free(Buffer);
526 		return ERR_MOREMEMORY;
527 	}
528 
529 	SMS->Number = 0;
530 
531 	if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) {
532 		Buffer[Length++] = 0x00; /* number of elements */
533 		for (i=1;i<Info->EntriesNum;i++) {
534 		switch (Info->Entries[i].ID) {
535 		case SMS_EMSSound10:
536 		case SMS_EMSSound12:
537 		case SMS_EMSSonyEricssonSound:
538 		case SMS_EMSSound10Long:
539 		case SMS_EMSSound12Long:
540 		case SMS_EMSSonyEricssonSoundLong:
541 		case SMS_EMSVariableBitmap:
542 		case SMS_EMSAnimation:
543 		case SMS_EMSVariableBitmapLong:
544 			break;
545 		case SMS_EMSPredefinedSound:
546 			Buffer[0]++;
547 			Buffer[Length++] 	= 0x01; 	/* type of data */
548 			Buffer[Length++] 	= 1 % 256;	/* len */
549 			Buffer[Length++] 	= 1 / 256;      /* len */
550 			Buffer[Length++] 	= Info->Entries[i].Number;
551 			break;
552 		case SMS_EMSPredefinedAnimation:
553 			Buffer[0]++;
554 			Buffer[Length++] 	= 0x02; 	/* type of data */
555 			Buffer[Length++] 	= 1 % 256;	/* len */
556 			Buffer[Length++] 	= 1 / 256;      /* len */
557 			Buffer[Length++] 	= Info->Entries[i].Number;
558 			break;
559 		case SMS_ConcatenatedTextLong:
560 			Buffer[0]++;
561 			p 	= UnicodeLength(Info->Entries[i].Buffer);
562 			EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, TRUE, NULL);
563 			Buffer[Length++]   	= 0x00; 	/* type of data */
564 			Length 			= Length + 2;
565 			smslen			= GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p);
566 			Buffer[Length-2] 	= smslen % 256; /* len */
567 			Buffer[Length-1] 	= smslen / 256; /* len */
568 			Length 			= Length + smslen;
569 			break;
570 		default:
571 			error = ERR_UNKNOWN;
572 			goto out;
573 		}
574 		}
575 		Buffer[0] = Buffer[0] * 2;
576 		error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE);
577 		goto out;
578 	}
579 
580 	for (i=0;i<Info->EntriesNum;i++) {
581 		switch (Info->Entries[i].ID) {
582 		case SMS_EMSPredefinedAnimation:
583 		case SMS_EMSPredefinedSound:
584 		case SMS_EMSSound10:
585 		case SMS_EMSSound12:
586 		case SMS_EMSSonyEricssonSound:
587 		case SMS_EMSSound10Long:
588 		case SMS_EMSSound12Long:
589 		case SMS_EMSSonyEricssonSoundLong:
590 		case SMS_EMSFixedBitmap:
591 		case SMS_EMSVariableBitmap:
592 		case SMS_EMSAnimation:
593 		case SMS_EMSVariableBitmapLong:
594 			EMS = TRUE;
595 			break;
596 		case SMS_ConcatenatedTextLong:
597 		case SMS_ConcatenatedTextLong16bit:
598 
599 			/* This covers situation, when somebody will call function
600 			 * with two or more SMS_Concatenated.... entries only.
601 			 * It will be still only linked sms, but functions below
602 			 * will pack only first entry according to own limits.
603 			 * We redirect to EMS functions, because they are more generic
604 			 * here and will handle it correctly and produce linked sms
605 			 * from all entries
606 			 */
607 			textnum ++;
608 			if (textnum > 1) EMS = TRUE;
609 
610 			if (Info->Entries[i].Left   || Info->Entries[i].Right      ||
611 			    Info->Entries[i].Center || Info->Entries[i].Large      ||
612 			    Info->Entries[i].Small  || Info->Entries[i].Bold       ||
613 			    Info->Entries[i].Italic || Info->Entries[i].Underlined ||
614 			    Info->Entries[i].Strikethrough) {
615 				EMS = TRUE;
616 			}
617 		default:
618 			break;
619 		}
620 		if (EMS) break;
621 	}
622 	if (EMS) {
623 		error=GSM_EncodeEMSMultiPartSMS(di, Info,SMS,UDH_NoUDH);
624 		if (error != ERR_NONE) {
625 			goto out;
626 		}
627 		if (SMS->Number != 1) {
628 			SMS->Number = 0;
629 			for (i=0;i<Info->EntriesNum;i++) {
630 				if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) {
631 					error = GSM_EncodeEMSMultiPartSMS(di, Info,SMS,UDH_ConcatenatedMessages);
632 					goto out;
633 				}
634 			}
635 			error = GSM_EncodeEMSMultiPartSMS(di, Info,SMS,UDH_ConcatenatedMessages16bit);
636 		}
637 		goto out;
638 	}
639 
640 	if (Info->EntriesNum != 1) {
641 		error = ERR_UNKNOWN;
642 		goto out;
643 	}
644 
645 	switch (Info->Entries[0].ID) {
646 	case SMS_AlcatelMonoBitmapLong:
647 		Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth;
648 		Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight;
649 		PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+2, &Info->Entries[0].Bitmap->Bitmap[0]);
650 		Length = PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight)+2;
651 		error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE);
652 		goto out;
653 	case SMS_AlcatelMonoAnimationLong:
654 		/* Number of sequence words */
655 		Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256;
656 		Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256;
657 		/* Picture display time 1 second (1 = 100ms) */
658 		Buffer[2] = 10 % 256;
659 		Buffer[3] = 10 / 256 + 0xF0;
660 
661 		Length    = 4;
662 		j	  = 0;
663 
664 		/* Offsets to bitmaps */
665 		for (i=0;i<Info->Entries[0].Bitmap->Number;i++) {
666 			Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256;
667 			Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256;
668 			j += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight)+2;
669 		}
670 
671 		/* Bitmaps */
672 		for (i=0;i<Info->Entries[0].Bitmap->Number;i++) {
673 			Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth;
674 			Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight;
675 			PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]);
676 			Length += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight);
677 		}
678 		error = GSM_EncodeAlcatelMultiPartSMS(di, SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION);
679 		goto out;
680 	case SMS_MMSIndicatorLong:
681 		Class	= 1;
682 		UDH	= UDH_MMSIndicatorLong;
683 		GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,Info->Entries[0].MMSIndicator);
684 		break;
685 	case SMS_WAPIndicatorLong:
686 		Class	= 1;
687 		UDH	= UDH_MMSIndicatorLong;
688 		GSM_EncodeWAPIndicatorSMSText(Buffer,&Length,Info->Entries[0].MMSIndicator->Title,Info->Entries[0].MMSIndicator->Address);
689 		break;
690 	case SMS_NokiaRingtoneLong:
691 	case SMS_NokiaRingtone:
692 		UDH	= UDH_NokiaRingtone;
693 		Class	= 1;
694 		/* 7 = length of UDH_NokiaRingtone UDH header */
695 		Length  = GSM_MAX_8BIT_SMS_LENGTH-7;
696 		Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer,&Length);
697 		if (Info->Entries[0].ID == SMS_NokiaRingtone) break;
698 		if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) {
699 			UDH    = UDH_NokiaRingtoneLong;
700 			Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3;
701 			Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(Info->Entries[0].Ringtone,Buffer,&Length);
702 		}
703 		break;
704 	case SMS_NokiaOperatorLogoLong:
705 		if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) {
706 			UDH	= UDH_NokiaOperatorLogoLong;
707 			Class 	= 1;
708 			NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
709 			Length = Length + 3;
710 			NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
711 			break;
712 		}
713 		FALLTHROUGH
714 	case SMS_NokiaOperatorLogo:
715 		UDH	= UDH_NokiaOperatorLogo;
716 		Class 	= 1;
717 		NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
718 		Length = Length + 3;
719 		NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
720 		break;
721 	case SMS_NokiaCallerLogo:
722 		UDH	= UDH_NokiaCallerLogo;
723 		Class 	= 1;
724 		NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length);
725 		break;
726 	case SMS_NokiaProfileLong:
727 	case SMS_NokiaPictureImageLong:
728 	case SMS_NokiaScreenSaverLong:
729 		Class   = 1;
730 		UDH	= UDH_NokiaProfileLong;
731 		GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length);
732 		break;
733 	case SMS_NokiaWAPBookmarkLong:
734 		Class	= 1;
735 		NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark);
736 		/* 7 = length of UDH_NokiaWAP UDH header */
737 		if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) {
738 			UDH=UDH_NokiaWAPLong;
739 		} else {
740 			UDH=UDH_NokiaWAP;
741 		}
742 		break;
743 	case SMS_NokiaWAPSettingsLong:
744 		Class	= 1;
745 		UDH	= UDH_NokiaWAPLong;
746 		NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,FALSE);
747 		break;
748 	case SMS_NokiaMMSSettingsLong:
749 		Class	= 1;
750 		UDH	= UDH_NokiaWAPLong;
751 		NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,TRUE);
752 		break;
753 	case SMS_NokiaVCARD10Long:
754 		Coding = SMS_Coding_Default_No_Compression;
755 		UDH = UDH_NokiaPhonebookLong;
756 		error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length, Info->Entries[0].Phonebook, TRUE, Nokia_VCard10);
757 		if (error != ERR_NONE) {
758 			goto out;
759 		}
760 		memcpy(Buffer2,Buffer,Length);
761 		EncodeUnicode(Buffer,Buffer2,Length);
762 		break;
763 	case SMS_NokiaVCARD21Long:
764 		error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length, Info->Entries[0].Phonebook, TRUE, Nokia_VCard21);
765 		if (error != ERR_NONE) {
766 			goto out;
767 		}
768 		Coding = SMS_Coding_Default_No_Compression;
769 		UDH = UDH_NokiaPhonebookLong;
770 		memcpy(Buffer2,Buffer,Length);
771 		EncodeUnicode(Buffer,Buffer2,Length);
772 		break;
773 	case SMS_VCARD10Long:
774 		error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length,Info->Entries[0].Phonebook,TRUE,Nokia_VCard10);
775 		if (error != ERR_NONE) {
776 			goto out;
777 		}
778 		if (Length>GSM_MAX_SMS_CHARS_LENGTH) UDH = UDH_ConcatenatedMessages;
779 		Coding = SMS_Coding_Default_No_Compression;
780 		memcpy(Buffer2,Buffer,Length);
781 		EncodeUnicode(Buffer,Buffer2,Length);
782 		break;
783 	case SMS_VCARD21Long:
784 		error = GSM_EncodeVCARD(di, Buffer, buffer_size, &Length,Info->Entries[0].Phonebook,TRUE,Nokia_VCard21);
785 		if (error != ERR_NONE) {
786 			goto out;
787 		}
788 		if (Length>GSM_MAX_SMS_CHARS_LENGTH) UDH = UDH_ConcatenatedMessages;
789 		Coding = SMS_Coding_Default_No_Compression;
790 		memcpy(Buffer2,Buffer,Length);
791 		EncodeUnicode(Buffer,Buffer2,Length);
792 		break;
793 	case SMS_NokiaVCALENDAR10Long:
794 		error=GSM_EncodeVCALENDAR(Buffer, buffer_size,&Length,Info->Entries[0].Calendar,TRUE,Nokia_VCalendar);
795 		if (error != ERR_NONE) {
796 			goto out;
797 		}
798 		Coding = SMS_Coding_Default_No_Compression;
799 		/* Is 1 SMS ? 8 = length of ..SCKE4 */
800 		if (Length <= GSM_MAX_SMS_CHARS_LENGTH - 8) {
801 			sprintf(Buffer,"//SCKE4 ");
802 			Length = 8;
803 		} else {
804 			UDH = UDH_NokiaCalendarLong;
805 		}
806 		memcpy(Buffer2,Buffer,Length);
807 		EncodeUnicode(Buffer,Buffer2,Length);
808 		break;
809 	case SMS_NokiaVTODOLong:
810 		error=GSM_EncodeVTODO(Buffer, buffer_size,&Length,Info->Entries[0].ToDo,TRUE,Nokia_VToDo);
811 		if (error != ERR_NONE) {
812 			goto out;
813 		}
814 		UDH = UDH_NokiaCalendarLong;
815 		Coding = SMS_Coding_Default_No_Compression;
816 		memcpy(Buffer2,Buffer,Length);
817 		EncodeUnicode(Buffer,Buffer2,Length);
818 		break;
819 	case SMS_DisableVoice:
820 	case SMS_DisableFax:
821 	case SMS_DisableEmail:
822 	case SMS_EnableVoice:
823 	case SMS_EnableFax:
824 	case SMS_EnableEmail:
825 	case SMS_VoidSMS:
826 	case SMS_Text:
827 		Class = Info->Class;
828 		switch (Info->Entries[0].ID) {
829 			case SMS_DisableVoice	: UDH = UDH_DisableVoice; break;
830 			case SMS_DisableFax	: UDH = UDH_DisableFax;	  break;
831 			case SMS_DisableEmail	: UDH = UDH_DisableEmail; break;
832 			case SMS_EnableVoice	: UDH = UDH_EnableVoice;  break;
833 			case SMS_EnableFax	: UDH = UDH_EnableFax; 	  break;
834 			case SMS_EnableEmail	: UDH = UDH_EnableEmail;  break;
835 			case SMS_VoidSMS	: UDH = UDH_VoidSMS;	  break;
836 			case SMS_Text		: UDH = UDH_NoUDH;	  break;
837 			default			:			  break;
838 		}
839 		UDHHeader.Type = UDH;
840 		GSM_EncodeUDHHeader(di, &UDHHeader);
841 		memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
842 		if (Info->UnicodeCoding) {
843 			Coding = SMS_Coding_Unicode_No_Compression;
844 			Length = UnicodeLength(Info->Entries[0].Buffer);
845 			if (Length > (size_t)(140 - UDHHeader.Length) / 2) {
846 				Length = (140 - UDHHeader.Length) / 2;
847 			}
848 		} else {
849 			Coding = SMS_Coding_Default_No_Compression;
850 			FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7);
851 		}
852 		break;
853 	case SMS_USSD:
854 		Class = Info->Class;
855 		break;
856 	case SMS_ConcatenatedAutoTextLong:
857 	case SMS_ConcatenatedAutoTextLong16bit:
858 		smslen = UnicodeLength(Info->Entries[0].Buffer);
859 		memcpy(Buffer,Info->Entries[0].Buffer,smslen*2);
860 		EncodeDefault(Buffer2, Buffer, &smslen, TRUE, NULL);
861 		DecodeDefault(Buffer,  Buffer2, smslen, TRUE, NULL);
862 #ifdef DEBUG
863 		if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
864 			smfprintf(di, "Info->Entries[0].Buffer:\n");
865 			DumpMessage(di, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2);
866 			smfprintf(di, "Buffer:\n");
867 			DumpMessage(di, Buffer, UnicodeLength(Buffer)*2);
868 		}
869 #endif
870 		Info->UnicodeCoding = FALSE;
871 		for (smslen = 0; smslen < UnicodeLength(Info->Entries[0].Buffer) * 2; smslen++) {
872 			if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) {
873 				Info->UnicodeCoding = TRUE;
874 				smfprintf(di, "Setting to Unicode %ld\n", (long)smslen);
875 				break;
876 			}
877 		}
878 		/* No break here - we go to the SMS_ConcatenatedTextLong */
879 		FALLTHROUGH
880 	case SMS_ConcatenatedTextLong:
881 	case SMS_ConcatenatedTextLong16bit:
882 		Class = Info->Class;
883 		if (Info->Entries[0].Buffer == NULL) {
884 			Buffer[0] = 0;
885 			Buffer[1] = 0;
886 		} else {
887 			memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2);
888 		}
889 		UDH = UDH_NoUDH;
890 		if (Info->UnicodeCoding) {
891 			Coding = SMS_Coding_Unicode_No_Compression;
892 			Length = UnicodeLength(Buffer);
893 			if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
894 			    Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
895 				if (Length>70) UDH=UDH_ConcatenatedMessages16bit;
896 			} else {
897 				if (Length>70) UDH=UDH_ConcatenatedMessages;
898 			}
899 		} else {
900 			Coding = SMS_Coding_Default_No_Compression;
901 			FindDefaultAlphabetLen(Buffer,&Length,&smslen,5000);
902 			if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit ||
903 			    Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) {
904 				if (smslen>GSM_MAX_SMS_CHARS_LENGTH) UDH=UDH_ConcatenatedMessages16bit;
905 			} else {
906 				if (smslen>GSM_MAX_SMS_CHARS_LENGTH) UDH=UDH_ConcatenatedMessages;
907 			}
908 		}
909 	default:
910 		break;
911 	}
912 	GSM_MakeMultiPartSMS(di, SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage);
913 	error = ERR_NONE;
914 out:
915 	free(Buffer);
916 	free(Buffer2);
917 	return error;
918 }
919 
GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo * Info)920 void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info)
921 {
922 	int i;
923 
924 	for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
925 		Info->Entries[i].Number		= 0;
926 		Info->Entries[i].Ringtone	= NULL;
927 		Info->Entries[i].Bitmap		= NULL;
928 		Info->Entries[i].Bookmark	= NULL;
929 		Info->Entries[i].File		= NULL;
930 		Info->Entries[i].Settings	= NULL;
931 		Info->Entries[i].MMSIndicator	= NULL;
932 		Info->Entries[i].Phonebook	= NULL;
933 		Info->Entries[i].Calendar	= NULL;
934 		Info->Entries[i].ToDo		= NULL;
935 		Info->Entries[i].Protected	= FALSE;
936 
937 		Info->Entries[i].Buffer		= NULL;
938 		Info->Entries[i].Left		= FALSE;
939 		Info->Entries[i].Right		= FALSE;
940 		Info->Entries[i].Center		= FALSE;
941 		Info->Entries[i].Large		= FALSE;
942 		Info->Entries[i].Small		= FALSE;
943 		Info->Entries[i].Bold		= FALSE;
944 		Info->Entries[i].Italic		= FALSE;
945 		Info->Entries[i].Underlined	= FALSE;
946 		Info->Entries[i].Strikethrough	= FALSE;
947 
948 		Info->Entries[i].RingtoneNotes	= 0;
949 	}
950 	Info->Unknown		= FALSE;
951 	Info->EntriesNum	= 0;
952 	Info->Class		= -1;
953 	Info->ReplaceMessage	= 0;
954 	Info->UnicodeCoding	= FALSE;
955 }
956 
GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo * Info)957 void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info)
958 {
959 	int i;
960 
961 	for (i=0;i<GSM_MAX_MULTI_SMS;i++) {
962 		free(Info->Entries[i].Ringtone);
963 		Info->Entries[i].Ringtone = NULL;
964 		free(Info->Entries[i].Bitmap);
965 		Info->Entries[i].Bitmap = NULL;
966 		free(Info->Entries[i].Bookmark);
967 		Info->Entries[i].Bookmark = NULL;
968 		free(Info->Entries[i].Settings);
969 		Info->Entries[i].Settings = NULL;
970 		free(Info->Entries[i].MMSIndicator);
971 		Info->Entries[i].MMSIndicator = NULL;
972 		free(Info->Entries[i].Phonebook);
973 		Info->Entries[i].Phonebook = NULL;
974 		free(Info->Entries[i].Calendar);
975 		Info->Entries[i].Calendar = NULL;
976 		free(Info->Entries[i].ToDo);
977 		Info->Entries[i].ToDo = NULL;
978 		free(Info->Entries[i].Buffer);
979 		Info->Entries[i].Buffer = NULL;
980 	}
981 }
982 
983 /**
984  * Decodes long MMS notification SMS.
985  */
GSM_DecodeMMSIndication(GSM_Debug_Info * di,GSM_MultiPartSMSInfo * Info,GSM_MultiSMSMessage * SMS)986 gboolean GSM_DecodeMMSIndication(GSM_Debug_Info *di,
987 			    GSM_MultiPartSMSInfo	*Info,
988 			    GSM_MultiSMSMessage		*SMS)
989 {
990 	int i, Length = 0, j;
991 	unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*GSM_MAX_MULTI_SMS];
992 
993 	/* Concatenate data */
994 	for (i = 0; i < SMS->Number; i++) {
995 		if (SMS->SMS[i].UDH.Type == UDH_MMSIndicatorLong) {
996 			if (SMS->SMS[i].UDH.Text[11] != i+1		 ||
997 			    SMS->SMS[i].UDH.Text[10] != SMS->Number) {
998 				return FALSE;
999 			}
1000 		} else if (SMS->SMS[i].UDH.Type != UDH_UserUDH) {
1001 			return FALSE;
1002 		}
1003 		memcpy(Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length);
1004 		Length = Length + SMS->SMS[i].Length;
1005 	}
1006 
1007 	dbgprintf(di, "MMS data of length %d:\n", Length);
1008 	DumpMessage(di, Buffer, Length);
1009 	Info->Entries[0].MMSIndicator = (GSM_MMSIndicator *)malloc(sizeof(GSM_MMSIndicator));
1010 	if (Info->Entries[0].MMSIndicator == NULL) {
1011 		return FALSE;
1012 	}
1013 	Info->EntriesNum    = 1;
1014 	Info->Entries[0].ID = SMS_MMSIndicatorLong;
1015 	Info->Entries[0].MMSIndicator->Class = GSM_MMS_None;
1016 	Info->Entries[0].MMSIndicator->MessageSize = 0;
1017 	Info->Entries[0].MMSIndicator->Title[0] = 0;
1018 	Info->Entries[0].MMSIndicator->Sender[0] = 0;
1019 	Info->Entries[0].MMSIndicator->Address[0] = 0;
1020 
1021 	/* First byte is the WSP transaction ID */
1022 	/* Second byte is PUSH */
1023 	if (Buffer[1] != 0x06) {
1024 		dbgprintf(di, "Unsupported WSP PDU type: 0x%02x\n", Buffer[1]);
1025 		return FALSE;
1026 	}
1027 	/*
1028 	 * WSP Push PDU follows:
1029 	 *
1030 	 * Buffer[2] is length of content type and headers
1031 	 * Buffer[3] is start of content type
1032 	 *
1033 	 * Process payload after headers per
1034 	 * Multimedia Messaging Service Encapsulation Protocol
1035 	 */
1036 	for (i = 3 + Buffer[2]; i < Length; i++) {
1037 		switch(Buffer[i]) {
1038 			case 0x8c:
1039 				/* X-Mms-Message-Type (Transaction type) */
1040 				i++;
1041 				/* We support only m-notification-ind (130) */
1042 				if (Buffer[i] != 0x82) {
1043 					dbgprintf(di, "Unsupported transaction type: 0x%02x\n", Buffer[i]);
1044 					return FALSE;
1045 				}
1046 				break;
1047 			case 0x98:
1048 				/* X-Mms-Transaction-Id (Message ID) */
1049 				dbgprintf(di, "Transaction ID: %s\n", Buffer + i + 1);
1050 				while (Buffer[i] != 0 && i < Length) i++;
1051 				break;
1052 			case 0x8d:
1053 				/*  X-Mms-MMS-Version (MMS version) */
1054 				i++;
1055 				if (Buffer[i] < 0x90 || Buffer[i] > 0x92) {
1056 					dbgprintf(di, "Unsupported MMS version: 0x%02x\n", Buffer[i]);
1057 					return FALSE;
1058 				}
1059 				break;
1060 			case 0x89:
1061 				/* From (Sender) */
1062 				i++;
1063 				/* Length */
1064 				if (Buffer[i] == 0) continue;
1065 				/* Address-present-token */
1066 				if (Buffer[i + 1] == 0x80) {
1067 					if (Buffer[i + 2] < 32) {
1068 						/* String with length + encoding, we just ignore it for now */
1069 						strcpy(Info->Entries[0].MMSIndicator->Sender, Buffer + i + 4);
1070 					} else {
1071 						strcpy(Info->Entries[0].MMSIndicator->Sender, Buffer + i + 2);
1072 					}
1073 				}
1074 				i += Buffer[i];
1075 				break;
1076 			case 0x96:
1077 				/* Subject (Title) */
1078 				if (Buffer[i + 1] == 0x0a && Buffer[i + 2] == 0xea) {
1079 					/* UTF-8 */
1080 					strcpy(Info->Entries[0].MMSIndicator->Title, Buffer + i + 3);
1081 					i += strlen(Info->Entries[0].MMSIndicator->Title) + 3;
1082 				} else {
1083 					strcpy(Info->Entries[0].MMSIndicator->Title, Buffer + i + 1);
1084 					i += strlen(Info->Entries[0].MMSIndicator->Title) + 1;
1085 				}
1086 				break;
1087 			case 0x8a:
1088 				/* X-Mms-Message-Class (Class) */
1089 				i++;
1090 				switch (Buffer[i]) {
1091 					case 0x80:
1092 						Info->Entries[0].MMSIndicator->Class = GSM_MMS_Personal;
1093 						break;
1094 					case 0x81:
1095 						Info->Entries[0].MMSIndicator->Class = GSM_MMS_Advertisement;
1096 						break;
1097 					case 0x82:
1098 						Info->Entries[0].MMSIndicator->Class = GSM_MMS_Info;
1099 						break;
1100 					case 0x83:
1101 						Info->Entries[0].MMSIndicator->Class = GSM_MMS_Auto;
1102 						break;
1103 					default:
1104 						dbgprintf(di, "Unsupported MMS class: 0x%02x\n", Buffer[i]);
1105 						break;
1106 				}
1107 				break;
1108 			case 0x8e:
1109 				/* X-Mms-Message-Size (Message size) */
1110 				i++;
1111 				for (j = i + 1; j < i + 1 + Buffer[i]; j++) {
1112 					Info->Entries[0].MMSIndicator->MessageSize = (Info->Entries[0].MMSIndicator->MessageSize << 8) + Buffer[j];
1113 				}
1114 				i += Buffer[i];
1115 				break;
1116 			case 0x83:
1117 				/* X-Mms-Content-Location (URL) */
1118 				strcpy(Info->Entries[0].MMSIndicator->Address, Buffer + i + 1);
1119 				i += strlen(Info->Entries[0].MMSIndicator->Address) + 1;
1120 				break;
1121 
1122 			/* Ignored variable length fields */
1123 			case 0x87: /* X-Mms-Delivery-Time */
1124 			case 0x88: /* X-Mms-Expiry */
1125 			case 0x9d: /* X-Mms-Reply-Charging-Deadline */
1126 			case 0xa0: /* X-Mms-Previously-Sent-By */
1127 			case 0xa1: /* X-Mms-Previously-Sent-Date */
1128 			case 0xa4: /* X-Mms-MM-Flags */
1129 			case 0xaa: /* X-Mms-Mbox-Totals */
1130 			case 0xac: /* X-Mms-Mbox-Quotas */
1131 			case 0xb2: /* X-Mms-Element-Descriptor */
1132 				i++;
1133 				i += Buffer[i];
1134 				break;
1135 
1136 			/* Ignored long integer types */
1137 			case 0x85: /* Date */
1138 			case 0x9f: /* X-Mms-Reply-Charging-Size */
1139 				i++;
1140 				i += Buffer[i];
1141 				break;
1142 
1143 			/* Ignored integer types */
1144 			case 0xad: /* X-Mms-Message-Count */
1145 			case 0xaf: /* X-Mms-Start */
1146 			case 0xb3: /* X-Mms-Limit */
1147 				i++;
1148 				break;
1149 
1150 			/* Ignored octet types */
1151 			case 0x86: /* X-Mms-Delivery-Report */
1152 			case 0x8f: /* X-Mms-Priority */
1153 			case 0x90: /* X-Mms-Read-Report */
1154 			case 0x91: /* X-Mms-Report-Allowed */
1155 			case 0x92: /* X-Mms-Response-Status */
1156 			case 0x94: /* X-Mms-Sender-Visibility */
1157 			case 0x95: /* X-Mms-Status */
1158 			case 0x99: /* X-Mms-Retrieve-Status */
1159 			case 0x9b: /* X-Mms-Read-Status */
1160 			case 0x9c: /* X-Mms-Reply-Charging */
1161 			case 0xa2: /* X-Mms-Store */
1162 			case 0xa3: /* X-Mms-MM-State */
1163 			case 0xa5: /* X-Mms-Store-Status */
1164 			case 0xa7: /* X-Mms-Stored */
1165 			case 0xa8: /* X-Mms-Attributes */
1166 			case 0xa9: /* X-Mms-Totals */
1167 			case 0xab: /* X-Mms-Quotas */
1168 			case 0xb1: /* X-Mms-Distribution-Indicator */
1169 			case 0xb4: /* X-Mms-Recommended-Retrieval-Mode */
1170 			case 0xba: /* X-Mms-Content-Class */
1171 			case 0xbb: /* X-Mms-DRM-Content */
1172 			case 0xbc: /* X-Mms-Adaptation-Allowed */
1173 			case 0xbf: /* X-Mms-Cancel-Status */
1174 				i++;
1175 				break;
1176 
1177 			/* Ignored encoded string types */
1178 			case 0x81: /* Bcc */
1179 			case 0x82: /* Cc */
1180 			case 0x84: /* Content-Type */
1181 			case 0x97: /* To */
1182 			case 0x93: /* X-Mms-Response-Text */
1183 			case 0x9a: /* X-Mms-Retrieve-Text */
1184 			case 0xa6: /* X-Mms-Store-Status-Text */
1185 			case 0xb5: /* X-Mms-Recommended-Retrieval-Mode-Text */
1186 			case 0xb6: /* X-Mms-Status-Text */
1187 				while (Buffer[i] != 0 && i < Length) {
1188 					i++;
1189 				}
1190 				break;
1191 
1192 			/* Ignored string types */
1193 			case 0x8b: /* Message-ID */
1194 			case 0x9e: /* X-Mms-Reply-Charging-ID */
1195 			case 0xb7: /* X-Mms-Applic-ID */
1196 			case 0xb8: /* X-Mms-Reply-Applic-ID */
1197 			case 0xb9: /* X-Mms-Aux-Applic-Info */
1198 			case 0xbd: /* X-Mms-Replace-ID */
1199 			case 0xbe: /* X-Mms-Cancel-ID */
1200 				i++;
1201 				i += Buffer[i];
1202 				break;
1203 			default:
1204 				dbgprintf(di, "Unknown MMS tag: 0x%02x\n", Buffer[i]);
1205 				break;
1206 		}
1207 	}
1208 
1209 	return TRUE;
1210 }
1211 
1212 /**
1213  * Decodes long Nokia profile SMS.
1214  */
GSM_DecodeNokiaProfile(GSM_Debug_Info * di,GSM_MultiPartSMSInfo * Info,GSM_MultiSMSMessage * SMS)1215 gboolean GSM_DecodeNokiaProfile(GSM_Debug_Info *di,
1216 			    GSM_MultiPartSMSInfo	*Info,
1217 			    GSM_MultiSMSMessage		*SMS)
1218 {
1219 	int i, Length = 0;
1220 	char Buffer[GSM_MAX_SMS_LENGTH*2*GSM_MAX_MULTI_SMS];
1221 
1222 	for (i=0;i<SMS->Number;i++) {
1223 		if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong ||
1224 		    SMS->SMS[i].UDH.Text[11] != i+1		 ||
1225 		    SMS->SMS[i].UDH.Text[10] != SMS->Number) {
1226 			return FALSE;
1227 		}
1228 		memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length);
1229 		Length = Length + SMS->SMS[i].Length;
1230 	}
1231 	Info->EntriesNum    = 1;
1232 	Info->Entries[0].ID = SMS_NokiaPictureImageLong;
1233 	Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1234 	if (Info->Entries[0].Bitmap == NULL) return FALSE;
1235 	Info->Entries[0].Bitmap->Number = 0;
1236 	Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0;
1237 	Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0;
1238 	i=1;
1239 	while (i < Length) {
1240 		switch (Buffer[i]) {
1241 		case SM30_ISOTEXT:
1242 			smfprintf(di, "ISO 8859-2 text\n");
1243 			break;
1244 		case SM30_UNICODETEXT:
1245 			smfprintf(di, "Unicode text\n");
1246 			break;
1247 		case SM30_OTA:
1248 			smfprintf(di, "OTA bitmap as Picture Image\n");
1249 			PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[Info->Entries[0].Bitmap->Number]);
1250 			Info->Entries[0].Bitmap->Number += 1;
1251 #ifdef DEBUG
1252 			if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
1253 				GSM_PrintBitmap(di->df, &Info->Entries[0].Bitmap->Bitmap[0]);
1254 			}
1255 #endif
1256 			break;
1257 		case SM30_RINGTONE:
1258 			smfprintf(di, "RTTL ringtone\n");
1259 			Info->Unknown = TRUE;
1260 			break;
1261 		case SM30_PROFILENAME:
1262 			smfprintf(di, "Profile Name\n");
1263 			Info->Entries[0].ID = SMS_NokiaProfileLong;
1264 			Info->Unknown = TRUE;
1265 			break;
1266 		case SM30_SCREENSAVER:
1267 			smfprintf(di, "OTA bitmap as Screen Saver\n");
1268 			PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[Info->Entries[0].Bitmap->Number]);
1269 			Info->Entries[0].Bitmap->Number += 1;
1270 #ifdef DEBUG
1271 			if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE) {
1272 				GSM_PrintBitmap(di->df, &Info->Entries[0].Bitmap->Bitmap[0]);
1273 			}
1274 #endif
1275 			Info->Entries[0].ID = SMS_NokiaScreenSaverLong;
1276 			break;
1277 		}
1278 		i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
1279 		smfprintf(di, "Profile: pos=%i length=%i\n", i, Length);
1280 	}
1281 	i=1;
1282 	while (i < Length) {
1283 		switch (Buffer[i]) {
1284 		case SM30_ISOTEXT:
1285 			smfprintf(di, "ISO 8859-2 text\n");
1286 			EncodeUnicode (Info->Entries[0].Bitmap->Bitmap[0].Text, Buffer+i+3, Buffer[i+2]);
1287 			smfprintf(di, "ISO Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
1288 			break;
1289 		case SM30_UNICODETEXT:
1290 			smfprintf(di, "Unicode text\n");
1291 			memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]);
1292 			Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] 	= 0;
1293 			Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] 	= 0;
1294 			smfprintf(di, "Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text));
1295 			break;
1296 		case SM30_OTA:
1297 			smfprintf(di, "OTA bitmap as Picture Image\n");
1298 			break;
1299 		case SM30_RINGTONE:
1300 			smfprintf(di, "RTTL ringtone\n");
1301 			break;
1302 		case SM30_PROFILENAME:
1303 			smfprintf(di, "Profile Name\n");
1304 			break;
1305 		case SM30_SCREENSAVER:
1306 			smfprintf(di, "OTA bitmap as Screen Saver\n");
1307 			break;
1308 		}
1309 		i = i + Buffer[i+1]*256 + Buffer[i+2] + 3;
1310 		smfprintf(di, "Profile: pos=%i length=%i\n", i, Length);
1311 	}
1312 	return TRUE;
1313 }
1314 
1315 /**
1316  * Decodes long linked text SMS.
1317  */
GSM_DecodeLinkedText(GSM_Debug_Info * di,GSM_MultiPartSMSInfo * Info,GSM_MultiSMSMessage * SMS)1318 gboolean GSM_DecodeLinkedText(GSM_Debug_Info *di,
1319 			    GSM_MultiPartSMSInfo	*Info,
1320 			    GSM_MultiSMSMessage		*SMS)
1321 {
1322 	int i, Length = 0;
1323 
1324 	Info->EntriesNum    = 1;
1325 	Info->Entries[0].ID = SMS_ConcatenatedTextLong;
1326 	if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
1327 		Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit;
1328 	}
1329 
1330 	for (i=0;i<SMS->Number;i++) {
1331 		switch (SMS->SMS[i].Coding) {
1332 		case SMS_Coding_8bit:
1333 			Info->Entries[0].Buffer = (unsigned char *)realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2);
1334 			if (Info->Entries[0].Buffer == NULL) return FALSE;
1335 
1336 			memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length);
1337 			Length=Length+SMS->SMS[i].Length;
1338 			break;
1339 		case SMS_Coding_Unicode_No_Compression:
1340 			if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) {
1341 				Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong;
1342 			}
1343 			if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) {
1344 				Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit;
1345 			}
1346 			FALLTHROUGH
1347 		case SMS_Coding_Default_No_Compression:
1348 			Info->Entries[0].Buffer = (unsigned char *)realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2);
1349 			if (Info->Entries[0].Buffer == NULL) return FALSE;
1350 
1351 			memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2);
1352 			Length=Length+UnicodeLength(SMS->SMS[i].Text)*2;
1353 			break;
1354 		default:
1355 			break;
1356 		}
1357 	}
1358 	Info->Entries[0].Buffer[Length]	  = 0;
1359 	Info->Entries[0].Buffer[Length+1] = 0;
1360 	return TRUE;
1361 }
1362 
1363 /* ----------------- Joining SMS from parts -------------------------------- */
1364 
GSM_DecodeMultiPartSMS(GSM_Debug_Info * di,GSM_MultiPartSMSInfo * Info,GSM_MultiSMSMessage * SMS,gboolean ems)1365 gboolean GSM_DecodeMultiPartSMS(GSM_Debug_Info *di,
1366 			    GSM_MultiPartSMSInfo	*Info,
1367 			    GSM_MultiSMSMessage		*SMS,
1368 			    gboolean			ems)
1369 {
1370 	int 			i;
1371 	unsigned int		j;
1372 	gboolean 			emsexist = FALSE, result;
1373 	GSM_SiemensOTASMSInfo	SiemensInfo;
1374 
1375 	GSM_ClearMultiPartSMSInfo(Info);
1376 	if (ems) {
1377 		emsexist = TRUE;
1378 		for (i=0;i<SMS->Number;i++) {
1379 			if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages 		&&
1380 			    SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit 	&&
1381 			    SMS->SMS[i].UDH.Type != UDH_UserUDH) {
1382 				emsexist = FALSE;
1383 				break;
1384 			}
1385 		}
1386 	}
1387 
1388 	/* EMS decoding */
1389 	if (emsexist) {
1390 		return GSM_DecodeEMSMultiPartSMS(di, Info,SMS);
1391 	}
1392 
1393 	/* Siemens OTA */
1394 	if (GSM_DecodeSiemensOTASMS(di, &SiemensInfo,&SMS->SMS[0])) {
1395 		Info->Entries[0].File = (GSM_File *)malloc(sizeof(GSM_File));
1396 		if (Info->Entries[0].File == NULL) return FALSE;
1397 		Info->Entries[0].File->Buffer 	= NULL;
1398 		Info->Entries[0].File->Used 	= 0;
1399 		for (i=0;i<SMS->Number;i++) {
1400 			if (GSM_DecodeSiemensOTASMS(di, &SiemensInfo,&SMS->SMS[i])) {
1401 				j = SiemensInfo.AllDataLen - Info->Entries[0].File->Used;
1402 				if (j>SiemensInfo.DataLen) j = SiemensInfo.DataLen;
1403 				Info->Entries[0].File->Buffer = (unsigned char *)realloc(Info->Entries[0].File->Buffer,j+Info->Entries[0].File->Used);
1404 				memcpy(Info->Entries[0].File->Buffer+Info->Entries[0].File->Used,SiemensInfo.Data,j);
1405 				Info->Entries[0].File->Used += j;
1406 			}
1407 		}
1408 		if (SiemensInfo.AllDataLen == Info->Entries[0].File->Used) {
1409 			Info->Entries[0].ID 	= SMS_SiemensFile;
1410 			Info->EntriesNum	= 1;
1411 			EncodeUnicode(Info->Entries[0].File->Name,SiemensInfo.DataName,strlen(SiemensInfo.DataName));
1412 			return TRUE;
1413 		}
1414 		free(Info->Entries[0].File->Buffer);
1415 		Info->Entries[0].File->Buffer=NULL;
1416 	}
1417 
1418 	/* Smart Messaging decoding */
1419 	if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) {
1420 		Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone));
1421 		if (Info->Entries[0].Ringtone == NULL) return FALSE;
1422 		if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) {
1423 			Info->Entries[0].ID 	= SMS_NokiaRingtone;
1424 			Info->EntriesNum	= 1;
1425 			return TRUE;
1426 		}
1427 	}
1428 	if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) {
1429 		Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1430 		if (Info->Entries[0].Bitmap == NULL) return FALSE;
1431 		Info->Entries[0].Bitmap->Number = 1;
1432 		PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]);
1433 #ifdef DEBUG
1434 		if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE)
1435 			GSM_PrintBitmap(di->df,&Info->Entries[0].Bitmap->Bitmap[0]);
1436 #endif
1437 		Info->Entries[0].ID 	= SMS_NokiaCallerLogo;
1438 		Info->EntriesNum	= 1;
1439 		return TRUE;
1440 	}
1441 	if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) {
1442 		Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap));
1443 		if (Info->Entries[0].Bitmap == NULL) return FALSE;
1444 		Info->Entries[0].Bitmap->Number = 1;
1445 		PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]);
1446 		NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode);
1447 #ifdef DEBUG
1448 		if (di->dl == DL_TEXTALL || di->dl == DL_TEXTALLDATE)
1449 			GSM_PrintBitmap(di->df,&Info->Entries[0].Bitmap->Bitmap[0]);
1450 #endif
1451 		Info->Entries[0].ID 	= SMS_NokiaOperatorLogo;
1452 		Info->EntriesNum	= 1;
1453 		return TRUE;
1454 	}
1455 	if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) {
1456 		return GSM_DecodeNokiaProfile(di, Info, SMS);
1457 	}
1458 
1459 	/* Linked sms */
1460 	if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages ||
1461 	    SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) {
1462 		return GSM_DecodeLinkedText(di, Info, SMS);
1463 	}
1464 	/* Nokia vCard/vCalendar */
1465 	if (SMS->SMS[0].UDH.Type == UDH_NokiaCalendarLong ||
1466 	    SMS->SMS[0].UDH.Type == UDH_NokiaPhonebookLong) {
1467 		result = GSM_DecodeLinkedText(di, Info, SMS);
1468 		if (result) {
1469 			if (SMS->SMS[0].UDH.Type == UDH_NokiaPhonebookLong) {
1470 				Info->Entries[0].ID = SMS_NokiaVCARD10Long;
1471 			} else {
1472 				Info->Entries[0].ID = SMS_NokiaVCALENDAR10Long;
1473 			}
1474 		}
1475 		return result;
1476 	}
1477 	/* MMS indication */
1478 	if (SMS->SMS[0].UDH.Type == UDH_MMSIndicatorLong) {
1479 		return GSM_DecodeMMSIndication(di, Info, SMS);
1480 	}
1481 
1482 	return FALSE;
1483 }
1484 
GSM_LinkSMS(GSM_Debug_Info * di,GSM_MultiSMSMessage ** InputMessages,GSM_MultiSMSMessage ** OutputMessages,gboolean ems)1485 GSM_Error GSM_LinkSMS(GSM_Debug_Info *di, GSM_MultiSMSMessage **InputMessages, GSM_MultiSMSMessage **OutputMessages, gboolean ems)
1486 {
1487 	gboolean			*InputMessagesSorted, copyit,OtherNumbers[GSM_SMS_OTHER_NUMBERS+1],wrong=FALSE;
1488 	int			i,OutputMessagesNum,z,w,m,p;
1489 	int			j;
1490 	GSM_SiemensOTASMSInfo	SiemensOTA,SiemensOTA2;
1491 
1492 	i = 0;
1493 	while (InputMessages[i] != NULL) i++;
1494 
1495 	OutputMessagesNum = 0;
1496 	OutputMessages[0] = NULL;
1497 
1498 	if (i == 0) {
1499 		return ERR_NONE;
1500 	}
1501 
1502 	InputMessagesSorted = calloc(i, sizeof(gboolean));
1503 	if (InputMessagesSorted == NULL) return ERR_MOREMEMORY;
1504 
1505 	if (ems) {
1506 		for (i = 0; InputMessages[i] != NULL; i++) {
1507 			if (InputMessages[i]->SMS[0].UDH.Type == UDH_UserUDH) {
1508 				w=1;
1509 				while (w < InputMessages[i]->SMS[0].UDH.Length) {
1510 					switch(InputMessages[i]->SMS[0].UDH.Text[w]) {
1511 					case 0x00:
1512 						smfprintf(di, "Adding ID to user UDH - linked SMS with 8 bit ID\n");
1513 						InputMessages[i]->SMS[0].UDH.ID8bit	= InputMessages[i]->SMS[0].UDH.Text[w+2];
1514 						InputMessages[i]->SMS[0].UDH.ID16bit	= -1;
1515 						InputMessages[i]->SMS[0].UDH.AllParts	= InputMessages[i]->SMS[0].UDH.Text[w+3];
1516 						InputMessages[i]->SMS[0].UDH.PartNumber	= InputMessages[i]->SMS[0].UDH.Text[w+4];
1517 						break;
1518 					case 0x08:
1519 						smfprintf(di, "Adding ID to user UDH - linked SMS with 16 bit ID\n");
1520 						InputMessages[i]->SMS[0].UDH.ID8bit	= -1;
1521 						InputMessages[i]->SMS[0].UDH.ID16bit	= InputMessages[i]->SMS[0].UDH.Text[w+2]*256+InputMessages[i]->SMS[0].UDH.Text[w+3];
1522 						InputMessages[i]->SMS[0].UDH.AllParts	= InputMessages[i]->SMS[0].UDH.Text[w+4];
1523 						InputMessages[i]->SMS[0].UDH.PartNumber	= InputMessages[i]->SMS[0].UDH.Text[w+5];
1524 						break;
1525 					default:
1526 						smfprintf(di, "Block %02x\n",InputMessages[i]->SMS[0].UDH.Text[w]);
1527 					}
1528 					smfprintf(di, "id8: %i, id16: %i, part: %i, parts count: %i\n",
1529 						InputMessages[i]->SMS[0].UDH.ID8bit,
1530 						InputMessages[i]->SMS[0].UDH.ID16bit,
1531 						InputMessages[i]->SMS[0].UDH.PartNumber,
1532 						InputMessages[i]->SMS[0].UDH.AllParts);
1533 					w=w+InputMessages[i]->SMS[0].UDH.Text[w+1]+2;
1534 				}
1535 			}
1536 		}
1537 	}
1538 
1539 	i=0;
1540 	while (InputMessages[i]!=NULL) {
1541 		/* If this one SMS was sorted earlier, do not touch */
1542 		if (InputMessagesSorted[i]) {
1543 			i++;
1544 			continue;
1545 		}
1546 		/* We have 1'st part of SIEMENS sms. It's single.
1547 		 * We will try to find other parts
1548 		 */
1549 		if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[i]->SMS[0]) &&
1550 		    SiemensOTA.PacketNum == 1) {
1551 			OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1552 			if (OutputMessages[OutputMessagesNum] == NULL) {
1553 				free(InputMessagesSorted);
1554 				InputMessagesSorted=NULL;
1555 				return ERR_MOREMEMORY;
1556 			}
1557 			OutputMessages[OutputMessagesNum+1] = NULL;
1558 
1559 			memcpy(&OutputMessages[OutputMessagesNum]->SMS[0],&InputMessages[i]->SMS[0],sizeof(GSM_SMSMessage));
1560 			OutputMessages[OutputMessagesNum]->Number = 1;
1561 			InputMessagesSorted[i]	= TRUE;
1562 			j		= 1;
1563 			/* We're searching for other parts in sequence */
1564 			while (j!=(int)SiemensOTA.PacketsNum) {
1565 
1566         if(j >= GSM_MAX_MULTI_SMS) {
1567           smfprintf(di,
1568             "WARNING: Hard coded message parts limit of %d has been reached,"
1569 						"skipping remaining parts.\n", GSM_MAX_MULTI_SMS);
1570           break;
1571         }
1572 
1573 				z=0;
1574 				while(InputMessages[z]!=NULL) {
1575 					/* This was sorted earlier or is not single */
1576 					if (InputMessagesSorted[z] || InputMessages[z]->Number != 1) {
1577 						z++;
1578 						continue;
1579 					}
1580 					if (!GSM_DecodeSiemensOTASMS(di, &SiemensOTA2,&InputMessages[z]->SMS[0])) {
1581 						z++;
1582 						continue;
1583 					}
1584 					if (SiemensOTA2.SequenceID != SiemensOTA.SequenceID ||
1585 					    (int)SiemensOTA2.PacketNum != j+1 ||
1586 					    SiemensOTA2.PacketsNum != SiemensOTA.PacketsNum ||
1587 					    strcmp(SiemensOTA2.DataType,SiemensOTA.DataType) ||
1588 					    strcmp(SiemensOTA2.DataName,SiemensOTA.DataName)) {
1589 						z++;
1590 						continue;
1591 					}
1592 					/* For SMS_Deliver compare also SMSC and Sender numbers */
1593 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1594 					    strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].SMSC.Number),DecodeUnicodeString(InputMessages[i]->SMS[0].SMSC.Number))) {
1595 						z++;
1596 						continue;
1597 					}
1598 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1599 					    InputMessages[z]->SMS[0].OtherNumbersNum!=InputMessages[i]->SMS[0].OtherNumbersNum) {
1600 						z++;
1601 						continue;
1602 					}
1603 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver) {
1604 						for (m=0;m<GSM_SMS_OTHER_NUMBERS+1;m++) {
1605 							OtherNumbers[m]=FALSE;
1606 						}
1607 						for (m=0;m<InputMessages[z]->SMS[0].OtherNumbersNum+1;m++) {
1608 							wrong=TRUE;
1609 							for (p=0;p<InputMessages[i]->SMS[0].OtherNumbersNum+1;p++) {
1610 								if (OtherNumbers[p]) continue;
1611 								if (m==0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1612 									OtherNumbers[0]=TRUE;
1613 									wrong=FALSE;
1614 									break;
1615 								}
1616 								if (m==0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1617 									OtherNumbers[p]=TRUE;
1618 									wrong=FALSE;
1619 									break;
1620 								}
1621 								if (m!=0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1622 									OtherNumbers[0]=TRUE;
1623 									wrong=FALSE;
1624 									break;
1625 								}
1626 								if (m!=0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1627 									OtherNumbers[p]=TRUE;
1628 									wrong=FALSE;
1629 									break;
1630 								}
1631 							}
1632 							if (wrong) break;
1633 						}
1634 						if (wrong) {
1635 							z++;
1636 							continue;
1637 						}
1638 					}
1639 					/* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */
1640 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver 		&&
1641 					    UnicodeLength(InputMessages[z]->SMS[0].SMSC.Number)==0 	&&
1642 					    UnicodeLength(InputMessages[z]->SMS[0].Number)==0 		&&
1643 					    (InputMessages[z]->SMS[0].DateTime.Day    != InputMessages[i]->SMS[0].DateTime.Day 	  ||
1644 	   				     InputMessages[z]->SMS[0].DateTime.Month  != InputMessages[i]->SMS[0].DateTime.Month  ||
1645 					     InputMessages[z]->SMS[0].DateTime.Year   != InputMessages[i]->SMS[0].DateTime.Year   ||
1646 					     InputMessages[z]->SMS[0].DateTime.Hour   != InputMessages[i]->SMS[0].DateTime.Hour   ||
1647 					     InputMessages[z]->SMS[0].DateTime.Minute != InputMessages[i]->SMS[0].DateTime.Minute ||
1648 					     InputMessages[z]->SMS[0].DateTime.Second != InputMessages[i]->SMS[0].DateTime.Second)) {
1649 						z++;
1650 						continue;
1651 					}
1652 					smfprintf(di, "Found Siemens SMS %i\n",j);
1653 					/* We found correct sms. Copy it */
1654 					memcpy(&OutputMessages[OutputMessagesNum]->SMS[j],&InputMessages[z]->SMS[0],sizeof(GSM_SMSMessage));
1655 					OutputMessages[OutputMessagesNum]->Number++;
1656 					InputMessagesSorted[z]=TRUE;
1657 					break;
1658 				}
1659 				/* Incomplete sequence */
1660 				if (OutputMessages[OutputMessagesNum]->Number==j) {
1661 					smfprintf(di, "Incomplete sequence\n");
1662 					break;
1663 				}
1664 				j++;
1665 			}
1666 			OutputMessagesNum++;
1667 			i = 0;
1668 			continue;
1669 		}
1670 		/* We have some next Siemens sms from sequence */
1671 		if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[i]->SMS[0]) &&
1672 		    SiemensOTA.PacketNum > 1) {
1673 			j = 0;
1674 			while (InputMessages[j]!=NULL) {
1675 				if (InputMessagesSorted[j]) {
1676 					j++;
1677 					continue;
1678 				}
1679 				/* We have some not unassigned first sms from sequence.
1680 				 * We can't touch other sms from sequences
1681 				 */
1682 				if (GSM_DecodeSiemensOTASMS(di, &SiemensOTA,&InputMessages[j]->SMS[0]) &&
1683 				    SiemensOTA.PacketNum == 1) {
1684 					break;
1685 				}
1686 				j++;
1687 			}
1688 			if (InputMessages[j]==NULL) {
1689 				OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1690 				if (OutputMessages[OutputMessagesNum] == NULL) {
1691 					free(InputMessagesSorted);
1692 					InputMessagesSorted=NULL;
1693 					return ERR_MOREMEMORY;
1694 				}
1695 				OutputMessages[OutputMessagesNum+1] = NULL;
1696 
1697 				memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1698 				InputMessagesSorted[i]=TRUE;
1699 				OutputMessagesNum++;
1700 				i = 0;
1701 				continue;
1702 			} else i++;
1703 		}
1704 		copyit = FALSE;
1705 		/* If we have:
1706 		 * - linked sms returned by phone driver
1707 		 * - sms without linking
1708 		 * we copy it to OutputMessages
1709 		 */
1710 		if (InputMessages[i]->Number 			!= 1 	       	||
1711 		    InputMessages[i]->SMS[0].UDH.Type 		== UDH_NoUDH   	||
1712                     InputMessages[i]->SMS[0].UDH.PartNumber 	== -1) {
1713 			copyit = TRUE;
1714 		}
1715 		/* If we have unknown UDH, we copy it to OutputMessages */
1716 		if (InputMessages[i]->SMS[0].UDH.Type == UDH_UserUDH) {
1717 			if (!ems) copyit = TRUE;
1718 			if (ems && InputMessages[i]->SMS[0].UDH.PartNumber == -1) copyit = TRUE;
1719 		}
1720 		if (copyit) {
1721 			OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1722 			if (OutputMessages[OutputMessagesNum] == NULL) {
1723 				free(InputMessagesSorted);
1724 				InputMessagesSorted=NULL;
1725 				return ERR_MOREMEMORY;
1726 			}
1727 			OutputMessages[OutputMessagesNum+1] = NULL;
1728 
1729 			memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1730 			InputMessagesSorted[i]=TRUE;
1731 			OutputMessagesNum++;
1732 			i = 0;
1733 			continue;
1734 		}
1735 		/* We have 1'st part of linked sms. It's single.
1736 		 * We will try to find other parts
1737 		 */
1738 		if (InputMessages[i]->SMS[0].UDH.PartNumber == 1) {
1739 			OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1740 			if (OutputMessages[OutputMessagesNum] == NULL) {
1741 				free(InputMessagesSorted);
1742 				InputMessagesSorted=NULL;
1743 				return ERR_MOREMEMORY;
1744 			}
1745 			OutputMessages[OutputMessagesNum+1] = NULL;
1746 
1747 			memcpy(&OutputMessages[OutputMessagesNum]->SMS[0],&InputMessages[i]->SMS[0],sizeof(GSM_SMSMessage));
1748 			OutputMessages[OutputMessagesNum]->Number = 1;
1749 			InputMessagesSorted[i]	= TRUE;
1750 			j		= 1;
1751 			/* We're searching for other parts in sequence */
1752 			while (j != InputMessages[i]->SMS[0].UDH.AllParts) {
1753 
1754 				if(j >= GSM_MAX_MULTI_SMS) {
1755 					smfprintf(di,
1756 						"WARNING: Hard coded message parts limit of %d has been reached,"
1757 			      "skipping remaining parts.\n", GSM_MAX_MULTI_SMS);
1758 					break;
1759 				}
1760 
1761 				z=0;
1762 				while(InputMessages[z]!=NULL) {
1763 					/* This was sorted earlier or is not single */
1764 					if (InputMessagesSorted[z] || InputMessages[z]->Number != 1) {
1765 						z++;
1766 						continue;
1767 					}
1768 					if (ems && InputMessages[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages &&
1769 					    InputMessages[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit   &&
1770 					    InputMessages[i]->SMS[0].UDH.Type != UDH_UserUDH 			 &&
1771 					    InputMessages[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages 	 &&
1772 					    InputMessages[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit   &&
1773 					    InputMessages[z]->SMS[0].UDH.Type != UDH_UserUDH) {
1774 						if (InputMessages[z]->SMS[0].UDH.Type != InputMessages[i]->SMS[0].UDH.Type) {
1775 							z++;
1776 							continue;
1777 						}
1778 					}
1779 					if (!ems && InputMessages[z]->SMS[0].UDH.Type != InputMessages[i]->SMS[0].UDH.Type) {
1780 						z++;
1781 						continue;
1782 					}
1783 					smfprintf(di, "compare %i         %i %i %i %i",
1784 						j+1,
1785 						InputMessages[i]->SMS[0].UDH.ID8bit,
1786 						InputMessages[i]->SMS[0].UDH.ID16bit,
1787 						InputMessages[i]->SMS[0].UDH.PartNumber,
1788 						InputMessages[i]->SMS[0].UDH.AllParts);
1789 					smfprintf(di, "         %i %i %i %i\n",
1790 						InputMessages[z]->SMS[0].UDH.ID8bit,
1791 						InputMessages[z]->SMS[0].UDH.ID16bit,
1792 						InputMessages[z]->SMS[0].UDH.PartNumber,
1793 						InputMessages[z]->SMS[0].UDH.AllParts);
1794 					if (InputMessages[z]->SMS[0].UDH.ID8bit      != InputMessages[i]->SMS[0].UDH.ID8bit	||
1795 							InputMessages[z]->SMS[0].UDH.ID16bit     != InputMessages[i]->SMS[0].UDH.ID16bit	||
1796 							InputMessages[z]->SMS[0].UDH.AllParts    != InputMessages[i]->SMS[0].UDH.AllParts 	||
1797 							(InputMessages[z]->SMS[0].UDH.PartNumber) != j + 1) {
1798 						z++;
1799 						continue;
1800 					}
1801 					/* For SMS_Deliver compare also SMSC and Sender numbers */
1802 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1803 					    strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].SMSC.Number),DecodeUnicodeString(InputMessages[i]->SMS[0].SMSC.Number))) {
1804 						z++;
1805 						continue;
1806 					}
1807 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver &&
1808 					    InputMessages[z]->SMS[0].OtherNumbersNum!=InputMessages[i]->SMS[0].OtherNumbersNum) {
1809 						z++;
1810 						continue;
1811 					}
1812 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver) {
1813 						for (m=0;m<GSM_SMS_OTHER_NUMBERS+1;m++) {
1814 							OtherNumbers[m]=FALSE;
1815 						}
1816 						for (m=0;m<InputMessages[z]->SMS[0].OtherNumbersNum+1;m++) {
1817 							wrong=TRUE;
1818 							for (p=0;p<InputMessages[i]->SMS[0].OtherNumbersNum+1;p++) {
1819 								if (OtherNumbers[p]) continue;
1820 								if (m==0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1821 									OtherNumbers[0]=TRUE;
1822 									wrong=FALSE;
1823 									break;
1824 								}
1825 								if (m==0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].Number),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1826 									OtherNumbers[p]=TRUE;
1827 									wrong=FALSE;
1828 									break;
1829 								}
1830 								if (m!=0 && p==0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].Number))) {
1831 									OtherNumbers[0]=TRUE;
1832 									wrong=FALSE;
1833 									break;
1834 								}
1835 								if (m!=0 && p!=0 && !strcmp(DecodeUnicodeString(InputMessages[z]->SMS[0].OtherNumbers[m-1]),DecodeUnicodeString(InputMessages[i]->SMS[0].OtherNumbers[p-1]))) {
1836 									OtherNumbers[p]=TRUE;
1837 									wrong=FALSE;
1838 									break;
1839 								}
1840 							}
1841 							if (wrong) break;
1842 						}
1843 						if (wrong) {
1844 							z++;
1845 							continue;
1846 						}
1847 					}
1848 					/* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */
1849 					if (InputMessages[z]->SMS[0].PDU == SMS_Deliver 		&&
1850 					    UnicodeLength(InputMessages[z]->SMS[0].SMSC.Number)==0 	&&
1851 					    UnicodeLength(InputMessages[z]->SMS[0].Number)==0 		&&
1852 					    (InputMessages[z]->SMS[0].DateTime.Day    != InputMessages[i]->SMS[0].DateTime.Day 	  ||
1853 	   				     InputMessages[z]->SMS[0].DateTime.Month  != InputMessages[i]->SMS[0].DateTime.Month  ||
1854 					     InputMessages[z]->SMS[0].DateTime.Year   != InputMessages[i]->SMS[0].DateTime.Year   ||
1855 					     InputMessages[z]->SMS[0].DateTime.Hour   != InputMessages[i]->SMS[0].DateTime.Hour   ||
1856 					     InputMessages[z]->SMS[0].DateTime.Minute != InputMessages[i]->SMS[0].DateTime.Minute ||
1857 					     InputMessages[z]->SMS[0].DateTime.Second != InputMessages[i]->SMS[0].DateTime.Second)) {
1858 						z++;
1859 						continue;
1860 					}
1861 					/* We found correct sms. Copy it */
1862 					memcpy(&OutputMessages[OutputMessagesNum]->SMS[j],&InputMessages[z]->SMS[0],sizeof(GSM_SMSMessage));
1863 					OutputMessages[OutputMessagesNum]->Number++;
1864 					InputMessagesSorted[z]=TRUE;
1865 					break;
1866 				}
1867 				/* Incomplete sequence */
1868 				if (OutputMessages[OutputMessagesNum]->Number==j) {
1869 					smfprintf(di, "Incomplete sequence\n");
1870 					break;
1871 				}
1872 				j++;
1873 			}
1874 			OutputMessagesNum++;
1875 			i = 0;
1876 			continue;
1877 		}
1878 		/* We have some next linked sms from sequence */
1879 		if (InputMessages[i]->SMS[0].UDH.PartNumber > 1) {
1880 			j = 0;
1881 			while (InputMessages[j]!=NULL) {
1882 				if (InputMessagesSorted[j]) {
1883 					j++;
1884 					continue;
1885 				}
1886 				/* We have some not unassigned first sms from sequence.
1887 				 * We can't touch other sms from sequences
1888 				 */
1889 				if (InputMessages[j]->SMS[0].UDH.PartNumber == 1) break;
1890 				j++;
1891 			}
1892 			if (InputMessages[j]==NULL) {
1893 				OutputMessages[OutputMessagesNum] = (GSM_MultiSMSMessage *)malloc(sizeof(GSM_MultiSMSMessage));
1894 				if (OutputMessages[OutputMessagesNum] == NULL) {
1895 					free(InputMessagesSorted);
1896 					InputMessagesSorted=NULL;
1897 					return ERR_MOREMEMORY;
1898 				}
1899 				OutputMessages[OutputMessagesNum+1] = NULL;
1900 
1901 				memcpy(OutputMessages[OutputMessagesNum],InputMessages[i],sizeof(GSM_MultiSMSMessage));
1902 				InputMessagesSorted[i]=TRUE;
1903 				OutputMessagesNum++;
1904 				i = 0;
1905 				continue;
1906 			} else i++;
1907 		}
1908 	}
1909 	free(InputMessagesSorted);
1910 	InputMessagesSorted=NULL;
1911 	return ERR_NONE;
1912 }
1913 
1914 /* How should editor hadle tabs in this file? Add editor commands here.
1915  * vim: noexpandtab sw=8 ts=8 sts=8:
1916  */
1917