agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit 985fbcacfe752019b8da39c7660f142c18237466
parent 2c713772ae19d0d6cdae756c6c189a9e3c880932
Author: Marc Coquand <marc@coquand.email>
Date:   Thu, 24 Jul 2025 10:51:09 +0200

Refactor out ical functions

Grouping the functions by what data they operate on.

Diffstat:
MMakefile | 2+-
Magenda_entry.c | 267+------------------------------------------------------------------------------
Magenda_entry.h | 25-------------------------
Aical_extra.c | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aical_extra.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain.c | 116++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mutil.h | 4++++
7 files changed, 386 insertions(+), 344 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,6 +1,6 @@
 CC ?= gcc
 CFLAGS = -Wall -O3
-CFLAGS_DEBUG = -Wall -g
+CFLAGS_DEBUG = -Wall -g -DDEBUG
 LIBS = `pkg-config uuid fuse3 libical --cflags --libs`
 
 all: agendafs
diff --git a/agenda_entry.c b/agenda_entry.c
@@ -1,5 +1,6 @@
 #include "agenda_entry.h"
 #include "hashmap.h"
+#include "ical_extra.h"
 #include "mregion.h"
 #include "path.h"
 #include "tree.h"
@@ -19,7 +20,6 @@
 #include <uuid/uuid.h>
 #include <wordexp.h>
 
-const char *IS_DIRECTORY_PROPERTY = "X-CALDAVFS-ISDIRECTORY";
 char VDIR[256];
 
 // Most memory is managed by memory_region, two exceptions are the
@@ -140,41 +140,6 @@ node_is_directory(memory_region *mreg, const struct tree_node *node,
 }
 
 bool
-is_directory_component(icalcomponent *component)
-{
-	icalcomponent *journal = icalcomponent_get_first_component(
-	    component, ICAL_VJOURNAL_COMPONENT);
-
-	for (icalproperty *prop = icalcomponent_get_first_property(
-		 journal, ICAL_RELATEDTO_PROPERTY);
-	     prop != NULL; prop = icalcomponent_get_next_property(
-			       journal, ICAL_RELATEDTO_PROPERTY)) {
-
-		const char *reltype =
-		    icalproperty_get_parameter_as_string(prop, "RELTYPE");
-		if (reltype && strcasecmp(reltype, "CHILD") == 0) {
-			return true;
-		}
-	}
-	for (icalproperty *prop =
-		 icalcomponent_get_first_property(journal, ICAL_X_PROPERTY);
-	     prop != NULL;
-	     prop = icalcomponent_get_next_property(journal, ICAL_X_PROPERTY)) {
-		LOG("FOUND X PROPERTY");
-
-		const char *prop_name = icalproperty_get_x_name(prop);
-		if (prop_name &&
-		    strcmp(prop_name, IS_DIRECTORY_PROPERTY) == 0) {
-			const char *value =
-			    icalproperty_get_value_as_string(prop);
-			LOG("FOUND DIRECTORY");
-			return value && strcmp(value, "YES") == 0;
-		}
-	}
-	return false;
-}
-
-bool
 is_root_node(const struct tree_node *node)
 {
 	return !node->data;
@@ -194,36 +159,6 @@ get_vdir_filepath(memory_region *mreg, const struct tree_node *node)
 	return append_path(mreg, VDIR, entry->filename_vdir);
 }
 
-// Owner: ctx
-icalcomponent *
-parse_ics_file(memory_region *mreg, const char *filename)
-{
-
-	FILE *file = fopen(filename, "r");
-	LOG("filename is %s", filename);
-
-	struct stat st;
-	assert(stat(filename, &st) == 0);
-
-	size_t size = st.st_size;
-	char *buffer = rmalloc(mreg, size + 1);
-
-	size_t bytes_read = fread(buffer, 1, size, file);
-	buffer[bytes_read] = '\0';
-	fclose(file);
-
-	icalcomponent *component = ricalcomponent_new_from_string(mreg, buffer);
-
-	return component;
-}
-
-icaltimetype
-get_ical_now()
-{
-	return icaltime_from_timet_with_zone(time(NULL), 0,
-					     icaltimezone_get_utc_timezone());
-}
-
 size_t
 write_ical_file(memory_region *mreg, const struct tree_node *node,
 		icalcomponent *ic)
@@ -272,72 +207,6 @@ get_icalcomponent_from_node(memory_region *mreg, const struct tree_node *n)
 	return ic;
 }
 
