trg_response *dispatch_public_http(TrgClient *tc, trg_request *req) { trg_response *response = g_new0(trg_response, 1); CURL* curl = get_curl(tc, HTTP_CLASS_PUBLIC); struct curl_slist *headers = NULL; long httpCode = 0; gchar *cookie_header = NULL; response->size = 0; response->raw = NULL; curl_easy_setopt(curl, CURLOPT_URL, req->url); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response); if (req->cookie) { cookie_header = g_strdup_printf("Cookie: %s", req->cookie); headers = curl_slist_append(NULL, cookie_header); } if (headers) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); response->status = curl_easy_perform(curl); trg_request_free(req); g_free(cookie_header); if (headers) curl_slist_free_all(headers); //g_message(response->raw); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); if (response->status == CURLE_OK && httpCode != HTTP_OK) { response->status = (-httpCode) - 100; } return response; }
static inline int trg_http_perform_inner(TrgClient * tc, trg_request * request, trg_response * response, gboolean recurse) { CURL* curl = get_curl(tc, HTTP_CLASS_TRANSMISSION); struct curl_slist *headers = NULL; gchar *session_id = NULL; long httpCode = 0; response->size = 0; response->raw = NULL; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request->body); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response); session_id = trg_client_get_session_id(tc); if (session_id) headers = curl_slist_append(NULL, session_id); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); response->status = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); g_free(session_id); if (headers) curl_slist_free_all(headers); if (response->status == CURLE_OK) { if (httpCode == HTTP_CONFLICT && recurse == TRUE) return trg_http_perform_inner(tc, request, response, FALSE); else if (httpCode != HTTP_OK) response->status = (-httpCode) - 100; } return response->status; }
/** * 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; }
/* * @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 getting freebusy within a time range from collection. * @param settings A pointer to caldav_settings. @see caldav_settings * @param error A pointer to caldav_error. @see caldav_error * @return TRUE in case of error, FALSE otherwise. */ gboolean caldav_freebusy(caldav_settings* settings, caldav_error* error) { CURL* curl; CURLcode res = 0; char error_buf[CURL_ERROR_SIZE + 1]; struct config_data data; struct MemoryStruct chunk; struct MemoryStruct headers; struct curl_slist *http_header = NULL; gboolean result = FALSE; gchar* request = NULL; chunk.memory = NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ headers.memory = NULL; headers.size = 0; curl = get_curl(settings); if (!curl) { error->code = -1; error->str = g_strdup("Could not initialize libcurl"); g_free(settings->file); settings->file = NULL; return TRUE; } http_header = curl_slist_append(http_header, "Content-Type: application/xml; charset=\"utf-8\""); http_header = curl_slist_append(http_header, "Depth: 1"); http_header = curl_slist_append(http_header, "Expect:"); http_header = curl_slist_append(http_header, "Transfer-Encoding:"); http_header = curl_slist_append(http_header, "Connection: close"); data.trace_ascii = settings->trace_ascii; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteHeaderCallback); /* we pass our 'headers' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&headers); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char *) &error_buf); if (settings->debug) { curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &data); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); } request = g_strdup_printf( "%s\r\n<C:time-range start=\"%s\"\r\n end=\"%s\"/>\r\n%s", getrange_request_head, get_caldav_datetime(&settings->start), get_caldav_datetime(&settings->end), getrange_request_foot); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request); curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE, strlen(request)); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1); curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); res = curl_easy_perform(curl); if (res != 0) { error->code = -1; error->str = g_strdup_printf("%s", error_buf); g_free(settings->file); settings->file = NULL; result = TRUE; } else { long code; res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 200) { error->code = code; error->str = g_strdup(headers.memory); result = TRUE; } else { /*gchar* report; report = parse_caldav_report(chunk.memory, "calendar-data", "VFREEBUSY"); settings->file = g_strdup(report);*/ settings->file = g_strdup(chunk.memory); /*g_free(report);*/ } } g_free(request); if (chunk.memory) free(chunk.memory); if (headers.memory) free(headers.memory); curl_slist_free_all(http_header); curl_easy_cleanup(curl); return result; }
/** * Function for modifying an event. * @param settings A pointer to caldav_settings. @see caldav_settings * @param error A pointer to caldav_error. @see caldav_error * @return TRUE in case of error, FALSE otherwise. */ gboolean caldav_modify(caldav_settings* settings, caldav_error* error) { CURL* curl; CURLcode res = 0; char error_buf[CURL_ERROR_SIZE]; struct config_data data; struct MemoryStruct chunk; struct MemoryStruct headers; struct curl_slist *http_header = NULL; gchar* search; gchar* uid; gboolean result = FALSE; gboolean LOCKSUPPORT = FALSE; gchar* lock_token = NULL; chunk.memory = NULL; /* we expect realloc(NULL, size) to work */ chunk.size = 0; /* no data at this point */ headers.memory = NULL; headers.size = 0; curl = get_curl(settings); if (!curl) { error->code = -1; error->str = g_strdup("Could not initialize libcurl"); g_free(settings->file); settings->file = NULL; return TRUE; } http_header = curl_slist_append(http_header, "Content-Type: application/xml; charset=\"utf-8\""); http_header = curl_slist_append(http_header, "Depth: 1"); http_header = curl_slist_append(http_header, "Expect:"); http_header = curl_slist_append(http_header, "Transfer-Encoding:"); http_header = curl_slist_append(http_header, "Connection: close"); data.trace_ascii = settings->trace_ascii; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); /* we pass our 'chunk' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, WriteHeaderCallback); /* we pass our 'headers' struct to the callback function */ curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&headers); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, (char *) &error_buf); if (settings->debug) { curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &data); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); } gchar* file = g_strdup(settings->file); if ((uid = get_response_header("uid", file, FALSE)) == NULL) { g_free(file); error->code = 1; error->str = g_strdup("Error: Missing required UID for object"); return TRUE; } g_free(file); /* * collation is not supported by ICalendar. * <C:text-match collation=\"i;ascii-casemap\">%s</C:text-match> */ search = g_strdup_printf( "%s\r\n<C:text-match>%s</C:text-match>\r\n%s", search_head, uid, search_tail); g_free(uid); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, search); curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE, strlen(search)); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1); curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); res = curl_easy_perform(curl); curl_slist_free_all(http_header); http_header = NULL; g_free(search); if (res != 0) { error->code = -1; error->str = g_strdup_printf("%s", error_buf); g_free(settings->file); settings->file = NULL; result = TRUE; } else { long code; res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); if (code != 207) { error->code = code; error->str = g_strdup(chunk.memory); result = TRUE; } else { /* enable uploading */ gchar* url = NULL; gchar* etag = NULL; url = get_url(chunk.memory); if (url) { etag = get_etag(chunk.memory); if (etag) { gchar* host = get_host(settings->url); if (host) { file = g_strdup(url); g_free(url); url = g_strdup_printf("%s%s", host, file); g_free(file); g_free(host); } else { g_free(etag); g_free(url); url = NULL; } } else { g_free(url); url = NULL; } if (url) { int lock = 0; caldav_error lock_error; file = g_strdup(etag); g_free(etag); etag = g_strdup_printf("If-Match: %s", file); g_free(file); http_header = curl_slist_append(http_header, etag); g_free(etag); http_header = curl_slist_append(http_header, "Content-Type: text/calendar; charset=\"utf-8\""); http_header = curl_slist_append(http_header, "Expect:"); http_header = curl_slist_append( http_header, "Transfer-Encoding:"); http_header = curl_slist_append(http_header, "Connection: close"); if (settings->use_locking) LOCKSUPPORT = caldav_lock_support(settings, &lock_error); else LOCKSUPPORT = FALSE; if (LOCKSUPPORT) { lock_token = caldav_lock_object(url, settings, &lock_error); if (lock_token) { http_header = curl_slist_append( http_header, g_strdup_printf( "If: (%s)", lock_token)); } /* * If error code is 423 (Resource is LOCKED) bail out */ else if (lock_error.code == 423) { lock = -1; } /* * If error code is 501 (Not implemented) we continue * hoping for the best. */ else if (lock_error.code == 501) { lock_token = g_strdup(""); } else { lock = -1; } } if (! LOCKSUPPORT || (LOCKSUPPORT && lock_token && lock_error.code != 423)) { curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header); curl_easy_setopt(curl, CURLOPT_URL, rebuild_url(settings, url)); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, settings->file); curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE, strlen(settings->file)); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1); curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); res = curl_easy_perform(curl); if (LOCKSUPPORT && lock_token) { caldav_unlock_object( lock_token, url, settings, &lock_error); } } g_free(url); g_free(lock_token); if (res != 0 || lock < 0) { /* Is this a lock_error don't change error*/ if (lock == 0 || lock_error.code == 423) { error->code = code; error->str = g_strdup(chunk.memory); } else { error->code = lock_error.code; error->str = g_strdup(lock_error.str); } result = TRUE; g_free(settings->file); settings->file = NULL; } else { long code; res = curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &code); if (code != 204) { error->code = code; error->str = g_strdup(chunk.memory); result = TRUE; } } curl_slist_free_all(http_header); } else { error->code = code; if (chunk.memory) error->str = g_strdup(chunk.memory); else error->str = g_strdup("No object found"); result = TRUE; } } else { /* * No object found on server. Posible synchronization * problem or a server side race condition */ error->code = 409; error->str = g_strdup("No object found"); result = TRUE; } } } if (chunk.memory) free(chunk.memory); if (headers.memory) free(headers.memory); curl_easy_cleanup(curl); return result; }