summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/misc
Side-by-side diff
Diffstat (limited to 'gammu/emb/common/misc') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/misc/cfg.c332
-rw-r--r--gammu/emb/common/misc/cfg.h42
-rw-r--r--gammu/emb/common/misc/coding/coding.c1409
-rw-r--r--gammu/emb/common/misc/coding/coding.h133
-rw-r--r--gammu/emb/common/misc/coding/md5.c298
-rw-r--r--gammu/emb/common/misc/coding/md5.h6
-rw-r--r--gammu/emb/common/misc/misc.c591
-rw-r--r--gammu/emb/common/misc/misc.h137
8 files changed, 2948 insertions, 0 deletions
diff --git a/gammu/emb/common/misc/cfg.c b/gammu/emb/common/misc/cfg.c
new file mode 100644
index 0000000..1c74874
--- a/dev/null
+++ b/gammu/emb/common/misc/cfg.c
@@ -0,0 +1,332 @@
+/* (c) 2002-2004 by Marcin Wiacek */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef __OpenBSD__
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+#include "../config.h"
+#include "coding/coding.h"
+#include "cfg.h"
+#include "misc.h"
+
+/*
+ * Read information from file in Windows INI format style
+ */
+INI_Section *INI_ReadFile(char *FileName, bool Unicode)
+{
+ FILE *f;
+ bool FFEEUnicode=false;
+ int level = -1, buffer1used, buffer2used;
+ int bufferused, i, buffused=1000,buffread=1000, num;
+ unsigned char ch[3], *buffer = NULL;
+ unsigned char *buffer2 = NULL, *buffer1 = NULL, buff[1000];
+ INI_Section *INI_info = NULL, *INI_head = NULL, *heading;
+ INI_Entry *entry;
+
+ f = fopen(FileName,"rb");
+ if (f == NULL) return NULL;
+
+ num = 0;
+ while(1) {
+ /* We read one line from file */
+ bufferused = 0;
+ while (1) {
+ if (buffused == buffread) {
+ buffused = fread(buff,1,1000,f);
+ buffread = 0;
+ if (buffused == 0) {
+ free(buffer); free(buffer1); free(buffer2);
+ fclose(f);
+ return INI_head;
+ }
+ }
+ if (Unicode) {
+ if (num == 0) {
+ if (buffused == buffread) continue;
+ ch[0] = buff[buffread++];
+ num = 1;
+ }
+ if (num == 1) {
+ if (buffused == buffread) continue;
+ ch[1] = buff[buffread++];
+ num = 0;
+ }
+ if (level == -1) {
+ if (ch[0] == 0xFF && ch[1] == 0xFE) FFEEUnicode = true;
+ level = 0;
+ continue;
+ }
+ if (FFEEUnicode) {
+ ch[2] = ch[0]; ch[0] = ch[1]; ch[1] = ch[2];
+ }
+ } else {
+ if (buffused == buffread) continue;
+ ch[0] = 0;
+ ch[1] = buff[buffread++];
+ if (level == -1) level = 0;
+ }
+ if ((ch[0] == 0 && ch[1] == 13) ||
+ (ch[0] == 0 && ch[1] == 10)) {
+ break;
+ }
+ buffer = realloc(buffer,bufferused+2);
+ buffer[bufferused] = ch[0];
+ buffer[bufferused+1] = ch[1];
+ bufferused = bufferused + 2;
+ }
+// printf("line \"%s\"\n",DecodeUnicodeConsole(buffer));
+
+ buffer1used = 0;
+ buffer2used = 0;
+ if (level == 1) level = 0;
+ if (level == 3 || level == 4 || level == 5) level = 2;
+
+ /* We parse read line */
+ for (i=0;i<bufferused/2;i++) {
+ ch[0] = buffer[i*2];
+ ch[1] = buffer[i*2+1];
+ if (level == 0) { //search for name of section
+ if (ch[0] == 0 && ch[1] == '[') level = 1;
+ if (ch[0] == 0 && ch[1] == ';') break;
+ if (ch[0] == 0 && ch[1] == '#') break;
+ continue;
+ }
+ if (level == 1) { //section name
+ if (ch[0] == 0 && ch[1] == ']') {
+ if (buffer1used == 0) break;
+ if (Unicode) {
+ buffer1 = realloc(buffer1,buffer1used+2);
+ buffer1[buffer1used] = 0;
+ buffer1[buffer1used+1] = 0;
+ buffer1used = buffer1used + 2;
+ } else {
+ buffer1 = realloc(buffer1,buffer1used+1);
+ buffer1[buffer1used] = 0x00;
+ buffer1used = buffer1used + 1;
+ }
+ heading = (INI_Section *)malloc(sizeof(*heading));
+ if (heading == NULL) {
+ free(buffer); free(buffer1); free(buffer2);
+ fclose(f);
+ return NULL;
+ }
+ heading->SectionName = (char *)malloc(buffer1used);
+ memcpy(heading->SectionName,buffer1,buffer1used);
+ heading->Prev = INI_info;
+ heading->Next = NULL;
+ if (INI_info != NULL) {
+ INI_info->Next = heading;
+ } else {
+ INI_head = heading;
+ }
+ INI_info = heading;
+ INI_info->SubEntries = NULL;
+ level = 2;
+// printf("[%s]\n",DecodeUnicodeConsole(buffer1));
+ break;
+ }
+ if (Unicode) {
+ buffer1 = realloc(buffer1,buffer1used+2);
+ buffer1[buffer1used] = ch[0];
+ buffer1[buffer1used+1] = ch[1];
+ buffer1used = buffer1used + 2;
+ } else {
+ buffer1 = realloc(buffer1,buffer1used+1);
+ buffer1[buffer1used] = ch[1];
+ buffer1used = buffer1used + 1;
+ }
+ continue;
+ }
+ if (level == 2) { //search for key name
+ if (ch[0] == 0 && ch[1] == ';') break;
+ if (ch[0] == 0 && ch[1] == '#') break;
+ if (ch[0] == 0 && ch[1] == '[') {
+ level = 1;
+ continue;
+ }
+ if (Unicode) {
+ if (myiswspace(ch)) continue;
+ } else {
+ if (isspace((int) ch[1])) continue;
+ }
+ level = 3;
+ }
+ if (level == 3) { //key name
+ if (ch[0] == 0 && ch[1] == '=') {
+ if (buffer1used == 0) break;
+ while(1) {
+ if (Unicode) {
+ if (!myiswspace(buffer1+(buffer1used-2))) break;
+ buffer1used = buffer1used - 2;
+ } else {
+ if (!isspace((int)buffer1[buffer1used-1])) break;
+ buffer1used = buffer1used - 1;
+ }
+ }
+ level = 4;
+ continue;
+ }
+ if (Unicode) {
+ buffer1 = realloc(buffer1,buffer1used+2);
+ buffer1[buffer1used] = ch[0];
+ buffer1[buffer1used+1] = ch[1];
+ buffer1used = buffer1used + 2;
+ } else {
+ buffer1 = realloc(buffer1,buffer1used+1);
+ buffer1[buffer1used] = ch[1];
+ buffer1used = buffer1used + 1;
+ }
+ }
+ if (level == 4) { //search for key value
+ if (Unicode) {
+ if (myiswspace(ch)) continue;
+ } else {
+ if (isspace((int) ch[1])) continue;
+ }
+ level = 5;
+ }
+ if (level == 5) { //key value
+ if (Unicode) {
+ buffer2 = realloc(buffer2,buffer2used+2);
+ buffer2[buffer2used] = ch[0];
+ buffer2[buffer2used+1] = ch[1];
+ buffer2used = buffer2used + 2;
+ } else {
+ buffer2 = realloc(buffer2,buffer2used+1);
+ buffer2[buffer2used] = ch[1];
+ buffer2used = buffer2used + 1;
+ }
+ }
+ }
+ if (level == 5) {
+ if (buffer2used == 0) continue;
+
+ entry = (INI_Entry *)malloc(sizeof(*entry));
+ if (entry == NULL) {
+ free(buffer); free(buffer1); free(buffer2);
+ fclose(f);
+ return NULL;
+ }
+ if (Unicode) {
+ buffer1 = realloc(buffer1,buffer1used+2);
+ buffer1[buffer1used] = 0;
+ buffer1[buffer1used+1] = 0;
+ buffer1used = buffer1used + 2;
+ buffer2 = realloc(buffer2,buffer2used+2);
+ buffer2[buffer2used] = 0;
+ buffer2[buffer2used+1] = 0;
+ buffer2used = buffer2used + 2;
+ } else {
+ buffer1 = realloc(buffer1,buffer1used+1);
+ buffer1[buffer1used] = 0x00;
+ buffer1used = buffer1used + 1;
+ buffer2 = realloc(buffer2,buffer2used+1);
+ buffer2[buffer2used] = 0x00;
+ buffer2used = buffer2used + 1;
+ }
+// printf("\"%s\"=\"%s\"\n",buffer1,buffer2);
+// printf("\"%s\"=",DecodeUnicodeConsole(buffer1));
+// printf("\"%s\"\n",DecodeUnicodeConsole(buffer2));
+
+ entry->EntryName = (char *)malloc(buffer1used);
+ memcpy(entry->EntryName,buffer1,buffer1used);
+
+ entry->EntryValue = (char *)malloc(buffer2used);
+ memcpy(entry->EntryValue,buffer2,buffer2used);
+
+ entry->Prev = NULL;
+ entry->Next = INI_info->SubEntries;
+ if (INI_info->SubEntries != NULL) INI_info->SubEntries->Prev = entry;
+ INI_info->SubEntries = entry;
+ }
+ }
+ free(buffer); free(buffer1); free(buffer2);
+ fclose(f);
+ return INI_head;
+}
+
+/*
+ * Search for key value in file in Windows INI format style
+ * Returns found value or NULL
+ */
+unsigned char *INI_GetValue(INI_Section *cfg, unsigned char *section, unsigned char *key, bool Unicode)
+{
+ INI_Section *sec;
+ INI_Entry *ent;
+
+ if (cfg == NULL || section == NULL || key == NULL) return NULL;
+
+ if (Unicode) {
+ /* Search for section */
+ sec = cfg;
+ while (sec != NULL) {
+ if (mywstrncasecmp(section, sec->SectionName, 0)) {
+ /* Search for key inside section */
+ ent = sec->SubEntries;
+ while (ent != NULL) {
+ if (mywstrncasecmp(key,ent->EntryName,0)) {
+ return ent->EntryValue;
+ }
+ ent = ent->Next;
+ }
+ }
+ sec = sec->Next;
+ }
+ } else {
+ /* Search for section */
+ sec = cfg;
+ while (sec != NULL) {
+ if (mystrncasecmp(section, sec->SectionName, 0)) {
+ /* Search for key inside section */
+ ent = sec->SubEntries;
+ while (ent != NULL) {
+ if (mystrncasecmp(key,ent->EntryName,0)) {
+ return ent->EntryValue;
+ }
+ ent = ent->Next;
+ }
+ }
+ sec = sec->Next;
+ }
+ }
+ return NULL;
+}
+
+/* Return last value in specified section */
+INI_Entry *INI_FindLastSectionEntry(INI_Section *file_info, unsigned char *section, bool Unicode)
+{
+ INI_Section *h;
+ INI_Entry *e;
+
+ e = NULL;
+ /* First find our section */
+ for (h = file_info; h != NULL; h = h->Next) {
+ if (Unicode) {
+ if (mywstrncasecmp(section, h->SectionName, 0)) {
+ e = h->SubEntries;
+ break;
+ }
+ } else {
+ if (mystrncasecmp(section, h->SectionName, 0)) {
+ e = h->SubEntries;
+ break;
+ }
+ }
+ }
+
+ if (e == NULL) return NULL;
+
+ /* Goes into last value in section */
+ while (e->Next != NULL) e = e->Next;
+ return e;
+}
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/misc/cfg.h b/gammu/emb/common/misc/cfg.h
new file mode 100644
index 0000000..edb9b09
--- a/dev/null
+++ b/gammu/emb/common/misc/cfg.h
@@ -0,0 +1,42 @@
+/* (c) 2003 by Marcin Wiacek */
+
+#ifndef _cfg_h
+#define _cfg_h
+
+#include "misc.h"
+
+/* -------------------------------- structures ----------------------------- */
+
+typedef struct _INI_Entry INI_Entry;
+
+/*
+ * Structure used to save value for single key in INI style file
+ */
+struct _INI_Entry {
+ INI_Entry *Next, *Prev;
+ unsigned char *EntryName;
+ unsigned char *EntryValue;
+};
+
+typedef struct _INI_Section INI_Section;
+
+/*
+ * Structure used to save section in INI style file
+ */
+struct _INI_Section {
+ INI_Section *Next, *Prev;
+ INI_Entry *SubEntries;
+ unsigned char *SectionName;
+};
+
+/* ------------------------- function prototypes --------------------------- */
+
+INI_Section *INI_ReadFile (char *FileName, bool Unicode);
+INI_Entry *INI_FindLastSectionEntry (INI_Section *file_info, unsigned char *section, bool Unicode);
+unsigned char *INI_GetValue (INI_Section *cfg, unsigned char *section, unsigned char *key, bool Unicode);
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/misc/coding/coding.c b/gammu/emb/common/misc/coding/coding.c
new file mode 100644
index 0000000..62543ac
--- a/dev/null
+++ b/gammu/emb/common/misc/coding/coding.c
@@ -0,0 +1,1409 @@
+/* (c) 2002-2004 by Marcin Wiacek, Michal Cihar and others */
+/* based on some work from MyGnokii and Gnokii */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <locale.h>
+#ifndef __OpenBSD__
+# include <wctype.h>
+#endif
+#ifdef WIN32
+# include "windows.h"
+#endif
+
+#include "../misc.h"
+#include "coding.h"
+
+unsigned int UnicodeLength(const unsigned char *str)
+{
+ unsigned int len = 0;
+
+ if (str == NULL) return 0;
+
+ while(str[len*2] != 0 || str[len*2+1] != 0) len++;
+
+ return len;
+}
+
+/* Convert Unicode char saved in src to dest */
+unsigned int EncodeWithUnicodeAlphabet(const unsigned char *src, wchar_t *dest)
+{
+ char retval;
+
+ switch (retval = mbtowc(dest, src, MB_CUR_MAX)) {
+ case -1 :
+ case 0 : return 1;
+ default : return retval;
+ }
+}
+
+/* Convert Unicode char saved in src to dest */
+unsigned int DecodeWithUnicodeAlphabet(wchar_t src, unsigned char *dest)
+{
+ int retval;
+
+ switch (retval = wctomb(dest, src)) {
+ case -1:
+ *dest = '?';
+ return 1;
+ default:
+ return retval;
+ }
+}
+
+void DecodeUnicode (const unsigned char *src, unsigned char *dest)
+{
+ int i=0,o=0;
+ wchar_t wc;
+
+ while (src[(2*i)+1]!=0x00 || src[2*i]!=0x00) {
+ wc = src[(2*i)+1] | (src[2*i] << 8);
+ o += DecodeWithUnicodeAlphabet(wc, dest + o);
+ i++;
+ }
+ dest[o]=0;
+}
+
+/* Decode Unicode string and return as function result */
+unsigned char *DecodeUnicodeString (const unsigned char *src)
+{
+ static char dest[500];
+
+ DecodeUnicode(src,dest);
+ return dest;
+}
+
+/* Decode Unicode string to UTF8 or other console charset
+ * and return as function result
+ */
+unsigned char *DecodeUnicodeConsole(const unsigned char *src)
+{
+ static char dest[500];
+
+ if (di.coding[0] != 0) {
+ if (!strcmp(di.coding,"utf8")) {
+ EncodeUTF8(dest, src);
+ } else {
+#ifdef WIN32
+ setlocale(LC_ALL, di.coding);
+#endif
+ DecodeUnicode(src,dest);
+ }
+ } else {
+#ifdef WIN32
+ setlocale(LC_ALL, ".OCP");
+#endif
+ DecodeUnicode(src,dest);
+#ifdef WIN32
+ setlocale(LC_ALL, ".ACP");
+#endif
+ }
+ return dest;
+}
+
+/* Encode string to Unicode. Len is number of input chars */
+void EncodeUnicode (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i_len = 0, o_len;
+ wchar_t wc;
+
+ for (o_len = 0; i_len < len; o_len++) {
+ i_len += EncodeWithUnicodeAlphabet(&src[i_len], &wc);
+ dest[o_len*2] = (wc >> 8) & 0xff;
+ dest[(o_len*2)+1] = wc & 0xff;
+ }
+ dest[o_len*2] = 0;
+ dest[(o_len*2)+1] = 0;
+}
+
+unsigned char EncodeWithBCDAlphabet(int value)
+{
+ div_t division;
+
+ division=div(value,10);
+ return ( ( (value-division.quot*10) & 0x0f) << 4) | (division.quot & 0xf);
+}
+
+int DecodeWithBCDAlphabet(unsigned char value)
+{
+ return 10*(value & 0x0f)+(value >> 4);
+}
+
+void DecodeBCD (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current=0,digit;
+
+ for (i = 0; i < len; i++) {
+ digit=src[i] & 0x0f;
+ if (digit<10) dest[current++]=digit + '0';
+ digit=src[i] >> 4;
+ if (digit<10) dest[current++]=digit + '0';
+ }
+ dest[current++]=0;
+}
+
+void EncodeBCD (unsigned char *dest, const unsigned char *src, int len, bool fill)
+{
+ int i,current=0;
+
+ for (i = 0; i < len; i++) {
+ if (i & 0x01) {
+ dest[current]=dest[current] | ((src[i]-'0') << 4);
+ current++;
+ } else {
+ dest[current]=src[i]-'0';
+ }
+ }
+
+ /* When fill is set: if number consist of odd number of digits,
+ we fill last bits in last byte with 0x0f
+ */
+ if (fill && (len & 0x01)) dest[current]=dest[current] | 0xf0;
+}
+
+int DecodeWithHexBinAlphabet (unsigned char mychar)
+{
+ if (mychar>='A' && mychar<='F') return mychar-'A'+10;
+ if (mychar>='a' && mychar<='f') return mychar-'a'+10;
+ if (mychar>='0' && mychar<='9') return mychar-'0';
+ return -1;
+}
+
+unsigned char EncodeWithHexBinAlphabet (int digit)
+{
+ if (digit >= 0 && digit <= 9) return '0'+(digit);
+ if (digit >=10 && digit <=15) return 'A'+(digit-10);
+ return 0;
+}
+
+void DecodeHexUnicode (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current=0;
+ bool first = false;
+
+ if (len != 0 && src[0] == '0' && src[1] == '0') {
+ first = true;
+ } else if (len != 0 && src[2] == '0' && src[3] == '0') {
+ first = false;
+ } else {
+ first = (10 * (src[0] - '0') + (src[1] - '0')) < (10 * (src[2] - '0')+ (src[3] - '0'));
+ }
+ for (i = 0; i < len/4 ; i++) {
+ if (first) {
+ dest[current++] = DecodeWithHexBinAlphabet(src[i*4+0])*16+
+ DecodeWithHexBinAlphabet(src[i*4+1]);
+ dest[current++] = DecodeWithHexBinAlphabet(src[i*4+2])*16+
+ DecodeWithHexBinAlphabet(src[i*4+3]);
+ } else {
+ dest[current++] = DecodeWithHexBinAlphabet(src[i*4+2])*16+
+ DecodeWithHexBinAlphabet(src[i*4+3]);
+ dest[current++] = DecodeWithHexBinAlphabet(src[i*4+0])*16+
+ DecodeWithHexBinAlphabet(src[i*4+1]);
+ }
+ }
+ dest[current++] = 0;
+ dest[current++] = 0;
+}
+
+void EncodeHexUnicode (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current=0;
+
+ for (i = 0; i < len; i++) {
+ dest[current++] = EncodeWithHexBinAlphabet(src[2*i] >> 0x04);
+ dest[current++] = EncodeWithHexBinAlphabet(src[2*i] & 0x0f);
+ dest[current++] = EncodeWithHexBinAlphabet(src[2*i+1] >> 0x04);
+ dest[current++] = EncodeWithHexBinAlphabet(src[2*i+1] & 0x0f);
+ }
+ dest[current++] = 0;
+}
+
+void DecodeHexBin (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current=0;
+
+ for (i = 0; i < len/2 ; i++) {
+ dest[current++] = DecodeWithHexBinAlphabet(src[i*2])*16+
+ DecodeWithHexBinAlphabet(src[i*2+1]);
+ }
+ dest[current++] = 0;
+}
+
+void EncodeHexBin (unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current=0;
+
+ for (i = 0; i < len; i++) {
+ dest[current++] = EncodeWithHexBinAlphabet(src[i] >> 0x04);
+ dest[current++] = EncodeWithHexBinAlphabet(src[i] & 0x0f);
+ }
+ dest[current++] = 0;
+}
+
+/* ETSI GSM 03.38, section 6.2.1: Default alphabet for SMS messages */
+static unsigned char GSM_DefaultAlphabetUnicode[128+1][2] =
+{
+ {0x00,0x40},{0x00,0xa3},{0x00,0x24},{0x00,0xA5},
+ {0x00,0xE8},{0x00,0xE9},{0x00,0xF9},{0x00,0xEC},/*0x08*/
+ {0x00,0xF2},{0x00,0xC7},{0x00,'\n'},{0x00,0xD8},
+ {0x00,0xF8},{0x00,'\r'},{0x00,0xC5},{0x00,0xE5},
+ {0x03,0x94},{0x00,0x5f},{0x03,0xA6},{0x03,0x93},
+ {0x03,0x9B},{0x03,0xA9},{0x03,0xA0},{0x03,0xA8},
+ {0x03,0xA3},{0x03,0x98},{0x03,0x9E},{0x00,0xb9},
+ {0x00,0xC6},{0x00,0xE6},{0x00,0xDF},{0x00,0xC9},/*0x20*/
+ {0x00,' ' },{0x00,'!' },{0x00,'\"'},{0x00,'#' },
+ {0x00,0xA4},{0x00,'%' },{0x00,'&' },{0x00,'\''},
+ {0x00,'(' },{0x00,')' },{0x00,'*' },{0x00,'+' },
+ {0x00,',' },{0x00,'-' },{0x00,'.' },{0x00,'/' },/*0x30*/
+ {0x00,'0' },{0x00,'1' },{0x00,'2' },{0x00,'3' },
+ {0x00,'4' },{0x00,'5' },{0x00,'6' },{0x00,'7' },
+ {0x00,'8' },{0x00,'9' },{0x00,':' },{0x00,';' },
+ {0x00,'<' },{0x00,'=' },{0x00,'>' },{0x00,'?' },/*0x40*/
+ {0x00,0xA1},{0x00,'A' },{0x00,'B' },{0x00,'C' },
+ {0x00,'D' },{0x00,'E' },{0x00,'F' },{0x00,'G' },
+ {0x00,'H' },{0x00,'I' },{0x00,'J' },{0x00,'K' },
+ {0x00,'L' },{0x00,'M' },{0x00,'N' },{0x00,'O' },
+ {0x00,'P' },{0x00,'Q' },{0x00,'R' },{0x00,'S' },
+ {0x00,'T' },{0x00,'U' },{0x00,'V' },{0x00,'W' },
+ {0x00,'X' },{0x00,'Y' },{0x00,'Z' },{0x00,0xC4},
+ {0x00,0xD6},{0x00,0xD1},{0x00,0xDC},{0x00,0xA7},
+ {0x00,0xBF},{0x00,'a' },{0x00,'b' },{0x00,'c' },
+ {0x00,'d' },{0x00,'e' },{0x00,'f' },{0x00,'g' },
+ {0x00,'h' },{0x00,'i' },{0x00,'j' },{0x00,'k' },
+ {0x00,'l' },{0x00,'m' },{0x00,'n' },{0x00,'o' },
+ {0x00,'p' },{0x00,'q' },{0x00,'r' },{0x00,'s' },
+ {0x00,'t' },{0x00,'u' },{0x00,'v' },{0x00,'w' },
+ {0x00,'x' },{0x00,'y' },{0x00,'z' },{0x00,0xE4},
+ {0x00,0xF6},{0x00,0xF1},{0x00,0xFC},{0x00,0xE0},
+ {0x00,0x00}
+};
+
+/* ETSI GSM 3.38
+ * Some sequences of 2 default alphabet chars (for example,
+ * 0x1b, 0x65) are visible as one single additional char (for example,
+ * 0x1b, 0x65 gives Euro char saved in Unicode as 0x20, 0xAC)
+ * This table contains:
+ * 1. two first chars means sequence of chars from GSM default alphabet
+ * 2. two second is target (encoded) char saved in Unicode
+ */
+static unsigned char GSM_DefaultAlphabetCharsExtension[][4] =
+{
+ {0x1b,0x14,0x00,0x5e}, /* ^ */
+ {0x1b,0x28,0x00,0x7b}, /* { */
+ {0x1b,0x29,0x00,0x7d}, /* } */
+ {0x1b,0x2f,0x00,0x5c}, /* \ */
+ {0x1b,0x3c,0x00,0x5b}, /* [ */
+ {0x1b,0x3d,0x00,0x7E}, /* ~ */
+ {0x1b,0x3e,0x00,0x5d}, /* ] */
+ {0x1b,0x40,0x00,0x7C}, /* | */
+ {0x1b,0x65,0x20,0xAC}, /* Euro */
+ {0x00,0x00,0x00,0x00}
+};
+
+void DecodeDefault (unsigned char *dest, const unsigned char *src, int len, bool UseExtensions, unsigned char *ExtraAlphabet)
+{
+ int i,current=0,j;
+ bool FoundSpecial = false;
+
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, src, len);
+#endif
+
+ for (i = 0; i < len; i++) {
+ FoundSpecial = false;
+ if ((i < (len-1)) && UseExtensions) {
+ j=0;
+ while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) {
+ if (GSM_DefaultAlphabetCharsExtension[j][0]==src[i] &&
+ GSM_DefaultAlphabetCharsExtension[j][1]==src[i+1]) {
+ FoundSpecial = true;
+ dest[current++] = GSM_DefaultAlphabetCharsExtension[j][2];
+ dest[current++] = GSM_DefaultAlphabetCharsExtension[j][3];
+ i++;
+ break;
+ }
+ j++;
+ }
+ }
+ if (ExtraAlphabet!=NULL && !FoundSpecial) {
+ j = 0;
+ while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) {
+ if (ExtraAlphabet[j] == src[i]) {
+ dest[current++] = ExtraAlphabet[j+1];
+ dest[current++] = ExtraAlphabet[j+2];
+ FoundSpecial = true;
+ break;
+ }
+ j=j+3;
+ }
+ }
+ if (!FoundSpecial) {
+ dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][0];
+ dest[current++] = GSM_DefaultAlphabetUnicode[src[i]][1];
+ }
+ }
+ dest[current++]=0;
+ dest[current++]=0;
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, dest, UnicodeLength(dest)*2);
+#endif
+}
+
+/* There are many national chars with "adds". In phone they're normally
+ * changed to "plain" Latin chars. We have such functionality too.
+ * This table is automatically created from convert.txt file (see
+ * /docs/developers) using --makeconverttable. It contains such chars
+ * to replace in order:
+ * 1. original char (Unicode) 2. destination char (Unicode)
+ */
+static unsigned char ConvertTable[] =
+"\x00\xc0\x00\x41\x00\xe0\x00\x61\x00\xc1\x00\x41\x00\xe1\x00\x61\x00\xc2\x00\x41\x00\xe2\x00\x61\x00\xc3\x00\x41\x00\xe3\x00\x61\x1e\xa0\x00\x41\x1e\xa1\x00\x61\x1e\xa2\x00\x41\x1e\xa3\x00\x61\x1e\xa4\x00\x41\x1e\xa5\x00\x61\x1e\xa6\x00\x41\x1e\xa7\x00\x61\x1e\xa8\x00\x41\x1e\xa9\x00\x61\x1e\xaa\x00\x41\x1e\xab\x00\x61\x1e\xac\x00\x41\x1e\xad\x00\x61\x1e\xae\x00\x41\x1e\xaf\x00\x61\x1e\xb0\x00\x41\x1e\xb1\x00\x61\x1e\xb2\x00\x41\x1e\xb3\x00\x61\x1e\xb4\x00\x41\x1e\xb5\x00\x61\x1e\xb6\x00\x41\x1e\xb7\x00\x61\x01\xcd\x00\x41\x01\xce\x00\x61\x01\x00\x00\x41\x01\x01\x00\x61\x01\x02\x00\x41\x01\x03\x00\x61\x01\x04\x00\x41\x01\x05\x00\x61\x01\xfb\x00\x61\x01\x06\x00\x43\x01\x07\x00\x63\x01\x08\x00\x43\x01\x09\x00\x63\x01\x0a\x00\x43\x01\x0b\x00\x63\x01\x0c\x00\x43\x01\x0d\x00\x63\x00\xe7"\
+"\x00\x63\x01\x0e\x00\x44\x01\x0f\x00\x64\x01\x10\x00\x44\x01\x11\x00\x64\x00\xc8\x00\x45\x00\xca\x00\x45\x00\xea\x00\x65\x00\xcb\x00\x45\x00\xeb\x00\x65\x1e\xb8\x00\x45\x1e\xb9\x00\x65\x1e\xba\x00\x45\x1e\xbb\x00\x65\x1e\xbc\x00\x45\x1e\xbd\x00\x65\x1e\xbe\x00\x45\x1e\xbf\x00\x65\x1e\xc0\x00\x45\x1e\xc1\x00\x65\x1e\xc2\x00\x45\x1e\xc3\x00\x65\x1e\xc4\x00\x45\x1e\xc5\x00\x65\x1e\xc6\x00\x45\x1e\xc7\x00\x65\x01\x12\x00\x45\x01\x13\x00\x65\x01\x14\x00\x45\x01\x15\x00\x65\x01\x16\x00\x45\x01\x17\x00\x65\x01\x18\x00\x45\x01\x19\x00\x65\x01\x1a\x00\x45\x01\x1b\x00\x65\x01\x1c\x00\x47\x01\x1d\x00\x67\x01\x1e\x00\x47\x01\x1f\x00\x67\x01\x20\x00\x47\x01\x21\x00\x67\x01\x22\x00\x47\x01\x23\x00\x67\x01\x24\x00\x48\x01\x25\x00\x68\x01\x26\x00\x48\x01\x27\x00\x68\x00\xcc\x00\x49\x00\xcd\x00\x49\x00\xed"\
+"\x00\x69\x00\xce\x00\x49\x00\xee\x00\x69\x00\xcf\x00\x49\x00\xef\x00\x69\x01\x28\x00\x49\x01\x29\x00\x69\x01\x2a\x00\x49\x01\x2b\x00\x69\x01\x2c\x00\x49\x01\x2d\x00\x69\x01\x2e\x00\x49\x01\x2f\x00\x69\x01\x30\x00\x49\x01\x31\x00\x69\x01\xcf\x00\x49\x01\xd0\x00\x69\x1e\xc8\x00\x49\x1e\xc9\x00\x69\x1e\xca\x00\x49\x1e\xcb\x00\x69\x01\x34\x00\x4a\x01\x35\x00\x6a\x01\x36\x00\x4b\x01\x37\x00\x6b\x01\x39\x00\x4c\x01\x3a\x00\x6c\x01\x3b\x00\x4c\x01\x3c\x00\x6c\x01\x3d\x00\x4c\x01\x3e\x00\x6c\x01\x3f\x00\x4c\x01\x40\x00\x6c\x01\x41\x00\x4c\x01\x42\x00\x6c\x01\x43\x00\x4e\x01\x44\x00\x6e\x01\x45\x00\x4e\x01\x46\x00\x6e\x01\x47\x00\x4e\x01\x48\x00\x6e\x01\x49\x00\x6e\x00\xd2\x00\x4f\x00\xd3\x00\x4f\x00\xf3\x00\x6f\x00\xd4\x00\x4f\x00\xf4\x00\x6f\x00\xd5\x00\x4f\x00\xf5\x00\x6f\x01\x4c\x00\x4f\x01\x4d"\
+"\x00\x6f\x01\x4e\x00\x4f\x01\x4f\x00\x6f\x01\x50\x00\x4f\x01\x51\x00\x6f\x01\xa0\x00\x4f\x01\xa1\x00\x6f\x01\xd1\x00\x4f\x01\xd2\x00\x6f\x1e\xcc\x00\x4f\x1e\xcd\x00\x6f\x1e\xce\x00\x4f\x1e\xcf\x00\x6f\x1e\xd0\x00\x4f\x1e\xd1\x00\x6f\x1e\xd2\x00\x4f\x1e\xd3\x00\x6f\x1e\xd4\x00\x4f\x1e\xd5\x00\x6f\x1e\xd6\x00\x4f\x1e\xd7\x00\x6f\x1e\xd8\x00\x4f\x1e\xd9\x00\x6f\x1e\xda\x00\x4f\x1e\xdb\x00\x6f\x1e\xdc\x00\x4f\x1e\xdd\x00\x6f\x1e\xde\x00\x4f\x1e\xdf\x00\x6f\x1e\xe0\x00\x4f\x1e\xe1\x00\x6f\x1e\xe2\x00\x4f\x1e\xe3\x00\x6f\x01\x54\x00\x52\x01\x55\x00\x72\x01\x56\x00\x52\x01\x57\x00\x72\x01\x58\x00\x52\x01\x59\x00\x72\x01\x5a\x00\x53\x01\x5b\x00\x73\x01\x5c\x00\x53\x01\x5d\x00\x73\x01\x5e\x00\x53\x01\x5f\x00\x73\x01\x60\x00\x53\x01\x61\x00\x73\x01\x62\x00\x54\x01\x63\x00\x74\x01\x64\x00\x54\x01\x65"\
+"\x00\x74\x01\x66\x00\x54\x01\x67\x00\x74\x00\xd9\x00\x55\x00\xda\x00\x55\x00\xfa\x00\x75\x00\xdb\x00\x55\x00\xfb\x00\x75\x01\x68\x00\x55\x01\x69\x00\x75\x01\x6a\x00\x55\x01\x6b\x00\x75\x01\x6c\x00\x55\x01\x6d\x00\x75\x01\x6e\x00\x55\x01\x6f\x00\x75\x01\x70\x00\x55\x01\x71\x00\x75\x01\x72\x00\x55\x01\x73\x00\x75\x01\xaf\x00\x55\x01\xb0\x00\x75\x01\xd3\x00\x55\x01\xd4\x00\x75\x01\xd5\x00\x55\x01\xd6\x00\x75\x01\xd7\x00\x55\x01\xd8\x00\x75\x01\xd9\x00\x55\x01\xda\x00\x75\x01\xdb\x00\x55\x01\xdc\x00\x75\x1e\xe4\x00\x55\x1e\xe5\x00\x75\x1e\xe6\x00\x55\x1e\xe7\x00\x75\x1e\xe8\x00\x55\x1e\xe9\x00\x75\x1e\xea\x00\x55\x1e\xeb\x00\x75\x1e\xec\x00\x55\x1e\xed\x00\x75\x1e\xee\x00\x55\x1e\xef\x00\x75\x1e\xf0\x00\x55\x1e\xf1\x00\x75\x01\x74\x00\x57\x01\x75\x00\x77\x1e\x80\x00\x57\x1e\x81\x00\x77\x1e\x82"\
+"\x00\x57\x1e\x83\x00\x77\x1e\x84\x00\x57\x1e\x85\x00\x77\x00\xdd\x00\x59\x00\xfd\x00\x79\x00\xff\x00\x79\x01\x76\x00\x59\x01\x77\x00\x79\x01\x78\x00\x59\x1e\xf2\x00\x59\x1e\xf3\x00\x75\x1e\xf4\x00\x59\x1e\xf5\x00\x79\x1e\xf6\x00\x59\x1e\xf7\x00\x79\x1e\xf8\x00\x59\x1e\xf9\x00\x79\x01\x79\x00\x5a\x01\x7a\x00\x7a\x01\x7b\x00\x5a\x01\x7c\x00\x7a\x01\x7d\x00\x5a\x01\x7e\x00\x7a\x01\xfc\x00\xc6\x01\xfd\x00\xe6\x01\xfe\x00\xd8\x01\xff\x00\xf8\x00\x00";
+
+void EncodeDefault(unsigned char *dest, const unsigned char *src, int *len, bool UseExtensions, unsigned char *ExtraAlphabet)
+{
+ int i,current=0,j,z;
+ char ret;
+ bool FoundSpecial,FoundNormal;
+
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, src, (*len)*2);
+#endif
+
+ for (i = 0; i < *len; i++) {
+ FoundSpecial = false;
+ j = 0;
+ while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00 && UseExtensions) {
+ if (src[i*2] == GSM_DefaultAlphabetCharsExtension[j][2] &&
+ src[i*2+1] == GSM_DefaultAlphabetCharsExtension[j][3]) {
+ dest[current++] = GSM_DefaultAlphabetCharsExtension[j][0];
+ dest[current++] = GSM_DefaultAlphabetCharsExtension[j][1];
+ FoundSpecial = true;
+ break;
+ }
+ j++;
+ }
+ if (!FoundSpecial) {
+ ret = '?';
+ FoundNormal = false;
+ j = 0;
+ while (GSM_DefaultAlphabetUnicode[j][1]!=0x00) {
+ if (src[i*2] == GSM_DefaultAlphabetUnicode[j][0] &&
+ src[i*2+1] == GSM_DefaultAlphabetUnicode[j][1]) {
+ ret = j;
+ FoundNormal = true;
+ break;
+ }
+ j++;
+ }
+ if (ExtraAlphabet!=NULL && !FoundNormal) {
+ j = 0;
+ while (ExtraAlphabet[j] != 0x00 || ExtraAlphabet[j+1] != 0x00 || ExtraAlphabet[j+2] != 0x00) {
+ if (ExtraAlphabet[j+1] == src[i*2] &&
+ ExtraAlphabet[j+2] == src[i*2 + 1]) {
+ ret = ExtraAlphabet[j];
+ FoundSpecial = true;
+ break;
+ }
+ j=j+3;
+ }
+ }
+ if (!FoundNormal && !FoundSpecial) {
+ j = 0;
+ FoundNormal = false;
+ while (ConvertTable[j*4] != 0x00 ||
+ ConvertTable[j*4+1] != 0x00) {
+ if (src[i*2] == ConvertTable[j*4] &&
+ src[i*2+1] == ConvertTable[j*4+1]) {
+ z = 0;
+ while (GSM_DefaultAlphabetUnicode[z][1]!=0x00) {
+ if (ConvertTable[j*4+2] == GSM_DefaultAlphabetUnicode[z][0] &&
+ ConvertTable[j*4+3] == GSM_DefaultAlphabetUnicode[z][1]) {
+ ret = z;
+ FoundNormal = true;
+ break;
+ }
+ z++;
+ }
+ if (FoundNormal) break;
+ }
+ j++;
+ }
+ }
+ dest[current++]=ret;
+ }
+ }
+ dest[current]=0;
+#ifdef DEBUG
+ if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, dest, current);
+#endif
+
+ *len = current;
+}
+
+/* You don't have to use ConvertTable here - 1 char is replaced there by 1 char */
+void FindDefaultAlphabetLen(const unsigned char *src, int *srclen, int *smslen, int maxlen)
+{
+ int current=0,j,i;
+ bool FoundSpecial;
+
+ i = 0;
+ while (src[i*2] != 0x00 || src[i*2+1] != 0x00) {
+ FoundSpecial = false;
+ j = 0;
+ while (GSM_DefaultAlphabetCharsExtension[j][0]!=0x00) {
+ if (src[i*2] == GSM_DefaultAlphabetCharsExtension[j][2] &&
+ src[i*2+1] == GSM_DefaultAlphabetCharsExtension[j][3]) {
+ FoundSpecial = true;
+ if (current+2 > maxlen) {
+ *srclen = i;
+ *smslen = current;
+ return;
+ }
+ current+=2;
+ break;
+ }
+ j++;
+ }
+ if (!FoundSpecial) {
+ if (current+1 > maxlen) {
+ *srclen = i;
+ *smslen = current;
+ return;
+ }
+ current++;
+ }
+ i++;
+ }
+ *srclen = i;
+ *smslen = current;
+}
+
+#ifndef ENABLE_LGPL
+# define ByteMask ((1 << Bits) - 1)
+#endif
+
+int GSM_UnpackEightBitsToSeven(int offset, int in_length, int out_length,
+ unsigned char *input, unsigned char *output)
+{
+#ifndef ENABLE_LGPL
+ /* (c) by Pavel Janik and Pawel Kot */
+
+ unsigned char *OUTPUT = output; /* Current pointer to the output buffer */
+ unsigned char *INPUT = input; /* Current pointer to the input buffer */
+ unsigned char Rest = 0x00;
+ int Bits;
+
+ Bits = offset ? offset : 7;
+
+ while ((INPUT - input) < in_length) {
+
+ *OUTPUT = ((*INPUT & ByteMask) << (7 - Bits)) | Rest;
+ Rest = *INPUT >> Bits;
+
+ /* If we don't start from 0th bit, we shouldn't go to the
+ next char. Under *OUTPUT we have now 0 and under Rest -
+ _first_ part of the char. */
+ if ((INPUT != input) || (Bits == 7)) OUTPUT++;
+ INPUT++;
+
+ if ((OUTPUT - output) >= out_length) break;
+
+ /* After reading 7 octets we have read 7 full characters but
+ we have 7 bits as well. This is the next character */
+ if (Bits == 1) {
+ *OUTPUT = Rest;
+ OUTPUT++;
+ Bits = 7;
+ Rest = 0x00;
+ } else {
+ Bits--;
+ }
+ }
+
+ return OUTPUT - output;
+#else
+ return 0;
+#endif
+}
+
+int GSM_PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output, int length)
+{
+#ifndef ENABLE_LGPL
+ /* (c) by Pavel Janik and Pawel Kot */
+
+ unsigned char *OUTPUT = output; /* Current pointer to the output buffer */
+ unsigned char *INPUT = input; /* Current pointer to the input buffer */
+ int Bits; /* Number of bits directly copied to
+ * the output buffer */
+ Bits = (7 + offset) % 8;
+
+ /* If we don't begin with 0th bit, we will write only a part of the
+ first octet */
+ if (offset) {
+ *OUTPUT = 0x00;
+ OUTPUT++;
+ }
+
+ while ((INPUT - input) < length) {
+ unsigned char Byte = *INPUT;
+
+ *OUTPUT = Byte >> (7 - Bits);
+ /* If we don't write at 0th bit of the octet, we should write
+ a second part of the previous octet */
+ if (Bits != 7)
+ *(OUTPUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
+
+ Bits--;
+
+ if (Bits == -1) Bits = 7; else OUTPUT++;
+
+ INPUT++;
+ }
+ return (OUTPUT - output);
+#else
+ return 0;
+#endif
+}
+
+void GSM_UnpackSemiOctetNumber(unsigned char *retval, unsigned char *Number, bool semioctet)
+{
+ unsigned char Buffer[50] = "";
+ int length = Number[0];
+
+ if (semioctet) {
+ /* Convert number of semioctets to number of chars */
+ if (length % 2) length++;
+ length=length / 2 + 1;
+ }
+
+ /*without leading byte with format of number*/
+ length--;
+
+ switch (Number[1]) {
+ case NUMBER_ALPHANUMERIC:
+ if (length > 6) length++;
+ dbgprintf("Alphanumeric number, length %i\n",length);
+ GSM_UnpackEightBitsToSeven(0, length, length, Number+2, Buffer);
+ Buffer[length]=0;
+ break;
+ case NUMBER_INTERNATIONAL:
+ dbgprintf("International number\n");
+ Buffer[0]='+';
+ DecodeBCD(Buffer+1,Number+2, length);
+ break;
+ default:
+ dbgprintf("Default number %02x\n",Number[1]);
+ DecodeBCD (Buffer, Number+2, length);
+ break;
+ }
+
+ EncodeUnicode(retval,Buffer,strlen(Buffer));
+}
+
+/**
+ * Packing some phone numbers (SMSC, SMS destination and others)
+ *
+ * See GSM 03.40 9.1.1:
+ * 1 byte - length of number given in semioctets or bytes (when given in
+ * bytes, includes one byte for byte with number format).
+ * Returned by function (set semioctet to true, if want result
+ * in semioctets).
+ * 1 byte - format of number (see GSM_NumberType in coding.h). Returned
+ * in unsigned char *Output.
+ * n bytes - 2n or 2n-1 semioctets with number. Returned in unsigned char
+ * *Output.
+ *
+ * 1 semioctet = 4 bits = half of byte
+ */
+int GSM_PackSemiOctetNumber(unsigned char *Number, unsigned char *Output, bool semioctet)
+{
+ unsigned char format, buffer[50];
+ int length, i;
+
+ length=UnicodeLength(Number);
+ memcpy(buffer,DecodeUnicodeString(Number),length+1);
+
+ /* Checking for format number */
+ format = NUMBER_UNKNOWN;
+ for (i=0;i<length;i++) {
+ /* first byte is '+'. Number can be international */
+ if (i==0 && buffer[i]=='+') {
+ format=NUMBER_INTERNATIONAL;
+ } else {
+ /*char is not number. It must be alphanumeric*/
+ if (!isdigit(buffer[i])) format=NUMBER_ALPHANUMERIC;
+ }
+ }
+
+ /**
+ * First byte is used for saving type of number. See GSM 03.40
+ * section 9.1.2.5
+ */
+ Output[0]=format;
+
+ /* After number type we will have number. GSM 03.40 section 9.1.2 */
+ switch (format) {
+ case NUMBER_ALPHANUMERIC:
+ length=GSM_PackSevenBitsToEight(0, buffer, Output+1, strlen(buffer))*2;
+ if (strlen(buffer)==7) length--;
+ break;
+ case NUMBER_INTERNATIONAL:
+ length--;
+ EncodeBCD (Output+1, buffer+1, length, true);
+ break;
+ default:
+ EncodeBCD (Output+1, buffer, length, true);
+ break;
+ }
+
+ if (semioctet) return length;
+
+ /* Convert number of semioctets to number of chars */
+ if (length % 2) length++;
+ return length / 2 + 1;
+}
+
+void CopyUnicodeString(unsigned char *Dest, unsigned char *Source)
+{
+ int j = 0;
+
+ while (Source[j]!=0x00 || Source[j+1]!=0x00) {
+ Dest[j] = Source[j];
+ Dest[j+1] = Source[j+1];
+ j=j+2;
+ }
+ Dest[j] = 0;
+ Dest[j+1] = 0;
+}
+
+/* Changes minor/major order in Unicode string */
+void ReverseUnicodeString(unsigned char *String)
+{
+ int j = 0;
+ unsigned char byte1, byte2;
+
+ while (String[j]!=0x00 || String[j+1]!=0x00) {
+ byte1 = String[j];
+ byte2 = String[j+1];
+ String[j+1] = byte1;
+ String[j] = byte2;
+ j=j+2;
+ }
+ String[j] = 0;
+ String[j+1] = 0;
+}
+
+/* All input is in Unicode. First char can show Unicode minor/major order.
+ Output is Unicode string in Gammu minor/major order */
+void ReadUnicodeFile(unsigned char *Dest, unsigned char *Source)
+{
+ int j = 0, current = 0;
+
+ if (Source[0] == 0xFF && Source[1] == 0xFE) j = 2;
+ if (Source[0] == 0xFE && Source[1] == 0xFF) j = 2;
+
+ while (Source[j]!=0x00 || Source[j+1]!=0x00) {
+ if (Source[0] == 0xFF) {
+ Dest[current++] = Source[j+1];
+ Dest[current++] = Source[j];
+ } else {
+ Dest[current++] = Source[j];
+ Dest[current++] = Source[j+1];
+ }
+ j=j+2;
+ }
+ Dest[current++] = 0;
+ Dest[current++] = 0;
+}
+
+int GetBit(unsigned char *Buffer, int BitNum)
+{
+ return Buffer[BitNum/8] & 1<<(7-(BitNum%8));
+}
+
+int SetBit(unsigned char *Buffer, int BitNum)
+{
+ return Buffer[BitNum/8] |= 1<<(7-(BitNum%8));
+}
+
+int ClearBit(unsigned char *Buffer, int BitNum)
+{
+ return Buffer[BitNum/8] &= 255 - (1 << (7-(BitNum%8)));
+}
+
+void BufferAlign(unsigned char *Destination, int *CurrentBit)
+{
+ int i=0;
+
+ while(((*CurrentBit) + i) % 8 != 0) {
+ ClearBit(Destination, (*CurrentBit)+i);
+ i++;
+ }
+
+ (*CurrentBit) = (*CurrentBit) + i;
+}
+
+void BufferAlignNumber(int *CurrentBit)
+{
+ int i=0;
+
+ while(((*CurrentBit) + i) % 8 != 0) {
+ i++;
+ }
+
+ (*CurrentBit) = (*CurrentBit) + i;
+}
+
+void AddBuffer(unsigned char *Destination,
+ int *CurrentBit,
+ unsigned char *Source,
+ int BitsToProcess)
+{
+ int i=0;
+
+ while (i!=BitsToProcess) {
+ if (GetBit(Source, i)) {
+ SetBit(Destination, (*CurrentBit)+i);
+ } else {
+ ClearBit(Destination, (*CurrentBit)+i);
+ }
+ i++;
+ }
+ (*CurrentBit) = (*CurrentBit) + BitsToProcess;
+}
+
+void AddBufferByte(unsigned char *Destination,
+ int *CurrentBit,
+ unsigned char Source,
+ int BitsToProcess)
+{
+ unsigned char Byte;
+
+ Byte = Source;
+
+ AddBuffer(Destination, CurrentBit, &Byte, BitsToProcess);
+}
+
+void GetBuffer(unsigned char *Source,
+ int *CurrentBit,
+ unsigned char *Destination,
+ int BitsToProcess)
+{
+ int i=0;
+
+ while (i!=BitsToProcess) {
+ if (GetBit(Source, (*CurrentBit)+i)) {
+ SetBit(Destination, i);
+ } else {
+ ClearBit(Destination, i);
+ }
+ i++;
+ }
+ (*CurrentBit) = (*CurrentBit) + BitsToProcess;
+}
+
+void GetBufferInt(unsigned char *Source,
+ int *CurrentBit,
+ int *integer,
+ int BitsToProcess)
+{
+ int l=0,z=128,i=0;
+
+ while (i!=BitsToProcess) {
+ if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
+ z=z/2;
+ i++;
+ }
+ *integer=l;
+ (*CurrentBit) = (*CurrentBit) + i;
+}
+
+void GetBufferI(unsigned char *Source,
+ int *CurrentBit,
+ int *result,
+ int BitsToProcess)
+{
+ int l=0,z,i=0;
+
+ z = 1<<(BitsToProcess-1);
+
+ while (i!=BitsToProcess) {
+ if (GetBit(Source, (*CurrentBit)+i)) l=l+z;
+ z=z>>1;
+ i++;
+ }
+ *result=l;
+ (*CurrentBit) = (*CurrentBit) + i;
+}
+
+/* Unicode char 0x00 0x01 makes blinking in some Nokia phones.
+ * We replace single ~ chars into it. When user give double ~, it's replaced
+ * to single ~
+ */
+void EncodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len)
+{
+ int i,current = 0;
+ bool special=false;
+
+ for (i = 0; i < len; i++) {
+ if (special) {
+ if (src[i*2] == 0x00 && src[i*2+1] == '~') {
+ dest[current++] = 0x00;
+ dest[current++] = '~';
+ } else {
+ dest[current++] = 0x00;
+ dest[current++] = 0x01;
+ dest[current++] = src[i*2];
+ dest[current++] = src[i*2+1];
+ }
+ special = false;
+ } else {
+ if (src[i*2] == 0x00 && src[i*2+1] == '~') {
+ special = true;
+ } else {
+ dest[current++] = src[i*2];
+ dest[current++] = src[i*2+1];
+ }
+ }
+ }
+ if (special) {
+ dest[current++] = 0x00;
+ dest[current++] = 0x01;
+ }
+ dest[current++] = 0x00;
+ dest[current++] = 0x00;
+}
+
+void DecodeUnicodeSpecialNOKIAChars(unsigned char *dest, const unsigned char *src, int len)
+{
+ int i=0,current=0;
+
+ for (i=0;i<len;i++) {
+ switch (src[2*i]) {
+ case 0x00:
+ switch (src[2*i+1]) {
+ case 0x01:
+ dest[current++] = 0x00;
+ dest[current++] = '~';
+ break;
+ case '~':
+ dest[current++] = 0x00;
+ dest[current++] = '~';
+ dest[current++] = 0x00;
+ dest[current++] = '~';
+ break;
+ default:
+ dest[current++] = src[i*2];
+ dest[current++] = src[i*2+1];
+ }
+ break;
+ default:
+ dest[current++] = src[i*2];
+ dest[current++] = src[i*2+1];
+ }
+ }
+ dest[current++] = 0x00;
+ dest[current++] = 0x00;
+}
+
+bool mystrncasecmp(unsigned const char *a, unsigned const char *b, int num)
+{
+ int i;
+
+ if (a == NULL || b == NULL) return false;
+
+ num--;
+
+ for (i = 0; i != num; i++) {
+ if (a[i] == 0x00 && b[i] == 0x00) return true;
+ if (a[i] == 0x00 || b[i] == 0x00) return false;
+ if (tolower(a[i]) != tolower(b[i])) return false;
+ }
+ return true;
+}
+
+/* Compares two Unicode strings without regarding to case.
+ * Return true, when they're equal
+ */
+bool mywstrncasecmp(unsigned const char *a, unsigned const char *b, int num)
+{
+ int i;
+ wchar_t wc,wc2;
+
+ if (a == NULL || b == NULL) return false;
+
+ num--;
+
+ for (i = 0; i != num; i++) {
+ if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) && (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return true;
+ if ((a[i*2] == 0x00 && a[i*2+1] == 0x00) || (b[i*2] == 0x00 && b[i*2+1] == 0x00)) return false;
+ wc = a[i*2+1] | (a[i*2] << 8);
+ wc2 = b[i*2+1] | (b[i*2] << 8);
+ if (mytowlower(wc) != mytowlower(wc2)) return false;
+ }
+ return true;
+}
+
+/* wcscmp in Mandrake 9.0 is wrong */
+bool mywstrncmp(unsigned const char *a, unsigned const char *b, int num)
+{
+ int i=0;
+
+ while (1) {
+ if (a[i*2] != b[i*2] || a[i*2+1] != b[i*2+1]) return false;
+ if (a[i*2] == 0x00 && a[i*2+1] == 0x00) return true;
+ i++;
+ if (num == i) return true;
+ }
+}
+
+/* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
+bool myiswspace(unsigned const char *src)
+{
+#ifndef HAVE_ISWSPACE
+ int o;
+ unsigned char dest[10];
+#endif
+ wchar_t wc;
+
+ wc = src[1] | (src[0] << 8);
+
+#ifndef HAVE_ISWSPACE
+ o = DecodeWithUnicodeAlphabet(wc, dest);
+ if (o == 1) {
+ if (isspace(((int)dest[0]))!=0) return true;
+ return false;
+ }
+ return false;
+#else
+ return iswspace(wc);
+#endif
+}
+
+/* FreeBSD boxes 4.7-STABLE does't have it, although it's ANSI standard */
+int mytowlower(wchar_t c)
+{
+#ifndef HAVE_TOWLOWER
+ unsigned char dest[10];
+
+ DecodeWithUnicodeAlphabet(c, dest);
+ return tolower(dest[0]);
+#else
+ return towlower(c);
+#endif
+}
+
+/*
+ * Following code is based on wcsstr from the GNU C Library, original
+ * comment follows:
+ */
+/*
+ * The original strstr() file contains the following comment:
+ *
+ * My personal strstr() implementation that beats most other algorithms.
+ * Until someone tells me otherwise, I assume that this is the
+ * fastest implementation of strstr() in C.
+ * I deliberately chose not to comment it. You should have at least
+ * as much fun trying to understand it, as I had to write it :-).
+ *
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
+
+unsigned char *mystrstr (const unsigned char *haystack, const unsigned char *needle)
+{
+/* One crazy define to convert unicode used in Gammu to standard wchar_t */
+#define tolowerwchar(x) (mytowlower((wchar_t)( (((&(x))[0] & 0xff) << 8) | (((&(x))[1] & 0xff)) )))
+ register wchar_t b, c;
+
+ if ((b = tolowerwchar(*needle)) != L'\0') {
+ haystack -= 2; /* possible ANSI violation */
+ do {
+ haystack += 2;
+ if ((c = tolowerwchar(*haystack)) == L'\0')
+ goto ret0;
+ } while (c != b);
+
+ needle += 2;
+ if ((c = tolowerwchar(*needle)) == L'\0')
+ goto foundneedle;
+ needle += 2;
+ goto jin;
+
+ for (;;) {
+ register wchar_t a;
+ register const unsigned char *rhaystack, *rneedle;
+
+ do {
+ haystack += 2;
+ if ((a = tolowerwchar(*haystack)) == L'\0')
+ goto ret0;
+ if (a == b)
+ break;
+ haystack += 2;
+ if ((a = tolowerwchar(*haystack)) == L'\0')
+ goto ret0;
+shloop: ;
+ } while (a != b);
+
+jin: haystack += 2;
+ if ((a = tolowerwchar(*haystack)) == L'\0')
+ goto ret0;
+
+ if (a != c)
+ goto shloop;
+
+ rhaystack = haystack + 2;
+ haystack -= 2;
+ rneedle = needle;
+ if (tolowerwchar(*rhaystack) == (a = tolowerwchar(*rneedle)))
+ do {
+ if (a == L'\0')
+ goto foundneedle;
+ rhaystack += 2;
+ needle += 2;
+ if (tolowerwchar(*rhaystack) != (a = tolowerwchar(*needle)))
+ break ;
+ if (a == L'\0')
+ goto foundneedle;
+ rhaystack += 2;
+ needle += 2;
+ } while (tolowerwchar(*rhaystack) == (a = tolowerwchar(*needle)));
+
+ needle = rneedle; /* took the register-poor approach */
+
+ if (a == L'\0')
+ break;
+ }
+ }
+foundneedle:
+ return (unsigned char *)haystack;
+ret0:
+ return NULL;
+#undef tolowerwchar
+}
+
+void MyGetLine(unsigned char *Buffer, int *Pos, unsigned char *OutBuffer, int MaxLen)
+{
+ OutBuffer[0] = 0;
+ if (Buffer == NULL) return;
+ while (1) {
+ if ((*Pos) >= MaxLen) return;
+ switch (Buffer[*Pos]) {
+ case 0x00:
+ return;
+ case 0x0A:
+ if (strlen(OutBuffer) != 0) return;
+ break;
+ case 0x0D:
+ if (strlen(OutBuffer) != 0) return;
+ break;
+ default :
+ OutBuffer[strlen(OutBuffer) + 1] = 0;
+ OutBuffer[strlen(OutBuffer)] = Buffer[*Pos];
+ }
+ (*Pos)++;
+ }
+}
+
+void StringToDouble(char *text, double *d)
+{
+ bool before=true;
+ double multiply = 1;
+ unsigned int i;
+
+ *d = 0;
+ for (i=0;i<strlen(text);i++) {
+ if (isdigit(text[i])) {
+ if (before) {
+ (*d)=(*d)*10+(text[i]-'0');
+ } else {
+ multiply=multiply*0.1;
+ (*d)=(*d)+(text[i]-'0')*multiply;
+ }
+ }
+ if (text[i]=='.' || text[i]==',') before=false;
+ }
+}
+
+/* When char can be converted, convert it from Unicode to UTF8 */
+bool EncodeWithUTF8Alphabet(unsigned char mychar1, unsigned char mychar2, unsigned char *ret1, unsigned char *ret2)
+{
+ unsigned char mychar3,mychar4;
+ int j=0;
+
+ if (mychar1>0x00 || mychar2>128) {
+ mychar3=0x00;
+ mychar4=128;
+ while (true) {
+ if (mychar3==mychar1) {
+ if (mychar4+64>=mychar2) {
+ *ret1=j+0xc2;
+ *ret2=0x80+(mychar2-mychar4);
+ return true;
+ }
+ }
+ if (mychar4==192) {
+ mychar3++;
+ mychar4=0;
+ } else {
+ mychar4=mychar4+64;
+ }
+ j++;
+ }
+ }
+ return false;
+}
+
+/* Make UTF8 string from Unicode input string */
+bool EncodeUTF8QuotedPrintable(unsigned char *dest, const unsigned char *src)
+{
+ int i,j=0;
+ unsigned char mychar1, mychar2;
+ bool retval = false;
+
+ for (i = 0; i < (int)(UnicodeLength(src)); i++) {
+ if (EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],&mychar1,&mychar2)) {
+ sprintf(dest+j, "=%02X=%02X",mychar1,mychar2);
+ j = j+6;
+ retval = true;
+ } else {
+ j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
+ }
+ }
+ dest[j++]=0;
+ return retval;
+}
+
+bool EncodeUTF8(unsigned char *dest, const unsigned char *src)
+{
+ int i,j=0;
+ unsigned char mychar1, mychar2;
+ bool retval = false;
+
+ for (i = 0; i < (int)(UnicodeLength(src)); i++) {
+ if (EncodeWithUTF8Alphabet(src[i*2],src[i*2+1],&mychar1,&mychar2)) {
+ sprintf(dest+j, "%c%c",mychar1,mychar2);
+ j = j+2;
+ retval = true;
+ } else {
+ j += DecodeWithUnicodeAlphabet(((wchar_t)(src[i*2]*256+src[i*2+1])), dest + j);
+ }
+ }
+ dest[j++]=0;
+ return retval;
+}
+
+/* Decode UTF8 char to Unicode char */
+wchar_t DecodeWithUTF8Alphabet(unsigned char mychar3, unsigned char mychar4)
+{
+ unsigned char mychar1, mychar2;
+ int j;
+
+ mychar1=0x00;
+ mychar2=128;
+ for(j=0;j<mychar3-0xc2;j++) {
+ if (mychar2==192) {
+ mychar1++;
+ mychar2 = 0;
+ } else {
+ mychar2 = mychar2+64;
+ }
+ }
+ mychar2 = mychar2+(mychar4-0x80);
+ return mychar2 | (mychar1 << 8);
+}
+
+/* Make Unicode string from UTF8 string */
+void DecodeUTF8QuotedPrintable(unsigned char *dest, const unsigned char *src, int len)
+{
+ int i=0,j=0;
+ unsigned char mychar1, mychar2;
+ wchar_t ret;
+
+ while (i<=len) {
+ if (len-6>=i) {
+ /* Need to have correct chars */
+ if (src[i] =='=' && DecodeWithHexBinAlphabet(src[i+1])!=-1
+ && DecodeWithHexBinAlphabet(src[i+2])!=-1 &&
+ src[i+3]=='=' && DecodeWithHexBinAlphabet(src[i+4])!=-1 &&
+ DecodeWithHexBinAlphabet(src[i+5])!=-1) {
+ mychar1 = 16*DecodeWithHexBinAlphabet(src[i+1])+DecodeWithHexBinAlphabet(src[i+2]);
+ mychar2 = 16*DecodeWithHexBinAlphabet(src[i+4])+DecodeWithHexBinAlphabet(src[i+5]);
+ ret = DecodeWithUTF8Alphabet(mychar1,mychar2);
+ i = i+6;
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ }
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ }
+ dest[j++] = (ret >> 8) & 0xff;
+ dest[j++] = ret & 0xff;
+ }
+ dest[j++] = 0;
+ dest[j++] = 0;
+}
+
+void DecodeUTF8(unsigned char *dest, const unsigned char *src, int len)
+{
+ int i=0,j=0;
+ wchar_t ret;
+
+ while (i<=len) {
+ if (len-2>=i) {
+ if (src[i] >= 0xC2) {
+ ret = DecodeWithUTF8Alphabet(src[i],src[i+1]);
+ i = i+2;
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ }
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ }
+ dest[j++] = (ret >> 8) & 0xff;
+ dest[j++] = ret & 0xff;
+ }
+ dest[j++] = 0;
+ dest[j++] = 0;
+}
+
+void DecodeUTF7(unsigned char *dest, const unsigned char *src, int len)
+{
+ int i=0,j=0,z,p;
+ wchar_t ret;
+
+ while (i<=len) {
+ if (len-5>=i) {
+ if (src[i] == '+') {
+ z=0;
+ while (src[z+i+1] != '-' && z+i+1<len) z++;
+ p=DecodeBASE64(src+i+1, dest+j, z);
+ if (p%2 != 0) p--;
+ j+=p;
+ i+=z+2;
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ dest[j++] = (ret >> 8) & 0xff;
+ dest[j++] = ret & 0xff;
+ }
+ } else {
+ i+=EncodeWithUnicodeAlphabet(&src[i], &ret);
+ dest[j++] = (ret >> 8) & 0xff;
+ dest[j++] = ret & 0xff;
+ }
+ }
+ dest[j++] = 0;
+ dest[j++] = 0;
+}
+
+/*
+Bob Trower 08/04/01
+Copyright (c) Trantor Standard Systems Inc., 2001
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall
+be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+static void EncodeBASE64Block(unsigned char in[3], unsigned char out[4], int len)
+{
+ /* BASE64 translation Table as described in RFC1113 */
+ unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ out[0] = cb64[ in[0] >> 2 ];
+ out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
+ out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
+ out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
+}
+
+void EncodeBASE64(const unsigned char *Input, unsigned char *Output, int Length)
+{
+ unsigned char in[3], out[4];
+ int i, pos = 0, len, outpos = 0;
+
+ while (pos < Length) {
+ len = 0;
+ for (i = 0; i < 3; i++) {
+ in[i] = 0;
+ if (pos < Length) {
+ in[i] = Input[pos];
+ len++;
+ pos++;
+ }
+ }
+ if(len) {
+ EncodeBASE64Block(in, out, len);
+ for (i = 0; i < 4; i++) Output[outpos++] = out[i];
+ }
+ }
+
+ Output[outpos++] = 0;
+}
+
+static void DecodeBASE64Block(unsigned char in[4], unsigned char out[3])
+{
+ out[0] = (unsigned char) (in[0] << 2 | in[1] >> 4);
+ out[1] = (unsigned char) (in[1] << 4 | in[2] >> 2);
+ out[2] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
+}
+
+int DecodeBASE64(const unsigned char *Input, unsigned char *Output, int Length)
+{
+ unsigned char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+ unsigned char in[4], out[3], v;
+ int i, len, pos = 0, outpos = 0;
+
+ while (pos < Length) {
+ len = 0;
+ for(i = 0; i < 4; i++) {
+ v = 0;
+ while(v == 0) {
+ if (pos >= Length) break;
+ v = (unsigned char) Input[pos++];
+ v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
+ if (v) v = (unsigned char) ((v == '$') ? 0 : v - 61);
+ }
+ if(pos<=Length) {
+ if (v) {
+ len++;
+ in[i] = (unsigned char) (v - 1);
+ }
+ }
+ }
+ if (len) {
+ DecodeBASE64Block(in, out);
+ for(i = 0; i < len - 1; i++) Output[outpos++] = out[i];
+ }
+ }
+ Output[outpos] = 0;
+ return outpos;
+}
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
+
diff --git a/gammu/emb/common/misc/coding/coding.h b/gammu/emb/common/misc/coding/coding.h
new file mode 100644
index 0000000..d0c334d
--- a/dev/null
+++ b/gammu/emb/common/misc/coding/coding.h
@@ -0,0 +1,133 @@
+/* (c) 2002-2004 by Marcin Wiacek and others */
+
+#ifndef __coding_h
+#define __coding_h
+
+#include <stdlib.h>
+
+#include "../misc.h"
+
+#ifdef __OpenBSD__
+typedef int wint_t;
+#endif
+
+/* ---------------------------- Unicode ------------------------------------ */
+bool mywstrncasecmp (unsigned const char *a, unsigned const char *b, int num);
+unsigned char *mystrstr (unsigned const char *haystack, unsigned const char *needle);
+bool mywstrncmp (unsigned const char *a, unsigned const char *b, int num);
+bool myiswspace (unsigned const char *src);
+int mytowlower (wchar_t c);
+
+unsigned int EncodeWithUnicodeAlphabet (const unsigned char *value, wchar_t *dest);
+unsigned int DecodeWithUnicodeAlphabet (wchar_t value, unsigned char *dest);
+
+unsigned int UnicodeLength (const unsigned char *str);
+unsigned char *DecodeUnicodeString (const unsigned char *src);
+unsigned char *DecodeUnicodeConsole (const unsigned char *src);
+void DecodeUnicode (const unsigned char *src, unsigned char *dest);
+void EncodeUnicode (unsigned char *dest, const unsigned char *src, int len);
+
+void CopyUnicodeString (unsigned char *Dest, unsigned char *Source);
+void ReverseUnicodeString (unsigned char *String);
+
+void ReadUnicodeFile (unsigned char *Dest, unsigned char *Source);
+
+void DecodeUnicodeSpecialNOKIAChars (unsigned char *dest, const unsigned char *src, int len);
+void EncodeUnicodeSpecialNOKIAChars (unsigned char *dest, const unsigned char *src, int len);
+
+/* ------------------------------- BCD ------------------------------------- */
+unsigned char EncodeWithBCDAlphabet (int value);
+int DecodeWithBCDAlphabet (unsigned char value);
+
+void DecodeBCD (unsigned char *dest, const unsigned char *src, int len);
+void EncodeBCD (unsigned char *dest, const unsigned char *src, int len, bool fill);
+
+/* ------------------------------ UTF7 ------------------------------------- */
+void DecodeUTF7 (unsigned char *dest, const unsigned char *src, int len);
+
+/* ------------------------------ UTF8 ------------------------------------- */
+wchar_t DecodeWithUTF8Alphabet (unsigned char mychar3, unsigned char mychar4);
+bool EncodeWithUTF8Alphabet (unsigned char mychar1, unsigned char mychar2, unsigned char *ret1, unsigned char *ret2);
+
+bool EncodeUTF8QuotedPrintable (unsigned char *dest, const unsigned char *src);
+void DecodeUTF8QuotedPrintable (unsigned char *dest, const unsigned char *src, int len);
+
+bool EncodeUTF8 (unsigned char *dest, const unsigned char *src);
+void DecodeUTF8 (unsigned char *dest, const unsigned char *src, int len);
+
+/* ------------------------------- BASE64 ---------------------------------- */
+void EncodeBASE64 (const unsigned char *Input, unsigned char *Output, int Length);
+int DecodeBASE64 (const unsigned char *Input, unsigned char *Output, int Length);
+
+/* ----------------------------- HexBin ------------------------------------ */
+void DecodeHexBin (unsigned char *dest, const unsigned char *src, int len);
+void EncodeHexBin (unsigned char *dest, const unsigned char *src, int len);
+
+/* ----------------------------- HexUnicode -------------------------------- */
+void DecodeHexUnicode (unsigned char *dest, const unsigned char *src, int len);
+void EncodeHexUnicode (unsigned char *dest, const unsigned char *src, int len);
+
+/* ---------------------- DefaultAlphabet for SMS -------------------------- */
+void EncodeDefault (unsigned char *dest, const unsigned char *src, int *len, bool UseExtensions, unsigned char *ExtraAlphabet);
+void DecodeDefault (unsigned char *dest, const unsigned char *src, int len, bool UseExtensions, unsigned char *ExtraAlphabet);
+void FindDefaultAlphabetLen (const unsigned char *src, int *srclen, int *smslen, int maxlen);
+
+int GSM_PackSevenBitsToEight (int offset, unsigned char *input, unsigned char *output, int length);
+int GSM_UnpackEightBitsToSeven (int offset, int in_length, int out_length,
+ unsigned char *input, unsigned char *output);
+
+/* ----------------- Phone numbers according to GSM specs ------------------ */
+
+/**
+ * Enum to handle types of phones numbers like
+ * specified in GSM 03.40 section 9.1.2.5
+ */
+typedef enum {
+ /**
+ * Unknown number type
+ */
+ NUMBER_UNKNOWN = 0x81,
+ /**
+ * International number (full number with code of country)
+ */
+ NUMBER_INTERNATIONAL = 0x91,
+ /**
+ * Alphanumeric number (with chars too)
+ */
+ NUMBER_ALPHANUMERIC = 0xD0
+
+ /* specification give also other values */
+} GSM_NumberType;
+
+void GSM_UnpackSemiOctetNumber (unsigned char *retval, unsigned char *Number, bool semioctet);
+int GSM_PackSemiOctetNumber (unsigned char *Number, unsigned char *Output, bool semioctet);
+
+/* ---------------------------- Bits --------------------------------------- */
+
+void BufferAlign (unsigned char *Destination, int *CurrentBit);
+void BufferAlignNumber(int *CurrentBit);
+
+void AddBuffer (unsigned char *Destination, int *CurrentBit, unsigned char *Source, int BitsToProcess);
+void AddBufferByte(unsigned char *Destination, int *CurrentBit, unsigned char Source, int BitsToProcess);
+
+void GetBuffer (unsigned char *Source, int *CurrentBit, unsigned char *Destination, int BitsToProcess);
+void GetBufferInt (unsigned char *Source, int *CurrentBit, int *integer, int BitsToProcess);
+void GetBufferI (unsigned char *Source, int *CurrentBit, int *result, int BitsToProcess);
+
+int GetBit (unsigned char *Buffer, int BitNum);
+int SetBit (unsigned char *Buffer, int BitNum);
+int ClearBit (unsigned char *Buffer, int BitNum);
+
+/* ---------------------------- Other -------------------------------------- */
+
+void StringToDouble (char *text, double *d);
+
+bool mystrncasecmp (unsigned const char *a, unsigned const char *b, int num);
+
+void MyGetLine(unsigned char *Buffer, int *Pos, unsigned char *OutBuffer, int MaxLen);
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/misc/coding/md5.c b/gammu/emb/common/misc/coding/md5.c
new file mode 100644
index 0000000..30fe33f
--- a/dev/null
+++ b/gammu/emb/common/misc/coding/md5.c
@@ -0,0 +1,298 @@
+/* Taken from ReHash (see http://www.reichlsoft.de.vu/) and released
+ * under GPL/LGPL with permission from ReHash author
+ * Dominik Reichl <dominik.reichl@t-online.de>, Germany
+ */
+
+/*
+ **********************************************************************
+ ** MD5.cpp **
+ ** **
+ ** - Style modified by Tony Ray, January 2001 **
+ ** Added support for randomizing initialization constants **
+ ** - Style modified by Dominik Reichl, April 2003 **
+ ** Optimized code **
+ ** **
+ ** MD5.c **
+ ** RSA Data Security, Inc. MD5 Message Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** MD5.h -- Header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ **********************************************************************
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "md5.h"
+
+/* Typedef a 32 bit type */
+#ifndef UINT4
+typedef unsigned long int UINT4;
+#endif
+
+/* Data structure for MD5 (Message Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* Number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* Scratch buffer */
+ unsigned char in[64]; /* Input buffer */
+ unsigned char digest[16]; /* Actual digest after MD5Final call */
+} MD5_CTX;
+
+/* Padding */
+static unsigned char MD5_PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* MD5_F, MD5_G and MD5_H are basic MD5 functions: selection, majority, parity */
+#define MD5_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define MD5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define MD5_H(x, y, z) ((x) ^ (y) ^ (z))
+#define MD5_I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#ifndef ROTATE_LEFT
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+#endif
+
+/* MD5_FF, MD5_GG, MD5_HH, and MD5_II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define MD5_FF(a, b, c, d, x, s, ac) {(a) += MD5_F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define MD5_GG(a, b, c, d, x, s, ac) {(a) += MD5_G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define MD5_HH(a, b, c, d, x, s, ac) {(a) += MD5_H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define MD5_II(a, b, c, d, x, s, ac) {(a) += MD5_I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+
+/* Constants for transformation */
+#define MD5_S11 7 /* Round 1 */
+#define MD5_S12 12
+#define MD5_S13 17
+#define MD5_S14 22
+#define MD5_S21 5 /* Round 2 */
+#define MD5_S22 9
+#define MD5_S23 14
+#define MD5_S24 20
+#define MD5_S31 4 /* Round 3 */
+#define MD5_S32 11
+#define MD5_S33 16
+#define MD5_S34 23
+#define MD5_S41 6 /* Round 4 */
+#define MD5_S42 10
+#define MD5_S43 15
+#define MD5_S44 21
+
+/* Basic MD5 step. MD5_Transform buf based on in */
+static void MD5_Transform (UINT4 *buf, UINT4 *in)
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ MD5_FF ( a, b, c, d, in[ 0], MD5_S11, (UINT4) 3614090360u); /* 1 */
+ MD5_FF ( d, a, b, c, in[ 1], MD5_S12, (UINT4) 3905402710u); /* 2 */
+ MD5_FF ( c, d, a, b, in[ 2], MD5_S13, (UINT4) 606105819u); /* 3 */
+ MD5_FF ( b, c, d, a, in[ 3], MD5_S14, (UINT4) 3250441966u); /* 4 */
+ MD5_FF ( a, b, c, d, in[ 4], MD5_S11, (UINT4) 4118548399u); /* 5 */
+ MD5_FF ( d, a, b, c, in[ 5], MD5_S12, (UINT4) 1200080426u); /* 6 */
+ MD5_FF ( c, d, a, b, in[ 6], MD5_S13, (UINT4) 2821735955u); /* 7 */
+ MD5_FF ( b, c, d, a, in[ 7], MD5_S14, (UINT4) 4249261313u); /* 8 */
+ MD5_FF ( a, b, c, d, in[ 8], MD5_S11, (UINT4) 1770035416u); /* 9 */
+ MD5_FF ( d, a, b, c, in[ 9], MD5_S12, (UINT4) 2336552879u); /* 10 */
+ MD5_FF ( c, d, a, b, in[10], MD5_S13, (UINT4) 4294925233u); /* 11 */
+ MD5_FF ( b, c, d, a, in[11], MD5_S14, (UINT4) 2304563134u); /* 12 */
+ MD5_FF ( a, b, c, d, in[12], MD5_S11, (UINT4) 1804603682u); /* 13 */
+ MD5_FF ( d, a, b, c, in[13], MD5_S12, (UINT4) 4254626195u); /* 14 */
+ MD5_FF ( c, d, a, b, in[14], MD5_S13, (UINT4) 2792965006u); /* 15 */
+ MD5_FF ( b, c, d, a, in[15], MD5_S14, (UINT4) 1236535329u); /* 16 */
+
+ /* Round 2 */
+ MD5_GG ( a, b, c, d, in[ 1], MD5_S21, (UINT4) 4129170786u); /* 17 */
+ MD5_GG ( d, a, b, c, in[ 6], MD5_S22, (UINT4) 3225465664u); /* 18 */
+ MD5_GG ( c, d, a, b, in[11], MD5_S23, (UINT4) 643717713u); /* 19 */
+ MD5_GG ( b, c, d, a, in[ 0], MD5_S24, (UINT4) 3921069994u); /* 20 */
+ MD5_GG ( a, b, c, d, in[ 5], MD5_S21, (UINT4) 3593408605u); /* 21 */
+ MD5_GG ( d, a, b, c, in[10], MD5_S22, (UINT4) 38016083u); /* 22 */
+ MD5_GG ( c, d, a, b, in[15], MD5_S23, (UINT4) 3634488961u); /* 23 */
+ MD5_GG ( b, c, d, a, in[ 4], MD5_S24, (UINT4) 3889429448u); /* 24 */
+ MD5_GG ( a, b, c, d, in[ 9], MD5_S21, (UINT4) 568446438u); /* 25 */
+ MD5_GG ( d, a, b, c, in[14], MD5_S22, (UINT4) 3275163606u); /* 26 */
+ MD5_GG ( c, d, a, b, in[ 3], MD5_S23, (UINT4) 4107603335u); /* 27 */
+ MD5_GG ( b, c, d, a, in[ 8], MD5_S24, (UINT4) 1163531501u); /* 28 */
+ MD5_GG ( a, b, c, d, in[13], MD5_S21, (UINT4) 2850285829u); /* 29 */
+ MD5_GG ( d, a, b, c, in[ 2], MD5_S22, (UINT4) 4243563512u); /* 30 */
+ MD5_GG ( c, d, a, b, in[ 7], MD5_S23, (UINT4) 1735328473u); /* 31 */
+ MD5_GG ( b, c, d, a, in[12], MD5_S24, (UINT4) 2368359562u); /* 32 */
+
+ /* Round 3 */
+ MD5_HH ( a, b, c, d, in[ 5], MD5_S31, (UINT4) 4294588738u); /* 33 */
+ MD5_HH ( d, a, b, c, in[ 8], MD5_S32, (UINT4) 2272392833u); /* 34 */
+ MD5_HH ( c, d, a, b, in[11], MD5_S33, (UINT4) 1839030562u); /* 35 */
+ MD5_HH ( b, c, d, a, in[14], MD5_S34, (UINT4) 4259657740u); /* 36 */
+ MD5_HH ( a, b, c, d, in[ 1], MD5_S31, (UINT4) 2763975236u); /* 37 */
+ MD5_HH ( d, a, b, c, in[ 4], MD5_S32, (UINT4) 1272893353u); /* 38 */
+ MD5_HH ( c, d, a, b, in[ 7], MD5_S33, (UINT4) 4139469664u); /* 39 */
+ MD5_HH ( b, c, d, a, in[10], MD5_S34, (UINT4) 3200236656u); /* 40 */
+ MD5_HH ( a, b, c, d, in[13], MD5_S31, (UINT4) 681279174u); /* 41 */
+ MD5_HH ( d, a, b, c, in[ 0], MD5_S32, (UINT4) 3936430074u); /* 42 */
+ MD5_HH ( c, d, a, b, in[ 3], MD5_S33, (UINT4) 3572445317u); /* 43 */
+ MD5_HH ( b, c, d, a, in[ 6], MD5_S34, (UINT4) 76029189u); /* 44 */
+ MD5_HH ( a, b, c, d, in[ 9], MD5_S31, (UINT4) 3654602809u); /* 45 */
+ MD5_HH ( d, a, b, c, in[12], MD5_S32, (UINT4) 3873151461u); /* 46 */
+ MD5_HH ( c, d, a, b, in[15], MD5_S33, (UINT4) 530742520u); /* 47 */
+ MD5_HH ( b, c, d, a, in[ 2], MD5_S34, (UINT4) 3299628645u); /* 48 */
+
+ /* Round 4 */
+ MD5_II ( a, b, c, d, in[ 0], MD5_S41, (UINT4) 4096336452u); /* 49 */
+ MD5_II ( d, a, b, c, in[ 7], MD5_S42, (UINT4) 1126891415u); /* 50 */
+ MD5_II ( c, d, a, b, in[14], MD5_S43, (UINT4) 2878612391u); /* 51 */
+ MD5_II ( b, c, d, a, in[ 5], MD5_S44, (UINT4) 4237533241u); /* 52 */
+ MD5_II ( a, b, c, d, in[12], MD5_S41, (UINT4) 1700485571u); /* 53 */
+ MD5_II ( d, a, b, c, in[ 3], MD5_S42, (UINT4) 2399980690u); /* 54 */
+ MD5_II ( c, d, a, b, in[10], MD5_S43, (UINT4) 4293915773u); /* 55 */
+ MD5_II ( b, c, d, a, in[ 1], MD5_S44, (UINT4) 2240044497u); /* 56 */
+ MD5_II ( a, b, c, d, in[ 8], MD5_S41, (UINT4) 1873313359u); /* 57 */
+ MD5_II ( d, a, b, c, in[15], MD5_S42, (UINT4) 4264355552u); /* 58 */
+ MD5_II ( c, d, a, b, in[ 6], MD5_S43, (UINT4) 2734768916u); /* 59 */
+ MD5_II ( b, c, d, a, in[13], MD5_S44, (UINT4) 1309151649u); /* 60 */
+ MD5_II ( a, b, c, d, in[ 4], MD5_S41, (UINT4) 4149444226u); /* 61 */
+ MD5_II ( d, a, b, c, in[11], MD5_S42, (UINT4) 3174756917u); /* 62 */
+ MD5_II ( c, d, a, b, in[ 2], MD5_S43, (UINT4) 718787259u); /* 63 */
+ MD5_II ( b, c, d, a, in[ 9], MD5_S44, (UINT4) 3951481745u); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+// Set pseudoRandomNumber to zero for RFC MD5 implementation
+void MD5Init (MD5_CTX *mdContext, unsigned long pseudoRandomNumber)
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants */
+ mdContext->buf[0] = (UINT4)0x67452301 + (pseudoRandomNumber * 11);
+ mdContext->buf[1] = (UINT4)0xefcdab89 + (pseudoRandomNumber * 71);
+ mdContext->buf[2] = (UINT4)0x98badcfe + (pseudoRandomNumber * 37);
+ mdContext->buf[3] = (UINT4)0x10325476 + (pseudoRandomNumber * 97);
+}
+
+void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)
+{
+ UINT4 in[16];
+ int mdi = 0;
+ unsigned int i = 0, ii = 0;
+
+ /* Compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* Add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* Transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+
+ MD5_Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+void MD5Final (MD5_CTX *mdContext)
+{
+ UINT4 in[16];
+ int mdi = 0;
+ unsigned int i = 0, ii = 0, padLen = 0;
+
+ /* Save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* Compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* Pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, MD5_PADDING, padLen);
+
+ /* Append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ MD5_Transform (mdContext->buf, in);
+
+ /* Store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)( mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] = (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] = (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] = (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+}
+
+void CalculateMD5(unsigned char *buffer, int length, unsigned char *checksum)
+{
+ int i;
+ MD5_CTX m_md5;
+
+ MD5Init(&m_md5, 0);
+ MD5Update(&m_md5, buffer, length);
+ MD5Final(&m_md5);
+
+ for (i = 0; i < 16; i++) sprintf(checksum+i*2,"%02X", m_md5.digest[i]);
+}
diff --git a/gammu/emb/common/misc/coding/md5.h b/gammu/emb/common/misc/coding/md5.h
new file mode 100644
index 0000000..9da9229
--- a/dev/null
+++ b/gammu/emb/common/misc/coding/md5.h
@@ -0,0 +1,6 @@
+#ifndef __md5_h
+#define __md5_h
+
+void CalculateMD5(unsigned char *buffer, int length, unsigned char *checksum);
+
+#endif
diff --git a/gammu/emb/common/misc/misc.c b/gammu/emb/common/misc/misc.c
new file mode 100644
index 0000000..c2f09e4
--- a/dev/null
+++ b/gammu/emb/common/misc/misc.c
@@ -0,0 +1,591 @@
+/* (c) 2002-2004 by Marcin Wiacek and Michal Cihar */
+/* Checking used compiler (c) 2002 by Michal Cihar */
+
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <locale.h>
+#include <sys/timeb.h>
+#ifdef WIN32
+# include "windows.h"
+#endif
+
+#include "../gsmstate.h"
+#include "misc.h"
+
+/* Based on article in Polish PC-Kurier 8/1998 page 104
+ * Archive on http://www.pckurier.pl
+ */
+char *DayOfWeek (int year, int month, int day)
+{
+ int p,q,r,w;
+ static char DayOfWeekChar[10];
+
+ p=(14-month) / 12;
+ q=month+12*p-2;
+ r=year-p;
+ w=(day+(31*q) / 12 + r + r / 4 - r / 100 + r / 400) % 7;
+ strcpy(DayOfWeekChar,"");
+ switch (w) {
+ case 0: strcpy(DayOfWeekChar,"Sun"); break;
+ case 1: strcpy(DayOfWeekChar,"Mon"); break;
+ case 2: strcpy(DayOfWeekChar,"Tue"); break;
+ case 3: strcpy(DayOfWeekChar,"Wed"); break;
+ case 4: strcpy(DayOfWeekChar,"Thu"); break;
+ case 5: strcpy(DayOfWeekChar,"Fri"); break;
+ case 6: strcpy(DayOfWeekChar,"Sat"); break;
+ }
+ return DayOfWeekChar;
+}
+
+void Fill_GSM_DateTime(GSM_DateTime *Date, time_t timet)
+{
+ struct tm *now;
+
+ now = localtime(&timet);
+ Date->Year = now->tm_year;
+ Date->Month = now->tm_mon+1;
+ Date->Day = now->tm_mday;
+ Date->Hour = now->tm_hour;
+ Date->Minute = now->tm_min;
+ Date->Second = now->tm_sec;
+}
+
+void GSM_GetCurrentDateTime (GSM_DateTime *Date)
+{
+ Fill_GSM_DateTime(Date, time(NULL));
+ if (Date->Year<1900) {
+ if (Date->Year>90) Date->Year = Date->Year+1900;
+ else Date->Year = Date->Year+2000;
+ }
+}
+
+time_t Fill_Time_T(GSM_DateTime DT, int TZ)
+{
+ struct tm tm_starttime;
+ unsigned char buffer[30];
+
+ dbgprintf(" StartTime : %02i-%02i-%04i %02i:%02i:%02i\n",
+ DT.Day,DT.Month,DT.Year,DT.Hour,DT.Minute,DT.Second);
+
+ if (TZ != 0) {
+#if defined(WIN32) || defined(__SVR4)
+ sprintf(buffer,"TZ=PST+%i",TZ);
+ putenv(buffer);
+#else
+ sprintf(buffer,"PST+%i",TZ);
+ setenv("TZ",buffer,1);
+#endif
+ }
+ tzset();
+
+ memset(&tm_starttime, 0, sizeof(tm_starttime));
+ tm_starttime.tm_year = DT.Year - 1900;
+ tm_starttime.tm_mon = DT.Month - 1;
+ tm_starttime.tm_mday = DT.Day;
+ tm_starttime.tm_hour = DT.Hour;
+ tm_starttime.tm_min = DT.Minute;
+ tm_starttime.tm_sec = DT.Second;
+ tm_starttime.tm_isdst = 0;
+
+ return mktime(&tm_starttime);
+}
+
+void GetTimeDifference(unsigned long diff, GSM_DateTime *DT, bool Plus, int multi)
+{
+ time_t t_time;
+
+ t_time = Fill_Time_T(*DT,8);
+
+ if (Plus) {
+ t_time += diff*multi;
+ } else {
+ t_time -= diff*multi;
+ }
+
+ Fill_GSM_DateTime(DT, t_time);
+ DT->Year = DT->Year + 1900;
+ dbgprintf(" EndTime : %02i-%02i-%04i %02i:%02i:%02i\n",
+ DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second);
+}
+
+char *OSDateTime (GSM_DateTime dt, bool TimeZone)
+{
+ struct tm timeptr;
+ static char retval[200],retval2[200];
+ int p,q,r,w;
+
+#ifdef WIN32
+ setlocale(LC_ALL, ".OCP");
+#endif
+
+ /* Based on article in Polish PC-Kurier 8/1998 page 104
+ * Archive on http://www.pckurier.pl
+ */
+ p=(14-dt.Month) / 12;
+ q=dt.Month+12*p-2;
+ r=dt.Year-p;
+ w=(dt.Day+(31*q) / 12 + r + r / 4 - r / 100 + r / 400) % 7;
+
+ timeptr.tm_yday = 0; /* FIXME */
+ timeptr.tm_isdst = -1; /* FIXME */
+ timeptr.tm_year = dt.Year - 1900;
+ timeptr.tm_mon = dt.Month - 1;
+ timeptr.tm_mday = dt.Day;
+ timeptr.tm_hour = dt.Hour;
+ timeptr.tm_min = dt.Minute;
+ timeptr.tm_sec = dt.Second;
+ timeptr.tm_wday = w;
+#ifdef _BSD_SOURCE
+ timeptr.tm_zone = NULL;
+#endif
+
+#ifdef WIN32
+ strftime(retval2, 200, "%#c", &timeptr);
+#else
+ strftime(retval2, 200, "%c", &timeptr);
+#endif
+ if (TimeZone) {
+ if (dt.Timezone >= 0) {
+ sprintf(retval," +%02i00",dt.Timezone);
+ } else {
+ sprintf(retval," -%02i00",dt.Timezone);
+ }
+ strcat(retval2,retval);
+ }
+ /* If don't have weekday name, include it */
+ strftime(retval, 200, "%A", &timeptr);
+ if (strstr(retval2,retval)==NULL) {
+ /* Check for abbreviated weekday */
+ strftime(retval, 200, "%a", &timeptr);
+ if (strstr(retval2,retval)==NULL) {
+ strcat(retval2," (");
+ strcat(retval2,retval);
+ strcat(retval2,")");
+ }
+ }
+
+#ifdef WIN32
+ setlocale(LC_ALL, ".ACP");
+#endif
+
+ return retval2;
+}
+
+char *OSDate (GSM_DateTime dt)
+{
+ struct tm timeptr;
+ static char retval[200],retval2[200];
+ int p,q,r,w;
+
+#ifdef WIN32
+ setlocale(LC_ALL, ".OCP");
+#endif
+
+ /* Based on article in Polish PC-Kurier 8/1998 page 104
+ * Archive on http://www.pckurier.pl
+ */
+ p=(14-dt.Month) / 12;
+ q=dt.Month+12*p-2;
+ r=dt.Year-p;
+ w=(dt.Day+(31*q) / 12 + r + r / 4 - r / 100 + r / 400) % 7;
+
+ timeptr.tm_yday = 0; /* FIXME */
+ timeptr.tm_isdst = -1; /* FIXME */
+ timeptr.tm_year = dt.Year - 1900;
+ timeptr.tm_mon = dt.Month - 1;
+ timeptr.tm_mday = dt.Day;
+ timeptr.tm_hour = dt.Hour;
+ timeptr.tm_min = dt.Minute;
+ timeptr.tm_sec = dt.Second;
+ timeptr.tm_wday = w;
+#ifdef _BSD_SOURCE
+ timeptr.tm_zone = NULL;
+#endif
+
+#ifdef WIN32
+ strftime(retval2, 200, "%#x", &timeptr);
+#else
+ strftime(retval2, 200, "%x", &timeptr);
+#endif
+ /* If don't have weekday name, include it */
+ strftime(retval, 200, "%A", &timeptr);
+ if (strstr(retval2,retval)==NULL) {
+ /* Check also for short name */
+ strftime(retval, 200, "%a", &timeptr);
+ if (strstr(retval2,retval)==NULL) {
+ strcat(retval2," (");
+ strcat(retval2,retval);
+ strcat(retval2,")");
+ }
+ }
+
+#ifdef WIN32
+ setlocale(LC_ALL, ".ACP");
+#endif
+
+ return retval2;
+}
+
+bool CheckDate(GSM_DateTime *date)
+{
+ /* FIXME: This could also check if day is correct for selected month */
+ return date->Year != 0 &&
+ date->Month >= 1 && date->Month <= 12 &&
+ date->Day >= 1 && date->Day <= 31;
+}
+
+bool CheckTime(GSM_DateTime *date)
+{
+ return date->Hour <= 23 && date->Hour >= 0 &&
+ date->Minute <= 59 && date->Minute >= 0 &&
+ date->Second <= 59 && date->Second >= 0;
+}
+
+int GetLine(FILE *File, char *Line, int count)
+{
+ int num;
+
+ if (fgets(Line, count, File) != NULL) {
+ num = strlen(Line) - 1;
+ while(1) {
+ if (Line[num] != '\n' && Line[num] != '\r') break;
+ if (num == 0) break;
+ Line[num--] = 0;
+ }
+ return strlen(Line);
+ }
+ return -1;
+}
+
+void SplitLines(unsigned char *message, int messagesize, GSM_Lines *lines, unsigned char *whitespaces, int spaceslen, bool eot)
+{
+ int i,number=0,j;
+ bool whitespace=true, nowwhite;
+
+ for (i=0;i<MAX_LINES*2;i++) lines->numbers[i]=0;
+
+ for (i=0;i<messagesize;i++) {
+ nowwhite = false;
+ for (j=0;j<spaceslen;j++) {
+ if (whitespaces[j] == message[i]) {
+ nowwhite = true;
+ break;
+ }
+ }
+ if (whitespace) {
+ if (!nowwhite) {
+ lines->numbers[number]=i;
+ number++;
+ whitespace=false;
+ }
+ } else {
+ if (nowwhite) {
+ lines->numbers[number]=i;
+ number++;
+ whitespace=true;
+ }
+
+ }
+ }
+ if (eot && !whitespace) lines->numbers[number]=messagesize;
+}
+
+char *GetLineString(unsigned char *message, GSM_Lines lines, int start)
+{
+ static char retval[800];
+
+ memcpy(retval,message + lines.numbers[start*2-2],lines.numbers[start*2-2+1]-lines.numbers[start*2-2]);
+ retval[lines.numbers[start*2-2+1]-lines.numbers[start*2-2]]=0;
+
+ return retval;
+}
+
+void CopyLineString(unsigned char *dest, unsigned char *src, GSM_Lines lines, int start)
+{
+ memcpy(dest,GetLineString(src, lines, start),strlen(GetLineString(src, lines, start)));
+ dest[strlen(GetLineString(src, lines, start))] = 0;
+}
+
+Debug_Info di = {0,NULL,false,""};
+
+#ifdef DEBUG
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+int dbgprintf(const char *format, ...)
+{
+ va_list argp;
+ int result;
+ static unsigned char nextline[2000]="";
+ unsigned char buffer[2000];
+ GSM_DateTime date_time;
+
+ if (di.df != NULL && (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE)) {
+ va_start(argp, format);
+ result = vsprintf(buffer, format, argp);
+ strcat(nextline, buffer);
+ if (strstr(buffer, "\n")) {
+ if (di.dl == DL_TEXTALLDATE) {
+ GSM_GetCurrentDateTime(&date_time);
+ fprintf(di.df,"%s %4d/%02d/%02d %02d:%02d:%02d: %s",
+ DayOfWeek(date_time.Year, date_time.Month, date_time.Day),
+ date_time.Year, date_time.Month, date_time.Day,
+ date_time.Hour, date_time.Minute, date_time.Second,nextline);
+ } else {
+ fprintf(di.df,"%s",nextline);
+ }
+ strcpy(nextline, "");
+ }
+ fflush(di.df);
+ va_end(argp);
+ return result;
+ }
+ return 0;
+}
+#endif
+
+/* assumption: if \n is present it is always the last char,
+ * string never of the form "......\n..."
+ */
+#ifdef __GNUC__
+__attribute__((format(printf, 3, 4)))
+#endif
+int smfprintf(FILE *f, Debug_Level dl, const char *format, ...)
+{
+ va_list argp;
+ int result=0;
+ static unsigned char prevline[2000] = "", nextline[2000]="";
+ static unsigned int linecount=0;
+ unsigned char buffer[2000];
+ GSM_DateTime date_time;
+
+ if (f == NULL) return 0;
+ va_start(argp, format);
+ result = vsprintf(buffer, format, argp);
+ strcat(nextline, buffer);
+ if (strstr(buffer, "\n")) {
+ if (ftell(f) < 5000000) {
+ GSM_GetCurrentDateTime(&date_time);
+ if (linecount > 0) {
+ if (dl == DL_TEXTALLDATE || dl == DL_TEXTERRORDATE || dl == DL_TEXTDATE) {
+ fprintf(f,"%s %4d/%02d/%02d %02d:%02d:%02d: <%i> %s",
+ DayOfWeek(date_time.Year, date_time.Month, date_time.Day),
+ date_time.Year, date_time.Month, date_time.Day,
+ date_time.Hour, date_time.Minute, date_time.Second,linecount,prevline);
+ } else {
+ fprintf(f,"%s",prevline);
+ }
+ }
+ linecount=0;
+ if (dl == DL_TEXTALLDATE || dl == DL_TEXTERRORDATE || dl == DL_TEXTDATE) {
+ fprintf(f,"%s %4d/%02d/%02d %02d:%02d:%02d: %s",
+ DayOfWeek(date_time.Year, date_time.Month, date_time.Day),
+ date_time.Year, date_time.Month, date_time.Day,
+ date_time.Hour, date_time.Minute, date_time.Second,nextline);
+ } else {
+ fprintf(f,"%s",nextline);
+ }
+ strcpy(prevline, nextline);
+ }
+ strcpy(nextline, "");
+ fflush(f);
+ }
+ va_end(argp);
+ return result;
+}
+
+bool GSM_SetDebugLevel(char *info, Debug_Info *di)
+{
+ if (!strcmp(info,"nothing")) {di->dl = 0; return true;}
+ if (!strcmp(info,"text")) {di->dl = DL_TEXT; return true;}
+ if (!strcmp(info,"textall")) {di->dl = DL_TEXTALL; return true;}
+ if (!strcmp(info,"binary")) {di->dl = DL_BINARY; return true;}
+ if (!strcmp(info,"errors")) {di->dl = DL_TEXTERROR; return true;}
+ if (!strcmp(info,"textdate")) {di->dl = DL_TEXTDATE; return true;}
+ if (!strcmp(info,"textalldate")) {di->dl = DL_TEXTALLDATE; return true;}
+ if (!strcmp(info,"errorsdate")) {di->dl = DL_TEXTERRORDATE; return true;}
+ return false;
+}
+
+/* Dumps a message */
+void DumpMessage(FILE *df, Debug_Level dl, const unsigned char *message, int messagesize)
+{
+ int i,j=0,len=16;
+ unsigned char buffer[200];
+
+ if (df==NULL || messagesize == 0) return;
+
+ smfprintf(df, dl, "\n");
+
+ memset(buffer,0x20,sizeof(buffer));
+ buffer[len*5-1]=0;
+
+ for (i = 0; i < messagesize; i++) {
+ sprintf(buffer+j*4,"%02X",message[i]);
+ buffer[j*4+2] = 0x20;
+ if (isprint(message[i]) && message[i]!=0x09) {
+ if (j != len-1) buffer[j*4+2] = message[i];
+ buffer[(len-1)*4+j+3] = message[i];
+ } else {
+ buffer[(len-1)*4+j+3] = '.';
+ }
+ if (j != len-1 && i != messagesize-1) buffer[j*4+3] = '|';
+ if (j == len-1) {
+ smfprintf(df, dl, "%s\n", buffer);
+ memset(buffer,0x20,sizeof(buffer));
+ buffer[len*5-1]=0;
+ j = 0;
+ } else {
+ j++;
+ }
+ }
+ if (j != 0) smfprintf(df, dl, "%s\n", buffer);
+}
+
+char *GetOS(void)
+{
+#ifdef WIN32
+ OSVERSIONINFOEX Ver;
+ bool Extended = true;
+#endif
+ static char Buffer[100] = {0x00};
+
+#ifdef WIN32
+ memset(&Ver,sizeof(OSVERSIONINFOEX),0);
+ Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+ if (!GetVersionEx((OSVERSIONINFO *)&Ver)) {
+ Extended = false;
+ Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx((OSVERSIONINFO *)&Ver)) {
+//#ifdef _MSC_VER
+// Ver.dwMajorVersion = _winmajor;
+// Ver.dwMinorVersion = _winminor;
+// Ver.dwBuildNumber = _osver;
+//#else
+ sprintf(Buffer, "Windows");
+ return Buffer;
+//#endif
+ }
+ }
+
+ /* ----------------- 9x family ------------------ */
+
+ /* no info about Win95 SP1, Win95 OSR2.1, Win95 OSR2.5.... */
+ if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 950) {
+ sprintf(Buffer,"Win 95");
+ } else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 1111) {
+ sprintf(Buffer,"Win 95 OSR2.x");
+
+ /* no info about Win98 SP1.... */
+ } else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 10 && Ver.dwBuildNumber == 1998) {
+ sprintf(Buffer,"Win 98");
+ } else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 10 && Ver.dwBuildNumber == 2222) {
+ sprintf(Buffer,"Win 98 SE");
+
+ } else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 90 && Ver.dwBuildNumber == 3000) {
+ sprintf(Buffer,"Win ME");
+
+ /* ---------------- NT family ------------------- */
+
+ } else if (Ver.dwMajorVersion == 4 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 1381) {
+ sprintf(Buffer,"Win NT 4.0");
+
+ } else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 0 && Ver.dwBuildNumber == 2195) {
+ sprintf(Buffer,"Win 2000");
+
+ } else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 1 && Ver.dwBuildNumber == 2600) {
+ sprintf(Buffer,"Win XP");
+#if _MSC_VER > 1200 //6.0 has it undeclared
+ if (Extended) {
+ if (Ver.wSuiteMask & VER_SUITE_PERSONAL) {
+ sprintf(Buffer+strlen(Buffer)," Home");
+ } else {
+ sprintf(Buffer+strlen(Buffer)," Pro");
+ }
+ }
+#endif
+
+ } else if (Ver.dwMajorVersion == 5 && Ver.dwMinorVersion == 2) {
+ sprintf(Buffer,"Win 2003");
+
+ } else {
+ sprintf(Buffer, "Windows %i.%i.%i",Ver.dwMajorVersion,Ver.dwMinorVersion,Ver.dwBuildNumber);
+ }
+
+ if (Extended && Ver.wServicePackMajor != 0) {
+ sprintf(Buffer+strlen(Buffer)," SP%i",Ver.wServicePackMajor);
+ }
+#elif defined(linux) || defined(__linux) || defined(__linux__)
+ sprintf(Buffer, "Linux");
+#elif defined(__FreeBSD__)
+ sprintf(Buffer, "FreeBSD");
+#elif defined(__NetBSD__)
+ sprintf(Buffer, "NetBSD");
+#elif defined(__OpenBSD__)
+ sprintf(Buffer, "OpenBSD");
+#elif defined(__GNU__)
+ sprintf(Buffer, "GNU/Hurd");
+#elif defined(sun) || defined(__sun) || defined(__sun__)
+# ifdef __SVR4
+ sprintf(Buffer, "Sun Solaris");
+# else
+ sprintf(Buffer, "SunOS");
+# endif
+#elif defined(hpux) || defined(__hpux) || defined(__hpux__)
+ sprintf(Buffer, "HP-UX");
+#elif defined(ultrix) || defined(__ultrix) || defined(__ultrix__)
+ sprintf(Buffer, "DEC Ultrix");
+#elif defined(sgi) || defined(__sgi)
+ sprintf(Buffer, "SGI Irix");
+#elif defined(__osf__)
+ sprintf(Buffer, "OSF Unix");
+#elif defined(bsdi) || defined(__bsdi__)
+ sprintf(Buffer, "BSDI Unix");
+#elif defined(_AIX)
+ sprintf(Buffer, "AIX Unix");
+#elif defined(_UNIXWARE)
+ sprintf(Buffer, "SCO Unixware");
+#elif defined(DGUX)
+ sprintf(Buffer, "DG Unix");
+#elif defined(__QNX__)
+ sprintf(Buffer, "QNX");
+#endif
+ return Buffer;
+}
+
+char *GetCompiler(void)
+{
+ static char Buffer[100] = {0x00};
+
+#ifdef WIN32
+# ifdef _MSC_VER
+ if (_MSC_VER == 1200) { //?
+ sprintf(Buffer, "MS VC 6.0");
+ } else if (_MSC_VER == 1300) {
+ sprintf(Buffer, "MS VC .NET 2002");
+ } else if (_MSC_VER == 1310) {
+ sprintf(Buffer, "MS VC .NET 2003");
+ } else {
+ sprintf(Buffer, "MS VC %i",_MSC_VER);
+ }
+# elif defined(__BORLANDC__)
+ sprintf(Buffer, "Borland C++ %i",__BORLANDC__);
+# endif
+#elif defined(DJGPP)
+ sprintf(Buffer, "djgpp");
+#elif defined(__GNUC__)
+ sprintf(Buffer, "gcc %i.%i", __GNUC__, __GNUC_MINOR__);
+#elif defined(__SUNPRO_CC)
+ sprintf(Buffer, "Sun C++ %x", __SUNPRO_CC);
+#endif
+
+ return Buffer;
+}
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */
diff --git a/gammu/emb/common/misc/misc.h b/gammu/emb/common/misc/misc.h
new file mode 100644
index 0000000..8b46170
--- a/dev/null
+++ b/gammu/emb/common/misc/misc.h
@@ -0,0 +1,137 @@
+/* (c) 2002-2004 by Marcin Wiacek */
+
+#ifndef __misc_h
+#define __misc_h
+
+#include <stdio.h>
+#include <time.h>
+#ifdef WIN32
+# include <windows.h>
+#endif
+
+#include "../config.h"
+
+#ifndef __cplusplus
+#ifndef false
+# define false 0
+#endif
+#ifndef true
+# define true !0
+#endif
+#ifndef bool
+# define bool char
+#endif
+#endif /* __cplusplus */
+
+#ifdef WIN32
+# define my_sleep(x) ((x)<1000 ? Sleep(1) : Sleep((x)/1000))
+#else
+# define my_sleep(x) usleep(x)
+#endif
+
+#undef MAX
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#undef MIN
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+/* ------------------------------------------------------------------------- */
+
+#define MAX_LINES 50
+
+int GetLine(FILE *File, char *Line, int count);
+
+typedef struct {
+ int numbers[MAX_LINES*2];
+} GSM_Lines;
+
+void SplitLines(unsigned char *message, int messagesize, GSM_Lines *lines, unsigned char *whitespaces, int spaceslen, bool eot);
+char *GetLineString(unsigned char *message, GSM_Lines lines, int start);
+void CopyLineString(unsigned char *dest, unsigned char *src, GSM_Lines lines, int start);
+
+/* ------------------------------------------------------------------------- */
+
+typedef enum {
+ DL_BINARY = 1, /* Binary transmission dump */
+ DL_TEXT, /* Text transmission dump */
+ DL_TEXTALL, /* Everything */
+ DL_TEXTERROR, /* Only errors */
+ DL_TEXTDATE, /* Text transmission dump */
+ DL_TEXTALLDATE, /* Everything */
+ DL_TEXTERRORDATE /* Only errors */
+} Debug_Level;
+
+typedef struct {
+ Debug_Level dl;
+ FILE *df;
+ bool use_global;
+ char *coding;
+} Debug_Info;
+
+extern Debug_Info di;
+
+#ifdef DEBUG
+#ifdef __GNUC__
+__attribute__((format(printf, 1, 2)))
+#endif
+int dbgprintf(const char *format, ...);
+#else
+# ifndef WIN32
+# define dbgprintf(a...) do { } while (0)
+# else
+# define dbgprintf
+# endif
+#endif
+
+#ifdef __GNUC__
+__attribute__((format(printf, 3, 4)))
+#endif
+int smfprintf(FILE *f, Debug_Level dl, const char *format, ...);
+
+void DumpMessage(FILE *df, Debug_Level dl, const unsigned char *message, int messagesize);
+
+bool GSM_SetDebugLevel(char *info, Debug_Info *di);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Structure used for saving date and time
+ */
+typedef struct {
+ /**
+ * The difference between local time and GMT in hours
+ */
+ int Timezone;
+
+ unsigned int Second;
+ unsigned int Minute;
+ unsigned int Hour;
+
+ unsigned int Day;
+ /**
+ * January = 1, February = 2, etc.
+ */
+ unsigned int Month;
+ /**
+ * Complete year number. Not 03, but 2003
+ */
+ unsigned int Year;
+} GSM_DateTime;
+
+void GSM_GetCurrentDateTime (GSM_DateTime *Date);
+char *OSDateTime (GSM_DateTime dt, bool TimeZone);
+char *OSDate (GSM_DateTime dt);
+char *DayOfWeek (int year, int month, int day);
+time_t Fill_Time_T (GSM_DateTime DT, int TZ);
+void GetTimeDifference (unsigned long diff, GSM_DateTime *DT, bool Plus, int multi);
+void Fill_GSM_DateTime (GSM_DateTime *Date, time_t timet);
+bool CheckDate (GSM_DateTime *date);
+bool CheckTime (GSM_DateTime *date);
+
+char *GetCompiler(void);
+char *GetOS(void);
+
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */