Gammu internals  1.38.0
obexgen.c
Go to the documentation of this file.
1 /* (c) 2003 by Marcin Wiacek */
2 /* (c) 2006-2007 by Michal Cihar */
3 
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 "../../../helper/string.h"
38 
39 #ifdef GSM_ENABLE_OBEXGEN
40 
41 /* Forward definitions */
42 GSM_Error OBEXGEN_GetModel(GSM_StateMachine *s);
43 
47 #define OBEX_TIMEOUT 10
48 
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 
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 
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 
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 
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;
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 
261 void IRMC_InitCapabilities(IRMC_Capability *Cap)
262 {
263  Cap->IEL = -1;
264  Cap->HD = FALSE;
265 }
266 
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 
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 */
356  smprintf(s, "Connected using model %s\n", s->CurrentConfig->Model);
357  if (strcmp(s->CurrentConfig->Model, "obex") == 0) {
359  service_forced = TRUE;
360  } else if (strcmp(s->CurrentConfig->Model, "obexfs") == 0) {
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) {
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 
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 
474 GSM_Error OBEXGEN_Terminate(GSM_StateMachine *s)
475 {
476  return OBEXGEN_Disconnect(s);
477 }
478 
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 
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 
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 
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 
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 
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 */
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  case 0xcb:
737  /* Skip Connection ID (we ignore this for now) */
738  Pos += 5;
739  break;
740  default:
741  Pos+=msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2];
742  break;
743  }
744  }
745  return ERR_NONE;
746  }
747  return ERR_UNKNOWNRESPONSE;
748 }
749 
750 GSM_Error OBEXGEN_PrivAddFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle UNUSED, gboolean HardDelete)
751 {
752  GSM_Error error;
753  size_t j;
754  int Current = 0;
755  unsigned char req[2000];
756  unsigned char hard_delete_header[2] = {'\x12', '\x0'};
757  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
758 
759  s->Phone.Data.File = File;
760 
761  if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
762  OBEXGEN_AddConnectionID(s, req, &Current);
763  }
764 
765  /* Are we sending first request or continuation? */
766  if (*Pos == 0) {
767  if (!strcmp(DecodeUnicodeString(File->ID_FullName),"")) {
768  error = OBEXGEN_Connect(s,OBEX_None);
769  if (error != ERR_NONE) return error;
770  } else {
771  if (Priv->Service == OBEX_BrowsingFolders) {
772  error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
773  if (error != ERR_NONE) return error;
774  }
775  }
776 
777  /* Name block */
778  if (Priv->Service == OBEX_m_OBEX) {
779  OBEXAddBlock(req, &Current, 0x42, DecodeUnicodeString(File->ID_FullName), UnicodeLength(File->ID_FullName) + 1);
780  } else {
781  OBEXAddBlock(req, &Current, 0x01, File->Name, UnicodeLength(File->Name)*2+2);
782  }
783 
784  /* Include m-obex application data */
785  if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
786  OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
787  }
788 
789  /* Adding empty file is special on mobex */
790  if (Priv->Service == OBEX_m_OBEX && File->Buffer == NULL) {
791  error = GSM_WaitFor (s, req, Current, 0x82, OBEX_TIMEOUT * 10, ID_AddFile);
792  if (error == ERR_NONE) {
793  return ERR_EMPTY;
794  }
795  return error;
796  }
797 
798  /* File size block */
799  req[Current++] = 0xC3; /* ID */
800  req[Current++] = (File->Used >> 24) & 0xff;
801  req[Current++] = (File->Used >> 16) & 0xff;
802  req[Current++] = (File->Used >> 8) & 0xff;
803  req[Current++] = File->Used & 0xff;
804 
805  /* Application data block for hard delete */
806  if (HardDelete) {
807  OBEXAddBlock(req, &Current, 0x4c, hard_delete_header, 2);
808  }
809  }
810 
811  j = Priv->FrameSize - Current - 20;
812  if (j > 1000) j = 1000;
813 
814  if (File->Used - *Pos < j) {
815  j = File->Used - *Pos;
816  /* End of file body block */
817  OBEXAddBlock(req, &Current, 0x49, File->Buffer+(*Pos), j);
818  smprintf(s, "Adding last file part %ld %ld\n", (long)*Pos, (long)j);
819  *Pos = *Pos + j;
820  error = GSM_WaitFor (s, req, (long)Current, 0x82, OBEX_TIMEOUT * 10, ID_AddFile);
821  if (error != ERR_NONE) return error;
822  return ERR_EMPTY;
823  } else {
824  /* File body block */
825  OBEXAddBlock(req, &Current, 0x48, File->Buffer+(*Pos), j);
826  smprintf(s, "Adding file part %ld %ld\n", (long)*Pos, (long)j);
827  *Pos = *Pos + j;
828  error=GSM_WaitFor (s, req, (long)Current, 0x02, OBEX_TIMEOUT * 10, ID_AddFile);
829  }
830  return error;
831 }
832 
833 GSM_Error OBEXGEN_AddFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
834 {
835  GSM_Error error;
836 
837  /* Go to default service */
838  error = OBEXGEN_Connect(s, 0);
839  if (error != ERR_NONE) return error;
840 
841  /* Add file */
842  smprintf(s,"Adding file\n");
843  error = OBEXGEN_PrivAddFilePart(s, File, Pos, Handle, FALSE);
844 
845  /* Calculate path of added file if we're done */
846  if (error == ERR_EMPTY) {
847  OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
848  }
849 
850  return error;
851 }
852 
853 GSM_Error OBEXGEN_SendFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
854 {
855  GSM_Error error;
856 
857  /* No service for this */
858  error = OBEXGEN_Connect(s, OBEX_None);
859  if (error != ERR_NONE) return error;
860 
861  /* Send file */
862  smprintf(s,"Sending file\n");
863  File->ID_FullName[0] = 0;
864  File->ID_FullName[1] = 0;
865  error = OBEXGEN_PrivAddFilePart(s, File, Pos, Handle, FALSE);
866  if (error != ERR_NONE) return error;
867 
868  /* Calculate path of added file */
869  OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
870  return ERR_NONE;
871 }
872 
876 static GSM_Error OBEXGEN_ReplyGetFilePart(GSM_Protocol_Message *msg, GSM_StateMachine *s)
877 {
878  size_t old,Pos=0,len2,pos2;
879  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
880 
881  /* Non standard Sharp GX reply */
882  if (msg->Type == 0x80) {
883  return ERR_FILENOTEXIST;
884  }
885 
886  /* Generic error codes */
887  if ((msg->Type & 0x7f) >= 0x40) {
888  return OBEXGEN_HandleError(msg, s);
889  }
890 
891  switch (msg->Type) {
892  case 0xA0:
893  smprintf(s,"Last file part received\n");
894  s->Phone.Data.Priv.OBEXGEN.FileLastPart = TRUE;
895  if (msg->Length == 0) return ERR_NONE;
896  /* Fallthrough */
897  case 0x90:
898  while(1) {
899  if (Pos >= msg->Length) break;
900  switch (msg->Buffer[Pos]) {
901  case 0x48:
902  case 0x49:
903  smprintf(s,"File part received\n");
904  old = s->Phone.Data.File->Used;
905  s->Phone.Data.File->Used += msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2]-3;
906  smprintf(s,"Length of file part: %i\n",
907  msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2]-3);
908  s->Phone.Data.File->Buffer = (unsigned char *)realloc(s->Phone.Data.File->Buffer,s->Phone.Data.File->Used);
909  memcpy(s->Phone.Data.File->Buffer+old,msg->Buffer+Pos+3,s->Phone.Data.File->Used-old);
910  return ERR_NONE;
911  case 0xc3:
912  /* Length */
916  Pos += 5;
917  break;
918  case 0xcb:
919  /* Skip Connection ID (we ignore this for now) */
920  Pos += 5;
921  break;
922  case 0x4C:
923  smprintf(s, "Application data received:");
924  len2 = msg->Buffer[Pos+1] * 256 + msg->Buffer[Pos+2];
925  pos2 = 0;
926  while(1) {
927  if (pos2 >= len2) break;
928  switch (msg->Buffer[Pos + 3 + pos2]) {
929  case 0x00:
930  if (Priv->Service == OBEX_m_OBEX) {
931  Priv->m_obex_error = msg->Buffer[Pos + 3 + pos2 + 1];
932  smprintf(s, " m-obex error=\"%d\"", Priv->m_obex_error);
933  /* This field has fixed size */
934  pos2 += 2;
935  continue;
936  }
937  break;
938  }
939  pos2 += 2 + msg->Buffer[Pos + 3 + pos2 + 1];
940  }
941  smprintf(s, "\n");
942  Pos += len2;
943  break;
944  default:
945  Pos+=msg->Buffer[Pos+1]*256+msg->Buffer[Pos+2];
946  break;
947  }
948  }
949  return ERR_UNKNOWNRESPONSE;
950  }
951  return ERR_UNKNOWNRESPONSE;
952 }
953 
954 static GSM_Error OBEXGEN_PrivGetFilePart(GSM_StateMachine *s, GSM_File *File, gboolean FolderList)
955 {
956  int Current = 0;
957  GSM_Error error;
958  unsigned char req[2000], req2[200];
959  int retries;
960  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
961 
962  s->Phone.Data.File = File;
963  File->ReadOnly = FALSE;
964  File->Protected = FALSE;
965  File->Hidden = FALSE;
966  File->System = FALSE;
967  File->ModifiedEmpty = TRUE;
968 
969  if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
970  OBEXGEN_AddConnectionID(s, req, &Current);
971  }
972 
973  if (File->Used == 0x00) {
974  if (FolderList) {
975  /* Type block */
976  strcpy(req2,"x-obex/folder-listing");
977  OBEXAddBlock(req, &Current, 0x42, req2, strlen(req2)+1);
978 
979  /* Name block should be empty, we're already in this folder */
980  OBEXAddBlock(req, &Current, 0x01, NULL, 0);
981  } else {
982  File->Folder = FALSE;
983 
984  if (File->ID_FullName[0] == 0x00 && File->ID_FullName[1] == 0x00) {
985  if (Priv->Service == OBEX_BrowsingFolders) {
986  /* No file name? Grab OBEX capabilities in browse mode */
987  smprintf(s, "No filename requested, grabbing OBEX capabilities as obex-capability.xml\n");
988  EncodeUnicode(File->Name, "obex-capability.xml", 19);
989  strcpy(req2,"x-obex/capability");
990 
991  /* Type block */
992  OBEXAddBlock(req, &Current, 0x42, req2, strlen(req2));
993  } else if (Priv->Service == OBEX_IRMC) {
994  /* No file name? Grab devinfo in IrMC mode */
995  smprintf(s, "No filename requested, grabbing device information as devinfo.txt\n");
996  EncodeUnicode(File->Name, "devinfo.txt", 19);
997  EncodeUnicode(req2,"telecom/devinfo.txt",19);
998 
999  /* Name block */
1000  OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1001  } else {
1002  return ERR_NOTSUPPORTED;
1003  }
1004  } else if (Priv->Service == OBEX_m_OBEX) {
1005  OBEXAddBlock(req, &Current, 0x42, DecodeUnicodeString(File->ID_FullName), UnicodeLength(File->ID_FullName) + 1);
1006  } else {
1007  if (Priv->Service == OBEX_BrowsingFolders) {
1008  error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, TRUE, req2);
1009  if (error != ERR_NONE) return error;
1010  } else {
1011  CopyUnicodeString(req2,File->ID_FullName);
1012  }
1013  CopyUnicodeString(File->Name,req2);
1014 
1015  s->Phone.Data.File = File;
1016 
1017  Current = 0;
1018  /* Name block */
1019  OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1020  }
1021  }
1022  }
1023 
1024  Priv->FileLastPart = FALSE;
1025 
1026  /* Include m-obex application data */
1027  if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
1028  OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
1029  }
1030 
1031  smprintf(s, "Getting first file part\n");
1032  retries = 0;
1033  while (retries < 5) {
1034  if (retries > 0) {
1035  smprintf(s, "Retry %d\n", retries);
1036  }
1037  error=GSM_WaitFor (s, req, Current, 0x83, OBEX_TIMEOUT, ID_GetFile);
1038  if (error != ERR_PERMISSION) break;
1039  usleep(200000);
1040  retries++;
1041  }
1042  if (error != ERR_NONE) return error;
1043 
1044  while (!Priv->FileLastPart) {
1045  Current = 0;
1046  if (Priv->Service == OBEX_BrowsingFolders || Priv->Service == OBEX_m_OBEX) {
1047  OBEXGEN_AddConnectionID(s, req, &Current);
1048  }
1049  /* Include m-obex application data */
1050  if (Priv->Service == OBEX_m_OBEX && Priv->m_obex_appdata != NULL && Priv->m_obex_appdata_len != 0) {
1051  OBEXAddBlock(req, &Current, 0x4C, Priv->m_obex_appdata, Priv->m_obex_appdata_len);
1052  }
1053  smprintf(s, "Getting next file part\n");
1054  /* We retry for ERR_PERMISSION, because it can be caused by database locked error */
1055  retries = 0;
1056  while (retries < 5) {
1057  if (retries > 0) {
1058  smprintf(s, "Retry %d\n", retries);
1059  }
1060  error = GSM_WaitFor (s, req, Current, 0x83, OBEX_TIMEOUT, ID_GetFile);
1061  if (error != ERR_PERMISSION) break;
1062  usleep(200000);
1063  retries++;
1064  }
1065  if (error != ERR_NONE) return error;
1066  }
1067  return ERR_EMPTY;
1068 }
1069 
1070 GSM_Error OBEXGEN_GetFilePart(GSM_StateMachine *s, GSM_File *File, int *Handle, size_t *Size)
1071 {
1072  GSM_Error error;
1073 
1074  /* Go to default service */
1075  error = OBEXGEN_Connect(s, 0);
1076  if (error != ERR_NONE) return error;
1077 
1078  (*Handle) = 0;
1079  error = OBEXGEN_PrivGetFilePart(s, File, FALSE);
1080  (*Size) = File->Used;
1081  return error;
1082 }
1083 
1084 
1092 {
1093  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1094  GSM_Error error;
1095  unsigned char Line[500],Line2[500],*name,*size;
1096  int i,j,num,pos2;
1097  size_t Pos;
1098 
1099  /* Go to default service */
1100  error = OBEXGEN_Connect(s, 0);
1101  if (error != ERR_NONE) return error;
1102 
1103  /* We can browse files only when using browse service */
1104  if (Priv->Service != OBEX_BrowsingFolders) {
1105  return ERR_NOTSUPPORTED;
1106  }
1107 
1108  if (start) {
1109  Priv->Files[0].Folder = TRUE;
1110  Priv->Files[0].Level = 1;
1111  Priv->Files[0].Name[0] = 0;
1112  Priv->Files[0].Name[1] = 0;
1113  Priv->Files[0].ID_FullName[0] = 0;
1114  Priv->Files[0].ID_FullName[1] = 0;
1115 
1116  Priv->FilesLocationsUsed = 1;
1117  Priv->FilesLocationsCurrent = 0;
1118  }
1119 
1120  while (1) {
1121  if (Priv->FilesLocationsCurrent == Priv->FilesLocationsUsed) {
1122  smprintf(s, "Last file\n");
1123  return ERR_EMPTY;
1124  }
1125 
1127  File->Level = Priv->Files[Priv->FilesLocationsCurrent].Level;
1128  File->Folder = Priv->Files[Priv->FilesLocationsCurrent].Folder;
1130  Priv->FilesLocationsCurrent++;
1131 
1132  if (File->Folder) {
1133  error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
1134  if (error != ERR_NONE) return error;
1135 
1136  File->Buffer = NULL;
1137  File->Used = 0;
1138  File->ModifiedEmpty = TRUE;
1139 
1140  error = OBEXGEN_PrivGetFilePart(s, File, TRUE);
1141  if (error != ERR_NONE && error != ERR_EMPTY) return error;
1142 
1143  num = 0;
1144  Pos = 0;
1145  /* Calculate number of files */
1146  while (1) {
1147  error = MyGetLine(File->Buffer, &Pos, Line, File->Used, sizeof(Line), FALSE);
1148  if (error != ERR_NONE) return error;
1149  if (strlen(Line) == 0) break;
1150  name = strstr(Line,"folder name=\"");
1151  if (name != NULL) {
1152  name += 13;
1153  j = 0;
1154  while(1) {
1155  if (name[j] == '"') break;
1156  j++;
1157  }
1158  name[j] = 0;
1159 
1160  if (strcmp(name,".")) num++;
1161  }
1162  name = strstr(Line,"file name=\"");
1163  if (name != NULL) num++;
1164  }
1165  /* Shift current files to the end of list */
1166  if (num != 0) {
1167  i = Priv->FilesLocationsUsed-1;
1168  while (1) {
1169  if (i==Priv->FilesLocationsCurrent-1) break;
1170  memcpy(&Priv->Files[i+num],&Priv->Files[i],sizeof(GSM_File));
1171  i--;
1172  }
1173  }
1174 
1175  /* Actually parse file listing */
1176  Pos = 0;
1177  pos2 = 0;
1178  while (1) {
1179  error = MyGetLine(File->Buffer, &Pos, Line, File->Used, sizeof(Line), FALSE);
1180  if (error != ERR_NONE) return error;
1181  if (strlen(Line) == 0) break;
1182  strcpy(Line2,Line);
1183  name = strstr(Line2,"folder name=\"");
1184  if (name != NULL) {
1185  name += 13;
1186  j = 0;
1187  while(1) {
1188  if (name[j] == '"') break;
1189  j++;
1190  }
1191  name[j] = 0;
1192  if (strcmp(name,".")) {
1193  smprintf(s, "copying folder %s to %i parent %i\n",name,Priv->FilesLocationsCurrent+pos2,Priv->FilesLocationsCurrent);
1194  /* Convert filename from UTF-8 */
1195  DecodeXMLUTF8(Priv->Files[Priv->FilesLocationsCurrent+pos2].Name, name, strlen(name));
1196  /* Create file name from parts */
1197  OBEXGEN_CreateFileName(
1198  Priv->Files[Priv->FilesLocationsCurrent+pos2].ID_FullName,
1199  File->ID_FullName,
1200  Priv->Files[Priv->FilesLocationsCurrent+pos2].Name
1201  );
1202  Priv->Files[Priv->FilesLocationsCurrent+pos2].Level = File->Level+1;
1203  Priv->Files[Priv->FilesLocationsCurrent+pos2].Folder = TRUE;
1204  Priv->FilesLocationsUsed++;
1205  pos2++;
1206  }
1207  }
1208  strcpy(Line2,Line);
1209  name = strstr(Line2,"file name=\"");
1210  if (name != NULL) {
1211  name += 11;
1212  j = 0;
1213  while(1) {
1214  if (name[j] == '"') break;
1215  j++;
1216  }
1217  name[j] = 0;
1218  smprintf(s, "copying file %s to %i\n",name,Priv->FilesLocationsCurrent+pos2);
1219  /* Convert filename from UTF-8 */
1220  DecodeXMLUTF8(Priv->Files[Priv->FilesLocationsCurrent+pos2].Name, name, strlen(name));
1221  /* Create file name from parts */
1222  OBEXGEN_CreateFileName(
1223  Priv->Files[Priv->FilesLocationsCurrent+pos2].ID_FullName,
1224  File->ID_FullName,
1225  Priv->Files[Priv->FilesLocationsCurrent+pos2].Name
1226  );
1227 
1228  Priv->Files[Priv->FilesLocationsCurrent+pos2].Level = File->Level+1;
1229  Priv->Files[Priv->FilesLocationsCurrent+pos2].Folder = FALSE;
1230  Priv->Files[Priv->FilesLocationsCurrent+pos2].Used = 0;
1231  strcpy(Line2,Line);
1232  size = strstr(Line2,"size=\"");
1233  if (size != NULL) Priv->Files[Priv->FilesLocationsCurrent+pos2].Used = atoi(size+6);
1234 
1235  Priv->Files[Priv->FilesLocationsCurrent+pos2].ModifiedEmpty = TRUE;
1236  strcpy(Line2,Line);
1237  size = strstr(Line2,"modified=\"");
1238  if (size != NULL) {
1239  Priv->Files[Priv->FilesLocationsCurrent+pos2].ModifiedEmpty = FALSE;
1240  ReadVCALDateTime(size+10, &Priv->Files[Priv->FilesLocationsCurrent+pos2].Modified);
1241  }
1242  Priv->FilesLocationsUsed++;
1243  pos2++;
1244  }
1245  }
1246 
1247  free(File->Buffer);
1248  File->Buffer = NULL;
1249  } else {
1250  File->Used = Priv->Files[Priv->FilesLocationsCurrent-1].Used;
1251  File->ModifiedEmpty = Priv->Files[Priv->FilesLocationsCurrent-1].ModifiedEmpty;
1252  if (!File->ModifiedEmpty) {
1253  memcpy(&File->Modified,&Priv->Files[Priv->FilesLocationsCurrent-1].Modified,sizeof(GSM_DateTime));
1254  }
1255  File->ReadOnly = FALSE;
1256  File->Protected = FALSE;
1257  File->Hidden = FALSE;
1258  File->System = FALSE;
1259 
1260  }
1261  return ERR_NONE;
1262  }
1263 }
1264 
1265 GSM_Error OBEXGEN_DeleteFile(GSM_StateMachine *s, unsigned char *ID)
1266 {
1267  GSM_Error error;
1268  int Current = 0;
1269  unsigned char req[200],req2[200];
1270 
1271  /* Go to default service */
1272  error = OBEXGEN_Connect(s, 0);
1273  if (error != ERR_NONE) return error;
1274 
1275  if (s->Phone.Data.Priv.OBEXGEN.Service != OBEX_BrowsingFolders) {
1276  return ERR_NOTSUPPORTED;
1277  }
1278 
1279  /* Go to file directory */
1280  error = OBEXGEN_ChangeToFilePath(s, ID, TRUE, req2);
1281  if (error != ERR_NONE) return error;
1282 
1283  /* Name block */
1284  OBEXAddBlock(req, &Current, 0x01, req2, UnicodeLength(req2)*2+2);
1285 
1286  /* connection ID block */
1287  OBEXGEN_AddConnectionID(s, req, &Current);
1288 
1289  return GSM_WaitFor (s, req, Current, 0x82, OBEX_TIMEOUT, ID_AddFile);
1290 }
1291 
1293 {
1294  GSM_Error error;
1295 
1296  /* Go to default service */
1297  error = OBEXGEN_Connect(s, 0);
1298  if (error != ERR_NONE) return error;
1299 
1300  if (s->Phone.Data.Priv.OBEXGEN.Service != OBEX_BrowsingFolders) {
1301  return ERR_NOTSUPPORTED;
1302  }
1303 
1304  /* Go to file directory */
1305  error = OBEXGEN_ChangeToFilePath(s, File->ID_FullName, FALSE, NULL);
1306  if (error != ERR_NONE) return error;
1307 
1308  /* Add folder */
1309  smprintf(s,"Adding directory\n");
1310  error = OBEXGEN_ChangePath(s, File->Name, 0);
1311  if (error != ERR_NONE) return error;
1312 
1313  /* Calculate path of added folder */
1314  OBEXGEN_CreateFileName(File->ID_FullName, File->ID_FullName, File->Name);
1315  return ERR_NONE;
1316 }
1317 
1329 GSM_Error OBEXGEN_GetFile(GSM_StateMachine *s, const char *FileName, unsigned char ** Buffer, size_t *len)
1330 {
1331  GSM_Error error = ERR_NONE;
1332  GSM_File File;
1333 
1334  /* Clear structure */
1335  memset(&File, 0, sizeof(GSM_File));
1336 
1337  /* Encode file name to unicode */
1338  EncodeUnicode(File.ID_FullName, FileName, strlen(FileName));
1339 
1340  /* Grab complete file */
1341  while (error == ERR_NONE) {
1342  error = OBEXGEN_PrivGetFilePart(s, &File, FALSE);
1343  }
1344 
1345  /* We should get ERR_EMPTY at the end of file */
1346  if (error != ERR_EMPTY) {
1347  if (File.Buffer != NULL) {
1348  free(File.Buffer);
1349  File.Buffer=NULL;
1350  }
1351  return error;
1352  }
1353 
1354  /* Return data we got */
1355  *Buffer = File.Buffer;
1356  *len = File.Used;
1357  return ERR_NONE;
1358 }
1359 
1363 GSM_Error OBEXGEN_GetBinaryFile(GSM_StateMachine *s, const char *FileName, unsigned char ** Buffer, size_t *len)
1364 {
1365  GSM_Error error = ERR_NONE;
1366 
1367  /* Grab complete file */
1368  error = OBEXGEN_GetFile(s, FileName, (unsigned char **)Buffer, len);
1369  if (error != ERR_NONE) return error;
1370 
1371  /* Return data we got */
1372  smprintf(s, "Got %ld bytes of data\n", (long int)*len);
1373  *Buffer = (unsigned char *)realloc(*Buffer, *len + 1);
1374  if (*Buffer == NULL) {
1375  return ERR_MOREMEMORY;
1376  }
1377  (*Buffer)[*len] = 0;
1378  return ERR_NONE;
1379 }
1380 
1384 GSM_Error OBEXGEN_GetTextFile(GSM_StateMachine *s, const char *FileName, char ** Buffer)
1385 {
1386  size_t len;
1387 
1388  return OBEXGEN_GetBinaryFile(s, FileName, (unsigned char **)Buffer, &len);
1389 }
1390 
1394 GSM_Error OBEXGEN_SetFile(GSM_StateMachine *s, const char *FileName, const unsigned char *Buffer, size_t Length, gboolean HardDelete)
1395 {
1396  GSM_Error error = ERR_NONE;
1397  GSM_File File;
1398  size_t Pos = 0;
1399  int Handle;
1400 
1401  /* Fill file structure */
1402  EncodeUnicode(File.ID_FullName, FileName, strlen(FileName));
1403  EncodeUnicode(File.Name, FileName, strlen(FileName));
1404  File.Used = Length;
1405  File.Buffer = (unsigned char *)Buffer;
1406 
1407  /* Send file */
1408  while (error == ERR_NONE) {
1409  error = OBEXGEN_PrivAddFilePart(s, &File, &Pos, &Handle, HardDelete);
1410  }
1411  if (error != ERR_EMPTY) return error;
1412 
1413  return ERR_NONE;
1414 }
1415 
1430 GSM_Error OBEXGEN_ParseInfoLog(GSM_StateMachine *s, const char *data, int *free_out, int *used_out, IRMC_Capability *Cap)
1431 {
1432  char *pos;
1433  int IEL;
1434  int maximum_records = -1;
1435  int used_records = -1;
1436  int free_records = -1;
1437  char free_text[] = "Free-Records:";
1438  char used_text[] = "Total-Records:";
1439  char maximum_text[] = "Maximum-Records:";
1440  char IEL_text[] = "IEL:";
1441  char HD_text[] = "HD:";
1442 
1443  smprintf(s, "OBEX info data:\n---\n%s\n---\n", data);
1444 
1445  pos = strstr(data, IEL_text);
1446  if (pos == NULL) {
1447  smprintf(s, "Could not grab Information Exchange Level, phone does not support it\n");
1448  return ERR_NOTSUPPORTED;
1449  }
1450  pos += strlen(IEL_text);
1451  /* This might be hex */
1452  if (pos[0] != 0 && pos[0] == '0' && pos[1] != 0 && pos[1] == 'x') {
1453  /* Hex means IEL flag we use */
1454  IEL = strtol(pos + 2, (char **)NULL, 16);
1455  } else {
1456  /* Decimal means directly IEL level, convert it to flags */
1457  IEL = atoi(pos);
1458  /* Adjust index to flags we use further */
1459  switch (IEL) {
1460  case 3:
1461  IEL = 0x4;
1462  break;
1463  case 4:
1464  IEL = 0x8;
1465  /* In fact this can be also 0x10, but we can't tell */
1466  break;
1467  }
1468  }
1469  switch (IEL) {
1470  case 0x1:
1471  smprintf(s, "Information Exchange Level 1 supported\n");
1472  break;
1473  case 0x2:
1474  smprintf(s, "Information Exchange Level 1 and 2 supported\n");
1475  break;
1476  case 0x4:
1477  smprintf(s, "Information Exchange Level 1, 2 and 3 supported\n");
1478  break;
1479  case 0x8:
1480  smprintf(s, "Information Exchange Level 1, 2 and 4 supported\n");
1481  break;
1482  case 0x10:
1483  smprintf(s, "Information Exchange Level 1, 2, 3 and 4 supported\n");
1484  break;
1485  default:
1486  smprintf(s, "Could not parse Information Exchange Level (0x%x)\n", IEL);
1487  return ERR_INVALIDDATA;
1488  }
1489 
1490  if (Cap != NULL) {
1491  Cap->IEL = IEL;
1492  }
1493 
1494  pos = strstr(data, HD_text);
1495  if (pos == NULL) {
1496  smprintf(s, "Could not grab HD support\n");
1497  } else {
1498  pos += strlen(HD_text);
1499  if (strncasecmp("YES", pos, 3) == 0) {
1500  smprintf(s, "HD is supported\n");
1501  if (Cap != NULL) {
1502  Cap->HD = TRUE;
1503  }
1504  } else if (strncasecmp("NO", pos, 2) == 0) {
1505  smprintf(s, "HD is not supported\n");
1506  } else {
1507  smprintf(s, "WARNING: Could not parse HD support\n");
1508  }
1509  }
1510 
1511  pos = strstr(data, free_text);
1512  if (pos == NULL) {
1513  smprintf(s, "Could not grab number of free records\n");
1514  } else {
1515  pos += strlen(free_text);
1516  free_records = atoi(pos);
1517  smprintf(s, "Number of free records: %d\n", free_records);
1518  }
1519 
1520  pos = strstr(data, used_text);
1521  if (pos == NULL) {
1522  smprintf(s, "Could not grab number of used records\n");
1523  } else {
1524  pos += strlen(used_text);
1525  used_records = atoi(pos);
1526  smprintf(s, "Number of used records: %d\n", used_records);
1527  }
1528 
1529  pos = strstr(data, maximum_text);
1530  if (pos == NULL) {
1531  smprintf(s, "Could not grab number of maximum records\n");
1532  } else {
1533  pos += strlen(maximum_text);
1534  maximum_records = atoi(pos);
1535  smprintf(s, "Number of maximum records: %d\n", maximum_records);
1536  }
1537 
1538  if (free_out != NULL) {
1539  if (free_records != -1) {
1540  *free_out = free_records;
1541  } else if (maximum_records != -1 && used_records != -1) {
1542  *free_out = maximum_records - used_records;
1543  } else {
1544  *free_out = 0;
1545  smprintf(s, "Could not grab number of free records\n");
1546  return ERR_INVALIDDATA;
1547  }
1548  }
1549 
1550  if (used_out != NULL) {
1551  if (used_records != -1) {
1552  *used_out = used_records;
1553  } else if (maximum_records != -1 && free_records != -1) {
1554  *used_out = maximum_records - free_records;
1555  } else {
1556  *used_out = 0;
1557  smprintf(s, "Could not grab number of used records\n");
1558  return ERR_INVALIDDATA;
1559  }
1560  }
1561 
1562  return ERR_NONE;
1563 }
1564 
1568 GSM_Error OBEXGEN_GetInformation(GSM_StateMachine *s, const char *path, int *free_records, int *used_records, IRMC_Capability *Cap)
1569 {
1570  GSM_Error error;
1571  char *data;
1572 
1573  /* IEL by default - support adding */
1574  Cap->IEL = 1;
1575 
1576  /* We need IrMC service for this */
1577  error = OBEXGEN_Connect(s, OBEX_IRMC);
1578  if (error != ERR_NONE) return error;
1579 
1580  /* Grab log info file */
1581  error = OBEXGEN_GetTextFile(s, path, &data);
1582 
1583  /* Level 0 or 1 phones do not have to expose information */
1584  if (error == ERR_BUG || error == ERR_FILENOTEXIST || error == ERR_PERMISSION) {
1585  /* Some phones do not follow IrMC specs and do not provide info.log for level 2 */
1587  Cap->IEL = 2;
1588  }
1589  if (free_records == NULL) {
1590  /* We were asked only for IEL, so don't bail out */
1591  return ERR_NONE;
1592  } else {
1593  /* No support for status if no info.log */
1594  return ERR_NOTSUPPORTED;
1595  }
1596  } else if (error != ERR_NONE) {
1597  /* Something wrong has happened */
1598  return error;
1599  }
1600 
1601  /* Parse it */
1602  error = OBEXGEN_ParseInfoLog(s, data, free_records, used_records, Cap);
1603 
1604  free(data);
1605  data=NULL;
1606  return error;
1607 }
1608 
1612 int OBEXGEN_GetFirstFreeLocation(int **IndexStorage, int *IndexCount) {
1613  int i;
1614  int max = -1;
1615 
1616  /* Find maximum used location */
1617  for (i = 0; i < *IndexCount; i++) {
1618  if (*IndexStorage[i] > max) {
1619  max = (*IndexStorage)[i];
1620  }
1621  }
1622 
1623  /* Next behind maximum is empty */
1624  max++;
1625 
1626  /* Update internal list */
1627  (*IndexCount)++;
1628  *IndexStorage = (int *)realloc(*IndexStorage, (*IndexCount + 1) * sizeof(int));
1629  (*IndexStorage)[*IndexCount] = max;
1630 
1631  return max;
1632 }
1633 
1637 GSM_Error OBEXGEN_InitLUID(GSM_StateMachine *s, const char *Name,
1638  const gboolean Recalculate,
1639  const char *Header,
1640  char **Data, int **Offsets, int *Count,
1641  char ***LUIDStorage, int *LUIDCount,
1642  int **IndexStorage, int *IndexCount)
1643 {
1644  GSM_Error error;
1645  char *pos;
1646  int LUIDSize = 0;
1647  int IndexSize = 0;
1648  int Size = 0;
1649  size_t linepos = 0;
1650  int prevpos;
1651  char line[2000];
1652  size_t len;
1653  size_t hlen;
1654  int level = 0;
1655 
1656  /* Free data if previously allocated */
1657  if (!Recalculate) {
1658  if (*Data != NULL) {
1659  free(*Data);
1660  *Data=NULL;
1661  }
1662  }
1667  /* Grab file with listing */
1668  if (!Recalculate || *Data == NULL) {
1669  /* We need IrMC service for this */
1670  error = OBEXGEN_Connect(s, OBEX_IRMC);
1671  if (error != ERR_NONE) return error;
1672 
1673  error = OBEXGEN_GetTextFile(s, Name, Data);
1674  if (error != ERR_NONE) return error;
1675  }
1676 
1677  *Count = 0;
1678  *Offsets = NULL;
1679  *LUIDCount = 0;
1680  *LUIDStorage = NULL;
1681  *IndexCount = 0;
1682  *IndexStorage = NULL;
1683  len = strlen(*Data);
1684  hlen = strlen(Header);
1685 
1686  while (1) {
1687  /* Remember line start position */
1688  prevpos = linepos;
1689  error = MyGetLine(*Data, &linepos, line, len, sizeof(line), TRUE);
1690  if (error != ERR_NONE) return error;
1691  if (strlen(line) == 0) break;
1692  switch (level) {
1693  case 0:
1694  if (strncmp(line, Header, hlen) == 0) {
1695  level = 1;
1696  (*Count)++;
1697  /* Do we need to reallocate? */
1698  if (*Count >= Size) {
1699  Size += 20;
1700  *Offsets = (int *)realloc(*Offsets, Size * sizeof(int));
1701  if (*Offsets == NULL) {
1702  return ERR_MOREMEMORY;
1703  }
1704  }
1705  /* Store start of item */
1706  (*Offsets)[*Count] = prevpos;
1707  } else if (strncmp(line, "BEGIN:VCALENDAR", 15) == 0) {
1708  /* We need to skip vCalendar header */
1709  } else if (strncmp(line, "BEGIN:", 6) == 0) {
1710  /* Skip other event types */
1711  level = 2;
1712  }
1713  break;
1714  case 1:
1715  if (strncmp(line, "END:", 4) == 0) {
1716  level = 0;
1717  } else if (strncmp(line, "X-IRMC-LUID:", 12) == 0) {
1718  pos = line + 12; /* Length of X-IRMC-LUID: */
1719  (*LUIDCount)++;
1720  /* Do we need to reallocate? */
1721  if (*LUIDCount >= LUIDSize) {
1722  LUIDSize += 20;
1723  *LUIDStorage = (char **)realloc(*LUIDStorage, LUIDSize * sizeof(char *));
1724  if (*LUIDStorage == NULL) {
1725  return ERR_MOREMEMORY;
1726  }
1727  }
1728  /* Copy LUID text */
1729  (*LUIDStorage)[*LUIDCount] = strdup(pos);
1730 #if 0
1731  smprintf(s, "Added LUID %s at position %d\n", (*LUIDStorage)[*LUIDCount], *LUIDCount);
1732 #endif
1733  } else if (strncmp(line, "X-INDEX:", 8) == 0) {
1734  pos = line + 8; /* Length of X-INDEX: */
1735  (*IndexCount)++;
1736  /* Do we need to reallocate? */
1737  if (*IndexCount >= IndexSize) {
1738  IndexSize += 20;
1739  *IndexStorage = (int *)realloc(*IndexStorage, IndexSize * sizeof(int));
1740  if (*IndexStorage == NULL) {
1741  return ERR_MOREMEMORY;
1742  }
1743  }
1744  /* Copy Index text */
1745  (*IndexStorage)[*IndexCount] = atoi(pos);
1746 #if 0
1747  smprintf(s, "Added Index %d at position %d\n", (*IndexStorage)[*IndexCount], *IndexCount);
1748 #endif
1749  }
1750  break;
1751  case 2:
1752  if (strncmp(line, "END:", 4) == 0) level = 0;
1753  break;
1754  }
1755  }
1756 
1757  smprintf(s, "Data parsed, found %d entries, %d indexes and %d LUIDs\n", *Count, *IndexCount, *LUIDCount);
1758 
1759  return ERR_NONE;
1760 }
1761 
1773 GSM_Error OBEXGEN_GetPbInformation(GSM_StateMachine *s, int *free_records, int *used)
1774 {
1775  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1776 
1777  return OBEXGEN_GetInformation(s, "telecom/pb/info.log", free_records, used, &(Priv->PbCap));
1778 
1779 }
1780 
1785 {
1786  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1787 
1788  if (Status->MemoryType != MEM_ME && Status->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
1789 
1790  if (Priv->Service == OBEX_m_OBEX) {
1791  return MOBEX_GetStatus(s, "m-obex/contacts/count", Status->MemoryType, &(Status->MemoryFree), &(Status->MemoryUsed));
1792  }
1793 
1794  if (Status->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
1795 
1796  return OBEXGEN_GetPbInformation(s, &(Status->MemoryFree), &(Status->MemoryUsed));
1797 
1798 }
1799 
1803 GSM_Error OBEXGEN_InitPbLUID(GSM_StateMachine *s)
1804 {
1805  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1806 
1807  /* We might do validation here using telecom/pb/luid/cc.log fir IEL 4, but not on each request */
1808  if (Priv->PbData != NULL) return ERR_NONE;
1809 
1810  return OBEXGEN_InitLUID(s, "telecom/pb.vcf", FALSE, "BEGIN:VCARD",
1811  &(Priv->PbData), &(Priv->PbOffsets), &(Priv->PbCount),
1812  &(Priv->PbLUID), &(Priv->PbLUIDCount),
1813  &(Priv->PbIndex), &(Priv->PbIndexCount));
1814 }
1815 
1819 GSM_Error OBEXGEN_GetMemoryIndex(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1820 {
1821  GSM_Error error;
1822  char *data=NULL;
1823  char *path=NULL;
1824  size_t pos = 0;
1825 
1826  error = OBEXGEN_InitPbLUID(s);
1827  if (error != ERR_NONE) return error;
1828 
1829  /* Calculate path */
1830  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
1831  if (path == NULL) {
1832  return ERR_MOREMEMORY;
1833  }
1834  sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
1835  smprintf(s, "Getting vCard %s\n", path);
1836 
1837  /* Grab vCard */
1838  error = OBEXGEN_GetTextFile(s, path, &data);
1839  free(path);
1840  path=NULL;
1841 
1842  if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
1843  if (error != ERR_NONE) return error;
1844 
1845  /* Decode it */
1846  error = GSM_DecodeVCARD(&(s->di), data, &pos, Entry, SonyEricsson_VCard21_Phone);
1847  free(data);
1848  data=NULL;
1849 
1850  if (error != ERR_NONE) return error;
1851 
1852  return ERR_NONE;
1853 }
1854 
1858 GSM_Error OBEXGEN_GetMemoryLUID(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1859 {
1860  GSM_Error error;
1861  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1862  char *data=NULL;
1863  char *path=NULL;
1864  size_t pos = 0;
1865 
1866  error = OBEXGEN_InitPbLUID(s);
1867  if (error != ERR_NONE) return error;
1868 
1869  /* Check bounds */
1870  if (Entry->Location > Priv->PbLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
1871  if (Priv->PbLUID[Entry->Location] == NULL) return ERR_EMPTY;
1872 
1873  /* Calculate path */
1874  path = (char *)malloc(strlen(Priv->PbLUID[Entry->Location]) + 22); /* Length of string below */
1875  if (path == NULL) {
1876  return ERR_MOREMEMORY;
1877  }
1878  sprintf(path, "telecom/pb/luid/%s.vcf", Priv->PbLUID[Entry->Location]);
1879  smprintf(s, "Getting vCard %s\n", path);
1880 
1881  /* Grab vCard */
1882  error = OBEXGEN_GetTextFile(s, path, &data);
1883  free(path);
1884  path=NULL;
1885  if (error != ERR_NONE) return error;
1886 
1887  /* Decode it */
1888  error = GSM_DecodeVCARD(&(s->di), data, &pos, Entry, SonyEricsson_VCard21_Phone);
1889  free(data);
1890  data=NULL;
1891  if (error != ERR_NONE) return error;
1892 
1893  return ERR_NONE;
1894 }
1895 
1899 GSM_Error OBEXGEN_GetMemoryFull(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
1900 {
1901  GSM_Error error;
1902  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1903  size_t pos = 0;
1904 
1905  /* Read phonebook data */
1906  error = OBEXGEN_InitPbLUID(s);
1907  if (error != ERR_NONE) return error;
1908 
1909  /* Check bounds */
1910  if (Entry->Location > Priv->PbCount) return ERR_EMPTY; /* Maybe invalid location? */
1911 
1912  /* Decode vCard */
1913  error = GSM_DecodeVCARD(&(s->di), Priv->PbData + Priv->PbOffsets[Entry->Location], &pos, Entry, SonyEricsson_VCard21_Phone);
1914  if (error != ERR_NONE) return error;
1915 
1916  return ERR_NONE;
1917 }
1918 
1920 {
1921  GSM_Error error;
1922  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1923 
1924  if (Entry->MemoryType != MEM_ME && Entry->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
1925 
1926  /* Handle m-obex case */
1927  if (Priv->Service == OBEX_m_OBEX) {
1928  return MOBEX_GetMemory(s, Entry);
1929  }
1930 
1931  if (Entry->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
1932 
1933  /* We need IrMC service for this */
1934  error = OBEXGEN_Connect(s, OBEX_IRMC);
1935  if (error != ERR_NONE) return error;
1936 
1937  /* We need IEL to correctly talk to phone */
1938  if (Priv->PbCap.IEL == -1) {
1939  error = OBEXGEN_GetPbInformation(s, NULL, NULL);
1940  if (error != ERR_NONE) return error;
1941  }
1942 
1943  /* Use correct function according to supported IEL */
1944  if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
1945  return OBEXGEN_GetMemoryLUID(s, Entry);
1946  } else if (Priv->PbCap.IEL == 0x4) {
1947  return OBEXGEN_GetMemoryIndex(s, Entry);
1948  } else if (Priv->PbCap.IEL == 0x2) {
1949  return OBEXGEN_GetMemoryFull(s, Entry);
1950  } else {
1951  smprintf(s, "Can not read phonebook from IEL 1 phone\n");
1952  return ERR_NOTSUPPORTED;
1953  }
1954 }
1955 
1957 {
1958  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
1959  GSM_Error error = ERR_EMPTY;;
1960 
1961 
1962  /* Handle m-obex case */
1963  if (Priv->Service == OBEX_m_OBEX) {
1964  return MOBEX_GetNextMemory(s, Entry, start);
1965  }
1966 
1967  /* Get location */
1968  if (start) {
1969  Entry->Location = 1;
1970  Priv->ReadPhonebook = 0;
1971  } else {
1972  Entry->Location++;
1973  }
1974 
1975  /* Do real getting */
1976  while (error == ERR_EMPTY) {
1977 
1978  /* Have we read them all? */
1979  /* Needs to be inside loop as we get count after
1980  * first invocation of get function */
1981  if (Priv->ReadPhonebook == Priv->PbCount) {
1982  return ERR_EMPTY;
1983  }
1984 
1985  error = OBEXGEN_GetMemory(s, Entry);
1986  if (error == ERR_NONE) {
1987  Priv->ReadPhonebook++;
1988  } else if (error == ERR_EMPTY) {
1989  Entry->Location++;
1990  }
1991  }
1992  return error;
1993 }
1994 
1996 {
1997  unsigned char req[5000];
1998  char path[100];
1999  size_t size=0;
2000  GSM_Error error;
2001  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2002 
2003  if (Entry->MemoryType != MEM_ME && (Entry->MemoryType != MEM_SM || Priv->Service != OBEX_m_OBEX)) return ERR_NOTSUPPORTED;
2004 
2005  /* Encode vCard */
2006  error = GSM_EncodeVCARD(&(s->di), req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCard21);
2007  if (error != ERR_NONE) return error;
2008 
2009  /* Handle m-obex case */
2010  if (Priv->Service == OBEX_m_OBEX) {
2011  return MOBEX_CreateEntry(s, "m-obex/contacts/create", Entry->MemoryType, &(Entry->Location), req);
2012  }
2013 
2014  /* We need IrMC service for this */
2015  error = OBEXGEN_Connect(s, OBEX_IRMC);
2016  if (error != ERR_NONE) return error;
2017 
2018  /* We need IEL to correctly talk to phone */
2019  if (Priv->PbCap.IEL == -1) {
2020  error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2021  if (error != ERR_NONE) return error;
2022  }
2023 
2024  /* Use correct function according to supported IEL */
2025  if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2026  /* We need to grab LUID list now in order to keep position later */
2027  error = OBEXGEN_InitPbLUID(s);
2028  if (error != ERR_NONE) return error;
2029 
2030  smprintf(s,"Adding phonebook entry %ld:\n%s\n", (long)size, req);
2031  Priv->UpdatePbLUID = TRUE;
2032  error = OBEXGEN_SetFile(s, "telecom/pb/luid/.vcf", req, size, FALSE);
2033  Entry->Location = Priv->PbLUIDCount;
2034  if (error == ERR_NONE) Priv->PbCount++;
2035  return error;
2036  } else if (Priv->PbCap.IEL == 0x4) {
2037  /* We need to grab LUID/Index list now in order to keep position later */
2038  error = OBEXGEN_InitPbLUID(s);
2039  if (error != ERR_NONE) return error;
2040 
2041  Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->PbIndex, &Priv->PbIndexCount);
2042  smprintf(s,"Adding phonebook entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2043  sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
2044  error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2045  if (error == ERR_NONE) Priv->PbCount++;
2046  return error;
2047  } else {
2048  /* I don't know add command for other levels, just plain send vCard */
2049  Entry->Location = 0;
2050  smprintf(s,"Sending phonebook entry\n");
2051  return OBEXGEN_SetFile(s, "gammu.vcf", req, size, FALSE);
2052  }
2053 }
2054 
2055 GSM_Error OBEXGEN_SetMemoryLUID(GSM_StateMachine *s, GSM_MemoryEntry *Entry, const char *Data, int Size)
2056 {
2057  GSM_Error error;
2058  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2059  char *path=NULL;
2060 
2061  error = OBEXGEN_InitPbLUID(s);
2062  if (error != ERR_NONE) return error;
2063 
2064  /* Check bounds */
2065  if (Entry->Location > Priv->PbLUIDCount ||
2066  Priv->PbLUID[Entry->Location] == NULL) {
2070  return OBEXGEN_AddMemory(s, Entry);
2071  }
2072 
2073  /* Calculate path */
2074  path = (char *)malloc(strlen(Priv->PbLUID[Entry->Location]) + 22); /* Length of string below */
2075  if (path == NULL) {
2076  return ERR_MOREMEMORY;
2077  }
2078  sprintf(path, "telecom/pb/luid/%s.vcf", Priv->PbLUID[Entry->Location]);
2079  smprintf(s, "Seting vCard %s [%d]\n", path, Entry->Location);
2080 
2081  /* Forget entry if we're deleting */
2082  if (Size == 0) {
2083  free(Priv->PbLUID[Entry->Location]);
2084  Priv->PbLUID[Entry->Location] = NULL;
2085  Priv->PbCount--;
2086  }
2087 
2088  /* Store vCard */
2089  error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->PbCap.HD : FALSE);;
2090  free(path);
2091  return error;
2092 }
2093 
2094 GSM_Error OBEXGEN_SetMemoryIndex(GSM_StateMachine *s, GSM_MemoryEntry *Entry, const char *Data, int Size)
2095 {
2096  char *path=NULL;
2097  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2098  GSM_Error error;
2099 
2100  /* Forget entry if we're deleting */
2101  if (Size == 0) {
2102  Priv->PbCount--;
2103  }
2104 
2105  /* Calculate path */
2106  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2107  if (path == NULL) {
2108  return ERR_MOREMEMORY;
2109  }
2110  sprintf(path, "telecom/pb/%d.vcf", Entry->Location);
2111  smprintf(s, "Seting vCard %s\n", path);
2112 
2113  /* Store vCard */
2114  error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
2115  free(path);
2116  return error;
2117 }
2118 
2120 {
2121  unsigned char req[5000];
2122  size_t size=0;
2123  GSM_Error error;
2124  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2125 
2126  if (Entry->MemoryType != MEM_ME && (Entry->MemoryType != MEM_SM || Priv->Service != OBEX_m_OBEX)) return ERR_NOTSUPPORTED;
2127 
2128  /* Encode vCard */
2129  error = GSM_EncodeVCARD(&(s->di), req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCard21);
2130  if (error != ERR_NONE) return error;
2131 
2132  /* Handle m-obex case */
2133  if (Priv->Service == OBEX_m_OBEX) {
2134  return MOBEX_UpdateEntry(s, "m-obex/contacts/write", Entry->Location, Entry->MemoryType, req);
2135  }
2136 
2137  /* We need IrMC service for this */
2138  error = OBEXGEN_Connect(s, OBEX_IRMC);
2139  if (error != ERR_NONE) return error;
2140 
2141  /* We need IEL to correctly talk to phone */
2142  if (Priv->PbCap.IEL == -1) {
2143  error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2144  if (error != ERR_NONE) return error;
2145  }
2146 
2147  /* Use correct function according to supported IEL */
2148  if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2149  return OBEXGEN_SetMemoryLUID(s, Entry, req, size);
2150  } else if (Priv->PbCap.IEL == 0x4) {
2151  return OBEXGEN_SetMemoryIndex(s, Entry, req, size);
2152  } else if (Priv->PbCap.IEL == 0x2) {
2153  /* Work on full phonebook */
2154  return ERR_NOTIMPLEMENTED;
2155  } else {
2156  return ERR_NOTSUPPORTED;
2157  }
2158 }
2159 
2161 {
2162  GSM_Error error;
2163  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2164 
2165  if (Entry->MemoryType != MEM_ME && Entry->MemoryType != MEM_SM) return ERR_NOTSUPPORTED;
2166 
2167  if (Priv->Service == OBEX_m_OBEX) {
2168  return MOBEX_UpdateEntry(s, "m-obex/contacts/delete", Entry->Location, Entry->MemoryType, NULL);
2169  }
2170 
2171  if (Entry->MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
2172 
2173  /* We need IrMC service for this */
2174  error = OBEXGEN_Connect(s, OBEX_IRMC);
2175  if (error != ERR_NONE) return error;
2176 
2177  /* We need IEL to correctly talk to phone */
2178  if (Priv->PbCap.IEL == -1) {
2179  error = OBEXGEN_GetPbInformation(s, NULL, NULL);
2180  if (error != ERR_NONE) return error;
2181  }
2182 
2183  /* Use correct function according to supported IEL */
2184  if (Priv->PbCap.IEL == 0x8 || Priv->PbCap.IEL == 0x10) {
2185  return OBEXGEN_SetMemoryLUID(s, Entry, "", 0);
2186  } else if (Priv->PbCap.IEL == 0x4) {
2187  return OBEXGEN_SetMemoryIndex(s, Entry, "", 0);
2188  } else if (Priv->PbCap.IEL == 0x2) {
2189  /* Work on full phonebook */
2190  return ERR_NOTIMPLEMENTED;
2191  } else {
2192  return ERR_NOTSUPPORTED;
2193  }
2194 }
2195 
2197 {
2198  GSM_Error error;
2199  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2200  GSM_MemoryEntry entry;
2201 
2202  /* Should not happen */
2203  if (MemoryType != MEM_ME) return ERR_NOTSUPPORTED;
2204 
2205  /* We need IrMC service for this */
2206  error = OBEXGEN_Connect(s, OBEX_IRMC);
2207  if (error != ERR_NONE) return error;
2208 
2209  /* We need count of entries */
2210  error = OBEXGEN_InitPbLUID(s);
2211  if (error != ERR_NONE) return error;
2212 
2213  /* Delete all entries */
2214  entry.Location = 1;
2215  entry.MemoryType = MEM_ME;
2216  while (Priv->PbCount > 0) {
2217  error = OBEXGEN_DeleteMemory(s, &entry);
2218  if (error != ERR_NONE && error != ERR_EMPTY) return error;
2219  entry.Location++;
2220  }
2221  return error;
2222 }
2223 
2235 GSM_Error OBEXGEN_GetCalInformation(GSM_StateMachine *s, int *free_records, int *used)
2236 {
2237  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2238 
2239  return OBEXGEN_GetInformation(s, "telecom/cal/info.log", free_records, used, &(Priv->CalCap));
2240 
2241 }
2242 
2246 GSM_Error OBEXGEN_InitCalLUID(GSM_StateMachine *s)
2247 {
2248  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2249  GSM_Error error;
2250 
2251  /* We might do validation here using telecom/cal/luid/cc.log fir IEL 4, but not on each request */
2252  if (Priv->CalData != NULL) return ERR_NONE;
2253 
2254  error = OBEXGEN_InitLUID(s, "telecom/cal.vcs", FALSE, "BEGIN:VEVENT",
2255  &(Priv->CalData), &(Priv->CalOffsets), &(Priv->CalCount),
2256  &(Priv->CalLUID), &(Priv->CalLUIDCount),
2257  &(Priv->CalIndex), &(Priv->CalIndexCount));
2258  if (error != ERR_NONE) return error;
2259  return OBEXGEN_InitLUID(s, "telecom/cal.vcs", TRUE, "BEGIN:VTODO",
2260  &(Priv->CalData), &(Priv->TodoOffsets), &(Priv->TodoCount),
2261  &(Priv->TodoLUID), &(Priv->TodoLUIDCount),
2262  &(Priv->TodoIndex), &(Priv->TodoIndexCount));
2263 }
2264 
2277 {
2278  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2279  GSM_Error error;
2280 
2281  if (Priv->Service == OBEX_m_OBEX) {
2282  return MOBEX_GetStatus(s, "m-obex/calendar/count", MEM_ME, &(Status->Free), &(Status->Used));
2283  }
2284 
2285  error = OBEXGEN_InitCalLUID(s);
2286  if (error != ERR_NONE) return error;
2287 
2288  Status->Used = Priv->CalCount;
2289 
2290  return OBEXGEN_GetCalInformation(s, &(Status->Free), NULL);
2291 
2292 }
2293 
2297 GSM_Error OBEXGEN_GetCalendarIndex(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2298 {
2299  GSM_Error error;
2300  char *data=NULL;
2301  char *path=NULL;
2302  size_t pos = 0;
2303  GSM_ToDoEntry ToDo;
2304 
2305  error = OBEXGEN_InitCalLUID(s);
2306  if (error != ERR_NONE) return error;
2307 
2308  /* Calculate path */
2309  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2310  if (path == NULL) {
2311  return ERR_MOREMEMORY;
2312  }
2313  sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2314  smprintf(s, "Getting vCalendar %s\n", path);
2315 
2316  /* Grab vCalendar */
2317  error = OBEXGEN_GetTextFile(s, path, &data);
2318  free(path);
2319  path=NULL;
2320  if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
2321  if (error != ERR_NONE) return error;
2322 
2323  /* Decode it */
2324  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2325  free(data);
2326  data=NULL;
2327  if (error != ERR_NONE) return error;
2328 
2329  return ERR_NONE;
2330 }
2331 
2335 GSM_Error OBEXGEN_GetCalendarLUID(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2336 {
2337  GSM_Error error;
2338  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2339  char *data=NULL;
2340  char *path=NULL;
2341  size_t pos = 0;
2342  GSM_ToDoEntry ToDo;
2343 
2344  error = OBEXGEN_InitCalLUID(s);
2345  if (error != ERR_NONE) return error;
2346 
2347  /* Check bounds */
2348  if (Entry->Location > Priv->CalLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
2349  if (Priv->CalLUID[Entry->Location] == NULL) return ERR_EMPTY;
2350 
2351  /* Calculate path */
2352  path = (char *)malloc(strlen(Priv->CalLUID[Entry->Location]) + 22); /* Length of string below */
2353  if (path == NULL) {
2354  return ERR_MOREMEMORY;
2355  }
2356  sprintf(path, "telecom/cal/luid/%s.vcs", Priv->CalLUID[Entry->Location]);
2357  smprintf(s, "Getting vCalendar %s\n", path);
2358 
2359  /* Grab vCalendar */
2360  error = OBEXGEN_GetTextFile(s, path, &data);
2361  free(path);
2362  path=NULL;
2363  if (error != ERR_NONE) return error;
2364 
2365  /* Decode it */
2366  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2367  free(data);
2368  data=NULL;
2369  if (error != ERR_NONE) return error;
2370 
2371  return ERR_NONE;
2372 }
2373 
2377 GSM_Error OBEXGEN_GetCalendarFull(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
2378 {
2379  GSM_Error error;
2380  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2381  size_t pos = 0;
2382  GSM_ToDoEntry ToDo;
2383 
2384  /* Read calendar data */
2385  error = OBEXGEN_InitCalLUID(s);
2386  if (error != ERR_NONE) return error;
2387 
2388  /* Check bounds */
2389  if (Entry->Location > Priv->CalCount) return ERR_EMPTY; /* Maybe invalid location? */
2390 
2391  /* Decode vCalendar */
2392  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), Priv->CalData + Priv->CalOffsets[Entry->Location], &pos, Entry, &ToDo, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2393  if (error != ERR_NONE) return error;
2394 
2395  return ERR_NONE;
2396 }
2397 
2399 {
2400  GSM_Error error;
2401  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2402 
2403  /* Handle m-obex case */
2404  if (Priv->Service == OBEX_m_OBEX) {
2405  return MOBEX_GetCalendar(s, Entry);
2406  }
2407 
2408  /* We need IrMC service for this */
2409  error = OBEXGEN_Connect(s, OBEX_IRMC);
2410  if (error != ERR_NONE) return error;
2411 
2412  /* We need IEL to correctly talk to phone */
2413  if (Priv->CalCap.IEL == -1) {
2414  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2415  if (error != ERR_NONE) return error;
2416  }
2417 
2418  /* Use correct function according to supported IEL */
2419  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2420  return OBEXGEN_GetCalendarLUID(s, Entry);
2421  } else if (Priv->CalCap.IEL == 0x4) {
2422  return OBEXGEN_GetCalendarIndex(s, Entry);
2423  } else if (Priv->CalCap.IEL == 0x2) {
2424  return OBEXGEN_GetCalendarFull(s, Entry);
2425  } else {
2426  smprintf(s, "Can not read calendar from IEL 1 phone\n");
2427  return ERR_NOTSUPPORTED;
2428  }
2429 }
2430 
2432 {
2433  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2434  GSM_Error error = ERR_EMPTY;;
2435 
2436  /* Handle m-obex case */
2437  if (Priv->Service == OBEX_m_OBEX) {
2438  return MOBEX_GetNextCalendar(s, Entry, start);
2439  }
2440 
2441  /* Get location */
2442  if (start) {
2443  Entry->Location = 1;
2444  Priv->ReadCalendar = 0;
2445  } else {
2446  Entry->Location++;
2447  }
2448 
2449  /* Do real getting */
2450  while (error == ERR_EMPTY) {
2451 
2452  /* Have we read them all? */
2453  /* Needs to be inside loop as we get count after
2454  * first invocation of get function */
2455  if (Priv->ReadCalendar == Priv->CalCount) {
2456  return ERR_EMPTY;
2457  }
2458 
2459  error = OBEXGEN_GetCalendar(s, Entry);
2460  if (error == ERR_NONE) {
2461  Priv->ReadCalendar++;
2462  } else if (error == ERR_EMPTY) {
2463  Entry->Location++;
2464  }
2465  }
2466  return error;
2467 }
2468 
2470 {
2471  unsigned char req[5000];
2472  char path[100];
2473  size_t size=0;
2474  GSM_Error error;
2475  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2476 
2477  /* Encode vCalendar */
2478  error = GSM_EncodeVCALENDAR(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCalendar);
2479  if (error != ERR_NONE) return error;
2480 
2481  /* Handle m-obex case */
2482  if (Priv->Service == OBEX_m_OBEX) {
2483  return MOBEX_CreateEntry(s, "m-obex/calendar/create", MEM_ME, &(Entry->Location), req);
2484  }
2485 
2486  /* We need IrMC service for this */
2487  error = OBEXGEN_Connect(s, OBEX_IRMC);
2488  if (error != ERR_NONE) return error;
2489 
2490  /* We need IEL to correctly talk to phone */
2491  if (Priv->CalCap.IEL == -1) {
2492  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2493  if (error != ERR_NONE) return error;
2494  }
2495 
2496  /* Use correct function according to supported IEL */
2497  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2498  /* We need to grab LUID list now in order to keep position later */
2499  error = OBEXGEN_InitCalLUID(s);
2500  if (error != ERR_NONE) return error;
2501 
2502  smprintf(s,"Adding calendar entry %ld:\n%s\n", (long)size, req);
2503  Priv->UpdateCalLUID = TRUE;
2504  error = OBEXGEN_SetFile(s, "telecom/cal/luid/.vcs", req, size, FALSE);
2505  Entry->Location = Priv->CalLUIDCount;
2506  if (error == ERR_NONE) Priv->CalCount++;
2507  return error;
2508  } else if (Priv->CalCap.IEL == 0x4) {
2509  /* We need to grab LUID/Index list now in order to keep position later */
2510  error = OBEXGEN_InitCalLUID(s);
2511  if (error != ERR_NONE) return error;
2512 
2513  Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->CalIndex, &Priv->CalIndexCount);
2514  smprintf(s,"Adding calendar entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2515  sprintf(path, "telecom/cal/%d.vcf", Entry->Location);
2516  error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2517  if (error == ERR_NONE) Priv->CalCount++;
2518  return error;
2519  } else {
2520  /* I don't know add command for other levels, just plain send vCalendar */
2521  Entry->Location = 0;
2522  smprintf(s,"Sending calendar entry\n");
2523  return OBEXGEN_SetFile(s, "gammu.vcs", req, size, FALSE);
2524  }
2525 }
2526 
2527 GSM_Error OBEXGEN_SetCalendarLUID(GSM_StateMachine *s, GSM_CalendarEntry *Entry, const char *Data, int Size)
2528 {
2529  GSM_Error error;
2530  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2531  char *path=NULL;
2532 
2533  error = OBEXGEN_InitCalLUID(s);
2534  if (error != ERR_NONE) return error;
2535 
2536  /* Check bounds */
2537  if (Entry->Location > Priv->CalLUIDCount
2538  || Priv->CalLUID[Entry->Location] == NULL) {
2542  return OBEXGEN_AddCalendar(s, Entry);
2543  }
2544 
2545  /* Calculate path */
2546  path = (char *)malloc(strlen(Priv->CalLUID[Entry->Location]) + 22); /* Length of string below */
2547  if (path == NULL) {
2548  return ERR_MOREMEMORY;
2549  }
2550  sprintf(path, "telecom/cal/luid/%s.vcs", Priv->CalLUID[Entry->Location]);
2551  smprintf(s, "Seting vCalendar %s\n", path);
2552 
2553  /* Forget entry if we're deleting */
2554  if (Size == 0) {
2555  free(Priv->CalLUID[Entry->Location]);
2556  Priv->CalLUID[Entry->Location] = NULL;
2557  Priv->CalCount--;
2558  }
2559 
2560  /* Store vCalendar */
2561  error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->CalCap.HD : FALSE);;
2562  free(path);
2563  return error;
2564 }
2565 
2566 GSM_Error OBEXGEN_SetCalendarIndex(GSM_StateMachine *s, GSM_CalendarEntry *Entry, const char *Data, int Size)
2567 {
2568  char *path=NULL;
2569  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2570  GSM_Error error;
2571 
2572  /* Forget entry if we're deleting */
2573  if (Size == 0) {
2574  Priv->CalCount--;
2575  }
2576 
2577  /* Calculate path */
2578  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2579  if (path == NULL) {
2580  return ERR_MOREMEMORY;
2581  }
2582  sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2583  smprintf(s, "Seting vCalendar %s\n", path);
2584 
2585  /* Store vCalendar */
2586  error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
2587  free(path);
2588  return error;
2589 }
2590 
2592 {
2593  unsigned char req[5000];
2594  size_t size=0;
2595  GSM_Error error;
2596  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2597 
2598  /* Encode vCalendar */
2599  error = GSM_EncodeVCALENDAR(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VCalendar);
2600  if (error != ERR_NONE) return error;
2601 
2602  /* Handle m-obex case */
2603  if (Priv->Service == OBEX_m_OBEX) {
2604  return MOBEX_UpdateEntry(s, "m-obex/calendar/write", Entry->Location, MEM_ME, req);
2605  }
2606 
2607  /* We need IrMC service for this */
2608  error = OBEXGEN_Connect(s, OBEX_IRMC);
2609  if (error != ERR_NONE) return error;
2610 
2611  /* We need IEL to correctly talk to phone */
2612  if (Priv->CalCap.IEL == -1) {
2613  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2614  if (error != ERR_NONE) return error;
2615  }
2616 
2617  /* Use correct function according to supported IEL */
2618  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2619  return OBEXGEN_SetCalendarLUID(s, Entry, req, size);
2620  } else if (Priv->CalCap.IEL == 0x4) {
2621  return OBEXGEN_SetCalendarIndex(s, Entry, req, size);
2622  } else if (Priv->CalCap.IEL == 0x2) {
2623  /* Work on full calendar */
2624  return ERR_NOTIMPLEMENTED;
2625  } else {
2626  return ERR_NOTSUPPORTED;
2627  }
2628 }
2629 
2631 {
2632  GSM_Error error;
2633  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2634 
2635  /* Handle m-obex case */
2636  if (Priv->Service == OBEX_m_OBEX) {
2637  return MOBEX_UpdateEntry(s, "m-obex/calendar/delete", Entry->Location, 1, NULL);
2638  }
2639 
2640  /* We need IrMC service for this */
2641  error = OBEXGEN_Connect(s, OBEX_IRMC);
2642  if (error != ERR_NONE) return error;
2643 
2644  /* We need IEL to correctly talk to phone */
2645  if (Priv->CalCap.IEL == -1) {
2646  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2647  if (error != ERR_NONE) return error;
2648  }
2649 
2650  /* Use correct function according to supported IEL */
2651  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2652  return OBEXGEN_SetCalendarLUID(s, Entry, "", 0);
2653  } else if (Priv->CalCap.IEL == 0x4) {
2654  return OBEXGEN_SetCalendarIndex(s, Entry, "", 0);
2655  } else if (Priv->CalCap.IEL == 0x2) {
2656  /* Work on full calendar */
2657  return ERR_NOTIMPLEMENTED;
2658  } else {
2659  return ERR_NOTSUPPORTED;
2660  }
2661 }
2662 
2664 {
2665  GSM_Error error;
2666  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2667  GSM_CalendarEntry entry;
2668 
2669  /* We need IrMC service for this */
2670  error = OBEXGEN_Connect(s, OBEX_IRMC);
2671  if (error != ERR_NONE) return error;
2672 
2673  /* We need count of entries */
2674  error = OBEXGEN_InitCalLUID(s);
2675  if (error != ERR_NONE) return error;
2676 
2677  /* Delete all entries */
2678  entry.Location = 1;
2679  while (Priv->CalCount > 0) {
2680  error = OBEXGEN_DeleteCalendar(s, &entry);
2681  if (error != ERR_NONE && error != ERR_EMPTY) return error;
2682  entry.Location++;
2683  }
2684  return error;
2685 }
2686 
2699 {
2700  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2701  GSM_Error error;
2702 
2703  if (Priv->Service == OBEX_m_OBEX) {
2704  return MOBEX_GetStatus(s, "m-obex/calendar/count", 0xff, &(Status->Free), &(Status->Used));
2705  }
2706 
2707  error = OBEXGEN_InitCalLUID(s);
2708  if (error != ERR_NONE) return error;
2709 
2710  Status->Used = Priv->TodoCount;
2711 
2712  return OBEXGEN_GetCalInformation(s, &(Status->Free), NULL);
2713 
2714 }
2715 
2719 GSM_Error OBEXGEN_GetTodoIndex(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2720 {
2721  GSM_Error error;
2722  char *data=NULL;
2723  char *path=NULL;
2724  size_t pos = 0;
2725  GSM_CalendarEntry Cal;
2726 
2727  /* Todoculate path */
2728  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
2729  if (path == NULL) {
2730  return ERR_MOREMEMORY;
2731  }
2732  sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
2733  smprintf(s, "Getting vTodo %s\n", path);
2734 
2735  /* Grab vTodo */
2736  error = OBEXGEN_GetTextFile(s, path, &data);
2737  free(path);
2738  path=NULL;
2739  if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
2740  if (error != ERR_NONE) return error;
2741 
2742  /* Decode it */
2743  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2744  free(data);
2745  data=NULL;
2746  if (error != ERR_NONE) return error;
2747 
2748  return ERR_NONE;
2749 }
2750 
2754 GSM_Error OBEXGEN_GetTodoLUID(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2755 {
2756  GSM_Error error;
2757  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2758  char *data=NULL;
2759  char *path=NULL;
2760  size_t pos = 0;
2761  GSM_CalendarEntry Cal;
2762 
2763  error = OBEXGEN_InitCalLUID(s);
2764  if (error != ERR_NONE) return error;
2765 
2766  /* Check bounds */
2767  if (Entry->Location > Priv->TodoLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
2768  if (Priv->TodoLUID[Entry->Location] == NULL) return ERR_EMPTY;
2769 
2770  /* Todoculate path */
2771  path = (char *)malloc(strlen(Priv->TodoLUID[Entry->Location]) + 22); /* Length of string below */
2772  if (path == NULL) {
2773  return ERR_MOREMEMORY;
2774  }
2775  sprintf(path, "telecom/cal/luid/%s.vcs", Priv->TodoLUID[Entry->Location]);
2776  smprintf(s, "Getting vTodo %s\n", path);
2777 
2778  /* Grab vTodo */
2779  error = OBEXGEN_GetTextFile(s, path, &data);
2780  free(path);
2781  path=NULL;
2782  if (error != ERR_NONE) return error;
2783 
2784  /* Decode it */
2785  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), data, &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2786  free(data);
2787  data=NULL;
2788  if (error != ERR_NONE) return error;
2789 
2790  return ERR_NONE;
2791 }
2792 
2796 GSM_Error OBEXGEN_GetTodoFull(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
2797 {
2798  GSM_Error error;
2799  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2800  size_t pos = 0;
2801  GSM_CalendarEntry Cal;
2802 
2803  /* Read todo data */
2804  error = OBEXGEN_InitCalLUID(s);
2805  if (error != ERR_NONE) return error;
2806 
2807  /* Check bounds */
2808  if (Entry->Location > Priv->TodoCount) return ERR_EMPTY; /* Maybe invalid location? */
2809 
2810  /* Decode vTodo */
2811  error = GSM_DecodeVCALENDAR_VTODO(&(s->di), Priv->CalData + Priv->TodoOffsets[Entry->Location], &pos, &Cal, Entry, SonyEricsson_VCalendar, SonyEricsson_VToDo);
2812  if (error != ERR_NONE) return error;
2813 
2814  return ERR_NONE;
2815 }
2816 
2818 {
2819  GSM_Error error;
2820  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2821 
2822  /* Handle m-obex case */
2823  if (Priv->Service == OBEX_m_OBEX) {
2824  return MOBEX_GetTodo(s, Entry);
2825  }
2826 
2827  /* We need IrMC service for this */
2828  error = OBEXGEN_Connect(s, OBEX_IRMC);
2829  if (error != ERR_NONE) return error;
2830 
2831  /* We need IEL to correctly talk to phone */
2832  if (Priv->CalCap.IEL == -1) {
2833  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2834  if (error != ERR_NONE) return error;
2835  }
2836 
2837  /* Use correct function according to supported IEL */
2838  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2839  return OBEXGEN_GetTodoLUID(s, Entry);
2840  } else if (Priv->CalCap.IEL == 0x4) {
2841  return OBEXGEN_GetTodoIndex(s, Entry);
2842  } else if (Priv->CalCap.IEL == 0x2) {
2843  return OBEXGEN_GetTodoFull(s, Entry);
2844  } else {
2845  smprintf(s, "Can not read todo from IEL 1 phone\n");
2846  return ERR_NOTSUPPORTED;
2847  }
2848 }
2849 
2851 {
2852  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2853  GSM_Error error = ERR_EMPTY;;
2854 
2855  /* Handle m-obex case */
2856  if (Priv->Service == OBEX_m_OBEX) {
2857  return MOBEX_GetNextTodo(s, Entry, start);
2858  }
2859 
2860  /* Get location */
2861  if (start) {
2862  Entry->Location = 1;
2863  Priv->ReadTodo = 0;
2864  } else {
2865  Entry->Location++;
2866  }
2867 
2868  smprintf (s, "stat: %d, %d\n", Priv->ReadTodo, Priv->TodoCount);
2869 
2870  /* Do real getting */
2871  while (error == ERR_EMPTY) {
2872 
2873  /* Have we read them all? */
2874  /* Needs to be inside loop as we get count after
2875  * first invocation of get function */
2876  if (Priv->ReadTodo >= Priv->TodoCount) {
2877  return ERR_EMPTY;
2878  }
2879 
2880  error = OBEXGEN_GetTodo(s, Entry);
2881  smprintf (s, "attempted location: %d, %d\n", Entry->Location, error);
2882  if (error == ERR_NONE) {
2883  Priv->ReadTodo++;
2884  } else if (error == ERR_EMPTY) {
2885  Entry->Location++;
2886  }
2887  }
2888  return error;
2889 }
2890 
2892 {
2893  unsigned char req[5000];
2894  char path[100];
2895  size_t size=0;
2896  GSM_Error error;
2897  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2898 
2899  /* Encode vTodo */
2900  error = GSM_EncodeVTODO(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VToDo);
2901  if (error != ERR_NONE) return error;
2902 
2903  /* Handle m-obex case */
2904  if (Priv->Service == OBEX_m_OBEX) {
2905  return MOBEX_CreateEntry(s, "m-obex/calendar/create", 7 /* 0xff */, &(Entry->Location), req);
2906  }
2907 
2908  /* We need IrMC service for this */
2909  error = OBEXGEN_Connect(s, OBEX_IRMC);
2910  if (error != ERR_NONE) return error;
2911 
2912  /* We need IEL to correctly talk to phone */
2913  if (Priv->CalCap.IEL == -1) {
2914  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
2915  if (error != ERR_NONE) return error;
2916  }
2917 
2918  /* Use correct function according to supported IEL */
2919  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
2920  /* We need to grab LUID list now in order to keep position later */
2921  error = OBEXGEN_InitCalLUID(s);
2922  if (error != ERR_NONE) return error;
2923 
2924  smprintf(s,"Adding todo entry %ld:\n%s\n", (long)size, req);
2925  Priv->UpdateTodoLUID = TRUE;
2926  error = OBEXGEN_SetFile(s, "telecom/cal/luid/.vcs", req, size, FALSE);
2927  Entry->Location = Priv->TodoLUIDCount;
2928  if (error == ERR_NONE) Priv->TodoCount++;
2929  return error;
2930  } else if (Priv->CalCap.IEL == 0x4) {
2931  /* We need to grab LUID/Index list now in order to keep position later */
2932  error = OBEXGEN_InitCalLUID(s);
2933  if (error != ERR_NONE) return error;
2934 
2935  Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->TodoIndex, &Priv->TodoIndexCount);
2936  smprintf(s,"Adding todo entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
2937  sprintf(path, "telecom/cal/%d.vcf", Entry->Location);
2938  error = OBEXGEN_SetFile(s, path, req, size, FALSE);
2939  if (error == ERR_NONE) Priv->TodoCount++;
2940  return error;
2941  } else {
2942  /* I don't know add command for other levels, just plain send vTodo */
2943  Entry->Location = 0;
2944  smprintf(s,"Sending todo entry\n");
2945  return OBEXGEN_SetFile(s, "gammu.vcs", req, size, FALSE);
2946  }
2947 }
2948 
2949 GSM_Error OBEXGEN_SetTodoLUID(GSM_StateMachine *s, GSM_ToDoEntry *Entry, const char *Data, int Size)
2950 {
2951  GSM_Error error;
2952  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2953  char *path=NULL;
2954 
2955  error = OBEXGEN_InitCalLUID(s);
2956  if (error != ERR_NONE) return error;
2957 
2958  /* Check bounds */
2959  if (Entry->Location > Priv->TodoLUIDCount ||
2960  Priv->TodoLUID[Entry->Location] == NULL) {
2964  return OBEXGEN_AddTodo(s, Entry);
2965  }
2966 
2967  /* Calculate path */
2968  path = (char *)malloc(strlen(Priv->TodoLUID[Entry->Location]) + 22); /* Length of string below */
2969  if (path == NULL) {
2970  return ERR_MOREMEMORY;
2971  }
2972  sprintf(path, "telecom/cal/luid/%s.vcs", Priv->TodoLUID[Entry->Location]);
2973  smprintf(s, "Seting vTodo %s\n", path);
2974 
2975  /* Forget entry if we're deleting */
2976  if (Size == 0) {
2977  free(Priv->TodoLUID[Entry->Location]);
2978  Priv->TodoLUID[Entry->Location] = NULL;
2979  Priv->TodoCount--;
2980  }
2981 
2982  /* Store vTodo */
2983  error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->CalCap.HD : FALSE);;
2984  free(path);
2985  return error;
2986 }
2987 
2988 GSM_Error OBEXGEN_SetTodoIndex(GSM_StateMachine *s, GSM_ToDoEntry *Entry, const char *Data, int Size)
2989 {
2990  char *path=NULL;
2991  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
2992  GSM_Error error;
2993 
2994  /* Forget entry if we're deleting */
2995  if (Size == 0) {
2996  Priv->TodoCount--;
2997  }
2998 
2999  /* Todoculate path */
3000  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3001  if (path == NULL) {
3002  return ERR_MOREMEMORY;
3003  }
3004  sprintf(path, "telecom/cal/%d.vcs", Entry->Location);
3005  smprintf(s, "Seting vTodo %s\n", path);
3006 
3007  /* Store vTodo */
3008  error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
3009  free(path);
3010  return error;
3011 }
3012 
3014 {
3015  unsigned char req[5000];
3016  size_t size=0;
3017  GSM_Error error;
3018  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3019 
3020  /* Encode vTodo */
3021  error = GSM_EncodeVTODO(req, sizeof(req), &size, Entry, TRUE, SonyEricsson_VToDo);
3022  if (error != ERR_NONE) return error;
3023 
3024  /* Handle m-obex case */
3025  if (Priv->Service == OBEX_m_OBEX) {
3026  return MOBEX_UpdateEntry(s, "m-obex/calendar/write",
3027  Entry->Location, 7, req);
3028  }
3029 
3030  /* We need IrMC service for this */
3031  error = OBEXGEN_Connect(s, OBEX_IRMC);
3032  if (error != ERR_NONE) return error;
3033 
3034  /* We need IEL to correctly talk to phone */
3035  if (Priv->CalCap.IEL == -1) {
3036  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
3037  if (error != ERR_NONE) return error;
3038  }
3039 
3040  /* Use correct function according to supported IEL */
3041  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
3042  return OBEXGEN_SetTodoLUID(s, Entry, req, size);
3043  } else if (Priv->CalCap.IEL == 0x4) {
3044  return OBEXGEN_SetTodoIndex(s, Entry, req, size);
3045  } else if (Priv->CalCap.IEL == 0x2) {
3046  /* Work on full todo */
3047  return ERR_NOTIMPLEMENTED;
3048  } else {
3049  return ERR_NOTSUPPORTED;
3050  }
3051 }
3052 
3054 {
3055  GSM_Error error;
3056  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3057 
3058  /* Handle m-obex case */
3059  if (Priv->Service == OBEX_m_OBEX) {
3060  return MOBEX_UpdateEntry(s, "m-obex/calendar/delete", Entry->Location, 7 /* 0xff */, NULL);
3061  }
3062 
3063  /* We need IrMC service for this */
3064  error = OBEXGEN_Connect(s, OBEX_IRMC);
3065  if (error != ERR_NONE) return error;
3066 
3067  /* We need IEL to correctly talk to phone */
3068  if (Priv->CalCap.IEL == -1) {
3069  error = OBEXGEN_GetCalInformation(s, NULL, NULL);
3070  if (error != ERR_NONE) return error;
3071  }
3072 
3073  /* Use correct function according to supported IEL */
3074  if (Priv->CalCap.IEL == 0x8 || Priv->CalCap.IEL == 0x10) {
3075  return OBEXGEN_SetTodoLUID(s, Entry, "", 0);
3076  } else if (Priv->CalCap.IEL == 0x4) {
3077  return OBEXGEN_SetTodoIndex(s, Entry, "", 0);
3078  } else if (Priv->CalCap.IEL == 0x2) {
3079  /* Work on full todo */
3080  return ERR_NOTIMPLEMENTED;
3081  } else {
3082  return ERR_NOTSUPPORTED;
3083  }
3084 }
3085 
3087 {
3088  GSM_Error error;
3089  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3090  GSM_ToDoEntry entry;
3091 
3092  /* We need IrMC service for this */
3093  error = OBEXGEN_Connect(s, OBEX_IRMC);
3094  if (error != ERR_NONE) return error;
3095 
3096  /* We need count of entries */
3097  error = OBEXGEN_InitCalLUID(s);
3098  if (error != ERR_NONE) return error;
3099 
3100  /* Delete all entries */
3101  entry.Location = 1;
3102  while (Priv->TodoCount > 0) {
3103  error = OBEXGEN_DeleteTodo(s, &entry);
3104  if (error != ERR_NONE && error != ERR_EMPTY) return error;
3105  entry.Location++;
3106  }
3107  return error;
3108 }
3109 
3121 GSM_Error OBEXGEN_GetNoteInformation(GSM_StateMachine *s, int *free_records, int *used)
3122 {
3123  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3124 
3125  return OBEXGEN_GetInformation(s, "telecom/nt/info.log", free_records, used, &(Priv->NoteCap));
3126 
3127 }
3128 
3133 {
3134  return OBEXGEN_GetNoteInformation(s, &(Status->Free), &(Status->Used));
3135 
3136 }
3137 
3141 GSM_Error OBEXGEN_InitNoteLUID(GSM_StateMachine *s)
3142 {
3143  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3144 
3145  /* We might do validation here using telecom/nt/luid/cc.log fir IEL 4, but not on each request */
3146  if (Priv->NoteData != NULL) return ERR_NONE;
3147 
3148  return OBEXGEN_InitLUID(s, "telecom/nt.vcf", FALSE, "BEGIN:VNOTE",
3149  &(Priv->NoteData), &(Priv->NoteOffsets), &(Priv->NoteCount),
3150  &(Priv->NoteLUID), &(Priv->NoteLUIDCount),
3151  &(Priv->NoteIndex), &(Priv->NoteIndexCount));
3152 }
3153 
3157 GSM_Error OBEXGEN_GetNoteIndex(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3158 {
3159  GSM_Error error;
3160  char *data=NULL;
3161  char *path=NULL;
3162  size_t pos = 0;
3163 
3164  error = OBEXGEN_InitNoteLUID(s);
3165  if (error != ERR_NONE) return error;
3166 
3167  /* Calculate path */
3168  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3169  if (path == NULL) {
3170  return ERR_MOREMEMORY;
3171  }
3172  sprintf(path, "telecom/nt/%d.vnt", Entry->Location);
3173  smprintf(s, "Getting vNote %s\n", path);
3174 
3175  /* Grab vCard */
3176  error = OBEXGEN_GetTextFile(s, path, &data);
3177  free(path);
3178  path=NULL;
3179  if (error == ERR_FILENOTEXIST) return ERR_EMPTY;
3180  if (error != ERR_NONE) return error;
3181 
3182  /* Decode it */
3183  error = GSM_DecodeVNOTE(data, &pos, Entry);
3184  free(data);
3185  data=NULL;
3186  if (error != ERR_NONE) return error;
3187 
3188  return ERR_NONE;
3189 }
3190 
3194 GSM_Error OBEXGEN_GetNoteLUID(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3195 {
3196  GSM_Error error;
3197  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3198  char *data=NULL;
3199  char *path=NULL;
3200  size_t pos = 0;
3201 
3202  error = OBEXGEN_InitNoteLUID(s);
3203  if (error != ERR_NONE) return error;
3204 
3205  /* Check bounds */
3206  if (Entry->Location > Priv->NoteLUIDCount) return ERR_EMPTY; /* Maybe invalid location? */
3207  if (Priv->NoteLUID[Entry->Location] == NULL) return ERR_EMPTY;
3208 
3209  /* Calculate path */
3210  path = (char *)malloc(strlen(Priv->NoteLUID[Entry->Location]) + 22); /* Length of string below */
3211  if (path == NULL) {
3212  return ERR_MOREMEMORY;
3213  }
3214  sprintf(path, "telecom/nt/luid/%s.vnt", Priv->NoteLUID[Entry->Location]);
3215  smprintf(s, "Getting vNote %s\n", path);
3216 
3217  /* Grab vCard */
3218  error = OBEXGEN_GetTextFile(s, path, &data);
3219  free(path);
3220  path=NULL;
3221  if (error != ERR_NONE) return error;
3222 
3223  /* Decode it */
3224  error = GSM_DecodeVNOTE(data, &pos, Entry);
3225  free(data);
3226  data=NULL;
3227  if (error != ERR_NONE) return error;
3228 
3229  return ERR_NONE;
3230 }
3231 
3235 GSM_Error OBEXGEN_GetNoteFull(GSM_StateMachine *s, GSM_NoteEntry *Entry)
3236 {
3237  GSM_Error error;
3238  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3239  size_t pos = 0;
3240 
3241  /* Read note data */
3242  error = OBEXGEN_InitNoteLUID(s);
3243  if (error != ERR_NONE) return error;
3244 
3245  /* Check bounds */
3246  if (Entry->Location > Priv->NoteCount) return ERR_EMPTY; /* Maybe invalid location? */
3247 
3248  /* Decode vNote */
3249  error = GSM_DecodeVNOTE(Priv->NoteData + Priv->NoteOffsets[Entry->Location], &pos, Entry);
3250  if (error != ERR_NONE) return error;
3251 
3252  return ERR_NONE;
3253 }
3254 
3256 {
3257  GSM_Error error;
3258  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3259 
3260  /* We need IrMC service for this */
3261  error = OBEXGEN_Connect(s, OBEX_IRMC);
3262  if (error != ERR_NONE) return error;
3263 
3264  /* We need IEL to correctly talk to phone */
3265  if (Priv->NoteCap.IEL == -1) {
3266  error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3267  if (error != ERR_NONE) return error;
3268  }
3269 
3270  /* Use correct function according to supported IEL */
3271  if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3272  return OBEXGEN_GetNoteLUID(s, Entry);
3273  } else if (Priv->NoteCap.IEL == 0x4) {
3274  return OBEXGEN_GetNoteIndex(s, Entry);
3275  } else if (Priv->NoteCap.IEL == 0x2) {
3276  return OBEXGEN_GetNoteFull(s, Entry);
3277  } else {
3278  smprintf(s, "Can not read note from IEL 1 phone\n");
3279  return ERR_NOTSUPPORTED;
3280  }
3281 }
3282 
3284 {
3285  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3286  GSM_Error error = ERR_EMPTY;;
3287 
3288  /* Get location */
3289  if (start) {
3290  Entry->Location = 1;
3291  Priv->ReadPhonebook = 0;
3292  } else {
3293  Entry->Location++;
3294  }
3295 
3296  /* Do real getting */
3297  while (error == ERR_EMPTY) {
3298 
3299  /* Have we read them all? */
3300  /* Needs to be inside loop as we get count after
3301  * first invocation of get function */
3302  if (Priv->ReadPhonebook == Priv->NoteCount) {
3303  return ERR_EMPTY;
3304  }
3305 
3306  error = OBEXGEN_GetNote(s, Entry);
3307  if (error == ERR_NONE) {
3308  Priv->ReadPhonebook++;
3309  } else if (error == ERR_EMPTY) {
3310  Entry->Location++;
3311  }
3312  }
3313  return error;
3314 }
3315 
3317 {
3318  unsigned char req[5000];
3319  char path[100];
3320  size_t size=0;
3321  GSM_Error error;
3322  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3323 
3324  /* We need IrMC service for this */
3325  error = OBEXGEN_Connect(s, OBEX_IRMC);
3326  if (error != ERR_NONE) return error;
3327 
3328  /* We need IEL to correctly talk to phone */
3329  if (Priv->NoteCap.IEL == -1) {
3330  error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3331  if (error != ERR_NONE) return error;
3332  }
3333 
3334  /* Encode vNote */
3335  error = GSM_EncodeVNTFile(req, sizeof(req), &size, Entry);
3336  if (error != ERR_NONE) return error;
3337 
3338  /* Use correct function according to supported IEL */
3339  if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3340  /* We need to grab LUID list now in order to keep position later */
3341  error = OBEXGEN_InitNoteLUID(s);
3342  if (error != ERR_NONE) return error;
3343 
3344  smprintf(s,"Adding note entry %ld:\n%s\n", (long)size, req);
3345  Priv->UpdateNoteLUID = TRUE;
3346  error = OBEXGEN_SetFile(s, "telecom/nt/luid/.vnt", req, size, FALSE);
3347  Entry->Location = Priv->NoteLUIDCount;
3348  if (error == ERR_NONE) Priv->NoteCount++;
3349  return error;
3350  } else if (Priv->NoteCap.IEL == 0x4) {
3351  /* We need to grab LUID/Index list now in order to keep position later */
3352  error = OBEXGEN_InitNoteLUID(s);
3353  if (error != ERR_NONE) return error;
3354 
3355  Entry->Location = OBEXGEN_GetFirstFreeLocation(&Priv->NoteIndex, &Priv->NoteIndexCount);
3356  smprintf(s,"Adding note entry %ld at location %d:\n%s\n", (long)size, Entry->Location, req);
3357  sprintf(path, "telecom/nt/%d.vcf", Entry->Location);
3358  error = OBEXGEN_SetFile(s, path, req, size, FALSE);
3359  if (error == ERR_NONE) Priv->NoteCount++;
3360  return error;
3361  } else {
3362  /* I don't know add command for other levels, just plain send vCard */
3363  Entry->Location = 0;
3364  smprintf(s,"Sending note entry\n");
3365  return OBEXGEN_SetFile(s, "gammu.vnt", req, size, FALSE);
3366  }
3367 }
3368 
3369 GSM_Error OBEXGEN_SetNoteLUID(GSM_StateMachine *s, GSM_NoteEntry *Entry, const char *Data, int Size)
3370 {
3371  GSM_Error error;
3372  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3373  char *path=NULL;
3374 
3375  error = OBEXGEN_InitNoteLUID(s);
3376  if (error != ERR_NONE) return error;
3377 
3378  /* Check bounds */
3379  if (Entry->Location > Priv->NoteLUIDCount ||
3380  Priv->NoteLUID[Entry->Location] == NULL) {
3384  return OBEXGEN_AddNote(s, Entry);
3385  }
3386 
3387  /* Calculate path */
3388  path = (char *)malloc(strlen(Priv->NoteLUID[Entry->Location]) + 22); /* Length of string below */
3389  if (path == NULL) {
3390  return ERR_MOREMEMORY;
3391  }
3392  sprintf(path, "telecom/nt/luid/%s.vnt", Priv->NoteLUID[Entry->Location]);
3393  smprintf(s, "Seting vNote %s\n", path);
3394 
3395  /* Forget entry if we're deleting */
3396  if (Size == 0) {
3397  free(Priv->NoteLUID[Entry->Location]);
3398  Priv->NoteLUID[Entry->Location] = NULL;
3399  Priv->NoteCount--;
3400  }
3401 
3402  /* Store vCard */
3403  error = OBEXGEN_SetFile(s, path, Data, Size, Size == 0 ? Priv->NoteCap.HD : FALSE);;
3404  free(path);
3405  return error;
3406 }
3407 
3408 GSM_Error OBEXGEN_SetNoteIndex(GSM_StateMachine *s, GSM_NoteEntry *Entry, const char *Data, int Size)
3409 {
3410  char *path=NULL;
3411  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3412  GSM_Error error;
3413 
3414  /* Forget entry if we're deleting */
3415  if (Size == 0) {
3416  Priv->NoteCount--;
3417  }
3418 
3419  /* Calculate path */
3420  path = (char *)malloc(20 + 22); /* Length of string below + length of number */
3421  if (path == NULL) {
3422  return ERR_MOREMEMORY;
3423  }
3424  sprintf(path, "telecom/nt/%d.vnt", Entry->Location);
3425  smprintf(s, "Seting vNote %s\n", path);
3426 
3427  /* Store vCard */
3428  error = OBEXGEN_SetFile(s, path, Data, Size, FALSE);;
3429  free(path);
3430  return error;
3431 }
3432 
3434 {
3435  unsigned char req[5000];
3436  size_t size=0;
3437  GSM_Error error;
3438  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3439 
3440  /* We need IrMC service for this */
3441  error = OBEXGEN_Connect(s, OBEX_IRMC);
3442  if (error != ERR_NONE) return error;
3443 
3444  /* We need IEL to correctly talk to phone */
3445  if (Priv->NoteCap.IEL == -1) {
3446  error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3447  if (error != ERR_NONE) return error;
3448  }
3449 
3450  /* Encode vNote */
3451  error = GSM_EncodeVNTFile(req, sizeof(req), &size, Entry);
3452  if (error != ERR_NONE) return error;
3453 
3454  /* Use correct function according to supported IEL */
3455  if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3456  return OBEXGEN_SetNoteLUID(s, Entry, req, size);
3457  } else if (Priv->NoteCap.IEL == 0x4) {
3458  return OBEXGEN_SetNoteIndex(s, Entry, req, size);
3459  } else if (Priv->NoteCap.IEL == 0x2) {
3460  /* Work on full note */
3461  return ERR_NOTIMPLEMENTED;
3462  } else {
3463  return ERR_NOTSUPPORTED;
3464  }
3465 }
3466 
3468 {
3469  GSM_Error error;
3470  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3471 
3472  /* We need IrMC service for this */
3473  error = OBEXGEN_Connect(s, OBEX_IRMC);
3474  if (error != ERR_NONE) return error;
3475 
3476  /* We need IEL to correctly talk to phone */
3477  if (Priv->NoteCap.IEL == -1) {
3478  error = OBEXGEN_GetNoteInformation(s, NULL, NULL);
3479  if (error != ERR_NONE) return error;
3480  }
3481 
3482  /* Use correct function according to supported IEL */
3483  if (Priv->NoteCap.IEL == 0x8 || Priv->NoteCap.IEL == 0x10) {
3484  return OBEXGEN_SetNoteLUID(s, Entry, "", 0);
3485  } else if (Priv->NoteCap.IEL == 0x4) {
3486  return OBEXGEN_SetNoteIndex(s, Entry, "", 0);
3487  } else if (Priv->NoteCap.IEL == 0x2) {
3488  /* Work on full note */
3489  return ERR_NOTIMPLEMENTED;
3490  } else {
3491  return ERR_NOTSUPPORTED;
3492  }
3493 }
3494 
3496 {
3497  GSM_Error error;
3498  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3499  GSM_NoteEntry entry;
3500 
3501  /* We need IrMC service for this */
3502  error = OBEXGEN_Connect(s, OBEX_IRMC);
3503  if (error != ERR_NONE) return error;
3504 
3505  /* We need count of entries */
3506  error = OBEXGEN_InitNoteLUID(s);
3507  if (error != ERR_NONE) return error;
3508 
3509  /* Delete all entries */
3510  entry.Location = 1;
3511  while (Priv->NoteCount > 0) {
3512  error = OBEXGEN_DeleteNote(s, &entry);
3513  if (error != ERR_NONE && error != ERR_EMPTY) return error;
3514  entry.Location++;
3515  }
3516  return error;
3517 }
3518 
3527 GSM_Error OBEXGEN_GetDevinfoField(GSM_StateMachine *s, const char *Name, char *Dest)
3528 {
3529  char *pos;
3530  char *dest;
3531  char match[200];
3532  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3533 
3534  if (Priv->OBEXDevinfo == NULL || strlen(Priv->OBEXDevinfo) == 0) return ERR_NOTSUPPORTED;
3535 
3536  /* Match begin tag */
3537  match[0] = 0;
3538  strcat(match, Name);
3539  strcat(match, ":");
3540 
3541  pos = strstr(Priv->OBEXDevinfo, match);
3542  if (pos == NULL) return ERR_INVALIDDATA;
3543  pos += strlen(match);
3544 
3545  /* Copy to end of line */
3546  dest = Dest;
3547  while (*pos != 0 && *pos != '\r' && *pos != '\n') {
3548  *(dest++) = *(pos++);
3549  }
3550  *dest = 0;
3551 
3552  return ERR_NONE;
3553 }
3554 
3555 GSM_Error OBEXGEN_GetCapabilityField(GSM_StateMachine *s, const char *Name, char *Dest)
3556 {
3557  char *pos_start;
3558  char *pos_end;
3559  char match[200];
3560  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3561 
3562  if (Priv->OBEXCapability == NULL || strlen(Priv->OBEXCapability) == 0) return ERR_NOTSUPPORTED;
3563 
3564  /* Match XML begin tag */
3565  match[0] = 0;
3566  strcat(match, "<");
3567  strcat(match, Name);
3568  strcat(match, ">");
3569 
3570  pos_start = strstr(Priv->OBEXCapability, match);
3571  if (pos_start == NULL) return ERR_INVALIDDATA;
3572  pos_start += strlen(match);
3573 
3574  /* Match XML end tag */
3575  match[0] = 0;
3576  strcat(match, "</");
3577  strcat(match, Name);
3578  strcat(match, ">");
3579 
3580  pos_end = strstr(pos_start, match);
3581  if (pos_end == NULL) return ERR_INVALIDDATA;
3582 
3583  /* Copy result string */
3584  strncpy(Dest, pos_start, pos_end - pos_start);
3585  Dest[pos_end - pos_start] = 0;
3586 
3587  return ERR_NONE;
3588 }
3589 
3590 GSM_Error OBEXGEN_GetCapabilityFieldAttrib(GSM_StateMachine *s, const char *Name, const char *Attrib, char *Dest)
3591 {
3592  char *pos_start;
3593  char *pos_end;
3594  char match[200];
3595  GSM_Phone_OBEXGENData *Priv = &s->Phone.Data.Priv.OBEXGEN;
3596 
3597  if (Priv->OBEXCapability == NULL || strlen(Priv->OBEXCapability) == 0) return ERR_NOTSUPPORTED;
3598 
3599  /* Match XML begin tag */
3600  match[0] = 0;
3601  strcat(match, "<");
3602  strcat(match, Name);
3603 
3604  pos_start = strstr(Priv->OBEXCapability, match);
3605  if (pos_start == NULL) return ERR_INVALIDDATA;
3606  pos_start += strlen(match);
3607 
3608  /* Match attribute begin */
3609  match[0] = 0;
3610  strcat(match, Attrib);
3611  strcat(match, "=\"");
3612 
3613  pos_start = strstr(pos_start, match);
3614  if (pos_start == NULL) return ERR_INVALIDDATA;
3615  pos_start += strlen(match);
3616 
3617  /* Match end quote */
3618  pos_end = strchr(pos_start, '"');
3619  if (pos_end == NULL) return ERR_INVALIDDATA;
3620 
3621  /* Copy result string */
3622  strncpy(Dest, pos_start, pos_end - pos_start);
3623  Dest[pos_end - pos_start] = 0;
3624 
3625  return ERR_NONE;
3626 }
3627 
3628 GSM_Error OBEXGEN_GetManufacturer(GSM_StateMachine *s)
3629 {
3630  GSM_Error error;
3631 
3632  if (s->Phone.Data.Manufacturer[0] != 0) return ERR_NONE;
3633 
3634  error = OBEXGEN_GetCapabilityField(s, "Manufacturer", s->Phone.Data.Manufacturer);
3635  if (error == ERR_NONE) return ERR_NONE;
3636 
3637  return OBEXGEN_GetDevinfoField(s, "MANU", s->Phone.Data.Manufacturer);
3638 }
3639 
3640 GSM_Error OBEXGEN_GetModel(GSM_StateMachine *s)
3641 {
3642  GSM_Error error;
3643  GSM_Phone_Data *Data = &s->Phone.Data;
3644 
3645  if (Data->Model[0] != 0) return ERR_NONE;
3646 
3647  error = OBEXGEN_GetCapabilityField(s, "Model", s->Phone.Data.Model);
3648 
3649  /* Retry with MOD if we failed */
3650  if (error != ERR_NONE) {
3651  error = OBEXGEN_GetDevinfoField(s, "MOD", s->Phone.Data.Model);
3652  }
3653 
3654  if (error == ERR_NONE) {
3655  Data->ModelInfo = GetModelData(s, NULL, Data->Model, NULL);
3656  if (Data->ModelInfo->number[0] == 0)
3657  Data->ModelInfo = GetModelData(s, NULL, NULL, Data->Model);
3658  if (Data->ModelInfo->number[0] == 0)
3659  Data->ModelInfo = GetModelData(s, Data->Model, NULL, NULL);
3660  return ERR_NONE;
3661  }
3662  return error;
3663 }
3664 
3665 GSM_Error OBEXGEN_GetFirmware(GSM_StateMachine *s)
3666 {
3667  GSM_Error error;
3668 
3669  if (s->Phone.Data.Version[0] != 0) return ERR_NONE;
3670 
3671  error = OBEXGEN_GetCapabilityFieldAttrib(s, "SW", "Version", s->Phone.Data.Version);
3672  if (error == ERR_NONE) {
3673  /* We don't care about error here, it is optional */
3674  OBEXGEN_GetCapabilityFieldAttrib(s, "SW", "Date", s->Phone.Data.VerDate);
3675  }
3676  if (error == ERR_NONE) return ERR_NONE;
3677  OBEXGEN_GetDevinfoField(s, "SW-DATE", s->Phone.Data.VerDate);
3678 
3679  return OBEXGEN_GetDevinfoField(s, "SW-VERSION", s->Phone.Data.Version);
3680 }
3681 
3682 GSM_Error OBEXGEN_GetIMEI(GSM_StateMachine *s)
3683 {
3684  GSM_Error error;
3685 
3686  if (s->Phone.Data.IMEI[0] != 0) return ERR_NONE;
3687 
3688  error = OBEXGEN_GetCapabilityField(s, "SN", s->Phone.Data.IMEI);
3689  if (error == ERR_NONE) return ERR_NONE;
3690 
3691  return OBEXGEN_GetDevinfoField(s, "SN", s->Phone.Data.IMEI);
3692 }
3693 
3696  /* CONTINUE block */
3697  {OBEXGEN_ReplyAddFilePart, "\x90",0x00,0x00,ID_AddFile },
3698  {OBEXGEN_ReplyGetFilePart, "\x90",0x00,0x00,ID_GetFile },
3699 
3700  /* OK block */
3701  {OBEXGEN_ReplyChangePath, "\xA0",0x00,0x00,ID_SetPath },
3702  {OBEXGEN_ReplyConnect, "\xA0",0x00,0x00,ID_Initialise },
3703  {OBEXGEN_ReplyAddFilePart, "\xA0",0x00,0x00,ID_AddFile },
3704  {OBEXGEN_ReplyGetFilePart, "\xA0",0x00,0x00,ID_GetFile },
3705 
3706  /* FOLDER CREATED block */
3707  {OBEXGEN_ReplyChangePath, "\xA1",0x00,0x00,ID_SetPath },
3708 
3709  /* NOT UNDERSTAND block */
3710  {OBEXGEN_ReplyConnect, "\xC0",0x00,0x00,ID_Initialise },
3711  {OBEXGEN_ReplyGetFilePart, "\xC0",0x00,0x00,ID_GetFile },
3712  {OBEXGEN_ReplyAddFilePart, "\xC0",0x00,0x00,ID_AddFile },
3713 
3714  /* Not allowed block */
3715  {OBEXGEN_ReplyConnect, "\xC1",0x00,0x00,ID_Initialise },
3716  {OBEXGEN_ReplyGetFilePart, "\xC1",0x00,0x00,ID_GetFile },
3717  {OBEXGEN_ReplyAddFilePart, "\xC1",0x00,0x00,ID_AddFile },
3718 
3719  /* FORBIDDEN block */
3720  {OBEXGEN_ReplyConnect, "\xC3",0x00,0x00,ID_Initialise },
3721  {OBEXGEN_ReplyChangePath, "\xC3",0x00,0x00,ID_SetPath },
3722  {OBEXGEN_ReplyGetFilePart, "\xC3",0x00,0x00,ID_GetFile },
3723  {OBEXGEN_ReplyAddFilePart, "\xC3",0x00,0x00,ID_AddFile },
3724 
3725  /* Not Acceptable block */
3726  {OBEXGEN_ReplyConnect, "\xC6",0x00,0x00,ID_Initialise },
3727  {OBEXGEN_ReplyChangePath, "\xC6",0x00,0x00,ID_SetPath },
3728  {OBEXGEN_ReplyGetFilePart, "\xC6",0x00,0x00,ID_GetFile },
3729  {OBEXGEN_ReplyAddFilePart, "\xC6",0x00,0x00,ID_AddFile },
3730 
3731  /* CONFLICT block */
3732  {OBEXGEN_ReplyConnect, "\xC9",0x00,0x00,ID_Initialise },
3733  {OBEXGEN_ReplyChangePath, "\xC9",0x00,0x00,ID_SetPath },
3734  {OBEXGEN_ReplyGetFilePart, "\xC9",0x00,0x00,ID_GetFile },
3735  {OBEXGEN_ReplyAddFilePart, "\xC9",0x00,0x00,ID_AddFile },
3736 
3737  /* NOT FOUND block */
3738  {OBEXGEN_ReplyConnect, "\xC4",0x00,0x00,ID_Initialise },
3739  {OBEXGEN_ReplyChangePath, "\xC4",0x00,0x00,ID_SetPath },
3740  {OBEXGEN_ReplyGetFilePart, "\xC4",0x00,0x00,ID_GetFile },
3741  {OBEXGEN_ReplyChangePath, "\xC4",0x00,0x00,ID_SetPath },
3742 
3743  /* Failed block */
3744  {OBEXGEN_ReplyConnect, "\xCC",0x00,0x00,ID_Initialise },
3745  {OBEXGEN_ReplyChangePath, "\xCC",0x00,0x00,ID_SetPath },
3746  {OBEXGEN_ReplyGetFilePart, "\xCC",0x00,0x00,ID_GetFile },
3747  {OBEXGEN_ReplyAddFilePart, "\xCC",0x00,0x00,ID_AddFile },
3748 
3749  /* Non standard Sharp GX reply */
3750  {OBEXGEN_ReplyGetFilePart, "\x80",0x00,0x00,ID_GetFile },
3751  {OBEXGEN_ReplyChangePath, "\x80",0x00,0x00,ID_SetPath },
3752 
3753  /* Internal server error */
3754  {OBEXGEN_ReplyConnect, "\xD0",0x00,0x00,ID_Initialise },
3755  {OBEXGEN_ReplyChangePath, "\xD0",0x00,0x00,ID_SetPath },
3756  {OBEXGEN_ReplyGetFilePart, "\xD0",0x00,0x00,ID_GetFile },
3757  {OBEXGEN_ReplyAddFilePart, "\xD0",0x00,0x00,ID_AddFile },
3758 
3759  /* Not implemented */
3760  {OBEXGEN_ReplyConnect, "\xD1",0x00,0x00,ID_Initialise },
3761  {OBEXGEN_ReplyChangePath, "\xD1",0x00,0x00,ID_SetPath },
3762  {OBEXGEN_ReplyGetFilePart, "\xD1",0x00,0x00,ID_GetFile },
3763  {OBEXGEN_ReplyAddFilePart, "\xD1",0x00,0x00,ID_AddFile },
3764 
3765  /* Service not available */
3766  {OBEXGEN_ReplyConnect, "\xD3",0x00,0x00,ID_Initialise },
3767  {OBEXGEN_ReplyChangePath, "\xD3",0x00,0x00,ID_SetPath },
3768  {OBEXGEN_ReplyGetFilePart, "\xD3",0x00,0x00,ID_GetFile },
3769  {OBEXGEN_ReplyAddFilePart, "\xD3",0x00,0x00,ID_AddFile },
3770 
3771  /* Database full */
3772  {OBEXGEN_ReplyConnect, "\xE0",0x00,0x00,ID_Initialise },
3773  {OBEXGEN_ReplyChangePath, "\xE0",0x00,0x00,ID_SetPath },
3774  {OBEXGEN_ReplyGetFilePart, "\xE0",0x00,0x00,ID_GetFile },
3775  {OBEXGEN_ReplyAddFilePart, "\xE0",0x00,0x00,ID_AddFile },
3776 
3777  /* Database locked */
3778  {OBEXGEN_ReplyConnect, "\xE1",0x00,0x00,ID_Initialise },
3779  {OBEXGEN_ReplyChangePath, "\xE1",0x00,0x00,ID_SetPath },
3780  {OBEXGEN_ReplyGetFilePart, "\xE1",0x00,0x00,ID_GetFile },
3781  {OBEXGEN_ReplyAddFilePart, "\xE1",0x00,0x00,ID_AddFile },
3782 
3783  {NULL, "\x00",0x00,0x00,ID_None }
3784 };
3785 
3786 GSM_Phone_Functions OBEXGENPhone = {
3787  "obex|seobex|obexfs|obexirmc|obexnone|mobex",
3789  NOTSUPPORTED, /* Install */
3790  OBEXGEN_Initialise,
3791  OBEXGEN_Terminate,
3793  NOTIMPLEMENTED, /* ShowStartInfo */
3794  OBEXGEN_GetManufacturer,
3795  OBEXGEN_GetModel,
3796  OBEXGEN_GetFirmware,
3797  OBEXGEN_GetIMEI,
3798  NOTIMPLEMENTED, /* GetOriginalIMEI */
3799  NOTIMPLEMENTED, /* GetManufactureMonth */
3800  NOTIMPLEMENTED, /* GetProductCode */
3801  NOTIMPLEMENTED, /* GetHardware */
3802  NOTIMPLEMENTED, /* GetPPM */
3803  NOTIMPLEMENTED, /* GetSIMIMSI */
3804  NOTIMPLEMENTED, /* GetDateTime */
3805  NOTIMPLEMENTED, /* SetDateTime */
3806  NOTIMPLEMENTED, /* GetAlarm */
3807  NOTIMPLEMENTED, /* SetAlarm */
3808  NOTSUPPORTED, /* GetLocale */
3809  NOTSUPPORTED, /* SetLocale */
3810  NOTIMPLEMENTED, /* PressKey */
3811  NOTIMPLEMENTED, /* Reset */
3812  NOTIMPLEMENTED, /* ResetPhoneSettings */
3813  NOTIMPLEMENTED, /* EnterSecurityCode */
3814  NOTIMPLEMENTED, /* GetSecurityStatus */
3815  NOTIMPLEMENTED, /* GetDisplayStatus */
3816  NOTIMPLEMENTED, /* SetAutoNetworkLogin */
3817  NOTIMPLEMENTED, /* GetBatteryCharge */
3818  NOTIMPLEMENTED, /* GetSignalQuality */
3819  NOTIMPLEMENTED, /* GetNetworkInfo */
3820  NOTIMPLEMENTED, /* GetCategory */
3821  NOTSUPPORTED, /* AddCategory */
3822  NOTIMPLEMENTED, /* GetCategoryStatus */
3830  NOTIMPLEMENTED, /* GetSpeedDial */
3831  NOTIMPLEMENTED, /* SetSpeedDial */
3832  NOTIMPLEMENTED, /* GetSMSC */
3833  NOTIMPLEMENTED, /* SetSMSC */
3834  NOTIMPLEMENTED, /* GetSMSStatus */
3835  NOTIMPLEMENTED, /* GetSMS */
3836  NOTIMPLEMENTED, /* GetNextSMS */
3837  NOTIMPLEMENTED, /* SetSMS */
3838  NOTIMPLEMENTED, /* AddSMS */
3839  NOTIMPLEMENTED, /* DeleteSMS */
3840  NOTIMPLEMENTED, /* SendSMSMessage */
3841  NOTSUPPORTED, /* SendSavedSMS */
3842  NOTSUPPORTED, /* SetFastSMSSending */
3843  NOTIMPLEMENTED, /* SetIncomingSMS */
3844  NOTIMPLEMENTED, /* SetIncomingCB */
3845  NOTIMPLEMENTED, /* GetSMSFolders */
3846  NOTIMPLEMENTED, /* AddSMSFolder */
3847  NOTIMPLEMENTED, /* DeleteSMSFolder */
3848  NOTIMPLEMENTED, /* DialVoice */
3849  NOTIMPLEMENTED, /* DialService */
3850  NOTIMPLEMENTED, /* AnswerCall */
3851  NOTIMPLEMENTED, /* CancelCall */
3852  NOTIMPLEMENTED, /* HoldCall */
3853  NOTIMPLEMENTED, /* UnholdCall */
3854  NOTIMPLEMENTED, /* ConferenceCall */
3855  NOTIMPLEMENTED, /* SplitCall */
3856  NOTIMPLEMENTED, /* TransferCall */
3857  NOTIMPLEMENTED, /* SwitchCall */
3858  NOTIMPLEMENTED, /* GetCallDivert */
3859  NOTIMPLEMENTED, /* SetCallDivert */
3860  NOTIMPLEMENTED, /* CancelAllDiverts */
3861  NOTIMPLEMENTED, /* SetIncomingCall */
3862  NOTIMPLEMENTED, /* SetIncomingUSSD */
3863  NOTIMPLEMENTED, /* SendDTMF */
3864  NOTIMPLEMENTED, /* GetRingtone */
3865  NOTIMPLEMENTED, /* SetRingtone */
3866  NOTIMPLEMENTED, /* GetRingtonesInfo */
3867  NOTIMPLEMENTED, /* DeleteUserRingtones */
3868  NOTIMPLEMENTED, /* PlayTone */
3869  NOTIMPLEMENTED, /* GetWAPBookmark */
3870  NOTIMPLEMENTED, /* SetWAPBookmark */
3871  NOTIMPLEMENTED, /* DeleteWAPBookmark */
3872  NOTIMPLEMENTED, /* GetWAPSettings */
3873  NOTIMPLEMENTED, /* SetWAPSettings */
3874  NOTSUPPORTED, /* GetSyncMLSettings */
3875  NOTSUPPORTED, /* SetSyncMLSettings */
3876  NOTSUPPORTED, /* GetChatSettings */
3877  NOTSUPPORTED, /* SetChatSettings */
3878  NOTSUPPORTED, /* GetMMSSettings */
3879  NOTSUPPORTED, /* SetMMSSettings */
3880  NOTSUPPORTED, /* GetMMSFolders */
3881  NOTSUPPORTED, /* GetNextMMSFileInfo */
3882  NOTIMPLEMENTED, /* GetBitmap */
3883  NOTIMPLEMENTED, /* SetBitmap */
3898  NOTSUPPORTED, /* GetCalendarSettings */
3899  NOTSUPPORTED, /* SetCalendarSettings */
3907  NOTIMPLEMENTED, /* GetProfile */
3908  NOTIMPLEMENTED, /* SetProfile */
3909  NOTIMPLEMENTED, /* GetFMStation */
3910  NOTIMPLEMENTED, /* SetFMStation */
3911  NOTIMPLEMENTED, /* ClearFMStations */
3913  NOTIMPLEMENTED, /* GetFolderListing */
3914  NOTSUPPORTED, /* GetNextRootFolder */
3915  NOTSUPPORTED, /* SetFileAttributes */
3919  NOTIMPLEMENTED, /* GetFileSystemStatus */
3922  OBEXGEN_DeleteFile, /* DeleteFolder */
3923  NOTSUPPORTED, /* GetGPRSAccessPoint */
3924  NOTSUPPORTED, /* SetGPRSAccessPoint */
3925  NOTSUPPORTED, /* GetScreenshot */
3926  NOTSUPPORTED, /* SetPower */
3927  NOTSUPPORTED, /* PostConnect */
3928  NONEFUNCTION /* PreAPICall */
3929 };
3930 
3931 #endif
3932 
3934 
3935 /* How should editor hadle tabs in this file? Add editor commands here.
3936  * vim: noexpandtab sw=8 ts=8 sts=8:
3937  */
GSM_Error GSM_EncodeVCALENDAR(char *Buffer, const size_t buff_len, size_t *Length, GSM_CalendarEntry *note, const gboolean header, const GSM_VCalendarVersion Version)
Definition: gsmcal.c:814
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
GSM_Error MOBEX_GetTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
gboolean UpdateCalLUID
Definition: obexgen.h:175
GSM_Error MOBEX_CreateEntry(GSM_StateMachine *s, const char *path, unsigned char type, int *location, const char *data)
GSM_Error MOBEX_GetMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
GSM_Error OBEXGEN_DeleteFile(GSM_StateMachine *s, unsigned char *ID)
unsigned char Name[2 *(GSM_MAX_FILENAME_LENGTH+1)]
Definition: gammu-file.h:74
GSM_Error OBEXGEN_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry, gboolean start)
size_t m_obex_contacts_buffer_pos
Definition: obexgen.h:271
size_t m_obex_calendar_buffer_size
Definition: obexgen.h:287
unsigned char ID_FullName[2 *(GSM_MAX_FILENAME_ID_LENGTH+1)]
Definition: gammu-file.h:90
GSM_Error GSM_EncodeVCARD(GSM_Debug_Info *di, char *Buffer, const size_t buff_len, size_t *Length, GSM_MemoryEntry *pbk, const gboolean header, const GSM_VCardVersion Version)
Definition: gsmpbk.c:126
char * DecodeUnicodeString(const unsigned char *src)
Definition: coding.c:245
void CopyUnicodeString(unsigned char *Dest, const unsigned char *Source)
Definition: coding.c:1192
int Level
Definition: gammu-file.h:82
GSM_Error MOBEX_UpdateEntry(GSM_StateMachine *s, const char *path, const int location, unsigned char type, const char *data)
unsigned char * m_obex_calendar_buffer
Definition: obexgen.h:279
GSM_MemoryType MemoryType
Definition: gammu-memory.h:415
OBEX_Service Service
Definition: obexgen.h:70
size_t m_obex_calendar_buffer_pos
Definition: obexgen.h:283
GSM_Error OBEXGEN_Connect(GSM_StateMachine *s, OBEX_Service service)
unsigned char * m_obex_appdata
Definition: obexgen.h:243
#define NOTSUPPORTED
Definition: gsmcomon.h:14
void OBEXAddBlock(char *Buffer, int *Pos, unsigned char ID, const char *AddData, int AddLength)
gboolean UpdateTodoLUID
Definition: obexgen.h:143
GSM_Error OBEXGEN_GetMemoryStatus(GSM_StateMachine *s, GSM_MemoryStatus *Status)
char VerDate[GSM_MAX_VERSION_DATE_LENGTH+1]
Definition: gsmstate.h:458
GSM_Error OBEXGEN_SetMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
GSM_Error OBEXGEN_GetFilePart(GSM_StateMachine *s, GSM_File *File, int *Handle, size_t *Size)
GSM_Error GSM_DispatchMessage(GSM_StateMachine *s)
Definition: gsmstate.c:1131
#define NONEFUNCTION
Definition: gsmcomon.h:12
GSM_Error OBEXGEN_GetNoteStatus(GSM_StateMachine *s, GSM_ToDoStatus *Status)
gboolean HD
Definition: obexgen.h:60
GSM_Error
Definition: gammu-error.h:23
unsigned char * m_obex_contacts_buffer
Definition: obexgen.h:267
GSM_Debug_Info di
Definition: gsmstate.h:1412
size_t UnicodeLength(const unsigned char *str)
Definition: coding.c:186
GSM_Error OBEXGEN_SetFile(GSM_StateMachine *s, const char *FileName, const unsigned char *Buffer, size_t Length, gboolean HardDelete)
GSM_Error OBEXGEN_DeleteTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
GSM_Error OBEXGEN_GetNextMemory(GSM_StateMachine *s, GSM_MemoryEntry *entry, gboolean start)
GSM_Error OBEXGEN_DeleteCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
gboolean Folder
Definition: gammu-file.h:78
gboolean ReadOnly
Definition: gammu-file.h:111
OBEX_Service InitialService
Definition: obexgen.h:74
char IMEI[GSM_MAX_IMEI_LENGTH+1]
Definition: gsmstate.h:437
unsigned char * Buffer
Definition: gammu-file.h:94
char Version[GSM_MAX_VERSION_LENGTH+1]
Definition: gsmstate.h:454
GSM_File * File
Definition: gsmstate.h:642
char Manufacturer[GSM_MAX_MANUFACTURER_LENGTH+1]
Definition: gsmstate.h:441
GSM_PhoneModel * ModelInfo
Definition: gsmstate.h:449
GSM_Error OBEXGEN_AddNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
GSM_Error OBEXGEN_AddCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
GSM_Error OBEXGEN_GetCalendarStatus(GSM_StateMachine *s, GSM_CalendarStatus *Status)
GSM_Error OBEXGEN_AddMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
gboolean Protected
Definition: gammu-file.h:107
size_t Used
Definition: gammu-file.h:70
IRMC_Capability CalCap
Definition: obexgen.h:179
GSM_Error OBEXGEN_SetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
gboolean ReadVCALDateTime(const char *Buffer, GSM_DateTime *dt)
Definition: gsmmisc.c:254
GSM_Error OBEXGEN_GetTodoStatus(GSM_StateMachine *s, GSM_ToDoStatus *Status)
gboolean System
Definition: gammu-file.h:119
GSM_Error OBEXGEN_DeleteMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
int gboolean
Definition: gammu-types.h:23
GSM_MemoryType
Definition: gammu-memory.h:31
GSM_Error OBEXGEN_GetMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry)
GSM_PhoneModel * GetModelData(GSM_StateMachine *s, const char *model, const char *number, const char *irdamodel)
Definition: gsmphones.c:1002
void EncodeUnicode(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:301
GSM_Phone Phone
Definition: gsmstate.h:1431
#define FALSE
Definition: gammu-types.h:25
struct GSM_Phone_Data::@2 Priv
GSM_Error OBEXGEN_DeleteAllMemory(GSM_StateMachine *, GSM_MemoryType MemoryTypes)
GSM_Error MOBEX_GetStatus(GSM_StateMachine *s, const char *path, unsigned char type, int *free_records, int *used)
void OBEXGEN_FreeVars(GSM_StateMachine *s)
GSM_Error GSM_EncodeVTODO(char *Buffer, const size_t buff_len, size_t *Length, const GSM_ToDoEntry *note, const gboolean header, const GSM_VToDoVersion Version)
Definition: gsmcal.c:1038
IRMC_Capability NoteCap
Definition: obexgen.h:219
GSM_Error GSM_WaitFor(GSM_StateMachine *s, unsigned const char *buffer, size_t length, int type, int timeout, GSM_Phone_RequestID request)
Definition: gsmstate.c:1029
GSM_Error OBEXGEN_GetTextFile(GSM_StateMachine *s, const char *FileName, char **Buffer)
int m_obex_contacts_nexterror
Definition: obexgen.h:255
GSM_Error OBEXGEN_DeleteAllCalendar(GSM_StateMachine *s)
OBEX_Service
Definition: obexgen.h:30
int m_obex_calendar_nexterror
Definition: obexgen.h:263
GSM_Error MOBEX_GetNextCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry, gboolean start)
GSM_DateTime Modified
Definition: gammu-file.h:98
GSM_Error OBEXGEN_SetNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
GSM_Error GSM_DecodeVCARD(GSM_Debug_Info *di, char *Buffer, size_t *Pos, GSM_MemoryEntry *Pbk, GSM_VCardVersion Version)
Definition: gsmpbk.c:677
GSM_Error GSM_DecodeVCALENDAR_VTODO(GSM_Debug_Info *di, char *Buffer, size_t *Pos, GSM_CalendarEntry *Calendar, GSM_ToDoEntry *ToDo, GSM_VCalendarVersion CalVer, GSM_VToDoVersion ToDoVer)
Definition: gsmcal.c:1673
gboolean ModifiedEmpty
Definition: gammu-file.h:102
GSM_File Files[500]
Definition: obexgen.h:66
GSM_Error GSM_EncodeVNTFile(char *Buffer, const size_t buff_len, size_t *Length, GSM_NoteEntry *Note)
Definition: gsmcal.c:2066
#define NOTIMPLEMENTED
Definition: gsmcomon.h:13
GSM_Error OBEXGEN_InitialiseVars(GSM_StateMachine *s)
gboolean UpdatePbLUID
Definition: obexgen.h:103
GSM_Error GSM_DecodeVNOTE(char *Buffer, size_t *Pos, GSM_NoteEntry *Note)
Definition: gsmcal.c:2030
unsigned char connection_id[4]
Definition: obexgen.h:291
GSM_Phone_Data Data
Definition: gsmstate.h:1369
size_t m_obex_contacts_buffer_size
Definition: obexgen.h:275
GSM_MemoryType MemoryType
Definition: gammu-memory.h:131
IRMC_Capability PbCap
Definition: obexgen.h:107
double VerNum
Definition: gsmstate.h:462
gboolean GSM_IsPhoneFeatureAvailable(GSM_PhoneModel *model, GSM_Feature feature)
Definition: gsmphones.c:1026
GSM_Error OBEXGEN_GetNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
GSM_Error OBEXGEN_Disconnect(GSM_StateMachine *s)
GSM_Error OBEXGEN_DeleteNote(GSM_StateMachine *s, GSM_NoteEntry *Entry)
const char * number
Definition: gammu-info.h:768
GSM_Error OBEXGEN_GetTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
gboolean FileLastPart
Definition: obexgen.h:67
GSM_Error OBEXGEN_DeleteAllNotes(GSM_StateMachine *s)
GSM_Error OBEXGEN_GetNextNote(GSM_StateMachine *s, GSM_NoteEntry *Entry, gboolean start)
GSM_Error OBEXGEN_AddFolder(GSM_StateMachine *s, GSM_File *File)
GSM_Error OBEXGEN_GetNextFileFolder(GSM_StateMachine *s, GSM_File *File, gboolean start)
GSM_Error OBEXGEN_AddFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
#define TRUE
Definition: gammu-types.h:28
GSM_Error OBEXGEN_SendFilePart(GSM_StateMachine *s, GSM_File *File, size_t *Pos, int *Handle)
GSM_Error OBEXGEN_GetBinaryFile(GSM_StateMachine *s, const char *FileName, unsigned char **Buffer, size_t *len)
GSM_Reply_Function OBEXGENReplyFunctions[]
GSM_Error OBEXGEN_AddTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
GSM_Error MOBEX_GetNextMemory(GSM_StateMachine *s, GSM_MemoryEntry *Entry, gboolean start)
unsigned char * Buffer
Definition: protocol.h:22
void DecodeXMLUTF8(unsigned char *dest, const char *src, size_t len)
Definition: coding.c:1966
#define UNUSED
Definition: gammu-misc.h:105
GSM_Error OBEXGEN_DeleteAllTodo(GSM_StateMachine *s)
gboolean UpdateNoteLUID
Definition: obexgen.h:215
char Model[GSM_MAX_MODEL_LENGTH+1]
Definition: gsmstate.h:445
GSM_Error MyGetLine(char *Buffer, size_t *Pos, char *OutBuffer, size_t MaxLen, size_t MaxOutLen, gboolean MergeLines)
Definition: coding.c:1580
GSM_Error MOBEX_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
GSM_Error OBEXGEN_SetTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry)
GSM_Error MOBEX_GetNextTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry, gboolean start)
GSM_Error OBEXGEN_GetCalendar(GSM_StateMachine *s, GSM_CalendarEntry *Entry)
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261
gboolean Hidden
Definition: gammu-file.h:115
GSM_Error OBEXGEN_GetNextTodo(GSM_StateMachine *s, GSM_ToDoEntry *Entry, gboolean start)