summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/phone/nokia/nfunc.c
Side-by-side diff
Diffstat (limited to 'gammu/emb/common/phone/nokia/nfunc.c') (more/less context) (ignore whitespace changes)
-rw-r--r--gammu/emb/common/phone/nokia/nfunc.c2143
1 files changed, 2143 insertions, 0 deletions
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 <string.h> /* memcpy only */
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#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;i<Folder->Number;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;i<cd->Response.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:
+ */