-const char *
-get_parent_uid(icalcomponent *component)
-{
-	icalcomponent *inner =
-	    icalcomponent_get_first_component(component, ICAL_ANY_COMPONENT);
-
-	for (icalproperty *prop = icalcomponent_get_first_property(
-		 inner, ICAL_RELATEDTO_PROPERTY);
-	     prop != NULL; prop = icalcomponent_get_next_property(
-			       inner, ICAL_RELATEDTO_PROPERTY)) {
-		const char *reltype =
-		    icalproperty_get_parameter_as_string(prop, "RELTYPE");
-		if (reltype && strcasecmp(reltype, "PARENT") == 0) {
-			return icalproperty_get_value_as_string(prop);
-		}
-	}
-
-	return NULL;
-}
-
-void
-remove_parent_child_relationship_from_component(icalcomponent *parent,
-						icalcomponent *child)
-{
-
-	const char *parent_uid = icalcomponent_get_uid(parent);
-
-	icalcomponent *inner =
-	    icalcomponent_get_first_component(child, ICAL_ANY_COMPONENT);
-
-	icalproperty *prop =
-	    icalcomponent_get_first_property(inner, ICAL_RELATEDTO_PROPERTY);
-	while (prop != NULL) {
-		icalproperty *next = icalcomponent_get_next_property(
-		    inner, ICAL_RELATEDTO_PROPERTY);
-		const char *value = icalproperty_get_relatedto(prop);
-		icalparameter *reltype = icalproperty_get_first_parameter(
-		    prop, ICAL_RELTYPE_PARAMETER);
-
-		if (value && strcmp(value, parent_uid) == 0 && reltype &&
-		    icalparameter_get_reltype(reltype) == ICAL_RELTYPE_PARENT) {
-			icalcomponent_remove_property(inner, prop);
-			icalproperty_free(prop);
-		}
-
-		prop = next;
-	}
-}
-
-void
-set_parent_child_relationship_to_component(icalcomponent *parent,
-					   icalcomponent *child)
-{
-	icalproperty *child_related_to_parent =
-	    icalproperty_new_relatedto(icalcomponent_get_uid(parent));
-	icalparameter *reltype_child =
-	    icalparameter_new_reltype(ICAL_RELTYPE_PARENT);
-	icalproperty_add_parameter(child_related_to_parent, reltype_child);
-
-	icalcomponent *inner =
-	    icalcomponent_get_first_component(child, ICAL_ANY_COMPONENT);
-	if (inner) {
-		icalcomponent_add_property(inner, child_related_to_parent);
-	}
-}
-
 int
 write_parent_child_components(memory_region *mreg,
 			      const struct tree_node *parent,
@@ -493,19 +362,13 @@ load_root_node_tree()
 		icalcomponent *ic = get_icalcomponent_from_node(mreg, child);
 		LOG("Success");
 
-		struct agenda_entry *entry = get_entry(child);
-
 		const char *parent_uid = get_parent_uid(ic);
-		LOG("Looking up entry %s, %s", entry->filename_vdir,
-		    entry->filename);
 		if (parent_uid) {
 			LOG("Has parent");
 
 			struct tree_node *parent =
 			    get_node_by_uuid(mreg, parent_uid);
 			if (parent) {
-				struct agenda_entry *p_entry = parent->data;
-				LOG("Adding to parent %s", p_entry->filename);
 				detach_tree_node(child);
 				add_child(parent, child);
 			}
@@ -679,36 +542,6 @@ set_node_categories(memory_region *mreg, const struct tree_node *node,
 }
 
 const char *
-format_ical_class(const enum icalproperty_class iclass)
-{
-	if (iclass == ICAL_CLASS_PRIVATE) {
-		return "private";
-	}
-	else if (iclass == ICAL_CLASS_PUBLIC) {
-		return "public";
-	}
-	else if (iclass == ICAL_CLASS_CONFIDENTIAL) {
-		return "confidential";
-	}
-	return NULL;
-}
-
-const icalproperty_class
-parse_ical_class(const char *input)
-{
-	if (strcmp(input, "private") == 0) {
-		return ICAL_CLASS_PRIVATE;
-	}
-	else if (strcmp(input, "public") == 0) {
-		return ICAL_CLASS_PUBLIC;
-	}
-	else if (strcmp(input, "confidential") == 0) {
-		return ICAL_CLASS_CONFIDENTIAL;
-	}
-	return ICAL_CLASS_X;
-}
-
-const char *
 get_node_class(memory_region *mreg, const struct tree_node *node)
 {
 	icalcomponent *component = get_icalcomponent_from_node(mreg, node);
@@ -768,49 +601,6 @@ set_node_class(memory_region *mreg, const struct tree_node *node,
 	return write_ical_file(mreg, node, component);
 }
 
-char *
-create_new_unique_ics_uid(memory_region *mreg)
-{
-	uuid_t uuid;
-	char uuid_str[37]; // UUIDs are 36 characters + null terminator
-	uuid_generate(uuid);
-	uuid_unparse(uuid, uuid_str);
-	char *res = NULL;
-	size_t wRes = rasprintf(mreg, &res, "%s-caldavfs", uuid_str);
-	assert(wRes != -1);
-
-	return res;
-}
-
-icalcomponent *
-create_vjournal_entry(memory_region *mreg, const char *summary)
-{
-
-	icalcomponent *calendar = ricalcomponent_new_vcalendar(mreg);
-
-	icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
-	icalcomponent_add_property(calendar,
-				   icalproperty_new_prodid("-//caldavfs//EN"));
-
-	// Step 2: Create a VJOURNAL entry
-	icalcomponent *journal = icalcomponent_new_vjournal();
-	char *id = create_new_unique_ics_uid(mreg);
-
-	icalcomponent_add_property(journal, icalproperty_new_uid(id));
-	icalcomponent_add_property(journal,
-				   icalproperty_new_class(ICAL_CLASS_PRIVATE));
-
-	icalcomponent_add_property(
-	    journal, icalproperty_new_dtstamp(icaltime_current_time_with_zone(
-			 icaltimezone_get_utc_timezone())));
-	icalcomponent_add_property(journal, icalproperty_new_summary(summary));
-	icalcomponent_add_property(journal, icalproperty_new_description(""));
-
-	icalcomponent_add_component(calendar, journal);
-
-	return calendar;
-}
-
 uid_t
 get_node_uid(const struct tree_node *node)
 {
@@ -837,61 +627,6 @@ get_node_ino(const struct tree_node *node)
 	return get_entry(node)->ino;
 }
 
-icaltimetype
-get_last_modified(icalcomponent *component)
-{
-	icalproperty *last_modified_prop = icalcomponent_get_next_property(
-	    component, ICAL_LASTMODIFIED_PROPERTY);
-
-	if (last_modified_prop) {
-		icaltimetype ical_lastmodified =
-		    icalproperty_get_lastmodified(last_modified_prop);
-		return ical_lastmodified;
-	}
-	else {
-		return icalcomponent_get_dtstamp(component);
-	}
-}
-
-size_t
-get_entry_content_size(icalcomponent *component)
-{
-	size_t size =
-	    snprintf(NULL, 0, "%s", icalcomponent_get_description(component));
-
-	assert(size != -1);
-	return size;
-}
-
-icalcomponent *
-create_vjournal_directory(memory_region *mreg, const char *summary)
-{
-
-	icalcomponent *calendar = icalcomponent_new_vcalendar();
-
-	icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
-	icalcomponent_add_property(calendar,
-				   icalproperty_new_prodid("-//caldavfs//EN"));
-
-	icalcomponent *journal = icalcomponent_new_vjournal();
-	char *id = create_new_unique_ics_uid(mreg);
-
-	icalcomponent_add_property(journal, icalproperty_new_uid(id));
-
-	icalcomponent_add_property(
-	    journal, icalproperty_new_dtstamp(icaltime_current_time_with_zone(
-			 icaltimezone_get_utc_timezone())));
-	icalcomponent_add_property(journal, icalproperty_new_summary(summary));
-
-	icalproperty *is_directory = icalproperty_new_x(IS_DIRECTORY_PROPERTY);
-	icalproperty_set_x_name(is_directory, IS_DIRECTORY_PROPERTY);
-	icalproperty_set_x(is_directory, "YES");
-	icalcomponent_add_property(journal, is_directory);
-
-	icalcomponent_add_component(calendar, journal);
-	return calendar;
-}
-
 int
 create_entry_from_fuse(memory_region *mreg, const char *fuse_path)
 {
diff --git a/agenda_entry.h b/agenda_entry.h
@@ -63,9 +63,6 @@ node_is_directory(memory_region *mreg, const struct tree_node *node,
 		  icalcomponent *node_ics);
 
 bool
-is_directory_component(icalcomponent *component);
-
-bool
 is_root_node(const struct tree_node *node);
 
 struct agenda_entry *
@@ -89,17 +86,6 @@ write_ical_file(memory_region *mreg, const struct tree_node *node,
 icalcomponent *
 get_icalcomponent_from_node(memory_region *mreg, const struct tree_node *n);
 
-const char *
-get_parent_uid(icalcomponent *component);
-
-void
-remove_parent_child_relationship_from_component(icalcomponent *parent,
-						icalcomponent *child);
-
-void
-set_parent_child_relationship_to_component(icalcomponent *parent,
-					   icalcomponent *child);
-
 int
 write_parent_child_components(memory_region *mreg,
 			      const struct tree_node *parent,
@@ -165,8 +151,6 @@ ino_t
 get_node_ino(const struct tree_node *node);
 char *
 get_fuse_path_from_vdir(memory_region *mreg, const char *filepath);
-icalcomponent *
-create_vjournal_entry(memory_region *mreg, const char *summary);
 
 uid_t
 get_node_uid(const struct tree_node *node);
@@ -174,15 +158,6 @@ get_node_uid(const struct tree_node *node);
 gid_t
 get_node_gid(const struct tree_node *node);
 
-icaltimetype
-get_last_modified(icalcomponent *component);
-
-size_t
-get_entry_content_size(icalcomponent *component);
-
-icalcomponent *
-create_vjournal_directory(memory_region *mreg, const char *summary);
-
 int
 create_entry_from_fuse(memory_region *mreg, const char *fuse_path);
 
diff --git a/ical_extra.c b/ical_extra.c
@@ -0,0 +1,265 @@
+#include "libical/ical.h"
+#include "mregion.h"
+#include "sys/stat.h"
+#include "uuid/uuid.h"
+#include <stdbool.h>
+const char *IS_DIRECTORY_PROPERTY = "X-CALDAVFS-ISDIRECTORY";
+
+icaltimetype
+get_last_modified(icalcomponent *component)
+{
+	icalproperty *last_modified_prop = icalcomponent_get_next_property(
+	    component, ICAL_LASTMODIFIED_PROPERTY);
+
+	if (last_modified_prop) {
+		icaltimetype ical_lastmodified =
+		    icalproperty_get_lastmodified(last_modified_prop);
+		return ical_lastmodified;
+	}
+	else {
+		return icalcomponent_get_dtstamp(component);
+	}
+}
+
+const icalproperty_class
+parse_ical_class(const char *input)
+{
+	if (strcmp(input, "private") == 0) {
+		return ICAL_CLASS_PRIVATE;
+	}
+	else if (strcmp(input, "public") == 0) {
+		return ICAL_CLASS_PUBLIC;
+	}
+	else if (strcmp(input, "confidential") == 0) {
+		return ICAL_CLASS_CONFIDENTIAL;
+	}
+	return ICAL_CLASS_X;
+}
+
+const char *
+format_ical_class(const enum icalproperty_class iclass)
+{
+	if (iclass == ICAL_CLASS_PRIVATE) {
+		return "private";
+	}
+	else if (iclass == ICAL_CLASS_PUBLIC) {
+		return "public";
+	}
+	else if (iclass == ICAL_CLASS_CONFIDENTIAL) {
+		return "confidential";
+	}
+	return NULL;
+}
+
+bool
+is_directory_component(icalcomponent *component)
+{
+	icalcomponent *journal = icalcomponent_get_first_component(
+	    component, ICAL_VJOURNAL_COMPONENT);
+
+	for (icalproperty *prop = icalcomponent_get_first_property(
+		 journal, ICAL_RELATEDTO_PROPERTY);
+	     prop != NULL; prop = icalcomponent_get_next_property(
+			       journal, ICAL_RELATEDTO_PROPERTY)) {
+
+		const char *reltype =
+		    icalproperty_get_parameter_as_string(prop, "RELTYPE");
+		if (reltype && strcasecmp(reltype, "CHILD") == 0) {
+			return true;
+		}
+	}
+	for (icalproperty *prop =
+		 icalcomponent_get_first_property(journal, ICAL_X_PROPERTY);
+	     prop != NULL;
+	     prop = icalcomponent_get_next_property(journal, ICAL_X_PROPERTY)) {
+		LOG("FOUND X PROPERTY");
+
+		const char *prop_name = icalproperty_get_x_name(prop);
+		if (prop_name &&
+		    strcmp(prop_name, IS_DIRECTORY_PROPERTY) == 0) {
+			const char *value =
+			    icalproperty_get_value_as_string(prop);
+			LOG("FOUND DIRECTORY");
+			return value && strcmp(value, "YES") == 0;
+		}
+	}
+	return false;
+}
+
+// Owner: ctx
+icalcomponent *
+parse_ics_file(memory_region *mreg, const char *filename)
+{
+
+	FILE *file = fopen(filename, "r");
+	LOG("filename is %s", filename);
+
+	struct stat st;
+	assert(stat(filename, &st) == 0);
+
+	size_t size = st.st_size;
+	char *buffer = rmalloc(mreg, size + 1);
+
+	size_t bytes_read = fread(buffer, 1, size, file);
+	buffer[bytes_read] = '\0';
+	fclose(file);
+
+	icalcomponent *component = ricalcomponent_new_from_string(mreg, buffer);
+
+	return component;
+}
+
+icaltimetype
+get_ical_now()
+{
+	return icaltime_from_timet_with_zone(time(NULL), 0,
+					     icaltimezone_get_utc_timezone());
+}
+
+size_t
+get_entry_content_size(icalcomponent *component)
+{
+	size_t size =
+	    snprintf(NULL, 0, "%s", icalcomponent_get_description(component));
+
+	assert(size != -1);
+	return size;
+}
+
+char *
+create_new_unique_ics_uid(memory_region *mreg)
+{
+	uuid_t uuid;
+	char uuid_str[37]; // UUIDs are 36 characters + null terminator
+	uuid_generate(uuid);
+	uuid_unparse(uuid, uuid_str);
+	char *res = NULL;
+	size_t wRes = rasprintf(mreg, &res, "%s-caldavfs", uuid_str);
+	assert(wRes != -1);
+
+	return res;
+}
+
+icalcomponent *
+create_vjournal_directory(memory_region *mreg, const char *summary)
+{
+
+	icalcomponent *calendar = icalcomponent_new_vcalendar();
+
+	icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
+	icalcomponent_add_property(calendar,
+				   icalproperty_new_prodid("-//caldavfs//EN"));
+
+	icalcomponent *journal = icalcomponent_new_vjournal();
+	char *id = create_new_unique_ics_uid(mreg);
+
+	icalcomponent_add_property(journal, icalproperty_new_uid(id));
+
+	icalcomponent_add_property(
+	    journal, icalproperty_new_dtstamp(icaltime_current_time_with_zone(
+			 icaltimezone_get_utc_timezone())));
+	icalcomponent_add_property(journal, icalproperty_new_summary(summary));
+
+	icalproperty *is_directory = icalproperty_new_x(IS_DIRECTORY_PROPERTY);
+	icalproperty_set_x_name(is_directory, IS_DIRECTORY_PROPERTY);
+	icalproperty_set_x(is_directory, "YES");
+	icalcomponent_add_property(journal, is_directory);
+
+	icalcomponent_add_component(calendar, journal);
+	return calendar;
+}
+
+icalcomponent *
+create_vjournal_entry(memory_region *mreg, const char *summary)
+{
+
+	icalcomponent *calendar = ricalcomponent_new_vcalendar(mreg);
+
+	icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
+	icalcomponent_add_property(calendar,
+				   icalproperty_new_prodid("-//caldavfs//EN"));
+
+	// Step 2: Create a VJOURNAL entry
+	icalcomponent *journal = icalcomponent_new_vjournal();
+	char *id = create_new_unique_ics_uid(mreg);
+
+	icalcomponent_add_property(journal, icalproperty_new_uid(id));
+	icalcomponent_add_property(journal,
+				   icalproperty_new_class(ICAL_CLASS_PRIVATE));
+
+	icalcomponent_add_property(
+	    journal, icalproperty_new_dtstamp(icaltime_current_time_with_zone(
+			 icaltimezone_get_utc_timezone())));
+	icalcomponent_add_property(journal, icalproperty_new_summary(summary));
+	icalcomponent_add_property(journal, icalproperty_new_description(""));
+
+	icalcomponent_add_component(calendar, journal);
+
+	return calendar;
+}
+
+const char *
+get_parent_uid(icalcomponent *component)
+{
+	icalcomponent *inner =
+	    icalcomponent_get_first_component(component, ICAL_ANY_COMPONENT);
+
+	for (icalproperty *prop = icalcomponent_get_first_property(
+		 inner, ICAL_RELATEDTO_PROPERTY);
+	     prop != NULL; prop = icalcomponent_get_next_property(
+			       inner, ICAL_RELATEDTO_PROPERTY)) {
+		const char *reltype =
+		    icalproperty_get_parameter_as_string(prop, "RELTYPE");
+		if (reltype && strcasecmp(reltype, "PARENT") == 0) {
+			return icalproperty_get_value_as_string(prop);
+		}
+	}
+
+	return NULL;
+}
+
+void
+remove_parent_child_relationship_from_component(icalcomponent *parent,
+						icalcomponent *child)
+{
+
+	const char *parent_uid = icalcomponent_get_uid(parent);
+
+	icalcomponent *inner =
+	    icalcomponent_get_first_component(child, ICAL_ANY_COMPONENT);
+
+	icalproperty *prop =
+	    icalcomponent_get_first_property(inner, ICAL_RELATEDTO_PROPERTY);
+	while (prop != NULL) {
+		icalproperty *next = icalcomponent_get_next_property(
+		    inner, ICAL_RELATEDTO_PROPERTY);
+		const char *value = icalproperty_get_relatedto(prop);
+		icalparameter *reltype = icalproperty_get_first_parameter(
+		    prop, ICAL_RELTYPE_PARAMETER);
+
+		if (value && strcmp(value, parent_uid) == 0 && reltype &&
+		    icalparameter_get_reltype(reltype) == ICAL_RELTYPE_PARENT) {
+			icalcomponent_remove_property(inner, prop);
+			icalproperty_free(prop);
+		}
+
+		prop = next;
+	}
+}
+
+void
+set_parent_child_relationship_to_component(icalcomponent *parent,
+					   icalcomponent *child)
+{
+	icalproperty *child_related_to_parent =
+	    icalproperty_new_relatedto(icalcomponent_get_uid(parent));
+	icalparameter *reltype_child =
+	    icalparameter_new_reltype(ICAL_RELTYPE_PARENT);
+	icalproperty_add_parameter(child_related_to_parent, reltype_child);
+
+	icalcomponent *inner =
+	    icalcomponent_get_first_component(child, ICAL_ANY_COMPONENT);
+	if (inner) {
+		icalcomponent_add_property(inner, child_related_to_parent);
+	}
+}
diff --git a/ical_extra.h b/ical_extra.h
@@ -0,0 +1,51 @@
+#ifndef ical_extra_h_INCLUDED
+#define ical_extra_h_INCLUDED
+#include "libical/ical.h"
+#include "mregion.h"
+#include "sys/stat.h"
+#include "uuid/uuid.h"
+#include <stdbool.h>
+
+icaltimetype
+get_last_modified(icalcomponent *component);
+
+bool
+is_directory_component(icalcomponent *component);
+
+// Owner: ctx
+icalcomponent *
+parse_ics_file(memory_region *mreg, const char *filename);
+
+icaltimetype
+get_ical_now();
+
+size_t
+get_entry_content_size(icalcomponent *component);
+
+char *
+create_new_unique_ics_uid(memory_region *mreg);
+
+icalcomponent *
+create_vjournal_directory(memory_region *mreg, const char *summary);
+
+icalcomponent *
+create_vjournal_entry(memory_region *mreg, const char *summary);
+
+const char *
+get_parent_uid(icalcomponent *component);
+
+void
+remove_parent_child_relationship_from_component(icalcomponent *parent,
+						icalcomponent *child);
+
+void
+set_parent_child_relationship_to_component(icalcomponent *parent,
+					   icalcomponent *child);
+
+const icalproperty_class
+parse_ical_class(const char *input);
+
+const char *
+format_ical_class(const enum icalproperty_class iclass);
+
+#endif // ical_extra_h_INCLUDED
diff --git a/main.c b/main.c
@@ -1,8 +1,9 @@
-#include "fuse3/fuse_opt.h"
 #define FUSE_USE_VERSION 31
 
 #include "agenda_entry.h"
+#include "fuse3/fuse_opt.h"
 #include "hashmap.h"
+#include "ical_extra.h"
 #include "mregion.h"
 #include "tree.h"
 #include "util.h"
@@ -30,7 +31,7 @@
 static pthread_mutex_t entries_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static int
-agenda_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
+fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 {
 	LOG("STAT %s", path);
 
@@ -100,7 +101,7 @@ cleanup_return:
 }
 
 static int
-agenda_readlink(const char *path, char *buf, size_t size)
+fuse_readlink(const char *path, char *buf, size_t size)
 {
 	// TODO: Implement
 	LOG("READLINK path: %s", path);
@@ -108,9 +109,8 @@ agenda_readlink(const char *path, char *buf, size_t size)
 }
 
 static int
-agenda_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-	       off_t offset, struct fuse_file_info *fi,
-	       enum fuse_readdir_flags flags)
+fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
+	     struct fuse_file_info *fi, enum fuse_readdir_flags flags)
 {
 
 	LOG("READDIR %s", path);
@@ -144,7 +144,11 @@ agenda_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 			st.st_mode = S_IFDIR | 0755;
 		}
 
-		filler(buf, get_node_filename(mreg, child), &st, 0, 0);
+		if (filler(buf, get_node_filename(mreg, child), &st, 0, 0) !=
+		    0) {
+			status = -ENOMEM;
+			goto cleanup_return;
+		}
 	}
 
 cleanup_return:
@@ -154,28 +158,34 @@ cleanup_return:
 }
 
 static int
-agenda_open(const char *path, struct fuse_file_info *fi)
+fuse_open(const char *path, struct fuse_file_info *fi)
 {
+	LOG("OPEN %s", path);
+
 	memory_region *mreg = create_region();
 	pthread_mutex_lock(&entries_mutex);
+	int status = 0;
 
-	LOG("Opening journal for %s", path);
 	const struct tree_node *node = get_node_by_path(mreg, path);
+	if (!node) {
+		status = -ENOENT;
+	}
 
 	pthread_mutex_unlock(&entries_mutex);
 	rfree_all(mreg);
-	return node ? 0 : -ENOENT;
+
+	return status;
 }
 
 static int
-agenda_mkdir(const char *path, mode_t mode)
+fuse_mkdir(const char *path, mode_t mode)
 {
+	LOG("MKDIR %s", path);
 
 	memory_region *mreg = create_region();
 	pthread_mutex_lock(&entries_mutex);
 	int status = 0;
 
-	LOG("MKDIR %s", path);
 	status = create_directory_from_fuse_path(mreg, path);
 
 	pthread_mutex_unlock(&entries_mutex);
@@ -184,10 +194,10 @@ agenda_mkdir(const char *path, mode_t mode)
 }
 
 static int
-agenda_read(const char *path, char *buf, size_t size, off_t offset,
-	    struct fuse_file_info *fi)
+fuse_read(const char *path, char *buf, size_t size, off_t offset,
+	  struct fuse_file_info *fi)
 {
-	LOG("READ on path %s", path);
+	LOG("READ %s", path);
 
 	memory_region *mreg = create_region();
 	pthread_mutex_lock(&entries_mutex);
@@ -205,8 +215,7 @@ agenda_read(const char *path, char *buf, size_t size, off_t offset,
 	}
 
 	// We now treat description as the full content
-	const char *content = description;
-	size_t content_len = strlen(content);
+	size_t content_len = strlen(description);
 
 	if (offset >= content_len) {
 		ret_code = 0;
@@ -214,12 +223,11 @@ agenda_read(const char *path, char *buf, size_t size, off_t offset,
 	}
 
 	if (offset + size > content_len) {
-		LOG("Size is set");
 		size = content_len - offset;
 	}
 
 	if (size > 0) {
-		memcpy(buf, content + offset, size);
+		memcpy(buf, description + offset, size);
 	}
 
 	ret_code = size;
@@ -231,8 +239,8 @@ cleanup_return:
 }
 
 static int
-agenda_write(const char *path, const char *buf, size_t size, off_t offset,
-	     struct fuse_file_info *fi)
+fuse_write(const char *path, const char *buf, size_t size, off_t offset,
+	   struct fuse_file_info *fi)
 {
 
 	LOG("WRITE %s, %zu, %zu", buf, size, offset);
@@ -266,7 +274,7 @@ cleanup_return:
 
 // Aka remove or delete
 static int
-agenda_unlink(const char *file)
+fuse_unlink(const char *file)
 {
 	LOG("DELETE %s", file);
 
@@ -282,7 +290,7 @@ agenda_unlink(const char *file)
 }
 
 static int
-agenda_rmdir(const char *file)
+fuse_rmdir(const char *file)
 {
 	LOG("DELETE %s", file);
 
@@ -298,7 +306,7 @@ agenda_rmdir(const char *file)
 }
 
 static int
-agenda_rename(const char *old, const char *new, unsigned int flags)
+fuse_rename(const char *old, const char *new, unsigned int flags)
 {
 
 	memory_region *mreg = create_region();
@@ -313,7 +321,7 @@ agenda_rename(const char *old, const char *new, unsigned int flags)
 }
 
 static int
-agenda_create(const char *filename, mode_t mode, struct fuse_file_info *info)
+fuse_create(const char *filename, mode_t mode, struct fuse_file_info *info)
 {
 
 	memory_region *mreg = create_region();
@@ -329,7 +337,7 @@ agenda_create(const char *filename, mode_t mode, struct fuse_file_info *info)
 }
 
 static int
-agenda_removexattr(const char *path, const char *header)
+fuse_removexattr(const char *path, const char *header)
 {
 	LOG("REMOVEXATTR '%s' '%s'", path, header);
 	memory_region *mreg = create_region();
@@ -364,8 +372,8 @@ cleanup_return:
 }
 
 static int
-agenda_setxattr(const char *path, const char *header,
-		const char *new_attributes, size_t s, int flags)
+fuse_setxattr(const char *path, const char *header, const char *new_attributes,
+	      size_t s, int flags)
 {
 	LOG("SETXATTR '%s' '%s' '%zu' '%s' '%d'", path, header, s,
 	    new_attributes, flags);
@@ -412,7 +420,7 @@ cleanup_return:
 }
 
 static int
-agenda_listxattr(const char *path, char *list, size_t size)
+fuse_listxattr(const char *path, char *list, size_t size)
 {
 	LOG("LISTXATTR %s %zu", list, size);
 	memory_region *mreg = create_region();
@@ -472,7 +480,7 @@ cleanup_return:
 }
 
 static int
-agenda_getxattr(const char *path, const char *header, char *buf, size_t s)
+fuse_getxattr(const char *path, const char *header, char *buf, size_t s)
 {
 	LOG("GETXATTR '%s' '%s' '%zu'\n", path, header, s);
 	pthread_mutex_lock(&entries_mutex);
@@ -602,28 +610,28 @@ watch_vdir_changes(void *arg)
 
 // Ignore for now
 static int
-agenda_utimens(const char *path, const struct timespec tv[2],
-	       struct fuse_file_info *info)
+fuse_utimens(const char *path, const struct timespec tv[2],
+	     struct fuse_file_info *info)
 {
 	return 0;
 }
 
-struct fuse_operations agenda_oper = {.getattr = agenda_getattr,
-				      .readdir = agenda_readdir,
-				      .open = agenda_open,
-				      .read = agenda_read,
-				      .utimens = agenda_utimens,
-				      .write = agenda_write,
-				      .create = agenda_create,
-				      .mkdir = agenda_mkdir,
-				      .unlink = agenda_unlink,
-				      .getxattr = agenda_getxattr,
-				      .setxattr = agenda_setxattr,
-				      .listxattr = agenda_listxattr,
-				      .removexattr = agenda_removexattr,
-				      .rmdir = agenda_rmdir,
-				      .readlink = agenda_readlink,
-				      .rename = agenda_rename};
+struct fuse_operations fuse_oper = {.getattr = fuse_getattr,
+				    .readdir = fuse_readdir,
+				    .open = fuse_open,
+				    .read = fuse_read,
+				    .utimens = fuse_utimens,
+				    .write = fuse_write,
+				    .create = fuse_create,
+				    .mkdir = fuse_mkdir,
+				    .unlink = fuse_unlink,
+				    .getxattr = fuse_getxattr,
+				    .setxattr = fuse_setxattr,
+				    .listxattr = fuse_listxattr,
+				    .removexattr = fuse_removexattr,
+				    .rmdir = fuse_rmdir,
+				    .readlink = fuse_readlink,
+				    .rename = fuse_rename};
 
 struct agendafs_config {
 	char *ics_directory;
@@ -653,13 +661,13 @@ agendafs_opt_proc(void *data, const char *arg, int key,
 			"    -o vdir=STRING\n",
 			outargs->argv[0]);
 		fuse_opt_add_arg(outargs, "-h");
-		fuse_main(outargs->argc, outargs->argv, &agenda_oper, NULL);
+		fuse_main(outargs->argc, outargs->argv, &fuse_oper, NULL);
 		exit(1);
 
 	case KEY_VERSION:
 		fprintf(stderr, "agendafs version %s\n", "v0.01 ALPHA");
 		fuse_opt_add_arg(outargs, "--version");
-		fuse_main(outargs->argc, outargs->argv, &agenda_oper, NULL);
+		fuse_main(outargs->argc, outargs->argv, &fuse_oper, NULL);
 		exit(0);
 	}
 	return 1;
@@ -685,10 +693,14 @@ main(int argc, char *argv[])
 			"    -o vdir=STRING\n",
 			argv[0]);
 		fuse_opt_add_arg(&args, "-h");
-		fuse_main(args.argc, args.argv, &agenda_oper, NULL);
+		fuse_main(args.argc, args.argv, &fuse_oper, NULL);
 		exit(1);
 	}
 
+#ifdef DEBUG
+	fuse_opt_add_arg(&args, "-f");
+#endif
+
 	if (load_agendafs_environment(conf.ics_directory) != 0) {
 		fprintf(stderr, "Failed to load ICS directory\n");
 		exit(1);
@@ -703,7 +715,7 @@ main(int argc, char *argv[])
 	}
 
 	load_root_node_tree();
-	int ret = fuse_main(args.argc, args.argv, &agenda_oper, NULL);
+	int ret = fuse_main(args.argc, args.argv, &fuse_oper, NULL);
 	LOG("Cleaning up");
 
 	pthread_cancel(watcher_thread);
diff --git a/util.h b/util.h
@@ -3,8 +3,12 @@
 
 #include <stdlib.h>
 
+#ifdef DEBUG
 #define LOG(fmt, ...)                                                          \
 	fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define LOG(fmt, ...)
+#endif
 
 void *
 reallocarray(void *, size_t, size_t);