2 #include <glib/gi18n.h>
8 #include <libxml/parser.h>
9 #include <libxml/tree.h>
11 #include <libgnomevfs/gnome-vfs.h>
19 typedef struct _GTodoCategory
{
24 /* should not be used by the user. internal function */
25 GTodoItem
* gtodo_client_get_todo_item_from_xml_ptr(GTodoClient
*cl
, xmlNodePtr node
);
27 /* this checks if the xml backend file exists.. not to be used by the user */
28 int check_item_changed(GnomeVFSMonitorHandle
*handle
, const gchar
*uri
, const gchar
*info
, GnomeVFSMonitorEventType event
, GTodoClient
*cl
);
30 int gtodo_client_check_file(GTodoClient
*cl
, GError
**error
);
33 /* Function that creates an empty todo item. WARNING Don't use this when adding a todo item to the list.*/
34 /* Use gtodo_client_create_new_todo_item instead */
35 /* note.. id is equal to the time created... this should be unique. (what is the change on 2 pc's its created at the vary same second )*/
37 GTodoItem
* gtodo_client_create_empty_todo_item(void)
39 GTodoItem
*item
= g_malloc(sizeof(GTodoItem
));
40 if(item
== NULL
) return NULL
;
43 item
->last_edited
= 0;
48 item
->category
= NULL
;
49 item
->priority
= GTODO_PRIORITY_MEDIUM
;
52 item
->due_time
[GTODO_DUE_TIME_HOURE
] = -1;
53 item
->due_time
[GTODO_DUE_TIME_MINUTE
] = 0;
57 /* create a new unique todo item */
58 /* use this to add an todo item */
59 GTodoItem
* gtodo_client_create_new_todo_item(GTodoClient
*cl
)
61 GTodoItem
*item
= gtodo_client_create_empty_todo_item();
62 /* give an nice "random" id */
63 item
->id
= (GTime
)time(NULL
);
64 /* set the start time */
65 item
->start
= g_date_new();
66 g_date_set_time(item
->start
, (GTime
)item
->id
);
71 /* free's an GTodoItem */
72 void gtodo_todo_item_free(GTodoItem
*item
)
74 if(item
->start
!= NULL
) g_date_free(item
->start
);
75 if(item
->stop
!= NULL
) g_date_free(item
->stop
);
76 if(item
->due
!= NULL
) g_date_free(item
->due
);
77 if(item
->category
!= NULL
) g_free(item
->category
);
78 if(item
->summary
!= NULL
) g_free(item
->summary
);
79 if(item
->comment
!= NULL
) g_free(item
->comment
);
84 /* get the id from an todo item in guint32 (its an GTime, but a gtime is an gint32)..*/
85 /* I made it a guint32 because there is no negative time here */
86 guint32
gtodo_todo_item_get_id(GTodoItem
*item
)
88 return (guint32
)item
->id
;
91 /* set the notification flag for this todo item. */
92 void gtodo_todo_item_set_notify(GTodoItem
*item
, gboolean notify
)
94 item
->notify
= notify
;
96 /* get the statis of the notification flag */
97 gboolean
gtodo_todo_item_get_notify(GTodoItem
*item
)
102 /* get the priority. see enumeration in libgtodo.h for possible return values */
103 int gtodo_todo_item_get_priority(GTodoItem
*item
)
105 return item
->priority
;
108 /* set the priority, for possible value's look @ enumeration in libgtodo.c */
109 void gtodo_todo_item_set_priority(GTodoItem
*item
, int priority
)
111 item
->priority
= priority
;
114 /* get the summary, the returned value shouldnt be freed.*/
115 /* I return an empty string when there is no value. I am afraid this is wrong now */
117 char *gtodo_todo_item_get_summary(GTodoItem
*item
)
119 if(item
->summary
== NULL
) return "";
120 return item
->summary
;
123 /* set the summary, also setting to NULL, or changing is allowed */
124 void gtodo_todo_item_set_summary(GTodoItem
*item
, gchar
*summary
)
128 if(item
->summary
!= NULL
) g_free(item
->summary
);
129 item
->summary
= NULL
;
135 string
= g_string_new(summary
);
136 for(i
=0;i
< string
->len
;i
++)
138 if(string
->str
[i
] == '&')
140 g_string_insert(string
, i
+1, "amp;");
143 if(item
->summary
!= NULL
) g_free(item
->summary
);
144 item
->summary
= string
->str
;
145 g_string_free(string
,FALSE
);
149 /* get the category, the returned value shouldnt be freeed.*/
150 char *gtodo_todo_item_get_category(GTodoItem
*item
)
152 return item
->category
;
155 /* set the category or changing is allowed */
156 /* FIXME if category exists, if not.. create it. */
157 void gtodo_todo_item_set_category(GTodoItem
*item
, gchar
*category
)
159 if(category
== NULL
) return;
160 /* setting to NULL is bad.. because the GTodoItem is invalid then */
162 if(item->category != NULL) g_free(item->category);
163 item->category = NULL;
167 if(item
->category
!= NULL
) g_free(item
->category
);
168 item
->category
= g_strdup(category
);
172 /* get the comment, this can be a multi line string */
173 char *gtodo_todo_item_get_comment(GTodoItem
*item
)
175 if(item
->comment
== NULL
) return "";
176 return item
->comment
;
179 /* set the comment, setting to NULL is allowed, or changing */
180 void gtodo_todo_item_set_comment(GTodoItem
*item
, gchar
*comment
)
184 if(item
->comment
!= NULL
) g_free(item
->comment
);
185 item
->comment
= NULL
;
190 string
= g_string_new(comment
);
191 for(i
=0;i
< string
->len
;i
++)
193 if(string
->str
[i
] == '&')
195 g_string_insert(string
, i
+1, "amp;");
198 if(item
->comment
!= NULL
) g_free(item
->comment
);
199 item
->comment
= string
->str
;
200 g_string_free(string
, FALSE
);
205 gboolean
gtodo_todo_item_get_done(GTodoItem
*item
)
210 void gtodo_todo_item_set_done(GTodoItem
*item
, gboolean done
)
212 /* if the item is set done, set done date aswell, useless to have the user set it twice */
213 if(done
== TRUE
) gtodo_todo_item_set_stop_date_today(item
);
217 /* > 0 allready due */
219 /* <0 due in future */
220 /* GTODO_NO_DUE_DATE = no due date */
221 gint32
gtodo_todo_item_check_due(GTodoItem
*item
)
225 if(item
->due
== NULL
) return GTODO_NO_DUE_DATE
;
226 today
= g_date_new();
227 g_date_set_time(today
, time(NULL
));
228 i
= g_date_days_between(item
->due
,today
);
232 /*returns the time in minutes that is still left.. it will return 0 when there is nothing left
235 int gtodo_todo_item_check_due_time_minutes_left(GTodoItem
*item
)
239 if(gtodo_todo_item_check_due(item
) != 0) return 0;
241 lctime
= localtime(&now
);
242 if(lctime
== NULL
) return 0;
243 if(item
->due_time
[GTODO_DUE_TIME_HOURE
] == -1 && item
->due_time
[GTODO_DUE_TIME_MINUTE
] == 0) return 3000;
244 return MAX(0, -((lctime
->tm_hour
*60+lctime
->tm_min
) - item
->due_time
[GTODO_DUE_TIME_HOURE
]*60-item
->due_time
[GTODO_DUE_TIME_MINUTE
]));
247 /* get the last_edited date in severall format's */
248 /* return an julian date ... -1 = no date set */
249 guint32
gtodo_todo_item_get_last_edited_date_as_julian(GTodoItem
*item
)
251 if(item
->last_edited
== 0 ) return 1;
254 GDate
*date
= g_date_new();
256 g_date_set_time(date
, item
->last_edited
);
257 julian
= g_date_get_julian(date
);
262 /* return the houre of the due time */
263 gint
gtodo_todo_item_get_due_time_houre(GTodoItem
*item
)
265 return item
->due_time
[GTODO_DUE_TIME_HOURE
];
267 /* return the houre of the due time */
268 gint
gtodo_todo_item_get_due_time_minute(GTodoItem
*item
)
270 return item
->due_time
[GTODO_DUE_TIME_MINUTE
];
272 /* return the houre of the due time */
273 gint
gtodo_todo_item_set_due_time_minute(GTodoItem
*item
, gint minute
)
275 if(minute
< 0 && minute
>=60 ) return FALSE
;
276 else item
->due_time
[GTODO_DUE_TIME_MINUTE
] = minute
;
279 /* return the houre of the due time */
280 gint
gtodo_todo_item_set_due_time_houre(GTodoItem
*item
, gint houre
)
282 if(houre
< -1 && houre
>= 24 ) return FALSE
;
283 else item
->due_time
[GTODO_DUE_TIME_HOURE
] = houre
;
286 /* get the start date in severall format's */
287 /* return an julian date ... -1 = no date set */
288 guint32
gtodo_todo_item_get_start_date_as_julian(GTodoItem
*item
)
290 if(item
->start
== NULL
|| !g_date_valid(item
->start
)) return 1;
293 if(!g_date_valid_julian(g_date_get_julian(item
->start
))) return 1;
294 return g_date_get_julian(item
->start
);
297 /* set start date returns false when not able to set */
298 gboolean
gtodo_todo_item_set_start_date_as_julian(GTodoItem
*item
, guint32 julian
)
300 if(!g_date_valid_julian(julian
)) return FALSE
;
301 if(item
->start
== NULL
) item
->start
= g_date_new_julian(julian
);
302 else g_date_set_julian(item
->start
, julian
);
307 /* get localized string.. this needs to be freed! */
308 gchar
*gtodo_todo_item_get_start_date_as_string(GTodoItem
*item
)
310 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
311 memset(buffer
,'\0', 64*sizeof(gchar
));
312 if(item
== NULL
|| item
->start
== NULL
)
317 if(!g_date_valid(item
->start
))
322 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->start
) == 0)
330 /* get the stop date in severall format's */
331 /* return an julian date ... 1 = no date set */
332 guint32
gtodo_todo_item_get_stop_date_as_julian(GTodoItem
*item
)
334 if(item
->stop
== NULL
|| !g_date_valid(item
->stop
)) return 1;
337 if(!g_date_valid_julian(g_date_get_julian(item
->stop
))) return 1;
338 return g_date_get_julian(item
->stop
);
342 /* set stop date returns false when not able to set */
343 gboolean
gtodo_todo_item_set_stop_date_as_julian(GTodoItem
*item
, guint32 julian
)
345 if(!g_date_valid_julian(julian
)) return FALSE
;
346 if(item
->stop
== NULL
) item
->stop
= g_date_new_julian(julian
);
347 else g_date_set_julian(item
->stop
, julian
);
350 gboolean
gtodo_todo_item_set_stop_date_today(GTodoItem
*item
)
352 if(item
== NULL
) return FALSE
;
353 if(item
->stop
== NULL
) item
->stop
= g_date_new();
354 g_date_set_time(item
->stop
, time(NULL
));
357 /* get localized string.. this needs to be freed! */
358 gchar
*gtodo_todo_item_get_stop_date_as_string(GTodoItem
*item
)
360 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
361 memset(buffer
, '\0', 64*sizeof(gchar
));
362 if(item
== NULL
|| item
->stop
== NULL
)
367 if(!g_date_valid(item
->stop
))
372 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->stop
) == 0)
379 /* get the due date in severall format's */
380 /* return an julian date ... 1 = no date set */
381 guint32
gtodo_todo_item_get_due_date_as_julian(GTodoItem
*item
)
383 if(item
->due
== NULL
|| !g_date_valid(item
->due
))
385 return GTODO_NO_DUE_DATE
;
389 if(!g_date_valid_julian(g_date_get_julian(item
->due
))) return GTODO_NO_DUE_DATE
;
390 return g_date_get_julian(item
->due
);
394 /* set due date returns false when not able to set */
395 gboolean
gtodo_todo_item_set_due_date_as_julian(GTodoItem
*item
, guint32 julian
)
397 if(julian
== GTODO_NO_DUE_DATE
)
399 if(item
->due
!= NULL
)
401 g_date_free(item
->due
);
405 if(!g_date_valid_julian((guint32
)julian
)) return FALSE
;
406 if(item
->due
== NULL
) item
->due
= g_date_new_julian((guint32
)julian
);
407 else g_date_set_julian(item
->due
, (guint32
)julian
);
411 GDate
* gtodo_todo_item_get_due_date(GTodoItem
*item
)
413 if(item
== NULL
|| item
->due
== NULL
) return NULL
;
414 if(!g_date_valid(item
->due
)) return NULL
;
418 /* get localized string.. this needs to be freed! */
419 gchar
*gtodo_todo_item_get_due_date_as_string(GTodoItem
*item
)
421 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
422 memset(buffer
, '\0', 64*sizeof(gchar
));
423 if(item
== NULL
|| item
->due
== NULL
)
428 if(!g_date_valid(item
->due
))
433 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->due
) == 0)
441 /* should not be used by the user. internal function */
442 GTodoItem
* gtodo_client_get_todo_item_from_xml_ptr(GTodoClient
*cl
, xmlNodePtr node
)
444 GTodoItem
*item
=NULL
;
446 if(node
== NULL
) return NULL
;
447 category
= xmlGetProp(node
->parent
, (const xmlChar
*)"title");
448 node
= node
->xmlChildrenNode
;
449 item
= gtodo_client_create_empty_todo_item();
450 gtodo_todo_item_set_category(item
, (gchar
*)category
);
454 if(xmlStrEqual(node
->name
, (const xmlChar
*)"comment"))
457 temp
= xmlNodeGetContent(node
);
460 item
->comment
= g_strdup((gchar
*)temp
);
464 else if(xmlStrEqual(node
->name
, (const xmlChar
*)"summary"))
467 temp
= xmlNodeGetContent(node
);
470 item
->summary
= g_strdup((gchar
*)temp
);
474 else if(xmlStrEqual(node
->name
, (const xmlChar
*)"attribute"))
477 temp
= xmlGetProp(node
, (const xmlChar
*)"id");
480 item
->id
= g_ascii_strtoull((gchar
*)temp
, NULL
,0);
483 temp
= xmlGetProp(node
, (const xmlChar
*)"priority");
486 item
->priority
= atoi((gchar
*)temp
);
489 temp
= xmlGetProp(node
, (const xmlChar
*)"done");
492 item
->done
= atoi((gchar
*)temp
);
495 temp
= xmlGetProp(node
, (const xmlChar
*)"start_date");
498 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
499 if(i
> 0) item
->start
= g_date_new_julian(i
);
502 temp
= xmlGetProp(node
, (const xmlChar
*)"completed_date");
505 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
506 if(i
> 0) item
->stop
= g_date_new_julian(i
);
510 temp
= xmlGetProp(node
, (const xmlChar
*)"notify");
513 gint i
= (int)g_ascii_strtod((gchar
*)temp
,NULL
);
514 item
->notify
= (int)i
;
517 temp
= xmlGetProp(node
, (const xmlChar
*)"enddate");
520 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
521 if(i
> 1 && i
!= GTODO_NO_DUE_DATE
) item
->due
= g_date_new_julian(i
);
524 temp
= xmlGetProp(node
, (const xmlChar
*)"endtime");
527 gint houre
=0, minute
= 0;
528 gint i
= (int)g_ascii_strtod((gchar
*)temp
,NULL
);
531 houre
= -1;minute
= 0;
533 else if( i
> 0 && i
< 1500)
536 minute
= (int)i
- houre
*60;
538 item
->due_time
[GTODO_DUE_TIME_HOURE
] = houre
;
539 item
->due_time
[GTODO_DUE_TIME_MINUTE
] = minute
;
542 temp
= xmlGetProp(node
, (const xmlChar
*)"last_edited");
545 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
546 item
->last_edited
= (GTime
) i
;
555 /* initialise the gtodo lib */
556 int gtodo_client_check_file(GTodoClient
*cl
, GError
**error
)
558 GnomeVFSFileInfo info
;
559 GnomeVFSResult result
;
560 GnomeVFSResult info_result
;
561 GError
*tmp_error
= NULL
;
562 gchar
*base_path
= g_path_get_dirname(cl
->xml_path
);
563 /* check if the error is good or wrong. */
564 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
566 /* this is dirty.. needs a fix hard *
567 * The client should do this.. so this code should be considert
568 * deprecated. I left it here thinking it wouldnt hurt anybody.
571 if(base_path
!= NULL
)
573 gnome_vfs_make_directory(base_path
, 0755);
577 /* Get permission of the file */
578 /* This also tell's us if it does exists */
579 info_result
= gnome_vfs_get_file_info(cl
->xml_path
,
581 GNOME_VFS_FILE_INFO_DEFAULT
|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
);
583 /* If I got the info to check it out */
584 if(info_result
== GNOME_VFS_OK
)
586 GnomeVFSHandle
*handle
;
587 gchar
*read_buf
= NULL
;
588 int perm
= (info
.permissions
-(int)(info
.permissions
/65536)*65536);
589 int read
= (int)(perm
/256);
590 int write
=(int)((perm
- (int)(perm
/256)*256)/128);
592 /* If I am not allowed to read the file */
595 /* save some more info here.. check for some logicol errors and print it. */
596 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_NO_PERMISSION
,
597 _("No permission to read the file."));
598 g_propagate_error(error
, tmp_error
);
601 cl
->read_only
= !write
;
604 if((result
= gnome_vfs_open(&handle
,cl
->xml_path
, GNOME_VFS_OPEN_READ
)) != GNOME_VFS_OK
)
606 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(result
));
607 g_propagate_error(error
, tmp_error
);
610 read_buf
= g_malloc0((info
.size
+1)*sizeof(char));
612 result
= gnome_vfs_read(handle
, read_buf
, info
.size
,NULL
);
613 if(!(result
== GNOME_VFS_OK
|| result
== GNOME_VFS_ERROR_EOF
))
616 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(result
));
617 g_propagate_error(error
, tmp_error
);
620 gnome_vfs_close(handle
);
621 cl
->gtodo_doc
= xmlParseMemory(read_buf
, info
.size
);
622 if(cl
->gtodo_doc
== NULL
)
624 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("Failed to parse xml structure"));
625 g_propagate_error(error
, tmp_error
);
626 if(debug
) g_print("**DEBUG** failed to read the file \n");
630 /* get root element.. this "root" is used in the while program */
631 cl
->root
= xmlDocGetRootElement(cl
->gtodo_doc
);
634 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("Failed to parse xml structure"));
635 g_propagate_error(error
, tmp_error
);
636 if(debug
)g_print("**DEBUG** failed to get root node.\n");
639 /* check if the name of the root file is ok.. just to make sure :) */
640 if(!xmlStrEqual(cl
->root
->name
, (const xmlChar
*)"gtodo"))
642 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("File is not a valid gtodo file"));
643 g_propagate_error(error
, tmp_error
);
647 else if(info_result
== GNOME_VFS_ERROR_NOT_FOUND
){
649 if(debug
) g_print("Trying to create new file\n");
650 cl
->gtodo_doc
= xmlNewDoc((xmlChar
*)"1.0");
651 cl
->root
= xmlNewDocNode(cl
->gtodo_doc
, NULL
, (xmlChar
*)"gtodo", NULL
);
652 xmlDocSetRootElement(cl
->gtodo_doc
, cl
->root
);
653 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
654 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Personal"));
655 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
656 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Business"));
657 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
658 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Unfiled"));
659 if(gtodo_client_save_xml(cl
, &tmp_error
))
661 g_propagate_error(error
, tmp_error
);
664 cl
->read_only
= FALSE
;
667 /* save some more info here.. check for some logicol errors and print it. */
668 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(info_result
));
669 g_propagate_error(error
, tmp_error
);
675 /* Remove unwanted text nodes from the document */
678 gtodo_client_cleanup_doc (GTodoClient
*cl
)
680 xmlNodePtr level1
, next1
;
681 level1
= cl
->root
->xmlChildrenNode
;
682 while(level1
!= NULL
){
683 xmlNodePtr level2
, next2
;
684 next1
= level1
->next
;
686 if(xmlNodeIsText(level1
)) {
687 xmlUnlinkNode(level1
);
690 level2
= level1
->xmlChildrenNode
;
691 while(level2
!= NULL
) {
692 xmlNodePtr level3
, next3
;
693 next2
= level2
->next
;
695 if(xmlNodeIsText(level2
)) {
696 xmlUnlinkNode(level2
);
699 level3
= level2
->xmlChildrenNode
;
700 while (level3
!= NULL
) {
701 // xmlNodePtr level4, next4;
702 next3
= level3
->next
;
704 if(xmlNodeIsText(level3
)) {
705 xmlUnlinkNode(level3
);
718 /* save the gtodo_Client */
720 int gtodo_client_save_xml(GTodoClient
*cl
, GError
**error
)
722 GError
*tmp_error
= NULL
;
723 /* check if the error is good or wrong. */
724 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
726 if(debug
)g_print("** DEBUG ** saving %s\n", cl
->xml_path
);
727 gtodo_client_cleanup_doc (cl
);
728 if(gtodo_client_save_xml_to_file(cl
, cl
->xml_path
, &tmp_error
))
730 g_propagate_error(error
, tmp_error
);
737 int gtodo_client_save_xml_to_file(GTodoClient
*cl
, gchar
*file
, GError
**error
)
740 GnomeVFSHandle
*handle
;
741 GnomeVFSResult result
= 0;
742 GError
*tmp_error
= NULL
;
744 /* Test if there is actually a client to save */
747 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("No Gtodo Client to save.") );
748 g_propagate_error(error
, tmp_error
);
751 /* dump the xml to memory */
752 /* xmlIndentTreeOutput = 1; */
753 xmlKeepBlanksDefault(0);
754 xmlDocDumpFormatMemory(cl
->gtodo_doc
, &buffer
, &size
, TRUE
);
755 /* dirty trick to get the whole crap to work on ftp */
756 if(!strncmp(file
, "ftp://", MIN(strlen(file
),6)))
758 GnomeVFSURI
*uri
= gnome_vfs_uri_new(file
);
759 if(uri
!= NULL
&& gnome_vfs_uri_exists(uri
))
761 /* stupid hack to make everything work.. darn ftp */
762 if(debug
)g_print("trying to unlink the file\n");
763 if(gnome_vfs_unlink(file
) != GNOME_VFS_OK
)
765 if(debug
)g_print("Failed to delete\n");
766 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to delete %s."),file
);
767 g_propagate_error(error
, tmp_error
);
772 if(debug
)g_print("file unlinked\n");
775 gnome_vfs_uri_unref(uri
);
778 /* open the file for writing */
779 result
= gnome_vfs_create(&handle
,file
,GNOME_VFS_OPEN_WRITE
, 0, 0644);
780 if(result
!= GNOME_VFS_OK
)
782 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to create/open file.") );
783 g_propagate_error(error
, tmp_error
);
788 result
= gnome_vfs_write(handle
, buffer
, size
, NULL
);
789 if(result
!= GNOME_VFS_OK
)
791 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to write data to file.") );
792 g_propagate_error(error
, tmp_error
);
796 /* close the file connection */
797 gnome_vfs_close(handle
);
800 /* return that everything is ok */
804 int gtodo_client_reload(GTodoClient
*cl
)
808 xmlFreeDoc(cl
->gtodo_doc
);
810 if(gtodo_client_check_file(cl
, NULL
))
812 if(debug
)g_print("Failed to reload the file\n");
818 int gtodo_client_load(GTodoClient
*cl
, const gchar
*xml_path
)
822 xmlFreeDoc(cl
->gtodo_doc
);
825 g_free (cl
->xml_path
);
826 cl
->xml_path
= g_strdup (xml_path
);
827 if(gtodo_client_check_file(cl
, NULL
))
829 if(debug
)g_print("Failed to reload the file\n");
832 gtodo_client_set_changed_callback (cl
, cl
->function
, cl
->data
);
834 cl
->function(cl
, cl
->data
);
838 GTodoClient
* gtodo_client_new_default(GError
**error
)
840 GError
*tmp_error
= NULL
;
841 GTodoClient
*cl
= NULL
;
842 /* check if the error is good or wrong. */
843 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
846 cl
= g_malloc(sizeof(GTodoClient
));
847 cl
->xml_path
= g_strdup_printf("file:///%s/.gtodo/todos", g_getenv("HOME"));
848 /* check, open or create the correct xml file */
849 if(gtodo_client_check_file(cl
, &tmp_error
))
851 g_propagate_error(error
, tmp_error
);
859 GTodoClient
* gtodo_client_new_from_file(char *filename
, GError
**error
)
861 GError
*tmp_error
= NULL
;
862 GTodoClient
*cl
= NULL
;
863 /* check if the error is good or wrong. */
864 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
865 if(debug
)g_print("Trying to create a new client %s\n", filename
);
868 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_NO_FILENAME
,_("No filename supplied.") );
869 g_propagate_error(error
, tmp_error
);
873 cl
= g_malloc(sizeof(GTodoClient
));
874 cl
->xml_path
= g_strdup(filename
);
875 /* check, open or create the correct xml file */
876 if(gtodo_client_check_file(cl
,&tmp_error
))
878 g_propagate_error(error
, tmp_error
);
886 void gtodo_client_quit(GTodoClient
*cl
)
888 gtodo_client_save_xml(cl
,NULL
);
889 g_free(cl
->xml_path
);
894 gboolean
sort_category_list(GTodoCategory
*a
, GTodoCategory
*b
)
900 GTodoList
* gtodo_client_get_category_list(GTodoClient
*cl
)
905 GTodoList
*list
= g_malloc(sizeof(GTodoList
));
908 cl
->number_of_categories
= 0;
909 cur
= cl
->root
->xmlChildrenNode
;
913 if(xmlStrEqual(cur
->name
, (const xmlChar
*)"category")){
914 xmlChar
*temp
, *place
;
916 temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
917 place
= xmlGetProp(cur
, (const xmlChar
*)"place");
920 gchar
*buf
= g_strdup_printf("%i", repos
);
921 xmlSetProp(cur
, (const xmlChar
*)"place", (xmlChar
*)buf
);
926 else pos
= atoi((gchar
*)place
);
927 cl
->number_of_categories
++;
928 cat
= g_malloc(sizeof(GTodoCategory
));
929 cat
->name
= g_strdup((gchar
*)temp
);
931 list
->list
= g_list_append(list
->list
, cat
);
938 list
->list
= g_list_sort(list
->list
, (GCompareFunc
) sort_category_list
);
939 /* if I passed numbers, save the file.. */
940 /* if its OK, this should be allright.. it goes horrible wrong
941 if there are items withouth a number in the same file that contain items with numbers */
942 if(repos
!= 0) gtodo_client_save_xml(cl
,NULL
);
943 if(list
->list
== NULL
)
950 list
->first
= g_list_first(list
->list
);
956 void gtodo_client_free_category_item(GTodoCategory
*cat
)
961 void gtodo_client_free_category_list(GTodoClient
*cl
, GTodoList
*list
)
967 g_list_foreach(list
->first
, (GFunc
) gtodo_client_free_category_item
, NULL
);
968 g_list_free(list
->first
);
972 /* get a glist with todo's */
973 GTodoList
*gtodo_client_get_todo_item_list(GTodoClient
*cl
, gchar
*category
)
975 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
976 GTodoList
*list
= g_malloc(sizeof(GTodoList
));
981 temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
982 if(category
== NULL
|| xmlStrEqual(temp
, (const xmlChar
*)category
))
985 cur1
= cur
->xmlChildrenNode
;
988 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
990 GTodoItem
*item
= gtodo_client_get_todo_item_from_xml_ptr(cl
,cur1
);
991 if(item
!= NULL
)list
->list
= g_list_append(list
->list
, item
);
999 if(list
->list
== NULL
)
1004 list
->first
= g_list_first(list
->list
);
1008 /* free the todo's items */
1009 void gtodo_client_free_todo_item_list(GTodoClient
*cl
, GTodoList
*list
)
1015 g_list_foreach(list
->first
, (GFunc
) gtodo_todo_item_free
, NULL
);
1016 g_list_free(list
->first
);
1021 GTodoItem
*gtodo_client_get_todo_item_from_id(GTodoClient
*cl
, guint32 id
)
1023 xmlNodePtr node
= cl
->root
;
1024 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1026 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1027 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1030 cur1
= cur
->xmlChildrenNode
;
1033 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
1036 cur2
= cur1
->xmlChildrenNode
;
1039 if(xmlStrEqual(cur2
->name
, (const xmlChar
*)"attribute"))
1041 xmlChar
*temp1
= xmlGetProp(cur2
,(xmlChar
*)"id");
1044 if(atoi((gchar
*)temp1
) == id
)node
= cur1
;
1059 if(node
== cl
->root
)
1063 return gtodo_client_get_todo_item_from_xml_ptr(cl
,node
);
1066 gboolean
gtodo_client_save_todo_item(GTodoClient
*cl
, GTodoItem
*item
)
1068 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1069 if(!gtodo_client_category_exists(cl
, item
->category
))
1071 gtodo_client_category_new(cl
, item
->category
);
1076 temp2
= xmlGetProp(cur
, (const xmlChar
*)"title");
1077 if(xmlStrEqual(temp2
, (xmlChar
*)item
->category
))
1080 xmlNodePtr newn
, newa
;
1081 newn
= xmlNewChild(cur
, NULL
, (xmlChar
*)"item", NULL
);
1083 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"attribute", NULL
);
1084 temp1
= g_strdup_printf("%i", item
->id
);
1085 xmlSetProp(newa
, (xmlChar
*)"id", (xmlChar
*)temp1
);
1088 temp1
= g_strdup_printf("%i", item
->priority
);
1089 xmlSetProp(newa
, (xmlChar
*)"priority", (xmlChar
*)temp1
);
1092 temp1
= g_strdup_printf("%i", item
->done
);
1093 xmlSetProp(newa
, (xmlChar
*)"done", (xmlChar
*)temp1
);
1097 /* if new item .. nothing is done yet */
1098 if(item
->start
!= NULL
)
1100 guint32 julian
= g_date_get_julian(item
->start
);
1101 temp1
= g_strdup_printf("%u", julian
);
1102 xmlSetProp(newa
, (xmlChar
*)"start_date", (xmlChar
*)temp1
);
1105 /*( COMPLETED_DATE */
1106 if(item
->stop
!= NULL
&& item
->done
)
1108 guint32 julian
= g_date_get_julian(item
->stop
);
1109 temp1
= g_strdup_printf("%u", julian
);
1110 xmlSetProp(newa
, (xmlChar
*)"completed_date", (xmlChar
*)temp1
);
1114 /* enddate (to the start date attribute) */
1115 if(item
->due
!= NULL
)
1117 guint32 julian
= g_date_get_julian(item
->due
);
1118 temp1
= g_strdup_printf("%u", julian
);
1119 xmlSetProp(newa
, (xmlChar
*)"enddate", (xmlChar
*)temp1
);
1122 /* enddate (to the start date attribute) */
1124 temp1
= g_strdup_printf("%i", (gint
)item
->notify
);
1125 xmlSetProp(newa
, (xmlChar
*)"notify", (xmlChar
*)temp1
);
1128 /* endtime (to the start date attribute) */
1129 if(item
->due
!= NULL
)
1131 temp1
= g_strdup_printf("%i", (item
->due_time
[GTODO_DUE_TIME_HOURE
]*60)+item
->due_time
[GTODO_DUE_TIME_MINUTE
]);
1132 xmlSetProp(newa
, (xmlChar
*)"endtime", (xmlChar
*)temp1
);
1135 /* last edited (to the start date attribute) */
1137 temp1
= g_strdup_printf("%u", (GTime
)time(NULL
));
1138 xmlSetProp(newa
, (xmlChar
*)"last_edited", (xmlChar
*)temp1
);
1142 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"summary", (xmlChar
*)item
->summary
);
1144 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"comment", (xmlChar
*)item
->comment
);
1149 gtodo_client_save_xml(cl
,NULL
);
1153 gchar
* gtodo_client_get_category_from_list(GTodoList
*list
)
1155 GTodoCategory
* cat
= list
->list
->data
;
1156 return _(cat
->name
);
1159 gint
gtodo_client_get_category_id_from_list(GTodoList
*list
)
1161 GTodoCategory
* cat
= list
->list
->data
;
1165 GTodoItem
*gtodo_client_get_todo_item_from_list(GTodoList
*list
)
1167 return list
->list
->data
;
1169 gboolean
gtodo_client_get_list_next(GTodoList
*list
)
1171 if(list
== NULL
) return FALSE
;
1172 if(list
->list
== NULL
) return FALSE
;
1173 list
->list
= g_list_next(list
->list
);
1174 if(list
->list
== NULL
) return FALSE
;
1178 /* You should get the todo item first.. then edit the item and pass it to this function to see it chagned*/
1179 gboolean
gtodo_client_edit_todo_item(GTodoClient
*cl
, GTodoItem
*item
)
1181 if(cl
== NULL
|| item
== NULL
) return FALSE
;
1182 if(!gtodo_client_category_exists(cl
, item
->category
)) return FALSE
;
1183 gtodo_client_delete_todo_by_id(cl
, item
->id
);
1184 if(!gtodo_client_save_todo_item(cl
, item
)) return FALSE
;
1188 void gtodo_client_delete_todo_by_id(GTodoClient
*cl
, guint32 id
)
1190 xmlNodePtr node
= cl
->root
;
1191 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1193 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1194 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1197 cur1
= cur
->xmlChildrenNode
;
1200 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
1203 cur2
= cur1
->xmlChildrenNode
;
1206 if(xmlStrEqual(cur2
->name
, (const xmlChar
*)"attribute"))
1208 xmlChar
*temp1
= xmlGetProp(cur2
,(xmlChar
*)"id");
1211 if(g_ascii_strtoull((gchar
*)temp1
,NULL
,0) == id
)node
= cur1
;
1226 if(node
== cl
->root
)
1230 xmlUnlinkNode(node
);
1232 gtodo_client_save_xml(cl
,NULL
);
1235 int check_item_changed(GnomeVFSMonitorHandle
*handle
, const gchar
*uri
, const gchar
*info
, GnomeVFSMonitorEventType event
, GTodoClient
*cl
)
1237 GnomeVFSURI
* vfs_uri
= gnome_vfs_uri_new(uri
);
1238 gboolean exists
= gnome_vfs_uri_exists(vfs_uri
);
1244 gtodo_client_reload(cl
);
1245 if(debug
)g_print("**DEBUG** Item changed\n");
1246 cl
->function(cl
, cl
->data
);
1250 /* set the fucntion it should call when the todo database has changed */
1251 /* function should be of type void functionname(GTodoType *cl, gpointer data); */
1252 void gtodo_client_set_changed_callback(GTodoClient
*cl
, void *(*function
)(gpointer cl
, gpointer data
), gpointer data
)
1254 cl
->function
= function
;
1255 gnome_vfs_monitor_add(&cl
->timeout
,cl
->xml_path
,
1256 GNOME_VFS_MONITOR_FILE
,
1257 (GnomeVFSMonitorCallback
)check_item_changed
, cl
);
1261 void gtodo_client_destroy_changed_callback(GTodoClient
*cl
, void *(*function
)(gpointer cl
, gpointer data
), gpointer data
)
1263 cl
->function
= NULL
;
1264 if(cl
->timeout
!= NULL
)
1266 gnome_vfs_monitor_cancel(cl
->timeout
);
1271 /* returns TRUE is successfull */
1272 gboolean
gtodo_client_category_edit(GTodoClient
*cl
, gchar
*old
, gchar
*newn
)
1274 if(cl
== NULL
|| old
== NULL
|| newn
== NULL
) return FALSE
;
1275 if(gtodo_client_category_exists(cl
, newn
) && !gtodo_client_category_exists(cl
, old
)) return FALSE
;
1278 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1280 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1281 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1282 if(xmlStrEqual(temp
, (const xmlChar
*)old
))
1284 xmlSetProp(cur
, (xmlChar
*)"title", (xmlChar
*)newn
);
1287 else cur
= cur
->next
;
1290 else cur
= cur
->next
;
1293 gtodo_client_save_xml(cl
,NULL
);
1299 gboolean
gtodo_client_category_set_id(GTodoClient
*cl
, gchar
*name
, gint id
)
1301 if(cl
== NULL
||name
== NULL
|| id
== -1) return FALSE
;
1302 if(!gtodo_client_category_exists(cl
, name
)) return FALSE
;
1305 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1307 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1308 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1309 if(xmlStrEqual(temp
, (const xmlChar
*)name
))
1311 gchar
*buf
= g_strdup_printf("%i", id
);
1312 xmlSetProp(cur
, (xmlChar
*)"place", (xmlChar
*)buf
);
1316 else cur
= cur
->next
;
1319 else cur
= cur
->next
;
1322 gtodo_client_save_xml(cl
,NULL
);
1328 gchar
*gtodo_client_category_get_from_id(GTodoClient
*cl
,gint id
)
1330 gchar
*ret_val
= NULL
;
1331 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1335 gint ref_id
= gtodo_client_get_category_id_from_list(list
);
1336 if(ref_id
== id
&& ret_val
== NULL
) ret_val
= g_strdup(gtodo_client_get_category_from_list(list
));
1337 }while(gtodo_client_get_list_next(list
));
1338 gtodo_client_free_category_list(cl
,list
);
1344 gboolean
gtodo_client_category_move_up(GTodoClient
*cl
, gchar
*name
)
1347 gchar
*above_name
= NULL
;
1350 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1354 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1355 gint id
= gtodo_client_get_category_id_from_list(list
);
1356 if(strcmp(name1
,name
) == 0 && orig_id
== 0)orig_id
= id
;
1357 }while(gtodo_client_get_list_next(list
));
1361 gtodo_client_free_category_list(cl
,list
);
1364 gtodo_client_get_list_first(list
);
1368 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1369 gint id
= gtodo_client_get_category_id_from_list(list
);
1370 if(id
== (orig_id
-1) && above_name
== NULL
) above_name
= g_strdup(name1
);
1371 }while(gtodo_client_get_list_next(list
));
1372 gtodo_client_free_category_list(cl
,list
);
1374 if(above_name
== NULL
) return FALSE
;
1375 gtodo_client_category_set_id(cl
, name
, (orig_id
-1));
1376 gtodo_client_category_set_id(cl
, above_name
, (orig_id
));
1383 gboolean
gtodo_client_category_move_down(GTodoClient
*cl
, gchar
*name
)
1386 gchar
*under_name
= NULL
;
1389 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1393 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1394 gint id
= gtodo_client_get_category_id_from_list(list
);
1395 if(strcmp(name1
,name
) == 0 && orig_id
== 0)orig_id
= id
;
1396 }while(gtodo_client_get_list_next(list
));
1398 if(orig_id
== (cl
->number_of_categories
-1))
1400 gtodo_client_free_category_list(cl
,list
);
1403 gtodo_client_get_list_first(list
);
1407 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1408 gint id
= gtodo_client_get_category_id_from_list(list
);
1409 if(id
== (orig_id
+1) && under_name
== NULL
) under_name
= g_strdup(name1
);
1410 }while(gtodo_client_get_list_next(list
));
1411 gtodo_client_free_category_list(cl
,list
);
1413 if(under_name
== NULL
) return FALSE
;
1414 gtodo_client_category_set_id(cl
, name
, (orig_id
+1));
1415 gtodo_client_category_set_id(cl
, under_name
, (orig_id
));
1422 gboolean
gtodo_client_category_exists(GTodoClient
*cl
, gchar
*name
)
1424 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1425 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1429 if(!strcmp(name
, gtodo_client_get_category_from_list(list
)))
1431 gtodo_client_free_category_list(cl
, list
);
1434 }while(gtodo_client_get_list_next(list
));
1439 gboolean
gtodo_client_category_new(GTodoClient
*cl
, gchar
*name
)
1443 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1444 if(gtodo_client_category_exists(cl
, name
)) return FALSE
;
1445 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
1446 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)name
);
1447 buf
= g_strdup_printf("%i", cl
->number_of_categories
);
1448 cl
->number_of_categories
++;
1449 xmlNewProp(newn
, (xmlChar
*)"place", (xmlChar
*)buf
);
1451 gtodo_client_save_xml(cl
,NULL
);
1455 gboolean
gtodo_client_category_remove(GTodoClient
*cl
, gchar
*name
)
1458 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1459 if(!gtodo_client_category_exists(cl
, name
)) return FALSE
;
1462 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1463 /* gtodo_client_block_changed_callback(cl);
1464 */ while(cur
!= NULL
){
1465 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1466 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1467 if(xmlStrEqual(temp
, (const xmlChar
*)name
))
1469 xmlChar
*idchar
= xmlGetProp(cur
, (const xmlChar
*)"place");
1470 if(idchar
!= NULL
) id
= atoi((gchar
*)idchar
);
1476 else cur
= cur
->next
;
1479 else cur
= cur
->next
;
1482 gtodo_client_save_xml(cl
,NULL
);
1483 /* one number is removed.. now we need to renumber.. */
1486 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1490 int ref_id
= gtodo_client_get_category_id_from_list(list
);
1493 gchar
*name
= gtodo_client_get_category_from_list(list
);
1494 gtodo_client_category_set_id(cl
, name
, (ref_id
-1));
1496 }while(gtodo_client_get_list_next(list
));
1499 gtodo_client_free_category_list(cl
, list
);
1502 gtodo_client_save_xml(cl
,NULL
);
1503 /* this doesnt work.. have to adapt gtodo to do that
1504 gtodo_client_unblock_changed_callback(cl);
1510 void gtodo_client_block_changed_callback(GTodoClient
*cl
)
1512 if(cl
->timeout
!= NULL
)
1514 gnome_vfs_monitor_cancel(cl
->timeout
);
1519 void gtodo_client_unblock_changed_callback(GTodoClient
*cl
)
1521 if(cl
->timeout
== NULL
)
1523 gnome_vfs_monitor_add(&cl
->timeout
,cl
->xml_path
,
1524 GNOME_VFS_MONITOR_FILE
,
1525 (GnomeVFSMonitorCallback
)check_item_changed
, cl
);
1529 /* This function is deprecated now */
1530 void gtodo_client_reset_changed_callback(GTodoClient
*cl
)
1532 if(cl
->timeout
!= NULL
) return;
1535 void gtodo_client_get_list_first(GTodoList
*list
)
1537 list
->list
= list
->first
;
1540 /* als base niewer is dan test dan positief */
1541 long int gtodo_item_compare_latest(GTodoItem
*base
, GTodoItem
*test
)
1543 if(base
== NULL
|| test
== NULL
) return 0;
1544 return base
->last_edited
-test
->last_edited
;
1547 /* make duplicate an exact copy of source */
1548 void gtodo_client_save_client_to_client(GTodoClient
*source
, GTodoClient
*duplicate
)
1550 gtodo_client_save_xml_to_file(source
, duplicate
->xml_path
,NULL
);
1551 gtodo_client_reload(duplicate
);
1554 gboolean
gtodo_client_get_read_only(GTodoClient
*cl
)
1556 if(cl
== NULL
) return FALSE
;
1557 return cl
->read_only
;