diff options
Diffstat (limited to 'src/caldav.c')
-rw-r--r-- | src/caldav.c | 995 |
1 files changed, 995 insertions, 0 deletions
diff --git a/src/caldav.c b/src/caldav.c new file mode 100644 index 0000000..9e2b0af --- /dev/null +++ b/src/caldav.c @@ -0,0 +1,995 @@ +/* vim: set textwidth=80 tabstop=4: */ + +/* Copyright (c) 2008 Michael Rasmussen (mir@datanom.net) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "caldav.h" +#include "caldav-utils.h" +#include "get-caldav-report.h" +#include "add-caldav-object.h" +#include "delete-caldav-object.h" +#include "modify-caldav-object.h" +#include "get-display-name.h" +#include "options-caldav-server.h" +#include "get-freebusy-report.h" +#include <curl/curl.h> +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void init_runtime(runtime_info* info) { + if (! info) + return; + if (! info->error) + info->error = g_new0(caldav_error, 1); + if (! info->options) { + info->options = g_new0(debug_curl, 1); + info->options->trace_ascii = 1; + info->options->debug = 0; + info->options->verify_ssl_certificate = TRUE; + info->options->use_locking = TRUE; + info->options->custom_cacert = NULL; + } +} + +/** + * @param curl An instance of libcurl. + * @param settings Defines CalDAV resource. Receiver is responsible for freeing + * the memory. URL is part of the structure. [http://][username:password@]host[:port]/url-path. + * See (RFC1738). + * @return FALSE (zero) mens URL does not reference a CalDAV calendar + * resource. TRUE if the URL does reference a CalDAV calendar resource. + */ +static gboolean test_caldav_enabled(CURL* curl, + caldav_settings* settings, + caldav_error* error) { + return caldav_getoptions(curl, settings, NULL, error, TRUE); +} + +/* + * @param settings An instance of caldav_settings. @see caldav_settings + * @return TRUE if there was an error. Error can be in libcurl, in libcaldav, + * or an error related to the CalDAV protocol. + */ +static gboolean make_caldav_call(caldav_settings* settings, + runtime_info* info) { + CURL* curl; + gboolean result = FALSE; + + g_return_val_if_fail(info != NULL, TRUE); + + curl = get_curl(settings); + if (!curl) { + info->error->str = g_strdup("Could not initialize libcurl"); + g_free(settings->file); + settings->file = NULL; + return TRUE; + } + if (!test_caldav_enabled(curl, settings, info->error)) { + g_free(settings->file); + settings->file = NULL; + curl_easy_cleanup(curl); + return TRUE; + } + curl_easy_cleanup(curl); + switch (settings->ACTION) { + case GETALL: result = caldav_getall(settings, info->error); break; + case GET: result = caldav_getrange(settings, info->error); break; + case GETALLTASKS: result = caldav_tasks_getall(settings, info->error); break; + case GETTASKS: result = caldav_tasks_getrange(settings, info->error); break; + case ADD: result = caldav_add(settings, info->error); break; + case DELETE: result = caldav_delete(settings, info->error); break; + case MODIFY: result = caldav_modify(settings, info->error); break; + case DELETETASKS: result = caldav_tasks_delete(settings, info->error); break; + case MODIFYTASKS: result = caldav_tasks_modify(settings, info->error); break; + case GETCALNAME: result = caldav_getname(settings, info->error); break; + case FREEBUSY: result = caldav_freebusy(settings, info->error); break; + default: break; + } + return result; +} + +/** + * Function for adding a new event. + * @param object Appointment following ICal format (RFC2445). Receiver is + * responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_add_object(const char* object, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + settings.file = g_strdup(object); + settings.ACTION = ADD; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for deleting an event. + * @param object Appointment following ICal format (RFC2445). Receiver is + * responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_delete_object(const char* object, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + settings.file = g_strdup(object); + settings.ACTION = DELETE; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for modifying an event. + * @param object Appointment following ICal format (RFC2445). Receiver is + * responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_modify_object(const char* object, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + settings.file = g_strdup(object); + settings.ACTION = MODIFY; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for getting a collection of events determined by time range. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param start time_t variable specifying start and end for range. Both + * are included in range. + * @param end time_t variable specifying start and end for range. Both + * are included in range. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_get_object(response *result, + time_t start, + time_t end, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = GET; + settings.start = start; + settings.end = end; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for getting all events from the collection. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_getall_object(response* result, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = GETALL; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for deleting a task. + * @param object Appointment following ICal format (RFC2445). Receiver is + * responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_tasks_delete_object(const char* object, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + settings.file = g_strdup(object); + settings.ACTION = DELETETASKS; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for modifying a task. + * @param object Appointment following ICal format (RFC2445). Receiver is + * responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_tasks_modify_object(const char* object, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + settings.file = g_strdup(object); + settings.ACTION = MODIFYTASKS; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for getting a collection of tasks determined by time range. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param start time_t variable specifying start and end for range. Both + * are included in range. + * @param end time_t variable specifying start and end for range. Both + * are included in range. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_tasks_get_object(response *result, + time_t start, + time_t end, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = GETTASKS; + settings.start = start; + settings.end = end; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for getting all tasks from the collection. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_tasks_getall_object(response* result, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = GETALLTASKS; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function for getting the stored display name for the collection. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_get_displayname(response* result, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = GETCALNAME; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function to test wether a calendar resource is CalDAV enabled or not. + * @param URL Defines CalDAV resource. Receiver is responsible for + * freeing the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @result 0 (zero) means no CalDAV support, otherwise CalDAV support + * detechted. + */ +int caldav_enabled_resource(const char* URL, runtime_info* info) { + CURL* curl; + caldav_settings settings; + struct config_data data; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + init_caldav_settings(&settings); + + parse_url(&settings, URL); + curl = get_curl(&settings); + if (!curl) { + info->error->code = -1; + info->error->str = g_strdup("Could not initialize libcurl"); + settings.file = NULL; + return TRUE; + } + + if (info->options->trace_ascii) + data.trace_ascii = 1; + else + data.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + + if (info->options->debug) { + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &data); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + } + gboolean res = test_caldav_enabled(curl, &settings, info->error); + free_caldav_settings(&settings); + curl_easy_cleanup(curl); + return (res && (info->error->code == 0 || info->error->code == 200)) ? 1 : 0; +} + +/** + * Function for getting free/busy information. + * @param result A pointer to struct _response where the result is to stored. + * @see response. Caller is responsible for freeing the memory. + * @param start time_t variable specifying start and end for range. Both + * are included in range. + * @param end time_t variable specifying start and end for range. Both + * are included in range. + * @param URL Defines CalDAV resource. Receiver is responsible for freeing + * the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @return Ok, FORBIDDEN, or CONFLICT. @see CALDAV_RESPONSE + */ +CALDAV_RESPONSE caldav_get_freebusy(response *result, + time_t start, + time_t end, + const char* URL, + runtime_info* info) { + caldav_settings settings; + CALDAV_RESPONSE caldav_response; + + g_return_val_if_fail(info != NULL, TRUE); + + init_runtime(info); + if (!result) { + result = malloc(sizeof(response *)); + memset(result, '\0', sizeof(response *)); + } + init_caldav_settings(&settings); + settings.ACTION = FREEBUSY; + settings.start = start; + settings.end = end; + if (info->options->debug) + settings.debug = TRUE; + else + settings.debug = FALSE; + if (info->options->trace_ascii) + settings.trace_ascii = 1; + else + settings.trace_ascii = 0; + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + parse_url(&settings, URL); + gboolean res = make_caldav_call(&settings, info); + if (res) { + result->msg = NULL; + if (info->error->code > 0) { + switch (info->error->code) { + case 403: caldav_response = FORBIDDEN; break; + case 409: caldav_response = CONFLICT; break; + case 423: caldav_response = LOCKED; break; + case 501: caldav_response = NOTIMPLEMENTED; break; + default: caldav_response = CONFLICT; break; + } + } + else { + /* fall-back to conflicting state */ + caldav_response = CONFLICT; + } + } + else { + result->msg = g_strdup(settings.file); + caldav_response = OK; + } + free_caldav_settings(&settings); + return caldav_response; +} + +/** + * Function which supports sending various options inside the library. + * @param curl_options A struct debug_curl. See debug_curl. + */ +void caldav_set_options(debug_curl curl_options) { +} + +/** + * @deprecated Function to call in case of errors. + * Caller provides a pointer to a local caldav_error structure. + * Caldav_get_error will initialize pointer if NULL. + * Caller is responsible for freeing returned memory. + * After the first call the internal error buffer is reset. + * @param lib_error A pointer to a struct _caldav_error. @see _caldav_error + * @return An initialized caldav_error pointer to memory where error + * messages can be found from the last call to the library. + */ +caldav_error* caldav_get_error(caldav_error* lib_error) { + if (!lib_error) { + lib_error = g_new0(caldav_error, 1); + } + return lib_error; +} + +/** + * Function for freeing memory for a previous initialization of a + * caldav_error. @see caldav_get_error() + * Caller provides a pointer to a local caldav_error structure. + * @param lib_error A pointer to a struct _caldav_error. @see _caldav_error + */ +void caldav_free_error(caldav_error* lib_error) { + if (lib_error->str) + g_free(lib_error->str); + g_free(lib_error); + lib_error = NULL; +} + +/** + * Function to call to get a list of supported CalDAV options for a server + * @param URL Defines CalDAV resource. Receiver is responsible for + * freeing the memory. [http://][username[:password]@]host[:port]/url-path. + * See (RFC1738). + * @result A list of available options or NULL in case of any error. + */ +char** caldav_get_server_options(const char* URL, runtime_info* info) { + CURL* curl; + caldav_settings settings; + response server_options; + gchar** option_list = NULL; + gchar** tmp; + gboolean res = FALSE; + + g_return_val_if_fail(info != NULL, NULL); + + init_runtime(info); + tmp = option_list = NULL; + init_caldav_settings(&settings); + + parse_url(&settings, URL); + curl = get_curl(&settings); + if (!curl) { + info->error->code = -1; + info->error->str = g_strdup("Could not initialize libcurl"); + settings.file = NULL; + return NULL; + } + if (info->options->use_locking) + settings.use_locking = 1; + else + settings.use_locking = 0; + + res = caldav_getoptions(curl, &settings, &server_options, info->error, FALSE); + if (res) { + if (server_options.msg) { + option_list = g_strsplit(server_options.msg, ", ", 0); + tmp = &(*(option_list)); + while (*tmp) { + g_strstrip(*tmp++); + } + } + } + free_caldav_settings(&settings); + curl_easy_cleanup(curl); + return (option_list) ? option_list : NULL; +} + +/** + * Function for getting an initialized runtime_info structure + * @return runtime_info. @see runtime_info + */ +runtime_info* caldav_get_runtime_info() { + runtime_info* rt_info; + + rt_info = g_new0(runtime_info, 1); + rt_info->error = g_new0(caldav_error, 1); + rt_info->options = g_new0(debug_curl, 1); + + return rt_info; +} + +/** + * Function for freeing memory for a previous initialization of an info + * structure + * @param info Address to a pointer to a runtime_info structure. @see + * runtime_info + */ +void caldav_free_runtime_info(runtime_info** info) { + runtime_info* ri; + + if (*info) { + ri = *info; + if (ri->error) { + if (ri->error->str) + g_free(ri->error->str); + g_free(ri->error); + ri->error = NULL; + } + if (ri->options) { + if (ri->options->custom_cacert) + g_free(ri->options->custom_cacert); + g_free(ri->options); + ri->options = NULL; + } + g_free(ri); + *info = ri = NULL; + } +} + +/** + * Function for getting an initialized response structure + * @return response. @see _response + */ +response* caldav_get_response() { + response* r; + + r = g_new0(response, 1); + + return r; +} + +/** + * Function for freeing memory for a previous initialization of an response + * structure + * @param info Address to a pointer to a response structure. @see + * _response + */ +void caldav_free_response(response** resp) { + response* r; + + if (*resp) { + r = *resp; + if (r->msg) + g_free(r->msg); + g_free(r); + *resp = r = NULL; + } +} |