1 /* (c) 2003 by Marcin Wiacek */
2 /* (c) 2006-2007 by Michal Cihar */
3 
4 /**
5  * \file obexgen.c
6  * @author Michal Čihař
7  * @author Marcin Wiacek
8  */
9 /**
10  * @addtogroup Phone
11  * @{
12  */
13 /**
14  * \defgroup OBEXPhone OBEX phones communication
15  * Generic OBEX access to phones, made addording to OBEX specification
16  * version 1.3 and IrMC specification version 1.1 as available from IrDA
17  * <http://www.irda.org>.
18  *
19  * @author Michal Cihar
20  * @author Marcin Wiacek
21  * @{
22  */
23 
24 #include <string.h>
25 #include <time.h>
26 
27 #include <gammu-config.h>
28 
29 #include "../../gsmcomon.h"
30 #include "../../misc/coding/coding.h"
31 #include "../../gsmphones.h"
32 #include "../../gsmstate.h"
33 #include "../../service/gsmmisc.h"
34 #include "../../protocol/obex/obex.h"
35 #include "obexfunc.h"
36 #include "mobex.h"
37 #include "../../../libgammu/misc/string.h"
38 
39 #ifdef GSM_ENABLE_OBEXGEN
40 
41 /* Forward definitions */
42 GSM_Error OBEXGEN_GetModel(GSM_StateMachine *s);
43 
44 /**
45  * How many read attempts will happen.
46  */
47 #define OBEX_TIMEOUT 10
48 
49 /**
50  * Handles various error codes in OBEX protocol.
51  */
OBEXGEN_HandleError(GSM_Protocol_Message * msg,GSM_StateMachine * s)52 static GSM_Error OBEXGEN_HandleError(GSM_Protocol_Message *msg, GSM_StateMachine *s)
53 {
54 	switch (msg->Type & 0x7f) {
55 		/* HTTP based codes */
56 		case 0x40:
57 		case 0x45:
58 		case 0x47:
59 		case 0x48:
60 		case 0x4d:
61 		case 0x4e:
62 		case 0x4f:
63 			smprintf(s, "Bad request (0x%02x)\n", msg->Type);
64 			return ERR_BUG;
65 		case 0x41:
66 		case 0x42:
67 		case 0x43:
68 		case 0x46: /* Not acceptable */
69 		case 0x49: /* Conflict */
70 			smprintf(s, "Security error (0x%02x)\n", msg->Type);
71 			return ERR_PERMISSION;
72 		case 0x44:
73 		case 0x4a:
74 			smprintf(s, "File not found (0x%02x)\n", msg->Type);
75 			return ERR_FILENOTEXIST;
76 		case 0x50: /* Internal server error */
77 		case 0x51: /* Not implemented */
78 		case 0x53: /* Service unavailable */
79 			smprintf(s, "Internal phone error (0x%02x)\n", msg->Type);
80 			return ERR_PHONE_INTERNAL;
81 		/* OBEX specials */
82 		case 0x60:
83 			smprintf(s, "Database full\n");
84 			return ERR_FULL;
85 		case 0x61:
86 			smprintf(s, "Database locked\n");
87 			return ERR_PERMISSION;
88 		case 0x4c:
89 			smprintf(s, "Precondition failed\n");
90 			return ERR_NOTSUPPORTED;
91 	}
92 	smprintf(s, "Unknown OBEX error (0x%02x)\n", msg->Type);
93 	return ERR_UNKNOWN;
94 }
95 
96 /**
97  * Adds connection ID block to the request.
98  */
OBEXGEN_AddConnectionID(GSM_StateMachine * s,char * Buffer,int * Pos)99 void OBEXGEN_AddConnectionID(GSM_StateMachine *s, char *Buffer, int *Pos)
100 {
101 	GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
102 
103 	Buffer[(*Pos)++] = 0xCB;
104 	Buffer[(*Pos)++] = Priv->connection_id[0];
105 	Buffer[(*Pos)++] = Priv->connection_id[1];
106 	Buffer[(*Pos)++] = Priv->connection_id[2];
107 	Buffer[(*Pos)++] = Priv->connection_id[3];
108 }
109 
110 /**
111  * \defgroup OBEXinit OBEX initialisation and terminating
112  * \ingroup OBEXPhone
113  * @{
114  */
115 
OBEXGEN_ReplyConnect(GSM_Protocol_Message * msg,GSM_StateMachine * s)116 static GSM_Error OBEXGEN_ReplyConnect(GSM_Protocol_Message *msg, GSM_StateMachine *s)
117 {
118 	size_t i;
119 	GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
120 
121 	switch (msg->Type) {
122 	case 0xA0:
123 		smprintf(s,"Connected/disconnected OK\n");
124 		/* Sample: 10 |00 |20 |00 |CB |00 |00 |00 |10 |4AJ|00 |08 |4DM|4FO|42B|45E|58X */
125 		/* Byte 0 - OBEX version */
126 		/* Byte 1 - flags */
127 		/* Bytes 2,3 - maximum size of packet */
128 		if (msg->Length >= 4) {
129 			s->Phone.Data.Priv.OBEXGEN.FrameSize = msg->Buffer[2]*256 + msg->Buffer[3];
130 			smprintf(s,"Maximum size of frame is %i 0x%x\n",s->Phone.Data.Priv.OBEXGEN.FrameSize,s->Phone.Data.Priv.OBEXGEN.FrameSize);
131 		}
132 		/* Remaining bytes - optional headers */
133 		for (i = 4; i < msg->Length;) {
134 			switch (msg->Buffer[i]) {
135 				case 0xCB:
136 					/* Connection ID */
137 					memcpy(Priv->connection_id, msg->Buffer + i + 1, 4);
138 					i += 5;
139 					break;
140 				case 0x4A:
141 					/* Peer */
142 					/* We just skip it */
143 					i += (msg->Buffer[i + 1] << 8) + msg->Buffer[i + 2];
144 					break;
145 				default:
146 					smprintf(s, "Unknown OBEX header: 0x%02X, skipping rest\n", msg->Buffer[i]);
147 					i = msg->Length;
148 					break;
149 			}
150 		}
151 		return ERR_NONE;
152 	case 0xC0:
153 		smprintf(s, "Wrong request sent to phone!\n");
154 		return ERR_BUG;
155 	case 0xC1:
156 	case 0xC3:
157 		smprintf(s, "Connection not allowed!\n");
158 		return ERR_SECURITYERROR;
159 	}
160 	/* Generic error codes */
161 	if ((msg->Type & 0x7f) >= 0x40) {
162 		return OBEXGEN_HandleError(msg, s);
163 	}
164 	return ERR_UNKNOWNRESPONSE;
165 }
166 
167 /**
168  * Disconnects from OBEX service
169  */
OBEXGEN_Disconnect(GSM_StateMachine * s)170 GSM_Error OBEXGEN_Disconnect(GSM_StateMachine *s)
171 {
172 	GSM_Error error;
173 	smprintf(s, "Disconnecting\n");
174 	error = GSM_WaitFor (s, NULL, 0, 0x81, OBEX_TIMEOUT, ID_Initialise);
175 	if (error == ERR_BUG) return ERR_NONE;
176 	return error;
177 }
178 
179 /**
180  * Connects to OBEX using selected service
181  */
OBEXGEN_Connect(GSM_StateMachine * s,OBEX_Service service)182 GSM_Error OBEXGEN_Connect(GSM_StateMachine *s, OBEX_Service service)
183 {
184 	GSM_Error	error = ERR_NONE;
185 	int		Current=4;
186 	unsigned char 	req2[200];
187 	unsigned char 	req[200] = {
188 		0x10,			/* Version 1.0 			*/
189 		0x00,			/* no flags 			*/
190 		0x04,0x00};		/* max size of packet (changed below for m-obex) */
191 
192 	/* Are we requsted for initial service? */
193 	if (service == 0) {
194 		/* If not set, stay as we are configured now */
195 		if (s->Phone.Data.Priv.OBEXGEN.InitialService == 0) {
196 			return ERR_NONE;
197 		}
198 		service = s->Phone.Data.Priv.OBEXGEN.InitialService;
199 	}
200 
201 	/* Don't we already have correct service? */
202 	if (service == s->Phone.Data.Priv.OBEXGEN.Service) return ERR_NONE;
203 
204 	/* Disconnect from current service, if we were connected */
205 	if (s->Phone.Data.Priv.OBEXGEN.Service != 0) {
206 		error = OBEXGEN_Disconnect(s);
207 		if (error != ERR_NONE) return error;
208 	}
209 
210 	switch (service) {
211 	case OBEX_None:
212 		smprintf(s, "No service requested\n");
213 		break;
214 	case OBEX_IRMC:
215 		smprintf(s, "IrMC service requested\n");
216 		/* IrMC Service UUID */
217 		req2[0] = 'I'; req2[1] = 'R'; req2[2] = 'M';
218 		req2[3] = 'C'; req2[4] = '-'; req2[5] = 'S';
219 		req2[6] = 'Y'; req2[7] = 'N'; req2[8] = 'C';
220 
221 		/* Target block */
222 		OBEXAddBlock(req, &Current, 0x46, req2, 9);
223 		break;
224 	case OBEX_BrowsingFolders:
225 		smprintf(s, "Folder Browsing service requested\n");
226 		/* Folder Browsing Service UUID */
227 		req2[0] = 0xF9; req2[1] = 0xEC; req2[2] = 0x7B;
228 		req2[3] = 0xC4; req2[4] = 0x95; req2[5] = 0x3C;
229 		req2[6] = 0x11; req2[7] = 0xD2; req2[8] = 0x98;
230 		req2[9] = 0x4E; req2[10]= 0x52; req2[11]= 0x54;
231 		req2[12]= 0x00; req2[13]= 0xDC; req2[14]= 0x9E;
232 		req2[15]= 0x09;
233 
234 		/* Target block */
235 		OBEXAddBlock(req, &Current, 0x46, req2, 16);
236 		break;
237 	case OBEX_m_OBEX:
238 		/* Bigger frame size for m-OBEX */
239 		req[2] = 0x20;
240 		/* IrMC Service UUID */
241 		req2[0] = 'M'; req2[1] = 'O'; req2[2] = 'B';
242 		req2[3] = 'E'; req2[4] = 'X';
243 
244 		req[0] = 0x11; /* Phones seem to require OBEX 1.1 */
245 
246 		/* Target block */
247 		OBEXAddBlock(req, &Current, 0x46, req2, 5);
248 		break;
249 	}
250 
251 	/* Remember current service */
252 	s->Phone.Data.Priv.OBEXGEN.Service = service;
253 
254 	smprintf(s, "Connecting\n");
255 	return GSM_WaitFor (s, req, Current, 0x80, OBEX_TIMEOUT, ID_Initialise);
256 }
257 
258 /**
259  * Clears any flags in IrMC capabilities structure.
260  */
IRMC_InitCapabilities(IRMC_Capability * Cap)261 void IRMC_InitCapabilities(IRMC_Capability *Cap)
262 {
263 	Cap->IEL = -1;
264 	Cap->HD = FALSE;
265 }
266 
267 /**
268  * Initializes OBEX internal variables. To be used by other who need
269  * OBEX protocol, but don't need it's init.
270  */
OBEXGEN_InitialiseVars(GSM_StateMachine * s)271 GSM_Error OBEXGEN_InitialiseVars(GSM_StateMachine *s)
272 {
273 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
274 
275 	Priv->Service = 0;
276 	Priv->InitialService = 0;
277 	Priv->PbLUID = NULL;
278 	Priv->PbLUIDCount = 0;
279 	Priv->PbIndex = NULL;
280 	Priv->PbIndexCount = 0;
281 	Priv->PbData = NULL;
282 	Priv->PbCount = -1;
283 	Priv->CalLUID = NULL;
284 	Priv->CalLUIDCount = 0;
285 	Priv->CalIndex = NULL;
286 	Priv->CalIndexCount = 0;
287 	Priv->CalData = NULL;
288 	Priv->TodoLUID = NULL;
289 	Priv->TodoLUIDCount = 0;
290 	Priv->TodoIndex = NULL;
291 	Priv->TodoIndexCount = 0;
292 	Priv->CalCount = -1;
293 	Priv->TodoCount = -1;
294 	Priv->CalOffsets = NULL;
295 	Priv->TodoOffsets = NULL;
296 	Priv->UpdateCalLUID = FALSE;
297 	Priv->UpdatePbLUID = FALSE;
298 	Priv->UpdateTodoLUID = FALSE;
299 	Priv->UpdateNoteLUID = FALSE;
300 	Priv->OBEXCapability = NULL;
301 	Priv->OBEXDevinfo = NULL;
302 	Priv->NoteLUID = NULL;
303 	Priv->NoteLUIDCount = 0;
304 	Priv->NoteIndex = NULL;
305 	Priv->NoteIndexCount = 0;
306 	Priv->NoteData = NULL;
307 	Priv->NoteCount = -1;
308 	Priv->NoteOffsets = NULL;
309 	Priv->m_obex_appdata = NULL;
310 	Priv->m_obex_appdata_len = 0;
311         Priv->m_obex_calendar_nextid = 0;
312         Priv->m_obex_calendar_nexterror = 0;
313         Priv->m_obex_calendar_buffer = NULL;
314         Priv->m_obex_calendar_buffer_pos = 0;
315         Priv->m_obex_calendar_buffer_size = 0;
316         Priv->m_obex_contacts_nextid = 0;
317         Priv->m_obex_contacts_nexterror = 0;
318         Priv->m_obex_contacts_buffer = NULL;
319         Priv->m_obex_contacts_buffer_pos = 0;
320         Priv->m_obex_contacts_buffer_size = 0;
321 
322 	/* Default connection ID */
323 	Priv->connection_id[0] = 0;
324 	Priv->connection_id[1] = 0;
325 	Priv->connection_id[2] = 0;
326 	Priv->connection_id[3] = 1;
327 
328 	IRMC_InitCapabilities(&(Priv->NoteCap));
329 	IRMC_InitCapabilities(&(Priv->PbCap));
330 	IRMC_InitCapabilities(&(Priv->CalCap));
331 
332 	return ERR_NONE;
333 }
334 
335 
336 /**
337  * Initializes OBEX connection in desired mode as defined by config.
338  */
OBEXGEN_Initialise(GSM_StateMachine * s)339 GSM_Error OBEXGEN_Initialise(GSM_StateMachine *s)
340 {
341 	GSM_Error	error = ERR_NONE;
342 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
343 	gboolean service_forced = FALSE;
344 
345 	/* Init variables */
346 	error = OBEXGEN_InitialiseVars(s);
347 	if (error != ERR_NONE) return error;
348 
349 
350 	s->Phone.Data.VerNum 		= 0;
351 	s->Phone.Data.Version[0] 	= 0;
352 	s->Phone.Data.Manufacturer[0] 	= 0;
353 
354 	/* Detect connection for desired type */
355 	Priv->InitialService = OBEX_BrowsingFolders;
356 	smprintf(s, "Connected using model %s\n", s->CurrentConfig->Model);
357 	if (strcmp(s->CurrentConfig->Model, "obex") == 0) {
358 		Priv->InitialService = OBEX_BrowsingFolders;
359 		service_forced = TRUE;
360 	} else if (strcmp(s->CurrentConfig->Model, "obexfs") == 0) {
361 		Priv->InitialService = OBEX_BrowsingFolders;
362 		service_forced = TRUE;
363 	} else if (strcmp(s->CurrentConfig->Model, "obexirmc") == 0) {
364 		Priv->InitialService = OBEX_IRMC;
365 		service_forced = TRUE;
366 	} else if (strcmp(s->CurrentConfig->Model, "seobex") == 0) {
367 		Priv->InitialService = OBEX_IRMC;
368 		service_forced = TRUE;
369 	} else if (strcmp(s->CurrentConfig->Model, "mobex") == 0) {
370 		Priv->InitialService = OBEX_m_OBEX;
371 		service_forced = TRUE;
372 	} else if (strcmp(s->CurrentConfig->Model, "obexnone") == 0) {
373 		Priv->InitialService = OBEX_None;
374 		service_forced = TRUE;
375 	}
376 
377 	/* Grab OBEX capability */
378 	if (!service_forced || Priv->InitialService == OBEX_BrowsingFolders) {
379 		error = OBEXGEN_Connect(s, OBEX_BrowsingFolders);
380 		if (error == ERR_NONE) {
381 			error = OBEXGEN_GetTextFile(s, "", &(Priv->OBEXCapability));
382 		}
383 	}
384 
385 	/* Grab IrMC devinfo */
386 	if (!service_forced || Priv->InitialService == OBEX_IRMC) {
387 		error = OBEXGEN_Connect(s, OBEX_IRMC);
388 		if (error == ERR_NONE) {
389 			error = OBEXGEN_GetTextFile(s, "", &(Priv->OBEXDevinfo));
390 		}
391 	}
392 
393 	/* Initialise connection */
394 	error = OBEXGEN_Connect(s, 0);
395 	if (error != ERR_NONE) return error;
396 
397 	return ERR_NONE;
398 }
399 
400 /**
401  * Frees internal OBEX variables.
402  *
403  * \todo This should be done on terminate, but not on termination from
404  * Sony-Ericsson.
405  */
OBEXGEN_FreeVars(GSM_StateMachine * s)406 void OBEXGEN_FreeVars(GSM_StateMachine *s)
407 {
408 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
409 	int i=0;
410 
411 	for (i = 1; i <= Priv->PbLUIDCount; i++) {
412 		free(Priv->PbLUID[i]);
413 		Priv->PbLUID[i]=NULL;
414 	}
415 	free(Priv->PbLUID);
416 	Priv->PbLUID=NULL;
417 	free(Priv->PbData);
418 	Priv->PbData=NULL;
419 
420 	for (i = 1; i <= Priv->NoteLUIDCount; i++) {
421 		free(Priv->NoteLUID[i]);
422 		Priv->NoteLUID[i]=NULL;
423 	}
424 	free(Priv->NoteLUID);
425 	Priv->NoteLUID=NULL;
426 	free(Priv->NoteData);
427 	Priv->NoteData=NULL;
428 
429 	for (i = 1; i <= Priv->CalLUIDCount; i++) {
430 		free(Priv->CalLUID[i]);
431 		Priv->CalLUID[i]=NULL;
432 	}
433 	free(Priv->CalLUID);
434 	Priv->CalLUID=NULL;
435 	free(Priv->CalData);
436 	Priv->CalData=NULL;
437 
438 	for (i = 1; i <= Priv->TodoLUIDCount; i++) {
439 		free(Priv->TodoLUID[i]);
440 		Priv->TodoLUID[i]=NULL;
441 	}
442 	free(Priv->TodoLUID);
443 	Priv->TodoLUID=NULL;
444 	free(Priv->PbIndex);
445 	Priv->PbIndex=NULL;
446 	free(Priv->NoteIndex);
447 	Priv->NoteIndex=NULL;
448 	free(Priv->CalIndex);
449 	Priv->CalIndex=NULL;
450 	free(Priv->TodoIndex);
451 	Priv->TodoIndex=NULL;
452 	free(Priv->PbOffsets);
453 	Priv->PbOffsets=NULL;
454 	free(Priv->NoteOffsets);
455 	Priv->NoteOffsets=NULL;
456 	free(Priv->CalOffsets);
457 	Priv->CalOffsets=NULL;
458 	free(Priv->TodoOffsets);
459 	Priv->TodoOffsets=NULL;
460 	free(Priv->OBEXCapability);
461 	Priv->OBEXCapability=NULL;
462 	free(Priv->OBEXDevinfo);
463 	Priv->OBEXDevinfo=NULL;
464 
465         free(Priv->m_obex_calendar_buffer);
466         Priv->m_obex_calendar_buffer = NULL;
467         free(Priv->m_obex_calendar_buffer);
468         Priv->m_obex_contacts_buffer = NULL;
469 }
470 
471 /**
472  * Terminates OBEX connection.
473  */
OBEXGEN_Terminate(GSM_StateMachine * s)474 GSM_Error OBEXGEN_Terminate(GSM_StateMachine *s)
475 {
476 	return OBEXGEN_Disconnect(s);
477 }
478 
479 /*@}*/
480 
481 /**
482  * \defgroup OBEXfiles OBEX transfer implementation
483  * \ingroup OBEXPhone
484  * @{
485  */
486 
487 /**
488  * Merges filename from path and file
489  */
OBEXGEN_CreateFileName(unsigned char * Dest,unsigned char * Path,unsigned char * Name)490 void OBEXGEN_CreateFileName(unsigned char *Dest, unsigned char *Path, unsigned char *Name)
491 {
492 	size_t len;
493 
494 	/* Folder name */
495 	CopyUnicodeString(Dest, Path);
496 	len = UnicodeLength(Dest);
497 	/* Append slash */
498 	if (len > 0) {
499 		Dest[2*len + 0] = 0;
500 		Dest[2*len + 1] = '/';
501 		len++;
502 	}
503 	/* And add filename */
504 	CopyUnicodeString(Dest + 2*len, Name);
505 }
506 
507 /**
508  * Grabs path part from complete path
509  */
OBEXGEN_FindNextDir(unsigned char * Path,size_t * Pos,unsigned char * Return)510 static void OBEXGEN_FindNextDir(unsigned char *Path, size_t *Pos, unsigned char *Return)
511 {
512 	int Retlen = 0;
513 
514 	while(1) {
515 		if (Path[(*Pos)*2] == 0 && Path[(*Pos)*2+1] == 0) break;
516 		if (Path[(*Pos)*2] == 0 && Path[(*Pos)*2+1] == '/') {
517 			(*Pos)++;
518 			break;
519 		}
520 		Return[Retlen*2]     = Path[(*Pos)*2];
521 		Return[Retlen*2+1]   = Path[(*Pos)*2+1];
522 		(*Pos)++;
523 		Retlen++;
524 	}
525 	Return[Retlen*2]     = 0;
526 	Return[Retlen*2+1]   = 0;
527 }
528 
529 /**
530  * Reply handler for changing path
531  */
OBEXGEN_ReplyChangePath(GSM_Protocol_Message * msg,GSM_StateMachine * s)532 static GSM_Error OBEXGEN_ReplyChangePath(GSM_Protocol_Message *msg, GSM_StateMachine *s)
533 {
534 	/* Non standard Sharp GX reply */
535 	if (msg->Type == 0x80) {
536 		return ERR_FILENOTEXIST;
537 	}
538 
539 	/* Generic error codes */
540 	if ((msg->Type & 0x7f) >= 0x40) {
541 		return OBEXGEN_HandleError(msg, s);
542 	}
543 	switch (msg->Type) {
544 	case 0xA0:
545 		smprintf(s,"Path set OK\n");
546 		return ERR_NONE;
547 	case 0xA1:
548 		smprintf(s,"Folder created\n");
549 		return ERR_NONE;
550 	}
551 	return ERR_UNKNOWNRESPONSE;
552 }
553 
554 /**
555  * Changes current path on OBEX device.
556  */
OBEXGEN_ChangePath(GSM_StateMachine * s,char * Name,unsigned char Flag)557 static GSM_Error OBEXGEN_ChangePath(GSM_StateMachine *s, char *Name, unsigned char Flag)
558 {
559 	unsigned char 	req[400];
560 	int		Current = 2;
561 
562 	/* Flags */
563 	req[0] = Flag;
564 	req[1] = 0x00;
565 
566 	/* Name block */
567 	if (Name != NULL && UnicodeLength(Name) != 0) {
568 		OBEXAddBlock(req, &Current, 0x01, Name, UnicodeLength(Name)*2+2);
569 	} else {
570 		OBEXAddBlock(req, &Current, 0x01, NULL, 0);
571 	}
572 
573 	OBEXGEN_AddConnectionID(s, req, &Current);
574 
575 	return GSM_WaitFor (s, req, Current, 0x85, OBEX_TIMEOUT, ID_SetPath);
576 }
577 
578 /**
579  * Changes current path on OBEX device to match GSM_File one.
580  *
581  * @param s State machine
582  * @param File File which path we want to set
583  * @param DirOnly Whether to descend only do directory name of path or full path (/foo or /foo/bar.png)
584  * @param Buffer Optional buffer for storing last path part. Not used if NULL.
585  */
OBEXGEN_ChangeToFilePath(GSM_StateMachine * s,char * File,gboolean DirOnly,unsigned char * Buffer)586 static GSM_Error OBEXGEN_ChangeToFilePath(GSM_StateMachine *s, char *File, gboolean DirOnly, unsigned char *Buffer)
587 {
588 	GSM_Error		error;
589 	size_t			Pos;
590 	unsigned char		*req, req2[200];
591 
592 	if (Buffer == NULL) {
593 		req = req2;
594 	} else {
595 		req = Buffer;
596 	}
597 
598 	smprintf(s,"Changing to root\n");
599 	error = OBEXGEN_ChangePath(s, NULL, 2);
600 	if (error != ERR_NONE) return error;
601 
602 	Pos = 0;
603 	do {
604 		OBEXGEN_FindNextDir(File, &Pos, req);
605 		if (DirOnly && Pos == UnicodeLength(File)) break;
606 		smprintf(s,"Changing path down to %s (%ld, %ld)\n",
607 			DecodeUnicodeString(req),
608 			(long)Pos,
609 			(long)UnicodeLength(File));
610 		error=OBEXGEN_ChangePath(s, req, 2);
611 		if (error != ERR_NONE) return error;
612 		if (Pos == UnicodeLength(File)) break;
613 	} while (1);
614 
615 	return ERR_NONE;
616 }
617 
618 /**
619  * Reply handler for most file write operations.
620  */
OBEXGEN_ReplyAddFilePart(GSM_Protocol_Message * msg,GSM_StateMachine * s)621 static GSM_Error OBEXGEN_ReplyAddFilePart(GSM_Protocol_Message *msg, GSM_StateMachine *s)
622 {
623 	size_t Pos=0, pos2, len2;
624 	char *NewLUID = NULL;
625 	char *timestamp = NULL;
626 	char *CC = NULL;
627 	gboolean UpdatePbLUID, UpdateCalLUID, UpdateTodoLUID;
628 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
629 
630 	UpdatePbLUID = Priv->UpdatePbLUID;
631 	Priv->UpdatePbLUID = FALSE;
632 	UpdateCalLUID = Priv->UpdateCalLUID;
633 	Priv->UpdateCalLUID = FALSE;
634 	UpdateTodoLUID = Priv->UpdateTodoLUID;
635 	Priv->UpdateTodoLUID = FALSE;
636 
637 	if ((msg->Type & 0x7f) >= 0x40) {
638 		return OBEXGEN_HandleError(msg, s);
639 	}
640 
641 	switch (msg->Type) {
642 	case 0x90:
643 		smprintf(s,"Last part of file added OK\n");
644 		return ERR_NONE;
645 	case 0xA0:
646 		smprintf(s,"Part of file added OK\n");
647 		while(1) {
648 			if (Pos >= msg->Length) break;
649 			switch (msg->Buffer[Pos]) {
650 			case 0x4C:
651 				smprintf(s, "Application data received:");
652 				len2 =  msg->Buffer[Pos+1] * 256 + msg->Buffer[Pos+2];
653 				pos2 = 0;
654 				while(1) {
655 					if (pos2 >= len2) break;
656 					switch (msg->Buffer[Pos + 3 + pos2]) {
657 						case 0x00:
658 							if (Priv->Service == OBEX_m_OBEX) {
659 								Priv->m_obex_error = msg->Buffer[Pos + 3 + pos2 + 1];
660 								smprintf(s, " m-obex error=\"%d\"", Priv->m_obex_error);
661 								/* This field has fixed size */
662 								pos2 += 2;
663 								continue;
664 							}
665 							break;
666 						case 0x01:
667 							NewLUID = (char *)malloc(msg->Buffer[Pos + 3 + pos2 + 1]+1);
668 							memcpy(NewLUID,msg->Buffer + Pos + 3 + pos2 + 2, msg->Buffer[Pos + 3 + pos2 + 1]);
669 							NewLUID[msg->Buffer[Pos + 3 + pos2 + 1]]=0;
670 							smprintf(s, " LUID=\"%s\"", NewLUID);
671 							break;
672 						case 0x02:
673 							CC = (char *)malloc(msg->Buffer[Pos + 3 + pos2 + 1]+1);
674 							memcpy(CC,msg->Buffer + Pos + 3 + pos2 + 2, msg->Buffer[Pos + 3 + pos2 + 1]);
675 							CC[msg->Buffer[Pos + 3 + pos2 + 1]]=0;
676 							smprintf(s, " CC=\"%s\"", CC);
677 							break;
678 						case 0x03:
679 							timestamp = (char *)malloc(msg->Buffer[Pos + 3 + pos2 + 1]+1);
680 							memcpy(timestamp,msg->Buffer + Pos + 3 + pos2 + 2, msg->Buffer[Pos + 3 + pos2 + 1]);
681 							timestamp[msg->Buffer[Pos + 3 + pos2 + 1]] = 0;
682 							smprintf(s, " Timestamp=\"%s\"", timestamp);
683 							break;
684 					}
685 					pos2 += 2 + msg->Buffer[Pos + 3 + pos2 + 1];
686 				}
687 				smprintf(s, "\n");
688 				if (timestamp != NULL) {
689 					free(timestamp);
690 					timestamp=NULL;
691 				}
692 				if (CC != NULL) {
693 					free(CC);
694 					CC=NULL;
695 				}
696 				if (NewLUID != NULL) {
697 					if (UpdatePbLUID) {
698 						Priv->PbLUIDCount++;
699 						Priv->PbLUID = (char **)realloc(Priv->PbLUID, (Priv->PbLUIDCount + 1) * sizeof(char *));
700 						if (Priv->PbLUID == NULL) {
701 							return ERR_MOREMEMORY;
702 						}
703 						Priv->PbLUID[Priv->PbLUIDCount] = NewLUID;
704 					} else if (UpdateTodoLUID) {
705 						Priv->TodoLUIDCount++;
706 						Priv->TodoLUID = (char **)realloc(Priv->TodoLUID, (Priv->TodoLUIDCount + 1) * sizeof(char *));
707 						if (Priv->TodoLUID == NULL) {
708 							return ERR_MOREMEMORY;
709 						}
710 						Priv->TodoLUID[Priv->TodoLUIDCount] = NewLUID;
711 					} else if (UpdateCalLUID) {
712 						Priv->CalLUIDCount++;
713 						Priv->CalLUID = (char **)realloc(Priv->CalLUID, (Priv->CalLUIDCount + 1) * sizeof(char *));
714 						if (Priv->CalLUID == NULL) {
715 							return ERR_MOREMEMORY;
716 						}
717 						Priv->CalLUID[Priv->CalLUIDCount] = NewLUID;
718 					} else {
719 						free(NewLUID);
720 						NewLUID=NULL;
721 					}
722 				}
723 				Pos += len2;
724 				break;
725 			case 0xc3:
726 				/* Length */
727 				/**
728 				 * @todo Lenght is ignored now
729 				 */
730 				Pos += 5;
731 				break;
732 			case 0x49:
733 				/* ID of newly created m-obex entry */
734 				Priv->m_obex_newid = msg->Buffer[Pos+3]*256 + msg->Buffer[Pos+4];
735 				Pos += 5;
736 				break;
737 			case 0xcb:
738 				/* Skip Connection ID (we ignore this for now) */
739 				Pos += 5;
740 				break;
741 			default:
742 				Pos+=msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2];
743 				break;
744 			}
745 		}
746 		return ERR_NONE;
747 	}
748 	return ERR_UNKNOWNRESPONSE;
749 }
750 
OBEXGEN_PrivAddFilePart(GSM_StateMachine * s,GSM_File * File,size_t * Pos,int * Handle UNUSED,gboolean HardDelete)751 GSM_Error OBEXGEN_PrivAddFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle UNUSED, gboolean HardDelete)
752 {
753 	GSM_Error		error;
754 	size_t			j;
755 	int		Current = 0;
756 	unsigned char 		req[2000];
757 	unsigned char		hard_delete_header[2] = {'\x12', '\x0'};
758 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
759 
760 	s->Phone.Data.File = File;
761 
762 	if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
763 		OBEXGEN_AddConnectionID(s, req, &Current);
764 	}
765 
766 	/* Are we sending first request or continuation? */
767 	if (*Pos == 0) {
768 		if (!strcmp(DecodeUnicodeString(File->ID_FullName),"")) {
769 			error = OBEXGEN_Connect(s,OBEX_None);
770 			if (error != ERR_NONE) return error;
771 		} else {
772 			if (Priv->Service == OBEX_BrowsingFolders) {
773 				error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
774 				if (error != ERR_NONE) return error;
775 			}
776 		}
777 
778 		/* Name block */
779 		if (Priv->Service == OBEX_m_OBEX) {
780 			OBEXAddBlock(req, &Current, 0x42, DecodeUnicodeString(File->ID_FullName), UnicodeLength(File->ID_FullName) + 1);
781 		} else {
782 			OBEXAddBlock(req, &Current, 0x01, File->Name, UnicodeLength(File->Name)*2+2);
783 		}
784 
785 		/* Include m-obex application data */
786 		if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
787 			OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
788 		}
789 
790 		/* Adding empty file is special on mobex */
791 		if (Priv->Service == OBEX_m_OBEX && File->Buffer == NULL) {
792 			error = GSM_WaitFor (s, req, Current, 0x82, OBEX_TIMEOUT * 10, ID_AddFile);
793 			if (error == ERR_NONE) {
794 				return ERR_EMPTY;
795 			}
796 			return error;
797 		}
798 
799 		/* File size block */
800 		req[Current++] = 0xC3; /* ID */
801 		req[Current++] = (File->Used >> 24) & 0xff;
802 		req[Current++] = (File->Used >> 16) & 0xff;
803 		req[Current++] = (File->Used >> 8) & 0xff;
804 		req[Current++] = File->Used & 0xff;
805 
806 		/* Application data block for hard delete */
807 		if (HardDelete) {
808 			OBEXAddBlock(req, &Current, 0x4c, hard_delete_header, 2);
809 		}
810 	}
811 
812 	j = Priv->FrameSize - Current - 20;
813 	if (j > 1000) j = 1000;
814 
815 	if (File->Used - *Pos < j) {
816 		j = File->Used - *Pos;
817 		/* End of file body block */
818 		OBEXAddBlock(req, &Current, 0x49, File->Buffer+(*Pos), j);
819 		smprintf(s, "Adding last file part %ld %ld\n", (long)*Pos, (long)j);
820 		*Pos = *Pos + j;
821 		error = GSM_WaitFor (s, req, (long)Current, 0x82, OBEX_TIMEOUT * 10, ID_AddFile);
822 		if (error != ERR_NONE) return error;
823 		return ERR_EMPTY;
824 	} else {
825 		/* File body block */
826 		OBEXAddBlock(req, &Current, 0x48, File->Buffer+(*Pos), j);
827 		smprintf(s, "Adding file part %ld %ld\n", (long)*Pos, (long)j);
828 		*Pos = *Pos + j;
829 		error=GSM_WaitFor (s, req, (long)Current, 0x02, OBEX_TIMEOUT * 10, ID_AddFile);
830 	}
831 	return error;
832 }
833 
OBEXGEN_AddFilePart(GSM_StateMachine * s,GSM_File * File,size_t * Pos,int * Handle)834 GSM_Error OBEXGEN_AddFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
835 {
836 	GSM_Error		error;
837 
838 	/* Go to default service */
839 	error = OBEXGEN_Connect(s, 0);
840 	if (error != ERR_NONE) return error;
841 
842 	/* Add file */
843 	smprintf(s,"Adding file\n");
844 	error = OBEXGEN_PrivAddFilePart(s, File, Pos, Handle, FALSE);
845 
846 	/* Calculate path of added file if we're done */
847 	if (error == ERR_EMPTY) {
848 		OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
849 	}
850 
851 	return error;
852 }
853 
OBEXGEN_SendFilePart(GSM_StateMachine * s,GSM_File * File,size_t * Pos,int * Handle)854 GSM_Error OBEXGEN_SendFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
855 {
856 	GSM_Error		error;
857 
858 	/* No service for this */
859 	error = OBEXGEN_Connect(s, OBEX_None);
860 	if (error != ERR_NONE) return error;
861 
862 	/* Send file */
863 	smprintf(s,"Sending file\n");
864 	File->ID_FullName[0] = 0;
865 	File->ID_FullName[1] = 0;
866 	error = OBEXGEN_PrivAddFilePart(s, File, Pos, Handle, FALSE);
867 	if (error != ERR_NONE) return error;
868 
869 	/* Calculate path of added file */
870 	OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
871 	return ERR_NONE;
872 }
873 
874 /**
875  * Reply handler for file reading operations.
876  */
OBEXGEN_ReplyGetFilePart(GSM_Protocol_Message * msg,GSM_StateMachine * s)877 static GSM_Error OBEXGEN_ReplyGetFilePart(GSM_Protocol_Message *msg, GSM_StateMachine *s)
878 {
879 	size_t old,Pos=0,len2,pos2;
880 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
881 
882 	/* Non standard Sharp GX reply */
883 	if (msg->Type == 0x80) {
884 		return ERR_FILENOTEXIST;
885 	}
886 
887 	/* Generic error codes */
888 	if ((msg->Type & 0x7f) >= 0x40) {
889 		return OBEXGEN_HandleError(msg, s);
890 	}
891 
892 	switch (msg->Type) {
893 	case 0xA0:
894 		smprintf(s,"Last file part received\n");
895 		s->Phone.Data.Priv.OBEXGEN.FileLastPart = TRUE;
896 		if (msg->Length == 0) return ERR_NONE;
897 		/* Fallthrough */
898 	case 0x90:
899 		while(1) {
900 			if (Pos >= msg->Length) break;
901 			switch (msg->Buffer[Pos]) {
902 			case 0x48:
903 			case 0x49:
904 				smprintf(s,"File part received\n");
905 				old = s->Phone.Data.File->Used;
906 				s->Phone.Data.File->Used += msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2]-3;
907 				smprintf(s,"Length of file part: %i\n",
908 						msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2]-3);
909 				s->Phone.Data.File->Buffer = (unsigned char *)realloc(s->Phone.Data.File->Buffer,s->Phone.Data.File->Used);
910 				memcpy(s->Phone.Data.File->Buffer+old,msg->Buffer+Pos+3,s->Phone.Data.File->Used-old);
911 				return ERR_NONE;
912 			case 0xc3:
913 				/* Length */
914 				/**
915 				 * @todo Length is ignored now
916 				 */
917 				Pos += 5;
918 				break;
919 			case 0xcb:
920 				/* Skip Connection ID (we ignore this for now) */
921 				Pos += 5;
922 				break;
923 			case 0x4C:
924 				smprintf(s, "Application data received:");
925 				len2 =  msg->Buffer[Pos+1] * 256 + msg->Buffer[Pos+2];
926 				pos2 = 0;
927 				while(1) {
928 					if (pos2 >= len2) break;
929 					switch (msg->Buffer[Pos + 3 + pos2]) {
930 						case 0x00:
931 							if (Priv->Service == OBEX_m_OBEX) {
932 								Priv->m_obex_error = msg->Buffer[Pos + 3 + pos2 + 1];
933 								smprintf(s, " m-obex error=\"%d\"", Priv->m_obex_error);
934 								/* This field has fixed size */
935 								pos2 += 2;
936 								continue;
937 							}
938 							break;
939 					}
940 					pos2 += 2 + msg->Buffer[Pos + 3 + pos2 + 1];
941 				}
942 				smprintf(s, "\n");
943 				Pos += len2;
944 				break;
945 			default:
946 				Pos+=msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2];
947 				break;
948 			}
949 		}
950 		return ERR_UNKNOWNRESPONSE;
951 	}
952 	return ERR_UNKNOWNRESPONSE;
953 }
954 
OBEXGEN_PrivGetFilePart(GSM_StateMachine * s,GSM_File * File,gboolean FolderList)955 static GSM_Error OBEXGEN_PrivGetFilePart(GSM_StateMachine *s, GSM_File *File, gboolean FolderList)
956 {
957 	int 		Current = 0;
958 	GSM_Error		error;
959 	unsigned char 		req[2000], req2[200];
960 	int			retries;
961 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
962 
963 	s->Phone.Data.File 	= File;
964 	File->ReadOnly 		= FALSE;
965 	File->Protected 	= FALSE;
966 	File->Hidden		= FALSE;
967 	File->System		= FALSE;
968 	File->ModifiedEmpty	= TRUE;
969 
970 	if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
971 		OBEXGEN_AddConnectionID(s, req, &Current);
972 	}
973 
974 	if (File->Used == 0x00) {
975 		if (FolderList) {
976 			/* Type block */
977 			strcpy(req2,"x-obex/folder-listing");
978 			OBEXAddBlock(req, &Current, 0x42, req2, strlen(req2)+1);
979 
980 			/* Name block should be empty, we're already in this folder */
981 			OBEXAddBlock(req, &Current, 0x01, NULL, 0);
982 		} else {
983 			File->Folder = FALSE;
984 
985 			if (File->ID_FullName[0] == 0x00 && File->ID_FullName[1] == 0x00) {
986 				if (Priv->Service == OBEX_BrowsingFolders) {
987 					/* No file name? Grab OBEX capabilities in browse mode */
988 					smprintf(s, "No filename requested, grabbing OBEX capabilities as obex-capability.xml\n");
989 					EncodeUnicode(File->Name, "obex-capability.xml", 19);
990 					strcpy(req2,"x-obex/capability");
991 
992 					/* Type block */
993 					OBEXAddBlock(req, &Current, 0x42, req2, strlen(req2));
994 				} else if (Priv->Service == OBEX_IRMC) {
995 					/* No file name? Grab devinfo in IrMC mode */
996 					smprintf(s, "No filename requested, grabbing device information as devinfo.txt\n");
997 					EncodeUnicode(File->Name, "devinfo.txt", 19);
998 					EncodeUnicode(req2,"telecom/devinfo.txt",19);
999 
1000 					/* Name block */
1001 					OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1002 				} else {
1003 					return ERR_NOTSUPPORTED;
1004 				}
1005 			} else if (Priv->Service == OBEX_m_OBEX) {
1006 				OBEXAddBlock(req, &Current, 0x42, DecodeUnicodeString(File->ID_FullName), UnicodeLength(File->ID_FullName) + 1);
1007 			} else {
1008 				if (Priv->Service == OBEX_BrowsingFolders) {
1009 					error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, TRUE, req2);
1010 					if (error != ERR_NONE) return error;
1011 				} else {
1012 					CopyUnicodeString(req2,File->ID_FullName);
1013 				}
1014 				CopyUnicodeString(File->Name,req2);
1015 
1016 				s->Phone.Data.File = File;
1017 
1018 				Current = 0;
1019 				/* Name block */
1020 				OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1021 			}
1022 		}
1023 	}
1024 
1025 	Priv->FileLastPart = FALSE;
1026 
1027 	/* Include m-obex application data */
1028 	if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
1029 		OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
1030 	}
1031 
1032 	smprintf(s, "Getting first file part\n");
1033 	retries = 0;
1034 	while (retries < 5) {
1035 		if (retries > 0) {
1036 			smprintf(s, "Retry %d\n", retries);
1037 		}
1038 		error=GSM_WaitFor (s, req, Current, 0x83, OBEX_TIMEOUT, ID_GetFile);
1039 		if (error != ERR_PERMISSION) break;
1040 		usleep(200000);
1041 		retries++;
1042 	}
1043 	if (error != ERR_NONE) return error;
1044 
1045 	while (!Priv->FileLastPart) {
1046 		Current = 0;
1047 		if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
1048 			OBEXGEN_AddConnectionID(s, req, &Current);
1049 		}
1050 		/* Include m-obex application data */
1051 		if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
1052 			OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
1053 		}
1054 		smprintf(s, "Getting next file part\n");
1055 		/* We retry for ERR_PERMISSION, because it can be caused by database locked error */
1056 		retries = 0;
1057 		while (retries < 5) {
1058 			if (retries > 0) {
1059 				smprintf(s, "Retry %d\n", retries);
1060 			}
1061 			error = GSM_WaitFor (s, req, Current, 0x83, OBEX_TIMEOUT, ID_GetFile);
1062 			if (error != ERR_PERMISSION) break;
1063 			usleep(200000);
1064 			retries++;
1065 		}
1066 		if (error != ERR_NONE) return error;
1067 	}
1068 	return ERR_EMPTY;
1069 }
1070 
OBEXGEN_GetFilePart(GSM_StateMachine * s,GSM_File * File,int * Handle,size_t * Size)1071 GSM_Error OBEXGEN_GetFilePart(GSM_StateMachine *s, GSM_File *File, int *Handle, size_t *Size)
1072 {
1073 	GSM_Error		error;
1074 
1075 	/* Go to default service */
1076 	error = OBEXGEN_Connect(s, 0);
1077 	if (error != ERR_NONE) return error;
1078 
1079 	(*Handle) = 0;
1080 	error = OBEXGEN_PrivGetFilePart(s, File, FALSE);
1081 	(*Size) = File->Used;
1082 	return error;
1083 }
1084 
1085 
1086 /**
1087  * List OBEX folder.
1088  */
1089 /**
1090  * @todo We assume XML reply is in UTF-8, but this doesn't have to be true.
1091  */
OBEXGEN_GetNextFileFolder(GSM_StateMachine * s,GSM_File * File,gboolean start)1092 GSM_Error OBEXGEN_GetNextFileFolder(GSM_StateMachine *s, GSM_File *File, gboolean start)
1093 {
1094 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1095 	GSM_Error		error;
1096 	unsigned char		Line[500],Line2[500],*name,*size;
1097 	int			i,j,num,pos2;
1098 	size_t			Pos;
1099 
1100 	/* Go to default service */
1101 	error = OBEXGEN_Connect(s, 0);
1102 	if (error != ERR_NONE) return error;
1103 
1104 	/* We can browse files only when using browse service */
1105 	if (Priv->Service != OBEX_BrowsingFolders) {
1106 		return ERR_NOTSUPPORTED;
1107 	}
1108 
1109 	if (start) {
1110 		Priv->Files[0].Folder		= TRUE;
1111 		Priv->Files[0].Level		= 1;
1112 		Priv->Files[0].Name[0]		= 0;
1113 		Priv->Files[0].Name[1]		= 0;
1114 		Priv->Files[0].ID_FullName[0]	= 0;
1115 		Priv->Files[0].ID_FullName[1]	= 0;
1116 
1117 		Priv->FilesLocationsUsed 	= 1;
1118 		Priv->FilesLocationsCurrent 	= 0;
1119 	}
1120 
1121 	while (1) {
1122 		if (Priv->FilesLocationsCurrent == Priv->FilesLocationsUsed) {
1123 			smprintf(s, "Last file\n");
1124 			return ERR_EMPTY;
1125 		}
1126 
1127 		CopyUnicodeString(File->ID_FullName,Priv->Files[Priv->FilesLocationsCurrent].ID_FullName);
1128 		File->Level	= Priv->Files[Priv->FilesLocationsCurrent].Level;
1129 		File->Folder	= Priv->Files[Priv->FilesLocationsCurrent].Folder;
1130 		CopyUnicodeString(File->Name,Priv->Files[Priv->FilesLocationsCurrent].Name);
1131 		Priv->FilesLocationsCurrent++;
1132 
1133 		if (File->Folder) {
1134 			error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
1135 			if (error != ERR_NONE) return error;
1136 
1137 			File->Buffer		= NULL;
1138 			File->Used		= 0;
1139 			File->ModifiedEmpty	= TRUE;
1140 
1141 			error = OBEXGEN_PrivGetFilePart(s, File, TRUE);
1142 			if (error != ERR_NONE && error != ERR_EMPTY) return error;
1143 
1144 			num = 0;
1145 			Pos = 0;
1146 			/* Calculate number of files */
1147 			while (1) {
1148 				error = MyGetLine(File->Buffer, &Pos, Line, File->Used, sizeof(Line), FALSE);
1149 				if (error != ERR_NONE) return error;
1150 				if (strlen(Line) == 0) break;
1151 				name = strstr(Line,"folder name=\"");
1152 				if (name != NULL) {
1153 					name += 13;
1154 					j = 0;
1155 					while(1) {
1156 						if (name[j] == '"') break;
1157 						j++;
1158 					}
1159 					name[j] = 0;
1160 
1161 					if (strcmp(name,".")) num++;
1162 				}
1163 				name = strstr(Line,"file name=\"");
1164 				if (name != NULL) num++;
1165 			}
1166 			/* Shift current files to the end of list */
1167 			if (num != 0) {
1168 				i = Priv->FilesLocationsUsed-1;
1169 				while (1) {
1170 					if (i==Priv->FilesLocationsCurrent-1) break;
1171 					memcpy(&Priv->Files[i+num],&Priv->Files[i],sizeof(GSM_File));
1172 					i--;
1173 				}
1174 			}
1175 
1176 			/* Actually parse file listing */
1177 			Pos 	= 0;
1178 			pos2 	= 0;
1179 			while (1) {
1180 				error = MyGetLine(File->Buffer, &Pos, Line, File->Used, sizeof(Line), FALSE);
1181 				if (error != ERR_NONE) return error;
1182 				if (strlen(Line) == 0) break;
1183 				strcpy(Line2,Line);
1184 				name = strstr(Line2,"folder name=\"");
1185 				if (name != NULL) {
1186 					name += 13;
1187 					j = 0;
1188 					while(1) {
1189 						if (name[j] == '"') break;
1190 						j++;
1191 					}
1192 					name[j] = 0;
1193 					if (strcmp(name,".")) {
1194 						smprintf(s, "copying folder %s to %i parent %i\n",name,Priv->FilesLocationsCurrent+pos2,Priv->FilesLocationsCurrent);
1195 						/* Convert filename from UTF-8 */
1196 						DecodeXMLUTF8(Priv->Files[Priv->FilesLocationsCurrent+pos2].Name, name, strlen(name));
1197 						/* Create file name from parts */
1198 						OBEXGEN_CreateFileName(
1199 							Priv->Files[Priv->FilesLocationsCurrent+pos2].ID_FullName,
1200 							File->ID_FullName,
1201 							Priv->Files[Priv->FilesLocationsCurrent+pos2].Name
1202 							);
1203 						Priv->Files[Priv->FilesLocationsCurrent+pos2].Level  = File->Level+1;
1204 						Priv->Files[Priv->FilesLocationsCurrent+pos2].Folder = TRUE;
1205 						Priv->FilesLocationsUsed++;
1206 						pos2++;
1207 					}
1208 				}
1209 				strcpy(Line2,Line);
1210 				name = strstr(Line2,"file name=\"");
1211 				if (name != NULL) {
1212 					name += 11;
1213 					j = 0;
1214 					while(1) {
1215 						if (name[j] == '"') break;
1216 						j++;
1217 					}
1218 					name[j] = 0;
1219 					smprintf(s, "copying file %s to %i\n",name,Priv->FilesLocationsCurrent+pos2);
1220 					/* Convert filename from UTF-8 */
1221 					DecodeXMLUTF8(Priv->Files[Priv->FilesLocationsCurrent+pos2].Name, name, strlen(name));
1222 					/* Create file name from parts */
1223 					OBEXGEN_CreateFileName(
1224 						Priv->Files[Priv->FilesLocationsCurrent+pos2].ID_FullName,
1225 						File->ID_FullName,
1226 						Priv->Files[Priv->FilesLocationsCurrent+pos2].Name
1227 						);
1228 
1229 					Priv->Files[Priv->FilesLocationsCurrent+pos2].Level	= File->Level+1;
1230 					Priv->Files[Priv->FilesLocationsCurrent+pos2].Folder 	= FALSE;
1231 					Priv->Files[Priv->FilesLocationsCurrent+pos2].Used 	= 0;
1232 					strcpy(Line2,Line);
1233 					size = strstr(Line2,"size=\"");
1234 					if (size != NULL) Priv->Files[Priv->FilesLocationsCurrent+pos2].Used = atoi(size+6);
1235 
1236 					Priv->Files[Priv->FilesLocationsCurrent+pos2].ModifiedEmpty = TRUE;
1237 					strcpy(Line2,Line);
1238 					size = strstr(Line2,"modified=\"");
1239 					if (size != NULL) {
1240 						Priv->Files[Priv->FilesLocationsCurrent+pos2].ModifiedEmpty = FALSE;
1241 						ReadVCALDateTime(size+10, &Priv->Files[Priv->FilesLocationsCurrent+pos2].Modified);
1242 					}
1243 					Priv->FilesLocationsUsed++;
1244 					pos2++;
1245 				}
1246 			}
1247 
1248 			free(File->Buffer);
1249 			File->Buffer = NULL;
1250 		} else {
1251 			File->Used 	    	= Priv->Files[Priv->FilesLocationsCurrent-1].Used;
1252 			File->ModifiedEmpty 	= Priv->Files[Priv->FilesLocationsCurrent-1].ModifiedEmpty;
1253 			if (!File->ModifiedEmpty) {
1254 				memcpy(&File->Modified,&Priv->Files[Priv->FilesLocationsCurrent-1].Modified,sizeof(GSM_DateTime));
1255 			}
1256 			File->ReadOnly 		= FALSE;
1257 			File->Protected 	= FALSE;
1258 			File->Hidden		= FALSE;
1259 			File->System		= FALSE;
1260 
1261 		}
1262 		return ERR_NONE;
1263 	}
1264 }
1265 
OBEXGEN_DeleteFile(GSM_StateMachine * s,unsigned char * ID)1266 GSM_Error OBEXGEN_DeleteFile(GSM_StateMachine *s, unsigned char *ID)
1267 {
1268 	GSM_Error		error;
1269 	int		Current = 0;
1270 	unsigned char		req[200],req2[200];
1271 
1272 	/* Go to default service */
1273 	error = OBEXGEN_Connect(s, 0);
1274 	if (error != ERR_NONE) return error;
1275 
1276 	if (s->Phone.Data.Priv.OBEXGEN.Service != OBEX_BrowsingFolders) {
1277 		return ERR_NOTSUPPORTED;
1278 	}
1279 
1280 	/* Go to file directory */
1281 	error = OBEXGEN_ChangeToFilePath(s, ID, TRUE, req2);
1282 	if (error != ERR_NONE) return error;
1283 
1284 	/* Name block */
1285 	OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1286 
1287 	/* connection ID block */
1288 	OBEXGEN_AddConnectionID(s, req, &Current);
1289 
1290 	return GSM_WaitFor (s, req, Current, 0x82, OBEX_TIMEOUT, ID_AddFile);
1291 }
1292 
OBEXGEN_AddFolder(GSM_StateMachine * s,GSM_File * File)1293 GSM_Error OBEXGEN_AddFolder(GSM_StateMachine *s, GSM_File *File)
1294 {
1295 	GSM_Error		error;
1296 
1297 	/* Go to default service */
1298 	error = OBEXGEN_Connect(s, 0);
1299 	if (error != ERR_NONE) return error;
1300 
1301 	if (s->Phone.Data.Priv.OBEXGEN.Service != OBEX_BrowsingFolders) {
1302 		return ERR_NOTSUPPORTED;
1303 	}
1304 
1305 	/* Go to file directory */
1306 	error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
1307 	if (error != ERR_NONE) return error;
1308 
1309 	/* Add folder */
1310 	smprintf(s,"Adding directory\n");
1311 	error = OBEXGEN_ChangePath(s, File->Name, 0);
1312 	if (error != ERR_NONE) return error;
1313 
1314 	/* Calculate path of added folder */
1315 	OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
1316 	return ERR_NONE;
1317 }
1318 
1319 /*@}*/
1320 
1321 /**
1322  * \defgroup OBEXhelper OBEX helper functions which are used in IrMC code
1323  * \ingroup OBEXPhone
1324  * @{
1325  */
1326 
1327 /**
1328  * Grabs complete single file
1329  */
OBEXGEN_GetFile(GSM_StateMachine * s,const char * FileName,unsigned char ** Buffer,size_t * len)1330 GSM_Error OBEXGEN_GetFile(GSM_StateMachine *s, const char *FileName, unsigned char ** Buffer, size_t *len)
1331 {
1332 	GSM_Error error = ERR_NONE;
1333 	GSM_File File;
1334 
1335 	/* Clear structure */
1336 	memset(&File, 0, sizeof(GSM_File));
1337 
1338 	/* Encode file name to unicode */
1339 	EncodeUnicode(File.ID_FullName, FileName, strlen(FileName));
1340 
1341 	/* Grab complete file */
1342 	while (error == ERR_NONE) {
1343 		error = OBEXGEN_PrivGetFilePart(s, &File, FALSE);
1344 	}
1345 
1346 	/* We should get ERR_EMPTY at the end of file */
1347 	if (error != ERR_EMPTY) {
1348 		if (File.Buffer != NULL) {
1349 			free(File.Buffer);
1350 			File.Buffer=NULL;
1351 		}
1352 		return error;
1353 	}
1354 
1355 	/* Return data we got */
1356 	*Buffer = File.Buffer;
1357 	*len = File.Used;
1358 	return ERR_NONE;
1359 }
1360 
1361 /**
1362  * Grabs complete single binary file
1363  */
OBEXGEN_GetBinaryFile(GSM_StateMachine * s,const char * FileName,unsigned char ** Buffer,size_t * len)1364 GSM_Error OBEXGEN_GetBinaryFile(GSM_StateMachine *s, const char *FileName, unsigned char ** Buffer, size_t *len)
1365 {
1366 	GSM_Error error = ERR_NONE;
1367 
1368 	/* Grab complete file */
1369 	error = OBEXGEN_GetFile(s, FileName, (unsigned char **)Buffer, len);
1370 	if (error != ERR_NONE) return error;
1371 
1372 	/* Return data we got */
1373 	smprintf(s, "Got %ld bytes of data\n", (long int)*len);
1374 	*Buffer = (unsigned char *)realloc(*Buffer, *len + 1);
1375 	if (*Buffer == NULL) {
1376 		return ERR_MOREMEMORY;
1377 	}
1378 	(*Buffer)[*len] = 0;
1379 	return ERR_NONE;
1380 }
1381 
1382 /**
1383  * Grabs complete single text file
1384  */
OBEXGEN_GetTextFile(GSM_StateMachine * s,const char * FileName,char ** Buffer)1385 GSM_Error OBEXGEN_GetTextFile(GSM_StateMachine *s, const char *FileName, char ** Buffer)
1386 {
1387 	size_t len;
1388 
1389 	return OBEXGEN_GetBinaryFile(s, FileName, (unsigned char **)Buffer, &len);
1390 }
1391 
1392 /**
1393  * Sets single file on filesystem, file can be created or updated.
1394  */
OBEXGEN_SetFile(GSM_StateMachine * s,const char * FileName,const unsigned char * Buffer,size_t Length,gboolean HardDelete)1395 GSM_Error OBEXGEN_SetFile(GSM_StateMachine *s, const char *FileName, const unsigned char *Buffer, size_t Length, gboolean HardDelete)
1396 {
1397 	GSM_Error	error = ERR_NONE;
1398 	GSM_File 	File;
1399 	size_t		Pos = 0;
1400 	int Handle;
1401 
1402 	/* Fill file structure */
1403 	EncodeUnicode(File.ID_FullName, FileName, strlen(FileName));
1404 	EncodeUnicode(File.Name, FileName, strlen(FileName));
1405 	File.Used 	= Length;
1406 	File.Buffer 	= (unsigned char *)Buffer;
1407 
1408 	/* Send file */
1409 	while (error == ERR_NONE) {
1410 		error = OBEXGEN_PrivAddFilePart(s, &File, &Pos, &Handle, HardDelete);
1411 	}
1412 	if (error != ERR_EMPTY) return error;
1413 
1414 	return ERR_NONE;
1415 }
1416 
1417 /*@}*/
1418 
1419 /**
1420  * \defgroup IrMChelper Generic IrMC helper functions
1421  * \ingroup OBEXPhone
1422  * @{
1423  */
1424 
1425 /**
1426  * Parses selected information from IrMC info.log. Information parsed:
1427  *  * IEL (Information Exchange Level)
1428  *  * Number of free records
1429  *  * Number of used records
1430  */
OBEXGEN_ParseInfoLog(GSM_StateMachine * s,const char * data,int * free_out,int * used_out,IRMC_Capability * Cap)1431 GSM_Error OBEXGEN_ParseInfoLog(GSM_StateMachine *s, const char *data, int *free_out, int *used_out, IRMC_Capability *Cap)
1432 {
1433 	char *pos;
1434 	int IEL;
1435 	int maximum_records = -1;
1436 	int used_records = -1;
1437 	int free_records = -1;
1438 	char free_text[] = "Free-Records:";
1439 	char used_text[] = "Total-Records:";
1440 	char maximum_text[] = "Maximum-Records:";
1441 	char IEL_text[] = "IEL:";
1442 	char HD_text[] = "HD:";
1443 
1444 	smprintf(s, "OBEX info data:\n---\n%s\n---\n", data);
1445 
1446 	pos = strstr(data, IEL_text);
1447 	if (pos == NULL) {
1448 		smprintf(s, "Could not grab Information Exchange Level, phone does not support it\n");
1449 		return ERR_NOTSUPPORTED;
1450 	}
1451 	pos += strlen(IEL_text);
1452 	/* This might be hex */
1453 	if (pos[0] != 0 && pos[0] == '0' && pos[1] != 0 && pos[1] == 'x') {
1454 		/* Hex means IEL flag we use */
1455 		IEL = strtol(pos + 2, (char **)NULL, 16);
1456 	} else {
1457 		/* Decimal means directly IEL level, convert it to flags */
1458 		IEL = atoi(pos);
1459 		/* Adjust index to flags we use further */
1460 		switch (IEL) {
1461 			case 3:
1462 				IEL = 0x4;
1463 				break;
1464 			case 4:
1465 				IEL = 0x8;
1466 				/* In fact this can be also 0x10, but we can't tell */
1467 				break;
1468 		}
1469 	}
1470 	switch (IEL) {
1471 		case 0x1:
1472 			smprintf(s, "Information Exchange Level 1 supported\n");
1473 			break;
1474 		case 0x2:
1475 			smprintf(s, "Information Exchange Level 1 and 2 supported\n");
1476 			break;
1477 		case 0x4:
1478 			smprintf(s, "Information Exchange Level 1, 2 and 3 supported\n");
1479 			break;
1480 		case 0x8:
1481 			smprintf(s, "Information Exchange Level 1, 2 and 4 supported\n");
1482 			break;
1483 		case 0x10:
1484 			smprintf(s, "Information Exchange Level 1, 2, 3 and 4 supported\n");
1485 			break;
1486 		default:
1487 			smprintf(s, "Could not parse Information Exchange Level (0x%x)\n", IEL);
1488 			return ERR_INVALIDDATA;
1489 	}
1490 
1491 	if (Cap != NULL) {
1492 		Cap->IEL = IEL;
1493 	}
1494 
1495 	pos = strstr(data, HD_text);
1496 	if (pos == NULL) {
1497 		smprintf(s, "Could not grab HD support\n");
1498 	} else {
1499 		pos += strlen(HD_text);
1500 		if (strncasecmp("YES", pos, 3) == 0) {
1501 			smprintf(s, "HD is supported\n");
1502 			if (Cap != NULL) {
1503 				Cap->HD = TRUE;
1504 			}
1505 		} else if (strncasecmp("NO", pos, 2) == 0) {
1506 			smprintf(s, "HD is not supported\n");
1507 		} else {
1508 			smprintf(s, "WARNING: Could not parse HD support\n");
1509 		}
1510 	}
1511 
1512 	pos = strstr(data, free_text);
1513 	if (pos == NULL) {
1514 		smprintf(s, "Could not grab number of free records\n");
1515 	} else {
1516 		pos += strlen(free_text);
1517 		free_records = atoi(pos);
1518 		smprintf(s, "Number of free records: %d\n", free_records);
1519 	}
1520 
1521 	pos = strstr(data, used_text);
1522 	if (pos == NULL) {
1523 		smprintf(s, "Could not grab number of used records\n");
1524 	} else {
1525 		pos += strlen(used_text);
1526 		used_records = atoi(pos);
1527 		smprintf(s, "Number of used records: %d\n", used_records);
1528 	}
1529 
1530 	pos = strstr(data, maximum_text);
1531 	if (pos == NULL) {
1532 		smprintf(s, "Could not grab number of maximum records\n");
1533 	} else {
1534 		pos += strlen(maximum_text);
1535 		maximum_records = atoi(pos);
1536 		smprintf(s, "Number of maximum records: %d\n", maximum_records);
1537 	}
1538 
1539 	if (free_out != NULL) {
1540 		if (free_records != -1) {
1541 			*free_out = free_records;
1542 		} else if (maximum_records != -1 && used_records != -1) {
1543 			*free_out = maximum_records - used_records;
1544 		} else {
1545 			*free_out = 0;
1546 			smprintf(s, "Could not grab number of free records\n");
1547 			return ERR_INVALIDDATA;
1548 		}
1549 	}
1550 
1551 	if (used_out != NULL) {
1552 		if (used_records != -1) {
1553 			*used_out = used_records;
1554 		} else if (maximum_records != -1 && free_records != -1) {
1555 			*used_out = maximum_records - free_records;
1556 		} else {
1557 			*used_out = 0;
1558 			smprintf(s, "Could not grab number of used records\n");
1559 			return ERR_INVALIDDATA;
1560 		}
1561 	}
1562 
1563 	return ERR_NONE;
1564 }
1565 
1566 /**
1567  * Grabs information from defined OBEX IrMC information log into variables.
1568  */
OBEXGEN_GetInformation(GSM_StateMachine * s,const char * path,int * free_records,int * used_records,IRMC_Capability * Cap)1569 GSM_Error OBEXGEN_GetInformation(GSM_StateMachine *s, const char *path, int *free_records, int *used_records, IRMC_Capability *Cap)
1570 {
1571 	GSM_Error 	error;
1572 	char		*data;
1573 
1574 	/* IEL by default - support adding */
1575 	Cap->IEL = 1;
1576 
1577 	/* We need IrMC service for this */
1578 	error = OBEXGEN_Connect(s, OBEX_IRMC);
1579 	if (error != ERR_NONE) return error;
1580 
1581 	/* Grab log info file */
1582 	error = OBEXGEN_GetTextFile(s, path, &data);
1583 
1584 	/* Level 0 or 1 phones do not have to expose information */
1585 	if (error == ERR_BUG || error == ERR_FILENOTEXIST || error == ERR_PERMISSION) {
1586 		/* Some phones do not follow IrMC specs and do not provide info.log for level 2 */
1587 		if (GSM_IsPhoneFeatureAvailable(s->Phone.Data.ModelInfo, F_IRMC_LEVEL_2)) {
1588 			Cap->IEL = 2;
1589 		}
1590 		if (free_records == NULL) {
1591 			/* We were asked only for IEL, so don't bail out */
1592 			return ERR_NONE;
1593 		} else {
1594 			/* No support for status if no info.log */
1595 			return ERR_NOTSUPPORTED;
1596 		}
1597 	} else if (error != ERR_NONE) {
1598 		/* Something wrong has happened */
1599 		return error;
1600 	}
1601 
1602 	/* Parse it */
1603 	error = OBEXGEN_ParseInfoLog(s, data, free_records, used_records, Cap);
1604 
1605 	free(data);
1606 	data=NULL;
1607 	return error;
1608 }
1609 
1610 /**
1611  * Finds first empty location in index list and appends it.
1612  */
OBEXGEN_GetFirstFreeLocation(int ** IndexStorage,int * IndexCount)1613 int OBEXGEN_GetFirstFreeLocation(int **IndexStorage, int *IndexCount) {
1614 	int i;
1615 	int max = -1;
1616 
1617 	/* Find maximum used location */
1618 	for (i = 0; i < *IndexCount; i++) {
1619 		if (*IndexStorage[i] > max) {
1620 			max = (*IndexStorage)[i];
1621 		}
1622 	}
1623 
1624 	/* Next behind maximum is empty */
1625 	max++;
1626 
1627 	/* Update internal list */
1628 	(*IndexCount)++;
1629 	*IndexStorage = (int *)realloc(*IndexStorage, (*IndexCount + 1) * sizeof(int));
1630 	(*IndexStorage)[*IndexCount] = max;
1631 
1632 	return max;
1633 }
1634 
1635 /**
1636  * Initialises LUID database, which is used for LUID - Location mapping.
1637  */
OBEXGEN_InitLUID(GSM_StateMachine * s,const char * Name,const gboolean Recalculate,const char * Header,char ** Data,int ** Offsets,int * Count,char *** LUIDStorage,int * LUIDCount,int ** IndexStorage,int * IndexCount)1638 GSM_Error OBEXGEN_InitLUID(GSM_StateMachine *s, const char *Name,
1639 		const gboolean Recalculate,
1640 		const char *Header,
1641 		char **Data, int **Offsets, int *Count,
1642 		char ***LUIDStorage, int *LUIDCount,
1643 		int **IndexStorage, int *IndexCount)
1644 {
1645 	GSM_Error 	error;
1646 	char		*pos;
1647 	int		LUIDSize = 0;
1648 	int		IndexSize = 0;
1649 	int		Size = 0;
1650 	size_t		linepos = 0;
1651 	int		prevpos;
1652 	char		line[2000];
1653 	size_t		len;
1654 	size_t		hlen;
1655 	int		level = 0;
1656 
1657 	/* Free data if previously allocated */
1658 	if (!Recalculate) {
1659 		if (*Data != NULL) {
1660 			free(*Data);
1661 			*Data=NULL;
1662 		}
1663 	}
1664 	/**
1665 	 * @todo should free all data here, but this execution path is not supported now
1666 	 */
1667 
1668 	/* Grab file with listing */
1669 	if (!Recalculate || *Data == NULL) {
1670 		/* We need IrMC service for this */
1671 		error = OBEXGEN_Connect(s, OBEX_IRMC);
1672 		if (error != ERR_NONE) return error;
1673 
1674 		error = OBEXGEN_GetTextFile(s, Name, Data);
1675 		if (error != ERR_NONE) return error;
1676 	}
1677 
1678 	*Count = 0;
1679 	*Offsets = NULL;
1680 	*LUIDCount = 0;
1681 	*LUIDStorage = NULL;
1682 	*IndexCount = 0;
1683 	*IndexStorage = NULL;
1684 	len = strlen(*Data);
1685 	hlen = strlen(Header);
1686 
1687 	while (1) {
1688 		/* Remember line start position */
1689 		prevpos = linepos;
1690 		error = MyGetLine(*Data, &linepos, line, len, sizeof(line), TRUE);
1691 		if (error != ERR_NONE) return error;
1692 		if (strlen(line) == 0) break;
1693 		switch (level) {
1694 			case 0:
1695 				if (strncmp(line, Header, hlen) == 0) {
1696 					level = 1;
1697 					(*Count)++;
1698 					/* Do we need to reallocate? */
1699 					if (*Count >= Size) {
1700 						Size += 20;
1701 						*Offsets = (int *)realloc(*Offsets, Size * sizeof(int));
1702 						if (*Offsets == NULL) {
1703 							return ERR_MOREMEMORY;
1704 						}
1705 					}
1706 					/* Store start of item */
1707 					(*Offsets)[*Count] = prevpos;
1708 				} else if (strncmp(line, "BEGIN:VCALENDAR", 15) == 0) {
1709 					/* We need to skip vCalendar header */
1710 				} else if (strncmp(line, "BEGIN:", 6) == 0) {
1711 					/* Skip other event types */
1712 					level = 2;
1713 				}
1714 				break;
1715 			case 1:
1716 				if (strncmp(line, "END:", 4) == 0) {
1717 					level = 0;
1718 				} else if (strncmp(line, "X-IRMC-LUID:", 12) == 0) {
1719 					pos = line + 12; /* Length of X-IRMC-LUID: */
1720 					(*LUIDCount)++;
1721 					/* Do we need to reallocate? */
1722 					if (*LUIDCount >= LUIDSize) {
1723 						LUIDSize += 20;
1724 						*LUIDStorage = (char **)realloc(*LUIDStorage, LUIDSize * sizeof(char *));
1725 						if (*LUIDStorage == NULL) {
1726 							return ERR_MOREMEMORY;
1727 						}
1728 					}
1729 					/* Copy LUID text */
1730 					(*LUIDStorage)[*LUIDCount] = strdup(pos);
1731 #if 0
1732 					smprintf(s, "Added LUID %s at position %d\n", (*LUIDStorage)[*LUIDCount], *LUIDCount);
1733 #endif
1734 				} else if (strncmp(line, "X-INDEX:", 8) == 0) {
1735 					pos = line + 8; /* Length of X-INDEX: */
1736 					(*IndexCount)++;
1737 					/* Do we need to reallocate? */
1738 					if (*IndexCount >= IndexSize) {
1739 						IndexSize += 20;
1740 						*IndexStorage = (int *)realloc(*IndexStorage, IndexSize * sizeof(int));
1741 						if (*IndexStorage == NULL) {
1742 							return ERR_MOREMEMORY;
1743 						}
1744 					}
1745 					/* Copy Index text */
1746 					(*IndexStorage)[*IndexCount] = atoi(pos);
1747 #if 0
1748 					smprintf(s, "Added Index %d at position %d\n", (*IndexStorage)[*IndexCount], *IndexCount);
1749 #endif
1750 				}
1751 				break;
1752 			case 2:
1753 				if (strncmp(line, "END:", 4) == 0) level = 0;
1754 				break;
1755 		}
1756 	}
1757 
1758 	smprintf(s, "Data parsed, found %d entries, %d indexes and %d LUIDs\n", *Count, *IndexCount, *LUIDCount);
1759 
1760 	return ERR_NONE;
1761 }
1762 
1763 /*@}*/
1764 
1765 /**
1766  * \defgroup IrMCphonebook IrMC phonebook support
1767  * \ingroup OBEXPhone
1768  * @{
1769  */
1770 
1771 /**
1772  * Parses pb/info.log (phonebook IrMC information log).
1773  */
OBEXGEN_GetPbInformation(GSM_StateMachine * s,int * free_records,int * used)1774 GSM_Error OBEXGEN_GetPbInformation(GSM_StateMachine *s, int *free_records, int *used)
1775 {
1776 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1777 
1778 	return OBEXGEN_GetInformation(s, "telecom/pb/info.log", free_records, used, &(Priv->PbCap));
1779 
1780 }
1781 
1782 /**
1783  * Grabs phonebook memory status
1784  */
OBEXGEN_GetMemoryStatus(GSM_StateMachine * s,GSM_MemoryStatus * Status)1785 GSM_Error OBEXGEN_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status)
1786 {
1787 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1788 
1789 	if (Status->MemoryType != MEM_ME && Status->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
1790 
1791 	if (Priv->Service == OBEX_m_OBEX) {
1792 		return MOBEX_GetStatus(s, "m-obex/contacts/count", Status->MemoryType, &(Status->MemoryFree), &(Status->MemoryUsed));
1793 	}
1794 
1795 	if (Status->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
1796 
1797 	return OBEXGEN_GetPbInformation(s, &(Status->MemoryFree), &(Status->MemoryUsed));
1798 
1799 }
1800 
1801 /**
1802  * Initializes phonebook LUID database.
1803  */
OBEXGEN_InitPbLUID(GSM_StateMachine * s)1804 GSM_Error OBEXGEN_InitPbLUID(GSM_StateMachine *s)
1805 {
1806 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1807 
1808 	/* We might do validation here using telecom/pb/luid/cc.log fir IEL 4, but not on each request */
1809 	if (Priv->PbData != NULL) return ERR_NONE;
1810 
1811 	return OBEXGEN_InitLUID(s, "telecom/pb.vcf", FALSE, "BEGIN:VCARD",
1812 			&(Priv->PbData), &(Priv->PbOffsets), &(Priv->PbCount),
1813 			&(Priv->PbLUID), &(Priv->PbLUIDCount),
1814 			&(Priv->PbIndex), &(Priv->PbIndexCount));
1815 }
1816 
1817 /**
1818  * Read memory by reading static index.
1819  */
OBEXGEN_GetMemoryIndex(GSM_StateMachine * s,GSM_MemoryEntry * Entry)1820 GSM_Error OBEXGEN_GetMemoryIndex(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1821 {
1822 	GSM_Error 	error;
1823 	char		*data=NULL;
1824 	char		*path=NULL;
1825 	size_t		pos = 0;
1826 
1827 	error = OBEXGEN_InitPbLUID(s);
1828 	if (error != ERR_NONE) return error;
1829 
1830 	/* Calculate path */
1831 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
1832 	if (path == NULL) {
1833 		return ERR_MOREMEMORY;
1834 	}
1835 	sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
1836 	smprintf(s, "Getting vCard %s\n", path);
1837 
1838 	/* Grab vCard */
1839 	error = OBEXGEN_GetTextFile(s, path, &data);
1840 	free(path);
1841 	path=NULL;
1842 
1843 	if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
1844 	if (error != ERR_NONE) return error;
1845 
1846 	/* Decode it */
1847 	error = GSM_DecodeVCARD(&(s->di), data, &pos, Entry, SonyEricsson_VCard21_Phone);
1848 	free(data);
1849 	data=NULL;
1850 
1851 	if (error != ERR_NONE) return error;
1852 
1853 	return ERR_NONE;
1854 }
1855 
1856 /**
1857  * Reads memory by reading from LUID location.
1858  */
OBEXGEN_GetMemoryLUID(GSM_StateMachine * s,GSM_MemoryEntry * Entry)1859 GSM_Error OBEXGEN_GetMemoryLUID(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1860 {
1861 	GSM_Error 	error;
1862 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1863 	char		*data=NULL;
1864 	char		*path=NULL;
1865 	size_t		pos = 0;
1866 
1867 	error = OBEXGEN_InitPbLUID(s);
1868 	if (error != ERR_NONE) return error;
1869 
1870 	/* Check bounds */
1871 	if (Entry->Location > Priv->PbLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
1872 	if (Priv->PbLUID[Entry->Location] == NULL) return ERR_EMPTY;
1873 
1874 	/* Calculate path */
1875 	path = (char *)malloc(strlen(Priv->PbLUID[Entry->Location]) + 22); /* Length of string below */
1876 	if (path == NULL) {
1877 		return ERR_MOREMEMORY;
1878 	}
1879 	sprintf(path, "telecom/pb/luid/%s.vcf", Priv->PbLUID[Entry->Location]);
1880 	smprintf(s, "Getting vCard %s\n", path);
1881 
1882 	/* Grab vCard */
1883 	error = OBEXGEN_GetTextFile(s, path, &data);
1884 	free(path);
1885 	path=NULL;
1886 	if (error != ERR_NONE) return error;
1887 
1888 	/* Decode it */
1889 	error = GSM_DecodeVCARD(&(s->di), data, &pos, Entry, SonyEricsson_VCard21_Phone);
1890 	free(data);
1891 	data=NULL;
1892 	if (error != ERR_NONE) return error;
1893 
1894 	return ERR_NONE;
1895 }
1896 
1897 /**
1898  * Reads memory by reading from full data.
1899  */
OBEXGEN_GetMemoryFull(GSM_StateMachine * s,GSM_MemoryEntry * Entry)1900 GSM_Error OBEXGEN_GetMemoryFull(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1901 {
1902 	GSM_Error 	error;
1903 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1904 	size_t		pos = 0;
1905 
1906 	/* Read phonebook data */
1907 	error = OBEXGEN_InitPbLUID(s);
1908 	if (error != ERR_NONE) return error;
1909 
1910 	/* Check bounds */
1911 	if (Entry->Location > Priv->PbCount) return ERR_EMPTY; /* Maybe invalid location? */
1912 
1913 	/* Decode vCard */
1914 	error = GSM_DecodeVCARD(&(s->di), Priv->PbData + Priv->PbOffsets[Entry->Location], &pos, Entry, SonyEricsson_VCard21_Phone);
1915 	if (error != ERR_NONE) return error;
1916 
1917 	return ERR_NONE;
1918 }
1919 
OBEXGEN_GetMemory(GSM_StateMachine * s,GSM_MemoryEntry * Entry)1920 GSM_Error OBEXGEN_GetMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1921 {
1922 	GSM_Error 	error;
1923 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1924 
1925 	if (Entry->MemoryType != MEM_ME && Entry->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
1926 
1927 	/* Handle m-obex case */
1928 	if (Priv->Service == OBEX_m_OBEX) {
1929 		return MOBEX_GetMemory(s, Entry);
1930 	}
1931 
1932 	if (Entry->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
1933 
1934 	/* We need IrMC service for this */
1935 	error = OBEXGEN_Connect(s, OBEX_IRMC);
1936 	if (error != ERR_NONE) return error;
1937 
1938 	/* We need IEL to correctly talk to phone */
1939 	if (Priv->PbCap.IEL == -1) {
1940 		error = OBEXGEN_GetPbInformation(s, NULL, NULL);
1941 		if (error != ERR_NONE) return error;
1942 	}
1943 
1944 	/* Use correct function according to supported IEL */
1945 	if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
1946 		return OBEXGEN_GetMemoryLUID(s, Entry);
1947 	} else if (Priv->PbCap.IEL == 0x4) {
1948 		return OBEXGEN_GetMemoryIndex(s, Entry);
1949 	} else if (Priv->PbCap.IEL == 0x2) {
1950 		return OBEXGEN_GetMemoryFull(s, Entry);
1951 	} else {
1952 		smprintf(s, "Can not read phonebook from IEL 1 phone\n");
1953 		return ERR_NOTSUPPORTED;
1954 	}
1955 }
1956 
OBEXGEN_GetNextMemory(GSM_StateMachine * s,GSM_MemoryEntry * Entry,gboolean start)1957 GSM_Error OBEXGEN_GetNextMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry, gboolean start)
1958 {
1959 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
1960 	GSM_Error 	error = ERR_EMPTY;;
1961 
1962 
1963 	/* Handle m-obex case */
1964 	if (Priv->Service == OBEX_m_OBEX) {
1965 		return MOBEX_GetNextMemory(s, Entry, start);
1966 	}
1967 
1968 	/* Get  location */
1969 	if (start) {
1970 		Entry->Location = 1;
1971 		Priv->ReadPhonebook = 0;
1972 	} else {
1973 		Entry->Location++;
1974 	}
1975 
1976 	/* Do real getting */
1977 	while (error == ERR_EMPTY) {
1978 
1979 		/* Have we read them all? */
1980 		/* Needs to be inside loop as we get count after
1981 		 * first invocation of get function */
1982 		if (Priv->ReadPhonebook == Priv->PbCount) {
1983 			return ERR_EMPTY;
1984 		}
1985 
1986 		error = OBEXGEN_GetMemory(s, Entry);
1987 		if (error == ERR_NONE) {
1988 			Priv->ReadPhonebook++;
1989 		} else if (error == ERR_EMPTY) {
1990 			Entry->Location++;
1991 		}
1992 	}
1993 	return error;
1994 }
1995 
OBEXGEN_AddMemory(GSM_StateMachine * s,GSM_MemoryEntry * Entry)1996 GSM_Error OBEXGEN_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1997 {
1998 	unsigned char 		req[5000];
1999 	char			path[100];
2000 	size_t			size=0;
2001 	GSM_Error		error;
2002 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2003 
2004 	if (Entry->MemoryType != MEM_ME && (Entry->MemoryType != MEM_SM || Priv->Service != OBEX_m_OBEX)) return ERR_NOTSUPPORTED;
2005 
2006 	/* Encode vCard */
2007 	error = GSM_EncodeVCARD(&(s->di), req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCard21);
2008 	if (error != ERR_NONE) return error;
2009 
2010 	/* Handle m-obex case */
2011 	if (Priv->Service == OBEX_m_OBEX) {
2012 		return MOBEX_CreateEntry(s, "m-obex/contacts/create", Entry->MemoryType, &(Entry->Location), req);
2013 	}
2014 
2015 	/* We need IrMC service for this */
2016 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2017 	if (error != ERR_NONE) return error;
2018 
2019 	/* We need IEL to correctly talk to phone */
2020 	if (Priv->PbCap.IEL == -1) {
2021 		error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2022 		if (error != ERR_NONE) return error;
2023 	}
2024 
2025 	/* Use correct function according to supported IEL */
2026 	if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2027 		/* We need to grab LUID list now in order to keep position later */
2028 		error = OBEXGEN_InitPbLUID(s);
2029 		if (error != ERR_NONE) return error;
2030 
2031 		smprintf(s,"Adding phonebook entry %ld:\n%s\n", (long)size, req);
2032 		Priv->UpdatePbLUID = TRUE;
2033 		error = OBEXGEN_SetFile(s, "telecom/pb/luid/.vcf", req, size, FALSE);
2034 		Entry->Location = Priv->PbLUIDCount;
2035 		if (error == ERR_NONE) Priv->PbCount++;
2036 		return error;
2037 	} else if (Priv->PbCap.IEL == 0x4) {
2038 		/* We need to grab LUID/Index list now in order to keep position later */
2039 		error = OBEXGEN_InitPbLUID(s);
2040 		if (error != ERR_NONE) return error;
2041 
2042 		Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->PbIndex, &Priv->PbIndexCount);
2043 		smprintf(s,"Adding phonebook entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2044 		sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
2045 		error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2046 		if (error == ERR_NONE) Priv->PbCount++;
2047 		return error;
2048 	} else {
2049 		/* I don't know add command for other levels, just plain send vCard */
2050 		Entry->Location = 0;
2051 		smprintf(s,"Sending phonebook entry\n");
2052 		return OBEXGEN_SetFile(s, "gammu.vcf", req, size, FALSE);
2053 	}
2054 }
2055 
OBEXGEN_SetMemoryLUID(GSM_StateMachine * s,GSM_MemoryEntry * Entry,const char * Data,int Size)2056 GSM_Error OBEXGEN_SetMemoryLUID(GSM_StateMachine *s, GSM_MemoryEntry *Entry, const char *Data, int Size)
2057 {
2058 	GSM_Error 	error;
2059 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2060 	char		*path=NULL;
2061 
2062 	error = OBEXGEN_InitPbLUID(s);
2063 	if (error != ERR_NONE) return error;
2064 
2065 	/* Check bounds */
2066 	if (Entry->Location > Priv->PbLUIDCount ||
2067 			Priv->PbLUID[Entry->Location] == NULL) {
2068 		/**
2069 		 * \todo We should keep location here!
2070 		 */
2071 		return OBEXGEN_AddMemory(s, Entry);
2072 	}
2073 
2074 	/* Calculate path */
2075 	path = (char *)malloc(strlen(Priv->PbLUID[Entry->Location]) + 22); /* Length of string below */
2076 	if (path == NULL) {
2077 		return ERR_MOREMEMORY;
2078 	}
2079 	sprintf(path, "telecom/pb/luid/%s.vcf", Priv->PbLUID[Entry->Location]);
2080 	smprintf(s, "Seting vCard %s [%d]\n", path, Entry->Location);
2081 
2082 	/* Forget entry if we're deleting */
2083 	if (Size == 0) {
2084 		free(Priv->PbLUID[Entry->Location]);
2085 		Priv->PbLUID[Entry->Location] = NULL;
2086 		Priv->PbCount--;
2087 	}
2088 
2089 	/* Store vCard */
2090 	error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->PbCap.HD : FALSE);;
2091 	free(path);
2092 	return error;
2093 }
2094 
OBEXGEN_SetMemoryIndex(GSM_StateMachine * s,GSM_MemoryEntry * Entry,const char * Data,int Size)2095 GSM_Error OBEXGEN_SetMemoryIndex(GSM_StateMachine *s, GSM_MemoryEntry *Entry, const char *Data, int Size)
2096 {
2097 	char		*path=NULL;
2098 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2099 	GSM_Error		error;
2100 
2101 	/* Forget entry if we're deleting */
2102 	if (Size == 0) {
2103 		Priv->PbCount--;
2104 	}
2105 
2106 	/* Calculate path */
2107 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2108 	if (path == NULL) {
2109 		return ERR_MOREMEMORY;
2110 	}
2111 	sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
2112 	smprintf(s, "Seting vCard %s\n", path);
2113 
2114 	/* Store vCard */
2115 	error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
2116 	free(path);
2117 	return error;
2118 }
2119 
OBEXGEN_SetMemory(GSM_StateMachine * s,GSM_MemoryEntry * Entry)2120 GSM_Error OBEXGEN_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
2121 {
2122 	unsigned char 		req[5000];
2123 	size_t			size=0;
2124 	GSM_Error		error;
2125 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2126 
2127 	if (Entry->MemoryType != MEM_ME && (Entry->MemoryType != MEM_SM || Priv->Service != OBEX_m_OBEX)) return ERR_NOTSUPPORTED;
2128 
2129 	/* Encode vCard */
2130 	error = GSM_EncodeVCARD(&(s->di), req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCard21);
2131 	if (error != ERR_NONE) return error;
2132 
2133 	/* Handle m-obex case */
2134 	if (Priv->Service == OBEX_m_OBEX) {
2135 		return MOBEX_UpdateEntry(s, "m-obex/contacts/write", Entry->Location, Entry->MemoryType, req);
2136 	}
2137 
2138 	/* We need IrMC service for this */
2139 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2140 	if (error != ERR_NONE) return error;
2141 
2142 	/* We need IEL to correctly talk to phone */
2143 	if (Priv->PbCap.IEL == -1) {
2144 		error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2145 		if (error != ERR_NONE) return error;
2146 	}
2147 
2148 	/* Use correct function according to supported IEL */
2149 	if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2150 		return OBEXGEN_SetMemoryLUID(s, Entry, req, size);
2151 	} else if (Priv->PbCap.IEL == 0x4) {
2152 		return OBEXGEN_SetMemoryIndex(s, Entry, req, size);
2153 	} else if (Priv->PbCap.IEL == 0x2) {
2154 		/* Work on full phonebook */
2155 		return ERR_NOTIMPLEMENTED;
2156 	} else {
2157 		return ERR_NOTSUPPORTED;
2158 	}
2159 }
2160 
OBEXGEN_DeleteMemory(GSM_StateMachine * s,GSM_MemoryEntry * Entry)2161 GSM_Error OBEXGEN_DeleteMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
2162 {
2163 	GSM_Error		error;
2164 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2165 
2166 	if (Entry->MemoryType != MEM_ME && Entry->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
2167 
2168 	if (Priv->Service == OBEX_m_OBEX) {
2169 		return MOBEX_UpdateEntry(s, "m-obex/contacts/delete", Entry->Location, Entry->MemoryType, NULL);
2170 	}
2171 
2172 	if (Entry->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
2173 
2174 	/* We need IrMC service for this */
2175 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2176 	if (error != ERR_NONE) return error;
2177 
2178 	/* We need IEL to correctly talk to phone */
2179 	if (Priv->PbCap.IEL == -1) {
2180 		error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2181 		if (error != ERR_NONE) return error;
2182 	}
2183 
2184 	/* Use correct function according to supported IEL */
2185 	if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2186 		return OBEXGEN_SetMemoryLUID(s, Entry, "", 0);
2187 	} else if (Priv->PbCap.IEL == 0x4) {
2188 		return OBEXGEN_SetMemoryIndex(s, Entry, "", 0);
2189 	} else if (Priv->PbCap.IEL == 0x2) {
2190 		/* Work on full phonebook */
2191 		return ERR_NOTIMPLEMENTED;
2192 	} else {
2193 		return ERR_NOTSUPPORTED;
2194 	}
2195 }
2196 
OBEXGEN_DeleteAllMemory(GSM_StateMachine * s,GSM_MemoryType MemoryType)2197 GSM_Error OBEXGEN_DeleteAllMemory(GSM_StateMachine *s, GSM_MemoryType MemoryType)
2198 {
2199 	GSM_Error		error;
2200 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2201 	GSM_MemoryEntry		entry;
2202 
2203 	/* Should not happen */
2204 	if (MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
2205 
2206 	/* We need IrMC service for this */
2207 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2208 	if (error != ERR_NONE) return error;
2209 
2210 	/* We need count of entries */
2211 	error = OBEXGEN_InitPbLUID(s);
2212 	if (error != ERR_NONE) return error;
2213 
2214 	/* Delete all entries */
2215 	entry.Location = 1;
2216 	entry.MemoryType = MEM_ME;
2217 	while (Priv->PbCount > 0) {
2218 		error = OBEXGEN_DeleteMemory(s, &entry);
2219 		if (error != ERR_NONE && error != ERR_EMPTY) return error;
2220 		entry.Location++;
2221 	}
2222 	return error;
2223 }
2224 
2225 /*@}*/
2226 
2227 /**
2228  * \defgroup IrMCcaltodo IrMC common calendar and todo functions
2229  * \ingroup OBEXPhone
2230  * @{
2231  */
2232 
2233 /**
2234  * Parses cal/info.log (calendar IrMC information log).
2235  */
OBEXGEN_GetCalInformation(GSM_StateMachine * s,int * free_records,int * used)2236 GSM_Error OBEXGEN_GetCalInformation(GSM_StateMachine *s, int *free_records, int *used)
2237 {
2238 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2239 
2240 	return OBEXGEN_GetInformation(s, "telecom/cal/info.log", free_records, used, &(Priv->CalCap));
2241 
2242 }
2243 
2244 /**
2245  * Initializes calendar LUID database.
2246  */
OBEXGEN_InitCalLUID(GSM_StateMachine * s)2247 GSM_Error OBEXGEN_InitCalLUID(GSM_StateMachine *s)
2248 {
2249 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2250 	GSM_Error 	error;
2251 
2252 	/* We might do validation here using telecom/cal/luid/cc.log fir IEL 4, but not on each request */
2253 	if (Priv->CalData != NULL) return ERR_NONE;
2254 
2255 	error = OBEXGEN_InitLUID(s, "telecom/cal.vcs", FALSE, "BEGIN:VEVENT",
2256 			&(Priv->CalData), &(Priv->CalOffsets), &(Priv->CalCount),
2257 			&(Priv->CalLUID), &(Priv->CalLUIDCount),
2258 			&(Priv->CalIndex), &(Priv->CalIndexCount));
2259 	if (error != ERR_NONE) return error;
2260 	return OBEXGEN_InitLUID(s, "telecom/cal.vcs", TRUE, "BEGIN:VTODO",
2261 			&(Priv->CalData), &(Priv->TodoOffsets), &(Priv->TodoCount),
2262 			&(Priv->TodoLUID), &(Priv->TodoLUIDCount),
2263 			&(Priv->TodoIndex), &(Priv->TodoIndexCount));
2264 }
2265 
2266 /*@}*/
2267 
2268 /**
2269  * \defgroup IrMCcalendar IrMC calendar support
2270  * \ingroup OBEXPhone
2271  * @{
2272  */
2273 
2274 /**
2275  * Grabs calendar memory status
2276  */
OBEXGEN_GetCalendarStatus(GSM_StateMachine * s,GSM_CalendarStatus * Status)2277 GSM_Error OBEXGEN_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
2278 {
2279 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2280 	GSM_Error 	error;
2281 
2282 	if (Priv->Service == OBEX_m_OBEX) {
2283 		return MOBEX_GetStatus(s, "m-obex/calendar/count", MEM_ME, &(Status->Free), &(Status->Used));
2284 	}
2285 
2286 	error = OBEXGEN_InitCalLUID(s);
2287 	if (error != ERR_NONE) return error;
2288 
2289 	Status->Used = Priv->CalCount;
2290 
2291 	return OBEXGEN_GetCalInformation(s, &(Status->Free), NULL);
2292 
2293 }
2294 
2295 /**
2296  * Read memory by reading static index.
2297  */
OBEXGEN_GetCalendarIndex(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2298 GSM_Error OBEXGEN_GetCalendarIndex(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2299 {
2300 	GSM_Error 	error;
2301 	char		*data=NULL;
2302 	char		*path=NULL;
2303 	size_t		pos = 0;
2304 	GSM_ToDoEntry	ToDo;
2305 
2306 	error = OBEXGEN_InitCalLUID(s);
2307 	if (error != ERR_NONE) return error;
2308 
2309 	/* Calculate path */
2310 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2311 	if (path == NULL) {
2312 		return ERR_MOREMEMORY;
2313 	}
2314 	sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2315 	smprintf(s, "Getting vCalendar %s\n", path);
2316 
2317 	/* Grab vCalendar */
2318 	error = OBEXGEN_GetTextFile(s, path, &data);
2319 	free(path);
2320 	path=NULL;
2321 	if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
2322 	if (error != ERR_NONE) return error;
2323 
2324 	/* Decode it */
2325 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2326 	free(data);
2327 	data=NULL;
2328 	if (error != ERR_NONE) return error;
2329 
2330 	return ERR_NONE;
2331 }
2332 
2333 /**
2334  * Reads memory by reading from LUID location.
2335  */
OBEXGEN_GetCalendarLUID(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2336 GSM_Error OBEXGEN_GetCalendarLUID(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2337 {
2338 	GSM_Error 	error;
2339 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2340 	char		*data=NULL;
2341 	char		*path=NULL;
2342 	size_t		pos = 0;
2343 	GSM_ToDoEntry	ToDo;
2344 
2345 	error = OBEXGEN_InitCalLUID(s);
2346 	if (error != ERR_NONE) return error;
2347 
2348 	/* Check bounds */
2349 	if (Entry->Location > Priv->CalLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
2350 	if (Priv->CalLUID[Entry->Location] == NULL) return ERR_EMPTY;
2351 
2352 	/* Calculate path */
2353 	path = (char *)malloc(strlen(Priv->CalLUID[Entry->Location]) + 22); /* Length of string below */
2354 	if (path == NULL) {
2355 		return ERR_MOREMEMORY;
2356 	}
2357 	sprintf(path, "telecom/cal/luid/%s.vcs", Priv->CalLUID[Entry->Location]);
2358 	smprintf(s, "Getting vCalendar %s\n", path);
2359 
2360 	/* Grab vCalendar */
2361 	error = OBEXGEN_GetTextFile(s, path, &data);
2362 	free(path);
2363 	path=NULL;
2364 	if (error != ERR_NONE) return error;
2365 
2366 	/* Decode it */
2367 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2368 	free(data);
2369 	data=NULL;
2370 	if (error != ERR_NONE) return error;
2371 
2372 	return ERR_NONE;
2373 }
2374 
2375 /**
2376  * Reads memory by reading from full data.
2377  */
OBEXGEN_GetCalendarFull(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2378 GSM_Error OBEXGEN_GetCalendarFull(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2379 {
2380 	GSM_Error 	error;
2381 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2382 	size_t		pos = 0;
2383 	GSM_ToDoEntry	ToDo;
2384 
2385 	/* Read calendar data */
2386 	error = OBEXGEN_InitCalLUID(s);
2387 	if (error != ERR_NONE) return error;
2388 
2389 	/* Check bounds */
2390 	if (Entry->Location > Priv->CalCount) return ERR_EMPTY; /* Maybe invalid location? */
2391 
2392 	/* Decode vCalendar */
2393 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), Priv->CalData + Priv->CalOffsets[Entry->Location], &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2394 	if (error != ERR_NONE) return error;
2395 
2396 	return ERR_NONE;
2397 }
2398 
OBEXGEN_GetCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2399 GSM_Error OBEXGEN_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2400 {
2401 	GSM_Error 	error;
2402 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2403 
2404 	/* Handle m-obex case */
2405 	if (Priv->Service == OBEX_m_OBEX) {
2406 		return MOBEX_GetCalendar(s, Entry);
2407 	}
2408 
2409 	/* We need IrMC service for this */
2410 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2411 	if (error != ERR_NONE) return error;
2412 
2413 	/* We need IEL to correctly talk to phone */
2414 	if (Priv->CalCap.IEL == -1) {
2415 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2416 		if (error != ERR_NONE) return error;
2417 	}
2418 
2419 	/* Use correct function according to supported IEL */
2420 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2421 		return OBEXGEN_GetCalendarLUID(s, Entry);
2422 	} else if (Priv->CalCap.IEL == 0x4) {
2423 		return OBEXGEN_GetCalendarIndex(s, Entry);
2424 	} else if (Priv->CalCap.IEL == 0x2) {
2425 		return OBEXGEN_GetCalendarFull(s, Entry);
2426 	} else {
2427 		smprintf(s, "Can not read calendar from IEL 1 phone\n");
2428 		return ERR_NOTSUPPORTED;
2429 	}
2430 }
2431 
OBEXGEN_GetNextCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Entry,gboolean start)2432 GSM_Error OBEXGEN_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry, gboolean start)
2433 {
2434 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2435 	GSM_Error 	error = ERR_EMPTY;;
2436 
2437 	/* Handle m-obex case */
2438 	if (Priv->Service == OBEX_m_OBEX) {
2439 		return MOBEX_GetNextCalendar(s, Entry, start);
2440 	}
2441 
2442 	/* Get  location */
2443 	if (start) {
2444 		Entry->Location = 1;
2445 		Priv->ReadCalendar = 0;
2446 	} else {
2447 		Entry->Location++;
2448 	}
2449 
2450 	/* Do real getting */
2451 	while (error == ERR_EMPTY) {
2452 
2453 		/* Have we read them all? */
2454 		/* Needs to be inside loop as we get count after
2455 		 * first invocation of get function */
2456 		if (Priv->ReadCalendar == Priv->CalCount) {
2457 			return ERR_EMPTY;
2458 		}
2459 
2460 		error = OBEXGEN_GetCalendar(s, Entry);
2461 		if (error == ERR_NONE) {
2462 			Priv->ReadCalendar++;
2463 		} else if (error == ERR_EMPTY) {
2464 			Entry->Location++;
2465 		}
2466 	}
2467 	return error;
2468 }
2469 
OBEXGEN_AddCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2470 GSM_Error OBEXGEN_AddCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2471 {
2472 	unsigned char 		req[5000];
2473 	char			path[100];
2474 	size_t			size=0;
2475 	GSM_Error		error;
2476 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2477 
2478 	/* Encode vCalendar */
2479 	error = GSM_EncodeVCALENDAR(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCalendar);
2480 	if (error != ERR_NONE) return error;
2481 
2482 	/* Handle m-obex case */
2483 	if (Priv->Service == OBEX_m_OBEX) {
2484 		return MOBEX_CreateEntry(s, "m-obex/calendar/create", MEM_ME, &(Entry->Location), req);
2485 	}
2486 
2487 	/* We need IrMC service for this */
2488 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2489 	if (error != ERR_NONE) return error;
2490 
2491 	/* We need IEL to correctly talk to phone */
2492 	if (Priv->CalCap.IEL == -1) {
2493 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2494 		if (error != ERR_NONE) return error;
2495 	}
2496 
2497 	/* Use correct function according to supported IEL */
2498 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2499 		/* We need to grab LUID list now in order to keep position later */
2500 		error = OBEXGEN_InitCalLUID(s);
2501 		if (error != ERR_NONE) return error;
2502 
2503 		smprintf(s,"Adding calendar entry %ld:\n%s\n", (long)size, req);
2504 		Priv->UpdateCalLUID = TRUE;
2505 		error = OBEXGEN_SetFile(s, "telecom/cal/luid/.vcs", req, size, FALSE);
2506 		Entry->Location = Priv->CalLUIDCount;
2507 		if (error == ERR_NONE) Priv->CalCount++;
2508 		return error;
2509 	} else if (Priv->CalCap.IEL == 0x4) {
2510 		/* We need to grab LUID/Index list now in order to keep position later */
2511 		error = OBEXGEN_InitCalLUID(s);
2512 		if (error != ERR_NONE) return error;
2513 
2514 		Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->CalIndex, &Priv->CalIndexCount);
2515 		smprintf(s,"Adding calendar entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2516 		sprintf(path, "telecom/cal/%d.vcf", Entry->Location);
2517 		error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2518 		if (error == ERR_NONE) Priv->CalCount++;
2519 		return error;
2520 	} else {
2521 		/* I don't know add command for other levels, just plain send vCalendar */
2522 		Entry->Location = 0;
2523 		smprintf(s,"Sending calendar entry\n");
2524 		return OBEXGEN_SetFile(s, "gammu.vcs", req, size, FALSE);
2525 	}
2526 }
2527 
OBEXGEN_SetCalendarLUID(GSM_StateMachine * s,GSM_CalendarEntry * Entry,const char * Data,int Size)2528 GSM_Error OBEXGEN_SetCalendarLUID(GSM_StateMachine *s, GSM_CalendarEntry *Entry, const char *Data, int Size)
2529 {
2530 	GSM_Error 	error;
2531 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2532 	char		*path=NULL;
2533 
2534 	error = OBEXGEN_InitCalLUID(s);
2535 	if (error != ERR_NONE) return error;
2536 
2537 	/* Check bounds */
2538 	if (Entry->Location > Priv->CalLUIDCount
2539 			|| Priv->CalLUID[Entry->Location] == NULL) {
2540 		/**
2541 		 * \todo We should keep location here!
2542 		 */
2543 		return OBEXGEN_AddCalendar(s, Entry);
2544 	}
2545 
2546 	/* Calculate path */
2547 	path = (char *)malloc(strlen(Priv->CalLUID[Entry->Location]) + 22); /* Length of string below */
2548 	if (path == NULL) {
2549 		return ERR_MOREMEMORY;
2550 	}
2551 	sprintf(path, "telecom/cal/luid/%s.vcs", Priv->CalLUID[Entry->Location]);
2552 	smprintf(s, "Seting vCalendar %s\n", path);
2553 
2554 	/* Forget entry if we're deleting */
2555 	if (Size == 0) {
2556 		free(Priv->CalLUID[Entry->Location]);
2557 		Priv->CalLUID[Entry->Location] = NULL;
2558 		Priv->CalCount--;
2559 	}
2560 
2561 	/* Store vCalendar */
2562 	error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->CalCap.HD : FALSE);;
2563 	free(path);
2564 	return error;
2565 }
2566 
OBEXGEN_SetCalendarIndex(GSM_StateMachine * s,GSM_CalendarEntry * Entry,const char * Data,int Size)2567 GSM_Error OBEXGEN_SetCalendarIndex(GSM_StateMachine *s, GSM_CalendarEntry *Entry, const char *Data, int Size)
2568 {
2569 	char		*path=NULL;
2570 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2571 	GSM_Error		error;
2572 
2573 	/* Forget entry if we're deleting */
2574 	if (Size == 0) {
2575 		Priv->CalCount--;
2576 	}
2577 
2578 	/* Calculate path */
2579 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2580 	if (path == NULL) {
2581 		return ERR_MOREMEMORY;
2582 	}
2583 	sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2584 	smprintf(s, "Seting vCalendar %s\n", path);
2585 
2586 	/* Store vCalendar */
2587 	error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
2588 	free(path);
2589 	return error;
2590 }
2591 
OBEXGEN_SetCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2592 GSM_Error OBEXGEN_SetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2593 {
2594 	unsigned char 		req[5000];
2595 	size_t			size=0;
2596 	GSM_Error		error;
2597 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2598 
2599 	/* Encode vCalendar */
2600 	error = GSM_EncodeVCALENDAR(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCalendar);
2601 	if (error != ERR_NONE) return error;
2602 
2603 	/* Handle m-obex case */
2604 	if (Priv->Service == OBEX_m_OBEX) {
2605 		return MOBEX_UpdateEntry(s, "m-obex/calendar/write", Entry->Location, MEM_ME, req);
2606 	}
2607 
2608 	/* We need IrMC service for this */
2609 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2610 	if (error != ERR_NONE) return error;
2611 
2612 	/* We need IEL to correctly talk to phone */
2613 	if (Priv->CalCap.IEL == -1) {
2614 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2615 		if (error != ERR_NONE) return error;
2616 	}
2617 
2618 	/* Use correct function according to supported IEL */
2619 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2620 		return OBEXGEN_SetCalendarLUID(s, Entry, req, size);
2621 	} else if (Priv->CalCap.IEL == 0x4) {
2622 		return OBEXGEN_SetCalendarIndex(s, Entry, req, size);
2623 	} else if (Priv->CalCap.IEL == 0x2) {
2624 		/* Work on full calendar */
2625 		return ERR_NOTIMPLEMENTED;
2626 	} else {
2627 		return ERR_NOTSUPPORTED;
2628 	}
2629 }
2630 
OBEXGEN_DeleteCalendar(GSM_StateMachine * s,GSM_CalendarEntry * Entry)2631 GSM_Error OBEXGEN_DeleteCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2632 {
2633 	GSM_Error		error;
2634 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2635 
2636 	/* Handle m-obex case */
2637 	if (Priv->Service == OBEX_m_OBEX) {
2638 		return MOBEX_UpdateEntry(s, "m-obex/calendar/delete", Entry->Location, 1, NULL);
2639 	}
2640 
2641 	/* We need IrMC service for this */
2642 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2643 	if (error != ERR_NONE) return error;
2644 
2645 	/* We need IEL to correctly talk to phone */
2646 	if (Priv->CalCap.IEL == -1) {
2647 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2648 		if (error != ERR_NONE) return error;
2649 	}
2650 
2651 	/* Use correct function according to supported IEL */
2652 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2653 		return OBEXGEN_SetCalendarLUID(s, Entry, "", 0);
2654 	} else if (Priv->CalCap.IEL == 0x4) {
2655 		return OBEXGEN_SetCalendarIndex(s, Entry, "", 0);
2656 	} else if (Priv->CalCap.IEL == 0x2) {
2657 		/* Work on full calendar */
2658 		return ERR_NOTIMPLEMENTED;
2659 	} else {
2660 		return ERR_NOTSUPPORTED;
2661 	}
2662 }
2663 
OBEXGEN_DeleteAllCalendar(GSM_StateMachine * s)2664 GSM_Error OBEXGEN_DeleteAllCalendar(GSM_StateMachine *s)
2665 {
2666 	GSM_Error		error;
2667 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2668 	GSM_CalendarEntry		entry;
2669 
2670 	/* We need IrMC service for this */
2671 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2672 	if (error != ERR_NONE) return error;
2673 
2674 	/* We need count of entries */
2675 	error = OBEXGEN_InitCalLUID(s);
2676 	if (error != ERR_NONE) return error;
2677 
2678 	/* Delete all entries */
2679 	entry.Location = 1;
2680 	while (Priv->CalCount > 0) {
2681 		error = OBEXGEN_DeleteCalendar(s, &entry);
2682 		if (error != ERR_NONE && error != ERR_EMPTY) return error;
2683 		entry.Location++;
2684 	}
2685 	return error;
2686 }
2687 
2688 /*@}*/
2689 
2690 /**
2691  * \defgroup IrMCtodo IrMC todo support
2692  * \ingroup OBEXPhone
2693  * @{
2694  */
2695 
2696 /**
2697  * Grabs todo memory status
2698  */
OBEXGEN_GetTodoStatus(GSM_StateMachine * s,GSM_ToDoStatus * Status)2699 GSM_Error OBEXGEN_GetTodoStatus(GSM_StateMachine *s, GSM_ToDoStatus *Status)
2700 {
2701 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2702 	GSM_Error 	error;
2703 
2704 	if (Priv->Service == OBEX_m_OBEX) {
2705 		return MOBEX_GetStatus(s, "m-obex/calendar/count", 0xff, &(Status->Free), &(Status->Used));
2706 	}
2707 
2708 	error = OBEXGEN_InitCalLUID(s);
2709 	if (error != ERR_NONE) return error;
2710 
2711 	Status->Used = Priv->TodoCount;
2712 
2713 	return OBEXGEN_GetCalInformation(s, &(Status->Free), NULL);
2714 
2715 }
2716 
2717 /**
2718  * Read memory by reading static index.
2719  */
OBEXGEN_GetTodoIndex(GSM_StateMachine * s,GSM_ToDoEntry * Entry)2720 GSM_Error OBEXGEN_GetTodoIndex(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2721 {
2722 	GSM_Error 	error;
2723 	char		*data=NULL;
2724 	char		*path=NULL;
2725 	size_t		pos = 0;
2726 	GSM_CalendarEntry	Cal;
2727 
2728 	/* Todoculate path */
2729 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2730 	if (path == NULL) {
2731 		return ERR_MOREMEMORY;
2732 	}
2733 	sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2734 	smprintf(s, "Getting vTodo %s\n", path);
2735 
2736 	/* Grab vTodo */
2737 	error = OBEXGEN_GetTextFile(s, path, &data);
2738 	free(path);
2739 	path=NULL;
2740 	if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
2741 	if (error != ERR_NONE) return error;
2742 
2743 	/* Decode it */
2744 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2745 	free(data);
2746 	data=NULL;
2747 	if (error != ERR_NONE) return error;
2748 
2749 	return ERR_NONE;
2750 }
2751 
2752 /**
2753  * Reads memory by reading from LUID location.
2754  */
OBEXGEN_GetTodoLUID(GSM_StateMachine * s,GSM_ToDoEntry * Entry)2755 GSM_Error OBEXGEN_GetTodoLUID(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2756 {
2757 	GSM_Error 	error;
2758 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2759 	char		*data=NULL;
2760 	char		*path=NULL;
2761 	size_t		pos = 0;
2762 	GSM_CalendarEntry	Cal;
2763 
2764 	error = OBEXGEN_InitCalLUID(s);
2765 	if (error != ERR_NONE) return error;
2766 
2767 	/* Check bounds */
2768 	if (Entry->Location > Priv->TodoLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
2769 	if (Priv->TodoLUID[Entry->Location] == NULL) return ERR_EMPTY;
2770 
2771 	/* Todoculate path */
2772 	path = (char *)malloc(strlen(Priv->TodoLUID[Entry->Location]) + 22); /* Length of string below */
2773 	if (path == NULL) {
2774 		return ERR_MOREMEMORY;
2775 	}
2776 	sprintf(path, "telecom/cal/luid/%s.vcs", Priv->TodoLUID[Entry->Location]);
2777 	smprintf(s, "Getting vTodo %s\n", path);
2778 
2779 	/* Grab vTodo */
2780 	error = OBEXGEN_GetTextFile(s, path, &data);
2781 	free(path);
2782 	path=NULL;
2783 	if (error != ERR_NONE) return error;
2784 
2785 	/* Decode it */
2786 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2787 	free(data);
2788 	data=NULL;
2789 	if (error != ERR_NONE) return error;
2790 
2791 	return ERR_NONE;
2792 }
2793 
2794 /**
2795  * Reads memory by reading from full data.
2796  */
OBEXGEN_GetTodoFull(GSM_StateMachine * s,GSM_ToDoEntry * Entry)2797 GSM_Error OBEXGEN_GetTodoFull(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2798 {
2799 	GSM_Error 	error;
2800 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2801 	size_t		pos = 0;
2802 	GSM_CalendarEntry	Cal;
2803 
2804 	/* Read todo data */
2805 	error = OBEXGEN_InitCalLUID(s);
2806 	if (error != ERR_NONE) return error;
2807 
2808 	/* Check bounds */
2809 	if (Entry->Location > Priv->TodoCount) return ERR_EMPTY; /* Maybe invalid location? */
2810 
2811 	/* Decode vTodo */
2812 	error = GSM_DecodeVCALENDAR_VTODO(&(s->di), Priv->CalData + Priv->TodoOffsets[Entry->Location], &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2813 	if (error != ERR_NONE) return error;
2814 
2815 	return ERR_NONE;
2816 }
2817 
OBEXGEN_GetTodo(GSM_StateMachine * s,GSM_ToDoEntry * Entry)2818 GSM_Error OBEXGEN_GetTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2819 {
2820 	GSM_Error 	error;
2821 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2822 
2823 	/* Handle m-obex case */
2824 	if (Priv->Service == OBEX_m_OBEX) {
2825 		return MOBEX_GetTodo(s, Entry);
2826 	}
2827 
2828 	/* We need IrMC service for this */
2829 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2830 	if (error != ERR_NONE) return error;
2831 
2832 	/* We need IEL to correctly talk to phone */
2833 	if (Priv->CalCap.IEL == -1) {
2834 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2835 		if (error != ERR_NONE) return error;
2836 	}
2837 
2838 	/* Use correct function according to supported IEL */
2839 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2840 		return OBEXGEN_GetTodoLUID(s, Entry);
2841 	} else if (Priv->CalCap.IEL == 0x4) {
2842 		return OBEXGEN_GetTodoIndex(s, Entry);
2843 	} else if (Priv->CalCap.IEL == 0x2) {
2844 		return OBEXGEN_GetTodoFull(s, Entry);
2845 	} else {
2846 		smprintf(s, "Can not read todo from IEL 1 phone\n");
2847 		return ERR_NOTSUPPORTED;
2848 	}
2849 }
2850 
OBEXGEN_GetNextTodo(GSM_StateMachine * s,GSM_ToDoEntry * Entry,gboolean start)2851 GSM_Error OBEXGEN_GetNextTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry, gboolean start)
2852 {
2853 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2854 	GSM_Error 	error = ERR_EMPTY;;
2855 
2856 	/* Handle m-obex case */
2857 	if (Priv->Service == OBEX_m_OBEX) {
2858 		return MOBEX_GetNextTodo(s, Entry, start);
2859 	}
2860 
2861 	/* Get  location */
2862 	if (start) {
2863 		Entry->Location = 1;
2864 		Priv->ReadTodo = 0;
2865 	} else {
2866 		Entry->Location++;
2867 	}
2868 
2869 	smprintf (s, "stat: %d, %d\n", Priv->ReadTodo, Priv->TodoCount);
2870 
2871 	/* Do real getting */
2872 	while (error == ERR_EMPTY) {
2873 
2874 		/* Have we read them all? */
2875 		/* Needs to be inside loop as we get count after
2876 		 * first invocation of get function */
2877 		if (Priv->ReadTodo >= Priv->TodoCount) {
2878 			return ERR_EMPTY;
2879 		}
2880 
2881 		error = OBEXGEN_GetTodo(s, Entry);
2882 		smprintf (s, "attempted location: %d, %d\n", Entry->Location, error);
2883 		if (error == ERR_NONE) {
2884 			Priv->ReadTodo++;
2885 		} else if (error == ERR_EMPTY) {
2886 			Entry->Location++;
2887 		}
2888 	}
2889 	return error;
2890 }
2891 
OBEXGEN_AddTodo(GSM_StateMachine * s,GSM_ToDoEntry * Entry)2892 GSM_Error OBEXGEN_AddTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2893 {
2894 	unsigned char 		req[5000];
2895 	char			path[100];
2896 	size_t			size=0;
2897 	GSM_Error		error;
2898 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2899 
2900 	/* Encode vTodo */
2901 	error = GSM_EncodeVTODO(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VToDo);
2902 	if (error != ERR_NONE) return error;
2903 
2904 	/* Handle m-obex case */
2905 	if (Priv->Service == OBEX_m_OBEX) {
2906 		return MOBEX_CreateEntry(s, "m-obex/calendar/create", 7 /* 0xff */, &(Entry->Location), req);
2907 	}
2908 
2909 	/* We need IrMC service for this */
2910 	error = OBEXGEN_Connect(s, OBEX_IRMC);
2911 	if (error != ERR_NONE) return error;
2912 
2913 	/* We need IEL to correctly talk to phone */
2914 	if (Priv->CalCap.IEL == -1) {
2915 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2916 		if (error != ERR_NONE) return error;
2917 	}
2918 
2919 	/* Use correct function according to supported IEL */
2920 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2921 		/* We need to grab LUID list now in order to keep position later */
2922 		error = OBEXGEN_InitCalLUID(s);
2923 		if (error != ERR_NONE) return error;
2924 
2925 		smprintf(s,"Adding todo entry %ld:\n%s\n", (long)size, req);
2926 		Priv->UpdateTodoLUID = TRUE;
2927 		error = OBEXGEN_SetFile(s, "telecom/cal/luid/.vcs", req, size, FALSE);
2928 		Entry->Location = Priv->TodoLUIDCount;
2929 		if (error == ERR_NONE) Priv->TodoCount++;
2930 		return error;
2931 	} else if (Priv->CalCap.IEL == 0x4) {
2932 		/* We need to grab LUID/Index list now in order to keep position later */
2933 		error = OBEXGEN_InitCalLUID(s);
2934 		if (error != ERR_NONE) return error;
2935 
2936 		Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->TodoIndex, &Priv->TodoIndexCount);
2937 		smprintf(s,"Adding todo entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2938 		sprintf(path, "telecom/cal/%d.vcf", Entry->Location);
2939 		error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2940 		if (error == ERR_NONE) Priv->TodoCount++;
2941 		return error;
2942 	} else {
2943 		/* I don't know add command for other levels, just plain send vTodo */
2944 		Entry->Location = 0;
2945 		smprintf(s,"Sending todo entry\n");
2946 		return OBEXGEN_SetFile(s, "gammu.vcs", req, size, FALSE);
2947 	}
2948 }
2949 
OBEXGEN_SetTodoLUID(GSM_StateMachine * s,GSM_ToDoEntry * Entry,const char * Data,int Size)2950 GSM_Error OBEXGEN_SetTodoLUID(GSM_StateMachine *s, GSM_ToDoEntry *Entry, const char *Data, int Size)
2951 {
2952 	GSM_Error 	error;
2953 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2954 	char		*path=NULL;
2955 
2956 	error = OBEXGEN_InitCalLUID(s);
2957 	if (error != ERR_NONE) return error;
2958 
2959 	/* Check bounds */
2960 	if (Entry->Location > Priv->TodoLUIDCount ||
2961 			NULL == Priv->TodoLUID || Priv->TodoLUID[Entry->Location] == NULL) {
2962 		/**
2963 		 * \todo We should keep location here!
2964 		 */
2965 		return OBEXGEN_AddTodo(s, Entry);
2966 	}
2967 
2968 	/* Calculate path */
2969 	path = (char *)malloc(strlen(Priv->TodoLUID[Entry->Location]) + 22); /* Length of string below */
2970 	if (path == NULL) {
2971 		return ERR_MOREMEMORY;
2972 	}
2973 	sprintf(path, "telecom/cal/luid/%s.vcs", Priv->TodoLUID[Entry->Location]);
2974 	smprintf(s, "Seting vTodo %s\n", path);
2975 
2976 	/* Forget entry if we're deleting */
2977 	if (Size == 0) {
2978 		free(Priv->TodoLUID[Entry->Location]);
2979 		Priv->TodoLUID[Entry->Location] = NULL;
2980 		Priv->TodoCount--;
2981 	}
2982 
2983 	/* Store vTodo */
2984 	error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->CalCap.HD : FALSE);;
2985 	free(path);
2986 	return error;
2987 }
2988 
OBEXGEN_SetTodoIndex(GSM_StateMachine * s,GSM_ToDoEntry * Entry,const char * Data,int Size)2989 GSM_Error OBEXGEN_SetTodoIndex(GSM_StateMachine *s, GSM_ToDoEntry *Entry, const char *Data, int Size)
2990 {
2991 	char		*path=NULL;
2992 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
2993 	GSM_Error		error;
2994 
2995 	/* Forget entry if we're deleting */
2996 	if (Size == 0) {
2997 		Priv->TodoCount--;
2998 	}
2999 
3000 	/* Todoculate path */
3001 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3002 	if (path == NULL) {
3003 		return ERR_MOREMEMORY;
3004 	}
3005 	sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
3006 	smprintf(s, "Seting vTodo %s\n", path);
3007 
3008 	/* Store vTodo */
3009 	error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
3010 	free(path);
3011 	return error;
3012 }
3013 
OBEXGEN_SetTodo(GSM_StateMachine * s,GSM_ToDoEntry * Entry)3014 GSM_Error OBEXGEN_SetTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
3015 {
3016 	unsigned char 		req[5000];
3017 	size_t			size=0;
3018 	GSM_Error		error;
3019 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3020 
3021 	/* Encode vTodo */
3022 	error = GSM_EncodeVTODO(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VToDo);
3023 	if (error != ERR_NONE) return error;
3024 
3025 	/* Handle m-obex case */
3026 	if (Priv->Service == OBEX_m_OBEX) {
3027 		return MOBEX_UpdateEntry(s, "m-obex/calendar/write",
3028 					 Entry->Location, 7, req);
3029 	}
3030 
3031 	/* We need IrMC service for this */
3032 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3033 	if (error != ERR_NONE) return error;
3034 
3035 	/* We need IEL to correctly talk to phone */
3036 	if (Priv->CalCap.IEL == -1) {
3037 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
3038 		if (error != ERR_NONE) return error;
3039 	}
3040 
3041 	/* Use correct function according to supported IEL */
3042 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
3043 		return OBEXGEN_SetTodoLUID(s, Entry, req, size);
3044 	} else if (Priv->CalCap.IEL == 0x4) {
3045 		return OBEXGEN_SetTodoIndex(s, Entry, req, size);
3046 	} else if (Priv->CalCap.IEL == 0x2) {
3047 		/* Work on full todo */
3048 		return ERR_NOTIMPLEMENTED;
3049 	} else {
3050 		return ERR_NOTSUPPORTED;
3051 	}
3052 }
3053 
OBEXGEN_DeleteTodo(GSM_StateMachine * s,GSM_ToDoEntry * Entry)3054 GSM_Error OBEXGEN_DeleteTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
3055 {
3056 	GSM_Error		error;
3057 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3058 
3059 	/* Handle m-obex case */
3060 	if (Priv->Service == OBEX_m_OBEX) {
3061 		return MOBEX_UpdateEntry(s, "m-obex/calendar/delete", Entry->Location, 7 /* 0xff */, NULL);
3062 	}
3063 
3064 	/* We need IrMC service for this */
3065 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3066 	if (error != ERR_NONE) return error;
3067 
3068 	/* We need IEL to correctly talk to phone */
3069 	if (Priv->CalCap.IEL == -1) {
3070 		error = OBEXGEN_GetCalInformation(s, NULL, NULL);
3071 		if (error != ERR_NONE) return error;
3072 	}
3073 
3074 	/* Use correct function according to supported IEL */
3075 	if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
3076 		return OBEXGEN_SetTodoLUID(s, Entry, "", 0);
3077 	} else if (Priv->CalCap.IEL == 0x4) {
3078 		return OBEXGEN_SetTodoIndex(s, Entry, "", 0);
3079 	} else if (Priv->CalCap.IEL == 0x2) {
3080 		/* Work on full todo */
3081 		return ERR_NOTIMPLEMENTED;
3082 	} else {
3083 		return ERR_NOTSUPPORTED;
3084 	}
3085 }
3086 
OBEXGEN_DeleteAllTodo(GSM_StateMachine * s)3087 GSM_Error OBEXGEN_DeleteAllTodo(GSM_StateMachine *s)
3088 {
3089 	GSM_Error		error;
3090 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3091 	GSM_ToDoEntry		entry;
3092 
3093 	/* We need IrMC service for this */
3094 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3095 	if (error != ERR_NONE) return error;
3096 
3097 	/* We need count of entries */
3098 	error = OBEXGEN_InitCalLUID(s);
3099 	if (error != ERR_NONE) return error;
3100 
3101 	/* Delete all entries */
3102 	entry.Location = 1;
3103 	while (Priv->TodoCount > 0) {
3104 		error = OBEXGEN_DeleteTodo(s, &entry);
3105 		if (error != ERR_NONE && error != ERR_EMPTY) return error;
3106 		entry.Location++;
3107 	}
3108 	return error;
3109 }
3110 
3111 /*@}*/
3112 
3113 /**
3114  * \defgroup IrMCnote IrMC note support
3115  * \ingroup OBEXPhone
3116  * @{
3117  */
3118 
3119 /**
3120  * Parses pb/info.log (note IrMC information log).
3121  */
OBEXGEN_GetNoteInformation(GSM_StateMachine * s,int * free_records,int * used)3122 GSM_Error OBEXGEN_GetNoteInformation(GSM_StateMachine *s, int *free_records, int *used)
3123 {
3124 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3125 
3126 	return OBEXGEN_GetInformation(s, "telecom/nt/info.log", free_records, used, &(Priv->NoteCap));
3127 
3128 }
3129 
3130 /**
3131  * Grabs note memory status
3132  */
OBEXGEN_GetNoteStatus(GSM_StateMachine * s,GSM_ToDoStatus * Status)3133 GSM_Error OBEXGEN_GetNoteStatus(GSM_StateMachine *s, GSM_ToDoStatus *Status)
3134 {
3135 	return OBEXGEN_GetNoteInformation(s, &(Status->Free), &(Status->Used));
3136 
3137 }
3138 
3139 /**
3140  * Initializes note LUID database.
3141  */
OBEXGEN_InitNoteLUID(GSM_StateMachine * s)3142 GSM_Error OBEXGEN_InitNoteLUID(GSM_StateMachine *s)
3143 {
3144 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3145 
3146 	/* We might do validation here using telecom/nt/luid/cc.log fir IEL 4, but not on each request */
3147 	if (Priv->NoteData != NULL) return ERR_NONE;
3148 
3149 	return OBEXGEN_InitLUID(s, "telecom/nt.vcf", FALSE, "BEGIN:VNOTE",
3150 			&(Priv->NoteData), &(Priv->NoteOffsets), &(Priv->NoteCount),
3151 			&(Priv->NoteLUID), &(Priv->NoteLUIDCount),
3152 			&(Priv->NoteIndex), &(Priv->NoteIndexCount));
3153 }
3154 
3155 /**
3156  * Read memory by reading static index.
3157  */
OBEXGEN_GetNoteIndex(GSM_StateMachine * s,GSM_NoteEntry * Entry)3158 GSM_Error OBEXGEN_GetNoteIndex(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3159 {
3160 	GSM_Error 	error;
3161 	char		*data=NULL;
3162 	char		*path=NULL;
3163 	size_t		pos = 0;
3164 
3165 	error = OBEXGEN_InitNoteLUID(s);
3166 	if (error != ERR_NONE) return error;
3167 
3168 	/* Calculate path */
3169 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3170 	if (path == NULL) {
3171 		return ERR_MOREMEMORY;
3172 	}
3173 	sprintf(path, "telecom/nt/%d.vnt", Entry->Location);
3174 	smprintf(s, "Getting vNote %s\n", path);
3175 
3176 	/* Grab vCard */
3177 	error = OBEXGEN_GetTextFile(s, path, &data);
3178 	free(path);
3179 	path=NULL;
3180 	if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
3181 	if (error != ERR_NONE) return error;
3182 
3183 	/* Decode it */
3184 	error = GSM_DecodeVNOTE(data, &pos, Entry);
3185 	free(data);
3186 	data=NULL;
3187 	if (error != ERR_NONE) return error;
3188 
3189 	return ERR_NONE;
3190 }
3191 
3192 /**
3193  * Reads memory by reading from LUID location.
3194  */
OBEXGEN_GetNoteLUID(GSM_StateMachine * s,GSM_NoteEntry * Entry)3195 GSM_Error OBEXGEN_GetNoteLUID(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3196 {
3197 	GSM_Error 	error;
3198 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3199 	char		*data=NULL;
3200 	char		*path=NULL;
3201 	size_t		pos = 0;
3202 
3203 	error = OBEXGEN_InitNoteLUID(s);
3204 	if (error != ERR_NONE) return error;
3205 
3206 	/* Check bounds */
3207 	if (Entry->Location > Priv->NoteLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
3208 	if (Priv->NoteLUID[Entry->Location] == NULL) return ERR_EMPTY;
3209 
3210 	/* Calculate path */
3211 	path = (char *)malloc(strlen(Priv->NoteLUID[Entry->Location]) + 22); /* Length of string below */
3212 	if (path == NULL) {
3213 		return ERR_MOREMEMORY;
3214 	}
3215 	sprintf(path, "telecom/nt/luid/%s.vnt", Priv->NoteLUID[Entry->Location]);
3216 	smprintf(s, "Getting vNote %s\n", path);
3217 
3218 	/* Grab vCard */
3219 	error = OBEXGEN_GetTextFile(s, path, &data);
3220 	free(path);
3221 	path=NULL;
3222 	if (error != ERR_NONE) return error;
3223 
3224 	/* Decode it */
3225 	error = GSM_DecodeVNOTE(data, &pos, Entry);
3226 	free(data);
3227 	data=NULL;
3228 	if (error != ERR_NONE) return error;
3229 
3230 	return ERR_NONE;
3231 }
3232 
3233 /**
3234  * Reads memory by reading from full data.
3235  */
OBEXGEN_GetNoteFull(GSM_StateMachine * s,GSM_NoteEntry * Entry)3236 GSM_Error OBEXGEN_GetNoteFull(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3237 {
3238 	GSM_Error 	error;
3239 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3240 	size_t		pos = 0;
3241 
3242 	/* Read note data */
3243 	error = OBEXGEN_InitNoteLUID(s);
3244 	if (error != ERR_NONE) return error;
3245 
3246 	/* Check bounds */
3247 	if (Entry->Location > Priv->NoteCount) return ERR_EMPTY; /* Maybe invalid location? */
3248 
3249 	/* Decode vNote */
3250 	error = GSM_DecodeVNOTE(Priv->NoteData + Priv->NoteOffsets[Entry->Location], &pos, Entry);
3251 	if (error != ERR_NONE) return error;
3252 
3253 	return ERR_NONE;
3254 }
3255 
OBEXGEN_GetNote(GSM_StateMachine * s,GSM_NoteEntry * Entry)3256 GSM_Error OBEXGEN_GetNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3257 {
3258 	GSM_Error 	error;
3259 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3260 
3261 	/* We need IrMC service for this */
3262 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3263 	if (error != ERR_NONE) return error;
3264 
3265 	/* We need IEL to correctly talk to phone */
3266 	if (Priv->NoteCap.IEL == -1) {
3267 		error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3268 		if (error != ERR_NONE) return error;
3269 	}
3270 
3271 	/* Use correct function according to supported IEL */
3272 	if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3273 		return OBEXGEN_GetNoteLUID(s, Entry);
3274 	} else if (Priv->NoteCap.IEL == 0x4) {
3275 		return OBEXGEN_GetNoteIndex(s, Entry);
3276 	} else if (Priv->NoteCap.IEL == 0x2) {
3277 		return OBEXGEN_GetNoteFull(s, Entry);
3278 	} else {
3279 		smprintf(s, "Can not read note from IEL 1 phone\n");
3280 		return ERR_NOTSUPPORTED;
3281 	}
3282 }
3283 
OBEXGEN_GetNextNote(GSM_StateMachine * s,GSM_NoteEntry * Entry,gboolean start)3284 GSM_Error OBEXGEN_GetNextNote(GSM_StateMachine *s, GSM_NoteEntry *Entry, gboolean start)
3285 {
3286 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3287 	GSM_Error 	error = ERR_EMPTY;;
3288 
3289 	/* Get  location */
3290 	if (start) {
3291 		Entry->Location = 1;
3292 		Priv->ReadPhonebook = 0;
3293 	} else {
3294 		Entry->Location++;
3295 	}
3296 
3297 	/* Do real getting */
3298 	while (error == ERR_EMPTY) {
3299 
3300 		/* Have we read them all? */
3301 		/* Needs to be inside loop as we get count after
3302 		 * first invocation of get function */
3303 		if (Priv->ReadPhonebook == Priv->NoteCount) {
3304 			return ERR_EMPTY;
3305 		}
3306 
3307 		error = OBEXGEN_GetNote(s, Entry);
3308 		if (error == ERR_NONE) {
3309 			Priv->ReadPhonebook++;
3310 		} else if (error == ERR_EMPTY) {
3311 			Entry->Location++;
3312 		}
3313 	}
3314 	return error;
3315 }
3316 
OBEXGEN_AddNote(GSM_StateMachine * s,GSM_NoteEntry * Entry)3317 GSM_Error OBEXGEN_AddNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3318 {
3319 	unsigned char 		req[5000];
3320 	char			path[100];
3321 	size_t			size=0;
3322 	GSM_Error		error;
3323 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3324 
3325 	/* We need IrMC service for this */
3326 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3327 	if (error != ERR_NONE) return error;
3328 
3329 	/* We need IEL to correctly talk to phone */
3330 	if (Priv->NoteCap.IEL == -1) {
3331 		error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3332 		if (error != ERR_NONE) return error;
3333 	}
3334 
3335 	/* Encode vNote */
3336 	error = GSM_EncodeVNTFile(req, sizeof(req), &size, Entry);
3337 	if (error != ERR_NONE) return error;
3338 
3339 	/* Use correct function according to supported IEL */
3340 	if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3341 		/* We need to grab LUID list now in order to keep position later */
3342 		error = OBEXGEN_InitNoteLUID(s);
3343 		if (error != ERR_NONE) return error;
3344 
3345 		smprintf(s,"Adding note entry %ld:\n%s\n", (long)size, req);
3346 		Priv->UpdateNoteLUID = TRUE;
3347 		error = OBEXGEN_SetFile(s, "telecom/nt/luid/.vnt", req, size, FALSE);
3348 		Entry->Location = Priv->NoteLUIDCount;
3349 		if (error == ERR_NONE) Priv->NoteCount++;
3350 		return error;
3351 	} else if (Priv->NoteCap.IEL == 0x4) {
3352 		/* We need to grab LUID/Index list now in order to keep position later */
3353 		error = OBEXGEN_InitNoteLUID(s);
3354 		if (error != ERR_NONE) return error;
3355 
3356 		Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->NoteIndex, &Priv->NoteIndexCount);
3357 		smprintf(s,"Adding note entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
3358 		sprintf(path, "telecom/nt/%d.vcf", Entry->Location);
3359 		error = OBEXGEN_SetFile(s, path, req, size, FALSE);
3360 		if (error == ERR_NONE) Priv->NoteCount++;
3361 		return error;
3362 	} else {
3363 		/* I don't know add command for other levels, just plain send vCard */
3364 		Entry->Location = 0;
3365 		smprintf(s,"Sending note entry\n");
3366 		return OBEXGEN_SetFile(s, "gammu.vnt", req, size, FALSE);
3367 	}
3368 }
3369 
OBEXGEN_SetNoteLUID(GSM_StateMachine * s,GSM_NoteEntry * Entry,const char * Data,int Size)3370 GSM_Error OBEXGEN_SetNoteLUID(GSM_StateMachine *s, GSM_NoteEntry *Entry, const char *Data, int Size)
3371 {
3372 	GSM_Error 	error;
3373 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3374 	char		*path=NULL;
3375 
3376 	error = OBEXGEN_InitNoteLUID(s);
3377 	if (error != ERR_NONE) return error;
3378 
3379 	/* Check bounds */
3380 	if (Entry->Location > Priv->NoteLUIDCount ||
3381 			Priv->NoteLUID[Entry->Location] == NULL) {
3382 		/**
3383 		 * \todo We should keep location here!
3384 		 */
3385 		return OBEXGEN_AddNote(s, Entry);
3386 	}
3387 
3388 	/* Calculate path */
3389 	path = (char *)malloc(strlen(Priv->NoteLUID[Entry->Location]) + 22); /* Length of string below */
3390 	if (path == NULL) {
3391 		return ERR_MOREMEMORY;
3392 	}
3393 	sprintf(path, "telecom/nt/luid/%s.vnt", Priv->NoteLUID[Entry->Location]);
3394 	smprintf(s, "Seting vNote %s\n", path);
3395 
3396 	/* Forget entry if we're deleting */
3397 	if (Size == 0) {
3398 		free(Priv->NoteLUID[Entry->Location]);
3399 		Priv->NoteLUID[Entry->Location] = NULL;
3400 		Priv->NoteCount--;
3401 	}
3402 
3403 	/* Store vCard */
3404 	error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->NoteCap.HD : FALSE);;
3405 	free(path);
3406 	return error;
3407 }
3408 
OBEXGEN_SetNoteIndex(GSM_StateMachine * s,GSM_NoteEntry * Entry,const char * Data,int Size)3409 GSM_Error OBEXGEN_SetNoteIndex(GSM_StateMachine *s, GSM_NoteEntry *Entry, const char *Data, int Size)
3410 {
3411 	char		*path=NULL;
3412 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3413 	GSM_Error		error;
3414 
3415 	/* Forget entry if we're deleting */
3416 	if (Size == 0) {
3417 		Priv->NoteCount--;
3418 	}
3419 
3420 	/* Calculate path */
3421 	path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3422 	if (path == NULL) {
3423 		return ERR_MOREMEMORY;
3424 	}
3425 	sprintf(path, "telecom/nt/%d.vnt", Entry->Location);
3426 	smprintf(s, "Seting vNote %s\n", path);
3427 
3428 	/* Store vCard */
3429 	error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
3430 	free(path);
3431 	return error;
3432 }
3433 
OBEXGEN_SetNote(GSM_StateMachine * s,GSM_NoteEntry * Entry)3434 GSM_Error OBEXGEN_SetNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3435 {
3436 	unsigned char 		req[5000];
3437 	size_t			size=0;
3438 	GSM_Error		error;
3439 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3440 
3441 	/* We need IrMC service for this */
3442 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3443 	if (error != ERR_NONE) return error;
3444 
3445 	/* We need IEL to correctly talk to phone */
3446 	if (Priv->NoteCap.IEL == -1) {
3447 		error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3448 		if (error != ERR_NONE) return error;
3449 	}
3450 
3451 	/* Encode vNote */
3452 	error = GSM_EncodeVNTFile(req, sizeof(req), &size, Entry);
3453 	if (error != ERR_NONE) return error;
3454 
3455 	/* Use correct function according to supported IEL */
3456 	if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3457 		return OBEXGEN_SetNoteLUID(s, Entry, req, size);
3458 	} else if (Priv->NoteCap.IEL == 0x4) {
3459 		return OBEXGEN_SetNoteIndex(s, Entry, req, size);
3460 	} else if (Priv->NoteCap.IEL == 0x2) {
3461 		/* Work on full note */
3462 		return ERR_NOTIMPLEMENTED;
3463 	} else {
3464 		return ERR_NOTSUPPORTED;
3465 	}
3466 }
3467 
OBEXGEN_DeleteNote(GSM_StateMachine * s,GSM_NoteEntry * Entry)3468 GSM_Error OBEXGEN_DeleteNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3469 {
3470 	GSM_Error		error;
3471 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3472 
3473 	/* We need IrMC service for this */
3474 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3475 	if (error != ERR_NONE) return error;
3476 
3477 	/* We need IEL to correctly talk to phone */
3478 	if (Priv->NoteCap.IEL == -1) {
3479 		error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3480 		if (error != ERR_NONE) return error;
3481 	}
3482 
3483 	/* Use correct function according to supported IEL */
3484 	if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3485 		return OBEXGEN_SetNoteLUID(s, Entry, "", 0);
3486 	} else if (Priv->NoteCap.IEL == 0x4) {
3487 		return OBEXGEN_SetNoteIndex(s, Entry, "", 0);
3488 	} else if (Priv->NoteCap.IEL == 0x2) {
3489 		/* Work on full note */
3490 		return ERR_NOTIMPLEMENTED;
3491 	} else {
3492 		return ERR_NOTSUPPORTED;
3493 	}
3494 }
3495 
OBEXGEN_DeleteAllNotes(GSM_StateMachine * s)3496 GSM_Error OBEXGEN_DeleteAllNotes(GSM_StateMachine *s)
3497 {
3498 	GSM_Error		error;
3499 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3500 	GSM_NoteEntry		entry;
3501 
3502 	/* We need IrMC service for this */
3503 	error = OBEXGEN_Connect(s, OBEX_IRMC);
3504 	if (error != ERR_NONE) return error;
3505 
3506 	/* We need count of entries */
3507 	error = OBEXGEN_InitNoteLUID(s);
3508 	if (error != ERR_NONE) return error;
3509 
3510 	/* Delete all entries */
3511 	entry.Location = 1;
3512 	while (Priv->NoteCount > 0) {
3513 		error = OBEXGEN_DeleteNote(s, &entry);
3514 		if (error != ERR_NONE && error != ERR_EMPTY) return error;
3515 		entry.Location++;
3516 	}
3517 	return error;
3518 }
3519 
3520 /*@}*/
3521 
3522 /**
3523  * \defgroup OBEXcap Phone information using OBEX capability XML or IrMC devinfo
3524  * \ingroup OBEXPhone
3525  * @{
3526  */
3527 
OBEXGEN_GetDevinfoField(GSM_StateMachine * s,const char * Name,char * Dest)3528 GSM_Error OBEXGEN_GetDevinfoField(GSM_StateMachine *s, const char *Name, char *Dest)
3529 {
3530 	char			*pos;
3531 	char			*dest;
3532 	char			match[200];
3533 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3534 
3535 	if (Priv->OBEXDevinfo == NULL || strlen(Priv->OBEXDevinfo) == 0) return ERR_NOTSUPPORTED;
3536 
3537 	/* Match begin tag */
3538 	match[0] = 0;
3539 	strcat(match, Name);
3540 	strcat(match, ":");
3541 
3542 	pos = strstr(Priv->OBEXDevinfo, match);
3543 	if (pos == NULL) return ERR_INVALIDDATA;
3544 	pos += strlen(match);
3545 
3546 	/* Copy to end of line */
3547 	dest = Dest;
3548 	while (*pos != 0 && *pos != '\r' && *pos != '\n') {
3549 		*(dest++) = *(pos++);
3550 	}
3551 	*dest  = 0;
3552 
3553 	return ERR_NONE;
3554 }
3555 
OBEXGEN_GetCapabilityField(GSM_StateMachine * s,const char * Name,char * Dest)3556 GSM_Error OBEXGEN_GetCapabilityField(GSM_StateMachine *s, const char *Name, char *Dest)
3557 {
3558 	char			*pos_start;
3559 	char			*pos_end;
3560 	char			match[200];
3561 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3562 
3563 	if (Priv->OBEXCapability == NULL || strlen(Priv->OBEXCapability) == 0) return ERR_NOTSUPPORTED;
3564 
3565 	/* Match XML begin tag */
3566 	match[0] = 0;
3567 	strcat(match, "<");
3568 	strcat(match, Name);
3569 	strcat(match, ">");
3570 
3571 	pos_start = strstr(Priv->OBEXCapability, match);
3572 	if (pos_start == NULL) return ERR_INVALIDDATA;
3573 	pos_start += strlen(match);
3574 
3575 	/* Match XML end tag */
3576 	match[0] = 0;
3577 	strcat(match, "</");
3578 	strcat(match, Name);
3579 	strcat(match, ">");
3580 
3581 	pos_end = strstr(pos_start, match);
3582 	if (pos_end == NULL) return ERR_INVALIDDATA;
3583 
3584 	/* Copy result string */
3585 	strncpy(Dest, pos_start, pos_end - pos_start);
3586 	Dest[pos_end - pos_start] = 0;
3587 
3588 	return ERR_NONE;
3589 }
3590 
OBEXGEN_GetCapabilityFieldAttrib(GSM_StateMachine * s,const char * Name,const char * Attrib,char * Dest)3591 GSM_Error OBEXGEN_GetCapabilityFieldAttrib(GSM_StateMachine *s, const char *Name, const char *Attrib, char *Dest)
3592 {
3593 	char			*pos_start;
3594 	char			*pos_end;
3595 	char			match[200];
3596 	GSM_Phone_OBEXGENData	*Priv = &s->Phone.Data.Priv.OBEXGEN;
3597 
3598 	if (Priv->OBEXCapability == NULL || strlen(Priv->OBEXCapability) == 0) return ERR_NOTSUPPORTED;
3599 
3600 	/* Match XML begin tag */
3601 	match[0] = 0;
3602 	strcat(match, "<");
3603 	strcat(match, Name);
3604 
3605 	pos_start = strstr(Priv->OBEXCapability, match);
3606 	if (pos_start == NULL) return ERR_INVALIDDATA;
3607 	pos_start += strlen(match);
3608 
3609 	/* Match attribute begin */
3610 	match[0] = 0;
3611 	strcat(match, Attrib);
3612 	strcat(match, "=\"");
3613 
3614 	pos_start = strstr(pos_start, match);
3615 	if (pos_start == NULL) return ERR_INVALIDDATA;
3616 	pos_start += strlen(match);
3617 
3618 	/* Match end quote */
3619 	pos_end = strchr(pos_start, '"');
3620 	if (pos_end == NULL) return ERR_INVALIDDATA;
3621 
3622 	/* Copy result string */
3623 	strncpy(Dest, pos_start, pos_end - pos_start);
3624 	Dest[pos_end - pos_start] = 0;
3625 
3626 	return ERR_NONE;
3627 }
3628 
OBEXGEN_GetManufacturer(GSM_StateMachine * s)3629 GSM_Error OBEXGEN_GetManufacturer(GSM_StateMachine *s)
3630 {
3631 	GSM_Error		error;
3632 
3633 	if (s->Phone.Data.Manufacturer[0] != 0) return ERR_NONE;
3634 
3635 	error = OBEXGEN_GetCapabilityField(s, "Manufacturer", s->Phone.Data.Manufacturer);
3636 	if (error == ERR_NONE) return ERR_NONE;
3637 
3638 	return OBEXGEN_GetDevinfoField(s, "MANU", s->Phone.Data.Manufacturer);
3639 }
3640 
OBEXGEN_GetModel(GSM_StateMachine * s)3641 GSM_Error OBEXGEN_GetModel(GSM_StateMachine *s)
3642 {
3643 	GSM_Error		error;
3644 	GSM_Phone_Data		*Data = &s->Phone.Data;
3645 
3646 	if (Data->Model[0] != 0) return ERR_NONE;
3647 
3648 	error = OBEXGEN_GetCapabilityField(s, "Model", s->Phone.Data.Model);
3649 
3650 	/* Retry with MOD if we failed */
3651 	if (error != ERR_NONE) {
3652 		error = OBEXGEN_GetDevinfoField(s, "MOD", s->Phone.Data.Model);
3653 	}
3654 
3655 	if (error == ERR_NONE) {
3656 		Data->ModelInfo = GetModelData(s, NULL, Data->Model, NULL);
3657 		if (Data->ModelInfo->number[0] == 0)
3658 			Data->ModelInfo = GetModelData(s, NULL, NULL, Data->Model);
3659 		if (Data->ModelInfo->number[0] == 0)
3660 			Data->ModelInfo = GetModelData(s, Data->Model, NULL, NULL);
3661 		return ERR_NONE;
3662 	}
3663 	return error;
3664 }
3665 
OBEXGEN_GetFirmware(GSM_StateMachine * s)3666 GSM_Error OBEXGEN_GetFirmware(GSM_StateMachine *s)
3667 {
3668 	GSM_Error		error;
3669 
3670 	if (s->Phone.Data.Version[0] != 0) return ERR_NONE;
3671 
3672 	error = OBEXGEN_GetCapabilityFieldAttrib(s, "SW", "Version", s->Phone.Data.Version);
3673 	if (error == ERR_NONE) {
3674 		/* We don't care about error here, it is optional */
3675 		OBEXGEN_GetCapabilityFieldAttrib(s, "SW", "Date", s->Phone.Data.VerDate);
3676 	}
3677 	if (error == ERR_NONE) return ERR_NONE;
3678 	OBEXGEN_GetDevinfoField(s, "SW-DATE", s->Phone.Data.VerDate);
3679 
3680 	return OBEXGEN_GetDevinfoField(s, "SW-VERSION", s->Phone.Data.Version);
3681 }
3682 
OBEXGEN_GetIMEI(GSM_StateMachine * s)3683 GSM_Error OBEXGEN_GetIMEI(GSM_StateMachine *s)
3684 {
3685 	GSM_Error		error;
3686 
3687 	if (s->Phone.Data.IMEI[0] != 0) return ERR_NONE;
3688 
3689 	error = OBEXGEN_GetCapabilityField(s, "SN", s->Phone.Data.IMEI);
3690 	if (error == ERR_NONE) return ERR_NONE;
3691 
3692 	return OBEXGEN_GetDevinfoField(s, "SN", s->Phone.Data.IMEI);
3693 }
3694 
3695 /*@}*/
3696 GSM_Reply_Function OBEXGENReplyFunctions[] = {
3697 	/* CONTINUE block */
3698 	{OBEXGEN_ReplyAddFilePart,	"\x90",0x00,0x00,ID_AddFile			},
3699 	{OBEXGEN_ReplyGetFilePart,	"\x90",0x00,0x00,ID_GetFile			},
3700 
3701 	/* OK block */
3702 	{OBEXGEN_ReplyChangePath,	"\xA0",0x00,0x00,ID_SetPath			},
3703 	{OBEXGEN_ReplyConnect,		"\xA0",0x00,0x00,ID_Initialise			},
3704 	{OBEXGEN_ReplyAddFilePart,	"\xA0",0x00,0x00,ID_AddFile			},
3705 	{OBEXGEN_ReplyGetFilePart,	"\xA0",0x00,0x00,ID_GetFile			},
3706 
3707 	/* FOLDER CREATED block */
3708 	{OBEXGEN_ReplyChangePath,	"\xA1",0x00,0x00,ID_SetPath			},
3709 
3710 	/* NOT UNDERSTAND block */
3711 	{OBEXGEN_ReplyConnect,		"\xC0",0x00,0x00,ID_Initialise			},
3712 	{OBEXGEN_ReplyGetFilePart,	"\xC0",0x00,0x00,ID_GetFile			},
3713 	{OBEXGEN_ReplyAddFilePart,	"\xC0",0x00,0x00,ID_AddFile			},
3714 
3715 	/* Not allowed block */
3716 	{OBEXGEN_ReplyConnect,		"\xC1",0x00,0x00,ID_Initialise			},
3717 	{OBEXGEN_ReplyGetFilePart,	"\xC1",0x00,0x00,ID_GetFile			},
3718 	{OBEXGEN_ReplyAddFilePart,	"\xC1",0x00,0x00,ID_AddFile			},
3719 
3720 	/* FORBIDDEN block */
3721 	{OBEXGEN_ReplyConnect,		"\xC3",0x00,0x00,ID_Initialise			},
3722 	{OBEXGEN_ReplyChangePath,	"\xC3",0x00,0x00,ID_SetPath			},
3723 	{OBEXGEN_ReplyGetFilePart,	"\xC3",0x00,0x00,ID_GetFile			},
3724 	{OBEXGEN_ReplyAddFilePart,	"\xC3",0x00,0x00,ID_AddFile			},
3725 
3726 	/* Not Acceptable block */
3727 	{OBEXGEN_ReplyConnect,		"\xC6",0x00,0x00,ID_Initialise			},
3728 	{OBEXGEN_ReplyChangePath,	"\xC6",0x00,0x00,ID_SetPath			},
3729 	{OBEXGEN_ReplyGetFilePart,	"\xC6",0x00,0x00,ID_GetFile			},
3730 	{OBEXGEN_ReplyAddFilePart,	"\xC6",0x00,0x00,ID_AddFile			},
3731 
3732 	/* CONFLICT block */
3733 	{OBEXGEN_ReplyConnect,		"\xC9",0x00,0x00,ID_Initialise			},
3734 	{OBEXGEN_ReplyChangePath,	"\xC9",0x00,0x00,ID_SetPath			},
3735 	{OBEXGEN_ReplyGetFilePart,	"\xC9",0x00,0x00,ID_GetFile			},
3736 	{OBEXGEN_ReplyAddFilePart,	"\xC9",0x00,0x00,ID_AddFile			},
3737 
3738 	/* NOT FOUND block */
3739 	{OBEXGEN_ReplyConnect,		"\xC4",0x00,0x00,ID_Initialise			},
3740 	{OBEXGEN_ReplyChangePath,	"\xC4",0x00,0x00,ID_SetPath			},
3741 	{OBEXGEN_ReplyGetFilePart,	"\xC4",0x00,0x00,ID_GetFile			},
3742 	{OBEXGEN_ReplyChangePath,	"\xC4",0x00,0x00,ID_SetPath			},
3743 
3744 	/* Failed block */
3745 	{OBEXGEN_ReplyConnect,		"\xCC",0x00,0x00,ID_Initialise			},
3746 	{OBEXGEN_ReplyChangePath,	"\xCC",0x00,0x00,ID_SetPath			},
3747 	{OBEXGEN_ReplyGetFilePart,	"\xCC",0x00,0x00,ID_GetFile			},
3748 	{OBEXGEN_ReplyAddFilePart,	"\xCC",0x00,0x00,ID_AddFile			},
3749 
3750 	/* Non standard Sharp GX reply */
3751 	{OBEXGEN_ReplyGetFilePart,	"\x80",0x00,0x00,ID_GetFile			},
3752 	{OBEXGEN_ReplyChangePath,	"\x80",0x00,0x00,ID_SetPath			},
3753 
3754 	/* Internal server error */
3755 	{OBEXGEN_ReplyConnect,		"\xD0",0x00,0x00,ID_Initialise			},
3756 	{OBEXGEN_ReplyChangePath,	"\xD0",0x00,0x00,ID_SetPath			},
3757 	{OBEXGEN_ReplyGetFilePart,	"\xD0",0x00,0x00,ID_GetFile			},
3758 	{OBEXGEN_ReplyAddFilePart,	"\xD0",0x00,0x00,ID_AddFile			},
3759 
3760 	/* Not implemented */
3761 	{OBEXGEN_ReplyConnect,		"\xD1",0x00,0x00,ID_Initialise			},
3762 	{OBEXGEN_ReplyChangePath,	"\xD1",0x00,0x00,ID_SetPath			},
3763 	{OBEXGEN_ReplyGetFilePart,	"\xD1",0x00,0x00,ID_GetFile			},
3764 	{OBEXGEN_ReplyAddFilePart,	"\xD1",0x00,0x00,ID_AddFile			},
3765 
3766 	/* Service not available */
3767 	{OBEXGEN_ReplyConnect,		"\xD3",0x00,0x00,ID_Initialise			},
3768 	{OBEXGEN_ReplyChangePath,	"\xD3",0x00,0x00,ID_SetPath			},
3769 	{OBEXGEN_ReplyGetFilePart,	"\xD3",0x00,0x00,ID_GetFile			},
3770 	{OBEXGEN_ReplyAddFilePart,	"\xD3",0x00,0x00,ID_AddFile			},
3771 
3772 	/* Database full */
3773 	{OBEXGEN_ReplyConnect,		"\xE0",0x00,0x00,ID_Initialise			},
3774 	{OBEXGEN_ReplyChangePath,	"\xE0",0x00,0x00,ID_SetPath			},
3775 	{OBEXGEN_ReplyGetFilePart,	"\xE0",0x00,0x00,ID_GetFile			},
3776 	{OBEXGEN_ReplyAddFilePart,	"\xE0",0x00,0x00,ID_AddFile			},
3777 
3778 	/* Database locked */
3779 	{OBEXGEN_ReplyConnect,		"\xE1",0x00,0x00,ID_Initialise			},
3780 	{OBEXGEN_ReplyChangePath,	"\xE1",0x00,0x00,ID_SetPath			},
3781 	{OBEXGEN_ReplyGetFilePart,	"\xE1",0x00,0x00,ID_GetFile			},
3782 	{OBEXGEN_ReplyAddFilePart,	"\xE1",0x00,0x00,ID_AddFile			},
3783 
3784 	{NULL,				"\x00",0x00,0x00,ID_None			}
3785 };
3786 
3787 GSM_Phone_Functions OBEXGENPhone = {
3788 	"obex|seobex|obexfs|obexirmc|obexnone|mobex",
3789 	OBEXGENReplyFunctions,
3790 	NOTSUPPORTED,			/* 	Install			*/
3791 	OBEXGEN_Initialise,
3792 	OBEXGEN_Terminate,
3793 	GSM_DispatchMessage,
3794 	NOTIMPLEMENTED,			/* 	ShowStartInfo		*/
3795 	OBEXGEN_GetManufacturer,
3796 	OBEXGEN_GetModel,
3797 	OBEXGEN_GetFirmware,
3798 	OBEXGEN_GetIMEI,
3799 	NOTIMPLEMENTED,			/*	GetOriginalIMEI		*/
3800 	NOTIMPLEMENTED,			/*	GetManufactureMonth	*/
3801 	NOTIMPLEMENTED,			/*	GetProductCode		*/
3802 	NOTIMPLEMENTED,			/*	GetHardware		*/
3803 	NOTIMPLEMENTED,			/*	GetPPM			*/
3804 	NOTIMPLEMENTED,			/*	GetSIMIMSI		*/
3805 	NOTIMPLEMENTED,			/*	GetDateTime		*/
3806 	NOTIMPLEMENTED,			/*	SetDateTime		*/
3807 	NOTIMPLEMENTED,			/*	GetAlarm		*/
3808 	NOTIMPLEMENTED,			/*	SetAlarm		*/
3809 	NOTSUPPORTED,			/* 	GetLocale		*/
3810 	NOTSUPPORTED,			/* 	SetLocale		*/
3811 	NOTIMPLEMENTED,			/*	PressKey		*/
3812 	NOTIMPLEMENTED,			/*	Reset			*/
3813 	NOTIMPLEMENTED,			/*	ResetPhoneSettings	*/
3814 	NOTIMPLEMENTED,			/*	EnterSecurityCode	*/
3815 	NOTIMPLEMENTED,			/*	GetSecurityStatus	*/
3816 	NOTIMPLEMENTED,			/*	GetDisplayStatus	*/
3817 	NOTIMPLEMENTED,			/*	SetAutoNetworkLogin	*/
3818 	NOTIMPLEMENTED,			/*	GetBatteryCharge	*/
3819 	NOTIMPLEMENTED,			/*	GetSignalQuality	*/
3820 	NOTIMPLEMENTED,			/*	GetNetworkInfo		*/
3821 	NOTIMPLEMENTED,     		/*  	GetCategory 		*/
3822  	NOTSUPPORTED,       		/*  	AddCategory 		*/
3823         NOTIMPLEMENTED,      		/*  	GetCategoryStatus 	*/
3824 	OBEXGEN_GetMemoryStatus,
3825 	OBEXGEN_GetMemory,
3826 	OBEXGEN_GetNextMemory,
3827 	OBEXGEN_SetMemory,
3828 	OBEXGEN_AddMemory,
3829 	OBEXGEN_DeleteMemory,
3830 	OBEXGEN_DeleteAllMemory,
3831 	NOTIMPLEMENTED,			/*	GetSpeedDial		*/
3832 	NOTIMPLEMENTED,			/*	SetSpeedDial		*/
3833 	NOTIMPLEMENTED,			/*	GetSMSC			*/
3834 	NOTIMPLEMENTED,			/*	SetSMSC			*/
3835 	NOTIMPLEMENTED,			/*	GetSMSStatus		*/
3836 	NOTIMPLEMENTED,			/*	GetSMS			*/
3837 	NOTIMPLEMENTED,			/*	GetNextSMS		*/
3838 	NOTIMPLEMENTED,			/*	SetSMS			*/
3839 	NOTIMPLEMENTED,			/*	AddSMS			*/
3840 	NOTIMPLEMENTED,			/* 	DeleteSMS 		*/
3841 	NOTIMPLEMENTED,			/*	SendSMSMessage		*/
3842 	NOTSUPPORTED,			/*	SendSavedSMS		*/
3843 	NOTSUPPORTED,			/*	SetFastSMSSending	*/
3844 	NOTIMPLEMENTED,			/*	SetIncomingSMS		*/
3845 	NOTIMPLEMENTED,			/* 	SetIncomingCB		*/
3846 	NOTIMPLEMENTED,			/*	GetSMSFolders		*/
3847  	NOTIMPLEMENTED,			/* 	AddSMSFolder		*/
3848  	NOTIMPLEMENTED,			/* 	DeleteSMSFolder		*/
3849 	NOTIMPLEMENTED,			/*	DialVoice		*/
3850         NOTIMPLEMENTED,			/*	DialService		*/
3851 	NOTIMPLEMENTED,			/*	AnswerCall		*/
3852 	NOTIMPLEMENTED,			/*	CancelCall		*/
3853  	NOTIMPLEMENTED,			/* 	HoldCall 		*/
3854  	NOTIMPLEMENTED,			/* 	UnholdCall 		*/
3855  	NOTIMPLEMENTED,			/* 	ConferenceCall 		*/
3856  	NOTIMPLEMENTED,			/* 	SplitCall		*/
3857  	NOTIMPLEMENTED,			/* 	TransferCall		*/
3858  	NOTIMPLEMENTED,			/* 	SwitchCall		*/
3859  	NOTIMPLEMENTED,			/* 	GetCallDivert		*/
3860  	NOTIMPLEMENTED,			/* 	SetCallDivert		*/
3861  	NOTIMPLEMENTED,			/* 	CancelAllDiverts	*/
3862 	NOTIMPLEMENTED,			/*	SetIncomingCall		*/
3863 	NOTIMPLEMENTED,			/*  	SetIncomingUSSD		*/
3864 	NOTIMPLEMENTED,			/*	SendDTMF		*/
3865 	NOTIMPLEMENTED,			/*	GetRingtone		*/
3866 	NOTIMPLEMENTED,			/*	SetRingtone		*/
3867 	NOTIMPLEMENTED,			/*	GetRingtonesInfo	*/
3868 	NOTIMPLEMENTED,			/* 	DeleteUserRingtones	*/
3869 	NOTIMPLEMENTED,			/*	PlayTone		*/
3870 	NOTIMPLEMENTED,			/*	GetWAPBookmark		*/
3871 	NOTIMPLEMENTED,			/* 	SetWAPBookmark 		*/
3872 	NOTIMPLEMENTED, 		/* 	DeleteWAPBookmark 	*/
3873 	NOTIMPLEMENTED,			/* 	GetWAPSettings 		*/
3874 	NOTIMPLEMENTED,			/* 	SetWAPSettings 		*/
3875 	NOTSUPPORTED,			/*	GetSyncMLSettings	*/
3876 	NOTSUPPORTED,			/*	SetSyncMLSettings	*/
3877 	NOTSUPPORTED,			/*	GetChatSettings		*/
3878 	NOTSUPPORTED,			/*	SetChatSettings		*/
3879 	NOTSUPPORTED,			/* 	GetMMSSettings		*/
3880 	NOTSUPPORTED,			/* 	SetMMSSettings		*/
3881 	NOTSUPPORTED,			/*	GetMMSFolders		*/
3882 	NOTSUPPORTED,			/*	GetNextMMSFileInfo	*/
3883 	NOTIMPLEMENTED,			/*	GetBitmap		*/
3884 	NOTIMPLEMENTED,			/*	SetBitmap		*/
3885 	OBEXGEN_GetTodoStatus,
3886 	OBEXGEN_GetTodo,
3887 	OBEXGEN_GetNextTodo,
3888 	OBEXGEN_SetTodo,
3889 	OBEXGEN_AddTodo,
3890 	OBEXGEN_DeleteTodo,
3891 	OBEXGEN_DeleteAllTodo,
3892 	OBEXGEN_GetCalendarStatus,
3893 	OBEXGEN_GetCalendar,
3894     	OBEXGEN_GetNextCalendar,
3895 	OBEXGEN_SetCalendar,
3896 	OBEXGEN_AddCalendar,
3897 	OBEXGEN_DeleteCalendar,
3898 	OBEXGEN_DeleteAllCalendar,
3899 	NOTSUPPORTED,			/* 	GetCalendarSettings	*/
3900 	NOTSUPPORTED,			/* 	SetCalendarSettings	*/
3901 	OBEXGEN_GetNoteStatus,
3902 	OBEXGEN_GetNote,
3903 	OBEXGEN_GetNextNote,
3904 	OBEXGEN_SetNote,
3905 	OBEXGEN_AddNote,
3906 	OBEXGEN_DeleteNote,
3907 	OBEXGEN_DeleteAllNotes,
3908 	NOTIMPLEMENTED, 		/*	GetProfile		*/
3909 	NOTIMPLEMENTED, 		/*	SetProfile		*/
3910     	NOTIMPLEMENTED,			/*  	GetFMStation        	*/
3911     	NOTIMPLEMENTED,			/*  	SetFMStation        	*/
3912     	NOTIMPLEMENTED,			/*  	ClearFMStations       	*/
3913 	OBEXGEN_GetNextFileFolder,
3914 	NOTIMPLEMENTED,			/*	GetFolderListing	*/
3915 	NOTSUPPORTED,			/*	GetNextRootFolder	*/
3916 	NOTSUPPORTED,			/*	SetFileAttributes	*/
3917 	OBEXGEN_GetFilePart,
3918 	OBEXGEN_AddFilePart,
3919 	OBEXGEN_SendFilePart,
3920 	NOTIMPLEMENTED, 		/* 	GetFileSystemStatus	*/
3921 	OBEXGEN_DeleteFile,
3922 	OBEXGEN_AddFolder,
3923 	OBEXGEN_DeleteFile,		/* 	DeleteFolder		*/
3924 	NOTSUPPORTED,			/* 	GetGPRSAccessPoint	*/
3925 	NOTSUPPORTED,			/* 	SetGPRSAccessPoint	*/
3926 	NOTSUPPORTED,			/* 	GetScreenshot		*/
3927 	NOTSUPPORTED,			/* 	SetPower		*/
3928 	NOTSUPPORTED,			/* 	PostConnect	*/
3929 	NONEFUNCTION			/*	PreAPICall		*/
3930 };
3931 
3932 #endif
3933 /*@}*/
3934 /*@}*/
3935 
3936 /* How should editor hadle tabs in this file? Add editor commands here.
3937  * vim: noexpandtab sw=8 ts=8 sts=8:
3938  */
3939