--- /dev/null
+/*
+ * cmdline-parser.c
+ *
+ * Copyright 2017 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 2 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <glib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cmdline-parser.h"
+#include "caldav.h"
+
+static const gchar* help[] = {
+ "Usage: test-app [Options] -o operation -p password -u username URL",
+ "",
+ "a|data Use this option to insert calendar data from file.",
+ " As an alternative use redirect IO with <.",
+ "d|debug Print a lot of debug information to STDOUT",
+ "e|etag ETag to use for update and delete",
+ "f|finish End time interval in ISO 8601 local time. 2017-01-13T13:13:13",
+ "h|help Show this help info.",
+ "r|href HREFs to use for getobjects. Each href on a separate line.",
+ " As an alternative use redirect IO with <.",
+ "s|start Start time interval in ISO 8601 local time. 2017-01-13T13:13:13",
+ NULL
+};
+
+static void show_help() {
+ for (int i = 0; help[i]; i++) {
+ printf("%s\n", help[i]);
+ }
+}
+
+static void get_operation(const gchar* op, Operation* o) {
+ if (o) {
+ if (g_strcmp0("CALENDARINFO", op) == 0) {
+ *o = CALENDARINFO;
+ } else if (g_strcmp0("GETOBJECTS", op) == 0) {
+ *o = GETOBJECTS;
+ } else if (g_strcmp0("GETALLOBJECTS", op) == 0) {
+ *o = GETALLOBJECTS;
+ } else if (g_strcmp0("SIMPLEGET", op) == 0) {
+ *o = SIMPLEGET;
+ } else if (g_strcmp0("CHANGEINFO", op) == 0) {
+ *o = CHANGEINFO;
+ } else if (g_strcmp0("UPDATEOBJECTS", op) == 0) {
+ *o = UPDATEOBJECTS;
+ } else if (g_strcmp0("ADDOBJECTS", op) == 0) {
+ *o = ADDOBJECTS;
+ } else if (g_strcmp0("DELETEOBJECTS", op) == 0) {
+ *o = DELETEOBJECTS;
+ } else if (g_strcmp0("DISCOVER", op) == 0) {
+ *o = DISCOVER;
+ } else if (g_strcmp0("OPTIONSINFO", op) == 0) {
+ *o = OPTIONSINFO;
+ } else if (g_strcmp0("FREEBUSY", op) == 0) {
+ *o = FREEBUSY;
+ } else {
+ *o = UNKNOWN;
+ }
+ }
+}
+
+static gboolean invalid_test_case(Runtime* test) {
+ gboolean invalid = TRUE;
+ gboolean error = FALSE;
+
+ if (test) {
+ if (!test->username) {
+ printf("Missing username\n");
+ error = TRUE;
+ }
+ if (!test->password) {
+ printf("Missing password\n");
+ error = TRUE;
+ }
+ if (!test->url) {
+ printf("Missing URL\n");
+ error = TRUE;
+ }
+ if (!test->operation) {
+ printf("Missing operation\n");
+ error = TRUE;
+ }
+ invalid = (error) ? TRUE : FALSE;
+ }
+
+ return invalid;
+}
+
+#define BUF_SIZE 1024
+static gchar* read_stream(FILE* stream) {
+ gchar buffer[BUF_SIZE];
+ size_t size = 1;
+ gchar* content = g_malloc0(sizeof(gchar) * BUF_SIZE);
+
+ while (fgets(buffer, BUF_SIZE, stream) != NULL) {
+ size += strlen(buffer);
+ content = g_realloc(content, size);
+ g_strlcat(content, buffer, size);
+ }
+
+ return content;
+}
+
+static GSList* parse_input(const gchar* input) {
+ GSList* list = NULL;
+
+ gchar** strings = g_strsplit(input, "\n", 0);
+ for (gchar** h = strings; *h; ++h) {
+ if (g_strcmp0(*h, "") != 0) {
+ HrefData* hd = href_data_new(*h, NULL);
+ list = g_slist_append(list, hd);
+ }
+ }
+ g_strfreev(strings);
+
+ return list;
+}
+
+Runtime* parse_cmdline(int argc, char **argv) {
+ int opt = 0;
+ int debug_flag = 0;
+ Runtime* test = runtime_new();
+ Operation* op = g_new(Operation, 1);
+ FILE* stream = NULL;
+
+ struct option long_options[] = {
+ {"data", required_argument, 0, 'a'},
+ {"etag", required_argument, 0, 'e'},
+ {"finish", required_argument, 0, 'f'},
+ {"debug", no_argument, &debug_flag, 1 },
+ {"help", no_argument, 0, 'h'},
+ {"operation", required_argument, 0, 'o'},
+ {"password", required_argument, 0, 'p'},
+ {"href", required_argument, 0, 'r'},
+ {"start", required_argument, 0, 's'},
+ {"username", required_argument, 0, 'u'},
+ {0, 0, 0, 0 }
+ };
+
+ int option_index = 0;
+ while ((opt = getopt_long(argc, argv, "a:de:f:h:o:p:rs:u:",
+ long_options, &option_index)) != -1) {
+ switch (opt) {
+ case 'a': {
+ stream = fopen(optarg, "r");
+ if (!stream) {
+ perror("File");
+ runtime_free(test);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+
+ case 'd':
+ debug_flag = 1;
+ break;
+
+ case 'e':
+ test->etag = g_strdup(optarg);
+ break;
+
+ case 'f':
+ test->finish = get_date_time_from_string(optarg);
+ break;
+
+ case 'h':
+ runtime_free(test);
+ show_help();
+ exit(EXIT_SUCCESS);
+
+ case 'o':
+ get_operation(optarg, op);
+ if (op && *op != UNKNOWN) {
+ test->operation = op;
+ } else {
+ runtime_free(test);
+ fprintf(stderr, "%s: Invalid operation\n", optarg);
+ show_help();
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'p':
+ test->password = g_strdup(optarg);
+ break;
+
+ case 'r': {
+ stream = fopen(optarg, "r");
+ if (!stream) {
+ perror("File");
+ runtime_free(test);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+
+ case 's':
+ test->start = get_date_time_from_string(optarg);
+ break;
+
+ case 'u':
+ test->username = g_strdup(optarg);
+ break;
+
+ case ':':
+ /* missing option argument */
+ runtime_free(test);
+ printf("%s: option '-%c' requires an argument\n", argv[0], optopt);
+ show_help();
+ exit(EXIT_FAILURE);
+
+ case '?':
+ default:
+ /* invalid option */
+ runtime_free(test);
+ fprintf(stderr, "%s: option '-%c' is invalid: ignored\n", argv[0], optopt);
+ show_help();
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind + 1 < argc) {
+ runtime_free(test);
+ printf("Only one URL allowed\n");
+ show_help();
+ exit(EXIT_FAILURE);
+ }
+
+ test->url= g_strdup(argv[optind]);
+
+ if (invalid_test_case(test)) {
+ runtime_free(test);
+ show_help();
+ exit(EXIT_FAILURE);
+ }
+
+ if (*test->operation == ADDOBJECTS || *test->operation == UPDATEOBJECTS) {
+ struct stat sb;
+ if (fstat(fileno(stdin), &sb) == -1) {
+ if (!stream) {
+ perror("Stat");
+ runtime_free(test);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if (stream && sb.st_size > 0) {
+ fprintf(stderr, "Error: Option --data or --href active. Cannot redirect STDIN\n");
+ runtime_free(test);
+ exit(EXIT_FAILURE);
+ } else {
+ stream = (stream) ? stream : stdin;
+ }
+ }
+
+ gchar* text = read_stream(stream);
+
+ switch (*test->operation) {
+ case GETOBJECTS:
+ test->hrefs = parse_input(text);
+ g_free(text);
+ break;
+ case UPDATEOBJECTS:
+ case ADDOBJECTS:
+ test->component = text;
+ break;
+ default:
+ fprintf(stderr, "%i: Input not allowed\n", *test->operation);
+ runtime_free(test);
+ g_free(text);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ test->debug = (debug_flag) ? TRUE : FALSE;
+
+ return test;
+}
+