agendafs

A filesystem for your calendar.

git clone git://mccd.space/agendafs
commit cca40f2c0bba3c84fb88b5c5dfe8562321e0ebc5
parent 40c4af71c6ca4926fc7da0b37030ea58f5f6f961
Author: Marc Coquand <marc@coquand.email>
Date:   Tue,  3 Jun 2025 11:23:29 +0100

Fix time bug

Diffstat:
Mmain.c | 85+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 44 insertions(+), 41 deletions(-)
diff --git a/main.c b/main.c
@@ -31,6 +31,8 @@ regex_t regex_dtstamp, regex_lastmod, regex_fuse_file;
 
 time_t INVALID_TIME = (time_t)-1;
 
+icaltimezone *local_ical_time;
+
 #define ENOTJOURNAL 1001
 
 typedef struct {
@@ -232,19 +234,6 @@ get_entry_from_fuse_path(const char *path)
 	return entry;
 }
 
-time_t
-icaltime_to_time_t(icaltimetype tt)
-{
-	struct tm t = {.tm_year = tt.year - 1900,
-		       .tm_mon = tt.month - 1,
-		       .tm_mday = tt.day,
-		       .tm_hour = tt.hour,
-		       .tm_min = tt.minute,
-		       .tm_sec = tt.second,
-		       .tm_isdst = -1};
-	return mktime(&t);
-}
-
 char *
 read_stream(char *s, size_t size, void *d)
 {
@@ -293,20 +282,16 @@ parse_ics_to_journal_entry(const char *filename, journal_entry *entry)
 	return 0;
 }
 
-// Dynamically create a time string using format
 char *
 time_string(icaltimetype t, const char *format)
 {
-	time_t time_val = icaltime_to_time_t(t);
-	struct tm tm_info;
-	if (!localtime_r(&time_val, &tm_info)) {
-		return NULL;
-	}
 
-	size_t buf_size = 64;
-	char *buffer = xmalloc(buf_size);
+	char *buffer = xmalloc(64);
+	time_t tme = icaltime_as_timet(t);
+	struct tm tm_info;
+	localtime_r(&tme, &tm_info);
 
-	strftime(buffer, buf_size, format, &tm_info);
+	strftime(buffer, 64, format, &tm_info);
 	return buffer;
 }
 
@@ -503,7 +488,7 @@ journal_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
 	if (last_modified_prop) {
 		icaltimetype ical_lastmodified =
 		    icalproperty_get_lastmodified(last_modified_prop);
-		lastmodified = icaltime_to_time_t(ical_lastmodified);
+		lastmodified = icaltime_as_timet(ical_lastmodified);
 	}
 	else {
 		lastmodified = time(NULL);
@@ -569,12 +554,20 @@ journal_read(const char *path, char *buf, size_t size, off_t offset,
 		goto unlock_and_return;
 	}
 
+	const char *summary = icalcomponent_get_summary(entry->component);
+	if (summary == NULL) {
+		summary = "";
+	}
+	const char *description =
+	    icalcomponent_get_description(entry->component);
+	if (description == NULL) {
+		description = "";
+	}
+
 	// Calculate required length for full content
 	char *full_content = NULL;
 	size_t needed_len =
-	    asprintf(&full_content, "%s\n---\n%s",
-		     icalcomponent_get_summary(entry->component),
-		     icalcomponent_get_description(entry->component));
+	    asprintf(&full_content, "%s\n---\n%s", summary, description);
 	if (needed_len == -1) {
 		LOG("Out of memory");
 		exit(1);
@@ -601,6 +594,14 @@ unlock_and_return:
 	return ret_code;
 }
 
+icaltimetype
+get_now()
+{
+	struct icaltimetype now_tt = icaltime_from_timet_with_zone(
+	    time(NULL), 0, icaltimezone_get_utc_timezone());
+	return now_tt;
+}
+
 size_t
 parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 {
@@ -624,19 +625,6 @@ parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 		return -EINVAL;
 	}
 
-	icalproperty *prop = icalcomponent_get_first_property(
-	    entry->component, ICAL_LASTMODIFIED_PROPERTY);
-	if (!prop) {
-		prop = icalproperty_new_lastmodified(icaltime_null_time());
-		icalcomponent_add_property(entry->component, prop);
-	}
-	else {
-		time_t now = time(NULL);
-		struct icaltimetype now_tt =
-		    icaltime_from_timet_with_zone(now, 0, NULL);
-		icalproperty_set_lastmodified(prop, now_tt);
-	}
-
 	icalcomponent_set_summary(entry->component, summary);
 	icalcomponent_set_description(entry->component, description);
 	free(copy);
@@ -646,6 +634,17 @@ parse_entry_content(journal_entry *entry, const char *buf, size_t size)
 size_t
 write_entry_to_ical_file(const journal_entry *entry, const char *filepath)
 {
+	// Always set last modified to the time we write
+	icalproperty *prop = icalcomponent_get_first_property(
+	    entry->component, ICAL_LASTMODIFIED_PROPERTY);
+	if (!prop) {
+		prop = icalproperty_new_lastmodified(get_now());
+		icalcomponent_add_property(entry->component, prop);
+	}
+	else {
+		icalproperty_set_lastmodified(prop, get_now());
+	}
+
 	char *ical_str = icalcomponent_as_ical_string_r(entry->component);
 
 	FILE *f = fopen(filepath, "w");
@@ -769,8 +768,8 @@ do_journal_entry_rename(time_t new_created_at, const char *old, const char *new)
 	journal_entry *new_entry = copy_journal_entry(old_entry);
 	free(new_entry->filename);
 	new_entry->filename = strdup(new_basename);
-	struct icaltimetype created_at_ical =
-	    icaltime_from_timet_with_zone(new_created_at, 0, NULL);
+	struct icaltimetype created_at_ical = icaltime_from_timet_with_zone(
+	    new_created_at, 0, icaltimezone_get_utc_timezone());
 
 	icalcomponent_set_dtstamp(new_entry->component, created_at_ical);
 
@@ -1092,6 +1091,10 @@ main(int argc, char *argv[])
 {
 	pthread_t watcher_thread;
 
+	tzset();
+	const char *tzid = getenv("TZ");
+	local_ical_time = icaltimezone_get_builtin_timezone(tzid);
+
 	if (load_caldavfs_environment() != 0) {
 		fprintf(stderr, "Failed to load ICS directory\n");
 		exit(1);