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