summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/phone/alcatel/alcatel.c
Side-by-side diff
Diffstat (limited to 'gammu/emb/common/phone/alcatel/alcatel.c') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/phone/alcatel/alcatel.c3991
1 files changed, 3991 insertions, 0 deletions
diff --git a/gammu/emb/common/phone/alcatel/alcatel.c b/gammu/emb/common/phone/alcatel/alcatel.c
new file mode 100644
index 0000000..f004ad4
--- a/dev/null
+++ b/gammu/emb/common/phone/alcatel/alcatel.c
@@ -0,0 +1,3991 @@
+/* (c) 2002-2004 by Michal Cihar */
+
+/*
+ * High level functions for communication with Alcatel One Touch 501 and
+ * compatible mobile phone.
+ *
+ * This code implements functions to communicate with Alcatel phones,
+ * currently seem to work:
+ * - BE5 series (501/701)
+ * - BF5 series (715)
+ * - BH4 series (535/735)
+ * For some functions it uses normal AT mode (not implemented here, look at
+ * ../at/atgen.[ch]) for others it switches into binary mode and initialises
+ * underlaying protocol (see ../../protocol/alcatel/alcabus.[ch]) and
+ * communicates over it. Don't ask me why Alcatel uses such silly thing...
+ *
+ * Notes for future features:
+ * - max phone number length is 61 (BE5)
+ * - max name length is 50 (BE5)
+ */
+
+#include "../../gsmstate.h"
+
+#ifdef GSM_ENABLE_ALCATEL
+#ifdef GSM_ENABLE_ATGEN
+
+#include <string.h>
+#include <time.h>
+
+#include "../../gsmcomon.h"
+#include "../../misc/coding/coding.h"
+#include "../../misc/misc.h"
+#include "../../service/sms/gsmsms.h"
+#include "../pfunc.h"
+#include "alcatel.h"
+
+/* Timeout for GSM_WaitFor calls. */
+#define ALCATEL_TIMEOUT 64
+
+/* Some magic numbers for protocol follow */
+
+/* synchronisation types (for everything except begin transfer): */
+#define ALCATEL_SYNC_TYPE_CALENDAR 0x64
+#define ALCATEL_SYNC_TYPE_TODO 0x68
+#define ALCATEL_SYNC_TYPE_CONTACTS 0x6C
+
+/* synchronisation types (for begin transfer): */
+#define ALCATEL_BEGIN_SYNC_CALENDAR 0x00
+#define ALCATEL_BEGIN_SYNC_TODO 0x02
+#define ALCATEL_BEGIN_SYNC_CONTACTS 0x01
+
+/* category types */
+#define ALCATEL_LIST_TODO_CAT 0x9B
+#define ALCATEL_LIST_CONTACTS_CAT 0x96
+
+
+/* We need lot of ATGEN functions, because Alcatel is an AT device. */
+
+extern GSM_Reply_Function ALCATELReplyFunctions[];
+extern GSM_Reply_Function ATGENReplyFunctions[];
+
+extern GSM_Error ATGEN_Initialise (GSM_StateMachine *s);
+extern GSM_Error ATGEN_Terminate (GSM_StateMachine *s);
+extern GSM_Error ATGEN_GetIMEI (GSM_StateMachine *s);
+extern GSM_Error ATGEN_GetFirmware (GSM_StateMachine *s);
+extern GSM_Error ATGEN_GetModel (GSM_StateMachine *s);
+extern GSM_Error ATGEN_GetDateTime (GSM_StateMachine *s, GSM_DateTime *date_time);
+extern GSM_Error ATGEN_GetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry);
+extern GSM_Error ATGEN_GetNextMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry, bool start);
+extern GSM_Error ATGEN_SetMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry);
+extern GSM_Error ATGEN_AddMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry);
+extern GSM_Error ATGEN_DeleteMemory (GSM_StateMachine *s, GSM_MemoryEntry *entry);
+extern GSM_Error ATGEN_GetMemoryStatus (GSM_StateMachine *s, GSM_MemoryStatus *Status);
+extern GSM_Error ATGEN_GetSMSC (GSM_StateMachine *s, GSM_SMSC *smsc);
+extern GSM_Error ATGEN_SetSMSC (GSM_StateMachine *s, GSM_SMSC *smsc);
+extern GSM_Error ATGEN_GetSMSFolders (GSM_StateMachine *s, GSM_SMSFolders *folders);
+extern GSM_Error ATGEN_GetSMSStatus (GSM_StateMachine *s, GSM_SMSMemoryStatus *status);
+extern GSM_Error ATGEN_GetSMS (GSM_StateMachine *s, GSM_MultiSMSMessage *sms);
+extern GSM_Error ATGEN_GetNextSMS (GSM_StateMachine *s, GSM_MultiSMSMessage *sms, bool start);
+extern GSM_Error ATGEN_SendSavedSMS (GSM_StateMachine *s, int Folder, int Location);
+extern GSM_Error ATGEN_SendSMS (GSM_StateMachine *s, GSM_SMSMessage *sms);
+extern GSM_Error ATGEN_DeleteSMS (GSM_StateMachine *s, GSM_SMSMessage *sms);
+extern GSM_Error ATGEN_AddSMS (GSM_StateMachine *s, GSM_SMSMessage *sms);
+extern GSM_Error ATGEN_GetBatteryCharge (GSM_StateMachine *s, GSM_BatteryCharge *bat);
+extern GSM_Error ATGEN_GetSignalQuality (GSM_StateMachine *s, GSM_SignalQuality *sig);
+extern GSM_Error ATGEN_DialVoice (GSM_StateMachine *s, char *number, GSM_CallShowNumber ShowNumber);
+extern GSM_Error ATGEN_AnswerCall (GSM_StateMachine *s, int ID, bool all);
+extern GSM_Error ATGEN_CancelCall (GSM_StateMachine *s, int ID, bool all);
+extern GSM_Error ATGEN_SetDateTime (GSM_StateMachine *s, GSM_DateTime *date_time);
+extern GSM_Error ATGEN_EnterSecurityCode (GSM_StateMachine *s, GSM_SecurityCode Code);
+extern GSM_Error ATGEN_GetSecurityStatus (GSM_StateMachine *s, GSM_SecurityCodeType *Status);
+extern GSM_Error ATGEN_ResetPhoneSettings (GSM_StateMachine *s, GSM_ResetSettingsType Type);
+extern GSM_Error ATGEN_SendDTMF (GSM_StateMachine *s, char *sequence);
+extern GSM_Error ATGEN_GetSIMIMSI (GSM_StateMachine *s, char *IMSI);
+extern GSM_Error ATGEN_HandleCMSError (GSM_StateMachine *s);
+extern GSM_Error ATGEN_GetNetworkInfo (GSM_StateMachine *s, GSM_NetworkInfo *netinfo);
+extern GSM_Error ATGEN_Reset (GSM_StateMachine *s, bool hard);
+extern GSM_Error ATGEN_PressKey (GSM_StateMachine *s, GSM_KeyCode Key, bool Press);
+extern GSM_Error ATGEN_GetDisplayStatus (GSM_StateMachine *s, GSM_DisplayFeatures *features);
+extern GSM_Error ATGEN_SetAutoNetworkLogin (GSM_StateMachine *s);
+extern GSM_Error ATGEN_DeleteAllMemory (GSM_StateMachine *s, GSM_MemoryType type);
+
+extern GSM_Error ATGEN_DispatchMessage (GSM_StateMachine *s);
+extern GSM_Error ATGEN_SetIncomingCB (GSM_StateMachine *s, bool enable);
+extern GSM_Error ATGEN_SetIncomingSMS (GSM_StateMachine *s, bool enable);
+
+/**
+ * Alcatel uses some 8-bit characters in contacts, calendar etc.. This table
+ * attempts to decode it, it is probably not complete, here are just chars
+ * that I found...
+ */
+unsigned char GSM_AlcatelAlphabet[] =
+{
+/* in phone unicode description */
+ 0x80, 0x00,0x20, /* empty */
+ 0x81, 0x00,0x20, /* empty */
+ 0x82, 0x00,0x20, /* empty */
+ 0x83, 0x00,0x20, /* empty */
+
+ 0x84, 0x00,0xe7, /* c cedilla */
+ 0x85, 0x20,0x26, /* ... */
+ 0x86, 0x03,0xc0, /* pi */
+ 0x87, 0x01,0x3e, /* l caron */
+ 0x88, 0x00,0xc0, /* A grave */
+ 0x89, 0x00,0xc1, /* A acute */
+ 0x8a, 0x00,0xc2, /* A circumflex */
+ 0x8b, 0x00,0xc3, /* A tilde */
+ 0x8c, 0x00,0xc8, /* E grave */
+ 0x8d, 0x00,0xca, /* E circumflex */
+ 0x8e, 0x00,0xcb, /* E diaresis */
+ 0x8f, 0x00,0xcc, /* I grave */
+ 0x90, 0x00,0xcd, /* I acute */
+ 0x91, 0x00,0xd0, /* ETH */
+ 0x92, 0x00,0xd2, /* O grave */
+ 0x93, 0x00,0xd3, /* O acute */
+ 0x94, 0x00,0xd4, /* O circumflex */
+ 0x95, 0x00,0xd5, /* O tilde */
+ 0x96, 0x00,0xd9, /* U grave */
+ 0x97, 0x00,0xda, /* U acute */
+ 0x98, 0x00,0xe1, /* a acute */
+ 0x99, 0x00,0xe2, /* a circumflex */
+ 0x9a, 0x00,0xe3, /* a tilde */
+ 0x9b, 0x00,0xea, /* e circumflex */
+ 0x9c, 0x00,0xeb, /* e diaresis */
+ 0x9d, 0x00,0xed, /* i acute */
+ 0x9e, 0x00,0xee, /* i circumflex */
+ 0x9f, 0x00,0xef, /* i diaresis */
+ 0xa0, 0x00,0xf3, /* o acute */
+ 0xa1, 0x00,0xf4, /* o circumflex */
+ 0xa2, 0x00,0xf5, /* o tilde */
+ 0xa3, 0x00,0xfa, /* u acute */
+ 0xa4, 0x00,0xa2, /* cent */
+ 0xa5, 0x00,0x5b, /* [ */
+ 0xa6, 0x01,0x59, /* r caron */
+ 0xa7, 0x01,0x0d, /* c caron */
+ 0xa8, 0x01,0x61, /* s caron */
+ 0xa9, 0x01,0x1b, /* e caron */
+ 0xaa, 0x01,0x6f, /* u ring */
+ 0xab, 0x00,0xfd, /* y acute */
+ 0xac, 0x00,0xf0, /* eth */
+ 0xad, 0x01,0x07, /* c acute */
+ 0xae, 0x01,0x19, /* e ogonek */
+ 0xaf, 0x01,0x05, /* a ogonek */
+ 0xb0, 0x01,0x7c, /* z dot */
+ 0xb1, 0x01,0x7a, /* z acute */
+ 0xb2, 0x01,0x5b, /* s acute */
+ 0xb3, 0x01,0x44, /* n acute */
+ 0xb4, 0x01,0x42, /* l stroke */
+
+ 0xb5, 0x00,0x20, /* empty */
+
+ 0xb6, 0x01,0x48, /* n caron */
+ 0xb7, 0x01,0x65, /* t caron */
+
+ 0xb8, 0x00,0x20, /* empty */
+
+ 0xb9, 0x01,0x7e, /* z caron */
+ 0xba, 0x01,0xe7, /* g caron */
+
+ 0xbb, 0x00,0x20, /* empty */
+ 0xbc, 0x00,0x20, /* empty */
+
+ 0xbd, 0x1e,0x20, /* G macron */
+ 0xbe, 0x1e,0x21, /* g macron */
+ 0xbf, 0x01,0x5e, /* S cedilla */
+ 0xc0, 0x01,0x5f, /* s cedilla */
+ 0xc1, 0x01,0x2f, /* i ogonek */ /* FIXME: not sure with this, it look like normal i */
+ 0xc2, 0x01,0x31, /* i dotless */
+ 0xc3, 0x01,0x68, /* U tilde */
+ 0xc4, 0x01,0x50, /* O dbl acute */
+ 0xc5, 0x01,0x69, /* u tilde */
+ 0xc6, 0x01,0x51, /* o dbl acute */
+ 0xc7, 0x27,0xa9, /* => */
+ 0xc8, 0x27,0xa8, /* filled => */
+ 0xc9, 0x00,0xd7, /* x */
+ 0xca, 0x00,0x5d, /* ] */
+ 0xcb, 0x26,0x0f, /* phone */
+ 0xcc, 0x01,0x0f, /* d caron */
+
+ 0xcd, 0x00,0x20, /* empty */
+
+ 0xce, 0x00,0x7e, /* ~ */
+ 0xcf, 0x00,0x5c, /* \ */
+ 0xd0, 0x00,0x5e, /* ^ */
+
+ 0xd1, 0x00,0x20, /* empty */
+
+ 0xd2, 0x00,0x7b, /* { */
+ 0xd3, 0x00,0x7c, /* | */
+ 0xd4, 0x00,0x7d, /* } */
+
+ 0xd5, 0x00,0x20, /* empty */
+
+ 0xd6, 0x01,0x63, /* t cedilla */
+
+ 0xd7, 0x00,0x20, /* empty */
+ 0xd8, 0x00,0x20, /* empty */
+ 0xd9, 0x00,0x20, /* empty */
+ 0xda, 0x00,0x20, /* empty */
+ 0xdb, 0x00,0x20, /* empty */
+ 0xdc, 0x00,0x20, /* empty */
+ 0xdd, 0x00,0x20, /* empty */
+ 0xde, 0x00,0x20, /* empty */
+ 0xdf, 0x00,0x20, /* empty */
+ 0xe0, 0x00,0x20, /* empty */
+
+ 0xe1, 0x00,0x20, /* two candles */ /* FIXME */
+
+ 0xe2, 0x00,0x20, /* empty */
+ 0xe3, 0x00,0x20, /* empty */
+ 0xe4, 0x00,0x20, /* empty */
+
+ 0xe5, 0x01,0xce, /* a caron */
+ 0xe6, 0x01,0x01, /* a macron */
+ 0xe7, 0x01,0x13, /* e macron */
+ 0xe8, 0x01,0x2b, /* i macron */
+ 0xe9, 0x01,0x4d, /* o macron */
+ 0xea, 0x01,0x6b, /* u macron */
+ 0xeb, 0x00,0x41, /* A */
+ 0xec, 0x00,0x40, /* @ */
+ 0xed, 0x00,0x20, /* some strange char :-) */ /* FIXME */
+
+ 0xee, 0x00,0x20, /* big key stroken */ /* FIXME */
+ 0xef, 0x00,0x20, /* big key */ /* FIXME */
+
+ 0xf0, 0x00,0x20, /* empty */
+
+ 0xf1, 0x00,0x31, /* 1 */
+ 0xf2, 0x00,0x21, /* bold ! */
+ 0xf3, 0x26,0x0e, /* black phone */
+ 0xf4, 0x00,0x26, /* & */
+ 0xf5, 0x23,0x7e, /* bell */
+ 0xf6, 0x26,0x6a, /* note */
+
+ 0xf7, 0x27,0x13, /* okay inv */ /* FIXME */
+ 0xf8, 0x27,0x13, /* okay */
+
+ 0xf9, 0x00,0x20, /* empty */
+
+ 0xfa, 0x00,0x20, /* key */ /* FIXME */
+
+ 0xfb, 0x00,0x20, /* empty */
+
+ 0xfc, 0x20,0xac, /* Euro */
+ 0xfd, 0x21,0x97, /* NE arrow */
+ 0xfe, 0x21,0x98, /* SE arrow */
+
+ 0xff, 0x00,0x20, /* empty */
+
+ 0x00, 0x00,0x00
+};
+
+/* This is being called from atgen */
+GSM_Error ALCATEL_ProtocolVersionReply (GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ char *str, *str2;
+/*
+ * Reply received here looks like:
+ * 1 "AT+CPROT=?"
+ * 2 "+CPROT: 0,"V1.0",1"
+ * 3 "+CPROT: 16,"V1.1",16"
+ * 4 "OK"
+ */
+ switch (s->Phone.Data.Priv.ATGEN.ReplyState) {
+ case AT_Reply_OK:
+ str = strstr(msg.Buffer, "\"V");
+ if (str == NULL) return ERR_UNKNOWNRESPONSE;
+ str += 2;
+ while((str2 = strstr(str, "\"V")) != NULL) str = str2 + 2;
+ if (strncmp(str, "1.0", 3) == 0) {
+ s->Phone.Data.Priv.ALCATEL.ProtocolVersion = V_1_0;
+ } else if (strncmp(str, "1.1", 3) == 0) {
+ s->Phone.Data.Priv.ALCATEL.ProtocolVersion = V_1_1;
+ } else {
+ smprintf(s, "Unknown protocol version. Please send debug log and phone info to author.\n");
+ return ERR_NOTIMPLEMENTED;
+ }
+ return ERR_NONE;
+ case AT_Reply_Error:
+ case AT_Reply_CMSError:
+ return ATGEN_HandleCMSError(s);
+ default:
+ return ERR_UNKNOWNRESPONSE;
+ }
+}
+
+static GSM_Error ALCATEL_SetBinaryMode(GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+
+ if (Priv->Mode == ModeBinary) return ERR_NONE;
+
+ dbgprintf ("Changing to binary mode\n");
+
+ error=GSM_WaitFor (s, "AT+IFC=2,2\r", 11, 0x02, 4, ID_SetFlowControl);
+ if (error != ERR_NONE) return error;
+
+ error=GSM_WaitFor (s, "AT+CPROT=?\r", 11, 0x02, 4, ID_AlcatelProtocol);
+ if (error != ERR_NONE) return error;
+
+ if (Priv->ProtocolVersion == V_1_0) {
+ error=GSM_WaitFor (s, "AT+CPROT=16,\"V1.0\",16\r", 22, 0x00, 4, ID_AlcatelConnect);
+ } else {
+ error=GSM_WaitFor (s, "AT+CPROT=16,\"V1.1\",16\r", 22, 0x00, 4, ID_AlcatelConnect);
+ }
+
+ if (error == ERR_TIMEOUT && s->Speed != 19200) {
+ smprintf(s, "HINT: Try changing speed to 19200, it is sometimes needed for Alcatel binary mode.\n");
+ }
+
+ if (error != ERR_NONE) return error;
+
+ dbgprintf ("Changing protocol to Alcabus\n");
+
+ s->Protocol.Functions = &ALCABUSProtocol;
+ error = s->Protocol.Functions->Initialise(s);
+ if (error != ERR_NONE) {
+ s->Protocol.Functions = &ATProtocol;
+ return error;
+ }
+ s->Phone.Functions->ReplyFunctions = ALCATELReplyFunctions;
+ Priv->Mode = ModeBinary;
+ Priv->BinaryItem = 0;
+ Priv->BinaryType = 0;
+ Priv->BinaryState = StateAttached;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GoToBinaryState(GSM_StateMachine *s, GSM_Alcatel_BinaryState state, GSM_Alcatel_BinaryType type, int item) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char attach_buffer[] = {0x00, 0x00, 0x7C ,0x20};
+ unsigned char detach_buffer[] = {0x00, 0x01, 0x7C ,0x00};
+ unsigned char start_buffer[] =
+ {0x00, 0x04, 0x7C, 0x80, /* 4 byte database id follows */
+ 0x12, 0x34, 0x56, 0x78};
+ unsigned char end_buffer[] =
+ {0x00, 0x04, 0x7C, 0x82,
+ 0x00, /* type */
+ 0x00, 0x00, 0x00, 0x00}; /* TimeStamp */
+ unsigned char close_buffer[] =
+ {0x00, 0x04,
+ 0x00, /*type */
+ 0x23, 0x01};
+ unsigned char select1_buffer[] =
+ {0x00, 0x00,
+ 0x00, /*type */
+ 0x20};
+ unsigned char select2_buffer[] =
+ {0x00, 0x04,
+ 0x00, /*type */
+ 0x22, 0x01, 0x00};
+ unsigned char begin_buffer[] =
+ {0x00, 0x04, 0x7C, 0x81,
+ 0x00, /*type */
+ 0x00, 0x85, 0x00};
+ unsigned char commit_buffer[] =
+ {0x00, 0x04,
+ 0x00, /*type */
+ 0x20, 0x01};
+
+ smprintf(s, "Alcatel state switcher: %d -> %d, %d -> %d, %d -> %d\n", Priv->BinaryState, state, Priv->BinaryType, type, Priv->BinaryItem, item);
+ error = ALCATEL_SetBinaryMode(s);
+ if (error != ERR_NONE) return error;
+
+ /* Do we need to do anything? */
+ if ((state == Priv->BinaryState) && (type == Priv->BinaryType) && (item == Priv->BinaryItem)) return ERR_NONE;
+
+ /* We're editing, but the next state is not the same. so commit editing */
+ if (Priv->BinaryState == StateEdit) {
+ /* Something has changed, we will have to reread fields! */
+ Priv->CurrentFieldsItem = -1;
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ commit_buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ commit_buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ commit_buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+ dbgprintf ("Commiting edited record\n");
+ error=GSM_WaitFor (s, commit_buffer, 5, 0x02, ALCATEL_TIMEOUT, ID_AlcatelCommit);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelCommit2);
+ if (error != ERR_NONE) return error;
+ Priv->BinaryState = StateSession;
+ Priv->BinaryItem = 0;
+ }
+
+ /* Do we want to edit something of same type? */
+ if ((state == StateEdit) && (type == Priv->BinaryType)) {
+ /* Edit state doesn't need any switching, it is needed only for
+ * indication that e have to commit record before we switch to other
+ * mode.
+ */
+ Priv->BinaryState = StateEdit;
+ Priv->BinaryItem = item;
+ return ERR_NONE;
+ }
+
+ /* Now we can be only in Attached or Session state, so if states and types matches, just keep them as they are */
+ if ((state == Priv->BinaryState) && (type == Priv->BinaryType)) {
+ return ERR_NONE;
+ }
+
+ /* Do we need to close session? */
+ if (Priv->BinaryState == StateSession) {
+ dbgprintf ("Ending session\n");
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ end_buffer[4] = ALCATEL_BEGIN_SYNC_CALENDAR;
+ break;
+ case TypeContacts:
+ end_buffer[4] = ALCATEL_BEGIN_SYNC_CONTACTS;
+ break;
+ case TypeToDo:
+ end_buffer[4] = ALCATEL_BEGIN_SYNC_TODO;
+ break;
+ }
+ error=GSM_WaitFor (s, end_buffer, 9, 0x02, ALCATEL_TIMEOUT, ID_AlcatelEnd);
+ if (error != ERR_NONE) return error;
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ close_buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ close_buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ close_buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+ dbgprintf ("Closing session\n");
+ error=GSM_WaitFor (s, close_buffer, 5, 0x02, ALCATEL_TIMEOUT, ID_AlcatelClose);
+ if (error != ERR_NONE) return error;
+
+ dbgprintf ("Detaching binary mode\n");
+ GSM_WaitFor (s, detach_buffer, 4, 0x02, ALCATEL_TIMEOUT, ID_AlcatelDetach);
+
+ Priv->BinaryState = StateAttached;
+ Priv->BinaryType = 0;
+ }
+
+ /* Do we need to open session? */
+ if (state == StateSession || state == StateEdit) {
+ dbgprintf ("Starting session for %s\n",
+ (type == TypeCalendar ? "Calendar" :
+ (type == TypeToDo ? "Todo" :
+ (type == TypeContacts ? "Contacts" :
+ "Unknown!"))));
+ /* Fill up buffers */
+ switch (type) {
+ case TypeCalendar:
+ select1_buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ select2_buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ begin_buffer[4] = ALCATEL_BEGIN_SYNC_CALENDAR;
+ break;
+ case TypeContacts:
+ select1_buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ select2_buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ begin_buffer[4] = ALCATEL_BEGIN_SYNC_CONTACTS;
+ break;
+ case TypeToDo:
+ select1_buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ select2_buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ begin_buffer[4] = ALCATEL_BEGIN_SYNC_TODO;
+ break;
+ }
+ dbgprintf ("Attaching in binary mode\n");
+
+ /* Communicate */
+ error=GSM_WaitFor (s, attach_buffer, 4, 0x02, ALCATEL_TIMEOUT, ID_AlcatelAttach);
+ if (error != ERR_NONE) return error;
+
+ smprintf(s,"Start session\n");
+ error=GSM_WaitFor (s, start_buffer, 8, 0x02, ALCATEL_TIMEOUT, ID_AlcatelStart);
+ if (error != ERR_NONE) return error;
+
+ smprintf(s,"Select type\n");
+ error=GSM_WaitFor (s, select1_buffer, 4, 0x02, ALCATEL_TIMEOUT, ID_AlcatelSelect1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, select2_buffer, 6, 0x02, ALCATEL_TIMEOUT, ID_AlcatelSelect2);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelSelect3);
+ if (error != ERR_NONE) return error;
+
+ smprintf(s,"Begin transfer\n");
+ error=GSM_WaitFor (s, begin_buffer, 8, 0x02, ALCATEL_TIMEOUT, ID_AlcatelBegin1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelBegin2);
+ if (error != ERR_NONE) return error;
+
+ Priv->BinaryState = StateSession;
+ Priv->BinaryType = type;
+ /* Do we want to edit something of same type? */
+ if ((state == StateEdit) && (type == Priv->BinaryType)) {
+ Priv->BinaryState = StateEdit;
+ Priv->BinaryItem = item;
+ return ERR_NONE;
+ }
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_SetATMode(GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+
+ if (Priv->Mode == ModeAT) return ERR_NONE;
+
+ error = ALCATEL_GoToBinaryState(s, StateAttached, 0, 0);
+ if (error != ERR_NONE) return error;
+
+ error = s->Protocol.Functions->Terminate(s);
+ if (error != ERR_NONE) return error;
+
+ dbgprintf ("Changing protocol to AT\n");
+ s->Protocol.Functions = &ATProtocol;
+ s->Phone.Functions->ReplyFunctions = ATGENReplyFunctions;
+ Priv->Mode = ModeAT;
+
+ my_sleep(100);
+
+ /* In case we don't send AT command short after closing binary mode,
+ * phone takes VERY long to react next time. The error code in
+ * intetionally ignored.
+ */
+ GSM_WaitFor (s, "AT\r", 3, 0x00, 0, ID_IncomingFrame);
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_Initialise(GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+
+ Priv->Mode = ModeAT;
+
+ Priv->CalendarItems = NULL;
+ Priv->ContactsItems = NULL;
+ Priv->ToDoItems = NULL;
+ Priv->CalendarItemsCount = 0;
+ Priv->ToDoItemsCount = 0;
+ Priv->ContactsItemsCount = 0;
+ Priv->CurrentFields[0] = 0;
+ Priv->CurrentFieldsCount = 0;
+ Priv->CurrentFieldsItem = 0;
+ Priv->CurrentFieldsType = 0;
+ Priv->ProtocolVersion = V_1_0;
+ Priv->CurrentFieldsItem = -1;
+
+ Priv->CurrentCategoriesCount = 0;
+ Priv->CurrentCategoriesType = 0;
+
+ s->Protocol.Functions = &ATProtocol;
+ s->Phone.Functions->ReplyFunctions = ATGENReplyFunctions;
+
+ if (ATGEN_Initialise(s) != ERR_NONE || GSM_WaitFor (s, "AT\r", 3, 0x00, 2, ID_IncomingFrame) != ERR_NONE) {
+ smprintf(s,"AT initialisation failed, trying to stop binary mode...\n");
+ s->Protocol.Functions = &ALCABUSProtocol;
+ error = s->Protocol.Functions->Terminate(s);
+ s->Protocol.Functions = &ATProtocol;
+
+ error = ATGEN_Initialise(s);
+ if (error != ERR_NONE) return error;
+ }
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_Terminate(GSM_StateMachine *s)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ free(Priv->CalendarItems);
+ free(Priv->ContactsItems);
+ free(Priv->ToDoItems);
+ error = ALCATEL_SetATMode(s);
+ return ATGEN_Terminate(s);
+}
+
+/* finds whether id is set in the phone */
+static GSM_Error ALCATEL_IsIdAvailable(GSM_StateMachine *s, int id) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ if (id > ALCATEL_MAX_LOCATION) return ERR_INVALIDLOCATION;
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ Priv->CurrentList = &(Priv->CalendarItems);
+ Priv->CurrentCount = &(Priv->CalendarItemsCount);
+ break;
+ case TypeContacts:
+ Priv->CurrentList = &(Priv->ContactsItems);
+ Priv->CurrentCount = &(Priv->ContactsItemsCount);
+ break;
+ case TypeToDo:
+ Priv->CurrentList = &(Priv->ToDoItems);
+ Priv->CurrentCount = &(Priv->ToDoItemsCount);
+ break;
+ }
+
+ for (i=0; i<*Priv->CurrentCount; i++) {
+ if ((*Priv->CurrentList)[i] == id) return ERR_NONE;
+ }
+
+ return ERR_EMPTY;
+}
+
+/* finds next id that is available in the phone */
+static GSM_Error ALCATEL_GetNextId(GSM_StateMachine *s, int *id) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i = 0;
+ int next = ALCATEL_MAX_LOCATION;
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ Priv->CurrentList = &(Priv->CalendarItems);
+ Priv->CurrentCount = &(Priv->CalendarItemsCount);
+ break;
+ case TypeContacts:
+ Priv->CurrentList = &(Priv->ContactsItems);
+ Priv->CurrentCount = &(Priv->ContactsItemsCount);
+ break;
+ case TypeToDo:
+ Priv->CurrentList = &(Priv->ToDoItems);
+ Priv->CurrentCount = &(Priv->ToDoItemsCount);
+ break;
+ }
+
+ for (i=0; i<*Priv->CurrentCount; i++) {
+ if (((*Priv->CurrentList)[i] > *id) && ((*Priv->CurrentList)[i] < next )) {
+ next = (*Priv->CurrentList)[i];
+ }
+ }
+ if (next == ALCATEL_MAX_LOCATION) {
+ return ERR_EMPTY;
+ } else {
+ *id = next;
+ return ERR_NONE;
+ }
+}
+
+static GSM_Error ALCATEL_ReplyGetIds(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int count,i,pos;
+
+ count = msg.Buffer[10];
+ *Priv->CurrentCount += count;
+
+ *Priv->CurrentList = (int *)realloc(*Priv->CurrentList, (*Priv->CurrentCount + 1)* sizeof(int));
+ if (*Priv->CurrentList == NULL) return ERR_MOREMEMORY;
+
+ for (i = 0; i < count; i++) {
+ pos = 11 + (4 * i);
+ (*Priv->CurrentList)[*Priv->CurrentCount - count + i] = msg.Buffer[pos + 3] +
+ (msg.Buffer[pos + 2] << 8) +
+ (msg.Buffer[pos + 1] << 16) +
+ (msg.Buffer[pos] << 24);
+ }
+ (*Priv->CurrentList)[*Priv->CurrentCount] = 0;
+
+ /* If last byte is 0, then we transmitted all items */
+ Priv->TransferCompleted = msg.Buffer[4 + msg.Buffer[4]] == 0;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetAvailableIds(GSM_StateMachine *s, bool refresh)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ int i;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00, /*type */
+ 0x2F, 0x01};
+
+ if (Priv->BinaryState != StateSession) return ERR_UNKNOWN;
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ Priv->CurrentList = &(Priv->CalendarItems);
+ Priv->CurrentCount = &(Priv->CalendarItemsCount);
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ Priv->CurrentList = &(Priv->ContactsItems);
+ Priv->CurrentCount = &(Priv->ContactsItemsCount);
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ Priv->CurrentList = &(Priv->ToDoItems);
+ Priv->CurrentCount = &(Priv->ToDoItemsCount);
+ break;
+ }
+
+ if (*Priv->CurrentList != NULL) {
+ if (!refresh) return ERR_NONE;
+ free(*Priv->CurrentList);
+ *Priv->CurrentList = NULL;
+ }
+ smprintf(s,"Reading items list\n");
+
+ *Priv->CurrentCount = 0;
+ Priv->TransferCompleted = false;
+
+ error=GSM_WaitFor (s, buffer, 5, 0x02, ALCATEL_TIMEOUT, ID_AlcatelGetIds1);
+ if (error != ERR_NONE) return error;
+
+ while (!Priv->TransferCompleted) {
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelGetIds2);
+ if (error != ERR_NONE) return error;
+ }
+
+ i = 0;
+ smprintf(s,"Received %d ids: ", *Priv->CurrentCount);
+ for (i=0; i < *Priv->CurrentCount; i++) {
+ smprintf(s,"%x ", (*Priv->CurrentList)[i]);
+ }
+ smprintf(s,"\n");
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_ReplyGetFields(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ if (msg.Buffer[14] > GSM_PHONEBOOK_ENTRIES) {
+ smprintf(s, "WARNING: Field list truncated, you should increase GSM_PHONEBOOK_ENTRIES to at least %d\n", msg.Buffer[14]);
+ Priv->CurrentFieldsCount = GSM_PHONEBOOK_ENTRIES;
+ } else {
+ Priv->CurrentFieldsCount = msg.Buffer[14];
+ }
+
+ Priv->CurrentFields[Priv->CurrentFieldsCount] = 0;
+
+ for (i = 0; i < Priv->CurrentFieldsCount; i++) {
+ Priv->CurrentFields[i] = msg.Buffer[15 + i];
+ }
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetFields(GSM_StateMachine *s, int id) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ int i;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x30, 0x01,
+ 0x00, 0x00, 0x00, 0x00}; /* item */
+
+ if (Priv->BinaryState != StateSession) return ERR_UNKNOWN;
+ if ((Priv->CurrentFieldsItem == id) && (Priv->CurrentFieldsType == Priv->BinaryType)) return ERR_NONE;
+
+ smprintf(s,"Reading item fields (%d)\n", id);
+
+ buffer[5] = (id >> 24);
+ buffer[6] = ((id >> 16) & 0xff);
+ buffer[7] = ((id >> 8) & 0xff);
+ buffer[8] = (id & 0xff);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+
+ Priv->CurrentFieldsItem = id;
+ Priv->CurrentFieldsType = Priv->BinaryType;
+
+ error=GSM_WaitFor (s, buffer, 9, 0x02, ALCATEL_TIMEOUT, ID_AlcatelGetFields1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelGetFields2);
+ if (error != ERR_NONE) return error;
+
+ i = 0;
+ smprintf(s,"Received %d fields: ", Priv->CurrentFieldsCount);
+ for (i=0; i < Priv->CurrentFieldsCount; i++) {
+ smprintf(s,"%x ", Priv->CurrentFields[i]);
+ }
+ smprintf(s,"\n");
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_ReplyGetFieldValue(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ unsigned char *buffer = &(msg.Buffer[16]);
+
+ if (buffer[1] == 0x05 && buffer[2] == 0x67) {
+ /* date */
+ Priv->ReturnType = Alcatel_date;
+ Priv->ReturnDateTime.Day = buffer[4];
+ Priv->ReturnDateTime.Month = buffer[5];
+ Priv->ReturnDateTime.Year = buffer[7] + (buffer[6] << 8);
+ Priv->ReturnDateTime.Timezone = 0; /* FIXME: how to acquire this? */
+
+ Priv->ReturnDateTime.Hour = 0;
+ Priv->ReturnDateTime.Minute = 0;
+ Priv->ReturnDateTime.Second = 0;
+ } else if (buffer[1] == 0x06 && buffer[2] == 0x68) {
+ /* time */
+ Priv->ReturnType = Alcatel_time;
+ Priv->ReturnDateTime.Hour = buffer[4];
+ Priv->ReturnDateTime.Minute = buffer[5];
+ Priv->ReturnDateTime.Second = buffer[6];
+
+ Priv->ReturnDateTime.Day = 0;
+ Priv->ReturnDateTime.Month = 0;
+ Priv->ReturnDateTime.Year = 0;
+ Priv->ReturnDateTime.Timezone = 0;
+ } else if (buffer[1] == 0x08 && buffer[2] == 0x3C) {
+ /* string */
+ Priv->ReturnType = Alcatel_string;
+ if (GSM_PHONEBOOK_TEXT_LENGTH < buffer[3])
+ smprintf(s, "WARNING: Text truncated, you should increase GSM_PHONEBOOK_TEXT_LENGTH to at least %d\n", buffer[3] + 1);
+ if (Priv->ProtocolVersion == V_1_0) {
+ DecodeDefault( Priv->ReturnString, buffer + 4, MIN(GSM_PHONEBOOK_TEXT_LENGTH, buffer[3]), false, GSM_AlcatelAlphabet);
+ } else if(Priv->ProtocolVersion == V_1_1 && (buffer[4] & 0x80)) {
+ memcpy(Priv->ReturnString, buffer + 5, buffer[3]);
+ Priv->ReturnString[buffer[3] + 1] = 0;
+ Priv->ReturnString[buffer[3] + 2] = 0;
+ ReverseUnicodeString(Priv->ReturnString);
+ } else {
+ DecodeDefault( Priv->ReturnString, buffer + 4, MIN(GSM_PHONEBOOK_TEXT_LENGTH, buffer[3]), false, GSM_AlcatelAlphabet);
+ }
+ } else if (buffer[1] == 0x07 && buffer[2] == 0x3C) {
+ /* phone */
+ Priv->ReturnType = Alcatel_phone;
+ if (GSM_PHONEBOOK_TEXT_LENGTH < buffer[3])
+ smprintf(s, "WARNING: Text truncated, you should increase GSM_PHONEBOOK_TEXT_LENGTH to at least %d\n", buffer[3] + 1);
+ if (Priv->ProtocolVersion == V_1_0) {
+ DecodeDefault( Priv->ReturnString, buffer + 4, MIN(GSM_PHONEBOOK_TEXT_LENGTH, buffer[3]), false, GSM_AlcatelAlphabet);
+ } else if(Priv->ProtocolVersion == V_1_1 && (buffer[4] & 0x80)) {
+ memcpy(Priv->ReturnString, buffer + 5, buffer[3]);
+ Priv->ReturnString[buffer[3] + 1] = 0;
+ Priv->ReturnString[buffer[3] + 2] = 0;
+ ReverseUnicodeString(Priv->ReturnString);
+ } else {
+ DecodeDefault( Priv->ReturnString, buffer + 4, MIN(GSM_PHONEBOOK_TEXT_LENGTH, buffer[3]), false, GSM_AlcatelAlphabet);
+ }
+ } else if (buffer[1] == 0x03 && buffer[2] == 0x3B) {
+ /* boolean */
+ Priv->ReturnType = Alcatel_bool;
+ Priv->ReturnInt = buffer[3];
+ } else if (buffer[1] == 0x02 && buffer[2] == 0x3A) {
+ /* integer */
+ Priv->ReturnType = Alcatel_int;
+ Priv->ReturnInt = buffer[6] + (buffer[5] << 8) + (buffer[4] << 16) + (buffer[3] << 24);
+ } else if (buffer[1] == 0x04 && buffer[2] == 0x38) {
+ /* enumeration */
+ Priv->ReturnType = Alcatel_enum;
+ Priv->ReturnInt = buffer[3];
+ } else if (buffer[1] == 0x00 && buffer[2] == 0x38) {
+ /* byte */
+ Priv->ReturnType = Alcatel_byte;
+ Priv->ReturnInt = buffer[3];
+ } else {
+ smprintf(s, "WARNING: Uknown data type received (%02X,%02X)\n", buffer[1], buffer[2]);
+ return ERR_UNKNOWNRESPONSE;
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetFieldValue(GSM_StateMachine *s, int id, int field)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x1f, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* here follows 4byte id */
+ 0x00}; /* field */
+
+ smprintf(s,"Reading item value (%08x.%02x)\n", id, field);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+
+ buffer[5] = (id >> 24);
+ buffer[6] = ((id >> 16) & 0xff);
+ buffer[7] = ((id >> 8) & 0xff);
+ buffer[8] = (id & 0xff);
+ buffer[9] = (field & 0xff);
+
+ error=GSM_WaitFor (s, buffer, 10, 0x02, ALCATEL_TIMEOUT, ID_AlcatelGetFieldValue1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelGetFieldValue2);
+ if (error != ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_ReplyGetCategories(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ /* Did we get any category? */
+ if (msg.Buffer[4] == 6) {
+ Priv->CurrentCategoriesCount = 0;
+ return ERR_NONE;
+ }
+ if (msg.Buffer[12] > ALCATEL_MAX_CATEGORIES) {
+ smprintf(s, "WARNING: Field list truncated, you should increase ALCATEL_MAX_CATEGORIES to at least %d\n", msg.Buffer[12]);
+ Priv->CurrentCategoriesCount = ALCATEL_MAX_CATEGORIES;
+ } else {
+ Priv->CurrentCategoriesCount = msg.Buffer[12];
+ }
+
+ for (i = 0; i < Priv->CurrentCategoriesCount; i++) {
+ Priv->CurrentCategories[i] = msg.Buffer[13 + i];
+ Priv->CurrentCategoriesCache[i][0] = '\000';
+ Priv->CurrentCategoriesCache[i][1] = '\000';
+ }
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetAvailableCategoryIds(GSM_StateMachine *s) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ int i;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00 /*type */,
+ 0x0b,
+ 0x00 /* list */};
+
+ if (Priv->BinaryState != StateSession) return ERR_UNKNOWN;
+ if (Priv->CurrentCategoriesType == Priv->BinaryType) return ERR_NONE;
+ switch (Priv->BinaryType) {
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ buffer[4] = ALCATEL_LIST_CONTACTS_CAT;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ buffer[4] = ALCATEL_LIST_TODO_CAT;
+ break;
+ default:
+ return ERR_NOTSUPPORTED;
+ }
+
+ Priv->CurrentCategoriesType = Priv->BinaryType;
+
+ smprintf(s,"Reading category list\n");
+
+ error=GSM_WaitFor (s, buffer, 5, 0x02, ALCATEL_TIMEOUT, ID_AlcatelGetCategories1);
+ if (error != ERR_NONE) return error;
+
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelGetCategories2);
+ if (error != ERR_NONE) return error;
+
+ i = 0;
+ smprintf(s,"Received %d ids: ", Priv->CurrentCategoriesCount);
+ for (i=0; i < Priv->CurrentCategoriesCount; i++) {
+ smprintf(s,"%i ", Priv->CurrentCategories[i]);
+ }
+ smprintf(s,"\n");
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_IsCategoryIdAvailable(GSM_StateMachine *s, int id) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i = 0;
+
+ if (Priv->CurrentCategoriesType != Priv->BinaryType) return ERR_UNKNOWN;
+
+ for (i = 0; i< Priv->CurrentCategoriesCount; i++) {
+ if (Priv->CurrentCategories[i] == id) return ERR_NONE;
+ }
+ return ERR_EMPTY;
+}
+
+static GSM_Error ALCATEL_ReplyAddCategoryText(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ Priv->ReturnInt = msg.Buffer[12];
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_AddCategoryText(GSM_StateMachine *s, const unsigned char *str) {
+ unsigned char buffer[200] = {0x00, 0x04, 0x00 /*type*/, 0x0d, 0x00 /*list*/, 0x0b };
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ int len;
+
+ smprintf(s,"Creating category\n");
+ len = UnicodeLength(str);
+ EncodeDefault(buffer + 8, str, &len, true, GSM_AlcatelAlphabet);
+ buffer[6] = len + 1;
+ buffer[7] = len;
+
+ switch (Priv->BinaryType) {
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ buffer[4] = ALCATEL_LIST_CONTACTS_CAT;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ buffer[4] = ALCATEL_LIST_TODO_CAT;
+ break;
+ default:
+ return ERR_NOTSUPPORTED;
+ }
+
+ error=GSM_WaitFor (s, buffer, 8 + len, 0x02, ALCATEL_TIMEOUT, ID_AlcatelAddCategoryText1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelAddCategoryText2);
+ if (error != ERR_NONE) return error;
+
+ /* Refresh list */
+ Priv->CurrentCategoriesType = 0;
+ return ALCATEL_GetAvailableCategoryIds(s);
+}
+
+static GSM_Error ALCATEL_ReplyGetCategoryText(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int len;
+
+ len = msg.Buffer[14];
+ if (len > GSM_MAX_CATEGORY_NAME_LENGTH) {
+ smprintf(s, "WARNING: Category name truncated, you should increase GSM_MAX_CATEGORY_NAME_LENGTH to at least %d\n", len);
+ }
+ if (Priv->ProtocolVersion == V_1_0) {
+ DecodeDefault( Priv->ReturnString, msg.Buffer + 15, MIN(GSM_MAX_CATEGORY_NAME_LENGTH, len), false, GSM_AlcatelAlphabet);
+ } else if(Priv->ProtocolVersion == V_1_1 && (msg.Buffer[15] & 0x80)) {
+ memcpy(Priv->ReturnString, msg.Buffer + 16, len);
+ Priv->ReturnString[len + 1] = 0;
+ Priv->ReturnString[len + 2] = 0;
+ ReverseUnicodeString(Priv->ReturnString);
+ } else {
+ DecodeDefault( Priv->ReturnString, msg.Buffer + 15, MIN(GSM_MAX_CATEGORY_NAME_LENGTH, len), false, GSM_AlcatelAlphabet);
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetCategoryText(GSM_StateMachine *s, int id) {
+ unsigned char buffer[] = {0x00, 0x04, 0x00 /*type*/, 0x0c, 0x00 /*list*/, 0x0A, 0x01, 0x00 /*item*/ };
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+
+ if (Priv->CurrentCategoriesCache[id][0] != '\000' || Priv->CurrentCategoriesCache[id][1] != '\000') {
+ CopyUnicodeString(Priv->ReturnString, Priv->CurrentCategoriesCache[id]);
+ return ERR_NONE;
+ }
+
+ smprintf(s,"Reading category %d\n", id);
+
+ switch (Priv->BinaryType) {
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ buffer[4] = ALCATEL_LIST_CONTACTS_CAT;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ buffer[4] = ALCATEL_LIST_TODO_CAT;
+ break;
+ default:
+ return ERR_NOTSUPPORTED;
+ }
+
+ buffer[7] = (id & 0xff);
+
+ error=GSM_WaitFor (s, buffer, 8, 0x02, ALCATEL_TIMEOUT, ID_AlcatelGetCategoryText1);
+ if (error != ERR_NONE) return error;
+ error=GSM_WaitFor (s, 0, 0, 0x00, ALCATEL_TIMEOUT, ID_AlcatelGetCategoryText2);
+ if (error != ERR_NONE) return error;
+
+ CopyUnicodeString(Priv->CurrentCategoriesCache[id], Priv->ReturnString);
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_DeleteField(GSM_StateMachine *s, int id, int field) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x26, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* here follows 4byte id */
+ 0x65, 0x01,
+ 0x00, /* field */
+ 0x01};
+
+ smprintf(s,"Deleting field (%08x.%02x)\n", id, field);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+
+ buffer[5] = (id >> 24);
+ buffer[6] = ((id >> 16) & 0xff);
+ buffer[7] = ((id >> 8) & 0xff);
+ buffer[8] = (id & 0xff);
+ buffer[11] = (field & 0xff);
+
+ error=GSM_WaitFor (s, buffer, 13, 0x02, ALCATEL_TIMEOUT, ID_AlcatelDeleteField);
+ if (error != ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_DeleteItem(GSM_StateMachine *s, int id) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char buffer[] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x27, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* here follows 4byte id */
+ 0x42};
+
+ smprintf(s,"Deleting item (%08x)\n", id);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+
+ buffer[5] = (id >> 24);
+ buffer[6] = ((id >> 16) & 0xff);
+ buffer[7] = ((id >> 8) & 0xff);
+ buffer[8] = (id & 0xff);
+
+ error=GSM_WaitFor (s, buffer, 10, 0x02, ALCATEL_TIMEOUT, ID_AlcatelDeleteItem1);
+ if (error != ERR_NONE) return error;
+
+ error=GSM_WaitFor (s, 0, 0, 0x0, ALCATEL_TIMEOUT, ID_AlcatelDeleteItem2);
+ if (error != ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_ReplyDeleteItem(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ if (msg.Buffer[8] != 0x25) return ERR_UNKNOWNRESPONSE;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_BuildWriteBuffer(unsigned char * buffer, GSM_Alcatel_FieldType type, int field, void *data) {
+ int len;
+
+ buffer[1] = field & 0xff;
+
+ switch(type) {
+ case Alcatel_date:
+ if (!CheckDate((GSM_DateTime *)data)) return ERR_INVALIDDATETIME;
+
+ buffer[3] = 0x05;
+ buffer[4] = 0x67;
+
+ buffer[0] = 0x09;
+ buffer[5] = 0x04;
+ buffer[6] = ((GSM_DateTime *)data)->Day & 0xff;
+ buffer[7] = ((GSM_DateTime *)data)->Month & 0xff;
+ buffer[8] = ((GSM_DateTime *)data)->Year >> 8;
+ buffer[9] = ((GSM_DateTime *)data)->Year & 0xff;
+ buffer[10] = 0x00;
+ break;
+ case Alcatel_time:
+ if (!CheckTime((GSM_DateTime *)data)) return ERR_INVALIDDATETIME;
+
+ buffer[3] = 0x06;
+ buffer[4] = 0x68;
+
+ buffer[0] = 0x08;
+ buffer[5] = 0x03;
+ buffer[6] = ((GSM_DateTime *)data)->Hour & 0xff;
+ buffer[7] = ((GSM_DateTime *)data)->Minute & 0xff;
+ buffer[8] = ((GSM_DateTime *)data)->Second & 0xff;
+ buffer[9] = 0x00;
+ break;
+ case Alcatel_string:
+ buffer[3] = 0x08;
+ buffer[4] = 0x3c;
+
+ len = MIN(UnicodeLength((char *)data),62);
+ EncodeDefault(buffer + 6, (char *)data, &len, true, GSM_AlcatelAlphabet);
+ buffer[5] = len;
+ buffer[0] = 5 + len;
+ buffer[6 + len] = 0x00;
+ break;
+ case Alcatel_phone:
+ buffer[3] = 0x07;
+ buffer[4] = 0x3c;
+
+ len = MIN(UnicodeLength((char *)data),50);
+ EncodeDefault(buffer + 6, (char *)data, &len, true, GSM_AlcatelAlphabet);
+ buffer[5] = len;
+ buffer[0] = 5 + len;
+ buffer[6 + len] = 0x00;
+ break;
+ case Alcatel_enum:
+ buffer[3] = 0x04;
+ buffer[4] = 0x38;
+
+ buffer[0] = 0x05;
+ buffer[5] = *(int *)data & 0xff;
+ buffer[6] = 0x00;
+ break;
+ case Alcatel_bool:
+ buffer[3] = 0x03;
+ buffer[4] = 0x3b;
+
+ buffer[0] = 0x05;
+ buffer[5] = *(int *)data & 0xff;
+ buffer[6] = 0x00;
+ break;
+ case Alcatel_int:
+ buffer[3] = 0x02;
+ buffer[4] = 0x3a;
+
+ buffer[0] = 0x08;
+ buffer[5] = *(unsigned int *)data >> 24;
+ buffer[6] = (*(unsigned int *)data >> 16) & 0xff;
+ buffer[7] = (*(unsigned int *)data >> 8) & 0xff;
+ buffer[8] = *(unsigned int *)data & 0xff;
+ buffer[9] = 0x00;
+ break;
+ case Alcatel_byte:
+ buffer[3] = 0x00;
+ buffer[4] = 0x38;
+
+ buffer[0] = 0x05;
+ buffer[5] = *(int *)data & 0xff;
+ buffer[6] = 0x00;
+ break;
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_CreateField(GSM_StateMachine *s, GSM_Alcatel_FieldType type, int field, void *data) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char buffer[200] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x25, 0x01, 0x65,
+ 0x00, /* length of remaining part */
+ 0x00, /* field */
+ 0x37}; /* data follows here */
+
+ smprintf(s,"Creating field (%02x)\n", field);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+ error = ALCATEL_BuildWriteBuffer(buffer + 6, type, field, data);
+ if (error != ERR_NONE) return error;
+
+ error = GSM_WaitFor (s, buffer, 8 + buffer[6], 0x02, ALCATEL_TIMEOUT, ID_AlcatelCreateField);
+ if (error != ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_UpdateField(GSM_StateMachine *s, GSM_Alcatel_FieldType type, int id, int field, void *data) {
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+ unsigned char buffer[200] =
+ {0x00, 0x04,
+ 0x00, /* type */
+ 0x26, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* id */
+ 0x65,
+ 0x00, /* length of remaining part */
+ 0x00, /* field */
+ 0x37}; /* data follows here */
+
+ smprintf(s,"Updating field (%08x.%02x)\n", id, field);
+
+ buffer[5] = (id >> 24);
+ buffer[6] = ((id >> 16) & 0xff);
+ buffer[7] = ((id >> 8) & 0xff);
+ buffer[8] = (id & 0xff);
+
+ switch (Priv->BinaryType) {
+ case TypeCalendar:
+ buffer[2] = ALCATEL_SYNC_TYPE_CALENDAR;
+ break;
+ case TypeContacts:
+ buffer[2] = ALCATEL_SYNC_TYPE_CONTACTS;
+ break;
+ case TypeToDo:
+ buffer[2] = ALCATEL_SYNC_TYPE_TODO;
+ break;
+ }
+ error = ALCATEL_BuildWriteBuffer(buffer + 10, type, field, data);
+ if (error != ERR_NONE) return error;
+
+ error = GSM_WaitFor (s, buffer, 12 + buffer[10], 0x02, ALCATEL_TIMEOUT, ID_AlcatelUpdateField);
+ if (error != ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetManufacturer(GSM_StateMachine *s)
+{
+ strcpy(s->Phone.Data.Manufacturer, "Alcatel");
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetIMEI (GSM_StateMachine *s)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetIMEI(s);
+}
+
+static GSM_Error ALCATEL_GetFirmware(GSM_StateMachine *s)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetFirmware(s);
+}
+
+static GSM_Error ALCATEL_GetModel(GSM_StateMachine *s)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetModel(s);
+}
+
+static GSM_Error ALCATEL_GetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetDateTime(s, date_time);
+}
+
+static GSM_Error ALCATEL_GetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+ int j = 0;
+
+ if (entry->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, entry->Location))!= ERR_NONE) {
+ entry->EntriesNum = 0;
+ return error;
+ }
+ if ((error = ALCATEL_GetFields(s, entry->Location))!= ERR_NONE) return error;
+
+ entry->EntriesNum = Priv->CurrentFieldsCount;
+
+ for (i=0; i<Priv->CurrentFieldsCount; i++) {
+ if ((error = ALCATEL_GetFieldValue(s, entry->Location, Priv->CurrentFields[i]))!= ERR_NONE) return error;
+ entry->Entries[i].VoiceTag = 0;
+ entry->Entries[i].SMSList[0] = 0;
+ switch (Priv->CurrentFields[i]) {
+ case 0:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 0, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_LastName;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 1:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 1, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_FirstName;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 2:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 2, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Company;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 3:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 3, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_JobTitle;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 4:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 4, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Note;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 5:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 5, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Category;
+ entry->Entries[i - j].Number = Priv->ReturnInt;
+ break;
+ case 6:
+ if (Priv->ReturnType != Alcatel_bool) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 6, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Private;
+ entry->Entries[i - j].Number = Priv->ReturnInt;
+ break;
+ case 7:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 7, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Work;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 8:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 8, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_General;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 9:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 9, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Fax;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 10:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 10, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Other;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 11:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 11, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Pager;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 12:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 12, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Mobile;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 13:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 13, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Number_Home;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 14:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 14, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Email;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 15:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 15, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Email2;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 16:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 16, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_StreetAddress;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 17:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 17, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_City;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 18:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 18, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_State;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 19:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 19, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Zip;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 20:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 20, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Country;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 21:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 21, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Custom1;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 22:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 22, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Custom2;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 23:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 23, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Custom3;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 24:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 24, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ entry->Entries[i - j].EntryType = PBK_Text_Custom4;
+ CopyUnicodeString(entry->Entries[i - j].Text, Priv->ReturnString);
+ break;
+ case 25:
+ if (Priv->ReturnType != Alcatel_int) {
+ smprintf(s,"WARNING: Received unexpected type %02X for field 25, ignoring\n", Priv->ReturnType);
+ entry->EntriesNum--;
+ j++;
+ break;
+ }
+ if (Priv->ReturnInt != 0) {
+ entry->Entries[i - j].EntryType = PBK_PictureID;
+ entry->Entries[i - j].Number = Priv->ReturnInt;
+ } else {
+ entry->EntriesNum--;
+ j++;
+ }
+ break;
+ default:
+ entry->EntriesNum--;
+ j++;
+ smprintf(s,"WARNING: Received unknown field %02X, ignoring. Type = %02X. Value = ", Priv->CurrentFields[i], Priv->ReturnType);
+ switch (Priv->ReturnType) {
+ case Alcatel_date:
+ smprintf(s, "%d.%d.%d", Priv->ReturnDateTime.Day, Priv->ReturnDateTime.Month, Priv->ReturnDateTime.Year);
+ break;
+ case Alcatel_time:
+ smprintf(s, "%d:%d:%d", Priv->ReturnDateTime.Hour, Priv->ReturnDateTime.Minute, Priv->ReturnDateTime.Second);
+ break;
+ case Alcatel_string:
+ case Alcatel_phone:
+ smprintf(s, "\"%s\"",DecodeUnicodeString(Priv->ReturnString));
+ break;
+ case Alcatel_enum:
+ case Alcatel_bool:
+ case Alcatel_int:
+ case Alcatel_byte:
+ smprintf(s, "%d", Priv->ReturnInt);
+ break;
+ }
+ smprintf(s,"\n");
+ }
+ }
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetMemory(s, entry);
+ }
+}
+
+static GSM_Error ALCATEL_GetNextMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry, bool start)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if (entry->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if (Priv->ContactsItemsCount == 0) return ERR_EMPTY;
+
+ if (start) entry->Location = 0;
+ if ((error = ALCATEL_GetNextId(s, &(entry->Location))) != ERR_NONE) return error;
+
+ return ALCATEL_GetMemory(s, entry);
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetNextMemory(s, entry, start);
+ }
+}
+
+static GSM_Error ALCATEL_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int NamePosition = -1;
+ bool NameSet = false;
+ int i;
+
+
+ if (entry->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeContacts, 0))!= ERR_NONE) return error;
+ for (i = 0; i < entry->EntriesNum; i++) {
+ switch (entry->Entries[i].EntryType) {
+ case PBK_Number_General:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 8, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Mobile:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 12, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Work:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 7, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Fax:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 9, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Home:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 13, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Pager:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 11, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Other:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 10, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Note:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 4, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Email:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 14, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Email2:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 15, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_LastName:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 0, entry->Entries[i].Text)) != ERR_NONE) return error;
+ NameSet = true;
+ break;
+ case PBK_Text_FirstName:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 1, entry->Entries[i].Text)) != ERR_NONE) return error;
+ NameSet = true;
+ break;
+ case PBK_Text_Company:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 2, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_JobTitle:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 3, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Category:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 5, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case PBK_Private:
+ if ((error = ALCATEL_CreateField(s, Alcatel_bool, 6, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case PBK_Text_StreetAddress:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 16, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_City:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 17, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_State:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 18, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Zip:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 19, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Country:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 20, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom1:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 21, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom2:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 22, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom3:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 23, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom4:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 24, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_PictureID:
+ if (s->Phone.Data.Priv.ALCATEL.ProtocolVersion == V_1_1) {
+ if ((error = ALCATEL_CreateField(s, Alcatel_int, 25, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ } else {
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", entry->Entries[i].EntryType);
+ }
+ break;
+
+ case PBK_Text_Name: NamePosition = i; break;
+ /* Following fields are not supported: */
+ case PBK_Text_UserID:
+ case PBK_SMSListID:
+ case PBK_RingtoneFileSystemID:
+ case PBK_Date:
+ case PBK_Caller_Group:
+ case PBK_RingtoneID:
+ case PBK_Text_Postal:
+ case PBK_Text_URL:
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", entry->Entries[i].EntryType);
+ break;
+ }
+ }
+ if (NamePosition != -1) {
+ if (NameSet) {
+ smprintf(s,"WARNING: Ignoring name, not supported by phone\n");
+ } else {
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 1, entry->Entries[i].Text)) != ERR_NONE) return error;
+ }
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ entry->Location = Priv->CommitedRecord;
+ /* Refresh list */
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_AddMemory(s, entry);
+ }
+}
+
+static GSM_Error ALCATEL_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int NamePosition = -1;
+ bool NameSet = false;
+ int i;
+ bool UpdatedFields[26];
+
+ if (entry->Location == 0) return ERR_INVALIDLOCATION;
+
+ if (entry->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ /* Save modified entry */
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, entry->Location))!= ERR_NONE) {
+ /* Entry doesn't exist, we will create new one */
+ return ALCATEL_AddMemory(s, entry);
+ }
+ /* Get fields for current item */
+ if ((error = ALCATEL_GetFields(s, entry->Location))!= ERR_NONE) return error;
+
+ for (i = 0; i < 26; i++) { UpdatedFields[i] = false; }
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeContacts, entry->Location))!= ERR_NONE) return error;
+ for (i = 0; i < entry->EntriesNum; i++) {
+ switch (entry->Entries[i].EntryType) {
+ case PBK_Number_General:
+ UpdatedFields[8] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 8, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Mobile:
+ UpdatedFields[12] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 12, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Work:
+ UpdatedFields[7] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 7, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Fax:
+ UpdatedFields[9] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 9, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Home:
+ UpdatedFields[13] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 13, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Pager:
+ UpdatedFields[11] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 11, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Number_Other:
+ UpdatedFields[10] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, entry->Location, 10, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Note:
+ UpdatedFields[4] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 4, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Email:
+ UpdatedFields[14] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 14, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Email2:
+ UpdatedFields[15] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 15, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_LastName:
+ UpdatedFields[0] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 0, entry->Entries[i].Text)) != ERR_NONE) return error; NameSet = true;
+ break;
+ case PBK_Text_FirstName:
+ UpdatedFields[1] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 1, entry->Entries[i].Text)) != ERR_NONE) return error; NameSet = true;
+ break;
+ case PBK_Text_Company:
+ UpdatedFields[2] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 2, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_JobTitle:
+ UpdatedFields[3] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 3, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Category:
+ UpdatedFields[5] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, entry->Location, 5, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case PBK_Private:
+ UpdatedFields[6] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_bool, entry->Location, 6, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case PBK_Text_StreetAddress:
+ UpdatedFields[16] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 16, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_City:
+ UpdatedFields[17] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 17, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_State:
+ UpdatedFields[18] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 18, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Zip:
+ UpdatedFields[19] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 19, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Country:
+ UpdatedFields[20] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 20, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom1:
+ UpdatedFields[21] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 21, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom2:
+ UpdatedFields[22] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 22, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom3:
+ UpdatedFields[23] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 23, entry->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case PBK_Text_Custom4:
+ UpdatedFields[24] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 24, entry->Entries[i].Text)) != ERR_NONE) return error
+ ; break;
+ case PBK_PictureID:
+ if (s->Phone.Data.Priv.ALCATEL.ProtocolVersion == V_1_1) {
+ UpdatedFields[25] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_int, entry->Location, 25, &(entry->Entries[i].Number))) != ERR_NONE) return error;
+ } else {
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", entry->Entries[i].EntryType);
+ }
+ break;
+
+ case PBK_Text_Name: NamePosition = i; break;
+ /* Following fields are not supported: */
+ case PBK_SMSListID:
+ case PBK_Text_UserID:
+ case PBK_RingtoneFileSystemID:
+ case PBK_Date:
+ case PBK_Caller_Group:
+ case PBK_RingtoneID:
+ case PBK_Text_Postal:
+ case PBK_Text_URL:
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", entry->Entries[i].EntryType);
+ break;
+ }
+ }
+ if (NamePosition != -1) {
+ if (NameSet) {
+ smprintf(s,"WARNING: Ignoring name, not supported by phone\n");
+ } else {
+ UpdatedFields[1] = true; if ((error = ALCATEL_UpdateField(s, Alcatel_string, entry->Location, 1, entry->Entries[i].Text)) != ERR_NONE) return error;
+ }
+ }
+ /* If we didn't update some field, we have to delete it... */
+ for (i=0; i<Priv->CurrentFieldsCount; i++) {
+ if (!UpdatedFields[Priv->CurrentFields[i]]) if ((error = ALCATEL_DeleteField(s, entry->Location, Priv->CurrentFields[i])) != ERR_NONE) return error;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ entry->Location = Priv->CommitedRecord;
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetMemory(s, entry);
+ }
+}
+
+static GSM_Error ALCATEL_DeleteMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry)
+{
+ GSM_Error error;
+
+ if (entry->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, entry->Location))!= ERR_NONE) {
+ /* Entry was empty => no error */
+ return ERR_NONE;
+ }
+ /* Do real delete */
+ error = ALCATEL_DeleteItem(s, entry->Location);
+ if (error != ERR_NONE) return error;
+
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_DeleteMemory(s, entry);
+ }
+}
+
+static GSM_Error ALCATEL_DeleteAllMemory(GSM_StateMachine *s, GSM_MemoryType type)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ if (type == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+
+ for (i=0; i<Priv->ContactsItemsCount; i++) {
+ error = ALCATEL_DeleteItem(s, Priv->ContactsItems[i]);
+ if (error != ERR_NONE) return error;
+ }
+
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_DeleteAllMemory(s, type);
+ }
+}
+
+static GSM_Error ALCATEL_GetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSMSC(s, smsc);
+}
+
+
+static GSM_Error ALCATEL_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status)
+{
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_Error error;
+
+ if (Status->MemoryType == MEM_ME) {
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeContacts, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ Status->MemoryUsed = Priv->ContactsItemsCount;
+ Status->MemoryFree = ALCATEL_FREE_MEMORY;
+ return ERR_NONE;
+ } else {
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetMemoryStatus(s, Status);
+ }
+}
+
+static GSM_Error ALCATEL_GetSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSMS(s, sms);
+}
+
+static GSM_Error ALCATEL_DeleteSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_DeleteSMS(s, sms);
+}
+
+static GSM_Error ALCATEL_AddSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_AddSMS(s, sms);
+}
+
+static GSM_Error ALCATEL_GetBatteryCharge(GSM_StateMachine *s, GSM_BatteryCharge *bat)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetBatteryCharge(s, bat);
+}
+
+static GSM_Error ALCATEL_GetSignalStrength(GSM_StateMachine *s, GSM_SignalQuality *sig)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSignalQuality(s, sig);
+}
+
+static GSM_Error ALCATEL_GetSMSFolders(GSM_StateMachine *s, GSM_SMSFolders *folders)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSMSFolders(s, folders);
+}
+
+static GSM_Error ALCATEL_GetNextSMS(GSM_StateMachine *s, GSM_MultiSMSMessage *sms, bool start)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetNextSMS(s, sms, start);
+}
+
+static GSM_Error ALCATEL_GetSMSStatus(GSM_StateMachine *s, GSM_SMSMemoryStatus *status)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSMSStatus(s, status);
+}
+
+static GSM_Error ALCATEL_DialVoice(GSM_StateMachine *s, char *number, GSM_CallShowNumber ShowNumber)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_DialVoice(s, number, ShowNumber);
+}
+
+static GSM_Error ALCATEL_AnswerCall(GSM_StateMachine *s, int ID, bool all)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_AnswerCall(s,ID,all);
+}
+
+static GSM_Error ALCATEL_GetNetworkInfo(GSM_StateMachine *s, GSM_NetworkInfo *netinfo)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetNetworkInfo(s, netinfo);
+}
+
+static GSM_Error ALCATEL_GetDisplayStatus(GSM_StateMachine *s, GSM_DisplayFeatures *features)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetDisplayStatus(s, features);
+}
+
+static GSM_Error ALCATEL_SetAutoNetworkLogin(GSM_StateMachine *s)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetAutoNetworkLogin(s);
+}
+
+static GSM_Error ALCATEL_PressKey(GSM_StateMachine *s, GSM_KeyCode Key, bool Press)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_PressKey(s, Key, Press);
+}
+
+static GSM_Error ALCATEL_Reset(GSM_StateMachine *s, bool hard)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_Reset(s, hard);
+}
+
+static GSM_Error ALCATEL_CancelCall(GSM_StateMachine *s, int ID, bool all)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_CancelCall(s,ID,all);
+}
+
+static GSM_Error ALCATEL_SendSavedSMS(GSM_StateMachine *s, int Folder, int Location)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SendSavedSMS(s, Folder, Location);
+}
+
+static GSM_Error ALCATEL_SendSMS(GSM_StateMachine *s, GSM_SMSMessage *sms)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SendSMS(s, sms);
+}
+
+static GSM_Error ALCATEL_SetDateTime(GSM_StateMachine *s, GSM_DateTime *date_time)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetDateTime(s, date_time);
+}
+
+static GSM_Error ALCATEL_SetSMSC(GSM_StateMachine *s, GSM_SMSC *smsc)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetSMSC(s, smsc);
+}
+
+static GSM_Error ALCATEL_EnterSecurityCode(GSM_StateMachine *s, GSM_SecurityCode Code)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_EnterSecurityCode(s, Code);
+}
+
+static GSM_Error ALCATEL_GetSecurityStatus(GSM_StateMachine *s, GSM_SecurityCodeType *Status)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSecurityStatus(s, Status);
+}
+
+static GSM_Error ALCATEL_ResetPhoneSettings(GSM_StateMachine *s, GSM_ResetSettingsType Type)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_ResetPhoneSettings(s, Type);
+}
+
+static GSM_Error ALCATEL_SendDTMF(GSM_StateMachine *s, char *sequence)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SendDTMF(s, sequence);
+}
+
+static GSM_Error ALCATEL_GetSIMIMSI(GSM_StateMachine *s, char *IMSI)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_GetSIMIMSI(s, IMSI);
+}
+
+static GSM_Error ALCATEL_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *status)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ status->Used = 0;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ status->Used = Priv->CalendarItemsCount;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
+{
+ GSM_Error error;
+ GSM_DateTime *dt = NULL;
+ GSM_DateTime evdate;
+ bool evdateused = true;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+ int j=0;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, Note->Location))!= ERR_NONE) {
+ Note->EntriesNum = 0;
+ return error;
+ }
+ if ((error = ALCATEL_GetFields(s, Note->Location))!= ERR_NONE) return error;
+
+ Note->EntriesNum = Priv->CurrentFieldsCount;
+
+ for (i=0; i < Priv->CurrentFieldsCount; i++) {
+ if ((error = ALCATEL_GetFieldValue(s, Note->Location, Priv->CurrentFields[i]))!= ERR_NONE) return error;
+ switch (Priv->CurrentFields[i]) {
+ case 0:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ j++;
+ Note->EntriesNum--;
+ evdate = Priv->ReturnDateTime;
+ evdateused = false;
+ break;
+ case 1:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_START_DATETIME;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ Note->Entries[i-j].Date.Day = evdate.Day;
+ Note->Entries[i-j].Date.Month = evdate.Month;
+ Note->Entries[i-j].Date.Year = evdate.Year;
+ Note->Entries[i-j].Date.Timezone = evdate.Timezone;
+ evdateused = true;
+ break;
+ case 2:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_END_DATETIME;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ Note->Entries[i-j].Date.Day = evdate.Day;
+ Note->Entries[i-j].Date.Month = evdate.Month;
+ Note->Entries[i-j].Date.Year = evdate.Year;
+ Note->Entries[i-j].Date.Timezone = evdate.Timezone;
+ evdateused = true;
+ break;
+ case 3:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (dt == NULL) {
+ Note->Entries[i-j].EntryType = CAL_ALARM_DATETIME;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ dt = &(Note->Entries[i-j].Date);
+ } else {
+ j++;
+ Note->EntriesNum--;
+ dt->Day = Priv->ReturnDateTime.Day;
+ dt->Month = Priv->ReturnDateTime.Month;
+ dt->Year = Priv->ReturnDateTime.Year;
+ dt->Timezone = Priv->ReturnDateTime.Timezone;
+ dt = NULL;
+ }
+ break;
+ case 4:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (dt == NULL) {
+ Note->Entries[i-j].EntryType = CAL_ALARM_DATETIME;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ dt = &(Note->Entries[i-j].Date);
+ } else {
+ j++;
+ Note->EntriesNum--;
+ dt->Hour = Priv->ReturnDateTime.Hour;
+ dt->Minute = Priv->ReturnDateTime.Minute;
+ dt->Second = Priv->ReturnDateTime.Second;
+ dt = NULL;
+ }
+ break;
+ case 5:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_TEXT;
+ CopyUnicodeString(Note->Entries[i-j].Text, Priv->ReturnString);
+ break;
+ case 6:
+ if (Priv->ReturnType != Alcatel_bool) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_PRIVATE;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 7:
+ if (Priv->ReturnType != Alcatel_enum) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ switch (Priv->ReturnInt) {
+ case 0:
+ Note->Type = GSM_CAL_MEETING;
+ break;
+ case 2:
+ Note->Type = GSM_CAL_BIRTHDAY;
+ break;
+ case 3:
+ Note->Type = GSM_CAL_CALL;
+ break;
+ case 4:
+ Note->Type = GSM_CAL_ALARM;
+ break;
+ case 5:
+ Note->Type = GSM_CAL_DAILY_ALARM;
+ break;
+ case 9:
+ /* I'd call this repeating event, but it makes no sense creating one more type ... */
+ Note->Type = GSM_CAL_MEETING;
+ break;
+ default:
+ smprintf(s,"WARNING: Received unknown event type %02X!\n", Priv->ReturnInt);
+ break;
+ }
+ j++;
+ Note->EntriesNum--;
+ break;
+ case 8:
+ if (Priv->ReturnType != Alcatel_int) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ /* 0xffffffff indicates that there is phone (BF5), 0 means none (BF5, BE5)*/
+ if (Priv->ReturnInt == 0xffffffff || Priv->ReturnInt == 0) {
+ j++;
+ Note->EntriesNum--;
+ } else {
+ Note->Entries[i-j].EntryType = CAL_CONTACTID;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ }
+ break;
+ case 9:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_PHONE;
+ CopyUnicodeString(Note->Entries[i-j].Text, Priv->ReturnString);
+ break;
+ case 10:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_DAYOFWEEK;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 11:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_DAY;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 12:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_WEEKOFMONTH;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 13:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_MONTH;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 17:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ /* In BF5 birthday has frequency = 1 */
+ if (Note->Type == GSM_CAL_BIRTHDAY) {
+ Note->EntriesNum--;
+ j++;
+ } else {
+ Note->Entries[i-j].EntryType = CAL_REPEAT_FREQUENCY;
+ Note->Entries[i-j].Number = Priv->ReturnInt;
+ }
+ break;
+ case 18:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_STARTDATE;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ break;
+ case 19:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ Note->Entries[i-j].EntryType = CAL_REPEAT_STOPDATE;
+ Note->Entries[i-j].Date = Priv->ReturnDateTime;
+ break;
+ case 20:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ /* This entry had always same value as the 3rd (alarm date) */
+ j++;
+ Note->EntriesNum--;
+ break;
+ case 21:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ Note->EntriesNum--;
+ j++;
+ break;
+ }
+ /* This entry had always same value as the 4th (alarm time) */
+ j++;
+ Note->EntriesNum--;
+ break;
+ default:
+ Note->EntriesNum--;
+ j++;
+ smprintf(s,"WARNING: Received unknown field %02X, ignoring. Type = %02X. Value = ", Priv->CurrentFields[i], Priv->ReturnType);
+ switch (Priv->ReturnType) {
+ case Alcatel_date:
+ smprintf(s, "%d.%d.%d", Priv->ReturnDateTime.Day, Priv->ReturnDateTime.Month, Priv->ReturnDateTime.Year);
+ break;
+ case Alcatel_time:
+ smprintf(s, "%d:%d:%d", Priv->ReturnDateTime.Hour, Priv->ReturnDateTime.Minute, Priv->ReturnDateTime.Second);
+ break;
+ case Alcatel_string:
+ case Alcatel_phone:
+ smprintf(s, "\"%s\"",DecodeUnicodeString(Priv->ReturnString));
+ break;
+ case Alcatel_enum:
+ case Alcatel_bool:
+ case Alcatel_int:
+ case Alcatel_byte:
+ smprintf(s, "%d", Priv->ReturnInt);
+ break;
+ }
+ smprintf(s,"\n");
+ }
+ }
+ /* The event didn't have start/stop time -> we need only date */
+ if (!evdateused) {
+ Note->EntriesNum++;
+ Note->Entries[i-j].EntryType = CAL_START_DATETIME;
+ Note->Entries[i-j].Date = evdate;
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if (Priv->CalendarItemsCount == 0) return ERR_EMPTY;
+
+ if (start) Note->Location = 0;
+ if ((error = ALCATEL_GetNextId(s, &(Note->Location))) != ERR_NONE) return error;
+
+ return ALCATEL_GetCalendar(s, Note);
+}
+
+
+static GSM_Error ALCATEL_DeleteCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ /* Delete Calendar */
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, Note->Location))!= ERR_NONE) {
+ /* Entry was empty => no error */
+ return ERR_NONE;
+ }
+ error = ALCATEL_DeleteItem(s, Note->Location);
+ if (error != ERR_NONE) return error;
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+
+static GSM_Error ALCATEL_AddCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
+{
+ GSM_Error error;
+ unsigned int val;
+ bool contact_set = false;
+ bool phone_set = false;
+ bool date_set = false;
+ bool repeating = false;
+ int i;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeCalendar, 0))!= ERR_NONE) return error;
+
+ for (i = 0; i < Note->EntriesNum; i++) {
+ switch (Note->Entries[i].EntryType) {
+ case CAL_START_DATETIME:
+ if (!date_set) {
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 0, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ date_set = true;
+ }
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 1, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case CAL_END_DATETIME:
+ if (!date_set) {
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 0, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ date_set = true;
+ }
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 2, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case CAL_ALARM_DATETIME:
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 3, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 4, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ if (Note->Type == GSM_CAL_ALARM || Note->Type == GSM_CAL_DAILY_ALARM) {
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 20, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 21, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ }
+ break;
+ case CAL_TEXT:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 5, Note->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case CAL_PRIVATE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_bool, 6, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case CAL_CONTACTID:
+ if ((error = ALCATEL_CreateField(s, Alcatel_int, 8, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ contact_set = true;
+ break;
+ case CAL_PHONE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 9, Note->Entries[i].Text)) != ERR_NONE) return error;
+ phone_set = true;
+ break;
+ case CAL_REPEAT_DAYOFWEEK:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 10, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_DAY:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 11, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_WEEKOFMONTH:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 12, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_MONTH:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 13, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_FREQUENCY:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 17, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_STARTDATE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 18, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_STOPDATE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 19, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_SILENT_ALARM_DATETIME:
+ case CAL_RECURRANCE:
+ case CAL_LOCATION:
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", Note->Entries[i].EntryType);
+ break;
+ }
+ }
+
+ switch (Note->Type) {
+ case GSM_CAL_CALL:
+ val = 3;
+ break;
+ case GSM_CAL_BIRTHDAY:
+ val = 2;
+ break;
+ case GSM_CAL_ALARM:
+ val = 4;
+ break;
+ case GSM_CAL_DAILY_ALARM:
+ val = 5;
+ break;
+ default:
+ if (repeating) {
+ val = 9;
+ } else {
+ val = 0;
+ }
+ }
+ if ((error = ALCATEL_CreateField(s, Alcatel_enum, 7, &val)) != ERR_NONE) return error;
+
+ if (!contact_set) {
+ if (phone_set) {
+ val = 0xffffffff;
+ } else {
+ val = 0;
+ }
+ if ((error = ALCATEL_CreateField(s, Alcatel_int, 8, &val)) != ERR_NONE) return error;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ Note->Location = Priv->CommitedRecord;
+ /* Refresh list */
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_SetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
+{
+ GSM_Error error;
+ unsigned int val;
+ bool contact_set = false;
+ bool phone_set = false;
+ bool date_set = false;
+ bool repeating = false;
+ int i;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ bool UpdatedFields[22];
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, Note->Location))!= ERR_NONE) {
+ /* Entry doesn't exist, we will create new one */
+ return ALCATEL_AddCalendar(s, Note);
+ }
+ /* Get fields for current item */
+ if ((error = ALCATEL_GetFields(s, Note->Location))!= ERR_NONE) return error;
+
+ for (i = 0; i < 22; i++) { UpdatedFields[i] = false; }
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeCalendar, Note->Location))!= ERR_NONE) return error;
+
+ for (i = 0; i < Note->EntriesNum; i++) {
+ switch (Note->Entries[i].EntryType) {
+ case CAL_START_DATETIME:
+ if (!date_set) {
+ UpdatedFields[0] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 0, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ date_set = true;
+ }
+ UpdatedFields[1] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_time, Note->Location, 1, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case CAL_END_DATETIME:
+ if (!date_set) {
+ UpdatedFields[0] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 0, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ date_set = true;
+ }
+ UpdatedFields[2] = true; if ((error = ALCATEL_UpdateField(s, Alcatel_time, Note->Location, 2, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case CAL_ALARM_DATETIME:
+ UpdatedFields[3] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 3, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[4] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_time, Note->Location, 4, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ if (Note->Type == GSM_CAL_ALARM || Note->Type == GSM_CAL_DAILY_ALARM) {
+ UpdatedFields[20] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 20, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[21] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_time, Note->Location, 21, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ }
+ break;
+ case CAL_TEXT:
+ UpdatedFields[5] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, Note->Location, 5, Note->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case CAL_PRIVATE:
+ UpdatedFields[6] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_bool, Note->Location, 6, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case CAL_CONTACTID:
+ UpdatedFields[8] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_int, Note->Location, 8, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ contact_set = true;
+ break;
+ case CAL_PHONE:
+ UpdatedFields[9] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, Note->Location, 9, Note->Entries[i].Text)) != ERR_NONE) return error;
+ phone_set = true;
+ break;
+ case CAL_REPEAT_DAYOFWEEK:
+ UpdatedFields[10] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, Note->Location, 10, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_DAY:
+ UpdatedFields[11] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, Note->Location, 11, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_WEEKOFMONTH:
+ UpdatedFields[12] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, Note->Location, 12, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_MONTH:
+ UpdatedFields[13] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, Note->Location, 13, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_FREQUENCY:
+ UpdatedFields[17] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, Note->Location, 17, &(Note->Entries[i].Number))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_STARTDATE:
+ UpdatedFields[18] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 18, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_REPEAT_STOPDATE:
+ UpdatedFields[19] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, Note->Location, 19, &(Note->Entries[i].Date))) != ERR_NONE) return error;
+ repeating = true;
+ break;
+ case CAL_SILENT_ALARM_DATETIME:
+ case CAL_RECURRANCE:
+ case CAL_LOCATION:
+ smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", Note->Entries[i].EntryType);
+ break;
+ }
+ }
+
+ switch (Note->Type) {
+ case GSM_CAL_CALL:
+ val = 3;
+ break;
+ case GSM_CAL_BIRTHDAY:
+ val = 2;
+ break;
+ case GSM_CAL_ALARM:
+ val = 4;
+ break;
+ case GSM_CAL_DAILY_ALARM:
+ val = 5;
+ break;
+ default:
+ if (repeating) {
+ val = 9;
+ } else {
+ val = 0;
+ }
+ }
+ UpdatedFields[7] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_enum, Note->Location, 7, &val)) != ERR_NONE) return error;
+
+ if (!contact_set) {
+ if (phone_set) {
+ val = 0xffffffff;
+ } else {
+ val = 0;
+ }
+ UpdatedFields[8] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_int, Note->Location, 8, &val)) != ERR_NONE) return error;
+ }
+ /* If we didn't update some field, we have to delete it... */
+ for (i=0; i<Priv->CurrentFieldsCount; i++) {
+ if (!UpdatedFields[Priv->CurrentFields[i]]) if ((error = ALCATEL_DeleteField(s, Note->Location, Priv->CurrentFields[i])) != ERR_NONE) return error;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_DeleteAllCalendar (GSM_StateMachine *s)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+
+ for (i=0; i<Priv->CalendarItemsCount; i++) {
+ error = ALCATEL_DeleteItem(s, Priv->CalendarItems[i]);
+ if (error != ERR_NONE) return error;
+ }
+
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+
+static GSM_Error ALCATEL_GetAlarm(GSM_StateMachine *s, GSM_Alarm *alarm)
+{
+ GSM_Error error;
+ GSM_CalendarEntry Note;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+ bool Found = false;
+ bool DateSet = false;
+ int alarm_number = alarm->Location;
+ static GSM_DateTime nulldt = {0,0,0,0,0,0,0};
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+
+ for (i=0; i<Priv->CalendarItemsCount; i++) {
+ if ((error = ALCATEL_GetFieldValue(s, Priv->CalendarItems[i], 7))!= ERR_NONE) return error;
+ if (Priv->ReturnType != Alcatel_enum) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ continue;
+ }
+ if (Priv->ReturnInt == 4 || Priv->ReturnInt == 5) {
+ alarm_number--;
+ if (alarm_number == 0) {
+ Found = true;
+ break;
+ }
+ }
+ }
+
+ if (!Found) return ERR_EMPTY;
+
+ Note.Location = Priv->CalendarItems[i];
+
+ if ((error = ALCATEL_GetCalendar(s, &Note))!= ERR_NONE) return error;
+
+ if (Note.Type == GSM_CAL_ALARM) {
+ alarm->Repeating = false;
+ } else {
+ alarm->Repeating = true;
+ }
+
+ alarm->Text[0] = 0; alarm->Text[1] = 0;
+
+
+ for (i = 0; i < Note.EntriesNum; i++) {
+ if (Note.Entries[i].EntryType == CAL_TEXT) {
+ CopyUnicodeString(alarm->Text, Note.Entries[i].Text);
+ } else if (Note.Entries[i].EntryType == CAL_ALARM_DATETIME) {
+ alarm->DateTime = Note.Entries[i].Date;
+ DateSet = false;
+ }
+ }
+ if (!DateSet) {
+ alarm->DateTime = nulldt;
+ }
+
+ return ERR_NONE;
+}
+
+
+static GSM_Error ALCATEL_SetAlarm (GSM_StateMachine *s, GSM_Alarm *alarm)
+{
+ GSM_Error error;
+ GSM_CalendarEntry Note;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ GSM_DateTime dt;
+ int i;
+ bool Found = false;
+ int alarm_number = alarm->Location;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeCalendar, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+
+ for (i=0; i<Priv->CalendarItemsCount; i++) {
+ if ((error = ALCATEL_GetFieldValue(s, Priv->CalendarItems[i], 7))!= ERR_NONE) return error;
+ if (Priv->ReturnType != Alcatel_enum) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ continue;
+ }
+ if (Priv->ReturnInt == 4 || Priv->ReturnInt == 5) {
+ alarm_number--;
+ if (alarm_number == 0) {
+ Found = true;
+ break;
+ }
+ }
+ }
+
+ if (Found) {
+ Note.Location = Priv->CalendarItems[i];
+ }
+
+ Note.EntriesNum = 1;
+
+ Note.Entries[0].EntryType = CAL_ALARM_DATETIME;
+ Note.Entries[0].Date = alarm->DateTime;
+
+ if (alarm->Repeating) {
+ Note.Type = GSM_CAL_DAILY_ALARM;
+ GSM_GetCurrentDateTime(&dt);
+ Note.Entries[0].Date.Day = dt.Day;
+ Note.Entries[0].Date.Month = dt.Month;
+ Note.Entries[0].Date.Year = dt.Year;
+ } else {
+ Note.Type = GSM_CAL_ALARM;
+ }
+
+ if (alarm->Text[0] != 0 || alarm->Text[1] != 0) {
+ Note.EntriesNum++;
+ Note.Entries[1].EntryType = CAL_TEXT;
+ CopyUnicodeString(Note.Entries[1].Text, alarm->Text);
+ }
+
+ if (Found) {
+ return ALCATEL_SetCalendar(s, &Note);
+ } else {
+ return ALCATEL_AddCalendar(s, &Note);
+ }
+}
+
+
+static GSM_Error ALCATEL_GetToDoStatus(GSM_StateMachine *s, GSM_ToDoStatus *status)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ status->Used = 0;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ status->Used = Priv->ToDoItemsCount;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
+{
+ GSM_Error error;
+ GSM_DateTime *dt = NULL;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+ int j=0;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, ToDo->Location))!= ERR_NONE) {
+ ToDo->EntriesNum = 0;
+ return error;
+ }
+ if ((error = ALCATEL_GetFields(s, ToDo->Location))!= ERR_NONE) return error;
+
+ ToDo->EntriesNum = Priv->CurrentFieldsCount;
+
+ for (i=0; i < Priv->CurrentFieldsCount; i++) {
+ if ((error = ALCATEL_GetFieldValue(s, ToDo->Location, Priv->CurrentFields[i]))!= ERR_NONE) return error;
+ switch (Priv->CurrentFields[i]) {
+ case 0:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ ToDo->Entries[i-j].EntryType = TODO_END_DATETIME;
+ ToDo->Entries[i-j].Date = Priv->ReturnDateTime;
+ break;
+ case 1:
+ if (Priv->ReturnType != Alcatel_bool) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ ToDo->Entries[i-j].EntryType = TODO_COMPLETED;
+ ToDo->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 2:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (dt == NULL) {
+ ToDo->Entries[i-j].EntryType = TODO_ALARM_DATETIME;
+ ToDo->Entries[i-j].Date = Priv->ReturnDateTime;
+ dt = &(ToDo->Entries[i-j].Date);
+ } else {
+ j++;
+ ToDo->EntriesNum--;
+ dt->Day = Priv->ReturnDateTime.Day;
+ dt->Month = Priv->ReturnDateTime.Month;
+ dt->Year = Priv->ReturnDateTime.Year;
+ dt->Timezone = Priv->ReturnDateTime.Timezone;
+ dt = NULL;
+ }
+ break;
+ case 3:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (dt == NULL) {
+ ToDo->Entries[i-j].EntryType = TODO_ALARM_DATETIME;
+ ToDo->Entries[i-j].Date = Priv->ReturnDateTime;
+ dt = &(ToDo->Entries[i-j].Date);
+ } else {
+ j++;
+ ToDo->EntriesNum--;
+ dt->Hour = Priv->ReturnDateTime.Hour;
+ dt->Minute = Priv->ReturnDateTime.Minute;
+ dt->Second = Priv->ReturnDateTime.Second;
+ dt = NULL;
+ }
+ break;
+ case 4:
+ if (Priv->ReturnType != Alcatel_string) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ ToDo->Entries[i-j].EntryType = TODO_TEXT;
+ CopyUnicodeString(ToDo->Entries[i-j].Text, Priv->ReturnString);
+ break;
+ case 5:
+ if (Priv->ReturnType != Alcatel_bool) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ ToDo->Entries[i-j].EntryType = TODO_PRIVATE;
+ ToDo->Entries[i-j].Number = Priv->ReturnInt;
+ break;
+ case 6:
+ if (Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (Priv->ReturnInt == 255) {
+ /* 255 means no category */
+ j++;
+ ToDo->EntriesNum--;
+ } else {
+ ToDo->Entries[i-j].EntryType = TODO_CATEGORY;
+ ToDo->Entries[i-j].Number = Priv->ReturnInt;
+ }
+ break;
+ case 7:
+ /* This one seems to be byte for BF5 and enum for BE5 */
+ if (Priv->ReturnType != Alcatel_enum && Priv->ReturnType != Alcatel_byte) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ switch (Priv->ReturnInt) {
+ case 0:
+ ToDo->Priority = GSM_Priority_High;
+ break;
+ case 1:
+ ToDo->Priority = GSM_Priority_Medium;
+ break;
+ case 2:
+ ToDo->Priority = GSM_Priority_Low;
+ break;
+ default:
+ ToDo->Priority = 0;
+ smprintf(s,"WARNING: Received unexpected priority %02X, ignoring\n", Priv->ReturnInt);
+ }
+ j++;
+ ToDo->EntriesNum--;
+ break;
+ case 8:
+ if (Priv->ReturnType != Alcatel_int) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ /* 0xffffffff indicates that there is phone, 0 means none */
+ if (Priv->ReturnInt == 0xffffffff || Priv->ReturnInt == 0) {
+ j++;
+ ToDo->EntriesNum--;
+ } else {
+ ToDo->Entries[i-j].EntryType = TODO_CONTACTID;
+ ToDo->Entries[i-j].Number = Priv->ReturnInt;
+ }
+ break;
+ case 9:
+ if (Priv->ReturnType != Alcatel_phone) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ ToDo->Entries[i-j].EntryType = TODO_PHONE;
+ CopyUnicodeString(ToDo->Entries[i-j].Text, Priv->ReturnString);
+ break;
+ case 10:
+ if (Priv->ReturnType != Alcatel_date) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckDate(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid date in phone, ignoring\n");
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ /* This entry had always same value as the 2nd (alarm date) */
+ j++;
+ ToDo->EntriesNum--;
+ break;
+ case 11:
+ if (Priv->ReturnType != Alcatel_time) {
+ smprintf(s,"WARNING: Received unexpected type %02X, ignoring\n", Priv->ReturnType);
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ if (!CheckTime(&(Priv->ReturnDateTime))) {
+ smprintf(s,"WARNING: Invalid time in phone, ignoring\n");
+ ToDo->EntriesNum--;
+ j++;
+ break;
+ }
+ /* This entry had always same value as the 3rd (alarm time) */
+ j++;
+ ToDo->EntriesNum--;
+ break;
+ default:
+ ToDo->EntriesNum--;
+ j++;
+ smprintf(s,"WARNING: Received unknown field %02X, ignoring. Type = %02X. Value = ", Priv->CurrentFields[i], Priv->ReturnType);
+ switch (Priv->ReturnType) {
+ case Alcatel_date:
+ smprintf(s, "%d.%d.%d", Priv->ReturnDateTime.Day, Priv->ReturnDateTime.Month, Priv->ReturnDateTime.Year);
+ break;
+ case Alcatel_time:
+ smprintf(s, "%d:%d:%d", Priv->ReturnDateTime.Hour, Priv->ReturnDateTime.Minute, Priv->ReturnDateTime.Second);
+ break;
+ case Alcatel_string:
+ case Alcatel_phone:
+ smprintf(s, "\"%s\"",DecodeUnicodeString(Priv->ReturnString));
+ break;
+ case Alcatel_enum:
+ case Alcatel_bool:
+ case Alcatel_int:
+ case Alcatel_byte:
+ smprintf(s, "%d", Priv->ReturnInt);
+ break;
+ }
+ smprintf(s,"\n");
+ }
+ }
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetNextToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, bool start)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if (Priv->ToDoItemsCount == 0) return ERR_EMPTY;
+
+ if (start) ToDo->Location = 0;
+ if ((error = ALCATEL_GetNextId(s, &(ToDo->Location))) != ERR_NONE) return error;
+
+ return ALCATEL_GetToDo(s, ToDo);
+}
+
+static GSM_Error ALCATEL_DeleteAllToDo (GSM_StateMachine *s)
+{
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+ int i;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+
+ for (i=0; i<Priv->ToDoItemsCount; i++) {
+ error = ALCATEL_DeleteItem(s, Priv->ToDoItems[i]);
+ if (error != ERR_NONE) return error;
+ }
+
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_AddToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
+{
+ GSM_Error error;
+ unsigned int val;
+ bool contact_set = false;
+ bool phone_set = false;
+ int i;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeToDo, 0))!= ERR_NONE) return error;
+
+ switch (ToDo->Priority) {
+ case GSM_Priority_High:
+ val = 0;
+ break;
+ case GSM_Priority_Low:
+ val = 2;
+ break;
+ case GSM_Priority_Medium:
+ default:
+ val = 1;
+ break;
+ }
+ /* This one seems to be byte for BF5 and enum for BE5 */
+ if (s->Phone.Data.Priv.ALCATEL.ProtocolVersion == V_1_1) {
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 7, &val)) != ERR_NONE) return error;
+ } else {
+ if ((error = ALCATEL_CreateField(s, Alcatel_enum, 7, &val)) != ERR_NONE) return error;
+ }
+
+ for (i = 0; i < ToDo->EntriesNum; i++) {
+ switch (ToDo->Entries[i].EntryType) {
+ case TODO_END_DATETIME:
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 0, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case TODO_COMPLETED:
+ if ((error = ALCATEL_CreateField(s, Alcatel_bool, 1, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case TODO_ALARM_DATETIME:
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 2, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 3, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ if ((error = ALCATEL_CreateField(s, Alcatel_date, 10, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ if ((error = ALCATEL_CreateField(s, Alcatel_time, 11, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ break;
+ case TODO_TEXT:
+ if ((error = ALCATEL_CreateField(s, Alcatel_string, 4, ToDo->Entries[i].Text)) != ERR_NONE) return error;
+ break;
+ case TODO_PRIVATE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_bool, 5, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case TODO_CATEGORY:
+ if ((error = ALCATEL_CreateField(s, Alcatel_byte, 6, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ break;
+ case TODO_CONTACTID:
+ if ((error = ALCATEL_CreateField(s, Alcatel_int, 8, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ contact_set = true;
+ break;
+ case TODO_PHONE:
+ if ((error = ALCATEL_CreateField(s, Alcatel_phone, 9, ToDo->Entries[i].Text)) != ERR_NONE) return error;
+ phone_set = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!contact_set) {
+ if (phone_set) {
+ val = 0xffffffff;
+ } else {
+ val = 0;
+ }
+ if ((error = ALCATEL_CreateField(s, Alcatel_int, 8, &val)) != ERR_NONE) return error;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ ToDo->Location = Priv->CommitedRecord;
+ /* Refresh list */
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_SetToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
+{
+ GSM_Error error;
+ unsigned int val;
+ bool contact_set = false;
+ bool phone_set = false;
+ bool UpdatedFields[12];
+ int i;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ /* Save modified ToDo */
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, ToDo->Location))!= ERR_NONE) {
+ /* Entry doesn't exist, we will create new one */
+ return ALCATEL_AddToDo(s, ToDo);
+ }
+ /* Get fields for current item */
+ if ((error = ALCATEL_GetFields(s, ToDo->Location))!= ERR_NONE) return error;
+
+ for (i = 0; i < 12; i++) { UpdatedFields[i] = false; }
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateEdit, TypeToDo, ToDo->Location))!= ERR_NONE) return error;
+
+ switch (ToDo->Priority) {
+ case GSM_Priority_High:
+ val = 0;
+ break;
+ case GSM_Priority_Low:
+ val = 2;
+ break;
+ case GSM_Priority_Medium:
+ default:
+ val = 1;
+ break;
+ }
+ /* This one seems to be byte for BF5 and enum for BE5 */
+ if (s->Phone.Data.Priv.ALCATEL.ProtocolVersion == V_1_1) {
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, ToDo->Location, 7, &val)) != ERR_NONE) return error;
+ } else {
+ if ((error = ALCATEL_UpdateField(s, Alcatel_enum, ToDo->Location, 7, &val)) != ERR_NONE) return error;
+ }
+ UpdatedFields[7] = true;
+
+ for (i = 0; i < ToDo->EntriesNum; i++) {
+ switch (ToDo->Entries[i].EntryType) {
+ case TODO_END_DATETIME:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, ToDo->Location, 0, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[0] = true;
+ break;
+ case TODO_COMPLETED:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_bool, ToDo->Location, 1, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ UpdatedFields[1] = true;
+ break;
+ case TODO_ALARM_DATETIME:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, ToDo->Location, 2, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[2] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_time, ToDo->Location, 3, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[3] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_date, ToDo->Location, 10, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[10] = true;
+ if ((error = ALCATEL_UpdateField(s, Alcatel_time, ToDo->Location, 11, &(ToDo->Entries[i].Date))) != ERR_NONE) return error;
+ UpdatedFields[11] = true;
+ break;
+ case TODO_TEXT:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_string, ToDo->Location, 4, ToDo->Entries[i].Text)) != ERR_NONE) return error;
+ UpdatedFields[4] = true;
+ break;
+ case TODO_PRIVATE:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_bool, ToDo->Location, 5, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ UpdatedFields[5] = true;
+ break;
+ case TODO_CATEGORY:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_byte, ToDo->Location, 6, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ UpdatedFields[6] = true;
+ break;
+ case TODO_CONTACTID:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_int, ToDo->Location, 8, &(ToDo->Entries[i].Number))) != ERR_NONE) return error;
+ UpdatedFields[8] = true;
+ contact_set = true;
+ break;
+ case TODO_PHONE:
+ if ((error = ALCATEL_UpdateField(s, Alcatel_phone, ToDo->Location, 9, ToDo->Entries[i].Text)) != ERR_NONE) return error;
+ UpdatedFields[9] = true;
+ phone_set = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (!contact_set) {
+ if (phone_set) {
+ val = 0xffffffff;
+ } else {
+ val = 0;
+ }
+ if ((error = ALCATEL_UpdateField(s, Alcatel_int, ToDo->Location, 8, &val)) != ERR_NONE) return error;
+ UpdatedFields[8] = true;
+ }
+
+
+ /* If we didn't update some field, we have to delete it... */
+ for (i=0; i<Priv->CurrentFieldsCount; i++) {
+ if (!UpdatedFields[Priv->CurrentFields[i]]) if ((error = ALCATEL_DeleteField(s, ToDo->Location, Priv->CurrentFields[i])) != ERR_NONE) return error;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_DeleteToDo (GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ /* Delete ToDo */
+ if ((error = ALCATEL_GetAvailableIds(s, false))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsIdAvailable(s, ToDo->Location))!= ERR_NONE) {
+ /* Entry was empty => no error */
+ return ERR_NONE;
+ }
+ error = ALCATEL_DeleteItem(s, ToDo->Location);
+ if (error != ERR_NONE) return error;
+ /* Refresh list */
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, TypeToDo, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableIds(s, true))!= ERR_NONE) return error;
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetCategoryStatus(GSM_StateMachine *s, GSM_CategoryStatus *Status)
+{
+ GSM_Alcatel_BinaryType type;
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ switch (Status->Type) {
+ case Category_ToDo: type = TypeToDo; break;
+ case Category_Phonebook: type = TypeContacts; break;
+ default: return ERR_NOTSUPPORTED;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, type, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableCategoryIds(s))!= ERR_NONE) return error;
+
+ Status->Used = Priv->CurrentCategoriesCount;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetCategory(GSM_StateMachine *s, GSM_Category *Category)
+{
+ GSM_Alcatel_BinaryType type;
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ switch (Category->Type) {
+ case Category_ToDo: type = TypeToDo; break;
+ case Category_Phonebook: type = TypeContacts; break;
+ default: return ERR_NOTSUPPORTED;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, type, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetAvailableCategoryIds(s))!= ERR_NONE) return error;
+ if ((error = ALCATEL_IsCategoryIdAvailable(s, Category->Location))!= ERR_NONE) return error;
+ if ((error = ALCATEL_GetCategoryText(s, Category->Location))!= ERR_NONE) return error;
+
+ CopyUnicodeString(Category->Name, Priv->ReturnString);
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_AddCategory(GSM_StateMachine *s, GSM_Category *Category)
+{
+ GSM_Alcatel_BinaryType type;
+ GSM_Error error;
+ GSM_Phone_ALCATELData *Priv = &s->Phone.Data.Priv.ALCATEL;
+
+ switch (Category->Type) {
+ case Category_ToDo: type = TypeToDo; break;
+ case Category_Phonebook: type = TypeContacts; break;
+ default: return ERR_NOTSUPPORTED;
+ }
+ if ((error = ALCATEL_GoToBinaryState(s, StateSession, type, 0))!= ERR_NONE) return error;
+ if ((error = ALCATEL_AddCategoryText(s, Category->Name))!= ERR_NONE) return error;
+
+ Category->Location = Priv->ReturnInt;
+
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_GetProductCode(GSM_StateMachine *s, char *value)
+{
+ strcpy(value, s->Phone.Data.ModelInfo->model);
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_DispatchMessage(GSM_StateMachine *s)
+{
+ if (s->Phone.Data.Priv.ALCATEL.Mode == ModeBinary) {
+ return GSM_DispatchMessage(s);
+ } else {
+ return ATGEN_DispatchMessage(s);
+ }
+}
+
+static GSM_Error ALCATEL_ReplyGeneric(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ /* All error values are just VERY wild guesses, but these seems to work
+ * almost as expected ...
+ */
+ switch (msg.Buffer[8]) {
+ case 0x00: /* no error */
+ return ERR_NONE;
+ case 0x10: /* same thing opened in phone menus */
+ return ERR_INSIDEPHONEMENU;
+ case 0x13:
+ /* This appears in more cases:
+ * - phone needs PIN code
+ * - we want to close not opened session
+ * For normal users the second case shouldn't occur...
+ */
+ return ERR_SECURITYERROR;
+ case 0x14: /* Bad data */
+ case 0x2f: /* Closing session when not opened */
+ case 0x1f: /* Bad in/out counter in packet/ack */
+ case 0x0e: /* Openning session when not closed */
+ case 0x0C: /* Bad id (item/database) */
+ case 0x11: /* Bad list id */
+ case 0x2A: /* Nonexistant field/item id */
+ case 0x35: /* Too long text */
+ return ERR_BUG;
+ case 0x23: /* Session opened */
+ case 0x80: /* Transfer started */
+ return ERR_NONE;
+ case 0x82: /* Transfer canceled */
+ return ERR_CANCELED;
+ default:
+ smprintf(s, "WARNING: Packet seems to indicate some status by %02X, ignoring!\n", msg.Buffer[8]);
+ return ERR_NONE;
+ }
+}
+
+static GSM_Error ALCATEL_ReplyCommit(GSM_Protocol_Message msg, GSM_StateMachine *s)
+{
+ s->Phone.Data.Priv.ALCATEL.CommitedRecord = msg.Buffer[12] + (msg.Buffer[11] << 8) + (msg.Buffer[10] << 16) + (msg.Buffer[9] << 24);
+ smprintf(s, "Created record %08x\n", s->Phone.Data.Priv.ALCATEL.CommitedRecord);
+ return ERR_NONE;
+}
+
+static GSM_Error ALCATEL_SetIncomingCB (GSM_StateMachine *s, bool enable)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetIncomingCB(s, enable);
+}
+
+static GSM_Error ALCATEL_SetIncomingSMS (GSM_StateMachine *s, bool enable)
+{
+ GSM_Error error;
+
+ if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
+ return ATGEN_SetIncomingSMS(s, enable);
+}
+
+static GSM_Reply_Function ALCATELReplyFunctions[] = {
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelAttach },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelDetach },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelCommit },
+{ALCATEL_ReplyCommit, "\x02",0x00,0x00, ID_AlcatelCommit2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelEnd },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelClose },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelStart },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelSelect1 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelSelect2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelSelect3 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelBegin1 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelBegin2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelGetIds1 },
+{ALCATEL_ReplyGetIds, "\x02",0x00,0x00, ID_AlcatelGetIds2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelGetCategories1 },
+{ALCATEL_ReplyGetCategories, "\x02",0x00,0x00, ID_AlcatelGetCategories2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelGetCategoryText1 },
+{ALCATEL_ReplyGetCategoryText, "\x02",0x00,0x00, ID_AlcatelGetCategoryText2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelAddCategoryText1 },
+{ALCATEL_ReplyAddCategoryText, "\x02",0x00,0x00, ID_AlcatelAddCategoryText2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelGetFields1 },
+{ALCATEL_ReplyGetFields, "\x02",0x00,0x00, ID_AlcatelGetFields2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelGetFieldValue1 },
+{ALCATEL_ReplyGetFieldValue, "\x02",0x00,0x00, ID_AlcatelGetFieldValue2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelDeleteField },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelDeleteItem1 },
+{ALCATEL_ReplyDeleteItem, "\x02",0x00,0x00, ID_AlcatelDeleteItem2 },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelCreateField },
+{ALCATEL_ReplyGeneric, "\x02",0x00,0x00, ID_AlcatelUpdateField },
+{NULL, "\x00",0x00,0x00, ID_None }
+};
+
+GSM_Phone_Functions ALCATELPhone = {
+ /* AFAIK, any 50[0123] phone should work, but I'm not sure whether all
+ * they were ever really released, if yes add them here also.
+ */
+ "alcatel|OT501|OT701|OT715|OT535|OT735|BE5|BF5|BH4",
+ ALCATELReplyFunctions,
+ ALCATEL_Initialise,
+ ALCATEL_Terminate,
+ ALCATEL_DispatchMessage,
+ NOTSUPPORTED, /* ShowStartInfo */
+ ALCATEL_GetManufacturer,
+ ALCATEL_GetModel,
+ ALCATEL_GetFirmware,
+ ALCATEL_GetIMEI,
+ NOTSUPPORTED, /* GetOriginalIMEI */
+ NOTSUPPORTED, /* GetManufactureMonth */
+ ALCATEL_GetProductCode,
+ NOTSUPPORTED, /* GetHardware */
+ NOTSUPPORTED, /* GetPPM */
+ ALCATEL_GetSIMIMSI,
+ ALCATEL_GetDateTime,
+ ALCATEL_SetDateTime,
+ ALCATEL_GetAlarm,
+ ALCATEL_SetAlarm,
+ NOTSUPPORTED, /* GetLocale */
+ NOTSUPPORTED, /* SetLocale */
+ ALCATEL_PressKey,
+ ALCATEL_Reset,
+ ALCATEL_ResetPhoneSettings,
+ ALCATEL_EnterSecurityCode,
+ ALCATEL_GetSecurityStatus,
+ ALCATEL_GetDisplayStatus,
+ ALCATEL_SetAutoNetworkLogin,
+ ALCATEL_GetBatteryCharge,
+ ALCATEL_GetSignalStrength,
+ ALCATEL_GetNetworkInfo,
+ ALCATEL_GetCategory,
+ ALCATEL_AddCategory,
+ ALCATEL_GetCategoryStatus,
+ ALCATEL_GetMemoryStatus,
+ ALCATEL_GetMemory,
+ ALCATEL_GetNextMemory,
+ ALCATEL_SetMemory,
+ ALCATEL_AddMemory,
+ ALCATEL_DeleteMemory,
+ ALCATEL_DeleteAllMemory,
+ NOTSUPPORTED, /* GetSpeedDial */
+ NOTSUPPORTED, /* SetSpeedDial */
+ ALCATEL_GetSMSC,
+ ALCATEL_SetSMSC,
+ ALCATEL_GetSMSStatus,
+ ALCATEL_GetSMS,
+ ALCATEL_GetNextSMS,
+ NOTSUPPORTED, /* SetSMS */
+ ALCATEL_AddSMS,
+ ALCATEL_DeleteSMS,
+ ALCATEL_SendSMS,
+ ALCATEL_SendSavedSMS,
+ ALCATEL_SetIncomingSMS,
+ ALCATEL_SetIncomingCB,
+ ALCATEL_GetSMSFolders,
+ NOTSUPPORTED, /* AddSMSFolder */
+ NOTSUPPORTED, /* DeleteSMSFolder */
+ ALCATEL_DialVoice,
+ ALCATEL_AnswerCall,
+ ALCATEL_CancelCall,
+ NOTSUPPORTED, /* HoldCall */
+ NOTSUPPORTED, /* UnholdCall */
+ NOTSUPPORTED, /* ConferenceCall */
+ NOTSUPPORTED, /* SplitCall */
+ NOTSUPPORTED, /* TransferCall */
+ NOTSUPPORTED, /* SwitchCall */
+ NOTSUPPORTED, /* GetCallDivert */
+ NOTSUPPORTED, /* SetCallDivert */
+ NOTSUPPORTED, /* CancelAllDiverts */
+ NONEFUNCTION, /* SetIncomingCall */
+ NOTSUPPORTED, /* SetIncomingUSSD */
+ ALCATEL_SendDTMF,
+ NOTSUPPORTED, /* GetRingtone */
+ NOTSUPPORTED, /* SetRingtone */
+ NOTSUPPORTED, /* GetRingtonesInfo */
+ NOTSUPPORTED, /* DeleteUserRingtones */
+ NOTSUPPORTED, /* PlayTone */
+ NOTSUPPORTED, /* GetWAPBookmark */
+ NOTSUPPORTED, /* SetWAPBookmark */
+ NOTSUPPORTED, /* DeleteWAPBookmark */
+ NOTSUPPORTED, /* GetWAPSettings */
+ NOTSUPPORTED, /* SetWAPSettings */
+ NOTSUPPORTED, /* GetMMSSettings */
+ NOTSUPPORTED, /* SetMMSSettings */
+ NOTSUPPORTED, /* GetSyncMLSettings */
+ NOTSUPPORTED, /* SetSyncMLSettings */
+ NOTSUPPORTED, /* GetChatSettings */
+ NOTSUPPORTED, /* SetChatSettings */
+ NOTSUPPORTED, /* GetBitmap */
+ NOTSUPPORTED, /* SetBitmap */
+ ALCATEL_GetToDoStatus,
+ ALCATEL_GetToDo,
+ ALCATEL_GetNextToDo,
+ ALCATEL_SetToDo,
+ ALCATEL_AddToDo,
+ ALCATEL_DeleteToDo,
+ ALCATEL_DeleteAllToDo,
+ ALCATEL_GetCalendarStatus,
+ ALCATEL_GetCalendar,
+ ALCATEL_GetNextCalendar,
+ ALCATEL_SetCalendar,
+ ALCATEL_AddCalendar,
+ ALCATEL_DeleteCalendar,
+ ALCATEL_DeleteAllCalendar,
+ NOTSUPPORTED, /* GetCalendarSettings */
+ NOTSUPPORTED, /* SetCalendarSettings */
+ NOTSUPPORTED, /* GetNote */
+ NOTSUPPORTED, /* GetProfile */
+ NOTSUPPORTED, /* SetProfile */
+ NOTSUPPORTED, /* GetFMStation */
+ NOTSUPPORTED, /* SetFMStation */
+ NOTSUPPORTED, /* ClearFMStations */
+ NOTSUPPORTED, /* GetNextFileFolder */
+ NOTSUPPORTED, /* GetFilePart */
+ NOTSUPPORTED, /* AddFilePart */
+ NOTSUPPORTED, /* GetFileSystemStatus */
+ NOTSUPPORTED, /* DeleteFile */
+ NOTSUPPORTED, /* AddFolder */
+ NOTSUPPORTED, /* GetGPRSAccessPoint */
+ NOTSUPPORTED /* SetGPRSAccessPoint */
+};
+
+#endif
+#endif
+
+/* How should editor hadle tabs in this file? Add editor commands here.
+ * vim: noexpandtab sw=8 ts=8 sts=8:
+ */