1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
/*
* icalfilter -- filter an iCalendar file
*
* Author: Bert Bos <bert@w3.org>
* Created: 30 Sep 2002
*/
#include "config.h"
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <getopt.h>
#include <ctype.h>
/*
#include <icaltime.h>
#include <icalcomponent.h>
#include <icalerror.h>
#include <icaltimezone.h>
*/
#include <libical/ical.h>
#include <libical/icalss.h>
/*
#include <icalset.h>
#include <icalfileset.h>
*/
#define PRODID "-//W3C//NONSGML icalfilter 0.1//EN"
#define ERR_OUT_OF_MEM 1 /* Program exit codes */
#define ERR_USAGE 2
#define ERR_DATE 3
#define ERR_PARSE 4
#define ERR_FILEIO 5
#define ERR_ICAL_ERR 6 /* Other error */
#define USAGE "Usage: ical2html [options] input output\n\
-p, --class=CLASS only (PUBLIC, CONFIDENTIAL, PRIVATE, NONE)\n\
-P, --not-class=CLASS exclude (PUBLIC, CONFIDENTIAL, PRIVATE, NONE)\n\
-c, --category=CATEGORY only events of this category\n\
-C, --not-category=CATEGORY exclude events of this category\n\
--add-category=CATEGORY add category to output events\n\
input and output are iCalendar files\n"
/* Long command line options */
static struct option options[] = {
{"class", 1, 0, 'p'},
{"not-class", 1, 0, 'P'},
{"category", 1, 0, 'c'},
{"not-category", 1, 0, 'C'},
{"add-category", 1, 0, 'a'},
{0, 0, 0, 0}
};
#define OPTIONS "p:P:c:C:"
/* Structure for storing applicable events */
typedef struct _event_item {
struct icaltimetype start;
struct icaltimetype end;
icalcomponent *event;
} event_item;
/* fatal -- print error message and exit with errcode */
static void fatal(int errcode, const char *message,...)
{
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
exit(errcode);
}
/* read_stream -- read size bytes into s from stream d */
static char* read_stream(char *s, size_t size, void *d)
{
return fgets(s, size, (FILE*)d);
}
/* main */
int main(int argc, char *argv[])
{
FILE* stream;
icalcomponent *comp;
icalparser *parser;
char *classmask = NULL, *categorymask = NULL;
char *notclassmask = NULL, *notcategorymask = NULL;
char *addcategory = NULL;
char c;
const char *class;
icalset *out;
icalcomponent *h, *next, *newset;
icalproperty *p;
/* We handle errors ourselves */
icalerror_set_errors_are_fatal(0);
icalerror_clear_errno();
/* Read commandline */
while ((c = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) {
switch (c) {
case 'p': classmask = strdup(optarg); break;
case 'P': notclassmask = strdup(optarg); break;
case 'c': categorymask = strdup(optarg); break;
case 'C': notcategorymask = strdup(optarg); break;
case 'a': addcategory = strdup(optarg); break;
default: fatal(ERR_USAGE, USAGE);
}
}
/* Get input file name */
if (optind == argc) fatal(ERR_USAGE, USAGE);
stream = optind == argc ? stdin : fopen(argv[optind], "r");
if (!stream) fatal(ERR_FILEIO, "%s: %s\n", argv[optind], strerror(errno));
optind++;
/* Get output file name */
if (optind == argc) fatal(ERR_USAGE, USAGE);
(void) unlink(argv[optind]); /* Remove output file if it already exists */
out = icalfileset_new(argv[optind]);
if (!out) fatal(ERR_FILEIO, "%s: %s\n", argv[optind], strerror(errno));
/* Should have no more arguments */
if (optind + 1 != argc) fatal(ERR_USAGE, USAGE);
/* Create a new parser object */
parser = icalparser_new();
/* Tell the parser what input stream it should use */
icalparser_set_gen_data(parser, stream);
/* Let the parser read the file and return all components */
if (! (comp = icalparser_parse(parser, read_stream)))
fatal(ERR_PARSE, "Parse error: %s\n", icalerror_strerror(icalerrno));
icalparser_free(parser);
/* Initialize a new VCALENDAR */
newset = icalcomponent_vanew(ICAL_VCALENDAR_COMPONENT,
icalproperty_new_version("2.0"),
icalproperty_new_prodid(PRODID),
0);
/* Iterate over VTIMEZONEs */
for (h = icalcomponent_get_first_component(comp, ICAL_VTIMEZONE_COMPONENT);
h; h = next) {
next = icalcomponent_get_next_component(comp, ICAL_VTIMEZONE_COMPONENT);
icalcomponent_remove_component(comp, h); /* Move from comp... */
icalcomponent_add_component(newset, h); /* ... to out */
}
/* Iterate over VEVENTs */
for (h = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT);
h; h = next) {
next = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT);
/* Check if the event is of the right class (unless we accept all) */
if (classmask || notclassmask) {
p = icalcomponent_get_first_property(h, ICAL_CLASS_PROPERTY);
class = p ? icalvalue_as_ical_string(icalproperty_get_value(p))
: "NONE";
if (classmask && strcasecmp(classmask, class) != 0) continue;
if (notclassmask && strcasecmp(notclassmask, class) == 0) continue;
}
/* Check if the event is of the right category (unless we accept all) */
if (categorymask) {
p = icalcomponent_get_first_property(h, ICAL_CATEGORIES_PROPERTY);
while (p && strcasecmp(categorymask, icalproperty_get_categories(p)))
p = icalcomponent_get_next_property(h, ICAL_CATEGORIES_PROPERTY);
if (!p) continue; /* No category was equal to categorymask */
}
if (notcategorymask) {
p = icalcomponent_get_first_property(h, ICAL_CATEGORIES_PROPERTY);
while (p && strcasecmp(notcategorymask, icalproperty_get_categories(p)))
p = icalcomponent_get_next_property(h, ICAL_CATEGORIES_PROPERTY);
if (p) continue; /* Some category equal to notcategorymask */
}
if (addcategory) {
icalcomponent_add_property(h, icalproperty_new_categories(addcategory));
}
/* The event passed our filters, so add it to the output set */
icalcomponent_remove_component(comp, h); /* Move from comp... */
icalcomponent_add_component(newset, h); /* ... to out */
}
/* Put new vcalendar in output file, flush to disk and close file */
icalfileset_add_component(out, newset);
icalfileset_free(out);
/* Clean up */
icalcomponent_free(comp);
return 0;
}
|