1 /* (c) 2002-2005 by Marcin Wiacek */
2 /* based on some work from Ralf Thelen, Gabriele Zappi and MyGnokii */
3
4 #include <string.h> /* memcpy only */
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <time.h>
8
9 #include <gammu-nokia.h>
10
11 #include "../../gsmstate.h"
12 #include "../../gsmphones.h"
13 #include "../../misc/coding/coding.h"
14 #include "../../misc/locales.h"
15 #include "../../service/gsmnet.h"
16 #include "../../service/gsmlogo.h"
17 #include "../../service/gsmcal.h"
18 #include "../pfunc.h"
19 #include "nfunc.h"
20
21 unsigned char N71_65_MEMORY_TYPES[] = {
22 MEM_DC, 0x01,
23 MEM_MC, 0x02,
24 MEM_RC, 0x03,
25 MEM_ME, 0x05,
26 MEM_SM, 0x06,
27 MEM_VM, 0x09,
28 MEM7110_SP, 0x0e,
29 MEM7110_CG, 0x10,
30 MEM_ON, 0x17,
31 MEM6510_CG2, 0x23,
32 MEM_SL, 0x27,
33 0x00, 0x00
34 };
35
N71_65_PackPBKBlock(GSM_StateMachine * s,int id,size_t size,int no,unsigned char * buf,unsigned char * block)36 size_t N71_65_PackPBKBlock(GSM_StateMachine *s, int id, size_t size, int no, unsigned char *buf, unsigned char *block)
37 {
38 smprintf(s, "Packing phonebook block with ID = %i, block number = %i, block length = %ld\n",
39 id,
40 no+1,
41 (long)size+6);
42
43 block[0] = id;
44 block[1] = 0;
45 block[2] = (size + 6) / 256;
46 block[3] = (size + 6) % 256;
47 block[4] = no + 1;
48 memcpy(block+5, buf, size);
49 block[5+size] = 0;
50
51 return (size + 6);
52 }
53
N71_65_EncodePhonebookFrame(GSM_StateMachine * s,unsigned char * req,GSM_MemoryEntry * entry,size_t * block2,gboolean DCT4,gboolean VoiceTag)54 size_t N71_65_EncodePhonebookFrame(GSM_StateMachine *s, unsigned char *req, GSM_MemoryEntry *entry, size_t *block2, gboolean DCT4, gboolean VoiceTag)
55 {
56 int count=0, len, i, block=0, j;
57 unsigned char string[500];
58 unsigned char type;
59 gboolean found;
60
61 for (i = 0; i < entry->EntriesNum; i++) {
62 entry->Entries[i].AddError = ERR_NOTSUPPORTED;
63 }
64 memset(string,0,sizeof(string));
65 found = FALSE;
66 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SERIES40_30)) {
67 for (i = 0; i < entry->EntriesNum; i++) {
68 if (entry->Entries[i].EntryType == PBK_Text_LastName ||
69 entry->Entries[i].EntryType == PBK_Text_FirstName) {
70 if (entry->Entries[i].EntryType==PBK_Text_LastName) {
71 type = S4030_PBK_LASTNAME;
72 } else {
73 type = S4030_PBK_FIRSTNAME;
74 }
75 found = TRUE;
76 entry->Entries[i].AddError = ERR_NONE;
77 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
78 string[0] = len*2+2;
79 CopyUnicodeString(string+1,entry->Entries[i].Text);
80 string[len*2+1] = 0;
81 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
82 }
83 }
84 for (i = 0; i < entry->EntriesNum; i++) {
85 if(entry->Entries[i].EntryType==PBK_Text_Name) {
86 if (!found) {
87 entry->Entries[i].AddError = ERR_NONE;
88 type = N7110_PBK_NAME;
89 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
90 string[0] = len*2+2;
91 CopyUnicodeString(string+1,entry->Entries[i].Text);
92 string[len*2+1] = 0;
93 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
94 found = TRUE;
95 } else {
96 entry->Entries[i].AddError = ERR_INVALIDDATA;
97 }
98 }
99 }
100 } else {
101 for (i = 0; i < entry->EntriesNum; i++) {
102 if (entry->Entries[i].EntryType == PBK_Text_LastName ||
103 entry->Entries[i].EntryType == PBK_Text_FirstName) {
104 if (UnicodeLength(string+1) > 0) {
105 string[UnicodeLength(string+1)*2+1] = ' ';
106 }
107 CopyUnicodeString(string+UnicodeLength(string+1)*2+1,entry->Entries[i].Text);
108 entry->Entries[i].AddError = ERR_DATACONVERTED;
109 found=TRUE;
110 }
111 }
112 if (UnicodeLength(string+1) != 0) {
113 type = N7110_PBK_NAME;
114 len = MIN(UnicodeLength(string+1), 126);
115 string[0] = len*2+2;
116 string[len*2+1] = 0;
117 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
118 }
119 for (i = 0; i < entry->EntriesNum; i++) {
120 if (entry->Entries[i].EntryType==PBK_Text_Name) {
121 if (!found) {
122 entry->Entries[i].AddError = ERR_NONE;
123 type = N7110_PBK_NAME;
124 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
125 string[0] = len*2+2;
126 CopyUnicodeString(string+1,entry->Entries[i].Text);
127 string[len*2+1] = 0;
128 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
129 found = TRUE;
130 } else {
131 entry->Entries[i].AddError = ERR_INVALIDDATA;
132 }
133 }
134 }
135 }
136 for (i = 0; i < entry->EntriesNum; i++) {
137 type = 0;
138 if (entry->Entries[i].EntryType == PBK_Number_General && entry->Entries[i].Location == PBK_Location_Work) type = N7110_PBK_NUMBER_WORK;
139 else if (entry->Entries[i].EntryType == PBK_Number_General && entry->Entries[i].Location == PBK_Location_Home) type = N7110_PBK_NUMBER_HOME;
140 else if (entry->Entries[i].EntryType == PBK_Number_General) type = N7110_PBK_NUMBER_GENERAL;
141 if (entry->Entries[i].EntryType == PBK_Number_Mobile) type = N7110_PBK_NUMBER_MOBILE;
142 if (entry->Entries[i].EntryType == PBK_Number_Fax) type = N7110_PBK_NUMBER_FAX;
143 if (type != 0) {
144 entry->Entries[i].AddError = ERR_NONE;
145
146 string[0] = type;
147 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
148
149 string[1] = 0;
150 string[2] = 0;
151
152 /* DCT 3 */
153 if (!DCT4) string[2] = entry->Entries[i].VoiceTag;
154
155 string[3] = 0;
156 string[4] = len*2+2;
157 CopyUnicodeString(string+5,entry->Entries[i].Text);
158 string[len * 2 + 5] = 0;
159 count += N71_65_PackPBKBlock(s, N7110_PBK_NUMBER, len*2+6, block++, string, req+count);
160
161 /* DCT 4 */
162 if (DCT4 && VoiceTag) {
163 block++;
164 req[count++] = N6510_PBK_VOICETAG_ID;
165 req[count++] = 0;
166 req[count++] = 0;
167 req[count++] = 8;
168 req[count++] = 0x00;
169 req[count++] = i+1;
170 req[count++] = 0x00;
171 req[count++] = entry->Entries[i].VoiceTag;
172 }
173 if (DCT4) {
174 j = 0;
175 while (entry->Entries[i].SMSList[j] != 0) {
176 string[0] = i+1;
177 string[1] = 0x00;
178 string[2] = 0x02;
179 string[3] = 0x00;
180 string[4] = entry->Entries[i].SMSList[j];
181 string[5] = 0x00;
182 count += N71_65_PackPBKBlock(s, N6510_PBK_SMSLIST_ID, 6, block++, string, req+count);
183
184 j++;
185 }
186 }
187 continue;
188 }
189 smprintf(s, "entry num %i %i\n",i,entry->EntriesNum);
190 if (entry->Entries[i].EntryType == PBK_Text_Note) type = N7110_PBK_NOTE;
191 if (entry->Entries[i].EntryType == PBK_Text_Postal) {
192 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKNOPOSTAL)) {
193 continue;
194 }
195 type = N7110_PBK_POSTAL;
196 }
197 if (entry->Entries[i].EntryType == PBK_Text_Email) type = N7110_PBK_EMAIL;
198 if (entry->Entries[i].EntryType == PBK_Text_Email2) type = N7110_PBK_EMAIL;
199 if (entry->Entries[i].EntryType == PBK_Text_URL) {
200 entry->Entries[i].AddError = ERR_DATACONVERTED;
201 type = N7110_PBK_NOTE;
202 if (DCT4) type = N6510_PBK_URL;
203 }
204 if (type != 0) {
205 if (entry->Entries[i].AddError==ERR_NOTSUPPORTED) entry->Entries[i].AddError = ERR_NONE;
206 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
207 string[0] = len*2+2;
208 CopyUnicodeString(string+1,entry->Entries[i].Text);
209 string[len*2+1] = 0;
210 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
211 continue;
212 }
213 if (entry->Entries[i].EntryType == PBK_Caller_Group) {
214 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) {
215 entry->Entries[i].AddError = ERR_NONE;
216 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_6230iCALLER)) {
217 string[0] = 0;
218 string[1] = 0;
219 count += N71_65_PackPBKBlock(s, N6510_PBK_GROUP2_ID, 2, block++, string, req + count);
220 req[count-1] = entry->Entries[i].Number;
221 } else {
222 string[0] = entry->Entries[i].Number;
223 string[1] = 0;
224 count += N71_65_PackPBKBlock(s, N7110_PBK_GROUP, 2, block++, string, req + count);
225 }
226 }
227 continue;
228 }
229 if (entry->Entries[i].EntryType == PBK_RingtoneID) {
230 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBK35)) {
231 entry->Entries[i].AddError = ERR_NONE;
232 string[0] = 0x00;
233 string[1] = 0x00;
234 string[2] = entry->Entries[i].Number;
235 count += N71_65_PackPBKBlock(s, N7110_PBK_RINGTONE_ID, 3, block++, string, req + count);
236 count --;
237 req[count-5] = 8;
238 }
239 continue;
240 }
241 if (entry->Entries[i].EntryType == PBK_PictureID) {
242 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKIMG)) {
243 entry->Entries[i].AddError = ERR_NONE;
244 string[0] = 0x00;
245 string[1] = 0x00;
246 string[2] = 0x00;
247 string[3] = 0x00;
248 string[4] = 0x01;
249 string[5] = entry->Entries[i].Number / 256;
250 string[6] = entry->Entries[i].Number % 256;
251 string[7] = 0x00;
252 string[8] = 0x00;
253 string[9] = 0x00;
254 count += N71_65_PackPBKBlock(s, N6510_PBK_PICTURE_ID, 10, block++, string, req + count);
255 req[count-1] = 0x01;
256 }
257 continue;
258 }
259 /* Maybe we should use separate feature for these new entries... */
260 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_SERIES40_30)) {
261 type = 0;
262 if (entry->Entries[i].EntryType == PBK_Text_FormalName) type = S4030_PBK_FORMALNAME;
263 if (entry->Entries[i].EntryType == PBK_Text_JobTitle) type = S4030_PBK_JOBTITLE;
264 if (entry->Entries[i].EntryType == PBK_Text_Company) type = S4030_PBK_COMPANY;
265 if (entry->Entries[i].EntryType == PBK_Text_NickName) type = S4030_PBK_NICKNAME;
266 if (type != 0) {
267 if (entry->Entries[i].AddError==ERR_NOTSUPPORTED) entry->Entries[i].AddError = ERR_NONE;
268 len = MIN(UnicodeLength(entry->Entries[i].Text), 126);
269 string[0] = len*2+2;
270 CopyUnicodeString(string+1,entry->Entries[i].Text);
271 string[len*2+1] = 0;
272 count += N71_65_PackPBKBlock(s, type, len * 2 + 2, block++, string, req + count);
273 continue;
274 }
275 if (entry->Entries[i].EntryType == PBK_Date) {
276 entry->Entries[i].AddError = ERR_NONE;
277
278 NOKIA_EncodeDateTime(s, string + 1, &(entry->Entries[i].Date));
279 count += N71_65_PackPBKBlock(s, S4030_PBK_BIRTHDAY, 6, block++, string, req + count);
280 continue;
281 }
282 }
283 if (entry->Entries[i].EntryType == PBK_Text_UserID) {
284 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKUSER)) {
285 entry->Entries[i].AddError = ERR_NONE;
286 string[0] = UnicodeLength(entry->Entries[i].Text)*2;
287 CopyUnicodeString(string+1,entry->Entries[i].Text);
288 count += N71_65_PackPBKBlock(s, N6510_PBK_USER_ID, string[0]+2, block++, string, req+count);
289 req[count-1]--;
290 }
291 continue;
292 }
293 if (entry->Entries[i].EntryType == PBK_PushToTalkID) {
294 entry->Entries[i].AddError = ERR_NONE;
295 string[0] = UnicodeLength(entry->Entries[i].Text)*2;
296 CopyUnicodeString(string+1,entry->Entries[i].Text);
297 count += N71_65_PackPBKBlock(s, N6510_PBK_PUSHTOTALK_ID, string[0]+2, block++, string, req+count);
298 req[count-1]--;
299 continue;
300 }
301 if (entry->Entries[i].EntryType == PBK_Number_Messaging) {
302 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_PBKFAVORITEMESSAGE)) {
303 entry->Entries[i].AddError = ERR_INVALIDDATA;
304 /* The favorite messaging number is stored as a phone number,
305 * the phone wants an id to a previously supplied entry, so we search for that.
306 * In case there was an error in the previous entries, we stop.
307 * Otherwise we would point past the supplied entries. */
308 for (j = 0; j < i && entry->Entries[j].AddError == ERR_NONE; j++) {
309 if (mywstrncmp(entry->Entries[i].Text, entry->Entries[j].Text, -1)) {
310 string[0] = j + 1;
311 string[1] = 0x00;
312 string[2] = 0x00;
313 count += N71_65_PackPBKBlock(s, N2630_PBK_FAVMESSAGING, 3, block++, string, req + count);
314 count --;
315 req[count-5] = 8;
316 entry->Entries[i].AddError = ERR_NONE;
317 break;
318 }
319
320 }
321 }
322 continue;
323 }
324 }
325
326 *block2=block;
327
328 return count;
329 }
330
331 /**
332 * Copy string to GSM_MemoryEntry
333 *
334 * Return false on failure
335 */
N71_65_PB_CopyString(GSM_StateMachine * s,GSM_MemoryEntry * entry,const unsigned char * src,unsigned char length)336 static gboolean N71_65_PB_CopyString(GSM_StateMachine *s,
337 GSM_MemoryEntry *entry,
338 const unsigned char *src,
339 unsigned char length)
340 {
341 if ((length & 1) != 0) {
342 smprintf(s, "String length not even\n");
343 return FALSE;
344 }
345 if (length/2 > GSM_PHONEBOOK_TEXT_LENGTH) {
346 smprintf(s, "Too long text\n");
347 return FALSE;
348 }
349 memcpy(entry->Entries[entry->EntriesNum].Text, src, length);
350 /* Zero terminate the string */
351 entry->Entries[entry->EntriesNum].Text[length] = 0;
352 entry->Entries[entry->EntriesNum].Text[length + 1] = 0;
353
354 smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
355
356 return TRUE;
357 }
358
359 /**
360 * Decodes nokia phonebook.
361 *
362 * \bug Type casting MemoryType to int is ugly.
363 */
N71_65_DecodePhonebook(GSM_StateMachine * s,GSM_MemoryEntry * entry,GSM_Bitmap * bitmap,GSM_SpeedDial * speed,unsigned char * MessageBuffer,int MessageLength,gboolean DayMonthReverse)364 GSM_Error N71_65_DecodePhonebook(GSM_StateMachine *s,
365 GSM_MemoryEntry *entry,
366 GSM_Bitmap *bitmap,
367 GSM_SpeedDial *speed,
368 unsigned char *MessageBuffer,
369 int MessageLength,
370 gboolean DayMonthReverse)
371 {
372 unsigned char *Block;
373 int length = 0, i, bs = 0;
374 GSM_EntryType Type;
375 GSM_EntryLocation Location = PBK_Location_Unknown;
376 gboolean found=FALSE;
377 gboolean foundbb5add=FALSE;
378 gboolean missed_call = FALSE;
379 int favorite_messaging_numbers[10];
380 size_t used_favorite_messaging_numbers = 0;
381
382 entry->EntriesNum = 0;
383
384 if ((int)entry->MemoryType==MEM7110_CG) {
385 bitmap->Text[0] = 0x00;
386 bitmap->Text[1] = 0x00;
387 bitmap->DefaultBitmap = TRUE;
388 bitmap->DefaultRingtone = TRUE;
389 bitmap->FileSystemPicture = FALSE;
390 }
391 if ((int)entry->MemoryType==MEM6510_CG2 && GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_6230iCALLER)) {
392 bitmap->DefaultName = FALSE;
393 bitmap->DefaultBitmap = TRUE;
394 bitmap->DefaultRingtone = TRUE;
395 bitmap->FileSystemPicture = FALSE;
396 }
397
398 Block = &MessageBuffer[0];
399 while (TRUE) {
400 entry->Entries[entry->EntriesNum].AddError = ERR_NONE;
401 entry->Entries[entry->EntriesNum].SMSList[0] = 0;
402 entry->Entries[entry->EntriesNum].VoiceTag = 0;
403 if (bs != 0) {
404 length = length + bs;
405 /* bb5 */
406 if (length >= MessageLength-1) break;
407 Block = &Block[bs];
408 }
409 bs = 256*Block[2]+Block[3];
410 if (bs == 0) break;
411 #ifdef DEBUG
412 smprintf(s, "Phonebook entry block 0x%02x - length %i\n",
413 Block[0], bs-6);
414 if (GSM_GetDI(s)->dl == DL_TEXTALL || GSM_GetDI(s)->dl == DL_TEXTALLDATE)
415 DumpMessage(&s->di, Block+0, bs-1);
416 #endif
417 if (entry->EntriesNum==GSM_PHONEBOOK_ENTRIES) {
418 smprintf(s, "Too many entries\n");
419 return ERR_UNKNOWNRESPONSE;
420 }
421
422 Type = 0;
423 if (Block[0] == S4030_PBK_FIRSTNAME) {
424 Type = PBK_Text_FirstName; smprintf(s,"First name ");
425 }
426 if (Block[0] == S4030_PBK_LASTNAME) {
427 Type = PBK_Text_LastName; smprintf(s,"Last name ");
428 }
429 if (Type != 0) {
430 found=TRUE;
431 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
432 return ERR_UNKNOWNRESPONSE;
433 entry->Entries[entry->EntriesNum].EntryType=Type;
434 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
435 entry->EntriesNum ++;
436 }
437 }
438
439 Block = &MessageBuffer[0];
440 bs=0;
441 length=0;
442 while (TRUE) {
443 entry->Entries[entry->EntriesNum].AddError = ERR_NONE;
444 entry->Entries[entry->EntriesNum].SMSList[0] = 0;
445 entry->Entries[entry->EntriesNum].VoiceTag = 0;
446 if (bs != 0) {
447 length = length + bs;
448 if (length >= MessageLength-1) break;
449 Block = &Block[bs];
450 }
451 bs = 256*Block[2]+Block[3];
452 smprintf(s, "Phonebook entry block 0x%02x - length %i\n",
453 Block[0], bs-6);
454 if (s->di.dl == DL_TEXTALL || s->di.dl == DL_TEXTALLDATE) {
455 DumpMessage(&s->di, Block+0, bs-1);
456 }
457 if (entry->EntriesNum >= GSM_PHONEBOOK_ENTRIES) {
458 smprintf(s, "Too many entries\n");
459 return ERR_MOREMEMORY;
460 }
461
462 Type = 0;
463 if (Block[0] == N7110_PBK_NAME) {
464 if (found) continue;
465 Type = PBK_Text_Name; smprintf(s,"Name ");
466 }
467 if (Block[0] == S4030_PBK_FIRSTNAME) continue;
468 if (Block[0] == S4030_PBK_LASTNAME) continue;
469 if (Block[0] == N7110_PBK_EMAIL) {
470 Type = PBK_Text_Email; smprintf(s,"Email ");
471 }
472 if (Block[0] == N7110_PBK_POSTAL) {
473 Type = PBK_Text_Postal; smprintf(s,"Postal ");
474 }
475 if (Block[0] == N7110_PBK_NOTE) {
476 Type = PBK_Text_Note; smprintf(s,"Text note ");
477 }
478 if (Block[0] == N6510_PBK_URL) {
479 Type = PBK_Text_URL; smprintf(s,"URL ");
480 }
481 if (Block[0] == N6510_PBK_USER_ID) {
482 Type = PBK_Text_UserID; smprintf(s,"User ID:");
483 }
484 if (Type != 0) {
485 if (Block[5]/2>GSM_PHONEBOOK_TEXT_LENGTH) {
486 smprintf(s, "Too long text\n");
487 return ERR_UNKNOWNRESPONSE;
488 }
489 /* No text? */
490 if (Block[5] < 2) {
491 entry->Entries[entry->EntriesNum].Text[0] = 0;
492 entry->Entries[entry->EntriesNum].Text[1] = 0;
493 } else {
494 memcpy(entry->Entries[entry->EntriesNum].Text,Block+6,Block[5]);
495 /* Zero terminate the string */
496 entry->Entries[entry->EntriesNum].Text[Block[5]] = 0;
497 entry->Entries[entry->EntriesNum].Text[Block[5] + 1] = 0;
498 }
499 entry->Entries[entry->EntriesNum].EntryType=Type;
500 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
501 smprintf(s, " \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
502 if (Block[0] == N7110_PBK_NAME) {
503 if ((int)entry->MemoryType == MEM7110_CG || (int)entry->MemoryType == MEM6510_CG2) {
504 /* No text? */
505 if (Block[5] < 2) {
506 bitmap->Text[0] = 0;
507 bitmap->Text[1] = 0;
508 } else {
509 memcpy(bitmap->Text,Block+6,Block[5]);
510 }
511 }
512 }
513 entry->EntriesNum ++;
514 continue;
515 }
516 if (Block[0] == N7110_PBK_DATETIME) {
517 entry->Entries[entry->EntriesNum].EntryType=PBK_Date;
518 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
519 NOKIA_DecodeDateTime(s, Block+6, &entry->Entries[entry->EntriesNum].Date, TRUE, DayMonthReverse);
520 if (CheckDate(&entry->Entries[entry->EntriesNum].Date) &&
521 CheckDate(&entry->Entries[entry->EntriesNum].Date)) {
522 entry->EntriesNum ++;
523 } else {
524 smprintf(s, "Datetime seems to be invalid, ignoring!\n");
525 }
526 continue;
527 }
528 if (Block[0] == N6510_PBK_PICTURE_ID) {
529 if ((int)entry->MemoryType==MEM6510_CG2) {
530 bitmap->FileSystemPicture = TRUE;
531 smprintf(s, "Picture ID \"%i\"\n",Block[10]*256+Block[11]);
532 bitmap->PictureID = Block[10]*256+Block[11];
533 } else {
534 entry->Entries[entry->EntriesNum].EntryType=PBK_PictureID;
535 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
536 smprintf(s, "Picture ID \"%i\"\n",Block[10]*256+Block[11]);
537 entry->Entries[entry->EntriesNum].Number=Block[10]*256+Block[11];
538 entry->EntriesNum ++;
539 }
540 continue;
541 }
542 if (Block[0] == N7110_PBK_NUMBER) {
543 if (Block[5] == 0x00) {
544 Type = PBK_Number_General; smprintf(s,"General number ");
545 }
546 /* Not assigned dialed number */
547 if (Block[5] == 0x01) {
548 Type = PBK_Number_General; smprintf(s,"General number ");
549 }
550 if (Block[5] == 0x0B) {
551 Type = PBK_Number_General; smprintf(s,"General number ");
552 }
553 /* In many firmwares 0x55 visible after using
554 * Save from Call Register menu and saving number
555 * to existing phonebook entry */
556 if (Block[5] == 0x55) {
557 Type = PBK_Number_General; smprintf(s,"General number ");
558 }
559 /* Yet another unknown General number */
560 if (Block[5] == 0x08) {
561 Type = PBK_Number_General; smprintf(s,"General number ");
562 }
563 if (Block[5] == N7110_PBK_NUMBER_GENERAL) {
564 Type = PBK_Number_General; smprintf(s,"General number ");
565 }
566 if (Block[5] == N7110_PBK_NUMBER_WORK) {
567 Type = PBK_Number_General; Location = PBK_Location_Work; smprintf(s,"Work number ");
568 }
569 if (Block[5] == N7110_PBK_NUMBER_FAX) {
570 Type = PBK_Number_Fax; smprintf(s,"Fax number ");
571 }
572 if (Block[5] == N7110_PBK_NUMBER_MOBILE) {
573 Type = PBK_Number_Mobile; smprintf(s,"Mobile number ");
574 }
575 if (Block[5] == N7110_PBK_NUMBER_HOME) {
576 Type = PBK_Number_General; Location = PBK_Location_Home; smprintf(s,"Home number ");
577 }
578 if (Type == 0x00) {
579 smprintf(s, "Unknown number type %02x\n",Block[5]);
580 return ERR_UNKNOWNRESPONSE;
581 }
582 entry->Entries[entry->EntriesNum].EntryType=Type;
583 entry->Entries[entry->EntriesNum].Location = Location;
584 if (! N71_65_PB_CopyString(s, entry, Block+10, Block[9]))
585 return ERR_UNKNOWNRESPONSE;
586 /* DCT3 phones like 6210 */
587 entry->Entries[entry->EntriesNum].VoiceTag = Block[7];
588 #ifdef DEBUG
589 if (entry->Entries[entry->EntriesNum].VoiceTag != 0) smprintf(s, "Voice tag %i assigned\n",Block[7]);
590 #endif
591 entry->Entries[entry->EntriesNum].SMSList[0] = 0;
592 entry->EntriesNum ++;
593 continue;
594 }
595 /* to checking */
596 if (Block[0] == S4030_PBK_CALLLENGTH) {
597 entry->Entries[entry->EntriesNum].CallLength = Block[9]*256*256+Block[10]*256+Block[11];
598 entry->Entries[entry->EntriesNum].EntryType=PBK_CallLength;
599 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
600 entry->EntriesNum ++;
601 continue;
602 }
603 if (Block[0] == S4030_PBK_POSTAL) {
604 if (Block[5] == S4030_PBK_POSTAL_EXTADDRESS) {
605 Type = PBK_Text_Custom1; smprintf(s,"Address extension ? ");
606 }
607 if (Block[5] == S4030_PBK_POSTAL_STREET) {
608 Type = PBK_Text_StreetAddress; smprintf(s,"Street ");
609 }
610 if (Block[5] == S4030_PBK_POSTAL_CITY) {
611 Type = PBK_Text_City; smprintf(s,"City ");
612 }
613 if (Block[5] == S4030_PBK_POSTAL_STATE) {
614 Type = PBK_Text_State; smprintf(s,"State ");
615 }
616 if (Block[5] == S4030_PBK_POSTAL_POSTAL) {
617 Type = PBK_Text_Postal; smprintf(s,"Postal ");
618 }
619 if (Block[5] == S4030_PBK_POSTAL_COUNTRY) {
620 Type = PBK_Text_Country; smprintf(s,"Country ");
621 }
622 if ((Type == 0x00) && (Block[7]>0)) {
623 smprintf(s, "Found new bb5 style address\n");
624 foundbb5add=TRUE;
625 continue;
626 }
627 if (Type == 0x00) {
628 smprintf(s, "Unknown address type %02x\n",Block[5]);
629 return ERR_UNKNOWNRESPONSE;
630 }
631 entry->Entries[entry->EntriesNum].EntryType=Type;
632 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
633 if (! N71_65_PB_CopyString(s, entry, Block+10, Block[9]))
634 return ERR_UNKNOWNRESPONSE;
635 entry->EntriesNum ++;
636 continue;
637 }
638
639
640 if ((Block[0] == S4030_PBK_POSTAL_EXTADDRESS) && (foundbb5add==TRUE)) {
641 Type = PBK_Text_Custom1; smprintf(s,"Address extension ? ");
642 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
643 return ERR_UNKNOWNRESPONSE;
644 entry->Entries[entry->EntriesNum].EntryType=Type;
645 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
646 entry->EntriesNum ++;
647 continue;
648 }
649 if ((Block[0] == S4030_PBK_POSTAL_STREET) && (foundbb5add==TRUE)) {
650 Type = PBK_Text_StreetAddress; smprintf(s,"Street ");
651 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
652 return ERR_UNKNOWNRESPONSE;
653 entry->Entries[entry->EntriesNum].EntryType=Type;
654 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
655 entry->EntriesNum ++;
656 continue;
657 }
658 if ((Block[0] == S4030_PBK_POSTAL_CITY) && (foundbb5add==TRUE)) {
659 Type = PBK_Text_City; smprintf(s,"City ");
660 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
661 return ERR_UNKNOWNRESPONSE;
662 entry->Entries[entry->EntriesNum].EntryType=Type;
663 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
664 entry->EntriesNum ++;
665 continue;
666 }
667 if ((Block[0] == S4030_PBK_POSTAL_STATE) && (foundbb5add==TRUE)) {
668 Type = PBK_Text_State; smprintf(s,"State ");
669 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
670 return ERR_UNKNOWNRESPONSE;
671 entry->Entries[entry->EntriesNum].EntryType=Type;
672 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
673 entry->EntriesNum ++;
674 continue;
675 }
676 if ((Block[0] == S4030_PBK_POSTAL_POSTAL) && (foundbb5add==TRUE)) {
677 Type = PBK_Text_Postal; smprintf(s,"Postal ");
678 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
679 return ERR_UNKNOWNRESPONSE;
680 entry->Entries[entry->EntriesNum].EntryType=Type;
681 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
682 entry->EntriesNum ++;
683 continue;
684 }
685 if ((Block[0] == S4030_PBK_POSTAL_COUNTRY) && (foundbb5add==TRUE)) {
686 Type = PBK_Text_Country; smprintf(s,"Country ");
687 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
688 return ERR_UNKNOWNRESPONSE;
689 entry->Entries[entry->EntriesNum].EntryType=Type;
690 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
691 entry->EntriesNum ++;
692 continue;
693 }
694 if (Block[0] == S4030_PBK_FORMALNAME) {
695 Type = PBK_Text_FormalName; smprintf(s,"FormalName ");
696 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
697 return ERR_UNKNOWNRESPONSE;
698 entry->Entries[entry->EntriesNum].EntryType=Type;
699 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
700 entry->EntriesNum ++;
701 continue;
702 }
703 if (Block[0] == S4030_PBK_JOBTITLE) {
704 Type = PBK_Text_JobTitle; smprintf(s,"JobTitle ");
705 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
706 return ERR_UNKNOWNRESPONSE;
707 entry->Entries[entry->EntriesNum].EntryType=Type;
708 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
709 entry->EntriesNum ++;
710 continue;
711 }
712 if (Block[0] == S4030_PBK_COMPANY) {
713 Type = PBK_Text_Company; smprintf(s,"Company ");
714 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
715 return ERR_UNKNOWNRESPONSE;
716 entry->Entries[entry->EntriesNum].EntryType=Type;
717 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
718 entry->EntriesNum ++;
719 continue;
720 }
721 if (Block[0] == S4030_PBK_NICKNAME) {
722 Type = PBK_Text_NickName; smprintf(s,"NickName ");
723 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
724 return ERR_UNKNOWNRESPONSE;
725 entry->Entries[entry->EntriesNum].EntryType=Type;
726 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
727 entry->EntriesNum ++;
728 continue;
729 }
730 if (Block[0] == S4030_PBK_BIRTHDAY) {
731 entry->Entries[entry->EntriesNum].EntryType=PBK_Date;
732 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
733 NOKIA_DecodeDateTime(s, Block+6, &entry->Entries[entry->EntriesNum].Date, FALSE, DayMonthReverse);
734 entry->EntriesNum ++;
735 continue;
736 }
737
738
739 if (Block[0] == N7110_PBK_RINGTONE_ID) {
740 if ((int)entry->MemoryType==MEM7110_CG) {
741 bitmap->RingtoneID=Block[5];
742 if (Block[5] == 0x00) bitmap->RingtoneID=Block[7];
743 smprintf(s, "Ringtone ID : %i\n",bitmap->RingtoneID);
744 bitmap->DefaultRingtone = FALSE;
745 bitmap->FileSystemRingtone = FALSE;
746 } else {
747 entry->Entries[entry->EntriesNum].EntryType=PBK_RingtoneID;
748 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
749 smprintf(s, "Ringtone ID \"%i\"\n",Block[7]);
750 entry->Entries[entry->EntriesNum].Number=Block[7];
751 entry->EntriesNum ++;
752 }
753 continue;
754 }
755 if (Block[0] == N7110_PBK_LOGOON) {
756 if ((int)entry->MemoryType==MEM7110_CG) {
757 bitmap->BitmapEnabled=(Block[5]==0x00 ? FALSE : TRUE);
758 smprintf(s, "Logo : %s\n", bitmap->BitmapEnabled==TRUE ? "enabled":"disabled");
759 } else {
760 return ERR_UNKNOWNRESPONSE;
761 }
762 continue;
763 }
764 if (Block[0] == N7110_PBK_GROUPLOGO) {
765 if ((int)entry->MemoryType==MEM7110_CG) {
766 smprintf(s, "Caller logo\n");
767 PHONE_DecodeBitmap(GSM_NokiaCallerLogo, Block+10, bitmap);
768 bitmap->DefaultBitmap = FALSE;
769 } else {
770 return ERR_UNKNOWNRESPONSE;
771 }
772 continue;
773 }
774 if (Block[0] == N7110_PBK_GROUP) {
775 entry->Entries[entry->EntriesNum].EntryType=PBK_Caller_Group;
776 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
777 smprintf(s, "Caller group \"%i\"\n",Block[5]);
778 entry->Entries[entry->EntriesNum].Number=Block[5];
779 if (Block[5]!=0) entry->EntriesNum ++;
780 continue;
781 }
782 if (Block[0] == N6510_PBK_VOICETAG_ID) {
783 smprintf(s, "Entry %i has voice tag %i\n",Block[5]-1,Block[7]);
784 entry->Entries[entry->EntriesNum].VoiceTag = Block[7];
785 continue;
786 }
787
788 /* 6210 5.56, SIM speed dials or ME with 1 number */
789 if (Block[0] == N7110_PBK_SIM_SPEEDDIAL) {
790 if ((int)entry->MemoryType==MEM7110_SP) {
791 #ifdef DEBUG
792 smprintf(s, "location %i\n",(Block[6]*256+Block[7]));
793 #endif
794 speed->MemoryType = MEM_ME;
795 if (Block[8] == 0x06) speed->MemoryType = MEM_SM;
796 speed->MemoryLocation = (Block[6]*256+Block[7]);
797 speed->MemoryNumberID = 2;
798 } else {
799 return ERR_UNKNOWNRESPONSE;
800 }
801 continue;
802 }
803
804 if (Block[0] == N7110_PBK_SPEEDDIAL) {
805 if ((int)entry->MemoryType==MEM7110_SP) {
806 #ifdef DEBUG
807 switch (Block[12]) {
808 case 0x05: smprintf(s, "ME\n"); break;
809 case 0x06: smprintf(s, "SM\n"); break;
810 default : smprintf(s, "%02x\n",Block[12]);
811 }
812 smprintf(s, "location %i, number %i in location\n",
813 (Block[6]*256+Block[7])-1,Block[14]);
814 #endif
815 switch (Block[12]) {
816 case 0x05: speed->MemoryType = MEM_ME; break;
817 case 0x06: speed->MemoryType = MEM_SM; break;
818 }
819 speed->MemoryLocation = (Block[6]*256+Block[7])-1;
820 speed->MemoryNumberID = Block[14];
821 } else {
822 return ERR_UNKNOWNRESPONSE;
823 }
824 continue;
825 }
826 if (Block[0] == N6510_PBK_RINGTONEFILE_ID) {
827 smprintf(s, "Ringtone ID with possibility of using filesystem\n");
828 if ((int)entry->MemoryType==MEM7110_CG) {
829 if (Block[9] == 0x01) {
830 smprintf(s, "Filesystem ringtone ID: %02x\n",Block[10]*256+Block[11]);
831 bitmap->FileSystemRingtone = TRUE;
832 } else {
833 smprintf(s, "Internal ringtone ID: %02x\n",Block[10]*256+Block[11]);
834 bitmap->FileSystemRingtone = FALSE;
835 }
836 bitmap->RingtoneID = Block[10]*256+Block[11];
837 bitmap->DefaultRingtone = FALSE;
838 } else if ((int)entry->MemoryType==MEM6510_CG2) {
839 /* FIXME */
840 smprintf(s, "Internal ringtone ID: %02x\n",Block[10]*256+Block[11]);
841 bitmap->FileSystemRingtone = FALSE;
842 bitmap->RingtoneID = Block[10]*256+Block[11];
843 bitmap->DefaultRingtone = FALSE;
844 } else {
845 /* series 40 3.0 */
846 smprintf(s, "Filesystem ringtone ID: %02x\n",Block[10]*256+Block[11]);
847 entry->Entries[entry->EntriesNum].EntryType=PBK_RingtoneID;
848 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
849 entry->Entries[entry->EntriesNum].Number=Block[10]*256+Block[11];
850 entry->EntriesNum ++;
851 }
852 continue;
853 }
854 if (Block[0] == N6510_PBK_SMSLIST_ID) {
855 smprintf(s, "Entry %i is assigned to SMS list %i\n",Block[5]-1,Block[9]);
856 i = 0;
857 while(entry->Entries[Block[5]-1].SMSList[i] != 0) i++;
858 entry->Entries[Block[5]-1].SMSList[i+1] = 0;
859 entry->Entries[Block[5]-1].SMSList[i] = Block[9];
860 continue;
861 }
862 if (Block[0] == N7110_PBK_MISSED) {
863 missed_call = TRUE;
864 smprintf(s,"Unknown entry type 0x%02x data length %d\n", Block[0], bs-6);
865 continue;
866 }
867 if (Block[0] == N7110_PBK_UNKNOWN2
868 || Block[0] == N7110_PBK_UNKNOWN3
869 || Block[0] == N3600_PBK_UNKNOWN1
870 || Block[0] == N6303_PBK_UNKNOWN1
871 || Block[0] == N6303_PBK_UNKNOWN2) {
872 smprintf(s,"Unknown entry type 0x%02x data length %d\n", Block[0], bs-6);
873 continue;
874 }
875 if (Block[0] == N6510_PBK_UNKNOWN2) {
876 smprintf(s,"Unknown entry - probably ID for conversation list\n");
877 continue;
878 }
879 if (Block[0] == N6510_PBK_UNKNOWN3) {
880 smprintf(s,"Unknown entry - probably ID for Instant Messaging service list\n");
881 continue;
882 }
883 if (Block[0] == N6510_PBK_UNKNOWN4) {
884 smprintf(s,"Unknown entry - probably ID for presence list\n");
885 continue;
886 }
887 if (Block[0] == N6510_PBK_PUSHTOTALK_ID) {
888 smprintf(s,"SIP Address (Push to Talk address)\n");
889 if (! N71_65_PB_CopyString(s, entry, Block+6, Block[5]))
890 return ERR_UNKNOWNRESPONSE;
891 entry->Entries[entry->EntriesNum].EntryType=PBK_PushToTalkID;
892 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
893 entry->EntriesNum ++;
894 continue;
895 }
896 if (Block[0] == N6510_PBK_UNKNOWN5) {
897 smprintf(s,"Unknown entry\n");
898 continue;
899 }
900 if (Block[0] == N6510_PBK_GROUP2_ID) {
901 smprintf(s,"Group ID (6230i or later)\n");
902
903 entry->Entries[entry->EntriesNum].EntryType=PBK_Caller_Group;
904 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
905 smprintf(s, "Caller group \"%i\"\n",Block[7]);
906 entry->Entries[entry->EntriesNum].Number=Block[7];
907 entry->EntriesNum ++;
908 continue;
909 }
910 if (Block[0] == N2630_PBK_FAVMESSAGING) {
911 if (used_favorite_messaging_numbers >= sizeof(favorite_messaging_numbers) / sizeof(int)) {
912 smprintf(s, "Too many favorite messaging numbers!\n");
913 return ERR_MOREMEMORY;
914 }
915 favorite_messaging_numbers[used_favorite_messaging_numbers] = (int)Block[5];
916 used_favorite_messaging_numbers++;
917
918 continue;
919 }
920 smprintf(s, "ERROR: unknown pbk entry 0x%02x\n",Block[0]);
921 return ERR_UNKNOWNRESPONSE;
922 }
923
924 if (entry->EntriesNum == 0) {
925 if (missed_call) {
926 smprintf(s, "Empty entry with missed call reference, adding blank number!\n");
927 entry->Entries[entry->EntriesNum].EntryType = PBK_Number_General;
928 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
929 EncodeUnicode(entry->Entries[entry->EntriesNum].Text, "", 0);
930 } else {
931 return ERR_EMPTY;
932 }
933 }
934
935 /* Process favorite messaging numbers */
936 for (i = 0; i < (int)used_favorite_messaging_numbers; i++) {
937 if (entry->EntriesNum >= GSM_PHONEBOOK_ENTRIES) {
938 smprintf(s, "Too many entries\n");
939 return ERR_MOREMEMORY;
940 }
941
942 /* The phone sends an entry id. We store it as phone number because
943 * entry->Entries doesn't retain order. */
944
945 entry->Entries[entry->EntriesNum].EntryType = PBK_Number_Messaging;
946 entry->Entries[entry->EntriesNum].Location = PBK_Location_Unknown;
947 CopyUnicodeString(entry->Entries[entry->EntriesNum].Text,entry->Entries[favorite_messaging_numbers[i] - 1].Text);
948 smprintf(s,"Marked entry #%i (%s) as favorite messaging number\n",
949 favorite_messaging_numbers[i],
950 DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
951 entry->EntriesNum ++;
952 }
953 return ERR_NONE;
954 }
955
NOKIA_GetDefaultCallerGroupName(GSM_Bitmap * Bitmap)956 void NOKIA_GetDefaultCallerGroupName(GSM_Bitmap *Bitmap)
957 {
958 Bitmap->DefaultName = FALSE;
959 if (Bitmap->Text[0]==0x00 && Bitmap->Text[1]==0x00) {
960 Bitmap->DefaultName = TRUE;
961 switch(Bitmap->Location) {
962 case 1: EncodeUnicode(Bitmap->Text,_("Family"),strlen(_("Family")));
963 break;
964 case 2: EncodeUnicode(Bitmap->Text,_("VIP"),strlen(_("VIP")));
965 break;
966 case 3: EncodeUnicode(Bitmap->Text,_("Friends"),strlen(_("Friends")));
967 break;
968 case 4: EncodeUnicode(Bitmap->Text,_("Colleagues"),strlen(_("Colleagues")));
969 break;
970 case 5: EncodeUnicode(Bitmap->Text,_("Other"),strlen(_("Other")));
971 break;
972 }
973 }
974 }
975
NOKIA_DecodeDateTime(GSM_StateMachine * s,unsigned char * buffer,GSM_DateTime * datetime,gboolean seconds,gboolean DayMonthReverse)976 void NOKIA_DecodeDateTime(GSM_StateMachine *s, unsigned char* buffer, GSM_DateTime *datetime, gboolean seconds, gboolean DayMonthReverse)
977 {
978 datetime->Year = buffer[0] * 256 + buffer[1];
979 /* Sometimes reversed */
980 if (datetime->Year > 3000) {
981 datetime->Year = buffer[1] * 256 + buffer[0];
982 }
983 if (DayMonthReverse) {
984 datetime->Month = buffer[3];
985 datetime->Day = buffer[2];
986 } else {
987 datetime->Month = buffer[2];
988 datetime->Day = buffer[3];
989 }
990
991 datetime->Hour = buffer[4];
992 datetime->Minute = buffer[5];
993 if (seconds) {
994 datetime->Second = buffer[6];
995 } else {
996 datetime->Second = 0;
997 }
998 datetime->Timezone = 0;
999
1000 smprintf(s, "Decoding date and time\n");
1001 smprintf(s, " Time: %02d:%02d:%02d\n",
1002 datetime->Hour, datetime->Minute, datetime->Second);
1003 smprintf(s, " Date: %4d/%02d/%02d\n",
1004 datetime->Year, datetime->Month, datetime->Day);
1005 }
1006
NOKIA_EncodeDateTime(GSM_StateMachine * s UNUSED,unsigned char * buffer,GSM_DateTime * datetime)1007 void NOKIA_EncodeDateTime(GSM_StateMachine *s UNUSED, unsigned char* buffer, GSM_DateTime *datetime)
1008 {
1009 buffer[0] = datetime->Year / 256;
1010 buffer[1] = datetime->Year % 256;
1011 buffer[2] = datetime->Month;
1012 buffer[3] = datetime->Day;
1013
1014 buffer[4] = datetime->Hour;
1015 buffer[5] = datetime->Minute;
1016 }
1017
1018
1019 #if defined(GSM_ENABLE_NOKIA_DCT3) || defined(GSM_ENABLE_NOKIA_DCT4)
1020
1021 /* --------------------- Some general Nokia functions ---------------------- */
1022
NOKIA_DecodeSMSState(GSM_StateMachine * s,unsigned char state,GSM_SMSMessage * sms)1023 void NOKIA_DecodeSMSState(GSM_StateMachine *s, unsigned char state, GSM_SMSMessage *sms)
1024 {
1025 switch (state) {
1026 case 0x01 : sms->State = SMS_Read; break;
1027 case 0x03 : sms->State = SMS_UnRead; break;
1028 case 0x05 : sms->State = SMS_Sent; break;
1029 case 0x07 : sms->State = SMS_UnSent; break;
1030 default :
1031 sms->State = SMS_Read;
1032 smprintf(s, "Unknown SMS state: %02x\n",state);
1033 break;
1034 }
1035 }
1036
NOKIA_ReplyGetPhoneString(GSM_Protocol_Message * msg,GSM_StateMachine * s)1037 GSM_Error NOKIA_ReplyGetPhoneString(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1038 {
1039 strcpy(s->Phone.Data.PhoneString, msg->Buffer+s->Phone.Data.StartPhoneString);
1040 return ERR_NONE;
1041 }
1042
1043 /* Some strings are very easy. Some header, after it required string and 0x00.
1044 * We can get them using this function. We give frame to send (*string),
1045 * type of message (type), pointer for buffer for response (*value), request
1046 * type (request) and what is start byte in response for our string
1047 */
NOKIA_GetPhoneString(GSM_StateMachine * s,const unsigned char * msgframe,int msglen,unsigned char msgtype,char * retvalue,GSM_Phone_RequestID request,int startresponse)1048 GSM_Error NOKIA_GetPhoneString(GSM_StateMachine *s, const unsigned char *msgframe, int msglen, unsigned char msgtype, char *retvalue, GSM_Phone_RequestID request, int startresponse)
1049 {
1050 retvalue[0] = 0;
1051 s->Phone.Data.StartPhoneString = startresponse;
1052 s->Phone.Data.PhoneString = retvalue;
1053 return GSM_WaitFor (s, msgframe, msglen,msgtype, 4, request);
1054 }
1055
NOKIA_GetManufacturer(GSM_StateMachine * s)1056 GSM_Error NOKIA_GetManufacturer(GSM_StateMachine *s)
1057 {
1058 strcpy(s->Phone.Data.Manufacturer,"Nokia");
1059 return ERR_NONE;
1060 }
1061
1062 /* Many functions contains such strings:
1063 * (1. length/256) - exist or not
1064 * 2. length%256
1065 * 3. string (unicode, no termination)
1066 * This function read string to output and increases counter
1067 */
NOKIA_GetUnicodeString(GSM_StateMachine * s UNUSED,int * current,unsigned char * input,unsigned char * output,gboolean FullLength)1068 void NOKIA_GetUnicodeString(GSM_StateMachine *s UNUSED, int *current, unsigned char *input, unsigned char *output, gboolean FullLength)
1069 {
1070 int length;
1071
1072 if (FullLength) {
1073 length = (input[*current]*256+input[*current+1])*2;
1074 memcpy(output,input+(*current+2),length);
1075 *current = *current + 2 + length;
1076 } else {
1077 length = (input[*current])*2;
1078 memcpy(output,input+(*current+1),length);
1079 *current = *current + 1 + length;
1080 }
1081
1082 output[length ] = 0;
1083 output[length+1] = 0;
1084 }
1085
NOKIA_SetUnicodeString(GSM_StateMachine * s UNUSED,unsigned char * dest,unsigned char * string,gboolean FullLength)1086 int NOKIA_SetUnicodeString(GSM_StateMachine *s UNUSED, unsigned char *dest, unsigned char *string, gboolean FullLength)
1087 {
1088 int length;
1089
1090 length = UnicodeLength(string);
1091 if (FullLength) {
1092 dest[0] = length / 256;
1093 dest[1] = length % 256;
1094 CopyUnicodeString(dest + 2, string);
1095 return 2+length*2;
1096 } else {
1097 dest[0] = length % 256;
1098 CopyUnicodeString(dest + 1, string);
1099 return 1+length*2;
1100 }
1101 }
1102
1103 /* Returns correct ID for concrete memory type */
NOKIA_GetMemoryType(GSM_StateMachine * s UNUSED,GSM_MemoryType memory_type,unsigned char * ID)1104 GSM_MemoryType NOKIA_GetMemoryType(GSM_StateMachine *s UNUSED, GSM_MemoryType memory_type, unsigned char *ID)
1105 {
1106 int i=0;
1107
1108 while (ID[i+1]!=0x00) {
1109 if (ID[i]==memory_type) return ID[i+1];
1110 i=i+2;
1111 }
1112 return 0xff;
1113 }
1114
NOKIA_SortSMSFolderStatus(GSM_StateMachine * s,GSM_NOKIASMSFolder * Folder)1115 void NOKIA_SortSMSFolderStatus(GSM_StateMachine *s, GSM_NOKIASMSFolder *Folder)
1116 {
1117 int i,j;
1118
1119 if (Folder->Number!=0) {
1120 /* Bouble sorting */
1121 i=0;
1122 while (i!=Folder->Number-1) {
1123 if (Folder->Location[i]>Folder->Location[i+1]) {
1124 j=Folder->Location[i];
1125 Folder->Location[i]=Folder->Location[i+1];
1126 Folder->Location[i+1]=j;
1127 i=0;
1128 } else {
1129 i++;
1130 }
1131 }
1132 #ifdef DEBUG
1133 smprintf(s, "Locations: ");
1134 for (i=0;i<Folder->Number;i++) {
1135 smprintf(s, "%i ",Folder->Location[i]);
1136 }
1137 smprintf(s, "\n");
1138 #endif
1139 }
1140 }
1141
NOKIA_GetDefaultProfileName(GSM_Profile * Profile)1142 void NOKIA_GetDefaultProfileName(GSM_Profile *Profile)
1143 {
1144 if (Profile->DefaultName) {
1145 switch(Profile->Location) {
1146 case 1: EncodeUnicode(Profile->Name,_("General"),strlen(_("General")));
1147 break;
1148 case 2: EncodeUnicode(Profile->Name,_("Silent"),strlen(_("Silent")));
1149 break;
1150 case 3: EncodeUnicode(Profile->Name,_("Meeting"),strlen(_("Meeting")));
1151 break;
1152 case 4: EncodeUnicode(Profile->Name,_("Outdoor"),strlen(_("Outdoor")));
1153 break;
1154 case 5: EncodeUnicode(Profile->Name,_("Pager"),strlen(_("Pager")));
1155 break;
1156 case 6: EncodeUnicode(Profile->Name,_("Car"),strlen(_("Car")));
1157 break;
1158 case 7: EncodeUnicode(Profile->Name,_("Headset"),strlen(_("Headset")));
1159 break;
1160 }
1161 }
1162 }
1163
1164 /* - Shared for DCT3 (n6110.c, n7110.c, n9110.c) and DCT4 (n6510.c) phones - */
1165
DCT3DCT4_ReplyCallDivert(GSM_Protocol_Message * msg,GSM_StateMachine * s)1166 GSM_Error DCT3DCT4_ReplyCallDivert(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1167 {
1168 GSM_MultiCallDivert *cd = s->Phone.Data.Divert;
1169 int i,pos = 11,j;
1170 size_t number_pos;
1171 GSM_Error error;
1172
1173 switch (msg->Buffer[3]) {
1174 case 0x02:
1175 smprintf(s,"Message: Call divert status received\n");
1176 smprintf(s," Divert type: ");
1177 switch (msg->Buffer[6]) {
1178 case 0x43: smprintf(s,"when busy"); break;
1179 case 0x3d: smprintf(s,"when not answered"); break;
1180 case 0x3e: smprintf(s,"when phone off or no coverage"); break;
1181 case 0x15: smprintf(s,"all types of diverts"); break;
1182 default: smprintf(s,"unknown %i",msg->Buffer[6]); break;
1183 }
1184 if (cd == NULL) {
1185 return ERR_NONE;
1186 }
1187 /* 6150 */
1188 if (msg->Length == 0x0b) {
1189 cd->EntriesNum = 0;
1190 return ERR_NONE;
1191 }
1192 cd->EntriesNum = msg->Buffer[10];
1193 for (i=0;i<cd->EntriesNum;i++) {
1194 smprintf(s,"\n Calls type : ");
1195 switch (msg->Buffer[pos]) {
1196 case 0x0b:
1197 smprintf(s,"voice");
1198 cd->Entries[i].CallType = GSM_DIVERT_VoiceCalls;
1199 break;
1200 case 0x0d:
1201 smprintf(s,"fax");
1202 cd->Entries[i].CallType = GSM_DIVERT_FaxCalls;
1203 break;
1204 case 0x19:
1205 smprintf(s,"data");
1206 cd->Entries[i].CallType = GSM_DIVERT_DataCalls;
1207 break;
1208 default:
1209 smprintf(s,"unknown %i",msg->Buffer[pos]);
1210 /* 6310i */
1211 cd->EntriesNum = 0;
1212 return ERR_NONE;
1213 }
1214 smprintf(s,"\n");
1215 j = pos + 2;
1216 while (msg->Buffer[j] != 0x00) j++;
1217 msg->Buffer[pos+1] = j - pos - 2;
1218 number_pos = pos + 1;
1219 error = GSM_UnpackSemiOctetNumber(&(s->di), cd->Entries[i].Number, msg->Buffer, &number_pos, msg->Length, FALSE);
1220 if (error != ERR_NONE) {
1221 return error;
1222 }
1223 smprintf(s," Number : %s\n",DecodeUnicodeString(cd->Entries[i].Number));
1224 cd->Entries[i].Timeout = msg->Buffer[pos+34];
1225 smprintf(s," Timeout : %i seconds\n",msg->Buffer[pos+34]);
1226 pos+=35;
1227 }
1228 return ERR_NONE;
1229 case 0x03:
1230 smprintf(s,"Message: Call divert status receiving error ?\n");
1231 return ERR_UNKNOWN;
1232 }
1233 return ERR_UNKNOWNRESPONSE;
1234 }
1235
DCT3DCT4_CallDivert(GSM_StateMachine * s,GSM_CallDivert * request,GSM_MultiCallDivert * response,gboolean get)1236 static GSM_Error DCT3DCT4_CallDivert(GSM_StateMachine *s, GSM_CallDivert *request, GSM_MultiCallDivert *response, gboolean get)
1237 {
1238 int length = 0x09;
1239 unsigned char req[55] = {N6110_FRAME_HEADER, 0x01,
1240 0x05, /* operation = Query */
1241 0x00,
1242 0x00, /* divert type */
1243 0x00, /* call type */
1244 0x00};
1245
1246 if (!get) {
1247 if (UnicodeLength(request->Number) == 0) {
1248 req[4] = 0x04;
1249 } else {
1250 req[4] = 0x03;
1251 req[8] = 0x01;
1252 req[29] = GSM_PackSemiOctetNumber(request->Number, req + 9, FALSE);
1253 req[52] = request->Timeout;
1254 length = 55;
1255 }
1256 }
1257 switch (request->DivertType) {
1258 case GSM_DIVERT_AllTypes : req[6] = 0x15; break;
1259 case GSM_DIVERT_Busy : req[6] = 0x43; break;
1260 case GSM_DIVERT_NoAnswer : req[6] = 0x3d; break;
1261 case GSM_DIVERT_OutOfReach: req[6] = 0x3e; break;
1262 default : return ERR_NOTIMPLEMENTED;
1263 }
1264
1265 switch (request->CallType) {
1266 case GSM_DIVERT_AllCalls : break;
1267 case GSM_DIVERT_VoiceCalls: req[7] = 0x0b; break;
1268 case GSM_DIVERT_FaxCalls : req[7] = 0x0d; break;
1269 case GSM_DIVERT_DataCalls : req[7] = 0x19; break;
1270 default : return ERR_NOTIMPLEMENTED;
1271 }
1272
1273 s->Phone.Data.Divert = response;
1274 smprintf(s, "Call divert\n");
1275 return GSM_WaitFor (s, req, length, 0x06, 10, ID_Divert);
1276 }
1277
DCT3DCT4_GetCallDivert(GSM_StateMachine * s,GSM_CallDivert * request,GSM_MultiCallDivert * response)1278 GSM_Error DCT3DCT4_GetCallDivert(GSM_StateMachine *s, GSM_CallDivert *request, GSM_MultiCallDivert *response)
1279 {
1280 return DCT3DCT4_CallDivert(s, request, response, TRUE);
1281 }
1282
DCT3DCT4_SetCallDivert(GSM_StateMachine * s,GSM_CallDivert * divert)1283 GSM_Error DCT3DCT4_SetCallDivert(GSM_StateMachine *s, GSM_CallDivert *divert)
1284 {
1285 return DCT3DCT4_CallDivert(s, divert, NULL, FALSE);
1286 }
1287
DCT3DCT4_CancelAllDiverts(GSM_StateMachine * s)1288 GSM_Error DCT3DCT4_CancelAllDiverts(GSM_StateMachine *s)
1289 {
1290 GSM_MultiCallDivert divert;
1291 unsigned char req[55] = {N6110_FRAME_HEADER, 0x01,
1292 0x04, /* operation = Disable */
1293 0x00,
1294 0x02, /* divert type */
1295 0x00, /* call type */
1296 0x00};
1297
1298 s->Phone.Data.Divert = &divert;
1299 smprintf(s, "Call divert\n");
1300 return GSM_WaitFor (s, req, 0x09, 0x06, 10, ID_Divert);
1301 }
1302
DCT3DCT4_ReplyGetActiveConnectSet(GSM_Protocol_Message * msg,GSM_StateMachine * s)1303 GSM_Error DCT3DCT4_ReplyGetActiveConnectSet(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1304 {
1305 GSM_Phone_Data *Data = &s->Phone.Data;
1306
1307 Data->WAPSettings->Active = FALSE;
1308 if (Data->WAPSettings->Location - 1 == msg->Buffer[4]) {
1309 Data->WAPSettings->Active = TRUE;
1310 }
1311 return ERR_NONE;
1312 }
1313
DCT3DCT4_GetActiveConnectSet(GSM_StateMachine * s)1314 GSM_Error DCT3DCT4_GetActiveConnectSet(GSM_StateMachine *s)
1315 {
1316 unsigned char GetSetreq[] = {N6110_FRAME_HEADER, 0x0F};
1317
1318 smprintf(s, "Checking, if connection settings are active\n");
1319 return GSM_WaitFor (s, GetSetreq, 4, 0x3f, 4, ID_GetConnectSet);
1320 }
1321
DCT3DCT4_ReplySetActiveConnectSet(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1322 GSM_Error DCT3DCT4_ReplySetActiveConnectSet(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1323 {
1324 smprintf(s, "Connection settings activated\n");
1325 return ERR_NONE;
1326 }
1327
DCT3DCT4_SetActiveConnectSet(GSM_StateMachine * s,GSM_MultiWAPSettings * settings)1328 GSM_Error DCT3DCT4_SetActiveConnectSet(GSM_StateMachine *s, GSM_MultiWAPSettings *settings)
1329 {
1330 unsigned char reqActivate[] = {N6110_FRAME_HEADER, 0x12,
1331 0x00}; /* Location */
1332
1333 if (settings->Active) {
1334 reqActivate[4] = settings->Location-1;
1335 smprintf(s, "Activating connection settings number %i\n",settings->Location);
1336 return GSM_WaitFor (s, reqActivate, 5, 0x3f, 4, ID_SetConnectSet);
1337 }
1338 return ERR_NONE;
1339 }
1340
1341
DCT3DCT4_SendDTMF(GSM_StateMachine * s,char * DTMFSequence)1342 GSM_Error DCT3DCT4_SendDTMF(GSM_StateMachine *s, char *DTMFSequence)
1343 {
1344 unsigned char req[100] = {N6110_FRAME_HEADER, 0x50,
1345 0x00}; /* Length */
1346
1347 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NODTMF)) return ERR_NOTSUPPORTED;
1348 if (strlen(DTMFSequence) > 100 - 5) return ERR_NOTSUPPORTED;
1349
1350 req[4] = strlen(DTMFSequence);
1351
1352 memcpy(req+5,DTMFSequence,strlen(DTMFSequence));
1353
1354 smprintf(s, "Sending DTMF\n");
1355 return GSM_WaitFor (s, req, 5+strlen(DTMFSequence), 0x01, 4, ID_SendDTMF);
1356 }
1357
DCT3DCT4_ReplyGetWAPBookmark(GSM_Protocol_Message * msg,GSM_StateMachine * s,gboolean FullLength)1358 GSM_Error DCT3DCT4_ReplyGetWAPBookmark(GSM_Protocol_Message *msg, GSM_StateMachine *s, gboolean FullLength)
1359 {
1360 int tmp;
1361 GSM_Phone_Data *Data = &s->Phone.Data;
1362
1363 smprintf(s, "WAP bookmark received\n");
1364 switch (msg->Buffer[3]) {
1365 case 0x07:
1366 tmp = 4;
1367
1368 Data->WAPBookmark->Location = msg->Buffer[tmp] * 256 + msg->Buffer[tmp+1];
1369 smprintf(s, "Location: %i\n",Data->WAPBookmark->Location);
1370 tmp = tmp + 2;
1371
1372 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer, Data->WAPBookmark->Title, FullLength);
1373 smprintf(s, "Title : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Title));
1374
1375 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer, Data->WAPBookmark->Address, FullLength);
1376 smprintf(s, "Address : \"%s\"\n",DecodeUnicodeString(Data->WAPBookmark->Address));
1377
1378 return ERR_NONE;
1379 case 0x08:
1380 switch (msg->Buffer[4]) {
1381 case 0x01:
1382 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
1383 return ERR_INSIDEPHONEMENU;
1384 case 0x02:
1385 smprintf(s, "Invalid or empty\n");
1386 return ERR_INVALIDLOCATION;
1387 default:
1388 smprintf(s, "ERROR: unknown %i\n",msg->Buffer[4]);
1389 return ERR_UNKNOWNRESPONSE;
1390 }
1391 }
1392 return ERR_UNKNOWNRESPONSE;
1393 }
1394
DCT3DCT4_ReplySetWAPBookmark(GSM_Protocol_Message * msg,GSM_StateMachine * s)1395 GSM_Error DCT3DCT4_ReplySetWAPBookmark(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1396 {
1397 switch (msg->Buffer[3]) {
1398 case 0x0A:
1399 smprintf(s, "WAP bookmark set OK\n");
1400 return ERR_NONE;
1401 case 0x0B:
1402 smprintf(s, "WAP bookmark setting error\n");
1403 switch (msg->Buffer[4]) {
1404 case 0x01:
1405 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
1406 return ERR_INSIDEPHONEMENU;
1407 case 0x02:
1408 smprintf(s, "Can't write to empty location ?\n");
1409 return ERR_EMPTY;
1410 case 0x04:
1411 smprintf(s, "Full memory\n");
1412 return ERR_FULL;
1413 default:
1414 smprintf(s, "ERROR: unknown %i\n",msg->Buffer[4]);
1415 return ERR_UNKNOWNRESPONSE;
1416 }
1417 }
1418 return ERR_UNKNOWNRESPONSE;
1419 }
1420
DCT3DCT4_ReplyEnableConnectFunc(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1421 GSM_Error DCT3DCT4_ReplyEnableConnectFunc(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1422 {
1423 smprintf(s, "Connection functions enabled\n");
1424 return ERR_NONE;
1425 }
1426
DCT3DCT4_EnableWAPFunctions(GSM_StateMachine * s)1427 GSM_Error DCT3DCT4_EnableWAPFunctions(GSM_StateMachine *s)
1428 {
1429 unsigned char req[] = {N6110_FRAME_HEADER, 0x00};
1430
1431 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOWAP)) return ERR_NOTSUPPORTED;
1432
1433 smprintf(s, "Enabling WAP\n");
1434 return GSM_WaitFor (s, req, 4, 0x3f, 4, ID_EnableConnectFunc);
1435 }
1436
DCT3DCT4_ReplyDisableConnectFunc(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1437 GSM_Error DCT3DCT4_ReplyDisableConnectFunc(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1438 {
1439 smprintf(s, "Connection functions disabled\n");
1440 return ERR_NONE;
1441 }
1442
DCT3DCT4_DisableConnectionFunctions(GSM_StateMachine * s)1443 GSM_Error DCT3DCT4_DisableConnectionFunctions(GSM_StateMachine *s)
1444 {
1445 unsigned char req[] = {N6110_FRAME_HEADER, 0x03};
1446
1447 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOWAP)) return ERR_NOTSUPPORTED;
1448
1449 smprintf(s, "Disabling connection settings\n");
1450 return GSM_WaitFor (s, req, 4, 0x3f, 4, ID_DisableConnectFunc);
1451 }
1452
DCT3DCT4_ReplyDelWAPBookmark(GSM_Protocol_Message * msg,GSM_StateMachine * s)1453 GSM_Error DCT3DCT4_ReplyDelWAPBookmark(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1454 {
1455 switch (msg->Buffer[3]) {
1456 case 0x0D:
1457 smprintf(s, "WAP bookmark deleted OK\n");
1458 return ERR_NONE;
1459 case 0x0E:
1460 smprintf(s, "WAP bookmark deleting error\n");
1461 switch (msg->Buffer[4]) {
1462 case 0x01:
1463 smprintf(s, "Security error. Inside WAP bookmarks menu\n");
1464 return ERR_SECURITYERROR;
1465 case 0x02:
1466 smprintf(s, "Invalid location\n");
1467 return ERR_INVALIDLOCATION;
1468 default:
1469 smprintf(s, "ERROR: unknown %i\n",msg->Buffer[4]);
1470 return ERR_UNKNOWNRESPONSE;
1471 }
1472 }
1473 return ERR_UNKNOWNRESPONSE;
1474 }
1475
DCT3DCT4_DeleteWAPBookmarkPart(GSM_StateMachine * s,GSM_WAPBookmark * bookmark)1476 GSM_Error DCT3DCT4_DeleteWAPBookmarkPart(GSM_StateMachine *s, GSM_WAPBookmark *bookmark)
1477 {
1478 GSM_Error error;
1479 unsigned char req[] = {N6110_FRAME_HEADER, 0x0C,
1480 0x00, 0x00}; /* Location */
1481
1482 req[5] = bookmark->Location;
1483
1484 smprintf(s, "Deleting WAP bookmark\n");
1485 error = GSM_WaitFor (s, req, 6, 0x3f, 4, ID_DeleteWAPBookmark);
1486 if (error != ERR_NONE) {
1487 if (error == ERR_INVALIDLOCATION || error == ERR_INSIDEPHONEMENU) {
1488 DCT3DCT4_DisableConnectionFunctions(s);
1489 }
1490 return error;
1491 }
1492
1493 return DCT3DCT4_DisableConnectionFunctions(s);
1494 }
1495
DCT3DCT4_GetWAPBookmarkPart(GSM_StateMachine * s,GSM_WAPBookmark * bookmark)1496 GSM_Error DCT3DCT4_GetWAPBookmarkPart(GSM_StateMachine *s, GSM_WAPBookmark *bookmark)
1497 {
1498 GSM_Error error;
1499 unsigned char req[] = {N6110_FRAME_HEADER, 0x06,
1500 0x00, 0x00}; /* Location */
1501
1502 req[5]=bookmark->Location-1;
1503
1504 s->Phone.Data.WAPBookmark=bookmark;
1505 smprintf(s, "Getting WAP bookmark\n");
1506 error = GSM_WaitFor (s, req, 6, 0x3f, 4, ID_GetWAPBookmark);
1507 if (error != ERR_NONE) {
1508 if (error == ERR_INVALIDLOCATION || error == ERR_INSIDEPHONEMENU) {
1509 DCT3DCT4_DisableConnectionFunctions(s);
1510 }
1511 return error;
1512 }
1513
1514 return DCT3DCT4_DisableConnectionFunctions(s);
1515 }
1516
DCT3DCT4_CancelCall(GSM_StateMachine * s,int ID)1517 GSM_Error DCT3DCT4_CancelCall(GSM_StateMachine *s, int ID)
1518 {
1519 unsigned char req[] = {N6110_FRAME_HEADER, 0x08, 0x00, 0x85};
1520
1521 req[4] = (unsigned char)ID;
1522 s->Phone.Data.CallID = ID;
1523
1524 smprintf(s, "Canceling single call\n");
1525 return GSM_WaitFor (s, req, 6, 0x01, 4, ID_CancelCall);
1526 }
1527
DCT3DCT4_AnswerCall(GSM_StateMachine * s,int ID)1528 GSM_Error DCT3DCT4_AnswerCall(GSM_StateMachine *s, int ID)
1529 {
1530 unsigned char req[] = {N6110_FRAME_HEADER, 0x06, 0x00, 0x00};
1531
1532 req[4] = (unsigned char)ID;
1533 s->Phone.Data.CallID = ID;
1534
1535 smprintf(s, "Answering single call\n");
1536 return GSM_WaitFor (s, req, 6, 0x01, 4, ID_AnswerCall);
1537 }
1538
DCT3DCT4_ReplyGetModelFirmware(GSM_Protocol_Message * msg,GSM_StateMachine * s)1539 GSM_Error DCT3DCT4_ReplyGetModelFirmware(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1540 {
1541 GSM_CutLines lines;
1542 GSM_Phone_Data *Data = &s->Phone.Data;
1543
1544 InitLines(&lines);
1545
1546 SplitLines(msg->Buffer, msg->Length, &lines, "\x20\x0A", 2, "", 0, FALSE);
1547
1548 strcpy(Data->Model,GetLineString(msg->Buffer, &lines, 4));
1549 smprintf(s, "Received model %s\n",Data->Model);
1550 Data->ModelInfo = GetModelData(s, NULL, Data->Model, NULL);
1551
1552 strcpy(Data->VerDate,GetLineString(msg->Buffer, &lines, 3));
1553 smprintf(s, "Received firmware date %s\n",Data->VerDate);
1554
1555 strcpy(Data->Version,GetLineString(msg->Buffer, &lines, 2));
1556 smprintf(s, "Received firmware version %s\n",Data->Version);
1557 GSM_CreateFirmwareNumber(s);
1558
1559 FreeLines(&lines);
1560
1561 return ERR_NONE;
1562 }
1563
DCT3DCT4_GetModel(GSM_StateMachine * s)1564 GSM_Error DCT3DCT4_GetModel (GSM_StateMachine *s)
1565 {
1566 unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};
1567 GSM_Error error;
1568
1569 if (strlen(s->Phone.Data.Model)>0) return ERR_NONE;
1570
1571 smprintf(s, "Getting model\n");
1572 error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetModel);
1573 if (error == ERR_NONE) {
1574 smprintf_level(s, D_TEXT, "[Connected model - \"%s\"]\n",
1575 s->Phone.Data.Model);
1576 smprintf_level(s, D_TEXT, "[Firmware version - \"%s\"]\n",
1577 s->Phone.Data.Version);
1578 smprintf_level(s, D_TEXT, "[Firmware date - \"%s\"]\n",
1579 s->Phone.Data.VerDate);
1580 }
1581 return error;
1582 }
1583
DCT3DCT4_GetFirmware(GSM_StateMachine * s)1584 GSM_Error DCT3DCT4_GetFirmware (GSM_StateMachine *s)
1585 {
1586 unsigned char req[5] = {N6110_FRAME_HEADER, 0x03, 0x00};
1587 GSM_Error error;
1588
1589 if (strlen(s->Phone.Data.Version)>0) return ERR_NONE;
1590
1591 smprintf(s, "Getting firmware version\n");
1592 error=GSM_WaitFor (s, req, 5, 0xd1, 3, ID_GetFirmware);
1593 if (error == ERR_NONE) {
1594 smprintf_level(s, D_TEXT, "[Connected model - \"%s\"]\n",
1595 s->Phone.Data.Model);
1596 smprintf_level(s, D_TEXT, "[Firmware version - \"%s\"]\n",
1597 s->Phone.Data.Version);
1598 smprintf_level(s, D_TEXT, "[Firmware date - \"%s\"]\n",
1599 s->Phone.Data.VerDate);
1600 }
1601 return error;
1602 }
1603
1604 /* ---------- Shared for n7110.c and n6510.c ------------------------------- */
1605
N71_65_ReplyGetMemoryError(unsigned char error,GSM_StateMachine * s)1606 GSM_Error N71_65_ReplyGetMemoryError(unsigned char error, GSM_StateMachine *s)
1607 {
1608 switch (error) {
1609 case 0x21:
1610 smprintf(s, "Wait for synchronisation???\n");
1611 return ERR_WORKINPROGRESS;
1612 case 0x24:
1613 smprintf(s, "No own number???\n");
1614 return ERR_NOTSUPPORTED;
1615 case 0x27:
1616 smprintf(s, "No PIN\n");
1617 return ERR_SECURITYERROR;
1618 case 0x30:
1619 if (s->Phone.Data.Memory->MemoryType == MEM_ME ||
1620 s->Phone.Data.Memory->MemoryType == MEM_SM) {
1621 smprintf(s, "Empty entry\n");
1622 return ERR_EMPTY;
1623 }
1624 smprintf(s, "Invalid memory type\n");
1625 return ERR_NOTSUPPORTED;
1626 case 0x31:
1627 smprintf(s, "Invalid memory type?\n");
1628 s->Phone.Data.Memory->EntriesNum = 0;
1629 return ERR_EMPTY;
1630 case 0x33:
1631 smprintf(s, "Empty location\n");
1632 s->Phone.Data.Memory->EntriesNum = 0;
1633 return ERR_EMPTY;
1634 case 0x34:
1635 smprintf(s, "Too high location ?\n");
1636 return ERR_INVALIDLOCATION;
1637 case 0x3B: /* Tim Dreessen, 6230 */
1638 smprintf(s, "Empty location\n");
1639 s->Phone.Data.Memory->EntriesNum = 0;
1640 /*
1641 * This is really empty, but this entry is calculated to
1642 * entries count, so we must return something.
1643 */
1644 return ERR_NONE;
1645 case 0x3d: /* Seen on RH-105 for own number */
1646 smprintf(s, "Empty location\n");
1647 s->Phone.Data.Memory->EntriesNum = 0;
1648 return ERR_NONE;
1649 default:
1650 smprintf(s, "ERROR: unknown status code 0x%x\n", error);
1651 return ERR_UNKNOWNRESPONSE;
1652 }
1653 }
1654
N71_65_ReplyWritePhonebook(GSM_Protocol_Message * msg,GSM_StateMachine * s)1655 GSM_Error N71_65_ReplyWritePhonebook(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1656 {
1657 switch (msg->Buffer[6]) {
1658 case 0x0f:
1659 smprintf(s, "Phonebook entry writing failed\n");
1660 switch (msg->Buffer[10]) {
1661 case 0xf:
1662 smprintf(s, "Invalid block sent\n");
1663 return ERR_BUG;
1664 case 0x21:
1665 smprintf(s, "Still busy processing the last command\n");
1666 return ERR_BUSY;
1667 case 0x23:
1668 smprintf(s, "Block size does not match a definition\n");
1669 return ERR_BUG;
1670 case 0x25:
1671 smprintf(s, "when you try to save into entry with caller group assignment in phone with caller groups standard 2 (like in 6230i)\n");
1672 return ERR_PERMISSION;
1673 case 0x29:
1674 smprintf(s, "no caller group with given number (6230i)\n");
1675 return ERR_MEMORY;
1676 case 0x32:
1677 smprintf(s, "Ignoring ERROR: unknown 50 (probably group contains 50 entries)\n");
1678 return ERR_NONE;
1679 case 0x36:
1680 smprintf(s, "Too long name\n");
1681 return ERR_NOTSUPPORTED;
1682 case 0x3c:
1683 smprintf(s, "Can not add entry with 0 subentries\n");
1684 return ERR_NOTSUPPORTED;
1685 case 0x3d:
1686 smprintf(s, "Wrong entry type\n");
1687 return ERR_NOTSUPPORTED;
1688 case 0x3e:
1689 smprintf(s, "Too many entries\n");
1690 return ERR_NOTSUPPORTED;
1691 case 0x43:
1692 smprintf(s, "Incorrect characters\n");
1693 return ERR_NOTSUPPORTED;
1694 default:
1695 smprintf(s, "ERROR: unknown %i\n",msg->Buffer[10]);
1696 return ERR_UNKNOWNRESPONSE;
1697 }
1698 default:
1699 smprintf(s, "Phonebook entry written\n");
1700 return ERR_NONE;
1701 }
1702 }
1703
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)1704 gboolean NOKIA_FindPhoneFeatureValue(GSM_StateMachine *s,
1705 GSM_Profile_PhoneTableValue ProfileTable[],
1706 GSM_Profile_Feat_ID FeatureID,
1707 GSM_Profile_Feat_Value FeatureValue,
1708 unsigned char *PhoneID,
1709 unsigned char *PhoneValue)
1710 {
1711 int i=0;
1712
1713 smprintf(s, "Trying to find feature %i with value %i\n",FeatureID,FeatureValue);
1714 while (ProfileTable[i].ID != 0x00) {
1715 if (ProfileTable[i].ID == FeatureID &&
1716 ProfileTable[i].Value == FeatureValue) {
1717 *PhoneID = ProfileTable[i].PhoneID;
1718 *PhoneValue = ProfileTable[i].PhoneValue;
1719 return TRUE;
1720 }
1721 i++;
1722 }
1723 return FALSE;
1724 }
1725
1726 #define PROFILE_CALLERGROUPS_GROUP1 0x01
1727 #define PROFILE_CALLERGROUPS_GROUP2 0x02
1728 #define PROFILE_CALLERGROUPS_GROUP3 0x04
1729 #define PROFILE_CALLERGROUPS_GROUP4 0x08
1730 #define PROFILE_CALLERGROUPS_GROUP5 0x10
1731
NOKIA_FindFeatureValue(GSM_StateMachine * s,GSM_Profile_PhoneTableValue ProfileTable[],unsigned char ID,unsigned char Value,GSM_Phone_Data * Data,gboolean CallerGroups)1732 void NOKIA_FindFeatureValue(GSM_StateMachine *s,
1733 GSM_Profile_PhoneTableValue ProfileTable[],
1734 unsigned char ID,
1735 unsigned char Value,
1736 GSM_Phone_Data *Data,
1737 gboolean CallerGroups)
1738 {
1739 int i;
1740
1741 if (CallerGroups) {
1742 smprintf(s, "Caller groups: %i\n", Value);
1743 Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = Profile_CallerGroups;
1744 Data->Profile->FeaturesNumber++;
1745 for (i=0;i<5;i++) Data->Profile->CallerGroups[i] = FALSE;
1746 if ((Value & PROFILE_CALLERGROUPS_GROUP1)==PROFILE_CALLERGROUPS_GROUP1) Data->Profile->CallerGroups[0] = TRUE;
1747 if ((Value & PROFILE_CALLERGROUPS_GROUP2)==PROFILE_CALLERGROUPS_GROUP2) Data->Profile->CallerGroups[1] = TRUE;
1748 if ((Value & PROFILE_CALLERGROUPS_GROUP3)==PROFILE_CALLERGROUPS_GROUP3) Data->Profile->CallerGroups[2] = TRUE;
1749 if ((Value & PROFILE_CALLERGROUPS_GROUP4)==PROFILE_CALLERGROUPS_GROUP4) Data->Profile->CallerGroups[3] = TRUE;
1750 if ((Value & PROFILE_CALLERGROUPS_GROUP5)==PROFILE_CALLERGROUPS_GROUP5) Data->Profile->CallerGroups[4] = TRUE;
1751 return;
1752 }
1753
1754 i = 0;
1755 while (ProfileTable[i].ID != 0x00) {
1756 if (ProfileTable[i].PhoneID == ID &&
1757 ProfileTable[i].PhoneValue == Value) {
1758 #ifdef DEBUG
1759 switch (ProfileTable[i].ID) {
1760 case Profile_KeypadTone : smprintf(s, "Keypad tones\n"); break;
1761 case Profile_CallAlert : smprintf(s, "Call alert\n"); break;
1762 case Profile_RingtoneVolume : smprintf(s, "Ringtone volume\n"); break;
1763 case Profile_MessageTone : smprintf(s, "SMS message tones\n"); break;
1764 case Profile_Vibration : smprintf(s, "Vibration\n"); break;
1765 case Profile_WarningTone : smprintf(s, "Warning (ang games) tones\n"); break;
1766 case Profile_AutoAnswer : smprintf(s, "Automatic answer\n"); break;
1767 case Profile_Lights : smprintf(s, "Lights\n"); break;
1768 case Profile_ScreenSaver : smprintf(s, "Screen Saver\n"); break;
1769 case Profile_ScreenSaverTime : smprintf(s, "Screen Saver timeout\n"); break;
1770 default : break;
1771 }
1772 #endif
1773 Data->Profile->FeatureID [Data->Profile->FeaturesNumber] = ProfileTable[i].ID;
1774 Data->Profile->FeatureValue [Data->Profile->FeaturesNumber] = ProfileTable[i].Value;
1775 Data->Profile->FeaturesNumber++;
1776 break;
1777 }
1778 i++;
1779 }
1780 }
1781
1782 GSM_Profile_PhoneTableValue Profile71_65[] = {
1783 {Profile_KeypadTone, PROFILE_KEYPAD_OFF, 0x00,0x00},
1784 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL1, 0x00,0x01},
1785 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL2, 0x00,0x02},
1786 {Profile_KeypadTone, PROFILE_KEYPAD_LEVEL3, 0x00,0x03},
1787 /* Lights ? */
1788 {Profile_CallAlert, PROFILE_CALLALERT_RINGING, 0x02,0x00},
1789 {Profile_CallAlert, PROFILE_CALLALERT_ASCENDING, 0x02,0x01},
1790 {Profile_CallAlert, PROFILE_CALLALERT_RINGONCE, 0x02,0x02},
1791 {Profile_CallAlert, PROFILE_CALLALERT_BEEPONCE, 0x02,0x03},
1792 {Profile_CallAlert, PROFILE_CALLALERT_OFF, 0x02,0x05},
1793 /* {Profile_CallAlert, PROFILE_CALLALERT_CALLERGROUPS,0x02,0x07}, */
1794 /* Ringtone ID */
1795 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL1, 0x04,0x00},
1796 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL2, 0x04,0x01},
1797 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL3, 0x04,0x02},
1798 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL4, 0x04,0x03},
1799 {Profile_RingtoneVolume, PROFILE_VOLUME_LEVEL5, 0x04,0x04},
1800 {Profile_MessageTone, PROFILE_MESSAGE_NOTONE, 0x05,0x00},
1801 {Profile_MessageTone, PROFILE_MESSAGE_STANDARD, 0x05,0x01},
1802 {Profile_MessageTone, PROFILE_MESSAGE_SPECIAL, 0x05,0x02},
1803 {Profile_MessageTone, PROFILE_MESSAGE_BEEPONCE, 0x05,0x03},
1804 {Profile_MessageTone, PROFILE_MESSAGE_ASCENDING, 0x05,0x04},
1805 {Profile_Vibration, PROFILE_VIBRATION_OFF, 0x06,0x00},
1806 {Profile_Vibration, PROFILE_VIBRATION_ON, 0x06,0x01},
1807 {Profile_WarningTone, PROFILE_WARNING_OFF, 0x07,0x00},
1808 {Profile_WarningTone, PROFILE_WARNING_ON, 0x07,0x01},
1809 /* Caller groups */
1810 {Profile_AutoAnswer, PROFILE_AUTOANSWER_OFF, 0x09,0x00},
1811 {Profile_AutoAnswer, PROFILE_AUTOANSWER_ON, 0x09,0x01},
1812 {0x00, 0x00, 0x00,0x00}
1813 };
1814
NOKIA_SetIncomingSMS(GSM_StateMachine * s,gboolean enable)1815 GSM_Error NOKIA_SetIncomingSMS(GSM_StateMachine *s, gboolean enable)
1816 {
1817 s->Phone.Data.EnableIncomingSMS = enable;
1818 #ifdef DEBUG
1819 if (enable) {
1820 smprintf(s, "Enabling incoming SMS\n");
1821 } else {
1822 smprintf(s, "Disabling incoming SMS\n");
1823 }
1824 #endif
1825 return ERR_NONE;
1826 }
1827
N71_65_ReplyUSSDInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)1828 GSM_Error N71_65_ReplyUSSDInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1829 {
1830 unsigned char buffer[2000];
1831 GSM_USSDMessage ussd;
1832
1833 if (s->Phone.Data.RequestID == ID_Divert) return ERR_NONE;
1834
1835 memcpy(buffer,msg->Buffer+8,msg->Buffer[7]);
1836 buffer[msg->Buffer[7]] = 0x00;
1837
1838 smprintf(s, "USSD reply: \"%s\"\n",buffer);
1839
1840 if (s->Phone.Data.EnableIncomingUSSD && s->User.IncomingUSSD!=NULL) {
1841 EncodeUnicode(ussd.Text,buffer,strlen(buffer));
1842 /**
1843 * @todo: Should determine status.
1844 */
1845 ussd.Status = USSD_Unknown;
1846 s->User.IncomingUSSD(s, &ussd, s->User.IncomingUSSDUserData);
1847 }
1848
1849 return ERR_NONE;
1850 }
1851
NOKIA_SetIncomingUSSD(GSM_StateMachine * s,gboolean enable)1852 GSM_Error NOKIA_SetIncomingUSSD(GSM_StateMachine *s, gboolean enable)
1853 {
1854 s->Phone.Data.EnableIncomingUSSD = enable;
1855 #ifdef DEBUG
1856 if (enable) {
1857 smprintf(s, "Enabling incoming USSD\n");
1858 } else {
1859 smprintf(s, "Disabling incoming USSD\n");
1860 }
1861 #endif
1862 return ERR_NONE;
1863 }
1864
NOKIA_SetIncomingCall(GSM_StateMachine * s,gboolean enable)1865 GSM_Error NOKIA_SetIncomingCall(GSM_StateMachine *s, gboolean enable)
1866 {
1867 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo,F_NOCALLINFO)) return ERR_NOTSUPPORTED;
1868
1869 s->Phone.Data.EnableIncomingCall = enable;
1870 #ifdef DEBUG
1871 if (enable) {
1872 smprintf(s, "Enabling incoming Call\n");
1873 } else {
1874 smprintf(s, "Disabling incoming Call\n");
1875 }
1876 #endif
1877 return ERR_NONE;
1878 }
1879
N71_65_ReplyCallInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)1880 GSM_Error N71_65_ReplyCallInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1881 {
1882 GSM_Call call;
1883 int tmp;
1884 unsigned char buffer[200];
1885
1886 call.Status = 0;
1887 call.StatusCode = 0;
1888 call.CallIDAvailable = TRUE;
1889 call.PhoneNumber[0] = 0;
1890 call.PhoneNumber[1] = 0;
1891 smprintf(s, "Call info, ");
1892 switch (msg->Buffer[3]) {
1893 case 0x02:
1894 smprintf(s, "Call established, waiting for answer\n");
1895 call.Status = GSM_CALL_CallEstablished;
1896 break;
1897 case 0x03:
1898 case 0x53:
1899 case 0x05:
1900 if (msg->Buffer[3] == 0x03) {
1901 smprintf(s, "Call started\n");
1902 call.Status = GSM_CALL_CallStart;
1903 } else if (msg->Buffer[3] == 0x05) {
1904 smprintf(s, "Incoming call\n");
1905 call.Status = GSM_CALL_IncomingCall;
1906 } else {
1907 smprintf(s, "Outgoing call\n");
1908 call.Status = GSM_CALL_OutgoingCall;
1909 }
1910 /* Sample reply:
1911 01 |72r|02 |03 |01 |03 |07 |04 |01 |01 |01 |1C |11 |300|00 | 0B .r...........0..
1912 00 |333|00 |322|00 |344|00 |399|00 |399|00 |355|00 |366|00 |377 .3.2.4.9.9.5.6.7
1913 00 |322|00 |311|00 |311|0E |1C |300|02 |0A |00 |00 |09 |00 |4AJ .2.1.1..0......J
1914 00 |6Fo|00 |72r|00 |69i|00 |73s|00 |20 |00 |41A|00 |63c|00 |63c .o.r.i.s. .A.c.c
1915 00 |00 |00 |00 |00 |00 |00 |00 |00 |00 |00 |00 ............
1916 */
1917 smprintf(s, "Call mode : %i\n",msg->Buffer[5]);/* such interpretation is in gnokii */
1918 /* This is probably wrong, but I need more sample data to properly parse output */
1919 if (msg->Buffer[6] == 7) {
1920 tmp = 14;
1921 } else {
1922 tmp = 6;
1923 }
1924 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer,call.PhoneNumber,FALSE);
1925 smprintf(s, "Number : \"%s\"\n",DecodeUnicodeString(call.PhoneNumber));
1926 /* FIXME: read name from frame */
1927
1928 break;
1929 case 0x04:
1930 smprintf(s, "Remote end hang up\n");
1931 smprintf(s, "Cause Type : %i\n",msg->Buffer[5]);/* such interpretation is in gnokii */
1932 smprintf(s, "CC : %i\n",msg->Buffer[6]);
1933 smprintf(s, "MM(?) : %i\n",msg->Buffer[7]);
1934 smprintf(s, "RR(?) : %i\n",msg->Buffer[8]);
1935 call.Status = GSM_CALL_CallRemoteEnd;
1936 call.StatusCode = msg->Buffer[6];
1937 break;
1938 case 0x07:
1939 smprintf(s, "Call answer initiated\n");
1940 break;
1941 case 0x09:
1942 smprintf(s, "Call released\n");
1943 call.Status = GSM_CALL_CallLocalEnd;
1944 break;
1945 case 0x0a:
1946 smprintf(s, "Call is being released\n");
1947 break;
1948 case 0x0b:
1949 smprintf(s, "Meaning not known\n");
1950 call.CallIDAvailable = FALSE;
1951 break;
1952 case 0x0c:
1953 smprintf(s, "Audio status\n");
1954 if (msg->Buffer[4] == 0x01) smprintf(s, "Audio enabled\n");
1955 else smprintf(s, "Audio disabled\n");
1956 call.CallIDAvailable = FALSE;
1957 break;
1958 case 0x0f: /* 6111 */
1959 if (msg->Buffer[8]==0x01) {
1960 smprintf(s, "Calling from phone keypad ?\n");
1961 if (msg->Buffer[14]==0x03) {
1962 tmp = 19;
1963 } else {
1964 tmp = 21;
1965 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer,buffer,FALSE);
1966 smprintf(s, "Name : \"%s\"\n",DecodeUnicodeString(buffer));
1967 tmp+=7;
1968 }
1969 if (msg->Buffer[tmp-3]==0x11) {
1970 call.PhoneNumber[0]=0;
1971 call.PhoneNumber[1]='+';
1972 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer,call.PhoneNumber+2,FALSE);
1973 } else {
1974 NOKIA_GetUnicodeString(s, &tmp, msg->Buffer,call.PhoneNumber,FALSE);
1975 }
1976 call.Status = GSM_CALL_OutgoingCall;
1977 }
1978 if (msg->Buffer[8]==0x00) {
1979 smprintf(s, "Call released\n");
1980 call.Status = GSM_CALL_CallLocalEnd;
1981 }
1982 break;
1983 case 0x10:
1984 smprintf(s, "Meaning not known\n");
1985 call.CallIDAvailable = FALSE;
1986 break;
1987 case 0x23:
1988 smprintf(s, "Call held\n");
1989 call.Status = GSM_CALL_CallHeld;
1990 break;
1991 case 0x25:
1992 smprintf(s, "Call resumed\n");
1993 call.Status = GSM_CALL_CallResumed;
1994 break;
1995 case 0x27:
1996 smprintf(s, "Call switched\n");
1997 call.Status = GSM_CALL_CallSwitched;
1998 break;
1999 case 0xA6:
2000 case 0xD2:
2001 case 0xD3:
2002 smprintf(s, "Meaning not known\n");
2003 call.CallIDAvailable = FALSE;
2004 break;
2005 }
2006 if (call.CallIDAvailable) smprintf(s, "Call ID : %d\n",msg->Buffer[4]);
2007 if (s->Phone.Data.EnableIncomingCall && s->User.IncomingCall!=NULL && call.Status != 0) {
2008 if (call.CallIDAvailable) call.CallID = msg->Buffer[4];
2009 s->User.IncomingCall(s, &call, s->User.IncomingCallUserData);
2010 }
2011 if (s->Phone.Data.RequestID == ID_DialVoice) {
2012 if (msg->Buffer[3] == 0x10) return ERR_NOTSUPPORTED;
2013 }
2014 if (s->Phone.Data.RequestID == ID_CancelCall) {
2015 if (msg->Buffer[3] == 0x09) {
2016 if (s->Phone.Data.CallID == msg->Buffer[4]) return ERR_NONE;
2017 /* when we canceled call and see frame about other
2018 * call releasing, we don't give ERR_NONE for "our"
2019 * call release command
2020 */
2021 return ERR_NEEDANOTHERANSWER;
2022 }
2023 }
2024 if (s->Phone.Data.RequestID == ID_AnswerCall) {
2025 if (msg->Buffer[3] == 0x07) {
2026 if (s->Phone.Data.CallID == msg->Buffer[4]) return ERR_NONE;
2027 return ERR_NEEDANOTHERANSWER;
2028 }
2029 }
2030 return ERR_NONE;
2031 }
2032
2033 /* method 2 */
N71_65_ReplyAddCalendar2(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)2034 GSM_Error N71_65_ReplyAddCalendar2(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
2035 {
2036 smprintf(s, "Calendar note added\n");
2037 return ERR_NONE;
2038 }
2039
2040 /* method 2 */
N71_65_AddCalendar2(GSM_StateMachine * s,GSM_CalendarEntry * Note)2041 GSM_Error N71_65_AddCalendar2(GSM_StateMachine *s, GSM_CalendarEntry *Note)
2042 {
2043 GSM_CalendarNoteType NoteType;
2044 time_t t_time1,t_time2;
2045 GSM_DateTime Date,date_time;
2046 GSM_Error error;
2047 long diff;
2048 int Text, Time, Alarm, Phone, EndTime, Location, length=25;
2049 unsigned char req[5000] = {
2050 N6110_FRAME_HEADER,
2051 0x40,
2052 0x00, /* frame length - 7 */
2053 0x00,0x00,0x00,0x00,
2054 0x00,0x00,0x00,0x00, /* start time saved as difference */
2055 0x00,0x00,0xff,0xff, /* alarm saved as difference */
2056 0x00, /* frame length - 7 */
2057 0x00, /* note type */
2058 0x00,0x00, /* recurrance */
2059 0x00,0x00,0x00,0x00,
2060 0x00,0x00,0x00,0x00}; /* rest depends on note type */
2061
2062 NoteType = N71_65_FindCalendarType(Note->Type, s->Phone.Data.ModelInfo);
2063
2064 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62) ||
2065 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65)) {
2066 switch(NoteType) {
2067 case GSM_CAL_MEETING : req[18] = 0x01; length = 25; break;
2068 case GSM_CAL_CALL : req[18] = 0x02; length = 27; break;
2069 case GSM_CAL_BIRTHDAY : req[18] = 0x04; length = 28; break;
2070 case GSM_CAL_MEMO : req[18] = 0x08; length = 25; break;
2071 default : return ERR_UNKNOWN;
2072 }
2073 } else {
2074 switch(NoteType) {
2075 case GSM_CAL_REMINDER : req[18] = 0x01; length = 25; break;
2076 case GSM_CAL_CALL : req[18] = 0x02; length = 27; break;
2077 case GSM_CAL_BIRTHDAY : req[18] = 0x04; length = 28; break;
2078 case GSM_CAL_MEMO : req[18] = 0x08; length = 25; break;
2079 default : return ERR_UNKNOWN;
2080 }
2081 }
2082
2083 GSM_CalendarFindDefaultTextTimeAlarmPhone(Note, &Text, &Time, &Alarm, &Phone, &EndTime, &Location);
2084
2085 if (Time == -1) {
2086 smprintf(s, "Can not save entry without time!\n");
2087 return ERR_UNKNOWN;
2088 }
2089 if (NoteType != GSM_CAL_BIRTHDAY) {
2090 Date.Year = 2030; Date.Month = 01; Date.Day = 01;
2091 Date.Hour = 00; Date.Minute = 00; Date.Second = 00;
2092 } else {
2093 Date.Year = 2029; Date.Month = 12; Date.Day = 31;
2094 Date.Hour = 22; Date.Minute = 59; Date.Second = 58;
2095 }
2096 t_time1 = Fill_Time_T(Date);
2097 memcpy(&Date,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
2098 if (NoteType != GSM_CAL_BIRTHDAY) {
2099 Date.Year -= 20;
2100 } else {
2101 /* 6230 and probably other new models handle it differently
2102 we don't make difference from 1980 year
2103 */
2104 if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35) ||
2105 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65) ||
2106 GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62)) {
2107 Date.Year = 1980;
2108 }
2109 Date.Hour = 22; Date.Minute = 58; Date.Second = 58;
2110 }
2111 t_time2 = Fill_Time_T(Date);
2112 diff = t_time1-t_time2;
2113 smprintf(s, " Difference : %li seconds\n", -diff);
2114 req[9] = (unsigned char)(-diff >> 24);
2115 req[10] = (unsigned char)(-diff >> 16);
2116 req[11] = (unsigned char)(-diff >> 8);
2117 req[12] = (unsigned char)(-diff);
2118 if (NoteType == GSM_CAL_BIRTHDAY) {
2119 req[25] = Note->Entries[Time].Date.Year / 256;
2120 req[26] = Note->Entries[Time].Date.Year % 256;
2121 /* Recurrance = 1 year */
2122 req[19] = 0xff;
2123 req[20] = 0xff;
2124 }
2125
2126 if (NoteType == GSM_CAL_CALL && Phone != -1) {
2127 req[25] = UnicodeLength(Note->Entries[Phone].Text);
2128 CopyUnicodeString(req+length,Note->Entries[Phone].Text);
2129 length += UnicodeLength(Note->Entries[Phone].Text)*2;
2130 }
2131
2132 if (Alarm != -1) {
2133 if (NoteType == GSM_CAL_BIRTHDAY) {
2134 if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[27] = 0x01;
2135 error=s->Phone.Functions->GetDateTime(s,&date_time);
2136 switch (error) {
2137 case ERR_EMPTY:
2138 case ERR_NOTIMPLEMENTED:
2139 GSM_GetCurrentDateTime(&date_time);
2140 break;
2141 case ERR_NONE:
2142 break;
2143 default:
2144 return error;
2145 }
2146 Date.Year = date_time.Year;
2147 Date.Hour = 23;
2148 Date.Minute = 59;
2149 } else {
2150 Date.Year += 20;
2151 }
2152 t_time2 = Fill_Time_T(Date);
2153 t_time1 = Fill_Time_T(Note->Entries[Alarm].Date);
2154 diff = t_time1-t_time2;
2155
2156 /* Sometimes we have difference in minutes */
2157 if (NoteType == GSM_CAL_MEETING) diff = diff / 60;
2158 if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35)) {
2159 if (NoteType == GSM_CAL_MEMO || NoteType == GSM_CAL_CALL) {
2160 diff = diff / 60;
2161 }
2162 }
2163
2164 smprintf(s, " Difference : %li seconds or minutes\n", -diff);
2165 req[13] = (unsigned char)(-diff >> 24);
2166 req[14] = (unsigned char)(-diff >> 16);
2167 req[15] = (unsigned char)(-diff >> 8);
2168 req[16] = (unsigned char)(-diff);
2169 }
2170
2171 GSM_SetCalendarRecurranceRepeat(&(s->di), req+19, NULL, Note);
2172
2173 if (Text != -1) {
2174 switch (NoteType) {
2175 case GSM_CAL_CALL:
2176 req[26] = UnicodeLength(Note->Entries[Text].Text);
2177 break;
2178 default:
2179 req[length++] = UnicodeLength(Note->Entries[Text].Text);
2180 if (NoteType == GSM_CAL_MEMO || NoteType == GSM_CAL_MEETING) req[length++] = 0x00;
2181 }
2182 CopyUnicodeString(req+length,Note->Entries[Text].Text);
2183 length += UnicodeLength(Note->Entries[Text].Text)*2;
2184 }
2185
2186 req[length++] = 0x00;
2187 req[length++] = 0x00;
2188
2189 req[4] = req[17] = length-7;
2190
2191 smprintf(s, "Writing calendar note method 2\n");
2192 return GSM_WaitFor (s, req, length, 0x13, 4, ID_SetCalendarNote);
2193 }
2194
2195 /* method 1*/
N71_65_ReplyGetCalendarNotePos1(GSM_Protocol_Message * msg,GSM_StateMachine * s,int * FirstCalendarPos)2196 GSM_Error N71_65_ReplyGetCalendarNotePos1(GSM_Protocol_Message *msg, GSM_StateMachine *s,int *FirstCalendarPos)
2197 {
2198 smprintf(s, "First calendar location: %i\n",msg->Buffer[4]*256+msg->Buffer[5]);
2199 *FirstCalendarPos = msg->Buffer[4]*256+msg->Buffer[5];
2200 return ERR_NONE;
2201 }
2202
2203 /* method 1*/
N71_65_GetCalendarNotePos1(GSM_StateMachine * s)2204 static GSM_Error N71_65_GetCalendarNotePos1(GSM_StateMachine *s)
2205 {
2206 unsigned char req[] = {N6110_FRAME_HEADER, 0x31};
2207
2208 smprintf(s, "Getting first free calendar note location\n");
2209 return GSM_WaitFor (s, req, 4, 0x13, 4, ID_GetCalendarNotePos);
2210 }
2211
2212 /* method 1 */
N71_65_ReplyAddCalendar1(GSM_Protocol_Message * msg,GSM_StateMachine * s)2213 GSM_Error N71_65_ReplyAddCalendar1(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2214 {
2215 #ifdef DEBUG
2216 smprintf(s, "Written calendar note type ");
2217 switch ((msg->Buffer[3]/2)-1) {
2218 case 0: smprintf(s, "Meeting"); break;
2219 case 1: smprintf(s, "Call"); break;
2220 case 2: smprintf(s, "Birthday");break;
2221 case 3: smprintf(s, "Reminder");break;
2222 }
2223 smprintf(s, " on location %d\n",msg->Buffer[4]*256+msg->Buffer[5]);
2224 #endif
2225 return ERR_NONE;
2226 }
2227
2228 /* method 1 */
N71_65_AddCalendar1(GSM_StateMachine * s,GSM_CalendarEntry * Note,int * FirstCalendarPos)2229 GSM_Error N71_65_AddCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, int *FirstCalendarPos)
2230 {
2231 long seconds;
2232 GSM_Error error;
2233 GSM_DateTime DT;
2234 int Text, Time, Alarm, Phone, EndTime, Location, count=12;
2235 unsigned char req[5000] = {
2236 N6110_FRAME_HEADER,
2237 0x01, /* note type */
2238 0x00, 0x00, /* location ? */
2239 0x00, /* entry type */
2240 0x00,
2241 0x00, 0x00, /* Year */
2242 0x00, /* Month */
2243 0x00, /* Day */
2244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2245
2246 error=N71_65_GetCalendarNotePos1(s);
2247 if (error!=ERR_NONE) return error;
2248 if (FirstCalendarPos != NULL) {
2249 Note->Location = *FirstCalendarPos;
2250 req[4] = *FirstCalendarPos/256;
2251 req[5] = *FirstCalendarPos%256;
2252 }
2253
2254 switch(Note->Type) {
2255 case GSM_CAL_CALL : req[3]=0x03; req[6]=0x02; break;
2256 case GSM_CAL_BIRTHDAY: req[3]=0x05; req[6]=0x04; break;
2257 case GSM_CAL_MEMO : req[3]=0x07; req[6]=0x08; break;
2258 case GSM_CAL_MEETING :
2259 default : req[3]=0x01; req[6]=0x01; break;
2260 }
2261
2262 GSM_CalendarFindDefaultTextTimeAlarmPhone(Note, &Text, &Time, &Alarm, &Phone, &EndTime, &Location);
2263
2264 if (Time == -1) {
2265 smprintf(s, "Can not save entry without time!\n");
2266 return ERR_UNKNOWN;
2267 }
2268 memcpy(&DT,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
2269 req[8] = DT.Year / 256;
2270 req[9] = DT.Year % 256;
2271 req[10] = DT.Month;
2272 req[11] = DT.Day;
2273
2274 switch(Note->Type) {
2275 case GSM_CAL_BIRTHDAY:
2276 /* byte 12 and 13 */
2277 req[count++] = 0x00;
2278 req[count++] = 0x00;
2279
2280 /* Alarm - bytes 14 to 17 */
2281 req[count++] = 0x00;
2282 req[count++] = 0x00;
2283 req[count++] = 0xff;
2284 req[count++] = 0xff;
2285 if (Alarm != -1) {
2286 /* Comment from original source by Gabriele Zappi:
2287 * I try with Time.Year = Alarm.Year. If negative, I increase 1 year,
2288 * but only once ! This thing, because I may have Alarm period across
2289 * a year. (eg. Birthday on 2001-01-10 and Alarm on 2000-12-27)
2290 */
2291 DT.Year = Note->Entries[Alarm].Date.Year;
2292 seconds = Fill_Time_T(DT)-Fill_Time_T(Note->Entries[Alarm].Date);
2293 if (seconds<0L) {
2294 DT.Year++;
2295 seconds = Fill_Time_T(DT)-Fill_Time_T(Note->Entries[Alarm].Date);
2296 }
2297 if (seconds>=0L) {
2298 count -= 4;
2299 /* bytes 14 to 17 */
2300 req[count++] = (unsigned char)(seconds>>24);
2301 req[count++] = (unsigned char)((seconds>>16) & 0xff);
2302 req[count++] = (unsigned char)((seconds>>8) & 0xff);
2303 req[count++] = (unsigned char)(seconds & 0xff);
2304 }
2305 /* byte 18 */
2306 if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) req[count++] = 0x01; else req[count++] = 0x00;
2307 }
2308
2309 /* byte 19 and next */
2310 if (Text != -1) {
2311 req[count++] = UnicodeLength(Note->Entries[Text].Text);
2312 CopyUnicodeString(req+count,Note->Entries[Text].Text);
2313 count=count+2*UnicodeLength(Note->Entries[Text].Text);
2314 } else {
2315 req[count++] = 0x00;
2316 }
2317 break;
2318 case GSM_CAL_MEMO:
2319 /* byte 12 and 13 */
2320 GSM_SetCalendarRecurranceRepeat(&(s->di), req+count, NULL, Note);
2321 count+=2;
2322
2323 /* byte 14 and next */
2324 if (Text != -1) {
2325 req[count++] = UnicodeLength(Note->Entries[Text].Text);
2326 req[count++] = 0x00;
2327 CopyUnicodeString(req+count,Note->Entries[Text].Text);
2328 count=count+2*UnicodeLength(Note->Entries[Text].Text);
2329 } else {
2330 req[count++] = 0x00;
2331 req[count++] = 0x00;
2332 }
2333 break;
2334 case GSM_CAL_MEETING:
2335 case GSM_CAL_CALL:
2336 default:
2337 /* byte 12 and 13 */
2338 req[count++] = DT.Hour;
2339 req[count++] = DT.Minute;
2340
2341 /* Alarm - byte 14 and 15 */
2342 req[count++] = 0xff;
2343 req[count++] = 0xff;
2344 if (Alarm != -1) {
2345 seconds=Fill_Time_T(DT)-Fill_Time_T(Note->Entries[Alarm].Date);
2346 if (seconds>=0L) {
2347 count -= 2;
2348 req[count++] = (unsigned char)((seconds/60L)>>8);
2349 req[count++] = (unsigned char)((seconds/60L)&0xff);
2350 }
2351 }
2352
2353 /* byte 16 and 17 */
2354 GSM_SetCalendarRecurranceRepeat(&(s->di), req+count, NULL, Note);
2355 count+=2;
2356
2357 /* byte 18 */
2358 if (Text != -1) {
2359 req[count++] = UnicodeLength(Note->Entries[Text].Text);
2360 } else {
2361 req[count++] = 0x00;
2362 }
2363 /* byte 19 */
2364 if (Note->Type == GSM_CAL_CALL && Phone != -1) {
2365 req[count++] = UnicodeLength(Note->Entries[Phone].Text);
2366 } else {
2367 req[count++] = 0x00;
2368 }
2369 if (Text != -1) {
2370 CopyUnicodeString(req+count,Note->Entries[Text].Text);
2371 count=count+2*UnicodeLength(Note->Entries[Text].Text);
2372 }
2373 if (Note->Type == GSM_CAL_CALL && Phone != -1) {
2374 CopyUnicodeString(req+count,Note->Entries[Phone].Text);
2375 count=count+2*UnicodeLength(Note->Entries[Phone].Text);
2376 }
2377 break;
2378 }
2379 req[count] = 0x00;
2380 smprintf(s, "Writing calendar note method 1\n");
2381 return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetCalendarNote);
2382 }
2383
N71_65_ReplyDelCalendar(GSM_Protocol_Message * msg,GSM_StateMachine * s)2384 GSM_Error N71_65_ReplyDelCalendar(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2385 {
2386 if (msg->Buffer[3] == 0xf0) return ERR_NOTSUPPORTED;
2387
2388 smprintf(s, "Deleted calendar note on location %d\n",msg->Buffer[4]*256+msg->Buffer[5]);
2389 return ERR_NONE;
2390 }
2391
N71_65_DelCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)2392 GSM_Error N71_65_DelCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
2393 {
2394 unsigned char req[] = {N6110_FRAME_HEADER, 0x0b,
2395 0x00, 0x00}; /* location */
2396
2397 req[4] = Note->Location / 256;
2398 req[5] = Note->Location % 256;
2399
2400 smprintf(s, "Deleting calendar note\n");
2401 return GSM_WaitFor (s, req, 6, 0x13, 4, ID_DeleteCalendarNote);
2402 }
2403
2404 /* method 1 */
N71_65_ReplyGetCalendarInfo1(GSM_Protocol_Message * msg,GSM_StateMachine * s,GSM_NOKIACalToDoLocations * LastCalendar)2405 GSM_Error N71_65_ReplyGetCalendarInfo1(GSM_Protocol_Message *msg, GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar)
2406 {
2407 size_t i,j=0;
2408
2409 smprintf(s, "Info with calendar notes locations received method 1\n");
2410 while (LastCalendar->Location[j] != 0x00) j++;
2411 if (j >= GSM_MAXCALENDARTODONOTES) {
2412 smprintf(s, "Increase GSM_MAXCALENDARNOTES\n");
2413 return ERR_MOREMEMORY;
2414 }
2415 if (j == 0) {
2416 LastCalendar->Number=msg->Buffer[4]*256+msg->Buffer[5];
2417 smprintf(s, "Number of Entries: %i\n",LastCalendar->Number);
2418 }
2419 smprintf(s, "Locations: ");
2420 i = 0;
2421 while (9+(i*2) <= msg->Length) {
2422 LastCalendar->Location[j++]=msg->Buffer[8+(i*2)]*256+msg->Buffer[9+(i*2)];
2423 smprintf(s, "%i ",LastCalendar->Location[j-1]);
2424 i++;
2425 }
2426 smprintf(s, "\nNumber of Entries in frame: %ld\n", (long)i);
2427 smprintf(s, "\n");
2428 LastCalendar->Location[j] = 0;
2429 if (i == 1 && msg->Buffer[8+(0*2)]*256+msg->Buffer[9+(0*2)] == 0) return ERR_EMPTY;
2430 if (i == 0) return ERR_EMPTY;
2431 return ERR_NONE;
2432 }
2433
2434 /* method 1 */
N71_65_GetCalendarInfo1(GSM_StateMachine * s,GSM_NOKIACalToDoLocations * LastCalendar)2435 GSM_Error N71_65_GetCalendarInfo1(GSM_StateMachine *s, GSM_NOKIACalToDoLocations *LastCalendar)
2436 {
2437 GSM_Error error;
2438 int i;
2439 unsigned char req[] = {N6110_FRAME_HEADER, 0x3a,
2440 0xFF, 0xFE}; /* First location number */
2441
2442 LastCalendar->Location[0] = 0x00;
2443 LastCalendar->Number = 0;
2444
2445 smprintf(s, "Getting locations for calendar method 1\n");
2446 error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo);
2447 if (error != ERR_NONE && error != ERR_EMPTY) return error;
2448
2449 while (1) {
2450 i=0;
2451 while (LastCalendar->Location[i] != 0x00) i++;
2452 if (i == LastCalendar->Number) break;
2453 if (i != LastCalendar->Number && error == ERR_EMPTY) {
2454 smprintf(s, "Phone doesn't support some notes with this method. Workaround\n");
2455 LastCalendar->Number = i;
2456 break;
2457 }
2458 smprintf(s, "i = %i %i\n",i,LastCalendar->Number);
2459 req[4] = LastCalendar->Location[i-1] / 256;
2460 req[5] = LastCalendar->Location[i-1] % 256;
2461 smprintf(s, "Getting locations for calendar\n");
2462 error = GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNotesInfo);
2463 if (error != ERR_NONE && error != ERR_EMPTY) return error;
2464 }
2465 return ERR_NONE;
2466 }
2467
2468 /* method 1 */
N71_65_ReplyGetNextCalendar1(GSM_Protocol_Message * msg,GSM_StateMachine * s)2469 GSM_Error N71_65_ReplyGetNextCalendar1(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2470 {
2471 int timedelta,i;
2472 GSM_CalendarEntry *entry = s->Phone.Data.Cal;
2473
2474 smprintf(s, "Calendar note received method 1\n");
2475
2476 /* Later these values can change */
2477 if (msg->Buffer[6]!=0x04) { /* Here not birthday */
2478 entry->Entries[0].Date.Year = msg->Buffer[8]*256+msg->Buffer[9];
2479 }
2480 entry->Entries[0].Date.Month = msg->Buffer[10];
2481 entry->Entries[0].Date.Day = msg->Buffer[11];
2482 entry->Entries[0].Date.Hour = msg->Buffer[12];
2483 entry->Entries[0].Date.Minute = msg->Buffer[13];
2484 entry->Entries[0].Date.Second = 0;
2485 entry->Entries[0].EntryType = CAL_START_DATETIME;
2486 entry->EntriesNum++;
2487
2488 switch (msg->Buffer[6]) {
2489 case 0x01:
2490 smprintf(s, "Meeting\n");
2491 entry->Type = GSM_CAL_MEETING;
2492
2493 timedelta=msg->Buffer[14]*256+msg->Buffer[15];
2494 if (timedelta != 0xffff) {
2495 smprintf(s, " Difference : %i seconds\n", timedelta);
2496 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
2497 GetTimeDifference(timedelta, &entry->Entries[1].Date, FALSE, 60);
2498 entry->Entries[1].EntryType = CAL_TONE_ALARM_DATETIME;
2499 entry->EntriesNum++;
2500 }
2501 GSM_GetCalendarRecurranceRepeat(&(s->di), msg->Buffer + 16, NULL, entry);
2502
2503 memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+20, msg->Buffer[18]*2);
2504 entry->Entries[entry->EntriesNum].Text[msg->Buffer[18]*2] = 0;
2505 entry->Entries[entry->EntriesNum].Text[msg->Buffer[18]*2+1] = 0;
2506 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
2507 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
2508 entry->EntriesNum++;
2509 return ERR_NONE;
2510 case 0x02:
2511 smprintf(s, "Call\n");
2512 entry->Type = GSM_CAL_CALL;
2513
2514 timedelta=msg->Buffer[14]*256+msg->Buffer[15];
2515 if (timedelta != 0xffff) {
2516 smprintf(s, " Difference : %i seconds\n", timedelta);
2517 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
2518 GetTimeDifference(timedelta, &entry->Entries[1].Date, FALSE, 60);
2519 entry->Entries[1].EntryType = CAL_TONE_ALARM_DATETIME;
2520 entry->EntriesNum++;
2521 }
2522 GSM_GetCalendarRecurranceRepeat(&(s->di), msg->Buffer + 16, NULL, entry);
2523
2524 i = msg->Buffer[18] * 2;
2525 if (i!=0) {
2526 memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+20, i);
2527 entry->Entries[entry->EntriesNum].Text[i] = 0;
2528 entry->Entries[entry->EntriesNum].Text[i+1] = 0;
2529 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
2530 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
2531 entry->EntriesNum++;
2532 }
2533
2534 memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+20+i, msg->Buffer[19]*2);
2535 entry->Entries[entry->EntriesNum].Text[msg->Buffer[19]*2] = 0;
2536 entry->Entries[entry->EntriesNum].Text[msg->Buffer[19]*2+1] = 0;
2537 entry->Entries[entry->EntriesNum].EntryType = CAL_PHONE;
2538 smprintf(s, "Phone : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
2539 entry->EntriesNum++;
2540 return ERR_NONE;
2541 case 0x04:
2542 smprintf(s, "Birthday\n");
2543 entry->Type = GSM_CAL_BIRTHDAY;
2544
2545 entry->Entries[0].Date.Hour = 23;
2546 entry->Entries[0].Date.Minute = 59;
2547 entry->Entries[0].Date.Second = 58;
2548
2549 timedelta = ((unsigned int)msg->Buffer[14]) << 24;
2550 timedelta += ((unsigned int)msg->Buffer[15]) << 16;
2551 timedelta += ((unsigned int)msg->Buffer[16]) << 8;
2552 timedelta += msg->Buffer[17];
2553 if (timedelta != 0xffff) {
2554 smprintf(s, " Difference : %i seconds\n", timedelta);
2555 memcpy(&entry->Entries[1].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
2556 GetTimeDifference(timedelta, &entry->Entries[1].Date, FALSE, 1);
2557 entry->Entries[1].EntryType = CAL_TONE_ALARM_DATETIME;
2558 if (msg->Buffer[20]!=0x00) {
2559 entry->Entries[1].EntryType = CAL_SILENT_ALARM_DATETIME;
2560 smprintf(s, "Alarm type : Silent\n");
2561 }
2562 entry->EntriesNum++;
2563 }
2564
2565 entry->Entries[0].Date.Year = msg->Buffer[18]*256 + msg->Buffer[19];
2566 if (entry->Entries[0].Date.Year == 65535) entry->Entries[0].Date.Year = 0;
2567 smprintf(s, "Age : %i\n",entry->Entries[0].Date.Year);
2568
2569 memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+22, msg->Buffer[21]*2);
2570 entry->Entries[entry->EntriesNum].Text[msg->Buffer[21]*2] = 0;
2571 entry->Entries[entry->EntriesNum].Text[msg->Buffer[21]*2+1] = 0;
2572 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
2573 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
2574 entry->EntriesNum++;
2575
2576 entry->Entries[entry->EntriesNum].EntryType = CAL_REPEAT_FREQUENCY;
2577 entry->Entries[entry->EntriesNum].Number = 1;
2578 entry->EntriesNum++;
2579 entry->Entries[entry->EntriesNum].EntryType = CAL_REPEAT_DAY;
2580 entry->Entries[entry->EntriesNum].Number = entry->Entries[0].Date.Day;
2581 entry->EntriesNum++;
2582 entry->Entries[entry->EntriesNum].EntryType = CAL_REPEAT_MONTH;
2583 entry->Entries[entry->EntriesNum].Number = entry->Entries[0].Date.Month;
2584 entry->EntriesNum++;
2585
2586 return ERR_NONE;
2587 case 0x08:
2588 smprintf(s, "Memo\n");
2589 entry->Type = GSM_CAL_MEMO;
2590
2591 entry->Entries[0].Date.Hour = 0;
2592 entry->Entries[0].Date.Minute = 0;
2593
2594 GSM_GetCalendarRecurranceRepeat(&(s->di), msg->Buffer + 12, NULL, entry);
2595
2596 memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+16, msg->Buffer[14]*2);
2597 entry->Entries[entry->EntriesNum].Text[msg->Buffer[14]*2] = 0;
2598 entry->Entries[entry->EntriesNum].Text[msg->Buffer[14]*2+1] = 0;
2599 entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
2600 smprintf(s, "Text : \"%s\"\n", DecodeUnicodeString(entry->Entries[entry->EntriesNum].Text));
2601 entry->EntriesNum++;
2602 return ERR_NONE;
2603 default:
2604 smprintf(s, "ERROR: unknown %i\n",msg->Buffer[6]);
2605 return ERR_UNKNOWNRESPONSE;
2606 }
2607 }
2608
2609 /* method 1 */
N71_65_GetNextCalendar1(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start,GSM_NOKIACalToDoLocations * LastCalendar,int * LastCalendarYear,int * LastCalendarPos)2610 GSM_Error N71_65_GetNextCalendar1(GSM_StateMachine *s, GSM_CalendarEntry *Note, gboolean start, GSM_NOKIACalToDoLocations *LastCalendar, int *LastCalendarYear, int *LastCalendarPos)
2611 {
2612 GSM_Error error;
2613 GSM_DateTime date_time;
2614 unsigned char req[] = {N6110_FRAME_HEADER, 0x19,
2615 0x00, 0x00}; /* Location */
2616
2617 if (start) {
2618 error=N71_65_GetCalendarInfo1(s, LastCalendar);
2619 if (error!=ERR_NONE) return error;
2620 if (LastCalendar->Number == 0) return ERR_EMPTY;
2621
2622 /* We have to get current year. It's NOT written in frame for
2623 * Birthday
2624 */
2625 error=s->Phone.Functions->GetDateTime(s,&date_time);
2626 switch (error) {
2627 case ERR_EMPTY:
2628 case ERR_NOTIMPLEMENTED:
2629 GSM_GetCurrentDateTime(&date_time);
2630 break;
2631 case ERR_NONE:
2632 break;
2633 default:
2634 return error;
2635 }
2636 *LastCalendarYear = date_time.Year;
2637 *LastCalendarPos = 0;
2638 } else {
2639 (*LastCalendarPos)++;
2640 }
2641
2642 if (*LastCalendarPos >= LastCalendar->Number) return ERR_EMPTY;
2643
2644 req[4] = LastCalendar->Location[*LastCalendarPos] / 256;
2645 req[5] = LastCalendar->Location[*LastCalendarPos] % 256;
2646
2647 Note->EntriesNum = 0;
2648 Note->Entries[0].Date.Year = *LastCalendarYear;
2649 Note->Location = LastCalendar->Location[*LastCalendarPos];
2650
2651 s->Phone.Data.Cal=Note;
2652 smprintf(s, "Getting calendar note method 1\n");
2653 return GSM_WaitFor (s, req, 6, 0x13, 4, ID_GetCalendarNote);
2654 }
2655
N71_65_EnableFunctions(GSM_StateMachine * s,const char * buff,int len)2656 GSM_Error N71_65_EnableFunctions(GSM_StateMachine *s,const char *buff,int len)
2657 {
2658 unsigned char buffer[50] = {N6110_FRAME_HEADER, 0x10,
2659 0x07}; /* Length */
2660
2661 buffer[4] = len;
2662 memcpy(buffer+5,buff,len);
2663
2664 /* Enables various things like incoming SMS, call info, etc. */
2665 return s->Protocol.Functions->WriteMessage(s, buffer, 5+len, 0x10);
2666 }
2667
N71_65_ReplySendDTMF(GSM_Protocol_Message * msg,GSM_StateMachine * s)2668 GSM_Error N71_65_ReplySendDTMF(GSM_Protocol_Message *msg, GSM_StateMachine *s)
2669 {
2670 switch (msg->Buffer[3]) {
2671 case 0xf0:
2672 return ERR_NOTSUPPORTED;
2673 case 0x51:
2674 smprintf(s, "DTMF sent OK\n");
2675 return ERR_NONE;
2676 case 0x59:
2677 case 0x5E:
2678 smprintf(s, "meaning unknown - during sending DTMF\n");
2679 return ERR_NONE;
2680 }
2681 return ERR_UNKNOWNRESPONSE;
2682 }
2683
N71_65_FindCalendarType(GSM_CalendarNoteType Type,GSM_PhoneModel * model)2684 GSM_CalendarNoteType N71_65_FindCalendarType(GSM_CalendarNoteType Type, GSM_PhoneModel *model)
2685 {
2686 switch (Type) {
2687 case GSM_CAL_CALL:
2688 return GSM_CAL_CALL;
2689 case GSM_CAL_BIRTHDAY:
2690 return GSM_CAL_BIRTHDAY;
2691 case GSM_CAL_MEETING:
2692 if (GSM_IsPhoneFeatureAvailable(model, F_CAL35)) {
2693 return GSM_CAL_REMINDER;
2694 } else return GSM_CAL_MEETING;
2695 case GSM_CAL_MEMO:
2696 if (GSM_IsPhoneFeatureAvailable(model, F_CAL35)) {
2697 return GSM_CAL_REMINDER;
2698 } else return GSM_CAL_MEMO;
2699 case GSM_CAL_REMINDER:
2700 if (GSM_IsPhoneFeatureAvailable(model, F_CAL62) ||
2701 GSM_IsPhoneFeatureAvailable(model, F_CAL65)) {
2702 return GSM_CAL_CALL;
2703 } else return GSM_CAL_REMINDER;
2704 default:
2705 return GSM_CAL_CALL;
2706 }
2707 }
2708
2709 #endif
2710
2711 /* How should editor hadle tabs in this file? Add editor commands here.
2712 * vim: noexpandtab sw=8 ts=8 sts=8:
2713 */
2714