Logo Search packages:      
Sourcecode: gammu version File versions  Download package

alcatel.c

/* (c) 2002-2005 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

/* Various flags */
#define ALCATEL_UNICODE_FLAG        0x80


/* 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_SetFastSMSSending  (GSM_StateMachine *s, bool enable);
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    - probably control char */
      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;
      s->Phone.Data.Priv.ATGEN.Charset    = 0;
      s->Phone.Data.Priv.ATGEN.PBKMemory  = 0;

      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 void ALCATEL_DecodeString(GSM_StateMachine *s, unsigned const char *buffer, unsigned char *target, int maxlen)
{
      GSM_Phone_ALCATELData   *Priv = &s->Phone.Data.Priv.ALCATEL;
      int               len;

      len = buffer[0];
      if (Priv->ProtocolVersion == V_1_1 && (buffer[1] == ALCATEL_UNICODE_FLAG)) {
            /* UCS-2-BE string */
            if (GSM_PHONEBOOK_TEXT_LENGTH < len/2) {
                  smprintf(s, "WARNING: Text truncated, to %d from %d\n", maxlen, len/2 + 1);
                  len = GSM_PHONEBOOK_TEXT_LENGTH * 2;
            }
            memcpy(target, buffer + 2, len);
            Priv->ReturnString[len + 1] = 0;
            Priv->ReturnString[len + 2] = 0;
      } else {
            /* Alcatel alphabet string */
            if (GSM_PHONEBOOK_TEXT_LENGTH < len) {
                  smprintf(s, "WARNING: Text truncated, to %d from %d\n", maxlen, len + 1);
                  len = GSM_PHONEBOOK_TEXT_LENGTH;
            }
            DecodeDefault(target, buffer + 1, len, false, GSM_AlcatelAlphabet);
      }
}

