summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/service
authorzautrix <zautrix>2004-08-07 17:24:40 (UTC)
committer zautrix <zautrix>2004-08-07 17:24:40 (UTC)
commit88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 (patch) (side-by-side diff)
tree6331418973714243beb674abc87692277b83869d /gammu/emb/common/service
parentef8a09ce74ad3f0a51484d03fdf009bd5b3677bf (diff)
downloadkdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.zip
kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.gz
kdepimpi-88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22.tar.bz2
Initial revision
Diffstat (limited to 'gammu/emb/common/service') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/service/backup/backgen.h69
-rw-r--r--gammu/emb/common/service/backup/backics.c42
-rw-r--r--gammu/emb/common/service/backup/backics.h17
-rw-r--r--gammu/emb/common/service/backup/backldif.c297
-rw-r--r--gammu/emb/common/service/backup/backldif.h17
-rw-r--r--gammu/emb/common/service/backup/backlmb.c413
-rw-r--r--gammu/emb/common/service/backup/backlmb.h17
-rw-r--r--gammu/emb/common/service/backup/backtext.c2908
-rw-r--r--gammu/emb/common/service/backup/backtext.h17
-rw-r--r--gammu/emb/common/service/backup/backvcf.c75
-rw-r--r--gammu/emb/common/service/backup/backvcf.h17
-rw-r--r--gammu/emb/common/service/backup/backvcs.c106
-rw-r--r--gammu/emb/common/service/backup/backvcs.h17
-rw-r--r--gammu/emb/common/service/backup/gsmback.c280
-rw-r--r--gammu/emb/common/service/backup/gsmback.h48
-rw-r--r--gammu/emb/common/service/gsmcal.c509
-rw-r--r--gammu/emb/common/service/gsmcal.h445
-rw-r--r--gammu/emb/common/service/gsmcall.h185
-rw-r--r--gammu/emb/common/service/gsmdata.c366
-rw-r--r--gammu/emb/common/service/gsmdata.h152
-rw-r--r--gammu/emb/common/service/gsmlogo.c1003
-rw-r--r--gammu/emb/common/service/gsmlogo.h180
-rw-r--r--gammu/emb/common/service/gsmmisc.c262
-rw-r--r--gammu/emb/common/service/gsmmisc.h316
-rw-r--r--gammu/emb/common/service/gsmnet.c444
-rw-r--r--gammu/emb/common/service/gsmnet.h98
-rw-r--r--gammu/emb/common/service/gsmpbk.c370
-rw-r--r--gammu/emb/common/service/gsmpbk.h270
-rw-r--r--gammu/emb/common/service/gsmprof.h104
-rw-r--r--gammu/emb/common/service/gsmring.c1600
-rw-r--r--gammu/emb/common/service/gsmring.h202
-rw-r--r--gammu/emb/common/service/sms/gsmems.c765
-rw-r--r--gammu/emb/common/service/sms/gsmems.h20
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.c1148
-rw-r--r--gammu/emb/common/service/sms/gsmmulti.h271
-rw-r--r--gammu/emb/common/service/sms/gsmsms.c663
-rw-r--r--gammu/emb/common/service/sms/gsmsms.h492
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, &note->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, &note->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, &note->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, &note->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, &note->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, &note->Entries[Time].Date, "DTSTART");
+
+ if (EndTime != -1) {
+ SaveVCALDateTime(Buffer, Length, &note->Entries[EndTime].Date, "DTEND");
+ }
+
+ if (Alarm != -1) {
+ if (note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) {
+ SaveVCALDateTime(Buffer, Length, &note->Entries[Alarm].Date, "DALARM");
+ } else {
+ SaveVCALDateTime(Buffer, Length, &note->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, &note->Entries[Time].Date, "DTSTART");
+
+ if (Alarm != -1) {
+ SaveVCALDateTime(Buffer, Length, &note->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, &note->Entries[Time].Date, "DTSTART");
+
+ if (EndTime != -1) {
+ SaveVCALDateTime(Buffer, Length, &note->Entries[EndTime].Date, "DTEND");
+ }
+
+ if (Alarm != -1) {
+ SaveVCALDateTime(Buffer, Length, &note->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, &note->Entries[EndTime].Date, "DUE");
+ }
+
+ if (Alarm != -1) {
+ if (note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) {
+ SaveVCALDateTime(Buffer, Length, &note->Entries[Alarm].Date, "DALARM");
+ } else {
+ SaveVCALDateTime(Buffer, Length, &note->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, &note->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,&current,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,&current,pause);
+ pause=0;
+ midifile[current++]=0x90; // note on
+ midifile[current++]=note;
+ midifile[current++]=0x64; // forte
+
+ WriteVarLen(midifile,&current,duration);
+ midifile[current++]=0x80; // note off
+ midifile[current++]=note;
+ midifile[current++]=0x64;
+ }
+ }
+ }
+ if (pause) {
+ WriteVarLen(midifile,&current,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:
+ */