1 /* (c) 2002-2005 by Marcin Wiacek */
2 
3 #include <gammu-config.h>
4 
5 #ifdef GSM_ENABLE_NOKIA6510
6 
7 #include <string.h>
8 #include <time.h>
9 
10 #include "../../../../misc/coding/coding.h"
11 #include "../../../../gsmcomon.h"
12 #include "../../../../service/gsmlogo.h"
13 #include "../../../../service/gsmcal.h"
14 #include "../../nfunc.h"
15 #include "../../nfuncold.h"
16 #include "../../../pfunc.h"
17 #include "../dct4func.h"
18 #include "n6510.h"
19 
20 /* method 3 */
N6510_ReplyGetCalendarInfo3(GSM_Protocol_Message * msg,GSM_StateMachine * s,GSM_NOKIACalToDoLocations * Last)21 GSM_Error N6510_ReplyGetCalendarInfo3(GSM_Protocol_Message *msg, GSM_StateMachine *s, GSM_NOKIACalToDoLocations *Last)
22 {
23 	size_t i=0,j=0;
24 
25 	while (Last->Location[j] != 0x00) j++;
26 	if (j >= GSM_MAXCALENDARTODONOTES) {
27 		smprintf(s, "Increase GSM_MAXCALENDARTODONOTES\n");
28 		return ERR_MOREMEMORY;
29 	}
30 	if (j == 0) {
31 		Last->Number = msg->Buffer[8]*256 + msg->Buffer[9];
32 		smprintf(s, "Number of Entries: %i\n", Last->Number);
33 	}
34 	smprintf(s, "Locations: ");
35 	while (14+(i*4) <= msg->Length) {
36 		Last->Location[j] = msg->Buffer[12+i*4]*256 + msg->Buffer[13+i*4];
37 		smprintf(s, "%i ", Last->Location[j]);
38 		i++;
39 		j++;
40 	}
41 	smprintf(s, "\nNumber of Entries in frame: %ld\n", (long)i);
42 	Last->Location[j] = 0;
43 	smprintf(s, "\n");
44 	if (i == 1 && msg->Buffer[12+0*4]*256+msg->Buffer[13+0*4] == 0) return ERR_EMPTY;
45 	if (i == 0) return ERR_EMPTY;
46 	return ERR_NONE;
47 }
48 
49 /* method 3 */
N6510_GetCalendarInfo3(GSM_StateMachine * s,GSM_NOKIACalToDoLocations * Last,char Type)50 GSM_Error N6510_GetCalendarInfo3(GSM_StateMachine *s, GSM_NOKIACalToDoLocations *Last, char Type)
51 {
52 	GSM_Error 	error = ERR_UNKNOWN;
53 	int		i;
54 	unsigned char   req[] = {N6110_FRAME_HEADER, 0x9E, 0xFF, 0xFF, 0x00, 0x00,
55 			         0x00, 0x00,	/* First location */
56 			         0x00};		/* 0 = calendar, 1 = ToDo in 6610 style, 2 = Notes */
57 
58 	Last->Location[0] = 0x00;
59 	Last->Number	  = 0;
60 
61 	req[10] = Type;
62 	if (Type == 0) {
63 		smprintf(s, "Getting locations for calendar method 3\n");
64 		error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetCalendarNotesInfo);
65 	} else if (Type == 1) {
66 		smprintf(s, "Getting locations for ToDo method 2\n");
67 		error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetToDo);
68 	} else if (Type == 2) {
69 		smprintf(s, "Getting locations for Notes\n");
70 		error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetNote);
71 	}
72 	if (error != ERR_NONE && error != ERR_EMPTY) return error;
73 
74 	while (1) {
75 		i=0;
76 		while (Last->Location[i] != 0x00) i++;
77 		smprintf(s, "i = %i last_number = %i\n",i,Last->Number);
78 		if (i == Last->Number) break;
79 		if (i != Last->Number && error == ERR_EMPTY) {
80 			smprintf(s, "Phone doesn't support some notes with this method. Workaround\n");
81 			Last->Number = i;
82 			break;
83 		}
84 		req[8] = Last->Location[i-1] / 256;
85 		req[9] = Last->Location[i-1] % 256;
86 		if (Type == 0) {
87 			smprintf(s, "Getting locations for calendar method 3\n");
88 			error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetCalendarNotesInfo);
89 		} else if (Type == 1) {
90 			smprintf(s, "Getting locations for todo method 2\n");
91 			error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetToDo);
92 		} else if (Type == 2) {
93 			smprintf(s, "Getting locations for Notes\n");
94 			error = GSM_WaitFor (s, req, 11, 0x13, 4, ID_GetNote);
95 		}
96 		if (error != ERR_NONE && error != ERR_EMPTY) return error;
97 	}
98 	return ERR_NONE;
99 }
100 
101 /* method 3 */
N6510_ReplyGetCalendar3(GSM_Protocol_Message * msg,GSM_StateMachine * s)102 GSM_Error N6510_ReplyGetCalendar3(GSM_Protocol_Message *msg, GSM_StateMachine *s)
103 {
104 	GSM_CalendarEntry 		*entry = s->Phone.Data.Cal;
105 	unsigned long			diff;
106 	int				i;
107 	gboolean				found = FALSE;
108 	GSM_Phone_N6510Data		*Priv = &s->Phone.Data.Priv.N6510;
109 	int len;
110 
111 	smprintf(s, "Calendar note received method 3\n");
112 
113 	smprintf(s,"Note type %02i: ",msg->Buffer[27]);
114 	switch(msg->Buffer[27]) {
115 		case 0x00: smprintf(s,"Reminder\n"); entry->Type = GSM_CAL_REMINDER; break;
116 		case 0x01: smprintf(s,"Meeting\n");  entry->Type = GSM_CAL_MEETING;  break;
117 		case 0x02: smprintf(s,"Call\n");     entry->Type = GSM_CAL_CALL;     break;
118 		case 0x04: smprintf(s,"Birthday\n"); entry->Type = GSM_CAL_BIRTHDAY; break;
119 		case 0x08: smprintf(s,"Memo\n");     entry->Type = GSM_CAL_MEMO;     break;
120 		case 0x20: smprintf(s,"Birthday\n"); entry->Type = GSM_CAL_BIRTHDAY; break;
121 		default  : smprintf(s,"unknown\n");  entry->Type = GSM_CAL_MEMO;
122 	}
123 
124 	smprintf(s,"StartTime: %04i-%02i-%02i %02i:%02i\n",
125 		msg->Buffer[28]*256+msg->Buffer[29],
126 		msg->Buffer[30],msg->Buffer[31],msg->Buffer[32],
127 		msg->Buffer[33]);
128 	GSM_GetCurrentDateTime(&entry->Entries[0].Date);
129 	entry->Entries[0].Date.Year 	= msg->Buffer[28]*256+msg->Buffer[29];
130 	if (entry->Type == GSM_CAL_BIRTHDAY) {
131 		entry->Entries[0].Date.Year = entry->Entries[0].Date.Year;
132 		smprintf(s,"%i\n",entry->Entries[0].Date.Year);
133 	}
134 	entry->Entries[0].Date.Month 	= msg->Buffer[30];
135 	entry->Entries[0].Date.Day 	= msg->Buffer[31];
136 	entry->Entries[0].Date.Hour 	= msg->Buffer[32];
137 	entry->Entries[0].Date.Minute 	= msg->Buffer[33];
138 	/* Garbage seen with 3510i 3.51 */
139 	if (entry->Entries[0].Date.Month == 0 &&
140 			entry->Entries[0].Date.Day == 0 &&
141 			entry->Entries[0].Date.Hour == 0 &&
142 			entry->Entries[0].Date.Minute == 0)
143 		return ERR_EMPTY;
144 	entry->Entries[0].Date.Second	= 0;
145 	entry->Entries[0].EntryType = CAL_START_DATETIME;
146 	entry->EntriesNum++;
147 
148 	GSM_GetCalendarRecurranceRepeat(&(s->di), msg->Buffer+40, msg->Buffer+46, entry);
149 
150 	if (entry->Type != GSM_CAL_BIRTHDAY) {
151 		smprintf(s,"EndTime: %04i-%02i-%02i %02i:%02i\n",
152 			msg->Buffer[34]*256+msg->Buffer[35],
153 			msg->Buffer[36],msg->Buffer[37],msg->Buffer[38],
154 			msg->Buffer[39]);
155 		entry->Entries[entry->EntriesNum].Date.Year 	= msg->Buffer[34]*256+msg->Buffer[35];
156 		entry->Entries[entry->EntriesNum].Date.Month 	= msg->Buffer[36];
157 		entry->Entries[entry->EntriesNum].Date.Day 	= msg->Buffer[37];
158 		entry->Entries[entry->EntriesNum].Date.Hour 	= msg->Buffer[38];
159 		entry->Entries[entry->EntriesNum].Date.Minute 	= msg->Buffer[39];
160 		entry->Entries[entry->EntriesNum].Date.Second	= 0;
161 		entry->Entries[entry->EntriesNum].EntryType = CAL_END_DATETIME;
162 		entry->EntriesNum++;
163 	}
164 
165 	smprintf(s, "Note icon: %02x\n",msg->Buffer[21]);
166 	for(i=0;i<Priv->CalendarIconsNum;i++) {
167 		if (Priv->CalendarIconsTypes[i] == entry->Type) {
168 			found = TRUE;
169 		}
170 	}
171 	if (!found) {
172 		Priv->CalendarIconsTypes[Priv->CalendarIconsNum] = entry->Type;
173 		Priv->CalendarIcons	[Priv->CalendarIconsNum] = msg->Buffer[21];
174 		Priv->CalendarIconsNum++;
175 	}
176 
177 	if (msg->Buffer[14] == 0xFF && msg->Buffer[15] == 0xFF && msg->Buffer[16] == 0xff && msg->Buffer[17] == 0xff) {
178 		smprintf(s, "No alarm\n");
179 	} else {
180 		diff  = ((unsigned int)msg->Buffer[14]) << 24;
181 		diff += ((unsigned int)msg->Buffer[15]) << 16;
182 		diff += ((unsigned int)msg->Buffer[16]) << 8;
183 		diff += msg->Buffer[17];
184 
185 		memcpy(&entry->Entries[entry->EntriesNum].Date,&entry->Entries[0].Date,sizeof(GSM_DateTime));
186 		GetTimeDifference(diff, &entry->Entries[entry->EntriesNum].Date, FALSE, 60);
187 		smprintf(s, "Alarm date   : %02i-%02i-%04i %02i:%02i:%02i\n",
188 			entry->Entries[entry->EntriesNum].Date.Day,   entry->Entries[entry->EntriesNum].Date.Month,
189 			entry->Entries[entry->EntriesNum].Date.Year,  entry->Entries[entry->EntriesNum].Date.Hour,
190 			entry->Entries[entry->EntriesNum].Date.Minute,entry->Entries[entry->EntriesNum].Date.Second);
191 
192 		entry->Entries[entry->EntriesNum].EntryType = CAL_TONE_ALARM_DATETIME;
193 		if (msg->Buffer[22]==0x00 && msg->Buffer[23]==0x00 &&
194 		    msg->Buffer[24]==0x00 && msg->Buffer[25]==0x00) {
195 			entry->Entries[entry->EntriesNum].EntryType = CAL_SILENT_ALARM_DATETIME;
196 			smprintf(s, "Alarm type   : Silent\n");
197 		}
198 		entry->EntriesNum++;
199 	}
200 
201 	if (entry->Type == GSM_CAL_BIRTHDAY) {
202 		if (msg->Buffer[42] == 0xff && msg->Buffer[43] == 0xff) {
203 			entry->Entries[0].Date.Year = 0;
204 		} else {
205 			entry->Entries[0].Date.Year = msg->Buffer[42]*256+msg->Buffer[43];
206 		}
207 	}
208 
209 	len = msg->Buffer[50] * 256 + msg->Buffer[51];
210 	if (len > GSM_MAX_CALENDAR_TEXT_LENGTH) {
211 		smprintf(s, "Calendar text too long (%d), truncating to %d\n", len, GSM_MAX_CALENDAR_TEXT_LENGTH);
212 		len = GSM_MAX_CALENDAR_TEXT_LENGTH;
213 	}
214 	memcpy(entry->Entries[entry->EntriesNum].Text,
215 		msg->Buffer + 54,
216 		len * 2);
217 	entry->Entries[entry->EntriesNum].Text[len * 2]  = 0;
218 	entry->Entries[entry->EntriesNum].Text[len * 2 + 1] = 0;
219 	entry->Entries[entry->EntriesNum].EntryType = CAL_TEXT;
220 	entry->EntriesNum++;
221 	smprintf(s, "Note text: \"%s\"\n",DecodeUnicodeString(entry->Entries[entry->EntriesNum-1].Text));
222 
223 	if (entry->Type == GSM_CAL_CALL) {
224 		memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+(54+msg->Buffer[51]*2), msg->Buffer[52]*2);
225 		entry->Entries[entry->EntriesNum].Text[msg->Buffer[52]*2]   = 0;
226 		entry->Entries[entry->EntriesNum].Text[msg->Buffer[52]*2+1] = 0;
227 		entry->Entries[entry->EntriesNum].EntryType		   = CAL_PHONE;
228 		entry->EntriesNum++;
229 	}
230 	if (entry->Type == GSM_CAL_MEETING) {
231 		memcpy(entry->Entries[entry->EntriesNum].Text, msg->Buffer+(54+msg->Buffer[51]*2), msg->Buffer[52]*2);
232 		entry->Entries[entry->EntriesNum].Text[msg->Buffer[52]*2]   = 0;
233 		entry->Entries[entry->EntriesNum].Text[msg->Buffer[52]*2+1] = 0;
234 		entry->Entries[entry->EntriesNum].EntryType		   = CAL_LOCATION;
235 		entry->EntriesNum++;
236 	}
237 
238 	return ERR_NONE;
239 }
240 
N6510_PrivGetGenericCalendar3(GSM_StateMachine * s,int Location,GSM_Phone_RequestID ID)241 static GSM_Error N6510_PrivGetGenericCalendar3(GSM_StateMachine *s, int Location, GSM_Phone_RequestID ID)
242 {
243 	unsigned char req[] = {N6110_FRAME_HEADER,0x7D,0x00,0x00,0x00,0x00,
244 			       0x00,0x99,	/* Location */
245 			       0xff,0xff,0xff,0xff};
246 
247 	req[8] = Location / 256;
248 	req[9] = Location % 256;
249 
250 	return GSM_WaitFor (s, req, 14, 0x13, 4, ID);
251 }
252 
N6510_PrivGetCalendar3(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start,int * LastCalendarYear)253 static GSM_Error N6510_PrivGetCalendar3(GSM_StateMachine *s, GSM_CalendarEntry *Note, gboolean start, int *LastCalendarYear)
254 {
255 	GSM_Error		error;
256 	GSM_DateTime		date_time;
257 
258 	if (start) {
259 		/* We have to get current year. It's NOT written in frame for
260 		 * Birthday
261 		 */
262 		error=s->Phone.Functions->GetDateTime(s,&date_time);
263 		switch (error) {
264 			case ERR_EMPTY:
265 			case ERR_NOTIMPLEMENTED:
266 				GSM_GetCurrentDateTime(&date_time);
267 				break;
268 			case ERR_NONE:
269 				break;
270 			default:
271 				return error;
272 		}
273 		*LastCalendarYear = date_time.Year;
274 	}
275 
276 	Note->EntriesNum		= 0;
277 	Note->Entries[0].Date.Year 	= *LastCalendarYear;
278 
279 	s->Phone.Data.Cal=Note;
280 	smprintf(s, "Getting calendar note method 3\n");
281 	return N6510_PrivGetGenericCalendar3(s, Note->Location, ID_GetCalendarNote);
282 }
283 
284 /* method 3 */
N6510_GetNextCalendar3(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start,GSM_NOKIACalToDoLocations * LastCalendar,int * LastCalendarYear,int * LastCalendarPos)285 static GSM_Error N6510_GetNextCalendar3(GSM_StateMachine *s, GSM_CalendarEntry *Note, gboolean start, GSM_NOKIACalToDoLocations *LastCalendar, int *LastCalendarYear, int *LastCalendarPos)
286 {
287 	GSM_Error error;
288 	gboolean	  start2;
289 
290 	if (start) {
291 		error=N6510_GetCalendarInfo3(s,LastCalendar,0);
292 		if (error!=ERR_NONE) return error;
293 		if (LastCalendar->Number == 0) return ERR_EMPTY;
294 
295 		*LastCalendarPos = 0;
296 	} else {
297 		(*LastCalendarPos)++;
298 	}
299 
300 	error  = ERR_EMPTY;
301 	start2 = start;
302 	while (error == ERR_EMPTY) {
303 		if (*LastCalendarPos >= LastCalendar->Number) return ERR_EMPTY;
304 
305 		Note->Location = LastCalendar->Location[*LastCalendarPos];
306 		error=N6510_PrivGetCalendar3(s, Note, start2, LastCalendarYear);
307 		if (error == ERR_EMPTY) (*LastCalendarPos)++;
308 
309 		start2 = FALSE;
310 	}
311 	return error;
312 }
313 
N6510_ReplyGetCalendarInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)314 GSM_Error N6510_ReplyGetCalendarInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
315 {
316 	switch (msg->Buffer[3]) {
317 	case 0x3B:
318 		/* Old method 1 for accessing calendar */
319 		return N71_65_ReplyGetCalendarInfo1(msg, s, &s->Phone.Data.Priv.N6510.LastCalendar);
320 	case 0x9F:
321 		smprintf(s, "Info with calendar notes locations received method 3\n");
322 		return N6510_ReplyGetCalendarInfo3(msg, s, &s->Phone.Data.Priv.N6510.LastCalendar);
323 	}
324 	return ERR_UNKNOWNRESPONSE;
325 }
326 
327 /* method 3 */
N6510_ReplyGetCalendarNotePos3(GSM_Protocol_Message * msg,GSM_StateMachine * s,int * FirstCalendarPos)328 GSM_Error N6510_ReplyGetCalendarNotePos3(GSM_Protocol_Message *msg, GSM_StateMachine *s,int *FirstCalendarPos)
329 {
330 	smprintf(s, "First calendar location: %i\n",msg->Buffer[8]*256+msg->Buffer[9]);
331 	*FirstCalendarPos = msg->Buffer[8]*256+msg->Buffer[9];
332 	return ERR_NONE;
333 }
334 
335 /* method 3 */
N6510_GetCalendarNotePos3(GSM_StateMachine * s)336 static GSM_Error N6510_GetCalendarNotePos3(GSM_StateMachine *s)
337 {
338 	unsigned char req[] = {N6110_FRAME_HEADER, 0x95, 0x00};
339 
340 	smprintf(s, "Getting first free calendar note location\n");
341 	return GSM_WaitFor (s, req, 5, 0x13, 4, ID_GetCalendarNotePos);
342 }
343 
N6510_ReplyGetCalendarNotePos(GSM_Protocol_Message * msg,GSM_StateMachine * s)344 GSM_Error N6510_ReplyGetCalendarNotePos(GSM_Protocol_Message *msg, GSM_StateMachine *s)
345 {
346 	switch (msg->Buffer[3]) {
347 	case 0xf0:
348 		return ERR_NOTSUPPORTED;
349 	case 0x32:
350 		/* Old method 1 for accessing calendar */
351 		return N71_65_ReplyGetCalendarNotePos1(msg, s,&s->Phone.Data.Priv.N6510.FirstCalendarPos);
352 	case 0x96:
353 		return N6510_ReplyGetCalendarNotePos3(msg, s,&s->Phone.Data.Priv.N6510.FirstCalendarPos);
354 	}
355 	return ERR_UNKNOWNRESPONSE;
356 }
357 
N6510_FindCalendarIconID3(GSM_StateMachine * s,GSM_CalendarEntry * Entry,unsigned char * ID)358 static GSM_Error N6510_FindCalendarIconID3(GSM_StateMachine *s, GSM_CalendarEntry *Entry, unsigned char *ID)
359 {
360 	int 				i,j,LastCalendarYear;
361 	GSM_Phone_N6510Data		*Priv = &s->Phone.Data.Priv.N6510;
362 	GSM_CalendarEntry 		Note;
363 	GSM_NOKIACalToDoLocations	LastCalendar1,LastCalendar2;
364 	GSM_Error			error;
365 	gboolean				found;
366 
367 	for(i=0;i<Priv->CalendarIconsNum;i++) {
368 		if (Priv->CalendarIconsTypes[i] == Entry->Type) {
369 			*ID = Priv->CalendarIcons[i];
370 			return ERR_NONE;
371 		}
372 	}
373 
374 	smprintf(s, "Starting finding note ID\n");
375 
376 	error=N6510_GetCalendarInfo3(s, &Priv->LastCalendar,0);
377 	memcpy(&LastCalendar1,&Priv->LastCalendar,sizeof(GSM_NOKIACalToDoLocations));
378 	if (error != ERR_NONE) return error;
379 
380 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35) ||
381 	    GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65) ||
382 	    GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62)) {
383 		error=N71_65_AddCalendar2(s,Entry);
384 	} else {
385 		/* First method 1 was used for meeting only
386 		 * but it made problems with 6230 RH-12 4.44
387                  * (probably for other Series 40 2.0 phones too)
388                  * For now meeting, call and memo uses method 1
389                  * Please note, that method 1 is the oldest one and in some
390                  * moment Nokia can remove it from firmware
391                  */
392 /* 		if (Entry->Type == GSM_CAL_MEETING) { */
393 		if (Entry->Type == GSM_CAL_MEETING || Entry->Type == GSM_CAL_CALL || Entry->Type == GSM_CAL_MEMO) {
394 			error=N71_65_AddCalendar1(s, Entry, &s->Phone.Data.Priv.N6510.FirstCalendarPos);
395 		} else {
396 			error=N71_65_AddCalendar2(s,Entry);
397 		}
398 	}
399 	if (error != ERR_NONE) return error;
400 
401 	error=N6510_GetCalendarInfo3(s, &Priv->LastCalendar,0);
402 	memcpy(&LastCalendar2,&Priv->LastCalendar,sizeof(GSM_NOKIACalToDoLocations));
403 	if (error != ERR_NONE) return error;
404 
405 	smprintf(s,"Number of entries: %i %i\n",LastCalendar1.Number,LastCalendar2.Number);
406 
407 	for(i=0;i<LastCalendar2.Number;i++) {
408 		found = TRUE;
409 		for(j=0;j<LastCalendar1.Number;j++) {
410 			if (LastCalendar1.Location[j] == LastCalendar2.Location[i]) {
411 				found = FALSE;
412 				break;
413 			}
414 		}
415 		if (found) {
416 			Note.Location = LastCalendar2.Location[i];
417 			error=N6510_PrivGetCalendar3(s, &Note, TRUE, &LastCalendarYear);
418 			if (error != ERR_NONE) return error;
419 
420 			error=N71_65_DelCalendar(s, &Note);
421 			if (error != ERR_NONE) return error;
422 
423 			smprintf(s, "Ending finding note ID\n");
424 
425 			for(j=0;j<Priv->CalendarIconsNum;j++) {
426 				if (Priv->CalendarIconsTypes[j] == Entry->Type) {
427 					*ID = Priv->CalendarIcons[j];
428 					return ERR_NONE;
429 				}
430 			}
431 			return ERR_UNKNOWN;
432 		}
433 	}
434 
435 	return ERR_UNKNOWN;
436 }
437 
438 /* method 3 */
N6510_ReplyAddCalendar3(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)439 GSM_Error N6510_ReplyAddCalendar3(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
440 {
441 	smprintf(s, "Calendar note added\n");
442 	return ERR_NONE;
443 }
444 
445 /* method 3 */
N6510_AddCalendar3(GSM_StateMachine * s,GSM_CalendarEntry * Note,int * FirstCalendarPos)446 static GSM_Error N6510_AddCalendar3(GSM_StateMachine *s, GSM_CalendarEntry *Note, int *FirstCalendarPos)
447 {
448 	GSM_CalendarNoteType	NoteType, OldNoteType;
449 	time_t     		t_time1,t_time2;
450 	long			diff;
451  	GSM_Error		error;
452 	GSM_DateTime		DT,date_time;
453  	int 			Text, Time, Alarm, Phone, EndTime, Location, count=54;
454 	unsigned char 		req[5000] = {
455 		N6110_FRAME_HEADER, 0x65,
456 		0x00,					/* 0 = calendar, 1 = todo 		*/
457 		0x00, 0x00, 0x00,
458 		0x00, 0x00,                             /* location 	    			*/
459 		0x00, 0x00, 0x00, 0x00,
460 		0xFF, 0xFF, 0xFF, 0xFF,			/* alarm 	    			*/
461 		0x80, 0x00, 0x00,
462 		0x01,					/* note icon	    			*/
463 		0xFF, 0xFF, 0xFF, 0xFF,			/* alarm type       			*/
464 		0x00,					/* 0x02 or 0x00     			*/
465 		0x01, 					/* note type	    			*/
466 		0x07, 0xD0, 0x01, 0x12, 0x0C, 0x00, 	/* start date/time  			*/
467 		0x07, 0xD0, 0x01, 0x12, 0x0C, 0x00, 	/* end date/time    			*/
468 		0x00, 0x00,				/* recurrance	    			*/
469 		0x00, 0x00,				/* birth year	    			*/
470 		0x20,					/* ToDo priority 			*/
471 		0x00,					/* ToDo completed ?			*/
472 		0x00, 0x00, 				/* How many times repeat cal note or 0 	*/
473 		0x00,
474 		0x00,					/* note text length 			*/
475 		0x00,					/* phone length/meeting place		*/
476 		0x00, 0x00, 0x00};
477 
478 	error=N6510_GetCalendarNotePos3(s);
479 	if (error!=ERR_NONE) return error;
480 	Note->Location = *FirstCalendarPos;
481 	req[8] = *FirstCalendarPos/256;
482 	req[9] = *FirstCalendarPos%256;
483 
484  	NoteType = N71_65_FindCalendarType(Note->Type, s->Phone.Data.ModelInfo);
485 
486 	switch(NoteType) {
487 		case GSM_CAL_REMINDER 	: req[27]=0x00; req[26]=0x02; break;
488 		case GSM_CAL_MEETING  	: req[27]=0x01; break;
489 		case GSM_CAL_CALL     	: req[27]=0x02; break;
490 		case GSM_CAL_BIRTHDAY 	: req[27]=0x04; break;
491 		case GSM_CAL_MEMO     	: req[27]=0x08; break;
492 		default		  	: return ERR_UNKNOWN;
493 	}
494 
495 	OldNoteType = Note->Type;
496 	Note->Type  = NoteType;
497 	error=N6510_FindCalendarIconID3(s, Note, &req[21]);
498 	Note->Type  = OldNoteType;
499 	if (error!=ERR_NONE) return error;
500 
501 	GSM_CalendarFindDefaultTextTimeAlarmPhone(Note, &Text, &Time, &Alarm, &Phone, &EndTime, &Location);
502 
503 	if (Time == -1) {
504 		smprintf(s,"No time!\n");
505 		return ERR_UNKNOWN;
506 	}
507 	smprintf(s, "Time OK\n");
508 	memcpy(&DT,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
509 	req[28]	= DT.Year / 256;
510 	req[29]	= DT.Year % 256;
511 	req[30]	= DT.Month;
512 	req[31]	= DT.Day;
513 	req[32]	= DT.Hour;
514 	req[33]	= DT.Minute;
515 
516 	if (NoteType == GSM_CAL_BIRTHDAY) {
517 		error=s->Phone.Functions->GetDateTime(s,&date_time);
518 		switch (error) {
519 			case ERR_EMPTY:
520 			case ERR_NOTIMPLEMENTED:
521 				GSM_GetCurrentDateTime(&date_time);
522 				break;
523 			case ERR_NONE:
524 				break;
525 			default:
526 				return error;
527 		}
528 		req[28]	= date_time.Year / 256;
529 		req[29]	= date_time.Year % 256;
530 		if (DT.Year == 0) {
531 			req[42]	= 0xff;
532 			req[43]	= 0xff;
533 		} else {
534 			req[42]	= DT.Year / 256;
535 			req[43]	= DT.Year % 256;
536 		}
537 	}
538 
539 	if (EndTime != -1) memcpy(&DT,&Note->Entries[EndTime].Date,sizeof(GSM_DateTime));
540 
541 	req[34]	= DT.Year / 256;
542 	req[35]	= DT.Year % 256;
543 	req[36]	= DT.Month;
544 	req[37]	= DT.Day;
545 	req[38]	= DT.Hour;
546 	req[39]	= DT.Minute;
547 	if (NoteType == GSM_CAL_BIRTHDAY) {
548 		req[34]	= date_time.Year / 256;
549 		req[35]	= date_time.Year % 256;
550 	}
551 
552 	GSM_SetCalendarRecurranceRepeat(&(s->di), req+40, req+52, Note);
553 
554 	if (Alarm != -1) {
555 		memcpy(&DT,&Note->Entries[Time].Date,sizeof(GSM_DateTime));
556 		if (Note->Entries[Alarm].EntryType == CAL_SILENT_ALARM_DATETIME) {
557 			req[22] = 0x00; req[23] = 0x00; req[24] = 0x00; req[25] = 0x00;
558 		}
559 		if (NoteType == GSM_CAL_BIRTHDAY) DT.Year = date_time.Year;
560 		t_time2   = Fill_Time_T(DT);
561 		t_time1   = Fill_Time_T(Note->Entries[Alarm].Date);
562 		diff	  = (t_time1-t_time2)/60;
563 
564 		smprintf(s, "  Difference : %li seconds or minutes\n", -diff);
565 		req[14] = (unsigned char)(-diff >> 24);
566 		req[15] = (unsigned char)(-diff >> 16);
567 		req[16] = (unsigned char)(-diff >> 8);
568 		req[17] = (unsigned char)(-diff);
569 	}
570 
571 	if (Text != -1) {
572 		req[48] = UnicodeLength(Note->Entries[Text].Text) / 256;
573 		req[49] = UnicodeLength(Note->Entries[Text].Text) % 256;
574 		CopyUnicodeString(req + 54, Note->Entries[Text].Text);
575 		count += req[49] * 2 + (req[48] * 256) * 2;
576 	}
577 
578 	if (Phone != -1 && NoteType == GSM_CAL_CALL) {
579 		req[50] = UnicodeLength(Note->Entries[Phone].Text);
580 		CopyUnicodeString(req+54+req[49]*2,Note->Entries[Phone].Text);
581 		count+= req[50]*2;
582 	}
583 
584 	if (Location != -1 && NoteType == GSM_CAL_MEETING) {
585 		if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62) ||
586 		    GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL65) ||
587 		    GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL35)) {
588 		} else {
589 			req[50] = UnicodeLength(Note->Entries[Location].Text);
590 			CopyUnicodeString(req+54+req[49]*2,Note->Entries[Location].Text);
591 			count+= req[50]*2;
592 		}
593 	}
594 
595 	req[count++] = 0x00;
596 
597 	smprintf(s, "Writing calendar note method 3\n");
598 	return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetCalendarNote);
599 }
600 
N6510_GetNextCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note,gboolean start)601 GSM_Error N6510_GetNextCalendar(GSM_StateMachine *s,  GSM_CalendarEntry *Note, gboolean start)
602 {
603 #ifdef GSM_FORCE_DCT4_CALENDAR_6210
604     	/* Method 1. Some features missed. Not working with some notes in 3510 */
605 	return N71_65_GetNextCalendar1(s,Note,start,&s->Phone.Data.Priv.N6510.LastCalendar,&s->Phone.Data.Priv.N6510.LastCalendarYear,&s->Phone.Data.Priv.N6510.LastCalendarPos);
606 #endif
607 
608 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62)) {
609 		/* Method 1. Some features missed. Not working with some notes in 3510 */
610 		return N71_65_GetNextCalendar1(s,Note,start,&s->Phone.Data.Priv.N6510.LastCalendar,&s->Phone.Data.Priv.N6510.LastCalendarYear,&s->Phone.Data.Priv.N6510.LastCalendarPos);
611 
612 	    	/* Method 2. In known phones texts of notes cut to 50 chars. Some features missed */
613 /* 		return N71_65_GetNextCalendar2(s,Note,start,&s->Phone.Data.Priv.N6510.LastCalendarYear,&s->Phone.Data.Priv.N6510.LastCalendarPos); */
614 	} else {
615 	    	/* Method 3. All DCT4 features supported. Not supported by 8910 */
616 	    	return N6510_GetNextCalendar3(s,Note,start,&s->Phone.Data.Priv.N6510.LastCalendar,&s->Phone.Data.Priv.N6510.LastCalendarYear,&s->Phone.Data.Priv.N6510.LastCalendarPos);
617 	}
618 }
619 
N6510_GetCalendarStatus(GSM_StateMachine * s,GSM_CalendarStatus * Status)620 GSM_Error N6510_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
621 {
622 	GSM_Error error;
623 
624 #ifdef GSM_FORCE_DCT4_CALENDAR_6210
625         /* Method 1 */
626 	error=N71_65_GetCalendarInfo1(s, &s->Phone.Data.Priv.N6510.LastCalendar);
627 	if (error!=ERR_NONE) return error;
628 	Status->Used = s->Phone.Data.Priv.N6510.LastCalendar.Number;
629 	return ERR_NONE;
630 #endif
631 
632 	/**
633 	 * @todo This should be acquired from phone
634 	 */
635 	Status->Free = 100;
636 
637 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62)) {
638 	        /* Method 1 */
639 		error=N71_65_GetCalendarInfo1(s, &s->Phone.Data.Priv.N6510.LastCalendar);
640 		if (error!=ERR_NONE) return error;
641 		Status->Used = s->Phone.Data.Priv.N6510.LastCalendar.Number;
642 		return ERR_NONE;
643 
644 	    	/* Method 2 */
645 /* 		return ERR_NOTSUPPORTED; */
646 	} else {
647 		/* Method 3 */
648 		error=N6510_GetCalendarInfo3(s,&s->Phone.Data.Priv.N6510.LastCalendar,0);
649 		if (error!=ERR_NONE) return error;
650 		Status->Used = s->Phone.Data.Priv.N6510.LastCalendar.Number;
651 		return ERR_NONE;
652 	}
653 }
654 
N6510_AddCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Note)655 GSM_Error N6510_AddCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Note)
656 {
657 #ifdef GSM_FORCE_DCT4_CALENDAR_6210
658 	return N71_65_AddCalendar2(s,Note);
659 #endif
660 
661 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_CAL62)) {
662 		return N71_65_AddCalendar2(s,Note);
663 /* 		return N71_65_AddCalendar1(s, Note, &s->Phone.Data.Priv.N6510.FirstCalendarPos); */
664 	} else {
665 		/* Method 3. All DCT4 features supported. Not supported by 8910 */
666 		return N6510_AddCalendar3(s, Note, &s->Phone.Data.Priv.N6510.FirstCalendarPos);
667 	}
668 }
669 
N6510_ReplyGetNoteInfo(GSM_Protocol_Message * msg,GSM_StateMachine * s)670 GSM_Error N6510_ReplyGetNoteInfo(GSM_Protocol_Message *msg, GSM_StateMachine *s)
671 {
672 	return N6510_ReplyGetCalendarInfo3(msg, s, &s->Phone.Data.Priv.N6510.LastNote);
673 }
674 
N6510_ReplyGetNote(GSM_Protocol_Message * msg,GSM_StateMachine * s)675 GSM_Error N6510_ReplyGetNote(GSM_Protocol_Message *msg, GSM_StateMachine *s)
676 {
677 	int len;
678 
679 	smprintf(s, "Note received\n");
680 	len = msg->Buffer[50] * 256 + msg->Buffer[51];
681 	if (len > GSM_MAX_NOTE_TEXT_LENGTH) {
682 		smprintf(s, "Note too long (%d), truncating to %d\n", len, GSM_MAX_NOTE_TEXT_LENGTH);
683 		len = GSM_MAX_NOTE_TEXT_LENGTH;
684 	}
685 	memcpy(s->Phone.Data.Note->Text,
686 		msg->Buffer + 54,
687 		len * 2);
688 	s->Phone.Data.Note->Text[len * 2] = 0;
689 	s->Phone.Data.Note->Text[(len * 2) + 1] = 0;
690 	return ERR_NONE;
691 }
692 
N6510_GetNextNote(GSM_StateMachine * s,GSM_NoteEntry * Note,gboolean start)693 GSM_Error N6510_GetNextNote(GSM_StateMachine *s, GSM_NoteEntry *Note, gboolean start)
694 {
695 	GSM_Error 			error;
696 	GSM_NOKIACalToDoLocations	*LastNote = &s->Phone.Data.Priv.N6510.LastNote;
697 
698 	if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NOTES)) return ERR_NOTSUPPORTED;
699 
700 	if (start) {
701 		error=N6510_GetCalendarInfo3(s,LastNote,2);
702 		if (error!=ERR_NONE) return error;
703 		Note->Location = 1;
704 	} else {
705 		Note->Location++;
706 	}
707 
708 	if (Note->Location > LastNote->Number) return ERR_EMPTY;
709 
710 	s->Phone.Data.Note = Note;
711 	smprintf(s, "Getting note\n");
712 	return N6510_PrivGetGenericCalendar3(s, LastNote->Location[Note->Location-1], ID_GetNote);
713 }
714 
N6510_DeleteNote(GSM_StateMachine * s,GSM_NoteEntry * Not)715 GSM_Error N6510_DeleteNote(GSM_StateMachine *s, GSM_NoteEntry *Not)
716 {
717 	GSM_Error 			error;
718 	GSM_NOKIACalToDoLocations	*LastNote = &s->Phone.Data.Priv.N6510.LastNote;
719 	GSM_CalendarEntry		Note;
720 
721 	if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_NOTES)) return ERR_NOTSUPPORTED;
722 
723 	error=N6510_GetCalendarInfo3(s,LastNote,2);
724 	if (error!=ERR_NONE) return error;
725 
726 	smprintf(s, "Deleting Note\n");
727 
728 	if (Not->Location > LastNote->Number || Not->Location == 0) return ERR_INVALIDLOCATION;
729 
730 	Note.Location = LastNote->Location[Not->Location-1];
731 	return N71_65_DelCalendar(s,&Note);
732 }
733 
N6510_ReplyGetNoteFirstLoc(GSM_Protocol_Message * msg,GSM_StateMachine * s)734 GSM_Error N6510_ReplyGetNoteFirstLoc(GSM_Protocol_Message *msg, GSM_StateMachine *s)
735 {
736 	smprintf(s, "First Note location: %i\n",msg->Buffer[8]*256+msg->Buffer[9]);
737 	s->Phone.Data.Note->Location = msg->Buffer[8]*256+msg->Buffer[9];
738 	return ERR_NONE;
739 }
740 
N6510_ReplyAddNote(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)741 GSM_Error N6510_ReplyAddNote(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
742 {
743 	smprintf(s, "Note added\n");
744 	return ERR_NONE;
745 }
746 
N6510_AddNote(GSM_StateMachine * s,GSM_NoteEntry * Not)747 GSM_Error N6510_AddNote(GSM_StateMachine *s, GSM_NoteEntry *Not)
748 {
749 	GSM_Error		error;
750 	int 			count=54;
751 	unsigned char 		reqLoc[] = {N6110_FRAME_HEADER, 0x95,
752 					    0x02};	/* 1 = todo, 2 = note */
753 	unsigned char 		req[GSM_MAX_NOTE_TEXT_LENGTH + 500] = {
754 		N6110_FRAME_HEADER, 0x65,
755 		0x02,					/* 0 = calendar, 1 = todo, 2 = note 	*/
756 		0x00, 0x00, 0x00,
757 		0x00, 0x00,                             /* location 	    			*/
758 		0x00, 0x00, 0x00, 0x00,
759 		0xFF, 0xFF, 0xFF, 0xFF,			/* alarm 	    			*/
760 		0x80, 0x00, 0x00,
761 		0xA9,					/* note icon	    			*/
762 		0x00, 0x00, 0x00, 0x00,			/* alarm type       			*/
763 		0x00,					/* 0x02 or 0x00     			*/
764 		0x80, 					/* note type	    			*/
765 		0x07, 0xD2, 0x01, 0x01, 0x00, 0x00, 	/* start date/time  			*/
766 		0x07, 0xD2, 0x01, 0x11, 0x00, 0x00, 	/* end date/time    			*/
767 		0x00, 0x00,				/* recurrance	    			*/
768 		0xFF, 0xFF,				/* birth year	    			*/
769 		0x00,					/* ToDo priority 			*/
770 		0x00,					/* ToDo completed ?			*/
771 		0x00, 0x00, 0x00,
772 		0x00,					/* note text length 			*/
773 		0x00,					/* phone length/meeting place		*/
774 		0x00, 0x00, 0x00};
775 	size_t length;
776 
777 	s->Phone.Data.Note = Not;
778 
779 	smprintf(s, "Getting first free Note location\n");
780 	error = GSM_WaitFor (s, reqLoc, 5, 0x13, 4, ID_SetNote);
781 	if (error!=ERR_NONE) return error;
782 	req[8] = Not->Location / 256;
783 	req[9] = Not->Location % 256;
784 
785 	length = UnicodeLength(Not->Text);
786 	req[48] = length / 256;
787 	req[49] = length % 256;
788 	CopyUnicodeString(req + 54, Not->Text);
789 	count += length * 2;
790 
791 	req[count++] = 0x00;
792 
793 	smprintf(s, "Adding Note\n");
794 	return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetNote);
795 }
796 
N6510_GetNoteStatus(GSM_StateMachine * s,GSM_ToDoStatus * status)797 GSM_Error N6510_GetNoteStatus(GSM_StateMachine *s, GSM_ToDoStatus *status)
798 {
799 	GSM_NOKIACalToDoLocations	*LastNote = &s->Phone.Data.Priv.N6510.LastNote;
800 	GSM_Error			error;
801 
802 	error = N6510_GetCalendarInfo3(s,LastNote,2);
803 	if (error!=ERR_NONE) return error;
804 
805 	status->Used = LastNote->Number;
806 	return ERR_NONE;
807 }
808 
809 /* ToDo support - 6310 style */
N6510_ReplyGetToDoStatus1(GSM_Protocol_Message * msg,GSM_StateMachine * s)810 GSM_Error N6510_ReplyGetToDoStatus1(GSM_Protocol_Message *msg, GSM_StateMachine *s)
811 {
812 	int				i;
813 	GSM_NOKIACalToDoLocations	*Last = &s->Phone.Data.Priv.N6510.LastToDo;
814 
815 	smprintf(s, "TODO locations received\n");
816 	Last->Number=msg->Buffer[6]*256+msg->Buffer[7];
817 	smprintf(s, "Number of Entries: %i\n",Last->Number);
818 	smprintf(s, "Locations: ");
819 	for (i=0;i<Last->Number;i++) {
820 		Last->Location[i]=msg->Buffer[12+(i*4)]*256+msg->Buffer[(i*4)+13];
821 		smprintf(s, "%i ",Last->Location[i]);
822 	}
823 	smprintf(s, "\n");
824 	return ERR_NONE;
825 }
826 
827 /* ToDo support - 6310 style */
N6510_GetToDoStatus1(GSM_StateMachine * s,GSM_ToDoStatus * status)828 static GSM_Error N6510_GetToDoStatus1(GSM_StateMachine *s, GSM_ToDoStatus *status)
829 {
830 	GSM_Error 			error;
831 	GSM_NOKIACalToDoLocations	*LastToDo = &s->Phone.Data.Priv.N6510.LastToDo;
832 	unsigned char reqLoc[] = {
833 			N6110_FRAME_HEADER,
834 			0x15, 0x01, 0x00, 0x00,
835 			0x00, 0x00, 0x00};
836 
837 	smprintf(s, "Getting ToDo locations\n");
838 	error = GSM_WaitFor (s, reqLoc, 10, 0x55, 4, ID_GetToDo);
839 	if (error != ERR_NONE) return error;
840 
841 	status->Used = LastToDo->Number;
842 	/**
843 	 * @todo This should be acquired from phone
844 	 */
845 	status->Free = 100;
846 	return ERR_NONE;
847 }
848 
N6510_GetToDoStatus2(GSM_StateMachine * s,GSM_ToDoStatus * status)849 static GSM_Error N6510_GetToDoStatus2(GSM_StateMachine *s, GSM_ToDoStatus *status)
850 {
851 	GSM_NOKIACalToDoLocations	*LastToDo = &s->Phone.Data.Priv.N6510.LastToDo;
852 	GSM_Error			error;
853 
854 	error = N6510_GetCalendarInfo3(s,LastToDo,1);
855 	if (error!=ERR_NONE) return error;
856 
857 	status->Used = LastToDo->Number;
858 	/**
859 	 * @todo This should be acquired from phone
860 	 */
861 	status->Free = 100;
862 	return ERR_NONE;
863 }
864 
N6510_GetToDoStatus(GSM_StateMachine * s,GSM_ToDoStatus * status)865 GSM_Error N6510_GetToDoStatus(GSM_StateMachine *s, GSM_ToDoStatus *status)
866 {
867 	status->Used = 0;
868 
869 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO63)) {
870 		return N6510_GetToDoStatus1(s, status);
871 	} else if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO66)) {
872 		return N6510_GetToDoStatus2(s, status);
873 	} else {
874 		return ERR_NOTSUPPORTED;
875 	}
876 }
877 
878 /* ToDo support - 6310 style */
N6510_ReplyGetToDo1(GSM_Protocol_Message * msg,GSM_StateMachine * s)879 GSM_Error N6510_ReplyGetToDo1(GSM_Protocol_Message *msg, GSM_StateMachine *s)
880 {
881 	GSM_ToDoEntry *Last = s->Phone.Data.ToDo;
882 
883 	smprintf(s, "TODO received method 1\n");
884 
885 	/**
886 	 * @todo There might be better type.
887 	 */
888 	Last->Type = GSM_CAL_MEMO;
889 
890 	switch (msg->Buffer[4]) {
891 		case 1  : Last->Priority = GSM_Priority_High; 	break;
892 		case 2  : Last->Priority = GSM_Priority_Medium; break;
893 		case 3  : Last->Priority = GSM_Priority_Low; 	break;
894 		default	: return ERR_UNKNOWN;
895 	}
896 	smprintf(s, "Priority: %i\n",msg->Buffer[4]);
897 
898 	CopyUnicodeString(Last->Entries[0].Text,msg->Buffer+14);
899  	Last->Entries[0].EntryType = TODO_TEXT;
900 	Last->EntriesNum		 = 1;
901 	smprintf(s, "Text: \"%s\"\n",DecodeUnicodeString(Last->Entries[0].Text));
902 
903 	return ERR_NONE;
904 }
905 
906 /* ToDo support - 6310 style */
N6510_GetNextToDo1(GSM_StateMachine * s,GSM_ToDoEntry * ToDo,gboolean refresh)907 static GSM_Error N6510_GetNextToDo1(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, gboolean refresh)
908 {
909 	GSM_Error 			error;
910 	GSM_ToDoStatus 			status;
911 	GSM_NOKIACalToDoLocations	*LastToDo = &s->Phone.Data.Priv.N6510.LastToDo;
912 	unsigned char reqGet[] = {
913 			N6110_FRAME_HEADER,
914 			0x03, 0x00, 0x00, 0x80, 0x00,
915 			0x00, 0x17};		/* Location */
916 
917 	if (refresh) {
918 		error = N6510_GetToDoStatus(s, &status);
919 		if (error != ERR_NONE) return error;
920 		ToDo->Location = 1;
921 	} else {
922 		ToDo->Location++;
923 	}
924 	if (ToDo->Location > LastToDo->Number) return ERR_EMPTY;
925 
926 	reqGet[8] = LastToDo->Location[ToDo->Location-1] / 256;
927 	reqGet[9] = LastToDo->Location[ToDo->Location-1] % 256;
928 	s->Phone.Data.ToDo = ToDo;
929 	smprintf(s, "Getting ToDo\n");
930 	return GSM_WaitFor (s, reqGet, 10, 0x55, 4, ID_GetToDo);
931 }
932 
N6510_ReplyGetToDoStatus2(GSM_Protocol_Message * msg,GSM_StateMachine * s)933 GSM_Error N6510_ReplyGetToDoStatus2(GSM_Protocol_Message *msg, GSM_StateMachine *s)
934 {
935 	return N6510_ReplyGetCalendarInfo3(msg, s, &s->Phone.Data.Priv.N6510.LastToDo);
936 }
937 
938 /* Similiar to getting calendar method 3 */
N6510_ReplyGetToDo2(GSM_Protocol_Message * msg,GSM_StateMachine * s)939 GSM_Error N6510_ReplyGetToDo2(GSM_Protocol_Message *msg, GSM_StateMachine *s)
940 {
941 	GSM_ToDoEntry 		*Last = s->Phone.Data.ToDo;
942 	GSM_DateTime		Date;
943 	unsigned long		diff;
944 	int len;
945 
946 	smprintf(s, "ToDo received method 2\n");
947 
948 	/**
949 	 * @todo There might be better type.
950 	 */
951 	Last->Type = GSM_CAL_MEMO;
952 
953 	switch (msg->Buffer[44]) {
954 		case 0x10: Last->Priority = GSM_Priority_Low; 		break;
955 		case 0x20: Last->Priority = GSM_Priority_Medium; 	break;
956 		case 0x30: Last->Priority = GSM_Priority_High; 		break;
957 		default	 : return ERR_UNKNOWN;
958 	}
959 
960 	len = msg->Buffer[50] * 256 + msg->Buffer[51];
961 	if (len > GSM_MAX_TODO_TEXT_LENGTH) {
962 		smprintf(s, "Todo text too long (%d), truncating to %d\n", len, GSM_MAX_TODO_TEXT_LENGTH);
963 		len = GSM_MAX_TODO_TEXT_LENGTH;
964 	}
965 	memcpy(Last->Entries[0].Text,
966 		msg->Buffer + 54,
967 		len * 2);
968 	Last->Entries[0].Text[len * 2] = 0;
969 	Last->Entries[0].Text[(len * 2) + 1] = 0;
970     	Last->Entries[0].EntryType = TODO_TEXT;
971 	smprintf(s, "Text: \"%s\"\n",DecodeUnicodeString(Last->Entries[0].Text));
972 
973 	smprintf(s,"EndTime: %04i-%02i-%02i %02i:%02i\n",
974 		msg->Buffer[34]*256+msg->Buffer[35],
975 		msg->Buffer[36],msg->Buffer[37],msg->Buffer[38],
976 		msg->Buffer[39]);
977 	Date.Year 	= msg->Buffer[34]*256+msg->Buffer[35];
978 	Date.Month 	= msg->Buffer[36];
979 	Date.Day 	= msg->Buffer[37];
980 	Date.Hour 	= msg->Buffer[38];
981 	Date.Minute 	= msg->Buffer[39];
982 	Date.Second	= 0;
983 	Date.Timezone	= 0;
984 	Last->Entries[1].EntryType = TODO_END_DATETIME;
985 	memcpy(&Last->Entries[1].Date, &Date, sizeof(GSM_DateTime));
986 
987 	smprintf(s,"StartTime: %04i-%02i-%02i %02i:%02i\n",
988 		msg->Buffer[28]*256+msg->Buffer[29],
989 		msg->Buffer[30],msg->Buffer[31],msg->Buffer[32],
990 		msg->Buffer[33]);
991 	Date.Year 	= msg->Buffer[28]*256+msg->Buffer[29];
992 	Date.Month 	= msg->Buffer[30];
993 	Date.Day 	= msg->Buffer[31];
994 	Date.Hour 	= msg->Buffer[32];
995 	Date.Minute 	= msg->Buffer[33];
996 	Date.Second	= 0;
997 	Date.Timezone	= 0;
998 
999 	Last->EntriesNum = 2;
1000 
1001 	if (msg->Buffer[45] == 0x01) {
1002 		Last->Entries[2].Number		= msg->Buffer[45];
1003 	    	Last->Entries[2].EntryType 	= TODO_COMPLETED;
1004 		Last->EntriesNum++;
1005 		smprintf(s,"Completed\n");
1006 	}
1007 
1008 	if (msg->Buffer[14] == 0xFF && msg->Buffer[15] == 0xFF && msg->Buffer[16] == 0xff && msg->Buffer[17] == 0xff) {
1009 		smprintf(s, "No alarm\n");
1010 	} else {
1011 		diff  = ((unsigned int)msg->Buffer[14]) << 24;
1012 		diff += ((unsigned int)msg->Buffer[15]) << 16;
1013 		diff += ((unsigned int)msg->Buffer[16]) << 8;
1014 		diff += msg->Buffer[17];
1015 
1016 		memcpy(&Last->Entries[Last->EntriesNum].Date,&Date,sizeof(GSM_DateTime));
1017 		GetTimeDifference(diff, &Last->Entries[Last->EntriesNum].Date, FALSE, 60);
1018 		smprintf(s, "Alarm date   : %02i-%02i-%04i %02i:%02i:%02i\n",
1019 			Last->Entries[Last->EntriesNum].Date.Day,   Last->Entries[Last->EntriesNum].Date.Month,
1020 			Last->Entries[Last->EntriesNum].Date.Year,  Last->Entries[Last->EntriesNum].Date.Hour,
1021 			Last->Entries[Last->EntriesNum].Date.Minute,Last->Entries[Last->EntriesNum].Date.Second);
1022 
1023 		Last->Entries[Last->EntriesNum].EntryType = TODO_ALARM_DATETIME;
1024 		if (msg->Buffer[22]==0x00 && msg->Buffer[23]==0x00 &&
1025 		    msg->Buffer[24]==0x00 && msg->Buffer[25]==0x00)
1026 		{
1027 			Last->Entries[Last->EntriesNum].EntryType = TODO_SILENT_ALARM_DATETIME;
1028 			smprintf(s, "Alarm type   : Silent\n");
1029 		}
1030 		Last->EntriesNum++;
1031 	}
1032 
1033 	return ERR_NONE;
1034 }
1035 
1036 /* ToDo support - 6610 style */
N6510_GetNextToDo2(GSM_StateMachine * s,GSM_ToDoEntry * ToDo,gboolean refresh)1037 static GSM_Error N6510_GetNextToDo2(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, gboolean refresh)
1038 {
1039 	GSM_Error 			error;
1040 	GSM_NOKIACalToDoLocations	*LastToDo = &s->Phone.Data.Priv.N6510.LastToDo;
1041 
1042 	if (refresh) {
1043 		error=N6510_GetCalendarInfo3(s,LastToDo,1);
1044 		if (error!=ERR_NONE) return error;
1045 		ToDo->Location = 1;
1046 	} else {
1047 		ToDo->Location++;
1048 	}
1049 
1050 	if (ToDo->Location > LastToDo->Number) return ERR_EMPTY;
1051 
1052 	s->Phone.Data.ToDo = ToDo;
1053 	smprintf(s, "Getting todo method 2\n");
1054 	return N6510_PrivGetGenericCalendar3(s, LastToDo->Location[ToDo->Location-1], ID_GetToDo);
1055 }
1056 
N6510_GetNextToDo(GSM_StateMachine * s,GSM_ToDoEntry * ToDo,gboolean refresh)1057 GSM_Error N6510_GetNextToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo, gboolean refresh)
1058 {
1059 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO63)) {
1060 		return N6510_GetNextToDo1(s, ToDo, refresh);
1061 	} else if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO66)) {
1062 		return N6510_GetNextToDo2(s, ToDo, refresh);
1063 	} else {
1064 		return ERR_NOTSUPPORTED;
1065 	}
1066 }
1067 
1068 /* ToDo support - 6310 style */
N6510_ReplyDeleteAllToDo1(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1069 GSM_Error N6510_ReplyDeleteAllToDo1(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1070 {
1071 	smprintf(s, "All TODO deleted\n");
1072 	return ERR_NONE;
1073 }
1074 
1075 /* ToDo support - 6310 style */
N6510_DeleteAllToDo1(GSM_StateMachine * s)1076 GSM_Error N6510_DeleteAllToDo1(GSM_StateMachine *s)
1077 {
1078 	unsigned char req[] = {N6110_FRAME_HEADER, 0x11};
1079 
1080 	if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO63)) {
1081 		return ERR_NOTSUPPORTED;
1082 	}
1083 
1084 	smprintf(s, "Deleting all ToDo method 1\n");
1085 	return GSM_WaitFor (s, req, 4, 0x55, 4, ID_DeleteAllToDo);
1086 }
1087 
N6510_DeleteToDo2(GSM_StateMachine * s,GSM_ToDoEntry * ToDo)1088 GSM_Error N6510_DeleteToDo2(GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
1089 {
1090 	GSM_Error 			error;
1091 	GSM_NOKIACalToDoLocations	*LastToDo = &s->Phone.Data.Priv.N6510.LastToDo;
1092 	GSM_CalendarEntry		Note;
1093 
1094 	if (!GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO66)) {
1095 		return ERR_NOTSUPPORTED;
1096 	}
1097 
1098 	error=N6510_GetCalendarInfo3(s,LastToDo,1);
1099 	if (error!=ERR_NONE) return error;
1100 
1101 	smprintf(s, "Deleting ToDo method 2\n");
1102 
1103 	if (ToDo->Location > LastToDo->Number || ToDo->Location == 0) return ERR_INVALIDLOCATION;
1104 
1105 	Note.Location = LastToDo->Location[ToDo->Location-1];
1106 	return N71_65_DelCalendar(s,&Note);
1107 }
1108 
1109 /* ToDo support - 6310 style */
N6510_ReplyGetToDoFirstLoc1(GSM_Protocol_Message * msg,GSM_StateMachine * s)1110 GSM_Error N6510_ReplyGetToDoFirstLoc1(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1111 {
1112 	smprintf(s, "TODO first location received method 1: %02x\n",msg->Buffer[9]);
1113 	s->Phone.Data.ToDo->Location = msg->Buffer[9];
1114 	return ERR_NONE;
1115 }
1116 
1117 /* ToDo support - 6310 style */
N6510_ReplyAddToDo1(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1118 GSM_Error N6510_ReplyAddToDo1(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1119 {
1120 	smprintf(s, "TODO set OK\n");
1121 	return ERR_NONE;
1122 }
1123 
1124 /* ToDo support - 6310 style */
N6510_AddToDo1(GSM_StateMachine * s,GSM_ToDoEntry * ToDo)1125 static GSM_Error N6510_AddToDo1(GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
1126 {
1127  	int 			Text, Alarm, EndTime, Completed, ulen, Phone;
1128 	GSM_Error		error;
1129 	unsigned char 		reqLoc[] 	= {N6110_FRAME_HEADER, 0x0F};
1130 	unsigned char 		reqSet[500] 	= {
1131 		N6110_FRAME_HEADER, 0x01,
1132 		0x03,		/* Priority */
1133 		0x00,		/* Length of text */
1134 		0x80,0x00,0x00,
1135 		0x18};		/* Location */
1136 
1137 	s->Phone.Data.ToDo = ToDo;
1138 
1139 	smprintf(s, "Getting first ToDo location\n");
1140 	error = GSM_WaitFor (s, reqLoc, 4, 0x55, 4, ID_SetToDo);
1141 	if (error != ERR_NONE) return error;
1142 	reqSet[9] = ToDo->Location;
1143 
1144 	switch (ToDo->Priority) {
1145 		case GSM_Priority_Low	: reqSet[4] = 3; break;
1146 		case GSM_Priority_Medium: reqSet[4] = 2; break;
1147 		case GSM_Priority_High	: reqSet[4] = 1; break;
1148 		default: break;
1149 	}
1150 
1151 	GSM_ToDoFindDefaultTextTimeAlarmCompleted(ToDo, &Text, &Alarm, &Completed, &EndTime, &Phone);
1152 
1153     	if (Text == -1) return ERR_NOTSUPPORTED; /* XXX: shouldn't this be handled different way? */
1154     	ulen = UnicodeLength(ToDo->Entries[Text].Text);
1155 	reqSet[5] = ulen+1;
1156 	CopyUnicodeString(reqSet+10,ToDo->Entries[Text].Text);
1157 	reqSet[10+ulen*2] 	= 0x00;
1158 	reqSet[10+ulen*2+1] 	= 0x00;
1159 	smprintf(s, "Adding ToDo method 1\n");
1160 	return GSM_WaitFor (s, reqSet, 12+ulen*2, 0x55, 4, ID_SetToDo);
1161 }
1162 
N6510_ReplyAddToDo2(GSM_Protocol_Message * msg UNUSED,GSM_StateMachine * s)1163 GSM_Error N6510_ReplyAddToDo2(GSM_Protocol_Message *msg UNUSED, GSM_StateMachine *s)
1164 {
1165 	smprintf(s, "ToDo added method 2\n");
1166 	return ERR_NONE;
1167 }
1168 
N6510_ReplyGetToDoFirstLoc2(GSM_Protocol_Message * msg,GSM_StateMachine * s)1169 GSM_Error N6510_ReplyGetToDoFirstLoc2(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1170 {
1171 	smprintf(s, "First ToDo location method 2: %i\n",msg->Buffer[8]*256+msg->Buffer[9]);
1172 	s->Phone.Data.ToDo->Location = msg->Buffer[8]*256+msg->Buffer[9];
1173 	return ERR_NONE;
1174 }
1175 
N6510_AddToDo2(GSM_StateMachine * s,GSM_ToDoEntry * ToDo)1176 static GSM_Error N6510_AddToDo2(GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
1177 {
1178 	GSM_CalendarEntry	Note;
1179 	time_t     		t_time1,t_time2;
1180 	long			diff;
1181  	GSM_Error		error;
1182 	GSM_DateTime		DT;
1183  	int 			Text, Alarm, EndTime, Completed, count=54, Phone;
1184 	unsigned char 		reqLoc[] = {N6110_FRAME_HEADER, 0x95,
1185 					    0x01};	/* 1 = todo, 2 = note */
1186 	unsigned char 		req[GSM_MAX_TODO_TEXT_LENGTH + 500] = {
1187 		N6110_FRAME_HEADER, 0x65,
1188 		0x01,					/* 0 = calendar, 1 = todo 		*/
1189 		0x00, 0x00, 0x00,
1190 		0x00, 0x00,                             /* location 	    			*/
1191 		0x00, 0x00, 0x00, 0x00,
1192 		0xFF, 0xFF, 0xFF, 0xFF,			/* alarm 	    			*/
1193 		0x80, 0x00, 0x00,
1194 		0x01,					/* note icon	    			*/
1195 		0xFF, 0xFF, 0xFF, 0xFF,			/* alarm type       			*/
1196 		0x00,					/* 0x02 or 0x00     			*/
1197 		0x01, 					/* note type	    			*/
1198 		0x07, 0xD0, 0x01, 0x12, 0x0C, 0x00, 	/* start date/time  			*/
1199 		0x07, 0xD0, 0x01, 0x12, 0x0C, 0x00, 	/* end date/time    			*/
1200 		0x00, 0x00,				/* recurrance	    			*/
1201 		0x00, 0x00,				/* birth year	    			*/
1202 		0x20,					/* ToDo priority 			*/
1203 		0x00,					/* ToDo completed ?			*/
1204 		0x00, 0x00, 				/* How many times repeat cal note or 0 	*/
1205 		0x00,
1206 		0x00,					/* note text length 			*/
1207 		0x00,					/* phone length/meeting place		*/
1208 		0x00, 0x00, 0x00};
1209 
1210 	s->Phone.Data.ToDo = ToDo;
1211 
1212 	smprintf(s, "Getting first free ToDo location method 2\n");
1213 	error = GSM_WaitFor (s, reqLoc, 5, 0x13, 4, ID_SetToDo);
1214 	if (error!=ERR_NONE) return error;
1215 	req[8] = ToDo->Location/256;
1216 	req[9] = ToDo->Location%256;
1217 
1218 	Note.Type = GSM_CAL_MEETING;
1219 	DT.Year = 2004; DT.Month  = 1; 	DT.Day 	  = 1;
1220 	DT.Hour = 12; 	DT.Minute = 12; DT.Second = 0;
1221 	DT.Timezone = 0;
1222 	memcpy(&Note.Entries[0].Date,&DT,sizeof(GSM_DateTime));
1223 	Note.Entries[0].EntryType 	= CAL_START_DATETIME;
1224 	memcpy(&Note.Entries[1].Date,&DT,sizeof(GSM_DateTime));
1225 	Note.Entries[1].EntryType 	= CAL_END_DATETIME;
1226 	EncodeUnicode(Note.Entries[2].Text,"ala",3);
1227 	Note.Entries[2].EntryType 	= CAL_TEXT;
1228 	Note.EntriesNum 		= 3;
1229 	error=N6510_FindCalendarIconID3(s, &Note, &req[21]);
1230 	if (error!=ERR_NONE) return error;
1231 
1232 	switch (ToDo->Priority) {
1233 		case GSM_Priority_Low	: req[44] = 0x10; break;
1234 		case GSM_Priority_Medium: req[44] = 0x20; break;
1235 		case GSM_Priority_High	: req[44] = 0x30; break;
1236 		default: break;
1237 	}
1238 
1239 	GSM_ToDoFindDefaultTextTimeAlarmCompleted(ToDo, &Text, &Alarm, &Completed, &EndTime, &Phone);
1240 
1241 	if (Completed != -1) req[45] = 0x01;
1242 
1243 	if (EndTime == -1) {
1244 		GSM_GetCurrentDateTime(&DT);
1245 	} else {
1246 		memcpy(&DT,&ToDo->Entries[EndTime].Date,sizeof(GSM_DateTime));
1247 	}
1248 	/*Start time*/
1249 	req[28]	= DT.Year / 256;
1250 	req[29]	= DT.Year % 256;
1251 	req[30]	= DT.Month;
1252 	req[31]	= DT.Day;
1253 	req[32]	= DT.Hour;
1254 	req[33]	= DT.Minute;
1255 	/*End time*/
1256 	req[34]	= DT.Year / 256;
1257 	req[35]	= DT.Year % 256;
1258 	req[36]	= DT.Month;
1259 	req[37]	= DT.Day;
1260 	req[38]	= DT.Hour;
1261 	req[39]	= DT.Minute;
1262 
1263 	if (Alarm != -1) {
1264 		if (ToDo->Entries[Alarm].EntryType == TODO_SILENT_ALARM_DATETIME)
1265 		{
1266 			req[22] = 0x00; req[23] = 0x00; req[24] = 0x00; req[25] = 0x00;
1267 		}
1268 		t_time2   = Fill_Time_T(DT);
1269 		t_time1   = Fill_Time_T(ToDo->Entries[Alarm].Date);
1270 		diff	  = (t_time1-t_time2)/60;
1271 
1272 		smprintf(s, "  Difference : %li seconds or minutes\n", -diff);
1273 		req[14] = (unsigned char)(-diff >> 24);
1274 		req[15] = (unsigned char)(-diff >> 16);
1275 		req[16] = (unsigned char)(-diff >> 8);
1276 		req[17] = (unsigned char)(-diff);
1277 	}
1278 
1279 	if (Text != -1) {
1280 		req[48] = UnicodeLength(ToDo->Entries[Text].Text) / 256;
1281 		req[49] = UnicodeLength(ToDo->Entries[Text].Text) % 256;
1282 		CopyUnicodeString(req + 54, ToDo->Entries[Text].Text);
1283 		count += req[49] * 2 + (req[48] * 256) * 2;
1284 	}
1285 
1286 	req[count++] = 0x00;
1287 
1288 	smprintf(s, "Adding ToDo method 2\n");
1289 	return GSM_WaitFor (s, req, count, 0x13, 4, ID_SetToDo);
1290 }
1291 
N6510_AddToDo(GSM_StateMachine * s,GSM_ToDoEntry * ToDo)1292 GSM_Error N6510_AddToDo(GSM_StateMachine *s, GSM_ToDoEntry *ToDo)
1293 {
1294 	if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO63)) {
1295 		return N6510_AddToDo1(s, ToDo);
1296 	} else if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_TODO66)) {
1297 		return N6510_AddToDo2(s, ToDo);
1298 	} else {
1299 		return ERR_NOTSUPPORTED;
1300 	}
1301 }
1302 
N6510_ReplyGetCalendarSettings(GSM_Protocol_Message * msg,GSM_StateMachine * s)1303 GSM_Error N6510_ReplyGetCalendarSettings(GSM_Protocol_Message *msg, GSM_StateMachine *s)
1304 {
1305 	GSM_CalendarSettings *sett = s->Phone.Data.CalendarSettings;
1306 
1307 	switch (msg->Buffer[3]) {
1308 	case 0x86:
1309 		smprintf(s, "Auto deleting setting received\n");
1310 		sett->AutoDelete = msg->Buffer[4];
1311 		return ERR_NONE;
1312 	case 0x8E:
1313 		smprintf(s, "Start day for calendar received\n");
1314 		switch(msg->Buffer[4]) {
1315 		case 0x04:
1316 			sett->StartDay = 1;
1317 			return ERR_NONE;
1318 		case 0x03:
1319 			sett->StartDay = 6;
1320 			return ERR_NONE;
1321 		case 0x02:
1322 			sett->StartDay = 7;
1323 			return ERR_NONE;
1324 		case 0x01:
1325 			sett->StartDay = 1;
1326 			return ERR_NONE;
1327 		}
1328 		break;
1329 	}
1330 	return ERR_UNKNOWNRESPONSE;
1331 }
1332 
N6510_GetCalendarSettings(GSM_StateMachine * s,GSM_CalendarSettings * settings)1333 GSM_Error N6510_GetCalendarSettings(GSM_StateMachine *s, GSM_CalendarSettings *settings)
1334 {
1335 	GSM_Error	error;
1336 	unsigned char 	req1[] = {N6110_FRAME_HEADER, 0x85};
1337 	unsigned char 	req2[] = {N6110_FRAME_HEADER, 0x8D};
1338 
1339 	s->Phone.Data.CalendarSettings = settings;
1340 
1341 	smprintf(s, "Getting auto delete\n");
1342 	error = GSM_WaitFor (s, req1, 4, 0x13, 4, ID_GetCalendarSettings);
1343 	if (error != ERR_NONE) return error;
1344 
1345 	smprintf(s, "Getting start day for week\n");
1346 	return GSM_WaitFor (s, req2, 4, 0x13, 4, ID_GetCalendarSettings);
1347 }
1348 
1349 #endif
1350 
1351 /* How should editor hadle tabs in this file? Add editor commands here.
1352  * vim: noexpandtab sw=8 ts=8 sts=8:
1353  */
1354