7 #include <libxml/parser.h>
8 #include <libxml/tree.h>
10 #include <libgnomevfs/gnome-vfs.h>
15 #define _(String) gettext (String)
17 # define N_(String) gettext_noop (String)
19 # define N_(String) (String)
22 #define _(String) String
31 typedef struct _GTodoCategory
{
36 /* should not be used by the user. internal function */
37 GTodoItem
* gtodo_client_get_todo_item_from_xml_ptr(GTodoClient
*cl
, xmlNodePtr node
);
39 /* this checks if the xml backend file exists.. not to be used by the user */
40 int check_item_changed(GnomeVFSMonitorHandle
*handle
, const gchar
*uri
, const gchar
*info
, GnomeVFSMonitorEventType event
, GTodoClient
*cl
);
42 int gtodo_client_check_file(GTodoClient
*cl
, GError
**error
);
45 /* Function that creates an empty todo item. WARNING Don't use this when adding a todo item to the list.*/
46 /* Use gtodo_client_create_new_todo_item instead */
47 /* 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 )*/
49 GTodoItem
* gtodo_client_create_empty_todo_item(void)
51 GTodoItem
*item
= g_malloc(sizeof(GTodoItem
));
52 if(item
== NULL
) return NULL
;
55 item
->last_edited
= 0;
60 item
->category
= NULL
;
61 item
->priority
= GTODO_PRIORITY_MEDIUM
;
64 item
->due_time
[GTODO_DUE_TIME_HOURE
] = -1;
65 item
->due_time
[GTODO_DUE_TIME_MINUTE
] = 0;
69 /* create a new unique todo item */
70 /* use this to add an todo item */
71 GTodoItem
* gtodo_client_create_new_todo_item(GTodoClient
*cl
)
73 GTodoItem
*item
= gtodo_client_create_empty_todo_item();
74 /* give an nice "random" id */
75 item
->id
= (GTime
)time(NULL
);
76 /* set the start time */
77 item
->start
= g_date_new();
78 g_date_set_time(item
->start
, (GTime
)item
->id
);
83 /* free's an GTodoItem */
84 void gtodo_todo_item_free(GTodoItem
*item
)
86 if(item
->start
!= NULL
) g_date_free(item
->start
);
87 if(item
->stop
!= NULL
) g_date_free(item
->stop
);
88 if(item
->due
!= NULL
) g_date_free(item
->due
);
89 if(item
->category
!= NULL
) g_free(item
->category
);
90 if(item
->summary
!= NULL
) g_free(item
->summary
);
91 if(item
->comment
!= NULL
) g_free(item
->comment
);
96 /* get the id from an todo item in guint32 (its an GTime, but a gtime is an gint32)..*/
97 /* I made it a guint32 because there is no negative time here */
98 guint32
gtodo_todo_item_get_id(GTodoItem
*item
)
100 return (guint32
)item
->id
;
103 /* set the notification flag for this todo item. */
104 void gtodo_todo_item_set_notify(GTodoItem
*item
, gboolean notify
)
106 item
->notify
= notify
;
108 /* get the statis of the notification flag */
109 gboolean
gtodo_todo_item_get_notify(GTodoItem
*item
)
114 /* get the priority. see enumeration in libgtodo.h for possible return values */
115 int gtodo_todo_item_get_priority(GTodoItem
*item
)
117 return item
->priority
;
120 /* set the priority, for possible value's look @ enumeration in libgtodo.c */
121 void gtodo_todo_item_set_priority(GTodoItem
*item
, int priority
)
123 item
->priority
= priority
;
126 /* get the summary, the returned value shouldnt be freed.*/
127 /* I return an empty string when there is no value. I am afraid this is wrong now */
129 char *gtodo_todo_item_get_summary(GTodoItem
*item
)
131 if(item
->summary
== NULL
) return "";
132 return item
->summary
;
135 /* set the summary, also setting to NULL, or changing is allowed */
136 void gtodo_todo_item_set_summary(GTodoItem
*item
, gchar
*summary
)
140 if(item
->summary
!= NULL
) g_free(item
->summary
);
141 item
->summary
= NULL
;
147 string
= g_string_new(summary
);
148 for(i
=0;i
< string
->len
;i
++)
150 if(string
->str
[i
] == '&')
152 g_string_insert(string
, i
+1, "amp;");
155 if(item
->summary
!= NULL
) g_free(item
->summary
);
156 item
->summary
= string
->str
;
157 g_string_free(string
,FALSE
);
161 /* get the category, the returned value shouldnt be freeed.*/
162 char *gtodo_todo_item_get_category(GTodoItem
*item
)
164 return item
->category
;
167 /* set the category or changing is allowed */
168 /* FIXME if category exists, if not.. create it. */
169 void gtodo_todo_item_set_category(GTodoItem
*item
, gchar
*category
)
171 if(category
== NULL
) return;
172 /* setting to NULL is bad.. because the GTodoItem is invalid then */
174 if(item->category != NULL) g_free(item->category);
175 item->category = NULL;
179 if(item
->category
!= NULL
) g_free(item
->category
);
180 item
->category
= g_strdup(category
);
184 /* get the comment, this can be a multi line string */
185 char *gtodo_todo_item_get_comment(GTodoItem
*item
)
187 if(item
->comment
== NULL
) return "";
188 return item
->comment
;
191 /* set the comment, setting to NULL is allowed, or changing */
192 void gtodo_todo_item_set_comment(GTodoItem
*item
, gchar
*comment
)
196 if(item
->comment
!= NULL
) g_free(item
->comment
);
197 item
->comment
= NULL
;
202 string
= g_string_new(comment
);
203 for(i
=0;i
< string
->len
;i
++)
205 if(string
->str
[i
] == '&')
207 g_string_insert(string
, i
+1, "amp;");
210 if(item
->comment
!= NULL
) g_free(item
->comment
);
211 item
->comment
= string
->str
;
212 g_string_free(string
, FALSE
);
217 gboolean
gtodo_todo_item_get_done(GTodoItem
*item
)
222 void gtodo_todo_item_set_done(GTodoItem
*item
, gboolean done
)
224 /* if the item is set done, set done date aswell, useless to have the user set it twice */
225 if(done
== TRUE
) gtodo_todo_item_set_stop_date_today(item
);
229 /* > 0 allready due */
231 /* <0 due in future */
232 /* GTODO_NO_DUE_DATE = no due date */
233 gint32
gtodo_todo_item_check_due(GTodoItem
*item
)
237 if(item
->due
== NULL
) return GTODO_NO_DUE_DATE
;
238 today
= g_date_new();
239 g_date_set_time(today
, time(NULL
));
240 i
= g_date_days_between(item
->due
,today
);
244 /*returns the time in minutes that is still left.. it will return 0 when there is nothing left
247 int gtodo_todo_item_check_due_time_minutes_left(GTodoItem
*item
)
251 if(gtodo_todo_item_check_due(item
) != 0) return 0;
253 lctime
= localtime(&now
);
254 if(lctime
== NULL
) return 0;
255 if(item
->due_time
[GTODO_DUE_TIME_HOURE
] == -1 && item
->due_time
[GTODO_DUE_TIME_MINUTE
] == 0) return 3000;
256 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
]));
259 /* get the last_edited date in severall format's */
260 /* return an julian date ... -1 = no date set */
261 guint32
gtodo_todo_item_get_last_edited_date_as_julian(GTodoItem
*item
)
263 if(item
->last_edited
== 0 ) return 1;
266 GDate
*date
= g_date_new();
268 g_date_set_time(date
, item
->last_edited
);
269 julian
= g_date_get_julian(date
);
274 /* return the houre of the due time */
275 gint
gtodo_todo_item_get_due_time_houre(GTodoItem
*item
)
277 return item
->due_time
[GTODO_DUE_TIME_HOURE
];
279 /* return the houre of the due time */
280 gint
gtodo_todo_item_get_due_time_minute(GTodoItem
*item
)
282 return item
->due_time
[GTODO_DUE_TIME_MINUTE
];
284 /* return the houre of the due time */
285 gint
gtodo_todo_item_set_due_time_minute(GTodoItem
*item
, gint minute
)
287 if(minute
< 0 && minute
>=60 ) return FALSE
;
288 else item
->due_time
[GTODO_DUE_TIME_MINUTE
] = minute
;
291 /* return the houre of the due time */
292 gint
gtodo_todo_item_set_due_time_houre(GTodoItem
*item
, gint houre
)
294 if(houre
< -1 && houre
>= 24 ) return FALSE
;
295 else item
->due_time
[GTODO_DUE_TIME_HOURE
] = houre
;
298 /* get the start date in severall format's */
299 /* return an julian date ... -1 = no date set */
300 guint32
gtodo_todo_item_get_start_date_as_julian(GTodoItem
*item
)
302 if(item
->start
== NULL
|| !g_date_valid(item
->start
)) return 1;
305 if(!g_date_valid_julian(g_date_get_julian(item
->start
))) return 1;
306 return g_date_get_julian(item
->start
);
309 /* set start date returns false when not able to set */
310 gboolean
gtodo_todo_item_set_start_date_as_julian(GTodoItem
*item
, guint32 julian
)
312 if(!g_date_valid_julian(julian
)) return FALSE
;
313 if(item
->start
== NULL
) item
->start
= g_date_new_julian(julian
);
314 else g_date_set_julian(item
->start
, julian
);
319 /* get localized string.. this needs to be freed! */
320 gchar
*gtodo_todo_item_get_start_date_as_string(GTodoItem
*item
)
322 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
323 memset(buffer
,'\0', 64*sizeof(gchar
));
324 if(item
== NULL
|| item
->start
== NULL
)
329 if(!g_date_valid(item
->start
))
334 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->start
) == 0)
342 /* get the stop date in severall format's */
343 /* return an julian date ... 1 = no date set */
344 guint32
gtodo_todo_item_get_stop_date_as_julian(GTodoItem
*item
)
346 if(item
->stop
== NULL
|| !g_date_valid(item
->stop
)) return 1;
349 if(!g_date_valid_julian(g_date_get_julian(item
->stop
))) return 1;
350 return g_date_get_julian(item
->stop
);
354 /* set stop date returns false when not able to set */
355 gboolean
gtodo_todo_item_set_stop_date_as_julian(GTodoItem
*item
, guint32 julian
)
357 if(!g_date_valid_julian(julian
)) return FALSE
;
358 if(item
->stop
== NULL
) item
->stop
= g_date_new_julian(julian
);
359 else g_date_set_julian(item
->stop
, julian
);
362 gboolean
gtodo_todo_item_set_stop_date_today(GTodoItem
*item
)
364 if(item
== NULL
) return FALSE
;
365 if(item
->stop
== NULL
) item
->stop
= g_date_new();
366 g_date_set_time(item
->stop
, time(NULL
));
369 /* get localized string.. this needs to be freed! */
370 gchar
*gtodo_todo_item_get_stop_date_as_string(GTodoItem
*item
)
372 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
373 memset(buffer
, '\0', 64*sizeof(gchar
));
374 if(item
== NULL
|| item
->stop
== NULL
)
379 if(!g_date_valid(item
->stop
))
384 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->stop
) == 0)
391 /* get the due date in severall format's */
392 /* return an julian date ... 1 = no date set */
393 guint32
gtodo_todo_item_get_due_date_as_julian(GTodoItem
*item
)
395 if(item
->due
== NULL
|| !g_date_valid(item
->due
))
397 return GTODO_NO_DUE_DATE
;
401 if(!g_date_valid_julian(g_date_get_julian(item
->due
))) return GTODO_NO_DUE_DATE
;
402 return g_date_get_julian(item
->due
);
406 /* set due date returns false when not able to set */
407 gboolean
gtodo_todo_item_set_due_date_as_julian(GTodoItem
*item
, guint32 julian
)
409 if(julian
== GTODO_NO_DUE_DATE
)
411 if(item
->due
!= NULL
)
413 g_date_free(item
->due
);
417 if(!g_date_valid_julian((guint32
)julian
)) return FALSE
;
418 if(item
->due
== NULL
) item
->due
= g_date_new_julian((guint32
)julian
);
419 else g_date_set_julian(item
->due
, (guint32
)julian
);
423 GDate
* gtodo_todo_item_get_due_date(GTodoItem
*item
)
425 if(item
== NULL
|| item
->due
== NULL
) return NULL
;
426 if(!g_date_valid(item
->due
)) return NULL
;
430 /* get localized string.. this needs to be freed! */
431 gchar
*gtodo_todo_item_get_due_date_as_string(GTodoItem
*item
)
433 gchar
*buffer
= g_malloc(sizeof(gchar
)*64);
434 memset(buffer
, '\0', 64*sizeof(gchar
));
435 if(item
== NULL
|| item
->due
== NULL
)
440 if(!g_date_valid(item
->due
))
445 if(g_date_strftime(buffer
, 64*sizeof(gchar
), "%d %b %G", item
->due
) == 0)
453 /* should not be used by the user. internal function */
454 GTodoItem
* gtodo_client_get_todo_item_from_xml_ptr(GTodoClient
*cl
, xmlNodePtr node
)
456 GTodoItem
*item
=NULL
;
458 if(node
== NULL
) return NULL
;
459 category
= xmlGetProp(node
->parent
, (const xmlChar
*)"title");
460 node
= node
->xmlChildrenNode
;
461 item
= gtodo_client_create_empty_todo_item();
462 gtodo_todo_item_set_category(item
, (gchar
*)category
);
466 if(xmlStrEqual(node
->name
, (const xmlChar
*)"comment"))
469 temp
= xmlNodeGetContent(node
);
472 item
->comment
= g_strdup((gchar
*)temp
);
476 else if(xmlStrEqual(node
->name
, (const xmlChar
*)"summary"))
479 temp
= xmlNodeGetContent(node
);
482 item
->summary
= g_strdup((gchar
*)temp
);
486 else if(xmlStrEqual(node
->name
, (const xmlChar
*)"attribute"))
489 temp
= xmlGetProp(node
, (const xmlChar
*)"id");
492 item
->id
= g_ascii_strtoull((gchar
*)temp
, NULL
,0);
495 temp
= xmlGetProp(node
, (const xmlChar
*)"priority");
498 item
->priority
= atoi((gchar
*)temp
);
501 temp
= xmlGetProp(node
, (const xmlChar
*)"done");
504 item
->done
= atoi((gchar
*)temp
);
507 temp
= xmlGetProp(node
, (const xmlChar
*)"start_date");
510 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
511 if(i
> 0) item
->start
= g_date_new_julian(i
);
514 temp
= xmlGetProp(node
, (const xmlChar
*)"completed_date");
517 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
518 if(i
> 0) item
->stop
= g_date_new_julian(i
);
522 temp
= xmlGetProp(node
, (const xmlChar
*)"notify");
525 gint i
= (int)g_ascii_strtod((gchar
*)temp
,NULL
);
526 item
->notify
= (int)i
;
529 temp
= xmlGetProp(node
, (const xmlChar
*)"enddate");
532 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
533 if(i
> 1 && i
!= GTODO_NO_DUE_DATE
) item
->due
= g_date_new_julian(i
);
536 temp
= xmlGetProp(node
, (const xmlChar
*)"endtime");
539 gint houre
=0, minute
= 0;
540 gint i
= (int)g_ascii_strtod((gchar
*)temp
,NULL
);
543 houre
= -1;minute
= 0;
545 else if( i
> 0 && i
< 1500)
548 minute
= (int)i
- houre
*60;
550 item
->due_time
[GTODO_DUE_TIME_HOURE
] = houre
;
551 item
->due_time
[GTODO_DUE_TIME_MINUTE
] = minute
;
554 temp
= xmlGetProp(node
, (const xmlChar
*)"last_edited");
557 guint64 i
= g_ascii_strtoull((gchar
*)temp
, NULL
, 0);
558 item
->last_edited
= (GTime
) i
;
567 /* initialise the gtodo lib */
568 int gtodo_client_check_file(GTodoClient
*cl
, GError
**error
)
570 GnomeVFSFileInfo info
;
571 GnomeVFSResult result
;
572 GnomeVFSResult info_result
;
573 GError
*tmp_error
= NULL
;
574 gchar
*base_path
= g_path_get_dirname(cl
->xml_path
);
575 /* check if the error is good or wrong. */
576 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
578 /* this is dirty.. needs a fix hard *
579 * The client should do this.. so this code should be considert
580 * deprecated. I left it here thinking it wouldnt hurt anybody.
583 if(base_path
!= NULL
)
585 gnome_vfs_make_directory(base_path
, 0755);
589 /* Get permission of the file */
590 /* This also tell's us if it does exists */
591 info_result
= gnome_vfs_get_file_info(cl
->xml_path
,
593 GNOME_VFS_FILE_INFO_DEFAULT
|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
);
595 /* If I got the info to check it out */
596 if(info_result
== GNOME_VFS_OK
)
598 GnomeVFSHandle
*handle
;
599 gchar
*read_buf
= NULL
;
600 int perm
= (info
.permissions
-(int)(info
.permissions
/65536)*65536);
601 int read
= (int)(perm
/256);
602 int write
=(int)((perm
- (int)(perm
/256)*256)/128);
604 /* If I am not allowed to read the file */
607 /* save some more info here.. check for some logicol errors and print it. */
608 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_NO_PERMISSION
,
609 _("No permission to read the file."));
610 g_propagate_error(error
, tmp_error
);
613 cl
->read_only
= !write
;
616 if((result
= gnome_vfs_open(&handle
,cl
->xml_path
, GNOME_VFS_OPEN_READ
)) != GNOME_VFS_OK
)
618 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(result
));
619 g_propagate_error(error
, tmp_error
);
622 read_buf
= g_malloc0((info
.size
+1)*sizeof(char));
624 result
= gnome_vfs_read(handle
, read_buf
, info
.size
,NULL
);
625 if(!(result
== GNOME_VFS_OK
|| result
== GNOME_VFS_ERROR_EOF
))
628 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(result
));
629 g_propagate_error(error
, tmp_error
);
632 gnome_vfs_close(handle
);
633 cl
->gtodo_doc
= xmlParseMemory(read_buf
, info
.size
);
634 if(cl
->gtodo_doc
== NULL
)
636 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("Failed to parse xml structure"));
637 g_propagate_error(error
, tmp_error
);
638 if(debug
) g_print("**DEBUG** failed to read the file \n");
642 /* get root element.. this "root" is used in the while program */
643 cl
->root
= xmlDocGetRootElement(cl
->gtodo_doc
);
646 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("Failed to parse xml structure"));
647 g_propagate_error(error
, tmp_error
);
648 if(debug
)g_print("**DEBUG** failed to get root node.\n");
651 /* check if the name of the root file is ok.. just to make sure :) */
652 if(!xmlStrEqual(cl
->root
->name
, (const xmlChar
*)"gtodo"))
654 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_XML
,_("File is not a valid gtodo file"));
655 g_propagate_error(error
, tmp_error
);
659 else if(info_result
== GNOME_VFS_ERROR_NOT_FOUND
){
661 if(debug
) g_print("Trying to create new file\n");
662 cl
->gtodo_doc
= xmlNewDoc((xmlChar
*)"1.0");
663 cl
->root
= xmlNewDocNode(cl
->gtodo_doc
, NULL
, (xmlChar
*)"gtodo", NULL
);
664 xmlDocSetRootElement(cl
->gtodo_doc
, cl
->root
);
665 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
666 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Personal"));
667 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
668 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Business"));
669 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
670 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)_("Unfiled"));
671 if(gtodo_client_save_xml(cl
, &tmp_error
))
673 g_propagate_error(error
, tmp_error
);
676 cl
->read_only
= FALSE
;
679 /* save some more info here.. check for some logicol errors and print it. */
680 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GNOME_VFS
,gnome_vfs_result_to_string(info_result
));
681 g_propagate_error(error
, tmp_error
);
687 /* Remove unwanted text nodes from the document */
690 gtodo_client_cleanup_doc (GTodoClient
*cl
)
692 xmlNodePtr level1
, next1
;
693 level1
= cl
->root
->xmlChildrenNode
;
694 while(level1
!= NULL
){
695 xmlNodePtr level2
, next2
;
696 next1
= level1
->next
;
698 if(xmlNodeIsText(level1
)) {
699 xmlUnlinkNode(level1
);
702 level2
= level1
->xmlChildrenNode
;
703 while(level2
!= NULL
) {
704 xmlNodePtr level3
, next3
;
705 next2
= level2
->next
;
707 if(xmlNodeIsText(level2
)) {
708 xmlUnlinkNode(level2
);
711 level3
= level2
->xmlChildrenNode
;
712 while (level3
!= NULL
) {
713 // xmlNodePtr level4, next4;
714 next3
= level3
->next
;
716 if(xmlNodeIsText(level3
)) {
717 xmlUnlinkNode(level3
);
730 /* save the gtodo_Client */
732 int gtodo_client_save_xml(GTodoClient
*cl
, GError
**error
)
734 GError
*tmp_error
= NULL
;
735 /* check if the error is good or wrong. */
736 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
738 if(debug
)g_print("** DEBUG ** saving %s\n", cl
->xml_path
);
739 gtodo_client_cleanup_doc (cl
);
740 if(gtodo_client_save_xml_to_file(cl
, cl
->xml_path
, &tmp_error
))
742 g_propagate_error(error
, tmp_error
);
749 int gtodo_client_save_xml_to_file(GTodoClient
*cl
, gchar
*file
, GError
**error
)
752 GnomeVFSHandle
*handle
;
753 GnomeVFSResult result
= 0;
754 GError
*tmp_error
= NULL
;
756 /* Test if there is actually a client to save */
759 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("No Gtodo Client to save.") );
760 g_propagate_error(error
, tmp_error
);
763 /* dump the xml to memory */
764 /* xmlIndentTreeOutput = 1; */
765 xmlKeepBlanksDefault(0);
766 xmlDocDumpFormatMemory(cl
->gtodo_doc
, &buffer
, &size
, TRUE
);
767 /* dirty trick to get the whole crap to work on ftp */
768 if(!strncmp(file
, "ftp://", MIN(strlen(file
),6)))
770 GnomeVFSURI
*uri
= gnome_vfs_uri_new(file
);
771 if(uri
!= NULL
&& gnome_vfs_uri_exists(uri
))
773 /* stupid hack to make everything work.. darn ftp */
774 if(debug
)g_print("trying to unlink the file\n");
775 if(gnome_vfs_unlink(file
) != GNOME_VFS_OK
)
777 if(debug
)g_print("Failed to delete\n");
778 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to delete %s."),file
);
779 g_propagate_error(error
, tmp_error
);
784 if(debug
)g_print("file unlinked\n");
787 gnome_vfs_uri_unref(uri
);
790 /* open the file for writing */
791 result
= gnome_vfs_create(&handle
,file
,GNOME_VFS_OPEN_WRITE
, 0, 0644);
792 if(result
!= GNOME_VFS_OK
)
794 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to create/open file.") );
795 g_propagate_error(error
, tmp_error
);
800 result
= gnome_vfs_write(handle
, buffer
, size
, NULL
);
801 if(result
!= GNOME_VFS_OK
)
803 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_GENERIC
,_("Failed to write data to file.") );
804 g_propagate_error(error
, tmp_error
);
808 /* close the file connection */
809 gnome_vfs_close(handle
);
812 /* return that everything is ok */
816 int gtodo_client_reload(GTodoClient
*cl
)
820 xmlFreeDoc(cl
->gtodo_doc
);
822 if(gtodo_client_check_file(cl
, NULL
))
824 if(debug
)g_print("Failed to reload the file\n");
830 int gtodo_client_load(GTodoClient
*cl
, const gchar
*xml_path
)
834 xmlFreeDoc(cl
->gtodo_doc
);
837 g_free (cl
->xml_path
);
838 cl
->xml_path
= g_strdup (xml_path
);
839 if(gtodo_client_check_file(cl
, NULL
))
841 if(debug
)g_print("Failed to reload the file\n");
844 gtodo_client_set_changed_callback (cl
, cl
->function
, cl
->data
);
846 cl
->function(cl
, cl
->data
);
850 GTodoClient
* gtodo_client_new_default(GError
**error
)
852 GError
*tmp_error
= NULL
;
853 GTodoClient
*cl
= NULL
;
854 /* check if the error is good or wrong. */
855 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
858 cl
= g_malloc(sizeof(GTodoClient
));
859 cl
->xml_path
= g_strdup_printf("file:///%s/.gtodo/todos", g_getenv("HOME"));
860 /* check, open or create the correct xml file */
861 if(gtodo_client_check_file(cl
, &tmp_error
))
863 g_propagate_error(error
, tmp_error
);
871 GTodoClient
* gtodo_client_new_from_file(char *filename
, GError
**error
)
873 GError
*tmp_error
= NULL
;
874 GTodoClient
*cl
= NULL
;
875 /* check if the error is good or wrong. */
876 g_return_val_if_fail(error
== NULL
|| *error
== NULL
,FALSE
);
877 if(debug
)g_print("Trying to create a new client %s\n", filename
);
880 g_set_error(&tmp_error
,LIBGTODO_ERROR
,LIBGTODO_ERROR_NO_FILENAME
,_("No filename supplied.") );
881 g_propagate_error(error
, tmp_error
);
885 cl
= g_malloc(sizeof(GTodoClient
));
886 cl
->xml_path
= g_strdup(filename
);
887 /* check, open or create the correct xml file */
888 if(gtodo_client_check_file(cl
,&tmp_error
))
890 g_propagate_error(error
, tmp_error
);
898 void gtodo_client_quit(GTodoClient
*cl
)
900 gtodo_client_save_xml(cl
,NULL
);
901 g_free(cl
->xml_path
);
906 gboolean
sort_category_list(GTodoCategory
*a
, GTodoCategory
*b
)
912 GTodoList
* gtodo_client_get_category_list(GTodoClient
*cl
)
917 GTodoList
*list
= g_malloc(sizeof(GTodoList
));
920 cl
->number_of_categories
= 0;
921 cur
= cl
->root
->xmlChildrenNode
;
925 if(xmlStrEqual(cur
->name
, (const xmlChar
*)"category")){
926 xmlChar
*temp
, *place
;
928 temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
929 place
= xmlGetProp(cur
, (const xmlChar
*)"place");
932 gchar
*buf
= g_strdup_printf("%i", repos
);
933 xmlSetProp(cur
, (const xmlChar
*)"place", (xmlChar
*)buf
);
938 else pos
= atoi((gchar
*)place
);
939 cl
->number_of_categories
++;
940 cat
= g_malloc(sizeof(GTodoCategory
));
941 cat
->name
= g_strdup((gchar
*)temp
);
943 list
->list
= g_list_append(list
->list
, cat
);
950 list
->list
= g_list_sort(list
->list
, (GCompareFunc
) sort_category_list
);
951 /* if I passed numbers, save the file.. */
952 /* if its OK, this should be allright.. it goes horrible wrong
953 if there are items withouth a number in the same file that contain items with numbers */
954 if(repos
!= 0) gtodo_client_save_xml(cl
,NULL
);
955 if(list
->list
== NULL
)
962 list
->first
= g_list_first(list
->list
);
968 void gtodo_client_free_category_item(GTodoCategory
*cat
)
973 void gtodo_client_free_category_list(GTodoClient
*cl
, GTodoList
*list
)
979 g_list_foreach(list
->first
, (GFunc
) gtodo_client_free_category_item
, NULL
);
980 g_list_free(list
->first
);
984 /* get a glist with todo's */
985 GTodoList
*gtodo_client_get_todo_item_list(GTodoClient
*cl
, gchar
*category
)
987 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
988 GTodoList
*list
= g_malloc(sizeof(GTodoList
));
993 temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
994 if(category
== NULL
|| xmlStrEqual(temp
, (const xmlChar
*)category
))
997 cur1
= cur
->xmlChildrenNode
;
1000 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
1002 GTodoItem
*item
= gtodo_client_get_todo_item_from_xml_ptr(cl
,cur1
);
1003 if(item
!= NULL
)list
->list
= g_list_append(list
->list
, item
);
1011 if(list
->list
== NULL
)
1016 list
->first
= g_list_first(list
->list
);
1020 /* free the todo's items */
1021 void gtodo_client_free_todo_item_list(GTodoClient
*cl
, GTodoList
*list
)
1027 g_list_foreach(list
->first
, (GFunc
) gtodo_todo_item_free
, NULL
);
1028 g_list_free(list
->first
);
1033 GTodoItem
*gtodo_client_get_todo_item_from_id(GTodoClient
*cl
, guint32 id
)
1035 xmlNodePtr node
= cl
->root
;
1036 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1038 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1039 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1042 cur1
= cur
->xmlChildrenNode
;
1045 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
1048 cur2
= cur1
->xmlChildrenNode
;
1051 if(xmlStrEqual(cur2
->name
, (const xmlChar
*)"attribute"))
1053 xmlChar
*temp1
= xmlGetProp(cur2
,(xmlChar
*)"id");
1056 if(atoi((gchar
*)temp1
) == id
)node
= cur1
;
1071 if(node
== cl
->root
)
1075 return gtodo_client_get_todo_item_from_xml_ptr(cl
,node
);
1078 gboolean
gtodo_client_save_todo_item(GTodoClient
*cl
, GTodoItem
*item
)
1080 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1081 if(!gtodo_client_category_exists(cl
, item
->category
))
1083 gtodo_client_category_new(cl
, item
->category
);
1088 temp2
= xmlGetProp(cur
, (const xmlChar
*)"title");
1089 if(xmlStrEqual(temp2
, (xmlChar
*)item
->category
))
1092 xmlNodePtr newn
, newa
;
1093 newn
= xmlNewChild(cur
, NULL
, (xmlChar
*)"item", NULL
);
1095 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"attribute", NULL
);
1096 temp1
= g_strdup_printf("%i", item
->id
);
1097 xmlSetProp(newa
, (xmlChar
*)"id", (xmlChar
*)temp1
);
1100 temp1
= g_strdup_printf("%i", item
->priority
);
1101 xmlSetProp(newa
, (xmlChar
*)"priority", (xmlChar
*)temp1
);
1104 temp1
= g_strdup_printf("%i", item
->done
);
1105 xmlSetProp(newa
, (xmlChar
*)"done", (xmlChar
*)temp1
);
1109 /* if new item .. nothing is done yet */
1110 if(item
->start
!= NULL
)
1112 guint32 julian
= g_date_get_julian(item
->start
);
1113 temp1
= g_strdup_printf("%u", julian
);
1114 xmlSetProp(newa
, (xmlChar
*)"start_date", (xmlChar
*)temp1
);
1117 /*( COMPLETED_DATE */
1118 if(item
->stop
!= NULL
&& item
->done
)
1120 guint32 julian
= g_date_get_julian(item
->stop
);
1121 temp1
= g_strdup_printf("%u", julian
);
1122 xmlSetProp(newa
, (xmlChar
*)"completed_date", (xmlChar
*)temp1
);
1126 /* enddate (to the start date attribute) */
1127 if(item
->due
!= NULL
)
1129 guint32 julian
= g_date_get_julian(item
->due
);
1130 temp1
= g_strdup_printf("%u", julian
);
1131 xmlSetProp(newa
, (xmlChar
*)"enddate", (xmlChar
*)temp1
);
1134 /* enddate (to the start date attribute) */
1136 temp1
= g_strdup_printf("%i", (gint
)item
->notify
);
1137 xmlSetProp(newa
, (xmlChar
*)"notify", (xmlChar
*)temp1
);
1140 /* endtime (to the start date attribute) */
1141 if(item
->due
!= NULL
)
1143 temp1
= g_strdup_printf("%i", (item
->due_time
[GTODO_DUE_TIME_HOURE
]*60)+item
->due_time
[GTODO_DUE_TIME_MINUTE
]);
1144 xmlSetProp(newa
, (xmlChar
*)"endtime", (xmlChar
*)temp1
);
1147 /* last edited (to the start date attribute) */
1149 temp1
= g_strdup_printf("%u", (GTime
)time(NULL
));
1150 xmlSetProp(newa
, (xmlChar
*)"last_edited", (xmlChar
*)temp1
);
1154 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"summary", (xmlChar
*)item
->summary
);
1156 newa
= xmlNewChild(newn
, NULL
, (xmlChar
*)"comment", (xmlChar
*)item
->comment
);
1161 gtodo_client_save_xml(cl
,NULL
);
1165 gchar
* gtodo_client_get_category_from_list(GTodoList
*list
)
1167 GTodoCategory
* cat
= list
->list
->data
;
1171 gint
gtodo_client_get_category_id_from_list(GTodoList
*list
)
1173 GTodoCategory
* cat
= list
->list
->data
;
1177 GTodoItem
*gtodo_client_get_todo_item_from_list(GTodoList
*list
)
1179 return list
->list
->data
;
1181 gboolean
gtodo_client_get_list_next(GTodoList
*list
)
1183 if(list
== NULL
) return FALSE
;
1184 if(list
->list
== NULL
) return FALSE
;
1185 list
->list
= g_list_next(list
->list
);
1186 if(list
->list
== NULL
) return FALSE
;
1190 /* You should get the todo item first.. then edit the item and pass it to this function to see it chagned*/
1191 gboolean
gtodo_client_edit_todo_item(GTodoClient
*cl
, GTodoItem
*item
)
1193 if(cl
== NULL
|| item
== NULL
) return FALSE
;
1194 if(!gtodo_client_category_exists(cl
, item
->category
)) return FALSE
;
1195 gtodo_client_delete_todo_by_id(cl
, item
->id
);
1196 if(!gtodo_client_save_todo_item(cl
, item
)) return FALSE
;
1200 void gtodo_client_delete_todo_by_id(GTodoClient
*cl
, guint32 id
)
1202 xmlNodePtr node
= cl
->root
;
1203 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1205 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1206 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1209 cur1
= cur
->xmlChildrenNode
;
1212 if(xmlStrEqual(cur1
->name
, (const xmlChar
*)"item"))
1215 cur2
= cur1
->xmlChildrenNode
;
1218 if(xmlStrEqual(cur2
->name
, (const xmlChar
*)"attribute"))
1220 xmlChar
*temp1
= xmlGetProp(cur2
,(xmlChar
*)"id");
1223 if(g_ascii_strtoull((gchar
*)temp1
,NULL
,0) == id
)node
= cur1
;
1238 if(node
== cl
->root
)
1242 xmlUnlinkNode(node
);
1244 gtodo_client_save_xml(cl
,NULL
);
1247 int check_item_changed(GnomeVFSMonitorHandle
*handle
, const gchar
*uri
, const gchar
*info
, GnomeVFSMonitorEventType event
, GTodoClient
*cl
)
1249 GnomeVFSURI
* vfs_uri
= gnome_vfs_uri_new(uri
);
1250 gboolean exists
= gnome_vfs_uri_exists(vfs_uri
);
1256 gtodo_client_reload(cl
);
1257 if(debug
)g_print("**DEBUG** Item changed\n");
1258 cl
->function(cl
, cl
->data
);
1262 /* set the fucntion it should call when the todo database has changed */
1263 /* function should be of type void functionname(GTodoType *cl, gpointer data); */
1264 void gtodo_client_set_changed_callback(GTodoClient
*cl
, void *(*function
)(gpointer cl
, gpointer data
), gpointer data
)
1266 cl
->function
= function
;
1267 gnome_vfs_monitor_add(&cl
->timeout
,cl
->xml_path
,
1268 GNOME_VFS_MONITOR_FILE
,
1269 (GnomeVFSMonitorCallback
)check_item_changed
, cl
);
1273 void gtodo_client_destroy_changed_callback(GTodoClient
*cl
, void *(*function
)(gpointer cl
, gpointer data
), gpointer data
)
1275 cl
->function
= NULL
;
1276 if(cl
->timeout
!= NULL
)
1278 gnome_vfs_monitor_cancel(cl
->timeout
);
1283 /* returns TRUE is successfull */
1284 gboolean
gtodo_client_category_edit(GTodoClient
*cl
, gchar
*old
, gchar
*newn
)
1286 if(cl
== NULL
|| old
== NULL
|| newn
== NULL
) return FALSE
;
1287 if(gtodo_client_category_exists(cl
, newn
) && !gtodo_client_category_exists(cl
, old
)) return FALSE
;
1290 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1292 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1293 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1294 if(xmlStrEqual(temp
, (const xmlChar
*)old
))
1296 xmlSetProp(cur
, (xmlChar
*)"title", (xmlChar
*)newn
);
1299 else cur
= cur
->next
;
1302 else cur
= cur
->next
;
1305 gtodo_client_save_xml(cl
,NULL
);
1311 gboolean
gtodo_client_category_set_id(GTodoClient
*cl
, gchar
*name
, gint id
)
1313 if(cl
== NULL
||name
== NULL
|| id
== -1) return FALSE
;
1314 if(!gtodo_client_category_exists(cl
, name
)) return FALSE
;
1317 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1319 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1320 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1321 if(xmlStrEqual(temp
, (const xmlChar
*)name
))
1323 gchar
*buf
= g_strdup_printf("%i", id
);
1324 xmlSetProp(cur
, (xmlChar
*)"place", (xmlChar
*)buf
);
1328 else cur
= cur
->next
;
1331 else cur
= cur
->next
;
1334 gtodo_client_save_xml(cl
,NULL
);
1340 gchar
*gtodo_client_category_get_from_id(GTodoClient
*cl
,gint id
)
1342 gchar
*ret_val
= NULL
;
1343 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1347 gint ref_id
= gtodo_client_get_category_id_from_list(list
);
1348 if(ref_id
== id
&& ret_val
== NULL
) ret_val
= g_strdup(gtodo_client_get_category_from_list(list
));
1349 }while(gtodo_client_get_list_next(list
));
1350 gtodo_client_free_category_list(cl
,list
);
1356 gboolean
gtodo_client_category_move_up(GTodoClient
*cl
, gchar
*name
)
1359 gchar
*above_name
= NULL
;
1362 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1366 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1367 gint id
= gtodo_client_get_category_id_from_list(list
);
1368 if(strcmp(name1
,name
) == 0 && orig_id
== 0)orig_id
= id
;
1369 }while(gtodo_client_get_list_next(list
));
1373 gtodo_client_free_category_list(cl
,list
);
1376 gtodo_client_get_list_first(list
);
1380 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1381 gint id
= gtodo_client_get_category_id_from_list(list
);
1382 if(id
== (orig_id
-1) && above_name
== NULL
) above_name
= g_strdup(name1
);
1383 }while(gtodo_client_get_list_next(list
));
1384 gtodo_client_free_category_list(cl
,list
);
1386 if(above_name
== NULL
) return FALSE
;
1387 gtodo_client_category_set_id(cl
, name
, (orig_id
-1));
1388 gtodo_client_category_set_id(cl
, above_name
, (orig_id
));
1395 gboolean
gtodo_client_category_move_down(GTodoClient
*cl
, gchar
*name
)
1398 gchar
*under_name
= NULL
;
1401 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1405 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1406 gint id
= gtodo_client_get_category_id_from_list(list
);
1407 if(strcmp(name1
,name
) == 0 && orig_id
== 0)orig_id
= id
;
1408 }while(gtodo_client_get_list_next(list
));
1410 if(orig_id
== (cl
->number_of_categories
-1))
1412 gtodo_client_free_category_list(cl
,list
);
1415 gtodo_client_get_list_first(list
);
1419 gchar
*name1
= gtodo_client_get_category_from_list(list
);
1420 gint id
= gtodo_client_get_category_id_from_list(list
);
1421 if(id
== (orig_id
+1) && under_name
== NULL
) under_name
= g_strdup(name1
);
1422 }while(gtodo_client_get_list_next(list
));
1423 gtodo_client_free_category_list(cl
,list
);
1425 if(under_name
== NULL
) return FALSE
;
1426 gtodo_client_category_set_id(cl
, name
, (orig_id
+1));
1427 gtodo_client_category_set_id(cl
, under_name
, (orig_id
));
1434 gboolean
gtodo_client_category_exists(GTodoClient
*cl
, gchar
*name
)
1436 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1437 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1441 if(!strcmp(name
, gtodo_client_get_category_from_list(list
)))
1443 gtodo_client_free_category_list(cl
, list
);
1446 }while(gtodo_client_get_list_next(list
));
1451 gboolean
gtodo_client_category_new(GTodoClient
*cl
, gchar
*name
)
1455 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1456 if(gtodo_client_category_exists(cl
, name
)) return FALSE
;
1457 newn
= xmlNewTextChild(cl
->root
, NULL
, (xmlChar
*)"category", NULL
);
1458 xmlNewProp(newn
, (xmlChar
*)"title", (xmlChar
*)name
);
1459 buf
= g_strdup_printf("%i", cl
->number_of_categories
);
1460 cl
->number_of_categories
++;
1461 xmlNewProp(newn
, (xmlChar
*)"place", (xmlChar
*)buf
);
1463 gtodo_client_save_xml(cl
,NULL
);
1467 gboolean
gtodo_client_category_remove(GTodoClient
*cl
, gchar
*name
)
1470 if(cl
== NULL
|| name
== NULL
) return FALSE
;
1471 if(!gtodo_client_category_exists(cl
, name
)) return FALSE
;
1474 xmlNodePtr cur
= cl
->root
->xmlChildrenNode
;
1475 /* gtodo_client_block_changed_callback(cl);
1476 */ while(cur
!= NULL
){
1477 if(xmlStrEqual(cur
->name
, (xmlChar
*)"category")){
1478 xmlChar
*temp
= xmlGetProp(cur
, (const xmlChar
*)"title");
1479 if(xmlStrEqual(temp
, (const xmlChar
*)name
))
1481 xmlChar
*idchar
= xmlGetProp(cur
, (const xmlChar
*)"place");
1482 if(idchar
!= NULL
) id
= atoi((gchar
*)idchar
);
1488 else cur
= cur
->next
;
1491 else cur
= cur
->next
;
1494 gtodo_client_save_xml(cl
,NULL
);
1495 /* one number is removed.. now we need to renumber.. */
1498 GTodoList
*list
= gtodo_client_get_category_list(cl
);
1502 int ref_id
= gtodo_client_get_category_id_from_list(list
);
1505 gchar
*name
= gtodo_client_get_category_from_list(list
);
1506 gtodo_client_category_set_id(cl
, name
, (ref_id
-1));
1508 }while(gtodo_client_get_list_next(list
));
1511 gtodo_client_free_category_list(cl
, list
);
1514 gtodo_client_save_xml(cl
,NULL
);
1515 /* this doesnt work.. have to adapt gtodo to do that
1516 gtodo_client_unblock_changed_callback(cl);
1522 void gtodo_client_block_changed_callback(GTodoClient
*cl
)
1524 if(cl
->timeout
!= NULL
)
1526 gnome_vfs_monitor_cancel(cl
->timeout
);
1531 void gtodo_client_unblock_changed_callback(GTodoClient
*cl
)
1533 if(cl
->timeout
== NULL
)
1535 gnome_vfs_monitor_add(&cl
->timeout
,cl
->xml_path
,
1536 GNOME_VFS_MONITOR_FILE
,
1537 (GnomeVFSMonitorCallback
)check_item_changed
, cl
);
1541 /* This function is deprecated now */
1542 void gtodo_client_reset_changed_callback(GTodoClient
*cl
)
1544 if(cl
->timeout
!= NULL
) return;
1547 void gtodo_client_get_list_first(GTodoList
*list
)
1549 list
->list
= list
->first
;
1552 /* als base niewer is dan test dan positief */
1553 long int gtodo_item_compare_latest(GTodoItem
*base
, GTodoItem
*test
)
1555 if(base
== NULL
|| test
== NULL
) return 0;
1556 return base
->last_edited
-test
->last_edited
;
1559 /* make duplicate an exact copy of source */
1560 void gtodo_client_save_client_to_client(GTodoClient
*source
, GTodoClient
*duplicate
)
1562 gtodo_client_save_xml_to_file(source
, duplicate
->xml_path
,NULL
);
1563 gtodo_client_reload(duplicate
);
1566 gboolean
gtodo_client_get_read_only(GTodoClient
*cl
)
1568 if(cl
== NULL
) return FALSE
;
1569 return cl
->read_only
;