1 /* (c) 2002-2004 by Marcin Wiacek, Michal Cihar and others */
2 /* based on some work from MyGnokii (www.mwiacek.com) */
3 /* based on some work from Gnokii (www.gnokii.org)
4  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
5  * GNU GPL version 2 or later
6  */
7 /* Due to a problem in the source code management, the names of some of
8  * the authors have unfortunately been lost. We do not mean to belittle
9  * their efforts and hope they will contact us to see their names
10  * properly added to the Copyright notice above.
11  * Having published their contributions under the terms of the GNU
12  * General Public License (GPL) [version 2], the Copyright of these
13  * authors will remain respected by adhering to the license they chose
14  * to publish their code under.
15  */
16 
17 #include <gammu-config.h>
18 
19 #ifdef HAVE_WCHAR_H
20 #  include <wchar.h>
21 #endif
22 #ifdef HAVE_WCTYPE_H
23 #  include <wctype.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <locale.h>
31 #include <limits.h>
32 #ifdef WIN32
33 #  define WIN32_LEAN_AND_MEAN
34 #  include <windows.h>
35 #endif
36 
37 #include "../../debug.h"
38 #include "coding.h"
39 
40 /* function changes #10 #13 chars to \n \r */
EncodeUnicodeSpecialChars(unsigned char * dest,const unsigned char * buffer)41 unsigned char *EncodeUnicodeSpecialChars(unsigned char *dest, const unsigned char *buffer)
42 {
43 	int 			Pos=0, Pos2=0;
44 
45 	while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) {
46 		if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 10) {
47 			dest[Pos2*2]   = 0x00;
48 			dest[Pos2*2+1] = '\\';
49 			Pos2++;
50 			dest[Pos2*2]   = 0x00;
51 			dest[Pos2*2+1] = 'n';
52 			Pos2++;
53 		} else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 13) {
54 			dest[Pos2*2]   = 0x00;
55 			dest[Pos2*2+1] = '\\';
56 			Pos2++;
57 			dest[Pos2*2]   = 0x00;
58 			dest[Pos2*2+1] = 'r';
59 			Pos2++;
60 		} else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
61 			dest[Pos2*2]   = 0x00;
62 			dest[Pos2*2+1] = '\\';
63 			Pos2++;
64 			dest[Pos2*2]   = 0x00;
65 			dest[Pos2*2+1] = '\\';
66 			Pos2++;
67 		} else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == ';') {
68 			dest[Pos2*2]   = 0x00;
69 			dest[Pos2*2+1] = '\\';
70 			Pos2++;
71 			dest[Pos2*2]   = 0x00;
72 			dest[Pos2*2+1] = ';';
73 			Pos2++;
74 		} else if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == ',') {
75 			dest[Pos2*2]   = 0x00;
76 			dest[Pos2*2+1] = '\\';
77 			Pos2++;
78 			dest[Pos2*2]   = 0x00;
79 			dest[Pos2*2+1] = ',';
80 			Pos2++;
81 		} else {
82 			dest[Pos2*2]   = buffer[Pos*2];
83 			dest[Pos2*2+1] = buffer[Pos*2+1];
84 			Pos2++;
85 		}
86 		Pos++;
87 	}
88 	dest[Pos2*2]   = 0;
89 	dest[Pos2*2+1] = 0;
90 	return dest;
91 }
92 
93 /* function changes #10 #13 chars to \n \r */
EncodeSpecialChars(char * dest,const char * buffer)94 char *EncodeSpecialChars(char *dest, const char *buffer)
95 {
96 	int 			Pos=0, Pos2=0;
97 
98 	while (buffer[Pos]!=0x00) {
99 		switch (buffer[Pos]) {
100 		case 10:
101 			dest[Pos2++] = '\\';
102 			dest[Pos2++] = 'n';
103 			break;
104 		case 13:
105 			dest[Pos2++] = '\\';
106 			dest[Pos2++] = 'r';
107 			break;
108 		case '\\':
109 			dest[Pos2++] = '\\';
110 			dest[Pos2++] = '\\';
111 			break;
112 		default:
113 			dest[Pos2++] = buffer[Pos];
114 		}
115 		Pos++;
116 	}
117 	dest[Pos2] = 0;
118 	return dest;
119 }
120 
DecodeUnicodeSpecialChars(unsigned char * dest,const unsigned char * buffer)121 unsigned char *DecodeUnicodeSpecialChars(unsigned char *dest, const unsigned char *buffer)
122 {
123 	int 			Pos=0, Pos2=0, level=0;
124 
125 	while (buffer[Pos*2]!=0x00 || buffer[Pos*2+1]!=0x00) {
126 		dest[Pos2*2]   = buffer[Pos*2];
127 		dest[Pos2*2+1] = buffer[Pos*2+1];
128 		switch (level) {
129 		case 0:
130 			if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
131 				level = 1;
132 			} else {
133 				Pos2++;
134 			}
135 			break;
136 		case 1:
137 			if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'n') {
138 				dest[Pos2*2]   = 0;
139 				dest[Pos2*2+1] = 10;
140 			} else
141 			if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == 'r') {
142 				dest[Pos2*2]   = 0;
143 				dest[Pos2*2+1] = 13;
144 			} else
145 			if (buffer[Pos*2] == 0x00 && buffer[Pos*2+1] == '\\') {
146 				dest[Pos2*2]   = 0;
147 				dest[Pos2*2+1] = '\\';
148 			}
149 			Pos2++;
150 			level = 0;
151 		}
152 		Pos++;
153 	}
154 	dest[Pos2*2]   = 0;
155 	dest[Pos2*2+1] = 0;
156 	return dest;
157 }
158 
DecodeSpecialChars(char * dest,const char * buffer)159 char *DecodeSpecialChars(char *dest, const char *buffer)
160 {
161 	int 			Pos=0, Pos2=0, level=0;
162 
163 	while (buffer[Pos]!=0x00) {
164 		dest[Pos2] = buffer[Pos];
165 		switch (level) {
166 		case 0:
167 			if (buffer[Pos] == '\\') {
168 				level = 1;
169 			} else {
170 				Pos2++;
171 			}
172 			break;
173 		case 1:
174 			if (buffer[Pos] == 'n') dest[Pos2] = 10;
175 			if (buffer[Pos] == 'r') dest[Pos2] = 13;
176 			if (buffer[Pos] == '\\') dest[Pos2] = '\\';
177 			Pos2++;
178 			level = 0;
179 		}
180 		Pos++;
181 	}
182 	dest[Pos2] = 0;
183 	return dest;
184 }
185 
UnicodeLength(const unsigned char * str)186 size_t UnicodeLength(const unsigned char *str)
187 {
188 	size_t len = 0;
189 
190 	if (str == NULL) return 0;
191 
192 	while(str[len*2] != 0 || str[len*2+1] != 0) len++;
193 
194 	return len;
195 }
196 
197 /* Convert Unicode char saved in src to dest */
EncodeWithUnicodeAlphabet(const unsigned char * src,gammu_char_t * dest)198 int EncodeWithUnicodeAlphabet(const unsigned char *src, gammu_char_t *dest)
199 {
200 	int retval;
201 	wchar_t out = 0;
202 
203 	retval = mbtowc(&out, src, MB_CUR_MAX);
204 	*dest = out;
205 
206 	switch (retval) {
207 		case -1 :
208 		case  0 : return 1;
209 		default : return retval;
210 	}
211 }
212 
213 /* Convert Unicode char saved in src to dest */
DecodeWithUnicodeAlphabet(gammu_char_t src,unsigned char * dest)214 int DecodeWithUnicodeAlphabet(gammu_char_t src, unsigned char *dest)
215 {
216         int retval;
217 
218         switch (retval = wctomb(dest, src)) {
219                 case -1:
220                         *dest = '?';
221                         return 1;
222                 default:
223                         return retval;
224         }
225 }
226 
DecodeUnicode(const unsigned char * src,char * dest)227 void DecodeUnicode (const unsigned char *src, char *dest)
228 {
229 	int		i=0,o=0;
230 	gammu_char_t		value, second;
231 
232 	while (src[(2*i)+1]!=0x00 || src[2*i]!=0x00) {
233 		value = src[i * 2] * 256 + src[i * 2 + 1];
234 		/* Decode UTF-16 */
235 		if (value >= 0xD800 && value <= 0xDBFF) {
236 			second = src[(i + 1) * 2] * 256 + src[(i + 1) * 2 + 1];
237 			if (second >= 0xDC00 && second <= 0xDFFF) {
238 				value = ((value - 0xD800) << 10) + (second - 0xDC00) + 0x010000;
239 				i++;
240 			} else if (second == 0) {
241 				/* Surrogate at the end of string */
242 				value = 0xFFFD; /* REPLACEMENT CHARACTER */
243 			}
244 		}
245 		o += DecodeWithUnicodeAlphabet(value, dest + o);
246 		i++;
247 	}
248 	dest[o]=0;
249 }
250 
251 /* Decode Unicode string and return as function result */
DecodeUnicodeString(const unsigned char * src)252 char *DecodeUnicodeString (const unsigned char *src)
253 {
254  	static char dest[500];
255 
256 	DecodeUnicode(src,dest);
257 	return dest;
258 }
259 
260 /* Decode Unicode string to UTF8 or other console charset
261  * and return as function result
262  */
DecodeUnicodeConsole(const unsigned char * src)263 char *DecodeUnicodeConsole(const unsigned char *src)
264 {
265  	static char dest[500];
266 
267 	if (GSM_global_debug.coding[0] != 0) {
268 		if (!strcmp(GSM_global_debug.coding,"utf8")) {
269 			EncodeUTF8(dest, src);
270 		} else {
271 #ifdef WIN32
272 			setlocale(LC_ALL, GSM_global_debug.coding);
273 #endif
274 			DecodeUnicode(src,dest);
275 		}
276 	} else {
277 #ifdef WIN32
278 		setlocale(LC_ALL, ".OCP");
279 #endif
280 		DecodeUnicode(src,dest);
281 #ifdef WIN32
282 		setlocale(LC_ALL, ".ACP");
283 #endif
284 	}
285 	return dest;
286 }
287 
288 /* Encode string to Unicode. Len is number of input chars */
DecodeISO88591(unsigned char * dest,const char * src,size_t len)289 void DecodeISO88591 (unsigned char *dest, const char *src, size_t len)
290 {
291 	size_t i;
292 
293 	for (i = 0; i < len; i++) {
294 		/* Hack for Euro sign */
295 		if ((unsigned char)src[i] == 0x80) {
296 			dest[2 * i] = 0x20;
297 			dest[(2 * i) + 1] = 0xac;
298 		} else {
299 			dest[2 * i] = 0;
300 			dest[(2 * i) + 1] = src[i];
301 		}
302 	}
303 	dest[2 * i] = 0;
304 	dest[(2 * i) + 1] = 0;
305 }
306 
307 /**
308  * Stores UTF16 char in output
309  *
310  * Returns 1 if additional output was used
311  */
StoreUTF16(unsigned char * dest,gammu_char_t wc)312 size_t StoreUTF16 (unsigned char *dest, gammu_char_t wc)
313 {
314 	gammu_char_t tmp;
315 
316 	if (wc > 0xffff) {
317 		wc = wc - 0x10000;
318 		tmp = 0xD800 | (wc >> 10);
319 		dest[0]	= (tmp >> 8) & 0xff;
320 		dest[1]	= tmp & 0xff;
321 
322 		tmp = 0xDC00 | (wc & 0x3ff);
323 
324 		dest[2]	= (tmp >> 8) & 0xff;
325 		dest[3]	= tmp & 0xff;
326 
327 		return 1;
328 	}
329 
330 	dest[0]	= (wc >> 8) & 0xff;
331 	dest[1]	= wc & 0xff;
332 	return 0;
333 }
334 
335 /* Encode string to Unicode. Len is number of input chars */
EncodeUnicode(unsigned char * dest,const char * src,size_t len)336 void EncodeUnicode (unsigned char *dest, const char *src, size_t len)
337 {
338 	size_t 		i_len = 0, o_len;
339  	gammu_char_t 	wc;
340 
341 	for (o_len = 0; i_len < len; o_len++) {
342 		i_len += EncodeWithUnicodeAlphabet(&src[i_len], &wc);
343 		if (StoreUTF16(dest + o_len * 2, wc)) {
344 			o_len++;
345 		}
346  	}
347 	dest[o_len*2]		= 0;
348 	dest[(o_len*2)+1]	= 0;
349 }
350 
EncodeWithBCDAlphabet(int value)351 unsigned char EncodeWithBCDAlphabet(int value)
352 {
353 	div_t division;
354 
355 	division=div(value,10);
356 	return ( ( (value-division.quot*10) & 0x0f) << 4) | (division.quot & 0xf);
357 }
358 
DecodeWithBCDAlphabet(unsigned char value)359 int DecodeWithBCDAlphabet(unsigned char value)
360 {
361 	return 10*(value & 0x0f)+(value >> 4);
362 }
363 
DecodeBCD(unsigned char * dest,const unsigned char * src,size_t len)364 void DecodeBCD (unsigned char *dest, const unsigned char *src, size_t len)
365 {
366 	size_t i,current=0;
367 	int digit;
368 
369 	for (i = 0; i < len; i++) {
370 	        digit=src[i] & 0x0f;
371                 if (digit<10) dest[current++]=digit + '0';
372 	        digit=src[i] >> 4;
373                 if (digit<10) dest[current++]=digit + '0';
374 	}
375 	dest[current]=0;
376 }
377 
EncodeBCD(unsigned char * dest,const unsigned char * src,size_t len,gboolean fill)378 void EncodeBCD (unsigned char *dest, const unsigned char *src, size_t len, gboolean fill)
379 {
380 	size_t i,current=0;
381 
382 	for (i = 0; i < len; i++) {
383         	if (i & 0x01) {
384 			dest[current]=dest[current] | ((src[i]-'0') << 4);
385 			current++;
386 		} else {
387 			dest[current]=src[i]-'0';
388 		}
389 	}
390 
391         /* When fill is set: if number consist of odd number of digits,
392 	   we fill last bits in last byte with 0x0f
393 	 */
394 	if (fill && (len & 0x01)) dest[current]=dest[current] | 0xf0;
395 }
396 
DecodeWithHexBinAlphabet(unsigned char mychar)397 int DecodeWithHexBinAlphabet (unsigned char mychar)
398 {
399 	if (mychar >= 'A' && mychar <= 'F')
400 		return mychar - 'A' + 10;
401 
402 	if (mychar >= 'a' && mychar <= 'f')
403 		return mychar - 'a' + 10;
404 
405 	if (mychar >= '0' && mychar <= '9')
406 		return mychar - '0';
407 
408 	return -1;
409 }
410 
EncodeWithHexBinAlphabet(int digit)411 char EncodeWithHexBinAlphabet (int digit)
412 {
413 	if (digit >= 0 && digit <= 9) return '0'+(digit);
414 	if (digit >=10 && digit <=15) return 'A'+(digit-10);
415 	return 0;
416 }
417 
DecodeHexUnicode(unsigned char * dest,const char * src,size_t len)418 gboolean DecodeHexUnicode (unsigned char *dest, const char *src, size_t len)
419 {
420 	size_t i, current = 0;
421 	int val0, val1, val2, val3;
422 
423 	for (i = 0; i < len ; i += 4) {
424 		val0 = DecodeWithHexBinAlphabet(src[i + 0]);
425 		val1 = DecodeWithHexBinAlphabet(src[i + 1]);
426 		val2 = DecodeWithHexBinAlphabet(src[i + 2]);
427 		val3 = DecodeWithHexBinAlphabet(src[i + 3]);
428 
429 		if (val0 < 0 || val1 < 0 || val2 < 0 || val3 < 0) {
430 			return FALSE;
431 		}
432 
433 		dest[current++] = (val0 << 4) + val1;
434 		dest[current++] = (val2 << 4) + val3;
435 	}
436 	dest[current++] = 0;
437 	dest[current] = 0;
438 
439 	return TRUE;
440 }
441 
EncodeHexUnicode(char * dest,const unsigned char * src,size_t len)442 void EncodeHexUnicode (char *dest, const unsigned char *src, size_t len)
443 {
444 	EncodeHexBin(dest, src, len * 2);
445 }
446 
DecodeHexBin(unsigned char * dest,const unsigned char * src,size_t len)447 gboolean DecodeHexBin (unsigned char *dest, const unsigned char *src, size_t len)
448 {
449 	size_t i,current=0;
450 	int low, high;
451 
452 	for (i = 0; i < len/2 ; i++) {
453 		low = DecodeWithHexBinAlphabet(src[i*2+1]);
454 		high = DecodeWithHexBinAlphabet(src[i*2]);
455 		if (low < 0 || high < 0) return FALSE;
456 		dest[current++] = (high << 4) | low;
457 	}
458 	dest[current] = 0;
459 	return TRUE;
460 }
461 
EncodeHexBin(char * dest,const unsigned char * src,size_t len)462 void EncodeHexBin (char *dest, const unsigned char *src, size_t len)
463 {
464 	size_t i, outpos = 0;
465 
466 	for (i = 0; i < len; i++) {
467 		dest[outpos++] = EncodeWithHexBinAlphabet(src[i] >> 4);
468 		dest[outpos++] = EncodeWithHexBinAlphabet(src[i] & 0xF);
469 	}
470 	dest[outpos] = 0;
471 }
472 
473 /* ETSI GSM 03.38, section 6.2.1: Default alphabet for SMS messages */
474 static unsigned char GSM_DefaultAlphabetUnicode[128+1][2] =
475 {
476 	{0x00,0x40},{0x00,0xa3},{0x00,0x24},{0x00,0xA5},
477 	{0x00,0xE8},{0x00,0xE9},{0x00,0xF9},{0x00,0xEC},/*0x08*/
478 	{0x00,0xF2},{0x00,0xC7},{0x00,'\n'},{0x00,0xD8},
479 	{0x00,0xF8},{0x00,'\r'},{0x00,0xC5},{0x00,0xE5},
480 	{0x03,0x94},{0x00,0x5f},{0x03,0xA6},{0x03,0x93},
481 	{0x03,0x9B},{0x03,0xA9},{0x03,0xA0},{0x03,0xA8},
482 	{0x03,0xA3},{0x03,0x98},{0x03,0x9E},{0x00,0xb9},
483 	{0x00,0xC6},{0x00,0xE6},{0x00,0xDF},{0x00,0xC9},/*0x20*/
484 	{0x00,' ' },{0x00,'!' },{0x00,'\"'},{0x00,'#' },
485 	{0x00,0xA4},{0x00,'%' },{0x00,'&' },{0x00,'\''},
486 	{0x00,'(' },{0x00,')' },{0x00,'*' },{0x00,'+' },
487 	{0x00,',' },{0x00,'-' },{0x00,'.' },{0x00,'/' },/*0x30*/
488 	{0x00,'0' },{0x00,'1' },{0x00,'2' },{0x00,'3' },
489 	{0x00,'4' },{0x00,'5' },{0x00,'6' },{0x00,'7' },
490 	{0x00,'8' },{0x00,'9' },{0x00,':' },{0x00,';' },
491 	{0x00,'<' },{0x00,'=' },{0x00,'>' },{0x00,'?' },/*0x40*/
492 	{0x00,0xA1},{0x00,'A' },{0x00,'B' },{0x00,'C' },
493 	{0x00,'D' },{0x00,'E' },{0x00,'F' },{0x00,'G' },
494 	{0x00,'H' },{0x00,'I' },{0x00,'J' },{0x00,'K' },
495 	{0x00,'L' },{0x00,'M' },{0x00,'N' },{0x00,'O' },
496 	{0x00,'P' },{0x00,'Q' },{0x00,'R' },{0x00,'S' },
497 	{0x00,'T' },{0x00,'U' },{0x00,'V' },{0x00,'W' },
498 	{0x00,'X' },{0x00,'Y' },{0x00,'Z' },{0x00,0xC4},
499 	{0x00,0xD6},{0x00,0xD1},{0x00,0xDC},{0x00,0xA7},
500 	{0x00,0xBF},{0x00,'a' },{0x00,'b' },{0x00,'c' },
501 	{0x00,'d' },{0x00,'e' },{0x00,'f' },{0x00,'g' },
502 	{0x00,'h' },{0x00,'i' },{0x00,'j' },{0x00,'k' },
503 	{0x00,'l' },{0x00,'m' },{0x00,'n' },{0x00,'o' },
504 	{0x00,'p' },{0x00,'q' },{0x00,'r' },{0x00,'s' },
505 	{0x00,'t' },{0x00,'u' },{0x00,'v' },{0x00,'w' },
506 	{0x00,'x' },{0x00,'y' },{0x00,'z' },{0x00,0xE4},
507 	{0x00,0xF6},{0x00,0xF1},{0x00,0xFC},{0x00,0xE0},
508 	{0x00,0x00}
509 };
510 
511 /* ETSI GSM 3.38
512  * Some sequences of 2 default alphabet chars (for example,
513  * 0x1b, 0x65) are visible as one single additional char (for example,
514  * 0x1b, 0x65 gives Euro char saved in Unicode as 0x20, 0xAC)
515  * This table contains:
516  * 1. two first char means second char from the sequence of chars from GSM default alphabet (first being 0x1b)
517  * 2. two second is target (encoded) char saved in Unicode
518  */
519 static unsigned char GSM_DefaultAlphabetCharsExtension[][3] =
520 {
521 	{0x0a,0x00,0x0c},	/* \r	*/
522 	{0x14,0x00,0x5e},	/* ^	*/
523 	{0x28,0x00,0x7b},	/* {	*/
524 	{0x29,0x00,0x7d},	/* }	*/
525 	{0x2f,0x00,0x5c},	/* \	*/
526 	{0x3c,0x00,0x5b},	/* [	*/
527 	{0x3d,0x00,0x7E},	/* ~	*/
528 	{0x3e,0x00,0x5d},	/* ]	*/
529 	{0x40,0x00,0x7C},	/* |	*/
530 	{0x65,0x20,0xAC},	/* Euro */
531 	{0x00,0x00,0x00}
532 };
533 
DecodeDefault(unsigned char * dest,const unsigned char * src,size_t len,gboolean UseExtensions,unsigned char * ExtraAlphabet)534 void DecodeDefault (unsigned char *dest, const unsigned char *src, size_t len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
535 {
536 	size_t 	pos, current = 0, i;
537 
538 #ifdef DEBUG
539 	DumpMessageText(&GSM_global_debug, src, len);
540 #endif
541 
542 	for (pos = 0; pos < len; pos++) {
543 		if ((pos < (len - 1)) && UseExtensions && src[pos] == 0x1b) {
544 			for (i = 0; GSM_DefaultAlphabetCharsExtension[i][0] != 0x00; i++) {
545 				if (GSM_DefaultAlphabetCharsExtension[i][0] == src[pos + 1]) {
546 					dest[current++] = GSM_DefaultAlphabetCharsExtension[i][1];
547 					dest[current++] = GSM_DefaultAlphabetCharsExtension[i][2];
548 					pos++;
549 					break;
550 				}
551 			}
552 			/* Skip rest if we've found something */
553 			if (GSM_DefaultAlphabetCharsExtension[i][0] != 0x00) {
554 				continue;
555 			}
556 		}
557 		if (ExtraAlphabet != NULL) {
558 			for (i = 0; ExtraAlphabet[i] != 0x00; i += 3) {
559 				if (ExtraAlphabet[i] == src[pos]) {
560 					dest[current++] = ExtraAlphabet[i + 1];
561 					dest[current++] = ExtraAlphabet[i + 2];
562 					break;
563 				}
564 			}
565 			/* Skip rest if we've found something */
566 			if (ExtraAlphabet[i] != 0x00) {
567 				continue;
568 			}
569 		}
570 		dest[current++] = GSM_DefaultAlphabetUnicode[src[pos]][0];
571 		dest[current++] = GSM_DefaultAlphabetUnicode[src[pos]][1];
572 	}
573 	dest[current++]=0;
574 	dest[current]=0;
575 #ifdef DEBUG
576 	DumpMessageText(&GSM_global_debug, dest, UnicodeLength(dest)*2);
577 #endif
578 }
579 
580 /* There are many national chars with "adds". In phone they're normally
581  * changed to "plain" Latin chars. We have such functionality too.
582  * This table is automatically created from convert.txt file (see
583  * /docs/developers) using --makeconverttable. It contains such chars
584  * to replace in order:
585  * 1. original char (Unicode) 2. destination char (Unicode)
586  */
587 static unsigned char ConvertTable[] =
588 "\x00\xc0\x00\x41" \
589 "\x00\xe0\x00\x61" \
590 "\x00\xc1\x00\x41" \
591 "\x00\xe1\x00\x61" \
592 "\x00\xc2\x00\x41" \
593 "\x00\xe2\x00\x61" \
594 "\x00\xc3\x00\x41" \
595 "\x00\xe3\x00\x61" \
596 "\x1e\xa0\x00\x41" \
597 "\x1e\xa1\x00\x61" \
598 "\x1e\xa2\x00\x41" \
599 "\x1e\xa3\x00\x61" \
600 "\x1e\xa4\x00\x41" \
601 "\x1e\xa5\x00\x61" \
602 "\x1e\xa6\x00\x41" \
603 "\x1e\xa7\x00\x61" \
604 "\x1e\xa8\x00\x41" \
605 "\x1e\xa9\x00\x61" \
606 "\x1e\xaa\x00\x41" \
607 "\x1e\xab\x00\x61" \
608 "\x1e\xac\x00\x41" \
609 "\x1e\xad\x00\x61" \
610 "\x1e\xae\x00\x41" \
611 "\x1e\xaf\x00\x61" \
612 "\x1e\xb0\x00\x41" \
613 "\x1e\xb1\x00\x61" \
614 "\x1e\xb2\x00\x41" \
615 "\x1e\xb3\x00\x61" \
616 "\x1e\xb4\x00\x41" \
617 "\x1e\xb5\x00\x61" \
618 "\x1e\xb6\x00\x41" \
619 "\x1e\xb7\x00\x61" \
620 "\x01\xcd\x00\x41" \
621 "\x01\xce\x00\x61" \
622 "\x01\x00\x00\x41" \
623 "\x01\x01\x00\x61" \
624 "\x01\x02\x00\x41" \
625 "\x01\x03\x00\x61" \
626 "\x01\x04\x00\x41" \
627 "\x01\x05\x00\x61" \
628 "\x01\xfb\x00\x61" \
629 "\x01\x06\x00\x43" \
630 "\x01\x07\x00\x63" \
631 "\x01\x08\x00\x43" \
632 "\x01\x09\x00\x63" \
633 "\x01\x0a\x00\x43" \
634 "\x01\x0b\x00\x63" \
635 "\x01\x0c\x00\x43" \
636 "\x01\x0d\x00\x63" \
637 "\x00\xe7\x00\x63" \
638 "\x01\x0e\x00\x44" \
639 "\x01\x0f\x00\x64" \
640 "\x01\x10\x00\x44" \
641 "\x01\x11\x00\x64" \
642 "\x00\xc8\x00\x45" \
643 "\x00\xca\x00\x45" \
644 "\x00\xea\x00\x65" \
645 "\x00\xcb\x00\x45" \
646 "\x00\xeb\x00\x65" \
647 "\x1e\xb8\x00\x45" \
648 "\x1e\xb9\x00\x65" \
649 "\x1e\xba\x00\x45" \
650 "\x1e\xbb\x00\x65" \
651 "\x1e\xbc\x00\x45" \
652 "\x1e\xbd\x00\x65" \
653 "\x1e\xbe\x00\x45" \
654 "\x1e\xbf\x00\x65" \
655 "\x1e\xc0\x00\x45" \
656 "\x1e\xc1\x00\x65" \
657 "\x1e\xc2\x00\x45" \
658 "\x1e\xc3\x00\x65" \
659 "\x1e\xc4\x00\x45" \
660 "\x1e\xc5\x00\x65" \
661 "\x1e\xc6\x00\x45" \
662 "\x1e\xc7\x00\x65" \
663 "\x01\x12\x00\x45" \
664 "\x01\x13\x00\x65" \
665 "\x01\x14\x00\x45" \
666 "\x01\x15\x00\x65" \
667 "\x01\x16\x00\x45" \
668 "\x01\x17\x00\x65" \
669 "\x01\x18\x00\x45" \
670 "\x01\x19\x00\x65" \
671 "\x01\x1a\x00\x45" \
672 "\x01\x1b\x00\x65" \
673 "\x01\x1c\x00\x47" \
674 "\x01\x1d\x00\x67" \
675 "\x01\x1e\x00\x47" \
676 "\x01\x1f\x00\x67" \
677 "\x01\x20\x00\x47" \
678 "\x01\x21\x00\x67" \
679 "\x01\x22\x00\x47" \
680 "\x01\x23\x00\x67" \
681 "\x01\x24\x00\x48" \
682 "\x01\x25\x00\x68" \
683 "\x01\x26\x00\x48" \
684 "\x01\x27\x00\x68" \
685 "\x00\xcc\x00\x49" \
686 "\x00\xcd\x00\x49" \
687 "\x00\xed\x00\x69" \
688 "\x00\xce\x00\x49" \
689 "\x00\xee\x00\x69" \
690 "\x00\xcf\x00\x49" \
691 "\x00\xef\x00\x69" \
692 "\x01\x28\x00\x49" \
693 "\x01\x29\x00\x69" \
694 "\x01\x2a\x00\x49" \
695 "\x01\x2b\x00\x69" \
696 "\x01\x2c\x00\x49" \
697 "\x01\x2d\x00\x69" \
698 "\x01\x2e\x00\x49" \
699 "\x01\x2f\x00\x69" \
700 "\x01\x30\x00\x49" \
701 "\x01\x31\x00\x69" \
702 "\x01\xcf\x00\x49" \
703 "\x01\xd0\x00\x69" \
704 "\x1e\xc8\x00\x49" \
705 "\x1e\xc9\x00\x69" \
706 "\x1e\xca\x00\x49" \
707 "\x1e\xcb\x00\x69" \
708 "\x01\x34\x00\x4a" \
709 "\x01\x35\x00\x6a" \
710 "\x01\x36\x00\x4b" \
711 "\x01\x37\x00\x6b" \
712 "\x01\x39\x00\x4c" \
713 "\x01\x3a\x00\x6c" \
714 "\x01\x3b\x00\x4c" \
715 "\x01\x3c\x00\x6c" \
716 "\x01\x3d\x00\x4c" \
717 "\x01\x3e\x00\x6c" \
718 "\x01\x3f\x00\x4c" \
719 "\x01\x40\x00\x6c" \
720 "\x01\x41\x00\x4c" \
721 "\x01\x42\x00\x6c" \
722 "\x01\x43\x00\x4e" \
723 "\x01\x44\x00\x6e" \
724 "\x01\x45\x00\x4e" \
725 "\x01\x46\x00\x6e" \
726 "\x01\x47\x00\x4e" \
727 "\x01\x48\x00\x6e" \
728 "\x01\x49\x00\x6e" \
729 "\x00\xd2\x00\x4f" \
730 "\x00\xd3\x00\x4f" \
731 "\x00\xf3\x00\x6f" \
732 "\x00\xd4\x00\x4f" \
733 "\x00\xf4\x00\x6f" \
734 "\x00\xd5\x00\x4f" \
735 "\x00\xf5\x00\x6f" \
736 "\x01\x4c\x00\x4f" \
737 "\x01\x4d\x00\x6f" \
738 "\x01\x4e\x00\x4f" \
739 "\x01\x4f\x00\x6f" \
740 "\x01\x50\x00\x4f" \
741 "\x01\x51\x00\x6f" \
742 "\x01\xa0\x00\x4f" \
743 "\x01\xa1\x00\x6f" \
744 "\x01\xd1\x00\x4f" \
745 "\x01\xd2\x00\x6f" \
746 "\x1e\xcc\x00\x4f" \
747 "\x1e\xcd\x00\x6f" \
748 "\x1e\xce\x00\x4f" \
749 "\x1e\xcf\x00\x6f" \
750 "\x1e\xd0\x00\x4f" \
751 "\x1e\xd1\x00\x6f" \
752 "\x1e\xd2\x00\x4f" \
753 "\x1e\xd3\x00\x6f" \
754 "\x1e\xd4\x00\x4f" \
755 "\x1e\xd5\x00\x6f" \
756 "\x1e\xd6\x00\x4f" \
757 "\x1e\xd7\x00\x6f" \
758 "\x1e\xd8\x00\x4f" \
759 "\x1e\xd9\x00\x6f" \
760 "\x1e\xda\x00\x4f" \
761 "\x1e\xdb\x00\x6f" \
762 "\x1e\xdc\x00\x4f" \
763 "\x1e\xdd\x00\x6f" \
764 "\x1e\xde\x00\x4f" \
765 "\x1e\xdf\x00\x6f" \
766 "\x1e\xe0\x00\x4f" \
767 "\x1e\xe1\x00\x6f" \
768 "\x1e\xe2\x00\x4f" \
769 "\x1e\xe3\x00\x6f" \
770 "\x01\x54\x00\x52" \
771 "\x01\x55\x00\x72" \
772 "\x01\x56\x00\x52" \
773 "\x01\x57\x00\x72" \
774 "\x01\x58\x00\x52" \
775 "\x01\x59\x00\x72" \
776 "\x01\x5a\x00\x53" \
777 "\x01\x5b\x00\x73" \
778 "\x01\x5c\x00\x53" \
779 "\x01\x5d\x00\x73" \
780 "\x01\x5e\x00\x53" \
781 "\x01\x5f\x00\x73" \
782 "\x01\x60\x00\x53" \
783 "\x01\x61\x00\x73" \
784 "\x01\x62\x00\x54" \
785 "\x01\x63\x00\x74" \
786 "\x01\x64\x00\x54" \
787 "\x01\x65\x00\x74" \
788 "\x01\x66\x00\x54" \
789 "\x01\x67\x00\x74" \
790 "\x00\xd9\x00\x55" \
791 "\x00\xda\x00\x55" \
792 "\x00\xfa\x00\x75" \
793 "\x00\xdb\x00\x55" \
794 "\x00\xfb\x00\x75" \
795 "\x01\x68\x00\x55" \
796 "\x01\x69\x00\x75" \
797 "\x01\x6a\x00\x55" \
798 "\x01\x6b\x00\x75" \
799 "\x01\x6c\x00\x55" \
800 "\x01\x6d\x00\x75" \
801 "\x01\x6e\x00\x55" \
802 "\x01\x6f\x00\x75" \
803 "\x01\x70\x00\x55" \
804 "\x01\x71\x00\x75" \
805 "\x01\x72\x00\x55" \
806 "\x01\x73\x00\x75" \
807 "\x01\xaf\x00\x55" \
808 "\x01\xb0\x00\x75" \
809 "\x01\xd3\x00\x55" \
810 "\x01\xd4\x00\x75" \
811 "\x01\xd5\x00\x55" \
812 "\x01\xd6\x00\x75" \
813 "\x01\xd7\x00\x55" \
814 "\x01\xd8\x00\x75" \
815 "\x01\xd9\x00\x55" \
816 "\x01\xda\x00\x75" \
817 "\x01\xdb\x00\x55" \
818 "\x01\xdc\x00\x75" \
819 "\x1e\xe4\x00\x55" \
820 "\x1e\xe5\x00\x75" \
821 "\x1e\xe6\x00\x55" \
822 "\x1e\xe7\x00\x75" \
823 "\x1e\xe8\x00\x55" \
824 "\x1e\xe9\x00\x75" \
825 "\x1e\xea\x00\x55" \
826 "\x1e\xeb\x00\x75" \
827 "\x1e\xec\x00\x55" \
828 "\x1e\xed\x00\x75" \
829 "\x1e\xee\x00\x55" \
830 "\x1e\xef\x00\x75" \
831 "\x1e\xf0\x00\x55" \
832 "\x1e\xf1\x00\x75" \
833 "\x01\x74\x00\x57" \
834 "\x01\x75\x00\x77" \
835 "\x1e\x80\x00\x57" \
836 "\x1e\x81\x00\x77" \
837 "\x1e\x82\x00\x57" \
838 "\x1e\x83\x00\x77" \
839 "\x1e\x84\x00\x57" \
840 "\x1e\x85\x00\x77" \
841 "\x00\xdd\x00\x59" \
842 "\x00\xfd\x00\x79" \
843 "\x00\xff\x00\x79" \
844 "\x01\x76\x00\x59" \
845 "\x01\x77\x00\x79" \
846 "\x01\x78\x00\x59" \
847 "\x1e\xf2\x00\x59" \
848 "\x1e\xf3\x00\x75" \
849 "\x1e\xf4\x00\x59" \
850 "\x1e\xf5\x00\x79" \
851 "\x1e\xf6\x00\x59" \
852 "\x1e\xf7\x00\x79" \
853 "\x1e\xf8\x00\x59" \
854 "\x1e\xf9\x00\x79" \
855 "\x01\x79\x00\x5a" \
856 "\x01\x7a\x00\x7a" \
857 "\x01\x7b\x00\x5a" \
858 "\x01\x7c\x00\x7a" \
859 "\x01\x7d\x00\x5a" \
860 "\x01\x7e\x00\x7a" \
861 "\x01\xfc\x00\xc6" \
862 "\x01\xfd\x00\xe6" \
863 "\x01\xfe\x00\xd8" \
864 "\x01\xff\x00\xf8" \
865 "\x00\x00";
866 
EncodeDefault(unsigned char * dest,const unsigned char * src,size_t * len,gboolean UseExtensions,unsigned char * ExtraAlphabet)867 void EncodeDefault(unsigned char *dest, const unsigned char *src, size_t *len, gboolean UseExtensions, unsigned char *ExtraAlphabet)
868 {
869 	size_t 	i,current=0;
870 	int j,z;
871 	char 	ret;
872 	gboolean	FoundSpecial,FoundNormal;
873 
874 #ifdef DEBUG
875 	DumpMessageText(&GSM_global_debug, src, (*len)*2);
876 #endif
877 
878 	for (i = 0; i < *len; i++) {
879 		FoundSpecial = FALSE;
880 		j = 0;
881 		while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00 && UseExtensions) {
882 			if (src[i*2] 	== GSM_DefaultAlphabetCharsExtension[j][1] &&
883 			    src[i*2+1] 	== GSM_DefaultAlphabetCharsExtension[j][2]) {
884 				dest[current++] = 0x1b;
885 				dest[current++] = GSM_DefaultAlphabetCharsExtension[j][0];
886 				FoundSpecial 	= TRUE;
887 				break;
888 			}
889 			j++;
890 		}
891 		if (!FoundSpecial) {
892 			ret 		= '?';
893 			FoundNormal 	= FALSE;
894 			j 		= 0;
895 			while (GSM_DefaultAlphabetUnicode[j][1]!=0x00) {
896 				if (src[i*2]	== GSM_DefaultAlphabetUnicode[j][0] &&
897 				    src[i*2+1]	== GSM_DefaultAlphabetUnicode[j][1]) {
898 					ret 		= j;
899 					FoundNormal 	= TRUE;
900 					break;
901 				}
902 				j++;
903 			}
904 			if (ExtraAlphabet!=NULL && !FoundNormal) {
905 				j = 0;
906 				while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) {
907 					if (ExtraAlphabet[j+1] == src[i*2] &&
908 					    ExtraAlphabet[j+2] == src[i*2 + 1]) {
909 						ret		= ExtraAlphabet[j];
910 						FoundSpecial	= TRUE;
911 						break;
912 					}
913 					j=j+3;
914 				}
915 			}
916 			if (!FoundNormal && !FoundSpecial) {
917 				j = 0;
918 				FoundNormal = FALSE;
919 				while (ConvertTable[j*4]   != 0x00 ||
920 				       ConvertTable[j*4+1] != 0x00) {
921 					if (src[i*2]   == ConvertTable[j*4] &&
922 					    src[i*2+1] == ConvertTable[j*4+1]) {
923 						z = 0;
924 						while (GSM_DefaultAlphabetUnicode[z][1]!=0x00) {
925 							if (ConvertTable[j*4+2]	== GSM_DefaultAlphabetUnicode[z][0] &&
926 							    ConvertTable[j*4+3]	== GSM_DefaultAlphabetUnicode[z][1]) {
927 								ret 		= z;
928 								FoundNormal 	= TRUE;
929 								break;
930 							}
931 							z++;
932 						}
933 						if (FoundNormal) break;
934 					}
935 					j++;
936 				}
937 			}
938 			dest[current++]=ret;
939 		}
940 	}
941 	dest[current]=0;
942 #ifdef DEBUG
943 	DumpMessageText(&GSM_global_debug, dest, current);
944 #endif
945 
946 	*len = current;
947 }
948 
949 /* You don't have to use ConvertTable here - 1 char is replaced there by 1 char */
FindDefaultAlphabetLen(const unsigned char * src,size_t * srclen,size_t * smslen,size_t maxlen)950 void FindDefaultAlphabetLen(const unsigned char *src, size_t *srclen, size_t *smslen, size_t maxlen)
951 {
952 	size_t 	current=0,j,i;
953 	gboolean	FoundSpecial;
954 
955 	i = 0;
956 	while (src[i*2] != 0x00 || src[i*2+1] != 0x00) {
957 		FoundSpecial = FALSE;
958 		j = 0;
959 		while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) {
960 			if (src[i*2] 	== GSM_DefaultAlphabetCharsExtension[j][1] &&
961 			    src[i*2+1] 	== GSM_DefaultAlphabetCharsExtension[j][2]) {
962 				FoundSpecial = TRUE;
963 				if (current+2 > maxlen) {
964 					*srclen = i;
965 					*smslen = current;
966 					return;
967 				}
968 				current+=2;
969 				break;
970 			}
971 			j++;
972 		}
973 		if (!FoundSpecial) {
974 			if (current+1 > maxlen) {
975 				*srclen = i;
976 				*smslen = current;
977 				return;
978 			}
979 			current++;
980 		}
981 		i++;
982 	}
983 	*srclen = i;
984 	*smslen = current;
985 }
986 
987 #define ByteMask ((1 << Bits) - 1)
988 
GSM_UnpackEightBitsToSeven(size_t offset,size_t in_length,size_t out_length,const unsigned char * input,unsigned char * output)989 int GSM_UnpackEightBitsToSeven(size_t offset, size_t in_length, size_t out_length,
990                            const unsigned char *input, unsigned char *output)
991 {
992 	/* (c) by Pavel Janik and Pawel Kot */
993 
994         unsigned char *output_pos 	= output; /* Current pointer to the output buffer */
995         const unsigned char *input_pos  	= input;  /* Current pointer to the input buffer */
996         unsigned char Rest 	= 0x00;
997         size_t	      Bits;
998 
999         Bits = offset ? offset : 7;
1000 
1001         while ((size_t)(input_pos - input) < in_length) {
1002 
1003                 *output_pos = ((*input_pos & ByteMask) << (7 - Bits)) | Rest;
1004                 Rest = *input_pos >> Bits;
1005 
1006                 /* If we don't start from 0th bit, we shouldn't go to the
1007                    next char. Under *output_pos we have now 0 and under Rest -
1008                    _first_ part of the char. */
1009                 if ((input_pos != input) || (Bits == 7)) output_pos++;
1010                 input_pos++;
1011 
1012                 if ((size_t)(output_pos - output) >= out_length) break;
1013 
1014                 /* After reading 7 octets we have read 7 full characters but
1015                    we have 7 bits as well. This is the next character */
1016                 if (Bits == 1) {
1017                         *output_pos = Rest;
1018                         output_pos++;
1019                         Bits = 7;
1020                         Rest = 0x00;
1021                 } else {
1022                         Bits--;
1023                 }
1024         }
1025 
1026         return output_pos - output;
1027 }
1028 
GSM_PackSevenBitsToEight(size_t offset,const unsigned char * input,unsigned char * output,size_t length)1029 int GSM_PackSevenBitsToEight(size_t offset, const unsigned char *input, unsigned char *output, size_t length)
1030 {
1031 	/* (c) by Pavel Janik and Pawel Kot */
1032 
1033         unsigned char 	*output_pos = output; /* Current pointer to the output buffer */
1034         const unsigned char 	*input_pos  = input;  /* Current pointer to the input buffer */
1035         int		Bits;             /* Number of bits directly copied to
1036                                            * the output buffer */
1037         Bits = (7 + offset) % 8;
1038 
1039         /* If we don't begin with 0th bit, we will write only a part of the
1040            first octet */
1041         if (offset) {
1042                 *output_pos = 0x00;
1043                 output_pos++;
1044         }
1045 
1046         while ((size_t)(input_pos - input) < length) {
1047                 unsigned char Byte = *input_pos;
1048 
1049                 *output_pos = Byte >> (7 - Bits);
1050                 /* If we don't write at 0th bit of the octet, we should write
1051                    a second part of the previous octet */
1052                 if (Bits != 7)
1053                         *(output_pos-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
1054 
1055                 Bits--;
1056 
1057                 if (Bits == -1) Bits = 7; else output_pos++;
1058 
1059                 input_pos++;
1060         }
1061         return (output_pos - output);
1062 }
1063 
GSM_UnpackSemiOctetNumber(GSM_Debug_Info * di,unsigned char * retval,const unsigned char * Number,size_t * pos,size_t bufferlength,gboolean semioctet)1064 GSM_Error GSM_UnpackSemiOctetNumber(GSM_Debug_Info *di, unsigned char *retval, const unsigned char *Number, size_t *pos, size_t bufferlength, gboolean semioctet)
1065 {
1066 	unsigned char	Buffer[GSM_MAX_NUMBER_LENGTH + 1];
1067 	size_t		length		= Number[*pos];
1068 	GSM_Error ret = ERR_NONE;
1069 
1070 	smfprintf(di, "Number Length=%ld\n", (long)length);
1071 
1072 	if (length == 0) {
1073 		strcpy(Buffer, "");
1074 		goto out;
1075 	}
1076 
1077 	/* Default ouput on error */
1078 	strcpy(Buffer, "<NOT DECODED>");
1079 
1080 	if (length > bufferlength) {
1081 		smfprintf(di, "Number too long!\n");
1082 		return ERR_UNKNOWN;
1083 	}
1084 
1085 	if (semioctet) {
1086 		/* Convert number of semioctets to number of chars */
1087 		if (length % 2) length++;
1088 		length=length / 2 + 1;
1089 	}
1090 
1091 	/* Check length */
1092 	if (length > GSM_MAX_NUMBER_LENGTH) {
1093 		smfprintf(di, "Number too big, not decoding! (Length=%ld, MAX=%d)\n", (long)length, GSM_MAX_NUMBER_LENGTH);
1094 		ret = ERR_UNKNOWN;
1095 		goto out;
1096 	}
1097 
1098 	/*without leading byte with format of number*/
1099 	length--;
1100 
1101 	smfprintf(di, "Number type %02x (%d %d %d %d|%d %d %d %d)\n", Number[*pos + 1],
1102 			Number[*pos + 1] & 0x80 ? 1 : 0,
1103 			Number[*pos + 1] & 0x40 ? 1 : 0,
1104 			Number[*pos + 1] & 0x20 ? 1 : 0,
1105 			Number[*pos + 1] & 0x10 ? 1 : 0,
1106 			Number[*pos + 1] & 0x08 ? 1 : 0,
1107 			Number[*pos + 1] & 0x04 ? 1 : 0,
1108 			Number[*pos + 1] & 0x02 ? 1 : 0,
1109 			Number[*pos + 1] & 0x01 ? 1 : 0
1110 			);
1111 
1112 	if ((Number[*pos + 1] & 0x80) == 0) {
1113 		smfprintf(di, "Numbering plan not supported!\n");
1114 		ret = ERR_UNKNOWN;
1115 		goto out;
1116 	}
1117 
1118 	switch ((Number[*pos + 1] & 0x70)) {
1119 	case (NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN & 0x70):
1120 		if (length > 6) length++;
1121 		smfprintf(di, "Alphanumeric number, length %ld\n", (long)length);
1122 		GSM_UnpackEightBitsToSeven(0, length, length, Number+*pos+2, Buffer);
1123 		Buffer[length]=0;
1124 		break;
1125 	case (NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN & 0x70):
1126 		smfprintf(di, "International number\n");
1127 		Buffer[0]='+';
1128 		DecodeBCD(Buffer+1,Number+*pos+2, length);
1129 		break;
1130 	default:
1131 		DecodeBCD (Buffer, Number+*pos+2, length);
1132 		break;
1133 	}
1134 
1135 	smfprintf(di, "Len %ld\n", (long)length);
1136 out:
1137 	EncodeUnicode(retval,Buffer,strlen(Buffer));
1138 	if (semioctet) {
1139 		*pos += 2 + ((Number[*pos] + 1) / 2);
1140 	} else {
1141 		*pos += 1 + Number[*pos];
1142 	}
1143 	return ret;
1144 }
1145 
1146 /**
1147  * Packing some phone numbers (SMSC, SMS destination and others)
1148  *
1149  * See GSM 03.40 9.1.1:
1150  * 1 byte  - length of number given in semioctets or bytes (when given in
1151  *           bytes, includes one byte for byte with number format).
1152  *           Returned by function (set semioctet to TRUE, if want result
1153  *           in semioctets).
1154  * 1 byte  - format of number (see GSM_NumberType in coding.h). Returned
1155  *           in unsigned char *Output.
1156  * n bytes - 2n or 2n-1 semioctets with number. Returned in unsigned char
1157  *           *Output.
1158  *
1159  * 1 semioctet = 4 bits = half of byte
1160  */
GSM_PackSemiOctetNumber(const unsigned char * Number,unsigned char * Output,gboolean semioctet)1161 int GSM_PackSemiOctetNumber(const unsigned char *Number, unsigned char *Output, gboolean semioctet)
1162 {
1163 	unsigned char	format;
1164 	size_t		length, i, skip = 0;
1165 	unsigned char    *buffer;
1166 
1167 	length = UnicodeLength(Number);
1168 	buffer = (unsigned char*)malloc(length + 2);
1169 
1170 	if (buffer == NULL) {
1171 		return 0;
1172 	}
1173 
1174 	DecodeUnicode(Number, buffer);
1175 
1176 	/* Checking for format number */
1177 	if (buffer[0] == '+') {
1178 		format = NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN;
1179 		skip = 1;
1180 	} else if (buffer[0] == '0' && buffer[1] == '0' && buffer[2] == '0') {
1181 		/* Most likely local provider number */
1182 		format = NUMBER_UNKNOWN_NUMBERING_PLAN_ISDN;
1183 	} else if (buffer[0] == '0' && buffer[1] == '0') {
1184 		format = NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN;
1185 		skip = 2;
1186 	} else if (buffer[0] == '+' && buffer[1] == '0' && buffer[2] == '0') {
1187 		/* This is obviously wrong, but try to cope with that */
1188 		format = NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN;
1189 		skip = 3;
1190 	} else {
1191 		format = NUMBER_UNKNOWN_NUMBERING_PLAN_ISDN;
1192 	}
1193 	for (i = 0; i < length; i++) {
1194 		/* If there is something which can not be in normal
1195 		 * number, mark it as alphanumberic */
1196 		if (strchr("+0123456789*#pP", buffer[i]) == NULL) {
1197 			format = NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN;
1198 		}
1199 	}
1200 
1201 	/**
1202 	 * First byte is used for saving type of number. See GSM 03.40
1203 	 * section 9.1.2.5
1204 	 */
1205 	Output[0]=format;
1206 
1207 	/* After number type we will have number. GSM 03.40 section 9.1.2 */
1208 	switch (format) {
1209 	case NUMBER_ALPHANUMERIC_NUMBERING_PLAN_UNKNOWN:
1210 		length=GSM_PackSevenBitsToEight(0, buffer, Output+1, strlen(buffer))*2;
1211 		if (strlen(buffer)==7) length--;
1212 		break;
1213 	case NUMBER_INTERNATIONAL_NUMBERING_PLAN_ISDN:
1214 		length -= skip;
1215 		EncodeBCD (Output+1, buffer + skip, length, TRUE);
1216 		break;
1217 	default:
1218 		EncodeBCD (Output+1, buffer, length, TRUE);
1219 		break;
1220 	}
1221 
1222 	free(buffer);
1223 
1224 	if (semioctet) return length;
1225 
1226 	/* Convert number of semioctets to number of chars */
1227 	if (length % 2) length++;
1228 	return length / 2 + 1;
1229 }
1230 
CopyUnicodeString(unsigned char * Dest,const unsigned char * Source)1231 void CopyUnicodeString(unsigned char *Dest, const unsigned char *Source)
1232 {
1233 	int j = 0;
1234 
1235 	/* No need to copy if both are on same address */
1236 	if (Dest == Source) return;
1237 
1238 	while (Source[j]!=0x00 || Source[j+1]!=0x00) {
1239 		Dest[j]		= Source[j];
1240 		Dest[j+1]	= Source[j+1];
1241 		j=j+2;
1242 	}
1243 	Dest[j]		= 0;
1244 	Dest[j+1]	= 0;
1245 }
1246 
1247 /* Changes minor/major order in Unicode string */
ReverseUnicodeString(unsigned char * String)1248 void ReverseUnicodeString(unsigned char *String)
1249 {
1250 	int 		j = 0;
1251 	unsigned char	byte1, byte2;
1252 
1253 	while (String[j]!=0x00 || String[j+1]!=0x00) {
1254 		byte1		= String[j];
1255 		byte2		= String[j+1];
1256 		String[j+1]	= byte1;
1257 		String[j]	= byte2;
1258 		j=j+2;
1259 	}
1260 	String[j]	= 0;
1261 	String[j+1]	= 0;
1262 }
1263 
1264 /* All input is in Unicode. First char can show Unicode minor/major order.
1265    Output is Unicode string in Gammu minor/major order */
ReadUnicodeFile(unsigned char * Dest,const unsigned char * Source)1266 void ReadUnicodeFile(unsigned char *Dest, const unsigned char *Source)
1267 {
1268 	int j = 0, current = 0;
1269 
1270 	if (Source[0] == 0xFF && Source[1] == 0xFE) j = 2;
1271 	if (Source[0] == 0xFE && Source[1] == 0xFF) j = 2;
1272 
1273 	while (Source[j]!=0x00 || Source[j+1]!=0x00) {
1274 		if (Source[0] == 0xFF) {
1275 			Dest[current++] = Source[j+1];
1276 			Dest[current++]	= Source[j];
1277 		} else {
1278 			Dest[current++] = Source[j];
1279 			Dest[current++]	= Source[j+1];
1280 		}
1281 		j=j+2;
1282 	}
1283 	Dest[current++] = 0;
1284 	Dest[current]	= 0;
1285 }
1286 
GetBit(unsigned char * Buffer,size_t BitNum)1287 int GetBit(unsigned char *Buffer, size_t BitNum)
1288 {
1289 	return Buffer[BitNum / 8] & (1 << (7 - (BitNum % 8)));
1290 }
1291 
SetBit(unsigned char * Buffer,size_t BitNum)1292 int SetBit(unsigned char *Buffer, size_t BitNum)
1293 {
1294 	return Buffer[BitNum / 8] |= 1 << (7 - (BitNum % 8));
1295 }
1296 
ClearBit(unsigned char * Buffer,size_t BitNum)1297 int ClearBit(unsigned char *Buffer, size_t BitNum)
1298 {
1299 	return Buffer[BitNum / 8] &= 255 - (1 << (7 - (BitNum % 8)));
1300 }
1301 
BufferAlign(unsigned char * Destination,size_t * CurrentBit)1302 void BufferAlign(unsigned char *Destination, size_t *CurrentBit)
1303 {
1304 	int i=0;
1305 
1306 	while(((*CurrentBit) + i) % 8 != 0) {
1307 		ClearBit(Destination, (*CurrentBit)+i);
1308 		i++;
1309 	}
1310 
1311 	(*CurrentBit) = (*CurrentBit) + i;
1312 }
1313 
BufferAlignNumber(size_t * CurrentBit)1314 void BufferAlignNumber(size_t *CurrentBit)
1315 {
1316 	int i=0;
1317 
1318 	while(((*CurrentBit) + i) % 8 != 0) {
1319 		i++;
1320 	}
1321 
1322 	(*CurrentBit) = (*CurrentBit) + i;
1323 }
1324 
AddBuffer(unsigned char * Destination,size_t * CurrentBit,unsigned char * Source,size_t BitsToProcess)1325 void AddBuffer(unsigned char 	*Destination,
1326 	       size_t		*CurrentBit,
1327 	       unsigned char 	*Source,
1328 	       size_t 		BitsToProcess)
1329 {
1330 	size_t i;
1331 
1332 	for (i = 0; i < BitsToProcess; i++) {
1333 		if (GetBit(Source, i)) {
1334 			SetBit(Destination, (*CurrentBit)+i);
1335 		} else {
1336 			ClearBit(Destination, (*CurrentBit)+i);
1337 		}
1338 	}
1339 	(*CurrentBit) = (*CurrentBit) + BitsToProcess;
1340 }
1341 
AddBufferByte(unsigned char * Destination,size_t * CurrentBit,unsigned char Source,size_t BitsToProcess)1342 void AddBufferByte(unsigned char *Destination,
1343 		   size_t		 *CurrentBit,
1344 		   unsigned char Source,
1345 		   size_t		 BitsToProcess)
1346 {
1347 	AddBuffer(Destination, CurrentBit, &Source, BitsToProcess);
1348 }
1349 
GetBuffer(unsigned char * Source,size_t * CurrentBit,unsigned char * Destination,size_t BitsToProcess)1350 void GetBuffer(unsigned char *Source,
1351 	       size_t	     *CurrentBit,
1352 	       unsigned char *Destination,
1353 	       size_t	     BitsToProcess)
1354 {
1355 	size_t i=0;
1356 
1357 	while (i!=BitsToProcess) {
1358 		if (GetBit(Source, (*CurrentBit)+i)) {
1359 			SetBit(Destination, i);
1360 		} else {
1361 			ClearBit(Destination, i);
1362 		}
1363 		i++;
1364 	}
1365 	(*CurrentBit) = (*CurrentBit) + BitsToProcess;
1366 }
1367 
GetBufferInt(unsigned char * Source,size_t * CurrentBit,int * integer,size_t BitsToProcess)1368 void GetBufferInt(unsigned char *Source,
1369 		  size_t	*CurrentBit,
1370 		  int 		*integer,
1371 		  size_t	BitsToProcess)
1372 {
1373 	size_t l=0,z=128,i=0;
1374 
1375 	while (i!=BitsToProcess) {
1376 		if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
1377 		z=z/2;
1378 		i++;
1379 	}
1380 	*integer=l;
1381 	(*CurrentBit) = (*CurrentBit) + i;
1382 }
1383 
GetBufferI(unsigned char * Source,size_t * CurrentBit,int * result,size_t BitsToProcess)1384 void GetBufferI(unsigned char 	*Source,
1385 		size_t 		*CurrentBit,
1386 		int 		*result,
1387 		size_t 		BitsToProcess)
1388 {
1389 	size_t l=0,z,i=0;
1390 
1391 	z = 1 << (BitsToProcess - 1);
1392 
1393 	while (i!=BitsToProcess) {
1394 		if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
1395 		z=z>>1;
1396 		i++;
1397 	}
1398 	*result=l;
1399 	(*CurrentBit) = (*CurrentBit) + i;
1400 }
1401 
1402 /* Unicode char 0x00 0x01 makes blinking in some Nokia phones.
1403  * We replace single ~ chars into it. When user give double ~, it's replaced
1404  * to single ~
1405  */
EncodeUnicodeSpecialNOKIAChars(unsigned char * dest,const unsigned char * src,size_t len)1406 void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
1407 {
1408 	size_t 	i,current = 0;
1409 	gboolean 	special=FALSE;
1410 
1411 	for (i = 0; i < len; i++) {
1412 		if (special) {
1413 			if (src[i*2] == 0x00 && src[i*2+1] == '~') {
1414 				dest[current++]	= 0x00;
1415 				dest[current++]	= '~';
1416 			} else {
1417 				dest[current++]	= 0x00;
1418 				dest[current++]	= 0x01;
1419 				dest[current++]	= src[i*2];
1420 				dest[current++]	= src[i*2+1];
1421 			}
1422 			special = FALSE;
1423 		} else {
1424 			if (src[i*2] == 0x00 && src[i*2+1] == '~') {
1425 				special = TRUE;
1426 			} else {
1427 				dest[current++]	= src[i*2];
1428 				dest[current++]	= src[i*2+1];
1429 			}
1430 		}
1431 	}
1432 	if (special) {
1433 		dest[current++]	= 0x00;
1434 		dest[current++]	= 0x01;
1435 	}
1436 	dest[current++] = 0x00;
1437 	dest[current] = 0x00;
1438 }
1439 
DecodeUnicodeSpecialNOKIAChars(unsigned char * dest,const unsigned char * src,size_t len)1440 void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, size_t len)
1441 {
1442 	size_t i=0,current=0;
1443 
1444 	for (i=0;i<len;i++) {
1445 		switch (src[2*i]) {
1446 		case 0x00:
1447 			switch (src[2*i+1]) {
1448 			case 0x01:
1449 				dest[current++] = 0x00;
1450 				dest[current++] = '~';
1451 				break;
1452 			case '~':
1453 				dest[current++] = 0x00;
1454 				dest[current++] = '~';
1455 				dest[current++] = 0x00;
1456 				dest[current++] = '~';
1457 				break;
1458 			default:
1459 				dest[current++] = src[i*2];
1460 				dest[current++] = src[i*2+1];
1461 			}
1462 			break;
1463 		default:
1464 			dest[current++] = src[i*2];
1465 			dest[current++] = src[i*2+1];
1466 		}
1467 	}
1468 	dest[current++] = 0x00;
1469 	dest[current] = 0x00;
1470 }
1471 
1472 
1473 /* Compares two Unicode strings without regarding to case.
1474  * Return TRUE, when they're equal
1475  */
mywstrncasecmp(unsigned const char * a,unsigned const char * b,int num)1476 gboolean mywstrncasecmp(unsigned const  char *a, unsigned const  char *b, int num)
1477 {
1478  	int 		i;
1479   	gammu_char_t 	wc,wc2;
1480 
1481         if (a == NULL || b == NULL) return FALSE;
1482 
1483 	if (num == 0) num = -1;
1484 
1485 	for (i = 0; i != num; i++) {
1486 		if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) && (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return TRUE;
1487 		if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) || (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return FALSE;
1488  		wc  = a[i*2+1] | (a[i*2] << 8);
1489  		wc2 = b[i*2+1] | (b[i*2] << 8);
1490  		if (towlower(wc) != towlower(wc2)) return FALSE;
1491  	}
1492 	return TRUE;
1493 }
1494 
1495 /* wcscmp in Mandrake 9.0 is wrong */
mywstrncmp(unsigned const char * a,unsigned const char * b,int num)1496 gboolean mywstrncmp(unsigned const  char *a, unsigned const  char *b, int num)
1497 {
1498 	int i=0;
1499 
1500 	while (1) {
1501 		if (a[i*2] != b[i*2] || a[i*2+1] != b[i*2+1]) return FALSE;
1502 		if (a[i*2] == 0x00 && a[i*2+1] == 0x00) return TRUE;
1503 		i++;
1504 		if (num == i) return TRUE;
1505 	}
1506 }
1507 
1508 /* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
myiswspace(unsigned const char * src)1509 gboolean myiswspace(unsigned const char *src)
1510 {
1511 #ifndef HAVE_ISWSPACE
1512  	int 		o;
1513 	unsigned char	dest[10];
1514 #endif
1515  	gammu_char_t 	wc;
1516 
1517 	wc = src[1] | (src[0] << 8);
1518 
1519 #ifndef HAVE_ISWSPACE
1520 	o = DecodeWithUnicodeAlphabet(wc, dest);
1521 	if (o == 1) {
1522 		if (isspace(((int)dest[0]))!=0) return TRUE;
1523 		return FALSE;
1524 	}
1525 	return FALSE;
1526 #else
1527 	if (iswspace(wc)) return TRUE;
1528 	return FALSE;
1529 #endif
1530 }
1531 
1532 /*
1533  * Following code is based on wcsstr from the GNU C Library, original
1534  * comment follows:
1535  */
1536 /*
1537  * The original strstr() file contains the following comment:
1538  *
1539  * My personal strstr() implementation that beats most other algorithms.
1540  * Until someone tells me otherwise, I assume that this is the
1541  * fastest implementation of strstr() in C.
1542  * I deliberately chose not to comment it.  You should have at least
1543  * as much fun trying to understand it, as I had to write it :-).
1544  *
1545  * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
1546 
mywstrstr(const unsigned char * haystack,const unsigned char * needle)1547 unsigned char *mywstrstr (const unsigned char *haystack, const unsigned char *needle)
1548 {
1549 /* One crazy define to convert unicode used in Gammu to standard gammu_char_t */
1550 #define tolowerwchar(x) (towlower((gammu_char_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) )))
1551 	register gammu_int_t a, b, c;
1552 	register const unsigned char *rhaystack, *rneedle;
1553 
1554 
1555 	if ((b = tolowerwchar(*needle)) != L'\0') {
1556 		haystack -= 2;				/* possible ANSI violation */
1557 		do {
1558 			haystack += 2;
1559 			if ((c = tolowerwchar(*haystack)) == L'\0')
1560 				goto ret0;
1561 		} while (c != b);
1562 
1563 		needle += 2;
1564 		if ((c = tolowerwchar(*needle)) == L'\0')
1565 			goto foundneedle;
1566 		needle += 2;
1567 		goto jin;
1568 
1569 		for (;;) {
1570 			do {
1571 				haystack += 2;
1572 				if ((a = tolowerwchar(*haystack)) == L'\0')
1573 					goto ret0;
1574 				if (a == b)
1575 					break;
1576 				haystack += 2;
1577 				if ((a = tolowerwchar(*haystack)) == L'\0')
1578 					goto ret0;
1579 shloop:				;
1580 			} while (a != b);
1581 
1582 jin:			haystack += 2;
1583 			if ((a = tolowerwchar(*haystack)) == L'\0')
1584 				goto ret0;
1585 
1586 			if (a != c)
1587 				goto shloop;
1588 
1589 			rhaystack = haystack + 2;
1590 			haystack -= 2;
1591 			rneedle = needle;
1592 			if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle)))
1593 				do {
1594 					if (a == L'\0')
1595 						goto foundneedle;
1596 					rhaystack += 2;
1597 					needle += 2;
1598 					if (tolowerwchar(*rhaystack) != (a = tolowerwchar(*needle)))
1599 						break ;
1600 					if (a == L'\0')
1601 						goto foundneedle;
1602 					rhaystack += 2;
1603 					needle += 2;
1604 				} while (tolowerwchar(*rhaystack) == (a = tolowerwchar(*needle)));
1605 
1606 			needle = rneedle;		  /* took the register-poor approach */
1607 
1608 			if (a == L'\0')
1609 				break;
1610 		}
1611 	}
1612 foundneedle:
1613 	return (unsigned char *)haystack;
1614 ret0:
1615 	return NULL;
1616 #undef tolowerwchar
1617 }
1618 
MyGetLine(char * Buffer,size_t * Pos,char * OutBuffer,size_t MaxLen,size_t MaxOutLen,gboolean MergeLines)1619 GSM_Error MyGetLine(char *Buffer, size_t *Pos, char *OutBuffer, size_t MaxLen, size_t MaxOutLen, gboolean MergeLines)
1620 {
1621 	gboolean skip = FALSE;
1622 	gboolean quoted_printable = FALSE;
1623 	gboolean was_cr = FALSE, was_lf = FALSE;
1624 	size_t pos;
1625 	int tmp;
1626 
1627 	OutBuffer[0] = 0;
1628 	pos = 0;
1629 	if (Buffer == NULL) return ERR_NONE;
1630 	for (; (*Pos) < MaxLen; (*Pos)++) {
1631 		switch (Buffer[*Pos]) {
1632 		case 0x00:
1633 			return ERR_NONE;
1634 		case 0x0A:
1635 		case 0x0D:
1636 			if (skip) {
1637 				if (Buffer[*Pos] == 0x0d) {
1638 					if (was_cr && skip) return ERR_NONE;
1639 					was_cr = TRUE;
1640 				} else {
1641 					if (was_lf && skip) return ERR_NONE;
1642 					was_lf = TRUE;
1643 				}
1644 			} else {
1645 				if (MergeLines) {
1646 					/* (Quote printable new line) Does string end with = ? */
1647 					if (quoted_printable && pos > 0 && OutBuffer[pos - 1] == '=') {
1648 						pos--;
1649 						OutBuffer[pos] = 0;
1650 						skip = TRUE;
1651 						was_cr = (Buffer[*Pos] == 0x0d);
1652 						was_lf = (Buffer[*Pos] == 0x0a);
1653 						break;
1654 					}
1655 					/* (vCard continuation) Next line start with space? */
1656 					tmp = *Pos + 1;
1657 					if (Buffer[*Pos + 1] == 0x0a || Buffer[*Pos + 1] == 0x0d) {
1658 						tmp += 1;
1659 					}
1660 					if (Buffer[tmp] == ' ') {
1661 						*Pos = tmp;
1662 						break;
1663 					}
1664 					/* We ignore empty lines in this mode */
1665 					if (pos == 0) {
1666 						continue;
1667 					}
1668 				}
1669 				if (Buffer[*Pos] == 0x0d && (*Pos)+1 < MaxLen && Buffer[*Pos + 1] == 0x0a) {
1670 					/* Skip \r\n */
1671 					(*Pos) += 2;
1672 				} else {
1673 					/* Skip single \r or \n */
1674 					(*Pos)++;
1675 				}
1676 				return ERR_NONE;
1677 			}
1678 			break;
1679 		default:
1680 			/* Detect quoted printable for possible escaping */
1681 			if (Buffer[*Pos] == ':' &&
1682 					strstr(OutBuffer, ";ENCODING=QUOTED-PRINTABLE") != NULL) {
1683 				quoted_printable = TRUE;
1684 			}
1685 			skip = FALSE;
1686 			OutBuffer[pos]     = Buffer[*Pos];
1687 			pos++;
1688 			OutBuffer[pos] = 0;
1689 			if (pos + 1 >= MaxOutLen) return ERR_MOREMEMORY;
1690 		}
1691 	}
1692 	return ERR_NONE;
1693 }
1694 
GSM_GetVCSLine(char ** OutBuffer,char * Buffer,size_t * Pos,size_t MaxLen,gboolean MergeLines)1695 GSM_Error GSM_GetVCSLine(char **OutBuffer, char *Buffer, size_t *Pos, size_t MaxLen, gboolean MergeLines)
1696 {
1697 	gboolean skip = FALSE;
1698 	gboolean quoted_printable = FALSE;
1699 	gboolean was_cr = FALSE, was_lf = FALSE;
1700 	size_t pos=0;
1701 	int tmp=0;
1702 	size_t OutLen = 200;
1703 
1704 	*OutBuffer = (char *)malloc(OutLen);
1705 	if (*OutBuffer == NULL) return ERR_MOREMEMORY;
1706 	(*OutBuffer)[0] = 0;
1707 	pos = 0;
1708 	if (Buffer == NULL) return ERR_NONE;
1709 	while ((*Pos) < MaxLen) {
1710 		switch (Buffer[*Pos]) {
1711 		case 0x00:
1712 			return ERR_NONE;
1713 		case 0x0A:
1714 		case 0x0D:
1715 			if (skip) {
1716 				if (Buffer[*Pos] == 0x0d) {
1717 					if (was_cr && skip) return ERR_NONE;
1718 					was_cr = TRUE;
1719 				} else {
1720 					if (was_lf && skip) return ERR_NONE;
1721 					was_lf = TRUE;
1722 				}
1723 			}
1724 			if (pos != 0 && !skip) {
1725 				if (MergeLines) {
1726 					/* (Quote printable new line) Does string end with = ? */
1727 					if ((*OutBuffer)[pos - 1] == '=' && quoted_printable) {
1728 						pos--;
1729 						(*OutBuffer)[pos] = 0;
1730 						skip = TRUE;
1731 						was_cr = (Buffer[*Pos] == 0x0d);
1732 						was_lf = (Buffer[*Pos] == 0x0a);
1733 						break;
1734 					}
1735 					/* (vCard continuation) Next line start with space? */
1736 					tmp = *Pos + 1;
1737 					if (Buffer[*Pos + 1] == 0x0a || Buffer[*Pos + 1] == 0x0d) {
1738 						tmp += 1;
1739 					}
1740 					if (Buffer[tmp] == ' ') {
1741 						*Pos = tmp;
1742 						break;
1743 					}
1744 				}
1745 				return ERR_NONE;
1746 			}
1747 			break;
1748 		default:
1749 			/* Detect quoted printable for possible escaping */
1750 			if (Buffer[*Pos] == ':' &&
1751 					strstr(*OutBuffer, ";ENCODING=QUOTED-PRINTABLE") != NULL) {
1752 				quoted_printable = TRUE;
1753 			}
1754 			skip = FALSE;
1755 			(*OutBuffer)[pos]     = Buffer[*Pos];
1756 			pos++;
1757 			(*OutBuffer)[pos] = 0;
1758 			if (pos + 2 >= OutLen) {
1759 				OutLen += 100;
1760 				*OutBuffer = (char *)realloc(*OutBuffer, OutLen);
1761 				if (*OutBuffer == NULL) return ERR_MOREMEMORY;
1762 			}
1763 		}
1764 		(*Pos)++;
1765 	}
1766 	return ERR_NONE;
1767 }
1768 
1769 
StringToDouble(char * text,double * d)1770 void StringToDouble(char *text, double *d)
1771 {
1772 	gboolean 		before=TRUE;
1773 	double		multiply = 1;
1774 	unsigned int 	i;
1775 
1776 	*d = 0;
1777 	for (i=0;i<strlen(text);i++) {
1778 		if (isdigit((int)text[i])) {
1779 			if (before) {
1780 				(*d)=(*d)*10+(text[i]-'0');
1781 			} else {
1782 				multiply=multiply*0.1;
1783 				(*d)=(*d)+(text[i]-'0')*multiply;
1784 			}
1785 		}
1786 		if (text[i]=='.' || text[i]==',') before=FALSE;
1787 	}
1788 }
1789 
1790 /* When char can be converted, convert it from Unicode to UTF8 */
EncodeWithUTF8Alphabet(unsigned long src,unsigned char * ret)1791 int EncodeWithUTF8Alphabet(unsigned long src, unsigned char *ret)
1792 {
1793 	if (src < 0x80) {
1794 		ret[0] = src;
1795 		return 1;
1796 	} else if (src < 0x800) {
1797 		ret[0] = 192 + (src / 64);
1798 		ret[1] = 128 + (src % 64);
1799 		return 2;
1800 	} else if (src < 0x10000) {
1801 		ret[0] = 224 + (src / (64 * 64));
1802 		ret[1] = 128 + ((src / 64) % 64);
1803 		ret[2] = 128 + (src % 64);
1804 		return 3;
1805 	} else if (src < 0x200000) {
1806 		ret[0] = 240 + (src / (64 * 64 * 64));
1807 		ret[1] = 128 + ((src / (64 * 64)) % 64);
1808 		ret[2] = 128 + ((src / 64) % 64);
1809 		ret[3] = 128 + (src % 64);
1810 		return 4;
1811 	} else if (src < 0x4000000) {
1812 		ret[0] = 248 + (src / (64 * 64 * 64 * 64));
1813 		ret[1] = 128 + ((src / (64 * 64 * 64)) % 64);
1814 		ret[2] = 128 + ((src / (64 * 64)) % 64);
1815 		ret[3] = 128 + ((src / 64) % 64);
1816 		ret[4] = 128 + (src % 64);
1817 		return 5;
1818 	} else if (src < 0x80000000L) {
1819 		ret[0] = 252 + (src / (64 * 64 * 64 * 64 * 64));
1820 		ret[1] = 128 + ((src / (64 * 64 * 64 * 64)) % 64);
1821 		ret[2] = 128 + ((src / (64 * 64 * 64)) % 64);
1822 		ret[3] = 128 + ((src / (64 * 64)) % 64);
1823 		ret[4] = 128 + ((src / 64) % 64);
1824 		ret[5] = 128 + (src % 64);
1825 		return 6;
1826 	}
1827 
1828 	ret[0] = src;
1829 	return 1;
1830 }
1831 
1832 /* Make UTF8 string from Unicode input string */
EncodeUTF8QuotedPrintable(char * dest,const unsigned char * src)1833 gboolean EncodeUTF8QuotedPrintable(char *dest, const unsigned char *src)
1834 {
1835 	size_t i, j=0, z, w, len;
1836 	unsigned char	mychar[8];
1837 	gboolean		retval = FALSE;
1838 	unsigned long value, second;
1839 
1840 	len = UnicodeLength(src);
1841 
1842 	for (i = 0; i < len; i++) {
1843 		value = src[i * 2] * 256 + src[i * 2 + 1];
1844 		/* Decode UTF-16 */
1845 		if (value >= 0xD800 && value <= 0xDBFF) {
1846 			if ((i + 1) < len) {
1847 				second = src[(i + 1) * 2] * 256 + src[(i + 1) * 2 + 1];
1848 				if (second >= 0xDC00 && second <= 0xDFFF) {
1849 					value = ((value - 0xD800) << 10) + (second - 0xDC00) + 0x010000;
1850 				}
1851 			} else {
1852 				/* Surrogate at the end of string */
1853 				value = 0xFFFD; /* REPLACEMENT CHARACTER */
1854 			}
1855 		}
1856 		z = EncodeWithUTF8Alphabet(value, mychar);
1857 		if (z == 1 && mychar[0] < 32) {
1858 			/* Need quoted printable for chars < 32 */
1859 			sprintf(dest + j, "=%02X", mychar[0]);
1860 			j = j + 3;
1861 		} else if (z == 1) {
1862 			memcpy(dest + j, mychar, z);
1863 			j += z;
1864 		} else {
1865 			/* Quoted printable unicode */
1866 			for (w = 0; w < z; w++) {
1867 				sprintf(dest + j, "=%02X", mychar[w]);
1868 				j = j + 3;
1869 			}
1870 			if (z > 1) {
1871 				retval = TRUE;
1872 			}
1873 	    	}
1874 	}
1875 	dest[j] = 0;
1876 	return retval;
1877 }
1878 
EncodeUTF8(char * dest,const unsigned char * src)1879 gboolean EncodeUTF8(char *dest, const unsigned char *src)
1880 {
1881 	size_t i, j=0, z, len;
1882 	unsigned char	mychar[8];
1883 	gboolean		retval = FALSE;
1884 	unsigned long value, second;
1885 
1886 	len = UnicodeLength(src);
1887 
1888 	for (i = 0; i < len; i++) {
1889 		value = src[i * 2] * 256 + src[i * 2 + 1];
1890 		/* Decode UTF-16 */
1891 		if (value >= 0xD800 && value <= 0xDBFF ) {
1892 			if ((i + 1) < len) {
1893 				second = src[(i + 1) * 2] * 256 + src[(i + 1) * 2 + 1];
1894 				if (second >= 0xDC00 && second <= 0xDFFF) {
1895 					i++;
1896 					value = ((value - 0xD800) << 10) + (second - 0xDC00) + 0x010000;
1897 				}
1898 			} else {
1899 				/* Surrogate at the end of string */
1900 				value = 0xFFFD; /* REPLACEMENT CHARACTER */
1901 			}
1902 		}
1903 		z = EncodeWithUTF8Alphabet(value, mychar);
1904 		memcpy(dest + j, mychar, z);
1905 		j += z;
1906 		if (z > 1) {
1907 			retval = TRUE;
1908 		}
1909 	}
1910 	dest[j] = 0;
1911 	return retval;
1912 }
1913 
1914 /* Decode UTF8 char to Unicode char */
DecodeWithUTF8Alphabet(const unsigned char * src,gammu_char_t * dest,size_t len)1915 int DecodeWithUTF8Alphabet(const unsigned char *src, gammu_char_t *dest, size_t len)
1916 {
1917 	gammu_char_t src0, src1, src2, src3;
1918 	if (len < 1) {
1919 		return 0;
1920 	}
1921 	src0 = src[0];
1922 
1923 	// 1-byte sequence (no continuation bytes)
1924 	if ((src0 & 0x80) == 0) {
1925 		(*dest) = src0;
1926 		return 1;
1927 	}
1928 
1929 	if (len < 2) {
1930 		return 0;
1931 	}
1932 	src1 = src[1];
1933 
1934 	// 2-byte sequence
1935 	if ((src0 & 0xE0) == 0xC0) {
1936 		(*dest) = ((src0 & 0x1F) << 6) | (src1 & 0x3f);
1937 		if (*dest >= 0x80) {
1938 			return 2;
1939 		} else {
1940 			return 0;
1941 		}
1942 	}
1943 
1944 	if (len < 3) {
1945 		return 0;
1946 	}
1947 	src2 = src[2];
1948 
1949 	// 3-byte sequence (may include unpaired surrogates)
1950 	if ((src0 & 0xF0) == 0xE0) {
1951 		(*dest) = ((src0 & 0x0F) << 12) | ((src1 & 0x3f) << 6) | (src2 & 0x3f);
1952 		if ((*dest) >= 0x0800) {
1953 			if ((*dest) >= 0xD800 && (*dest) <= 0xDFFF) {
1954 				return 0;
1955 			}
1956 			return 3;
1957 		}
1958 	}
1959 
1960 	if (len < 4) {
1961 		return 0;
1962 	}
1963 	src3 = src[3];
1964 
1965 	// 4-byte sequence
1966 	if ((src0 & 0xF8) == 0xF0) {
1967 		(*dest) = ((src0 & 0x07) << 0x12) | ((src1 & 0x3f) << 0x0C) |
1968 			((src2 & 0x3f) << 0x06) | (src3 & 0x3f);
1969 		if ((*dest) >= 0x010000 && (*dest) <= 0x10FFFF) {
1970 			return 4;
1971 		}
1972 	}
1973 
1974 	return 0;
1975 }
1976 
1977 
1978 /* Make Unicode string from ISO-8859-1 string */
DecodeISO88591QuotedPrintable(unsigned char * dest,const unsigned char * src,size_t len)1979 void DecodeISO88591QuotedPrintable(unsigned char *dest, const unsigned char *src, size_t len)
1980 {
1981 	size_t 		i = 0, j = 0;
1982 
1983 	while (i < len) {
1984 		if (src[i] == '=' && i + 2 < len
1985 			&& DecodeWithHexBinAlphabet(src[i + 1]) != -1
1986 			&& DecodeWithHexBinAlphabet(src[i + 2]) != -1) {
1987 			dest[j++] = 0;
1988 			dest[j++] = 16 * DecodeWithHexBinAlphabet(src[i + 1]) + DecodeWithHexBinAlphabet(src[i + 2]);
1989 			i += 2;
1990 		} else {
1991 			dest[j++] = 0;
1992 			dest[j++] = src[i];
1993 		}
1994 		i++;
1995 	}
1996 	dest[j++] = 0;
1997 	dest[j] = 0;
1998 }
1999 
2000 /* Make Unicode string from UTF8 string */
DecodeUTF8QuotedPrintable(unsigned char * dest,const char * src,size_t len)2001 void DecodeUTF8QuotedPrintable(unsigned char *dest, const char *src, size_t len)
2002 {
2003 	size_t 		i,j=0;
2004 	int		z;
2005 	unsigned char	mychar[10];
2006 	gammu_char_t		ret;
2007 
2008 	for (i = 0; i<=len; ) {
2009 		z=0;
2010 		while (TRUE) {
2011 			if (src[z*3+i] != '=' || z*3+i+3>len ||
2012 			    DecodeWithHexBinAlphabet(src[z*3+i+1])==-1 ||
2013 			    DecodeWithHexBinAlphabet(src[z*3+i+2])==-1) {
2014 				break;
2015 			}
2016 			mychar[z] = 16*DecodeWithHexBinAlphabet(src[z*3+i+1])+DecodeWithHexBinAlphabet(src[z*3+i+2]);
2017 			z++;
2018 			/* Is it plain ASCII? */
2019 			if (z == 1 && mychar[0] < 194) break;
2020 			/* Do we already have valid UTF-8 char? */
2021 			if (DecodeWithUTF8Alphabet(mychar, &ret, z) == z) break;
2022 		}
2023 		if (z>0) {
2024 			i += z * 3;
2025 			/*  we ignore wrong sequence */
2026 			if (DecodeWithUTF8Alphabet(mychar, &ret, z)==0) continue;
2027 		} else {
2028 			i += EncodeWithUnicodeAlphabet(&src[i], &ret);
2029 		}
2030 		if (StoreUTF16(dest + j, ret)) {
2031 			j += 4;
2032 		} else {
2033 			j += 2;
2034 		}
2035 	}
2036 	dest[j++] = 0;
2037 	dest[j] = 0;
2038 }
2039 
DecodeUTF8(unsigned char * dest,const char * src,size_t len)2040 void DecodeUTF8(unsigned char *dest, const char *src, size_t len)
2041 {
2042 	size_t 		i=0,j=0,z;
2043 	gammu_char_t		ret;
2044 
2045 	while (i < len) {
2046 		z = DecodeWithUTF8Alphabet(src+i, &ret, len - i);
2047 		if (z < 1) {
2048 			break;
2049 		}
2050 		i += z;
2051 		if (StoreUTF16(dest + j, ret)) {
2052 			j += 4;
2053 		} else {
2054 			j += 2;
2055 		}
2056 	}
2057 	dest[j++] = 0;
2058 	dest[j] = 0;
2059 }
2060 
DecodeXMLUTF8(unsigned char * dest,const char * src,size_t len)2061 void DecodeXMLUTF8(unsigned char *dest, const char *src, size_t len)
2062 {
2063 	char *tmp;
2064 	char *pos, *pos_end;
2065 	const char *lastpos;
2066 	char *entity;
2067 	unsigned long long int c;
2068 	int tmplen;
2069 
2070 	/* Allocate buffer */
2071 	tmp = (char *)calloc(2 * len, sizeof(char));
2072 	if (tmp == NULL) {
2073 		/* We have no memory for XML decoding */
2074 		DecodeUTF8(dest, src, len);
2075 		return;
2076 	}
2077 	if (src == NULL) {
2078 		*dest = 0;
2079 		free(tmp);
2080 		return;
2081 	}
2082 
2083 	/* Find ampersand and decode the */
2084 	lastpos = src;
2085 	while ((*lastpos != 0) && ((pos = strchr(lastpos, '&')) != NULL)) {
2086 		/* Store current string */
2087 		strncat(tmp, lastpos, pos - lastpos);
2088 		lastpos = pos;
2089 		/* Skip ampersand */
2090 		pos++;
2091 		/* Detect end of string */
2092 		if (*pos == 0) break;
2093 		/* Find entity length */
2094 		pos_end = strchr(pos, ';');
2095 		if (pos_end - pos > 6 || pos_end == NULL) {
2096 			if (pos_end == NULL) {
2097 				dbgprintf(NULL, "No entity end found, ignoring!\n");
2098 			} else {
2099 				dbgprintf(NULL, "Too long html entity, ignoring!\n");
2100 			}
2101 			strncat(tmp, lastpos, 1);
2102 			lastpos++;
2103 			continue;
2104 		}
2105 		/* Create entity */
2106 		/* strndup would be better, but not portable */
2107 		entity = strdup(pos);
2108 		if (entity == NULL) break;
2109 		entity[pos_end - pos] = 0;
2110 		dbgprintf(NULL, "Found XML entity: %s\n", entity);
2111 		if (entity[0] == '#') {
2112 			if (entity[1] == 'x' || entity[1] == 'X') {
2113 				c = strtoull(entity + 2, NULL, 16);
2114 			} else {
2115 				c = strtoull(entity + 1, NULL, 10);
2116 			}
2117 			dbgprintf(NULL, "Unicode char 0x%04llx\n", c);
2118 			tmplen = strlen(tmp);
2119 			tmplen += EncodeWithUTF8Alphabet(c, tmp + tmplen);
2120 			tmp[tmplen] = 0;
2121 		} else if (strcmp(entity, "amp") == 0) {
2122 			strcat(tmp, "&");
2123 		} else if (strcmp(entity, "apos") == 0) {
2124 			strcat(tmp, "'");
2125 		} else if (strcmp(entity, "gt") == 0) {
2126 			strcat(tmp, ">");
2127 		} else if (strcmp(entity, "lt") == 0) {
2128 			strcat(tmp, "<");
2129 		} else if (strcmp(entity, "quot") == 0) {
2130 			strcat(tmp, "\"");
2131 		} else {
2132 			dbgprintf(NULL, "Could not decode XML entity!\n");
2133 			strncat(tmp, lastpos, pos_end - pos + 1);
2134 		}
2135 		free(entity);
2136 		entity=NULL;
2137 		lastpos = pos_end + 1;
2138 	}
2139 	/* Copy rest of string */
2140 	strcat(tmp, lastpos);
2141 	DecodeUTF8(dest, tmp, strlen(tmp));
2142 	free(tmp);
2143 	tmp=NULL;
2144 }
2145 
DecodeUTF7(unsigned char * dest,const unsigned char * src,size_t len)2146 void DecodeUTF7(unsigned char *dest, const unsigned char *src, size_t len)
2147 {
2148 	size_t 		i=0,j=0,z,p;
2149 	gammu_char_t		ret;
2150 
2151 	while (i<=len) {
2152 		if (len-5>=i) {
2153 			if (src[i] == '+') {
2154 				z=0;
2155 				while (src[z+i+1] != '-' && z+i+1<len) z++;
2156 				p=DecodeBASE64(src+i+1, dest+j, z);
2157 				if (p%2 != 0) p--;
2158 				j+=p;
2159 				i+=z+2;
2160 			} else {
2161 				i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
2162 				if (StoreUTF16(dest + j, ret)) {
2163 					j += 4;
2164 				} else {
2165 					j += 2;
2166 				}
2167 			}
2168 		} else {
2169 			i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
2170 			if (StoreUTF16(dest + j, ret)) {
2171 				j += 4;
2172 			} else {
2173 				j += 2;
2174 			}
2175 		}
2176 	}
2177 	dest[j++] = 0;
2178 	dest[j] = 0;
2179 }
2180 
2181 /*
2182 Bob Trower 08/04/01
2183 Copyright (c) Trantor Standard Systems Inc., 2001
2184 
2185 Permission is hereby granted, free of charge, to any person
2186 obtaining a copy of this software and associated
2187 documentation files (the "Software"), to deal in the
2188 Software without restriction, including without limitation
2189 the rights to use, copy, modify, merge, publish, distribute,
2190 sublicense, and/or sell copies of the Software, and to
2191 permit persons to whom the Software is furnished to do so,
2192 subject to the following conditions:
2193 
2194 The above copyright notice and this permission notice shall
2195 be included in all copies or substantial portions of the
2196 Software.
2197 
2198 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
2199 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
2200 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
2201 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
2202 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2203 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2204 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2205 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2206 */
2207 
EncodeBASE64Block(const unsigned char in[3],char out[4],const size_t len)2208 static void EncodeBASE64Block(const unsigned char in[3], char out[4], const size_t len)
2209 {
2210 	/* BASE64 translation Table as described in RFC1113 */
2211 	unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2212 
2213 	out[0] = cb64[ in[0] >> 2 ];
2214 	out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
2215 	out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
2216 	out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
2217 }
2218 
EncodeBASE64(const unsigned char * Input,char * Output,const size_t Length)2219 void EncodeBASE64(const unsigned char *Input, char *Output, const size_t Length)
2220 {
2221 	unsigned char 	in[3], out[4];
2222 	size_t 		i, pos = 0, len, outpos = 0;
2223 
2224 	while (pos < Length) {
2225 		len = 0;
2226 		for (i = 0; i < 3; i++) {
2227 			in[i] = 0;
2228 			if (pos < Length) {
2229 				in[i] = Input[pos];
2230 				len++;
2231 				pos++;
2232 			}
2233 		}
2234 	        if(len) {
2235 			EncodeBASE64Block(in, out, len);
2236 			for (i = 0; i < 4; i++) Output[outpos++] = out[i];
2237 		}
2238         }
2239 
2240 	Output[outpos] = 0;
2241 }
2242 
DecodeBASE64Block(const char in[4],unsigned char out[3])2243 static void DecodeBASE64Block(const char in[4], unsigned char out[3])
2244 {
2245 	out[0] = (unsigned char) ((in[0] << 2) | (in[1] >> 4));
2246 	out[1] = (unsigned char) ((in[1] << 4) | (in[2] >> 2));
2247 	out[2] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
2248 }
2249 
DecodeBASE64(const char * Input,unsigned char * Output,const size_t Length)2250 int DecodeBASE64(const char *Input, unsigned char *Output, const size_t Length)
2251 {
2252 	unsigned char 	cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
2253 	unsigned char 	in[4], out[3], v;
2254 	size_t 		i, len, pos = 0, outpos = 0;
2255 
2256 	while (pos < Length) {
2257 		len = 0;
2258 	        for(i = 0; i < 4; i++) {
2259 	       		v = 0;
2260 			while(v == 0) {
2261 				if (pos >= Length) break;
2262 		                v = (unsigned char) Input[pos++];
2263                 		v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
2264 				if (v) v = (unsigned char) ((v == '$') ? 0 : v - 61);
2265 			}
2266 			if(pos<=Length) {
2267 				if (v) {
2268 					len++;
2269 					in[i] = (unsigned char) (v - 1);
2270 				}
2271 			}
2272 		}
2273 		if (len) {
2274 			DecodeBASE64Block(in, out);
2275 			for(i = 0; i < len - 1; i++) Output[outpos++] = out[i];
2276 		}
2277 	}
2278 	Output[outpos] = 0;
2279 	return outpos;
2280 }
2281 
2282 #ifdef ICONV_FOUND
2283 
2284 #include <iconv.h>
2285 
2286 #ifdef ICONV_SECOND_ARGUMENT_IS_CONST
2287 #  define SECOND_ICONV_ARG const char *
2288 #else
2289 #  define SECOND_ICONV_ARG char *
2290 #endif
2291 
IconvDecode(const char * charset,const char * input,const size_t inlen,unsigned char * output,size_t outlen)2292 gboolean IconvDecode(const char *charset, const char *input, const size_t inlen, unsigned char *output, size_t outlen)
2293 {
2294 	iconv_t ic;
2295 	/* Add one to convert also trailing zero, this is broken for
2296 	 * multibyte input, but we don't use iconv for this so far */
2297 	size_t rest = inlen + 1;
2298 	SECOND_ICONV_ARG in;
2299 	char *out;
2300 
2301 	ic = iconv_open("UCS-2BE", charset);
2302 	if (ic == (iconv_t)(-1)) return FALSE;
2303 
2304 	/* I know I loose const here, but it's iconv choice... */
2305 	in = (SECOND_ICONV_ARG)input;
2306 	out = output;
2307 	iconv(ic, &in, &rest, &out, &outlen);
2308 
2309 	iconv_close(ic);
2310 
2311 	return (rest == 0);
2312 }
2313 
IconvEncode(const char * charset,const unsigned char * input,const size_t inlen,char * output,size_t outlen)2314 gboolean IconvEncode(const char *charset, const unsigned char *input, const size_t inlen, char *output, size_t outlen)
2315 {
2316 	iconv_t ic;
2317 	size_t rest = inlen;
2318 	SECOND_ICONV_ARG in;
2319 	char *out;
2320 
2321 	ic = iconv_open(charset, "UCS-2BE");
2322 	if (ic == (iconv_t)(-1)) return FALSE;
2323 
2324 	/* I know I loose const here, but it's iconv choice... */
2325 	in = (SECOND_ICONV_ARG)input;
2326 	out = output;
2327 	iconv(ic, &in, &rest, &out, &outlen);
2328 
2329 	iconv_close(ic);
2330 
2331 	return (rest == 0);
2332 }
2333 #endif
2334 
2335 
2336 /* How should editor hadle tabs in this file? Add editor commands here.
2337  * vim: noexpandtab sw=8 ts=8 sts=8:
2338  */
2339