commit e75cbc27e901841a9297ce4eed3100b9668e797d
parent bca4f026e08975ee6c0a9ae1bdcd81f021b1a6bc
Author: Andreas Gruhler <agruhl@gmx.ch>
Date: Wed, 16 Jun 2021 23:29:32 +0200
fold TEXT
Diffstat:
M | src/caldav.c | | | 61 | +++++++++++++++++++++++++++++++++++++++---------------------- |
M | src/utils.c | | | 162 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
2 files changed, 170 insertions(+), 53 deletions(-)
diff --git a/src/caldav.c b/src/caldav.c
@@ -121,6 +121,9 @@ char* read_tokenfile() {
fprintf(stderr, "Access token: %s\n", access_token);
fprintf(stderr, "Token TTL: %i\n", token_ttl);
fprintf(stderr, "Refresh token: %s\n", refresh_token);
+ } else {
+ perror("malloc failed");
+ return NULL;
}
fclose(token_file);
return token_buf;
@@ -395,6 +398,10 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
// https://curl.se/libcurl/c/getinmemory.html
struct curl_mem_chunk caldav_resp;
caldav_resp.memory = malloc(1);
+ if (caldav_resp.memory == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
caldav_resp.size = 0;
if (curl) {
@@ -426,11 +433,11 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
curl_easy_cleanup(curl);
- //fprintf(stderr, "Curl retrieved %lu bytes\n", (unsigned long)caldav_resp.size);
- //fprintf(stderr, "Curl content: %s\n", caldav_resp.memory);
+ fprintf(stderr, "Curl retrieved %lu bytes\n", (unsigned long)caldav_resp.size);
+ fprintf(stderr, "Curl content: %s\n", caldav_resp.memory);
if (res != CURLE_OK) {
- //fprintf(stderr, "Curl response: %s\n", caldav_resp.memory);
+ fprintf(stderr, "Curl response: %s\n", caldav_resp.memory);
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return NULL;
}
@@ -447,7 +454,7 @@ char* parse_caldav_current_user_principal(char* xml) {
return NULL;
}
- //fprintf(stderr, "Found current-user-principal at position: %i\n", *xml_key_pos);
+ fprintf(stderr, "Found current-user-principal at position: %i\n", *xml_key_pos);
//<D:current-user-principal>
//<D:href>/caldav/v2/diary.in0rdr%40gmail.com/user</D:href>
@@ -489,12 +496,12 @@ char* parse_caldav_calendar(char* xml, char* calendar) {
*displayname_pos= '\0';
char* href = strrstr(xml, "<D:href>");
if (href != NULL) {
- //fprintf(stderr, "Found calendar href: %s\n", href);
+ fprintf(stderr, "Found calendar href: %s\n", href);
href = strtok(href, "<"); // :href>/caldav/v2/aaa%40group.calendar.google.com/events/
if (href != NULL) {
href = strchr(href, '>');
href++; // cut >
- //fprintf(stderr, "Found calendar href: %s\n", href);
+ fprintf(stderr, "Found calendar href: %s\n", href);
}
return href;
}
@@ -521,15 +528,28 @@ void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar
descr_bytes = ftell(fp);
rewind(fp);
- descr = malloc(descr_bytes);
- if (descr == NULL) perror("Error allocating space for description");
+ size_t descr_labell = strlen("DESCRIPTION:");
+ size_t descrl = descr_bytes + descr_labell;
+ descr = malloc(descrl);
+ if (descr == NULL) {
+ perror("malloc failed");
+ return;
+ }
+
+ descr[0] = '\0';
+ strcat(descr, "DESCRIPTION:");
- fread(descr, sizeof(char), descr_bytes, fp);
- descr[descr_bytes] = '\0';
+ int items_read = fread(descr + descr_labell, sizeof(char), descr_bytes, fp);
+ if (items_read != descr_bytes) {
+ fprintf(stderr, "Read %i items but expected %li, aborting.", items_read, descr_bytes);
+ return;
+ }
+
+ descr[descrl] = '\0';
fprintf(stderr, "File buffer that will be uploaded to the remote CalDAV server:\n%s\n", descr);
char* folded_descr = fold(descr);
- fprintf(stderr, "Folded descr:\n%s\n", folded_descr);
+ fprintf(stderr, "Folded descr:%s\n", folded_descr);
char uid[9];
strftime(uid, sizeof uid, "%Y%m%d", date);
@@ -539,7 +559,7 @@ void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar
"UID:%s\n"
"DTSTART;VALUE=DATE:%s\n"
"SUMMARY:%s\n"
- "DESCRIPTION:%s\n"
+ "%s\n"
"END:VEVENT\n"
"END:VCALENDAR";
char postfields[strlen(ics) + strlen(folded_descr) + 100];
@@ -547,7 +567,7 @@ void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar
uid,
uid,
uid, // todo: display first few chars of DESCRIPTION as SUMMARY
- folded_descr); //todo: fold multiline descriptions
+ folded_descr);
fprintf(stderr, "PUT event postfields:\n%s\n", postfields);
@@ -661,7 +681,7 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
sprintf(uri, "%s%s", GOOGLE_API_URI, user_principal);
fprintf(stderr, "\nHome Set URI: %s\n", uri);
char* home_set = caldav_req(date, uri, "PROPFIND", "", 1);
- //fprintf(stderr, "\nHome Set: %s\n", home_set);
+ fprintf(stderr, "\nHome Set: %s\n", home_set);
// get calendar URI from the home-set
char* calendar_href = parse_caldav_calendar(home_set, CONFIG.google_calendar);
@@ -720,9 +740,9 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
fprintf(stderr, "Local dst: %i\n", localfile_time->tm_isdst);
//local_time->tm_isdst = -1;
time_t localfile_date = mktime(localfile_time);
- //fprintf(stderr, "Local dst: %i\n", localfile_time->tm_isdst);
+ fprintf(stderr, "Local dst: %i\n", localfile_time->tm_isdst);
fprintf(stderr, "Local file last modified time: %s\n", ctime(&localfile_date));
- //fprintf(stderr, "Local file last modified time: %s\n", ctime(&attr.st_mtime));
+ fprintf(stderr, "Local file last modified time: %s\n", ctime(&attr.st_mtime));
struct tm remote_datetime;
time_t remote_date;
@@ -737,7 +757,7 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
} else {
strptime(remote_last_mod, "%Y%m%dT%H%M%SZ", &remote_datetime);
//remote_datetime.tm_isdst = -1;
- //fprintf(stderr, "Remote dst: %i\n", remote_datetime.tm_isdst);
+ fprintf(stderr, "Remote dst: %i\n", remote_datetime.tm_isdst);
remote_date = mktime(&remote_datetime);
fprintf(stderr, "Remote dst: %i\n", remote_datetime.tm_isdst);
fprintf(stderr, "Remote last modified: %s\n", ctime(&remote_date));
@@ -750,9 +770,6 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
return;
}
- // TODO: check SEQUENCE:24 ?
- // update sequence on upload
-
double timediff = difftime(localfile_date, remote_date);
fprintf(stderr, "Time diff between local and remote mod time:%e\n", timediff);
@@ -768,7 +785,7 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
caldav_req(date, event_uri, "DELETE", "", 0);
}
- fprintf(stderr, "Local file is newer, uploading to remote...\n");
+ fputs("Local file is newer, uploading to remote...\n", stderr);
put_event(date, dir, dir_size, uri);
pthread_cancel(progress_tid);
@@ -784,7 +801,7 @@ void caldav_sync(struct tm* date, WINDOW* header, WINDOW* cal, int pad_pos, cons
fprintf(stderr, "Remote event description:%s\n", rmt_desc);
if (rmt_desc == NULL) {
- fprintf(stderr, "Failed to fetch description of remote event. Might be empty.\n");
+ fprintf(stderr, "Could not fetch description of remote event.\n");
pthread_cancel(progress_tid);
wclear(header);
return;
diff --git a/src/utils.c b/src/utils.c
@@ -15,7 +15,11 @@ void update_date(WINDOW* header, struct tm* curs_date) {
char* extract_json_value(const char* json, char* key, bool quoted) {
// work on a copy of the json
- char* jsoncp = (char*) malloc(strlen(json) * sizeof(char));
+ char* jsoncp = (char*) malloc(strlen(json) * sizeof(char) + 1);
+ if (jsoncp == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(jsoncp, json);
char* tok = strtok(jsoncp, " ");
@@ -37,7 +41,11 @@ char* extract_json_value(const char* json, char* key, bool quoted) {
char* res = NULL;
if (tok != NULL) {
- res = (char*) malloc(strlen(tok) * sizeof(char));
+ res = (char*) malloc(strlen(tok) * sizeof(char) + 1);
+ if (res == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(res, tok);
}
@@ -47,49 +55,128 @@ char* extract_json_value(const char* json, char* key, bool quoted) {
char* fold(const char* str) {
// work on a copy of the str
- int strl = strlen(str);
- char* strcp = (char *) malloc(strl * sizeof(char));
+ char* strcp = (char *) malloc(strlen(str) * sizeof(char) + 1);
+ if (strcp == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(strcp, str);
- if (strlen(strcp) <= 75) return strcp;
-
+ // create buffer for escaped result TEXT
char* buf = malloc(1);
- buf = '\0';
- size_t bufl = 0;
-
- // break lines after 75 chars
- for (char* i = strcp; i-strcp < strl; i += 75) {
- // split between any two characters by inserting a CRLF
- // immediately followed by a white space character
- fprintf(stderr, "next size: %li\n", bufl + 77);
- fprintf(stderr, "buf: %s\n", buf);
- buf = realloc(buf, bufl + 77);
- if (buf == NULL) {
+ if (buf == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
+ buf[0] = '\0';
+
+ void* newbuf;
+ // bufl is the current buffer size incl. \0
+ int bufl = 1;
+ // i is the iterator in strcp
+ char* i = strcp;
+ // escch is the char to be escaped,
+ // only written when esc=true
+ char escch;
+ bool esc = false;
+
+ while(*i != '\0' || esc) {
+ fprintf(stderr, "strlen(buf): %i\n", bufl);
+ fprintf(stderr, "*i: %c\n", *i);
+ fprintf(stderr, "escch: %c\n", escch);
+ fprintf(stderr, "esc: %i\n", esc);
+ fprintf(stderr, "buffer: %s\n\n", buf);
+
+ newbuf = realloc(buf, ++bufl);
+ if (newbuf == NULL) {
perror("realloc failed");
- return buf;
+ free(buf);
+ return NULL;
+ }
+ buf = (char*) newbuf;
+
+ if ((bufl > 1) && ((bufl % 77) == 0)) {
+ // break lines after 75 chars
+ // split between any two characters by inserting a CRLF
+ // immediately followed by a white space character
+ buf[bufl-2] = '\n';
+ escch = ' ';
+ esc = true;
+ continue;
+ }
+
+ if (esc) {
+ // only escape char, do not advance iterator i
+ buf[bufl-2] = escch;
+ esc = false;
+ } else {
+ // escape characters
+ // https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.11
+ switch (*i) {
+ case 0x5c: // backslash
+ buf[bufl-2] = 0x5c;
+ escch = 0x5c;
+ esc = true;
+ break;
+ case ';':
+ buf[bufl-2] = 0x5c;
+ escch = ';';
+ esc = true;
+ break;
+ case ',':
+ buf[bufl-2] = 0x5c;
+ escch = ',';
+ esc = true;
+ break;
+ case '\n':
+ buf[bufl-2] = 0x5c;
+ escch = 'n';
+ esc = true;
+ break;
+ default:
+ // write regular character from strcp
+ buf[bufl-2] = *i;
+ break;
+ }
+ i++;
}
- strncat(buf, i, 75);
- buf[i - strcp] = '\n';
- buf[i - strcp + 1] = ' ';
- bufl = strlen(buf);
+
+ // terminate the char string in any case (esc or not)
+ buf[bufl-1] = '\0';
}
+ fprintf(stderr, "escch: %c\n", escch);
+ fprintf(stderr, "end: %c\n", buf[bufl]);
+
free(strcp);
return buf;
}
char* unfold(const char* str) {
- if (strcmp(str, "\n")) return NULL;
+ fprintf(stderr, "Before unfolding: %s\n", str);
+ //if (strcmp(str, "")) {
+ // fputs("Unfold string is empty.\n", stderr);
+ // return NULL;
+ //}
// work on a copy of the str
- char* strcp = (char *) malloc(strlen(str) * sizeof(char));
+ char* strcp = (char *) malloc(strlen(str) * sizeof(char) + 1);
+ if (strcp == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(strcp, str);
char* res = strtok(strcp, "\n");
- char* buf = malloc(strlen(res));
+ char* buf = malloc(strlen(res) + 1);
+ if (buf == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(buf, res);
+ char* newbuf;
regex_t re;
regmatch_t pm[1];
@@ -107,12 +194,14 @@ char* unfold(const char* str) {
break;
}
- buf = realloc(buf, strlen(buf) + strlen(res));
- if (buf != NULL) {
- strcat(buf, res + 1);
- } else {
+ newbuf = realloc(buf, strlen(buf) + strlen(res) + 1);
+ if (buf == NULL) {
perror("realloc failed");
+ free(buf);
return NULL;
+ } else {
+ buf = newbuf;
+ strcat(buf, res + 1);
}
}
@@ -134,7 +223,11 @@ char* extract_ical_field(const char* ics, char* key, bool multiline) {
}
// work on a copy of the ical xml response
- char* icscp= (char *) malloc(strlen(ics) * sizeof(char));
+ char* icscp = (char *) malloc(strlen(ics) * sizeof(char) + 1);
+ if (icscp == NULL) {
+ perror("malloc failed");
+ return NULL;
+ }
strcpy(icscp, ics);
// tokenize ical by newlines
@@ -145,7 +238,13 @@ char* extract_ical_field(const char* ics, char* key, bool multiline) {
res = strstr(res, ":"); // value
res++; // strip the ":"
- if (multiline) {
+ fprintf(stderr, "Extracted ical result value: %s\n", res);
+ fprintf(stderr, "Extracted ical result size: %li\n", strlen(res));
+
+ if (strlen(res) == 0) {
+ // empty remote description
+ res = NULL;
+ } else if (multiline) {
res = unfold(ics + (res - icscp));
}
break;
@@ -153,6 +252,7 @@ char* extract_ical_field(const char* ics, char* key, bool multiline) {
// key not in this line, advance line
res = strtok(NULL, "\n");
}
+ fprintf(stderr, "Sizeof ics: %li\n", strlen(ics));
free(icscp);
return res;