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