static GSM_Error ALCATEL_EncodeString(GSM_StateMachine *s, unsigned const char *buffer, unsigned char *target, GSM_Alcatel_FieldType type)
{
      GSM_Phone_ALCATELData   *Priv = &s->Phone.Data.Priv.ALCATEL;
      int               len;
      int               maxlen = 0;
      bool              unicode = false;
      unsigned char           text[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)];
      unsigned char           utext[2*(GSM_PHONEBOOK_TEXT_LENGTH + 1)];

      len = UnicodeLength(buffer);
      /* Maximal length is item and phone dependant, we use it only for guessing as phone will report too big entry correctly. */
      if (type == Alcatel_string) {
            if (Priv->ProtocolVersion == V_1_1) {
                  maxlen = 151;
            } else {
                  maxlen = 62;
            }
      } else if (type == Alcatel_phone) {
            if (Priv->ProtocolVersion == V_1_1) {
                  maxlen = 61;
            } else {
                  maxlen = 50;
            }
      } else if (type == 0) {
            /* We're creating category */
            maxlen = 60;
      }

      if (Priv->ProtocolVersion == V_1_1) {

            /* Compare if we would loose some information when not using
             * unicode */
            EncodeDefault(text, buffer, &len, true, GSM_AlcatelAlphabet);
            DecodeDefault(utext, text, len, true, GSM_AlcatelAlphabet);
            if (!mywstrncmp(utext, buffer, len)) {
                  /* Use unicode only when we have enough space */
                  unicode = ((len * 2) < maxlen);
            }
      }

      if (unicode) {
            /* UCS-2-BE string */
            target[0] = len * 2 + 3;
            target[1] = ALCATEL_UNICODE_FLAG;
            memcpy(target + 2, buffer, len * 2 + 2);
      } else {
            /* Alcatel alphabet string */
            EncodeDefault(target + 1, buffer, &len, true, GSM_AlcatelAlphabet);
            target[0] = len;
            target[len + 1] = 0;
      }

      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;
            ALCATEL_DecodeString(s, buffer + 3, Priv->ReturnString, GSM_PHONEBOOK_TEXT_LENGTH);
      } else if (buffer[1] == 0x07 && buffer[2] == 0x3C) {
            /* phone */
            Priv->ReturnType = Alcatel_phone;
            ALCATEL_DecodeString(s, buffer + 3, Priv->ReturnString, GSM_PHONEBOOK_TEXT_LENGTH);
      } 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;


      smprintf(s,"Creating category\n");
      ALCATEL_EncodeString(s, str, buffer + 7, 0);
      buffer[6] = buffer[7] + 1;

      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 + buffer[7], 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;

      ALCATEL_DecodeString(s,msg.Buffer + 14, Priv->ReturnString, GSM_MAX_CATEGORY_NAME_LENGTH);

      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(GSM_StateMachine *s, unsigned char * buffer, GSM_Alcatel_FieldType type, int field, void *data) {
      GSM_Error         error;

      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;

                  error = ALCATEL_EncodeString(s, (char *)data, buffer + 5, Alcatel_string);
                  if (error != ERR_NONE) return error;
                  buffer[0] = 5 + buffer[5];
                  break;
            case Alcatel_phone:
                  buffer[3] = 0x07;
                  buffer[4] = 0x3c;

                  error = ALCATEL_EncodeString(s, (char *)data, buffer + 5, Alcatel_phone);
                  if (error != ERR_NONE) return error;
                  buffer[0] = 5 + buffer[5];
                  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(s, 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[50 + GSM_PHONEBOOK_TEXT_LENGTH] =
                              {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(s, 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:
                        case PBK_CallLength:
                              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++) {
                  entry->Entries[i].AddError = ERR_NONE;
                  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);
                                    entry->Entries[i].AddError = ERR_NOTSUPPORTED;
                              }
                              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:
                        case PBK_CallLength:                      
                              entry->Entries[i].AddError = ERR_NOTSUPPORTED;
                              smprintf(s,"WARNING: Ignoring entry %d, not supported by phone\n", entry->Entries[i].EntryType);
                              break;
                  }
            }
            if (NamePosition != -1) {
                  if (NameSet) {
                        entry->Entries[NamePosition].AddError = ERR_NOTSUPPORTED;
                        smprintf(s,"WARNING: Ignoring name, not supported by phone\n");
                  } else {
                        //mw: fixme ?
                        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            EventDate = {0,0,0,0,0,0,0};
      GSM_DateTime            EventStart = {0,0,0,0,0,0,0};
      GSM_DateTime            EventEnd = {0,0,0,0,0,0,0};
      bool              EventDateSet = false;
      bool              EventStartSet = false;
      bool              EventEndSet = false;
      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;
                        }
                        /* Date and time is composed at the end, when we have all needed data */
                        j++;
                        Note->EntriesNum--;
                        EventDate = Priv->ReturnDateTime;
                        EventDateSet = true;
                        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;
                        }
                        /* Date and time is composed at the end, when we have all needed data */
                        j++;
                        Note->EntriesNum--;
                        EventStart = Priv->ReturnDateTime;
                        EventStartSet = 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;
                        }
                        /* Date and time is composed at the end, when we have all needed data */
                        j++;
                        Note->EntriesNum--;
                        EventEnd = Priv->ReturnDateTime;
                        EventEndSet = 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_TONE_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_TONE_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");
            }
      }
      /* Fill start/stop datetime */
      if (EventDateSet) {
            if (EventStartSet) {
                  Note->Entries[i-j].EntryType = CAL_START_DATETIME;
                  Note->Entries[i-j].Date = EventDate;
                  Note->Entries[i-j].Date.Timezone = EventStart.Timezone;
                  Note->Entries[i-j].Date.Hour = EventStart.Hour;
                  Note->Entries[i-j].Date.Minute = EventStart.Minute;
                  Note->Entries[i-j].Date.Second = EventStart.Second;
                  Note->EntriesNum++;
                  i++;
            }
            if (EventEndSet) {
                  Note->Entries[i-j].EntryType = CAL_END_DATETIME;
                  Note->Entries[i-j].Date = EventDate;
                  Note->Entries[i-j].Date.Timezone = EventEnd.Timezone;
                  Note->Entries[i-j].Date.Hour = EventEnd.Hour;
                  Note->Entries[i-j].Date.Minute = EventEnd.Minute;
                  Note->Entries[i-j].Date.Second = EventEnd.Second;
                  Note->EntriesNum++;
                  i++;
            }
            if (!EventStartSet && !EventEndSet) {
                  Note->Entries[i-j].EntryType = CAL_START_DATETIME;
                  Note->Entries[i-j].Date = EventDate;
                  Note->EntriesNum++;
                  i++;
            }
      }
      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_TONE_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_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_TONE_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_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_TONE_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_TONE_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;
      ToDo->Priority = GSM_Priority_None;

      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:
                                    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;

      /* Set priority if wanted */
      switch (ToDo->Priority) {
            case GSM_Priority_High:
                  val = 0;
                  break;
            case GSM_Priority_Low:
                  val = 2;
                  break;
            case GSM_Priority_Medium:
                  val = 1;
                  break;
            case GSM_Priority_None:
            default:
                  val = -1;
                  break;
      }

      if (val != -1) {
            /* 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;

      /* Set priority if wanted */
      switch (ToDo->Priority) {
            case GSM_Priority_High:
                  val = 0;
                  break;
            case GSM_Priority_Low:
                  val = 2;
                  break;
            case GSM_Priority_Medium:
                  val = 1;
                  break;
            case GSM_Priority_None:
            default:
                  val = -1;
                  break;
      }

      if (val != -1) {
            /* 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 0x0e: /* Opening session when not closed (might be also opened somewhere else) */
            case 0x10: /* Some 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 */
                  return ERR_INVALIDDATA;
            case 0x2f: /* Closing session when not opened */
            case 0x1f: /* Bad in/out counter in packet/ack */
            case 0x0C: /* Bad id (item/database) */
            case 0x11: /* Bad list id */
            case 0x2A: /* Nonexistant field/item id */
                  smprintf(s, "WARNING: Bug reply %02X\n", msg.Buffer[8]);
                  return ERR_BUG;
            case 0x35: /* Too long text */
                  return ERR_INVALIDDATA;
            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_Error ALCATEL_SetFastSMSSending(GSM_StateMachine *s, bool enable)
{
      GSM_Error error;

      if ((error = ALCATEL_SetATMode(s))!= ERR_NONE) return error;
      return ATGEN_SetFastSMSSending(s, enable);
}

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_SetFastSMSSending,
      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,                 /*    GetSyncMLSettings */
      NOTSUPPORTED,                 /*    SetSyncMLSettings */
      NOTSUPPORTED,                 /*    GetChatSettings         */
      NOTSUPPORTED,                 /*    SetChatSettings         */
      NOTSUPPORTED,                 /*    GetMMSSettings          */
      NOTSUPPORTED,                 /*    SetMMSSettings          */
      NOTSUPPORTED,                 /*    GetMMSFolders           */
      NOTSUPPORTED,                 /*    GetNextMMSFileInfo      */
      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,                 /*    GetNoteStatus           */
      NOTSUPPORTED,                 /*    GetNote                 */
      NOTSUPPORTED,                 /*    GetNextNote       */
      NOTSUPPORTED,                 /*    SetNote                 */
      NOTSUPPORTED,                 /*    AddNote                 */
      NOTSUPPORTED,                 /*    DeleteNote        */
      NOTSUPPORTED,                 /*    DeleteAllNotes          */
      NOTSUPPORTED,                 /*    GetProfile        */
      NOTSUPPORTED,                 /*    SetProfile        */
      NOTSUPPORTED,                 /*    GetFMStation            */
      NOTSUPPORTED,                 /*    SetFMStation            */
      NOTSUPPORTED,                 /*    ClearFMStations         */
      NOTSUPPORTED,                 /*    GetNextFileFolder */
      NOTSUPPORTED,                 /*    GetFolderListing  */
      NOTSUPPORTED,                 /*    GetNextRootFolder */
      NOTSUPPORTED,                 /*    SetFileAttributes */
      NOTSUPPORTED,                 /*    GetFilePart       */
      NOTSUPPORTED,                 /*    AddFilePart       */
      NOTSUPPORTED,                 /*    GetFileSystemStatus     */
      NOTSUPPORTED,                 /*    DeleteFile        */
      NOTSUPPORTED,                 /*    AddFolder         */
      NOTSUPPORTED,                 /*    DeleteFolder            */
      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:
 */

Generated by  Doxygen 1.6.0   Back to index