37 files changed, 14205 insertions, 0 deletions
diff --git a/gammu/emb/common/service/backup/backgen.h b/gammu/emb/common/service/backup/backgen.h new file mode 100644 index 0000000..9d7d973 --- a/dev/null +++ b/gammu/emb/common/service/backup/backgen.h @@ -0,0 +1,69 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#ifndef __gsm_backgen_h +#define __gsm_backgen_h + +#include "../../config.h" +#include "../../misc/misc.h" +#include "../gsmpbk.h" +#include "../gsmcal.h" +#include "../gsmlogo.h" +#include "../gsmring.h" +#include "../gsmdata.h" +#include "../gsmprof.h" +#include "../gsmmisc.h" +#include "../sms/gsmsms.h" + +#define GSM_BACKUP_MAX_PHONEPHONEBOOK 501 +#define GSM_BACKUP_MAX_SIMPHONEBOOK 251 +#define GSM_BACKUP_MAX_CALLER 6 +#define GSM_BACKUP_MAX_SMSC 10 +#define GSM_BACKUP_MAX_WAPBOOKMARK 40 +#define GSM_BACKUP_MAX_WAPSETTINGS 30 +#define GSM_BACKUP_MAX_MMSSETTINGS 30 +#define GSM_BACKUP_MAX_RINGTONES 30 +#define GSM_BACKUP_MAX_PROFILES 10 +#define GSM_BACKUP_MAX_FMSTATIONS 20 +#define GSM_BACKUP_MAX_GPRSPOINT 10 +#define GSM_BACKUP_MAX_NOTE 10 /* FIXME */ + +typedef struct { + char IMEI [MAX_IMEI_LENGTH]; + char Model [MAX_MODEL_LENGTH+MAX_VERSION_LENGTH]; + char Creator [80]; + GSM_DateTime DateTime; + bool DateTimeAvailable; + char MD5Original [100]; + char MD5Calculated [100]; + GSM_MemoryEntry *PhonePhonebook [GSM_BACKUP_MAX_PHONEPHONEBOOK + 1]; + GSM_MemoryEntry *SIMPhonebook [GSM_BACKUP_MAX_SIMPHONEBOOK + 1]; + GSM_CalendarEntry *Calendar [GSM_MAXCALENDARTODONOTES + 1]; + GSM_Bitmap *CallerLogos [GSM_BACKUP_MAX_CALLER + 1]; + GSM_SMSC *SMSC [GSM_BACKUP_MAX_SMSC + 1]; + GSM_WAPBookmark *WAPBookmark [GSM_BACKUP_MAX_WAPBOOKMARK + 1]; + GSM_MultiWAPSettings *WAPSettings [GSM_BACKUP_MAX_WAPSETTINGS + 1]; + GSM_MultiWAPSettings *MMSSettings [GSM_BACKUP_MAX_MMSSETTINGS + 1]; + GSM_Ringtone *Ringtone [GSM_BACKUP_MAX_RINGTONES + 1]; + GSM_ToDoEntry *ToDo [GSM_MAXCALENDARTODONOTES + 1]; + GSM_Profile *Profiles [GSM_BACKUP_MAX_PROFILES + 1]; + GSM_FMStation *FMStation [GSM_BACKUP_MAX_FMSTATIONS +1]; + GSM_GPRSAccessPoint *GPRSPoint [GSM_BACKUP_MAX_GPRSPOINT + 1]; + GSM_NoteEntry *Note [GSM_BACKUP_MAX_NOTE + 1]; + GSM_Bitmap *StartupLogo; + GSM_Bitmap *OperatorLogo; +} GSM_Backup; + +#define GSM_BACKUP_MAX_SMS 500 + +typedef struct { + GSM_SMSMessage *SMS[GSM_BACKUP_MAX_SMS]; +} GSM_SMS_Backup; + +extern GSM_Error GSM_ReadSMSBackupFile(char *FileName, GSM_SMS_Backup *backup); +extern GSM_Error GSM_SaveSMSBackupFile(char *FileName, GSM_SMS_Backup *backup); + +#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/service/backup/backics.c b/gammu/emb/common/service/backup/backics.c new file mode 100644 index 0000000..3e6b083 --- a/dev/null +++ b/gammu/emb/common/service/backup/backics.c @@ -0,0 +1,42 @@ +/* (c) 2003 by Marcin Wiacek */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backics.h" + +#ifdef GSM_ENABLE_BACKUP + +GSM_Error SaveICS(char *FileName, GSM_Backup *backup) +{ + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + fclose(file); + return ERR_NONE; +} + +GSM_Error LoadICS(char *FileName, GSM_Backup *backup) +{ + GSM_File File; + GSM_Error error; + + File.Buffer = NULL; + error = GSM_ReadFile(FileName, &File); + if (error != ERR_NONE) return error; + + return ERR_NONE; +} + +#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/service/backup/backics.h b/gammu/emb/common/service/backup/backics.h new file mode 100644 index 0000000..80e2b15 --- a/dev/null +++ b/gammu/emb/common/service/backup/backics.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backics_h +#define __gsm_backics_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error SaveICS(char *FileName, GSM_Backup *backup); +GSM_Error LoadICS(char *FileName, GSM_Backup *backup); +#endif + +#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/service/backup/backldif.c b/gammu/emb/common/service/backup/backldif.c new file mode 100644 index 0000000..ab16160 --- a/dev/null +++ b/gammu/emb/common/service/backup/backldif.c @@ -0,0 +1,297 @@ +/* (c) 2003-2004 by Marcin Wiacek */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backldif.h" + +#ifdef GSM_ENABLE_BACKUP + +static void SaveLDIFText(FILE *file, unsigned char *Name, unsigned char *Value) +{ + unsigned char Buffer[1000],Buffer2[1000]; + + if (EncodeUTF8(Buffer, Value)) { +// dbgprintf("%s\n",Buffer); + EncodeBASE64(Buffer, Buffer2, strlen(Buffer)); + fprintf(file,"%s:: %s%c%c",Name,Buffer2,13,10); + } else { + fprintf(file,"%s: %s%c%c",Name,DecodeUnicodeString(Value),13,10); + } +} + +GSM_Error SaveLDIF(char *FileName, GSM_Backup *backup) +{ + int i, j; + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + i=0; + while (backup->PhonePhonebook[i]!=NULL) { + for (j=0;j<backup->PhonePhonebook[i]->EntriesNum;j++) { + switch (backup->PhonePhonebook[i]->Entries[j].EntryType) { + case PBK_Text_Name: + SaveLDIFText(file, "dn", backup->PhonePhonebook[i]->Entries[j].Text); + break; + default: + break; + } + } + fprintf(file, "objectclass: top%c%c",13,10); + fprintf(file, "objectclass: person%c%c",13,10); + fprintf(file, "objectclass: organizationalPerson%c%c",13,10); + fprintf(file, "objectclass: inetOrgPerson%c%c",13,10); + fprintf(file, "objectclass: mozillaAbPersonObsolete%c%c",13,10); + for (j=0;j<backup->PhonePhonebook[i]->EntriesNum;j++) { + switch (backup->PhonePhonebook[i]->Entries[j].EntryType) { + case PBK_Text_Postal: + SaveLDIFText(file, "HomePostalAddress", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_URL: + SaveLDIFText(file, "homeurl", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Name: + SaveLDIFText(file, "givenName", backup->PhonePhonebook[i]->Entries[j].Text); + SaveLDIFText(file, "cn", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Note: + SaveLDIFText(file, "Description", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Number_Work: + SaveLDIFText(file, "workPhone", backup->PhonePhonebook[i]->Entries[j].Text);//not exist in Mozilla 1.4 win32 + break; + case PBK_Number_Mobile: + SaveLDIFText(file, "mobile", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Number_Pager: + SaveLDIFText(file, "pager", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Number_Fax: + SaveLDIFText(file, "fax", backup->PhonePhonebook[i]->Entries[j].Text);//facsimileTelephoneNumber + break; + case PBK_Number_Home: + SaveLDIFText(file, "homePhone", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Number_General: + SaveLDIFText(file, "telephoneNumber", backup->PhonePhonebook[i]->Entries[j].Text);//work in Mozilla 1.4 win32 + break; + case PBK_Text_Email: + SaveLDIFText(file, "mail", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Email2: + SaveLDIFText(file, "mozillaSecondEmail", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Custom1: + SaveLDIFText(file, "custom1", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Custom2: + SaveLDIFText(file, "custom2", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Custom3: + SaveLDIFText(file, "custom3", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Custom4: + SaveLDIFText(file, "custom4", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Company: + SaveLDIFText(file, "o", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_JobTitle: + SaveLDIFText(file, "title", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_StreetAddress: + SaveLDIFText(file, "homePostalAddress", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_City: + SaveLDIFText(file, "mozillaHomeLocalityName", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_State: + SaveLDIFText(file, "mozillaHomeState", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Zip: + SaveLDIFText(file, "mozillaHomePostalCode", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Text_Country: + SaveLDIFText(file, "mozillaHomeCountryName", backup->PhonePhonebook[i]->Entries[j].Text); + break; + case PBK_Number_Other: + case PBK_Caller_Group: + case PBK_RingtoneID: + case PBK_PictureID: + case PBK_Date: + case PBK_RingtoneFileSystemID: + case PBK_Text_UserID: + case PBK_SMSListID: + case PBK_Category: + case PBK_Private: + case PBK_Text_LastName: + case PBK_Text_FirstName: + dbgprintf("Feature missed\n"); + break; + } + } + fprintf(file, "%c%c",13,10); + i++; + } + fclose(file); + return ERR_NONE; +} + +static bool ReadLDIFText(char *Buffer, char *Start, char *Value) +{ + unsigned char Buffer2[1000],buff[200]; + int i; + + Value[0] = 0x00; + + strcpy(buff,Start); + strcat(buff,":: "); + if (!strncmp(Buffer,buff,strlen(buff))) { + i = DecodeBASE64(Buffer+strlen(Start)+3, Buffer2, strlen(Buffer)-(strlen(Start)+3)); + dbgprintf("Text after DecodeBASE64 is \"%s\"\n",Buffer2); + DecodeUTF8(Value, Buffer2, i); + dbgprintf("Text after DecodeUTF8 is \"%s\"\n",DecodeUnicodeString(Value)); + return true; + } + strcpy(buff,Start); + strcat(buff,": "); + if (!strncmp(Buffer,buff,strlen(buff))) { + EncodeUnicode(Value,Buffer+strlen(Start)+2,strlen(Buffer)-(strlen(Start)+2)); + dbgprintf("Text after EncodeUnicode is \"%s\"\n",DecodeUnicodeString(Value)); + return true; + } + return false; +} + +static GSM_Error GSM_DecodeLDIFEntry(unsigned char *Buffer, int *Pos, GSM_MemoryEntry *Pbk) +{ + unsigned char Line[2000],Buff[2000],Buff2[2000]; + int Level = 0; + + Buff[0] = 0; + Pbk->EntriesNum = 0; + + while (1) { + MyGetLine(Buffer, Pos, Line, strlen(Buffer)); + if (strlen(Line) == 0) break; + switch (Level) { + case 0: + if (ReadLDIFText(Line, "objectclass", Buff)) { + sprintf(Buff2,"%s",DecodeUnicodeString(Buff)); + if (!strcmp("mozillaAbPersonObsolete",Buff2)) { + dbgprintf("level1\n"); + Level = 1; + } + } + break; + case 1: + if (ReadLDIFText(Line, "dn", Buff)) { + dbgprintf("entries num is %i\n",Pbk->EntriesNum); + if (Pbk->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; + } + if (ReadLDIFText(Line, "givenName", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Name; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "telephoneNumber", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_General; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "mobile", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Mobile; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "workPhone", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Work; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "fax", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Fax; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "homePhone",Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Home; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "Description", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Note; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "HomePostalAddress", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Postal; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "mail", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Email; + Pbk->EntriesNum++; + } + if (ReadLDIFText(Line, "homeurl", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_URL; + Pbk->EntriesNum++; + } + /* FIXME: add rest */ + break; + } + } + + dbgprintf("entries num is %i\n",Pbk->EntriesNum); + if (Pbk->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; +} + +GSM_Error LoadLDIF(char *FileName, GSM_Backup *backup) +{ + GSM_File File; + GSM_Error error; + GSM_MemoryEntry Pbk; + int numPbk = 0, Pos; + + File.Buffer = NULL; + error = GSM_ReadFile(FileName, &File); + if (error != ERR_NONE) return error; + + Pos = 0; + while (1) { + error = GSM_DecodeLDIFEntry(File.Buffer, &Pos, &Pbk); + if (error == ERR_EMPTY) break; + if (error != ERR_NONE) return error; + if (numPbk < GSM_BACKUP_MAX_PHONEPHONEBOOK) { + backup->PhonePhonebook[numPbk] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->PhonePhonebook[numPbk] == NULL) return ERR_MOREMEMORY; + backup->PhonePhonebook[numPbk + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_PHONEPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + memcpy(backup->PhonePhonebook[numPbk],&Pbk,sizeof(GSM_MemoryEntry)); + backup->PhonePhonebook[numPbk]->Location = numPbk + 1; + backup->PhonePhonebook[numPbk]->MemoryType = MEM_ME; + numPbk++; + } + + return ERR_NONE; +} + +#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/service/backup/backldif.h b/gammu/emb/common/service/backup/backldif.h new file mode 100644 index 0000000..212c048 --- a/dev/null +++ b/gammu/emb/common/service/backup/backldif.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backldif_h +#define __gsm_backldif_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error SaveLDIF(char *FileName, GSM_Backup *backup); +GSM_Error LoadLDIF(char *FileName, GSM_Backup *backup); +#endif + +#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/service/backup/backlmb.c b/gammu/emb/common/service/backup/backlmb.c new file mode 100644 index 0000000..d7f845a --- a/dev/null +++ b/gammu/emb/common/service/backup/backlmb.c @@ -0,0 +1,413 @@ +/* (c) 2001-2004 by Marcin Wiacek */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backlmb.h" + +#ifdef GSM_ENABLE_BACKUP + +static void SaveLMBStartupEntry(FILE *file, GSM_Bitmap bitmap) +{ + int count=13; + GSM_Phone_Bitmap_Types Type; + /* Welcome note and logo header block */ + char req[1000] = { + 'W','E','L',' ', /*block identifier*/ + 00,00, /*block data size*/ + 0x02,00,00,00,00,00, + 0x00}; /*number of blocks (like in 6110 frame)*/ + + if (bitmap.Type == GSM_StartupLogo) { + req[count++] = 0x01; + req[count++] = bitmap.BitmapHeight; + req[count++] = bitmap.BitmapWidth; + Type = GSM_NokiaStartupLogo; + switch (bitmap.BitmapHeight) { + case 65: Type = GSM_Nokia7110StartupLogo; break; + case 60: Type = GSM_Nokia6210StartupLogo; break; + } + PHONE_EncodeBitmap(Type, req+count, &bitmap); + count = count + PHONE_GetBitmapSize(Type, 0, 0); + + req[12]++; + } + if (bitmap.Type == GSM_WelcomeNote_Text) { + req[count++]=0x02; + req[count++]=UnicodeLength(bitmap.Text); + memcpy(req+count,DecodeUnicodeString(bitmap.Text),UnicodeLength(bitmap.Text)); + count=count+UnicodeLength(bitmap.Text); + + req[12]++; + } + + req[4]=(count-12)%256; + req[5]=(count-12)/256; + + fwrite(req, 1, count, file); +} + +static void SaveLMBCallerEntry(FILE *file, GSM_Bitmap bitmap) +{ + int count=12, textlen; + char req[500] = { + 'C','G','R',' ', /*block identifier*/ + 00,00, /*block data size*/ + 02,00, + 00, /*group number=0,1,etc.*/ + 00,00,00}; + + req[count++] = bitmap.Location - 1; + if (bitmap.DefaultName) { + req[count++] = 0; + } else { + textlen = UnicodeLength(bitmap.Text); + req[count++] = textlen; + memcpy(req+count,DecodeUnicodeString(bitmap.Text),textlen); + count += textlen; + } + if (bitmap.DefaultRingtone) { + req[count++] = 0x16; + } else { + req[count++] = bitmap.RingtoneID; + } + if (bitmap.BitmapEnabled) req[count++] = 0x01; else req[count++] = 0x00; + req[count++] = (PHONE_GetBitmapSize(GSM_NokiaCallerLogo,0,0) + 4) >> 8; + req[count++] = (PHONE_GetBitmapSize(GSM_NokiaCallerLogo,0,0) + 4) % 0xff; + if (bitmap.DefaultBitmap) { + bitmap.BitmapWidth = 72; + bitmap.BitmapHeight = 14; + GSM_ClearBitmap(&bitmap); + } + NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &bitmap, req, &count); + req[count++]=0; + + req[4]=(count-12)%256; + req[5]=(count-12)/256; + req[8]=bitmap.Location; + + fwrite(req, 1, count, file); +} + +void SaveLMBPBKEntry(FILE *file, GSM_MemoryEntry *entry) +{ + int count = 16, blocks; + char req[500] = { + 'P','B','E','2', /*block identifier*/ + 00,00, /*block data size*/ + 00,00, + 00,00, /*position of phonebook entry*/ + 03, /*memory type. ME=02;SM=03*/ + 00, + 00,00, /*position of phonebook entry*/ + 03, /*memory type. ME=02;SM=03*/ + 00}; + + count=count+N71_65_EncodePhonebookFrame(NULL, req+16, *entry, &blocks, true, true); + + req[4]=(count-12)%256; + req[5]=(count-12)/256; + req[8]=req[12] = entry->Location & 0xff; + req[9]=req[13] = (entry->Location >> 8); + if (entry->MemoryType==MEM_ME) req[10]=req[14]=2; + + fwrite(req, 1, count, file); +} + +GSM_Error SaveLMB(char *FileName, GSM_Backup *backup) +{ + FILE *file; + int i; + char LMBHeader[] = {'L','M','B',' '}; /*file identifier*/ + char PBKHeader[] = { /*Phonebook header block */ + 'P','B','K',' ', /*block identifier*/ + 0x08,00, /*block data size*/ + 0x02,00, + 03, /*memory type. ME=02;SM=03*/ + 00,00,00, + 00,00, /*size of phonebook*/ + 14, /*max length of each position*/ + 00,00,00,00,00}; + + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + /* Write the header of the file. */ + fwrite(LMBHeader, 1, sizeof(LMBHeader), file); + + if (backup->PhonePhonebook[0]!=NULL) { + PBKHeader[8] = 2; /* memory type=MEM_ME */ + PBKHeader[12] = (unsigned char)(500 % 256); + PBKHeader[13] = 500 / 256; + fwrite(PBKHeader, 1, sizeof(PBKHeader), file); + i=0; + while (backup->PhonePhonebook[i]!=NULL) { + SaveLMBPBKEntry(file, backup->PhonePhonebook[i]); + i++; + } + } + if (backup->SIMPhonebook[0]!=NULL) { + PBKHeader[8] = 3; /* memory type=MEM_SM */ + PBKHeader[12] = (unsigned char)(250 % 256); + PBKHeader[13] = 250 / 256; + PBKHeader[14] = 0x16; /* max size of one entry */ + fwrite(PBKHeader, 1, sizeof(PBKHeader), file); + i=0; + while (backup->SIMPhonebook[i]!=NULL) { + SaveLMBPBKEntry(file, backup->SIMPhonebook[i]); + i++; + } + } + i=0; + while (backup->CallerLogos[i]!=NULL) { + SaveLMBCallerEntry(file, *backup->CallerLogos[i]); + i++; + } + if (backup->StartupLogo!=NULL) { + SaveLMBStartupEntry(file, *backup->StartupLogo); + } + + fclose(file); + return ERR_NONE; +} + +static GSM_Error LoadLMBCallerEntry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup) +{ + GSM_Bitmap bitmap; + int num; + +#ifdef DEBUG + dbgprintf("Number %i, name \"", buffer2[0]+1); + for (num=0;num<buffer2[1];num++) dbgprintf("%c", buffer2[num+2]); + dbgprintf("\"\n"); + dbgprintf("Ringtone ID=%i\n", buffer2[num+2]); + if (buffer2[num+3]==1) { + dbgprintf("Logo enabled\n"); + } else { + dbgprintf("Logo disabled\n"); + } +#endif + + bitmap.Location = buffer2[0] + 1; + bitmap.Type = GSM_CallerGroupLogo; + bitmap.DefaultRingtone = false; + bitmap.RingtoneID = buffer2[buffer2[1]+2]; + + EncodeUnicode(bitmap.Text,buffer2+2,buffer2[1]); + if (bitmap.Text[0] == 0x00 && bitmap.Text[1] == 0x00) { + bitmap.DefaultName = true; + } else { + bitmap.DefaultName = false; + } + + bitmap.BitmapEnabled = false; + if (buffer2[buffer2[1]+3]==1) bitmap.BitmapEnabled=true; + + bitmap.DefaultBitmap = false; + PHONE_DecodeBitmap(GSM_NokiaCallerLogo, buffer2+(buffer2[1]+10), &bitmap); + +#ifdef DEBUG + dbgprintf("Caller logo\n"); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&bitmap); +#endif + + num = 0; + while (backup->CallerLogos[num] != NULL) num++; + if (num < GSM_BACKUP_MAX_CALLER) { + backup->CallerLogos[num] = malloc(sizeof(GSM_Bitmap)); + if (backup->CallerLogos[num] == NULL) return ERR_MOREMEMORY; + backup->CallerLogos[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_CALLER\n"); + return ERR_MOREMEMORY; + } + *backup->CallerLogos[num] = bitmap; + + return ERR_NONE; +} + +static GSM_Error LoadLMBStartupEntry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup) +{ + int i,j; +#ifdef DEBUG + int z; +#endif + GSM_Phone_Bitmap_Types Type; + + j=1; + for (i=0;i<buffer2[0];i++) { + switch (buffer2[j++]) { + case 1: + dbgprintf("Block 1 - startup logo\n"); + backup->StartupLogo = malloc(sizeof(GSM_Bitmap)); + if (backup->StartupLogo == NULL) return ERR_MOREMEMORY; + backup->StartupLogo->Location = 1; + backup->StartupLogo->BitmapHeight = buffer2[j++]; + backup->StartupLogo->BitmapWidth = buffer2[j++]; + Type = GSM_NokiaStartupLogo; + switch (backup->StartupLogo->BitmapHeight) { + case 65: Type = GSM_Nokia7110StartupLogo; break; + case 60: Type = GSM_Nokia6210StartupLogo; break; + } + PHONE_DecodeBitmap(Type, buffer2+j, backup->StartupLogo); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,backup->StartupLogo); +#endif + j = j + PHONE_GetBitmapSize(Type,0,0); + break; + case 2: +#ifdef DEBUG + dbgprintf("Block 2 - welcome note \""); + for (z=0;z<buffer2[j];z++) dbgprintf("%c",buffer2[j+z+1]); + dbgprintf("\"\n"); +#endif + if (backup->StartupLogo == NULL) { + backup->StartupLogo = malloc(sizeof(GSM_Bitmap)); + if (backup->StartupLogo == NULL) return ERR_MOREMEMORY; + backup->StartupLogo->Type = GSM_WelcomeNote_Text; + EncodeUnicode(backup->StartupLogo->Text,buffer2+j,buffer2[j]); + } + j = j + buffer2[j]; + break; + default: + dbgprintf("Unknown block %02x\n",buffer2[j]); + break; + } + } + return ERR_NONE; +} + +static GSM_Error LoadLMBPbkEntry(unsigned char *buffer, unsigned char *buffer2, GSM_Backup *backup) +{ + GSM_MemoryEntry pbk; + int num; + +#ifdef DEBUG + dbgprintf("Memory : "); + switch(buffer[10]) { + case 2 : dbgprintf("(internal)\n"); break; + case 3 : dbgprintf("(sim)\n"); break; + default: dbgprintf("(unknown)\n"); break; + } + dbgprintf("Location : %i\n",buffer2[0]+buffer2[1]*256); +#endif + + N71_65_DecodePhonebook(NULL, &pbk, NULL,NULL,buffer2+4,(buffer[4]+buffer[5]*256)-4,false); + + pbk.MemoryType=MEM_SM; + if (buffer[10]==2) pbk.MemoryType=MEM_ME; + + pbk.Location=buffer2[0]+256*buffer2[1]; + + num = 0; + if (buffer[10]==2) { + while (backup->PhonePhonebook[num] != NULL) num++; + if (num < GSM_BACKUP_MAX_PHONEPHONEBOOK) { + backup->PhonePhonebook[num] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->PhonePhonebook[num] == NULL) return ERR_MOREMEMORY; + backup->PhonePhonebook[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_PHONEPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + *backup->PhonePhonebook[num] = pbk; + } else { + while (backup->SIMPhonebook[num] != NULL) num++; + if (num < GSM_BACKUP_MAX_SIMPHONEBOOK) { + backup->SIMPhonebook[num] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->SIMPhonebook[num] == NULL) return ERR_MOREMEMORY; + backup->SIMPhonebook[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_SIMPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + *backup->SIMPhonebook[num] = pbk; + } + return ERR_NONE; +} + +GSM_Error LoadLMB(char *FileName, GSM_Backup *backup) +{ +#ifdef DEBUG + int i; +#endif + unsigned char buffer[12], buffer2[1000]; + FILE *file; + GSM_Error error; + + file = fopen(FileName, "rb"); + if (file == NULL) return(ERR_CANTOPENFILE); + + /* Read the header of the file. */ + fread(buffer, 1, 4, file); + + /* while we have something to read */ + while (fread(buffer, 1, 12, file)==12) { +#ifdef DEBUG + /* Info about block in the file */ + dbgprintf("Block \""); + for (i=0;i<4;i++) {dbgprintf("%c",buffer[i]);} + dbgprintf("\" ("); + if (memcmp(buffer, "PBK ",4)==0) { dbgprintf("Phonebook"); + } else if (memcmp(buffer, "PBE2",4)==0) { dbgprintf("Phonebook entry"); + } else if (memcmp(buffer, "CGR ",4)==0) { dbgprintf("Caller group"); + } else if (memcmp(buffer, "SPD ",4)==0) { dbgprintf("Speed dial"); + } else if (memcmp(buffer, "OLG ",4)==0) { dbgprintf("Operator logo"); + } else if (memcmp(buffer, "WEL ",4)==0) { dbgprintf("Startup logo and welcome text"); + } else { dbgprintf("unknown - ignored"); + } + dbgprintf(") - length %i\n", buffer[4]+buffer[5]*256); +#endif + /* reading block data */ + fread(buffer2, 1, buffer[4]+buffer[5]*256, file); + +#ifdef DEBUG + if (memcmp(buffer, "PBK ",4)==0) { + dbgprintf("Size of phonebook %i, type %i ",(buffer2[0]+buffer2[1]*256),buffer[8]); + switch(buffer[8]) { + case 2 : dbgprintf("(internal)");break; + case 3 : dbgprintf("(sim)") ;break; + default: dbgprintf("(unknown)") ;break; + } + dbgprintf(", length of each position - %i\n",buffer2[2]); + } +#endif + if (memcmp(buffer, "PBE2",4)==0) { + error = LoadLMBPbkEntry(buffer,buffer2,backup); + if (error != ERR_NONE) { + fclose(file); + return error; + } + } + if (memcmp(buffer, "CGR ",4)==0) { + error = LoadLMBCallerEntry(buffer, buffer2, backup); + if (error != ERR_NONE) { + fclose(file); + return error; + } + } + if (memcmp(buffer, "WEL ",4)==0) { + error = LoadLMBStartupEntry(buffer, buffer2, backup); + if (error != ERR_NONE) { + fclose(file); + return error; + } + } + } + + fclose(file); + + return ERR_NONE; +} + +#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/service/backup/backlmb.h b/gammu/emb/common/service/backup/backlmb.h new file mode 100644 index 0000000..18bba66 --- a/dev/null +++ b/gammu/emb/common/service/backup/backlmb.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backlmb_h +#define __gsm_backlmb_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error SaveLMB(char *FileName, GSM_Backup *backup); +GSM_Error LoadLMB(char *FileName, GSM_Backup *backup); +#endif + +#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/service/backup/backtext.c b/gammu/emb/common/service/backup/backtext.c new file mode 100644 index 0000000..fee0f73 --- a/dev/null +++ b/gammu/emb/common/service/backup/backtext.c @@ -0,0 +1,2908 @@ +/* (c) 2002-2004 by Marcin Wiacek, Walek and Michal Cihar */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/cfg.h" +#include "../../misc/coding/coding.h" +#include "../../misc/coding/md5.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backtext.h" + +#ifdef GSM_ENABLE_BACKUP + +GSM_Error FindBackupChecksum(char *FileName, bool UseUnicode, char *checksum) +{ + INI_Section *file_info, *h; + INI_Entry *e; + char *buffer = NULL,buff[100]; + int len=0; + + //int i; + + file_info = INI_ReadFile(FileName, UseUnicode); + + if (UseUnicode) { + for (h = file_info; h != NULL; h = h->Next) { + EncodeUnicode(buff,"Checksum",8); + if (mywstrncasecmp(buff, h->SectionName, 8)) continue; + + buffer = (unsigned char *)realloc(buffer,len+UnicodeLength(h->SectionName)*2+2); + CopyUnicodeString(buffer+len,h->SectionName); + len+=UnicodeLength(h->SectionName)*2; +// dbgprintf("[%s]\n",DecodeUnicodeConsole(h->SectionName)); + + for (e = h->SubEntries; e != NULL; e = e->Next) { + buffer = (unsigned char *)realloc(buffer,len+UnicodeLength(e->EntryName)*2+2); + CopyUnicodeString(buffer+len,e->EntryName); + len+=UnicodeLength(e->EntryName)*2; + buffer = (unsigned char *)realloc(buffer,len+UnicodeLength(e->EntryValue)*2+2); + CopyUnicodeString(buffer+len,e->EntryValue); + len+=UnicodeLength(e->EntryValue)*2; +// dbgprintf("\"%s\"",DecodeUnicodeConsole(e->EntryName)); +// dbgprintf("=\"%s\"\n",DecodeUnicodeConsole(e->EntryValue)); + } + } + } else { + for (h = file_info; h != NULL; h = h->Next) { + if (mystrncasecmp("Checksum", h->SectionName, 8)) continue; + + buffer = (unsigned char *)realloc(buffer,len+strlen(h->SectionName)+1); + strcpy(buffer+len,h->SectionName); + len+=strlen(h->SectionName); + + for (e = h->SubEntries; e != NULL; e = e->Next) { +// dbgprintf("%s=%s\n",e->EntryName,e->EntryValue); + buffer = (unsigned char *)realloc(buffer,len+strlen(e->EntryName)+1); + strcpy(buffer+len,e->EntryName); + len+=strlen(e->EntryName); + buffer = (unsigned char *)realloc(buffer,len+strlen(e->EntryValue)+1); + strcpy(buffer+len,e->EntryValue); + len+=strlen(e->EntryValue); + } + } + } + + //for (i=0;i<len;i++) printf("%02x",buffer[i]); + CalculateMD5(buffer, len, checksum); + free(buffer); + + return ERR_NONE; +} + +static unsigned char *ReadCFGText(INI_Section *cfg, unsigned char *section, unsigned char *key, bool Unicode) +{ + unsigned char Buffer[500],Buffer2[500],*retval; + + if (Unicode) { + EncodeUnicode(Buffer2,key,strlen(key)); + retval = INI_GetValue(cfg,section,Buffer2,Unicode); + if (retval != NULL) return DecodeUnicodeString(retval); + return NULL; + } else { + strcpy(Buffer,section); + strcpy(Buffer2,key); + return INI_GetValue(cfg,section,key,Unicode); + } +} + +static void SaveLinkedBackupText(FILE *file, char *myname, char *myvalue, bool UseUnicode) +{ + int w,current; + unsigned char buffer2[1000],buffer3[1000]; + + current = strlen(myvalue); w = 0; + while (true) { + if (current > 200) { + memcpy(buffer2,myvalue+(strlen(myvalue)-current),200); + buffer2[200] = 0; + current = current - 200; + } else { + memcpy(buffer2,myvalue+(strlen(myvalue)-current),current); + buffer2[current] = 0; + current = 0; + } + if (UseUnicode) { + sprintf(buffer3,"%s%02i = %s%c%c",myname,w,buffer2,13,10); + EncodeUnicode(buffer2,buffer3,strlen(buffer3)); + fwrite(buffer2,1,strlen(buffer3)*2,file); + } else { + fprintf(file,"%s%02i = %s%c%c",myname,w,buffer2,13,10); + } + if (current == 0) break; + w++; + } +} + +static void ReadLinkedBackupText(INI_Section *file_info, char *section, char *myname, char *myvalue, bool UseUnicode) +{ + unsigned char buffer2[300]; + char *readvalue; + int i; + + i=0; + myvalue[0] = 0; + while (true) { + sprintf(buffer2,"%s%02i",myname,i); + readvalue = ReadCFGText(file_info, section, buffer2, UseUnicode); + if (readvalue!=NULL) { + myvalue[strlen(myvalue)+strlen(readvalue)]=0; + memcpy(myvalue+strlen(myvalue),readvalue,strlen(readvalue)); + } else break; + i++; + } +} + +static void SaveBackupText(FILE *file, char *myname, char *myvalue, bool UseUnicode) +{ + unsigned char buffer[10000], buffer2[10000]; + + if (myname[0] == 0x00) { + if (UseUnicode) { + EncodeUnicode(buffer,myvalue,strlen(myvalue)); + fwrite(buffer,1,strlen(myvalue)*2,file); + } else fprintf(file,"%s",myvalue); + } else { + if (UseUnicode) { + sprintf(buffer,"%s = \"",myname); + EncodeUnicode(buffer2,buffer,strlen(buffer)); + fwrite(buffer2,1,strlen(buffer)*2,file); + + fwrite(myvalue,1,UnicodeLength(myvalue)*2,file); + + sprintf(buffer,"\"%c%c",13,10); + EncodeUnicode(buffer2,buffer,strlen(buffer)); + fwrite(buffer2,1,strlen(buffer)*2,file); + } else { + sprintf(buffer,"%s = \"%s\"%c%c",myname,DecodeUnicodeString(myvalue),13,10); + fprintf(file,"%s",buffer); + + EncodeHexBin(buffer,myvalue,UnicodeLength(myvalue)*2); + fprintf(file,"%sUnicode = %s%c%c",myname,buffer,13,10); + } + } +} + +static bool ReadBackupText(INI_Section *file_info, char *section, char *myname, char *myvalue, bool UseUnicode) +{ + unsigned char paramname[10000],*readvalue; + + if (UseUnicode) { + EncodeUnicode(paramname,myname,strlen(myname)); + readvalue = INI_GetValue(file_info, section, paramname, UseUnicode); + if (readvalue!=NULL) { + CopyUnicodeString(myvalue,readvalue+2); + myvalue[UnicodeLength(readvalue)*2-4]=0; + myvalue[UnicodeLength(readvalue)*2-3]=0; + dbgprintf("%s\n",DecodeUnicodeString(readvalue)); + } else { + myvalue[0]=0; + myvalue[1]=0; + return false; + } + } else { + strcpy(paramname,myname); + strcat(paramname,"Unicode"); + readvalue = ReadCFGText(file_info, section, paramname, UseUnicode); + if (readvalue!=NULL) { + dbgprintf("%s %i\n",readvalue,strlen(readvalue)); + DecodeHexBin (myvalue, readvalue, strlen(readvalue)); + myvalue[strlen(readvalue)/2]=0; + myvalue[strlen(readvalue)/2+1]=0; + dbgprintf("%s\n",DecodeUnicodeString(myvalue)); + } else { + strcpy(paramname,myname); + readvalue = ReadCFGText(file_info, section, paramname, UseUnicode); + if (readvalue!=NULL) { + EncodeUnicode(myvalue,readvalue+1,strlen(readvalue)-2); + } else { + myvalue[0]=0; + myvalue[1]=0; + return false; + } + } + } + return true; +} + +static void SaveVCalDateTime(FILE *file, GSM_DateTime *dt, bool UseUnicode) +{ + unsigned char buffer[100]; + int Length = 3; + + sprintf(buffer, " = "); + SaveVCALDateTime(buffer, &Length, dt, NULL); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveVCalDate(FILE *file, GSM_DateTime *dt, bool UseUnicode) +{ + unsigned char buffer[100]; + + sprintf(buffer, " = %04d%02d%02d%c%c", dt->Year, dt->Month, dt->Day,13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +/* ---------------------- backup files ------------------------------------- */ + +static void SavePbkEntry(FILE *file, GSM_MemoryEntry *Pbk, bool UseUnicode) +{ + bool text; + char buffer[1000]; + int j, i; + + sprintf(buffer,"Location = %03i%c%c",Pbk->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + for (j=0;j<Pbk->EntriesNum;j++) { + text = true; + switch (Pbk->Entries[j].EntryType) { + case PBK_Number_General: + sprintf(buffer,"Entry%02iType = NumberGeneral%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Mobile: + sprintf(buffer,"Entry%02iType = NumberMobile%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Work: + sprintf(buffer,"Entry%02iType = NumberWork%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Fax: + sprintf(buffer,"Entry%02iType = NumberFax%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Home: + sprintf(buffer,"Entry%02iType = NumberHome%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Pager: + sprintf(buffer,"Entry%02iType = NumberPager%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Number_Other: + sprintf(buffer,"Entry%02iType = NumberOther%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Note: + sprintf(buffer,"Entry%02iType = Note%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Postal: + sprintf(buffer,"Entry%02iType = Postal%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Email: + sprintf(buffer,"Entry%02iType = Email%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Email2: + sprintf(buffer,"Entry%02iType = Email2%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_URL: + sprintf(buffer,"Entry%02iType = URL%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Name: + sprintf(buffer,"Entry%02iType = Name%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Caller_Group: + sprintf(buffer,"Entry%02iType = CallerGroup%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Entry%02iNumber = %i%c%c",j,Pbk->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + text = false; + break; + case PBK_RingtoneID: + sprintf(buffer,"Entry%02iType = RingtoneID%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Entry%02iNumber = %i%c%c",j,Pbk->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + text = false; + break; + case PBK_PictureID: + sprintf(buffer,"Entry%02iType = PictureID%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Entry%02iNumber = %i%c%c",j,Pbk->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + text = false; + break; + case PBK_Text_UserID: + sprintf(buffer,"Entry%02iType = UserID%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Category: + sprintf(buffer,"Entry%02iType = Category%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Entry%02iNumber = %i%c%c",j,Pbk->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + text = false; + break; + case PBK_Private: + sprintf(buffer,"Entry%02iType = Private%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Entry%02iNumber = %i%c%c",j,Pbk->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + text = false; + break; + case PBK_Text_LastName: + sprintf(buffer,"Entry%02iType = LastName%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_FirstName: + sprintf(buffer,"Entry%02iType = FirstName%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Company: + sprintf(buffer,"Entry%02iType = Company%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_JobTitle: + sprintf(buffer,"Entry%02iType = JobTitle%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_StreetAddress: + sprintf(buffer,"Entry%02iType = Address%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_City: + sprintf(buffer,"Entry%02iType = City%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_State: + sprintf(buffer,"Entry%02iType = State%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Zip: + sprintf(buffer,"Entry%02iType = Zip%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Country: + sprintf(buffer,"Entry%02iType = Country%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Custom1: + sprintf(buffer,"Entry%02iType = Custom1%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Custom2: + sprintf(buffer,"Entry%02iType = Custom2%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Custom3: + sprintf(buffer,"Entry%02iType = Custom3%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_Text_Custom4: + sprintf(buffer,"Entry%02iType = Custom4%c%c",j,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case PBK_SMSListID: + case PBK_RingtoneFileSystemID: + case PBK_Date: + break; + } + if (text) { + sprintf(buffer,"Entry%02iText",j); + SaveBackupText(file,buffer,Pbk->Entries[j].Text, UseUnicode); + } + switch (Pbk->Entries[j].EntryType) { + case PBK_Number_General: + case PBK_Number_Mobile: + case PBK_Number_Work: + case PBK_Number_Fax: + case PBK_Number_Home: + case PBK_Number_Other: + case PBK_Number_Pager: + if (Pbk->Entries[j].VoiceTag!=0) { + sprintf(buffer,"Entry%02iVoiceTag = %i%c%c",j,Pbk->Entries[j].VoiceTag,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + i = 0; + while (Pbk->Entries[j].SMSList[i]!=0) { + sprintf(buffer,"Entry%02iSMSList%02i = %i%c%c",j,i,Pbk->Entries[j].SMSList[i],13,10); + SaveBackupText(file, "", buffer, UseUnicode); + i++; + } + break; + default: + break; + } + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveCalendarEntry(FILE *file, GSM_CalendarEntry *Note, bool UseUnicode) +{ + int i; + char buffer[1000]; + + sprintf(buffer,"Location = %d%c%c", Note->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "", "Type = ", UseUnicode); + switch (Note->Type) { + case GSM_CAL_REMINDER : sprintf(buffer,"Reminder%c%c", 13,10); break; + case GSM_CAL_CALL : sprintf(buffer,"Call%c%c", 13,10); break; + case GSM_CAL_MEETING : sprintf(buffer,"Meeting%c%c", 13,10); break; + case GSM_CAL_BIRTHDAY : sprintf(buffer,"Birthday%c%c", 13,10); break; + case GSM_CAL_TRAVEL : sprintf(buffer,"Travel%c%c", 13,10); break; + case GSM_CAL_VACATION : sprintf(buffer,"Vacation%c%c", 13,10); break; + case GSM_CAL_MEMO : sprintf(buffer,"Memo%c%c", 13,10); break; + case GSM_CAL_ALARM : sprintf(buffer,"Alarm%c%c", 13,10); break; + case GSM_CAL_DAILY_ALARM : sprintf(buffer,"DailyAlarm%c%c", 13,10); break; + case GSM_CAL_T_ATHL : sprintf(buffer,"Training/Athletism%c%c", 13,10); break; + case GSM_CAL_T_BALL : sprintf(buffer,"Training/BallGames%c%c", 13,10); break; + case GSM_CAL_T_CYCL : sprintf(buffer,"Training/Cycling%c%c", 13,10); break; + case GSM_CAL_T_BUDO : sprintf(buffer,"Training/Budo%c%c", 13,10); break; + case GSM_CAL_T_DANC : sprintf(buffer,"Training/Dance%c%c", 13,10); break; + case GSM_CAL_T_EXTR : sprintf(buffer,"Training/ExtremeSports%c%c", 13,10); break; + case GSM_CAL_T_FOOT : sprintf(buffer,"Training/Football%c%c", 13,10); break; + case GSM_CAL_T_GOLF : sprintf(buffer,"Training/Golf%c%c", 13,10); break; + case GSM_CAL_T_GYM : sprintf(buffer,"Training/Gym%c%c", 13,10); break; + case GSM_CAL_T_HORS : sprintf(buffer,"Training/HorseRaces%c%c", 13,10); break; + case GSM_CAL_T_HOCK : sprintf(buffer,"Training/Hockey%c%c", 13,10); break; + case GSM_CAL_T_RACE : sprintf(buffer,"Training/Races%c%c", 13,10); break; + case GSM_CAL_T_RUGB : sprintf(buffer,"Training/Rugby%c%c", 13,10); break; + case GSM_CAL_T_SAIL : sprintf(buffer,"Training/Sailing%c%c", 13,10); break; + case GSM_CAL_T_STRE : sprintf(buffer,"Training/StreetGames%c%c", 13,10); break; + case GSM_CAL_T_SWIM : sprintf(buffer,"Training/Swimming%c%c", 13,10); break; + case GSM_CAL_T_TENN : sprintf(buffer,"Training/Tennis%c%c", 13,10); break; + case GSM_CAL_T_TRAV : sprintf(buffer,"Training/Travels%c%c", 13,10); break; + case GSM_CAL_T_WINT : sprintf(buffer,"Training/WinterGames%c%c", 13,10); break; + } + SaveBackupText(file, "", buffer, UseUnicode); + for (i=0;i<Note->EntriesNum;i++) { + switch (Note->Entries[i].EntryType) { + case CAL_START_DATETIME: + SaveBackupText(file, "", "StartTime", UseUnicode); + SaveVCalDateTime(file, &Note->Entries[i].Date, UseUnicode); + break; + case CAL_END_DATETIME: + SaveBackupText(file, "", "StopTime", UseUnicode); + SaveVCalDateTime(file, &Note->Entries[i].Date, UseUnicode); + break; + case CAL_ALARM_DATETIME: + SaveBackupText(file, "", "Alarm", UseUnicode); + SaveVCalDateTime(file, &Note->Entries[i].Date, UseUnicode); + sprintf(buffer,"AlarmType = Tone%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_SILENT_ALARM_DATETIME: + SaveBackupText(file, "", "Alarm", UseUnicode); + SaveVCalDateTime(file, &Note->Entries[i].Date, UseUnicode); + sprintf(buffer,"AlarmType = Silent%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_PRIVATE: + sprintf(buffer, "Private = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_LOCATION: + SaveBackupText(file, "EventLocation", Note->Entries[i].Text, UseUnicode); + break; + case CAL_CONTACTID: + sprintf(buffer, "ContactID = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_RECURRANCE: + sprintf(buffer, "Recurrance = %d%c%c",Note->Entries[i].Number/24,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_TEXT: + SaveBackupText(file, "Text", Note->Entries[i].Text, UseUnicode); + break; + case CAL_PHONE: + SaveBackupText(file, "Phone", Note->Entries[i].Text, UseUnicode); + break; + case CAL_REPEAT_STOPDATE: + SaveBackupText(file, "", "RepeatStopDate", UseUnicode); + SaveVCalDate(file, &Note->Entries[i].Date, UseUnicode); + break; + case CAL_REPEAT_STARTDATE: + SaveBackupText(file, "", "RepeatStartDate", UseUnicode); + SaveVCalDate(file, &Note->Entries[i].Date, UseUnicode); + break; + case CAL_REPEAT_DAYOFWEEK: + sprintf(buffer, "RepeatDayOfWeek = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_REPEAT_DAY: + sprintf(buffer, "RepeatDay = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_REPEAT_WEEKOFMONTH: + sprintf(buffer, "RepeatWeekOfMonth = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_REPEAT_MONTH: + sprintf(buffer, "RepeatMonth = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case CAL_REPEAT_FREQUENCY: + sprintf(buffer, "RepeatFrequency = %d%c%c",Note->Entries[i].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + } + } + sprintf(buffer, "%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveWAPSettingsEntry(FILE *file, GSM_MultiWAPSettings *settings, bool UseUnicode) +{ + int i; + char buffer[10000]; + + if (settings->Active) { + sprintf(buffer,"Active = Yes%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + switch (settings->ActiveBearer) { + case WAPSETTINGS_BEARER_SMS : sprintf(buffer,"Bearer = SMS%c%c",13,10); break; + case WAPSETTINGS_BEARER_GPRS: sprintf(buffer,"Bearer = GPRS%c%c",13,10); break; + case WAPSETTINGS_BEARER_DATA: sprintf(buffer,"Bearer = Data%c%c",13,10); break; + case WAPSETTINGS_BEARER_USSD: sprintf(buffer,"Bearer = USSD%c%c",13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + if (settings->ReadOnly) { + sprintf(buffer,"ReadOnly = Yes%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + sprintf(buffer,"Proxy"); + SaveBackupText(file, buffer, settings->Proxy, UseUnicode); + sprintf(buffer,"ProxyPort = %i%c%c",settings->ProxyPort,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Proxy2"); + SaveBackupText(file, buffer, settings->Proxy2, UseUnicode); + sprintf(buffer,"Proxy2Port = %i%c%c",settings->Proxy2Port,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + for (i=0;i<settings->Number;i++) { + sprintf(buffer,"Title%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].Title, UseUnicode); + sprintf(buffer,"HomePage%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].HomePage, UseUnicode); + if (settings->Settings[i].IsContinuous) { + sprintf(buffer,"Type%02i = Continuous%c%c",i,13,10); + } else { + sprintf(buffer,"Type%02i = Temporary%c%c",i,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + if (settings->Settings[i].IsSecurity) { + sprintf(buffer,"Security%02i = On%c%c",i,13,10); + } else { + sprintf(buffer,"Security%02i = Off%c%c",i,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + switch (settings->Settings[i].Bearer) { + case WAPSETTINGS_BEARER_SMS: + sprintf(buffer,"Bearer%02i = SMS%c%c",i,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Server%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].Server, UseUnicode); + sprintf(buffer,"Service%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].Service, UseUnicode); + break; + case WAPSETTINGS_BEARER_GPRS: + sprintf(buffer,"Bearer%02i = GPRS%c%c",i,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"IP%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].IPAddress, UseUnicode); + case WAPSETTINGS_BEARER_DATA: + if (settings->Settings[i].Bearer == WAPSETTINGS_BEARER_DATA) { + sprintf(buffer,"Bearer%02i = Data%c%c",i,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + if (settings->Settings[i].IsISDNCall) { + sprintf(buffer,"CallType%02i = ISDN%c%c",i,13,10); + } else { + sprintf(buffer,"CallType%02i = Analogue%c%c",i,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"IP%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].IPAddress, UseUnicode); + } + sprintf(buffer,"Number%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].DialUp, UseUnicode); + if (settings->Settings[i].ManualLogin) { + sprintf(buffer,"Login%02i = Manual%c%c",i,13,10); + } else { + sprintf(buffer,"Login%02i = Automatic%c%c",i,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + if (settings->Settings[i].IsNormalAuthentication) { + sprintf(buffer,"Authentication%02i = Normal%c%c",i,13,10); + } else { + sprintf(buffer,"Authentication%02i = Secure%c%c",i,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + switch (settings->Settings[i].Speed) { + case WAPSETTINGS_SPEED_9600 : sprintf(buffer,"CallSpeed%02i = 9600%c%c" ,i,13,10); break; + case WAPSETTINGS_SPEED_14400: sprintf(buffer,"CallSpeed%02i = 14400%c%c",i,13,10); break; + case WAPSETTINGS_SPEED_AUTO : sprintf(buffer,"CallSpeed%02i = auto%c%c" ,i,13,10); break; + } + switch (settings->Settings[i].Speed) { + case WAPSETTINGS_SPEED_9600 : + case WAPSETTINGS_SPEED_14400: + case WAPSETTINGS_SPEED_AUTO : + SaveBackupText(file, "", buffer, UseUnicode); + default: + break; + } + sprintf(buffer,"User%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].User, UseUnicode); + sprintf(buffer,"Password%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].Password, UseUnicode); + break; + case WAPSETTINGS_BEARER_USSD: + sprintf(buffer,"Bearer%02i = USSD%c%c",i,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"ServiceCode%02i",i); + SaveBackupText(file, buffer, settings->Settings[i].Code, UseUnicode); + if (settings->Settings[i].IsIP) { + sprintf(buffer,"IP%02i",i); + } else { + sprintf(buffer,"Number%02i",i); + } + SaveBackupText(file, buffer, settings->Settings[i].Service, UseUnicode); + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } +} + +static void SaveBitmapEntry(FILE *file, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[10000],buffer2[10000]; + int x,y; + + sprintf(buffer,"Width = %i%c%c",bitmap->BitmapWidth,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Height = %i%c%c",bitmap->BitmapHeight,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + for (y=0;y<bitmap->BitmapHeight;y++) { + for (x=0;x<bitmap->BitmapWidth;x++) { + buffer[x] = ' '; + if (GSM_IsPointBitmap(bitmap,x,y)) buffer[x]='#'; + } + buffer[bitmap->BitmapWidth] = 0; + sprintf(buffer2,"Bitmap%02i = \"%s\"%c%c",y,buffer,13,10); + SaveBackupText(file, "", buffer2, UseUnicode); + } +} + +static void SaveCallerEntry(FILE *file, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"Location = %03i%c%c",bitmap->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + if (!bitmap->DefaultName) SaveBackupText(file, "Name", bitmap->Text, UseUnicode); + if (!bitmap->DefaultRingtone) { + if (bitmap->FileSystemRingtone) { + sprintf(buffer,"FileRingtone = %02x%c%c",bitmap->RingtoneID,13,10); + } else { + sprintf(buffer,"Ringtone = %02x%c%c",bitmap->RingtoneID,13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + } + if (bitmap->BitmapEnabled) { + sprintf(buffer,"Enabled = True%c%c",13,10); + } else { + sprintf(buffer,"Enabled = False%c%c",13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + if (!bitmap->DefaultBitmap) SaveBitmapEntry(file, bitmap, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveWAPBookmarkEntry(FILE *file, GSM_WAPBookmark *bookmark, bool UseUnicode) +{ + unsigned char buffer[1000]; + + SaveBackupText(file, "URL", bookmark->Address, UseUnicode); + SaveBackupText(file, "Title", bookmark->Title, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveStartupEntry(FILE *file, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"[Startup]%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + if (bitmap->Type == GSM_WelcomeNote_Text) { + SaveBackupText(file, "Text", bitmap->Text, UseUnicode); + } + if (bitmap->Type == GSM_StartupLogo) { + SaveBitmapEntry(file, bitmap, UseUnicode); + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveSMSCEntry(FILE *file, GSM_SMSC *SMSC, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"Location = %03i%c%c",SMSC->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "Name", SMSC->Name, UseUnicode); + SaveBackupText(file, "Number", SMSC->Number, UseUnicode); + SaveBackupText(file, "DefaultNumber", SMSC->DefaultNumber, UseUnicode); + SaveBackupText(file, "", "Format = ", UseUnicode); + switch (SMSC->Format) { + case SMS_FORMAT_Text : sprintf(buffer,"Text"); break; + case SMS_FORMAT_Fax : sprintf(buffer,"Fax"); break; + case SMS_FORMAT_Email : sprintf(buffer,"Email"); break; + case SMS_FORMAT_Pager : sprintf(buffer,"Pager"); break; + } + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"%c%cValidity = ",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + switch (SMSC->Validity.Relative) { + case SMS_VALID_1_Hour : sprintf(buffer, "1hour" ); break; + case SMS_VALID_6_Hours : sprintf(buffer, "6hours" ); break; + case SMS_VALID_1_Day : sprintf(buffer, "24hours" ); break; + case SMS_VALID_3_Days : sprintf(buffer, "72hours" ); break; + case SMS_VALID_1_Week : sprintf(buffer, "1week" ); break; + case SMS_VALID_Max_Time : + default : sprintf(buffer,"MaximumTime" ); break; + } + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"%c%c%c%c",13,10,13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveRingtoneEntry(FILE *file, GSM_Ringtone *ringtone, bool UseUnicode) +{ + unsigned char buffer[45000]; + int i,j; + + sprintf(buffer,"Location = %i%c%c",ringtone->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "Name", ringtone->Name, UseUnicode); + switch (ringtone->Format) { + case RING_NOKIABINARY: + j = 0; i = 0; + EncodeHexBin(buffer,ringtone->NokiaBinary.Frame,ringtone->NokiaBinary.Length); + SaveLinkedBackupText(file, "NokiaBinary", buffer, UseUnicode); + break; + case RING_MIDI: + j = 0; i = 0; + EncodeHexBin(buffer,ringtone->NokiaBinary.Frame,ringtone->NokiaBinary.Length); + SaveLinkedBackupText(file, "Pure Midi", buffer, UseUnicode); + break; + case RING_NOTETONE: + break; + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveOperatorEntry(FILE *file, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"[Operator]%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Network = \"%s\"%c%c", bitmap->NetworkCode,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBitmapEntry(file, bitmap, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveToDoEntry(FILE *file, GSM_ToDoEntry *ToDo, bool UseUnicode) +{ + unsigned char buffer[1000]; + int j; + + sprintf(buffer,"Location = %i%c%c",ToDo->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + switch (ToDo->Priority) { + case GSM_Priority_High: + sprintf(buffer,"Priority = High%c%c",13,10); + break; + case GSM_Priority_Medium: + sprintf(buffer,"Priority = Medium%c%c",13,10); + break; + case GSM_Priority_Low: + sprintf(buffer,"Priority = Low%c%c",13,10); + break; + } + SaveBackupText(file, "", buffer, UseUnicode); + + for (j=0;j<ToDo->EntriesNum;j++) { + switch (ToDo->Entries[j].EntryType) { + case TODO_END_DATETIME: + SaveBackupText(file, "", "DueTime", UseUnicode); + SaveVCalDateTime(file, &ToDo->Entries[j].Date, UseUnicode); + break; + case TODO_COMPLETED: + sprintf(buffer,"Completed = %s%c%c",ToDo->Entries[j].Number == 1 ? "yes" : "no" ,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case TODO_ALARM_DATETIME: + SaveBackupText(file, "", "Alarm", UseUnicode); + SaveVCalDateTime(file, &ToDo->Entries[j].Date, UseUnicode); + break; + case TODO_SILENT_ALARM_DATETIME: + SaveBackupText(file, "", "SilentAlarm", UseUnicode); + SaveVCalDateTime(file, &ToDo->Entries[j].Date, UseUnicode); + break; + case TODO_TEXT: + SaveBackupText(file, "Text", ToDo->Entries[j].Text, UseUnicode); + break; + case TODO_PRIVATE: + sprintf(buffer,"Private = %i%c%c",ToDo->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case TODO_CATEGORY: + sprintf(buffer,"Category = %i%c%c",ToDo->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case TODO_CONTACTID: + sprintf(buffer,"ContactID = %i%c%c",ToDo->Entries[j].Number,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case TODO_PHONE: + SaveBackupText(file, "Phone", ToDo->Entries[j].Text, UseUnicode); + break; + } + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveProfileEntry(FILE *file, GSM_Profile *Profile, bool UseUnicode) +{ + int j,k; + bool special; + unsigned char buffer[1000]; + + sprintf(buffer,"Location = %i%c%c",Profile->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "Name",Profile->Name, UseUnicode); + + if (Profile->DefaultName) { + sprintf(buffer,"DefaultName = true%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + if (Profile->HeadSetProfile) { + sprintf(buffer,"HeadSetProfile = true%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + if (Profile->CarKitProfile) { + sprintf(buffer,"CarKitProfile = true%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + + for (j=0;j<Profile->FeaturesNumber;j++) { + sprintf(buffer,"Feature%02i = ",j); + SaveBackupText(file, "", buffer, UseUnicode); + special = false; + switch (Profile->FeatureID[j]) { + case Profile_MessageToneID: + case Profile_RingtoneID: + special = true; + if (Profile->FeatureID[j] == Profile_RingtoneID) { + sprintf(buffer,"RingtoneID%c%c",13,10); + } else { + sprintf(buffer,"MessageToneID%c%c",13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Value%02i = %i%c%c",j,Profile->FeatureValue[j],13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case Profile_CallerGroups: + special = true; + sprintf(buffer,"CallerGroups%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Value%02i = ",j); + SaveBackupText(file, "", buffer, UseUnicode); + for (k=0;k<5;k++) { + if (Profile->CallerGroups[k]) { + sprintf(buffer,"%i",k); + SaveBackupText(file, "", buffer, UseUnicode); + } + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case Profile_ScreenSaverNumber: + special = true; + sprintf(buffer,"ScreenSaverNumber%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Value%02i = %i%c%c",j,Profile->FeatureValue[j],13,10); + SaveBackupText(file, "", buffer, UseUnicode); + break; + case Profile_CallAlert : sprintf(buffer,"IncomingCallAlert%c%c",13,10); break; + case Profile_RingtoneVolume : sprintf(buffer,"RingtoneVolume%c%c",13,10); break; + case Profile_Vibration : sprintf(buffer,"Vibrating%c%c",13,10); break; + case Profile_MessageTone : sprintf(buffer,"MessageTone%c%c",13,10); break; + case Profile_KeypadTone : sprintf(buffer,"KeypadTones%c%c",13,10); break; + case Profile_WarningTone : sprintf(buffer,"WarningTones%c%c",13,10); break; + case Profile_ScreenSaver : sprintf(buffer,"ScreenSaver%c%c",13,10); break; + case Profile_ScreenSaverTime : sprintf(buffer,"ScreenSaverTimeout%c%c",13,10); break; + case Profile_AutoAnswer : sprintf(buffer,"AutomaticAnswer%c%c",13,10); break; + case Profile_Lights : sprintf(buffer,"Lights%c%c",13,10); break; + default : special = true; + } + if (!special) { + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Value%02i = ",j); + SaveBackupText(file, "", buffer, UseUnicode); + switch (Profile->FeatureValue[j]) { + case PROFILE_VOLUME_LEVEL1 : + case PROFILE_KEYPAD_LEVEL1 : sprintf(buffer,"Level1%c%c",13,10); break; + case PROFILE_VOLUME_LEVEL2 : + case PROFILE_KEYPAD_LEVEL2 : sprintf(buffer,"Level2%c%c",13,10); break; + case PROFILE_VOLUME_LEVEL3 : + case PROFILE_KEYPAD_LEVEL3 : sprintf(buffer,"Level3%c%c",13,10); break; + case PROFILE_VOLUME_LEVEL4 : sprintf(buffer,"Level4%c%c",13,10); break; + case PROFILE_VOLUME_LEVEL5 : sprintf(buffer,"Level5%c%c",13,10); break; + case PROFILE_MESSAGE_NOTONE : + case PROFILE_AUTOANSWER_OFF : + case PROFILE_LIGHTS_OFF : + case PROFILE_SAVER_OFF : + case PROFILE_WARNING_OFF : + case PROFILE_CALLALERT_OFF : + case PROFILE_VIBRATION_OFF : + case PROFILE_KEYPAD_OFF : sprintf(buffer,"Off%c%c",13,10); break; + case PROFILE_CALLALERT_RINGING : sprintf(buffer,"Ringing%c%c",13,10); break; + case PROFILE_CALLALERT_RINGONCE : sprintf(buffer,"RingOnce%c%c",13,10); break; + case PROFILE_CALLALERT_ASCENDING : sprintf(buffer,"Ascending%c%c",13,10); break; + case PROFILE_CALLALERT_CALLERGROUPS : sprintf(buffer,"CallerGroups%c%c",13,10); break; + case PROFILE_MESSAGE_STANDARD : sprintf(buffer,"Standard%c%c",13,10); break; + case PROFILE_MESSAGE_SPECIAL : sprintf(buffer,"Special%c%c",13,10); break; + case PROFILE_MESSAGE_BEEPONCE : + case PROFILE_CALLALERT_BEEPONCE : sprintf(buffer,"BeepOnce%c%c",13,10); break; + case PROFILE_MESSAGE_ASCENDING : sprintf(buffer,"Ascending%c%c",13,10); break; + case PROFILE_MESSAGE_PERSONAL : sprintf(buffer,"Personal%c%c",13,10); break; + case PROFILE_AUTOANSWER_ON : + case PROFILE_WARNING_ON : + case PROFILE_SAVER_ON : + case PROFILE_VIBRATION_ON : sprintf(buffer,"On%c%c",13,10); break; + case PROFILE_VIBRATION_FIRST : sprintf(buffer,"VibrateFirst%c%c",13,10); break; + case PROFILE_LIGHTS_AUTO : sprintf(buffer,"Auto%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_5SEC : sprintf(buffer,"5Seconds%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_20SEC : sprintf(buffer,"20Seconds%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_1MIN : sprintf(buffer,"1Minute%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_2MIN : sprintf(buffer,"2Minutes%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_5MIN : sprintf(buffer,"5Minutes%c%c",13,10); break; + case PROFILE_SAVER_TIMEOUT_10MIN : sprintf(buffer,"10Minutes%c%c",13,10); break; + default : sprintf(buffer,"UNKNOWN%c%c",13,10); + } + SaveBackupText(file, "", buffer, UseUnicode); + } + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveFMStationEntry(FILE *file, GSM_FMStation *FMStation, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"Location = %i%c%c",FMStation->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "StationName", FMStation->StationName, UseUnicode); + sprintf(buffer,"Frequency = %f%c%c",FMStation->Frequency,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +static void SaveGPRSPointEntry(FILE *file, GSM_GPRSAccessPoint *GPRSPoint, bool UseUnicode) +{ + unsigned char buffer[1000]; + + sprintf(buffer,"Location = %i%c%c",GPRSPoint->Location,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveBackupText(file, "Name", GPRSPoint->Name, UseUnicode); + SaveBackupText(file, "URL", GPRSPoint->URL, UseUnicode); + if (GPRSPoint->Active) { + sprintf(buffer,"Active = Yes%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); +} + +GSM_Error SaveBackup(char *FileName, GSM_Backup *backup, bool UseUnicode) +{ + int i; + unsigned char buffer[1000],checksum[200]; + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + if (UseUnicode) { + sprintf(buffer,"%c%c", 0xFE, 0xFF); + SaveBackupText(file, "", buffer, false); + } + + sprintf(buffer,"# Format of this file was designed for Gammu (see www.mwiacek.com)%c%c%c%c",13,10,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"[Backup]%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"IMEI = \"%s\"%c%c",backup->IMEI,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"Phone = \"%s\"%c%c",backup->Model,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + if (backup->Creator[0] != 0) { + sprintf(buffer,"Creator = \"%s\"%c%c",backup->Creator,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + } + if (backup->DateTimeAvailable) { + SaveBackupText(file, "", "DateTime", UseUnicode); + SaveVCalDateTime(file, &backup->DateTime, UseUnicode); + } + sprintf(buffer,"Format = 1.03%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + + i=0; + while (backup->PhonePhonebook[i]!=NULL) { + sprintf(buffer,"[PhonePBK%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SavePbkEntry(file, backup->PhonePhonebook[i], UseUnicode); + i++; + } + i=0; + while (backup->SIMPhonebook[i]!=NULL) { + sprintf(buffer,"[SIMPBK%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SavePbkEntry(file, backup->SIMPhonebook[i], UseUnicode); + i++; + } + i=0; + while (backup->Calendar[i]!=NULL) { + sprintf(buffer,"[Calendar%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveCalendarEntry(file, backup->Calendar[i], UseUnicode); + i++; + } + i=0; + while (backup->CallerLogos[i]!=NULL) { + sprintf(buffer,"[Caller%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveCallerEntry(file, backup->CallerLogos[i], UseUnicode); + i++; + } + i=0; + while (backup->SMSC[i]!=NULL) { + sprintf(buffer,"[SMSC%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveSMSCEntry(file, backup->SMSC[i], UseUnicode); + i++; + } + i=0; + while (backup->WAPBookmark[i]!=NULL) { + sprintf(buffer,"[WAPBookmark%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveWAPBookmarkEntry(file, backup->WAPBookmark[i], UseUnicode); + i++; + } + i=0; + while (backup->WAPSettings[i]!=NULL) { + sprintf(buffer,"[WAPSettings%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveWAPSettingsEntry(file, backup->WAPSettings[i], UseUnicode); + i++; + } + i=0; + while (backup->MMSSettings[i]!=NULL) { + sprintf(buffer,"[MMSSettings%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveWAPSettingsEntry(file, backup->MMSSettings[i], UseUnicode); + i++; + } + i=0; + while (backup->Ringtone[i]!=NULL) { + sprintf(buffer,"[Ringtone%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveRingtoneEntry(file, backup->Ringtone[i], UseUnicode); + i++; + } + i=0; + while (backup->ToDo[i]!=NULL) { + sprintf(buffer,"[TODO%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveToDoEntry(file, backup->ToDo[i], UseUnicode); + i++; + } + i=0; + while (backup->Profiles[i]!=NULL) { + sprintf(buffer,"[Profile%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveProfileEntry(file, backup->Profiles[i], UseUnicode); + i++; + } + i=0; + while (backup->FMStation[i]!=NULL) { + sprintf(buffer,"[FMStation%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveFMStationEntry(file, backup->FMStation[i], UseUnicode); + i++; + } + i=0; + while (backup->GPRSPoint[i]!=NULL) { + sprintf(buffer,"[GPRSPoint%03i]%c%c",i+1,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + SaveGPRSPointEntry(file, backup->GPRSPoint[i], UseUnicode); + i++; + } + + if (backup->StartupLogo!=NULL) { + SaveStartupEntry(file, backup->StartupLogo, UseUnicode); + } + if (backup->OperatorLogo!=NULL) { + SaveOperatorEntry(file, backup->OperatorLogo, UseUnicode); + } + + fclose(file); + + FindBackupChecksum(FileName, UseUnicode, checksum); + + file = fopen(FileName, "ab"); + if (file == NULL) return ERR_CANTOPENFILE; + sprintf(buffer,"[Checksum]%c%c",13,10); + SaveBackupText(file, "", buffer, UseUnicode); + sprintf(buffer,"MD5=%s%c%c",checksum,13,10); + SaveBackupText(file, "", buffer, UseUnicode); + fclose(file); + + return ERR_NONE; +} + +static void ReadPbkEntry(INI_Section *file_info, char *section, GSM_MemoryEntry *Pbk, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + int num,i; + INI_Entry *e; + + Pbk->EntriesNum = 0; + e = INI_FindLastSectionEntry(file_info, section, UseUnicode); + + while (e != NULL) { + num = -1; + if (UseUnicode) { + sprintf(buffer,"%s",DecodeUnicodeString(e->EntryName)); + } else { + sprintf(buffer,"%s",e->EntryName); + } + if (strlen(buffer) == 11) { + if (mystrncasecmp("Entry", buffer, 5) && + mystrncasecmp("Type", buffer+7, 4)) { + num = atoi(buffer+5); + } + } + e = e->Prev; + if (num != -1) { + sprintf(buffer,"Entry%02iType",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (mystrncasecmp(readvalue,"NumberGeneral",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_General; + } else if (mystrncasecmp(readvalue,"NumberMobile",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Mobile; + } else if (mystrncasecmp(readvalue,"NumberWork",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Work; + } else if (mystrncasecmp(readvalue,"NumberFax",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Fax; + } else if (mystrncasecmp(readvalue,"NumberHome",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Home; + } else if (mystrncasecmp(readvalue,"NumberOther",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Other; + } else if (mystrncasecmp(readvalue,"NumberPager",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Pager; + } else if (mystrncasecmp(readvalue,"Note",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Note; + } else if (mystrncasecmp(readvalue,"Postal",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Postal; + } else if (mystrncasecmp(readvalue,"Email",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Email; + } else if (mystrncasecmp(readvalue,"Email2",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Email2; + } else if (mystrncasecmp(readvalue,"URL",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_URL; + } else if (mystrncasecmp(readvalue,"FirstName",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_FirstName; + } else if (mystrncasecmp(readvalue,"LastName",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_LastName; + } else if (mystrncasecmp(readvalue,"Company",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Company; + } else if (mystrncasecmp(readvalue,"JobTitle",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_JobTitle; + } else if (mystrncasecmp(readvalue,"Address",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_StreetAddress; + } else if (mystrncasecmp(readvalue,"City",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_City; + } else if (mystrncasecmp(readvalue,"State",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_State; + } else if (mystrncasecmp(readvalue,"Zip",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Zip; + } else if (mystrncasecmp(readvalue,"Country",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Country; + } else if (mystrncasecmp(readvalue,"Custom1",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Custom1; + } else if (mystrncasecmp(readvalue,"Custom2",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Custom2; + } else if (mystrncasecmp(readvalue,"Custom3",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Custom3; + } else if (mystrncasecmp(readvalue,"Custom4",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Custom4; + } else if (mystrncasecmp(readvalue,"Name",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Name; + } else if (mystrncasecmp(readvalue,"Category",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Category; + Pbk->Entries[Pbk->EntriesNum].Number = 0; + sprintf(buffer,"Entry%02iNumber",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].Number = atoi(readvalue); + } + Pbk->EntriesNum ++; + continue; + } else if (mystrncasecmp(readvalue,"Private",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Private; + Pbk->Entries[Pbk->EntriesNum].Number = 0; + sprintf(buffer,"Entry%02iNumber",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].Number = atoi(readvalue); + } + Pbk->EntriesNum ++; + continue; + } else if (mystrncasecmp(readvalue,"CallerGroup",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Caller_Group; + Pbk->Entries[Pbk->EntriesNum].Number = 0; + sprintf(buffer,"Entry%02iNumber",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].Number = atoi(readvalue); + } + Pbk->EntriesNum ++; + continue; + } else if (mystrncasecmp(readvalue,"RingtoneID",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_RingtoneID; + Pbk->Entries[Pbk->EntriesNum].Number = 0; + sprintf(buffer,"Entry%02iNumber",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].Number = atoi(readvalue); + } + Pbk->EntriesNum ++; + continue; + } else if (mystrncasecmp(readvalue,"PictureID",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_PictureID; + Pbk->Entries[Pbk->EntriesNum].Number = 0; + sprintf(buffer,"Entry%02iNumber",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].Number = atoi(readvalue); + } + Pbk->EntriesNum ++; + continue; + } else if (mystrncasecmp(readvalue,"UserID",0)) { + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_UserID; + } + sprintf(buffer,"Entry%02iText",num); + ReadBackupText(file_info, section, buffer, Pbk->Entries[Pbk->EntriesNum].Text,UseUnicode); + dbgprintf("text \"%s\", type %i\n",DecodeUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text),Pbk->Entries[Pbk->EntriesNum].EntryType); + Pbk->Entries[Pbk->EntriesNum].VoiceTag = 0; + sprintf(buffer,"Entry%02iVoiceTag",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + Pbk->Entries[Pbk->EntriesNum].VoiceTag = atoi(readvalue); + } + i = 0; + while (1) { + Pbk->Entries[Pbk->EntriesNum].SMSList[i] = 0; + sprintf(buffer,"Entry%02iSMSList%02i",num,i); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) break; + Pbk->Entries[Pbk->EntriesNum].SMSList[i] = atoi(readvalue); + i++; + } + Pbk->EntriesNum ++; + } + } +} + +static void ReadCalendarEntry(INI_Section *file_info, char *section, GSM_CalendarEntry *note, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) note->Location = atoi(readvalue); + + sprintf(buffer,"Type"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + note->Type = GSM_CAL_REMINDER; + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Call",0)) { + note->Type = GSM_CAL_CALL; + } else if (mystrncasecmp(readvalue,"Meeting",0)) { + note->Type = GSM_CAL_MEETING; + } else if (mystrncasecmp(readvalue,"Birthday",0)) { + note->Type = GSM_CAL_BIRTHDAY; + } else if (mystrncasecmp(readvalue,"Memo",0)) { + note->Type = GSM_CAL_MEMO; + } else if (mystrncasecmp(readvalue,"Travel",0)) { + note->Type = GSM_CAL_TRAVEL; + } else if (mystrncasecmp(readvalue,"Vacation",0)) { + note->Type = GSM_CAL_VACATION; + } else if (mystrncasecmp(readvalue,"DailyAlarm",0)) { + note->Type = GSM_CAL_DAILY_ALARM; + } else if (mystrncasecmp(readvalue,"Alarm",0)) { + note->Type = GSM_CAL_ALARM; + } else if (mystrncasecmp(readvalue,"Training/Athletism",0)) { + note->Type = GSM_CAL_T_ATHL; + } else if (mystrncasecmp(readvalue,"Training/BallGames",0)) { + note->Type = GSM_CAL_T_BALL; + } else if (mystrncasecmp(readvalue,"Training/Cycling",0)) { + note->Type = GSM_CAL_T_CYCL; + } else if (mystrncasecmp(readvalue,"Training/Budo",0)) { + note->Type = GSM_CAL_T_BUDO; + } else if (mystrncasecmp(readvalue,"Training/Dance",0)) { + note->Type = GSM_CAL_T_DANC; + } else if (mystrncasecmp(readvalue,"Training/ExtremeSports",0)) { + note->Type = GSM_CAL_T_EXTR; + } else if (mystrncasecmp(readvalue,"Training/Football",0)) { + note->Type = GSM_CAL_T_FOOT; + } else if (mystrncasecmp(readvalue,"Training/Golf",0)) { + note->Type = GSM_CAL_T_GOLF; + } else if (mystrncasecmp(readvalue,"Training/Gym",0)) { + note->Type = GSM_CAL_T_GYM; + } else if (mystrncasecmp(readvalue,"Training/HorseRaces",0)) { + note->Type = GSM_CAL_T_HORS; + } else if (mystrncasecmp(readvalue,"Training/Hockey",0)) { + note->Type = GSM_CAL_T_HOCK; + } else if (mystrncasecmp(readvalue,"Training/Races",0)) { + note->Type = GSM_CAL_T_RACE; + } else if (mystrncasecmp(readvalue,"Training/Rugby",0)) { + note->Type = GSM_CAL_T_RUGB; + } else if (mystrncasecmp(readvalue,"Training/Sailing",0)) { + note->Type = GSM_CAL_T_SAIL; + } else if (mystrncasecmp(readvalue,"Training/StreetGames",0)) { + note->Type = GSM_CAL_T_STRE; + } else if (mystrncasecmp(readvalue,"Training/Swimming",0)) { + note->Type = GSM_CAL_T_SWIM; + } else if (mystrncasecmp(readvalue,"Training/Tennis",0)) { + note->Type = GSM_CAL_T_TENN; + } else if (mystrncasecmp(readvalue,"Training/Travels",0)) { + note->Type = GSM_CAL_T_TRAV; + } else if (mystrncasecmp(readvalue,"Training/WinterGames",0)) { + note->Type = GSM_CAL_T_WINT; + } + } + note->EntriesNum = 0; + sprintf(buffer,"Text"); + if (ReadBackupText(file_info, section, buffer, note->Entries[note->EntriesNum].Text,UseUnicode)) { + note->Entries[note->EntriesNum].EntryType = CAL_TEXT; + note->EntriesNum++; + } + sprintf(buffer,"Phone"); + if (ReadBackupText(file_info, section, buffer, note->Entries[note->EntriesNum].Text,UseUnicode)) { + note->Entries[note->EntriesNum].EntryType = CAL_PHONE; + note->EntriesNum++; + } + sprintf(buffer,"Private"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_PRIVATE; + note->EntriesNum++; + } + sprintf(buffer,"EventLocation"); + if (ReadBackupText(file_info, section, buffer, note->Entries[note->EntriesNum].Text,UseUnicode)) { + note->Entries[note->EntriesNum].EntryType = CAL_LOCATION; + note->EntriesNum++; + } + sprintf(buffer,"ContactID"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_CONTACTID; + note->EntriesNum++; + } + sprintf(buffer,"Recurrance"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue) * 24; + note->Entries[note->EntriesNum].EntryType = CAL_RECURRANCE; + note->EntriesNum++; + } + sprintf(buffer,"StartTime"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, ¬e->Entries[note->EntriesNum].Date); + note->Entries[note->EntriesNum].EntryType = CAL_START_DATETIME; + note->EntriesNum++; + } + sprintf(buffer,"StopTime"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, ¬e->Entries[note->EntriesNum].Date); + note->Entries[note->EntriesNum].EntryType = CAL_END_DATETIME; + note->EntriesNum++; + } + sprintf(buffer,"Alarm"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + ReadVCALDateTime(readvalue, ¬e->Entries[note->EntriesNum].Date); + note->Entries[note->EntriesNum].EntryType = CAL_ALARM_DATETIME; + sprintf(buffer,"AlarmType"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Silent",0)) { + note->Entries[note->EntriesNum].EntryType = CAL_SILENT_ALARM_DATETIME; + } + } + note->EntriesNum++; + } + sprintf(buffer,"RepeatStartDate"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, ¬e->Entries[note->EntriesNum].Date); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_STARTDATE; + note->EntriesNum++; + } + sprintf(buffer,"RepeatStopDate"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, ¬e->Entries[note->EntriesNum].Date); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_STOPDATE; + note->EntriesNum++; + } + sprintf(buffer,"RepeatDayOfWeek"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_DAYOFWEEK; + note->EntriesNum++; + } + sprintf(buffer,"RepeatDay"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_DAY; + note->EntriesNum++; + } + sprintf(buffer,"RepeatWeekOfMonth"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_WEEKOFMONTH; + note->EntriesNum++; + } + sprintf(buffer,"RepeatMonth"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_MONTH; + note->EntriesNum++; + } + sprintf(buffer,"RepeatFrequency"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + note->Entries[note->EntriesNum].Number = atoi(readvalue); + note->Entries[note->EntriesNum].EntryType = CAL_REPEAT_FREQUENCY; + note->EntriesNum++; + } +} + +static void ReadToDoEntry(INI_Section *file_info, char *section, GSM_ToDoEntry *ToDo, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + + ToDo->EntriesNum = 0; + + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) ToDo->Location = atoi(readvalue); + + ToDo->Priority = GSM_Priority_High; + sprintf(buffer,"Priority"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (!strcmp(readvalue,"3") || !strcmp(readvalue,"Low")) { + ToDo->Priority = GSM_Priority_Low; + } + if (!strcmp(readvalue,"2") || !strcmp(readvalue,"Medium")) { + ToDo->Priority = GSM_Priority_Medium; + } + } + + sprintf(buffer,"Text"); + if (ReadBackupText(file_info, section, buffer, ToDo->Entries[ToDo->EntriesNum].Text,UseUnicode)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_TEXT; + ToDo->EntriesNum++; + } + + sprintf(buffer,"Phone"); + if (ReadBackupText(file_info, section, buffer, ToDo->Entries[ToDo->EntriesNum].Text,UseUnicode)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_PHONE; + ToDo->EntriesNum++; + } + + sprintf(buffer,"Private"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ToDo->Entries[ToDo->EntriesNum].Number = atoi(readvalue); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_PRIVATE; + ToDo->EntriesNum++; + } + + sprintf(buffer,"Completed"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (strncmp(readvalue, "yes", 3) == 0) { + ToDo->Entries[ToDo->EntriesNum].Number = 1; + } else { + ToDo->Entries[ToDo->EntriesNum].Number = 0; + } + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_COMPLETED; + ToDo->EntriesNum++; + } + + sprintf(buffer,"Category"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ToDo->Entries[ToDo->EntriesNum].Number = atoi(readvalue); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_CATEGORY; + ToDo->EntriesNum++; + } + + sprintf(buffer,"ContactID"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ToDo->Entries[ToDo->EntriesNum].Number = atoi(readvalue); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_CONTACTID; + ToDo->EntriesNum++; + } + + sprintf(buffer,"DueTime"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_END_DATETIME; + ToDo->EntriesNum++; + } + + sprintf(buffer,"Alarm"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_ALARM_DATETIME; + ToDo->EntriesNum++; + } + + sprintf(buffer,"SilentAlarm"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_SILENT_ALARM_DATETIME; + ToDo->EntriesNum++; + } +} + +static bool ReadBitmapEntry(INI_Section *file_info, char *section, GSM_Bitmap *bitmap, bool UseUnicode) +{ + char *readvalue; + unsigned char buffer[10000]; + unsigned char Width, Height; + int x, y; + + GSM_GetMaxBitmapWidthHeight(bitmap->Type, &Width, &Height); + sprintf(buffer,"Width"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) bitmap->BitmapWidth = Width; else bitmap->BitmapWidth = atoi(readvalue); + sprintf(buffer,"Height"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) bitmap->BitmapHeight = Height; else bitmap->BitmapHeight = atoi(readvalue); + GSM_ClearBitmap(bitmap); + for (y=0;y<bitmap->BitmapHeight;y++) { + sprintf(buffer,"Bitmap%02i",y); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + for (x=0;x<bitmap->BitmapWidth;x++) { + if (readvalue[x+1]=='#') GSM_SetPointBitmap(bitmap,x,y); + } + } else return false; + } + return true; +} + +static void ReadCallerEntry(INI_Section *file_info, char *section, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + + bitmap->Type = GSM_CallerGroupLogo; + bitmap->DefaultBitmap = !ReadBitmapEntry(file_info, section, bitmap, UseUnicode); + if (bitmap->DefaultBitmap) { + bitmap->BitmapWidth = 72; + bitmap->BitmapHeight = 14; + GSM_ClearBitmap(bitmap); + } + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, bitmap->Text,UseUnicode); + if (bitmap->Text[0] == 0x00 && bitmap->Text[1] == 0x00) { + bitmap->DefaultName = true; + } else { + bitmap->DefaultName = false; + } + sprintf(buffer,"Ringtone"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) { + sprintf(buffer,"FileRingtone"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) { + bitmap->DefaultRingtone = true; + } else { + DecodeHexBin (&bitmap->RingtoneID, readvalue, 2); + bitmap->DefaultRingtone = false; + bitmap->FileSystemRingtone = true; + } + } else { + DecodeHexBin (&bitmap->RingtoneID, readvalue, 2); + bitmap->DefaultRingtone = false; + bitmap->FileSystemRingtone = false; + } + sprintf(buffer,"Enabled"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + bitmap->BitmapEnabled = true; + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"False",0)) bitmap->BitmapEnabled = false; + } +} + +static void ReadStartupEntry(INI_Section *file_info, char *section, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[10000]; + + sprintf(buffer,"Text"); + ReadBackupText(file_info, section, buffer, bitmap->Text,UseUnicode); + if (bitmap->Text[0]!=0 || bitmap->Text[1]!=0) { + bitmap->Type = GSM_WelcomeNote_Text; + } else { + bitmap->Type = GSM_StartupLogo; + bitmap->Location = 1; + ReadBitmapEntry(file_info, section, bitmap, UseUnicode); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,bitmap); +#endif + } +} + +static void ReadWAPBookmarkEntry(INI_Section *file_info, char *section, GSM_WAPBookmark *bookmark, bool UseUnicode) +{ + unsigned char buffer[10000]; + + sprintf(buffer,"URL"); + ReadBackupText(file_info, section, buffer, bookmark->Address,UseUnicode); + sprintf(buffer,"Title"); + ReadBackupText(file_info, section, buffer, bookmark->Title,UseUnicode); +} + +static void ReadOperatorEntry(INI_Section *file_info, char *section, GSM_Bitmap *bitmap, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + + sprintf(buffer,"Network"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + memcpy(bitmap->NetworkCode, readvalue + 1, 6); + bitmap->NetworkCode[6] = 0; + bitmap->Type = GSM_OperatorLogo; + ReadBitmapEntry(file_info, section, bitmap, UseUnicode); +} + +static void ReadSMSCEntry(INI_Section *file_info, char *section, GSM_SMSC *SMSC, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, SMSC->Name,UseUnicode); + sprintf(buffer,"Number"); + ReadBackupText(file_info, section, buffer, SMSC->Number,UseUnicode); + sprintf(buffer,"DefaultNumber"); + ReadBackupText(file_info, section, buffer, SMSC->DefaultNumber,UseUnicode); + sprintf(buffer,"Format"); + SMSC->Format = SMS_FORMAT_Text; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Fax",0)) { + SMSC->Format = SMS_FORMAT_Fax; + } else if (mystrncasecmp(readvalue,"Email",0)) { + SMSC->Format = SMS_FORMAT_Email; + } else if (mystrncasecmp(readvalue,"Pager",0)) { + SMSC->Format = SMS_FORMAT_Pager; + } + } + sprintf(buffer,"Validity"); + SMSC->Validity.Relative = SMS_VALID_Max_Time; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"1hour",0)) { + SMSC->Validity.Relative = SMS_VALID_1_Hour; + } else if (mystrncasecmp(readvalue,"6hours",0)) { + SMSC->Validity.Relative = SMS_VALID_6_Hours; + } else if (mystrncasecmp(readvalue,"24hours",0)) { + SMSC->Validity.Relative = SMS_VALID_1_Day; + } else if (mystrncasecmp(readvalue,"72hours",0)) { + SMSC->Validity.Relative = SMS_VALID_3_Days; + } else if (mystrncasecmp(readvalue,"1week",0)) { + SMSC->Validity.Relative = SMS_VALID_1_Week; + } + } +} + +static void ReadWAPSettingsEntry(INI_Section *file_info, char *section, GSM_MultiWAPSettings *settings, bool UseUnicode) +{ + unsigned char buffer[10000], *readvalue; + int num; + INI_Entry *e; + + settings->ActiveBearer = WAPSETTINGS_BEARER_DATA; + sprintf(buffer,"Bearer"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"SMS",0)) { + settings->ActiveBearer = WAPSETTINGS_BEARER_SMS; + } else if (mystrncasecmp(readvalue,"GPRS",0)) { + settings->ActiveBearer = WAPSETTINGS_BEARER_GPRS; + } else if (mystrncasecmp(readvalue,"USSD",0)) { + settings->ActiveBearer = WAPSETTINGS_BEARER_USSD; + } + } + + settings->Active = false; + sprintf(buffer,"Active"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Yes",0)) settings->Active = true; + } + + settings->ReadOnly = false; + sprintf(buffer,"ReadOnly"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Yes",0)) settings->ReadOnly = true; + } + + sprintf(buffer,"Proxy"); + ReadBackupText(file_info, section, buffer, settings->Proxy,UseUnicode); + sprintf(buffer,"ProxyPort"); + settings->ProxyPort = 8080; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) settings->ProxyPort = atoi(readvalue); + sprintf(buffer,"Proxy2"); + ReadBackupText(file_info, section, buffer, settings->Proxy2,UseUnicode); + sprintf(buffer,"Proxy2Port"); + settings->Proxy2Port = 8080; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) settings->Proxy2Port = atoi(readvalue); + + settings->Number = 0; + e = INI_FindLastSectionEntry(file_info, section, UseUnicode); + while (e != NULL) { + num = -1; + if (UseUnicode) { + sprintf(buffer,"%s",DecodeUnicodeString(e->EntryName)); + } else { + sprintf(buffer,"%s",e->EntryName); + } + if (strlen(buffer) == 7) { + if (mystrncasecmp("Title", buffer,5)) num = atoi(buffer+5); + } + e = e->Prev; + if (num != -1) { + sprintf(buffer,"Title%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Title,UseUnicode); + sprintf(buffer,"HomePage%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].HomePage,UseUnicode); + sprintf(buffer,"Type%02i",num); + settings->Settings[settings->Number].IsContinuous = true; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Temporary",0)) settings->Settings[settings->Number].IsContinuous = false; + } + sprintf(buffer,"Security%02i",num); + settings->Settings[settings->Number].IsSecurity = true; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Off",0)) settings->Settings[settings->Number].IsSecurity = false; + } + sprintf(buffer,"Bearer%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"SMS",0)) { + settings->Settings[settings->Number].Bearer = WAPSETTINGS_BEARER_SMS; + sprintf(buffer,"Server%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Server,UseUnicode); + sprintf(buffer,"Service%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Service,UseUnicode); + } else if ((mystrncasecmp(readvalue,"Data",0) || mystrncasecmp(readvalue,"GPRS",0))) { + settings->Settings[settings->Number].Bearer = WAPSETTINGS_BEARER_DATA; + if (mystrncasecmp(readvalue,"GPRS",0)) settings->Settings[settings->Number].Bearer = WAPSETTINGS_BEARER_GPRS; + sprintf(buffer,"Number%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].DialUp,UseUnicode); + sprintf(buffer,"IP%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].IPAddress,UseUnicode); + sprintf(buffer,"User%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].User,UseUnicode); + sprintf(buffer,"Password%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Password,UseUnicode); + sprintf(buffer,"Authentication%02i",num); + settings->Settings[settings->Number].IsNormalAuthentication = true; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Secure",0)) settings->Settings[settings->Number].IsNormalAuthentication = false; + } + sprintf(buffer,"CallSpeed%02i",num); + settings->Settings[settings->Number].Speed = WAPSETTINGS_SPEED_14400; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"9600",0)) settings->Settings[settings->Number].Speed = WAPSETTINGS_SPEED_9600; + if (mystrncasecmp(readvalue,"auto",0)) settings->Settings[settings->Number].Speed = WAPSETTINGS_SPEED_AUTO; + } + sprintf(buffer,"Login%02i",num); + settings->Settings[settings->Number].ManualLogin = false; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Manual",0)) settings->Settings[settings->Number].ManualLogin = true; + } + sprintf(buffer,"CallType%02i",num); + settings->Settings[settings->Number].IsISDNCall = true; + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) + { + if (mystrncasecmp(readvalue,"Analogue",0)) settings->Settings[settings->Number].IsISDNCall = false; + } + } else if (mystrncasecmp(readvalue,"USSD",0)) { + settings->Settings[settings->Number].Bearer = WAPSETTINGS_BEARER_USSD; + sprintf(buffer,"ServiceCode%02i",num); + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Code,UseUnicode); + sprintf(buffer,"IP%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + settings->Settings[settings->Number].IsIP = true; + sprintf(buffer,"IP%02i",num); + } else { + settings->Settings[settings->Number].IsIP = false; + sprintf(buffer,"Number%02i",num); + } + ReadBackupText(file_info, section, buffer, settings->Settings[settings->Number].Service,UseUnicode); + } + } + settings->Number++; + } + } +} + +static void ReadRingtoneEntry(INI_Section *file_info, char *section, GSM_Ringtone *ringtone, bool UseUnicode) +{ + unsigned char buffer[10000], buffer2[10000], *readvalue; + + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, ringtone->Name,UseUnicode); + ringtone->Location = 0; + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) ringtone->Location = atoi(readvalue); + sprintf(buffer,"NokiaBinary00"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ringtone->Format = RING_NOKIABINARY; + ReadLinkedBackupText(file_info, section, "NokiaBinary", buffer2, UseUnicode); + DecodeHexBin (ringtone->NokiaBinary.Frame, buffer2, strlen(buffer2)); + ringtone->NokiaBinary.Length = strlen(buffer2)/2; + } + sprintf(buffer,"Pure Midi00"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + ringtone->Format = RING_MIDI; + ReadLinkedBackupText(file_info, section, "Pure Midi", buffer2, UseUnicode); + DecodeHexBin (ringtone->NokiaBinary.Frame, buffer2, strlen(buffer2)); + ringtone->NokiaBinary.Length = strlen(buffer2)/2; + } + +} + +static void ReadProfileEntry(INI_Section *file_info, char *section, GSM_Profile *Profile, bool UseUnicode) +{ + unsigned char buffer[10000]; + char *readvalue; + bool unknown; + int num,j; + INI_Entry *e; + + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, Profile->Name,UseUnicode); + + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + Profile->Location = atoi(readvalue); + + Profile->DefaultName = false; + sprintf(buffer,"DefaultName"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL && mystrncasecmp(buffer,"true",0)) Profile->DefaultName = true; + + Profile->HeadSetProfile = false; + sprintf(buffer,"HeadSetProfile"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL && mystrncasecmp(buffer,"true",0)) Profile->HeadSetProfile = true; + + Profile->CarKitProfile = false; + sprintf(buffer,"CarKitProfile"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL && mystrncasecmp(buffer,"true",0)) Profile->CarKitProfile = true; + + Profile->FeaturesNumber = 0; + e = INI_FindLastSectionEntry(file_info, section, UseUnicode); + while (e != NULL) { + num = -1; + if (UseUnicode) { + sprintf(buffer,"%s",DecodeUnicodeString(e->EntryName)); + } else { + sprintf(buffer,"%s",e->EntryName); + } + if (strlen(buffer) == 9) { + if (mystrncasecmp("Feature", buffer, 7)) num = atoi(buffer+7); + } + e = e->Prev; + if (num != -1) { + sprintf(buffer,"Feature%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue==NULL) break; + unknown = true; + if (mystrncasecmp(readvalue,"RingtoneID",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_RingtoneID; + sprintf(buffer,"Value%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + Profile->FeatureValue[Profile->FeaturesNumber]=atoi(readvalue); + Profile->FeaturesNumber++; + } else if (mystrncasecmp(readvalue,"MessageToneID",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_MessageToneID; + sprintf(buffer,"Value%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + Profile->FeatureValue[Profile->FeaturesNumber]=atoi(readvalue); + Profile->FeaturesNumber++; + } else if (mystrncasecmp(readvalue,"ScreenSaverNumber",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_ScreenSaverNumber; + sprintf(buffer,"Value%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + Profile->FeatureValue[Profile->FeaturesNumber]=atoi(readvalue); + Profile->FeaturesNumber++; + } else if (mystrncasecmp(readvalue,"CallerGroups",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_CallerGroups; + sprintf(buffer,"Value%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + for (j=0;j<5;j++) { + Profile->CallerGroups[j]=false; + if (strstr(readvalue,"1"+j)!=NULL) Profile->CallerGroups[j]=true; + } + Profile->FeaturesNumber++; + } else if (mystrncasecmp(readvalue,"IncomingCallAlert",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_CallAlert; + unknown = false; + } else if (mystrncasecmp(readvalue,"RingtoneVolume",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_RingtoneVolume; + unknown = false; + } else if (mystrncasecmp(readvalue,"Vibrating",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_Vibration; + unknown = false; + } else if (mystrncasecmp(readvalue,"MessageTone",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_MessageTone; + unknown = false; + } else if (mystrncasecmp(readvalue,"KeypadTones",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_KeypadTone; + unknown = false; + } else if (mystrncasecmp(readvalue,"WarningTones",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_WarningTone; + unknown = false; + } else if (mystrncasecmp(readvalue,"ScreenSaver",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_ScreenSaver; + unknown = false; + } else if (mystrncasecmp(readvalue,"ScreenSaverTimeout",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_ScreenSaverTime; + unknown = false; + } else if (mystrncasecmp(readvalue,"AutomaticAnswer",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_AutoAnswer; + unknown = false; + } else if (mystrncasecmp(readvalue,"Lights",0)) { + Profile->FeatureID[Profile->FeaturesNumber]=Profile_Lights; + unknown = false; + } + if (!unknown) { + sprintf(buffer,"Value%02i",num); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (mystrncasecmp(readvalue,"Level1",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VOLUME_LEVEL1; + if (Profile->FeatureID[Profile->FeaturesNumber]==Profile_KeypadTone) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_KEYPAD_LEVEL1; + } + } else if (mystrncasecmp(readvalue,"Level2",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VOLUME_LEVEL2; + if (Profile->FeatureID[Profile->FeaturesNumber]==Profile_KeypadTone) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_KEYPAD_LEVEL2; + } + } else if (mystrncasecmp(readvalue,"Level3",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VOLUME_LEVEL3; + if (Profile->FeatureID[Profile->FeaturesNumber]==Profile_KeypadTone) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_KEYPAD_LEVEL3; + } + } else if (mystrncasecmp(readvalue,"Level4",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VOLUME_LEVEL4; + } else if (mystrncasecmp(readvalue,"Level5",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VOLUME_LEVEL5; + } else if (mystrncasecmp(readvalue,"Off",0)) { + switch (Profile->FeatureID[Profile->FeaturesNumber]) { + case Profile_MessageTone: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_NOTONE; + break; + case Profile_AutoAnswer: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_AUTOANSWER_OFF; + break; + case Profile_Lights: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_LIGHTS_OFF; + break; + case Profile_ScreenSaver: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_OFF; + break; + case Profile_WarningTone: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_WARNING_OFF; + break; + case Profile_CallAlert: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_OFF; + break; + case Profile_Vibration: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VIBRATION_OFF; + break; + default: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_KEYPAD_OFF; + break; + } + } else if (mystrncasecmp(readvalue,"Ringing",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_RINGING; + } else if (mystrncasecmp(readvalue,"BeepOnce",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_BEEPONCE; + if (Profile->FeatureID[Profile->FeaturesNumber]==Profile_MessageTone) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_BEEPONCE; + } + } else if (mystrncasecmp(readvalue,"RingOnce",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_RINGONCE; + } else if (mystrncasecmp(readvalue,"Ascending",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_ASCENDING; + } else if (mystrncasecmp(readvalue,"CallerGroups",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_CALLALERT_CALLERGROUPS; + } else if (mystrncasecmp(readvalue,"Standard",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_STANDARD; + } else if (mystrncasecmp(readvalue,"Special",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_SPECIAL; + } else if (mystrncasecmp(readvalue,"Ascending",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_ASCENDING; + } else if (mystrncasecmp(readvalue,"Personal",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_MESSAGE_PERSONAL; + } else if (mystrncasecmp(readvalue,"VibrateFirst",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VIBRATION_FIRST; + } else if (mystrncasecmp(readvalue,"Auto",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_LIGHTS_AUTO; + } else if (mystrncasecmp(readvalue,"5Seconds",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_5SEC; + } else if (mystrncasecmp(readvalue,"20Seconds",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_20SEC; + } else if (mystrncasecmp(readvalue,"1Minute",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_1MIN; + } else if (mystrncasecmp(readvalue,"2Minutes",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_2MIN; + } else if (mystrncasecmp(readvalue,"5Minutes",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_5MIN; + } else if (mystrncasecmp(readvalue,"10Minutes",0)) { + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_TIMEOUT_10MIN; + } else if (mystrncasecmp(readvalue,"On",0)) { + switch (Profile->FeatureID[Profile->FeaturesNumber]) { + case Profile_AutoAnswer: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_AUTOANSWER_ON; + break; + case Profile_WarningTone: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_WARNING_ON; + break; + case Profile_ScreenSaver: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_SAVER_ON; + break; + default: + Profile->FeatureValue[Profile->FeaturesNumber]=PROFILE_VIBRATION_ON; + break; + } + } else unknown = true; + } + if (!unknown) Profile->FeaturesNumber++; + } + } +} + +static void ReadFMStationEntry(INI_Section *file_info, char *section, GSM_FMStation *FMStation, bool UseUnicode) +{ + unsigned char buffer[10000], *readvalue; + + FMStation->Location = 0; + FMStation->Frequency = 0; + + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) FMStation->Location = atoi(readvalue); + + sprintf(buffer,"StationName"); + ReadBackupText(file_info, section, buffer, FMStation->StationName,UseUnicode); + + sprintf(buffer,"Frequency"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) StringToDouble(readvalue, &FMStation->Frequency); +} + +static void ReadGPRSPointEntry(INI_Section *file_info, char *section, GSM_GPRSAccessPoint *GPRSPoint, bool UseUnicode) +{ + unsigned char buffer[10000], *readvalue; + + GPRSPoint->Name[0] = 0; + GPRSPoint->Name[1] = 0; + GPRSPoint->URL[0] = 0; + GPRSPoint->URL[1] = 0; + GPRSPoint->Location = 0; + + GPRSPoint->Active = false; + sprintf(buffer,"Active"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Yes",0)) GPRSPoint->Active = true; + } + + sprintf(buffer,"Location"); + readvalue = ReadCFGText(file_info, section, buffer, UseUnicode); + if (readvalue!=NULL) GPRSPoint->Location = atoi(readvalue); + + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, GPRSPoint->Name,UseUnicode); + + sprintf(buffer,"URL"); + ReadBackupText(file_info, section, buffer, GPRSPoint->URL,UseUnicode); +} + +static void ReadNoteEntry(INI_Section *file_info, char *section, GSM_NoteEntry *Note, bool UseUnicode) +{ + unsigned char buffer[100]; + + sprintf(buffer,"Text"); + ReadBackupText(file_info, section, buffer, Note->Text,UseUnicode); +} + +GSM_Error LoadBackup(char *FileName, GSM_Backup *backup, bool UseUnicode) +{ + INI_Section *file_info, *h; + char buffer[100], *readvalue; + int num; + GSM_MemoryEntry PBK; + bool found; + + file_info = INI_ReadFile(FileName, UseUnicode); + + sprintf(buffer,"Backup"); + if (UseUnicode) EncodeUnicode(buffer,"Backup",6); + + readvalue = ReadCFGText(file_info, buffer, "Format", UseUnicode); + /* Did we read anything? */ + if (readvalue == NULL) return ERR_FILENOTSUPPORTED; + /* Is this format version supported ? */ + if (strcmp(readvalue,"1.01")!=0 && strcmp(readvalue,"1.02")!=0 && + strcmp(readvalue,"1.03")!=0) return ERR_FILENOTSUPPORTED; + + readvalue = ReadCFGText(file_info, buffer, "IMEI", UseUnicode); + if (readvalue!=NULL) strcpy(backup->IMEI,readvalue); + readvalue = ReadCFGText(file_info, buffer, "Phone", UseUnicode); + if (readvalue!=NULL) strcpy(backup->Model,readvalue); + readvalue = ReadCFGText(file_info, buffer, "Creator", UseUnicode); + if (readvalue!=NULL) strcpy(backup->Creator,readvalue); + readvalue = ReadCFGText(file_info, buffer, "DateTime", UseUnicode); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, &backup->DateTime); + backup->DateTimeAvailable = true; + } + + sprintf(buffer,"Checksum"); + if (UseUnicode) EncodeUnicode(buffer,"Checksum",8); + readvalue = ReadCFGText(file_info, buffer, "MD5", UseUnicode); + if (readvalue!=NULL) strcpy(backup->MD5Original,readvalue); + + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"Profile",7); + if (mywstrncasecmp(buffer, h->SectionName, 7)) found = true; + } else { + if (mystrncasecmp("Profile", h->SectionName, 7)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_PROFILES) { + backup->Profiles[num] = malloc(sizeof(GSM_Profile)); + if (backup->Profiles[num] == NULL) return ERR_MOREMEMORY; + backup->Profiles[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_PROFILES\n"); + return ERR_MOREMEMORY; + } + ReadProfileEntry(file_info, h->SectionName, backup->Profiles[num], UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"PhonePBK",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } else { + if (mystrncasecmp("PhonePBK", h->SectionName, 8)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_PHONEPHONEBOOK) { + backup->PhonePhonebook[num] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->PhonePhonebook[num] == NULL) return ERR_MOREMEMORY; + backup->PhonePhonebook[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_PHONEPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + backup->PhonePhonebook[num]->Location = atoi (readvalue); + backup->PhonePhonebook[num]->MemoryType = MEM_ME; + ReadPbkEntry(file_info, h->SectionName, backup->PhonePhonebook[num],UseUnicode); + dbgprintf("number of entries = %i\n",backup->PhonePhonebook[num]->EntriesNum); + num++; + } + } + num = 0; + while (0) { + if (backup->PhonePhonebook[num] == NULL) break; + if (backup->PhonePhonebook[num+1] != NULL) { + if (backup->PhonePhonebook[num+1]->Location < backup->PhonePhonebook[num]->Location) { + memcpy(&PBK,backup->PhonePhonebook[num+1],sizeof(GSM_MemoryEntry)); + memcpy(backup->PhonePhonebook[num+1],backup->PhonePhonebook[num],sizeof(GSM_MemoryEntry)); + memcpy(backup->PhonePhonebook[num],&PBK,sizeof(GSM_MemoryEntry)); + num = 0; + continue; + } + } + num++; + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"SIMPBK",6); + if (mywstrncasecmp(buffer, h->SectionName, 6)) found = true; + } else { + if (mystrncasecmp("SIMPBK", h->SectionName, 6)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_SIMPHONEBOOK) { + backup->SIMPhonebook[num] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->SIMPhonebook[num] == NULL) return ERR_MOREMEMORY; + backup->SIMPhonebook[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_SIMPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + backup->SIMPhonebook[num]->Location = atoi (readvalue); + backup->SIMPhonebook[num]->MemoryType = MEM_SM; + ReadPbkEntry(file_info, h->SectionName, backup->SIMPhonebook[num],UseUnicode); + num++; + } + } + num = 0; + while (0) { + if (backup->SIMPhonebook[num] == NULL) break; + if (backup->SIMPhonebook[num+1] != NULL) { + if (backup->SIMPhonebook[num+1]->Location < backup->SIMPhonebook[num]->Location) { + memcpy(&PBK,backup->SIMPhonebook[num+1],sizeof(GSM_MemoryEntry)); + memcpy(backup->SIMPhonebook[num+1],backup->SIMPhonebook[num],sizeof(GSM_MemoryEntry)); + memcpy(backup->SIMPhonebook[num],&PBK,sizeof(GSM_MemoryEntry)); + num = 0; + continue; + } + } + num++; + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"Calendar",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } else { + if (mystrncasecmp("Calendar", h->SectionName, 8)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Type", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_MAXCALENDARTODONOTES) { + backup->Calendar[num] = malloc(sizeof(GSM_CalendarEntry)); + if (backup->Calendar[num] == NULL) return ERR_MOREMEMORY; + backup->Calendar[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_MAXCALENDARTODONOTES\n"); + return ERR_MOREMEMORY; + } + backup->Calendar[num]->Location = num + 1; + ReadCalendarEntry(file_info, h->SectionName, backup->Calendar[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"Caller",6); + if (mywstrncasecmp(buffer, h->SectionName, 6)) found = true; + } else { + if (mystrncasecmp("Caller", h->SectionName, 6)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_CALLER) { + backup->CallerLogos[num] = malloc(sizeof(GSM_Bitmap)); + if (backup->CallerLogos[num] == NULL) return ERR_MOREMEMORY; + backup->CallerLogos[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_CALLER\n"); + return ERR_MOREMEMORY; + } + backup->CallerLogos[num]->Location = atoi (readvalue); + ReadCallerEntry(file_info, h->SectionName, backup->CallerLogos[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"SMSC",4); + if (mywstrncasecmp(buffer, h->SectionName, 4)) found = true; + } else { + if (mystrncasecmp("SMSC", h->SectionName, 4)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_SMSC) { + backup->SMSC[num] = malloc(sizeof(GSM_SMSC)); + if (backup->SMSC[num] == NULL) return ERR_MOREMEMORY; + backup->SMSC[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_SMSC\n"); + return ERR_MOREMEMORY; + } + backup->SMSC[num]->Location = atoi (readvalue); + ReadSMSCEntry(file_info, h->SectionName, backup->SMSC[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"WAPBookmark",11); + if (mywstrncasecmp(buffer, h->SectionName, 11)) found = true; + if (!found) { + EncodeUnicode(buffer,"Bookmark",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } + } else { + if (mystrncasecmp("WAPBookmark", h->SectionName, 11)) found = true; + if (!found) { + if (mystrncasecmp("Bookmark", h->SectionName, 8)) found = true; + } + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "URL", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_WAPBOOKMARK) { + backup->WAPBookmark[num] = malloc(sizeof(GSM_WAPBookmark)); + if (backup->WAPBookmark[num] == NULL) return ERR_MOREMEMORY; + backup->WAPBookmark[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_WAPBOOKMARK\n"); + return ERR_MOREMEMORY; + } + backup->WAPBookmark[num]->Location = num + 1; + ReadWAPBookmarkEntry(file_info, h->SectionName, backup->WAPBookmark[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"WAPSettings",11); + if (mywstrncasecmp(buffer, h->SectionName, 11)) found = true; + if (!found) { + EncodeUnicode(buffer,"Settings",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } + } else { + if (mystrncasecmp("WAPSettings", h->SectionName, 11)) found = true; + if (!found) { + if (mystrncasecmp("Settings", h->SectionName, 8)) found = true; + } + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Title00", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_WAPSETTINGS) { + backup->WAPSettings[num] = malloc(sizeof(GSM_MultiWAPSettings)); + if (backup->WAPSettings[num] == NULL) return ERR_MOREMEMORY; + backup->WAPSettings[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_WAPSETTINGS\n"); + return ERR_MOREMEMORY; + } + backup->WAPSettings[num]->Location = num + 1; + dbgprintf("reading wap settings\n"); + ReadWAPSettingsEntry(file_info, h->SectionName, backup->WAPSettings[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"MMSSettings",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } else { + if (mystrncasecmp("MMSSettings", h->SectionName, 8)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Title00", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_MMSSETTINGS) { + backup->MMSSettings[num] = malloc(sizeof(GSM_MultiWAPSettings)); + if (backup->MMSSettings[num] == NULL) return ERR_MOREMEMORY; + backup->MMSSettings[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_MMSSETTINGS\n"); + return ERR_MOREMEMORY; + } + backup->MMSSettings[num]->Location = num + 1; + dbgprintf("reading mms settings\n"); + ReadWAPSettingsEntry(file_info, h->SectionName, backup->MMSSettings[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"Ringtone",8); + if (mywstrncasecmp(buffer, h->SectionName, 8)) found = true; + } else { + if (mystrncasecmp("Ringtone", h->SectionName, 8)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_RINGTONES) { + backup->Ringtone[num] = malloc(sizeof(GSM_Ringtone)); + if (backup->Ringtone[num] == NULL) return ERR_MOREMEMORY; + backup->Ringtone[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_RINGTONES\n"); + return ERR_MOREMEMORY; + } + ReadRingtoneEntry(file_info, h->SectionName, backup->Ringtone[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"TODO",4); + if (mywstrncasecmp(buffer, h->SectionName, 4)) found = true; + } else { + if (mystrncasecmp("TODO", h->SectionName, 4)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_MAXCALENDARTODONOTES) { + backup->ToDo[num] = malloc(sizeof(GSM_ToDoEntry)); + if (backup->ToDo[num] == NULL) return ERR_MOREMEMORY; + backup->ToDo[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_MAXCALENDARTODONOTES\n"); + return ERR_MOREMEMORY; + } + backup->ToDo[num]->Location = num + 1; + ReadToDoEntry(file_info, h->SectionName, backup->ToDo[num],UseUnicode); + num++; + } + } + sprintf(buffer,"Startup"); + readvalue = ReadCFGText(file_info, buffer, "Text", UseUnicode); + if (readvalue==NULL) { + readvalue = ReadCFGText(file_info, buffer, "Width", UseUnicode); + } + if (readvalue!=NULL) { + backup->StartupLogo = malloc(sizeof(GSM_Bitmap)); + if (backup->StartupLogo == NULL) return ERR_MOREMEMORY; + ReadStartupEntry(file_info, buffer, backup->StartupLogo,UseUnicode); + } + sprintf(buffer,"Operator"); + readvalue = ReadCFGText(file_info, buffer, "Network", UseUnicode); + if (readvalue!=NULL) { + backup->OperatorLogo = malloc(sizeof(GSM_Bitmap)); + if (backup->OperatorLogo == NULL) return ERR_MOREMEMORY; + ReadOperatorEntry(file_info, buffer, backup->OperatorLogo,UseUnicode); + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"FMStation",9); + if (mywstrncasecmp(buffer, h->SectionName, 9)) found = true; + } else { + if (mystrncasecmp("FMStation", h->SectionName, 9)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_FMSTATIONS) { + backup->FMStation[num] = malloc(sizeof(GSM_FMStation)); + if (backup->FMStation[num] == NULL) return ERR_MOREMEMORY; + backup->FMStation[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_FMSTATIONS\n"); + return ERR_MOREMEMORY; + } + backup->FMStation[num]->Location = num + 1; + ReadFMStationEntry(file_info, h->SectionName, backup->FMStation[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"GPRSPoint",9); + if (mywstrncasecmp(buffer, h->SectionName, 9)) found = true; + } else { + if (mystrncasecmp("GPRSPoint", h->SectionName, 9)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Location", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_GPRSPOINT) { + backup->GPRSPoint[num] = malloc(sizeof(GSM_GPRSAccessPoint)); + if (backup->GPRSPoint[num] == NULL) return ERR_MOREMEMORY; + backup->GPRSPoint[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_GPRSPOINT\n"); + return ERR_MOREMEMORY; + } + backup->GPRSPoint[num]->Location = num + 1; + ReadGPRSPointEntry(file_info, h->SectionName, backup->GPRSPoint[num],UseUnicode); + num++; + } + } + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + found = false; + if (UseUnicode) { + EncodeUnicode(buffer,"Note",4); + if (mywstrncasecmp(buffer, h->SectionName, 4)) found = true; + } else { + if (mystrncasecmp("Note", h->SectionName, 4)) found = true; + } + if (found) { + readvalue = ReadCFGText(file_info, h->SectionName, "Text", UseUnicode); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_NOTE) { + backup->Note[num] = malloc(sizeof(GSM_NoteEntry)); + if (backup->Note[num] == NULL) return ERR_MOREMEMORY; + backup->Note[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_NOTE\n"); + return ERR_MOREMEMORY; + } + ReadNoteEntry(file_info, h->SectionName, backup->Note[num],UseUnicode); + num++; + } + } + if (backup->MD5Original[0]!=0) { + FindBackupChecksum(FileName, UseUnicode, backup->MD5Calculated); + } + + return ERR_NONE; +} + +/* ---------------------- backup files for SMS ----------------------------- */ + +static void ReadSMSBackupEntry(INI_Section *file_info, char *section, GSM_SMSMessage *SMS) +{ + unsigned char buffer[10000], *readvalue; + + GSM_SetDefaultSMSData(SMS); + + SMS->PDU = SMS_Submit; + SMS->SMSC.Location = 0; + sprintf(buffer,"SMSC"); + ReadBackupText(file_info, section, buffer, SMS->SMSC.Number, false); + sprintf(buffer,"ReplySMSC"); + SMS->ReplyViaSameSMSC = false; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"True",0)) SMS->ReplyViaSameSMSC = true; + } + sprintf(buffer,"Class"); + SMS->Class = -1; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) SMS->Class = atoi(readvalue); + sprintf(buffer,"Sent"); + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + ReadVCALDateTime(readvalue, &SMS->DateTime); + SMS->PDU = SMS_Deliver; + } + sprintf(buffer,"RejectDuplicates"); + SMS->RejectDuplicates = false; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"True",0)) SMS->RejectDuplicates = true; + } + sprintf(buffer,"ReplaceMessage"); + SMS->ReplaceMessage = 0; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) SMS->ReplaceMessage = atoi(readvalue); + sprintf(buffer,"MessageReference"); + SMS->MessageReference = 0; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) SMS->MessageReference = atoi(readvalue); + sprintf(buffer,"State"); + SMS->State = SMS_UnRead; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Read",0)) SMS->State = SMS_Read; + else if (mystrncasecmp(readvalue,"Sent",0)) SMS->State = SMS_Sent; + else if (mystrncasecmp(readvalue,"UnSent",0)) SMS->State = SMS_UnSent; + } + sprintf(buffer,"Number"); + ReadBackupText(file_info, section, buffer, SMS->Number, false); + sprintf(buffer,"Name"); + ReadBackupText(file_info, section, buffer, SMS->Name, false); + sprintf(buffer,"Length"); + SMS->Length = 0; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) SMS->Length = atoi(readvalue); + sprintf(buffer,"Coding"); + SMS->Coding = SMS_Coding_Default; + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + if (mystrncasecmp(readvalue,"Unicode",0)) { + SMS->Coding = SMS_Coding_Unicode; + } else if (mystrncasecmp(readvalue,"8bit",0)) { + SMS->Coding = SMS_Coding_8bit; + } + } + ReadLinkedBackupText(file_info, section, "Text", buffer, false); + DecodeHexBin (SMS->Text, buffer, strlen(buffer)); + SMS->Text[strlen(buffer)/2] = 0; + SMS->Text[strlen(buffer)/2+1] = 0; + sprintf(buffer,"Folder"); + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) SMS->Folder = atoi(readvalue); + SMS->UDH.Type = UDH_NoUDH; + SMS->UDH.Length = 0; + SMS->UDH.ID8bit = -1; + SMS->UDH.ID16bit = -1; + SMS->UDH.PartNumber = -1; + SMS->UDH.AllParts = -1; + sprintf(buffer,"UDH"); + readvalue = ReadCFGText(file_info, section, buffer, false); + if (readvalue!=NULL) { + DecodeHexBin (SMS->UDH.Text, readvalue, strlen(readvalue)); + SMS->UDH.Length = strlen(readvalue)/2; + GSM_DecodeUDHHeader(&SMS->UDH); + } +} + +static GSM_Error GSM_ReadSMSBackupTextFile(char *FileName, GSM_SMS_Backup *backup) +{ + INI_Section *file_info, *h; + char *readvalue; + int num; + + backup->SMS[0] = NULL; + + file_info = INI_ReadFile(FileName, false); + + num = 0; + for (h = file_info; h != NULL; h = h->Next) { + if (mystrncasecmp("SMSBackup", h->SectionName, 9)) { + readvalue = ReadCFGText(file_info, h->SectionName, "Number", false); + if (readvalue==NULL) break; + if (num < GSM_BACKUP_MAX_SMS) { + backup->SMS[num] = malloc(sizeof(GSM_SMSMessage)); + if (backup->SMS[num] == NULL) return ERR_MOREMEMORY; + backup->SMS[num + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_SMS\n"); + return ERR_MOREMEMORY; + } + backup->SMS[num]->Location = num + 1; + ReadSMSBackupEntry(file_info, h->SectionName, backup->SMS[num]); + num++; + } + } + return ERR_NONE; +} + +GSM_Error GSM_ReadSMSBackupFile(char *FileName, GSM_SMS_Backup *backup) +{ + FILE *file; + + backup->SMS[0] = NULL; + + file = fopen(FileName, "rb"); + if (file == NULL) return(ERR_CANTOPENFILE); + + fclose(file); + + return GSM_ReadSMSBackupTextFile(FileName, backup); +} + +GSM_Error SaveSMSBackupTextFile(FILE *file, GSM_SMS_Backup *backup) +{ + int i,w,current; + unsigned char buffer[10000]; + GSM_DateTime DT; + + fprintf(file,"\n# File created by Gammu (www.mwiacek.com) version %s\n",VERSION); + GSM_GetCurrentDateTime (&DT); + fprintf(file,"# Saved %s\n\n",OSDateTime(DT,false)); + + i=0; + while (backup->SMS[i]!=NULL) { + fprintf(file,"[SMSBackup%03i]\n",i); + switch (backup->SMS[i]->Coding) { + case SMS_Coding_Unicode: + case SMS_Coding_Default: + sprintf(buffer,"%s",DecodeUnicodeString(backup->SMS[i]->Text)); + fprintf(file,"#"); + current = 0; + for (w=0;w<(int)(strlen(buffer));w++) { + switch (buffer[w]) { + case 10: + fprintf(file,"\n#"); + current = 0; + break; + case 13: + break; + default: + if (isprint(buffer[w])) { + fprintf(file,"%c",buffer[w]); + current ++; + } + if (current == 75) { + fprintf(file,"\n#"); + current = 0; + } + } + } + fprintf(file,"\n"); + break; + default: + break; + } + if (backup->SMS[i]->PDU == SMS_Deliver) { + SaveBackupText(file, "SMSC", backup->SMS[i]->SMSC.Number, false); + if (backup->SMS[i]->ReplyViaSameSMSC) fprintf(file,"SMSCReply = true\n"); + fprintf(file,"Sent"); + SaveVCalDateTime(file,&backup->SMS[i]->DateTime, false); + } + fprintf(file,"State = "); + switch (backup->SMS[i]->State) { + case SMS_UnRead : fprintf(file,"UnRead\n"); break; + case SMS_Read : fprintf(file,"Read\n"); break; + case SMS_Sent : fprintf(file,"Sent\n"); break; + case SMS_UnSent : fprintf(file,"UnSent\n"); break; + } + SaveBackupText(file, "Number", backup->SMS[i]->Number, false); + SaveBackupText(file, "Name", backup->SMS[i]->Name, false); + if (backup->SMS[i]->UDH.Type != UDH_NoUDH) { + EncodeHexBin(buffer,backup->SMS[i]->UDH.Text,backup->SMS[i]->UDH.Length); + fprintf(file,"UDH = %s\n",buffer); + } + switch (backup->SMS[i]->Coding) { + case SMS_Coding_Unicode: + case SMS_Coding_Default: + EncodeHexBin(buffer,backup->SMS[i]->Text,backup->SMS[i]->Length*2); + break; + default: + EncodeHexBin(buffer,backup->SMS[i]->Text,backup->SMS[i]->Length); + break; + } + SaveLinkedBackupText(file, "Text", buffer, false); + switch (backup->SMS[i]->Coding) { + case SMS_Coding_Unicode : fprintf(file,"Coding = Unicode\n"); break; + case SMS_Coding_Default : fprintf(file,"Coding = Default\n"); break; + case SMS_Coding_8bit : fprintf(file,"Coding = 8bit\n"); break; + } + fprintf(file,"Folder = %i\n",backup->SMS[i]->Folder); + fprintf(file,"Length = %i\n",backup->SMS[i]->Length); + fprintf(file,"Class = %i\n",backup->SMS[i]->Class); + fprintf(file,"ReplySMSC = "); + if (backup->SMS[i]->ReplyViaSameSMSC) fprintf(file,"True\n"); else fprintf(file,"False\n"); + fprintf(file,"RejectDuplicates = "); + if (backup->SMS[i]->RejectDuplicates) fprintf(file,"True\n"); else fprintf(file,"False\n"); + fprintf(file,"ReplaceMessage = %i\n",backup->SMS[i]->ReplaceMessage); + fprintf(file,"MessageReference = %i\n",backup->SMS[i]->MessageReference); + fprintf(file,"\n"); + i++; + } + return ERR_NONE; +} + +GSM_Error GSM_SaveSMSBackupFile(char *FileName, GSM_SMS_Backup *backup) +{ + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return(ERR_CANTOPENFILE); + + SaveSMSBackupTextFile(file,backup); + + fclose(file); + + return ERR_NONE; +} + +#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/service/backup/backtext.h b/gammu/emb/common/service/backup/backtext.h new file mode 100644 index 0000000..a95bd89 --- a/dev/null +++ b/gammu/emb/common/service/backup/backtext.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backtext_h +#define __gsm_backtext_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error LoadBackup(char *FileName, GSM_Backup *backup, bool UseUnicode); +GSM_Error SaveBackup(char *FileName, GSM_Backup *backup, bool UseUnicode); +#endif + +#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/service/backup/backvcf.c b/gammu/emb/common/service/backup/backvcf.c new file mode 100644 index 0000000..761a81b --- a/dev/null +++ b/gammu/emb/common/service/backup/backvcf.c @@ -0,0 +1,75 @@ +/* (c) 2003 by Marcin Wiacek */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backvcf.h" + +#ifdef GSM_ENABLE_BACKUP + +GSM_Error SaveVCard(char *FileName, GSM_Backup *backup) +{ + int i, Length = 0; + unsigned char Buffer[1000]; + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + i=0; + while (backup->PhonePhonebook[i]!=NULL) { + sprintf(Buffer, "%c%c",13,10); + fwrite(Buffer,1,2,file); + Length = 0; + GSM_EncodeVCARD(Buffer,&Length,backup->PhonePhonebook[i],true,Nokia_VCard21); + fwrite(Buffer,1,Length,file); + i++; + } + + fclose(file); + return ERR_NONE; +} + +GSM_Error LoadVCard(char *FileName, GSM_Backup *backup) +{ + GSM_File File; + GSM_Error error; + GSM_MemoryEntry Pbk; + int numPbk = 0, Pos; + + File.Buffer = NULL; + error = GSM_ReadFile(FileName, &File); + if (error != ERR_NONE) return error; + + Pos = 0; + while (1) { + error = GSM_DecodeVCARD(File.Buffer, &Pos, &Pbk, Nokia_VCard21); + if (error == ERR_EMPTY) break; + if (error != ERR_NONE) return error; + if (numPbk < GSM_BACKUP_MAX_PHONEPHONEBOOK) { + backup->PhonePhonebook[numPbk] = malloc(sizeof(GSM_MemoryEntry)); + if (backup->PhonePhonebook[numPbk] == NULL) return ERR_MOREMEMORY; + backup->PhonePhonebook[numPbk + 1] = NULL; + } else { + dbgprintf("Increase GSM_BACKUP_MAX_PHONEPHONEBOOK\n"); + return ERR_MOREMEMORY; + } + memcpy(backup->PhonePhonebook[numPbk],&Pbk,sizeof(GSM_MemoryEntry)); + backup->PhonePhonebook[numPbk]->Location = numPbk + 1; + backup->PhonePhonebook[numPbk]->MemoryType = MEM_ME; + numPbk++; + } + + return ERR_NONE; +} + +#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/service/backup/backvcf.h b/gammu/emb/common/service/backup/backvcf.h new file mode 100644 index 0000000..8cbb6cf --- a/dev/null +++ b/gammu/emb/common/service/backup/backvcf.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backvcf_h +#define __gsm_backvcf_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error SaveVCard(char *FileName, GSM_Backup *backup); +GSM_Error LoadVCard(char *FileName, GSM_Backup *backup); +#endif + +#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/service/backup/backvcs.c b/gammu/emb/common/service/backup/backvcs.c new file mode 100644 index 0000000..332e718 --- a/dev/null +++ b/gammu/emb/common/service/backup/backvcs.c @@ -0,0 +1,106 @@ +/* (c) 2003 by Marcin Wiacek */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "backvcs.h" + +#ifdef GSM_ENABLE_BACKUP + +GSM_Error SaveVCalendar(char *FileName, GSM_Backup *backup) +{ + int i, Length = 0; + unsigned char Buffer[1000]; + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + Length=sprintf(Buffer, "BEGIN:VCALENDAR%c%c",13,10); + Length+=sprintf(Buffer+Length, "VERSION:1.0%c%c",13,10); + fwrite(Buffer,1,Length,file); + + i=0; + while (backup->Calendar[i]!=NULL) { + sprintf(Buffer, "%c%c",13,10); + fwrite(Buffer,1,2,file); + Length = 0; + GSM_EncodeVCALENDAR(Buffer,&Length,backup->Calendar[i],false,Nokia_VCalendar); + fwrite(Buffer,1,Length,file); + i++; + } + i=0; + while (backup->ToDo[i]!=NULL) { + sprintf(Buffer, "%c%c",13,10); + fwrite(Buffer,1,2,file); + Length = 0; + GSM_EncodeVTODO(Buffer,&Length,backup->ToDo[i],false,Nokia_VToDo); + fwrite(Buffer,1,Length,file); + i++; + } + + Length=sprintf(Buffer, "%c%cEND:VCALENDAR%c%c",13,10,13,10); + fwrite(Buffer,1,Length,file); + + fclose(file); + return ERR_NONE; +} + +GSM_Error LoadVCalendar(char *FileName, GSM_Backup *backup) +{ + GSM_File File; + GSM_Error error; + GSM_CalendarEntry Calendar; + GSM_ToDoEntry ToDo; + int numCal = 0, numToDo = 0, Pos; + + File.Buffer = NULL; + error = GSM_ReadFile(FileName, &File); + if (error != ERR_NONE) return error; + + Pos = 0; + while (1) { + error = GSM_DecodeVCALENDAR_VTODO(File.Buffer, &Pos, &Calendar, &ToDo, Nokia_VCalendar, Nokia_VToDo); + if (error == ERR_EMPTY) break; + if (error != ERR_NONE) return error; + if (Calendar.EntriesNum != 0) { + if (numCal < GSM_MAXCALENDARTODONOTES) { + backup->Calendar[numCal] = malloc(sizeof(GSM_CalendarEntry)); + if (backup->Calendar[numCal] == NULL) return ERR_MOREMEMORY; + backup->Calendar[numCal + 1] = NULL; + } else { + dbgprintf("Increase GSM_MAXCALENDARTODONOTES\n"); + return ERR_MOREMEMORY; + } + memcpy(backup->Calendar[numCal],&Calendar,sizeof(GSM_CalendarEntry)); + backup->Calendar[numCal]->Location = numCal + 1; + numCal++; + } + if (ToDo.EntriesNum != 0) { + if (numToDo < GSM_MAXCALENDARTODONOTES) { + backup->ToDo[numToDo] = malloc(sizeof(GSM_ToDoEntry)); + if (backup->ToDo[numToDo] == NULL) return ERR_MOREMEMORY; + backup->ToDo[numToDo + 1] = NULL; + } else { + dbgprintf("Increase GSM_MAXCALENDARTODONOTES\n"); + return ERR_MOREMEMORY; + } + memcpy(backup->ToDo[numToDo],&ToDo,sizeof(GSM_ToDoEntry)); + backup->ToDo[numToDo]->Location = numToDo + 1; + numToDo++; + } + } + + return ERR_NONE; +} + +#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/service/backup/backvcs.h b/gammu/emb/common/service/backup/backvcs.h new file mode 100644 index 0000000..f3331b5 --- a/dev/null +++ b/gammu/emb/common/service/backup/backvcs.h @@ -0,0 +1,17 @@ +/* (c) 2003 by Marcin Wiacek */ + +#ifndef __gsm_backvcs_h +#define __gsm_backvcs_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP +GSM_Error SaveVCalendar(char *FileName, GSM_Backup *backup); +GSM_Error LoadVCalendar(char *FileName, GSM_Backup *backup); +#endif + +#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/service/backup/gsmback.c b/gammu/emb/common/service/backup/gsmback.c new file mode 100644 index 0000000..91ac745 --- a/dev/null +++ b/gammu/emb/common/service/backup/gsmback.c @@ -0,0 +1,280 @@ +/* (c) 2002-2004 by Marcin Wiacek & Michal Cihar */ + +#include <string.h> +#include <ctype.h> + +#include "../../phone/nokia/nfunc.h" +#include "../../phone/nokia/dct3/n7110.h" +#include "../../misc/coding/coding.h" +#include "../../misc/cfg.h" +#include "../gsmlogo.h" +#include "../gsmmisc.h" +#include "../gsmcal.h" +#include "gsmback.h" +#include "backtext.h" +#include "backldif.h" +#include "backlmb.h" +#include "backvcs.h" +#include "backvcf.h" +#include "backics.h" + +#ifdef GSM_ENABLE_BACKUP + +void GSM_FreeBackup(GSM_Backup *backup) +{ + int i; + + i=0; + while (backup->PhonePhonebook[i]!=NULL) { + free(backup->PhonePhonebook[i]); + backup->PhonePhonebook[i] = NULL; + i++; + } + i=0; + while (backup->SIMPhonebook[i]!=NULL) { + free(backup->SIMPhonebook[i]); + backup->SIMPhonebook[i] = NULL; + i++; + } + i=0; + while (backup->Calendar[i]!=NULL) { + free(backup->Calendar[i]); + backup->Calendar[i] = NULL; + i++; + } + i=0; + while (backup->CallerLogos[i]!=NULL) { + free(backup->CallerLogos[i]); + backup->CallerLogos[i] = NULL; + i++; + } + i=0; + while (backup->SMSC[i]!=NULL) { + free(backup->SMSC[i]); + backup->SMSC[i] = NULL; + i++; + } + i=0; + while (backup->WAPBookmark[i]!=NULL) { + free(backup->WAPBookmark[i]); + backup->WAPBookmark[i] = NULL; + i++; + } + i=0; + while (backup->WAPSettings[i]!=NULL) { + free(backup->WAPSettings[i]); + backup->WAPSettings[i] = NULL; + i++; + } + i=0; + while (backup->MMSSettings[i]!=NULL) { + free(backup->MMSSettings[i]); + backup->MMSSettings[i] = NULL; + i++; + } + i=0; + while (backup->Ringtone[i]!=NULL) { + free(backup->Ringtone[i]); + backup->Ringtone[i] = NULL; + i++; + } + i=0; + while (backup->ToDo[i]!=NULL) { + free(backup->ToDo[i]); + backup->ToDo[i] = NULL; + i++; + } + i=0; + while (backup->Profiles[i]!=NULL) { + free(backup->Profiles[i]); + backup->Profiles[i] = NULL; + i++; + } + i=0; + while (backup->FMStation[i]!=NULL) { + free(backup->FMStation[i]); + backup->FMStation[i] = NULL; + i++; + } + if (backup->StartupLogo!=NULL) { + free(backup->StartupLogo); + backup->StartupLogo = NULL; + } + if (backup->OperatorLogo!=NULL) { + free(backup->OperatorLogo); + backup->OperatorLogo = NULL; + } + i=0; + while (backup->GPRSPoint[i]!=NULL) { + free(backup->GPRSPoint[i]); + backup->GPRSPoint[i] = NULL; + i++; + } + i=0; + while (backup->Note[i]!=NULL) { + free(backup->Note[i]); + backup->Note[i] = NULL; + i++; + } +} + +GSM_Error GSM_SaveBackupFile(char *FileName, GSM_Backup *backup, bool UseUnicode) +{ + if (strstr(FileName,".lmb")) { + return SaveLMB(FileName,backup); + } else if (strstr(FileName,".vcs")) { + return SaveVCalendar(FileName,backup); + } else if (strstr(FileName,".vcf")) { + return SaveVCard(FileName,backup); + } else if (strstr(FileName,".ldif")) { + return SaveLDIF(FileName,backup); + } else if (strstr(FileName,".ics")) { + return SaveICS(FileName,backup); + } else { + return SaveBackup(FileName,backup, UseUnicode); + } +} + +GSM_Error GSM_ReadBackupFile(char *FileName, GSM_Backup *backup) +{ + FILE *file; + unsigned char buffer[300]; + + file = fopen(FileName, "rb"); + if (file == NULL) return ERR_CANTOPENFILE; + fread(buffer, 1, 9, file); /* Read the header of the file. */ + fclose(file); + + GSM_ClearBackup(backup); + + /* Attempt to identify filetype */ + if (strstr(FileName,".vcs")) { + return LoadVCalendar(FileName,backup); + } else if (strstr(FileName,".vcf")) { + return LoadVCard(FileName,backup); + } else if (strstr(FileName,".ldif")) { + return LoadLDIF(FileName,backup); + } else if (strstr(FileName,".ics")) { + return LoadICS(FileName,backup); + } else if (memcmp(buffer, "LMB ",4)==0) { + return LoadLMB(FileName,backup); + } else if (buffer[0] == 0xFE && buffer[1] == 0xFF) { + return LoadBackup(FileName,backup,true); + } else if (buffer[0] == 0xFF && buffer[1] == 0xFE) { + return LoadBackup(FileName,backup,true); + } else { + return LoadBackup(FileName,backup,false); + } +} + +void GSM_ClearBackup(GSM_Backup *backup) +{ + backup->PhonePhonebook [0] = NULL; + backup->SIMPhonebook [0] = NULL; + backup->Calendar [0] = NULL; + backup->CallerLogos [0] = NULL; + backup->SMSC [0] = NULL; + backup->WAPBookmark [0] = NULL; + backup->WAPSettings [0] = NULL; + backup->MMSSettings [0] = NULL; + backup->Ringtone [0] = NULL; + backup->Profiles [0] = NULL; + backup->ToDo [0] = NULL; + backup->GPRSPoint [0] = NULL; + backup->FMStation [0] = NULL; + backup->Note [0] = NULL; + backup->StartupLogo = NULL; + backup->OperatorLogo = NULL; + + backup->Creator [0] = 0; + backup->IMEI [0] = 0; + backup->Model [0] = 0; + backup->DateTimeAvailable = false; + backup->MD5Original [0] = 0; + backup->MD5Calculated [0] = 0; +} + +void GSM_GetBackupFormatFeatures(char *FileName, GSM_Backup_Info *info) +{ + info->UseUnicode = false; + info->IMEI = false; + info->Model = false; + info->DateTime = false; + info->PhonePhonebook = false; + info->SIMPhonebook = false; + info->ToDo = false; + info->Calendar = false; + info->CallerLogos = false; + info->SMSC = false; + info->WAPBookmark = false; + info->WAPSettings = false; + info->MMSSettings = false; + info->Ringtone = false; + info->StartupLogo = false; + info->OperatorLogo = false; + info->Profiles = false; + info->FMStation = false; + info->GPRSPoint = false; + info->Note = false; + + if (strstr(FileName,".lmb")) { + info->PhonePhonebook = true; + info->SIMPhonebook = true; + info->CallerLogos = true; + info->StartupLogo = true; + } else if (strstr(FileName,".vcs")) { + info->ToDo = true; + info->Calendar = true; + } else if (strstr(FileName,".vcf")) { + info->PhonePhonebook = true; + } else if (strstr(FileName,".ics")) { + info->ToDo = true; + info->Calendar = true; + } else if (strstr(FileName,".ldif")) { + info->PhonePhonebook = true; + } else { + info->UseUnicode = true; + info->IMEI = true; + info->Model = true; + info->DateTime = true; + info->PhonePhonebook = true; + info->SIMPhonebook = true; + info->ToDo = true; + info->Calendar = true; + info->CallerLogos = true; + info->SMSC = true; + info->WAPBookmark = true; + info->WAPSettings = true; + info->MMSSettings = true; + info->Ringtone = true; + info->StartupLogo = true; + info->OperatorLogo = true; + info->Profiles = true; + info->FMStation = true; + info->GPRSPoint = true; + info->Note = true; + } +} + +void GSM_GetBackupFileFeatures(char *FileName, GSM_Backup_Info *info, GSM_Backup *backup) +{ + GSM_GetBackupFormatFeatures(FileName, info); + + if (info->PhonePhonebook && backup->PhonePhonebook[0] == NULL) info->PhonePhonebook = false; + if (info->SIMPhonebook && backup->SIMPhonebook[0] == NULL) info->SIMPhonebook = false; + if (info->Calendar && backup->Calendar[0] == NULL) info->Calendar = false; + if (info->ToDo && backup->ToDo[0] == NULL) info->ToDo = false; + if (info->WAPBookmark && backup->WAPBookmark[0] == NULL) info->WAPBookmark = false; + if (info->WAPSettings && backup->WAPSettings[0] == NULL) info->WAPSettings = false; + if (info->MMSSettings && backup->MMSSettings[0] == NULL) info->MMSSettings = false; + if (info->FMStation && backup->FMStation[0] == NULL) info->FMStation = false; + if (info->GPRSPoint && backup->GPRSPoint[0] == NULL) info->GPRSPoint = false; + if (info->Profiles && backup->Profiles[0] == NULL) info->Profiles = false; + /* .... */ +} + +#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/service/backup/gsmback.h b/gammu/emb/common/service/backup/gsmback.h new file mode 100644 index 0000000..1fd99b0 --- a/dev/null +++ b/gammu/emb/common/service/backup/gsmback.h @@ -0,0 +1,48 @@ +/* (c) 2003-2004 by Marcin Wiacek */ + +#ifndef __gsm_back_h +#define __gsm_back_h + +#include "backgen.h" + +#ifdef GSM_ENABLE_BACKUP + +GSM_Error GSM_SaveBackupFile(char *FileName, GSM_Backup *backup, bool UseUnicode); +GSM_Error GSM_ReadBackupFile(char *FileName, GSM_Backup *backup); + +void GSM_ClearBackup (GSM_Backup *backup); +void GSM_FreeBackup (GSM_Backup *backup); + +typedef struct { + bool UseUnicode; + + bool IMEI; + bool Model; + bool DateTime; + bool ToDo; + bool PhonePhonebook; + bool SIMPhonebook; + bool Calendar; + bool CallerLogos; + bool SMSC; + bool WAPBookmark; + bool Profiles; + bool WAPSettings; + bool MMSSettings; + bool Ringtone; + bool StartupLogo; + bool OperatorLogo; + bool FMStation; + bool GPRSPoint; + bool Note; +} GSM_Backup_Info; + +void GSM_GetBackupFormatFeatures(char *FileName, GSM_Backup_Info *info); +void GSM_GetBackupFileFeatures (char *FileName, GSM_Backup_Info *info, GSM_Backup *backup); + +#endif +#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/service/gsmcal.c b/gammu/emb/common/service/gsmcal.c new file mode 100644 index 0000000..950e35e --- a/dev/null +++ b/gammu/emb/common/service/gsmcal.c @@ -0,0 +1,509 @@ +/* (c) 2002-2003 by Marcin Wiacek */ + +#include <string.h> + +#include "gsmcal.h" +#include "gsmmisc.h" +#include "../misc/coding/coding.h" + +bool IsCalendarNoteFromThePast(GSM_CalendarEntry *note) +{ + bool Past = true; + int i; + GSM_DateTime DT; + + GSM_GetCurrentDateTime (&DT); + for (i = 0; i < note->EntriesNum; i++) { + switch (note->Entries[i].EntryType) { + case CAL_RECURRANCE: + Past = false; + break; + case CAL_START_DATETIME : + if (note->Entries[i].Date.Year > DT.Year) Past = false; + if (note->Entries[i].Date.Year == DT.Year && + note->Entries[i].Date.Month > DT.Month) Past = false; + if (note->Entries[i].Date.Year == DT.Year && + note->Entries[i].Date.Month == DT.Month && + note->Entries[i].Date.Day > DT.Day) Past = false; + break; + default: + break; + } + if (!Past) break; + } + switch (note->Type) { + case GSM_CAL_BIRTHDAY: + Past = false; + break; + default: + break; + } + return Past; +} + +void GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(GSM_CalendarEntry *entry, int *Text, int *Time, int *Alarm, int *Phone, int *Recurrance, int *EndTime, int *Location) +{ + int i; + + *Text = -1; + *Time = -1; + *Alarm = -1; + *Phone = -1; + *Recurrance = -1; + *EndTime = -1; + *Location = -1; + for (i = 0; i < entry->EntriesNum; i++) { + switch (entry->Entries[i].EntryType) { + case CAL_START_DATETIME : + if (*Time == -1) *Time = i; + break; + case CAL_END_DATETIME : + if (*EndTime == -1) *EndTime = i; + break; + case CAL_ALARM_DATETIME : + case CAL_SILENT_ALARM_DATETIME: + if (*Alarm == -1) *Alarm = i; + break; + case CAL_RECURRANCE: + if (*Recurrance == -1) *Recurrance = i; + break; + case CAL_TEXT: + if (*Text == -1) *Text = i; + break; + case CAL_PHONE: + if (*Phone == -1) *Phone = i; + break; + case CAL_LOCATION: + if (*Location == -1) *Location = i; + break; + default: + break; + } + } +} + +GSM_Error GSM_EncodeVCALENDAR(char *Buffer, int *Length, GSM_CalendarEntry *note, bool header, GSM_VCalendarVersion Version) +{ + int Text, Time, Alarm, Phone, Recurrance, EndTime, Location; + char buffer[2000]; + + GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(note, &Text, &Time, &Alarm, &Phone, &Recurrance, &EndTime, &Location); + + if (header) { + *Length+=sprintf(Buffer, "BEGIN:VCALENDAR%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "VERSION:1.0%c%c",13,10); + } + *Length+=sprintf(Buffer+(*Length), "BEGIN:VEVENT%c%c",13,10); + + if (Version == Nokia_VCalendar) { + *Length+=sprintf(Buffer+(*Length), "CATEGORIES:"); + switch (note->Type) { + case GSM_CAL_REMINDER: + *Length+=sprintf(Buffer+(*Length), "REMINDER%c%c",13,10); + break; + case GSM_CAL_MEMO: + *Length+=sprintf(Buffer+(*Length), "MISCELLANEOUS%c%c",13,10); + break; + case GSM_CAL_CALL: + *Length+=sprintf(Buffer+(*Length), "PHONE CALL%c%c",13,10); + break; + case GSM_CAL_BIRTHDAY: + *Length+=sprintf(Buffer+(*Length), "SPECIAL OCCASION%c%c",13,10); + break; + case GSM_CAL_MEETING: + default: + *Length+=sprintf(Buffer+(*Length), "MEETING%c%c",13,10); + break; + } + if (note->Type == GSM_CAL_CALL) { + buffer[0] = 0; + buffer[1] = 0; + if (Phone != -1) CopyUnicodeString(buffer,note->Entries[Phone].Text); + if (Text != -1) { + if (Phone != -1) EncodeUnicode(buffer+UnicodeLength(buffer)*2," ",1); + CopyUnicodeString(buffer+UnicodeLength(buffer)*2,note->Entries[Text].Text); + } + SaveVCALText(Buffer, Length, buffer, "SUMMARY"); + } else { + SaveVCALText(Buffer, Length, note->Entries[Text].Text, "SUMMARY"); + } + if (note->Type == GSM_CAL_MEETING && Location != -1) { + SaveVCALText(Buffer, Length, note->Entries[Location].Text, "LOCATION"); + } + + if (Time == -1) return ERR_UNKNOWN; + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Time].Date, "DTSTART"); + + if (EndTime != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[EndTime].Date, "DTEND"); + } + + if (Alarm != -1) { + if (note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "DALARM"); + } else { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "AALARM"); + } + } + + /* Birthday is known to be recurranced */ + if (Recurrance != -1 && note->Type != GSM_CAL_BIRTHDAY) { + switch(note->Entries[Recurrance].Number/24) { + case 1 : *Length+=sprintf(Buffer+(*Length), "RRULE:D1 #0%c%c",13,10); break; + case 7 : *Length+=sprintf(Buffer+(*Length), "RRULE:W1 #0%c%c",13,10); break; + case 14 : *Length+=sprintf(Buffer+(*Length), "RRULE:W2 #0%c%c",13,10); break; + case 365 : *Length+=sprintf(Buffer+(*Length), "RRULE:YD1 #0%c%c",13,10); break; + } + } + } else if (Version == Siemens_VCalendar) { + *Length+=sprintf(Buffer+(*Length), "CATEGORIES:"); + switch (note->Type) { + case GSM_CAL_MEETING: + *Length+=sprintf(Buffer+(*Length), "MEETING%c%c",13,10); + break; + case GSM_CAL_CALL: + *Length+=sprintf(Buffer+(*Length), "PHONE CALL%c%c",13,10); + break; + case GSM_CAL_BIRTHDAY: + *Length+=sprintf(Buffer+(*Length), "ANNIVERSARY%c%c",13,10); + break; + case GSM_CAL_MEMO: + default: + *Length+=sprintf(Buffer+(*Length), "MISCELLANEOUS%c%c",13,10); + break; + } + + if (Time == -1) return ERR_UNKNOWN; + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Time].Date, "DTSTART"); + + if (Alarm != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "DALARM"); + } + + if (Recurrance != -1) { + switch(note->Entries[Recurrance].Number/24) { + case 1 : *Length+=sprintf(Buffer+(*Length), "RRULE:D1%c%c",13,10); break; + case 7 : *Length+=sprintf(Buffer+(*Length), "RRULE:D7%c%c",13,10); break; + case 30 : *Length+=sprintf(Buffer+(*Length), "RRULE:MD1%c%c",13,10); break; + case 365 : *Length+=sprintf(Buffer+(*Length), "RRULE:YD1%c%c",13,10); break; + } + } + + if (note->Type == GSM_CAL_CALL) { + buffer[0] = 0; + buffer[1] = 0; + if (Phone != -1) CopyUnicodeString(buffer,note->Entries[Phone].Text); + if (Text != -1) { + if (Phone != -1) EncodeUnicode(buffer+UnicodeLength(buffer)*2," ",1); + CopyUnicodeString(buffer+UnicodeLength(buffer)*2,note->Entries[Text].Text); + } + SaveVCALText(Buffer, Length, buffer, "DESCRIPTION"); + } else { + SaveVCALText(Buffer, Length, note->Entries[Text].Text, "DESCRIPTION"); + } + } else if (Version == SonyEricsson_VCalendar) { + *Length+=sprintf(Buffer+(*Length), "CATEGORIES:"); + switch (note->Type) { + case GSM_CAL_MEETING: + *Length+=sprintf(Buffer+(*Length), "MEETING%c%c",13,10); + break; + case GSM_CAL_REMINDER: + *Length+=sprintf(Buffer+(*Length), "DATE%c%c",13,10); + break; + case GSM_CAL_TRAVEL: + *Length+=sprintf(Buffer+(*Length), "TRAVEL%c%c",13,10); + break; + case GSM_CAL_VACATION: + *Length+=sprintf(Buffer+(*Length), "VACATION%c%c",13,10); + break; + case GSM_CAL_BIRTHDAY: + *Length+=sprintf(Buffer+(*Length), "ANNIVERSARY%c%c",13,10); + break; + case GSM_CAL_MEMO: + default: + *Length+=sprintf(Buffer+(*Length), "MISCELLANEOUS%c%c",13,10); + break; + } + + if (Time == -1) return ERR_UNKNOWN; + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Time].Date, "DTSTART"); + + if (EndTime != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[EndTime].Date, "DTEND"); + } + + if (Alarm != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "AALARM"); + } + + SaveVCALText(Buffer, Length, note->Entries[Text].Text, "SUMMARY"); + + if (Location != -1) { + SaveVCALText(Buffer, Length, note->Entries[Location].Text, "LOCATION"); + } + } + + *Length+=sprintf(Buffer+(*Length), "END:VEVENT%c%c",13,10); + if (header) *Length+=sprintf(Buffer+(*Length), "END:VCALENDAR%c%c",13,10); + + return ERR_NONE; +} + +void GSM_ToDoFindDefaultTextTimeAlarmCompleted(GSM_ToDoEntry *entry, int *Text, int *Alarm, int *Completed, int *EndTime, int *Phone) +{ + int i; + + *Text = -1; + *EndTime = -1; + *Alarm = -1; + *Completed = -1; + *Phone = -1; + for (i = 0; i < entry->EntriesNum; i++) { + switch (entry->Entries[i].EntryType) { + case TODO_END_DATETIME : + if (*EndTime == -1) *EndTime = i; + break; + case TODO_ALARM_DATETIME : + case TODO_SILENT_ALARM_DATETIME: + if (*Alarm == -1) *Alarm = i; + break; + case TODO_TEXT: + if (*Text == -1) *Text = i; + break; + case TODO_COMPLETED: + if (*Completed == -1) *Completed = i; + break; + case TODO_PHONE: + if (*Phone == -1) *Phone = i; + break; + default: + break; + } + } +} + +GSM_Error GSM_EncodeVTODO(char *Buffer, int *Length, GSM_ToDoEntry *note, bool header, GSM_VToDoVersion Version) +{ + int Text, Alarm, Completed, EndTime, Phone; + + GSM_ToDoFindDefaultTextTimeAlarmCompleted(note, &Text, &Alarm, &Completed, &EndTime, &Phone); + + if (header) { + *Length+=sprintf(Buffer, "BEGIN:VCALENDAR%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "VERSION:1.0%c%c",13,10); + } + + *Length+=sprintf(Buffer+(*Length), "BEGIN:VTODO%c%c",13,10); + + if (Version == Nokia_VToDo) { + if (Text == -1) return ERR_UNKNOWN; + SaveVCALText(Buffer, Length, note->Entries[Text].Text, "SUMMARY"); + + if (Completed == -1) { + *Length+=sprintf(Buffer+(*Length), "STATUS:NEEDS ACTION%c%c",13,10); + } else { + *Length+=sprintf(Buffer+(*Length), "STATUS:COMPLETED%c%c",13,10); + } + + switch (note->Priority) { + case GSM_Priority_Low : *Length+=sprintf(Buffer+(*Length), "PRIORITY:1%c%c",13,10); break; + case GSM_Priority_Medium: *Length+=sprintf(Buffer+(*Length), "PRIORITY:2%c%c",13,10); break; + case GSM_Priority_High : *Length+=sprintf(Buffer+(*Length), "PRIORITY:3%c%c",13,10); break; + } + + if (EndTime != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[EndTime].Date, "DUE"); + } + + if (Alarm != -1) { + if (note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "DALARM"); + } else { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "AALARM"); + } + } + } else if (Version == SonyEricsson_VToDo) { + if (Text == -1) return ERR_UNKNOWN; + SaveVCALText(Buffer, Length, note->Entries[Text].Text, "SUMMARY"); + + if (Completed == -1) { + *Length+=sprintf(Buffer+(*Length), "STATUS:NEEDS ACTION%c%c",13,10); + } else { + *Length+=sprintf(Buffer+(*Length), "STATUS:COMPLETED%c%c",13,10); + } + + switch (note->Priority) { + case GSM_Priority_Low : *Length+=sprintf(Buffer+(*Length), "PRIORITY:3%c%c",13,10); break; + case GSM_Priority_Medium: *Length+=sprintf(Buffer+(*Length), "PRIORITY:2%c%c",13,10); break; + case GSM_Priority_High : *Length+=sprintf(Buffer+(*Length), "PRIORITY:1%c%c",13,10); break; + } + + if (Alarm != -1) { + SaveVCALDateTime(Buffer, Length, ¬e->Entries[Alarm].Date, "AALARM"); + } + } + + *Length+=sprintf(Buffer+(*Length), "END:VTODO%c%c",13,10); + + if (header) { + *Length+=sprintf(Buffer+(*Length), "END:VCALENDAR%c%c",13,10); + } + return ERR_NONE; +} + +GSM_Error GSM_DecodeVCALENDAR_VTODO(unsigned char *Buffer, int *Pos, GSM_CalendarEntry *Calendar, GSM_ToDoEntry *ToDo, GSM_VCalendarVersion CalVer, GSM_VToDoVersion ToDoVer) +{ + unsigned char Line[2000],Buff[2000]; + int Level = 0; + + Calendar->EntriesNum = 0; + ToDo->EntriesNum = 0; + + while (1) { + MyGetLine(Buffer, Pos, Line, strlen(Buffer)); + if (strlen(Line) == 0) break; + switch (Level) { + case 0: + if (strstr(Line,"BEGIN:VEVENT")) { + Calendar->Type = GSM_CAL_MEMO; + Level = 1; + } + if (strstr(Line,"BEGIN:VTODO")) { + ToDo->Priority = GSM_Priority_Low; + Level = 2; + } + break; + case 1: /* Calendar note */ + if (strstr(Line,"END:VEVENT")) { + if (Calendar->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; + } + if (strstr(Line,"CATEGORIES:REMINDER")) Calendar->Type = GSM_CAL_REMINDER; + if (strstr(Line,"CATEGORIES:DATE")) Calendar->Type = GSM_CAL_REMINDER;//SE + if (strstr(Line,"CATEGORIES:TRAVEL")) Calendar->Type = GSM_CAL_TRAVEL; //SE + if (strstr(Line,"CATEGORIES:VACATION")) Calendar->Type = GSM_CAL_VACATION;//SE + if (strstr(Line,"CATEGORIES:MISCELLANEOUS")) Calendar->Type = GSM_CAL_MEMO; + if (strstr(Line,"CATEGORIES:PHONE CALL")) Calendar->Type = GSM_CAL_CALL; + if (strstr(Line,"CATEGORIES:SPECIAL OCCASION")) Calendar->Type = GSM_CAL_BIRTHDAY; + if (strstr(Line,"CATEGORIES:ANNIVERSARY")) Calendar->Type = GSM_CAL_BIRTHDAY; + if (strstr(Line,"CATEGORIES:MEETING")) Calendar->Type = GSM_CAL_MEETING; + if (strstr(Line,"CATEGORIES:APPOINTMENT")) Calendar->Type = GSM_CAL_MEETING; + if (strstr(Line,"RRULE:D1")) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_RECURRANCE; + Calendar->Entries[Calendar->EntriesNum].Number = 1*24; + Calendar->EntriesNum++; + } + if ((strstr(Line,"RRULE:W1")) || (strstr(Line,"RRULE:D7"))) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_RECURRANCE; + Calendar->Entries[Calendar->EntriesNum].Number = 7*24; + Calendar->EntriesNum++; + } + if (strstr(Line,"RRULE:W2")) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_RECURRANCE; + Calendar->Entries[Calendar->EntriesNum].Number = 14*24; + Calendar->EntriesNum++; + } + if (strstr(Line,"RRULE:MD1")) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_RECURRANCE; + Calendar->Entries[Calendar->EntriesNum].Number = 30*24; + Calendar->EntriesNum++; + } + if (strstr(Line,"RRULE:YD1")) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_RECURRANCE; + Calendar->Entries[Calendar->EntriesNum].Number = 365*24; + Calendar->EntriesNum++; + } + if ((ReadVCALText(Line, "SUMMARY", Buff)) || (ReadVCALText(Line, "DESCRIPTION", Buff))) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_TEXT; + CopyUnicodeString(Calendar->Entries[Calendar->EntriesNum].Text,Buff); + Calendar->EntriesNum++; + } + if (ReadVCALText(Line, "LOCATION", Buff)) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_LOCATION; + CopyUnicodeString(Calendar->Entries[Calendar->EntriesNum].Text,Buff); + Calendar->EntriesNum++; + } + if (ReadVCALText(Line, "DTSTART", Buff)) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_START_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &Calendar->Entries[Calendar->EntriesNum].Date); + Calendar->EntriesNum++; + } + if (ReadVCALText(Line, "DTEND", Buff)) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_END_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &Calendar->Entries[Calendar->EntriesNum].Date); + Calendar->EntriesNum++; + } + if (ReadVCALText(Line, "DALARM", Buff)) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_SILENT_ALARM_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &Calendar->Entries[Calendar->EntriesNum].Date); + Calendar->EntriesNum++; + } + if (ReadVCALText(Line, "AALARM", Buff)) { + Calendar->Entries[Calendar->EntriesNum].EntryType = CAL_ALARM_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &Calendar->Entries[Calendar->EntriesNum].Date); + Calendar->EntriesNum++; + } + break; + case 2: /* ToDo note */ + if (strstr(Line,"END:VTODO")) { + if (ToDo->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; + } + if (ReadVCALText(Line, "DUE", Buff)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_END_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->EntriesNum++; + } + if (ReadVCALText(Line, "DALARM", Buff)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_SILENT_ALARM_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->EntriesNum++; + } + if (ReadVCALText(Line, "AALARM", Buff)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_ALARM_DATETIME; + ReadVCALDateTime(DecodeUnicodeString(Buff), &ToDo->Entries[ToDo->EntriesNum].Date); + ToDo->EntriesNum++; + } + if (ReadVCALText(Line, "SUMMARY", Buff)) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_TEXT; + CopyUnicodeString(ToDo->Entries[ToDo->EntriesNum].Text,Buff); + ToDo->EntriesNum++; + } + if (ReadVCALText(Line, "PRIORITY", Buff)) { + if (ToDoVer == SonyEricsson_VToDo) { + ToDo->Priority = GSM_Priority_Low; + if (atoi(DecodeUnicodeString(Buff))==2) ToDo->Priority = GSM_Priority_Medium; + if (atoi(DecodeUnicodeString(Buff))==1) ToDo->Priority = GSM_Priority_High; + dbgprintf("atoi is %i %s\n",atoi(DecodeUnicodeString(Buff)),DecodeUnicodeString(Buff)); + } else if (ToDoVer == Nokia_VToDo) { + ToDo->Priority = GSM_Priority_Low; + if (atoi(DecodeUnicodeString(Buff))==2) ToDo->Priority = GSM_Priority_Medium; + if (atoi(DecodeUnicodeString(Buff))==3) ToDo->Priority = GSM_Priority_High; + } + } + if (strstr(Line,"STATUS:COMPLETED")) { + ToDo->Entries[ToDo->EntriesNum].EntryType = TODO_COMPLETED; + ToDo->Entries[ToDo->EntriesNum].Number = 1; + ToDo->EntriesNum++; + } + break; + } + } + + if (Calendar->EntriesNum == 0 && ToDo->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; +} + +GSM_Error GSM_EncodeVNTFile(unsigned char *Buffer, int *Length, GSM_NoteEntry *Note) +{ + *Length+=sprintf(Buffer+(*Length), "BEGIN:VNOTE%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "VERSION:1.1%c%c",13,10); + SaveVCALText(Buffer, Length, Note->Text, "BODY"); + *Length+=sprintf(Buffer+(*Length), "END:VNOTE%c%c",13,10); + + return ERR_NONE; +} + +/* 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/service/gsmcal.h b/gammu/emb/common/service/gsmcal.h new file mode 100644 index 0000000..067a4a4 --- a/dev/null +++ b/gammu/emb/common/service/gsmcal.h @@ -0,0 +1,445 @@ +/* (c) 2002-2004 by Marcin Wiacek */ +/* 5210 calendar IDs by Frederick Ros */ + +#ifndef __gsm_cal_h +#define __gsm_cal_h + +#include "../gsmcomon.h" + +/* ---------------------------- calendar ----------------------------------- */ + +#define GSM_CALENDAR_ENTRIES 16 +#define MAX_CALENDAR_TEXT_LENGTH 256 /* In 6310 max. 256 chars */ + +/** + * Enum defines types of calendar notes + */ +typedef enum { + /** + * Reminder or Date + */ + GSM_CAL_REMINDER=1, + /** + * Call + */ + GSM_CAL_CALL, + /** + * Meeting + */ + GSM_CAL_MEETING, + /** + * Birthday or Anniversary or Special Occasion + */ + GSM_CAL_BIRTHDAY, + /** + * Memo or Miscellaneous + */ + GSM_CAL_MEMO, + /** + * Travel + */ + GSM_CAL_TRAVEL, + /** + * Vacation + */ + GSM_CAL_VACATION, + /** + * Training - Athletism + */ + GSM_CAL_T_ATHL, + /** + * Training - Ball Games + */ + GSM_CAL_T_BALL, + /** + * Training - Cycling + */ + GSM_CAL_T_CYCL, + /** + * Training - Budo + */ + GSM_CAL_T_BUDO, + /** + * Training - Dance + */ + GSM_CAL_T_DANC, + /** + * Training - Extreme Sports + */ + GSM_CAL_T_EXTR, + /** + * Training - Football + */ + GSM_CAL_T_FOOT, + /** + * Training - Golf + */ + GSM_CAL_T_GOLF, + /** + * Training - Gym + */ + GSM_CAL_T_GYM, + /** + * Training - Horse Race + */ + GSM_CAL_T_HORS, + /** + * Training - Hockey + */ + GSM_CAL_T_HOCK, + /** + * Training - Races + */ + GSM_CAL_T_RACE, + /** + * Training - Rugby + */ + GSM_CAL_T_RUGB, + /** + * Training - Sailing + */ + GSM_CAL_T_SAIL, + /** + * Training - Street Games + */ + GSM_CAL_T_STRE, + /** + * Training - Swimming + */ + GSM_CAL_T_SWIM, + /** + * Training - Tennis + */ + GSM_CAL_T_TENN, + /** + * Training - Travels + */ + GSM_CAL_T_TRAV, + /** + * Training - Winter Games + */ + GSM_CAL_T_WINT, + /** + * Alarm + */ + GSM_CAL_ALARM, + /** + * Alarm repeating each day. + */ + GSM_CAL_DAILY_ALARM +} GSM_CalendarNoteType; + +/** + * One value of calendar event. + */ +typedef enum { + /** + * Date and time of event start. + */ + CAL_START_DATETIME = 1, + /** + * Date and time of event end. + */ + CAL_END_DATETIME, + /** + * Alarm date and time. + */ + CAL_ALARM_DATETIME, + /** + * Date and time of silent alarm. + */ + CAL_SILENT_ALARM_DATETIME, + /** + * Recurrance. + */ + CAL_RECURRANCE, + /** + * Text. + */ + CAL_TEXT, + /** + * Location. + */ + CAL_LOCATION, + /** + * Phone number. + */ + CAL_PHONE, + /** + * Whether this entry is private. + */ + CAL_PRIVATE, + /** + * Related contact id. + */ + CAL_CONTACTID, + /** + * Repeat each x'th day of week. + */ + CAL_REPEAT_DAYOFWEEK, + /** + * Repeat each x'th day of month. + */ + CAL_REPEAT_DAY, + /** + * Repeat x'th week of month. + */ + CAL_REPEAT_WEEKOFMONTH, + /** + * Repeat x'th month. + */ + CAL_REPEAT_MONTH, + /** + * Repeating frequency. + */ + CAL_REPEAT_FREQUENCY, + /** + * Repeating start. + */ + CAL_REPEAT_STARTDATE, + /** + * Repeating end. + */ + CAL_REPEAT_STOPDATE +} GSM_CalendarType; + +/** + * One value of calendar event. + */ +typedef struct { + /** + * Type of value. + */ + GSM_CalendarType EntryType; + /** + * Text of value, if applicable. + */ + unsigned char Text[(MAX_CALENDAR_TEXT_LENGTH + 1)*2]; + /** + * Date and time of value, if applicable. + */ + GSM_DateTime Date; + /** + * Number of value, if applicable. + */ + unsigned int Number; +} GSM_SubCalendarEntry; + +/** + * Calendar note values. + */ +typedef struct { + /** + * Type of calendar note. + */ + GSM_CalendarNoteType Type; + /** + * Location in memory. + */ + int Location; + /** + * Number of entries. + */ + int EntriesNum; + /** + * Values of entries. + */ + GSM_SubCalendarEntry Entries[GSM_CALENDAR_ENTRIES]; +} GSM_CalendarEntry; + +void GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(GSM_CalendarEntry *entry, int *Text, int *Time, int *Alarm, int *Phone, int *Recurrance, int *EndTime, int *Location); + +typedef enum { + Nokia_VCalendar = 1, + Siemens_VCalendar, + SonyEricsson_VCalendar +} GSM_VCalendarVersion; + +GSM_Error GSM_EncodeVCALENDAR(char *Buffer, int *Length, GSM_CalendarEntry *note, bool header, GSM_VCalendarVersion Version); + +bool IsCalendarNoteFromThePast(GSM_CalendarEntry *note); + +typedef struct { + /** + * Monday = 1, Tuesday = 2,... + */ + int StartDay; + /** + * 0 = no delete, 1 = after day,... + */ + int AutoDelete; +} GSM_CalendarSettings; + +/** + * Structure used for returning calendar status. + */ +typedef struct { + /** + * Number of used positions. + */ + int Used; +} GSM_CalendarStatus; + + +/* ------------------------------ to-do ------------------------------------ */ + +#define GSM_TODO_ENTRIES 7 +#define MAX_TODO_TEXT_LENGTH 50 /* Alcatel BE5 50 chars */ + +/** + * Types of to do values. In parenthesis is member of @ref GSM_SubToDoEntry, + * where value is stored. + */ +typedef enum { + /** + * Due date. (Date) + */ + TODO_END_DATETIME = 1, + /** + * Whether is completed. (Number) + */ + TODO_COMPLETED, + /** + * When should alarm be fired (Date). + */ + TODO_ALARM_DATETIME, + /** + * When should silent alarm be fired (Date). + */ + TODO_SILENT_ALARM_DATETIME, + /** + * Text of to do (Text). + */ + TODO_TEXT, + /** + * Whether entry is private (Number). + */ + TODO_PRIVATE, + /** + * Category of entry (Number). + */ + TODO_CATEGORY, + /** + * Related contact ID (Number). + */ + TODO_CONTACTID, + /** + * Number to call (Text). + */ + TODO_PHONE +} GSM_ToDoType; + +/** + * Priority of to do. + */ +typedef enum { + GSM_Priority_High = 1, + GSM_Priority_Medium, + GSM_Priority_Low +} GSM_ToDo_Priority; + +/** + * Value of to do entry. + */ +typedef struct { + /** + * Type of entry. + */ + GSM_ToDoType EntryType; + /** + * Text of value, if appropriate, see @ref GSM_ToDoType. + */ + unsigned char Text[(MAX_TODO_TEXT_LENGTH + 1)*2]; + /** + * Date of value, if appropriate, see @ref GSM_ToDoType. + */ + GSM_DateTime Date; + /** + * Number of value, if appropriate, see @ref GSM_ToDoType. + */ + unsigned int Number; +} GSM_SubToDoEntry; + +/** + * To do entry. + */ +typedef struct { + /** + * Priority of entry. + */ + GSM_ToDo_Priority Priority; + /** + * Location in memory. + */ + int Location; + /** + * Number of entries. + */ + int EntriesNum; + /** + * Values of current entry. + */ + GSM_SubToDoEntry Entries[GSM_TODO_ENTRIES]; +} GSM_ToDoEntry; + +void GSM_ToDoFindDefaultTextTimeAlarmCompleted(GSM_ToDoEntry *entry, int *Text, int *Alarm, int *Completed, int *EndTime, int *Phone); + +typedef enum { + Nokia_VToDo = 1, + SonyEricsson_VToDo +} GSM_VToDoVersion; + +GSM_Error GSM_EncodeVTODO(char *Buffer, int *Length, GSM_ToDoEntry *note, bool header, GSM_VToDoVersion Version); + +/** + * Status of to do entries. + */ +typedef struct { + /** + * Number of used positions. + */ + int Used; +} GSM_ToDoStatus; + +/* --------------------------- note ---------------------------------------- */ + +typedef struct { + int Location; + char Text[100]; +} GSM_NoteEntry; + +GSM_Error GSM_EncodeVNTFile(unsigned char *Buffer, int *Length, GSM_NoteEntry *Note); + +/* --------------------------- alarm --------------------------------------- */ + +/** + * Alarm values. + */ +typedef struct { + /** + * Location where it is stored. + */ + int Location; + /** + * Date and time of alarm. + */ + GSM_DateTime DateTime; + /** + * Whether it repeats each day. + */ + bool Repeating; + /** + * Text that is shown on display. + */ + char Text[(MAX_CALENDAR_TEXT_LENGTH + 1) * 2]; +} GSM_Alarm; + +/* --------------------------- calendar & todo ----------------------------- */ + +GSM_Error GSM_DecodeVCALENDAR_VTODO(unsigned char *Buffer, int *Pos, GSM_CalendarEntry *Calendar, GSM_ToDoEntry *ToDo, GSM_VCalendarVersion CalVer, GSM_VToDoVersion ToDoVer); + +#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/service/gsmcall.h b/gammu/emb/common/service/gsmcall.h new file mode 100644 index 0000000..c5032a5 --- a/dev/null +++ b/gammu/emb/common/service/gsmcall.h @@ -0,0 +1,185 @@ +/* (c) 2002-2003 by Marcin Wiacek */ + +#ifndef _gsm_call_h +#define _gsm_call_h + +#include "../misc/misc.h" + +/* ------------------ call info -------------------------------------------- */ + +/** + * Enum with status of call. + */ +typedef enum { + /** + * Somebody calls to us + */ + GSM_CALL_IncomingCall=1, + /** + * We call somewhere + */ + GSM_CALL_OutgoingCall, + /** + * Call started + */ + GSM_CALL_CallStart, + /** + * End of call from unknown side + */ + GSM_CALL_CallEnd, + /** + * End of call from remote side + */ + GSM_CALL_CallRemoteEnd, + /** + * End of call from our side + */ + GSM_CALL_CallLocalEnd, + /** + * Call established. Waiting for answer or dropping + */ + GSM_CALL_CallEstablished, + /** + * Call held + */ + GSM_CALL_CallHeld, + /** + * Call resumed + */ + GSM_CALL_CallResumed, + /** + * We switch to call + */ + GSM_CALL_CallSwitched +} GSM_CallStatus; + +/** + * Call information. + */ +typedef struct { + /** + * Call status. + */ + GSM_CallStatus Status; + /** + * Remote phone number. + */ + char PhoneNumber [(GSM_MAX_NUMBER_LENGTH+1)*2]; + /** + * Call ID + */ + int CallID; + /** + * Whether Call ID is available. + */ + bool CallIDAvailable; + /** + * Status code. + */ + int StatusCode; +} GSM_Call; + +/* --------------- Data structures for the call divert -------------------- */ + +/** + * Defines when diversion is active. + */ +typedef enum { + /** + * Divert when busy. + */ + GSM_DIVERT_Busy = 0x01, + /** + * Divert when not answered. + */ + GSM_DIVERT_NoAnswer, + /** + * Divert when phone off or no coverage. + */ + GSM_DIVERT_OutOfReach, + /** + * Divert all calls without ringing. + */ + GSM_DIVERT_AllTypes +} GSM_Divert_DivertTypes; + +/** + * Which type of calls should be diverted. + */ +typedef enum { + /** + * Voice calls. + */ + GSM_DIVERT_VoiceCalls = 0x01, + /** + * Fax calls. + */ + GSM_DIVERT_FaxCalls, + /** + * Data calls. + */ + GSM_DIVERT_DataCalls, + /** + * All calls. + */ + GSM_DIVERT_AllCalls +} GSM_Divert_CallTypes; + +/** + * Call diversion definition. + */ +typedef struct { + /** + * When diversion is active. + */ + GSM_Divert_DivertTypes DivertType; + /** + * Type of call to divert. + */ + GSM_Divert_CallTypes CallType; + /** + * Number where to divert. + */ + char Number[(GSM_MAX_NUMBER_LENGTH+1)*2]; + /** + * Timeout for diversion. + */ + unsigned int Timeout; +} GSM_CallDivert; + +/** + * Multiple call diversions. + */ +typedef struct { + GSM_CallDivert Request; + struct { + int EntriesNum; + GSM_CallDivert Entries[10]; + } Response; +} GSM_MultiCallDivert; + +/* -------------------------------- dial voice ---------------------------- */ + +/** + * How to handle number when initiating voice call. + */ +typedef enum { + /** + * Show number. + */ + GSM_CALL_ShowNumber = 1, + /** + * Hide number. + */ + GSM_CALL_HideNumber, + /** + * Keep phone default settings. + */ + GSM_CALL_DefaultNumberPresence +} GSM_CallShowNumber; + +#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/service/gsmdata.c b/gammu/emb/common/service/gsmdata.c new file mode 100644 index 0000000..94e9b7b --- a/dev/null +++ b/gammu/emb/common/service/gsmdata.c @@ -0,0 +1,366 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#include <string.h> + +#include "gsmdata.h" +#include "../misc/coding/coding.h" + +/* SNIFFS, specs somewhere in http://www.wapforum.org */ +void GSM_EncodeMMSIndicatorSMSText(unsigned char *Buffer, int *Length, GSM_MMSIndicator Indicator) +{ + unsigned char buffer[200]; + int i; + + strcpy(Buffer+(*Length),"\xE6\x06\""); + (*Length)=(*Length)+3; + strcpy(Buffer+(*Length),"application/vnd.wap.mms-message"); + (*Length)=(*Length)+31; + Buffer[(*Length)++] = 0x00; + + strcpy(Buffer+(*Length),"\xAF\x84\x8C\x82\x98"); + (*Length)=(*Length)+5; + + i = strlen(Indicator.Address); + while (Indicator.Address[i] != '/' && i!=0) i--; + strcpy(Buffer+(*Length),Indicator.Address+i+1); + (*Length)=(*Length)+strlen(Indicator.Address+i+1); + Buffer[(*Length)++] = 0x00; + + strcpy(Buffer+(*Length),"\x8D\x90\x89"); + (*Length)=(*Length)+3; + + sprintf(buffer,"%s/TYPE=PLMN",Indicator.Sender); + Buffer[(*Length)++] = strlen(buffer); + Buffer[(*Length)++] = 0x80; + strcpy(Buffer+(*Length),buffer); + (*Length)=(*Length)+strlen(buffer); + Buffer[(*Length)++] = 0x00; + + Buffer[(*Length)++] = 0x96; + strcpy(Buffer+(*Length),Indicator.Title); + (*Length)=(*Length)+strlen(Indicator.Title); + Buffer[(*Length)++] = 0x00; + + strcpy(Buffer+(*Length),"\x8A\x80\x8E\x02\x47\xBB\x88\x05\x81\x03\x02\xA3"); + (*Length)=(*Length)+12; + Buffer[(*Length)++] = 0x00; + + Buffer[(*Length)++] = 0x83; + strcpy(Buffer+(*Length),Indicator.Address); + (*Length)=(*Length)+strlen(Indicator.Address); + Buffer[(*Length)++] = 0x00; +} + +/* http://forum.nokia.com: OTA MMS Settings 1.0, OTA Settings 7.0 */ +static void AddWAPSMSParameterText(unsigned char *Buffer, int *Length, unsigned char ID, char *Text, int Len) +{ + int i; + + Buffer[(*Length)++] = 0x87; //PARM with attributes + Buffer[(*Length)++] = ID; + Buffer[(*Length)++] = 0x11; //VALUE + Buffer[(*Length)++] = 0x03; //Inline string + for (i=0;i<Len;i++) { + Buffer[(*Length)++] = Text[i]; //Text + } + Buffer[(*Length)++] = 0x00; //END Inline string + Buffer[(*Length)++] = 0x01; //END PARMeter +} + +/* http://forum.nokia.com: OTA MMS Settings 1.0, OTA Settings 7.0 */ +static void AddWAPSMSParameterInt(unsigned char *Buffer, int *Length, unsigned char ID, unsigned char Value) +{ + Buffer[(*Length)++] = 0x87; //PARM with attributes + Buffer[(*Length)++] = ID; + Buffer[(*Length)++] = Value; + Buffer[(*Length)++] = 0x01; //END PARMeter +} + +/* http://forum.nokia.com : OTA MMS Settings 1.0, OTA Settings 7.0 + * http://www.wapforum.org : Wireless Datagram Protocol + */ +void NOKIA_EncodeWAPMMSSettingsSMSText(unsigned char *Buffer, int *Length, GSM_WAPSettings *settings, bool MMS) +{ + int i; + unsigned char buffer[400]; + + Buffer[(*Length)++] = 0x01; //Push ID + Buffer[(*Length)++] = 0x06; //PDU Type (push) + Buffer[(*Length)++] = 0x2C; //Headers length (content type + headers) + strcpy(Buffer+(*Length),"\x1F\x2A"); + (*Length)=(*Length)+2; //Value length + strcpy(Buffer+(*Length),"application/x-wap-prov.browser-settings"); + (*Length)=(*Length)+39; //MIME-Type + Buffer[(*Length)++] = 0x00; //end inline string + strcpy(Buffer+(*Length),"\x81\xEA"); + (*Length)=(*Length)+2; //charset UTF-8 short int. + strcpy(Buffer+(*Length),"\x01\x01"); + (*Length)=(*Length)+2; //version WBXML 1.1 + Buffer[(*Length)++] = 0x6A; //charset UTF-8 + Buffer[(*Length)++] = 0x00; //string table length + + Buffer[(*Length)++] = 0x45; //CHARACTERISTIC-LIST with content + Buffer[(*Length)++] = 0xC6; //CHARACTERISTIC with content and attributes + Buffer[(*Length)++] = 0x06; //TYPE=ADDRESS + Buffer[(*Length)++] = 0x01; //END PARMeter + switch (settings->Bearer) { + case WAPSETTINGS_BEARER_GPRS: + /* Bearer */ + AddWAPSMSParameterInt(Buffer, Length, 0x12, 0x49); + /* PPP_LOGINTYPE (manual login or not) */ + if (settings->ManualLogin) { + AddWAPSMSParameterInt(Buffer, Length, 0x1D, 0x65); + } else { + AddWAPSMSParameterInt(Buffer, Length, 0x1D, 0x64); + } + /* PPP_AUTHTYPE*/ + if (settings->IsNormalAuthentication) { + /* OTA_CSD_AUTHTYPE_PAP */ + AddWAPSMSParameterInt(Buffer, Length, 0x22, 0x70); + } else { + /* OTA_CSD_AUTHTYPE_CHAP */ + AddWAPSMSParameterInt(Buffer, Length, 0x22, 0x71); + } + /* GPRS_ACCESSPOINTNAME */ + AddWAPSMSParameterText(Buffer, Length, 0x1C, DecodeUnicodeString(settings->DialUp), UnicodeLength(settings->DialUp)); + /* PROXY */ + AddWAPSMSParameterText(Buffer, Length, 0x13, DecodeUnicodeString(settings->IPAddress), UnicodeLength(settings->IPAddress)); + /* PPP_AUTHNAME (user) */ + AddWAPSMSParameterText(Buffer, Length, 0x23, DecodeUnicodeString(settings->User), UnicodeLength(settings->User)); + /* PPP_AUTHSECRET (password) */ + AddWAPSMSParameterText(Buffer, Length, 0x24, DecodeUnicodeString(settings->Password), UnicodeLength(settings->Password)); + break; + case WAPSETTINGS_BEARER_DATA: + /* Bearer */ + AddWAPSMSParameterInt(Buffer, Length, 0x12, 0x45); + /* CSD_DIALSTRING */ + AddWAPSMSParameterText(Buffer, Length, 0x21, DecodeUnicodeString(settings->DialUp), UnicodeLength(settings->DialUp)); + /* PROXY */ + AddWAPSMSParameterText(Buffer, Length, 0x13, DecodeUnicodeString(settings->IPAddress), UnicodeLength(settings->IPAddress)); + /* PPP_LOGINTYPE (manual login or not) */ + if (settings->ManualLogin) { + AddWAPSMSParameterInt(Buffer, Length, 0x1D, 0x65); + } else { + AddWAPSMSParameterInt(Buffer, Length, 0x1D, 0x64); + } + /* PPP_AUTHTYPE*/ + if (settings->IsNormalAuthentication) { + /* OTA_CSD_AUTHTYPE_PAP */ + AddWAPSMSParameterInt(Buffer, Length, 0x22, 0x70); + } else { + /* OTA_CSD_AUTHTYPE_CHAP */ + AddWAPSMSParameterInt(Buffer, Length, 0x22, 0x71); + } + /* CSD_CALLTYPE (type of call) */ + if (settings->IsISDNCall) { + /* ISDN */ + AddWAPSMSParameterInt(Buffer, Length, 0x28, 0x73); + } else { + /* analogue */ + AddWAPSMSParameterInt(Buffer, Length, 0x28, 0x72); + } + /* CSD_CALLSPEED (speed of call) */ + switch (settings->Speed) { + case WAPSETTINGS_SPEED_AUTO: + AddWAPSMSParameterInt(Buffer, Length, 0x29, 0x6A); + break; + case WAPSETTINGS_SPEED_9600: + AddWAPSMSParameterInt(Buffer, Length, 0x29, 0x6B); + break; + case WAPSETTINGS_SPEED_14400: + AddWAPSMSParameterInt(Buffer, Length, 0x29, 0x6C); + } + /* PPP_AUTHNAME (user) */ + AddWAPSMSParameterText(Buffer, Length, 0x23, DecodeUnicodeString(settings->User), UnicodeLength(settings->User)); + /* PPP_AUTHSECRET (password) */ + AddWAPSMSParameterText(Buffer, Length, 0x24, DecodeUnicodeString(settings->Password), UnicodeLength(settings->Password)); + break; +#ifdef DEVELOP + case WAPSETTINGS_BEARER_SMS: + /* Bearer */ + AddWAPSMSParameterInt(Buffer, Length, 0x12, 0x41); + /* PROXY */ + AddWAPSMSParameterText(Buffer, Length, 0x13, DecodeUnicodeString(settings->Server), UnicodeLength(settings->Server)); + /* SMS_SMSC_ADDRESS */ + // ..... + break; + case WAPSETTINGS_BEARER_USSD: + /* FIXME */ + /* Bearer */ + AddWAPSMSParameterInt(Buffer, Length, 0x12, 0x41); + /* PROXY */ + AddWAPSMSParameterText(Buffer, Length, 0x13, DecodeUnicodeString(settings->Service), UnicodeLength(settings->Service)); + /* USSD_SERVICE_CODE */ + /* FIXME */ + AddWAPSMSParameterText(Buffer, Length, 0x13, DecodeUnicodeString(settings->Code), UnicodeLength(settings->Code)); +#else + case WAPSETTINGS_BEARER_SMS: + case WAPSETTINGS_BEARER_USSD: + break; +#endif + } + /* PORT */ + if (settings->IsSecurity) { + if (settings->IsContinuous) { + /* Port = 9203. Continuous */ + AddWAPSMSParameterInt(Buffer, Length, 0x14, 0x63); + } else { + /* Port = 9202. Temporary */ + AddWAPSMSParameterInt(Buffer, Length, 0x14, 0x62); + } + } else { + if (settings->IsContinuous) { + /* Port = 9201. Continuous */ + AddWAPSMSParameterInt(Buffer, Length, 0x14, 0x61); + } else { + /* Port = 9200. Temporary */ + AddWAPSMSParameterInt(Buffer, Length, 0x14, 0x60); + } + } + Buffer[(*Length)++] = 0x01; //END PARMeter + + /* URL */ + Buffer[(*Length)++] = 0x86; //CHARACTERISTIC-LIST with attributes + if (MMS) { + Buffer[(*Length)++] = 0x7C; //TYPE = MMSURL + } else { + Buffer[(*Length)++] = 0x07; //TYPE = URL + } + Buffer[(*Length)++] = 0x11; //VALUE + Buffer[(*Length)++] = 0x03; //Inline string + sprintf(buffer,"%s",DecodeUnicodeString(settings->HomePage)); + for (i=0;i<(int)strlen(buffer);i++) { + Buffer[(*Length)++] = buffer[i];//Text + } + Buffer[(*Length)++] = 0x00; //END Inline string + Buffer[(*Length)++] = 0x01; //END PARMeter + + /* ISP_NAME (name) */ + Buffer[(*Length)++] = 0xC6; //CHARACTERISTIC with content and attributes + Buffer[(*Length)++] = 0x08; //TYPE=NAME + Buffer[(*Length)++] = 0x01; //END PARMeter + /* Settings name */ + AddWAPSMSParameterText(Buffer, Length, 0x15, DecodeUnicodeString(settings->Title), UnicodeLength(settings->Title)); + Buffer[(*Length)++] = 0x01; //END PARMeter + Buffer[(*Length)++] = 0x01; //END PARMeter +} + +/* http://forum.nokia.com: OTA Settings 7.0 */ +void NOKIA_EncodeWAPBookmarkSMSText(unsigned char *Buffer, int *Length, GSM_WAPBookmark *bookmark) +{ + unsigned char buffer[100]; + bool UnicodeCoding = false; + + EncodeUTF8QuotedPrintable(buffer,bookmark->Title); + if (UnicodeLength(bookmark->Title)!=strlen(buffer)) UnicodeCoding = true; + + Buffer[(*Length)++] = 0x01; //Push ID + Buffer[(*Length)++] = 0x06; //PDU Type (push) + Buffer[(*Length)++] = 0x2D; //Headers length (content type + headers) + strcpy(Buffer+(*Length),"\x1F\x2B"); + (*Length)=(*Length)+2; //Value length + strcpy(Buffer+(*Length),"application/x-wap-prov.browser-bookmarks"); + (*Length)=(*Length)+40; //MIME-Type + Buffer[(*Length)++] = 0x00; //end inline string + strcpy(Buffer+(*Length),"\x81\xEA"); + (*Length)=(*Length)+2; //charset UTF-8 short int. + + /* Block from sniffs. UNKNOWN */ + if (!UnicodeCoding) { + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = 0x01; + } else { + strcpy(Buffer+(*Length),"\x01\x01\x87\x68"); + (*Length)=(*Length)+4; + } + Buffer[(*Length)++] = 0x00; + + Buffer[(*Length)++] = 0x45; //CHARACTERISTIC-LIST with content + /* URL */ + Buffer[(*Length)++] = 0xC6; //CHARACTERISTIC with content and attributes + Buffer[(*Length)++] = 0x7F; //TYPE = BOOKMARK + Buffer[(*Length)++] = 0x01; //END PARMeter + if (!UnicodeCoding) { + /* TITLE */ + AddWAPSMSParameterText(Buffer, Length, 0x15, DecodeUnicodeString(bookmark->Title), UnicodeLength(bookmark->Title)); + /* URL */ + AddWAPSMSParameterText(Buffer, Length, 0x17, DecodeUnicodeString(bookmark->Address), UnicodeLength(bookmark->Address)); + } else { + /* TITLE */ + AddWAPSMSParameterText(Buffer, Length, 0x15, bookmark->Title, UnicodeLength(bookmark->Title)*2+1); + /* URL */ + AddWAPSMSParameterText(Buffer, Length, 0x17, bookmark->Address, UnicodeLength(bookmark->Address)*2+1); + } + Buffer[(*Length)++] = 0x01; //END PARMeter + Buffer[(*Length)++] = 0x01; //END PARMeter +} + +void GSM_EncodeMMSFile(GSM_EncodeMultiPartMMSInfo *Info, unsigned char *Buffer, int *Length) +{ + int i; + + strcpy(Buffer+(*Length),"\x8C\x80\x98\x4F"); + (*Length)=(*Length)+4; + + /* Unique MMS ID ? */ + strcpy(Buffer+(*Length),"123456789"); + (*Length)=(*Length)+9; + Buffer[(*Length)++] = 0x00; + + strcpy(Buffer+(*Length),"\x8D\x90\x89"); + (*Length)=(*Length)+3; + + strcpy(Buffer+(*Length),"\x01\x81\x86\x81\x96"); + (*Length)=(*Length)+5; + + if (UnicodeLength(Info->Subject) != 0) { + sprintf(Buffer+(*Length),"%s",DecodeUnicodeString(Info->Subject)); + (*Length)=(*Length)+UnicodeLength(Info->Subject); + Buffer[(*Length)++] = 0x00; + } + + for (i=0;i<Info->EntriesNum;i++) { + switch(Info->Entries[i].ID) { + case MMS_Text: + strcpy(Buffer+(*Length),"\x84\xA3\x01\x04\x04\x03\x83\x81\xEA"); + (*Length)=(*Length)+9; + + sprintf(Buffer+(*Length),"%s",DecodeUnicodeString(Info->Entries[i].Buffer)); + (*Length)=(*Length)+UnicodeLength(Info->Entries[i].Buffer); + break; + default: + break; + } + } +} + +void GSM_ClearMultiPartMMSInfo(GSM_EncodeMultiPartMMSInfo *Info) +{ + Info->EntriesNum = 0; + Info->Subject[0] = 0x00; + Info->Subject[1] = 0x00; + Info->Source[0] = 0x00; + Info->Source[1] = 0x00; + Info->Destination[0] = 0x00; + Info->Destination[1] = 0x00; +} + +GSM_Error GSM_EncodeURLFile(unsigned char *Buffer, int *Length, GSM_WAPBookmark *bookmark) +{ + *Length+=sprintf(Buffer+(*Length), "BEGIN:VBKM%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "VERSION:1.0%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "TITLE:%s%c%c",DecodeUnicodeString(bookmark->Title),13,10); + *Length+=sprintf(Buffer+(*Length), "URL:%s%c%c",DecodeUnicodeString(bookmark->Address),13,10); + *Length+=sprintf(Buffer+(*Length), "BEGIN:ENV%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "X-IRMC-URL;QUOTED-PRINTABLE:=%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "[InternetShortcut] =%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "URL=%s%c%c",DecodeUnicodeString(bookmark->Address),13,10); + *Length+=sprintf(Buffer+(*Length), "END:ENV%c%c",13,10); + *Length+=sprintf(Buffer+(*Length), "END:VBKM%c%c",13,10); + + return ERR_NONE; +} + +/* 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/service/gsmdata.h b/gammu/emb/common/service/gsmdata.h new file mode 100644 index 0000000..f5f8e07 --- a/dev/null +++ b/gammu/emb/common/service/gsmdata.h @@ -0,0 +1,152 @@ +/* (c) 2001-2004 by Marcin Wiacek */ + +#ifndef __gsm_wap_h +#define __gsm_wap_h + +#include "gsmmisc.h" +#include "../misc/misc.h" + +/* --------------------------- WAP or MMS settings ------------------------- */ + +typedef enum { + WAPSETTINGS_SPEED_9600, + WAPSETTINGS_SPEED_14400, + WAPSETTINGS_SPEED_AUTO +} WAPSettings_Speed; + +typedef enum { + WAPSETTINGS_BEARER_SMS = 1, + WAPSETTINGS_BEARER_DATA, + WAPSETTINGS_BEARER_USSD, + WAPSETTINGS_BEARER_GPRS +} WAPSettings_Bearer; + +typedef struct { + char Title [(20+1)*2]; + char HomePage [(100+1)*2]; + WAPSettings_Bearer Bearer; + bool IsSecurity; + bool IsContinuous; + + /* for data bearer */ + bool IsISDNCall; + bool IsNormalAuthentication; + + /* for sms bearer */ + char Server [(21+1)*2]; + + /* for sms or ussd bearer */ + char Service [(20+1)*2]; + bool IsIP; + + /* for ussd bearer */ + char Code [(10+1)*2]; + + /* for data or gprs */ + char IPAddress [(20+1)*2]; + bool ManualLogin; + char DialUp [(20+1)*2]; + char User [(50+1)*2]; /*is length OK ?*/ + char Password [(50+1)*2]; /*is length OK ?*/ + WAPSettings_Speed Speed; +} GSM_WAPSettings; + +typedef struct { + int Location; + unsigned char Number; + GSM_WAPSettings Settings[4]; + bool Active; + bool ReadOnly; + char Proxy [(100+1)*2]; + int ProxyPort; + char Proxy2 [(100+1)*2]; + int Proxy2Port; + + WAPSettings_Bearer ActiveBearer; +} GSM_MultiWAPSettings; + +void NOKIA_EncodeWAPMMSSettingsSMSText(unsigned char *Buffer, int *Length, GSM_WAPSettings *settings, bool MMS); + +/* -------------------------------- WAP Bookmark --------------------------- */ + +typedef struct { + char Address [(255+1)*2]; + char Title [(50+1)*2]; + int Location; +} GSM_WAPBookmark; + +void NOKIA_EncodeWAPBookmarkSMSText (unsigned char *Buffer, int *Length, GSM_WAPBookmark *bookmark); +GSM_Error GSM_EncodeURLFile (unsigned char *Buffer, int *Length, GSM_WAPBookmark *bookmark); + +/* ------------------------------ MMS Indicator ---------------------------- */ + +typedef struct { + unsigned char Address[500]; + unsigned char Title[200]; + unsigned char Sender[200]; +} GSM_MMSIndicator; + +void GSM_EncodeMMSIndicatorSMSText(unsigned char *Buffer, int *Length, GSM_MMSIndicator Indicator); + +/* ------------------------------ MMS file --------------------------------- */ + +#define MAX_MULTI_MMS 20 + +typedef enum { + MMS_Text = 1, + MMS_Bitmap_JPG +} EncodeMultiPartMMSID; + +typedef struct { + EncodeMultiPartMMSID ID; + + GSM_File File; + unsigned char *Buffer; +} EncodeMultiPartMMSEntry; + +typedef struct { + /* Input values */ + EncodeMultiPartMMSEntry Entries[MAX_MULTI_MMS]; + int EntriesNum; + + unsigned char Source[200]; + unsigned char Destination[200]; + unsigned char Subject[200]; +} GSM_EncodeMultiPartMMSInfo; + +void GSM_EncodeMMSFile (GSM_EncodeMultiPartMMSInfo *Info, unsigned char *Buffer, int *Length); +void GSM_ClearMultiPartMMSInfo (GSM_EncodeMultiPartMMSInfo *Info); + +/* ------------------------------------------------------------------------ */ + +typedef struct { + int Location; + bool Active; + bool SyncPhonebook; + bool SyncCalendar; + char Name[(20+1)*2]; + char PhonebookDataBase[(50+1)*2]; + char CalendarDataBase[(50+1)*2]; + char User[(30+1)*2]; + char Password[(20+1)*2]; + char Server[(128+1)*2]; + GSM_MultiWAPSettings Connection; +} GSM_SyncMLSettings; + +/* ------------------------------------------------------------------------ */ + +typedef struct { + char Name[(50+1)*2]; + char HomePage[(200+1)*2]; + char User[(50+1)*2]; + char Password[(50+1)*2]; + int Location; + bool Active; + GSM_MultiWAPSettings Connection; +} GSM_ChatSettings; + +#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/service/gsmlogo.c b/gammu/emb/common/service/gsmlogo.c new file mode 100644 index 0000000..c992915 --- a/dev/null +++ b/gammu/emb/common/service/gsmlogo.c @@ -0,0 +1,1003 @@ +/* (c) 2001-2004 by Marcin Wiacek */ + +#include <string.h> +#include <stdlib.h> + +#include "../misc/misc.h" +#include "../misc/coding/coding.h" +#include "gsmlogo.h" +#include "gsmnet.h" + +void PHONE_GetBitmapWidthHeight(GSM_Phone_Bitmap_Types Type, int *width, int *height) +{ + *width = 0; + *height = 0; + switch (Type) { + case GSM_EMSSmallPicture : *width=8; *height=8; break; + case GSM_EMSMediumPicture : *width=16; *height=16; break; + case GSM_EMSBigPicture : *width=32; *height=32; break; + case GSM_NokiaOperatorLogo : + case GSM_NokiaCallerLogo : *width=72; *height=14; break; + case GSM_NokiaPictureImage : *width=72; *height=28; break; + case GSM_Nokia7110OperatorLogo : + case GSM_Nokia6510OperatorLogo : *width=78; *height=21; break; + case GSM_NokiaStartupLogo : *width=84; *height=48; break; + case GSM_Nokia6210StartupLogo : *width=96; *height=60; break; + case GSM_Nokia7110StartupLogo : *width=96; *height=65; break; + case GSM_EMSVariablePicture : break; + case GSM_AlcatelBMMIPicture : break; + } +} + +int PHONE_GetBitmapSize(GSM_Phone_Bitmap_Types Type, int Width, int Height) +{ + int width, height, x; + + PHONE_GetBitmapWidthHeight(Type, &width, &height); + if (width == 0 && height == 0) { + width = Width; + height = Height; + } + switch (Type) { + case GSM_Nokia6510OperatorLogo: + x = width * height; + return x/8 + (x%8 > 0); + case GSM_Nokia7110OperatorLogo: + return (width*height + 7)/8; + case GSM_NokiaStartupLogo: + case GSM_NokiaOperatorLogo: + case GSM_NokiaCallerLogo: + case GSM_NokiaPictureImage: + case GSM_EMSSmallPicture: + case GSM_EMSMediumPicture: + case GSM_EMSBigPicture: + case GSM_EMSVariablePicture: + return height*width/8; + case GSM_Nokia7110StartupLogo: + case GSM_Nokia6210StartupLogo: + return (height+7)/8*width; + case GSM_AlcatelBMMIPicture: + return width*((height+7)/8); + } + return 0; +} + +static bool PHONE_IsPointBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, int x, int y, int width, int height) +{ + int i=0, pixel; + + switch (Type) { + case GSM_NokiaStartupLogo: + case GSM_Nokia6210StartupLogo: + case GSM_Nokia7110StartupLogo: + case GSM_Nokia6510OperatorLogo: + i=(buffer[(y/8*width) + x] & 1<<(y%8)); + break; + case GSM_NokiaOperatorLogo: + case GSM_Nokia7110OperatorLogo: + case GSM_NokiaCallerLogo: + case GSM_EMSVariablePicture: + case GSM_EMSSmallPicture: + case GSM_EMSMediumPicture: + case GSM_EMSBigPicture: + pixel=width*y + x; + i=(buffer[pixel/8] & 1<<(7-(pixel%8))); + break; + case GSM_NokiaPictureImage: + i=(buffer[9*y + x/8] & 1<<(7-(x%8))); + break; + case GSM_AlcatelBMMIPicture: + break; + } + if (i) return true; else return false; +} + +static void PHONE_SetPointBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, int x, int y, int width, int height) +{ + int pixel; + + switch (Type) { + case GSM_NokiaStartupLogo: + case GSM_Nokia6210StartupLogo: + case GSM_Nokia7110StartupLogo: + case GSM_Nokia6510OperatorLogo: + buffer[(y/8*width)+x] |= 1 << (y%8); + break; + case GSM_NokiaOperatorLogo: + case GSM_Nokia7110OperatorLogo: + case GSM_NokiaCallerLogo: + case GSM_EMSSmallPicture: + case GSM_EMSMediumPicture: + case GSM_EMSBigPicture: + case GSM_EMSVariablePicture: + pixel = width*y + x; + buffer[pixel/8] |= 1 << (7-(pixel%8)); + break; + case GSM_NokiaPictureImage: + buffer[9*y + x/8] |= 1 << (7-(x%8)); + break; + case GSM_AlcatelBMMIPicture: + pixel = height / 8; + if ((height % 8) != 0) pixel++; + buffer[pixel*x + y/8] |= 1 << (7 - (y%8)); + break; + } +} + +void PHONE_DecodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap) +{ + int width, height, x,y; + + PHONE_GetBitmapWidthHeight(Type, &width, &height); + if (Type != GSM_Nokia6510OperatorLogo && Type != GSM_Nokia7110OperatorLogo && Type != GSM_EMSVariablePicture) { + Bitmap->BitmapHeight = height; + Bitmap->BitmapWidth = width; + } + switch (Type) { + case GSM_NokiaOperatorLogo : + case GSM_Nokia7110OperatorLogo : + case GSM_Nokia6510OperatorLogo : Bitmap->Type=GSM_OperatorLogo; break; + case GSM_NokiaCallerLogo : Bitmap->Type=GSM_CallerGroupLogo; break; + case GSM_AlcatelBMMIPicture : + case GSM_NokiaStartupLogo : + case GSM_Nokia7110StartupLogo : + case GSM_Nokia6210StartupLogo : Bitmap->Type=GSM_StartupLogo; break; + case GSM_NokiaPictureImage : + case GSM_EMSVariablePicture : + case GSM_EMSSmallPicture : + case GSM_EMSMediumPicture : + case GSM_EMSBigPicture : Bitmap->Type=GSM_PictureImage; break; + } + + Bitmap->Location = 0; + Bitmap->Text[0] = 0; + Bitmap->Text[1] = 0; + Bitmap->BitmapEnabled = false; + Bitmap->DefaultName = false; + Bitmap->DefaultBitmap = false; + Bitmap->DefaultRingtone = false; + Bitmap->RingtoneID = 0; + Bitmap->NetworkCode[0] = 0; + Bitmap->Sender[0] = 0; + Bitmap->Sender[1] = 0; + Bitmap->ID = 0; + + GSM_ClearBitmap(Bitmap); + for (x=0;x<Bitmap->BitmapWidth;x++) { + for (y=0;y<Bitmap->BitmapHeight;y++) { + if (PHONE_IsPointBitmap(Type, buffer, x, y, Bitmap->BitmapWidth, Bitmap->BitmapHeight)) { + GSM_SetPointBitmap(Bitmap,x,y); + } + } + } +} + +void PHONE_ClearBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, int width, int height) +{ + memset(buffer,0,PHONE_GetBitmapSize(Type,width,height)); +} + +void PHONE_EncodeBitmap(GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap) +{ + int width, height, x, y; + GSM_Bitmap dest; + + PHONE_GetBitmapWidthHeight(Type, &width, &height); + if (width == 0 && height == 0) { + width = Bitmap->BitmapWidth; + height = Bitmap->BitmapHeight; + } + GSM_ResizeBitmap(&dest, Bitmap, width, height); + PHONE_ClearBitmap(Type, buffer, width, height); + + for (x=0;x<width;x++) { + for (y=0;y<height;y++) { + if (GSM_IsPointBitmap(&dest,x,y)) PHONE_SetPointBitmap(Type, buffer, x, y, width, height); + } + } +} + +void GSM_GetMaxBitmapWidthHeight(GSM_Bitmap_Types Type, unsigned char *width, unsigned char *height) +{ + switch (Type) { + case GSM_CallerGroupLogo: *width=72; *height=14; break; + case GSM_OperatorLogo : *width=101;*height=21; break; + case GSM_StartupLogo : *width=96; *height=65; break; + case GSM_PictureImage : *width=72; *height=28; break; + default : break; + } +} + +void GSM_SetPointBitmap(GSM_Bitmap *bmp, int x, int y) +{ + SetBit(bmp->BitmapPoints,y*bmp->BitmapWidth+x); +} + +void GSM_ClearPointBitmap(GSM_Bitmap *bmp, int x, int y) +{ + ClearBit(bmp->BitmapPoints,y*bmp->BitmapWidth+x); +} + +bool GSM_IsPointBitmap(GSM_Bitmap *bmp, int x, int y) +{ + if (GetBit(bmp->BitmapPoints,y*bmp->BitmapWidth+x)) return true; else return false; +} + +void GSM_ClearBitmap(GSM_Bitmap *bmp) +{ + memset(bmp->BitmapPoints,0,GSM_GetBitmapSize(bmp)); +} + +int GSM_GetBitmapSize(GSM_Bitmap *bmp) +{ + return bmp->BitmapWidth*bmp->BitmapHeight/8+1; +} + +void GSM_PrintBitmap(FILE *file, GSM_Bitmap *bitmap) +{ + int x,y; + + for (y=0;y<bitmap->BitmapHeight;y++) { + for (x=0;x<bitmap->BitmapWidth;x++) { + if (GSM_IsPointBitmap(bitmap,x,y)) { + fprintf(file,"#"); + } else { + fprintf(file," "); + } + } + fprintf(file,"\n"); + } +} + +void GSM_ReverseBitmap(GSM_Bitmap *Bitmap) +{ + int x, y; + + for (x=0;x<Bitmap->BitmapWidth;x++) { + for (y=0;y<Bitmap->BitmapHeight;y++) { + if (GSM_IsPointBitmap(Bitmap,x,y)) { + GSM_ClearPointBitmap(Bitmap, x, y); + } else { + GSM_SetPointBitmap(Bitmap, x, y); + } + } + } +} + +void GSM_ResizeBitmap(GSM_Bitmap *dest, GSM_Bitmap *src, int width, int height) +{ + int startx=0,endx=0,setx=0, starty=0,endy=0,sety=0, x, y; + + if (src->BitmapWidth<=width) { + startx = 0; + endx = src->BitmapWidth; + setx = (width-src->BitmapWidth)/2; + } else { + startx = (src->BitmapWidth-width)/2; + endx = startx + width; + setx = 0; + } + if (src->BitmapHeight<=height) { + starty = 0; + endy = src->BitmapHeight; + sety = (height-src->BitmapHeight)/2; + } else { + starty = (src->BitmapHeight-height)/2; + endy = starty + height; + sety = 0; + } + dest->BitmapHeight = height; + dest->BitmapWidth = width; + GSM_ClearBitmap(dest); + for (x=startx;x<endx;x++) { + for (y=starty;y<endy;y++) { + if (GSM_IsPointBitmap(src,x,y)) + GSM_SetPointBitmap(dest,setx+x-startx,sety+y-starty); + } + } +} + +GSM_Error Bitmap2BMP(unsigned char *buffer, FILE *file,GSM_Bitmap *bitmap) +{ + int x,y,pos,i,sizeimage,buffpos=0; + unsigned char buff[1]; + div_t division; + bool isfile=false; + + unsigned char header[]={ +/*1'st header*/ 'B','M', /* BMP file ID */ + 0x00,0x00,0x00,0x00, /* Size of file */ + 0x00,0x00, /* Reserved for future use */ + 0x00,0x00, /* Reserved for future use */ + 62,0x00,0x00,0x00, /* Offset for image data */ + +/*2'nd header*/ 40,0x00,0x00,0x00, /* Length of this part of header */ + 0x00,0x00,0x00,0x00, /* Width of image */ + 0x00,0x00,0x00,0x00, /* Height of image */ + 1,0x00, /* How many planes in target device */ + 1,0x00, /* How many colors in image. 1 means 2^1=2 colors */ + 0x00,0x00,0x00,0x00, /* Type of compression. 0 means no compression */ +/*Sometimes */ 0x00,0x00,0x00,0x00, /* Size of part with image data */ +/*ttttttt...*/ 0xE8,0x03,0x00,0x00, /* XPelsPerMeter */ +/*hhiiiiissss*/ 0xE8,0x03,0x00,0x00, /* YPelsPerMeter */ +/*part of header*/0x02,0x00,0x00,0x00, /* How many colors from palette is used */ +/*doesn't exist*/ 0x00,0x00,0x00,0x00, /* How many colors from palette is required to display image. 0 means all */ + +/*Color palette*/ 0x00,0x00,0x00, /* First color in palette in Blue, Green, Red. Here white */ + 0x00, /* Each color in palette is end by 4'th byte */ + 102, 204, 102, /* Second color in palette in Blue, Green, Red. Here green */ + 0x00}; /* Each color in palette is end by 4'th byte */ + + if (file!=NULL) isfile=true; + + header[22]=bitmap->BitmapHeight; + header[18]=bitmap->BitmapWidth; + + pos = 7; + sizeimage = 0; + /*lines are written from the last to the first*/ + for (y=bitmap->BitmapHeight-1;y>=0;y--) { + i=1; + for (x=0;x<bitmap->BitmapWidth;x++) { + /*new byte !*/ + if (pos==7) { + if (x!=0) sizeimage++; + i++; + /*each line is written in multiply of 4 bytes*/ + if(i==5) i=1; + } + pos--; + /*going to new byte*/ + if (pos<0) pos=7; + } + /*going to new byte*/ + pos=7; + sizeimage++; + if (i!=1) { + /*each line is written in multiply of 4 bytes*/ + while (i!=5) { + sizeimage++; + i++; + } + } + } + dbgprintf("Data size in BMP file: %i\n",sizeimage); + division=div(sizeimage,256); + header[35]=division.quot; + header[34]=sizeimage-(division.quot*256); + sizeimage=sizeimage+sizeof(header); + dbgprintf("Size of BMP file: %i\n",sizeimage); + division=div(sizeimage,256); + header[3]=division.quot; + header[2]=sizeimage-(division.quot*256); + + if (isfile) { + fwrite(header,1,sizeof(header),file); + } else { + memcpy(buffer,header,sizeof(header)); + buffpos += sizeof(header); + } + + pos=7; + /*lines are written from the last to the first*/ + for (y=bitmap->BitmapHeight-1;y>=0;y--) { + i=1; + for (x=0;x<bitmap->BitmapWidth;x++) { + /*new byte !*/ + if (pos==7) { + if (x!=0) { + if (isfile) { + fwrite(buff, 1, sizeof(buff), file); + } else { + memcpy (buffer+buffpos,buff,1); + buffpos++; + } + } + i++; + /*each line is written in multiply of 4 bytes*/ + if(i==5) i=1; + buff[0]=0; + } + if (!GSM_IsPointBitmap(bitmap,x,y)) buff[0]|=(1<<pos); + pos--; + /*going to new byte*/ + if (pos<0) pos=7; + } + /*going to new byte*/ + pos=7; + if (isfile) { + fwrite(buff, 1, sizeof(buff), file); + } else { + memcpy (buffer+buffpos,buff,1); + buffpos++; + } + if (i!=1) { + /*each line is written in multiply of 4 bytes*/ + while (i!=5) { + buff[0]=0; + if (isfile) { + fwrite(buff, 1, sizeof(buff), file); + } else { + memcpy (buffer+buffpos,buff,1); + buffpos++; + } + i++; + } + } + } + return ERR_NONE; +} + +static GSM_Error savebmp(FILE *file, GSM_MultiBitmap *bitmap) +{ + GSM_Error error; + + error=Bitmap2BMP(NULL,file,&bitmap->Bitmap[0]); + return error; +} + +static void PrivSaveNLMWBMP(FILE *file, GSM_Bitmap *Bitmap) +{ + unsigned char buffer[1000]; + int x,y,pos,pos2; + div_t division; + + pos=0;pos2=7; + for (y=0;y<Bitmap->BitmapHeight;y++) { + for (x=0;x<Bitmap->BitmapWidth;x++) { + if (pos2==7) buffer[pos]=0; + if (GSM_IsPointBitmap(Bitmap,x,y)) buffer[pos]|=(1<<pos2); + pos2--; + /* going to new line */ + if (pos2<0) {pos2=7;pos++;} + } + /* for startup logos - new line with new byte */ + if (pos2!=7) {pos2=7;pos++;} + } + + division=div(Bitmap->BitmapWidth,8); + /* For startup logos */ + if (division.rem!=0) division.quot++; + + fwrite(buffer,1,(division.quot*Bitmap->BitmapHeight),file); +} + +static GSM_Error savenlm(FILE *file, GSM_MultiBitmap *bitmap) +{ + int i; + char header[]={ + 'N','L','M',' ', /* Nokia Logo Manager file ID. */ + 0x01, + 0x00, /* 0x00 (OP), 0x01 (CLI), 0x02 (Startup), 0x03 (Picture)*/ + 0x00, /* Number of images inside file - 1. 0x01==2 images, 0x03==4 images, etc. */ + 0x00, /* Width. */ + 0x00, /* Height. */ + 0x01}; + + switch (bitmap->Bitmap[0].Type) { + case GSM_OperatorLogo : header[5]=0x00; break; + case GSM_CallerGroupLogo : header[5]=0x01; break; + case GSM_StartupLogo : header[5]=0x02; break; + case GSM_PictureImage : header[5]=0x03; break; + default : return ERR_UNKNOWN; + } + header[6] = bitmap->Number - 1; + header[7] = bitmap->Bitmap[0].BitmapWidth; + header[8] = bitmap->Bitmap[0].BitmapHeight; + fwrite(header,1,sizeof(header),file); + + for (i=0;i<bitmap->Number;i++) { + PrivSaveNLMWBMP(file, &bitmap->Bitmap[i]); + } + + return ERR_NONE; +} + +static void PrivSaveNGGNOL(FILE *file, GSM_MultiBitmap *bitmap) +{ + char buffer[GSM_BITMAP_SIZE]; + int x,y,current=0; + + for (y=0;y<bitmap->Bitmap[0].BitmapHeight;y++) { + for (x=0;x<bitmap->Bitmap[0].BitmapWidth;x++) { + if (GSM_IsPointBitmap(&bitmap->Bitmap[0],x,y)) { + buffer[current++] = '1'; + } else { + buffer[current++] = '0'; + } + } + } + fwrite(buffer,1,current,file); +} + +static GSM_Error savengg(FILE *file, GSM_MultiBitmap *bitmap) +{ + char header[]={ + 'N','G','G',0x00,0x01,0x00, + 0x00,0x00, /* Width */ + 0x00,0x00, /* Height */ + 0x01,0x00,0x01,0x00, + 0x00, /* Unknown.Can't be checksum - for */ + /* the same logo files can be different */ + 0x00}; + + header[6] = bitmap->Bitmap[0].BitmapWidth; + header[8] = bitmap->Bitmap[0].BitmapHeight; + fwrite(header,1,sizeof(header),file); + + PrivSaveNGGNOL(file,bitmap); + + return ERR_NONE; +} + +static GSM_Error savenol(FILE *file, GSM_MultiBitmap *bitmap) +{ + int country,net; + char header[]={ + 'N','O','L',0x00,0x01,0x00, + 0x00,0x00, /* MCC */ + 0x00,0x00, /* MNC */ + 0x00,0x00, /* Width */ + 0x00,0x00, /* Height */ + 0x01,0x00,0x01,0x00, + 0x00, /* Unknown.Can't be checksum - for */ + /* the same logo files can be different */ + 0x00}; + + if (bitmap->Bitmap[0].Type == GSM_OperatorLogo) sscanf(bitmap->Bitmap[0].NetworkCode, "%d %d", &country, &net); + + header[6] = country%256; + header[7] = country/256; + header[8] = net%256; + header[9] = net/256; + header[10] = bitmap->Bitmap[0].BitmapWidth; + header[12] = bitmap->Bitmap[0].BitmapHeight; + fwrite(header,1,sizeof(header),file); + + PrivSaveNGGNOL(file,bitmap); + + return ERR_NONE; +} + +static GSM_Error savexpm(FILE *file, GSM_MultiBitmap *bitmap) +{ + int x,y; + + fprintf(file,"/* XPM */\n"); + fprintf(file,"static char * ala_xpm[] = {\n"); + fprintf(file,"\"%i %i 2 1\",\n",bitmap->Bitmap[0].BitmapWidth,bitmap->Bitmap[0].BitmapHeight); + fprintf(file,"\". s c m #000000 g4 #000000 g #000000 c #000000\",\n"); + fprintf(file,"\"# s c m #ffffff g4 #ffffff g #ffffff c #ffffff\",\n"); + + for (y=0;y<bitmap->Bitmap[0].BitmapHeight;y++) { + fprintf(file,"\""); + for (x=0;x<bitmap->Bitmap[0].BitmapWidth;x++) + if (GSM_IsPointBitmap(&bitmap->Bitmap[0],x,y)) { + fprintf(file,"."); + } else { + fprintf(file,"#"); + } + fprintf(file,"\""); + if (y==bitmap->Bitmap[0].BitmapHeight-1) { + fprintf(file,"};\n"); + } else { + fprintf(file,",\n"); + } + } + + return ERR_NONE; +} + +static GSM_Error savensl(FILE *file, GSM_MultiBitmap *bitmap) +{ + char buffer[GSM_BITMAP_SIZE]; + unsigned char header[]={ + 'F','O','R','M', 0x01,0xFE, /* File ID block, size 1*256+0xFE=510*/ + 'N','S','L','D', 0x01,0xF8}; /* Startup Logo block, size 1*256+0xF8=504*/ + + fwrite(header,1,sizeof(header),file); + PHONE_EncodeBitmap(GSM_NokiaStartupLogo, buffer, &bitmap->Bitmap[0]); + fwrite(buffer,1,PHONE_GetBitmapSize(GSM_NokiaStartupLogo,0,0),file); + + return ERR_NONE; +} + +static GSM_Error savewbmp(FILE *file, GSM_MultiBitmap *bitmap) +{ + unsigned char buffer[4]; + + buffer[0] = 0x00; + buffer[1] = 0x00; + buffer[2] = bitmap->Bitmap[0].BitmapWidth; + buffer[3] = bitmap->Bitmap[0].BitmapHeight; + fwrite(buffer,1,4,file); + + PrivSaveNLMWBMP(file, &bitmap->Bitmap[0]); + + return ERR_NONE; +} + +GSM_Error GSM_SaveBitmapFile(char *FileName, GSM_MultiBitmap *bitmap) +{ + FILE *file; + GSM_Error error=ERR_NONE; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + /* Attempt to identify filetype */ + if (strstr(FileName,".nlm")) { + error=savenlm(file,bitmap); + } else if (strstr(FileName,".ngg")) { + error=savengg(file,bitmap); + } else if (strstr(FileName,".nol")) { + error=savenol(file,bitmap); + } else if (strstr(FileName,".xpm")) { + error=savexpm(file,bitmap); + } else if (strstr(FileName,".nsl")) { + error=savensl(file,bitmap); + } else if (strstr(FileName,".wbmp")) { + error=savewbmp(file,bitmap); + } else { + error=savebmp(file,bitmap); + } + fclose(file); + + return error; +} + +GSM_Error BMP2Bitmap(unsigned char *buffer, FILE *file,GSM_Bitmap *bitmap) +{ + bool first_white,isfile=false; + unsigned char buff[34]; + int w,h,pos,y,x,i,buffpos=0; +#ifdef DEBUG + int sizeimage=0; +#endif + + if (bitmap->Type == GSM_None) bitmap->Type = GSM_StartupLogo; + if (file!=NULL) isfile=true; + if (isfile) { + fread(buff, 1, 34, file); + } else { + memcpy(buff,buffer,34); + } + + /* height and width of image in the file */ + h=buff[22]+256*buff[21]; + w=buff[18]+256*buff[17]; + dbgprintf("Image Size in BMP file: %dx%d\n",w,h); + + GSM_GetMaxBitmapWidthHeight(bitmap->Type, &bitmap->BitmapWidth, &bitmap->BitmapHeight); + if (h<bitmap->BitmapHeight) bitmap->BitmapHeight=h; + if (w<bitmap->BitmapWidth) bitmap->BitmapWidth=w; + dbgprintf("Height %i %i, width %i %i\n",h,bitmap->BitmapHeight,w,bitmap->BitmapWidth); + + GSM_ClearBitmap(bitmap); + +#ifdef DEBUG + dbgprintf("Number of colors in BMP file: "); + switch (buff[28]) { + case 1 : dbgprintf("2 (supported)\n"); break; + case 4 : dbgprintf("16 (NOT SUPPORTED)\n"); break; + case 8 : dbgprintf("256 (NOT SUPPORTED)\n"); break; + case 24 : dbgprintf("True Color (NOT SUPPORTED)\n"); break; + default : dbgprintf("unknown\n"); break; + } +#endif + if (buff[28]!=1) { + dbgprintf("Wrong number of colors\n"); + return ERR_FILENOTSUPPORTED; + } + +#ifdef DEBUG + dbgprintf("Compression in BMP file: "); + switch (buff[30]) { + case 0 :dbgprintf("no compression (supported)\n"); break; + case 1 :dbgprintf("RLE8 (NOT SUPPORTED)\n"); break; + case 2 :dbgprintf("RLE4 (NOT SUPPORTED)\n"); break; + default :dbgprintf("unknown\n"); break; + } +#endif + if (buff[30]!=0) { + dbgprintf("Compression type not supported\n"); + return ERR_FILENOTSUPPORTED; + } + + /* read rest of header (if exists) and color palette */ + if (isfile) { + pos=buff[10]-34; + fread(buff, 1, pos, file); + } else { + pos=buff[10]-34; + buffpos=buff[10];
+ memcpy (buff,buffer+34,pos); + } + +#ifdef DEBUG + dbgprintf("First color in BMP file: %i %i %i ",buff[pos-8], buff[pos-7], buff[pos-6]); + if (buff[pos-8]==0 && buff[pos-7]==0 && buff[pos-6]==0) dbgprintf("(white)"); + if (buff[pos-8]==0xFF && buff[pos-7]==0xFF && buff[pos-6]==0xFF) dbgprintf("(black)"); + if (buff[pos-8]==102 && buff[pos-7]==204 && buff[pos-6]==102) dbgprintf("(green)"); + dbgprintf("\n"); + dbgprintf("Second color in BMP file: %i %i %i ",buff[pos-38], buff[pos-37], buff[pos-36]); + if (buff[pos-4]==0 && buff[pos-3]==0 && buff[pos-2]==0) dbgprintf("(white)"); + if (buff[pos-4]==0xFF && buff[pos-3]==0xFF && buff[pos-2]==0xFF) dbgprintf("(black)"); + dbgprintf("\n"); +#endif + first_white=true; + if (buff[pos-8]!=0 || buff[pos-7]!=0 || buff[pos-6]!=0) first_white=false; + + pos=7; + /* lines are written from the last to the first */ + for (y=h-1;y>=0;y--) {
i=1; + for (x=0;x<w;x++) {
/* new byte ! */ + if (pos==7) {
if (isfile) { + fread(buff, 1, 1, file); + } else { + memcpy (buff,buffer+buffpos,1); + buffpos++; + } +#ifdef DEBUG + sizeimage++; +#endif + i++; + /* each line is written in multiply of 4 bytes */ + if(i==5) i=1; + } + /* we have top left corner ! */ + if (x<=bitmap->BitmapWidth && y<=bitmap->BitmapHeight) {
if (first_white) { + if ((buff[0]&(1<<pos))<=0) GSM_SetPointBitmap(bitmap,x,y); + } else { + if ((buff[0]&(1<<pos))>0) GSM_SetPointBitmap(bitmap,x,y); + } + } + pos--; + /* going to new byte */ + if (pos<0) pos=7; + } + /* going to new byte */ + pos=7; + if (i!=1) { + /* each line is written in multiply of 4 bytes */ + while (i!=5) { + if (isfile) { + fread(buff, 1, 1, file); + } else { + memcpy (buff,buffer+buffpos,1); + buffpos++; + } +#ifdef DEBUG + sizeimage++; +#endif + i++; + } + } + } +#ifdef DEBUG + dbgprintf("Data size in BMP file: %i\n",sizeimage); +#endif + return(ERR_NONE); +} + +static GSM_Error loadbmp(FILE *file, GSM_MultiBitmap *bitmap) +{ + GSM_Error error; + + error=BMP2Bitmap(NULL,file,&bitmap->Bitmap[0]); + bitmap->Number = 1; + return error; +} + +static GSM_Error loadnlm (FILE *file, GSM_MultiBitmap *bitmap) +{ + unsigned char buffer[1000]; + int pos,pos2,x,y,h,w,i,number; + div_t division; + + fread(buffer,1,5,file); + + fread(buffer,1,1,file); + switch (buffer[0]) { + case 0x00: + dbgprintf("Operator logo\n"); + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_OperatorLogo; + break; + case 0x01: + dbgprintf("Caller logo\n"); + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_CallerGroupLogo; + break; + case 0x02: + dbgprintf("Startup logo\n"); + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_StartupLogo; + break; + case 0x03: + dbgprintf("Picture Image logo\n"); + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_PictureImage; + break; + } + + bitmap->Number = 0; + fread(buffer,1,4,file); + number = buffer[0] + 1; + w = buffer[1]; + h = buffer[2]; + for (i=0;i<number;i++) { + bitmap->Bitmap[i].Type = bitmap->Bitmap[0].Type; + GSM_GetMaxBitmapWidthHeight(bitmap->Bitmap[i].Type, &bitmap->Bitmap[i].BitmapWidth, &bitmap->Bitmap[i].BitmapHeight); + if (h < bitmap->Bitmap[i].BitmapHeight) bitmap->Bitmap[i].BitmapHeight = h; + if (w < bitmap->Bitmap[i].BitmapWidth) bitmap->Bitmap[i].BitmapWidth = w; + + division=div(w,8); + /* For startup logos */ + if (division.rem!=0) division.quot++; + if (fread(buffer,1,(division.quot*h),file)!=(unsigned int)(division.quot*h)) return ERR_UNKNOWN; + + GSM_ClearBitmap(&bitmap->Bitmap[i]); + + pos=0;pos2=7; + for (y=0;y<h;y++) { + for (x=0;x<w;x++) { + if ((buffer[pos]&(1<<pos2))>0) { + if (y<bitmap->Bitmap[i].BitmapHeight && x<bitmap->Bitmap[i].BitmapWidth) GSM_SetPointBitmap(&bitmap->Bitmap[i],x,y); + } + pos2--; + /* going to new byte */ + if (pos2<0) {pos2=7;pos++;} + } + /* for startup logos-new line means new byte */ + if (pos2!=7) {pos2=7;pos++;} + } + bitmap->Number++; + if (bitmap->Number == MAX_MULTI_BITMAP) break; + } + return (ERR_NONE); +} + +static GSM_Error loadnolngg(FILE *file, GSM_MultiBitmap *bitmap, bool nolformat) +{ + unsigned char buffer[2000]; + int i,h,w,x,y; + + fread(buffer, 1, 6, file); + + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_CallerGroupLogo; + if (nolformat) { + fread(buffer, 1, 4, file); + sprintf(bitmap->Bitmap[0].NetworkCode, "%d %02d", buffer[0]+256*buffer[1], buffer[2]); + if (bitmap->Bitmap[0].Type == GSM_None) bitmap->Bitmap[0].Type = GSM_OperatorLogo; + } + + fread(buffer, 1, 4, file); + w = buffer[0]; + h = buffer[2]; + GSM_GetMaxBitmapWidthHeight(bitmap->Bitmap[0].Type, &bitmap->Bitmap[0].BitmapWidth, &bitmap->Bitmap[0].BitmapHeight); + if (h < bitmap->Bitmap[0].BitmapHeight) bitmap->Bitmap[0].BitmapHeight = h; + if (w < bitmap->Bitmap[0].BitmapWidth) bitmap->Bitmap[0].BitmapWidth = w; + + /* Unknown bytes. */ + fread(buffer, 1, 6, file); + + GSM_ClearBitmap(&bitmap->Bitmap[0]); + + x=0; y=0; + for (i=0; i<w*h; i++) { + if (fread(buffer, 1, 1, file)!=1) return ERR_UNKNOWN; + if (buffer[0]=='1') GSM_SetPointBitmap(&bitmap->Bitmap[0],x,y); + x++; + if (x==w) {x=0; y++;} + } + +#ifdef DEBUG + /* Some programs writes here fileinfo */ + if (fread(buffer, 1, 1, file)==1) { + dbgprintf("Fileinfo: %c",buffer[0]); + while (fread(buffer, 1, 1, file)==1) { + if (buffer[0]!=0x0A) dbgprintf("%c",buffer[0]); + } + dbgprintf("\n"); + } +#endif + bitmap->Number = 1; + return(ERR_NONE); +} + +static GSM_Error loadnsl(FILE *file, GSM_MultiBitmap *bitmap) +{ + unsigned char block[6],buffer[505]; + int block_size; + GSM_Bitmap_Types OldType; + + while (fread(block,1,6,file)==6) { + block_size = block[4]*256 + block[5]; + dbgprintf("Block %c%c%c%c, size %i\n",block[0],block[1],block[2],block[3],block_size); + if (!strncmp(block, "FORM", 4)) { + dbgprintf("File ID\n"); + } else { + if (block_size>504) return ERR_UNKNOWN; + if (block_size!=0) { + fread(buffer,1,block_size,file); + /* if it's string, we end it with 0 */ + buffer[block_size]=0; +#ifdef DEBUG + if (!strncmp(block, "VERS", 4)) dbgprintf("File saved by: %s\n",buffer); + if (!strncmp(block, "MODL", 4)) dbgprintf("Logo saved from: %s\n",buffer); + if (!strncmp(block, "COMM", 4)) dbgprintf("Phone was connected to COM port: %s\n",buffer); +#endif + if (!strncmp(block, "NSLD", 4)) { + bitmap->Bitmap[0].BitmapHeight = 48; + bitmap->Bitmap[0].BitmapWidth = 84; + OldType = bitmap->Bitmap[0].Type; + PHONE_DecodeBitmap(GSM_NokiaStartupLogo, buffer, &bitmap->Bitmap[0]); + if (OldType != GSM_None) bitmap->Bitmap[0].Type = OldType; + dbgprintf("Startup logo (size %i)\n",block_size); + } + } + } + } + bitmap->Number = 1; + return(ERR_NONE); +} + +static GSM_Error loadwbmp(FILE *file, GSM_MultiBitmap *bitmap) +{ + unsigned char buffer[10000]; + + fread(buffer,1,4,file); + bitmap->Bitmap[0].BitmapWidth = buffer[2]; + bitmap->Bitmap[0].BitmapHeight = buffer[3]; + bitmap->Number = 1; + + fread(buffer,1,10000,file); + PHONE_DecodeBitmap(GSM_Nokia7110OperatorLogo, buffer, &bitmap->Bitmap[0]); + GSM_ReverseBitmap(&bitmap->Bitmap[0]); + + return ERR_NONE; +} + +GSM_Error GSM_ReadBitmapFile(char *FileName, GSM_MultiBitmap *bitmap) +{ + FILE *file; + unsigned char buffer[300]; + + file = fopen(FileName, "rb"); + if (file == NULL) return ERR_CANTOPENFILE; + + fread(buffer, 1, 9, file); /* Read the header of the file. */ + rewind(file); + + bitmap->Bitmap[0].DefaultBitmap = false; + + /* Attempt to identify filetype */ + if (memcmp(buffer, "BM",2)==0) { + return loadbmp(file,bitmap); + } else if (buffer[0] == 0x00 && buffer[1] == 0x00) { + return loadwbmp(file,bitmap); + } else if (memcmp(buffer, "NLM",3)==0) { + return loadnlm(file,bitmap); + } else if (memcmp(buffer, "NOL",3)==0) { + return loadnolngg(file,bitmap,true); + } else if (memcmp(buffer, "NGG",3)==0) { + return loadnolngg(file,bitmap,false); + } else if (memcmp(buffer, "FORM",4)==0) { + return loadnsl(file,bitmap); + } + return ERR_UNKNOWN; +} + +void NOKIA_CopyBitmap(GSM_Phone_Bitmap_Types Type, GSM_Bitmap *Bitmap, char *Buffer, int *Length) +{ + int Width, Height; + + Buffer[(*Length)++] = 0x00; + PHONE_GetBitmapWidthHeight(Type, &Width, &Height); + Buffer[(*Length)++] = Width; + Buffer[(*Length)++] = Height; + Buffer[(*Length)++] = 0x01; + PHONE_EncodeBitmap(Type, Buffer + (*Length), Bitmap); + (*Length) = (*Length) + PHONE_GetBitmapSize(Type,0,0); +} + +/* 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/service/gsmlogo.h b/gammu/emb/common/service/gsmlogo.h new file mode 100644 index 0000000..b1b579d --- a/dev/null +++ b/gammu/emb/common/service/gsmlogo.h @@ -0,0 +1,180 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#ifndef __gsm_bitmaps_h +#define __gsm_bitmaps_h + +#include "../gsmcomon.h" + +/** + * Enum to handle all possible bitmaps, which are not saved in various filesystems. + */ +typedef enum { + GSM_None = 1, + /** + * ID of static file in filesystem displayed during startup + */ + GSM_ColourStartupLogo_ID, + /** + * Static mono bitmap/ID of animated mono bitmap displayed during startup + */ + GSM_StartupLogo, + /** + * ID of static file in filesystem displayed instead of operator name + */ + GSM_ColourOperatorLogo_ID, + /** + * Mono bitmap displayed instead of operator name + */ + GSM_OperatorLogo, + /** + * ID of static file in filesystem displayed as wallpaper + */ + GSM_ColourWallPaper_ID, + /** + * Mono bitmap assigned to caller group + */ + GSM_CallerGroupLogo, + /** + * Text displayed during startup, which can't be removed from phone menu + */ + GSM_DealerNote_Text, + /** + * Text displayed during startup + */ + GSM_WelcomeNote_Text, + /** + * Image defined in Smart Messaging specification + */ + GSM_PictureImage +} GSM_Bitmap_Types; + +#define GSM_BITMAP_SIZE (65+7)/8*96 +#define GSM_BITMAP_TEXT_LENGTH 128 + +/** + * Structure for all possible bitmaps, which are not saved in various filesystems + */ +typedef struct { + /** + * For all: bitmap type + */ + GSM_Bitmap_Types Type; + /** + * For caller group logos: number of group + * For startup logos: number of animated bitmap + */ + unsigned char Location; + /** + * For dealer/welcome note text: text + * For caller group logo: name of group + * For picture images: text assigned to it + */ + unsigned char Text[2 * (GSM_BITMAP_TEXT_LENGTH + 1)]; + /** + * For caller group logo: true, when logo is enabled in group + */ + bool BitmapEnabled; + /** + * For caller group logo: true, when group has default name + */ + bool DefaultName; + /** + * For caller group logo: true, when group has default bitmap + */ + bool DefaultBitmap; + /** + * For caller group logo: true, when group has default ringtone + */ + bool DefaultRingtone; + /** + * For caller group logo: ringtone ID. Phone model specific + */ + unsigned char RingtoneID; + bool FileSystemRingtone; + /** + * For mono bitmaps: body of bitmap + */ + unsigned char BitmapPoints[GSM_BITMAP_SIZE]; + /** + * For mono bitmaps: height specified in pixels + */ + unsigned char BitmapHeight; + /** + * For mono bitmaps: width specified in pixels + */ + unsigned char BitmapWidth; + /** + * For operator logos: Network operator code + */ + char NetworkCode[7]; + /** + * For picture images: number of sender + */ + unsigned char Sender[2 * (GSM_MAX_NUMBER_LENGTH + 1)]; + /** + * For colour bitmaps: ID + */ + unsigned char ID; +} GSM_Bitmap; + +#define MAX_MULTI_BITMAP 6 + +/** + * Structure to handle more than one bitmap + */ +typedef struct { + /** + * Number of bitmaps + */ + unsigned char Number; + /** + * All bitmaps + */ + GSM_Bitmap Bitmap[MAX_MULTI_BITMAP]; +} GSM_MultiBitmap; + +typedef enum { + GSM_NokiaStartupLogo = 1, /*size 84*48*/ + GSM_NokiaOperatorLogo, /*size 72*14*/ + GSM_Nokia7110OperatorLogo, /*size 78*21*/ + GSM_Nokia6510OperatorLogo, /*size 78*21*/ + GSM_NokiaCallerLogo, /*size 72*14*/ + GSM_NokiaPictureImage, /*size 72*28*/ + GSM_Nokia7110StartupLogo, /*size 96*65*/ + GSM_Nokia6210StartupLogo, /*size 96*60*/ + GSM_AlcatelBMMIPicture, + GSM_EMSSmallPicture, /*size 8* 8*/ + GSM_EMSMediumPicture, /*size 16*16*/ + GSM_EMSBigPicture, /*size 32*32*/ + GSM_EMSVariablePicture +} GSM_Phone_Bitmap_Types; + +bool GSM_IsPointBitmap (GSM_Bitmap *bmp, int x, int y); +void GSM_SetPointBitmap (GSM_Bitmap *bmp, int x, int y); +void GSM_ClearPointBitmap (GSM_Bitmap *bmp, int x, int y); +void GSM_ClearBitmap (GSM_Bitmap *bmp); +void GSM_ResizeBitmap (GSM_Bitmap *dest, GSM_Bitmap *src, int width, int height); +void GSM_ReverseBitmap (GSM_Bitmap *Bitmap); +void GSM_GetMaxBitmapWidthHeight(GSM_Bitmap_Types Type, unsigned char *width, unsigned char *height); +int GSM_GetBitmapSize (GSM_Bitmap *bmp); +void GSM_PrintBitmap (FILE *file, GSM_Bitmap *bitmap); + +GSM_Error GSM_SaveBitmapFile (char *FileName, GSM_MultiBitmap *bitmap); +GSM_Error GSM_ReadBitmapFile (char *FileName, GSM_MultiBitmap *bitmap); + +GSM_Error BMP2Bitmap (unsigned char *buffer, FILE *file,GSM_Bitmap *bitmap); +GSM_Error Bitmap2BMP (unsigned char *buffer, FILE *file,GSM_Bitmap *bitmap); + +void PHONE_GetBitmapWidthHeight (GSM_Phone_Bitmap_Types Type, int *width, int *height); +int PHONE_GetBitmapSize (GSM_Phone_Bitmap_Types Type, int width, int height); +void PHONE_ClearBitmap (GSM_Phone_Bitmap_Types Type, char *buffer, int width, int height); +void PHONE_DecodeBitmap (GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap); +void PHONE_EncodeBitmap (GSM_Phone_Bitmap_Types Type, char *buffer, GSM_Bitmap *Bitmap); + +void NOKIA_CopyBitmap (GSM_Phone_Bitmap_Types Type, GSM_Bitmap *Bitmap, char *Buffer, int *Length); + +#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/service/gsmmisc.c b/gammu/emb/common/service/gsmmisc.c new file mode 100644 index 0000000..6959a22 --- a/dev/null +++ b/gammu/emb/common/service/gsmmisc.c @@ -0,0 +1,262 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#ifdef WIN32 +# include <io.h> +# include <fcntl.h> +#endif + +#include "../misc/coding/coding.h" +#include "../gsmcomon.h" +#include "gsmmisc.h" + +struct keys_table_position { + char whatchar; + int whatcode; +}; + +static struct keys_table_position Keys[] = { + {'m',GSM_KEY_MENU}, {'M',GSM_KEY_MENU}, + {'n',GSM_KEY_NAMES}, {'N',GSM_KEY_NAMES}, + {'p',GSM_KEY_POWER}, {'P',GSM_KEY_POWER}, + {'u',GSM_KEY_UP}, {'U',GSM_KEY_UP}, + {'d',GSM_KEY_DOWN}, {'D',GSM_KEY_DOWN}, + {'+',GSM_KEY_INCREASEVOLUME}, {'-',GSM_KEY_DECREASEVOLUME}, + {'1',GSM_KEY_1}, {'2',GSM_KEY_2}, {'3',GSM_KEY_3}, + {'4',GSM_KEY_4}, {'5',GSM_KEY_5}, {'6',GSM_KEY_6}, + {'7',GSM_KEY_7}, {'8',GSM_KEY_8}, {'9',GSM_KEY_9}, + {'*',GSM_KEY_ASTERISK}, {'0',GSM_KEY_0}, {'#',GSM_KEY_HASH}, + {'g',GSM_KEY_GREEN}, {'G',GSM_KEY_GREEN}, + {'r',GSM_KEY_RED}, {'R',GSM_KEY_RED}, + {' ',0} +}; + +GSM_Error MakeKeySequence(char *text, GSM_KeyCode *KeyCode, int *Length) +{ + int i,j; + unsigned char key; + + for (i=0;i<(int)(strlen(text));i++) { + key = text[i]; + KeyCode[i] = GSM_KEY_NONE; + j = 0; + while (Keys[j].whatchar!=' ') { + if (Keys[j].whatchar==key) { + KeyCode[i]=Keys[j].whatcode; + break; + } + j++; + } + if (KeyCode[i] == GSM_KEY_NONE) { + *Length = i; + return ERR_NOTSUPPORTED; + } + } + *Length = i; + return ERR_NONE; +} + +GSM_Error GSM_ReadFile(char *FileName, GSM_File *File) +{ + int i = 1000; + FILE *file; + struct stat fileinfo; + + if (FileName[0] == 0x00) return ERR_UNKNOWN; + file = fopen(FileName,"rb"); + if (file == NULL) return ERR_CANTOPENFILE; + + free(File->Buffer); + File->Buffer = NULL; + File->Used = 0; + while (i == 1000) { + File->Buffer = realloc(File->Buffer,File->Used + 1000); + i = fread(File->Buffer+File->Used,1,1000,file); + File->Used = File->Used + i; + } + File->Buffer = realloc(File->Buffer,File->Used); + fclose(file); + + File->ModifiedEmpty = true; + if (stat(FileName,&fileinfo) == 0) { + File->ModifiedEmpty = false; + dbgprintf("File info read correctly\n"); + //st_mtime is time of last modification of file + Fill_GSM_DateTime(&File->Modified, fileinfo.st_mtime); + File->Modified.Year = File->Modified.Year + 1900; + dbgprintf("FileTime: %02i-%02i-%04i %02i:%02i:%02i\n", + File->Modified.Day,File->Modified.Month,File->Modified.Year, + File->Modified.Hour,File->Modified.Minute,File->Modified.Second); + } + + return ERR_NONE; +} + +static void GSM_JADFindLine(GSM_File File, char *Name, char *Value) +{ + unsigned char Line[2000]; + int Pos = 0; + + Value[0] = 0; + + while (1) { + MyGetLine(File.Buffer, &Pos, Line, File.Used); + if (strlen(Line) == 0) break; + if (!strncmp(Line,Name,strlen(Name))) { + Pos = strlen(Name); + while (Line[Pos] == 0x20) Pos++; + strcpy(Value,Line+Pos); + return; + } + } +} + +GSM_Error GSM_JADFindData(GSM_File File, char *Vendor, char *Name, char *JAR, char *Version, int *Size) +{ + char Size2[200]; + + GSM_JADFindLine(File, "MIDlet-Vendor:", Vendor); + if (Vendor[0] == 0x00) return ERR_FILENOTSUPPORTED; + dbgprintf("Vendor: \"%s\"\n",Vendor); + + GSM_JADFindLine(File, "MIDlet-Name:", Name); + if (Name[0] == 0x00) return ERR_FILENOTSUPPORTED; + dbgprintf("Name: \"%s\"\n",Name); + + GSM_JADFindLine(File, "MIDlet-Jar-URL:", JAR); + if (JAR[0] == 0x00) return ERR_FILENOTSUPPORTED; + dbgprintf("JAR file URL: \"%s\"\n",JAR); + + GSM_JADFindLine(File, "MIDlet-Jar-Size:", Size2); + *Size = -1; + if (Size2[0] == 0x00) return ERR_FILENOTSUPPORTED; + dbgprintf("JAR size: \"%s\"\n",Size2); + (*Size) = atoi(Size2); + + GSM_JADFindLine(File, "MIDlet-Version:", Version); + dbgprintf("Version: \"%s\"\n",Version); + + return ERR_NONE; +} + +void GSM_IdentifyFileFormat(GSM_File *File) +{ + File->Type = GSM_File_Other; + if (File->Used > 2) { + if (memcmp(File->Buffer, "BM",2)==0) { + File->Type = GSM_File_Image_BMP; + } else if (memcmp(File->Buffer, "GIF",3)==0) { + File->Type = GSM_File_Image_GIF; + } else if (File->Buffer[0] == 0x00 && File->Buffer[1] == 0x00) { + File->Type = GSM_File_Image_WBMP; + } else if (memcmp(File->Buffer+1, "PNG",3)==0) { + File->Type = GSM_File_Image_PNG; + } else if (File->Buffer[0] == 0xFF && File->Buffer[1] == 0xD8) { + File->Type = GSM_File_Image_JPG; + } else if (memcmp(File->Buffer, "MThd",4)==0) { + File->Type = GSM_File_Sound_MIDI; + } else if (File->Buffer[0] == 0x00 && File->Buffer[1] == 0x02) { + File->Type = GSM_File_Sound_NRT; + } + } +} + +void SaveVCALDateTime(char *Buffer, int *Length, GSM_DateTime *Date, char *Start) +{ + if (Start != NULL) { + *Length+=sprintf(Buffer+(*Length), "%s:",Start); + } + *Length+=sprintf(Buffer+(*Length), "%04d%02d%02dT%02d%02d%02d%c%c", + Date->Year, Date->Month, Date->Day, + Date->Hour, Date->Minute, Date->Second,13,10); +} + +void ReadVCALDateTime(char *Buffer, GSM_DateTime *dt) +{ + char year[5]="", month[3]="", day[3]="", hour[3]="", minute[3]="", second[3]=""; + + memset(dt,0,sizeof(dt)); + + strncpy(year, Buffer, 4); + strncpy(month, Buffer+4, 2); + strncpy(day, Buffer+6, 2); + strncpy(hour, Buffer+9, 2); + strncpy(minute, Buffer+11, 2); + strncpy(second, Buffer+13, 2); + + /* FIXME: Should check ranges... */ + dt->Year = atoi(year); + dt->Month = atoi(month); + dt->Day = atoi(day); + dt->Hour = atoi(hour); + dt->Minute = atoi(minute); + dt->Second = atoi(second); + /* FIXME */ + dt->Timezone = 0; +} + +void SaveVCALText(char *Buffer, int *Length, char *Text, char *Start) +{ + char buffer[1000]; + + if (UnicodeLength(Text) != 0) { + EncodeUTF8QuotedPrintable(buffer,Text); + if (UnicodeLength(Text)==strlen(buffer)) { + *Length+=sprintf(Buffer+(*Length), "%s:%s%c%c",Start,DecodeUnicodeString(Text),13,10); + } else { + *Length+=sprintf(Buffer+(*Length), "%s;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:%s%c%c",Start,buffer,13,10); + } + } +} + +bool ReadVCALText(char *Buffer, char *Start, char *Value) +{ + unsigned char buff[200]; + + Value[0] = 0x00; + Value[1] = 0x00; + + strcpy(buff,Start); + strcat(buff,":"); + if (!strncmp(Buffer,buff,strlen(buff))) { + EncodeUnicode(Value,Buffer+strlen(Start)+1,strlen(Buffer)-(strlen(Start)+1)); + dbgprintf("ReadVCalText is \"%s\"\n",DecodeUnicodeConsole(Value)); + return true; + } + /* SE T68i */ + strcpy(buff,Start); + strcat(buff,";ENCODING=QUOTED-PRINTABLE:"); + if (!strncmp(Buffer,buff,strlen(buff))) { + DecodeUTF8QuotedPrintable(Value,Buffer+strlen(Start)+27,strlen(Buffer)-(strlen(Start)+27)); + dbgprintf("ReadVCalText is \"%s\"\n",DecodeUnicodeConsole(Value)); + return true; + } + strcpy(buff,Start); + strcat(buff,";CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"); + if (!strncmp(Buffer,buff,strlen(buff))) { + DecodeUTF8QuotedPrintable(Value,Buffer+strlen(Start)+41,strlen(Buffer)-(strlen(Start)+41)); + dbgprintf("ReadVCalText is \"%s\"\n",DecodeUnicodeConsole(Value)); + return true; + } + strcpy(buff,Start); + strcat(buff,";CHARSET=UTF-8:"); + if (!strncmp(Buffer,buff,strlen(buff))) { + DecodeUTF8(Value,Buffer+strlen(Start)+15,strlen(Buffer)-(strlen(Start)+15)); + dbgprintf("ReadVCalText is \"%s\"\n",DecodeUnicodeConsole(Value)); + return true; + } + strcpy(buff,Start); + strcat(buff,";CHARSET=UTF-7:"); + if (!strncmp(Buffer,buff,strlen(buff))) { + DecodeUTF7(Value,Buffer+strlen(Start)+15,strlen(Buffer)-(strlen(Start)+15)); + dbgprintf("ReadVCalText is \"%s\"\n",DecodeUnicodeConsole(Value)); + return true; + } + return false; +} + +/* 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/service/gsmmisc.h b/gammu/emb/common/service/gsmmisc.h new file mode 100644 index 0000000..37501ad --- a/dev/null +++ b/gammu/emb/common/service/gsmmisc.h @@ -0,0 +1,316 @@ +/* (c) 2001-2004 by Marcin Wiacek, Walek and Michal Cihar */ + +#ifndef __gsm_misc_h +#define __gsm_misc_h + +#include "../gsmcomon.h" + +/** + * Enum defines ID for various phone and SIM memories. + * Phone modules can translate them to values specific for concrete models + * Two letter codes (excluding VM) are from GSM 07.07 + */ +typedef enum { + /** + * Internal memory of the mobile equipment + */ + MEM_ME=1, + /** + * SIM card memory + */ + MEM_SM, + /** + * Own numbers + */ + MEM_ON, + /** + * Dialled calls + */ + MEM_DC, + /** + * Received calls + */ + MEM_RC, + /** + * Missed calls + */ + MEM_MC, + /** + * Combined ME and SIM phonebook + */ + MEM_MT, + /** + * Fixed dial + */ + MEM_FD, + + /** + * Voice mailbox + */ + MEM_VM +} GSM_MemoryType; + +/* --------------------------- resetting phone settings ------------------- */ + +typedef enum { + GSM_RESET_PHONESETTINGS = 1, + GSM_RESET_USERINTERFACE, + GSM_RESET_USERINTERFACE_PHONESETTINGS, + GSM_RESET_DEVICE, + GSM_RESET_FULLFACTORY +} GSM_ResetSettingsType; + +/* --------------------------- security codes ------------------------------ */ + +/** + * Definition of security codes. + */ +typedef enum { + /** + * Security code. + */ + SEC_SecurityCode = 0x01, + /** + * PIN. + */ + SEC_Pin, + /** + * PIN 2. + */ + SEC_Pin2, + /** + * PUK. + */ + SEC_Puk, + /** + * PUK 2. + */ + SEC_Puk2, + /** + * Code not needed. + */ + SEC_None +} GSM_SecurityCodeType; + +#define GSM_SECURITY_CODE_LEN 15 + +/** + * Security code definition. + */ +typedef struct { + /** + * Actual code. + */ + char Code[GSM_SECURITY_CODE_LEN+1]; + /** + * Type of the code. + */ + GSM_SecurityCodeType Type; +} GSM_SecurityCode; + +/* ---------------------------- keyboard ----------------------------------- */ + +typedef enum { + GSM_KEY_NONE = 0x00, + GSM_KEY_1 = 0x01, + GSM_KEY_2, + GSM_KEY_3, + GSM_KEY_4, + GSM_KEY_5, + GSM_KEY_6, + GSM_KEY_7, + GSM_KEY_8, + GSM_KEY_9, + GSM_KEY_0, + /** + * # + */ + GSM_KEY_HASH, + /** + * * + */ + GSM_KEY_ASTERISK, + GSM_KEY_POWER, + /** + * in some phone ie. N5110 sometimes works identical to POWER + */ + GSM_KEY_GREEN, + /** + * (c) key in some phone: ie. N5110 + */ + GSM_KEY_RED, + /** + * doesn't available in some phones as separate button: ie. N5110 + */ + GSM_KEY_INCREASEVOLUME, + /** + * doesn't available in some phones as separate button: ie. N5110 + */ + GSM_KEY_DECREASEVOLUME, + GSM_KEY_UP = 0x17, + GSM_KEY_DOWN, + GSM_KEY_MENU, + /** + * doesn't available in some phone: ie. N5110 + */ + GSM_KEY_NAMES +} GSM_KeyCode; + +GSM_Error MakeKeySequence(char *text, GSM_KeyCode *KeyCode, int *Length); + +/* ------------------------------- display features ------------------------ */ + +typedef enum { + GSM_CallActive = 1, + /** + * blinking envelope + */ + GSM_SMSMemoryFull, + GSM_FaxCall, + GSM_UnreadSMS, + GSM_DataCall, + GSM_VoiceCall, + GSM_KeypadLocked +} GSM_DisplayFeature; + +typedef struct { + int Number; + GSM_DisplayFeature Feature[7]; +} GSM_DisplayFeatures; + +/* ----------------------------- power source ------------------------------ */ + +typedef enum { + GSM_BatteryPowered = 1, + GSM_BatteryConnected, + GSM_BatteryNotConnected, + GSM_PowerFault +} GSM_ChargeState; + +typedef struct { + /** + * Signal strength in percent, -1 = unknown + */ + int BatteryPercent; + /** + * Charge state + */ + GSM_ChargeState ChargeState; +} GSM_BatteryCharge; + +/* ------------------------------ categories ------------------------------- */ + +#define GSM_MAX_CATEGORY_NAME_LENGTH 50 + +typedef enum { + Category_ToDo = 1, + Category_Phonebook +} GSM_CategoryType; + +typedef struct { + GSM_CategoryType Type; + int Location; + unsigned char Name[(GSM_MAX_CATEGORY_NAME_LENGTH + 1)*2]; +} GSM_Category; + +typedef struct { + GSM_CategoryType Type; + int Used; +} GSM_CategoryStatus; + +/* ------------------- radio FM stations ---------------------------------- */ + +#define GSM_MAX_FMSTATION_LENGTH 12 +#define GSM_MAX_FM_STATION 20 + +typedef struct { + int Location; + char StationName [(GSM_MAX_FMSTATION_LENGTH+1)*2]; + double Frequency; +} GSM_FMStation; + +/* ----------------------- filesystem ------------------------------------- */ + +typedef enum { + GSM_File_Java_JAR = 1, + GSM_File_Image_JPG, + GSM_File_Image_BMP, + GSM_File_Image_GIF, + GSM_File_Image_PNG, + GSM_File_Image_WBMP, + GSM_File_Video_3GP, + GSM_File_Sound_AMR, + GSM_File_Sound_NRT, /* DCT4 binary format */ + GSM_File_Sound_MIDI, +#ifdef DEVELOP + GSM_File_MMS, +#endif + GSM_File_Other +} GSM_FileType; + +typedef struct { + int Used; /* how many bytes used */ + unsigned char Name[300]; /* Name */ + bool Folder; /* true, when folder */ + int Level; + GSM_FileType Type; + unsigned char ID_FullName[400]; + unsigned char *Buffer; + + GSM_DateTime Modified; + bool ModifiedEmpty; + + /* File attributes */ + bool Protected; + bool ReadOnly; + bool Hidden; + bool System; +} GSM_File; + +GSM_Error GSM_ReadFile(char *FileName, GSM_File *File); + +GSM_Error GSM_JADFindData(GSM_File File, char *Vendor, char *Name, char *JAR, char *Version, int *Size); + +void GSM_IdentifyFileFormat(GSM_File *File); + +typedef struct { + int Free; + int Used; +} GSM_FileSystemStatus; + +/* ----------------------------- GPRS access points ----------------------- */ + +typedef struct { + int Location; + unsigned char Name[300]; + unsigned char URL[500]; + bool Active; +} GSM_GPRSAccessPoint; + +/* ------------------------------------------------------------------------ */ + +typedef enum { + GSM_Date_DDMMYYYY = 1, + GSM_Date_MMDDYYYY, + GSM_Date_YYYYMMDD +} GSM_DateFormat; + +typedef struct { + unsigned char DateSeparator; + GSM_DateFormat DateFormat; + bool AMPMTime; +} GSM_Locale; + +/* ------------------------------------------------------------------------ */ + +void ReadVCALDateTime(char *Buffer, GSM_DateTime *dt); +void SaveVCALDateTime(char *Buffer, int *Length, GSM_DateTime *Date, char *Start); + +void SaveVCALText(char *Buffer, int *Length, char *Text, char *Start); +bool ReadVCALText(char *Buffer, char *Start, char *Value); + +#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/service/gsmnet.c b/gammu/emb/common/service/gsmnet.c new file mode 100644 index 0000000..a0ddaa7 --- a/dev/null +++ b/gammu/emb/common/service/gsmnet.c @@ -0,0 +1,444 @@ +/* (c) 2001-2003 by Marcin Wiacek */ + +#include <string.h> + +#include "gsmnet.h" +#include "../misc/coding/coding.h" + +unsigned char *GSM_Countries[] = { + "202", "Greece", + "204", "Netherlands", + "206", "Belgium", + "208", "France", + "213", "Andorra" , + "214", "Spain", + "216", "Hungary", + "218", "Bosnia Herzegovina", + "219", "Croatia", + "220", "Yugoslavia", + "222", "Italy", + "226", "Romania", + "228", "Switzerland", + "230", "Czech Republic", + "231", "Slovak Republic", + "232", "Austria", + "234", "United Kingdom", + "238", "Denmark", + "240", "Sweden", + "242", "Norway", + "244", "Finland", + "246", "Lithuania", + "247", "Latvia", + "248", "Estonia", + "250", "Russia", + "255", "Ukraine", + "259", "Moldova", + "260", "Poland", + "262", "Germany", + "266", "Gibraltar", + "268", "Portugal", + "270", "Luxembourg", + "272", "Ireland", + "274", "Iceland", + "276", "Albania", + "278", "Malta", + "280", "Cyprus", + "282", "Georgia", + "283", "Armenia", + "284", "Bulgaria", + "286", "Turkey", + "290", "Greenland", + "293", "Slovenia", + "294", "Macedonia", + "302", "Canada", + "310", "U.S.A.", + "340", "French West Indies", + "400", "Azerbaijan", + "404", "India", + "410", "Pakistan", + "413", "Sri Lanka", + "415", "Lebanon", + "416", "Jordan", + "417", "Syria", + "418", "Iraq", + "419", "Kuwait", + "420", "Saudi Arabia", + "422", "Oman", + "424", "United Arab Emirates", + "425", "Israel", + "426", "Bahrain", + "427", "Qatar", + "432", "Iran", + "434", "Uzbekistan", + "437", "Kyrgyz Republic", + "452", "Vietnam", + "454", "Hong Kong", + "455", "Macau", + "456", "Cambodia", + "457", "Lao", + "460", "China", + "466", "Taiwan", + "470", "Bangladesh", + "502", "Malaysia", + "505", "Australia", + "510", "Indonesia", + "515", "Philippines", + "520", "Thailand", + "525", "Singapore", + "528", "Brunei Darussalam", + "530", "New Zealand", + "542", "Fiji", + "546", "New Caledonia", + "547", "French Polynesia", + "602", "Egypt", + "603", "Algeria", + "604", "Morocco", + "605", "Tunisia", + "608", "Senegal", + "611", "Guinea", + "612", "Cote d'Ivoire", + "615", "Togo", + "617", "Mauritius", + "618", "Liberia", + "620", "Ghana", + "624", "Cameroon", + "625", "Cape Verde", + "633", "Seychelles", + "634", "Mozambique", + "634", "Sudan", + "635", "Rwanda", + "636", "Ethiopia", + "640", "Tanzania", + "641", "Uganda", + "645", "Zambia", + "646", "Madagascar", + "647", "Reunion", + "648", "Zimbabwe", + "649", "Namibia", + "650", "Malawi", + "651", "Lesotho", + "652", "Botswana", + "655", "South Africa", + "730", "Chile", + "734", "Venezuela", + + NULL +}; + +unsigned char *GSM_Networks[] = { + "202 01", "Cosmote", + "202 05", "PANAFON", + "202 10", "TELESTET", + "204 04", "LIBERTEL", + "204 08", "KPN Telecom", + "204 12", "O2", + "204 16", "BEN", + "204 20", "Dutchtone NV", + "206 01", "PROXIMUS", + "206 10", "Mobistar", + "206 20", "Base", + "208 01", "ITINERIS", + "208 10", "SFR", + "208 20", "Bouygues Telecom", + "213 03", "MOBILAND", + "214 01", "Airtel GSM 900-Spain", + "214 03", "Retevision Movil", + "214 07", "MOVISTAR", + "216 01", "Pannon GSM", + "216 70", "Vodafone", + "216 30", "Westel 900", + "218 90", "GSMBIH", + "219 01", "CRONET", + "219 10", "VIP", + "220 01", "MOBTEL", + "220 02", "ProMonte GSM", + "220 03", "Telekom Srbije", + "222 01", "Telecom Italia Mobile", + "222 10", "OMNITEL", + "222 88", "Wind Telecomunicazioni SpA", + "226 01", "CONNEX GSM", + "226 10", "DIALOG", + "228 01", "NATEL International", + "228 02", "diAx Mobile AG", + "230 01", "T-Mobile CZ", + "230 02", "EuroTel", + "230 03", "Oskar", + "231 01", "Orange", + "231 02", "EuroTel GSM", + "232 01", "A1", + "232 03", "T-Mobile AT", + "232 05", "ONE", + "232 07", "tele.ring", + "234 10", "Cellnet", + "234 15", "Vodafone", + "234 30", "T-Mobile UK", + "234 33", "ORANGE", + "234 50", "Jersey Telecoms GSM", + "234 55", "Guernsey Telecoms GSM", + "234 58", "PRONTO GSM", + "238 01", "TDK-MOBIL", + "238 02", "SONOFON", + "238 20", "TELIA DK", + "238 30", "Mobilix", + "240 01", "Telia AB", + "240 07", "COMVIQ", + "240 08", "EUROPOLITAN", + "242 01", "Telenor Mobil", + "242 02", "NetCom GSM", + "244 03", "Telia City (Finland)", + "244 05", "Radiolinja", + "244 09", "Finnet", + "244 12", "DNA (FI2G)", + "244 14", "Alands Mobiltelefon", + "244 91", "Sonera", + "246 01", "OMNITEL", + "246 02", "Bite GSM", + "247 01", "LMT LV", + "247 02", "BALTCOM GSM", + "248 01", "EMT GSM", + "248 02", "Radiolinja Eesti AS", + "248 03", "Q GSM", + "250 01", "Mobile Telesystems", + "250 02", "North-West GSM", + "250 05", "Siberian Cellular Systems 900", + "250 07", "BM Telecom", + "250 10", "Don Telecom", + "250 12", "FECS-900", + "250 13", "Kuban GSM", + "250 39", "Uraltel", + "250 44", "North Caucasian GSM", + "250 99", "BeeLine", + "255 01", "UMC", + "255 02", "WellCOM", + "255 03", "Kyivstar", + "255 05", "Golden Telecom", + "259 01", "VOXTEL", + "260 01", "PLUS GSM", + "260 02", "ERA GSM", + "260 03", "IDEA Centertel", + "262 01", "T-Mobile D", + "262 02", "D2 PRIVAT", + "262 03", "E-Plus", + "262 07", "Interkom", + "266 01", "Gibtel GSM", + "268 01", "TELECEL", + "268 03", "OPTIMUS", + "268 06", "TMN", + "270 01", "LUXGSM", + "270 77", "TANGO", + "272 01", "EIRCELL-GSM", + "272 02", "Digifone", + "274 01", "Landssiminn GSM 900", + "274 02", "TAL hf", + "276 01", "AMC", + "278 01", "Vodafone Malta Limited", + "280 01", "CYTAGSM", + "282 01", "Geocell Limited", + "282 02", "Magti GSM", + "283 01", "ArmGSM", + "284 01", "M-TEL GSM BG", + "286 01", "Turkcell", + "286 02", "TELSIM GSM", + "288 01", "Faroese Telecom", + "290 01", "Tele Greenland", + "293 40", "SI.MOBIL d. d.", + "293 41", "MOBITEL", + "293 70", "SI VEGA 070", + "294 01", "MobiMak", + "302 37", "Microcell Connexions Inc", + "302 72", "Rogers AT&T", + "310 01", "Cellnet", + "310 02", "Sprint Spectrum", + "310 11", "Wireless 2000 Telephone Co.", + "310 15", "BellSouth Mobility DCS", + "310 16", "T-Mobile", + "310 17", "Pac Bell", + "310 20", "T-Mobile", + "310 21", "T-Mobile", + "310 22", "T-Mobile", + "310 23", "T-Mobile", + "310 24", "T-Mobile", + "310 25", "T-Mobile", + "310 26", "T-Mobile", + "310 27", "T-Mobile", + "310 31", "T-Mobile", + "310 38", "AT&T Wireless", + "310 58", "T-Mobile", + "310 66", "T-Mobile", + "310 77", "Iowa Wireless Services LP", + "310 80", "T-Mobile", + "340 01", "AMERIS", + "400 01", "AZERCELL GSM", + "400 02", "Bakcell GSM 2000", + "404 07", "TATA Cellular", + "404 10", "AirTel", + "404 11", "Essar Cellphone", + "404 12", "Escotel", + "404 14", "Modicom", + "404 15", "Essar Cellphone", + "404 20", "Max Touch", + "404 21", "BPL - Mobile", + "404 27", "BPL USWEST Cellular", + "404 30", "Command", + "404 40", "SkyCell", + "404 41", "RPG Cellular", + "404 42", "AIRCEL", + "410 01", "Mobilink", + "413 02", "DIALOG GSM", + "415 01", "CELLIS", + "415 03", "LIBANCELL", + "416 01", "Fastlink", + "417 09", "MOBILE SYRIA", + "419 02", "MTCNet", + "420 01", "Al Jawwal", + "420 07", "E.A.E", + "422 02", "GTO", + "424 02", "UAE-ETISALAT", + "425 01", "Partner Communications Company Ltd", + "425 02", "Cellcom Israel Ltd", + "426 01", "BHR MOBILE PLUS", + "427 01", "QATARNET", + "432 11", "TCI", + "434 04", "Daewoo Unitel", + "434 05", "Coscom", + "437 01", "Bitel", + "454 00", "TCSL GSM", + "454 04", "HKGHT", + "454 06", "SMARTONE GSM", + "454 10", "New World PCS", + "454 12", "PEOPLES", + "454 16", "SUNDAY", + "455 01", "TELEMOVEL+ GSM900-Macau", + "456 01", "MobiTel", + "456 02", "SAMART-GSM", + "457 01", "Lao Shinawatra Telecom", + "460 00", "China Telecom GSM", + "460 01", "CU-GSM", + "466 01", "Far EasTone Telecoms 900", + "466 06", "TUNTEX GSM 1800", + "466 88", "KG Telecom", + "466 92", "Chunghwa GSM", + "466 93", "MobiTai", + "466 97", "TWNGSM", + "466 99", "TransAsia", + "470 01", "GrameenPhone Ltd", + "470 19", "Mobile 2000", + "502 12", "Maxis Mobile", + "502 13", "TM Touch", + "502 16", "DiGi 1800", + "502 17", "ADAM", + "502 19", "CELCOM", + "505 01", "MobileNet", + "505 02", "OPTUS", + "505 03", "VODAFONE", + "505 08", "One.Tel", + "510 01", "SATELINDO", + "510 08", "LIPPO TELECOM", + "510 10", "TELKOMSEL", + "510 11", "Excelcom", + "510 21", "INDOSAT", + "515 01", "ISLACOM", + "515 02", "Globe Telecom", + "520 01", "AIS GSM", + "520 10", "WCS", + "520 18", "Worldphone 1800", + "520 23", "HELLO", + "525 01", "SingTel Mobile", + "525 02", "ST-PCN", + "525 03", "MOBILEONE", + "528 11", "DSTCom", + "530 01", "Vodafone New Zealand Limited", + "542 01", "Vodafone", + "546 01", "Mobilis", + "547 20", "VINI", + "602 01", "MobiNil", + "602 02", "Tunicell", + "603 01", "ALGERIAN MOBILE NETWORK", + "604 01", "I A M", + "608 01", "ALIZE", + "611 02", "Lagui", + "612 03", "IVOIRIS", + "612 05", "Telecel", + "615 01", "TOGO CELL", + "617 01", "Cellplus Mobile Comms", + "618 01", "Omega", + "620 01", "SPACEFON", + "625 01", "CVMOVEL", + "633 01", "Seychelles Cellular Services", + "633 10", "AIRTEL", + "634 01", "MobiTel", + "635 10", "Rwandacell", + "636 01", "ETMTN", + "640 01", "TRITEL", + "641 10", "MTN-Uganda", + "642 02", "ANTARIS", + "643 01", "T.D.M GSM 900", + "645 01", "ZAMCELL", + "646 01", "Madacom", + "646 03", "Sacel Madagascar S.A.", + "647 10", "SRR", + "648 01", "NET*ONE", + "648 03", "Telecel", + "649 01", "MTC", + "650 01", "Callpoint 900", + "651 01", "Vodacom Lesotho (Pty) Ltd", + "655 01", "Vodacom", + "655 10", "MTN", + "680 38", "NPI Wireless", + "730 01", "Entel Telefonia Movi", + "730 10", "Entel PCS", + "734 01", "Infonet", + + NULL +}; + +char *GSM_GetNetworkName(char *NetworkCode) +{ + int i = 0; + static char retval[200]; + + EncodeUnicode(retval,"unknown",7); + while (GSM_Networks[i*2] != NULL) { + if (!strncmp(GSM_Networks[i*2],NetworkCode,6)) { + EncodeUnicode(retval, GSM_Networks[i*2+1], strlen(GSM_Networks[i*2+1])); + break; + } + i++; + } + return retval; +} + +char *GSM_GetCountryName(char *CountryCode) +{ + int i = 0; + static char retval[200]; + + EncodeUnicode(retval,"unknown",7); + while (GSM_Countries[i*2] != NULL) { + if (!strncmp(GSM_Countries[i*2],CountryCode,3)) { + EncodeUnicode(retval, GSM_Countries[i*2+1], strlen(GSM_Countries[i*2+1])); + break; + } + i++; + } + return retval; +} + +void NOKIA_EncodeNetworkCode(unsigned char* buffer, unsigned char* output) +{ + EncodeBCD(buffer, output, 6, false); + buffer[1] = buffer[1] | 0xf0; +} + +void NOKIA_DecodeNetworkCode(unsigned char* buffer, unsigned char* output) +{ + DecodeBCD(output, buffer, 3); + output[6] = output[5]; + output[5] = output[4]; + output[4] = output[3]; + output[3] = ' '; +} + +/* 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/service/gsmnet.h b/gammu/emb/common/service/gsmnet.h new file mode 100644 index 0000000..aaea22f --- a/dev/null +++ b/gammu/emb/common/service/gsmnet.h @@ -0,0 +1,98 @@ +/* (c) 2002-2003 by Marcin Wiacek & Michal Cihar */ + +#ifndef __gsm_net_h +#define __gsm_net_h + +/** + * Find network name from given network code. + */ +char *GSM_GetNetworkName(char *NetworkCode); + +/** + * Find country name from given country code. + */ +char *GSM_GetCountryName(char *CountryCode); + +/** + * Status of network logging + */ +typedef enum { + /** + * Home network for used SIM card. + */ + GSM_HomeNetwork = 1, + /** + * No network available for used SIM card. + */ + GSM_NoNetwork, + /** + * SIM card uses roaming. + */ + GSM_RoamingNetwork, + /** + * Network registration denied - card blocked or expired or disabled. + */ + GSM_RegistrationDenied, + /** + * Unknown network status. + */ + GSM_NetworkStatusUnknown, + /** + * Network explicitely requested by user. + */ + GSM_RequestingNetwork +} GSM_NetworkInfo_State; + +/** + * Structure for getting the current network info. + */ +typedef struct { + /** + * Cell ID (CID) + */ + unsigned char CID[10]; + /** + * GSM network code. + */ + char NetworkCode[10]; + /** + * Status of network logging. If phone is not logged into any network, + * some values are not filled + */ + GSM_NetworkInfo_State State; + /** + * LAC (Local Area Code). + */ + unsigned char LAC[10]; + /** + * Name of current network like returned from phone (or empty). + */ + unsigned char NetworkName[15*2]; +} GSM_NetworkInfo; + +void NOKIA_EncodeNetworkCode (unsigned char* buffer, unsigned char* output); +void NOKIA_DecodeNetworkCode (unsigned char* buffer, unsigned char* output); + +/** + * Information about signal quality, all these should be -1 when unknown. + */ +typedef struct { + /* + * Signal strength in dBm + */ + int SignalStrength; + /** + * Signal strength in percent. + */ + int SignalPercent; + /** + * Bit error rate in percent. + */ + int BitErrorRate; +} GSM_SignalQuality; + +#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/service/gsmpbk.c b/gammu/emb/common/service/gsmpbk.c new file mode 100644 index 0000000..05e5cb9 --- a/dev/null +++ b/gammu/emb/common/service/gsmpbk.c @@ -0,0 +1,370 @@ +/* (c) 2001-2003 by Marcin Wiacek,... */ + +#include <string.h> + +#include "../misc/coding/coding.h" +#include "gsmpbk.h" +#include "gsmmisc.h" + +unsigned char *GSM_PhonebookGetEntryName (GSM_MemoryEntry *entry) +{ + /* We possibly store here "LastName, FirstName" so allocate enough memory */ + static char dest[(GSM_PHONEBOOK_TEXT_LENGTH*2+2+1)*2]; + static char split[] = { '\0', ',', '\0', ' ', '\0', '\0'}; + int i; + int first = -1, last = -1, name = -1; + int len = 0; + + for (i = 0; i < entry->EntriesNum; i++) { + switch (entry->Entries[i].EntryType) { + case PBK_Text_LastName: + last = i; + break; + case PBK_Text_FirstName: + first = i; + break; + case PBK_Text_Name: + name = i; + break; + default: + break; + } + } + + if (name != -1) { + CopyUnicodeString(dest, entry->Entries[name].Text); + } else { + if (last != -1 && first != -1) { + len = UnicodeLength(entry->Entries[last].Text); + CopyUnicodeString(dest, entry->Entries[last].Text); + CopyUnicodeString(dest + 2*len, split); + CopyUnicodeString(dest + 2*len + 4, entry->Entries[first].Text); + } else if (last != -1) { + CopyUnicodeString(dest, entry->Entries[last].Text); + } else if (first != -1) { + CopyUnicodeString(dest, entry->Entries[first].Text); + } else { + return NULL; + } + } + + return dest; +} + +void GSM_PhonebookFindDefaultNameNumberGroup(GSM_MemoryEntry *entry, int *Name, int *Number, int *Group) +{ + int i; + + *Name = -1; + *Number = -1; + *Group = -1; + for (i = 0; i < entry->EntriesNum; i++) { + switch (entry->Entries[i].EntryType) { + case PBK_Number_General : if (*Number == -1) *Number = i; break; + case PBK_Text_Name : if (*Name == -1) *Name = i; break; + case PBK_Caller_Group : if (*Group == -1) *Group = i; break; + default : break; + } + } + if ((*Number) == -1) { + for (i = 0; i < entry->EntriesNum; i++) { + switch (entry->Entries[i].EntryType) { + case PBK_Number_Mobile: + case PBK_Number_Work: + case PBK_Number_Fax: + case PBK_Number_Home: + case PBK_Number_Pager: + case PBK_Number_Other: + *Number = i; + break; + default: + break; + } + if (*Number != -1) break; + } + } + if ((*Name) == -1) { + for (i = 0; i < entry->EntriesNum; i++) { + if (entry->Entries[i].EntryType != PBK_Text_LastName) continue; + *Name = i; + break; + } + } + if ((*Name) == -1) { + for (i = 0; i < entry->EntriesNum; i++) { + if (entry->Entries[i].EntryType != PBK_Text_FirstName) continue; + *Name = i; + break; + } + } +} + +void GSM_EncodeVCARD(char *Buffer, int *Length, GSM_MemoryEntry *pbk, bool header, GSM_VCardVersion Version) +{ + int Name, Number, Group, i; + bool ignore; + + GSM_PhonebookFindDefaultNameNumberGroup(pbk, &Name, &Number, &Group); + + if (Version == Nokia_VCard10) { + if (header) *Length+=sprintf(Buffer+(*Length),"BEGIN:VCARD%c%c",13,10); + if (Name != -1) { + *Length+=sprintf(Buffer+(*Length),"N:%s%c%c",DecodeUnicodeString(pbk->Entries[Name].Text),13,10); + } + if (Number != -1) { + *Length +=sprintf(Buffer+(*Length),"TEL:%s%c%c",DecodeUnicodeString(pbk->Entries[Number].Text),13,10); + } + if (header) *Length+=sprintf(Buffer+(*Length),"END:VCARD%c%c",13,10); + } else if (Version == Nokia_VCard21) { + if (header) *Length+=sprintf(Buffer+(*Length),"BEGIN:VCARD%c%cVERSION:2.1%c%c",13,10,13,10); + if (Name != -1) { + SaveVCALText(Buffer, Length, pbk->Entries[Name].Text, "N"); + } + for (i=0; i < pbk->EntriesNum; i++) { + if (i != Name) { + ignore = false; + switch(pbk->Entries[i].EntryType) { + case PBK_Text_Name : + case PBK_Date : + case PBK_Caller_Group : + ignore = true; + break; + case PBK_Number_General : + *Length+=sprintf(Buffer+(*Length),"TEL"); + if (Number == i) (*Length)+=sprintf(Buffer+(*Length),";PREF"); + break; + case PBK_Number_Mobile : + *Length+=sprintf(Buffer+(*Length),"TEL"); + if (Number == i) (*Length)+=sprintf(Buffer+(*Length),";PREF"); + *Length+=sprintf(Buffer+(*Length),";CELL"); + break; + case PBK_Number_Work : + *Length+=sprintf(Buffer+(*Length),"TEL"); + if (Number == i) (*Length)+=sprintf(Buffer+(*Length),";PREF"); + *Length+=sprintf(Buffer+(*Length),";WORK;VOICE"); + break; + case PBK_Number_Fax : + *Length+=sprintf(Buffer+(*Length),"TEL"); + if (Number == i) (*Length)+=sprintf(Buffer+(*Length),";PREF"); + *Length+=sprintf(Buffer+(*Length),";FAX"); + break; + case PBK_Number_Home : + *Length+=sprintf(Buffer+(*Length),"TEL"); + if (Number == i) (*Length)+=sprintf(Buffer+(*Length),";PREF"); + *Length+=sprintf(Buffer+(*Length),";HOME;VOICE"); + break; + case PBK_Text_Note : + *Length+=sprintf(Buffer+(*Length),"NOTE"); + break; + case PBK_Text_Postal : + /* Don't ask why. Nokia phones save postal address + * double - once like LABEL, second like ADR + */ + SaveVCALText(Buffer, Length, pbk->Entries[i].Text, "LABEL"); + *Length+=sprintf(Buffer+(*Length),"ADR"); + break; + case PBK_Text_Email : + case PBK_Text_Email2 : + *Length+=sprintf(Buffer+(*Length),"EMAIL"); + break; + case PBK_Text_URL : + *Length+=sprintf(Buffer+(*Length),"URL"); + break; + default : + ignore = true; + break; + } + if (!ignore) { + SaveVCALText(Buffer, Length, pbk->Entries[i].Text, ""); + } + } + } + if (header) *Length+=sprintf(Buffer+(*Length),"END:VCARD%c%c",13,10); + } +} + +GSM_Error GSM_DecodeVCARD(unsigned char *Buffer, int *Pos, GSM_MemoryEntry *Pbk, GSM_VCardVersion Version) +{ + unsigned char Line[2000],Buff[2000]; + int Level = 0; + + Buff[0] = 0; + Pbk->EntriesNum = 0; + + while (1) { + MyGetLine(Buffer, Pos, Line, strlen(Buffer)); + if (strlen(Line) == 0) break; + switch (Level) { + case 0: + if (strstr(Line,"BEGIN:VCARD")) Level = 1; + break; + case 1: + if (strstr(Line,"END:VCARD")) { + if (Pbk->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; + } + if (ReadVCALText(Line, "N", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Name; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "TEL", Buff) || + ReadVCALText(Line, "TEL;VOICE", Buff) || + ReadVCALText(Line, "TEL;PREF", Buff) || + ReadVCALText(Line, "TEL;PREF;VOICE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_General; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "TEL;CELL", Buff) || + ReadVCALText(Line, "TEL;CELL;VOICE", Buff) || + ReadVCALText(Line, "TEL;PREF;CELL", Buff) || + ReadVCALText(Line, "TEL;PREF;CELL;VOICE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Mobile; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "TEL;WORK", Buff) || + ReadVCALText(Line, "TEL;PREF;WORK", Buff) || + ReadVCALText(Line, "TEL;WORK;VOICE", Buff) || + ReadVCALText(Line, "TEL;PREF;WORK;VOICE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Work; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "TEL;FAX", Buff) || + ReadVCALText(Line, "TEL;PREF;FAX", Buff) || + ReadVCALText(Line, "TEL;FAX;VOICE", Buff) || + ReadVCALText(Line, "TEL;PREF;FAX;VOICE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Fax; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "TEL;HOME", Buff) || + ReadVCALText(Line, "TEL;PREF;HOME", Buff) || + ReadVCALText(Line, "TEL;HOME;VOICE", Buff) || + ReadVCALText(Line, "TEL;PREF;HOME;VOICE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Number_Home; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "NOTE", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Note; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "ADR", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Postal; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "EMAIL", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_Email; + Pbk->EntriesNum++; + } + if (ReadVCALText(Line, "URL", Buff)) { + CopyUnicodeString(Pbk->Entries[Pbk->EntriesNum].Text,Buff); + Pbk->Entries[Pbk->EntriesNum].EntryType = PBK_Text_URL; + Pbk->EntriesNum++; + } + break; + } + } + + if (Pbk->EntriesNum == 0) return ERR_EMPTY; + return ERR_NONE; +} + +/* -------------- OLD functions (c) by Timo Teras -------------------------- */ + +#ifndef ENABLE_LGPL + +static void ParseVCardLine(char **pos, char *Name, char *Parameters, char *Value) +{ + int i; + + Name[0] = Parameters[0] = Value[0] = 0; + + if (**pos == 0) return; + + for (i=0; **pos && **pos != ':' && **pos != ';'; i++, (*pos)++) Name[i] = **pos; + Name[i] = 0; + + //dbgprintf("ParseVCardLine: name tag = '%s'\n", Name); + if (**pos == ';') { + (*pos)++; + for (i=0; **pos && **pos != ':'; i++, (*pos)++) Parameters[i] = **pos; + Parameters[i] = ';'; + Parameters[i+1] = 0; + //dbgprintf("ParseVCardLine: parameter tag = '%s'\n", Parameters); + } + + if (**pos != 0) (*pos)++; + + i=0; + while (**pos) { + if ((*pos)[0] == '\x0d' && (*pos)[1] == '\x0a') { + (*pos) += 2; + if (**pos != '\t' && **pos != ' ') break; + while (**pos == '\t' || **pos == ' ') (*pos)++; + continue; + } + Value[i++] = **pos; + (*pos)++; + } + Value[i] = 0; + + //dbgprintf("ParseVCardLine: value tag = '%s'\n", Value); +} + +void DecodeVCARD21Text(char *VCard, GSM_MemoryEntry *pbk) +{ + char *pos = VCard; + char Name[32], Parameters[256], Value[1024]; + + dbgprintf("Parsing VCard:\n%s\n", VCard); + + ParseVCardLine(&pos, Name, Parameters, Value); + if (!mystrncasecmp(Name, "BEGIN", 0) || !mystrncasecmp(Value, "VCARD", 0)) { + dbgprintf("No valid VCARD signature\n"); + return; + } + + while (1) { + GSM_SubMemoryEntry *pbe = &pbk->Entries[pbk->EntriesNum]; + + ParseVCardLine(&pos, Name, Parameters, Value); + if (Name[0] == 0x00 || + (mystrncasecmp(Name, "END", 0) && mystrncasecmp(Value, "VCARD", 0))) + return; + + if (mystrncasecmp(Name, "N", 0)) { + //FIXME: Name is tagged field which should be parsed + pbe->EntryType = PBK_Text_Name; + EncodeUnicode(pbe->Text, Value, strlen(Value)); + pbk->EntriesNum++; + } else if (mystrncasecmp(Name, "EMAIL", 0)) { + pbe->EntryType = PBK_Text_Email; + EncodeUnicode(pbe->Text, Value, strlen(Value)); + pbk->EntriesNum++; + } else if (mystrncasecmp(Name, "TEL", 0)) { + if (strstr(Parameters, "WORK;")) + pbe->EntryType = PBK_Number_Work; + else if (strstr(Name, "HOME;")) + pbe->EntryType = PBK_Number_Home; + else if (strstr(Name, "FAX;")) + pbe->EntryType = PBK_Number_Fax; + else pbe->EntryType = PBK_Number_General; + + EncodeUnicode(pbe->Text, Value, strlen(Value)); + pbk->EntriesNum++; + } + } +} + +#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/service/gsmpbk.h b/gammu/emb/common/service/gsmpbk.h new file mode 100644 index 0000000..e556793 --- a/dev/null +++ b/gammu/emb/common/service/gsmpbk.h @@ -0,0 +1,270 @@ +/* (c) 2001-2004 by Marcin Wiacek and Michal Cihar */ + +#ifndef __gsm_pbk_h +#define __gsm_pbk_h + +#include <stdlib.h> + +#include "../gsmcomon.h" +#include "gsmmisc.h" + +/** + * Structure contains info about number of used/free entries in phonebook + * memory + */ +typedef struct { + /** + * Number of used entries + */ + int MemoryUsed; + /** + * Memory type + */ + GSM_MemoryType MemoryType; + /** + * Number of free entries + */ + int MemoryFree; +} GSM_MemoryStatus; + +/** + * Type of specific phonebook entry. In parenthesis is specified in which + * member of @ref GSM_SubMemoryEntry value is stored. + */ +typedef enum { + /** + * General number. (Text) + */ + PBK_Number_General = 1, + /** + * Mobile number. (Text) + */ + PBK_Number_Mobile, + /** + * Work number. (Text) + */ + PBK_Number_Work, + /** + * Fax number. (Text) + */ + PBK_Number_Fax, + /** + * Home number. (Text) + */ + PBK_Number_Home, + /** + * Pager number. (Text) + */ + PBK_Number_Pager, + /** + * Other number. (Text) + */ + PBK_Number_Other, + /** + * Note. (Text) + */ + PBK_Text_Note, + /** + * Complete postal address. (Text) + */ + PBK_Text_Postal, + /** + * Email. (Text) + */ + PBK_Text_Email, + /** + * Second email. (Text) + */ + PBK_Text_Email2, + /** + * URL (Text) + */ + PBK_Text_URL, + /** + * Date and time. FIXME: describe better (Date) + */ + PBK_Date, + /** + * Caller group. (Text) + */ + PBK_Caller_Group, + /** + * Name (Text) + */ + PBK_Text_Name, + /** + * Last name. (Text) + */ + PBK_Text_LastName, + /** + * First name. (Text) + */ + PBK_Text_FirstName, + /** + * Company. (Text) + */ + PBK_Text_Company, + /** + * Job title. (Text) + */ + PBK_Text_JobTitle, + /** + * Category. (Number) + */ + PBK_Category, + /** + * Whether entry is private. (Number) + */ + PBK_Private, + /** + * Street address. (Text) + */ + PBK_Text_StreetAddress, + /** + * City. (Text) + */ + PBK_Text_City, + /** + * State. (Text) + */ + PBK_Text_State, + /** + * Zip code. (Text) + */ + PBK_Text_Zip, + /** + * Country. (Text) + */ + PBK_Text_Country, + /** + * Custom information 1. (Text) + */ + PBK_Text_Custom1, + /** + * Custom information 2. (Text) + */ + PBK_Text_Custom2, + /** + * Custom information 3. (Text) + */ + PBK_Text_Custom3, + /** + * Custom information 4. (Text) + */ + PBK_Text_Custom4, + /** + * Ringtone ID. (Number) + */ + PBK_RingtoneID, + /** + * Ringtone ID in phone filesystem. (Number) + */ + PBK_RingtoneFileSystemID, + /** + * Picture ID. (Number) + */ + PBK_PictureID, + PBK_SMSListID, + /** + * User ID. (Text) + */ + PBK_Text_UserID +} GSM_EntryType; + +#define GSM_PHONEBOOK_TEXT_LENGTH 200 +#define GSM_PHONEBOOK_ENTRIES 26 + +/** + * One value of phonebook memory entry. + */ +typedef struct { + /** + * Type of entry. + */ + GSM_EntryType EntryType; + /** + * Text of entry (if applicable, see @ref GSM_EntryType). + */ + unsigned char Text[(GSM_PHONEBOOK_TEXT_LENGTH+1)*2]; + /** + * Text of entry (if applicable, see @ref GSM_EntryType). + */ + GSM_DateTime Date; + /** + * Number of entry (if applicable, see @ref GSM_EntryType). + */ + int Number; + /** + * Voice dialling tag. + */ + int VoiceTag; + int SMSList[20]; +} GSM_SubMemoryEntry; + +/** + * Structure for saving phonebook entries + */ +typedef struct { + /** + * Used memory for phonebook entry + */ + GSM_MemoryType MemoryType; + /** + * Used location for phonebook entry + */ + int Location; + /** + * Number of SubEntries in Entries table. + */ + int EntriesNum; + /** + * Values of SubEntries. + */ + GSM_SubMemoryEntry Entries[GSM_PHONEBOOK_ENTRIES]; +} GSM_MemoryEntry; + +typedef enum { + Nokia_VCard10 = 1, + Nokia_VCard21, + SonyEricsson_VCard10, + SonyEricsson_VCard21 +} GSM_VCardVersion; + +void GSM_PhonebookFindDefaultNameNumberGroup(GSM_MemoryEntry *entry, int *Name, int *Number, int *Group); +unsigned char *GSM_PhonebookGetEntryName (GSM_MemoryEntry *entry); + +void GSM_EncodeVCARD(char *Buffer, int *Length, GSM_MemoryEntry *pbk, bool header, GSM_VCardVersion Version); +GSM_Error GSM_DecodeVCARD(unsigned char *Buffer, int *Pos, GSM_MemoryEntry *Pbk, GSM_VCardVersion Version); + +#ifndef ENABLE_LGPL +/* (c) by Timo Teras */ +void DecodeVCARD21Text(char *VCard, GSM_MemoryEntry *pbk); +#endif + +/** + * Structure for saving speed dials + */ +typedef struct { + /** + * Number of speed dial: 2,3..,8,9 + */ + int Location; + /** + * ID of phone number used in phonebook entry + */ + int MemoryNumberID; + /** + * Memory, where is saved used phonebook entry + */ + GSM_MemoryType MemoryType; + /** + * Location in memory, where is saved used phonebook entry + */ + int MemoryLocation; +} GSM_SpeedDial; + +#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/service/gsmprof.h b/gammu/emb/common/service/gsmprof.h new file mode 100644 index 0000000..2e3d087 --- a/dev/null +++ b/gammu/emb/common/service/gsmprof.h @@ -0,0 +1,104 @@ +/* (c) 2002-2003 by Marcin Wiacek */ + +#ifndef __gsm_prof_h +#define __gsm_prof_h + +typedef enum { + PROFILE_KEYPAD_LEVEL1 = 1, + PROFILE_KEYPAD_LEVEL2, + PROFILE_KEYPAD_LEVEL3, + PROFILE_KEYPAD_OFF, + PROFILE_CALLALERT_RINGING, + PROFILE_CALLALERT_BEEPONCE, + PROFILE_CALLALERT_OFF, + PROFILE_CALLALERT_RINGONCE, + PROFILE_CALLALERT_ASCENDING, + PROFILE_CALLALERT_CALLERGROUPS, + PROFILE_VOLUME_LEVEL1, + PROFILE_VOLUME_LEVEL2, + PROFILE_VOLUME_LEVEL3, + PROFILE_VOLUME_LEVEL4, + PROFILE_VOLUME_LEVEL5, + PROFILE_MESSAGE_NOTONE, + PROFILE_MESSAGE_STANDARD, + PROFILE_MESSAGE_SPECIAL, + PROFILE_MESSAGE_BEEPONCE, + PROFILE_MESSAGE_ASCENDING, + PROFILE_MESSAGE_PERSONAL, + PROFILE_VIBRATION_OFF, + PROFILE_VIBRATION_ON, + PROFILE_VIBRATION_FIRST, + PROFILE_WARNING_ON, + PROFILE_WARNING_OFF, + PROFILE_AUTOANSWER_ON, + PROFILE_AUTOANSWER_OFF, + PROFILE_LIGHTS_OFF, + PROFILE_LIGHTS_AUTO, + PROFILE_SAVER_ON, + PROFILE_SAVER_OFF, + PROFILE_SAVER_TIMEOUT_5SEC, + PROFILE_SAVER_TIMEOUT_20SEC, + PROFILE_SAVER_TIMEOUT_1MIN, + PROFILE_SAVER_TIMEOUT_2MIN, + PROFILE_SAVER_TIMEOUT_5MIN, + PROFILE_SAVER_TIMEOUT_10MIN +} GSM_Profile_Feat_Value; + +typedef enum { + Profile_KeypadTone = 1, + Profile_CallAlert, + Profile_RingtoneVolume, + Profile_MessageTone, + Profile_Vibration, + Profile_WarningTone, + Profile_AutoAnswer, + Profile_Lights, + Profile_ScreenSaverTime, + Profile_ScreenSaver, + + Profile_ScreenSaverNumber, + Profile_RingtoneID, + Profile_MessageToneID, + Profile_CallerGroups +} GSM_Profile_Feat_ID; + +/** + * It contains phone profiles + */ +typedef struct { + bool Active; + + /** + * Profile number + */ + int Location; + /** + * Profile name + */ + char Name[40*2]; + /** + * Is it default name for profile ? + */ + bool DefaultName; + bool HeadSetProfile; + bool CarKitProfile; + + int FeaturesNumber; + GSM_Profile_Feat_Value FeatureValue[15]; + GSM_Profile_Feat_ID FeatureID[15]; + + bool CallerGroups[5]; +} GSM_Profile; + +typedef struct { + GSM_Profile_Feat_ID ID; + GSM_Profile_Feat_Value Value; + unsigned char PhoneID; + unsigned char PhoneValue; +} GSM_Profile_PhoneTableValue; + +#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/service/gsmring.c b/gammu/emb/common/service/gsmring.c new file mode 100644 index 0000000..5a1ff87 --- a/dev/null +++ b/gammu/emb/common/service/gsmring.c @@ -0,0 +1,1600 @@ +/* (c) 2001-2004 by Marcin Wiacek */ +/* Based on some work from Ralf Thelen (7110 ringtones), + * Gnokii (RTTL and SM) and others + */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <math.h> +#ifdef WIN32 +# include <windows.h> +#endif + +#include "../gsmcomon.h" +#include "../misc/coding/coding.h" +#include "../gsmstate.h" +#include "gsmring.h" +#include "sms/gsmsms.h" + +int GSM_RingNoteGetFrequency(GSM_RingNote Note) +{ + double freq=0; + + /* Values according to the software from http://iki.fi/too/sw/xring/ + * generated with: + * perl -e 'print int(4400 * (2 **($_/12)) + .5)/10, "\n" for(3..14)' + */ + switch (Note.Note) { + case Note_C : freq = 523.3; break; + case Note_Cis: freq = 554.4; break; + case Note_D : freq = 587.3; break; + case Note_Dis: freq = 622.3; break; + case Note_E : freq = 659.3; break; + case Note_F : freq = 698.5; break; + case Note_Fis: freq = 740; break; + case Note_G : freq = 784; break; + case Note_Gis: freq = 830.6; break; + case Note_A : freq = 880; break; + case Note_Ais: freq = 932.3; break; + case Note_H : freq = 987.8; break; + case Note_Pause: break; + } + switch (Note.Scale) { + case Scale_440 : freq = freq / 2; break; + case Scale_880 : break; + case Scale_1760: freq = freq * 2; break; + case Scale_3520: freq = freq * 4; break; + default : break; + } + return (int)freq; +} + +int GSM_RingNoteGetFullDuration(GSM_RingNote Note) +{ + int duration = 1; + + switch (Note.Duration) { + case Duration_Full : duration = 128; break; + case Duration_1_2 : duration = 64; break; + case Duration_1_4 : duration = 32; break; + case Duration_1_8 : duration = 16; break; + case Duration_1_16 : duration = 8; break; + case Duration_1_32 : duration = 4; break; + } + switch (Note.DurationSpec) { + case NoSpecialDuration : break; + case DottedNote : duration = duration * 3/2; break; + case DoubleDottedNote : duration = duration * 9/4; break; + case Length_2_3 : duration = duration * 2/3; break; + } + return duration; +} + +#ifndef PI +# define PI 3.141592654 +#endif + +#define WAV_SAMPLE_RATE 44100 + +GSM_Error savewav(FILE *file, GSM_Ringtone *ringtone) +{ + unsigned char WAV_Header[] = { + 'R','I','F','F', + 0x00,0x00,0x00,0x00, /* Length */ + 'W','A','V','E'}; + unsigned char FMT_Header[] = {'f','m','t',' ', + 0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x44,0xac, + 0x00,0x00,0x88,0x58,0x01,0x00,0x02,0x00,0x10,0x00}; + unsigned char DATA_Header[] = { + 'd','a','t','a', + 0x00,0x00,0x00,0x00}; /* Length */ + short DATA_Buffer[60000]; + long wavfilesize; + GSM_RingNote *Note; + long i,j,length=0; + double phase=0,phase_step; + + fwrite(&WAV_Header, 1, sizeof(WAV_Header), file); + fwrite(&FMT_Header, 1, sizeof(FMT_Header), file); + fwrite(&DATA_Header, 1, sizeof(DATA_Header), file); + + for (i=0;i<ringtone->NoteTone.NrCommands;i++) { + if (ringtone->NoteTone.Commands[i].Type == RING_Note) { + Note = &ringtone->NoteTone.Commands[i].Note; + phase_step = GSM_RingNoteGetFrequency(*Note)*WAV_SAMPLE_RATE*1.5; + for (j=0;j<((long)(GSM_RingNoteGetFullDuration(*Note)*WAV_SAMPLE_RATE/70));j++) { + DATA_Buffer[j] = ((int)(sin(phase*PI)*50000)); + phase = phase + phase_step; + length++; + } + fwrite(&DATA_Buffer,sizeof(short),j,file); + } + } + + wavfilesize = sizeof(WAV_Header) + sizeof(FMT_Header) + sizeof(DATA_Header) + length*2; + WAV_Header[4] = ((unsigned char)wavfilesize % 256); + WAV_Header[5] = ((unsigned char)wavfilesize / 256); + WAV_Header[6] = ((unsigned char)wavfilesize / (256*256)); + WAV_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); + wavfilesize = wavfilesize - 54; + DATA_Header[4] = ((unsigned char)wavfilesize % 256); + DATA_Header[5] = ((unsigned char)wavfilesize / 256); + DATA_Header[6] = ((unsigned char)wavfilesize / (256*256)); + DATA_Header[7] = ((unsigned char)wavfilesize / (256*256*256)); + + fseek( file, 0, SEEK_SET); + fwrite(&WAV_Header, 1, sizeof(WAV_Header), file); + fwrite(&FMT_Header, 1, sizeof(FMT_Header), file); + fwrite(&DATA_Header, 1, sizeof(DATA_Header), file); + + return ERR_NONE; +} + +static GSM_Error savebin(FILE *file, GSM_Ringtone *ringtone) +{ + char nullchar=0x00; + + fwrite(&nullchar,1,1,file); + fwrite(&nullchar,1,1,file); + fprintf(file,"\x0C\x01\x2C"); + fprintf(file,"%s",DecodeUnicodeString(ringtone->Name)); + fwrite(&nullchar,1,1,file); + fwrite(&nullchar,1,1,file); + fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); + return ERR_NONE; +} + +static GSM_Error savepuremidi(FILE *file, GSM_Ringtone *ringtone) +{ + fwrite(ringtone->NokiaBinary.Frame,1,ringtone->NokiaBinary.Length,file); + return ERR_NONE; +} + +GSM_Error saverttl(FILE *file, GSM_Ringtone *ringtone) +{ + GSM_RingNoteScale DefNoteScale; + GSM_RingNoteDuration DefNoteDuration; + + GSM_RingNoteStyle DefNoteStyle=0; + int DefNoteTempo=0; + + bool started = false, firstcomma = true; + GSM_RingNote *Note; + + unsigned char buffer[15]; + int i,j,k=0; + + /* Saves ringtone name */ + fprintf(file,"%s:",DecodeUnicodeString(ringtone->Name)); + + /* Find the most frequently used duration */ + for (i=0;i<6;i++) buffer[i]=0; + for (i=0;i<ringtone->NoteTone.NrCommands;i++) { + if (ringtone->NoteTone.Commands[i].Type == RING_Note) { + Note = &ringtone->NoteTone.Commands[i].Note; + /* some durations need 2 bytes in file, some 1 */ + if (Note->Duration >= Duration_Full && Note->Duration <= Duration_1_8) { + buffer[Note->Duration/32]++; + } + if (Note->Duration >= Duration_1_16 && Note->Duration <= Duration_1_32) { + buffer[Note->Duration/32]+=2; + } + } + } + /* Now find the most frequently used */ + j=0; + for (i=0;i<6;i++) { + if (buffer[i]>j) { + k=i; + j=buffer[i]; + } + } + /* Finally convert the default duration */ + DefNoteDuration = k * 32; + dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); + switch (DefNoteDuration) { + case Duration_Full:fprintf(file,"d=1"); break; + case Duration_1_2 :fprintf(file,"d=2"); break; + case Duration_1_4 :fprintf(file,"d=4"); break; + case Duration_1_8 :fprintf(file,"d=8"); break; + case Duration_1_16:fprintf(file,"d=16");break; + case Duration_1_32:fprintf(file,"d=32");break; + } + + /* Find the most frequently used scale */ + for (i=0;i<9;i++) buffer[i]=0; + for (i=0;i<ringtone->NoteTone.NrCommands;i++) { + if (ringtone->NoteTone.Commands[i].Type == RING_Note) { + Note = &ringtone->NoteTone.Commands[i].Note; + if (Note->Note!=Note_Pause && + Note->Scale >= Scale_55 && Note->Scale <= Scale_14080) { + buffer[Note->Scale - 1]++; + } + } + } + j=0; + for (i=0;i<9;i++) { + if (buffer[i]>j) { + k = i; + j=buffer[i]; + } + } + DefNoteScale = k + 1; + /* Save the default scale */ + fprintf(file,",o=%i,",DefNoteScale); + dbgprintf("DefNoteScale=%d\n", DefNoteScale); + + for (i=0;i<ringtone->NoteTone.NrCommands;i++) { + if (ringtone->NoteTone.Commands[i].Type != RING_Note) continue; + + Note = &ringtone->NoteTone.Commands[i].Note; + + /* Trick from PPM Edit */ + if (Note->DurationSpec == DoubleDottedNote) { + switch (Note->Duration) { + case Duration_Full:Note->Duration = Duration_Full;break; + case Duration_1_2 :Note->Duration = Duration_Full;break; + case Duration_1_4 :Note->Duration = Duration_1_2; break; + case Duration_1_8 :Note->Duration = Duration_1_4; break; + case Duration_1_16:Note->Duration = Duration_1_8; break; + case Duration_1_32:Note->Duration = Duration_1_16;break; + } + Note->DurationSpec = NoSpecialDuration; + } + + if (!started) { + DefNoteTempo=Note->Tempo; + DefNoteStyle=Note->Style; + switch (Note->Style) { + case StaccatoStyle : fprintf(file,"s=S,"); break; + case NaturalStyle : fprintf(file,"s=N,"); break; + case ContinuousStyle : break; + } + /* Save the default tempo */ + fprintf(file,"b=%i:",DefNoteTempo); + dbgprintf("DefNoteTempo=%d\n", DefNoteTempo); + started = true; + firstcomma = true; + } + + if (!started) continue; + + if (Note->Style!=DefNoteStyle) { + /* And a separator */ + if (!firstcomma) fprintf(file,","); + firstcomma = false; + DefNoteStyle=Note->Style; + switch (Note->Style) { + case StaccatoStyle : fprintf(file,"s=S"); break; + case NaturalStyle : fprintf(file,"s=N"); break; + case ContinuousStyle: fprintf(file,"s=C"); break; + } + } + if (Note->Tempo!=DefNoteTempo) { + /* And a separator */ + if (!firstcomma) fprintf(file,","); + firstcomma = false; + DefNoteTempo=Note->Tempo; + fprintf(file,"b=%i",DefNoteTempo); + } + /* This note has a duration different than the default. We must save it */ + if (Note->Duration!=DefNoteDuration) { + /* And a separator */ + if (!firstcomma) fprintf(file,","); + firstcomma = false; + switch (Note->Duration) { + case Duration_Full:fprintf(file,"1"); break; + case Duration_1_2 :fprintf(file,"2"); break; + case Duration_1_4 :fprintf(file,"4"); break; + case Duration_1_8 :fprintf(file,"8"); break; + case Duration_1_16:fprintf(file,"16");break; + case Duration_1_32:fprintf(file,"32");break; + } + } else { + /* And a separator */ + if (!firstcomma) fprintf(file,","); + firstcomma = false; + } + /* Now save the actual note */ + switch (Note->Note) { + case Note_C :fprintf(file,"c"); break; + case Note_Cis:fprintf(file,"c#"); break; + case Note_D :fprintf(file,"d"); break; + case Note_Dis:fprintf(file,"d#"); break; + case Note_E :fprintf(file,"e"); break; + case Note_F :fprintf(file,"f"); break; + case Note_Fis:fprintf(file,"f#"); break; + case Note_G :fprintf(file,"g"); break; + case Note_Gis:fprintf(file,"g#"); break; + case Note_A :fprintf(file,"a"); break; + case Note_Ais:fprintf(file,"a#"); break; + case Note_H :fprintf(file,"h"); break; + default :fprintf(file,"p"); break; /*Pause ?*/ + } + switch (Note->DurationSpec) { + case DottedNote : fprintf(file,"."); break; + default : break; + } + if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) { + fprintf(file,"%i",Note->Scale); + } + } + return ERR_NONE; +} + +void saveimelody(FILE *file, GSM_Ringtone *ringtone) +{ + char Buffer[2000]; + int i=2000; + + GSM_EncodeEMSSound(*ringtone, Buffer, &i, (float)1.2, true); + + fwrite(Buffer, 1, i, file); +} + +#ifndef ENABLE_LGPL + +static void WriteVarLen(unsigned char* midifile, int* current, long value) +{ + long buffer; + + buffer = value & 0x7f; + + while (value >>= 7) { + buffer <<= 8; + buffer |= 0x80; + buffer += (value & 0x7f); + } + + while (1) { + midifile[(*current)++] = (unsigned char)buffer; + if (buffer & 0x80) { + buffer >>= 8; + } else { + break; + } + } +} + +#define singlepauses + +/* FIXME: need adding tempo before each note and scale too ? */ +void savemid(FILE* file, GSM_Ringtone *ringtone) +{ + int pause = 0, current = 26, duration, i, note=0, length = 20; + bool started = false; + GSM_RingNote *Note; + unsigned char midifile[3000] = { + 0x4D, 0x54, 0x68, 0x64, // MThd + 0x00, 0x00, 0x00, 0x06, // chunk length + 0x00, 0x00, // format 0 + 0x00, 0x01, // one track + 0x00, 0x20, // 32 per quarter note + 0x4D, 0x54, 0x72, 0x6B, // MTrk + 0x00, 0x00, 0x00, 0x00, // chunk length + 0x00, 0xFF, 0x51, 0x03, // tempo meta event + 0x00, 0x00, 0x00}; // 3 bytes for us for a quarter note + + for (i = 0; i < ringtone->NoteTone.NrCommands; i++) { + if (ringtone->NoteTone.Commands[i].Type == RING_Note) { + Note = &ringtone->NoteTone.Commands[i].Note; + if (!started) { + /* readmid does not read pauses at the beginning */ + if (Note->Note != Note_Pause) { + /* FIXME: we need add tempo before each note or so... */ + long duration=60000000/Note->Tempo; + + midifile[current++] = (unsigned char)(duration >> 16); + midifile[current++] = (unsigned char)(duration >> 8); + midifile[current++] = (unsigned char)duration; + + started = true; + } + } + if (!started) continue; + duration = GSM_RingNoteGetFullDuration(*Note); + if (Note->Note == Note_Pause) { + pause += duration; +#ifdef singlepauses + WriteVarLen(midifile,¤t,pause); + pause=0; + midifile[current++]=0x00; // pause + midifile[current++]=0x00; +#endif + } else { + if (Note->Note >= Note_C && Note->Note <= Note_H) { + note = Note->Note/16 + 12 * Note->Scale - 1; + } + + WriteVarLen(midifile,¤t,pause); + pause=0; + midifile[current++]=0x90; // note on + midifile[current++]=note; + midifile[current++]=0x64; // forte + + WriteVarLen(midifile,¤t,duration); + midifile[current++]=0x80; // note off + midifile[current++]=note; + midifile[current++]=0x64; + } + } + } + if (pause) { + WriteVarLen(midifile,¤t,pause); + midifile[current++]=0x00; // pause + midifile[current++]=0x00; // + } + midifile[current++] = 0x00; + midifile[current++] = 0xFF; // track end + midifile[current++] = 0x2F; + midifile[current++] = 0x00; + midifile[length++] = (current-22) >> 8; + midifile[length++] = current-22; + + fwrite(midifile,1,current,file); +} + +#endif + +void saveott(FILE *file, GSM_Ringtone *ringtone) +{ + char Buffer[2000]; + int i=2000; + + GSM_EncodeNokiaRTTLRingtone(*ringtone, Buffer, &i); + + fwrite(Buffer, 1, i, file); +} + +GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone) +{ + FILE *file; + + file = fopen(FileName, "wb"); + if (file == NULL) return ERR_CANTOPENFILE; + + switch (ringtone->Format) { + case RING_NOTETONE: + if (strstr(FileName,".ott")) { + saveott(file,ringtone); +#ifndef ENABLE_LGPL + } else if (strstr(FileName,".mid")) { + savemid(file,ringtone); +#endif + } else if (strstr(FileName,".rng")) { + saveott(file,ringtone); + } else if (strstr(FileName,".imy")) { + saveimelody(file,ringtone); + } else if (strstr(FileName,".ime")) { + saveimelody(file,ringtone); + } else if (strstr(FileName,".wav")) { + savewav(file,ringtone); + } else { + saverttl(file, ringtone); + } + break; + case RING_NOKIABINARY: + savebin(file, ringtone); + break; + case RING_MIDI: + savepuremidi(file, ringtone); + break; + } + + fclose(file); + + return ERR_NONE; +} + +static GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone) +{ + GSM_RingNoteScale DefNoteScale = Scale_880; + GSM_RingNoteDuration DefNoteDuration = Duration_1_4; + GSM_RingNoteStyle DefNoteStyle = NaturalStyle; + int DefNoteTempo = 63, i=0; + + unsigned char buffer[2000],Name[100]; + GSM_RingNote *Note; + + fread(buffer, 2000, 1, file); + + ringtone->NoteTone.NrCommands = 0; + + /* -------------- name ---------------- */ + while (buffer[i] != ':') { + if (buffer[i] == 0x00) return ERR_NONE; + i++; + } + if (i == 0) { + /* This is for RTTL ringtones without name. */ + EncodeUnicode(ringtone->Name,"Gammu",5); + } else { + memcpy(Name,buffer,i); + Name[i] = 0x00; + EncodeUnicode(ringtone->Name,Name,strlen(Name)); + } + i++; + + /* --------- section with default ringtone settings ----------- */ + while(1) { + switch (buffer[i]) { + case ':': + break; + case 0x00: + return ERR_NONE; + case 'd': case 'D': + switch (atoi(buffer+i+2)) { + case 1: DefNoteDuration = Duration_Full; break; + case 2: DefNoteDuration = Duration_1_2 ; break; + case 4: DefNoteDuration = Duration_1_4 ; break; + case 8: DefNoteDuration = Duration_1_8 ; break; + case 16: DefNoteDuration = Duration_1_16; break; + case 32: DefNoteDuration = Duration_1_32; break; + } + break; + case 'o': case 'O': + switch (atoi(buffer+i+2)) { + case 4: DefNoteScale = Scale_440 ; break; + case 5: DefNoteScale = Scale_880 ; break; + case 6: DefNoteScale = Scale_1760; break; + case 7: DefNoteScale = Scale_3520; break; + } + break; + case 'b': case 'B': + DefNoteTempo=atoi(buffer+i+2); + dbgprintf("Tempo = %i\n",DefNoteTempo); + break; + case 's': case 'S': + switch (buffer[i+1]) { + case 'C': case 'c': DefNoteStyle=ContinuousStyle; break; + case 'N': case 'n': DefNoteStyle=NaturalStyle; break; + case 'S': case 's': DefNoteStyle=StaccatoStyle; break; + } + switch (buffer[i+2]) { + case 'C': case 'c': DefNoteStyle=ContinuousStyle; break; + case 'N': case 'n': DefNoteStyle=NaturalStyle; break; + case 'S': case 's': DefNoteStyle=StaccatoStyle; break; + } + break; + } + while (buffer[i] != ':' && buffer[i] != ',') { + if (buffer[i] == 0x00) return ERR_NONE; + i++; + } + if (buffer[i] == ',') i++; + if (buffer[i] == ':') break; + } + dbgprintf("DefNoteDuration=%d\n", DefNoteDuration); + dbgprintf("DefNoteScale=%d\n", DefNoteScale); + i++; + + /* ------------------------- notes ------------------------------ */ + while (buffer[i] != 0x00 && ringtone->NoteTone.NrCommands != MAX_RINGTONE_NOTES) { + switch(buffer[i]) { + case 'z': case 'Z': + switch (buffer[i+1]) { + case 'd': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLED; + ringtone->NoteTone.NrCommands++; + break; + case 'D': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLED; + ringtone->NoteTone.NrCommands++; + break; + case 'v': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableVibra; + ringtone->NoteTone.NrCommands++; + break; + case 'V': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableVibra; + ringtone->NoteTone.NrCommands++; + break; + case 'l': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_DisableLight; + ringtone->NoteTone.NrCommands++; + break; + case 'L': + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_EnableLight; + ringtone->NoteTone.NrCommands++; + } + break; + case 'o': case 'O': + switch (buffer[i+2]) { + case 4: DefNoteScale = Scale_440 ; break; + case 5: DefNoteScale = Scale_880 ; break; + case 6: DefNoteScale = Scale_1760; break; + case 7: DefNoteScale = Scale_3520; break; + } + break; + case 's': case 'S': + switch (buffer[i+1]) { + case 'C': case 'c': DefNoteStyle=ContinuousStyle; break; + case 'N': case 'n': DefNoteStyle=NaturalStyle; break; + case 'S': case 's': DefNoteStyle=StaccatoStyle; break; + } + switch (buffer[i+2]) { + case 'C': case 'c': DefNoteStyle=ContinuousStyle; break; + case 'N': case 'n': DefNoteStyle=NaturalStyle; break; + case 'S': case 's': DefNoteStyle=StaccatoStyle; break; + } + break; + default: + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; + Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; + Note->Style = DefNoteStyle; + Note->Tempo = DefNoteTempo; + Note->Scale = DefNoteScale; + Note->Duration = DefNoteDuration; + Note->DurationSpec = NoSpecialDuration; + Note->Note = Note_Pause; + + /* Duration */ + switch (atoi(buffer+i)) { + case 1: Note->Duration = Duration_Full ; break; + case 2: Note->Duration = Duration_1_2 ; break; + case 4: Note->Duration = Duration_1_4 ; break; + case 8: Note->Duration = Duration_1_8 ; break; + case 16: Note->Duration = Duration_1_16 ; break; + case 32: Note->Duration = Duration_1_32 ; break; + } + /* We skip all numbers from duration specification */ + while(isdigit(buffer[i])) i++; + + /* Some files can have special duration here */ + if (buffer[i]=='.') { + Note->DurationSpec = DottedNote; + i++; + } + + /* Note */ + /* B or b is not in specs, but I decided to put it, because + * it's in some RTTL files. It's the same to H note */ + switch (buffer[i]) { + case 'A': case 'a': Note->Note = Note_A; break; + case 'B': case 'b': Note->Note = Note_H; break; + case 'C': case 'c': Note->Note = Note_C; break; + case 'D': case 'd': Note->Note = Note_D; break; + case 'E': case 'e': Note->Note = Note_E; break; + case 'F': case 'f': Note->Note = Note_F; break; + case 'G': case 'g': Note->Note = Note_G; break; + case 'H': case 'h': Note->Note = Note_H; break; + } + i++; + + if (buffer[i]=='#') { + switch (Note->Note) { + case Note_A : Note->Note = Note_Ais; break; + case Note_C : Note->Note = Note_Cis; break; + case Note_D : Note->Note = Note_Dis; break; + case Note_F : Note->Note = Note_Fis; break; + case Note_G : Note->Note = Note_Gis; break; + default : break; + } + i++; + } + + /* Some files can have special duration here */ + if (buffer[i]=='.') { + Note->DurationSpec = DottedNote; + i++; + } + + /* Scale */ + if (Note->Note!=Note_Pause && isdigit(buffer[i])) { + switch (atoi(buffer+i)) { + case 4: Note->Scale = Scale_440 ; break; + case 5: Note->Scale = Scale_880 ; break; + case 6: Note->Scale = Scale_1760; break; + case 7: Note->Scale = Scale_3520; break; + } + i++; + } + + ringtone->NoteTone.NrCommands++; + break; + } + while (buffer[i] != ',') { + if (buffer[i] == 0x00) return ERR_NONE; + i++; + } + if (buffer[i] == ',') i++; + } + + return ERR_NONE; +} + +static GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone) +{ + char Buffer[2000]; + int i; + + i=fread(Buffer, 1, 2000, file); + + return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer, i); +} + +static GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone) +{ + char Buffer[4000]; + int i,j; + + i=fread(Buffer, 1, 4000, file); + + i=0;j=0; + while (true) { + if (Buffer[j] ==0x00 && Buffer[j+1]==0x02 && + Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break; + if (j==i-4) return ERR_UNKNOWN; + j++; + } + j++; + + return GSM_DecodeNokiaRTTLRingtone(ringtone, Buffer+j, i-j); +} + +static GSM_Error loadbin(FILE *file, GSM_Ringtone *ringtone) +{ + int i; + unsigned char buffer[2000]; + + dbgprintf("loading binary\n"); + ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); + i=5; + while (buffer[i]!=0x00) i++; + EncodeUnicode(ringtone->Name,buffer+5,i-5); + while (buffer[i]!=0x02 && buffer[i+1]!=0xFC && buffer[i+2]!=0x09) { + i++; + } + ringtone->NokiaBinary.Length=ringtone->NokiaBinary.Length-i; + memcpy(ringtone->NokiaBinary.Frame,buffer+i,ringtone->NokiaBinary.Length); + dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); + return ERR_NONE; +} + +static GSM_Error loadpuremidi(FILE *file, GSM_Ringtone *ringtone) +{ + unsigned char buffer[30000]; + + dbgprintf("loading midi\n"); + EncodeUnicode(ringtone->Name,"MIDI",4); + ringtone->NokiaBinary.Length=fread(buffer, 1, 30000, file); + memcpy(ringtone->NokiaBinary.Frame,buffer,ringtone->NokiaBinary.Length); + dbgprintf("Length %i name \"%s\"\n",ringtone->NokiaBinary.Length,DecodeUnicodeString(ringtone->Name)); + return ERR_NONE; +} + +static GSM_Error loadre(FILE *file, GSM_Ringtone *ringtone) +{ + unsigned char buffer[2000]; + + ringtone->NokiaBinary.Length=fread(buffer, 1, 500, file); + + if (buffer[18]==0x00 && buffer[21]!=0x02) { + /* DCT3, Unicode subformat, 62xx & 7110 */ + CopyUnicodeString(ringtone->Name,buffer+18); + ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (21+UnicodeLength(ringtone->Name)*2); + memcpy(ringtone->NokiaBinary.Frame,buffer+21+UnicodeLength(ringtone->Name)*2,ringtone->NokiaBinary.Length); + } else { + /* DCT3, normal subformat, 32xx/33xx/51xx/5210/5510/61xx/8xxx */ + EncodeUnicode(ringtone->Name,buffer+17,buffer[16]); + ringtone->NokiaBinary.Length = ringtone->NokiaBinary.Length - (19+UnicodeLength(ringtone->Name)); + memcpy(ringtone->NokiaBinary.Frame,buffer+19+UnicodeLength(ringtone->Name),ringtone->NokiaBinary.Length); + } + dbgprintf("Name \"%s\"\n",DecodeUnicodeString(ringtone->Name)); + return ERR_NONE; +} + +GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone) +{ + FILE *file; + unsigned char buffer[300]; + GSM_Error error = ERR_UNKNOWN; + + dbgprintf("Loading ringtone %s\n",FileName); + file = fopen(FileName, "rb"); + if (file == NULL) return ERR_CANTOPENFILE; + + /* Read the header of the file. */ + fread(buffer, 1, 4, file); + if (ringtone->Format == 0x00) { + ringtone->Format = RING_NOTETONE; + if (buffer[0]==0x00 && buffer[1]==0x00 && + buffer[2]==0x0C && buffer[3]==0x01) { + ringtone->Format = RING_NOKIABINARY; + } + if (buffer[0]==0x00 && buffer[1]==0x00 && + buffer[2]==0x00) { + ringtone->Format = RING_NOKIABINARY; + } + if (buffer[0]==0x4D && buffer[1]==0x54 && + buffer[2]==0x68 && buffer[3]==0x64) { + ringtone->Format = RING_MIDI; + } + } + rewind(file); + switch (ringtone->Format) { + case RING_NOTETONE: + if (buffer[0]==0x02 && buffer[1]==0x4A) { + error=loadott(file,ringtone); + } else if (buffer[0]==0xC7 && buffer[1]==0x45) { + error=loadcommunicator(file,ringtone); + } else { + error=loadrttl(file,ringtone); + } + ringtone->NoteTone.AllNotesScale=false; + break; + case RING_NOKIABINARY: + if (buffer[0]==0x00 && buffer[1]==0x00 && + buffer[2]==0x0C && buffer[3]==0x01) { + error=loadbin(file,ringtone); + } + if (buffer[0]==0x00 && buffer[1]==0x00 && + buffer[2]==0x00) { + error=loadre(file,ringtone); + } + break; + case RING_MIDI: + EncodeUnicode(ringtone->Name,FileName,strlen(FileName)); + error = loadpuremidi(file,ringtone); + } + fclose(file); + return(error); +} + +/* -------------------------- required with Nokia & RTTL ------------------- */ + +/* Beats per Minute like written in Smart Messaging */ +static int SM_BeatsPerMinute[] = { + 25, 28, 31, 35, 40, 45, 50, 56, 63, 70, + 80, 90, 100, 112, 125, 140, 160, 180, 200, 225, + 250, 285, 320, 355, 400, 450, 500, 565, 635, 715, + 800, 900 +}; + +int GSM_RTTLGetTempo(int Beats) +{ + int i=0; + + while (Beats > SM_BeatsPerMinute[i] && SM_BeatsPerMinute[i] != 900) i++; + + return i<<3; +} + +/* This function packs the ringtone from the structure "ringtone" to + "package", where maxlength means length of package. + Function returns number of packed notes and change maxlength to + number of used chars in "package" */ +unsigned char GSM_EncodeNokiaRTTLRingtone(GSM_Ringtone ringtone, unsigned char *package, int *maxlength) +{ + unsigned char CommandLength = 0x02; + unsigned char Loop = 0x15; /* Infinite */ + + unsigned char Buffer[200]; + int StartBit=0, OldStartBit; + int StartBitHowManyCommands; + int HowManyCommands = 0; /* How many instructions packed */ + int HowManyNotes = 0; + int i,j; + bool started; + GSM_RingNote *Note; + + GSM_RingNoteScale DefScale = 255; + GSM_RingNoteStyle DefStyle = 255; + int DefTempo = 255; + + AddBufferByte(package, &StartBit, CommandLength, 8); + AddBufferByte(package, &StartBit, SM_Command_RingingToneProgramming, 7); + + /* According to specification we need have next part octet-aligned */ + BufferAlign(package, &StartBit); + + AddBufferByte(package, &StartBit, SM_Command_Sound, 7); + AddBufferByte(package, &StartBit, SM_Song_BasicSongType, 3); + + /* Packing the name of the tune. */ + EncodeUnicodeSpecialNOKIAChars(Buffer, ringtone.Name, UnicodeLength(ringtone.Name)); + AddBufferByte(package, &StartBit, ((unsigned char)(UnicodeLength(Buffer)<<4)), 4); + AddBuffer(package, &StartBit, DecodeUnicodeString(Buffer), 8*UnicodeLength(Buffer)); + + /* Packing info about song pattern */ + AddBufferByte(package, &StartBit, 0x01, 8); //one pattern + AddBufferByte(package, &StartBit, SM_InstructionID_PatternHeaderId, 3); + AddBufferByte(package, &StartBit, SM_PatternID_A_part, 2); + AddBufferByte(package, &StartBit, ((unsigned char)(Loop<<4)), 4); + + /* Later here will be HowManyCommands */ + StartBitHowManyCommands=StartBit; + StartBit = StartBit + 8; + + started = false; + for (i=0; i<ringtone.NoteTone.NrCommands; i++) { + if (ringtone.NoteTone.Commands[i].Type != RING_Note) { + HowManyNotes++; + continue; + } + Note = &ringtone.NoteTone.Commands[i].Note; + if (!started) { + /* First note can't be Pause - it makes problems + * for example with PC Composer + */ + if (Note->Note != Note_Pause) started = true; + } + if (!started) { + HowManyNotes++; + continue; + } + OldStartBit = StartBit; + /* we don't write Scale & Style info before "Pause" note - it saves place */ + if (Note->Note!=Note_Pause) { + if (DefScale != Note->Scale || ringtone.NoteTone.AllNotesScale) { + j = StartBit+5+8; + BufferAlignNumber(&j); + if ((j/8)>(*maxlength)) { + StartBit = OldStartBit; + break; + } + DefScale = Note->Scale; + AddBufferByte(package, &StartBit, SM_InstructionID_ScaleInstructionId, 3); + AddBufferByte(package, &StartBit, ((unsigned char)((DefScale-4)<<6)), 2); + HowManyCommands++; + } + if (DefStyle != Note->Style) { + j = StartBit+5+8; + BufferAlignNumber(&j); + if ((j/8)>(*maxlength)) { + StartBit = OldStartBit; + break; + } + DefStyle = Note->Style; + AddBufferByte(package, &StartBit, SM_InstructionID_StyleInstructionId, 3); + AddBufferByte(package, &StartBit, ((unsigned char)DefStyle), 2); + HowManyCommands++; + } + } + /* Beats per minute/tempo of the tune */ + if (DefTempo != GSM_RTTLGetTempo(Note->Tempo)) { + j = StartBit+8+8; + BufferAlignNumber(&j); + if ((j/8)>(*maxlength)) { + StartBit = OldStartBit; + break; + } + DefTempo=GSM_RTTLGetTempo(Note->Tempo); + /* Adding beats per minute (tempo) of the tune */ + AddBufferByte(package, &StartBit, SM_InstructionID_TempoInstructionId, 3); + AddBufferByte(package, &StartBit, ((unsigned char)DefTempo), 5); + HowManyCommands++; + } + j = StartBit+12+8; + BufferAlignNumber(&j); + if ((j/8)>(*maxlength)) { + StartBit = OldStartBit; + break; + } + /* Note */ + AddBufferByte(package, &StartBit, SM_InstructionID_NoteInstructionId, 3); + AddBufferByte(package, &StartBit, ((unsigned char)Note->Note), 4); + AddBufferByte(package, &StartBit, ((unsigned char)Note->Duration), 3); + AddBufferByte(package, &StartBit, ((unsigned char)Note->DurationSpec), 2); + HowManyCommands++; + /* We are sure, we pack it for SMS or setting to phone, not for OTT file */ + if (*maxlength<1000) { + /* Like Pc Composer say - before of phone limitations...*/ + if (HowManyNotes==130-1) break; + } + HowManyNotes++; + } + + BufferAlign(package, &StartBit); + AddBufferByte(package, &StartBit, SM_CommandEnd_CommandEnd, 8); + + OldStartBit = StartBit; + StartBit = StartBitHowManyCommands; + /* HowManyCommands */ + AddBufferByte(package, &StartBit, ((unsigned char)HowManyCommands), 8); + StartBit = OldStartBit; + + *maxlength=StartBit/8; + + return(i); +} + +GSM_Error GSM_DecodeNokiaRTTLRingtone(GSM_Ringtone *ringtone, unsigned char *package, int maxlength) +{ + int StartBit=0, HowMany, l, q, i, spec; + char Buffer[100]; + GSM_RingNote *Note; + + /* Default ringtone parameters */ + GSM_RingNoteScale DefScale = Scale_880; + GSM_RingNoteStyle DefStyle = NaturalStyle; + int DefTempo = 63; + + ringtone->Format = RING_NOTETONE; + ringtone->NoteTone.NrCommands = 0; + + GetBufferInt(package,&StartBit,&l,8); + if (l!=0x02) { + dbgprintf("Not header\n"); + return ERR_NOTSUPPORTED; + } + + GetBufferInt(package,&StartBit,&l,7); + if (l!=SM_Command_RingingToneProgramming) { + dbgprintf("Not RingingToneProgramming\n"); + return ERR_NOTSUPPORTED; + } + + /* According to specification we need have next part octet-aligned */ + BufferAlignNumber(&StartBit); + + GetBufferInt(package,&StartBit,&l,7); + if (l!=SM_Command_Sound) { + dbgprintf("Not Sound\n"); + return ERR_NOTSUPPORTED; + } + + GetBufferInt(package,&StartBit,&l,3); + if (l!=SM_Song_BasicSongType) { + dbgprintf("Not BasicSongType\n"); + return ERR_NOTSUPPORTED; + } + + /* Getting length of the tune name */ + GetBufferInt(package,&StartBit,&l,4); + l=l>>4; + + /* Unpacking the name of the tune. */ + GetBuffer(package, &StartBit, Buffer, 8*l); + Buffer[l]=0; + EncodeUnicode(ringtone->Name,Buffer,strlen(Buffer)); + DecodeUnicodeSpecialNOKIAChars(Buffer, ringtone->Name, UnicodeLength(ringtone->Name)); + CopyUnicodeString(ringtone->Name,Buffer); + + GetBufferInt(package,&StartBit,&l,8); + dbgprintf("Number of song patterns: %i\n",l); + /* we support only one song pattern */ + if (l!=1) return ERR_NOTSUPPORTED; + + GetBufferInt(package,&StartBit,&l,3); + if (l!=SM_InstructionID_PatternHeaderId) { + dbgprintf("Not PatternHeaderId\n"); + return ERR_NOTSUPPORTED; + } + + /* Pattern ID - we ignore it */ + StartBit+=2; + + GetBufferInt(package,&StartBit,&l,4); + l=l>>4; + dbgprintf("Loop value: %i\n",l); + + HowMany=0; + GetBufferInt(package, &StartBit, &HowMany, 8); + + for (i=0;i<HowMany;i++) { + GetBufferInt(package,&StartBit,&q,3); + switch (q) { + case SM_InstructionID_VolumeInstructionId: + StartBit+=4; + break; + case SM_InstructionID_StyleInstructionId: + GetBufferInt(package,&StartBit,&l,2); + if (l>=NaturalStyle && l<=StaccatoStyle) DefStyle = l; + break; + case SM_InstructionID_TempoInstructionId: + GetBufferInt(package,&StartBit,&l,5); + DefTempo=SM_BeatsPerMinute[l>>3]; + break; + case SM_InstructionID_ScaleInstructionId: + GetBufferInt(package,&StartBit,&l,2); + DefScale=(l>>6)+4; + break; + case SM_InstructionID_NoteInstructionId: + Note = &ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Note; + ringtone->NoteTone.Commands[ringtone->NoteTone.NrCommands].Type = RING_Note; + + GetBufferInt(package,&StartBit,&l,4); + Note->Note=Note_Pause; + if (l >= Note_C && l <= Note_H) Note->Note = l; + + GetBufferInt(package,&StartBit,&l,3); + if (l >= Duration_Full && l <= Duration_1_32) Note->Duration = l; + + GetBufferInt(package,&StartBit,&spec,2); + if (spec >= NoSpecialDuration && spec <= Length_2_3) { + Note->DurationSpec = spec; + } + + Note->Scale = DefScale; + Note->Style = DefStyle; + Note->Tempo = DefTempo; + if (ringtone->NoteTone.NrCommands==MAX_RINGTONE_NOTES) break; + ringtone->NoteTone.NrCommands++; + break; + default: + dbgprintf("Unsupported block %i %i\n",q,i); + return ERR_NOTSUPPORTED; + } + } + return ERR_NONE; +} + +static void RTTL2Binary(GSM_Ringtone *dest, GSM_Ringtone *src) +{ + int current = 0, i, note, lastnote = 0, duration; + GSM_RingNote *Note; + unsigned char end[] = {0x40, 0x7D, 0x40, 0x5C, 0x0A, 0xFE, 0x40, + 0x20, 0x40, 0x7D, 0x40, 0x37, 0x0A, 0xFE, + 0x0A, 0x0A, 0x40, 0x32, 0x07, 0x0B}; + + strcpy(dest->NokiaBinary.Frame+current,"\x02\xFC\x09"); current=current+3; + dest->NokiaBinary.Frame[current++]=0x00; + +/* This command can be used to loop, where 0xLL = 0x01 - 0x10 + * 0x01=loop once [...] 0x10=loop infinite + * Commented now + + dest->NokiaBinary.Frame[current++]=0x05; + dest->NokiaBinary.Frame[current++]=0xLL; + */ + strcpy(dest->NokiaBinary.Frame+current,"\x0A\x01"); current=current+2; + + for (i=0; i<src->NoteTone.NrCommands; i++) { + if (src->NoteTone.Commands[i].Type != RING_Note) continue; + + Note = &src->NoteTone.Commands[i].Note; + note = 64; /* Pause */ + if (Note->Note!=Note_Pause) { + if (Note->Note >= Note_C && Note->Note <= Note_H) { + note = 113 + Note->Note/16; + } + switch (Note->Scale) { + case Scale_440 : break; + case Scale_880 : note = note + 12; break; + case Scale_1760: note = note + 24; break; + case Scale_3520: note = note + 36; break; + default : break; + } + } + + /* In 7110 we have 8 ms long sounds */ + duration = 60000 * GSM_RingNoteGetFullDuration(*Note) / Note->Tempo / 256; + + switch (Note->Style) { + case StaccatoStyle: + if (duration) { + /* Note needs only one sound */ + dest->NokiaBinary.Frame[current++] = note; + dest->NokiaBinary.Frame[current++] = 1; + duration--; + } + note = 0x40; /* The rest is pause */ + case NaturalStyle: + if (note != 0x40 && duration) { + dest->NokiaBinary.Frame[current++] = 0x40; + /* There is small pause between notes */ + dest->NokiaBinary.Frame[current++] = 1; + duration--; + } + default: + if (note != 0x40 && note == lastnote && duration) { + dest->NokiaBinary.Frame[current++] = 0x40; + /* There is small pause between same notes */ + dest->NokiaBinary.Frame[current++] = 1; + duration--; + } + while (duration > 125) { + dest->NokiaBinary.Frame[current++] = note; + dest->NokiaBinary.Frame[current++] = 125; + duration -= 125; + } + dest->NokiaBinary.Frame[current++] = note; + dest->NokiaBinary.Frame[current++] = duration; + } + lastnote = note; + } + for (i = 0; i < (int)sizeof(end); i++) dest->NokiaBinary.Frame[current++] = end[i]; + dest->NokiaBinary.Length=current; +} + +static void Binary2RTTL(GSM_Ringtone *dest, GSM_Ringtone *src) +{ + int i = 3, j, z, NrNotes = 0, repeat = 0, accuracy; + int StartRepeat = 0, EndRepeat, Speed; + unsigned char command,length=0; + int NotesLen[500]; + GSM_RingNoteScale NotesScale[500]; + GSM_RingNoteNote Notes[500]; + int Lengths[6*4]; + GSM_RingNoteDurationSpec DurationSpec[6*4]; + GSM_RingNoteDuration Duration[6*4]; + bool foundlen; + GSM_RingNote *Note; + + while (i<src->NokiaBinary.Length) { + command = src->NokiaBinary.Frame[i]; + i++; + if (command != 0x06 && command != 0x00 && command != 0x09) { + length = src->NokiaBinary.Frame[i]; + i++; + dbgprintf("Block %02x %02x - ",length,command); + } else dbgprintf("Block %02x - ",command); + if (command >= 114 && command <= 161) { + dbgprintf("note\n"); + if (command >= 114 && command <= 124) { + NotesScale[NrNotes] = Scale_440; command -= 114; + } else if (command >= 125 && command <= 137) { + NotesScale[NrNotes] = Scale_880; command -= 126; + } else if (command >= 138 && command <= 149) { + NotesScale[NrNotes] = Scale_1760; command -= 138; + } else if (command >= 150 && command <= 161) { + NotesScale[NrNotes] = Scale_3520; command -= 150; + } + switch (command) { + case 0 : Notes[NrNotes] = Note_C; break; + case 1 : Notes[NrNotes] = Note_Cis; break; + case 2 : Notes[NrNotes] = Note_D; break; + case 3 : Notes[NrNotes] = Note_Dis; break; + case 4 : Notes[NrNotes] = Note_E; break; + case 5 : Notes[NrNotes] = Note_F; break; + case 6 : Notes[NrNotes] = Note_Fis; break; + case 7 : Notes[NrNotes] = Note_G; break; + case 8 : Notes[NrNotes] = Note_Gis; break; + case 9 : Notes[NrNotes] = Note_A; break; + case 10 : Notes[NrNotes] = Note_Ais; break; + case 11 : Notes[NrNotes] = Note_H; break; + } + if (NrNotes > 0) { + if (Notes[NrNotes-1] == Notes[NrNotes] && + NotesScale[NrNotes-1] == NotesScale[NrNotes]) { + NotesLen[NrNotes-1]+=length; + } else { + NotesLen[NrNotes]=length; + NrNotes++; + } + } else { + NotesLen[NrNotes]=length; + NrNotes++; + } + } else switch (command) { + case 0x00: + dbgprintf("Unknown\n"); + break; + case 0x05: + dbgprintf("repeat %i times\n",length); + repeat = length; + StartRepeat = NrNotes; + break; + case 0x06: + dbgprintf("end repeat\n"); + EndRepeat = NrNotes; + for (z=0;z<repeat-1;z++) { + for (j=StartRepeat;j<EndRepeat;j++) { + Notes[NrNotes] = Notes[j]; + NotesScale[NrNotes] = NotesScale[j]; + NotesLen[NrNotes] = NotesLen[j]; + NrNotes++; + dbgprintf("Adding repeat note %i %i\n",Notes[j],NotesLen[j]); + } + } + break; + case 0x07: + if (length == 0x0B) { + dbgprintf("Ringtone end\n"); + i = src->NokiaBinary.Length + 1; + } + break; + case 0x09: + dbgprintf("Unknown\n"); + break; + case 0x0A: + if (length == 0x01) { + dbgprintf("Let's start our song\n"); + break; + } + if (length == 0x0A) { + dbgprintf("Ending joining note\n"); + break; + } + if (length == 0xFE) { + dbgprintf("Starting joining note\n"); + break; + } + break; + case 0x40: + dbgprintf("Pause\n"); + Notes[NrNotes] = Note_Pause; + if (NrNotes > 0) { + if (Notes[NrNotes-1] == Notes[NrNotes] && + NotesScale[NrNotes-1] == NotesScale[NrNotes]) { + NotesLen[NrNotes-1]+=length; + } else { + NotesLen[NrNotes]=length; + NrNotes++; + } + } else { + NotesLen[NrNotes]=length; + NrNotes++; + } + break; + default: + dbgprintf("Unknown\n"); + } + } + + while (NrNotes>0) { + if (Notes[NrNotes-1] == Note_Pause) { + NrNotes--; + } else break; + } + + for (accuracy=1; accuracy<5; accuracy++) { + i = 1; + while (i < 1000) { + Lengths[0] = 30000/i; + for (j=0;j<5;j++) Lengths[j+1] = Lengths[j] / 2; + for (j=0;j<6;j++) Lengths[6+j] = Lengths[j] * 3/2; + for (j=0;j<6;j++) Lengths[12+j] = Lengths[j] * 9/4; + for (j=0;j<6;j++) Lengths[18+j] = Lengths[j] * 2/3; + +#ifdef DEBUG + dbgprintf("Length matrix (%i) : ",i); + for (j=0;j<6*4;j++) dbgprintf("%i ",Lengths[j]); + dbgprintf("\n"); +#endif + foundlen = false; + + for (j=0;j<NrNotes;j++) { + dbgprintf("Comparing to %i\n",NotesLen[j]); + foundlen = false; + for (z=0;z<6*4;z++) { + if (NotesLen[j] - Lengths[z] > -accuracy && + NotesLen[j] - Lengths[z] < accuracy) { + foundlen = true; + break; + } + } + if (!foundlen) break; + } + if (foundlen) break; + i++; + } + + if (foundlen) { + Speed = i; + Duration[5] = Duration_1_32; Duration[4] = Duration_1_16; + Duration[3] = Duration_1_8; Duration[2] = Duration_1_4; + Duration[1] = Duration_1_2; Duration[0] = Duration_Full; + for (i=0;i<6;i++) Duration[i] = Duration[i]; + for (i=0;i<6;i++) Duration[i+6] = Duration[i]; + for (i=0;i<6;i++) Duration[i+12] = Duration[i]; + for (i=0;i<6;i++) Duration[i+18] = Duration[i]; + for (i=0;i<6;i++) DurationSpec[i] = NoSpecialDuration; + for (i=0;i<6;i++) DurationSpec[i+6] = DottedNote; + for (i=0;i<6;i++) DurationSpec[i+12] = DoubleDottedNote; + for (i=0;i<6;i++) DurationSpec[i+18] = Length_2_3; + + for (i=0;i<NrNotes;i++) { + dest->NoteTone.Commands[i].Type = RING_Note; + Note = &dest->NoteTone.Commands[i].Note; + Note->Note = Notes[i]; + Note->Tempo = Speed; + Note->Style = ContinuousStyle; + if (Notes[i] != Note_Pause) Note->Scale = NotesScale[i]; + for (z=0;z<6*4;z++) { + if (NotesLen[i] - Lengths[z] > -accuracy && + NotesLen[i] - Lengths[z] < accuracy) { + Note->Duration = Duration[z]; + Note->DurationSpec = DurationSpec[z]; + /* Trick from PPM Edit */ + if (Note->DurationSpec == DoubleDottedNote) { + switch (Note->Duration) { + case Duration_Full:Note->Duration = Duration_Full;break; + case Duration_1_2 :Note->Duration = Duration_Full;break; + case Duration_1_4 :Note->Duration = Duration_1_2; break; + case Duration_1_8 :Note->Duration = Duration_1_4; break; + case Duration_1_16:Note->Duration = Duration_1_8; break; + case Duration_1_32:Note->Duration = Duration_1_16;break; + } + Note->DurationSpec = NoSpecialDuration; + } + /* Here happy creation */ + if (Note->DurationSpec == Length_2_3) { + Note->DurationSpec = NoSpecialDuration; + } + + break; + } + } + } + dest->NoteTone.NrCommands = NrNotes; + dbgprintf("speed = %i\n",Speed); + break; + } + } + + if (!foundlen) dest->NoteTone.NrCommands = 0; +} + +GSM_Error GSM_RingtoneConvert(GSM_Ringtone *dest, GSM_Ringtone *src, GSM_RingtoneFormat Format) +{ + dest->Format = Format; + CopyUnicodeString(dest->Name,src->Name); + if (src->Format==RING_NOTETONE && Format==RING_NOKIABINARY) { + RTTL2Binary(dest, src); + return ERR_NONE; + } + if (src->Format==RING_NOKIABINARY && Format==RING_NOTETONE) { + Binary2RTTL(dest, src); + return ERR_NONE; + } + /* The same source and target format */ + if (src->Format==Format) { + memcpy(dest,src,sizeof(GSM_Ringtone)); + return ERR_NONE; + } + return ERR_NOTIMPLEMENTED; +} + +/* 0 = No header and footer, 0.5 = partial header and footer, + * 1.0 = IMelody 1.0, 1.2 = IMelody 1.2 */ +unsigned char GSM_EncodeEMSSound(GSM_Ringtone ringtone, unsigned char *package, int *maxlength, double version, bool start) +{ + int i, NrNotes = 0, Len, Max = *maxlength; + + GSM_RingNote *Note; + + GSM_RingNoteScale DefNoteScale; + GSM_RingNoteStyle DefNoteStyle=0; + int DefNoteTempo=0; + + bool started = false, end; + + *maxlength = 0; + + if (start) { + if (version != 0) *maxlength+=sprintf(package,"BEGIN:IMELODY%c%c",13,10); + if (version == 1.0) *maxlength+=sprintf(package+(*maxlength),"VERSION:1.0%c%c",13,10); + if (version == 1.2) *maxlength+=sprintf(package+(*maxlength),"VERSION:1.2%c%c",13,10); + if (version >= 1.0) *maxlength+=sprintf(package+(*maxlength),"FORMAT:CLASS1.0%c%c",13,10); + if (version == 1.2) *maxlength+=sprintf(package+(*maxlength),"NAME:%s%c%c",DecodeUnicodeString(ringtone.Name),13,10); + } + + DefNoteScale = Scale_880; /* by iMelody definition */ + + for (i=0;i<ringtone.NoteTone.NrCommands;i++) { + Len = *maxlength; + if (ringtone.NoteTone.Commands[i].Type != RING_Note) continue; + + Note = &ringtone.NoteTone.Commands[i].Note; + if (Note->Note == Note_Pause) continue; + + if (version == 1.2 && start) { + /* Save the default tempo */ + DefNoteTempo = Note->Tempo; + Len+=sprintf(package+Len,"BEAT:%i%c%c",DefNoteTempo,13,10); + dbgprintf("DefNoteTempo=%d\n",DefNoteTempo); + + /* Save default style */ + DefNoteStyle = Note->Style; + switch (DefNoteStyle) { + case NaturalStyle :Len+=sprintf(package+Len,"STYLE:S0%c%c",13,10); break; + case ContinuousStyle:Len+=sprintf(package+Len,"STYLE:S1%c%c",13,10); break; + case StaccatoStyle :Len+=sprintf(package+Len,"STYLE:S2%c%c",13,10); break; + } + } + Len+=sprintf(package+Len,"MELODY:"); + if (version != 0) { + /* 15 = Len of END:IMELODY... */ + if ((Len+15) > Max) { end = true; break; } + } else { + if (Len > Max) { end = true; break; } + } + *maxlength = Len; + break; + } + + for (i=0;i<ringtone.NoteTone.NrCommands;i++) { + end = false; + Len = *maxlength; + switch (ringtone.NoteTone.Commands[i].Type) { + case RING_Note: + Note = &ringtone.NoteTone.Commands[i].Note; + if (!started && Note->Note != Note_Pause) started = true; + if (!started) break; + if (Note->Note!=Note_Pause && Note->Scale != DefNoteScale) { + Len+=sprintf(package+Len,"*%i",Note->Scale-1); + } + switch (Note->Note) { + case Note_C :Len+=sprintf(package+Len,"c"); break; + case Note_Cis :Len+=sprintf(package+Len,"#c");break; + case Note_D :Len+=sprintf(package+Len,"d"); break; + case Note_Dis :Len+=sprintf(package+Len,"#d");break; + case Note_E :Len+=sprintf(package+Len,"e"); break; + case Note_F :Len+=sprintf(package+Len,"f"); break; + case Note_Fis :Len+=sprintf(package+Len,"#f");break; + case Note_G :Len+=sprintf(package+Len,"g"); break; + case Note_Gis :Len+=sprintf(package+Len,"#g");break; + case Note_A :Len+=sprintf(package+Len,"a"); break; + case Note_Ais :Len+=sprintf(package+Len,"#a");break; + case Note_H :Len+=sprintf(package+Len,"b"); break; + case Note_Pause :Len+=sprintf(package+Len,"r"); break; + } + switch (Note->Duration) { + case Duration_Full : package[Len++]='0'; break; + case Duration_1_2 : package[Len++]='1'; break; + case Duration_1_4 : package[Len++]='2'; break; + case Duration_1_8 : package[Len++]='3'; break; + case Duration_1_16 : package[Len++]='4'; break; + case Duration_1_32 : package[Len++]='5'; break; + default : break; + } + switch (Note->DurationSpec) { + case DottedNote : package[Len++] = '.'; break; + case DoubleDottedNote : package[Len++] = ':'; break; + case Length_2_3 : package[Len++] = ';'; break; + default : break; + } + if (version != 0) { + /* 15 = Len of END:IMELODY... */ + if ((Len+15) > Max) { end = true; break; } + } else { + if (Len > Max) { end = true; break; } + } + *maxlength = Len; + break; + case RING_DisableLED: + if ((Len + 6) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"ledoff"); + break; + case RING_EnableLED: + if ((Len + 5) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"ledon"); + break; + case RING_DisableVibra: + if ((Len + 7) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"vibeoff"); + break; + case RING_EnableVibra: + if ((Len + 6) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"vibeon"); + break; + case RING_DisableLight: + if ((Len + 7) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"backoff"); + break; + case RING_EnableLight: + if ((Len + 6) > Max) { end = true; break; } + (*maxlength)+=sprintf(package+Len,"backon"); + break; + default: + break; + } + if (end) break; + NrNotes ++; + } + + if (version != 0) *maxlength+=sprintf(package+(*maxlength),"%c%cEND:IMELODY%c%c",13,10,13,10); + + return NrNotes; +} + +char *GSM_GetRingtoneName(GSM_AllRingtonesInfo *Info, int ID) +{ + int i; + static char ala[2]; + + for (i=0;i<Info->Number;i++) { + if (Info->Ringtone[i].ID == ID) return Info->Ringtone[i].Name; + } + + ala[0] = 0; + ala[1] = 0; + return ala; +} + +/* 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/service/gsmring.h b/gammu/emb/common/service/gsmring.h new file mode 100644 index 0000000..207cf31 --- a/dev/null +++ b/gammu/emb/common/service/gsmring.h @@ -0,0 +1,202 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#ifndef __gsm_ring_h +#define __gsm_ring_h + +/* --------------- Smart Messaging Specification 2.0 & 3.0 ----------------- */ + +#define SM_CommandEnd_CommandEnd 0x00 + +/* specification gives also other */ +#define SM_Command_RingingToneProgramming 0x25<<1 +#define SM_Command_Sound 0x1d<<1 +/* specification gives also other */ + +#define SM_Song_BasicSongType 0x01<<5 +/* specification gives also other */ + +#define SM_PatternID_A_part 0x00<<6 +/* specification gives also other */ + +#define SM_InstructionID_PatternHeaderId 0x00<<5 +#define SM_InstructionID_NoteInstructionId 0x01<<5 +#define SM_InstructionID_ScaleInstructionId 0x02<<5 +#define SM_InstructionID_StyleInstructionId 0x03<<5 +#define SM_InstructionID_TempoInstructionId 0x04<<5 +#define SM_InstructionID_VolumeInstructionId 0x05<<5 + +/* ------ end of Smart Messaging Specification 2.0 & 3.0 definitions ------- */ + +#define MAX_RINGTONE_NOTES 255 + +typedef enum { + /** + * Natural style (rest between notes) + */ + NaturalStyle = 0x00<<6, + /** + * Continuous style (no rest between notes) + */ + ContinuousStyle = 0x01<<6, + /** + * Staccato style (shorter notes and longer rest period) + */ + StaccatoStyle = 0x02<<6 +} GSM_RingNoteStyle; + +typedef enum { + Note_Pause = 0x00<<4, + Note_C = 0x01<<4, + Note_Cis = 0x02<<4, + Note_D = 0x03<<4, + Note_Dis = 0x04<<4, + Note_E = 0x05<<4, + Note_F = 0x06<<4, + Note_Fis = 0x07<<4, + Note_G = 0x08<<4, + Note_Gis = 0x09<<4, + Note_A = 0x0a<<4, + Note_Ais = 0x0b<<4, + Note_H = 0x0c<<4 +} GSM_RingNoteNote; + +typedef enum { + Duration_Full = 0x00<<5, + Duration_1_2 = 0x01<<5, + Duration_1_4 = 0x02<<5, + Duration_1_8 = 0x03<<5, + Duration_1_16 = 0x04<<5, + Duration_1_32 = 0x05<<5 +} GSM_RingNoteDuration; + +typedef enum { + NoSpecialDuration = 0x00<<6, + DottedNote = 0x01<<6, + DoubleDottedNote = 0x02<<6, + Length_2_3 = 0x03<<6 +} GSM_RingNoteDurationSpec; + +typedef enum { + Scale_55 = 1, /* 55 Hz for note A */ + Scale_110, /* 110 Hz for note A */ + Scale_220, + Scale_440, /* first scale for Nokia */ + Scale_880, + Scale_1760, + Scale_3520, /* last scale for Nokia */ + Scale_7040, + Scale_14080 +} GSM_RingNoteScale; + +typedef struct { + GSM_RingNoteDuration Duration; + GSM_RingNoteDurationSpec DurationSpec; + GSM_RingNoteNote Note; + GSM_RingNoteStyle Style; + GSM_RingNoteScale Scale; + int Tempo; +} GSM_RingNote; + +typedef enum { + RING_Note = 1, + RING_EnableVibra, + RING_DisableVibra, + RING_EnableLight, + RING_DisableLight, + RING_EnableLED, + RING_DisableLED, + RING_Repeat +} GSM_RingCommandType; + +typedef struct { + GSM_RingCommandType Type; + GSM_RingNote Note; + unsigned char Value; +} GSM_RingCommand; + +typedef struct { + int NrCommands; + GSM_RingCommand Commands[MAX_RINGTONE_NOTES]; + bool AllNotesScale; +} GSM_NoteRingtone; + +/* Structure to hold Nokia binary ringtones. */ +typedef struct { + unsigned char Frame[30000]; + int Length; +} GSM_NokiaBinaryRingtone; + +typedef struct { + unsigned char *Frame; + int Length; +} GSM_BinaryTone; + +typedef enum { + RING_NOTETONE = 1, + RING_NOKIABINARY, + RING_MIDI +} GSM_RingtoneFormat; + +/** + * Structure for saving various ringtones formats + */ +typedef struct { + /** + * Ringtone saved in one of three formats + */ + GSM_NokiaBinaryRingtone NokiaBinary; + GSM_BinaryTone BinaryTone; + GSM_NoteRingtone NoteTone; + /** + * Ringtone format + */ + GSM_RingtoneFormat Format; + /** + * Ringtone name + */ + char Name[20*2]; + /** + * Ringtone location + */ + int Location; +} GSM_Ringtone; + +typedef struct { + int Group; //Nokia specific + int ID; + char Name[30*2]; +} GSM_RingtoneInfo; + +typedef struct { + int Number; + GSM_RingtoneInfo Ringtone[100]; +} GSM_AllRingtonesInfo; + +GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone); +GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone); + +void saveott(FILE *file, GSM_Ringtone *ringtone); +void savemid(FILE *file, GSM_Ringtone *ringtone); +void saverng(FILE *file, GSM_Ringtone *ringtone); +void saveimelody(FILE *file, GSM_Ringtone *ringtone); +GSM_Error savewav(FILE *file, GSM_Ringtone *ringtone); +GSM_Error saverttl(FILE *file, GSM_Ringtone *ringtone); + +unsigned char GSM_EncodeNokiaRTTLRingtone (GSM_Ringtone ringtone, unsigned char *package, int *maxlength); +unsigned char GSM_EncodeEMSSound (GSM_Ringtone ringtone, unsigned char *package, int *maxlength, double version, bool start); + +GSM_Error GSM_DecodeNokiaRTTLRingtone (GSM_Ringtone *ringtone, unsigned char *package, int maxlength); + +GSM_Error GSM_RingtoneConvert(GSM_Ringtone *dest, GSM_Ringtone *src, GSM_RingtoneFormat Format); + +int GSM_RTTLGetTempo (int Beats); +int GSM_RingNoteGetFrequency (GSM_RingNote Note); +int GSM_RingNoteGetFullDuration (GSM_RingNote Note); + +char *GSM_GetRingtoneName(GSM_AllRingtonesInfo *Info, int ID); + +#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/service/sms/gsmems.c b/gammu/emb/common/service/sms/gsmems.c new file mode 100644 index 0000000..a7e20f4 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmems.c @@ -0,0 +1,765 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#include <ctype.h> +#include <string.h> +#include <time.h> + +#include "../../gsmcomon.h" +#include "../../misc/coding/coding.h" +#include "../gsmcal.h" +#include "../gsmpbk.h" +#include "../gsmlogo.h" +#include "../gsmring.h" +#include "../gsmdata.h" +#include "../gsmnet.h" +#include "gsmsms.h" +#include "gsmmulti.h" + +/* EMS Developers' Guidelines from www.sonyericsson.com + * docs from Alcatel + */ +GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS, + GSM_UDH UDHType) +{ + unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + int i,UsedText,j,Length,Width,Height,z,x,y; + unsigned int Len; + int Used,FreeText,FreeBytes,Width2,CopiedText,CopiedSMSText; + unsigned char UDHID; + GSM_Bitmap Bitmap,Bitmap2; + GSM_Ringtone Ring; + GSM_Coding_Type Coding = SMS_Coding_Default; + GSM_Phone_Bitmap_Types BitmapType; + MultiPartSMSEntry *Entry; + bool start; + GSM_DateTime Date; + +#ifdef DEBUG + if (UDHType != UDH_NoUDH) dbgprintf("linked EMS\n"); +#endif + + if (Info->UnicodeCoding) Coding = SMS_Coding_Unicode; + + /* Cleaning on the start */ + for (i=0;i<MAX_MULTI_SMS;i++) { + GSM_SetDefaultSMSData(&SMS->SMS[i]); + SMS->SMS[i].UDH.Type = UDHType; + GSM_EncodeUDHHeader(&SMS->SMS[i].UDH); + SMS->SMS[i].Coding = Coding; + } + + /* Packing */ + for (i=0;i<Info->EntriesNum;i++) { + Entry = &Info->Entries[i]; + + switch (Entry->ID) { + case SMS_ConcatenatedTextLong: + case SMS_ConcatenatedTextLong16bit: + Len = 0; + while(1) { + if (Entry->Left || Entry->Right || + Entry->Center || Entry->Large || + Entry->Small || Entry->Bold || + Entry->Italic || Entry->Underlined || + Entry->Strikethrough) { + Buffer[0] = 0x0A; /* ID for text format */ + Buffer[1] = 0x03; /* length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + Buffer[3] = 0x00; /* how many chars */ + Buffer[4] = 0x00; /* formatting bits */ + if (Entry->Left) { + } else if (Entry->Right) { Buffer[4] |= 1; + } else if (Entry->Center) { Buffer[4] |= 2; + } else Buffer[4] |= 3; + if (Entry->Large) { Buffer[4] |= 4; + } else if (Entry->Small) { Buffer[4] |= 8;} + if (Entry->Bold) Buffer[4] |= 16; + if (Entry->Italic) Buffer[4] |= 32; + if (Entry->Underlined) Buffer[4] |= 64; + if (Entry->Strikethrough) Buffer[4] |= 128; + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5,true,&UsedText,&CopiedText,&CopiedSMSText); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); + if (FreeText == 0) continue; + } + GSM_AddSMS_Text_UDH(SMS,Coding,Entry->Buffer+Len*2,UnicodeLength(Entry->Buffer) - Len,false,&UsedText,&CopiedText,&CopiedSMSText); + if (Entry->Left || Entry->Right || + Entry->Center || Entry->Large || + Entry->Small || Entry->Bold || + Entry->Italic || Entry->Underlined || + Entry->Strikethrough) { + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3] = UsedText; + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = CopiedSMSText; + } + Len += CopiedText; + if (Len == UnicodeLength(Entry->Buffer)) break; + dbgprintf("%i %i\n",Len,UnicodeLength(Entry->Buffer)); + } + break; + case SMS_EMSPredefinedSound: + case SMS_EMSPredefinedAnimation: + if (Entry->ID == SMS_EMSPredefinedSound) { + Buffer[0] = 0x0B; /* ID for def.sound */ + } else { + Buffer[0] = 0x0D; /* ID for def.animation */ + } + Buffer[1] = 0x02; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + Buffer[3] = Entry->Number; /* Number of anim. */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-2] = UsedText; + break; + case SMS_EMSSonyEricssonSound: + case SMS_EMSSound10: + case SMS_EMSSound12: + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + Length = 128; /* 128 bytes is maximal length from specs */ + switch (Entry->ID) { + case SMS_EMSSound10: + Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.0, true); + break; + case SMS_EMSSound12: + Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 1.2, true); + break; + case SMS_EMSSonyEricssonSound: + Entry->RingtoneNotes = GSM_EncodeEMSSound(*Entry->Ringtone, Buffer+3, &Length, 0, true); + break; + default: + break; + } + + Buffer[0] = 0x0C; /* ID for EMS sound */ + Buffer[1] = Length+1; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; + break; + case SMS_EMSSonyEricssonSoundLong: + case SMS_EMSSound10Long: + case SMS_EMSSound12Long: + Ring = *Entry->Ringtone; + + /* First check if we can use classic format */ + Length = 128; /* 128 bytes is maximal length from specs */ + switch (Entry->ID) { + case SMS_EMSSound10Long: + Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, true); + break; + case SMS_EMSSound12Long: + Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, true); + break; + case SMS_EMSSonyEricssonSoundLong: + Entry->RingtoneNotes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, true); + break; + default: + break; + } + if (Entry->RingtoneNotes == Ring.NoteTone.NrCommands) { + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + Buffer[0] = 0x0C; /* ID for EMS sound */ + Buffer[1] = Length+1; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; + break; + } + + /* Find free place in first SMS */ + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); + Length = FreeBytes - 3; + if (Entry->Protected) Length = Length - 4; + if (Length < 0) Length = 128; + if (Length > 128) Length = 128; + + Ring = *Entry->Ringtone; + + /* Checking number of SMS */ + Used = 0; + FreeBytes = 0; + start = true; + while (1) { + if (FreeBytes != 0) { + z = 0; + for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { + Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; + z++; + } + Ring.NoteTone.NrCommands -= FreeBytes; + if (Ring.NoteTone.NrCommands == 0) break; + Length = 128; /* 128 bytes is maximal length from specs */ + } + switch (Entry->ID) { + case SMS_EMSSound10Long: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); + break; + case SMS_EMSSound12Long: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); + break; + case SMS_EMSSonyEricssonSoundLong: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); + break; + default: + break; + } + start = false; + Used++; + } + dbgprintf("Used SMS: %i\n",Used); + + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = Used+1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + /* Save UPI UDH */ + Buffer[0] = 0x13; /* ID for UPI */ + Buffer[1] = 1; /* Length of rest */ + Buffer[2] = Used; /* Number of used parts */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); + + /* Find free place in first SMS */ + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); + Length = FreeBytes - 3; + if (Length < 0) Length = 128; + if (Length > 128) Length = 128; + + Ring = *Entry->Ringtone; + + /* Saving */ + FreeBytes = 0; + start = true; + while (1) { + if (FreeBytes != 0) { + z = 0; + for (j=FreeBytes;j<Ring.NoteTone.NrCommands;j++) { + Ring.NoteTone.Commands[z] = Ring.NoteTone.Commands[j]; + z++; + } + Ring.NoteTone.NrCommands -= FreeBytes; + if (Ring.NoteTone.NrCommands == 0) break; + Length = 128; /* 128 bytes is maximal length from specs */ + } + switch (Entry->ID) { + case SMS_EMSSound10Long: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.0, start); + break; + case SMS_EMSSound12Long: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 1.2, start); + break; + case SMS_EMSSonyEricssonSoundLong: + FreeBytes = GSM_EncodeEMSSound(Ring, Buffer+3, &Length, 0, start); + break; + default: + break; + } + Buffer[0] = 0x0C; /* ID for EMS sound */ + Buffer[1] = Length+1; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,Length+3,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-Length-1] = UsedText; + start = false; + } + + Entry->RingtoneNotes = Entry->Ringtone->NoteTone.NrCommands; + + break; + case SMS_EMSAnimation: + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + if (Entry->Bitmap->Bitmap[0].BitmapWidth > 8 || Entry->Bitmap->Bitmap[0].BitmapHeight > 8) { + BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */ + Buffer[0] = 0x0E; /* ID for 16x16 animation */ + } else { + BitmapType = GSM_EMSSmallPicture; /* Bitmap 8x8 */ + Buffer[0] = 0x0F; /* ID for 8x8 animation */ + } + Length = PHONE_GetBitmapSize(BitmapType,0,0); + + Buffer[1] = Length*Entry->Bitmap->Number + 1; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + for (j=0;j<Entry->Bitmap->Number;j++) { + PHONE_EncodeBitmap(BitmapType, Buffer+3+j*Length, &Entry->Bitmap->Bitmap[j]); + } + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length*Entry->Bitmap->Number,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length*Entry->Bitmap->Number] = UsedText; + break; + case SMS_EMSFixedBitmap: + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + if (Entry->Bitmap->Bitmap[0].BitmapWidth > 16 || Entry->Bitmap->Bitmap[0].BitmapHeight > 16) { + BitmapType = GSM_EMSBigPicture; /* Bitmap 32x32 */ + Buffer[0] = 0x10; /* ID for EMS bitmap */ + } else { + BitmapType = GSM_EMSMediumPicture; /* Bitmap 16x16 */ + Buffer[0] = 0x11; /* ID for EMS bitmap */ + } + Length = PHONE_GetBitmapSize(BitmapType,0,0); + PHONE_GetBitmapWidthHeight(BitmapType, &Width, &Height); + + Buffer[1] = Length + 1; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + PHONE_EncodeBitmap(BitmapType,Buffer+3, &Entry->Bitmap->Bitmap[0]); + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3+Length,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-1-Length] = UsedText; + break; + case SMS_EMSVariableBitmapLong: + BitmapType = GSM_EMSVariablePicture; + Width = Entry->Bitmap->Bitmap[0].BitmapWidth; + Height = Entry->Bitmap->Bitmap[0].BitmapHeight; + Bitmap = Entry->Bitmap->Bitmap[0]; + + /* First check if we can use classical format */ + while (1) { + /* Width should be multiply of 8 */ + while (Width % 8 != 0) Width--; + + /* specs */ + if (Width <= 96 && Height <= 128) break; + + Height--; + } + Length = PHONE_GetBitmapSize(BitmapType,Width,Height); + if (Length <= 128) { + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + Buffer[0] = 0x12; /* ID for EMS bitmap */ + Buffer[1] = Length + 3; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + Buffer[3] = Width/8; /* Bitmap width/8 */ + Buffer[4] = Height; /* Bitmap height */ + + GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); +#endif + PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; + break; + } + + /* Find free place in first SMS */ + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); + Used = 0; + Length = FreeBytes - 3; + if (Entry->Protected) Length = Length - 4; + if (Length < 0) Length = 128; + if (Length > 128) Length = 128; + + /* Checking number of SMS */ + FreeBytes = 0; + while (FreeBytes != Width) { + Width2 = 8; + while (FreeBytes + Width2 != Width) { + if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; + + Width2 = Width2 + 8; + } + FreeBytes = FreeBytes + Width2; + Length = 128; + Used ++; + } + dbgprintf("Used SMS: %i\n",Used); + + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = Used+1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + /* Save UPI UDH */ + Buffer[0] = 0x13; /* ID for UPI */ + Buffer[1] = 1; /* Length of rest */ + Buffer[2] = Used; /* Number of used parts */ + + /* Find free place in first SMS */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,3,true,&UsedText,&CopiedText,&CopiedSMSText); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], &UsedText, &FreeText, &FreeBytes); + Length = FreeBytes - 3; + if (Length < 0) Length = 128; + if (Length > 128) Length = 128; + +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); +#endif + + /* Saving SMS */ + FreeBytes = 0; + while (FreeBytes != Width) { + Width2 = 8; + while (FreeBytes + Width2 != Width) { + if (PHONE_GetBitmapSize(BitmapType,Width2+8,Height) > Length) break; + + Width2 = Width2 + 8; + } + + /* Copying part of bitmap to new structure */ + Bitmap2.BitmapWidth = Width2; + Bitmap2.BitmapHeight = Height; + GSM_ClearBitmap(&Bitmap2); + for (x=0;x<Width2;x++) { + for (y=0;y<Height;y++) { + if (GSM_IsPointBitmap(&Bitmap,x+FreeBytes,y)) { + GSM_SetPointBitmap(&Bitmap2, x, y); + } + } + } +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap2); +#endif + + /* Adding new bitmap to SMS */ + Length = PHONE_GetBitmapSize(BitmapType,Width2,Height); + Buffer[0] = 0x12; /* ID for EMS bitmap */ + Buffer[1] = Length + 3; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + Buffer[3] = Width2/8; /* Bitmap width/8 */ + Buffer[4] = Height; /* Bitmap height */ + PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap2); + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; + + FreeBytes = FreeBytes + Width2; + Length = 128; + } + break; + case SMS_EMSVariableBitmap: + if (Entry->Protected) { + Buffer[0] = 0x17; /* ID for ODI */ + Buffer[1] = 2; /* Length of rest */ + Buffer[2] = 1; /* Number of protected objects */ + Buffer[3] = 1; /* 1=Protected,0=Not protected */ + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,4,true,&UsedText,&CopiedText,&CopiedSMSText); + } + + BitmapType = GSM_EMSVariablePicture; + Width = Entry->Bitmap->Bitmap[0].BitmapWidth; + Height = Entry->Bitmap->Bitmap[0].BitmapHeight; + + while (1) { + /* Width should be multiply of 8 */ + while (Width % 8 != 0) Width--; + + /* specs */ + if (PHONE_GetBitmapSize(BitmapType,Width,Height) <= 128) break; + + Height--; + } + + Length = PHONE_GetBitmapSize(BitmapType,Width,Height); + + Buffer[0] = 0x12; /* ID for EMS bitmap */ + Buffer[1] = Length + 3; /* Length of rest */ + Buffer[2] = 0x00; /* Position in EMS msg */ + Buffer[3] = Width/8; /* Bitmap width/8 */ + Buffer[4] = Height; /* Bitmap height */ + + GSM_ResizeBitmap(&Bitmap, &Entry->Bitmap->Bitmap[0], Width, Height); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Bitmap); +#endif + PHONE_EncodeBitmap(BitmapType,Buffer+5, &Bitmap); + GSM_AddSMS_Text_UDH(SMS,Coding,Buffer,5+Length,true,&UsedText,&CopiedText,&CopiedSMSText); + SMS->SMS[SMS->Number].UDH.Text[SMS->SMS[SMS->Number].UDH.Length-3-Length] = UsedText; + break; + default: + break; + } + } + + SMS->Number++; + + if (UDHType == UDH_ConcatenatedMessages) { + UDHID = GSM_MakeSMSIDFromTime(); + for (i=0;i<SMS->Number;i++) { + SMS->SMS[i].UDH.Text[2+1] = UDHID; + SMS->SMS[i].UDH.Text[3+1] = SMS->Number; + SMS->SMS[i].UDH.Text[4+1] = i+1; + } + } + if (UDHType == UDH_ConcatenatedMessages16bit) { + UDHID = GSM_MakeSMSIDFromTime(); + GSM_GetCurrentDateTime (&Date); + for (i=0;i<SMS->Number;i++) { + SMS->SMS[i].UDH.Text[2+1] = Date.Hour; + SMS->SMS[i].UDH.Text[3+1] = UDHID; + SMS->SMS[i].UDH.Text[4+1] = SMS->Number; + SMS->SMS[i].UDH.Text[5+1] = i+1; + } + } + +#ifdef DEBUG + dbgprintf("SMS number is %i\n",SMS->Number); + for (i=0;i<SMS->Number;i++) { + dbgprintf("UDH length %i\n",SMS->SMS[i].UDH.Length); + DumpMessage(di.df, di.dl, SMS->SMS[i].UDH.Text, SMS->SMS[i].UDH.Length); + dbgprintf("SMS length %i\n",UnicodeLength(SMS->SMS[i].Text)*2); + DumpMessage(di.df, di.dl, SMS->SMS[i].Text, UnicodeLength(SMS->SMS[i].Text)*2); + } +#endif + return ERR_NONE; +} + +static bool AddEMSText(GSM_SMSMessage *SMS, GSM_MultiPartSMSInfo *Info, int *Pos, int Len) +{ + int BufferLen; + + if (Len==0) return true; + + if (Info->Entries[Info->EntriesNum].ID!=SMS_ConcatenatedTextLong && + Info->Entries[Info->EntriesNum].ID!=0) { + (Info->EntriesNum)++; + } + BufferLen = UnicodeLength(Info->Entries[Info->EntriesNum].Buffer)*2; + switch (SMS->Coding) { + case SMS_Coding_8bit: +// memcpy(Info->Entries[Info->EntriesNum].Buffer+BufferLen,SMS->Text+(*Pos),Len); +// BufferLen+=Len; +// (*Pos)+=Len; + break; + case SMS_Coding_Unicode: + case SMS_Coding_Default: + Info->Entries[Info->EntriesNum].Buffer = realloc(Info->Entries[Info->EntriesNum].Buffer, BufferLen + (Len * 2) + 2); + if (Info->Entries[Info->EntriesNum].Buffer == NULL) return false; + memcpy(Info->Entries[Info->EntriesNum].Buffer + BufferLen, SMS->Text + (*Pos) *2, Len * 2); + BufferLen += Len * 2; + break; + } + (*Pos)+=Len; + Info->Entries[Info->EntriesNum].Buffer[BufferLen] = 0; + Info->Entries[Info->EntriesNum].Buffer[BufferLen+1] = 0; + Info->Entries[Info->EntriesNum].ID = SMS_ConcatenatedTextLong; + return true; +} + +bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS) +{ + int i, w, Pos, z, UPI = 1, width, height; + bool RetVal = false, NewPicture = true; + GSM_Phone_Bitmap_Types BitmapType; + GSM_Bitmap Bitmap,Bitmap2; + + for (i=0;i<MAX_MULTI_SMS;i++) { + Info->Entries[i].ID = 0; + } + + for (i=0;i<SMS->Number;i++) { + Pos = 0; + w = 1; + while (w < SMS->SMS[i].UDH.Length) { + if (Info->EntriesNum + 1 == MAX_MULTI_SMS) { + dbgprintf("Couldn't parse SMS, contains too many EMS parts!\n"); + return false; + } + switch(SMS->SMS[i].UDH.Text[w]) { + case 0x00: + dbgprintf("UDH part - linked SMS with 8 bit ID\n"); + break; + case 0x08: + dbgprintf("UDH part - linked SMS with 16 bit ID\n"); + break; +// case 0x0A: +// dbgprintf("UDH part - EMS text formatting\n"); +// break; + case 0x0B: + dbgprintf("UDH part - default EMS sound\n"); + if (SMS->SMS[i].UDH.Text[w+2] > Pos) { + z = Pos; + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; + } + if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; + Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; + Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedSound; + RetVal = true; + break; +// case 0x0C: +// dbgprintf("UDH part - EMS sound\n"); +// break; + case 0x0D: + dbgprintf("UDH part - default EMS animation\n"); + if (SMS->SMS[i].UDH.Text[w+2] > Pos) { + z = Pos; + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; + } + if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; + Info->Entries[Info->EntriesNum].Number = SMS->SMS[i].UDH.Text[w+3]; + Info->Entries[Info->EntriesNum].ID = SMS_EMSPredefinedAnimation; + RetVal = true; + break; + case 0x0E: + case 0x0F: + if (SMS->SMS[i].UDH.Text[w] == 0x0E) { + dbgprintf("UDH part - EMS 16x16 animation\n"); + BitmapType = GSM_EMSMediumPicture; + } else { + dbgprintf("UDH part - EMS 8x8 animation\n"); + BitmapType = GSM_EMSSmallPicture; + } + dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); + if (SMS->SMS[i].UDH.Text[w+2] > Pos) { + z = Pos; + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; + } + (Info->EntriesNum)++; + Info->Entries[Info->EntriesNum].ID = SMS_EMSAnimation; + Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; + Info->Entries[Info->EntriesNum].Bitmap->Number = 0; + for (z=0;z<((SMS->SMS[i].UDH.Text[w+1]-1)/PHONE_GetBitmapSize(BitmapType,0,0));z++) { + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z].Type = GSM_PictureImage; + PHONE_DecodeBitmap(BitmapType, + SMS->SMS[i].UDH.Text + w + 3 + PHONE_GetBitmapSize(BitmapType,0,0) * z, + &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[z]); + Info->Entries[Info->EntriesNum].Bitmap->Number++; + } + RetVal = true; + break; + case 0x10: + case 0x11: + if (SMS->SMS[i].UDH.Text[w] == 0x10) { + dbgprintf("UDH part - EMS 32x32 picture\n"); + BitmapType = GSM_EMSBigPicture; + } else { + dbgprintf("UDH part - EMS 16x16 picture\n"); + BitmapType = GSM_EMSMediumPicture; + } + dbgprintf("Position - %i\n",SMS->SMS[i].UDH.Text[w+2]); + if (SMS->SMS[i].UDH.Text[w+2] > Pos) { + z = Pos; + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; + } + if (Info->Entries[Info->EntriesNum].ID != 0) (Info->EntriesNum)++; + Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; + PHONE_DecodeBitmap(BitmapType, + SMS->SMS[i].UDH.Text + w + 3, + &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); + Info->Entries[Info->EntriesNum].Bitmap->Number = 1; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; + Info->Entries[Info->EntriesNum].ID = SMS_EMSFixedBitmap; + RetVal = true; + break; + case 0x12: + dbgprintf("UDH part - EMS variable width bitmap\n"); + if (SMS->SMS[i].UDH.Text[w+2] > Pos) { + z = Pos; + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].UDH.Text[w+2]-z)) return false; + } + if (NewPicture) { + (Info->EntriesNum)++; + Info->Entries[Info->EntriesNum].Bitmap->Number = 0; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = 0; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = 0; + } + Bitmap.BitmapWidth = SMS->SMS[i].UDH.Text[w+3]*8; + Bitmap.BitmapHeight = SMS->SMS[i].UDH.Text[w+4]; + Info->Entries[Info->EntriesNum].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[Info->EntriesNum].Bitmap == NULL) return false; + if (NewPicture) { + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap.BitmapHeight; + PHONE_DecodeBitmap(GSM_EMSVariablePicture, + SMS->SMS[i].UDH.Text + w + 5, + &Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]); + } else { + PHONE_DecodeBitmap(GSM_EMSVariablePicture, + SMS->SMS[i].UDH.Text + w + 5, + &Bitmap); + Bitmap2 = Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0]; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapWidth = Bitmap.BitmapWidth+Bitmap2.BitmapWidth; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].BitmapHeight = Bitmap2.BitmapHeight; + for (width=0;width<Bitmap2.BitmapWidth;width++) { + for (height=0;height<Bitmap2.BitmapHeight;height++) { + if (GSM_IsPointBitmap(&Bitmap2, width, height)) { + GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); + } else { + GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width,height); + } + } + } + for (width=0;width<Bitmap.BitmapWidth;width++) { + for (height=0;height<Bitmap2.BitmapHeight;height++) { + if (GSM_IsPointBitmap(&Bitmap, width, height)) { + GSM_SetPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); + } else { + GSM_ClearPointBitmap(&Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0],width+Bitmap2.BitmapWidth,height); + } + } + } + } + if (UPI == 1) { + Info->Entries[Info->EntriesNum].Bitmap->Number = 1; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[0] = 0; + Info->Entries[Info->EntriesNum].Bitmap->Bitmap[0].Text[1] = 0; + Info->Entries[Info->EntriesNum].ID = SMS_EMSVariableBitmap; + RetVal = true; + NewPicture = true; + dbgprintf("New variable picture\n"); + } else { + NewPicture = false; + UPI--; + } + break; + case 0x13: + dbgprintf("UDH part - UPI\n"); + dbgprintf("Value %i\n",SMS->SMS[i].UDH.Text[w+2]); + UPI = SMS->SMS[i].UDH.Text[w+2]; + break; + case 0x17: + dbgprintf("UDH part - Object Distribution Indicator (Media Rights Protecting) ignored now\n"); + break; + default: + dbgprintf("UDH part - block %02x\n",SMS->SMS[i].UDH.Text[w]); + Info->Unknown = true; + } /* switch */ + w=w+SMS->SMS[i].UDH.Text[w+1]+2; + } /* while */ + if (!AddEMSText(&SMS->SMS[i], Info, &Pos, SMS->SMS[i].Length-Pos)) return false; + RetVal = true; + } + if (RetVal) (Info->EntriesNum)++; + return RetVal; +} + +/* 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/service/sms/gsmems.h b/gammu/emb/common/service/sms/gsmems.h new file mode 100644 index 0000000..6701d28 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmems.h @@ -0,0 +1,20 @@ +/* (c) 2002-2003 by Marcin Wiacek */ + +#ifndef __gsm_ems_h +#define __gsm_ems_h + +#include "../../gsmcomon.h" +#include "gsmmulti.h" + +GSM_Error GSM_EncodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS, + GSM_UDH UDHType); + +bool GSM_DecodeEMSMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS); + +#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/service/sms/gsmmulti.c b/gammu/emb/common/service/sms/gsmmulti.c new file mode 100644 index 0000000..6c1cdcd --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmmulti.c @@ -0,0 +1,1148 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#include <ctype.h> +#include <string.h> +#include <time.h> + +#include "../../gsmcomon.h" +#include "../../misc/coding/coding.h" +#include "../gsmcal.h" +#include "../gsmpbk.h" +#include "../gsmlogo.h" +#include "../gsmring.h" +#include "../gsmdata.h" +#include "../gsmnet.h" +#include "gsmsms.h" +#include "gsmmulti.h" +#include "gsmems.h" + +/* ----------------- Splitting SMS into parts ------------------------------ */ + +unsigned char GSM_MakeSMSIDFromTime(void) +{ + GSM_DateTime Date; + unsigned char retval; + + GSM_GetCurrentDateTime (&Date); + retval = Date.Second; + switch (Date.Minute/10) { + case 2: case 7: retval = retval + 60; break; + case 4: case 8: retval = retval + 120; break; + case 9: case 5: case 0: retval = retval + 180; break; + } + retval += Date.Minute/10; + return retval; +} + +void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes) +{ + int UsedBytes; + + switch (Coding) { + case SMS_Coding_Default: + FindDefaultAlphabetLen(SMS.Text,&UsedBytes,UsedText,500); + UsedBytes = *UsedText * 7 / 8; + if (UsedBytes * 8 / 7 != *UsedText) UsedBytes++; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = (GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length) * 8 / 7 - *UsedText; + break; + case SMS_Coding_Unicode: + *UsedText = UnicodeLength(SMS.Text); + UsedBytes = *UsedText * 2; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = *FreeBytes / 2; + break; + case SMS_Coding_8bit: + *UsedText = UsedBytes = SMS.Length; + *FreeBytes = GSM_MAX_8BIT_SMS_LENGTH - SMS.UDH.Length - UsedBytes; + *FreeText = *FreeBytes; + break; + } + dbgprintf("UDH len %i, UsedBytes %i, FreeText %i, UsedText %i, FreeBytes %i\n",SMS.UDH.Length,UsedBytes,*FreeText,*UsedText,*FreeBytes); +} + +GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, + GSM_Coding_Type Coding, + char *Buffer, + int BufferLen, + bool UDH, + int *UsedText, + int *CopiedText, + int *CopiedSMSText) +{ + int FreeText,FreeBytes,Copy,i,j; + + dbgprintf("Checking used\n"); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + + if (UDH) { + dbgprintf("Adding UDH\n"); + if (FreeBytes - BufferLen <= 0) { + dbgprintf("Going to the new SMS\n"); + SMS->Number++; + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + } + if (SMS->SMS[SMS->Number].UDH.Length == 0) { + SMS->SMS[SMS->Number].UDH.Length = 1; + SMS->SMS[SMS->Number].UDH.Text[0] = 0x00; + } + memcpy(SMS->SMS[SMS->Number].UDH.Text+SMS->SMS[SMS->Number].UDH.Length,Buffer,BufferLen); + SMS->SMS[SMS->Number].UDH.Length += BufferLen; + SMS->SMS[SMS->Number].UDH.Text[0] += BufferLen; + SMS->SMS[SMS->Number].UDH.Type = UDH_UserUDH; + dbgprintf("UDH added %i\n",BufferLen); + } else { + dbgprintf("Adding text\n"); + if (FreeText == 0) { + dbgprintf("Going to the new SMS\n"); + SMS->Number++; + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + } + + Copy = FreeText; + dbgprintf("copy %i\n",Copy); + if (BufferLen < Copy) Copy = BufferLen; + dbgprintf("copy %i\n",Copy); + + switch (Coding) { + case SMS_Coding_Default: + FindDefaultAlphabetLen(Buffer,&i,&j,FreeText); + dbgprintf("def length %i %i\n",i,j); + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2] = 0; + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+i*2+1] = 0; + memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,i*2); + *CopiedText = i; + *CopiedSMSText = j; + SMS->SMS[SMS->Number].Length += i; + break; + case SMS_Coding_Unicode: + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2] = 0; + SMS->SMS[SMS->Number].Text[UnicodeLength(SMS->SMS[SMS->Number].Text)*2+Copy*2+1] = 0; + memcpy(SMS->SMS[SMS->Number].Text+UnicodeLength(SMS->SMS[SMS->Number].Text)*2,Buffer,Copy*2); + *CopiedText = *CopiedSMSText = Copy; + SMS->SMS[SMS->Number].Length += Copy; + break; + case SMS_Coding_8bit: + memcpy(SMS->SMS[SMS->Number].Text+SMS->SMS[SMS->Number].Length,Buffer,Copy); + SMS->SMS[SMS->Number].Length += Copy; + *CopiedText = *CopiedSMSText = Copy; + break; + } + dbgprintf("Text added\n"); + } + + dbgprintf("Checking on the end\n"); + GSM_Find_Free_Used_SMS2(Coding,SMS->SMS[SMS->Number], UsedText, &FreeText, &FreeBytes); + + return ERR_NONE; +} + +void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS, + unsigned char *MessageBuffer, + int MessageLength, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int Class, + unsigned char ReplaceMessage) +{ + int j,Len,UsedText,CopiedText,CopiedSMSText; + unsigned char UDHID; + GSM_DateTime Date; + + Len = 0; + while(1) { + GSM_SetDefaultSMSData(&SMS->SMS[SMS->Number]); + SMS->SMS[SMS->Number].Class = Class; + SMS->SMS[SMS->Number].Coding = Coding; + + SMS->SMS[SMS->Number].UDH.Type = UDHType; + GSM_EncodeUDHHeader(&SMS->SMS[SMS->Number].UDH); + + if (Coding == SMS_Coding_8bit) { + GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); + } else { + GSM_AddSMS_Text_UDH(SMS,Coding,MessageBuffer+Len*2,MessageLength - Len,false,&UsedText,&CopiedText,&CopiedSMSText); + } + Len += CopiedText; + dbgprintf("%i %i\n",Len,MessageLength); + if (Len == MessageLength) break; + if (SMS->Number == MAX_MULTI_SMS) break; + SMS->Number++; + } + + SMS->Number++; + + UDHID = GSM_MakeSMSIDFromTime(); + GSM_GetCurrentDateTime (&Date); + for (j=0;j<SMS->Number;j++) { + SMS->SMS[j].UDH.Type = UDHType; + SMS->SMS[j].UDH.ID8bit = UDHID; + SMS->SMS[j].UDH.ID16bit = UDHID + 256 * Date.Hour; + SMS->SMS[j].UDH.PartNumber = j+1; + SMS->SMS[j].UDH.AllParts = SMS->Number; + GSM_EncodeUDHHeader(&SMS->SMS[j].UDH); + } + if (SMS->Number == 1) SMS->SMS[0].ReplaceMessage = ReplaceMessage; +} + +/* Calculates number of SMS and number of left chars in SMS */ +void GSM_SMSCounter(int MessageLength, + unsigned char *MessageBuffer, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int *SMSNum, + int *CharsLeft) +{ + int UsedText,FreeBytes; + GSM_MultiSMSMessage MultiSMS; + + MultiSMS.Number = 0; + GSM_MakeMultiPartSMS(&MultiSMS,MessageBuffer,MessageLength,UDHType,Coding,-1,false); + GSM_Find_Free_Used_SMS2(Coding,MultiSMS.SMS[MultiSMS.Number-1], &UsedText, CharsLeft, &FreeBytes); + *SMSNum = MultiSMS.Number; +} + +/* Nokia Smart Messaging 3.0 */ +static void GSM_EncodeSMS30MultiPartSMS(GSM_MultiPartSMSInfo *Info, + char *Buffer, int *Length) +{ + int len; + + /*SM version. Here 3.0*/ + Buffer[(*Length)++] = 0x30; + + if (Info->Entries[0].ID == SMS_NokiaProfileLong) { + if (Info->Entries[0].Buffer != NULL) { + if (Info->Entries[0].Buffer[0]!=0x00 || Info->Entries[0].Buffer[1]!=0x00) { + Buffer[(*Length)++] = SM30_PROFILENAME; + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = 2*UnicodeLength(Info->Entries[0].Buffer); + CopyUnicodeString(Buffer+(*Length),Info->Entries[0].Buffer); + *Length = *Length + 2*UnicodeLength(Info->Entries[0].Buffer); + } + } + if (Info->Entries[0].Ringtone != NULL) { + Buffer[(*Length)++] = SM30_RINGTONE; + /* Length for this part later will be changed */ + Buffer[(*Length)++] = 0x01; + Buffer[(*Length)++] = 0x00; + /* Smart Messaging 3.0 says: 16*9=144 bytes, + * but on 3310 4.02 it was possible to save about 196 chars + * (without cutting) */ + len = 196; + Info->Entries[0].RingtoneNotes=GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer+(*Length),&len); + Buffer[(*Length)-2] = len / 256; + Buffer[(*Length)-1] = len % 256; + *Length = *Length + len; + } + } + if (Info->Entries[0].Bitmap != NULL) { + if (Info->Entries[0].ID == SMS_NokiaPictureImageLong) { + Buffer[(*Length)++] = SM30_OTA; + } else { + Buffer[(*Length)++] = SM30_SCREENSAVER; + } + Buffer[(*Length)++] = 0x01; + Buffer[(*Length)++] = 0x00; + NOKIA_CopyBitmap(GSM_NokiaPictureImage, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, Length); + if (Info->Entries[0].Bitmap->Bitmap[0].Text[0]!=0 || Info->Entries[0].Bitmap->Bitmap[0].Text[1]!=0) { + if (Info->UnicodeCoding) { + Buffer[(*Length)++] = SM30_UNICODETEXT; + /* Length for text part */ + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; + memcpy(Buffer+(*Length),Info->Entries[0].Bitmap->Bitmap[0].Text,UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2); + *Length = *Length + UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)*2; + } else { + /*ID for ISO-8859-1 text*/ + Buffer[(*Length)++] = SM30_ISOTEXT; + Buffer[(*Length)++] = 0x00; + Buffer[(*Length)++] = UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); + memcpy(Buffer+(*Length),DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text),UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text)); + *Length = *Length +UnicodeLength(Info->Entries[0].Bitmap->Bitmap[0].Text); + } + } + } +} + +/* Alcatel docs from www.alcatel.com/wap/ahead */ +GSM_Error GSM_EncodeAlcatelMultiPartSMS(GSM_MultiSMSMessage *SMS, + unsigned char *Data, + int Len, + unsigned char *Name, + int Type) +{ + unsigned char buff[100],UDHID; + int p,i; + GSM_UDHHeader MyUDH; + + for (i=0;i<MAX_MULTI_SMS;i++) { + GSM_SetDefaultSMSData(&SMS->SMS[i]); + SMS->SMS[i].UDH.Type = UDH_UserUDH; + SMS->SMS[i].UDH.Text[1] = 0x80; /* Alcatel */ + p = UnicodeLength(Name); + EncodeDefault(buff, Name, &p, true, NULL); + SMS->SMS[i].UDH.Text[2] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p) + 4; + SMS->SMS[i].UDH.Text[3] = GSM_PackSevenBitsToEight(0, buff, SMS->SMS[i].UDH.Text+3, p); + SMS->SMS[i].UDH.Text[4] = Type; + SMS->SMS[i].UDH.Text[5] = Len / 256; + SMS->SMS[i].UDH.Text[6] = Len % 256; + SMS->SMS[i].UDH.Text[0] = 6 + SMS->SMS[i].UDH.Text[3]; + SMS->SMS[i].UDH.Length = SMS->SMS[i].UDH.Text[0] + 1; + + if (Len > 140 - SMS->SMS[i].UDH.Length) { + MyUDH.Type = UDH_ConcatenatedMessages; + GSM_EncodeUDHHeader(&MyUDH); + + memcpy(SMS->SMS[i].UDH.Text+SMS->SMS[i].UDH.Length,MyUDH.Text+1,MyUDH.Length-1); + SMS->SMS[i].UDH.Text[0] += MyUDH.Length-1; + SMS->SMS[i].UDH.Length += MyUDH.Length-1; + } + + SMS->SMS[i].Coding = SMS_Coding_8bit; + SMS->SMS[i].Class = 1; + } + + p = 0; + while (p != Len) { + i = 140-SMS->SMS[SMS->Number].UDH.Length; + if (Len - p < i) i = Len - p; + memcpy(SMS->SMS[SMS->Number].Text,Data+p,i); + p += i; + SMS->SMS[SMS->Number].Length = i; + SMS->Number++; + + } + + /* Linked sms UDH */ + if (SMS->Number != 1) { + UDHID = GSM_MakeSMSIDFromTime(); + for (i=0;i<SMS->Number;i++) { + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-3] = UDHID; + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-2] = SMS->Number; + SMS->SMS[i].UDH.Text[SMS->SMS[i].UDH.Length-1] = i+1; + } + } + + return ERR_NONE; +} + +/* Alcatel docs from www.alcatel.com/wap/ahead and other */ +GSM_Error GSM_EncodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS) +{ + unsigned char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + unsigned char Buffer2[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + int Length = 0,smslen,i, Class = -1, j,p; + GSM_Error error; + GSM_Coding_Type Coding = SMS_Coding_8bit; + GSM_UDH UDH = UDH_NoUDH; + GSM_UDHHeader UDHHeader; + bool EMS = false; + int textnum = 0; + + SMS->Number = 0; + + if (Info->Entries[0].ID == SMS_AlcatelSMSTemplateName) { + Buffer[Length++] = 0x00; //number of elements + for (i=1;i<Info->EntriesNum;i++) { + switch (Info->Entries[i].ID) { + case SMS_EMSSound10: + case SMS_EMSSound12: + case SMS_EMSSonyEricssonSound: + case SMS_EMSSound10Long: + case SMS_EMSSound12Long: + case SMS_EMSSonyEricssonSoundLong: + case SMS_EMSVariableBitmap: + case SMS_EMSAnimation: + case SMS_EMSVariableBitmapLong: + break; + case SMS_EMSPredefinedSound: + Buffer[0]++; + Buffer[Length++] = 0x01; //type of data + Buffer[Length++] = 1 % 256; //len + Buffer[Length++] = 1 / 256; //len + Buffer[Length++] = Info->Entries[i].Number; + break; + case SMS_EMSPredefinedAnimation: + Buffer[0]++; + Buffer[Length++] = 0x02; //type of data + Buffer[Length++] = 1 % 256; //len + Buffer[Length++] = 1 / 256; //len + Buffer[Length++] = Info->Entries[i].Number; + break; + case SMS_ConcatenatedTextLong: + Buffer[0]++; + p = UnicodeLength(Info->Entries[i].Buffer); + EncodeDefault(Buffer2, Info->Entries[i].Buffer, &p, true, NULL); + Buffer[Length++] = 0x00; //type of data + Length = Length + 2; + smslen = GSM_PackSevenBitsToEight(0, Buffer2, Buffer+Length, p); + Buffer[Length-2] = smslen % 256; //len + Buffer[Length-1] = smslen / 256; //len + Length = Length + smslen; + break; + default: + return ERR_UNKNOWN; + } + } + Buffer[0] = Buffer[0] * 2; + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Buffer,ALCATELTDD_SMSTEMPLATE); + } + + for (i=0;i<Info->EntriesNum;i++) { + switch (Info->Entries[i].ID) { + case SMS_EMSPredefinedAnimation: + case SMS_EMSPredefinedSound: + case SMS_EMSSound10: + case SMS_EMSSound12: + case SMS_EMSSonyEricssonSound: + case SMS_EMSSound10Long: + case SMS_EMSSound12Long: + case SMS_EMSSonyEricssonSoundLong: + case SMS_EMSFixedBitmap: + case SMS_EMSVariableBitmap: + case SMS_EMSAnimation: + case SMS_EMSVariableBitmapLong: + EMS = true; + break; + case SMS_ConcatenatedTextLong: + case SMS_ConcatenatedTextLong16bit: + + /* This covers situation, when somebody will call function + * with two or more SMS_Concatenated.... entries only. + * It will be still only linked sms, but functions below + * will pack only first entry according to own limits. + * We redirect to EMS functions, because they are more generic + * here and will handle it correctly and produce linked sms + * from all entries + */ + textnum ++; + if (textnum > 1) EMS = true; + + if (Info->Entries[i].Left || Info->Entries[i].Right || + Info->Entries[i].Center || Info->Entries[i].Large || + Info->Entries[i].Small || Info->Entries[i].Bold || + Info->Entries[i].Italic || Info->Entries[i].Underlined || + Info->Entries[i].Strikethrough) { + EMS = true; + } + default: + break; + } + if (EMS) break; + } + if (EMS) { + error=GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_NoUDH); + if (error != ERR_NONE) return error; + if (SMS->Number != 1) { + SMS->Number = 0; + for (i=0;i<Info->EntriesNum;i++) { + if (Info->Entries[i].ID == SMS_ConcatenatedTextLong16bit) { + return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages); + } + } + return GSM_EncodeEMSMultiPartSMS(Info,SMS,UDH_ConcatenatedMessages16bit); + } + return error; + } + + if (Info->EntriesNum != 1) return ERR_UNKNOWN; + + switch (Info->Entries[0].ID) { + case SMS_AlcatelMonoBitmapLong: + Buffer[0] = Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth; + Buffer[1] = Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight; + PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+2, &Info->Entries[0].Bitmap->Bitmap[0]); + Length = PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight)+2; + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_PICTURE); + case SMS_AlcatelMonoAnimationLong: + /* Number of sequence words */ + Buffer[0] = (Info->Entries[0].Bitmap->Number+1) % 256; + Buffer[1] = (Info->Entries[0].Bitmap->Number+1) / 256; + /* Picture display time 1 second (1 = 100ms) */ + Buffer[2] = 10 % 256; + Buffer[3] = 10 / 256 + 0xF0; + + Length = 4; + j = 0; + + /* Offsets to bitmaps */ + for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { + Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) % 256; + Buffer[Length++] = (4+j+Info->Entries[0].Bitmap->Number*2) / 256; + j += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight)+2; + } + + /* Bitmaps */ + for (i=0;i<Info->Entries[0].Bitmap->Number;i++) { + Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth; + Buffer[Length++] = Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight; + PHONE_EncodeBitmap(GSM_AlcatelBMMIPicture, Buffer+Length, &Info->Entries[0].Bitmap->Bitmap[i]); + Length += PHONE_GetBitmapSize(GSM_AlcatelBMMIPicture,Info->Entries[0].Bitmap->Bitmap[i].BitmapWidth,Info->Entries[0].Bitmap->Bitmap[i].BitmapHeight); + } + return GSM_EncodeAlcatelMultiPartSMS(SMS,Buffer,Length,Info->Entries[0].Bitmap->Bitmap[0].Text,ALCATELTDD_ANIMATION); + case SMS_MMSIndicatorLong: + Class = 1; + UDH = UDH_MMSIndicatorLong; + GSM_EncodeMMSIndicatorSMSText(Buffer,&Length,*Info->Entries[0].MMSIndicator); + break; + case SMS_NokiaRingtoneLong: + case SMS_NokiaRingtone: + UDH = UDH_NokiaRingtone; + Class = 1; + /* 7 = length of UDH_NokiaRingtone UDH header */ + Length = GSM_MAX_8BIT_SMS_LENGTH-7; + Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); + if (Info->Entries[0].ID == SMS_NokiaRingtone) break; + if (Info->Entries[0].RingtoneNotes != Info->Entries[0].Ringtone->NoteTone.NrCommands) { + UDH = UDH_NokiaRingtoneLong; + Length = (GSM_MAX_8BIT_SMS_LENGTH-12)*3; + Info->Entries[0].RingtoneNotes = GSM_EncodeNokiaRTTLRingtone(*Info->Entries[0].Ringtone,Buffer,&Length); + } + break; + case SMS_NokiaOperatorLogoLong: + if (Info->Entries[0].Bitmap->Bitmap[0].BitmapWidth > 72 || Info->Entries[0].Bitmap->Bitmap[0].BitmapHeight > 14) { + UDH = UDH_NokiaOperatorLogoLong; + Class = 1; + NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); + Length = Length + 3; + NOKIA_CopyBitmap(GSM_Nokia7110OperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + } + case SMS_NokiaOperatorLogo: + UDH = UDH_NokiaOperatorLogo; + Class = 1; + NOKIA_EncodeNetworkCode(Buffer, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); + Length = Length + 3; + NOKIA_CopyBitmap(GSM_NokiaOperatorLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + case SMS_NokiaCallerLogo: + UDH = UDH_NokiaCallerLogo; + Class = 1; + NOKIA_CopyBitmap(GSM_NokiaCallerLogo, &Info->Entries[0].Bitmap->Bitmap[0], Buffer, &Length); + break; + case SMS_NokiaProfileLong: + case SMS_NokiaPictureImageLong: + case SMS_NokiaScreenSaverLong: + Class = 1; + UDH = UDH_NokiaProfileLong; + GSM_EncodeSMS30MultiPartSMS(Info,Buffer,&Length); + break; + case SMS_NokiaWAPBookmarkLong: + Class = 1; + NOKIA_EncodeWAPBookmarkSMSText(Buffer,&Length,Info->Entries[0].Bookmark); + /* 7 = length of UDH_NokiaWAP UDH header */ + if (Length>(GSM_MAX_8BIT_SMS_LENGTH-7)) { + UDH=UDH_NokiaWAPLong; + } else { + UDH=UDH_NokiaWAP; + } + break; + case SMS_NokiaWAPSettingsLong: + Class = 1; + UDH = UDH_NokiaWAPLong; + NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,false); + break; + case SMS_NokiaMMSSettingsLong: + Class = 1; + UDH = UDH_NokiaWAPLong; + NOKIA_EncodeWAPMMSSettingsSMSText(Buffer,&Length,Info->Entries[0].Settings,true); + break; + case SMS_NokiaVCARD10Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + /* is 1 SMS ? 8 = length of ..SCKE2 */ + if (Length<=GSM_MAX_SMS_LENGTH-8) { + sprintf(Buffer,"//SCKE2 "); + Length = 8; + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + } else { + /* FIXME: It wasn't checked */ + UDH = UDH_NokiaPhonebookLong; + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVCARD21Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + /* Is 1 SMS ? 12 = length of ..SCKL23F4 */ + if (Length<=GSM_MAX_SMS_LENGTH-12) { + sprintf(Buffer,"//SCKL23F4%c%c",13,10); + Length = 12; + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + } else { + UDH = UDH_NokiaPhonebookLong; + /* Here can be also 8 bit coding */ + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_VCARD10Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard10); + if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_VCARD21Long: + GSM_EncodeVCARD(Buffer,&Length,Info->Entries[0].Phonebook,true,Nokia_VCard21); + if (Length>GSM_MAX_SMS_LENGTH) UDH = UDH_ConcatenatedMessages; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVCALENDAR10Long: + error=GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); + if (error != ERR_NONE) return error; + /* Is 1 SMS ? 8 = length of ..SCKE4 */ + if (Length<=GSM_MAX_SMS_LENGTH-8) { + sprintf(Buffer,"//SCKE4 "); + Length = 8; + GSM_EncodeVCALENDAR(Buffer,&Length,Info->Entries[0].Calendar,true,Nokia_VCalendar); + } else { + UDH = UDH_NokiaCalendarLong; + /* can be here 8 bit coding ? */ + } + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_NokiaVTODOLong: + error=GSM_EncodeVTODO(Buffer,&Length,Info->Entries[0].ToDo,true,Nokia_VToDo); + if (error != ERR_NONE) return error; + UDH = UDH_NokiaCalendarLong; + Coding = SMS_Coding_Default; + memcpy(Buffer2,Buffer,Length); + EncodeUnicode(Buffer,Buffer2,Length); + break; + case SMS_DisableVoice: + case SMS_DisableFax: + case SMS_DisableEmail: + case SMS_EnableVoice: + case SMS_EnableFax: + case SMS_EnableEmail: + case SMS_VoidSMS: + case SMS_Text: + Class = Info->Class; + switch (Info->Entries[0].ID) { + case SMS_DisableVoice : UDH = UDH_DisableVoice; break; + case SMS_DisableFax : UDH = UDH_DisableFax; break; + case SMS_DisableEmail : UDH = UDH_DisableEmail; break; + case SMS_EnableVoice : UDH = UDH_EnableVoice; break; + case SMS_EnableFax : UDH = UDH_EnableFax; break; + case SMS_EnableEmail : UDH = UDH_EnableEmail; break; + case SMS_VoidSMS : UDH = UDH_VoidSMS; break; + case SMS_Text : UDH = UDH_NoUDH; break; + default : break; + } + UDHHeader.Type = UDH; + GSM_EncodeUDHHeader(&UDHHeader); + memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); + if (Info->UnicodeCoding) { + Coding = SMS_Coding_Unicode; + Length = UnicodeLength(Info->Entries[0].Buffer); + if (Length>(140-UDHHeader.Length)/2) Length = (140-UDHHeader.Length)/2; + } else { + Coding = SMS_Coding_Default; + FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,(GSM_MAX_8BIT_SMS_LENGTH-UDHHeader.Length)*8/7); + } + break; + case SMS_ConcatenatedAutoTextLong: + case SMS_ConcatenatedAutoTextLong16bit: + smslen = UnicodeLength(Info->Entries[0].Buffer); + memcpy(Buffer,Info->Entries[0].Buffer,smslen*2); + EncodeDefault(Buffer2, Buffer, &smslen, true, NULL); + DecodeDefault(Buffer, Buffer2, smslen, true, NULL); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) { + dbgprintf("Info->Entries[0].Buffer:\n"); + DumpMessage(di.df, di.dl, Info->Entries[0].Buffer, UnicodeLength(Info->Entries[0].Buffer)*2); + dbgprintf("Buffer:\n"); + DumpMessage(di.df, di.dl, Buffer, UnicodeLength(Buffer)*2); + } +#endif + Info->UnicodeCoding = false; + for (smslen=0;smslen<(int)(UnicodeLength(Info->Entries[0].Buffer)*2);smslen++) { + if (Info->Entries[0].Buffer[smslen] != Buffer[smslen]) { + Info->UnicodeCoding = true; + dbgprintf("Setting to Unicode %i\n",smslen); + break; + } + } + /* No break here - we go to the SMS_ConcatenatedTextLong */ + case SMS_ConcatenatedTextLong: + case SMS_ConcatenatedTextLong16bit: + Class = Info->Class; + memcpy(Buffer,Info->Entries[0].Buffer,UnicodeLength(Info->Entries[0].Buffer)*2+2); + UDH = UDH_NoUDH; + if (Info->UnicodeCoding) { + Coding = SMS_Coding_Unicode; + Length = UnicodeLength(Info->Entries[0].Buffer); + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || + Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { + if (Length>70) UDH=UDH_ConcatenatedMessages16bit; + } else { + if (Length>70) UDH=UDH_ConcatenatedMessages; + } + } else { + Coding = SMS_Coding_Default; + FindDefaultAlphabetLen(Info->Entries[0].Buffer,&Length,&smslen,5000); + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit || + Info->Entries[0].ID == SMS_ConcatenatedAutoTextLong16bit) { + if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages16bit; + } else { + if (smslen>GSM_MAX_SMS_LENGTH) UDH=UDH_ConcatenatedMessages; + } + } + default: + break; + } + GSM_MakeMultiPartSMS(SMS,Buffer,Length,UDH,Coding,Class,Info->ReplaceMessage); + return ERR_NONE; +} + +void GSM_ClearMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) +{ + int i; + + for (i=0;i<MAX_MULTI_SMS;i++) { + Info->Entries[i].Number = 0; + Info->Entries[i].Ringtone = NULL; + Info->Entries[i].Bitmap = NULL; + Info->Entries[i].Bookmark = NULL; + Info->Entries[i].Settings = NULL; + Info->Entries[i].MMSIndicator = NULL; + Info->Entries[i].Phonebook = NULL; + Info->Entries[i].Calendar = NULL; + Info->Entries[i].ToDo = NULL; + Info->Entries[i].Protected = false; + + Info->Entries[i].Buffer = NULL; + Info->Entries[i].Left = false; + Info->Entries[i].Right = false; + Info->Entries[i].Center = false; + Info->Entries[i].Large = false; + Info->Entries[i].Small = false; + Info->Entries[i].Bold = false; + Info->Entries[i].Italic = false; + Info->Entries[i].Underlined = false; + Info->Entries[i].Strikethrough = false; + + Info->Entries[i].RingtoneNotes = 0; + } + Info->Unknown = false; + Info->EntriesNum = 0; + Info->Class = -1; + Info->ReplaceMessage = 0; + Info->UnicodeCoding = false; +} + +void GSM_FreeMultiPartSMSInfo(GSM_MultiPartSMSInfo *Info) +{ + int i; + + for (i=0;i<MAX_MULTI_SMS;i++) { + free(Info->Entries[i].Ringtone); + Info->Entries[i].Ringtone = NULL; + free(Info->Entries[i].Bitmap); + Info->Entries[i].Bitmap = NULL; + free(Info->Entries[i].Bookmark); + Info->Entries[i].Bookmark = NULL; + free(Info->Entries[i].Settings); + Info->Entries[i].Settings = NULL; + free(Info->Entries[i].MMSIndicator); + Info->Entries[i].MMSIndicator = NULL; + free(Info->Entries[i].Phonebook); + Info->Entries[i].Phonebook = NULL; + free(Info->Entries[i].Calendar); + Info->Entries[i].Calendar = NULL; + free(Info->Entries[i].ToDo); + Info->Entries[i].ToDo = NULL; + free(Info->Entries[i].Buffer); + Info->Entries[i].Buffer = NULL; + } +} + +/* ----------------- Joining SMS from parts -------------------------------- */ + +bool GSM_DecodeMultiPartSMS(GSM_MultiPartSMSInfo *Info, + GSM_MultiSMSMessage *SMS, + bool ems) +{ + int i, Length = 0; + char Buffer[GSM_MAX_SMS_LENGTH*2*MAX_MULTI_SMS]; + bool emsexist = false; + + GSM_ClearMultiPartSMSInfo(Info); + if (ems) { + emsexist = true; + for (i=0;i<SMS->Number;i++) { + if (SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages && + SMS->SMS[i].UDH.Type != UDH_ConcatenatedMessages16bit && + SMS->SMS[i].UDH.Type != UDH_UserUDH) { + emsexist = false; + break; + } + } + } + + /* EMS decoding */ + if (emsexist) return GSM_DecodeEMSMultiPartSMS(Info,SMS); + + /* Smart Messaging decoding */ + if (SMS->SMS[0].UDH.Type == UDH_NokiaRingtone && SMS->Number == 1) { + Info->Entries[0].Ringtone = (GSM_Ringtone *)malloc(sizeof(GSM_Ringtone)); + if (Info->Entries[0].Ringtone == NULL) return false; + if (GSM_DecodeNokiaRTTLRingtone(Info->Entries[0].Ringtone, SMS->SMS[0].Text, SMS->SMS[0].Length)==ERR_NONE) { + Info->Entries[0].ID = SMS_NokiaRingtone; + Info->EntriesNum = 1; + return true; + } + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaCallerLogo && SMS->Number == 1) { + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + PHONE_DecodeBitmap(GSM_NokiaCallerLogo, SMS->SMS[0].Text+4, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaCallerLogo; + Info->EntriesNum = 1; + return true; + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaOperatorLogo && SMS->Number == 1) { + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + PHONE_DecodeBitmap(GSM_NokiaOperatorLogo, SMS->SMS[0].Text+7, &Info->Entries[0].Bitmap->Bitmap[0]); + NOKIA_DecodeNetworkCode(SMS->SMS[0].Text, Info->Entries[0].Bitmap->Bitmap[0].NetworkCode); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaOperatorLogo; + Info->EntriesNum = 1; + return true; + } + if (SMS->SMS[0].UDH.Type == UDH_NokiaProfileLong) { + for (i=0;i<SMS->Number;i++) { + if (SMS->SMS[i].UDH.Type != UDH_NokiaProfileLong || + SMS->SMS[i].UDH.Text[11] != i+1 || + SMS->SMS[i].UDH.Text[10] != SMS->Number) { + return false; + } + memcpy(Buffer+Length,SMS->SMS[i].Text,SMS->SMS[i].Length); + Length = Length + SMS->SMS[i].Length; + } + Info->EntriesNum = 1; + Info->Entries[0].ID = SMS_NokiaPictureImageLong; + Info->Entries[0].Bitmap = (GSM_MultiBitmap *)malloc(sizeof(GSM_MultiBitmap)); + if (Info->Entries[0].Bitmap == NULL) return false; + Info->Entries[0].Bitmap->Number = 1; + Info->Entries[0].Bitmap->Bitmap[0].Text[0] = 0; + Info->Entries[0].Bitmap->Bitmap[0].Text[1] = 0; + i=1; + while (i!=Length) { + switch (Buffer[i]) { + case SM30_ISOTEXT: + dbgprintf("ISO 8859-2 text\n"); + Info->Unknown = true; + break; + case SM30_UNICODETEXT: + dbgprintf("Unicode text\n"); + memcpy(Info->Entries[0].Bitmap->Bitmap[0].Text,Buffer+i+3,Buffer[i+1]*256+Buffer[i+2]); + Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]] = 0; + Info->Entries[0].Bitmap->Bitmap[0].Text[Buffer[i+1]*256 + Buffer[i+2]+ 1] = 0; + dbgprintf("Unicode Text \"%s\"\n",DecodeUnicodeString(Info->Entries[0].Bitmap->Bitmap[0].Text)); + break; + case SM30_OTA: + dbgprintf("OTA bitmap as Picture Image\n"); + PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + break; + case SM30_RINGTONE: + dbgprintf("RTTL ringtone\n"); + Info->Unknown = true; + break; + case SM30_PROFILENAME: + dbgprintf("Profile Name\n"); + Info->Entries[0].ID = SMS_NokiaProfileLong; + Info->Unknown = true; + break; + case SM30_SCREENSAVER: + dbgprintf("OTA bitmap as Screen Saver\n"); + PHONE_DecodeBitmap(GSM_NokiaPictureImage, Buffer + i + 7, &Info->Entries[0].Bitmap->Bitmap[0]); +#ifdef DEBUG + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) GSM_PrintBitmap(di.df,&Info->Entries[0].Bitmap->Bitmap[0]); +#endif + Info->Entries[0].ID = SMS_NokiaScreenSaverLong; + break; + } + i = i + Buffer[i+1]*256 + Buffer[i+2] + 3; + dbgprintf("%i %i\n",i,Length); + } + return true; + } + + /* Linked sms */ + if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages || + SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { + Info->EntriesNum = 1; + Info->Entries[0].ID = SMS_ConcatenatedTextLong; + if (SMS->SMS[0].UDH.Type == UDH_ConcatenatedMessages16bit) { + Info->Entries[0].ID = SMS_ConcatenatedTextLong16bit; + } + + for (i=0;i<SMS->Number;i++) { + switch (SMS->SMS[i].Coding) { + case SMS_Coding_8bit: + Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + SMS->SMS[i].Length + 2); + if (Info->Entries[0].Buffer == NULL) return false; + + memcpy(Info->Entries[0].Buffer + Length, SMS->SMS[i].Text, SMS->SMS[i].Length); + Length=Length+SMS->SMS[i].Length; + break; + case SMS_Coding_Unicode: + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong) { + Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong; + } + if (Info->Entries[0].ID == SMS_ConcatenatedTextLong16bit) { + Info->Entries[0].ID = SMS_ConcatenatedAutoTextLong16bit; + } + case SMS_Coding_Default: + Info->Entries[0].Buffer = realloc(Info->Entries[0].Buffer, Length + UnicodeLength(SMS->SMS[i].Text)*2 + 2); + if (Info->Entries[0].Buffer == NULL) return false; + + memcpy(Info->Entries[0].Buffer+Length,SMS->SMS[i].Text,UnicodeLength(SMS->SMS[i].Text)*2); + Length=Length+UnicodeLength(SMS->SMS[i].Text)*2; + break; + } + } + Info->Entries[0].Buffer[Length] = 0; + Info->Entries[0].Buffer[Length+1] = 0; + return true; + } + + return false; +} + +GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems) +{ + bool *INPUTSorted, copyit; + int i,OUTPUTNum,j,z,w; + + i = 0; + while (INPUT[i] != NULL) i++; + + INPUTSorted = calloc(i, sizeof(bool)); + if (INPUTSorted == NULL) return ERR_MOREMEMORY; + + OUTPUTNum = 0; + OUTPUT[0] = NULL; + + if (ems) { + i=0; + while (INPUT[i] != NULL) { + if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { + w=1; + while (w < INPUT[i]->SMS[0].UDH.Length) { + switch(INPUT[i]->SMS[0].UDH.Text[w]) { + case 0x00: + dbgprintf("Adding ID to user UDH - linked SMS with 8 bit ID\n"); + INPUT[i]->SMS[0].UDH.ID8bit = INPUT[i]->SMS[0].UDH.Text[w+2]; + INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+3]; + INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+4]; + break; + case 0x08: + dbgprintf("Adding ID to user UDH - linked SMS with 16 bit ID\n"); + INPUT[i]->SMS[0].UDH.ID16bit = INPUT[i]->SMS[0].UDH.Text[w+2]*256+INPUT[i]->SMS[0].UDH.Text[w+3]; + INPUT[i]->SMS[0].UDH.AllParts = INPUT[i]->SMS[0].UDH.Text[w+4]; + INPUT[i]->SMS[0].UDH.PartNumber = INPUT[i]->SMS[0].UDH.Text[w+5]; + break; + default: + dbgprintf("Block %02x\n",INPUT[i]->SMS[0].UDH.Text[w]); + } + dbgprintf("%i %i %i %i\n", + INPUT[i]->SMS[0].UDH.ID8bit, + INPUT[i]->SMS[0].UDH.ID16bit, + INPUT[i]->SMS[0].UDH.PartNumber, + INPUT[i]->SMS[0].UDH.AllParts); + w=w+INPUT[i]->SMS[0].UDH.Text[w+1]+2; + } + } + i++; + } + } + + i=0; + while (INPUT[i]!=NULL) { + /* If this one SMS was sorted earlier, do not touch */ + if (INPUTSorted[i]) { + i++; + continue; + } + copyit = false; + /* If we have: + * - linked sms returned by phone driver + * - sms without linking + * we copy it to OUTPUT + */ + if (INPUT[i]->Number != 1 || + INPUT[i]->SMS[0].UDH.Type == UDH_NoUDH || + INPUT[i]->SMS[0].UDH.PartNumber == -1) { + copyit = true; + } + /* If we have unknown UDH, we copy it to OUTPUT */ + if (INPUT[i]->SMS[0].UDH.Type == UDH_UserUDH) { + if (!ems) copyit = true; + if (ems && INPUT[i]->SMS[0].UDH.PartNumber == -1) copyit = true; + } + if (copyit) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); + INPUTSorted[i]=true; + OUTPUTNum++; + i = 0; + continue; + } + /* We have 1'st part of linked sms. It's single. + * We will try to find other parts + */ + if (INPUT[i]->SMS[0].UDH.PartNumber == 1) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(&OUTPUT[OUTPUTNum]->SMS[0],&INPUT[i]->SMS[0],sizeof(GSM_SMSMessage)); + OUTPUT[OUTPUTNum]->Number = 1; + INPUTSorted[i] = true; + j = 1; + /* We're searching for other parts in sequence */ + while (j!=INPUT[i]->SMS[0].UDH.AllParts) { + z=0; + while(INPUT[z]!=NULL) { + /* This was sorted earlier or is not single */ + if (INPUTSorted[z] || INPUT[z]->Number != 1) { + z++; + continue; + } + if (ems && INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && + INPUT[i]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && + INPUT[i]->SMS[0].UDH.Type != UDH_UserUDH && + INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages && + INPUT[z]->SMS[0].UDH.Type != UDH_ConcatenatedMessages16bit && + INPUT[z]->SMS[0].UDH.Type != UDH_UserUDH) { + if (INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { + z++; + continue; + } + } + if (!ems && INPUT[z]->SMS[0].UDH.Type != INPUT[i]->SMS[0].UDH.Type) { + z++; + continue; + } + dbgprintf("compare %i %i %i %i %i", + j+1, + INPUT[i]->SMS[0].UDH.ID8bit, + INPUT[i]->SMS[0].UDH.ID16bit, + INPUT[i]->SMS[0].UDH.PartNumber, + INPUT[i]->SMS[0].UDH.AllParts); + dbgprintf(" %i %i %i %i\n", + INPUT[z]->SMS[0].UDH.ID8bit, + INPUT[z]->SMS[0].UDH.ID16bit, + INPUT[z]->SMS[0].UDH.PartNumber, + INPUT[z]->SMS[0].UDH.AllParts); + if (INPUT[z]->SMS[0].UDH.ID8bit != INPUT[i]->SMS[0].UDH.ID8bit || + INPUT[z]->SMS[0].UDH.ID16bit != INPUT[i]->SMS[0].UDH.ID16bit || + INPUT[z]->SMS[0].UDH.AllParts != INPUT[i]->SMS[0].UDH.AllParts || + INPUT[z]->SMS[0].UDH.PartNumber != j+1) { + z++; + continue; + } + /* For SMS_Deliver compare also SMSC and Sender number */ + if (INPUT[z]->SMS[0].PDU == SMS_Deliver && + (strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].SMSC.Number),DecodeUnicodeString(INPUT[i]->SMS[0].SMSC.Number)) || + strcmp(DecodeUnicodeString(INPUT[z]->SMS[0].Number),DecodeUnicodeString(INPUT[i]->SMS[0].Number)))) { + z++; + continue; + } + /* DCT4 Outbox: SMS Deliver. Empty number and SMSC. We compare dates */ + if (INPUT[z]->SMS[0].PDU == SMS_Deliver && + UnicodeLength(INPUT[z]->SMS[0].SMSC.Number)==0 && + UnicodeLength(INPUT[z]->SMS[0].Number)==0 && + (INPUT[z]->SMS[0].DateTime.Day != INPUT[i]->SMS[0].DateTime.Day || + INPUT[z]->SMS[0].DateTime.Month != INPUT[i]->SMS[0].DateTime.Month || + INPUT[z]->SMS[0].DateTime.Year != INPUT[i]->SMS[0].DateTime.Year || + INPUT[z]->SMS[0].DateTime.Hour != INPUT[i]->SMS[0].DateTime.Hour || + INPUT[z]->SMS[0].DateTime.Minute != INPUT[i]->SMS[0].DateTime.Minute || + INPUT[z]->SMS[0].DateTime.Second != INPUT[i]->SMS[0].DateTime.Second)) { + z++; + continue; + } + /* We found correct sms. Copy it */ + memcpy(&OUTPUT[OUTPUTNum]->SMS[j],&INPUT[z]->SMS[0],sizeof(GSM_SMSMessage)); + OUTPUT[OUTPUTNum]->Number++; + INPUTSorted[z]=true; + break; + } + /* Incomplete sequence */ + if (OUTPUT[OUTPUTNum]->Number==j) { + dbgprintf("Incomplete sequence\n"); + break; + } + j++; + } + OUTPUTNum++; + i = 0; + continue; + } + /* We have some next linked sms from sequence */ + if (INPUT[i]->SMS[0].UDH.PartNumber > 1) { + j = 0; + while (INPUT[j]!=NULL) { + if (INPUTSorted[j]) { + j++; + continue; + } + /* We have some not unassigned first sms from sequence. + * We can't touch other sms from sequences + */ + if (INPUT[j]->SMS[0].UDH.PartNumber == 1) break; + j++; + } + if (INPUT[j]==NULL) { + OUTPUT[OUTPUTNum] = malloc(sizeof(GSM_MultiSMSMessage)); + if (OUTPUT[OUTPUTNum] == NULL) { + free(INPUTSorted); + return ERR_MOREMEMORY; + } + OUTPUT[OUTPUTNum+1] = NULL; + + memcpy(OUTPUT[OUTPUTNum],INPUT[i],sizeof(GSM_MultiSMSMessage)); + INPUTSorted[i]=true; + OUTPUTNum++; + i = 0; + continue; + } else i++; + } + } + free(INPUTSorted); + return ERR_NONE; +} + +/* 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/service/sms/gsmmulti.h b/gammu/emb/common/service/sms/gsmmulti.h new file mode 100644 index 0000000..c672261 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmmulti.h @@ -0,0 +1,271 @@ +/* (c) 2002-2004 by Marcin Wiacek */ + +#ifndef __gsm_multi_h +#define __gsm_multi_h + +#include "../../gsmcomon.h" +#include "../gsmlogo.h" +#include "../gsmcal.h" +#include "../gsmpbk.h" +#include "../gsmdata.h" +#include "../gsmring.h" +#include "gsmsms.h" + +/* ---------------------- multi SMS --------------------------------------- */ + +/* Identifiers for Smart Messaging 3.0 multipart SMS */ + +#define SM30_ISOTEXT 0 /* ISO 8859-1 text */ +#define SM30_UNICODETEXT 1 +#define SM30_OTA 2 +#define SM30_RINGTONE 3 +#define SM30_PROFILENAME 4 +/* ... */ +#define SM30_SCREENSAVER 6 + +/* Identifiers for Alcatel Terminal Data Download */ +#define ALCATELTDD_PICTURE 4 +#define ALCATELTDD_ANIMATION 5 +#define ALCATELTDD_SMSTEMPLATE 6 + +void GSM_SMSCounter(int MessageLength, + unsigned char *MessageBuffer, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int *SMSNum, + int *CharsLeft); + +#define MAX_MULTI_SMS 10 + +/** + * Multiple SMS messages, used for Smart Messaging 3.0/EMS. + */ +typedef struct { + /** + * Sender or recipient number. + */ + unsigned char Number; + /** + * Array of SMSes. + */ + GSM_SMSMessage SMS[MAX_MULTI_SMS]; +} GSM_MultiSMSMessage; + +GSM_Error GSM_AddSMS_Text_UDH(GSM_MultiSMSMessage *SMS, + GSM_Coding_Type Coding, + char *Buffer, + int BufferLen, + bool UDH, + int *UsedText, + int *CopiedText, + int *CopiedSMSText); + +void GSM_MakeMultiPartSMS(GSM_MultiSMSMessage *SMS, + unsigned char *MessageBuffer, + int MessageLength, + GSM_UDH UDHType, + GSM_Coding_Type Coding, + int Class, + unsigned char RejectDuplicates); + +void GSM_Find_Free_Used_SMS2(GSM_Coding_Type Coding,GSM_SMSMessage SMS, int *UsedText, int *FreeText, int *FreeBytes); + +unsigned char GSM_MakeSMSIDFromTime(void); + +/** + * ID during packing SMS for Smart Messaging 3.0, EMS and other + */ +typedef enum { + /** + * 1 text SMS. + */ + SMS_Text = 1, + /** + * Contacenated SMS, when longer than 1 SMS. + */ + SMS_ConcatenatedTextLong, + /** + * Contacenated SMS, auto Default/Unicode coding. + */ + SMS_ConcatenatedAutoTextLong, + SMS_ConcatenatedTextLong16bit, + SMS_ConcatenatedAutoTextLong16bit, + /** + * Nokia profile = Name, Ringtone, ScreenSaver + */ + SMS_NokiaProfileLong, + /** + * Nokia Picture Image + (text) + */ + SMS_NokiaPictureImageLong, + /** + * Nokia screen saver + (text) + */ + SMS_NokiaScreenSaverLong, + /** + * Nokia ringtone - old SM2.0 format, 1 SMS + */ + SMS_NokiaRingtone, + /** + * Nokia ringtone contacenated, when very long + */ + SMS_NokiaRingtoneLong, + /** + * Nokia 72x14 operator logo, 1 SMS + */ + SMS_NokiaOperatorLogo, + /** + * Nokia 72x14 op logo or 78x21 in 2 SMS + */ + SMS_NokiaOperatorLogoLong, + /** + * Nokia 72x14 caller logo, 1 SMS + */ + SMS_NokiaCallerLogo, + /** + * Nokia WAP bookmark in 1 or 2 SMS + */ + SMS_NokiaWAPBookmarkLong, + /** + * Nokia WAP settings in 2 SMS + */ + SMS_NokiaWAPSettingsLong, + /** + * Nokia MMS settings in 2 SMS + */ + SMS_NokiaMMSSettingsLong, + /** + * Nokia VCARD 1.0 - only name and default number + */ + SMS_NokiaVCARD10Long, + /** + * Nokia VCARD 2.1 - all numbers + text + */ + SMS_NokiaVCARD21Long, + /** + * Nokia VCALENDAR 1.0 - can be in few sms + */ + SMS_NokiaVCALENDAR10Long, + SMS_NokiaVTODOLong, + SMS_VCARD10Long, + SMS_VCARD21Long, + SMS_DisableVoice, + SMS_DisableFax, + SMS_DisableEmail, + SMS_EnableVoice, + SMS_EnableFax, + SMS_EnableEmail, + SMS_VoidSMS, + /** + * IMelody 1.0 + */ + SMS_EMSSound10, + /** + * IMelody 1.2 + */ + SMS_EMSSound12, + /** + * IMelody without header - SonyEricsson extension + */ + SMS_EMSSonyEricssonSound, + /** + * IMelody 1.0 with UPI. + */ + SMS_EMSSound10Long, + /*** + * IMelody 1.2 with UPI. + */ + SMS_EMSSound12Long, + /** + * IMelody without header with UPI. + */ + SMS_EMSSonyEricssonSoundLong, + SMS_EMSPredefinedSound, + SMS_EMSPredefinedAnimation, + SMS_EMSAnimation, + /** + * Fixed bitmap of size 16x16 or 32x32. + */ + SMS_EMSFixedBitmap, + SMS_EMSVariableBitmap, + SMS_EMSVariableBitmapLong, + SMS_MMSIndicatorLong, + /** + * Variable bitmap with black and white colors + */ + SMS_AlcatelMonoBitmapLong, + /** + * Variable animation with black and white colors + */ + SMS_AlcatelMonoAnimationLong, + SMS_AlcatelSMSTemplateName +} EncodeMultiPartSMSID; + +typedef struct { + EncodeMultiPartSMSID ID; + + int Number; + GSM_Ringtone *Ringtone; + GSM_MultiBitmap *Bitmap; + GSM_WAPBookmark *Bookmark; + GSM_WAPSettings *Settings; + GSM_MMSIndicator *MMSIndicator; + GSM_MemoryEntry *Phonebook; + GSM_CalendarEntry *Calendar; + GSM_ToDoEntry *ToDo; + bool Protected; + + unsigned char *Buffer; + bool Left; + bool Right; + bool Center; + bool Large; + bool Small; + bool Bold; + bool Italic; + bool Underlined; + bool Strikethrough; + + /* Return values */ + int RingtoneNotes; +} MultiPartSMSEntry; + +typedef struct { + MultiPartSMSEntry Entries[MAX_MULTI_SMS]; + int EntriesNum; + bool UnicodeCoding; + int Class; + unsigned char ReplaceMessage; + bool Unknown; +} GSM_MultiPartSMSInfo; + +/** + * Encodes multi part SMS from "readable" format. + */ +GSM_Error GSM_EncodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS); + +/** + * Decodes multi part SMS to "readable" format. + */ +bool GSM_DecodeMultiPartSMS (GSM_MultiPartSMSInfo *Info, GSM_MultiSMSMessage *SMS, bool ems); + +/** + * Clears @ref GSM_MultiPartSMSInfo to default values. + */ +void GSM_ClearMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info); + +/** + * Frees any allocated structures inside @ref GSM_MultiPartSMSInfo. + */ +void GSM_FreeMultiPartSMSInfo (GSM_MultiPartSMSInfo *Info); + +/** + * Links SMS messages according to IDs. + */ +GSM_Error GSM_LinkSMS(GSM_MultiSMSMessage **INPUT, GSM_MultiSMSMessage **OUTPUT, bool ems); + +#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/service/sms/gsmsms.c b/gammu/emb/common/service/sms/gsmsms.c new file mode 100644 index 0000000..9920835 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmsms.c @@ -0,0 +1,663 @@ +/* (c) 2001-2004 by Marcin Wiacek */ +/* based on some work from Pawel Kot, others and Gnokii */ + +#include <ctype.h> +#include <string.h> +#include <time.h> + +#include "../../gsmcomon.h" +#include "../../misc/coding/coding.h" +#include "../gsmcal.h" +#include "../gsmpbk.h" +#include "../gsmlogo.h" +#include "../gsmring.h" +#include "../gsmdata.h" +#include "../gsmnet.h" +#include "gsmsms.h" + +/* User data headers */ +static GSM_UDHHeader UDHHeaders[] = { + /* See GSM 03.40 section 9.2.3.24.1 + * 1 byte 0x00 + * 1 byte 0x03 + * 1 byte 0x01: unique ID for message series + * 1 byte 0x00: how many SMS in sequence + * 1 byte 0x00: number of current SMS in sequence */ + { UDH_ConcatenatedMessages, 0x05, "\x00\x03\x01\x00\x00",2,-1,4,3}, + + /* See GSM 03.40 section 9.2.3.24.2 for voice, fax and email messages */ + { UDH_DisableVoice, 0x04, "\x01\x02\x00\x00",-1,-1,-1,-1}, + { UDH_DisableFax, 0x04, "\x01\x02\x01\x00",-1,-1,-1,-1}, + { UDH_DisableEmail, 0x04, "\x01\x02\x02\x00",-1,-1,-1,-1}, + { UDH_EnableVoice, 0x04, "\x01\x02\x00\x01",-1,-1,-1,-1}, + { UDH_EnableFax, 0x04, "\x01\x02\x01\x01",-1,-1,-1,-1}, + { UDH_EnableEmail, 0x04, "\x01\x02\x02\x01",-1,-1,-1,-1}, + + /* When send such SMS to some phones, they don't display anything, + * only beep and enable vibra/light + */ + { UDH_VoidSMS, 0x08, "\x01\x02\x02\x01\x01\x02\x02\x00",-1,-1,-1,-1}, + + /* Nokia Smart Messaging (short version) UDH + * General format : + * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address + * 1 byte 0x04 : IEI length + * 2 bytes : destination address : high & low byte + * 2 bytes 0x00 0x00 : originator address : high & low byte */ + { UDH_NokiaRingtone, 0x06, "\x05\x04\x15\x81\x00\x00",-1,-1,-1,-1}, + { UDH_NokiaOperatorLogo, 0x06, "\x05\x04\x15\x82\x00\x00",-1,-1,-1,-1}, + { UDH_NokiaCallerLogo, 0x06, "\x05\x04\x15\x83\x00\x00",-1,-1,-1,-1}, + { UDH_NokiaWAP, 0x06, "\x05\x04\xc3\x4f\x00\x00",-1,-1,-1,-1}, + + /* Nokia Smart Messaging (long version) UDH and other + * General format: + * 1 byte 0x05 : IEI application port addressing scheme, 16 bit address + * 1 byte 0x04 : IEI length + * 2 bytes 0x00 0x00 : destination address : high & low byte + * 2 bytes 0x00 0x00 : originator address : high & low byte + * 1 byte 0x00 : SAR + * 1 byte 0x03 : SAR length + * 1 byte : diagram reference number (unique ID for message series) + * 1 byte : number of all SMS + * 1 byte : number of current SMS */ + { UDH_NokiaCalendarLong, 0x0b, "\x05\x04\x00\xe4\x00\x00\x00\x03\xc7\x00\x00",8,-1,10,9}, + { UDH_MMSIndicatorLong, 0x0b, "\x05\x04\x0b\x84\x23\xf0\x00\x03\xe5\x00\x00",8,-1,10,9}, + { UDH_NokiaRingtoneLong, 0x0b, "\x05\x04\x15\x81\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, + { UDH_NokiaOperatorLogoLong, 0x0b, "\x05\x04\x15\x82\x00\x00\x00\x03\x02\x00\x00",8,-1,10,9}, + { UDH_NokiaProfileLong, 0x0b, "\x05\x04\x15\x8a\x00\x00\x00\x03\xce\x00\x00",8,-1,10,9}, + { UDH_NokiaPhonebookLong, 0x0b, "\x05\x04\x23\xf4\x00\x00\x00\x03\x01\x00\x00",8,-1,10,9}, + { UDH_NokiaWAPLong, 0x0b, "\x05\x04\xc3\x4f\x00\x00\x00\x03\x7f\x00\x00",8,-1,10,9}, + + { UDH_ConcatenatedMessages16bit,0x06, "\x08\x04\x00\x00\x00\x00",-1,2,5,4}, + + { UDH_NoUDH, 0x00, "",-1,-1,-1,-1} +}; + +/* --------------------------- Unpacking SMS ------------------------------- */ + +/* See GSM 03.40 section 9.2.3.11 */ +static GSM_Error GSM_DecodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) +{ + DT->Year = DecodeWithBCDAlphabet(req[0]); + if (DT->Year<90) DT->Year=DT->Year+2000; else DT->Year=DT->Year+1990; + DT->Month = DecodeWithBCDAlphabet(req[1]); + DT->Day = DecodeWithBCDAlphabet(req[2]); + DT->Hour = DecodeWithBCDAlphabet(req[3]); + DT->Minute = DecodeWithBCDAlphabet(req[4]); + DT->Second = DecodeWithBCDAlphabet(req[5]); + + /* Base for timezone is GMT. It's in quarters */ + DT->Timezone=(10*(req[6]&0x07)+(req[6]>>4))/4; + + if (req[6]&0x08) DT->Timezone = -DT->Timezone; + + dbgprintf("Decoding date & time: "); + dbgprintf("%s %4d/%02d/%02d ", DayOfWeek(DT->Year, DT->Month, DT->Day), + DT->Year, DT->Month, DT->Day); + dbgprintf("%02d:%02d:%02d %02d00\n", DT->Hour, DT->Minute, DT->Second, DT->Timezone); + + return ERR_NONE; +} + +void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH) +{ + int i, tmp, w; + bool UDHOK; + + UDH->Type = UDH_UserUDH; + UDH->ID8bit = -1; + UDH->ID16bit = -1; + UDH->PartNumber = -1; + UDH->AllParts = -1; + + i=-1; + while (true) { + i++; + if (UDHHeaders[i].Type==UDH_NoUDH) break; + + tmp=UDHHeaders[i].Length; + /* if length is the same */ + if (tmp==UDH->Text[0]) { + + if (tmp==0x05) tmp=tmp-3;/*three last bytes can be different for such UDH*/ + if (tmp==0x0b) tmp=tmp-3;/*three last bytes can be different for such UDH*/ + if (tmp==0x06 && UDH->Text[1] == 0x08) tmp=tmp-4; + + UDHOK=true; + for (w=0;w<tmp;w++) { + if (UDHHeaders[i].Text[w]!=UDH->Text[w+1]) { + UDHOK=false; + break; + } + } + if (UDHOK) { + UDH->Type=UDHHeaders[i].Type; + + if (UDHHeaders[i].ID8bit !=-1) UDH->ID8bit = UDH->Text[UDHHeaders[i].ID8bit+1]; + if (UDHHeaders[i].ID16bit !=-1) UDH->ID16bit = UDH->Text[UDHHeaders[i].ID16bit+1]*256+UDH->Text[UDHHeaders[i].ID16bit+2]; + if (UDHHeaders[i].PartNumber !=-1) UDH->PartNumber = UDH->Text[UDHHeaders[i].PartNumber+1]; + if (UDHHeaders[i].AllParts !=-1) UDH->AllParts = UDH->Text[UDHHeaders[i].AllParts+1]; + break; + } + } + } + +#ifdef DEBUG + dbgprintf("Type of UDH: "); + switch (UDH->Type) { + case UDH_ConcatenatedMessages : dbgprintf("Concatenated (linked) message"); break; + case UDH_ConcatenatedMessages16bit : dbgprintf("Concatenated (linked) message"); break; + case UDH_DisableVoice : dbgprintf("Disables voice indicator"); break; + case UDH_EnableVoice : dbgprintf("Enables voice indicator"); break; + case UDH_DisableFax : dbgprintf("Disables fax indicator"); break; + case UDH_EnableFax : dbgprintf("Enables fax indicator"); break; + case UDH_DisableEmail : dbgprintf("Disables email indicator"); break; + case UDH_EnableEmail : dbgprintf("Enables email indicator"); break; + case UDH_VoidSMS : dbgprintf("Void SMS"); break; + case UDH_NokiaWAP : dbgprintf("Nokia WAP Bookmark"); break; + case UDH_NokiaOperatorLogoLong : dbgprintf("Nokia operator logo"); break; + case UDH_NokiaWAPLong : dbgprintf("Nokia WAP Bookmark or WAP/MMS Settings"); break; + case UDH_NokiaRingtone : dbgprintf("Nokia ringtone"); break; + case UDH_NokiaRingtoneLong : dbgprintf("Nokia ringtone"); break; + case UDH_NokiaOperatorLogo : dbgprintf("Nokia GSM operator logo"); break; + case UDH_NokiaCallerLogo : dbgprintf("Nokia caller logo"); break; + case UDH_NokiaProfileLong : dbgprintf("Nokia profile"); break; + case UDH_NokiaCalendarLong : dbgprintf("Nokia calendar note"); break; + case UDH_NokiaPhonebookLong : dbgprintf("Nokia phonebook entry"); break; + case UDH_UserUDH : dbgprintf("User UDH"); break; + case UDH_MMSIndicatorLong : dbgprintf("MMS indicator"); break; + case UDH_NoUDH: break; + } + if (UDH->ID8bit != -1) dbgprintf(", ID 8 bit %i",UDH->ID8bit); + if (UDH->ID16bit != -1) dbgprintf(", ID 16 bit %i",UDH->ID16bit); + if (UDH->PartNumber != -1 && UDH->AllParts != -1) { + dbgprintf(", part %i of %i",UDH->PartNumber,UDH->AllParts); + } + dbgprintf("\n"); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, UDH->Text, UDH->Length); +#endif +} + +GSM_Error GSM_DecodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) +{ + int off=0; // length of the User Data Header + int w,i,tmp=0; + unsigned char output[161]; + + SMS->UDH.Length = 0; + /* UDH header available */ + if (buffer[Layout.firstbyte] & 64) { + /* Length of UDH header */ + off = (buffer[Layout.Text] + 1); + SMS->UDH.Length = off; + dbgprintf("UDH header available (length %i)\n",off); + + /* Copy UDH header into SMS->UDH */ + for (i = 0; i < off; i++) SMS->UDH.Text[i] = buffer[Layout.Text + i]; + + GSM_DecodeUDHHeader(&SMS->UDH); + } + + /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ + if ((buffer[Layout.TPDCS] & 0xf4) == 0xf4) SMS->Coding=SMS_Coding_8bit; + if ((buffer[Layout.TPDCS] & 0x08) == 0x08) SMS->Coding=SMS_Coding_Unicode; + + switch (SMS->Coding) { + case SMS_Coding_Default: + i = 0; + do { + i+=7; + w=(i-off)%i; + } while (w<0); + SMS->Length=buffer[Layout.TPUDL] - (off*8 + w) / 7; + tmp=GSM_UnpackEightBitsToSeven(w, buffer[Layout.TPUDL]-off, SMS->Length, buffer+(Layout.Text+off), output); + dbgprintf("7 bit SMS, length %i\n",SMS->Length); + DecodeDefault (SMS->Text, output, SMS->Length, true, NULL); + dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); + break; + case SMS_Coding_8bit: + SMS->Length=buffer[Layout.TPUDL] - off; + memcpy(SMS->Text,buffer+(Layout.Text+off),SMS->Length); +#ifdef DEBUG + dbgprintf("8 bit SMS, length %i\n",SMS->Length); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->Text, SMS->Length); +#endif + break; + case SMS_Coding_Unicode: + SMS->Length=(buffer[Layout.TPUDL] - off) / 2; + DecodeUnicodeSpecialNOKIAChars(SMS->Text,buffer+(Layout.Text+off), SMS->Length); +#ifdef DEBUG + dbgprintf("Unicode SMS, length %i\n",SMS->Length); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, buffer+(Layout.Text+off), SMS->Length*2); + dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); +#endif + break; + } + + return ERR_NONE; +} + +GSM_Error GSM_DecodeSMSFrameStatusReportData(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) +{ + SMS->DeliveryStatus = buffer[Layout.TPStatus]; + + if (buffer[Layout.TPStatus] < 0x03) { + EncodeUnicode(SMS->Text,"Delivered",9); + SMS->Length = 9; + } else if (buffer[Layout.TPStatus] & 0x40) { + EncodeUnicode(SMS->Text,"Failed",6); + SMS->Length = 6; + } else if (buffer[Layout.TPStatus] & 0x20) { + EncodeUnicode(SMS->Text,"Pending",7); + SMS->Length = 7; + } else { + EncodeUnicode(SMS->Text,"Unknown",7); + SMS->Length = 7; + } + +#ifdef DEBUG + /* See GSM 03.40 section 9.2.3.15 (TP-Status) */ + if (buffer[Layout.TPStatus] & 0x40) { + if (buffer[Layout.TPStatus] & 0x20) { + /* 0x60, 0x61, ... */ + dbgprintf("Temporary error, SC is not making any more transfer attempts\n"); + } else { + /* 0x40, 0x41, ... */ + dbgprintf("Permanent error, SC is not making any more transfer attempts\n"); + } + } else if (buffer[Layout.TPStatus] & 0x20) { + /* 0x20, 0x21, ... */ + dbgprintf("Temporary error, SC still trying to transfer SM\n"); + } + switch (buffer[Layout.TPStatus]) { + case 0x00: dbgprintf("SM received by the SME"); break; + case 0x01: dbgprintf("SM forwarded by the SC to the SME but the SC is unable to confirm delivery");break; + case 0x02: dbgprintf("SM replaced by the SC"); break; + case 0x20: dbgprintf("Congestion"); break; + case 0x21: dbgprintf("SME busy"); break; + case 0x22: dbgprintf("No response from SME"); break; + case 0x23: dbgprintf("Service rejected"); break; + case 0x24: dbgprintf("Quality of service not available"); break; + case 0x25: dbgprintf("Error in SME"); break; + case 0x40: dbgprintf("Remote procedure error"); break; + case 0x41: dbgprintf("Incompatibile destination"); break; + case 0x42: dbgprintf("Connection rejected by SME"); break; + case 0x43: dbgprintf("Not obtainable"); break; + case 0x44: dbgprintf("Quality of service not available"); break; + case 0x45: dbgprintf("No internetworking available"); break; + case 0x46: dbgprintf("SM Validity Period Expired"); break; + case 0x47: dbgprintf("SM deleted by originating SME"); break; + case 0x48: dbgprintf("SM Deleted by SC Administration"); break; + case 0x49: dbgprintf("SM does not exist"); break; + case 0x60: dbgprintf("Congestion"); break; + case 0x61: dbgprintf("SME busy"); break; + case 0x62: dbgprintf("No response from SME"); break; + case 0x63: dbgprintf("Service rejected"); break; + case 0x64: dbgprintf("Quality of service not available"); break; + case 0x65: dbgprintf("Error in SME"); break; + default : dbgprintf("Reserved/Specific to SC: %x",buffer[Layout.TPStatus]); break; + } + dbgprintf("\n"); +#endif + + return ERR_NONE; +} + +GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) +{ + GSM_DateTime zerodt = {0,0,0,0,0,0,0}; +#ifdef DEBUG + if (Layout.firstbyte == 255) { + dbgprintf("ERROR: firstbyte in SMS layout not set\n"); + return ERR_UNKNOWN; + } + if (Layout.TPDCS != 255) dbgprintf("TPDCS : %02x %i\n",buffer[Layout.TPDCS] ,buffer[Layout.TPDCS]); + if (Layout.TPMR != 255) dbgprintf("TPMR : %02x %i\n",buffer[Layout.TPMR] ,buffer[Layout.TPMR]); + if (Layout.TPPID != 255) dbgprintf("TPPID : %02x %i\n",buffer[Layout.TPPID] ,buffer[Layout.TPPID]); + if (Layout.TPUDL != 255) dbgprintf("TPUDL : %02x %i\n",buffer[Layout.TPUDL] ,buffer[Layout.TPUDL]); + if (Layout.firstbyte != 255) dbgprintf("FirstByte : %02x %i\n",buffer[Layout.firstbyte],buffer[Layout.firstbyte]); + if (Layout.Text != 255) dbgprintf("Text : %02x %i\n",buffer[Layout.Text] ,buffer[Layout.Text]); +#endif + + SMS->UDH.Type = UDH_NoUDH; + SMS->Coding = SMS_Coding_Default; + SMS->Length = 0; + SMS->SMSC.Location = 0; + SMS->SMSC.DefaultNumber[0] = 0; + SMS->SMSC.DefaultNumber[1] = 0; + SMS->SMSC.Number[0] = 0; + SMS->SMSC.Number[1] = 0; + SMS->SMSC.Name[0] = 0; + SMS->SMSC.Name[1] = 0; + SMS->SMSC.Validity.Format = SMS_Validity_NotAvailable; + SMS->SMSC.Format = SMS_FORMAT_Text; + SMS->Number[0] = 0; + SMS->Number[1] = 0; + SMS->Name[0] = 0; + SMS->Name[1] = 0; + SMS->ReplyViaSameSMSC = false; + if (Layout.SMSCNumber!=255) { + GSM_UnpackSemiOctetNumber(SMS->SMSC.Number,buffer+Layout.SMSCNumber,false); + dbgprintf("SMS center number : \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); + } + if ((buffer[Layout.firstbyte] & 0x80)!=0) SMS->ReplyViaSameSMSC=true; +#ifdef DEBUG + if (SMS->ReplyViaSameSMSC) dbgprintf("SMS centre set for reply\n"); +#endif + if (Layout.Number!=255) { + GSM_UnpackSemiOctetNumber(SMS->Number,buffer+Layout.Number,true); + dbgprintf("Remote number : \"%s\"\n",DecodeUnicodeString(SMS->Number)); + } + if (Layout.Text != 255 && Layout.TPDCS!=255 && Layout.TPUDL!=255) { + GSM_DecodeSMSFrameText(SMS, buffer, Layout); + } + if (Layout.DateTime != 255) { + GSM_DecodeSMSDateTime(&SMS->DateTime,buffer+(Layout.DateTime)); + } else { + SMS->DateTime = zerodt; + } + if (Layout.SMSCTime != 255 && Layout.TPStatus != 255) { + /* GSM 03.40 section 9.2.3.11 (TP-Service-Centre-Time-Stamp) */ + dbgprintf("SMSC response date: "); + GSM_DecodeSMSDateTime(&SMS->SMSCTime, buffer+(Layout.SMSCTime)); + GSM_DecodeSMSFrameStatusReportData(SMS,buffer,Layout); + } else { + SMS->SMSCTime = zerodt; + } + SMS->Class = -1; + if (Layout.TPDCS != 255) { + if ((buffer[Layout.TPDCS] & 0xF3)==0xF0) SMS->Class = 0; + if ((buffer[Layout.TPDCS] & 0xF3)==0xF1) SMS->Class = 1; + if ((buffer[Layout.TPDCS] & 0xF3)==0xF2) SMS->Class = 2; + if ((buffer[Layout.TPDCS] & 0xF3)==0xF3) SMS->Class = 3; + } + dbgprintf("SMS class: %i\n",SMS->Class); + + SMS->MessageReference = 0; + if (Layout.TPMR != 255) SMS->MessageReference = buffer[Layout.TPMR]; + + SMS->ReplaceMessage = 0; + if (Layout.TPPID != 255) { + if (buffer[Layout.TPPID] > 0x40 && buffer[Layout.TPPID] < 0x48) { + SMS->ReplaceMessage = buffer[Layout.TPPID] - 0x40; + } + } + SMS->RejectDuplicates = false; + if ((buffer[Layout.firstbyte] & 0x04)==0x04) SMS->RejectDuplicates = true; + + return ERR_NONE; +} + +/* ----------------------------- Packing SMS ------------------------------- */ + +/* See GSM 03.40 section 9.2.3.11 */ +static GSM_Error GSM_EncodeSMSDateTime(GSM_DateTime *DT, unsigned char *req) +{ + int Year; + + dbgprintf("Encoding SMS datetime: %02i/%02i/%04i %02i:%02i:%02i\n", + DT->Day,DT->Month,DT->Year,DT->Hour,DT->Minute,DT->Second); + + /* We need to have only two last digits of year */ + if (DT->Year>1900) { + if (DT->Year<2000) Year = DT->Year-1900; + else Year = DT->Year-2000; + } else Year = DT->Year; + + req[0]=EncodeWithBCDAlphabet(Year); + req[1]=EncodeWithBCDAlphabet(DT->Month); + req[2]=EncodeWithBCDAlphabet(DT->Day); + req[3]=EncodeWithBCDAlphabet(DT->Hour); + req[4]=EncodeWithBCDAlphabet(DT->Minute); + req[5]=EncodeWithBCDAlphabet(DT->Second); + + /* FIXME: do it */ + req[6]=0; /* TimeZone = +-0 */ + + return ERR_NONE; +} + +static int GSM_EncodeSMSFrameText(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout) +{ + int off = 0; // length of the User Data Header + int size = 0, size2 = 0, w,p; + char buff[200]; + + if (SMS->UDH.Type!=UDH_NoUDH) { + buffer[Layout.firstbyte] |= 0x40; /* GSM 03.40 section 9.2.3.23 (TP-User-Data-Header-Indicator) */ + off = 1 + SMS->UDH.Text[0]; /* off - length of the User Data Header */ + memcpy(buffer+Layout.Text, SMS->UDH.Text, off); /* we copy the udh */ +#ifdef DEBUG + dbgprintf("UDH, length %i\n",off); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->UDH.Text, off); +#endif + } + switch (SMS->Coding) { + case SMS_Coding_8bit: + /* the mask for the 8-bit data */ + /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) + * and GSM 03.38 section 4 */ + buffer[Layout.TPDCS] |= 0xf4; + memcpy(buffer+(Layout.Text+off), SMS->Text, SMS->Length); + size2 = size = SMS->Length+off; +#ifdef DEBUG + dbgprintf("8 bit SMS, length %i\n",SMS->Length); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, SMS->Text, SMS->Length); +#endif + break; + case SMS_Coding_Default: + p = 0; + do { + p+=7; + w=(p-off)%p; + } while (w<0); + p = UnicodeLength(SMS->Text); + EncodeDefault(buff, SMS->Text, &p, true, NULL); + size = GSM_PackSevenBitsToEight(w, buff, buffer+(Layout.Text+off), p); + size += off; + size2 = (off*8 + w) / 7 + p; + dbgprintf("7 bit SMS, length %i, %i\n",size,size2); + dbgprintf("%s\n",DecodeUnicodeString(SMS->Text)); + if (size > GSM_MAX_8BIT_SMS_LENGTH) { + size = 0; size2 = 0; + } + break; + case SMS_Coding_Unicode: + /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) + * and GSM 03.38 section 4 */ + buffer[Layout.TPDCS] |= 0x08; + EncodeUnicodeSpecialNOKIAChars(buffer+(Layout.Text+off), SMS->Text, UnicodeLength(SMS->Text)); + size=size2=UnicodeLength(buffer+(Layout.Text+off))*2+off; +#ifdef DEBUG + dbgprintf("Unicode SMS, length %i\n",(size2-off)/2); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, buffer+(Layout.Text+off), size2-off); + dbgprintf("%s\n",DecodeUnicodeString(buffer+(Layout.Text+off))); +#endif + break; + } + + /* GSM 03.40 section 9.2.3.16 (TP-User-Data-Length) + * SMS->Length is: + - integer representation of the number od octets within the + user data when TP-User-Data is coded using 8 bit data + - the sum of the number of septets in UDH including any padding + and the number of septets in TP-User-Data in other case + */ + buffer[Layout.TPUDL] = size2; + return size; +} + +GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear) +{ + int i; + + if (clear) { + /* Cleaning up to the SMS text */ + for (i=0;i<Layout.Text;i++) buffer[i] = 0; + } + + /* GSM 03.40 section 9.2.3.1 (TP-Message-Type-Indicator) */ + switch (SMS->PDU) { + case SMS_Submit: + buffer[Layout.firstbyte] |= 0x01; + break; + /* SMS_Status_Report when Submit sms should have delivery report */ + /* We DON'T CREATE FRAME FOR REAL SMS_STATUS_REPORT */ + case SMS_Status_Report: + buffer[Layout.firstbyte] |= 0x01; + /* GSM 03.40 section 9.2.3.5 (TP-Status-Raport-Request) */ + /* Set when want delivery report from SMSC */ + buffer[Layout.firstbyte] |= 0x20; + break; + case SMS_Deliver: + buffer[Layout.firstbyte] |= 0x00; + } + + /* GSM 03.40 section 9.2.3.17 (TP-Reply-Path) */ + if (SMS->ReplyViaSameSMSC) buffer[Layout.firstbyte] |= 0x80; + + if (Layout.Number!=255) { + buffer[Layout.Number] = GSM_PackSemiOctetNumber(SMS->Number,buffer+(Layout.Number+1),true); + dbgprintf("Recipient number \"%s\"\n",DecodeUnicodeString(SMS->Number)); + } + if (Layout.SMSCNumber!=255) { + buffer[Layout.SMSCNumber]=GSM_PackSemiOctetNumber(SMS->SMSC.Number,buffer+(Layout.SMSCNumber+1), false); + dbgprintf("SMSC number \"%s\"\n",DecodeUnicodeString(SMS->SMSC.Number)); + } + + /* Message Class*/ + /* GSM 03.40 section 9.2.3.10 (TP-Data-Coding-Scheme) and GSM 03.38 section 4 */ + if (Layout.TPDCS != 255) { + if (SMS->Class>=0 && SMS->Class<5) buffer[Layout.TPDCS] |= (240+SMS->Class); + dbgprintf("SMS class %i\n",SMS->Class); + } + + if (Layout.TPVP != 255) { + /* GSM 03.40 section 9.2.3.3 (TP-Validity-Period-Format) */ + /* Bits 4 and 3: 10. TP-VP field present and integer represent (relative) */ + buffer[Layout.firstbyte] |= 0x10; + buffer[Layout.TPVP]=((unsigned char)SMS->SMSC.Validity.Relative); + dbgprintf("SMS validity %02x\n",SMS->SMSC.Validity.Relative); + } + + if (Layout.DateTime != 255) { + GSM_EncodeSMSDateTime(&SMS->DateTime, buffer+Layout.DateTime); + } + + if (Layout.TPMR != 255) { + dbgprintf("TPMR: %02x %i\n",SMS->MessageReference,SMS->MessageReference); + buffer[Layout.TPMR] = SMS->MessageReference; + } + + if (SMS->RejectDuplicates) { + /* GSM 03.40 section 9.2.3.25 (TP Reject Duplicates) */ + buffer[Layout.firstbyte] |= 0x04; + } + + if (Layout.TPPID != 255) { + buffer[Layout.TPPID] = 0; + if (SMS->ReplaceMessage > 0 && SMS->ReplaceMessage < 8) { + buffer[Layout.TPPID] = 0x40 + SMS->ReplaceMessage; + } + } + + /* size is the length of the data in octets including UDH */ + *length=GSM_EncodeSMSFrameText(SMS,buffer,Layout); +// if (*length == 0) return GE_UNKNOWN; + *length += Layout.Text; + + return ERR_NONE; +} + +/* ----------------- Some help functions ----------------------------------- */ + +void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS) +{ + SMS->Class = -1; + SMS->SMSC.Location = 1; + SMS->SMSC.Format = SMS_FORMAT_Text; + SMS->SMSC.Validity.Format = SMS_Validity_RelativeFormat; + SMS->SMSC.Validity.Relative = SMS_VALID_Max_Time; + SMS->ReplyViaSameSMSC = false; + SMS->UDH.Type = UDH_NoUDH; + SMS->UDH.Length = 0; + SMS->UDH.Text[0] = 0; + SMS->UDH.ID8bit = 0; + SMS->UDH.ID16bit = 0; + SMS->UDH.PartNumber = 0; + SMS->UDH.AllParts = 0; + SMS->Coding = SMS_Coding_Default; + SMS->Text[0] = 0; + SMS->Text[1] = 0; + SMS->PDU = SMS_Submit; + SMS->RejectDuplicates = false; + SMS->MessageReference = 0; + SMS->ReplaceMessage = 0; + SMS->Length = 0; + + /* This part is required to save SMS */ + SMS->State = SMS_UnSent; + SMS->Location = 0; + SMS->Folder = 0x02; /*Outbox*/ + GSM_GetCurrentDateTime (&SMS->DateTime); + SMS->Name[0] = 0; + SMS->Name[1] = 0; +} + +/** + * GSM 03.40 section 9.2.3.24 + */ +void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH) +{ + int i=0; + + if (UDH->Type == UDH_NoUDH) { + UDH->Length = 0; + return; + } + if (UDH->Type == UDH_UserUDH) { + UDH->Length = UDH->Text[0] + 1; + return; + } + while (true) { + if (UDHHeaders[i].Type==UDH_NoUDH) { + dbgprintf("Not supported UDH type\n"); + break; + } + if (UDHHeaders[i].Type!=UDH->Type) { + i++; + continue; + } + /* UDH Length */ + UDH->Text[0] = UDHHeaders[i].Length; + memcpy(UDH->Text+1, UDHHeaders[i].Text, UDHHeaders[i].Length); + UDH->Length = UDH->Text[0] + 1; + + if (UDHHeaders[i].ID8bit != -1) { + UDH->Text[UDHHeaders[i].ID8bit+1] = UDH->ID8bit % 256; + } else { + UDH->ID8bit = -1; + } + if (UDHHeaders[i].ID16bit != -1) { + UDH->Text[UDHHeaders[i].ID16bit+1] = UDH->ID16bit / 256; + UDH->Text[UDHHeaders[i].ID16bit+2] = UDH->ID16bit % 256; + } else { + UDH->ID16bit = -1; + } + if (UDHHeaders[i].PartNumber != -1) { + UDH->Text[UDHHeaders[i].PartNumber+1] = UDH->PartNumber; + } else { + UDH->PartNumber = -1; + } + if (UDHHeaders[i].AllParts != -1) { + UDH->Text[UDHHeaders[i].AllParts+1] = UDH->AllParts; + } else { + UDH->AllParts = -1; + } + break; + } +} + +/* 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/service/sms/gsmsms.h b/gammu/emb/common/service/sms/gsmsms.h new file mode 100644 index 0000000..d87ff60 --- a/dev/null +++ b/gammu/emb/common/service/sms/gsmsms.h @@ -0,0 +1,492 @@ +/* (c) 2001-2004 by Marcin Wiacek */ +/* based on some work from Pawel Kot, others and Gnokii */ + +#ifndef __gsm_sms_h +#define __gsm_sms_h + +#include "../../gsmcomon.h" +#include "../gsmlogo.h" +#include "../gsmcal.h" +#include "../gsmpbk.h" +#include "../gsmdata.h" +#include "../gsmring.h" + +/* --------------------- Some general definitions ------------------------- */ + +#define GSM_MAX_UDH_LENGTH 140 +#define GSM_MAX_SMS_LENGTH 160 +#define GSM_MAX_8BIT_SMS_LENGTH 140 + +/* -------------------- Cell Broadcast ------------------------------------ */ + +/** + * Structure for Cell Broadcast messages. + */ +typedef struct { + /** + * Message text. + */ + char Text[300]; + /** + * Channel number. + */ + int Channel; +} GSM_CBMessage; + +/* ------------------------ SMS status ------------------------------------ */ + +/** + * Status of SMS memory. + */ +typedef struct { + /** + * Number of unread messages on SIM. + */ + int SIMUnRead; + /** + * Number of all saved messages (including unread) on SIM. + */ + int SIMUsed; + /** + * Number of all possible messages on SIM. + */ + int SIMSize; + /** + * Number of used templates (62xx/63xx/7110/etc.). + */ + int TemplatesUsed; + /** + * Number of unread messages in phone. + */ + int PhoneUnRead; + /** + * Number of all saved messages in phone. + */ + int PhoneUsed; + /** + * Number of all possible messages on phone. + */ + int PhoneSize; +} GSM_SMSMemoryStatus; + +/* --------------------- SMS Center --------------------------------------- */ + +/** + * Enum defines format of SMS messages. See GSM 03.40 section 9.2.3.9 + */ +typedef enum { + SMS_FORMAT_Pager = 1, + SMS_FORMAT_Fax, + SMS_FORMAT_Email, + SMS_FORMAT_Text + /* Some values not handled here */ +} GSM_SMSFormat; + +/** + * Enum defines some the most often used validity lengths for SMS messages + * for relative validity format. See GSM 03.40 section 9.2.3.12.1 - it gives + * more values + */ +typedef enum { + SMS_VALID_1_Hour = 0x0b, + SMS_VALID_6_Hours = 0x47, + SMS_VALID_1_Day = 0xa7, + SMS_VALID_3_Days = 0xa9, + SMS_VALID_1_Week = 0xad, + SMS_VALID_Max_Time = 0xff +} GSM_ValidityPeriod; + +/** + * Enum defines format of validity period for SMS messages. + * See GSM 03.40 section 9.2.3.12 + */ +typedef enum { + SMS_Validity_NotAvailable = 1, + SMS_Validity_RelativeFormat + /* Specification gives also other possibilities */ +} GSM_ValidityPeriodFormat; + +/** + * Structure for validity of SMS messages + */ +typedef struct { + GSM_ValidityPeriodFormat Format; + /** + * Value defines period for relative format + */ + GSM_ValidityPeriod Relative; +} GSM_SMSValidity; + +#define GSM_MAX_SMSC_NAME_LENGTH 30 + +/** + * Structure for SMSC (SMS Center) information. + */ +typedef struct { + /** + * Number of the SMSC on SIM + */ + int Location; + /** + * Name of the SMSC + */ + unsigned char Name[(GSM_MAX_SMSC_NAME_LENGTH+1)*2]; + /** + * SMSC phone number. + */ + unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2]; + /** + * Validity of SMS messages. + */ + GSM_SMSValidity Validity; + /** + * Format of sent SMS messages. + */ + GSM_SMSFormat Format; + /** + * Default recipient number. In old DCT3 ignored + */ + unsigned char DefaultNumber[(GSM_MAX_NUMBER_LENGTH+1)*2]; +} GSM_SMSC; + +/* --------------------- single SMS --------------------------------------- */ + +/** + * Status of SMS message. + */ +typedef enum { + SMS_Sent = 1, + SMS_UnSent, + SMS_Read, + SMS_UnRead +} GSM_SMS_State; + +/** + * Coding type of SMS. + */ +typedef enum { + /** + * Unicode + */ + SMS_Coding_Unicode = 1, + /** + * Default GSM aplhabet. + */ + SMS_Coding_Default, + /** + * 8-bit. + */ + SMS_Coding_8bit +} GSM_Coding_Type; + +/** + * Types of UDH (User Data Header). + */ +typedef enum { + UDH_NoUDH = 1, + /** + * Linked SMS. + */ + UDH_ConcatenatedMessages, + /** + * Linked SMS with 16 bit reference. + */ + UDH_ConcatenatedMessages16bit, + UDH_DisableVoice, + UDH_DisableFax, + UDH_DisableEmail, + UDH_EnableVoice, + UDH_EnableFax, + UDH_EnableEmail, + UDH_VoidSMS, + UDH_NokiaRingtone, + UDH_NokiaRingtoneLong, + UDH_NokiaOperatorLogo, + UDH_NokiaOperatorLogoLong, + UDH_NokiaCallerLogo, + UDH_NokiaWAP, + UDH_NokiaWAPLong, + UDH_NokiaCalendarLong, + UDH_NokiaProfileLong, + UDH_NokiaPhonebookLong, + UDH_UserUDH, + UDH_MMSIndicatorLong +} GSM_UDH; + +/** + * Structure for User Data Header. + */ +typedef struct { + /** + * UDH type. + */ + GSM_UDH Type; + /** + * UDH length. + */ + int Length; + /** + * UDH text. + */ + unsigned char Text[GSM_MAX_UDH_LENGTH]; + /** + * 8-bit ID, when required (-1 otherwise). + */ + int ID8bit; + /** + * 16-bit ID, when required (-1 otherwise). + */ + int ID16bit; + /** + * Number of current part. + */ + int PartNumber; + /** + * Total number of parts. + */ + int AllParts; +} GSM_UDHHeader; + +/** + * TP-Message-Type-Indicator. See GSM 03.40 section 9.2.3.1. + */ +typedef enum { + /** + * SMS in Inbox. + */ + SMS_Deliver = 1, + /** + * Delivery Report + */ + SMS_Status_Report, + /** + * SMS for sending or in Outbox + */ + SMS_Submit + /* specification gives more */ +} GSM_SMSMessageType; + +/** + * Maximal length of SMS name. + */ +#define GSM_MAX_SMS_NAME_LENGTH 40 + +/** + * SMS message data. + */ +typedef struct { + /** + * Message to be replaced. + */ + unsigned char ReplaceMessage; + /** + * Whether to reject duplicates. + */ + bool RejectDuplicates; + /** + * UDH (User Data Header) + */ + GSM_UDHHeader UDH; + /** + * Sender or recipient number. + */ + unsigned char Number[(GSM_MAX_NUMBER_LENGTH+1)*2]; + /** + * SMSC (SMS Center) + */ + GSM_SMSC SMSC; + /** + * For saved SMS: where exactly it's saved (SIM/phone) + */ + GSM_MemoryType Memory; + /** + * For saved SMS: location of SMS in memory. + */ + int Location; + /** + * For saved SMS: number of folder, where SMS is saved + */ + int Folder; + /** + * For saved SMS: whether SMS is really in Inbox. + */ + bool InboxFolder; + /** + * Length of the SMS message. + */ + int Length; + /** + * Status (read/unread/...) of SMS message. + */ + GSM_SMS_State State; + /** + * Name in Nokia with SMS memory (6210/7110, etc.) Ignored in other. + */ + unsigned char Name[(GSM_MAX_SMS_NAME_LENGTH+1)*2]; + /** + * Text for SMS. + */ + unsigned char Text[(GSM_MAX_SMS_LENGTH+1)*2]; + /** + * Type of message. + */ + GSM_SMSMessageType PDU; + /** + * Type of coding. + */ + GSM_Coding_Type Coding; + /** + * Date and time, when SMS was saved or sent + */ + GSM_DateTime DateTime; + /** + * Date of SMSC response in DeliveryReport messages. + */ + GSM_DateTime SMSCTime; + /** + * In delivery reports: status. + */ + unsigned char DeliveryStatus; + /** + * Indicates whether "Reply via same center" is set. + */ + bool ReplyViaSameSMSC; + /** + * SMS class. + */ + char Class; + /** + * Message reference. + */ + unsigned char MessageReference; +} GSM_SMSMessage; + +/* In layouts are saved locations for some SMS part. Below are listed + * specs, which describe them + */ +typedef struct { + /** + * TP-User-Data. GSM 03.40 section 9.2.3.24. + */ + unsigned char Text; + /** + * - In SMS-Deliver: TP-Originating-Address. GSM 03.40 section 9.2.3.7. + * - In SMS-Submit: TP-Destination-Address. GSM 03.40 section 9.2.3.8. + * - In SMS-Status-Report: TP-Recipient-Address. GSM 03.40 section 9.2.3.14. + */ + unsigned char Number; + /** + * SMSC number + */ + unsigned char SMSCNumber; + /** + * TP-Data-Coding-Scheme. GSM 03.40 section 9.2.3.10 + */ + unsigned char TPDCS; + /** + * - For SMS-Submit: TP-Validity-Period. GSM 03.40 section 9.2.3.12. + * - For SMS-Status-Report: TP-Discharge Time. GSM 03.40 section 9.2.3.13. + */ + unsigned char DateTime; + /** + * TP-Service-Centre-Time-Stamp in SMS-Status-Report. GSM 03.40 section 9.2.3.11. + */ + unsigned char SMSCTime; + /** + * TP-Status in SMS-Status-Report. GSM 03.40 section 9.2.3.15. + */ + unsigned char TPStatus; + /** + * TP-User-Data-Length. GSM 03.40 section 9.2.3.16. + */ + unsigned char TPUDL; + /** + * TP-Validity Period in SMS-Submit. GSM 03.40 section 9.2.3.12. + */ + unsigned char TPVP; + /** + * Byte contains in SMS-Deliver: + * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1 + * - TP-More-Messages-To-Send (1 bit). GSM 03.40 section 9.2.3.2 + * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17 + * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23 + * - TP-Status-Report-Indicator (1 bit). GSM 03.40 section 9.2.3.4 + * + * Byte contains in SMS-Submit: + * - TP-Message-Type-Indicator (2 bits) GSM 03.40 section 9.2.3.1 + * - TP-Reject-Duplicates (1 bit). GSM 03.40 section + * - TP-Validity-Period-Format (2 bits).GSM 03.40 section 9.2.3.3 + * - TP-Reply-Path (1 bit). GSM 03.40 section 9.2.3.17 + * - TP-User-Data-Header-Indicator (1 bit). GSM 03.40 section 9.2.3.23 + * - TP-Status-Report-Request (1 bit). GSM 03.40 section 9.2.3.5 + */ + unsigned char firstbyte; + /** + * TP-Message Reference in SMS-Submit. GSM 03.40 section 9.2.3.6 + */ + unsigned char TPMR; + /** + * TP-Protocol-Identifier. GSM 03.40 section 9.2.3.9 + */ + unsigned char TPPID; +} GSM_SMSMessageLayout; + +GSM_Error GSM_DecodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); +GSM_Error GSM_EncodeSMSFrame(GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout, int *length, bool clear); + +GSM_Error GSM_DecodeSMSFrameStatusReportData (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); +GSM_Error GSM_DecodeSMSFrameText (GSM_SMSMessage *SMS, unsigned char *buffer, GSM_SMSMessageLayout Layout); + +void GSM_DecodeUDHHeader(GSM_UDHHeader *UDH); +void GSM_EncodeUDHHeader(GSM_UDHHeader *UDH); + +void GSM_SetDefaultSMSData(GSM_SMSMessage *SMS); + +/* ---------------------- SMS folders ------------------------------------- */ + +/** + * Number of possible SMS folders. + */ +#define GSM_MAX_SMS_FOLDERS 24 +/** + * Maximal length of SMS folder name. + */ +#define GSM_MAX_SMS_FOLDER_NAME_LEN 20 + +/** + * Information about SMS folder. + */ +typedef struct { + /** + * Whether it is really inbox. + */ + bool InboxFolder; + /** + * Where exactly it's saved + */ + GSM_MemoryType Memory; + /** + * Name for SMS folder. + */ + char Name[(GSM_MAX_SMS_FOLDER_NAME_LEN+1)*2]; +} GSM_OneSMSFolder; + +/** + * List of SMS folders. + */ +typedef struct { + /** + * Array of structures holding information about each folder. + */ + GSM_OneSMSFolder Folder[GSM_MAX_SMS_FOLDERS]; + /** + * Number of SMS folders. + */ + unsigned char Number; +} GSM_SMSFolders; + +#endif + +/* How should editor hadle tabs in this file? Add editor commands here. + * vim: noexpandtab sw=8 ts=8 sts=8: + */ |