commit d4902f6a3a2adc9e5950e6b9b8d21bcbca4dc0ca
parent c437923fc2ea3462ae92f3a368978400020ac539
Author: Andreas Gruhler <agruhl@gmx.ch>
Date: Thu, 23 Jun 2022 12:11:08 +0200
fix(#3): Only write tokenfile on CURLE_OK
Diffstat:
2 files changed, 43 insertions(+), 31 deletions(-)
diff --git a/src/caldav.c b/src/caldav.c
@@ -72,6 +72,7 @@ char* extract_oauth_code(char* http_header) {
return res;
}
+/* Read access token from file and refresh global token vars */
char* read_tokenfile() {
FILE* token_file;
char* token_buf;
@@ -95,7 +96,18 @@ char* read_tokenfile() {
fread(token_buf, sizeof(char), token_bytes, token_file);
token_buf[token_bytes] = '\0';
- char* new_access_token = extract_json_value(token_buf, "access_token", true);
+ update_global_token_vars(token_buf);
+ } else {
+ perror("malloc failed");
+ return NULL;
+ }
+ fclose(token_file);
+ return token_buf;
+}
+
+/* Refresh global token variables from input buffer */
+void update_global_token_vars(char* input) {
+ char* new_access_token = extract_json_value(input, "access_token", true);
//fprintf(stderr, "Info - New access token: %s\n", new_access_token);
if (new_access_token != NULL) {
strncpy(access_token, new_access_token, 200);
@@ -103,7 +115,7 @@ char* read_tokenfile() {
}
// program segfaults if NULL value is provided to atoi
- char* token_ttl_str = extract_json_value(token_buf, "expires_in", false);
+ char* token_ttl_str = extract_json_value(input, "expires_in", false);
if (token_ttl_str == NULL) {
token_ttl = 0;
} else {
@@ -114,25 +126,20 @@ char* read_tokenfile() {
// only update the existing refresh token if the request actually
// contained a valid refresh_token, i.e, if it was the initial
// interactive authZ request from token code confirmed by the user
- char* new_refresh_token = extract_json_value(token_buf, "refresh_token", true);
+ char* new_refresh_token = extract_json_value(input, "refresh_token", true);
if (new_refresh_token != NULL) {
strncpy(refresh_token, new_refresh_token, 200);
free(new_refresh_token);
}
- } else {
- perror("malloc failed");
- return NULL;
- }
- fclose(token_file);
- return token_buf;
}
-void write_tokenfile() {
+/* Persist contents from global token file variables to tokenfile */
+void update_tokenfile_from_global_vars() {
char* tokenfile_path = expand_path(CONFIG.google_tokenfile);
FILE* tokenfile = fopen(tokenfile_path, "wb");
if (tokenfile == NULL) {
- perror("Warning - failed to open tokenfile in write_tokenfile()");
+ perror("Warning - failed to open tokenfile in update_tokenfile_from_global_vars()");
} else {
char contents[1000];
char* tokenfile_contents = "{\n"
@@ -143,6 +150,10 @@ void write_tokenfile() {
sprintf(contents, tokenfile_contents,
access_token,
token_ttl,
+ // Make sure the refresh token is re-written and persistet
+ // to the tokenfile for further requests, because this token
+ // is not returned by the refresh_token call:
+ // https://developers.google.com/identity/protocols/oauth2/native-app#offline
refresh_token);
fputs(contents, tokenfile);
}
@@ -152,15 +163,12 @@ void write_tokenfile() {
perror("chmod");
}
- char* tokfile = read_tokenfile();
- free(tokfile);
free(tokenfile_path);
}
+/* Get access token with authorization code or refresh token */
void get_access_token(char* code, char* verifier, bool refresh) {
CURLcode res;
- char* tokfile;
-
char* postfields_refresh = "client_id=%s&client_secret=%s&grant_type=refresh_token&refresh_token=%s";
char* postfields_code = "client_id=%s&client_secret=%s&code=%s&code_verifier=%s&grant_type=authorization_code&redirect_uri=http://%s:%i";
char* postfields;
@@ -205,26 +213,26 @@ void get_access_token(char* code, char* verifier, bool refresh) {
curl_easy_cleanup(curl);
- fputs(token_resp.memory, stderr);
+ // Only write tokenfile if the token in token_resp.memory looks valid.
+ // Assume it's valid, when the curl request succeeds (no HTTP errors).
+ // Otherwise, a valid token in the possisbly already existing file would
+ // be overwritten. This happens usually during syncing (s/S) while offline.
+ if (res == CURLE_OK) {
+ // fputs(token_resp.memory, stderr);
- if (res != CURLE_OK) {
- fprintf(stderr, "Error - curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
+ // update global token variables
+ update_global_token_vars(token_resp.memory);
+ update_tokenfile_from_global_vars();
+ } else {
+ fprintf(stderr, "Error - curl_easy_perform() failed in get_access_token(): %s\n", curl_easy_strerror(res));
return;
}
- // update global variables from tokenfile
- // this will also init the access_token var the first time
- tokfile = read_tokenfile();
- free(tokfile);
- // Make sure the refresh token is re-written and persistet
- // to the tokenfile for further requests, because this token
- // is not returned by the refresh_token call:
- // https://developers.google.com/identity/protocols/oauth2/native-app#offline
- write_tokenfile();
}
free(postfields);
}
+/* Perform challenge/request to fetch authorization code */
char* get_oauth_code(const char* verifier, WINDOW* header) {
struct addrinfo hints, *addr_res;
@@ -383,6 +391,7 @@ char* get_oauth_code(const char* verifier, WINDOW* header) {
return oauth_code;
}
+/* Make a CalDAV request */
char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields, int depth) {
// only support depths 0 or 1
if (depth < 0 || depth > 1) {
@@ -407,6 +416,7 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method);
+ fprintf(stderr, "caldav_req(): %s\n", url);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_mem_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&caldav_resp);
@@ -434,7 +444,7 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
- fprintf(stderr, "Error - curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
+ fprintf(stderr, "Error - curl_easy_perform() failed in caldav_req(): %s\n", curl_easy_strerror(res));
free(caldav_resp.memory);
return NULL;
}
@@ -443,7 +453,7 @@ char* caldav_req(struct tm* date, char* url, char* http_method, char* postfields
return caldav_resp.memory;
}
-// return current user principal from CalDAV XML response
+/* Return current user principal from CalDAV XML response */
char* parse_caldav_current_user_principal(char* xml) {
char* xml_key_pos = strstr(xml, "<D:current-user-principal>");
// this XML does not contain a user principal at all
@@ -465,7 +475,7 @@ char* parse_caldav_current_user_principal(char* xml) {
return tok;
}
-// return calendar uri from CalDAV home set XML response
+/* Return calendar uri from CalDAV home set XML response */
char* parse_caldav_calendar(char* xml, char* calendar) {
char displayname_needle[strlen(calendar) + strlen("<D:displayname></D:displayname>")];
sprintf(displayname_needle, "<D:displayname>%s</D:displayname>", calendar);
@@ -500,6 +510,7 @@ char* parse_caldav_calendar(char* xml, char* calendar) {
return NULL;
}
+/* Upload event to CalDAV server */
void put_event(struct tm* date, const char* dir, size_t dir_size, char* calendar_uri) {
// get entry path
char path[100];
@@ -587,7 +598,7 @@ int caldav_sync(struct tm* date,
bool confirm) {
pthread_t progress_tid;
- // fetch existing API tokens
+ // fetch existing API tokens from file
char* tokfile = read_tokenfile();
free(tokfile);
diff --git a/src/caldav.h b/src/caldav.h
@@ -41,6 +41,7 @@ int caldav_sync(struct tm* date,
const char* dir,
size_t dir_size,
bool confirm);
+void update_global_token_vars(char*);
struct curl_mem_chunk {
char* memory;