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