commit 33495a785319543c1036da68d781ea31e705ef9e
parent 480e24766f4d10b6fd73d23e2aa0c10c4ae64729
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date: Sun, 12 Nov 2023 17:06:37 +0100
draft: caldav server with basicauth
Diffstat:
6 files changed, 87 insertions(+), 44 deletions(-)
diff --git a/config/diary.cfg b/config/diary.cfg
@@ -14,10 +14,17 @@ fmt_cmd =
#no_mouse = false
# Editor to open journal files with
editor =
-# Google calendar name for CalDAV sync
-#google_calendar =
+# CalDAV server URI
+# For example, Google calendar URI: "https://apidata.googleusercontent.com/caldav/v2"
+#caldav_server =
+# Calendar name for CalDAV sync
+#caldav_calendar =
# Google OAuth2 clientid and secretid
#google_clientid =
#google_secretid =
# Google OAuth2 tokenfile
#google_tokenfile = ~/.diary-token
+# CalDAV server username
+#caldav_username =
+# CalDAV server password
+#caldav_password =
diff --git a/src/caldav.c b/src/caldav.c
@@ -407,7 +407,7 @@ char* get_oauth_code(const char* verifier, WINDOW* header) {
}
/* Make a CalDAV request */
-char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields, int depth) {
+char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields, int depth, bool basicauth) {
// only support depths 0 or 1
if (depth < 0 || depth > 1) {
return NULL;
@@ -435,6 +435,13 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_mem_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&caldav_resp);
+ // default to basic auth when Google credentials are not set
+ if (basicauth) {
+ char basicauth [strlen(CONFIG.caldav_username) + strlen(CONFIG.caldav_username) + 1];
+ sprintf(basicauth, "%s:%s", CONFIG.caldav_username, CONFIG.caldav_password);
+ curl_easy_setopt(curl, CURLOPT_USERPWD, basicauth);
+ }
+
// construct header fields
struct curl_slist *header = NULL;
char bearer_token[strlen("Authorization: Bearer ") + strlen(access_token) + 1];
@@ -525,7 +532,7 @@ char* parse_caldav_calendar(char* xml, char* calendar) {
}
/* Upload event to CalDAV server */
-void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar_uri) {
+void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar_uri, bool basicauth) {
// get entry path
char path[100];
char* ppath = path;
@@ -584,7 +591,7 @@ void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar
strcat(calendar_uri, uid);
strcat(calendar_uri, ".ics");
- char* response = caldav_req(date, calendar_uri, "PUT", postfields, 0);
+ char* response = caldav_req(date, calendar_uri, "PUT", postfields, 0, basicauth);
fclose(fp);
free(folded_descr);
free(descr);
@@ -614,10 +621,17 @@ int caldav_sync(struct tm* date,
char* info_txt;
- if (strcmp(CONFIG.google_clientid, "") == 0 || strcmp(CONFIG.google_secretid, "") == 0 || strcmp(CONFIG.google_calendar, "") == 0 ) {
+ bool google_oath_enabled = !(strcmp(CONFIG.google_clientid, "") == 0 || strcmp(CONFIG.google_clientid, "") == 0);
+ bool basicauth_enabled = !(strcmp(CONFIG.caldav_username, "") == 0 || strcmp(CONFIG.caldav_password, "") == 0);
+
+ if (strcmp(CONFIG.caldav_server, "") == 0 || strcmp(CONFIG.caldav_calendar, "") == 0 || !(google_oath_enabled && basicauth_enabled)) {
+ tracepoint(diary, debug_string, "CONFIG.caldav_server", CONFIG.caldav_server);
+ tracepoint(diary, debug_string, "CONFIG.caldav_calendar", CONFIG.caldav_calendar);
+ tracepoint(diary, debug_string, "CONFIG.caldav_username", CONFIG.caldav_username);
+ tracepoint(diary, debug_string, "CONFIG.caldav_password", CONFIG.caldav_password);
wclear(header);
wresize(header, LINES, getmaxx(header));
- info_txt = "Missing sync parameters. Set Google Client ID, secret and remote calendar name.\n"
+ info_txt = "Missing sync parameters. Configure CalDAV server and credentials.\n"
"Press any key to continue.";
mvwaddstr(header, 0, 0, info_txt);
wrefresh(header);
@@ -629,27 +643,29 @@ int caldav_sync(struct tm* date,
wclear(header);
}
- // fetch existing API tokens from file
- char* tokfile = read_tokenfile();
- free(tokfile);
+ if (google_oath_enabled) {
+ // fetch existing API tokens from file
+ char* tokfile = read_tokenfile();
+ free(tokfile);
- if (strcmp(access_token, "") == 0) {
- // no access token exists yet, create new verifier
- char challenge[GOOGLE_OAUTH_CODE_VERIFIER_LENGTH + 1];
- random_code_challenge(GOOGLE_OAUTH_CODE_VERIFIER_LENGTH, challenge);
+ if (strcmp(access_token, "") == 0) {
+ // no access token exists yet, create new verifier
+ char challenge[GOOGLE_OAUTH_CODE_VERIFIER_LENGTH + 1];
+ random_code_challenge(GOOGLE_OAUTH_CODE_VERIFIER_LENGTH, challenge);
- // fetch new code with verifier
- char* code = get_oauth_code(challenge, header);
- if (code == NULL) {
- tracepoint(diary, error, "Error retrieving oauth code in caldav_sync()");
- return -1;
- }
+ // fetch new code with verifier
+ char* code = get_oauth_code(challenge, header);
+ if (code == NULL) {
+ tracepoint(diary, error, "Error retrieving oauth code in caldav_sync()");
+ return -1;
+ }
- // get acess token using code and verifier
- tracepoint(diary, debug, "Fetching access token with code challenge");
- get_access_token(code, challenge, false);
+ // get acess token using code and verifier
+ tracepoint(diary, debug, "Fetching access token with code challenge");
+ get_access_token(code, challenge, false);
- free(code);
+ free(code);
+ }
}
pthread_create(&progress_tid, NULL, show_progress, (void*)header);
@@ -661,22 +677,25 @@ int caldav_sync(struct tm* date,
// check if we can use the token from the tokenfile
- char* user_principal = caldav_req(date, GOOGLE_CALDAV_URI, "PROPFIND", principal_postfields, 0);
+ char* user_principal = caldav_req(date, CONFIG.caldav_server, "PROPFIND", principal_postfields, 0, basicauth_enabled);
if (user_principal == NULL) {
- // The principal could not be fetched,
- // get new acess token with refresh token
- tracepoint(diary, debug, "Unable to fetch principal, refreshing API token");
- tracepoint(diary, debug, "Fetching access token with refresh token");
- get_access_token(NULL, NULL, true);
- // Retry request for event with new token
- user_principal = caldav_req(date, GOOGLE_CALDAV_URI, "PROPFIND", principal_postfields, 0);
+ // The principal could not be fetched
+ tracepoint(diary, debug, "Unable to fetch principal");
+ if (google_oath_enabled) {
+ // get new acess token with refresh token
+ tracepoint(diary, debug, "Fetching access token with refresh token");
+ get_access_token(NULL, NULL, true);
+ // Retry request for event with new token
+ user_principal = caldav_req(date, CONFIG.caldav_server, "PROPFIND", principal_postfields, 0, basicauth_enabled);
+ }
}
if (user_principal == NULL) {
pthread_cancel(progress_tid);
wclear(header);
wresize(header, LINES, getmaxx(header));
+ // TODO: this could also be wrong basicauth credentials
info_txt = "Offline, corrupted or otherwise invalid OAuth2 credential tokenfile.\n"
"Go online or delete tokenfile '%s' and restart diary to retry.\n"
"Press any key to continue.";
@@ -699,10 +718,10 @@ int caldav_sync(struct tm* date,
sprintf(uri, "%s%s", GOOGLE_API_URI, current_user_principal);
// free memory allocated by curl request
free(user_principal);
- char* home_set = caldav_req(date, uri, "PROPFIND", "", 1);
+ char* home_set = caldav_req(date, uri, "PROPFIND", "", 1, basicauth_enabled);
// get calendar URI from the home-set
- char* calendar_href = parse_caldav_calendar(home_set, CONFIG.google_calendar);
+ char* calendar_href = parse_caldav_calendar(home_set, CONFIG.caldav_calendar);
char* xml_filter = "<c:calendar-query xmlns:d='DAV:' xmlns:c='urn:ietf:params:xml:ns:caldav'>"
"<d:prop><c:calendar-data/></d:prop>"
@@ -732,7 +751,7 @@ int caldav_sync(struct tm* date,
// fetch event for the cursor date
sprintf(uri, "%s%s", GOOGLE_API_URI, calendar_href);
- char* event = caldav_req(date, uri, "REPORT", caldata_postfields, 0);
+ char* event = caldav_req(date, uri, "REPORT", caldata_postfields, 0, basicauth_enabled);
// todo: warn if multiple events,
// multistatus has more than just one caldav:calendar-data elements
// currently, the code below will just extract the first occurance of
@@ -812,11 +831,11 @@ int caldav_sync(struct tm* date,
char event_uri[300];
sprintf(event_uri, "%s%s%s.ics", GOOGLE_API_URI, calendar_href, remote_uid);
tracepoint(diary, debug_string, "Event URI for DELETE request", event_uri);
- char* response = caldav_req(date, event_uri, "DELETE", NULL, 0);
+ char* response = caldav_req(date, event_uri, "DELETE", NULL, 0, basicauth_enabled);
free(response);
}
- put_event(date, dir, dir_size, uri);
+ put_event(date, dir, dir_size, uri, basicauth_enabled);
pthread_cancel(progress_tid);
wclear(header);
diff --git a/src/caldav.h b/src/caldav.h
@@ -32,7 +32,6 @@
#define GOOGLE_OAUTH_REDIRECT_PORT 9004
#define GOOGLE_OAUTH_REDIRECT_SOCKET_BACKLOG 10
#define GOOGLE_API_URI "https://apidata.googleusercontent.com"
-#define GOOGLE_CALDAV_URI GOOGLE_API_URI "/caldav/v2"
int caldav_sync(struct tm* date,
WINDOW* header,
diff --git a/src/diary.c b/src/diary.c
@@ -363,9 +363,18 @@ bool read_config(const char* file_path) {
} else if (strcmp("google_secretid", key_buf) == 0) {
CONFIG.google_secretid = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
strcpy(CONFIG.google_secretid, value_buf);
- } else if (strcmp("google_calendar", key_buf) == 0) {
- CONFIG.google_calendar = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
- strcpy(CONFIG.google_calendar, value_buf);
+ } else if (strcmp("caldav_server", key_buf) == 0) {
+ CONFIG.caldav_server = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
+ strcpy(CONFIG.caldav_server, value_buf);
+ } else if (strcmp("caldav_calendar", key_buf) == 0) {
+ CONFIG.caldav_calendar = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
+ strcpy(CONFIG.caldav_calendar, value_buf);
+ } else if (strcmp("caldav_username", key_buf) == 0) {
+ CONFIG.caldav_username = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
+ strcpy(CONFIG.caldav_username, value_buf);
+ } else if (strcmp("caldav_password", key_buf) == 0) {
+ CONFIG.caldav_password = (char *) malloc(strlen(value_buf) + 1 * sizeof(char));
+ strcpy(CONFIG.caldav_password, value_buf);
}
}
}
diff --git a/src/utils.c b/src/utils.c
@@ -405,5 +405,8 @@ config CONFIG = {
.google_tokenfile = GOOGLE_OAUTH_TOKEN_FILE,
.google_clientid = GOOGLE_OAUTH_CLIENT_ID,
.google_secretid = GOOGLE_OAUTH_CLIENT_SECRET,
- .google_calendar = ""
+ .caldav_calendar = "",
+ .caldav_server = "",
+ .caldav_username = "",
+ .caldav_password = ""
};
diff --git a/src/utils.h b/src/utils.h
@@ -62,8 +62,14 @@ typedef struct
char* google_clientid;
// Google secret id
char* google_secretid;
- // Google calendar to synchronize
- char* google_calendar;
+ // CalDAV calendar to synchronize
+ char* caldav_calendar;
+ // CalDAV server URI
+ char* caldav_server;
+ // CalDAV username
+ char* caldav_username;
+ // CalDAV password
+ char* caldav_password;
} config;
extern config CONFIG;