You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
10 KiB
384 lines
10 KiB
13 years ago
|
/* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <glib.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
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;
|
||
|
}
|