From 88b0d33b8b0b1f6ae320cfc863ca6a47fa8fec22 Mon Sep 17 00:00:00 2001 From: zautrix Date: Sat, 07 Aug 2004 17:24:40 +0000 Subject: Initial revision --- (limited to 'gammu/emb/common/phone/nokia/nfunc.c') diff --git a/gammu/emb/common/phone/nokia/nfunc.c b/gammu/emb/common/phone/nokia/nfunc.c new file mode 100644 index 0000000..3acfb10 --- a/dev/null +++ b/gammu/emb/common/phone/nokia/nfunc.c @@ -0,0 +1,2143 @@ +/* (c) 2002-2004 by Marcin Wiacek */ +/* based on some work from Ralf Thelen, Gabriele Zappi and MyGnokii */ + +#include /* memcpy only */ +#include +#include +#include + +#include "../../gsmstate.h" +#include "../../misc/coding/coding.h" +#include "../../service/sms/gsmsms.h" +#include "../pfunc.h" +#include "nfunc.h" + +unsigned char N71_65_MEMORY_TYPES[] = { + MEM_DC, 0x01, + MEM_MC, 0x02, + MEM_RC, 0x03, + MEM_ME, 0x05, + MEM_SM, 0x06, + MEM_VM, 0x09, + MEM7110_SP, 0x0e, + MEM7110_CG, 0x10, + MEM_ON, 0x17, + 0x00, 0x00 +}; + +int N71_65_PackPBKBlock(GSM_StateMachine *s, int id, int size, int no, unsigned char *buf, unsigned char *block) +{ + smprintf(s, "Packing phonebook block with ID = %i, block number = %i, block length = %i\n",id,no+1,size+6); + + block[0] = id; + block[1] = 0; + block[2] = 0; + block[3] = size + 6; + block[4] = no + 1; + memcpy(block+5, buf, size); + block[5+size] = 0; + + return (size + 6); +} + +int N71_65_EncodePhonebookFrame(GSM_StateMachine *s, unsigned char *req, GSM_MemoryEntry entry, int *block2, bool DCT4, bool VoiceTag) +{ + int count=0, len, i, block=0, j; + char string[500]; + unsigned char type; + + for (i = 0; i < entry.EntriesNum; i++) { + type = 0; + if (entry.Entries[i].EntryType == PBK_Number_General) type = N7110_PBK_NUMBER_GENERAL; + if (entry.Entries[i].EntryType == PBK_Number_Mobile) type = N7110_PBK_NUMBER_MOBILE; + if (entry.Entries[i].EntryType == PBK_Number_Work) type = N7110_PBK_NUMBER_WORK; + if (entry.Entries[i].EntryType == PBK_Number_Fax) type = N7110_PBK_NUMBER_FAX; + if (entry.Entries[i].EntryType == PBK_Number_Home) type = N7110_PBK_NUMBER_HOME; + if (type != 0) { + string[0] = type; + len = UnicodeLength(entry.Entries[i].Text); + + string[1] = 0; + string[2] = 0; + + /* DCT 3 */ + if (!DCT4) string[2] = entry.Entries[i].VoiceTag; + + string[3] = 0; + string[4] = len*2+2; + CopyUnicodeString(string+5,entry.Entries[i].Text); + string[len * 2 + 5] = 0; + count += N71_65_PackPBKBlock(s, N7110_PBK_NUMBER, len*2+6, block++, string, req+count); + + /* DCT 4 */ + if (DCT4 && VoiceTag) { + block++; + req[count++] = N6510_PBK_VOICETAG_ID; + req[count++] = 0; + req[count++] = 0; + req[count++] = 8; + req[count++] = 0x00; + req[count++] = i+1; + req[count++] = 0x00; + req[count++] = entry.Entries[i].VoiceTag; + } + if (DCT4) { + j = 0; + while (entry.Entries[i].SMSList[j] != 0) { + string[0] = i+1; + string[1] = 0x00; + string[2] = 0x02; + string[3] = 0x00; + string[4] = entry.Entries[i].SMSList[j]; + string[5] = 0x00; + count += N71_65_PackPBKBlock(s, N6510_PBK_SMSLIST_ID, 6, block++, string, req+count); + + j++; + } + } + continue; + } + if (entry.Entries[i].EntryType == PBK_Text_Note) type = N7110_PBK_NOTE; + if (entry.Entries[i].EntryType == PBK_Text_Postal) type = N7110_PBK_POSTAL; + if (entry.Entries[i].EntryType == PBK_Text_Email) type = N7110_PBK_EMAIL; + if (entry.Entries[i].EntryType == PBK_Text_Email2) type = N7110_PBK_EMAIL; + if (entry.Entries[i].EntryType == PBK_Text_Name) type = N7110_PBK_NAME; + if (entry.Entries[i].EntryType == PBK_Text_URL) { + type = N7110_PBK_NOTE; + if (DCT4) type = N6510_PBK_URL; + } + if (type != 0) { + len = UnicodeLength(entry.Entries[i].Text); + string[0] = len*2+2; + CopyUnicodeString(string+1,entry.Entries[i].Text); + string[len*2+1] = 0; + count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count); + continue; + + } + if (entry.Entries[i].EntryType == PBK_Caller_Group) { + if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) { + string[0] = entry.Entries[i].Number; + string[1] = 0; + count += N71_65_PackPBKBlock(s, N7110_PBK_GROUP, 2, block++, string, req + count); + } + continue; + } + if (entry.Entries[i].EntryType == PBK_RingtoneID) { + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) { + string[0] = 0x00; + string[1] = 0x00; + string[2] = entry.Entries[i].Number; + count += N71_65_PackPBKBlock(s, N7110_PBK_RINGTONE_ID, 3, block++, string, req + count); + count --; + req[count-5] = 8; + } + continue; + } + if (entry.Entries[i].EntryType == PBK_PictureID) { + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKIMG)) { + string[0] = 0x00; + string[1] = 0x00; + string[2] = 0x00; + string[3] = 0x00; + string[4] = 0x01; + string[5] = entry.Entries[i].Number / 256; + string[6] = entry.Entries[i].Number % 256; + string[7] = 0x00; + string[8] = 0x00; + string[9] = 0x00; + count += N71_65_PackPBKBlock(s, N6510_PBK_PICTURE_ID, 10, block++, string, req + count); + req[count-1] = 0x01; + } + continue; + } + if (entry.Entries[i].EntryType == PBK_Text_UserID) { + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKUSER)) { + string[0] = UnicodeLength(entry.Entries[i].Text)*2; + CopyUnicodeString(string+1,entry.Entries[i].Text); + count += N71_65_PackPBKBlock(s, N6510_PBK_USER_ID, string[0]+2, block++, string, req+count); + req[count-1]--; + } + continue; + } + } + + *block2=block; + + return count; +} + +GSM_Error N71_65_DecodePhonebook(GSM_StateMachine *s, + GSM_MemoryEntry *entry, + GSM_Bitmap *bitmap, + GSM_SpeedDial *speed, + unsigned char *MessageBuffer, + int MessageLength, + bool DayMonthReverse) +{ + unsigned char *Block; + int length = 0, i; + GSM_71_65_Phonebook_Entries_Types Type; + + entry->EntriesNum = 0; + + if (entry->MemoryType==MEM7110_CG) { + bitmap->Text[0] = 0x00; + bitmap->Text[1] = 0x00; + bitmap->DefaultBitmap = true; + bitmap->DefaultRingtone = true; + } + + Block = &MessageBuffer[0]; + while (length != MessageLength) { +#ifdef DEBUG + smprintf(s, "Phonebook entry block - length %i", Block[3]-6); + if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, di.dl, Block+5, Block[3]-6); +#endif + if (entry->EntriesNum==GSM_PHONEBOOK_ENTRIES) { + smprintf(s, "Too many entries\n"); + return ERR_UNKNOWNRESPONSE; + } + + Type = 0; + if (Block[0] == N7110_PBK_NAME) { + Type = PBK_Text_Name; smprintf(s,"Name "); + } + if (Block[0] == N7110_PBK_EMAIL) { + Type = PBK_Text_Email; smprintf(s,"Email "); + } + if (Block[0] == N7110_PBK_POSTAL) { + Type = PBK_Text_Postal; smprintf(s,"Postal "); + } + if (Block[0] == N7110_PBK_NOTE) { + Type = PBK_Text_Note; smprintf(s,"Text note "); + } + if (Block[0] == N6510_PBK_URL) { + Type = PBK_Text_URL; smprintf(s,"URL "); + } + if (Type != 0) { + if (Block[5]/2>GSM_PHONEBOOK_TEXT_LENGTH) { + smprintf(s, "Too long text\n"); + return ERR_UNKNOWNRESPONSE; + } + memcpy(entry->Entries[entry->EntriesNum].Text,Block+6,Block[5]); + entry->Entries[entry->EntriesNum].EntryType=Type; + smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + if (Block[0] == N7110_PBK_NAME) { + if (entry->MemoryType==MEM7110_CG) { + memcpy(bitmap->Text,Block+6,Block[5]); + } + } + entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + + if (Block[0] == N7110_PBK_DATETIME) { + entry->Entries[entry->EntriesNum].EntryType=PBK_Date; + NOKIA_DecodeDateTime(s, Block+6, &entry->Entries[entry->EntriesNum].Date); + if (DayMonthReverse) { + i = entry->Entries[entry->EntriesNum].Date.Month; + entry->Entries[entry->EntriesNum].Date.Month = entry->Entries[entry->EntriesNum].Date.Day; + entry->Entries[entry->EntriesNum].Date.Day = i; + } + entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N6510_PBK_PICTURE_ID) { + entry->Entries[entry->EntriesNum].EntryType=PBK_PictureID; + smprintf(s, "Picture ID \"%i\"\n",Block[10]*256+Block[11]); + entry->Entries[entry->EntriesNum].Number=Block[10]*256+Block[11]; + entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + + if (Block[0] == N7110_PBK_NUMBER) { + if (Block[5] == 0x00) { + Type = PBK_Number_General; smprintf(s,"General number "); + } + /* Not assigned dialed number */ + if (Block[5] == 0x01) { + Type = PBK_Number_General; smprintf(s,"General number "); + } + if (Block[5] == 0x0B) { + Type = PBK_Number_General; smprintf(s,"General number "); + } + /* In many firmwares 0x55 visible after using + * Save from Call Register menu and saving number + * to existing phonebook entry */ + if (Block[5] == 0x55) { + Type = PBK_Number_General; smprintf(s,"General number "); + } + if (Block[5] == N7110_PBK_NUMBER_GENERAL) { + Type = PBK_Number_General; smprintf(s,"General number "); + } + if (Block[5] == N7110_PBK_NUMBER_WORK) { + Type = PBK_Number_Work; smprintf(s,"Work number "); + } + if (Block[5] == N7110_PBK_NUMBER_FAX) { + Type = PBK_Number_Fax; smprintf(s,"Fax number "); + } + if (Block[5] == N7110_PBK_NUMBER_MOBILE) { + Type = PBK_Number_Mobile; smprintf(s,"Mobile number "); + } + if (Block[5] == N7110_PBK_NUMBER_HOME) { + Type = PBK_Number_Home; smprintf(s,"Home number "); + } + if (Type == 0x00) { + smprintf(s, "Unknown number type %02x\n",Block[5]); + return ERR_UNKNOWNRESPONSE; + } + entry->Entries[entry->EntriesNum].EntryType=Type; + if (Block[9]/2>GSM_PHONEBOOK_TEXT_LENGTH) { + smprintf(s, "Too long text\n"); + return ERR_UNKNOWNRESPONSE; + } + memcpy(entry->Entries[entry->EntriesNum].Text,Block+10,Block[9]); + smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + /* DCT3 phones like 6210 */ + entry->Entries[entry->EntriesNum].VoiceTag = Block[7]; +#ifdef DEBUG + if (entry->Entries[entry->EntriesNum].VoiceTag != 0) smprintf(s, "Voice tag %i assigned\n",Block[7]); +#endif + entry->Entries[entry->EntriesNum].SMSList[0] = 0; + entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N7110_PBK_RINGTONE_ID) { + if (entry->MemoryType==MEM7110_CG) { + bitmap->RingtoneID=Block[5]; + if (Block[5] == 0x00) bitmap->RingtoneID=Block[7]; + smprintf(s, "Ringtone ID : %i\n",bitmap->RingtoneID); + bitmap->DefaultRingtone = false; + bitmap->FileSystemRingtone = false; + } else { + entry->Entries[entry->EntriesNum].EntryType=PBK_RingtoneID; + smprintf(s, "Ringtone ID \"%i\"\n",Block[7]); + entry->Entries[entry->EntriesNum].Number=Block[7]; + entry->EntriesNum ++; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N7110_PBK_LOGOON) { + if (entry->MemoryType==MEM7110_CG) { + bitmap->BitmapEnabled=(Block[5]==0x00 ? false : true); + smprintf(s, "Logo : %s\n", bitmap->BitmapEnabled==true ? "enabled":"disabled"); + } else { + return ERR_UNKNOWNRESPONSE; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N7110_PBK_GROUPLOGO) { + if (entry->MemoryType==MEM7110_CG) { + smprintf(s, "Caller logo\n"); + PHONE_DecodeBitmap(GSM_NokiaCallerLogo, Block+10, bitmap); + bitmap->DefaultBitmap = false; + } else { + return ERR_UNKNOWNRESPONSE; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N7110_PBK_GROUP) { + entry->Entries[entry->EntriesNum].EntryType=PBK_Caller_Group; + smprintf(s, "Caller group \"%i\"\n",Block[5]); + entry->Entries[entry->EntriesNum].Number=Block[5]; + if (Block[5]!=0) entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N6510_PBK_VOICETAG_ID) { + smprintf(s, "Entry %i has voice tag %i\n",Block[5]-1,Block[7]); + entry->Entries[Block[5]-1].VoiceTag = Block[7]; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + + /* 6210 5.56, SIM speed dials or ME with 1 number */ + if (Block[0] == N7110_PBK_SIM_SPEEDDIAL) { + if (entry->MemoryType==MEM7110_SP) { +#ifdef DEBUG + smprintf(s, "location %i\n",(Block[6]*256+Block[7])); +#endif + speed->MemoryType = MEM_ME; + if (Block[8] == 0x06) speed->MemoryType = MEM_SM; + speed->MemoryLocation = (Block[6]*256+Block[7]); + speed->MemoryNumberID = 2; + } else { + return ERR_UNKNOWNRESPONSE; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + + if (Block[0] == N7110_PBK_SPEEDDIAL) { + if (entry->MemoryType==MEM7110_SP) { +#ifdef DEBUG + switch (Block[12]) { + case 0x05: smprintf(s, "ME\n"); break; + case 0x06: smprintf(s, "SM\n"); break; + default : smprintf(s, "%02x\n",Block[12]); + } + smprintf(s, "location %i, number %i in location\n", + (Block[6]*256+Block[7])-1,Block[14]); +#endif + switch (Block[12]) { + case 0x05: speed->MemoryType = MEM_ME; break; + case 0x06: speed->MemoryType = MEM_SM; break; + } + speed->MemoryLocation = (Block[6]*256+Block[7])-1; + speed->MemoryNumberID = Block[14]; + } else { + return ERR_UNKNOWNRESPONSE; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N6510_PBK_RINGTONEFILE_ID) { + smprintf(s, "Ringtone ID with possibility of using filesystem\n"); + if (entry->MemoryType==MEM7110_CG) { + if (Block[9] == 0x01) { + smprintf(s, "Filesystem ringtone ID: %02x\n",Block[10]*256+Block[11]); + bitmap->FileSystemRingtone = true; + } else { + smprintf(s, "Internal ringtone ID: %02x\n",Block[10]*256+Block[11]); + bitmap->FileSystemRingtone = false; + } + bitmap->RingtoneID = Block[10]*256+Block[11]; + bitmap->DefaultRingtone = false; + } else { + return ERR_UNKNOWNRESPONSE; + } + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N6510_PBK_SMSLIST_ID) { + smprintf(s, "Entry %i is assigned to SMS list %i\n",Block[5]-1,Block[9]); + i = 0; + while(entry->Entries[Block[5]-1].SMSList[i] != 0) i++; + entry->Entries[Block[5]-1].SMSList[i+1] = 0; + entry->Entries[Block[5]-1].SMSList[i] = Block[9]; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N6510_PBK_USER_ID) { + smprintf(s, "User ID:"); + entry->Entries[entry->EntriesNum].EntryType=PBK_Text_UserID; + if (Block[5]/2>GSM_PHONEBOOK_TEXT_LENGTH) { + smprintf(s, "Too long text\n"); + return ERR_UNKNOWNRESPONSE; + } + memcpy(entry->Entries[entry->EntriesNum].Text,Block+6,Block[5]); + smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum ++; + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + if (Block[0] == N7110_PBK_UNKNOWN1) { + smprintf(s,"Unknown entry\n"); + + length = length + Block[3]; + Block = &Block[(int) Block[3]]; + continue; + } + + smprintf(s, "ERROR: unknown pbk entry 0x%02x\n",Block[0]); + return ERR_UNKNOWNRESPONSE; + } + + if (entry->EntriesNum == 0) return ERR_EMPTY; + + return ERR_NONE; +} + +void NOKIA_GetDefaultCallerGroupName(GSM_StateMachine *s, GSM_Bitmap *Bitmap) +{ + Bitmap->DefaultName = false; + if (Bitmap->Text[0]==0x00 && Bitmap->Text[1]==0x00) { + Bitmap->DefaultName = true; + switch(Bitmap->Location) { + case 1: EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Family"),strlen(GetMsg(s->msg,"Family"))); + break; + case 2: EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"VIP"),strlen(GetMsg(s->msg,"VIP"))); + break; + case 3: EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Friends"),strlen(GetMsg(s->msg,"Friends"))); + break; + case 4: EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Colleagues"),strlen(GetMsg(s->msg,"Colleagues"))); + break; + case 5: EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Other"),strlen(GetMsg(s->msg,"Other"))); + break; + } + } +} + +void NOKIA_DecodeDateTime(GSM_StateMachine *s, unsigned char* buffer, GSM_DateTime *datetime) +{ + datetime->Year = buffer[0] * 256 + buffer[1]; + datetime->Month = buffer[2]; + datetime->Day = buffer[3]; + + datetime->Hour = buffer[4]; + datetime->Minute = buffer[5]; + datetime->Second = buffer[6]; + + smprintf(s, "Decoding date and time\n"); + smprintf(s, " Time: %02d:%02d:%02d\n", + datetime->Hour, datetime->Minute, datetime->Second); + smprintf(s, " Date: %4d/%02d/%02d\n", + datetime->Year, datetime->Month, datetime->Day); +} + +#if defined(GSM_ENABLE_NOKIA_DCT3) || defined(GSM_ENABLE_NOKIA_DCT4) + +/* --------------------- Some general Nokia functions ---------------------- */ + +void NOKIA_DecodeSMSState(GSM_StateMachine *s, unsigned char state, GSM_SMSMessage *sms) +{ + switch (state) { + case 0x01 : sms->State = SMS_Read; break; + case 0x03 : sms->State = SMS_UnRead; break; + case 0x05 : sms->State = SMS_Sent; break; + case 0x07 : sms->State = SMS_UnSent; break; + default : smprintf(s, "Unknown SMS state: %02x\n",state); + } +} + +GSM_Error NOKIA_ReplyGetPhoneString(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + strcpy(s->Phone.Data.PhoneString, msg.Buffer+s->Phone.Data.StartPhoneString); + return ERR_NONE; +} + +/* Some strings are very easy. Some header, after it required string and 0x00. + * We can get them using this function. We give frame to send (*string), + * type of message (type), pointer for buffer for response (*value), request + * type (request) and what is start byte in response for our string + */ +GSM_Error NOKIA_GetPhoneString(GSM_StateMachine *s, unsigned char *msgframe, int msglen, unsigned char msgtype, char *retvalue, GSM_Phone_RequestID request, int startresponse) +{ + retvalue[0] = 0; + s->Phone.Data.StartPhoneString = startresponse; + s->Phone.Data.PhoneString = retvalue; + return GSM_WaitFor (s, msgframe, msglen,msgtype, 4, request); +} + +GSM_Error NOKIA_GetManufacturer(GSM_StateMachine *s) +{ + strcpy(s->Phone.Data.Manufacturer,"Nokia"); + return ERR_NONE; +} + +/* Many functions contains such strings: + * (1. length/256) - exist or not + * 2. length%256 + * 3. string (unicode, no termination) + * This function read string to output and increases counter + */ +void NOKIA_GetUnicodeString(GSM_StateMachine *s, int *current, unsigned char *input, unsigned char *output, bool FullLength) +{ + int length; + + if (FullLength) { + length = (input[*current]*256+input[*current+1])*2; + memcpy(output,input+(*current+2),length); + *current = *current + 2 + length; + } else { + length = (input[*current])*2; + memcpy(output,input+(*current+1),length); + *current = *current + 1 + length; + } + + output[length ] = 0; + output[length+1] = 0; +} + +int NOKIA_SetUnicodeString(GSM_StateMachine *s, unsigned char *dest, unsigned char *string, bool FullLength) +{ + int length; + + length = UnicodeLength(string); + if (FullLength) { + dest[0] = length / 256; + dest[1] = length % 256; + CopyUnicodeString(dest + 2, string); + return 2+length*2; + } else { + dest[0] = length % 256; + CopyUnicodeString(dest + 1, string); + return 1+length*2; + } +} + +/* Returns correct ID for concrete memory type */ +GSM_MemoryType NOKIA_GetMemoryType(GSM_StateMachine *s, GSM_MemoryType memory_type, unsigned char *ID) +{ + int i=0; + + while (ID[i+1]!=0x00) { + if (ID[i]==memory_type) return ID[i+1]; + i=i+2; + } + return 0xff; +} + +void NOKIA_EncodeDateTime(GSM_StateMachine *s, unsigned char* buffer, GSM_DateTime *datetime) +{ + buffer[0] = datetime->Year / 256; + buffer[1] = datetime->Year % 256; + buffer[2] = datetime->Month; + buffer[3] = datetime->Day; + + buffer[4] = datetime->Hour; + buffer[5] = datetime->Minute; +} + +void NOKIA_SortSMSFolderStatus(GSM_StateMachine *s, GSM_NOKIASMSFolder *Folder) +{ + int i,j; + + if (Folder->Number!=0) { + /* Bouble sorting */ + i=0; + while (i!=Folder->Number-1) { + if (Folder->Location[i]>Folder->Location[i+1]) { + j=Folder->Location[i]; + Folder->Location[i]=Folder->Location[i+1]; + Folder->Location[i+1]=j; + i=0; + } else { + i++; + } + } +#ifdef DEBUG + smprintf(s, "Locations: "); + for (i=0;iNumber;i++) { + smprintf(s, "%i ",Folder->Location[i]); + } + smprintf(s, "\n"); +#endif + } +} + +void NOKIA_GetDefaultProfileName(GSM_StateMachine *s, GSM_Profile *Profile) +{ + if (Profile->DefaultName) { + switch(Profile->Location) { + case 1: EncodeUnicode(Profile->Name,GetMsg(s->msg,"General"),strlen(GetMsg(s->msg,"General"))); + break; + case 2: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Silent"),strlen(GetMsg(s->msg,"Silent"))); + break; + case 3: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Meeting"),strlen(GetMsg(s->msg,"Meeting"))); + break; + case 4: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Outdoor"),strlen(GetMsg(s->msg,"Outdoor"))); + break; + case 5: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Pager"),strlen(GetMsg(s->msg,"Pager"))); + break; + case 6: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Car"),strlen(GetMsg(s->msg,"Car"))); + break; + case 7: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Headset"),strlen(GetMsg(s->msg,"Headset"))); + break; + } + } +} + +/* - Shared for DCT3 (n6110.c, n7110.c, n9110.c) and DCT4 (n6510.c) phones - */ + +GSM_Error DCT3DCT4_ReplyCallDivert(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_MultiCallDivert *cd = s->Phone.Data.Divert; + int i,pos = 11,j; + + switch (msg.Buffer[3]) { + case 0x02: + smprintf(s,"Message: Call divert status received\n"); + smprintf(s," Divert type: "); + switch (msg.Buffer[6]) { + case 0x43: smprintf(s,"when busy"); break; + case 0x3d: smprintf(s,"when not answered"); break; + case 0x3e: smprintf(s,"when phone off or no coverage"); break; + case 0x15: smprintf(s,"all types of diverts"); break; + default: smprintf(s,"unknown %i",msg.Buffer[6]); break; + } + /* 6150 */ + if (msg.Length == 0x0b) { + cd->Response.EntriesNum = 0; + return ERR_NONE; + } + cd->Response.EntriesNum = msg.Buffer[10]; + for (i=0;iResponse.EntriesNum;i++) { + smprintf(s,"\n Calls type : "); + switch (msg.Buffer[pos]) { + case 0x0b: + smprintf(s,"voice"); + cd->Response.Entries[i].CallType = GSM_DIVERT_VoiceCalls; + break; + case 0x0d: + smprintf(s,"fax"); + cd->Response.Entries[i].CallType = GSM_DIVERT_FaxCalls; + break; + case 0x19: + smprintf(s,"data"); + cd->Response.Entries[i].CallType = GSM_DIVERT_DataCalls; + break; + default: + smprintf(s,"unknown %i",msg.Buffer[pos]); + /* 6310i */ + cd->Response.EntriesNum = 0; + return ERR_NONE; + break; + } + smprintf(s,"\n"); + j = pos + 2; + while (msg.Buffer[j] != 0x00) j++; + msg.Buffer[pos+1] = j - pos - 2; + GSM_UnpackSemiOctetNumber(cd->Response.Entries[i].Number,msg.Buffer+(pos+1),false); + smprintf(s," Number : %s\n",DecodeUnicodeString(cd->Response.Entries[i].Number)); + cd->Response.Entries[i].Timeout = msg.Buffer[pos+34]; + smprintf(s," Timeout : %i seconds\n",msg.Buffer[pos+34]); + pos+=35; + } + return ERR_NONE; + case 0x03: + smprintf(s,"Message: Call divert status receiving error ?\n"); + return ERR_UNKNOWN; + } + return ERR_UNKNOWNRESPONSE; +} + +static GSM_Error DCT3DCT4_CallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert, bool get) +{ + int length = 0x09; + unsigned char req[55] = {N6110_FRAME_HEADER, 0x01, + 0x05, /* operation = Query */ + 0x00, + 0x00, /* divert type */ + 0x00, /* call type */ + 0x00}; + + if (!get) { + if (UnicodeLength(divert->Request.Number) == 0) { + req[4] = 0x04; + } else { + req[4] = 0x03; + req[8] = 0x01; + req[29] = GSM_PackSemiOctetNumber(divert->Request.Number, req + 9, false); + req[52] = divert->Request.Timeout; + length = 55; + } + } + switch (divert->Request.DivertType) { + case GSM_DIVERT_AllTypes : req[6] = 0x15; break; + case GSM_DIVERT_Busy : req[6] = 0x43; break; + case GSM_DIVERT_NoAnswer : req[6] = 0x3d; break; + case GSM_DIVERT_OutOfReach: req[6] = 0x3e; break; + default : return ERR_NOTIMPLEMENTED; + } + + switch (divert->Request.CallType) { + case GSM_DIVERT_AllCalls : break; + case GSM_DIVERT_VoiceCalls: req[7] = 0x0b; break; + case GSM_DIVERT_FaxCalls : req[7] = 0x0d; break; + case GSM_DIVERT_DataCalls : req[7] = 0x19; break; + default : return ERR_NOTIMPLEMENTED; + } + + s->Phone.Data.Divert = divert; + smprintf(s, "Call divert\n"); + return GSM_WaitFor (s, req, length, 0x06, 10, ID_Divert); +} + +GSM_Error DCT3DCT4_GetCallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert) +{ + return DCT3DCT4_CallDivert(s,divert,true); +} + +GSM_Error DCT3DCT4_SetCallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert) +{ + return DCT3DCT4_CallDivert(s,divert,false); +} + +GSM_Error DCT3DCT4_CancelAllDiverts(GSM_StateMachine *s) +{ + GSM_MultiCallDivert divert; + unsigned char req[55] = {N6110_FRAME_HEADER, 0x01, + 0x04, /* operation = Disable */ + 0x00, + 0x02, /* divert type */ + 0x00, /* call type */ + 0x00}; + + s->Phone.Data.Divert = &divert; + smprintf(s, "Call divert\n"); + return GSM_WaitFor (s, req, 0x09, 0x06, 10, ID_Divert); +} + +GSM_Error DCT3DCT4_ReplyGetActiveConnectSet(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_Phone_Data *Data = &s->Phone.Data; + + Data->WAPSettings->Active = false; + if (Data->WAPSettings->Location - 1 == msg.Buffer[4]) { + Data->WAPSettings->Active = true; + } + return ERR_NONE; +} + +GSM_Error DCT3DCT4_GetActiveConnectSet(GSM_StateMachine *s) +{ + unsigned char GetSetreq[] = {N6110_FRAME_HEADER, 0x0F}; + + smprintf(s, "Checking, if connection settings are active\n"); + return GSM_WaitFor (s, GetSetreq, 4, 0x3f, 4, ID_GetConnectSet); +} + +GSM_Error DCT3DCT4_ReplySetActiveConnectSet(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Connection settings activated\n"); + return ERR_NONE; +} + +GSM_Error DCT3DCT4_SetActiveConnectSet(GSM_StateMachine *s, GSM_MultiWAPSettings *settings) +{ + unsigned char reqActivate[] = {N6110_FRAME_HEADER, 0x12, + 0x00}; /* Location */ + + if (settings->Active) { + reqActivate[4] = settings->Location-1; + smprintf(s, "Activating connection settings number %i\n",settings->Location); + return GSM_WaitFor (s, reqActivate, 5, 0x3f, 4, ID_SetMMSSettings); + } + return ERR_NONE; +} + + +GSM_Error DCT3DCT4_SendDTMF(GSM_StateMachine *s, char *DTMFSequence) +{ + unsigned char req[100] = {N6110_FRAME_HEADER, 0x50, + 0x00}; /* Length */ + + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NODTMF)) return ERR_NOTSUPPORTED; + if (strlen(DTMFSequence) > 100 - 5) return ERR_NOTSUPPORTED; + + req[4] = strlen(DTMFSequence); + + memcpy(req+5,DTMFSequence,strlen(DTMFSequence)); + + smprintf(s, "Sending DTMF\n"); + return GSM_WaitFor (s, req, 5+strlen(DTMFSequence), 0x01, 4, ID_SendDTMF); +} + +GSM_Error DCT3DCT4_ReplyGetWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s, bool FullLength) +{ + int tmp; + GSM_Phone_Data *Data = &s->Phone.Data; + + smprintf(s, "WAP bookmark received\n"); + switch (msg.Buffer[3]) { + case 0x07: + tmp = 4; + + Data->WAPBookmark->Location = msg.Buffer[tmp] * 256 + msg.Buffer[tmp+1]; + smprintf(s, "Location: %i\n",Data->WAPBookmark->Location); + tmp = tmp + 2; + + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer, Data->WAPBookmark->Title, FullLength); + smprintf(s, "Title : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Title)); + + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer, Data->WAPBookmark->Address, FullLength); + smprintf(s, "Address : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Address)); + + return ERR_NONE; + case 0x08: + switch (msg.Buffer[4]) { + case 0x01: + smprintf(s, "Security error. Inside WAP bookmarks menu\n"); + return ERR_INSIDEPHONEMENU; + case 0x02: + smprintf(s, "Invalid or empty\n"); + return ERR_INVALIDLOCATION; + default: + smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]); + return ERR_UNKNOWNRESPONSE; + } + break; + } + return ERR_UNKNOWNRESPONSE; +} + +GSM_Error DCT3DCT4_ReplySetWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + switch (msg.Buffer[3]) { + case 0x0A: + smprintf(s, "WAP bookmark set OK\n"); + return ERR_NONE; + case 0x0B: + smprintf(s, "WAP bookmark setting error\n"); + switch (msg.Buffer[4]) { + case 0x01: + smprintf(s, "Security error. Inside WAP bookmarks menu\n"); + return ERR_INSIDEPHONEMENU; + case 0x02: + smprintf(s, "Can't write to empty location ?\n"); + return ERR_EMPTY; + case 0x04: + smprintf(s, "Full memory\n"); + return ERR_FULL; + default: + smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]); + return ERR_UNKNOWNRESPONSE; + } + } + return ERR_UNKNOWNRESPONSE; +} + +GSM_Error DCT3DCT4_ReplyEnableConnectFunc(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Connection functions enabled\n"); + return ERR_NONE; +} + +GSM_Error DCT3DCT4_EnableWAPFunctions(GSM_StateMachine *s) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x00}; + + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOWAP)) return ERR_NOTSUPPORTED; + + smprintf(s, "Enabling WAP\n"); + return GSM_WaitFor (s, req, 4, 0x3f, 4, ID_EnableConnectFunc); +} + +GSM_Error DCT3DCT4_ReplyDisableConnectFunc(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Connection functions disabled\n"); + return ERR_NONE; +} + +GSM_Error DCT3DCT4_DisableConnectionFunctions(GSM_StateMachine *s) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x03}; + + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOWAP)) return ERR_NOTSUPPORTED; + + smprintf(s, "Disabling connection settings\n"); + return GSM_WaitFor (s, req, 4, 0x3f, 4, ID_DisableConnectFunc); +} + +GSM_Error DCT3DCT4_ReplyDelWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + switch (msg.Buffer[3]) { + case 0x0D: + smprintf(s, "WAP bookmark deleted OK\n"); + return ERR_NONE; + case 0x0E: + smprintf(s, "WAP bookmark deleting error\n"); + switch (msg.Buffer[4]) { + case 0x01: + smprintf(s, "Security error. Inside WAP bookmarks menu\n"); + return ERR_SECURITYERROR; + case 0x02: + smprintf(s, "Invalid location\n"); + return ERR_INVALIDLOCATION; + default: + smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]); + return ERR_UNKNOWNRESPONSE; + } + } + return ERR_UNKNOWNRESPONSE; +} + +GSM_Error DCT3DCT4_DeleteWAPBookmarkPart(GSM_StateMachine *s, GSM_WAPBookmark *bookmark) +{ + GSM_Error error; + unsigned char req[] = {N6110_FRAME_HEADER, 0x0C, + 0x00, 0x00}; /* Location */ + + req[5] = bookmark->Location; + + smprintf(s, "Deleting WAP bookmark\n"); + error = GSM_WaitFor (s, req, 6, 0x3f, 4, ID_DeleteWAPBookmark); + if (error != ERR_NONE) { + if (error == ERR_INVALIDLOCATION || error == ERR_INSIDEPHONEMENU) { + DCT3DCT4_DisableConnectionFunctions(s); + } + return error; + } + + return DCT3DCT4_DisableConnectionFunctions(s); +} + +GSM_Error DCT3DCT4_GetWAPBookmarkPart(GSM_StateMachine *s, GSM_WAPBookmark *bookmark) +{ + GSM_Error error; + unsigned char req[] = {N6110_FRAME_HEADER, 0x06, + 0x00, 0x00}; /* Location */ + + req[5]=bookmark->Location-1; + + s->Phone.Data.WAPBookmark=bookmark; + smprintf(s, "Getting WAP bookmark\n"); + error = GSM_WaitFor (s, req, 6, 0x3f, 4, ID_GetWAPBookmark); + if (error != ERR_NONE) { + if (error == ERR_INVALIDLOCATION || error == ERR_INSIDEPHONEMENU) { + DCT3DCT4_DisableConnectionFunctions(s); + } + return error; + } + + return DCT3DCT4_DisableConnectionFunctions(s); +} + +GSM_Error DCT3DCT4_CancelCall(GSM_StateMachine *s, int ID) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x08, 0x00, 0x85}; + + req[4] = (unsigned char)ID; + s->Phone.Data.CallID = ID; + + smprintf(s, "Canceling single call\n"); + return GSM_WaitFor (s, req, 6, 0x01, 4, ID_CancelCall); +} + +GSM_Error DCT3DCT4_AnswerCall(GSM_StateMachine *s, int ID) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x06, 0x00, 0x00}; + + req[4] = (unsigned char)ID; + s->Phone.Data.CallID = ID; + + smprintf(s, "Answering single call\n"); + return GSM_WaitFor (s, req, 6, 0x01, 4, ID_AnswerCall); +} + +GSM_Error DCT3DCT4_ReplyGetModelFirmware(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_Lines lines; + GSM_Phone_Data *Data = &s->Phone.Data; + + SplitLines(msg.Buffer, msg.Length, &lines, "\x20\x0A", 2, false); + + strcpy(Data->Model,GetLineString(msg.Buffer, lines, 4)); + smprintf(s, "Received model %s\n",Data->Model); + Data->ModelInfo = GetModelData(NULL,Data->Model,NULL); + + strcpy(Data->VerDate,GetLineString(msg.Buffer, lines, 3)); + smprintf(s, "Received firmware date %s\n",Data->VerDate); + + strcpy(Data->Version,GetLineString(msg.Buffer, lines, 2)); + smprintf(s, "Received firmware version %s\n",Data->Version); + GSM_CreateFirmwareNumber(s); + + return ERR_NONE; +} + +GSM_Error DCT3DCT4_GetModel (GSM_StateMachine *s) +{ + unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00}; + GSM_Error error; + + if (strlen(s->Phone.Data.Model)>0) return ERR_NONE; + + smprintf(s, "Getting model\n"); + error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetModel); + if (error==ERR_NONE) { + if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL || + s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) { + smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model); + smprintf(s, "[Firmware version - \"%s\"]\n",s->Phone.Data.Version); + smprintf(s, "[Firmware date - \"%s\"]\n",s->Phone.Data.VerDate); + } + } + return error; +} + +GSM_Error DCT3DCT4_GetFirmware (GSM_StateMachine *s) +{ + unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00}; + GSM_Error error; + + if (strlen(s->Phone.Data.Version)>0) return ERR_NONE; + + smprintf(s, "Getting firmware version\n"); + error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetFirmware); + if (error==ERR_NONE) { + if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL || + s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) { + smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model); + smprintf(s, "[Firmware version - \"%s\"]\n",s->Phone.Data.Version); + smprintf(s, "[Firmware date - \"%s\"]\n",s->Phone.Data.VerDate); + } + } + return error; +} + +/* ---------- Shared for n7110.c and n6510.c ------------------------------- */ + +GSM_Error N71_65_ReplyGetMemoryError(unsigned char error, GSM_StateMachine *s) +{ + switch (error) { + case 0x27: + smprintf(s, "No PIN\n"); + return ERR_SECURITYERROR; + case 0x30: + smprintf(s, "Invalid memory type\n"); + if (s->Phone.Data.Memory->MemoryType == MEM_ME) return ERR_EMPTY; + if (s->Phone.Data.Memory->MemoryType == MEM_SM) return ERR_EMPTY; + return ERR_NOTSUPPORTED; + case 0x33: + smprintf(s, "Empty location\n"); + s->Phone.Data.Memory->EntriesNum = 0; + return ERR_EMPTY; + case 0x34: + smprintf(s, "Too high location ?\n"); + return ERR_INVALIDLOCATION; + default: + smprintf(s, "ERROR: unknown %i\n",error); + return ERR_UNKNOWNRESPONSE; + } +} + +GSM_Error N71_65_ReplyWritePhonebook(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Phonebook entry written "); + switch (msg.Buffer[6]) { + case 0x0f: + smprintf(s, " - error\n"); + switch (msg.Buffer[10]) { + case 0x36: + smprintf(s, "Too long name\n"); + return ERR_NOTSUPPORTED; + case 0x3c: + smprintf(s, "Can not add entry with 0 subentries\n"); + return ERR_NOTSUPPORTED; + case 0x3d: + smprintf(s, "Wrong entry type\n"); + return ERR_NOTSUPPORTED; + case 0x3e: + smprintf(s, "Too much entries\n"); + return ERR_NOTSUPPORTED; + default: + smprintf(s, "ERROR: unknown %i\n",msg.Buffer[10]); + return ERR_UNKNOWNRESPONSE; + } + default: + smprintf(s, " - OK\n"); + return ERR_NONE; + } +} + +bool NOKIA_FindPhoneFeatureValue(GSM_StateMachine *s, + GSM_Profile_PhoneTableValue ProfileTable[], + GSM_Profile_Feat_ID FeatureID, + GSM_Profile_Feat_Value FeatureValue, + unsigned char *PhoneID, + unsigned char *PhoneValue) +{ + int i=0; + + smprintf(s, "Trying to find feature %i with value %i\n",FeatureID,FeatureValue); + while (ProfileTable[i].ID != 0x00) { + if (ProfileTable[i].ID == FeatureID && + ProfileTable[i].Value == FeatureValue) { + *PhoneID = ProfileTable[i].PhoneID; + *PhoneValue = ProfileTable[i].PhoneValue; + return true; + } + i++; + } + return false; +} + +#define PROFILE_CALLERGROUPS_GROUP1 0x01 +#define PROFILE_CALLERGROUPS_GROUP2 0x02 +#define PROFILE_CALLERGROUPS_GROUP3 0x04 +#define PROFILE_CALLERGROUPS_GROUP4 0x08 +#define PROFILE_CALLERGROUPS_GROUP5 0x10 + +void NOKIA_FindFeatureValue(GSM_StateMachine *s, + GSM_Profile_PhoneTableValue ProfileTable[], + unsigned char ID, + unsigned char Value, + GSM_Phone_Data *Data, + bool CallerGroups) +{ + int i; + + if (CallerGroups) { + smprintf(s, "Caller groups: %i\n", Value); + Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = Profile_CallerGroups; + Data->Profile->FeaturesNumber++; + for (i=0;i<5;i++) Data->Profile->CallerGroups[i] = false; + if ((Value & PROFILE_CALLERGROUPS_GROUP1)==PROFILE_CALLERGROUPS_GROUP1) Data->Profile->CallerGroups[0] = true; + if ((Value & PROFILE_CALLERGROUPS_GROUP2)==PROFILE_CALLERGROUPS_GROUP2) Data->Profile->CallerGroups[1] = true; + if ((Value & PROFILE_CALLERGROUPS_GROUP3)==PROFILE_CALLERGROUPS_GROUP3) Data->Profile->CallerGroups[2] = true; + if ((Value & PROFILE_CALLERGROUPS_GROUP4)==PROFILE_CALLERGROUPS_GROUP4) Data->Profile->CallerGroups[3] = true; + if ((Value & PROFILE_CALLERGROUPS_GROUP5)==PROFILE_CALLERGROUPS_GROUP5) Data->Profile->CallerGroups[4] = true; + return; + } + + i = 0; + while (ProfileTable[i].ID != 0x00) { + if (ProfileTable[i].PhoneID == ID && + ProfileTable[i].PhoneValue == Value) { +#ifdef DEBUG + switch (ProfileTable[i].ID) { + case Profile_KeypadTone : smprintf(s, "Keypad tones\n"); break; + case Profile_CallAlert : smprintf(s, "Call alert\n"); break; + case Profile_RingtoneVolume : smprintf(s, "Ringtone volume\n"); break; + case Profile_MessageTone : smprintf(s, "SMS message tones\n"); break; + case Profile_Vibration : smprintf(s, "Vibration\n"); break; + case Profile_WarningTone : smprintf(s, "Warning (ang games) tones\n"); break; + case Profile_AutoAnswer : smprintf(s, "Automatic answer\n"); break; + case Profile_Lights : smprintf(s, "Lights\n"); break; + case Profile_ScreenSaver : smprintf(s, "Screen Saver\n"); break; + case Profile_ScreenSaverTime : smprintf(s, "Screen Saver timeout\n"); break; + default : break; + } +#endif + Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = ProfileTable[i].ID; + Data->Profile->FeatureValue [Data->Profile->FeaturesNumber] = ProfileTable[i].Value; + Data->Profile->FeaturesNumber++; + break; + } + i++; + } +} + +GSM_Profile_PhoneTableValue Profile71_65[] = { + {Profile_KeypadTone, PROFILE_KEYPAD_OFF, 0x00,0x00}, + {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL1, 0x00,0x01}, + {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL2, 0x00,0x02}, + {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL3, 0x00,0x03}, + /* Lights ? */ + {Profile_CallAlert, PROFILE_CALLALERT_RINGING, 0x02,0x00}, + {Profile_CallAlert, PROFILE_CALLALERT_ASCENDING, 0x02,0x01}, + {Profile_CallAlert, PROFILE_CALLALERT_RINGONCE, 0x02,0x02}, + {Profile_CallAlert, PROFILE_CALLALERT_BEEPONCE, 0x02,0x03}, + {Profile_CallAlert, PROFILE_CALLALERT_OFF, 0x02,0x05}, +/* {Profile_CallAlert, PROFILE_CALLALERT_CALLERGROUPS,0x02,0x07}, */ + /* Ringtone ID */ + {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL1, 0x04,0x00}, + {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL2, 0x04,0x01}, + {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL3, 0x04,0x02}, + {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL4, 0x04,0x03}, + {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL5, 0x04,0x04}, + {Profile_MessageTone, PROFILE_MESSAGE_NOTONE, 0x05,0x00}, + {Profile_MessageTone, PROFILE_MESSAGE_STANDARD, 0x05,0x01}, + {Profile_MessageTone, PROFILE_MESSAGE_SPECIAL, 0x05,0x02}, + {Profile_MessageTone, PROFILE_MESSAGE_BEEPONCE, 0x05,0x03}, + {Profile_MessageTone, PROFILE_MESSAGE_ASCENDING, 0x05,0x04}, + {Profile_Vibration, PROFILE_VIBRATION_OFF, 0x06,0x00}, + {Profile_Vibration, PROFILE_VIBRATION_ON, 0x06,0x01}, + {Profile_WarningTone, PROFILE_WARNING_OFF, 0x07,0x00}, + {Profile_WarningTone, PROFILE_WARNING_ON, 0x07,0x01}, + /* Caller groups */ + {Profile_AutoAnswer, PROFILE_AUTOANSWER_OFF, 0x09,0x00}, + {Profile_AutoAnswer, PROFILE_AUTOANSWER_ON, 0x09,0x01}, + {0x00, 0x00, 0x00,0x00} +}; + +GSM_Error NOKIA_SetIncomingSMS(GSM_StateMachine *s, bool enable) +{ + s->Phone.Data.EnableIncomingSMS = enable; +#ifdef DEBUG + if (enable) { + smprintf(s, "Enabling incoming SMS\n"); + } else { + smprintf(s, "Disabling incoming SMS\n"); + } +#endif + return ERR_NONE; +} + +GSM_Error N71_65_ReplyUSSDInfo(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + unsigned char buffer[2000],buffer2[4000]; + + if (s->Phone.Data.RequestID == ID_Divert) return ERR_NONE; + + memcpy(buffer,msg.Buffer+8,msg.Buffer[7]); + buffer[msg.Buffer[7]] = 0x00; + + smprintf(s, "USSD reply: \"%s\"\n",buffer); + + if (s->Phone.Data.EnableIncomingUSSD && s->User.IncomingUSSD!=NULL) { + EncodeUnicode(buffer2,buffer,strlen(buffer)); + s->User.IncomingUSSD(s->CurrentConfig->Device, buffer2); + } + + return ERR_NONE; +} + +GSM_Error NOKIA_SetIncomingUSSD(GSM_StateMachine *s, bool enable) +{ + s->Phone.Data.EnableIncomingUSSD = enable; +#ifdef DEBUG + if (enable) { + smprintf(s, "Enabling incoming USSD\n"); + } else { + smprintf(s, "Disabling incoming USSD\n"); + } +#endif + return ERR_NONE; +} + +GSM_Error NOKIA_SetIncomingCall(GSM_StateMachine *s, bool enable) +{ + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOCALLINFO)) return ERR_NOTSUPPORTED; + + s->Phone.Data.EnableIncomingCall = enable; +#ifdef DEBUG + if (enable) { + smprintf(s, "Enabling incoming Call\n"); + } else { + smprintf(s, "Disabling incoming Call\n"); + } +#endif + return ERR_NONE; +} + +GSM_Error N71_65_ReplyCallInfo(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + GSM_Call call; + int tmp; + unsigned char buffer[200]; + + call.Status = 0; + call.CallIDAvailable = true; + smprintf(s, "Call info, "); + switch (msg.Buffer[3]) { + case 0x02: + smprintf(s, "Call established, waiting for answer\n"); + call.Status = GSM_CALL_CallEstablished; + break; + case 0x03: + smprintf(s, "Call started\n"); + smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//such interpretation is in gnokii + tmp = 6; + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false); + smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer)); + /* FIXME: read name from frame */ + + call.Status = GSM_CALL_CallStart; + break; + case 0x04: + smprintf(s, "Remote end hang up\n"); + smprintf(s, "Cause Type : %i\n",msg.Buffer[5]);//such interpretation is in gnokii + smprintf(s, "CC : %i\n",msg.Buffer[6]); + smprintf(s, "MM(?) : %i\n",msg.Buffer[7]); + smprintf(s, "RR(?) : %i\n",msg.Buffer[8]); + call.Status = GSM_CALL_CallRemoteEnd; + call.StatusCode = msg.Buffer[6]; + break; + case 0x05: + smprintf(s, "Incoming call\n"); + smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//such interpretation is in gnokii + tmp = 6; + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false); + smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer)); + /* FIXME: read name from frame */ + call.Status = GSM_CALL_IncomingCall; + tmp = 6; + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,call.PhoneNumber,false); + break; + case 0x07: + smprintf(s, "Call answer initiated\n"); + break; + case 0x09: + smprintf(s, "Call released\n"); + call.Status = GSM_CALL_CallLocalEnd; + break; + case 0x0a: + smprintf(s, "Call is being released\n"); + break; + case 0x0b: + smprintf(s, "Meaning not known\n"); + call.CallIDAvailable = false; + break; + case 0x0c: + smprintf(s, "Audio status\n"); + if (msg.Buffer[4] == 0x01) smprintf(s, "Audio enabled\n"); + else smprintf(s, "Audio disabled\n"); + call.CallIDAvailable = false; + break; + case 0x23: + smprintf(s, "Call held\n"); + call.Status = GSM_CALL_CallHeld; + break; + case 0x25: + smprintf(s, "Call resumed\n"); + call.Status = GSM_CALL_CallResumed; + break; + case 0x27: + smprintf(s, "Call switched\n"); + call.Status = GSM_CALL_CallSwitched; + break; + case 0x53: + smprintf(s, "Outgoing call\n"); + smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//such interpretation is in gnokii + tmp = 6; + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false); + smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer)); + /* FIXME: read name from frame */ + call.Status = GSM_CALL_OutgoingCall; + tmp = 6; + NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,call.PhoneNumber,false); + break; + } + if (call.CallIDAvailable) smprintf(s, "Call ID : %d\n",msg.Buffer[4]); + if (s->Phone.Data.EnableIncomingCall && s->User.IncomingCall!=NULL && call.Status != 0) { + if (call.CallIDAvailable) call.CallID = msg.Buffer[4]; + s->User.IncomingCall(s->CurrentConfig->Device, call); + } + if (s->Phone.Data.RequestID == ID_CancelCall) { + if (msg.Buffer[3] == 0x09) { + if (s->Phone.Data.CallID == msg.Buffer[4]) return ERR_NONE; + /* when we canceled call and see frame about other + * call releasing, we don't give ERR_NONE for "our" + * call release command + */ + return ERR_NEEDANOTHERANSWER; + } + } + if (s->Phone.Data.RequestID == ID_AnswerCall) { + if (msg.Buffer[3] == 0x07) { + if (s->Phone.Data.CallID == msg.Buffer[4]) return ERR_NONE; + return ERR_NEEDANOTHERANSWER; + } + } + return ERR_NONE; +} + +void N71_65_GetCalendarRecurrance(GSM_StateMachine *s, unsigned char *buffer, GSM_CalendarEntry *entry) +{ + int Recurrance; + + Recurrance = buffer[0]*256 + buffer[1]; + /* 8760 hours = 1 year */ + if (Recurrance == 0xffff) Recurrance=8760; + if (Recurrance != 0) { + smprintf(s, "Recurrance : %i hours\n",Recurrance); + entry->Entries[entry->EntriesNum].EntryType = CAL_RECURRANCE; + entry->Entries[entry->EntriesNum].Number = Recurrance; + entry->EntriesNum++; + } +} + +/* method 2 */ +GSM_Error N71_65_ReplyAddCalendar2(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Calendar note added\n"); + return ERR_NONE; +} + +/* method 2 */ +GSM_Error N71_65_AddCalendar2(GSM_StateMachine *s, GSM_CalendarEntry *Note) +{ + GSM_CalendarNoteType NoteType; + time_t t_time1,t_time2; + GSM_DateTime Date,date_time; + GSM_Error error; + long diff; + int Text, Time, Alarm, Phone, Recurrance, EndTime, Location, length=25; + unsigned char req[5000] = { + N6110_FRAME_HEADER, + 0x40, + 0x00, /* frame length - 7 */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, /* start time saved as difference */ + 0x00,0x00,0xff,0xff, /* alarm saved as difference */ + 0x00, /* frame length - 7 */ + 0x00, /* note type */ + 0x00,0x00, /* recurrance */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}; /* rest depends on note type */ + + NoteType = N71_65_FindCalendarType(Note->Type, s->Phone.Data.ModelInfo); + + if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62) || + IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65)) { + switch(NoteType) { + case GSM_CAL_MEETING : req[18] = 0x01; length = 25; break; + case GSM_CAL_CALL : req[18] = 0x02; length = 27; break; + case GSM_CAL_BIRTHDAY: req[18] = 0x04; length = 28; break; + case GSM_CAL_MEMO : req[18] = 0x08; length = 25; break; + default : return ERR_UNKNOWN; + } + } else { + switch(NoteType) { + case GSM_CAL_REMINDER: req[18] = 0x01; length = 25; break; + case GSM_CAL_CALL : req[18] = 0x02; length = 27; break; + case GSM_CAL_BIRTHDAY: req[18] = 0x04; length = 28; break; + case GSM_CAL_MEMO : req[18] = 0x08; length = 25; break; + default : return ERR_UNKNOWN; + } + } + + GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(Note, &Text, &Time, &Alarm, &Phone, &Recurrance, &EndTime, &Location); + + if (Time == -1) return ERR_UNKNOWN; + if (NoteType != GSM_CAL_BIRTHDAY) { + Date.Year = 2030; Date.Month = 01; Date.Day = 01; + Date.Hour = 00; Date.Minute = 00; Date.Second = 00; + } else { + Date.Year = 2029; Date.Month = 12; Date.Day = 31; + Date.Hour = 22; Date.Minute = 59; Date.Second = 58; + } + t_time1 = Fill_Time_T(Date,8); + memcpy(&Date,&Note->Entries[Time].Date,sizeof(GSM_DateTime)); + if (NoteType != GSM_CAL_BIRTHDAY) { + Date.Year -= 20; + } else { + Date.Year = 1980; + Date.Hour = 22; Date.Minute = 58; Date.Second = 58; + } + t_time2 = Fill_Time_T(Date,8); + diff = t_time1-t_time2; + smprintf(s, " Difference : %li seconds\n", -diff); + req[9] = (unsigned char)(-diff >> 24); + req[10] = (unsigned char)(-diff >> 16); + req[11] = (unsigned char)(-diff >> 8); + req[12] = (unsigned char)(-diff); + if (NoteType == GSM_CAL_BIRTHDAY) { + req[25] = Note->Entries[Time].Date.Year / 256; + req[26] = Note->Entries[Time].Date.Year % 256; + /* Recurrance = 1 year */ + req[19] = 0xff; + req[20] = 0xff; + } + + if (NoteType == GSM_CAL_CALL && Phone != -1) { + req[25] = UnicodeLength(Note->Entries[Phone].Text); + CopyUnicodeString(req+length,Note->Entries[Phone].Text); + length += UnicodeLength(Note->Entries[Phone].Text)*2; + } + + if (Alarm != -1) { + if (NoteType == GSM_CAL_BIRTHDAY) { + if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[27] = 0x01; + error=s->Phone.Functions->GetDateTime(s,&date_time); + switch (error) { + case ERR_EMPTY: + case ERR_NOTIMPLEMENTED: + GSM_GetCurrentDateTime(&date_time); + break; + case ERR_NONE: + break; + default: + return error; + } + Date.Year = date_time.Year; + Date.Hour = 23; + Date.Minute = 59; + } else { + Date.Year += 20; + } + t_time2 = Fill_Time_T(Date,8); + t_time1 = Fill_Time_T(Note->Entries[Alarm].Date,8); + diff = t_time1-t_time2; + + /* Sometimes we have difference in minutes */ + if (NoteType == GSM_CAL_MEETING) diff = diff / 60; + if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35)) { + if (NoteType == GSM_CAL_MEMO || NoteType == GSM_CAL_CALL) { + diff = diff / 60; + } + } + + smprintf(s, " Difference : %li seconds or minutes\n", -diff); + req[13] = (unsigned char)(-diff >> 24); + req[14] = (unsigned char)(-diff >> 16); + req[15] = (unsigned char)(-diff >> 8); + req[16] = (unsigned char)(-diff); + } + + if (Recurrance != -1) { + /* 8760 hours = 1 year */ + if (Note->Entries[Recurrance].Number >= 8760) { + req[19] = 0xff; + req[20] = 0xff; + } else { + req[19] = Note->Entries[Recurrance].Number / 256; + req[20] = Note->Entries[Recurrance].Number % 256; + } + } + + if (Text != -1) { + switch (NoteType) { + case GSM_CAL_CALL: + req[26] = UnicodeLength(Note->Entries[Text].Text); + break; + default: + req[length++] = UnicodeLength(Note->Entries[Text].Text); + if (NoteType == GSM_CAL_MEMO || NoteType == GSM_CAL_MEETING) req[length++] = 0x00; + } + CopyUnicodeString(req+length,Note->Entries[Text].Text); + length += UnicodeLength(Note->Entries[Text].Text)*2; + } + + req[length++] = 0x00; + req[length++] = 0x00; + + req[4] = req[17] = length-7; + + smprintf(s, "Writing calendar note method 2\n"); + return GSM_WaitFor (s, req, length, 0x13, 4, ID_SetCalendarNote); +} + +/* method 1*/ +GSM_Error N71_65_ReplyGetCalendarNotePos1(GSM_Protocol_Message msg, GSM_StateMachine *s,int *FirstCalendarPos) +{ + smprintf(s, "First calendar location: %i\n",msg.Buffer[4]*256+msg.Buffer[5]); + *FirstCalendarPos = msg.Buffer[4]*256+msg.Buffer[5]; + return ERR_NONE; +} + +/* method 1*/ +static GSM_Error N71_65_GetCalendarNotePos1(GSM_StateMachine *s) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x31}; + + smprintf(s, "Getting first free calendar note location\n"); + return GSM_WaitFor (s, req, 4, 0x13, 4, ID_GetCalendarNotePos); +} + +/* method 1 */ +GSM_Error N71_65_ReplyAddCalendar1(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ +#ifdef DEBUG + smprintf(s, "Written calendar note type "); + switch ((msg.Buffer[3]/2)-1) { + case 0: smprintf(s, "Meeting"); break; + case 1: smprintf(s, "Call"); break; + case 2: smprintf(s, "Birthday");break; + case 3: smprintf(s, "Reminder");break; + } + smprintf(s, " on location %d\n",msg.Buffer[4]*256+msg.Buffer[5]); +#endif + return ERR_NONE; +} + +/* method 1 */ +GSM_Error N71_65_AddCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, int *FirstCalendarPos) +{ + long seconds; + GSM_Error error; + GSM_DateTime DT; + int Text, Time, Alarm, Phone, Recurrance, EndTime, Location, count=12; + unsigned char req[5000] = { + N6110_FRAME_HEADER, + 0x01, /* note type */ + 0x00, 0x00, /* location ? */ + 0x00, /* entry type */ + 0x00, + 0x00, 0x00, /* Year */ + 0x00, /* Month */ + 0x00, /* Day */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + error=N71_65_GetCalendarNotePos1(s); + if (error!=ERR_NONE) return error; + if (FirstCalendarPos != NULL) { + req[4] = *FirstCalendarPos/256; + req[5] = *FirstCalendarPos%256; + } + + switch(Note->Type) { + case GSM_CAL_CALL : req[3]=0x03; req[6]=0x02; break; + case GSM_CAL_BIRTHDAY: req[3]=0x05; req[6]=0x04; break; + case GSM_CAL_MEMO : req[3]=0x07; req[6]=0x08; break; + case GSM_CAL_MEETING : + default : req[3]=0x01; req[6]=0x01; break; + } + + GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(Note, &Text, &Time, &Alarm, &Phone, &Recurrance, &EndTime, &Location); + + if (Time == -1) return ERR_UNKNOWN; + memcpy(&DT,&Note->Entries[Time].Date,sizeof(GSM_DateTime)); + req[8] = DT.Year / 256; + req[9] = DT.Year % 256; + req[10] = DT.Month; + req[11] = DT.Day; + + switch(Note->Type) { + case GSM_CAL_BIRTHDAY: + /* byte 12 and 13 */ + req[count++] = 0x00; + req[count++] = 0x00; + + /* Alarm - bytes 14 to 17 */ + req[count++] = 0x00; + req[count++] = 0x00; + req[count++] = 0xff; + req[count++] = 0xff; + if (Alarm != -1) { +#ifndef ENABLE_LGPL + /* Comment from original source by Gabriele Zappi: + * I try with Time.Year = Alarm.Year. If negative, I increase 1 year, + * but only once ! This thing, because I may have Alarm period across + * a year. (eg. Birthday on 2001-01-10 and Alarm on 2000-12-27) + */ +#endif + DT.Year = Note->Entries[Alarm].Date.Year; + seconds = Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8); + if (seconds<0L) { + DT.Year++; + seconds = Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8); + } + if (seconds>=0L) { + count -= 4; + /* bytes 14 to 17 */ + req[count++] = (unsigned char)(seconds>>24); + req[count++] = (unsigned char)((seconds>>16) & 0xff); + req[count++] = (unsigned char)((seconds>>8) & 0xff); + req[count++] = (unsigned char)(seconds & 0xff); + } + /* byte 18 */ + if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[count++] = 0x01; else req[count++] = 0x00; + } + + /* byte 19 and next */ + if (Text != -1) { + req[count++] = UnicodeLength(Note->Entries[Text].Text); + CopyUnicodeString(req+count,Note->Entries[Text].Text); + count=count+2*UnicodeLength(Note->Entries[Text].Text); + } else { + req[count++] = 0x00; + } + break; + case GSM_CAL_MEMO: + /* byte 12 and 13 */ + if (Recurrance != -1) { + /* 8760 hours = 1 year */ + if (Note->Entries[Recurrance].Number >= 8760) { + req[count++] = 0xff; + req[count++] = 0xff; + } else { + req[count++] = Note->Entries[Recurrance].Number / 256; + req[count++] = Note->Entries[Recurrance].Number % 256; + } + } else { + req[count++] = 0x00; + req[count++] = 0x00; + } + + /* byte 14 and next */ + if (Text != -1) { + req[count++] = UnicodeLength(Note->Entries[Text].Text); + req[count++] = 0x00; + CopyUnicodeString(req+count,Note->Entries[Text].Text); + count=count+2*UnicodeLength(Note->Entries[Text].Text); + } else { + req[count++] = 0x00; + req[count++] = 0x00; + } + break; + case GSM_CAL_MEETING: + case GSM_CAL_CALL: + default: + /* byte 12 and 13 */ + req[count++] = DT.Hour; + req[count++] = DT.Minute; + + /* Alarm - byte 14 and 15 */ + req[count++] = 0xff; + req[count++] = 0xff; + if (Alarm != -1) { + seconds=Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8); + if (seconds>=0L) { + count -= 2; + req[count++] = ((unsigned char)(seconds/60L)>>8); + req[count++] = (unsigned char)((seconds/60L)&0xff); + } + } + + /* byte 16 and 17 */ + if (Recurrance != -1) { + /* 8760 hours = 1 year */ + if (Note->Entries[Recurrance].Number >= 8760) { + req[count++] = 0xff; + req[count++] = 0xff; + } else { + req[count++] = Note->Entries[Recurrance].Number / 256; + req[count++] = Note->Entries[Recurrance].Number % 256; + } + } else { + req[count++] = 0x00; + req[count++] = 0x00; + } + + /* byte 18 */ + if (Text != -1) { + req[count++] = UnicodeLength(Note->Entries[Text].Text); + } else { + req[count++] = 0x00; + } + /* byte 19 */ + if (Note->Type == GSM_CAL_CALL && Phone != -1) { + req[count++] = UnicodeLength(Note->Entries[Phone].Text); + } else { + req[count++] = 0x00; + } + if (Text != -1) { + CopyUnicodeString(req+count,Note->Entries[Text].Text); + count=count+2*UnicodeLength(Note->Entries[Text].Text); + } + if (Note->Type == GSM_CAL_CALL && Phone != -1) { + CopyUnicodeString(req+count,Note->Entries[Phone].Text); + count=count+2*UnicodeLength(Note->Entries[Phone].Text); + } + break; + } + req[count] = 0x00; + smprintf(s, "Writing calendar note method 1\n"); + return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetCalendarNote); +} + +GSM_Error N71_65_ReplyDelCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + smprintf(s, "Deleted calendar note on location %d\n",msg.Buffer[4]*256+msg.Buffer[5]); + return ERR_NONE; +} + +GSM_Error N71_65_DelCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note) +{ + unsigned char req[] = {N6110_FRAME_HEADER, 0x0b, + 0x00, 0x00}; /* location */ + + req[4] = Note->Location / 256; + req[5] = Note->Location % 256; + + smprintf(s, "Deleting calendar note\n"); + return GSM_WaitFor (s, req, 6, 0x13, 4, ID_DeleteCalendarNote); +} + +/* method 1 */ +GSM_Error N71_65_ReplyGetCalendarInfo1(GSM_Protocol_Message msg, GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar) +{ + int i,j=0; + + smprintf(s, "Info with calendar notes locations received method 1\n"); + while (LastCalendar->Location[j] != 0x00) j++; + if (j >= GSM_MAXCALENDARTODONOTES) { + smprintf(s, "Increase GSM_MAXCALENDARNOTES\n"); + return ERR_UNKNOWN; + } + if (j == 0) { + LastCalendar->Number=msg.Buffer[4]*256+msg.Buffer[5]; + smprintf(s, "Number of Entries: %i\n",LastCalendar->Number); + } + smprintf(s, "Locations: "); + i = 0; + while (9+(i*2) <= msg.Length) { + LastCalendar->Location[j++]=msg.Buffer[8+(i*2)]*256+msg.Buffer[9+(i*2)]; + smprintf(s, "%i ",LastCalendar->Location[j-1]); + i++; + } + smprintf(s, "\nNumber of Entries in frame: %i\n",i); + smprintf(s, "\n"); + LastCalendar->Location[j] = 0; + if (i == 1 && msg.Buffer[8+(0*2)]*256+msg.Buffer[9+(0*2)] == 0) return ERR_EMPTY; + if (i == 0) return ERR_EMPTY; + return ERR_NONE; +} + +/* method 1 */ +GSM_Error N71_65_GetCalendarInfo1(GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar) +{ + GSM_Error error; + int i; + unsigned char req[] = {N6110_FRAME_HEADER, 0x3a, + 0xFF, 0xFE}; /* First location number */ + + LastCalendar->Location[0] = 0x00; + LastCalendar->Number = 0; + + smprintf(s, "Getting locations for calendar method 1\n"); + error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo); + if (error != ERR_NONE && error != ERR_EMPTY) return error; + + while (1) { + i=0; + while (LastCalendar->Location[i] != 0x00) i++; + if (i == LastCalendar->Number) break; + if (i != LastCalendar->Number && error == ERR_EMPTY) { + smprintf(s, "Phone doesn't support some notes with this method. Workaround\n"); + LastCalendar->Number = i; + break; + } + smprintf(s, "i = %i %i\n",i,LastCalendar->Number); + req[4] = LastCalendar->Location[i-1] / 256; + req[5] = LastCalendar->Location[i-1] % 256; + smprintf(s, "Getting locations for calendar\n"); + error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo); + if (error != ERR_NONE && error != ERR_EMPTY) return error; + } + return ERR_NONE; +} + +/* method 1 */ +GSM_Error N71_65_ReplyGetNextCalendar1(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + int alarm,i; + GSM_CalendarEntry *entry = s->Phone.Data.Cal; + + smprintf(s, "Calendar note received method 1\n"); + + /* Later these values can change */ + if (msg.Buffer[6]!=0x04) { /* Here not birthday */ + entry->Entries[0].Date.Year = msg.Buffer[8]*256+msg.Buffer[9]; + } + entry->Entries[0].Date.Month = msg.Buffer[10]; + entry->Entries[0].Date.Day = msg.Buffer[11]; + entry->Entries[0].Date.Hour = msg.Buffer[12]; + entry->Entries[0].Date.Minute = msg.Buffer[13]; + entry->Entries[0].Date.Second = 0; + entry->Entries[0].EntryType = CAL_START_DATETIME; + entry->EntriesNum++; + + switch (msg.Buffer[6]) { + case 0x01: + smprintf(s, "Meeting\n"); + entry->Type = GSM_CAL_MEETING; + + alarm=msg.Buffer[14]*256+msg.Buffer[15]; + if (alarm != 0xffff) { + smprintf(s, " Difference : %i seconds\n", alarm); + memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime)); + GetTimeDifference(alarm, &entry->Entries[1].Date, false, 60); + entry->Entries[1].EntryType = CAL_ALARM_DATETIME; + entry->EntriesNum++; + } + N71_65_GetCalendarRecurrance(s, msg.Buffer + 16, entry); + + memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20, msg.Buffer[18]*2); + entry->Entries[entry->EntriesNum].Text[msg.Buffer[18]*2] = 0; + entry->Entries[entry->EntriesNum].Text[msg.Buffer[18]*2+1] = 0; + entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT; + smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum++; + return ERR_NONE; + case 0x02: + smprintf(s, "Call\n"); + entry->Type = GSM_CAL_CALL; + + alarm=msg.Buffer[14]*256+msg.Buffer[15]; + if (alarm != 0xffff) { + smprintf(s, " Difference : %i seconds\n", alarm); + memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime)); + GetTimeDifference(alarm, &entry->Entries[1].Date, false, 60); + entry->Entries[1].EntryType = CAL_ALARM_DATETIME; + entry->EntriesNum++; + } + N71_65_GetCalendarRecurrance(s, msg.Buffer + 16, entry); + + i = msg.Buffer[18] * 2; + if (i!=0) { + memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20, i); + entry->Entries[entry->EntriesNum].Text[i] = 0; + entry->Entries[entry->EntriesNum].Text[i+1] = 0; + entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT; + smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum++; + } + + memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20+i, msg.Buffer[19]*2); + entry->Entries[entry->EntriesNum].Text[msg.Buffer[19]*2] = 0; + entry->Entries[entry->EntriesNum].Text[msg.Buffer[19]*2+1] = 0; + entry->Entries[entry->EntriesNum].EntryType = CAL_PHONE; + smprintf(s, "Phone : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum++; + return ERR_NONE; + case 0x04: + smprintf(s, "Birthday\n"); + entry->Type = GSM_CAL_BIRTHDAY; + + entry->Entries[0].Date.Hour = 23; + entry->Entries[0].Date.Minute = 59; + entry->Entries[0].Date.Second = 58; + + alarm = ((unsigned int)msg.Buffer[14]) << 24; + alarm += ((unsigned int)msg.Buffer[15]) << 16; + alarm += ((unsigned int)msg.Buffer[16]) << 8; + alarm += msg.Buffer[17]; + if (alarm != 0xffff) { + smprintf(s, " Difference : %i seconds\n", alarm); + memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime)); + GetTimeDifference(alarm, &entry->Entries[1].Date, false, 1); + entry->Entries[1].EntryType = CAL_ALARM_DATETIME; + if (msg.Buffer[20]!=0x00) { + entry->Entries[1].EntryType = CAL_SILENT_ALARM_DATETIME; + smprintf(s, "Alarm type : Silent\n"); + } + entry->EntriesNum++; + } + + entry->Entries[0].Date.Year = msg.Buffer[18]*256 + msg.Buffer[19]; + if (entry->Entries[0].Date.Year == 65535) entry->Entries[0].Date.Year = 0; + smprintf(s, "Age : %i\n",entry->Entries[0].Date.Year); + + memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+22, msg.Buffer[21]*2); + entry->Entries[entry->EntriesNum].Text[msg.Buffer[21]*2] = 0; + entry->Entries[entry->EntriesNum].Text[msg.Buffer[21]*2+1] = 0; + entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT; + smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum++; + return ERR_NONE; + case 0x08: + smprintf(s, "Memo\n"); + entry->Type = GSM_CAL_MEMO; + + entry->Entries[0].Date.Hour = 0; + entry->Entries[0].Date.Minute = 0; + + N71_65_GetCalendarRecurrance(s, msg.Buffer + 12, entry); + + memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+16, msg.Buffer[14]*2); + entry->Entries[entry->EntriesNum].Text[msg.Buffer[14]*2] = 0; + entry->Entries[entry->EntriesNum].Text[msg.Buffer[14]*2+1] = 0; + entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT; + smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text)); + entry->EntriesNum++; + return ERR_NONE; + default: + smprintf(s, "ERROR: unknown %i\n",msg.Buffer[6]); + return ERR_UNKNOWNRESPONSE; + } +} + +/* method 1 */ +GSM_Error N71_65_GetNextCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start, GSM_NOKIACalToDoLocations *LastCalendar, int *LastCalendarYear, int *LastCalendarPos) +{ + GSM_Error error; + GSM_DateTime date_time; + unsigned char req[] = {N6110_FRAME_HEADER, 0x19, + 0x00, 0x00}; /* Location */ + + if (start) { + error=N71_65_GetCalendarInfo1(s, LastCalendar); + if (error!=ERR_NONE) return error; + if (LastCalendar->Number == 0) return ERR_EMPTY; + + /* We have to get current year. It's NOT written in frame for + * Birthday + */ + error=s->Phone.Functions->GetDateTime(s,&date_time); + switch (error) { + case ERR_EMPTY: + case ERR_NOTIMPLEMENTED: + GSM_GetCurrentDateTime(&date_time); + break; + case ERR_NONE: + break; + default: + return error; + } + *LastCalendarYear = date_time.Year; + *LastCalendarPos = 0; + } else { + (*LastCalendarPos)++; + } + + if (*LastCalendarPos >= LastCalendar->Number) return ERR_EMPTY; + + req[4] = LastCalendar->Location[*LastCalendarPos] / 256; + req[5] = LastCalendar->Location[*LastCalendarPos] % 256; + + Note->EntriesNum = 0; + Note->Entries[0].Date.Year = *LastCalendarYear; + Note->Location = LastCalendar->Location[*LastCalendarPos]; + + s->Phone.Data.Cal=Note; + smprintf(s, "Getting calendar note method 1\n"); + return GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNote); +} + +GSM_Error N71_65_EnableFunctions(GSM_StateMachine *s,char *buff,int len) +{ + unsigned char buffer[50] = {N6110_FRAME_HEADER, 0x10, + 0x07}; /* Length */ + + buffer[4] = len; + memcpy(buffer+5,buff,len); + + /* Enables various things like incoming SMS, call info, etc. */ + return s->Protocol.Functions->WriteMessage(s, buffer, 5+len, 0x10); +} + +GSM_Error N71_65_ReplySendDTMF(GSM_Protocol_Message msg, GSM_StateMachine *s) +{ + switch (msg.Buffer[3]) { + case 0x51: + smprintf(s, "DTMF sent OK\n"); + return ERR_NONE; + case 0x59: + case 0x5E: + smprintf(s, "meaning unknown - during sending DTMF\n"); + return ERR_NONE; + } + return ERR_UNKNOWNRESPONSE; +} + +GSM_CalendarNoteType N71_65_FindCalendarType(GSM_CalendarNoteType Type, OnePhoneModel *model) +{ + switch (Type) { + case GSM_CAL_CALL: + return GSM_CAL_CALL; + case GSM_CAL_BIRTHDAY: + return GSM_CAL_BIRTHDAY; + case GSM_CAL_MEETING: + if (IsPhoneFeatureAvailable(model, F_CAL35)) { + return GSM_CAL_REMINDER; + } else return GSM_CAL_MEETING; + case GSM_CAL_MEMO: + if (IsPhoneFeatureAvailable(model, F_CAL35)) { + return GSM_CAL_REMINDER; + } else return GSM_CAL_MEMO; + case GSM_CAL_REMINDER: + if (IsPhoneFeatureAvailable(model, F_CAL62) || + IsPhoneFeatureAvailable(model, F_CAL65)) { + return GSM_CAL_CALL; + } else return GSM_CAL_REMINDER; + default: + return GSM_CAL_CALL; + } +} + +#endif + +/* How should editor hadle tabs in this file? Add editor commands here. + * vim: noexpandtab sw=8 ts=8 sts=8: + */ -- cgit v0.9.0.2