\n\ -l, --location include event's location in that\n\ -t, --title=TEXT use text for HTML title\n\ -f, --footer=TEXT add text at the bottom of the HTML file\n\ -T, --today mark current day with #today in HTML file\n\ -z, --timezone=country/city adjust for this timezone (default: GMT)\n\ -m, --monday draw Monday as first week day (Sunday is default)\n\ start is of the form yyyymmdd, e.g., 20020927 (27 Sep 2002)\n\ duration is in days or weeks, e.g., P5W (5 weeks) or P60D (60 days)\n\ file is an iCalendar file, default is standard input\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'}, {"description", 0, 0, 'd'}, {"location", 0, 0, 'l'}, {"title", 1, 0, 't'}, {"footer", 1, 0, 'f'}, {"today", 0, 0, 'T'}, {"timezone", 1, 0, 'z'}, {"monday", 0, 0, 'm'}, {0, 0, 0, 0} }; #define OPTIONS "dlmTp:P:c:C:f:z:" static const char *months[] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; /* Structure for storing applicable events */ typedef struct _event_item { struct icaltimetype start; struct icaltimetype end; const char *uid; struct icaltimetype recur_time; icalcomponent *event; } event_item; static event_item *events = NULL; static int nrevents = 0; /* 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); } /* compare_events -- compare two event_items (for qsort) */ static int compare_events(const void *aa, const void *bb) { event_item *a = (event_item *)aa; event_item *b = (event_item *)bb; int h; h = icaltime_compare(a->start, b->start); if (h == 0) h = icaltime_compare(a->end, b->end); if (h == 0) h = strcmp(a->uid, b->uid); if (h == 0) h = icaltime_compare(a->recur_time, b->recur_time); return h; } /* 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); } /* print_esc -- print with <, >, & and " escaped, until end or \0 */ static void print_esc(const char *s, const char *end) { const char *t; for (t = s; *t && t != end; t++) switch (*t) { case '<': printf("<"); break; case '>': printf(">"); break; case '&': printf("&"); break; default: putchar(*t); } } /* print_escaped -- print with <, >, & and " escaped */ static void print_escaped(const char *s) { print_esc(s, NULL); } /* print_escaped_with_links -- print with <, >, & and " escaped, URLs linked */ static void print_escaped_with_links(const char *s) { static regex_t url_pattern; static int initialized = 0; regmatch_t pmatch[1]; const char *t; if (!initialized) { if (regcomp(&url_pattern, "^([a-z]+://|mailto:|geo:|urn:[a-z0-9-]+:)([][a-z0-9._~/?#[@!$&'()*+,;=-]|%[0-9a-f][0-9a-f])+", REG_EXTENDED | REG_ICASE) != 0) fatal(ERR_BUG, "regcomp() failed. This is a bug in the program. Sorry!\n"); initialized = 1; } for (t = s; *t; t++) /* TODO: handle case that regexec returns REG_ESPACE or REG_ASSERT. */ if (regexec(&url_pattern, t, 1, pmatch, 0) != REG_NOMATCH) { printf(""); print_esc(t, t + pmatch[0].rm_eo); printf(""); t += pmatch[0].rm_eo - 1; } else { switch (*t) { case '<': printf("<"); break; case '>': printf(">"); break; case '&': printf("&"); break; default: putchar(*t); } } } /* print_header -- print boilerplate at start of output */ static void print_header(struct icaltimetype start, struct icaldurationtype dur, const char *title) { struct icaltimetype end = icaltime_add(start, dur); printf("\n"); printf("\n"); printf("\n"); printf("\n"); printf(""); if (title) print_escaped(title); else printf("Calendar %d %s %d - %d %s %d", start.day, months[start.month], start.year, end.day, months[end.month], end.year); printf(" \n"); printf("\n"); printf("\n"); printf("\n"); } /* print_footer -- print boilerplate at end of output */ static void print_footer(const char *footer) { if (footer) printf("%s\n", footer); printf("\n"); printf("\n"); } /* print_as_one_word -- replace non-alphanumeric characters by dashes */ static void print_as_one_word(const char *s) { const char *t; for (t = s; *t; t++) if (isalnum(*t)) putchar(*t); else putchar('-'); } #if 0 /* print_attribute -- printf with &, " and newlines escaped */ static void print_attribute(const char *s) { const char *t; for (t = s; *t; t++) switch (*t) { case '<': printf("<"); break; case '>': printf(">"); break; case '&': printf("&"); break; case '"': printf("""); break; case '\n': printf(" "); break; default: putchar(*t); } } #endif /* print_event -- print HTML paragraph for one event */ static void print_event(const event_item ev, const int do_description, const int do_location) { icaltimezone *utc = icaltimezone_get_utc_timezone(); icaltimetype start_utc, end_utc; icalproperty *p, *desc, *loc; enum icalproperty_status status; int first; status = icalcomponent_get_status(ev.event); printf("\n\n"); } /* print_calendar -- print monthly calendars with events */ static void print_calendar(const struct icaltimetype start, const struct icaldurationtype duration, const int nrevents, const event_item events[], const int do_description, const int do_location, const int starts_on_monday, const int do_today, const struct icaltimetype now) { struct icaltimetype day; struct icaltimetype end; char s[9]; int y, m, d, w; int i = 0; /* Loop over events */ int skip; /* How many days to skip of that week until 1st */ int lastDay; if (starts_on_monday) lastDay = 2; else lastDay = 1; end = icaltime_add(start, duration); /* Loop over the years in our period */ for (y = start.year; y <= end.year; y++) { /* Loop over the months in this year */ for (m = (y == start.year ? start.month : 1); m <= (y == end.year ? end.month : 12); m++) { /* Is there a more efficient way to set day than via a string? */ sprintf(s, "%04d%02d01", y, m); day = icaltime_from_string(s); printf("\n"); /* Also add all categories as content */ first = 1; p = icalcomponent_get_first_property(ev.event, ICAL_CATEGORIES_PROPERTY); while (p) { if (first) first = 0; else printf(", "); print_as_one_word(icalproperty_get_categories(p)); p = icalcomponent_get_next_property(ev.event, ICAL_CATEGORIES_PROPERTY); } printf("\n"); /* If there is a time, print it */ start_utc = icaltime_convert_to_zone(ev.start, utc); end_utc = icaltime_convert_to_zone(ev.end, utc); if (ev.start.hour || ev.start.minute || ev.end.hour || ev.end.minute) printf("%02d:%02d-%02d:%02d\n", start_utc.year, start_utc.month, start_utc.day, start_utc.hour, start_utc.minute, start_utc.second, ev.start.hour, ev.start.minute, end_utc.year, end_utc.month, end_utc.day, end_utc.hour, end_utc.minute, end_utc.second, ev.end.hour, ev.end.minute); else printf("(whole day)\n", start_utc.year, start_utc.month, start_utc.day); /* Print the summary */ printf(""); p = icalcomponent_get_first_property(ev.event, ICAL_SUMMARY_PROPERTY); if (p) print_escaped_with_links(icalproperty_get_summary(p)); printf("\n"); /* If we want descriptions, check if there is one */ if (do_description) desc = icalcomponent_get_first_property(ev.event, ICAL_DESCRIPTION_PROPERTY); else desc = NULL; /* If we want locations, check if there is one */ if (do_location) loc = icalcomponent_get_first_property(ev.event, ICAL_LOCATION_PROPERTY); else loc = NULL; /* If we have a description and/or location, print them */ if (desc || loc) printf(""); if (desc) { printf(""); print_escaped_with_links(icalproperty_get_description(desc)); printf(""); } if (desc && loc) printf("\n"); if (loc) { printf(""); print_escaped_with_links(icalproperty_get_description(loc)); printf(""); } if (desc || loc) printf("
\n"); printf("
Monday | Tuesday | Wednesday | "); printf("Thursday | Friday | Saturday | "); printf("Sunday | \n"); } else { printf("Sunday | Monday | Tuesday | "); printf("Wednesday | Thursday | Friday | "); printf("Saturday | \n"); } printf("
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
\n"); } /* Skip events before this day (can only occur at very start) */ for (; i < nrevents && icaltime_compare_date_only(events[i].start, day) < 0; i++) ; /* Loop over the days in this month */ for (d = 1; d <= icaltime_days_in_month(m, y); d++) { sprintf(s, "%04d%02d%02d", y, m, d); day = icaltime_from_string(s); w = icaltime_day_of_week(day); if (w == lastDay && d != 1) { printf(" | |||||||||||||
%d \n\n", d); /* Print all events on this day (the events are sorted) */ for (; i < nrevents && icaltime_compare_date_only(events[i].start, day) == 0; i++) print_event(events[i], do_description, do_location); printf(" | \n");
}
printf("