Imported gammu 0.90.7
[gammu.git] / common / phone / nokia / nfunc.c
blobca669075e5ef4347915f9ad76e2766f818fc15bd
2 #include <string.h> /* memcpy only */
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <time.h>
7 #include "../../gsmstate.h"
8 #include "../../misc/coding/coding.h"
9 #include "../../service/sms/gsmsms.h"
10 #include "../pfunc.h"
11 #include "nfunc.h"
13 unsigned char N71_65_MEMORY_TYPES[] = {
14 GMT_DC, 0x01,
15 GMT_MC, 0x02,
16 GMT_RC, 0x03,
17 GMT_ME, 0x05,
18 GMT_SM, 0x06,
19 GMT_VM, 0x09,
20 GMT7110_SP, 0x0e,
21 GMT7110_CG, 0x10,
22 GMT_ON, 0x17,
23 0x00, 0x00
26 int N71_65_PackPBKBlock(GSM_StateMachine *s, int id, int size, int no, unsigned char *buf, unsigned char *block)
28 smprintf(s, "Adding block id:%i,number:%i,length:%i\n",id,no+1,size+6);
30 *(block++) = id;
31 *(block++) = 0;
32 *(block++) = 0;
33 *(block++) = size + 6;
34 *(block++) = no + 1;
35 memcpy(block, buf, size);
36 block += size;
37 *(block++) = 0;
39 return (size + 6);
42 int N71_65_EncodePhonebookFrame(GSM_StateMachine *s, unsigned char *req, GSM_MemoryEntry entry, int *block2, bool DCT4, bool VoiceTag)
44 int count=0, len, i, block=0;
45 char string[500];
46 unsigned char type=0;
48 for (i = 0; i < entry.EntriesNum; i++)
50 switch (entry.Entries[i].EntryType) {
51 case PBK_Number_General:
52 case PBK_Number_Mobile:
53 case PBK_Number_Work:
54 case PBK_Number_Fax:
55 case PBK_Number_Home:
56 switch (entry.Entries[i].EntryType) {
57 case PBK_Number_General:
58 string[0] = N7110_NUMBER_GENERAL; break;
59 case PBK_Number_Mobile:
60 string[0] = N7110_NUMBER_MOBILE; break;
61 case PBK_Number_Work:
62 string[0] = N7110_NUMBER_WORK; break;
63 case PBK_Number_Fax:
64 string[0] = N7110_NUMBER_FAX; break;
65 case PBK_Number_Home:
66 string[0] = N7110_NUMBER_HOME; break;
67 default: break;
69 len = UnicodeLength(entry.Entries[i].Text);
70 string[1] = 0;
71 /* DCT 3 */
72 if (!DCT4) string[2] = entry.Entries[i].VoiceTag;
73 string[3] = 0;
74 string[4] = len * 2 + 2; /* length (with Termination) */
75 CopyUnicodeString(string+5,entry.Entries[i].Text);
76 string[len * 2 + 5] = 0; /* Terminating 0 */
77 count += N71_65_PackPBKBlock(s, N7110_ENTRYTYPE_NUMBER, len * 2 + 6, block++, string, req + count);
78 /* DCT 4 */
79 if (DCT4 && VoiceTag) {
80 block++;
81 req[count++] = N6510_ENTRYTYPE_VOICETAG;
82 req[count++] = 0;
83 req[count++] = 0;
84 req[count++] = 8;
85 req[count++] = 0x00;
86 req[count++] = i+1;
87 req[count++] = 0x00;
88 req[count++] = entry.Entries[i].VoiceTag;
90 break;
91 case PBK_Text_Name:
92 case PBK_Text_Note:
93 case PBK_Text_Postal:
94 case PBK_Text_Email:
95 case PBK_Text_Email2:
96 case PBK_Text_URL:
97 len = UnicodeLength(entry.Entries[i].Text);
98 string[0] = len * 2 + 2; /* length (with Termination) */
99 CopyUnicodeString(string+1,entry.Entries[i].Text);
100 string[len * 2 + 1] = 0; /* Terminating 0 */
101 switch (entry.Entries[i].EntryType) {
102 case PBK_Text_Note:
103 type = N7110_ENTRYTYPE_NOTE; break;
104 case PBK_Text_Postal:
105 type = N7110_ENTRYTYPE_POSTAL; break;
106 case PBK_Text_Email:
107 case PBK_Text_Email2:
108 type = N7110_ENTRYTYPE_EMAIL; break;
109 case PBK_Text_URL:
110 type = N7110_ENTRYTYPE_NOTE;
111 if (DCT4) type = N6510_ENTRYTYPE_URL;
112 break;
113 case PBK_Text_Name:
114 type = N7110_ENTRYTYPE_NAME; break;
115 default: break;
117 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
118 break;
119 case PBK_Caller_Group:
120 if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) {
121 string[0] = entry.Entries[i].Number;
122 string[1] = 0;
123 count += N71_65_PackPBKBlock(s, N7110_ENTRYTYPE_GROUP, 2, block++, string, req + count);
125 break;
126 case PBK_RingtoneID:
127 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) {
128 string[0] = 0x00;
129 string[1] = 0x00;
130 string[2] = entry.Entries[i].Number;
131 count += N71_65_PackPBKBlock(s, N7110_ENTRYTYPE_RINGTONE, 3, block++, string, req + count);
132 count --;
133 req[count-5] = 8;
135 break;
136 case PBK_Date:
137 break;
138 default:
139 break;
143 *block2=block;
145 return count;
148 GSM_Error N71_65_DecodePhonebook(GSM_StateMachine *s,
149 GSM_MemoryEntry *entry,
150 GSM_Bitmap *bitmap,
151 GSM_SpeedDial *speed,
152 unsigned char *MessageBuffer,
153 int MessageLength)
155 unsigned char *Block;
156 int length = 0;
158 entry->EntriesNum = 0;
159 entry->PreferUnicode = false;
161 if (entry->MemoryType==GMT7110_CG) {
162 bitmap->Text[0] = 0x00;
163 bitmap->Text[1] = 0x00;
164 bitmap->DefaultBitmap = true;
165 bitmap->DefaultRingtone = true;
168 Block = &MessageBuffer[0];
169 while (length != MessageLength) {
170 #ifdef DEBUG
171 smprintf(s, "Phonebook entry block - length %i", Block[3]-6);
172 if (di.dl == DL_TEXTALL || di.dl == DL_TEXTALLDATE) DumpMessage(di.df, Block+5, Block[3]-6);
173 #endif
174 if (entry->EntriesNum==GSM_PHONEBOOK_ENTRIES) {
175 smprintf(s, "Too many entries\n");
176 return GE_UNKNOWNRESPONSE;
179 switch (Block[0]) {
180 case N7110_ENTRYTYPE_NAME:
181 case N7110_ENTRYTYPE_EMAIL:
182 case N7110_ENTRYTYPE_POSTAL:
183 case N7110_ENTRYTYPE_NOTE:
184 case N6510_ENTRYTYPE_URL:
185 if (Block[5]/2>GSM_PHONEBOOK_TEXT_LENGTH) {
186 smprintf(s, "Too long text\n");
187 return GE_UNKNOWNRESPONSE;
189 memcpy(entry->Entries[entry->EntriesNum].Text,Block+6,Block[5]);
190 switch (Block[0]) {
191 case N7110_ENTRYTYPE_NAME:
192 entry->Entries[entry->EntriesNum].EntryType=PBK_Text_Name;
193 if (entry->MemoryType==GMT7110_CG) {
194 memcpy(bitmap->Text,Block+6,Block[5]);
196 smprintf(s, " Name \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
197 break;
198 case N7110_ENTRYTYPE_EMAIL:
199 entry->Entries[entry->EntriesNum].EntryType=PBK_Text_Email;
200 smprintf(s, " Email \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
201 break;
202 case N7110_ENTRYTYPE_POSTAL:
203 entry->Entries[entry->EntriesNum].EntryType=PBK_Text_Postal;
204 smprintf(s, " Postal \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
205 break;
206 case N7110_ENTRYTYPE_NOTE:
207 entry->Entries[entry->EntriesNum].EntryType=PBK_Text_Note;
208 smprintf(s, " Note \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
209 break;
210 case N6510_ENTRYTYPE_URL:
211 entry->Entries[entry->EntriesNum].EntryType=PBK_Text_URL;
212 smprintf(s, " URL \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
213 break;
215 entry->EntriesNum ++;
216 break;
217 case N7110_ENTRYTYPE_DATE:
218 entry->Entries[entry->EntriesNum].EntryType=PBK_Date;
219 NOKIA_DecodeDateTime(s, Block+6, &entry->Entries[entry->EntriesNum].Date);
220 entry->EntriesNum ++;
221 break;
222 case N7110_ENTRYTYPE_NUMBER:
223 switch (Block[5]) {
224 case 0x00:
225 case 0x01: /* Not assigned dialed number */
226 case 0x0b:
227 case 0x55: /* In many firmwares 0x55 visible after using
228 * Save from Call Register menu and saving number
229 * to existing phonebook entry */
230 case N7110_NUMBER_GENERAL:
231 smprintf(s, " General number");
232 entry->Entries[entry->EntriesNum].EntryType=PBK_Number_General;
233 break;
234 case N7110_NUMBER_WORK:
235 smprintf(s, " Work number");
236 entry->Entries[entry->EntriesNum].EntryType=PBK_Number_Work;
237 break;
238 case N7110_NUMBER_FAX:
239 smprintf(s, " Fax number");
240 entry->Entries[entry->EntriesNum].EntryType=PBK_Number_Fax;
241 break;
242 case N7110_NUMBER_MOBILE:
243 smprintf(s, " Mobile number");
244 entry->Entries[entry->EntriesNum].EntryType=PBK_Number_Mobile;
245 break;
246 case N7110_NUMBER_HOME:
247 smprintf(s, " Home number");
248 entry->Entries[entry->EntriesNum].EntryType=PBK_Number_Home;
249 break;
250 default:
251 smprintf(s, "Unknown number type %02x\n",Block[5]);
252 return GE_UNKNOWNRESPONSE;
254 if (Block[9]/2>GSM_PHONEBOOK_TEXT_LENGTH) {
255 smprintf(s, "Too long text\n");
256 return GE_UNKNOWNRESPONSE;
258 memcpy(entry->Entries[entry->EntriesNum].Text,Block+10,Block[9]);
259 smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
260 /* DCT3 phones like 6210 */
261 entry->Entries[entry->EntriesNum].VoiceTag = Block[7];
262 #ifdef DEBUG
263 if (entry->Entries[entry->EntriesNum].VoiceTag != 0) smprintf(s, "Voice tag %i assigned\n",Block[7]);
264 #endif
265 entry->EntriesNum ++;
266 break;
267 case N7110_ENTRYTYPE_RINGTONE:
268 if (entry->MemoryType==GMT7110_CG) {
269 bitmap->Ringtone=Block[5];
270 if (Block[5] == 0x00) bitmap->Ringtone=Block[7];
271 smprintf(s, "Ringtone ID : %i\n",bitmap->Ringtone);
272 bitmap->DefaultRingtone = false;
273 } else {
274 entry->Entries[entry->EntriesNum].EntryType=PBK_RingtoneID;
275 smprintf(s, "Ringtone ID \"%i\"\n",Block[7]);
276 entry->Entries[entry->EntriesNum].Number=Block[7];
277 entry->EntriesNum ++;
279 break;
280 case N7110_ENTRYTYPE_LOGOON:
281 if (entry->MemoryType==GMT7110_CG) {
282 bitmap->Enabled=(Block[5]==0x00 ? false : true);
283 smprintf(s, "Logo : %s\n", bitmap->Enabled==true ? "enabled":"disabled");
284 } else return GE_UNKNOWNRESPONSE;
285 break;
286 case N7110_ENTRYTYPE_GROUPLOGO:
287 if (entry->MemoryType==GMT7110_CG) {
288 smprintf(s, "Caller logo\n");
289 PHONE_DecodeBitmap(GSM_NokiaCallerLogo, Block+10, bitmap);
290 bitmap->DefaultBitmap = false;
291 } else return GE_UNKNOWNRESPONSE;
292 break;
293 case N7110_ENTRYTYPE_GROUP:
294 entry->Entries[entry->EntriesNum].EntryType=PBK_Caller_Group;
295 smprintf(s, "Caller group \"%i\"\n",Block[5]);
296 entry->Entries[entry->EntriesNum].Number=Block[5];
297 if (Block[5]!=0) entry->EntriesNum ++;
298 break;
299 case N6510_ENTRYTYPE_VOICETAG:
300 smprintf(s, "Entry %i has voice tag %i\n",Block[5]-1,Block[7]);
301 entry->Entries[Block[5]-1].VoiceTag = Block[7];
302 break;
303 /* 6210 5.56, SIM speed dials or ME with 1 number */
304 case N7110_ENTRYTYPE_SIM_SPEEDDIAL:
305 if (entry->MemoryType==GMT7110_SP) {
306 #ifdef DEBUG
307 smprintf(s, "location %i\n",(Block[6]*256+Block[7]));
308 #endif
309 speed->MemoryType = GMT_ME;
310 if (Block[8] == 0x06) speed->MemoryType = GMT_SM;
311 speed->MemoryLocation = (Block[6]*256+Block[7]);
312 speed->MemoryNumberID = 2;
313 } else return GE_UNKNOWNRESPONSE;
314 break;
315 case N7110_ENTRYTYPE_SPEEDDIAL:
316 if (entry->MemoryType==GMT7110_SP) {
317 #ifdef DEBUG
318 switch (Block[12]) {
319 case 0x05: smprintf(s, "ME\n"); break;
320 case 0x06: smprintf(s, "SM\n"); break;
321 default : smprintf(s, "%02x\n",Block[12]);
323 smprintf(s, "location %i, number %i in location\n",
324 (Block[6]*256+Block[7])-1,Block[14]);
325 #endif
326 switch (Block[12]) {
327 case 0x05: speed->MemoryType = GMT_ME; break;
328 case 0x06: speed->MemoryType = GMT_SM; break;
330 speed->MemoryLocation = (Block[6]*256+Block[7])-1;
331 speed->MemoryNumberID = Block[14];
332 } else return GE_UNKNOWNRESPONSE;
333 break;
334 case N7110_ENTRYTYPE_UNKNOWN1:
335 smprintf(s,"Unknown entry\n");
336 break;
337 default:
338 smprintf(s, "ERROR: unknown pbk entry %i\n",Block[0]);
339 return GE_UNKNOWNRESPONSE;
341 length=length + Block[3];
342 Block = &Block[(int) Block[3]];
345 if (entry->EntriesNum == 0) return GE_EMPTY;
347 return GE_NONE;
350 void NOKIA_GetDefaultCallerGroupName(GSM_StateMachine *s, GSM_Bitmap *Bitmap)
352 Bitmap->DefaultName = false;
353 if (Bitmap->Text[0]==0x00 && Bitmap->Text[1]==0x00) {
354 Bitmap->DefaultName = true;
355 switch(Bitmap->Location) {
356 case 1:
357 EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Family"),strlen(GetMsg(s->msg,"Family")));
358 break;
359 case 2:
360 EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"VIP"),strlen(GetMsg(s->msg,"VIP")));
361 break;
362 case 3:
363 EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Friends"),strlen(GetMsg(s->msg,"Friends")));
364 break;
365 case 4:
366 EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Colleagues"),strlen(GetMsg(s->msg,"Colleagues")));
367 break;
368 case 5:
369 EncodeUnicode(Bitmap->Text,GetMsg(s->msg,"Other"),strlen(GetMsg(s->msg,"Other")));
370 break;
375 void NOKIA_DecodeDateTime(GSM_StateMachine *s, unsigned char* buffer, GSM_DateTime *datetime)
377 datetime->Year = buffer[0] * 256 + buffer[1];
378 datetime->Month = buffer[2];
379 datetime->Day = buffer[3];
381 datetime->Hour = buffer[4];
382 datetime->Minute = buffer[5];
383 datetime->Second = buffer[6];
385 smprintf(s, "Decoding date and time\n");
386 smprintf(s, " Time: %02d:%02d:%02d\n",
387 datetime->Hour, datetime->Minute, datetime->Second);
388 smprintf(s, " Date: %4d/%02d/%02d\n",
389 datetime->Year, datetime->Month, datetime->Day);
392 #if defined(GSM_ENABLE_NOKIA_DCT3) || defined(GSM_ENABLE_NOKIA_DCT4)
394 /* --------------------- Some general Nokia functions ---------------------- */
396 void NOKIA_DecodeSMSState(GSM_StateMachine *s, unsigned char state, GSM_SMSMessage *sms)
398 switch (state) {
399 case 0x01 : sms->State = GSM_Read; break;
400 case 0x03 : sms->State = GSM_UnRead; break;
401 case 0x05 : sms->State = GSM_Sent; break;
402 case 0x07 : sms->State = GSM_UnSent; break;
403 default : smprintf(s, "Unknown SMS state: %02x\n",state);
407 GSM_Error NOKIA_ReplyGetPhoneString(GSM_Protocol_Message msg, GSM_StateMachine *s)
409 strcpy(s->Phone.Data.PhoneString, msg.Buffer+s->Phone.Data.StartPhoneString);
410 return GE_NONE;
413 /* Some strings are very easy. Some header, after it required string and 0x00.
414 * We can get them using this function. We give frame to send (*string),
415 * type of message (type), pointer for buffer for response (*value), request
416 * type (request) and what is start byte in response for our string
418 GSM_Error NOKIA_GetPhoneString(GSM_StateMachine *s, unsigned char *msgframe, int msglen, unsigned char msgtype, char *retvalue, GSM_Phone_RequestID request, int startresponse)
420 retvalue[0] = 0;
421 s->Phone.Data.StartPhoneString = startresponse;
422 s->Phone.Data.PhoneString = retvalue;
423 return GSM_WaitFor (s, msgframe, msglen,msgtype, 4, request);
426 GSM_Error NOKIA_GetManufacturer(GSM_StateMachine *s)
428 strcpy(s->Phone.Data.Manufacturer,"Nokia");
429 return GE_NONE;
432 /* Many functions contains such strings:
433 * (1. length/256) - exist or not
434 * 2. length%256
435 * 3. string (unicode, no termination)
436 * This function read string to output and increases counter
438 void NOKIA_GetUnicodeString(GSM_StateMachine *s, int *current, unsigned char *input, unsigned char *output, bool FullLength)
440 int length;
442 if (FullLength) {
443 length = (input[*current]*256+input[*current+1])*2;
444 memcpy(output,input+(*current+2),length);
445 *current = *current + 2 + length;
446 } else {
447 length = (input[*current])*2;
448 memcpy(output,input+(*current+1),length);
449 *current = *current + 1 + length;
452 output[length ] = 0;
453 output[length+1] = 0;
456 int NOKIA_SetUnicodeString(GSM_StateMachine *s, unsigned char *dest, unsigned char *string, bool FullLength)
458 int length;
460 length = UnicodeLength(string);
461 if (FullLength) {
462 dest[0] = length / 256;
463 dest[1] = length % 256;
464 CopyUnicodeString(dest + 2, string);
465 return 2+length*2;
466 } else {
467 dest[0] = length % 256;
468 CopyUnicodeString(dest + 1, string);
469 return 1+length*2;
473 /* Returns correct ID for concrete memory type */
474 GSM_MemoryType NOKIA_GetMemoryType(GSM_StateMachine *s, GSM_MemoryType memory_type, unsigned char *ID)
476 int i=0;
478 while (ID[i+1]!=0x00) {
479 if (ID[i]==memory_type) return ID[i+1];
480 i=i+2;
482 return 0xff;
485 void NOKIA_EncodeDateTime(GSM_StateMachine *s, unsigned char* buffer, GSM_DateTime *datetime)
487 buffer[0] = datetime->Year / 256;
488 buffer[1] = datetime->Year % 256;
489 buffer[2] = datetime->Month;
490 buffer[3] = datetime->Day;
492 buffer[4] = datetime->Hour;
493 buffer[5] = datetime->Minute;
496 void NOKIA_SortSMSFolderStatus(GSM_StateMachine *s, GSM_NOKIASMSFolder *Folder)
498 int i,j;
500 if (Folder->Number!=0) {
501 /* Bouble sorting */
502 i=0;
503 while (i!=Folder->Number-1) {
504 if (Folder->Location[i]>Folder->Location[i+1]) {
505 j=Folder->Location[i];
506 Folder->Location[i]=Folder->Location[i+1];
507 Folder->Location[i+1]=j;
508 i=0;
509 } else {
510 i++;
513 #ifdef DEBUG
514 smprintf(s, "Locations: ");
515 for (i=0;i<Folder->Number;i++) {
516 smprintf(s, "%i ",Folder->Location[i]);
518 smprintf(s, "\n");
519 #endif
523 void NOKIA_GetDefaultProfileName(GSM_StateMachine *s, GSM_Profile *Profile)
525 if (Profile->DefaultName) {
526 switch(Profile->Location) {
527 case 1: EncodeUnicode(Profile->Name,GetMsg(s->msg,"General"),strlen(GetMsg(s->msg,"General")));
528 break;
529 case 2: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Silent"),strlen(GetMsg(s->msg,"Silent")));
530 break;
531 case 3: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Meeting"),strlen(GetMsg(s->msg,"Meeting")));
532 break;
533 case 4: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Outdoor"),strlen(GetMsg(s->msg,"Outdoor")));
534 break;
535 case 5: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Pager"),strlen(GetMsg(s->msg,"Pager")));
536 break;
537 case 6: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Car"),strlen(GetMsg(s->msg,"Car")));
538 break;
539 case 7: EncodeUnicode(Profile->Name,GetMsg(s->msg,"Headset"),strlen(GetMsg(s->msg,"Headset")));
540 break;
545 /* - Shared for DCT3 (n6110.c, n7110.c, n9110.c) and DCT4 (n6510.c) phones - */
547 GSM_Error DCT3DCT4_ReplyCallDivert(GSM_Protocol_Message msg, GSM_StateMachine *s)
549 GSM_MultiCallDivert *cd = s->Phone.Data.Divert;
550 int i,pos = 11,j;
552 switch (msg.Buffer[3]) {
553 case 0x02:
554 smprintf(s,"Message: Call divert status received\n");
555 smprintf(s," Divert type: ");
556 switch (msg.Buffer[6]) {
557 case 0x43: smprintf(s,"when busy"); break;
558 case 0x3d: smprintf(s,"when not answered"); break;
559 case 0x3e: smprintf(s,"when phone off or no coverage"); break;
560 case 0x15: smprintf(s,"all types of diverts"); break;
561 default: smprintf(s,"unknown %i",msg.Buffer[6]); break;
563 /* 6150 */
564 if (msg.Length == 0x0b) {
565 cd->Response.EntriesNum = 0;
566 return GE_NONE;
568 cd->Response.EntriesNum = msg.Buffer[10];
569 for (i=0;i<cd->Response.EntriesNum;i++) {
570 smprintf(s,"\n Calls type : ");
571 switch (msg.Buffer[pos]) {
572 case 0x0b:
573 smprintf(s,"voice");
574 cd->Response.Entries[i].CType = GSM_CDV_VoiceCalls;
575 break;
576 case 0x0d:
577 smprintf(s,"fax");
578 cd->Response.Entries[i].CType = GSM_CDV_FaxCalls;
579 break;
580 case 0x19:
581 smprintf(s,"data");
582 cd->Response.Entries[i].CType = GSM_CDV_DataCalls;
583 break;
584 default:
585 smprintf(s,"unknown %i",msg.Buffer[pos]);
586 /* 6310i */
587 cd->Response.EntriesNum = 0;
588 return GE_NONE;
589 break;
591 smprintf(s,"\n");
592 j = pos + 2;
593 while (msg.Buffer[j] != 0x00) j++;
594 msg.Buffer[pos+1] = j - pos - 2;
595 GSM_UnpackSemiOctetNumber(cd->Response.Entries[i].Number,msg.Buffer+(pos+1),false);
596 smprintf(s," Number : %s\n",DecodeUnicodeString(cd->Response.Entries[i].Number));
597 cd->Response.Entries[i].Timeout = msg.Buffer[pos+34];
598 smprintf(s," Timeout : %i seconds\n",msg.Buffer[pos+34]);
599 pos+=35;
601 return GE_NONE;
602 case 0x03:
603 smprintf(s,"Message: Call divert status receiving error ?\n");
604 return GE_UNKNOWN;
606 return GE_UNKNOWNRESPONSE;
609 static GSM_Error DCT3DCT4_CallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert, bool get)
611 int length = 0x09;
612 unsigned char req[55] = {N6110_FRAME_HEADER, 0x01,
613 0x05, /* operation = Query */
614 0x00,
615 0x00, /* divert type */
616 0x00, /* call type */
617 0x00};
619 if (!get) {
620 if (UnicodeLength(divert->Request.Number) == 0) {
621 req[4] = 0x04;
622 } else {
623 req[4] = 0x03;
624 req[8] = 0x01;
625 req[29] = GSM_PackSemiOctetNumber(divert->Request.Number, req + 9, false);
626 req[52] = divert->Request.Timeout;
627 length = 55;
630 switch (divert->Request.DType) {
631 case GSM_CDV_AllTypes : req[6] = 0x15; break;
632 case GSM_CDV_Busy : req[6] = 0x43; break;
633 case GSM_CDV_NoAnswer : req[6] = 0x3d; break;
634 case GSM_CDV_OutOfReach: req[6] = 0x3e; break;
635 default : return GE_NOTIMPLEMENTED;
638 switch (divert->Request.CType) {
639 case GSM_CDV_AllCalls : break;
640 case GSM_CDV_VoiceCalls: req[7] = 0x0b; break;
641 case GSM_CDV_FaxCalls : req[7] = 0x0d; break;
642 case GSM_CDV_DataCalls : req[7] = 0x19; break;
643 default : return GE_NOTIMPLEMENTED;
646 s->Phone.Data.Divert = divert;
647 smprintf(s, "Call divert\n");
648 return GSM_WaitFor (s, req, length, 0x06, 10, ID_Divert);
651 GSM_Error DCT3DCT4_GetCallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert)
653 return DCT3DCT4_CallDivert(s,divert,true);
656 GSM_Error DCT3DCT4_SetCallDivert(GSM_StateMachine *s, GSM_MultiCallDivert *divert)
658 return DCT3DCT4_CallDivert(s,divert,false);
661 GSM_Error DCT3DCT4_CancelAllDiverts(GSM_StateMachine *s)
663 GSM_MultiCallDivert divert;
664 unsigned char req[55] = {N6110_FRAME_HEADER, 0x01,
665 0x04, /* operation = Disable */
666 0x00,
667 0x02, /* divert type */
668 0x00, /* call type */
669 0x00};
671 s->Phone.Data.Divert = &divert;
672 smprintf(s, "Call divert\n");
673 return GSM_WaitFor (s, req, 0x09, 0x06, 10, ID_Divert);
676 GSM_Error DCT3DCT4_ReplyGetActiveWAPMMSSet(GSM_Protocol_Message msg, GSM_StateMachine *s)
678 GSM_Phone_Data *Data = &s->Phone.Data;
680 Data->WAPSettings->Active = false;
681 if (Data->WAPSettings->Location - 1 == msg.Buffer[4]) {
682 Data->WAPSettings->Active = true;
684 return GE_NONE;
687 GSM_Error DCT3DCT4_GetActiveWAPMMSSet(GSM_StateMachine *s)
689 unsigned char GetSetreq[] = {N6110_FRAME_HEADER, 0x0F};
691 smprintf(s, "Checking, if WAP/MMS settings are active\n");
692 return GSM_WaitFor (s, GetSetreq, 4, 0x3f, 4, ID_GetWAPSettings);
695 GSM_Error DCT3DCT4_ReplySetActiveWAPMMSSet(GSM_Protocol_Message msg, GSM_StateMachine *s)
697 smprintf(s, "WAP settings activated\n");
698 return GE_NONE;
701 GSM_Error DCT3DCT4_SetActiveWAPMMSSet(GSM_StateMachine *s, GSM_MultiWAPSettings *settings, bool MMS)
703 unsigned char reqActivate[] = {
704 N6110_FRAME_HEADER, 0x12,
705 0x00}; /* Location */
707 if (settings->Active) {
708 reqActivate[4] = settings->Location-1;
709 if (MMS) {
710 smprintf(s, "Activating MMS settings\n");
711 return GSM_WaitFor (s, reqActivate, 5, 0x3f, 4, ID_SetMMSSettings);
712 } else {
713 smprintf(s, "Activating WAP settings\n");
714 return GSM_WaitFor (s, reqActivate, 5, 0x3f, 4, ID_SetWAPSettings);
717 return GE_NONE;
721 GSM_Error DCT3DCT4_SendDTMF(GSM_StateMachine *s, char *sequence)
723 unsigned char length = strlen(sequence);
724 unsigned char req[64] = {
725 N6110_FRAME_HEADER, 0x50,
726 0x00}; /* Length of DTMF string. */
728 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NODTMF)) return GE_NOTSUPPORTED;
730 if (length>59) length=59;
731 req[4] = length;
733 memcpy(req+5,sequence,length);
735 smprintf(s, "Sending DTMF\n");
736 return GSM_WaitFor (s, req, 5+length, 0x01, 4, ID_SendDTMF);
739 GSM_Error DCT3DCT4_ReplyGetWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s, bool FullLength)
741 int tmp;
742 GSM_Phone_Data *Data = &s->Phone.Data;
744 smprintf(s, "WAP bookmark received\n");
745 switch (msg.Buffer[3]) {
746 case 0x07:
747 tmp = 4;
749 Data->WAPBookmark->Location = msg.Buffer[tmp] * 256 + msg.Buffer[tmp+1];
750 smprintf(s, "Location: %i\n",Data->WAPBookmark->Location);
751 tmp = tmp + 2;
753 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer, Data->WAPBookmark->Title, FullLength);
754 smprintf(s, "Title : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Title));
756 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer, Data->WAPBookmark->Address, FullLength);
757 smprintf(s, "Address : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Address));
759 return GE_NONE;
760 case 0x08:
761 switch (msg.Buffer[4]) {
762 case 0x01:
763 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
764 return GE_INSIDEPHONEMENU;
765 case 0x02:
766 smprintf(s, "Invalid or empty\n");
767 return GE_INVALIDLOCATION;
768 default:
769 smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]);
770 return GE_UNKNOWNRESPONSE;
772 break;
774 return GE_UNKNOWNRESPONSE;
777 GSM_Error DCT3DCT4_ReplySetWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s)
779 switch (msg.Buffer[3]) {
780 case 0x0A:
781 smprintf(s, "WAP bookmark set OK\n");
782 return GE_NONE;
783 case 0x0B:
784 smprintf(s, "WAP bookmark setting error\n");
785 switch (msg.Buffer[4]) {
786 case 0x01:
787 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
788 return GE_INSIDEPHONEMENU;
789 case 0x02:
790 smprintf(s, "Can't write to empty location ?\n");
791 return GE_EMPTY;
792 case 0x04:
793 smprintf(s, "Full memory\n");
794 return GE_FULL;
795 default:
796 smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]);
797 return GE_UNKNOWNRESPONSE;
800 return GE_UNKNOWNRESPONSE;
803 GSM_Error DCT3DCT4_ReplyEnableWAP(GSM_Protocol_Message msg, GSM_StateMachine *s)
805 smprintf(s, "WAP functions enabled\n");
806 return GE_NONE;
809 GSM_Error DCT3DCT4_EnableWAP(GSM_StateMachine *s)
811 unsigned char req[] = { N6110_FRAME_HEADER, 0x00 };
813 /* Check if have WAP in phone */
814 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOWAP)) return GE_NOTSUPPORTED;
816 smprintf(s, "Enabling WAP\n");
817 return GSM_WaitFor (s, req, 4, 0x3f, 4, ID_EnableWAP);
820 GSM_Error DCT3DCT4_ReplyDelWAPBookmark(GSM_Protocol_Message msg, GSM_StateMachine *s)
822 switch (msg.Buffer[3]) {
823 case 0x0D:
824 smprintf(s, "WAP bookmark deleted OK\n");
825 return GE_NONE;
826 case 0x0E:
827 smprintf(s, "WAP bookmark deleting error\n");
828 switch (msg.Buffer[4]) {
829 case 0x01:
830 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
831 return GE_SECURITYERROR;
832 case 0x02:
833 smprintf(s, "Invalid location\n");
834 return GE_INVALIDLOCATION;
835 default:
836 smprintf(s, "ERROR: unknown %i\n",msg.Buffer[4]);
837 return GE_UNKNOWNRESPONSE;
840 return GE_UNKNOWNRESPONSE;
843 GSM_Error DCT3DCT4_DeleteWAPBookmark(GSM_StateMachine *s, GSM_WAPBookmark *bookmark)
845 GSM_Error error;
846 unsigned char req[] = {
847 N6110_FRAME_HEADER, 0x0C,
848 0x00, 0x00}; /* Location */
850 /* We have to enable WAP frames in phone */
851 error=DCT3DCT4_EnableWAP(s);
852 if (error!=GE_NONE) return error;
854 req[5] = bookmark->Location;
856 smprintf(s, "Deleting WAP bookmark\n");
857 return GSM_WaitFor (s, req, 6, 0x3f, 4, ID_DeleteWAPBookmark);
860 GSM_Error DCT3DCT4_GetWAPBookmark(GSM_StateMachine *s, GSM_WAPBookmark *bookmark)
862 GSM_Error error;
863 unsigned char req[] = {
864 N6110_FRAME_HEADER, 0x06,
865 0x00, 0x00}; /* Location */
867 /* We have to enable WAP frames in phone */
868 error=DCT3DCT4_EnableWAP(s);
869 if (error!=GE_NONE) return error;
871 req[5]=bookmark->Location-1;
873 s->Phone.Data.WAPBookmark=bookmark;
874 smprintf(s, "Getting WAP bookmark\n");
875 return GSM_WaitFor (s, req, 6, 0x3f, 4, ID_GetWAPBookmark);
878 GSM_Error DCT3DCT4_CancelCall(GSM_StateMachine *s, int ID)
880 unsigned char req[] = {N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
882 req[4] = (unsigned char)ID;
883 s->Phone.Data.CallID = ID;
885 smprintf(s, "Canceling single call\n");
886 return GSM_WaitFor (s, req, 6, 0x01, 4, ID_CancelCall);
889 GSM_Error DCT3DCT4_AnswerCall(GSM_StateMachine *s, int ID)
891 unsigned char req[] = {N6110_FRAME_HEADER, 0x06, 0x00, 0x00};
893 req[4] = (unsigned char)ID;
894 s->Phone.Data.CallID = ID;
896 smprintf(s, "Answering single call\n");
897 return GSM_WaitFor (s, req, 6, 0x01, 4, ID_AnswerCall);
900 GSM_Error DCT3DCT4_ReplyGetModelFirmware(GSM_Protocol_Message msg, GSM_StateMachine *s)
902 GSM_Lines lines;
903 GSM_Phone_Data *Data = &s->Phone.Data;
905 SplitLines(msg.Buffer, msg.Length, &lines, "\x20\x0A", 2, false);
907 strcpy(Data->Model,GetLineString(msg.Buffer, lines, 4));
908 smprintf(s, "Received model %s\n",Data->Model);
909 Data->ModelInfo = GetModelData(NULL,Data->Model,NULL);
911 strcpy(Data->VerDate,GetLineString(msg.Buffer, lines, 3));
912 smprintf(s, "Received firmware date %s\n",Data->VerDate);
914 strcpy(Data->Version,GetLineString(msg.Buffer, lines, 2));
915 smprintf(s, "Received firmware version %s\n",Data->Version);
916 GSM_CreateFirmwareNumber(s);
918 return GE_NONE;
921 GSM_Error DCT3DCT4_GetModel (GSM_StateMachine *s)
923 unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};
924 GSM_Error error;
926 if (strlen(s->Phone.Data.Model)>0) return GE_NONE;
928 smprintf(s, "Getting model\n");
929 error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetModel);
930 if (error==GE_NONE) {
931 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL ||
932 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) {
933 smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model);
934 smprintf(s, "[Firmware version - \"%s\"]\n",s->Phone.Data.Version);
935 smprintf(s, "[Firmware date - \"%s\"]\n",s->Phone.Data.VerDate);
938 return error;
941 GSM_Error DCT3DCT4_GetFirmware (GSM_StateMachine *s)
943 unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};
944 GSM_Error error;
946 if (strlen(s->Phone.Data.Version)>0) return GE_NONE;
948 smprintf(s, "Getting firmware version\n");
949 error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetFirmware);
950 if (error==GE_NONE) {
951 if (s->di.dl==DL_TEXT || s->di.dl==DL_TEXTALL ||
952 s->di.dl==DL_TEXTDATE || s->di.dl==DL_TEXTALLDATE) {
953 smprintf(s, "[Connected model - \"%s\"]\n",s->Phone.Data.Model);
954 smprintf(s, "[Firmware version - \"%s\"]\n",s->Phone.Data.Version);
955 smprintf(s, "[Firmware date - \"%s\"]\n",s->Phone.Data.VerDate);
958 return error;
961 /* ---------- Shared for n7110.c and n6510.c ------------------------------- */
963 GSM_Error N71_65_ReplyGetMemoryError(unsigned char error, GSM_StateMachine *s)
965 switch (error) {
966 case 0x27:
967 smprintf(s, "No PIN\n");
968 return GE_SECURITYERROR;
969 case 0x30:
970 smprintf(s, "Invalid memory type\n");
971 if (s->Phone.Data.Memory->MemoryType == GMT_ME) return GE_EMPTY;
972 if (s->Phone.Data.Memory->MemoryType == GMT_SM) return GE_EMPTY;
973 return GE_NOTSUPPORTED;
974 case 0x33:
975 smprintf(s, "Empty location\n");
976 s->Phone.Data.Memory->EntriesNum = 0;
977 return GE_EMPTY;
978 case 0x34:
979 smprintf(s, "Too high location ?\n");
980 return GE_INVALIDLOCATION;
981 default:
982 smprintf(s, "ERROR: unknown %i\n",error);
983 return GE_UNKNOWNRESPONSE;
987 GSM_Error N71_65_ReplyWritePhonebook(GSM_Protocol_Message msg, GSM_StateMachine *s)
989 smprintf(s, "Phonebook entry written ");
990 switch (msg.Buffer[6]) {
991 case 0x0f:
992 smprintf(s, " - error\n");
993 switch (msg.Buffer[10]) {
994 case 0x36:
995 smprintf(s, "Too long name\n");
996 return GE_NOTSUPPORTED;
997 case 0x3c:
998 smprintf(s, "Can not add entry with 0 subentries\n");
999 return GE_NOTSUPPORTED;
1000 case 0x3d:
1001 smprintf(s, "Wrong entry type\n");
1002 return GE_NOTSUPPORTED;
1003 case 0x3e:
1004 smprintf(s, "Too much entries\n");
1005 return GE_NOTSUPPORTED;
1006 default:
1007 smprintf(s, "ERROR: unknown %i\n",msg.Buffer[10]);
1008 return GE_UNKNOWNRESPONSE;
1010 default:
1011 smprintf(s, " - OK\n");
1012 return GE_NONE;
1016 bool NOKIA_FindPhoneFeatureValue(GSM_StateMachine *s,
1017 GSM_Profile_PhoneTableValue ProfileTable[],
1018 GSM_Profile_Feat_ID FeatureID,
1019 GSM_Profile_Feat_Value FeatureValue,
1020 unsigned char *PhoneID,
1021 unsigned char *PhoneValue)
1023 int i=0;
1025 smprintf(s, "Trying to find feature %i with value %i\n",FeatureID,FeatureValue);
1026 while (ProfileTable[i].ID != 0x00) {
1027 if (ProfileTable[i].ID == FeatureID &&
1028 ProfileTable[i].Value == FeatureValue) {
1029 *PhoneID = ProfileTable[i].PhoneID;
1030 *PhoneValue = ProfileTable[i].PhoneValue;
1031 return true;
1033 i++;
1035 return false;
1038 #define PROFILE_CALLERGROUPS_GROUP1 0x01
1039 #define PROFILE_CALLERGROUPS_GROUP2 0x02
1040 #define PROFILE_CALLERGROUPS_GROUP3 0x04
1041 #define PROFILE_CALLERGROUPS_GROUP4 0x08
1042 #define PROFILE_CALLERGROUPS_GROUP5 0x10
1044 void NOKIA_FindFeatureValue(GSM_StateMachine *s,
1045 GSM_Profile_PhoneTableValue ProfileTable[],
1046 unsigned char ID,
1047 unsigned char Value,
1048 GSM_Phone_Data *Data,
1049 bool CallerGroups)
1051 int i;
1053 if (CallerGroups) {
1054 smprintf(s, "Caller groups: %i\n", Value);
1055 Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = Profile_CallerGroups;
1056 Data->Profile->FeaturesNumber++;
1057 for (i=0;i<5;i++) Data->Profile->CallerGroups[i] = false;
1058 if ((Value & PROFILE_CALLERGROUPS_GROUP1)==PROFILE_CALLERGROUPS_GROUP1) Data->Profile->CallerGroups[0] = true;
1059 if ((Value & PROFILE_CALLERGROUPS_GROUP2)==PROFILE_CALLERGROUPS_GROUP2) Data->Profile->CallerGroups[1] = true;
1060 if ((Value & PROFILE_CALLERGROUPS_GROUP3)==PROFILE_CALLERGROUPS_GROUP3) Data->Profile->CallerGroups[2] = true;
1061 if ((Value & PROFILE_CALLERGROUPS_GROUP4)==PROFILE_CALLERGROUPS_GROUP4) Data->Profile->CallerGroups[3] = true;
1062 if ((Value & PROFILE_CALLERGROUPS_GROUP5)==PROFILE_CALLERGROUPS_GROUP5) Data->Profile->CallerGroups[4] = true;
1063 return;
1066 i = 0;
1067 while (ProfileTable[i].ID != 0x00) {
1068 if (ProfileTable[i].PhoneID == ID &&
1069 ProfileTable[i].PhoneValue == Value) {
1070 #ifdef DEBUG
1071 switch (ProfileTable[i].ID) {
1072 case Profile_KeypadTone : smprintf(s, "Keypad tones\n"); break;
1073 case Profile_CallAlert : smprintf(s, "Call alert\n"); break;
1074 case Profile_RingtoneVolume : smprintf(s, "Ringtone volume\n"); break;
1075 case Profile_MessageTone : smprintf(s, "SMS message tones\n"); break;
1076 case Profile_Vibration : smprintf(s, "Vibration\n"); break;
1077 case Profile_WarningTone : smprintf(s, "Warning (ang games) tones\n"); break;
1078 case Profile_AutoAnswer : smprintf(s, "Automatic answer\n"); break;
1079 case Profile_Lights : smprintf(s, "Lights\n"); break;
1080 case Profile_ScreenSaver : smprintf(s, "Screen Saver\n"); break;
1081 case Profile_ScreenSaverTime : smprintf(s, "Screen Saver timeout\n"); break;
1082 default : break;
1084 #endif
1085 Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = ProfileTable[i].ID;
1086 Data->Profile->FeatureValue [Data->Profile->FeaturesNumber] = ProfileTable[i].Value;
1087 Data->Profile->FeaturesNumber++;
1088 break;
1090 i++;
1094 GSM_Profile_PhoneTableValue Profile71_65[] = {
1095 {Profile_KeypadTone, PROFILE_KEYPAD_OFF, 0x00,0x00},
1096 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL1, 0x00,0x01},
1097 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL2, 0x00,0x02},
1098 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL3, 0x00,0x03},
1099 /* Lights ? */
1100 {Profile_CallAlert, PROFILE_CALLALERT_RINGING, 0x02,0x00},
1101 {Profile_CallAlert, PROFILE_CALLALERT_ASCENDING, 0x02,0x01},
1102 {Profile_CallAlert, PROFILE_CALLALERT_RINGONCE, 0x02,0x02},
1103 {Profile_CallAlert, PROFILE_CALLALERT_BEEPONCE, 0x02,0x03},
1104 {Profile_CallAlert, PROFILE_CALLALERT_OFF, 0x02,0x05},
1105 /* {Profile_CallAlert, PROFILE_CALLALERT_CALLERGROUPS,0x02,0x07}, */
1106 /* Ringtone ID */
1107 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL1, 0x04,0x00},
1108 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL2, 0x04,0x01},
1109 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL3, 0x04,0x02},
1110 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL4, 0x04,0x03},
1111 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL5, 0x04,0x04},
1112 {Profile_MessageTone, PROFILE_MESSAGE_NOTONE, 0x05,0x00},
1113 {Profile_MessageTone, PROFILE_MESSAGE_STANDARD, 0x05,0x01},
1114 {Profile_MessageTone, PROFILE_MESSAGE_SPECIAL, 0x05,0x02},
1115 {Profile_MessageTone, PROFILE_MESSAGE_BEEPONCE, 0x05,0x03},
1116 {Profile_MessageTone, PROFILE_MESSAGE_ASCENDING, 0x05,0x04},
1117 {Profile_Vibration, PROFILE_VIBRATION_OFF, 0x06,0x00},
1118 {Profile_Vibration, PROFILE_VIBRATION_ON, 0x06,0x01},
1119 {Profile_WarningTone, PROFILE_WARNING_OFF, 0x07,0x00},
1120 {Profile_WarningTone, PROFILE_WARNING_ON, 0x07,0x01},
1121 /* Caller groups */
1122 {Profile_AutoAnswer, PROFILE_AUTOANSWER_OFF, 0x09,0x00},
1123 {Profile_AutoAnswer, PROFILE_AUTOANSWER_ON, 0x09,0x01},
1124 {0x00, 0x00, 0x00,0x00}
1127 GSM_Error NOKIA_SetIncomingSMS(GSM_StateMachine *s, bool enable)
1129 s->Phone.Data.EnableIncomingSMS = enable;
1130 #ifdef DEBUG
1131 if (enable) {
1132 smprintf(s, "Enabling incoming SMS\n");
1133 } else {
1134 smprintf(s, "Disabling incoming SMS\n");
1136 #endif
1137 return GE_NONE;
1140 GSM_Error N71_65_ReplyUSSDInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
1142 unsigned char buffer[2000],buffer2[4000];
1144 if (s->Phone.Data.RequestID == ID_Divert) return GE_NONE;
1146 memcpy(buffer,msg.Buffer+8,msg.Buffer[7]);
1147 buffer[msg.Buffer[7]] = 0x00;
1149 smprintf(s, "USSD reply: \"%s\"\n",buffer);
1151 if (s->Phone.Data.EnableIncomingUSSD && s->User.IncomingUSSD!=NULL) {
1152 EncodeUnicode(buffer2,buffer,strlen(buffer));
1153 s->User.IncomingUSSD(s->CurrentConfig->Device, buffer2);
1156 return GE_NONE;
1159 GSM_Error NOKIA_SetIncomingUSSD(GSM_StateMachine *s, bool enable)
1161 s->Phone.Data.EnableIncomingUSSD = enable;
1162 #ifdef DEBUG
1163 if (enable) {
1164 smprintf(s, "Enabling incoming USSD\n");
1165 } else {
1166 smprintf(s, "Disabling incoming USSD\n");
1168 #endif
1169 return GE_NONE;
1172 GSM_Error NOKIA_SetIncomingCall(GSM_StateMachine *s, bool enable)
1174 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOCALLINFO)) return GE_NOTSUPPORTED;
1176 s->Phone.Data.EnableIncomingCall = enable;
1177 #ifdef DEBUG
1178 if (enable) {
1179 smprintf(s, "Enabling incoming Call\n");
1180 } else {
1181 smprintf(s, "Disabling incoming Call\n");
1183 #endif
1184 return GE_NONE;
1187 GSM_Error N71_65_ReplyCallInfo(GSM_Protocol_Message msg, GSM_StateMachine *s)
1189 GSM_Call call;
1190 int tmp;
1191 unsigned char buffer[200];
1193 call.Status = 0;
1194 call.CallIDAvailable = true;
1195 smprintf(s, "Call info, ");
1196 switch (msg.Buffer[3]) {
1197 case 0x02:
1198 smprintf(s, "Call established, waiting for answer\n");
1199 call.Status = GN_CALL_CallEstablished;
1200 break;
1201 case 0x03:
1202 smprintf(s, "Call started\n");
1203 smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//after gnokii
1204 tmp = 6;
1205 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false);
1206 smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer));
1207 /* FIXME: read name from frame */
1209 call.Status = GN_CALL_CallStart;
1210 break;
1211 case 0x04:
1212 smprintf(s, "Remote end hang up\n");
1213 smprintf(s, "Cause Type : %i\n",msg.Buffer[5]);//after gnokii
1214 smprintf(s, "CC : %i\n",msg.Buffer[6]);
1215 smprintf(s, "MM(?) : %i\n",msg.Buffer[7]);
1216 smprintf(s, "RR(?) : %i\n",msg.Buffer[8]);
1217 call.Status = GN_CALL_CallRemoteEnd;
1218 call.StatusCode = msg.Buffer[6];
1219 break;
1220 case 0x05:
1221 smprintf(s, "Incoming call\n");
1222 smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//after gnokii
1223 tmp = 6;
1224 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false);
1225 smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer));
1226 /* FIXME: read name from frame */
1227 call.Status = GN_CALL_IncomingCall;
1228 tmp = 6;
1229 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,call.PhoneNumber,false);
1230 break;
1231 case 0x07:
1232 smprintf(s, "Call answer initiated\n");
1233 break;
1234 case 0x09:
1235 smprintf(s, "Call released\n");
1236 call.Status = GN_CALL_CallLocalEnd;
1237 break;
1238 case 0x0a:
1239 smprintf(s, "Call is being released\n");
1240 break;
1241 case 0x0b:
1242 smprintf(s, "Meaning not known\n");
1243 call.CallIDAvailable = false;
1244 break;
1245 case 0x0c:
1246 smprintf(s, "Audio status\n");
1247 if (msg.Buffer[4] == 0x01) smprintf(s, "Audio enabled\n");
1248 else smprintf(s, "Audio disabled\n");
1249 call.CallIDAvailable = false;
1250 break;
1251 case 0x23:
1252 smprintf(s, "Call held\n");
1253 call.Status = GN_CALL_CallHeld;
1254 break;
1255 case 0x25:
1256 smprintf(s, "Call resumed\n");
1257 call.Status = GN_CALL_CallResumed;
1258 break;
1259 case 0x27:
1260 smprintf(s, "Call switched\n");
1261 call.Status = GN_CALL_CallSwitched;
1262 break;
1263 case 0x53:
1264 smprintf(s, "Outgoing call\n");
1265 smprintf(s, "Call mode : %i\n",msg.Buffer[5]);//after gnokii
1266 tmp = 6;
1267 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,buffer,false);
1268 smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(buffer));
1269 /* FIXME: read name from frame */
1270 call.Status = GN_CALL_OutgoingCall;
1271 tmp = 6;
1272 NOKIA_GetUnicodeString(s, &tmp, msg.Buffer,call.PhoneNumber,false);
1273 break;
1275 if (call.CallIDAvailable) smprintf(s, "Call ID : %d\n",msg.Buffer[4]);
1276 if (s->Phone.Data.EnableIncomingCall && s->User.IncomingCall!=NULL && call.Status != 0) {
1277 if (call.CallIDAvailable) call.CallID = msg.Buffer[4];
1278 s->User.IncomingCall(s->CurrentConfig->Device, call);
1280 if (s->Phone.Data.RequestID == ID_CancelCall) {
1281 if (msg.Buffer[3] == 0x09) {
1282 if (s->Phone.Data.CallID == msg.Buffer[4]) return GE_NONE;
1283 /* when we canceled call and see frame about other
1284 * call releasing, we don't give GE_NONE for "our"
1285 * call release command
1287 return GE_NEEDANOTHERANSWER;
1290 if (s->Phone.Data.RequestID == ID_AnswerCall) {
1291 if (msg.Buffer[3] == 0x07) {
1292 if (s->Phone.Data.CallID == msg.Buffer[4]) return GE_NONE;
1293 return GE_NEEDANOTHERANSWER;
1296 return GE_NONE;
1299 void N71_65_GetCalendarRecurrance(GSM_StateMachine *s, unsigned char *buffer, GSM_CalendarEntry *entry)
1301 int Recurrance;
1303 Recurrance = buffer[0]*256 + buffer[1];
1304 if (Recurrance == 0xffff) Recurrance=8760; /* 0xffff -> 1 Year (8760 hours) */
1305 if (Recurrance != 0) {
1306 smprintf(s, "Recurrance : %i hours\n",Recurrance);
1307 entry->Entries[entry->EntriesNum].EntryType = CAL_RECURRANCE;
1308 entry->Entries[entry->EntriesNum].Number = Recurrance;
1309 entry->EntriesNum++;
1313 /* method 2 */
1314 GSM_Error N71_65_ReplyAddCalendar2(GSM_Protocol_Message msg, GSM_StateMachine *s)
1316 smprintf(s, "Calendar note added\n");
1317 return GE_NONE;
1320 /* method 2 */
1321 GSM_Error N71_65_AddCalendar2(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1323 GSM_CalendarNoteType NoteType;
1324 time_t t_time1,t_time2;
1325 GSM_DateTime Date,date_time;
1326 GSM_Error error;
1327 long diff;
1328 int Text, Time, Alarm, Phone, Recurrance, EndTime, Location, length=25;
1329 unsigned char req[5000] = {
1330 N6110_FRAME_HEADER,
1331 0x40,
1332 0x00, /* frame length - 7 */
1333 0x00,0x00,0x00,0x00,
1334 0x00,0x00,0x00,0x00, /* start time saved as difference */
1335 0x00,0x00,0xff,0xff, /* alarm saved as difference */
1336 0x00, /* frame length - 7 */
1337 0x00, /* note type */
1338 0x00,0x00, /* recurrance */
1339 0x00,0x00,0x00,0x00,
1340 0x00,0x00,0x00,0x00}; /* rest depends on note type */
1342 NoteType = N71_65_FindCalendarType(Note->Type, s->Phone.Data.ModelInfo);
1344 if (IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62) ||
1345 IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65))
1347 switch(NoteType) {
1348 case GCN_MEETING : req[18] = 0x01; length = 25; break;
1349 case GCN_CALL : req[18] = 0x02; length = 27; break;
1350 case GCN_BIRTHDAY: req[18] = 0x04; length = 28; break;
1351 case GCN_MEMO : req[18] = 0x08; length = 25; break;
1352 default : return GE_UNKNOWN;
1354 } else {
1355 switch(NoteType) {
1356 case GCN_REMINDER: req[18] = 0x01; length = 25; break;
1357 case GCN_CALL : req[18] = 0x02; length = 27; break;
1358 case GCN_BIRTHDAY: req[18] = 0x04; length = 28; break;
1359 case GCN_MEMO : req[18] = 0x08; length = 25; break;
1360 default : return GE_UNKNOWN;
1364 GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(Note, &Text, &Time, &Alarm, &Phone, &Recurrance, &EndTime, &Location);
1366 if (Time == -1) return GE_UNKNOWN;
1367 if (NoteType != GCN_BIRTHDAY) {
1368 Date.Year = 2030; Date.Month = 01; Date.Day = 01;
1369 Date.Hour = 00; Date.Minute = 00; Date.Second = 00;
1370 } else {
1371 Date.Year = 2029; Date.Month = 12; Date.Day = 31;
1372 Date.Hour = 22; Date.Minute = 59; Date.Second = 58;
1374 t_time1 = Fill_Time_T(Date,8);
1375 memcpy(&Date,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
1376 if (NoteType != GCN_BIRTHDAY) {
1377 Date.Year -= 20;
1378 } else {
1379 Date.Year = 1980;
1380 Date.Hour = 22; Date.Minute = 58; Date.Second = 58;
1382 t_time2 = Fill_Time_T(Date,8);
1383 diff = t_time1-t_time2;
1384 smprintf(s, " Difference : %i seconds\n", -diff);
1385 req[9] = (unsigned char)(-diff >> 24);
1386 req[10] = (unsigned char)(-diff >> 16);
1387 req[11] = (unsigned char)(-diff >> 8);
1388 req[12] = (unsigned char)(-diff);
1389 if (NoteType == GCN_BIRTHDAY) {
1390 req[25] = Note->Entries[Time].Date.Year / 256;
1391 req[26] = Note->Entries[Time].Date.Year % 256;
1392 /* Recurrance = 1 year */
1393 req[19] = 0xff;
1394 req[20] = 0xff;
1397 if (NoteType == GCN_CALL && Phone != -1) {
1398 req[25] = UnicodeLength(Note->Entries[Phone].Text);
1399 CopyUnicodeString(req+length,Note->Entries[Phone].Text);
1400 length += UnicodeLength(Note->Entries[Phone].Text)*2;
1403 if (Alarm != -1) {
1404 if (NoteType == GCN_BIRTHDAY) {
1405 if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[27] = 0x01;
1406 error=s->Phone.Functions->GetDateTime(s,&date_time);
1407 switch (error) {
1408 case GE_EMPTY:
1409 case GE_NOTIMPLEMENTED:
1410 GSM_GetCurrentDateTime(&date_time);
1411 break;
1412 case GE_NONE:
1413 break;
1414 default:
1415 return error;
1417 Date.Year = date_time.Year;
1418 Date.Hour = 23;
1419 Date.Minute = 59;
1420 } else {
1421 Date.Year += 20;
1423 t_time2 = Fill_Time_T(Date,8);
1424 t_time1 = Fill_Time_T(Note->Entries[Alarm].Date,8);
1425 diff = t_time1-t_time2;
1427 /* Sometimes we have difference in minutes */
1428 if (NoteType == GCN_MEETING) diff = diff / 60;
1429 if (!IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35)) {
1430 if (NoteType == GCN_MEMO || NoteType == GCN_CALL) {
1431 diff = diff / 60;
1435 smprintf(s, " Difference : %i seconds or minutes\n", -diff);
1436 req[13] = (unsigned char)(-diff >> 24);
1437 req[14] = (unsigned char)(-diff >> 16);
1438 req[15] = (unsigned char)(-diff >> 8);
1439 req[16] = (unsigned char)(-diff);
1442 if (Recurrance != -1) {
1443 /* 0xffff -> 1 Year (8760 hours) */
1444 if (Note->Entries[Recurrance].Number >= 8760) {
1445 req[19] = 0xff;
1446 req[20] = 0xff;
1447 } else {
1448 req[19] = Note->Entries[Recurrance].Number / 256;
1449 req[20] = Note->Entries[Recurrance].Number % 256;
1453 if (Text != -1) {
1454 switch (NoteType) {
1455 case GCN_CALL:
1456 req[26] = UnicodeLength(Note->Entries[Text].Text);
1457 break;
1458 default:
1459 req[length++] = UnicodeLength(Note->Entries[Text].Text);
1460 if (NoteType == GCN_MEMO || NoteType == GCN_MEETING) req[length++] = 0x00;
1462 CopyUnicodeString(req+length,Note->Entries[Text].Text);
1463 length += UnicodeLength(Note->Entries[Text].Text)*2;
1466 req[length++] = 0x00;
1467 req[length++] = 0x00;
1469 req[4] = req[17] = length-7;
1471 smprintf(s, "Writing calendar note method 2\n");
1472 return GSM_WaitFor (s, req, length, 0x13, 4, ID_SetCalendarNote);
1475 /* method 1*/
1476 GSM_Error N71_65_ReplyGetCalendarNotePos1(GSM_Protocol_Message msg, GSM_StateMachine *s,int *FirstCalendarPos)
1478 smprintf(s, "First calendar location: %i\n",msg.Buffer[4]*256+msg.Buffer[5]);
1479 *FirstCalendarPos = msg.Buffer[4]*256+msg.Buffer[5];
1480 return GE_NONE;
1483 /* method 1*/
1484 static GSM_Error N71_65_GetCalendarNotePos1(GSM_StateMachine *s)
1486 unsigned char req[] = {N6110_FRAME_HEADER, 0x31};
1488 smprintf(s, "Getting first free calendar note location\n");
1489 return GSM_WaitFor (s, req, 4, 0x13, 4, ID_GetCalendarNotePos);
1492 /* method 1 */
1493 GSM_Error N71_65_ReplyAddCalendar1(GSM_Protocol_Message msg, GSM_StateMachine *s)
1495 #ifdef DEBUG
1496 smprintf(s, "Written Calendar Note type ");
1497 switch ((msg.Buffer[3]/2)-1) {
1498 case 0: smprintf(s, "Meeting"); break;
1499 case 1: smprintf(s, "Call"); break;
1500 case 2: smprintf(s, "Birthday");break;
1501 case 3: smprintf(s, "Reminder");break;
1503 smprintf(s, " on location %d\n",msg.Buffer[4]*256+msg.Buffer[5]);
1504 #endif
1505 return GE_NONE;
1508 /* method 1 */
1509 GSM_Error N71_65_AddCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, int *FirstCalendarPos)
1511 long seconds;
1512 GSM_Error error;
1513 GSM_DateTime DT;
1514 int Text, Time, Alarm, Phone, Recurrance, EndTime, Location, count=12;
1515 unsigned char req[5000] = {
1516 N6110_FRAME_HEADER,
1517 0x01, /* note type */
1518 0x00, 0x00, /* location ? */
1519 0x00, /* entry type */
1520 0x00,
1521 0x00, 0x00, 0x00, 0x00, /* Year(2bytes), Month, Day */
1522 /* here starts block ... depends on note type */
1523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1525 error=N71_65_GetCalendarNotePos1(s);
1526 if (error!=GE_NONE) return error;
1527 if (FirstCalendarPos != NULL) {
1528 req[4] = *FirstCalendarPos/256;
1529 req[5] = *FirstCalendarPos%256;
1532 switch(Note->Type) {
1533 case GCN_CALL : req[3]=0x03; req[6]=0x02; break;
1534 case GCN_BIRTHDAY: req[3]=0x05; req[6]=0x04; break;
1535 case GCN_MEMO : req[3]=0x07; req[6]=0x08; break;
1536 case GCN_MEETING :
1537 default : req[3]=0x01; req[6]=0x01; break;
1540 GSM_CalendarFindDefaultTextTimeAlarmPhoneRecurrance(Note, &Text, &Time, &Alarm, &Phone, &Recurrance, &EndTime, &Location);
1542 if (Time == -1) return GE_UNKNOWN;
1543 memcpy(&DT,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
1544 req[8] = DT.Year >> 8;
1545 req[9] = DT.Year & 0xff;
1546 req[10] = DT.Month;
1547 req[11] = DT.Day;
1549 switch(Note->Type) {
1550 case GCN_BIRTHDAY:
1551 req[count++] = 0x00; /* 12 */
1552 req[count++] = 0x00; /* 13 */
1554 /* Alarm */
1555 req[count++] = 0x00; /* 14 */
1556 req[count++] = 0x00; /* 15 */
1557 req[count++] = 0xff; /* 16 */
1558 req[count++] = 0xff; /* 17 */
1559 if (Alarm != -1) {
1560 /* I try with Time.Year = Alarm.Year. If negative, I increase 1 year,
1561 * but only once ! This thing, because I may have Alarm period across
1562 * a year. (eg. Birthday on 2001-01-10 and Alarm on 2000-12-27)
1564 DT.Year = Note->Entries[Alarm].Date.Year;
1565 if((seconds = Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8))<0L)
1567 DT.Year++;
1568 seconds = Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8);
1570 if(seconds>=0L)
1572 count -= 4;
1573 req[count++] = (unsigned char)(seconds>>24); /* 14 */
1574 req[count++] = (unsigned char)((seconds>>16) & 0xff); /* 15 */
1575 req[count++] = (unsigned char)((seconds>>8) & 0xff); /* 16 */
1576 req[count++] = (unsigned char)(seconds & 0xff); /* 17 */
1578 if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[count++] = 0x01; else req[count++] = 0x00;
1581 if (Text != -1) {
1582 req[count++] = UnicodeLength(Note->Entries[Text].Text); /* 19 */
1583 CopyUnicodeString(req+count,Note->Entries[Text].Text);
1584 count=count+2*UnicodeLength(Note->Entries[Text].Text); /* 22->N */
1585 } else {
1586 req[count++] = 0x00;
1588 break;
1589 case GCN_MEMO:
1590 if (Recurrance != -1) {
1591 /* 0xffff -> 1 Year (8760 hours) */
1592 if (Note->Entries[Recurrance].Number >= 8760) {
1593 req[count++] = 0xff;
1594 req[count++] = 0xff;
1595 } else {
1596 req[count++] = Note->Entries[Recurrance].Number >> 8; /* 12 */
1597 req[count++] = Note->Entries[Recurrance].Number & 0xff; /* 13 */
1599 } else {
1600 req[count++] = 0x00; /* 12 */
1601 req[count++] = 0x00; /* 13 */
1604 if (Text != -1) {
1605 req[count++] = UnicodeLength(Note->Entries[Text].Text); /* 14 */
1606 req[count++] = 0x00; /* 15 */
1607 CopyUnicodeString(req+count,Note->Entries[Text].Text);
1608 count=count+2*UnicodeLength(Note->Entries[Text].Text); /* 16->N */
1609 } else {
1610 req[count++] = 0x00;
1611 req[count++] = 0x00;
1613 break;
1614 case GCN_MEETING:
1615 case GCN_CALL:
1616 default:
1617 req[count++] = DT.Hour; /* 12 */
1618 req[count++] = DT.Minute; /* 13 */
1620 /* Alarm */
1621 req[count++] = 0xff; /* 14 */
1622 req[count++] = 0xff; /* 15 */
1623 if (Alarm != -1) {
1624 seconds=Fill_Time_T(DT,8)-Fill_Time_T(Note->Entries[Alarm].Date,8);
1625 if(seconds>=0L)
1627 count -= 2;
1628 req[count++] = ((unsigned char)(seconds/60L)>>8);
1629 req[count++] = (unsigned char)((seconds/60L)&0xff);
1633 if (Recurrance != -1) {
1634 /* 0xffff -> 1 Year (8760 hours) */
1635 if (Note->Entries[Recurrance].Number >= 8760) {
1636 req[count++] = 0xff;
1637 req[count++] = 0xff;
1638 } else {
1639 req[count++] = Note->Entries[Recurrance].Number >> 8; /* 12 */
1640 req[count++] = Note->Entries[Recurrance].Number & 0xff; /* 13 */
1642 } else {
1643 req[count++] = 0x00; /* 16 */
1644 req[count++] = 0x00; /* 17 */
1647 if (Text != -1) {
1648 req[count++] = UnicodeLength(Note->Entries[Text].Text);
1649 } else {
1650 req[count++] = 0x00; /* 18 */
1652 if (Note->Type == GCN_CALL && Phone != -1) {
1653 req[count++] = UnicodeLength(Note->Entries[Phone].Text);
1654 } else {
1655 req[count++] = 0x00; /* 19 */
1657 if (Text != -1) {
1658 CopyUnicodeString(req+count,Note->Entries[Text].Text);
1659 count=count+2*UnicodeLength(Note->Entries[Text].Text);/* 20->N */
1661 if (Note->Type == GCN_CALL && Phone != -1) {
1662 CopyUnicodeString(req+count,Note->Entries[Phone].Text);
1663 count=count+2*UnicodeLength(Note->Entries[Phone].Text);/* (N+1)->n */
1665 break;
1667 req[count] = 0x00;
1668 smprintf(s, "Writing calendar note method 1\n");
1669 return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetCalendarNote);
1672 GSM_Error N71_65_ReplyDelCalendar(GSM_Protocol_Message msg, GSM_StateMachine *s)
1674 smprintf(s, "Deleted calendar note on location %d\n",msg.Buffer[4]*256+msg.Buffer[5]);
1675 return GE_NONE;
1678 GSM_Error N71_65_DelCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
1680 unsigned char req[] = {
1681 N6110_FRAME_HEADER, 0x0b,
1682 0x00, 0x00}; /* location */
1684 req[4] = Note->Location >> 8;
1685 req[5] = Note->Location & 0xff;
1687 smprintf(s, "Deleting calendar note\n");
1688 return GSM_WaitFor (s, req, 6, 0x13, 4, ID_DeleteCalendarNote);
1691 /* method 1 */
1692 GSM_Error N71_65_ReplyGetCalendarInfo1(GSM_Protocol_Message msg, GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar)
1694 int i,j=0;
1696 smprintf(s, "Info with calendar notes locations received method 1\n");
1697 while (LastCalendar->Location[j] != 0x00) j++;
1698 if (j >= GSM_MAXCALENDARTODONOTES) {
1699 smprintf(s, "Increase GSM_MAXCALENDARNOTES\n");
1700 return GE_UNKNOWN;
1702 if (j == 0) {
1703 LastCalendar->Number=msg.Buffer[4]*256+msg.Buffer[5];
1704 smprintf(s, "Number of Entries: %i\n",LastCalendar->Number);
1706 smprintf(s, "Locations: ");
1707 i = 0;
1708 while (9+(i*2) <= msg.Length) {
1709 LastCalendar->Location[j++]=msg.Buffer[8+(i*2)]*256+msg.Buffer[9+(i*2)];
1710 smprintf(s, "%i ",LastCalendar->Location[j-1]);
1711 i++;
1713 smprintf(s, "\nNumber of Entries in frame: %i\n",i);
1714 smprintf(s, "\n");
1715 LastCalendar->Location[j] = 0;
1716 if (i == 1 && msg.Buffer[8+(0*2)]*256+msg.Buffer[9+(0*2)] == 0) return GE_EMPTY;
1717 if (i == 0) return GE_EMPTY;
1718 return GE_NONE;
1721 /* method 1 */
1722 GSM_Error N71_65_GetCalendarInfo1(GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar)
1724 GSM_Error error;
1725 int i;
1726 unsigned char req[] = {N6110_FRAME_HEADER, 0x3a,
1727 0xFF, 0xFE}; /* First location number */
1729 LastCalendar->Location[0] = 0x00;
1730 LastCalendar->Number = 0;
1732 smprintf(s, "Getting locations for calendar method 1\n");
1733 error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo);
1734 if (error != GE_NONE && error != GE_EMPTY) return error;
1736 while (1) {
1737 i=0;
1738 while (LastCalendar->Location[i] != 0x00) i++;
1739 if (i == LastCalendar->Number) break;
1740 if (i != LastCalendar->Number && error == GE_EMPTY) {
1741 smprintf(s, "Phone doesn't support some notes with this method. Workaround\n");
1742 LastCalendar->Number = i;
1743 break;
1745 smprintf(s, "i = %i %i\n",i,LastCalendar->Number);
1746 req[4] = LastCalendar->Location[i-1] / 256;
1747 req[5] = LastCalendar->Location[i-1] % 256;
1748 smprintf(s, "Getting locations for calendar\n");
1749 error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo);
1750 if (error != GE_NONE && error != GE_EMPTY) return error;
1752 return GE_NONE;
1755 /* method 1 */
1756 GSM_Error N71_65_ReplyGetNextCalendar1(GSM_Protocol_Message msg, GSM_StateMachine *s)
1758 int alarm,i;
1759 GSM_CalendarEntry *entry = s->Phone.Data.Cal;
1761 smprintf(s, "Calendar note received method 1\n");
1763 /* Later these values can change */
1764 if (msg.Buffer[6]!=0x04) { /* Here not birthday */
1765 entry->Entries[0].Date.Year = msg.Buffer[8]*256+msg.Buffer[9];
1767 entry->Entries[0].Date.Month = msg.Buffer[10];
1768 entry->Entries[0].Date.Day = msg.Buffer[11];
1769 entry->Entries[0].Date.Hour = msg.Buffer[12];
1770 entry->Entries[0].Date.Minute = msg.Buffer[13];
1771 entry->Entries[0].Date.Second = 0;
1772 entry->Entries[0].EntryType = CAL_START_DATETIME;
1773 entry->EntriesNum++;
1775 switch (msg.Buffer[6]) {
1776 case 0x01:
1777 smprintf(s, "Meeting\n");
1778 entry->Type = GCN_MEETING;
1780 alarm=msg.Buffer[14]*256+msg.Buffer[15];
1781 if (alarm != 0xffff) {
1782 smprintf(s, " Difference : %i seconds\n", alarm);
1783 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
1784 GetTimeDifference(alarm, &entry->Entries[1].Date, false, 60);
1785 entry->Entries[1].EntryType = CAL_ALARM_DATETIME;
1786 entry->EntriesNum++;
1788 N71_65_GetCalendarRecurrance(s, msg.Buffer + 16, entry);
1790 memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20, msg.Buffer[18]*2);
1791 entry->Entries[entry->EntriesNum].Text[msg.Buffer[18]*2] = 0;
1792 entry->Entries[entry->EntriesNum].Text[msg.Buffer[18]*2+1] = 0;
1793 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
1794 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
1795 entry->EntriesNum++;
1796 return GE_NONE;
1797 case 0x02:
1798 smprintf(s, "Call\n");
1799 entry->Type = GCN_CALL;
1801 alarm=msg.Buffer[14]*256+msg.Buffer[15];
1802 if (alarm != 0xffff) {
1803 smprintf(s, " Difference : %i seconds\n", alarm);
1804 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
1805 GetTimeDifference(alarm, &entry->Entries[1].Date, false, 60);
1806 entry->Entries[1].EntryType = CAL_ALARM_DATETIME;
1807 entry->EntriesNum++;
1809 N71_65_GetCalendarRecurrance(s, msg.Buffer + 16, entry);
1811 i = msg.Buffer[18] * 2;
1812 if (i!=0) {
1813 memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20, i);
1814 entry->Entries[entry->EntriesNum].Text[i] = 0;
1815 entry->Entries[entry->EntriesNum].Text[i+1] = 0;
1816 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
1817 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
1818 entry->EntriesNum++;
1821 memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+20+i, msg.Buffer[19]*2);
1822 entry->Entries[entry->EntriesNum].Text[msg.Buffer[19]*2] = 0;
1823 entry->Entries[entry->EntriesNum].Text[msg.Buffer[19]*2+1] = 0;
1824 entry->Entries[entry->EntriesNum].EntryType = CAL_PHONE;
1825 smprintf(s, "Phone : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
1826 entry->EntriesNum++;
1827 return GE_NONE;
1828 case 0x04:
1829 smprintf(s, "Birthday\n");
1830 entry->Type = GCN_BIRTHDAY;
1832 entry->Entries[0].Date.Hour = 23;
1833 entry->Entries[0].Date.Minute = 59;
1834 entry->Entries[0].Date.Second = 58;
1836 alarm = ((unsigned int)msg.Buffer[14]) << 24;
1837 alarm += ((unsigned int)msg.Buffer[15]) << 16;
1838 alarm += ((unsigned int)msg.Buffer[16]) << 8;
1839 alarm += msg.Buffer[17];
1840 if (alarm != 0xffff) {
1841 smprintf(s, " Difference : %i seconds\n", alarm);
1842 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
1843 GetTimeDifference(alarm, &entry->Entries[1].Date, false, 1);
1844 entry->Entries[1].EntryType = CAL_ALARM_DATETIME;
1845 if (msg.Buffer[20]!=0x00) {
1846 entry->Entries[1].EntryType = CAL_SILENT_ALARM_DATETIME;
1847 smprintf(s, "Alarm type : Silent\n");
1849 entry->EntriesNum++;
1852 entry->Entries[0].Date.Year = msg.Buffer[18]*256 + msg.Buffer[19];
1853 if (entry->Entries[0].Date.Year == 65535) entry->Entries[0].Date.Year = 0;
1854 smprintf(s, "Age : %i\n",entry->Entries[0].Date.Year);
1856 memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+22, msg.Buffer[21]*2);
1857 entry->Entries[entry->EntriesNum].Text[msg.Buffer[21]*2] = 0;
1858 entry->Entries[entry->EntriesNum].Text[msg.Buffer[21]*2+1] = 0;
1859 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
1860 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
1861 entry->EntriesNum++;
1862 return GE_NONE;
1863 case 0x08:
1864 smprintf(s, "Memo\n");
1865 entry->Type = GCN_MEMO;
1867 entry->Entries[0].Date.Hour = 0;
1868 entry->Entries[0].Date.Minute = 0;
1870 N71_65_GetCalendarRecurrance(s, msg.Buffer + 12, entry);
1872 memcpy(entry->Entries[entry->EntriesNum].Text, msg.Buffer+16, msg.Buffer[14]*2);
1873 entry->Entries[entry->EntriesNum].Text[msg.Buffer[14]*2] = 0;
1874 entry->Entries[entry->EntriesNum].Text[msg.Buffer[14]*2+1] = 0;
1875 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
1876 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
1877 entry->EntriesNum++;
1878 return GE_NONE;
1879 default:
1880 smprintf(s, "ERROR: unknown %i\n",msg.Buffer[6]);
1881 return GE_UNKNOWNRESPONSE;
1885 /* method 1 */
1886 GSM_Error N71_65_GetNextCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, bool start, GSM_NOKIACalToDoLocations *LastCalendar, int *LastCalendarYear, int *LastCalendarPos)
1888 GSM_Error error;
1889 GSM_DateTime date_time;
1890 unsigned char req[] = {
1891 N6110_FRAME_HEADER, 0x19,
1892 0x00, 0x00}; /* Location */
1894 if (start) {
1895 error=N71_65_GetCalendarInfo1(s, LastCalendar);
1896 if (error!=GE_NONE) return error;
1897 if (LastCalendar->Number == 0) return GE_EMPTY;
1899 /* We have to get current year. It's NOT written in frame for
1900 * Birthday
1902 error=s->Phone.Functions->GetDateTime(s,&date_time);
1903 switch (error) {
1904 case GE_EMPTY:
1905 case GE_NOTIMPLEMENTED:
1906 GSM_GetCurrentDateTime(&date_time);
1907 break;
1908 case GE_NONE:
1909 break;
1910 default:
1911 return error;
1913 *LastCalendarYear = date_time.Year;
1914 *LastCalendarPos = 0;
1915 } else {
1916 (*LastCalendarPos)++;
1919 if (*LastCalendarPos >= LastCalendar->Number) return GE_EMPTY;
1921 req[4] = LastCalendar->Location[*LastCalendarPos] >> 8;
1922 req[5] = LastCalendar->Location[*LastCalendarPos] & 0xff;
1924 Note->EntriesNum = 0;
1925 Note->Entries[0].Date.Year = *LastCalendarYear;
1926 Note->Location = LastCalendar->Location[*LastCalendarPos];
1928 s->Phone.Data.Cal=Note;
1929 smprintf(s, "Getting calendar note method 1\n");
1930 return GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNote);
1933 GSM_Error N71_65_EnableFunctions(GSM_StateMachine *s,char *buff,int len)
1935 unsigned char buffer[50] =
1936 {N6110_FRAME_HEADER,0x10,
1937 0x07}; /* Length */
1939 buffer[4] = len;
1940 memcpy(buffer+5,buff,len);
1942 /* Enables various things like incoming SMS, call info, etc. */
1943 return s->Protocol.Functions->WriteMessage(s, buffer, 5+len, 0x10);
1946 GSM_Error N71_65_ReplySendDTMF(GSM_Protocol_Message msg, GSM_StateMachine *s)
1948 switch (msg.Buffer[3]) {
1949 case 0x51:
1950 smprintf(s, "DTMF sent OK\n");
1951 return GE_NONE;
1952 case 0x59:
1953 case 0x5E:
1954 smprintf(s, "meaning unknown - during sending DTMF\n");
1955 return GE_NONE;
1957 return GE_UNKNOWNRESPONSE;
1960 GSM_CalendarNoteType N71_65_FindCalendarType(GSM_CalendarNoteType Type, OnePhoneModel *model)
1962 switch (Type) {
1963 case GCN_CALL:
1964 return GCN_CALL;
1965 case GCN_BIRTHDAY:
1966 return GCN_BIRTHDAY;
1967 case GCN_MEETING:
1968 if (IsPhoneFeatureAvailable(model, F_CAL35)) {
1969 return GCN_REMINDER;
1970 } else return GCN_MEETING;
1971 case GCN_MEMO:
1972 if (IsPhoneFeatureAvailable(model, F_CAL35)) {
1973 return GCN_REMINDER;
1974 } else return GCN_MEMO;
1975 case GCN_REMINDER:
1976 if (IsPhoneFeatureAvailable(model, F_CAL62) ||
1977 IsPhoneFeatureAvailable(model, F_CAL65)) {
1978 return GCN_CALL;
1979 } else return GCN_REMINDER;
1980 default:
1981 return GCN_CALL;
1985 #endif
1987 /* How should editor hadle tabs in this file? Add editor commands here.
1988 * vim: noexpandtab sw=8 ts=8 sts=8: