/* 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 #include #include #include #include #include #include gchar* make_url(gchar* uid, gchar* pwd, gchar* url) { char* pos; char* protocol = NULL; char* uri = NULL; char* newurl = NULL; if (!uid) return g_strdup(url); if ((pos = strstr(url, "//")) != NULL) { uri = g_strdup(&(*(pos + 2))); protocol = g_strndup(url, pos + 2 - url); } else { protocol = g_strdup("http://"); } if (!pwd) newurl = g_strdup_printf("%s%s@%s", protocol, uid, uri); else newurl = g_strdup_printf("%s%s:%s@%s", protocol, uid, pwd, uri); g_free(uri); g_free(protocol); return newurl; } #define BUFFER 1000 gchar* read_stream(FILE* stream, gchar* mem) { int len, fd; char buf[BUFFER]; struct stat sb; fd = fileno(stream); fstat(fd, &sb); while ((len = read(fd, &buf, sizeof(buf))) > 0) { mem = (char *) realloc(mem, sizeof(buf) + 1); strncat(mem, buf, sizeof(buf)); } mem[sb.st_size] = '\0'; fclose(stream); return mem; } time_t make_time_t(const char* time_elem) { struct tm datetime = {0,0,0,0,0,0,0,0,0,0,NULL}; //struct tm* tmp; gchar** elem; time_t t; //t = time(NULL); //tmp = localtime(&t); elem = g_strsplit(time_elem, "/", 3); if (g_strv_length(elem) == 3) { datetime.tm_year = atoi(elem[0]) - 1900; datetime.tm_mon = atoi(elem[1]) - 1; datetime.tm_mday = atoi(elem[2]); t = mktime(&datetime); } g_strfreev(elem); return t; } /* [yyyy/mm/dd[ hh/mm[/ss[/z]]] */ time_t make_fbtime_t(const char* time_elem) { struct tm datetime = {0,0,0,0,0,0,0,0,0,0,NULL}; gboolean utc = FALSE; gchar** elem; gchar** dt; time_t t; guint length; dt = g_strsplit(time_elem, " ", 2); length = g_strv_length(dt); if (length > 1) { elem = g_strsplit(dt[1], "/", 4); length = g_strv_length(elem); datetime.tm_hour = atoi(elem[0]); datetime.tm_min = atoi(elem[1]); if (length > 2) datetime.tm_sec = atoi(elem[2]); if (length > 3 && strcasecmp(elem[3], "z") == 0) utc = TRUE; g_strfreev(elem); } elem = g_strsplit(time_elem, "/", 3); datetime.tm_year = atoi(elem[0]) - 1900; datetime.tm_mon = atoi(elem[1]) - 1; datetime.tm_mday = atoi(elem[2]); g_strfreev(elem); if (utc) { t = mktime(&datetime); struct tm* utc_time = gmtime(&t); t = mktime(utc_time); //g_free(utc_time); } else t = mktime(&datetime); return t; } static const char* usage[] = { "caldav-test is part of libcaldav for claws-mails " "vcalendar plugin.\nCopyright (C) Michael Rasmussen, 2008.\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 3 of the License, or\n" "(at your option) any later version.\n" "\nusage:\n\tcaldav-test [Options] URL\n" "\n\tOptions:\n\t\t-a\taction [is-caldav|add|delete|modify|get|get-all|displayname|options|freebusy]\n" "\t\t-c\tprovide custom cacert (path to cert)\n" "\t\t-d\tdebug (show request/response)\n" "\t\t-e\tend [yyyy/mm/dd]. For FREEBUSY [yyyy/mm/dd[ hh/mm[/ss[/z]]]\n" "\t\t-f\tfile. Alternative is to use IO redirection (<)\n" "\t\t-p\tpassword\n" "\t\t-s\tstart [yyyy/mm/dd]. For FREEBUSY [yyyy/mm/dd[ hh/mm[/ss[/z]]]\n" "\t\t-u\tusername\n" "\t\t-v\tdisable certificate verification\n" "\t\t-h|-?\tusage\n" }; int main(int argc, char **argv) { int c; CALDAV_ACTION ACTION = UNKNOWN; gboolean debug = FALSE; gboolean verify_ssl_certificate = TRUE; FILE* stream = NULL; gchar* username = NULL; gchar* password = NULL; gchar* url = NULL; gchar* start = NULL; gchar* end = NULL; response* result; CALDAV_RESPONSE res = UNKNOWN; gchar* input = NULL; char** options = NULL; runtime_info* opt; gchar* custom_cacert = NULL; opt = caldav_get_runtime_info(); while ((c = getopt(argc, argv, "a:c:de:f:hp:s:u:v?")) != -1) { switch (c) { case 'h': case '?': fprintf(stdout, "%s", usage[0]); return 0; case 'a': if (strcmp("add", optarg) == 0) { ACTION = ADD; } else if (strcmp("delete", optarg) == 0) { ACTION = DELETE; } else if (strcmp("modify", optarg) == 0) { ACTION = MODIFY; } else if (strcmp("get", optarg) == 0) { ACTION = GET; } else if (strcmp("get-all", optarg) == 0) { ACTION = GETALL; } else if (strcmp("displayname", optarg) == 0) { ACTION = GETCALNAME; } else if (strcmp("is-caldav", optarg) == 0) { ACTION = ISCALDAV; } else if (strcmp("options", optarg) == 0) { ACTION = OPTIONS; } else if (strcmp("freebusy", optarg) == 0) { ACTION = FREEBUSY; } else { fprintf(stderr, "Unknown action: %s\n", optarg); fprintf(stderr, "%s", usage[0]); return 1; } break; case 'c': custom_cacert = g_strdup(optarg); break; case 'd': debug = TRUE; break; case 'e': end = optarg; break; case 'f': stream = fopen(optarg, "r"); if (!stream) { perror("File"); caldav_free_runtime_info(&opt); return 1; } case 'p': password = optarg; break; case 's': start = optarg; break; case 'u': username = optarg; break; case 'v': verify_ssl_certificate = FALSE; break; default: return 1; } } if (optind < argc - 1) { fprintf(stderr, "Error: Only enter one URL\n"); fprintf(stderr, "%s", usage[0]); caldav_free_runtime_info(&opt); return 1; } if (optind == argc) { fprintf(stderr, "Error: Missing URL\n"); fprintf(stderr, "%s", usage[0]); caldav_free_runtime_info(&opt); return 1; } if (ACTION == UNKNOWN) { fprintf(stderr, "Error: Missing action\n"); fprintf(stderr, "%s", usage[0]); caldav_free_runtime_info(&opt); return 1; } if (ACTION != GETALL && ACTION != GET && ACTION != GETCALNAME && ACTION != ISCALDAV && ACTION != OPTIONS && ACTION != FREEBUSY) { struct stat sb; if (fstat(fileno(stdin), &sb) == -1) { if (!stream) { perror("stat"); caldav_free_runtime_info(&opt); return 1; } } else { if (stream && sb.st_size > 0) { fprintf(stderr, "Error: Option -f is in use. Cannot redirect stdin\n"); caldav_free_runtime_info(&opt); return 1; } else stream = (stream) ? stream : stdin; } input = read_stream(stream, input); if (!input) { fprintf(stderr, "Error: Could not read from file\n"); caldav_free_runtime_info(&opt); return 1; } } if (ACTION == GET || ACTION == FREEBUSY) { if (start == NULL || end == NULL) { fprintf(stderr, "Error: Option '-a get' or '-a freebusy' requires option e and s\n"); fprintf(stderr, "%s", usage[0]); caldav_free_runtime_info(&opt); return 1; } } url = make_url(username, password, argv[optind]); if (debug) { opt->options->debug = 1; opt->options->trace_ascii = 1; } opt->options->verify_ssl_certificate = verify_ssl_certificate; opt->options->custom_cacert = g_strdup(custom_cacert); g_free(custom_cacert); result = caldav_get_response(); switch (ACTION) { case GETALL: res = caldav_getall_object(result, url, opt); break; case GET: res = caldav_get_object( result, make_time_t(start), make_time_t(end), url, opt); break; case FREEBUSY: res = caldav_get_freebusy( result, make_fbtime_t(start), make_fbtime_t(end), url, opt); break; case ADD: res = caldav_add_object(input, url, opt); break; case DELETE: res = caldav_delete_object(input, url, opt); break; case MODIFY: res = caldav_modify_object(input, url, opt); break; case GETCALNAME: res = caldav_get_displayname(result, url, opt); break; case ISCALDAV: res = caldav_enabled_resource(url, opt); if (res) res = OK; else { if (opt->error->code > 0) { switch (opt->error->code) { case 401: case 403: res = FORBIDDEN; break; case 409: res = CONFLICT; break; case 423: res = LOCKED; break; case 501: res = NOTIMPLEMENTED; break; default: res = CONFLICT; break; } } else res = CONFLICT; } break; case OPTIONS: options = caldav_get_server_options(url, opt); if (options) res = OK; else { if (opt->error->code > 0) { switch (opt->error->code) { case 401: case 403: res = FORBIDDEN; break; case 409: res = CONFLICT; break; case 423: res = LOCKED; break; case 501: res = NOTIMPLEMENTED; break; default: res = CONFLICT; break; } } else res = CONFLICT; } break; default: break; } g_free(url); g_free(input); if (res != OK) { fprintf(stderr, "Error\nCode: %ld\n%s\n", opt->error->code, opt->error->str); caldav_free_runtime_info(&opt); caldav_free_response(&result); return 1; } if (result->msg && ACTION != OPTIONS) { fprintf(stdout, "%s", result->msg); gchar* endline = strrchr(result->msg, '\n'); if (endline) { if (strlen(endline) != 1) fprintf(stdout, "\n"); } else fprintf(stdout, "\n"); } else if (ACTION == OPTIONS) { char** tmp = options; while (*options) { fprintf(stdout, "%s\n", *options++); } g_strfreev(tmp); } else if (ACTION == GET || ACTION == GETALL || ACTION == GETCALNAME || ACTION == FREEBUSY) { fprintf(stdout, "empty collection\n"); } fprintf(stdout, "OK\n"); caldav_free_response(&result); caldav_free_runtime_info(&opt); return 0; }