diff options
Diffstat (limited to 'src/io.c')
-rw-r--r-- | src/io.c | 3338 |
1 files changed, 791 insertions, 2547 deletions
@@ -1,7 +1,7 @@ /* * Calcurse - text-based organizer * - * Copyright (c) 2004-2011 calcurse Development Team <misc@calcurse.org> + * Copyright (c) 2004-2012 calcurse Development Team <misc@calcurse.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,9 +45,7 @@ #include <errno.h> #include "calcurse.h" - -#define ICALDATEFMT "%Y%m%d" -#define ICALDATETIMEFMT "%Y%m%dT%H%M%S" +#include "sha1.h" typedef enum { PROGRESS_BAR_SAVE, @@ -68,650 +66,147 @@ enum { PROGRESS_BAR_EXPORT_TODO }; -typedef enum { - ICAL_VEVENT, - ICAL_VTODO, - ICAL_TYPES -} ical_types_e; - -typedef enum { - UNDEFINED, - APPOINTMENT, - EVENT -} ical_vevent_e; - -typedef struct { - enum recur_type type; - int freq; - long until; - unsigned count; -} ical_rpt_t; - struct ht_keybindings_s { - char *label; - enum key key; - HTABLE_ENTRY (ht_keybindings_s); + const char *label; + enum key key; + HTABLE_ENTRY(ht_keybindings_s); }; -/* Type definition for callbacks to multiple-mode export functions. */ -typedef void (*cb_export_t)(FILE *); -typedef void (*cb_dump_t)(FILE *, long, long, char *); - -/* Static functions used to add export functionalities. */ -static void ical_export_header (FILE *); -static void ical_export_recur_events (FILE *); -static void ical_export_events (FILE *); -static void ical_export_recur_apoints (FILE *); -static void ical_export_apoints (FILE *); -static void ical_export_todo (FILE *); -static void ical_export_footer (FILE *); - -static void pcal_export_header (FILE *); -static void pcal_export_recur_events (FILE *); -static void pcal_export_events (FILE *); -static void pcal_export_recur_apoints (FILE *); -static void pcal_export_apoints (FILE *); -static void pcal_export_todo (FILE *); -static void pcal_export_footer (FILE *); - -cb_export_t cb_export_header[IO_EXPORT_NBTYPES] = - {ical_export_header, pcal_export_header}; -cb_export_t cb_export_recur_events[IO_EXPORT_NBTYPES] = - {ical_export_recur_events, pcal_export_recur_events}; -cb_export_t cb_export_events[IO_EXPORT_NBTYPES] = - {ical_export_events, pcal_export_events}; -cb_export_t cb_export_recur_apoints[IO_EXPORT_NBTYPES] = - {ical_export_recur_apoints, pcal_export_recur_apoints}; -cb_export_t cb_export_apoints[IO_EXPORT_NBTYPES] = - {ical_export_apoints, pcal_export_apoints}; -cb_export_t cb_export_todo[IO_EXPORT_NBTYPES] = - {ical_export_todo, pcal_export_todo}; -cb_export_t cb_export_footer[IO_EXPORT_NBTYPES] = - {ical_export_footer, pcal_export_footer}; - -static char *ical_recur_type[RECUR_TYPES] = - { "", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" }; +static void load_keys_ht_getkey(struct ht_keybindings_s *, const char **, + int *); +static int load_keys_ht_compare(struct ht_keybindings_s *, + struct ht_keybindings_s *); + +#define HSIZE 256 +HTABLE_HEAD(ht_keybindings, HSIZE, ht_keybindings_s); +HTABLE_PROTOTYPE(ht_keybindings, ht_keybindings_s) + HTABLE_GENERATE(ht_keybindings, ht_keybindings_s, load_keys_ht_getkey, + load_keys_ht_compare) /* Draw a progress bar while saving, loading or exporting data. */ -static void -progress_bar (progress_bar_t type, int progress) +static void progress_bar(progress_bar_t type, int progress) { -#define SLEEPTIME 125000 #define NBFILES 4 #define NBEXPORTED 3 #define LABELENGTH 15 int i, step, steps; - char *mesg_sav = _("Saving..."); - char *mesg_load = _("Loading..."); - char *mesg_export = _("Exporting..."); - char *error_msg = _("Internal error while displaying progress bar"); - char *barchar = "|"; - char *file[NBFILES] = { + const char *mesg_sav = _("Saving..."); + const char *mesg_load = _("Loading..."); + const char *mesg_export = _("Exporting..."); + const char *error_msg = _("Internal error while displaying progress bar"); + const char *barchar = "|"; + const char *file[NBFILES] = { "[ conf ]", "[ todo ]", "[ apts ]", "[ keys ]" }; - char *data[NBEXPORTED] = { + const char *data[NBEXPORTED] = { "[ events ]", "[appointments]", "[ todo ]" }; - int ipos = LABELENGTH + 2; + int ipos = LABELENGTH + 2; int epos[NBFILES]; /* progress bar length init. */ ipos = LABELENGTH + 2; steps = (type == PROGRESS_BAR_EXPORT) ? NBEXPORTED : NBFILES; - step = floor (col / (steps + 1)); + step = floor(col / (steps + 1)); for (i = 0; i < steps - 1; i++) epos[i] = (i + 2) * step; epos[steps - 1] = col - 2; - switch (type) - { - case PROGRESS_BAR_SAVE: - EXIT_IF (progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); - status_mesg (mesg_sav, file[progress]); - break; - case PROGRESS_BAR_LOAD: - EXIT_IF (progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); - status_mesg (mesg_load, file[progress]); - break; - case PROGRESS_BAR_EXPORT: - EXIT_IF (progress < 0 - || progress > PROGRESS_BAR_EXPORT_TODO, "%s", error_msg); - status_mesg (mesg_export, data[progress]); - break; - } + switch (type) { + case PROGRESS_BAR_SAVE: + EXIT_IF(progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); + status_mesg(mesg_sav, file[progress]); + break; + case PROGRESS_BAR_LOAD: + EXIT_IF(progress < 0 || progress > PROGRESS_BAR_KEYS, "%s", error_msg); + status_mesg(mesg_load, file[progress]); + break; + case PROGRESS_BAR_EXPORT: + EXIT_IF(progress < 0 + || progress > PROGRESS_BAR_EXPORT_TODO, "%s", error_msg); + status_mesg(mesg_export, data[progress]); + break; + } /* Draw the progress bar. */ - mvwprintw (win[STA].p, 1, ipos, barchar); - mvwprintw (win[STA].p, 1, epos[steps - 1], barchar); - custom_apply_attr (win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 1, ipos, barchar); + mvwprintw(win[STA].p, 1, epos[steps - 1], barchar); + custom_apply_attr(win[STA].p, ATTR_HIGHEST); for (i = ipos + 1; i < epos[progress]; i++) - mvwaddch (win[STA].p, 1, i, ' ' | A_REVERSE); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); - wmove (win[STA].p, 0, 0); - wins_wrefresh (win[STA].p); - (void)usleep (SLEEPTIME); -#undef SLEEPTIME + mvwaddch(win[STA].p, 1, i, ' ' | A_REVERSE); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); + wmove(win[STA].p, 0, 0); + wins_wrefresh(win[STA].p); #undef NBFILES #undef NBEXPORTED #undef LABELENGTH } /* Ask user for a file name to export data to. */ -static FILE * -get_export_stream (enum export_type type) +static FILE *get_export_stream(enum export_type type) { FILE *stream; int cancel; char *home, *stream_name; - char *question = _("Choose the file used to export calcurse data:"); - char *wrong_name = - _("The file cannot be accessed, please enter another file name."); - char *press_enter = _("Press [ENTER] to continue."); - const char *file_ext[IO_EXPORT_NBTYPES] = {"ical", "txt"}; + const char *question = _("Choose the file used to export calcurse data:"); + const char *wrong_name = + _("The file cannot be accessed, please enter another file name."); + const char *press_enter = _("Press [ENTER] to continue."); + const char *file_ext[IO_EXPORT_NBTYPES] = { "ical", "txt" }; stream = NULL; - stream_name = (char *) mem_malloc (BUFSIZ); - if ((home = getenv ("HOME")) != NULL) - (void)snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", home, - file_ext[type]); + stream_name = (char *)mem_malloc(BUFSIZ); + if ((home = getenv("HOME")) != NULL) + snprintf(stream_name, BUFSIZ, "%s/calcurse.%s", home, file_ext[type]); else - (void)snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", get_tempdir (), - file_ext[type]); - - while (stream == NULL) - { - status_mesg (question, ""); - cancel = updatestring (win[STA].p, &stream_name, 0, 1); - if (cancel) - { - mem_free (stream_name); - return (NULL); - } - stream = fopen (stream_name, "w"); - if (stream == NULL) - { - status_mesg (wrong_name, press_enter); - (void)wgetch (win[STA].p); - } - } - mem_free (stream_name); - - return (stream); -} - -/* - * Travel through each occurence of an item, and execute the given callback - * (mainly used to export data). - */ -static void -foreach_date_dump (const long date_end, struct rpt *rpt, llist_t *exc, - long item_first_date, long item_dur, char *item_mesg, - cb_dump_t cb_dump, FILE *stream) -{ - long date, item_time; - struct tm lt; - time_t t; - - t = item_first_date; - lt = *localtime (&t); - lt.tm_hour = lt.tm_min = lt.tm_sec = 0; - lt.tm_isdst = -1; - date = mktime (<); - item_time = item_first_date - date; - - while (date <= date_end && date <= rpt->until) - { - if (recur_item_inday (item_first_date, exc, rpt->type, rpt->freq, - rpt->until, date)) - { - (*cb_dump)(stream, date + item_time, item_dur, item_mesg); - } - switch (rpt->type) - { - case RECUR_DAILY: - date = date_sec_change (date, 0, rpt->freq); - break; - case RECUR_WEEKLY: - date = date_sec_change (date, 0, rpt->freq * WEEKINDAYS); - break; - case RECUR_MONTHLY: - date = date_sec_change (date, rpt->freq, 0); - break; - case RECUR_YEARLY: - date = date_sec_change (date, rpt->freq * 12, 0); - break; - default: - EXIT (_("incoherent repetition type")); - /* NOTREACHED */ - break; - } - } -} - -/* iCal alarm notification. */ -static void -ical_export_valarm (FILE *stream) -{ - (void)fprintf (stream, "BEGIN:VALARM\n"); - pthread_mutex_lock (&nbar.mutex); - (void)fprintf (stream, "TRIGGER:-P%dS\n", nbar.cntdwn); - pthread_mutex_unlock (&nbar.mutex); - (void)fprintf (stream, "ACTION:DISPLAY\n"); - (void)fprintf (stream, "END:VALARM\n"); -} - -/* Export header. */ -static void -ical_export_header (FILE *stream) -{ - (void)fprintf (stream, "BEGIN:VCALENDAR\n"); - (void)fprintf (stream, "PRODID:-//calcurse//NONSGML v%s//EN\n", VERSION); - (void)fprintf (stream, "VERSION:2.0\n"); -} - -static void -pcal_export_header (FILE *stream) -{ - (void)fprintf (stream, "# calcurse pcal export\n"); - (void)fprintf (stream, "\n# =======\n# options\n# =======\n"); - (void)fprintf (stream, "opt -A -K -l -m -F %s\n", - calendar_week_begins_on_monday () ? - "Monday" : "Sunday"); - (void)fprintf (stream, "# Display week number (i.e. 1-52) on every Monday\n"); - (void)fprintf (stream, "all monday in all week %%w\n"); - (void)fprintf (stream, "\n"); -} - -/* Export footer. */ -static void -ical_export_footer (FILE *stream) -{ - (void)fprintf (stream, "END:VCALENDAR\n"); -} - -static void -pcal_export_footer (FILE *stream) -{ -} - -/* Export recurrent events. */ -static void -ical_export_recur_events (FILE *stream) -{ - llist_item_t *i, *j; - char ical_date[BUFSIZ]; - - LLIST_FOREACH (&recur_elist, i) - { - struct recur_event *rev = LLIST_GET_DATA (i); - date_sec2date_fmt (rev->day, ICALDATEFMT, ical_date); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_date); - (void)fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d", - ical_recur_type[rev->rpt->type], rev->rpt->freq); - - if (rev->rpt->until != 0) - { - date_sec2date_fmt (rev->rpt->until, ICALDATEFMT, ical_date); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); - } - else - (void)fprintf (stream, "\n"); - - if (LLIST_FIRST (&rev->exc)) - { - (void)fprintf (stream, "EXDATE:"); - LLIST_FOREACH (&rev->exc, j) - { - struct excp *exc = LLIST_GET_DATA (j); - date_sec2date_fmt (exc->st, ICALDATEFMT, ical_date); - (void)fprintf (stream, "%s", ical_date); - if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); - else - (void)fprintf (stream, "\n"); - } - } - - (void)fprintf (stream, "SUMMARY:%s\n", rev->mesg); - (void)fprintf (stream, "END:VEVENT\n"); - } -} - -/* Format and dump event data to a pcal formatted file. */ -static void -pcal_dump_event (FILE *stream, long event_date, long event_dur, - char *event_mesg) -{ - char pcal_date[BUFSIZ]; - - date_sec2date_fmt (event_date, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, event_mesg); -} - -/* Format and dump appointment data to a pcal formatted file. */ -static void -pcal_dump_apoint (FILE *stream, long apoint_date, long apoint_dur, - char *apoint_mesg) -{ - char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; - - date_sec2date_fmt (apoint_date, "%b %d", pcal_date); - date_sec2date_fmt (apoint_date, "%R", pcal_beg); - date_sec2date_fmt (apoint_date + apoint_dur, "%R", pcal_end); - (void)fprintf (stream, "%s ", pcal_date); - (void)fprintf (stream, "(%s -> %s) %s\n", pcal_beg, pcal_end, apoint_mesg); -} - -static void -pcal_export_recur_events (FILE *stream) -{ - llist_item_t *i; - char pcal_date[BUFSIZ]; - - (void)fprintf (stream, "\n# ============="); - (void)fprintf (stream, "\n# Recur. Events"); - (void)fprintf (stream, "\n# =============\n"); - (void)fprintf (stream, - "# (pcal does not support from..until dates specification\n"); - - LLIST_FOREACH (&recur_elist, i) - { - struct recur_event *rev = LLIST_GET_DATA (i); - if (rev->rpt->until == 0 && rev->rpt->freq == 1) - { - switch (rev->rpt->type) - { - case RECUR_DAILY: - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "all day on_or_after %s %s\n", - pcal_date, rev->mesg); - break; - case RECUR_WEEKLY: - date_sec2date_fmt (rev->day, "%a", pcal_date); - (void)fprintf (stream, "all %s on_or_after ", pcal_date); - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, rev->mesg); - break; - case RECUR_MONTHLY: - date_sec2date_fmt (rev->day, "%d", pcal_date); - (void)fprintf (stream, "day on all %s %s\n", pcal_date, - rev->mesg); - break; - case RECUR_YEARLY: - date_sec2date_fmt (rev->day, "%b %d", pcal_date); - (void)fprintf (stream, "%s %s\n", pcal_date, rev->mesg); - break; - default: - EXIT (_("incoherent repetition type")); - } - } - else - { - const long YEAR_START = calendar_start_of_year (); - const long YEAR_END = calendar_end_of_year (); - - if (rev->day < YEAR_END && rev->day > YEAR_START) - foreach_date_dump (YEAR_END, rev->rpt, &rev->exc, rev->day, 0, - rev->mesg, (cb_dump_t) pcal_dump_event, stream); - } - } -} - -/* Export events. */ -static void -ical_export_events (FILE *stream) -{ - llist_item_t *i; - char ical_date[BUFSIZ]; - - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - date_sec2date_fmt (ev->day, ICALDATEFMT, ical_date); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_date); - (void)fprintf (stream, "SUMMARY:%s\n", ev->mesg); - (void)fprintf (stream, "END:VEVENT\n"); - } -} - -static void -pcal_export_events (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "\n# ======\n# Events\n# ======\n"); - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - pcal_dump_event (stream, ev->day, 0, ev->mesg); - } - (void)fprintf (stream, "\n"); -} - -/* Export recurrent appointments. */ -static void -ical_export_recur_apoints (FILE *stream) -{ - llist_item_t *i, *j; - char ical_datetime[BUFSIZ]; - char ical_date[BUFSIZ]; - - LLIST_TS_LOCK (&recur_alist_p); - LLIST_TS_FOREACH (&recur_alist_p, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - - date_sec2date_fmt (rapt->start, ICALDATETIMEFMT, ical_datetime); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_datetime); - (void)fprintf (stream, "DURATION:PT0H0M%ldS\n", rapt->dur); - (void)fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d", - ical_recur_type[rapt->rpt->type], rapt->rpt->freq); - - if (rapt->rpt->until != 0) - { - date_sec2date_fmt (rapt->rpt->until + HOURINSEC, ICALDATEFMT, - ical_date); - (void)fprintf (stream, ";UNTIL=%s\n", ical_date); - } - else - (void)fprintf (stream, "\n"); - - if (LLIST_FIRST (&rapt->exc)) - { - (void)fprintf (stream, "EXDATE:"); - LLIST_FOREACH (&rapt->exc, j) - { - struct excp *exc = LLIST_GET_DATA (j); - date_sec2date_fmt (exc->st, ICALDATEFMT, ical_date); - (void)fprintf (stream, "%s", ical_date); - if (LLIST_NEXT (j)) - (void)fprintf (stream, ","); - else - (void)fprintf (stream, "\n"); - } - } - - (void)fprintf (stream, "SUMMARY:%s\n", rapt->mesg); - if (rapt->state & APOINT_NOTIFY) - ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); - } - LLIST_TS_UNLOCK (&recur_alist_p); -} - -static void -pcal_export_recur_apoints (FILE *stream) -{ - llist_item_t *i; - char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ]; - - (void)fprintf (stream, "\n# =============="); - (void)fprintf (stream, "\n# Recur. Apoints"); - (void)fprintf (stream, "\n# ==============\n"); - (void)fprintf (stream, - "# (pcal does not support from..until dates specification\n"); - - LLIST_TS_FOREACH (&recur_alist_p, i) - { - struct recur_apoint *rapt = LLIST_TS_GET_DATA (i); - - if (rapt->rpt->until == 0 && rapt->rpt->freq == 1) - { - date_sec2date_fmt (rapt->start, "%R", pcal_beg); - date_sec2date_fmt (rapt->start + rapt->dur, "%R", pcal_end); - switch (rapt->rpt->type) - { - case RECUR_DAILY: - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "all day on_or_after %s (%s -> %s) %s\n", - pcal_date, pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_WEEKLY: - date_sec2date_fmt (rapt->start, "%a", pcal_date); - (void)fprintf (stream, "all %s on_or_after ", pcal_date); - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "%s (%s -> %s) %s\n", pcal_date, - pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_MONTHLY: - date_sec2date_fmt (rapt->start, "%d", pcal_date); - (void)fprintf (stream, "day on all %s (%s -> %s) %s\n", - pcal_date, pcal_beg, pcal_end, rapt->mesg); - break; - case RECUR_YEARLY: - date_sec2date_fmt (rapt->start, "%b %d", pcal_date); - (void)fprintf (stream, "%s (%s -> %s) %s\n", pcal_date, - pcal_beg, pcal_end, rapt->mesg); - break; - default: - EXIT (_("incoherent repetition type")); - } - } - else - { - const long YEAR_START = calendar_start_of_year (); - const long YEAR_END = calendar_end_of_year (); - - if (rapt->start < YEAR_END && rapt->start > YEAR_START) - foreach_date_dump (YEAR_END, rapt->rpt, &rapt->exc, rapt->start, - rapt->dur, rapt->mesg, - (cb_dump_t)pcal_dump_apoint, stream); - } - } -} - -/* Export appointments. */ -static void -ical_export_apoints (FILE *stream) -{ - llist_item_t *i; - char ical_datetime[BUFSIZ]; - - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - date_sec2date_fmt (apt->start, ICALDATETIMEFMT, ical_datetime); - (void)fprintf (stream, "BEGIN:VEVENT\n"); - (void)fprintf (stream, "DTSTART:%s\n", ical_datetime); - (void)fprintf (stream, "DURATION:P%ldDT%ldH%ldM%ldS\n", - apt->dur / DAYINSEC, - (apt->dur / HOURINSEC) % 24, - (apt->dur / MININSEC) % 60, - apt->dur % MININSEC); - (void)fprintf (stream, "SUMMARY:%s\n", apt->mesg); - if (apt->state & APOINT_NOTIFY) - ical_export_valarm (stream); - (void)fprintf (stream, "END:VEVENT\n"); + snprintf(stream_name, BUFSIZ, "%s/calcurse.%s", get_tempdir(), + file_ext[type]); + + while (stream == NULL) { + status_mesg(question, ""); + cancel = updatestring(win[STA].p, &stream_name, 0, 1); + if (cancel) { + mem_free(stream_name); + return NULL; } - LLIST_TS_UNLOCK (&alist_p); -} - -static void -pcal_export_apoints (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "\n# ============\n# Appointments\n# ============\n"); - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - pcal_dump_apoint (stream, apt->start, apt->dur, apt->mesg); + stream = fopen(stream_name, "w"); + if (stream == NULL) { + status_mesg(wrong_name, press_enter); + wgetch(win[STA].p); } - LLIST_TS_UNLOCK (&alist_p); - (void)fprintf (stream, "\n"); -} - -/* Export todo items. */ -static void -ical_export_todo (FILE *stream) -{ - llist_item_t *i; - - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->id < 0) /* completed items */ - continue; + } + mem_free(stream_name); - (void)fprintf (stream, "BEGIN:VTODO\n"); - (void)fprintf (stream, "PRIORITY:%d\n", todo->id); - (void)fprintf (stream, "SUMMARY:%s\n", todo->mesg); - (void)fprintf (stream, "END:VTODO\n"); - } -} - -static void -pcal_export_todo (FILE *stream) -{ - llist_item_t *i; - - (void)fprintf (stream, "#\n# Todos\n#\n"); - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->id < 0) /* completed items */ - continue; - - (void)fprintf (stream, "note all "); - (void)fprintf (stream, "%d. %s\n", todo->id, todo->mesg); - } - (void)fprintf (stream, "\n"); + return stream; } /* Append a line to a file. */ -unsigned -io_fprintln (const char *fname, const char *fmt, ...) +unsigned io_fprintln(const char *fname, const char *fmt, ...) { FILE *fp; va_list ap; char buf[BUFSIZ]; int ret; - fp = fopen (fname, "a"); - RETVAL_IF (!fp, 0, _("Failed to open \"%s\", - %s\n"), - fname, strerror (errno)); + fp = fopen(fname, "a"); + RETVAL_IF(!fp, 0, _("Failed to open \"%s\", - %s\n"), fname, strerror(errno)); - va_start (ap, fmt); - ret = vsnprintf (buf, sizeof buf, fmt, ap); - RETVAL_IF (ret < 0, 0, _("Failed to build message\n")); - va_end (ap); + va_start(ap, fmt); + ret = vsnprintf(buf, sizeof buf, fmt, ap); + RETVAL_IF(ret < 0, 0, _("Failed to build message\n")); + va_end(ap); - ret = fprintf (fp, "%s", buf); - RETVAL_IF (ret < 0, 0, _("Failed to print message \"%s\"\n"), buf); + ret = fprintf(fp, "%s", buf); + RETVAL_IF(ret < 0, 0, _("Failed to print message \"%s\"\n"), buf); - ret = fclose (fp); - RETVAL_IF (ret != 0, 0, _("Failed to close \"%s\" - %s\n"), - fname, strerror (errno)); + ret = fclose(fp); + RETVAL_IF(ret != 0, 0, _("Failed to close \"%s\" - %s\n"), + fname, strerror(errno)); return 1; } @@ -723,383 +218,231 @@ io_fprintln (const char *fname, const char *fmt, ...) * is created. * The datadir argument can be use to specify an alternative data root dir. */ -void -io_init (char *cfile, char *datadir) +void io_init(const char *cfile, const char *datadir) { FILE *data_file; - char *home; + const char *home; char apts_file[BUFSIZ] = ""; int ch; - if (datadir != NULL) - { - home = datadir; - (void)snprintf (path_dir, BUFSIZ, "%s", home); - (void)snprintf (path_todo, BUFSIZ, "%s/" TODO_PATH_NAME, home); - (void)snprintf (path_conf, BUFSIZ, "%s/" CONF_PATH_NAME, home); - (void)snprintf (path_notes, BUFSIZ, "%s/" NOTES_DIR_NAME, home); - (void)snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH_NAME, home); - (void)snprintf (path_keys, BUFSIZ, "%s/" KEYS_PATH_NAME, home); - (void)snprintf (path_cpid, BUFSIZ, "%s/" CPID_PATH_NAME, home); - (void)snprintf (path_dpid, BUFSIZ, "%s/" DPID_PATH_NAME, home); - (void)snprintf (path_dmon_log, BUFSIZ, "%s/" DLOG_PATH_NAME, home); - } - else - { - home = getenv ("HOME"); - if (home == NULL) - { - home = "."; - } - (void)snprintf (path_dir, BUFSIZ, "%s/" DIR_NAME, home); - (void)snprintf (path_todo, BUFSIZ, "%s/" TODO_PATH, home); - (void)snprintf (path_conf, BUFSIZ, "%s/" CONF_PATH, home); - (void)snprintf (path_keys, BUFSIZ, "%s/" KEYS_PATH, home); - (void)snprintf (path_cpid, BUFSIZ, "%s/" CPID_PATH, home); - (void)snprintf (path_dpid, BUFSIZ, "%s/" DPID_PATH, home); - (void)snprintf (path_dmon_log, BUFSIZ, "%s/" DLOG_PATH, home); - (void)snprintf (path_notes, BUFSIZ, "%s/" NOTES_DIR, home); - if (cfile == NULL) - { - (void)snprintf (path_apts, BUFSIZ, "%s/" APTS_PATH, home); - } - else - { - (void)snprintf (apts_file, BUFSIZ, "%s", cfile); - (void)strncpy (path_apts, apts_file, BUFSIZ); - /* check if the file exists, otherwise create it */ - data_file = fopen (path_apts, "r"); - if (data_file == NULL) - { - printf (_("%s does not exist, create it now [y or n] ? "), - path_apts); - ch = getchar (); - switch (ch) - { - case 'N': - case 'n': - printf (_("aborting...\n")); - exit_calcurse (EXIT_FAILURE); - break; - - case 'Y': - case 'y': - data_file = fopen (path_apts, "w"); - if (data_file == NULL) - { - perror (path_apts); - exit_calcurse (EXIT_FAILURE); - } - else - { - printf (_("%s successfully created\n"), path_apts); - printf (_("starting interactive mode...\n")); - } - break; - - default: - printf (_("aborting...\n")); - exit_calcurse (EXIT_FAILURE); - break; - } - } - file_close (data_file, __FILE_POS__); + if (datadir != NULL) { + home = datadir; + snprintf(path_dir, BUFSIZ, "%s", home); + snprintf(path_todo, BUFSIZ, "%s/" TODO_PATH_NAME, home); + snprintf(path_conf, BUFSIZ, "%s/" CONF_PATH_NAME, home); + snprintf(path_notes, BUFSIZ, "%s/" NOTES_DIR_NAME, home); + snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH_NAME, home); + snprintf(path_keys, BUFSIZ, "%s/" KEYS_PATH_NAME, home); + snprintf(path_cpid, BUFSIZ, "%s/" CPID_PATH_NAME, home); + snprintf(path_dpid, BUFSIZ, "%s/" DPID_PATH_NAME, home); + snprintf(path_dmon_log, BUFSIZ, "%s/" DLOG_PATH_NAME, home); + } else { + home = getenv("HOME"); + if (home == NULL) { + home = "."; + } + snprintf(path_dir, BUFSIZ, "%s/" DIR_NAME, home); + snprintf(path_todo, BUFSIZ, "%s/" TODO_PATH, home); + snprintf(path_conf, BUFSIZ, "%s/" CONF_PATH, home); + snprintf(path_keys, BUFSIZ, "%s/" KEYS_PATH, home); + snprintf(path_cpid, BUFSIZ, "%s/" CPID_PATH, home); + snprintf(path_dpid, BUFSIZ, "%s/" DPID_PATH, home); + snprintf(path_dmon_log, BUFSIZ, "%s/" DLOG_PATH, home); + snprintf(path_notes, BUFSIZ, "%s/" NOTES_DIR, home); + if (cfile == NULL) { + snprintf(path_apts, BUFSIZ, "%s/" APTS_PATH, home); + } else { + snprintf(apts_file, BUFSIZ, "%s", cfile); + strncpy(path_apts, apts_file, BUFSIZ); + /* check if the file exists, otherwise create it */ + data_file = fopen(path_apts, "r"); + if (data_file == NULL) { + printf(_("%s does not exist, create it now [y or n] ? "), path_apts); + ch = getchar(); + switch (ch) { + case 'N': + case 'n': + puts(_("aborting...\n")); + exit_calcurse(EXIT_FAILURE); + break; + + case 'Y': + case 'y': + data_file = fopen(path_apts, "w"); + if (data_file == NULL) { + perror(path_apts); + exit_calcurse(EXIT_FAILURE); + } else { + printf(_("%s successfully created\n"), path_apts); + puts(_("starting interactive mode...\n")); + } + break; + + default: + puts(_("aborting...\n")); + exit_calcurse(EXIT_FAILURE); + break; } + } + file_close(data_file, __FILE_POS__); } + } } -void -io_extract_data (char *dst_data, const char *org, int len) +void io_extract_data(char *dst_data, const char *org, int len) { int i; - for (i = 0; i < len - 1; i++) - { - if (*org == '\n' || *org == '\0') - break; - *dst_data++ = *org++; - } + for (; *org == ' ' || *org == '\t'; org++) ; + for (i = 0; i < len - 1; i++) { + if (*org == '\n' || *org == '\0' || *org == '#') + break; + *dst_data++ = *org++; + } *dst_data = '\0'; } -void -display_mark (void) +static void display_mark(void) { const int DISPLAY_TIME = 1; WINDOW *mwin; - mwin = newwin (1, 2, 1, col - 3); + mwin = newwin(1, 2, 1, col - 3); - custom_apply_attr (mwin, ATTR_HIGHEST); - mvwprintw (mwin, 0, 0, "**"); - wins_wrefresh (mwin); - sleep (DISPLAY_TIME); - mvwprintw (mwin, 0, 0, " "); - wins_wrefresh (mwin); - delwin (mwin); - wins_doupdate (); + custom_apply_attr(mwin, ATTR_HIGHEST); + mvwprintw(mwin, 0, 0, "**"); + wins_wrefresh(mwin); + sleep(DISPLAY_TIME); + mvwprintw(mwin, 0, 0, " "); + wins_wrefresh(mwin); + delwin(mwin); + wins_doupdate(); } static pthread_mutex_t io_save_mutex = PTHREAD_MUTEX_INITIALIZER; -/* Save the user configuration. */ -unsigned -io_save_conf (struct conf *conf) -{ - char *config_txt = - "#\n" - "# Calcurse configuration file\n#\n" - "# This file sets the configuration options used by Calcurse. These\n" - "# options are usually set from within Calcurse. A line beginning with \n" - "# a space or tab is considered to be a continuation of the previous " - "line.\n" - "# For a variable to be unset its value must be blank.\n" - "# To set a variable to the empty string its value should be \"\".\n" - "# Lines beginning with \"#\" are comments, and ignored by Calcurse.\n"; - char theme_name[BUFSIZ]; - FILE *fp; - - if ((fp = fopen (path_conf, "w")) == NULL) - return 0; - - custom_color_theme_name (theme_name); - - (void)fprintf (fp, "%s\n", config_txt); - - (void)fprintf (fp, "# If this option is set to yes, " - "automatic save is done when quitting\n"); - (void)fprintf (fp, "auto_save=\n"); - (void)fprintf (fp, "%s\n", (conf->auto_save) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If not null, perform automatic saves every " - "'periodic_save' minutes\n"); - (void)fprintf (fp, "periodic_save=\n"); - (void)fprintf (fp, "%d\n", conf->periodic_save); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "confirmation is required before quitting\n"); - (void)fprintf (fp, "confirm_quit=\n"); - (void)fprintf (fp, "%s\n", (conf->confirm_quit) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "confirmation is required before deleting an event\n"); - (void)fprintf (fp, "confirm_delete=\n"); - (void)fprintf (fp, "%s\n", (conf->confirm_delete) ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "messages about loaded and saved data will not be displayed\n"); - (void)fprintf (fp, "skip_system_dialogs=\n"); - (void)fprintf (fp, "%s\n", (conf->skip_system_dialogs) ? "yes" : "no"); - - (void)fprintf (fp, - "\n# If this option is set to yes, progress bar appearing " - "when saving data will not be displayed\n"); - (void)fprintf (fp, "skip_progress_bar=\n"); - (void)fprintf (fp, "%s\n", (conf->skip_progress_bar) ? "yes" : "no"); - - (void)fprintf (fp, "\n# Default calendar view (0)monthly (1)weekly:\n"); - (void)fprintf (fp, "calendar_default_view=\n"); - (void)fprintf (fp, "%d\n", calendar_get_view ()); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "monday is the first day of the week, else it is sunday\n"); - (void)fprintf (fp, "week_begins_on_monday=\n"); - (void)fprintf (fp, "%s\n", - (calendar_week_begins_on_monday ())? "yes" : "no"); - - (void)fprintf (fp, "\n# This is the color theme used for menus :\n"); - (void)fprintf (fp, "color-theme=\n"); - (void)fprintf (fp, "%s\n", theme_name); - - (void)fprintf (fp, "\n# This is the layout of the calendar :\n"); - (void)fprintf (fp, "layout=\n"); - (void)fprintf (fp, "%d\n", wins_layout ()); - - (void)fprintf (fp, "\n# Width (in percentage, 0 being minimun width) " - "of the side bar :\n"); - (void)fprintf (fp, "side-bar_width=\n"); - (void)fprintf (fp, "%d\n", wins_sbar_wperc ()); - - if (ui_mode == UI_CURSES) - pthread_mutex_lock (&nbar.mutex); - (void)fprintf (fp, - "\n# If this option is set to yes, " - "notify-bar will be displayed :\n"); - (void)fprintf (fp, "notify-bar_show=\n"); - (void)fprintf (fp, "%s\n", (nbar.show) ? "yes" : "no"); - - (void)fprintf (fp, - "\n# Format of the date to be displayed inside notify-bar :\n"); - (void)fprintf (fp, "notify-bar_date=\n"); - (void)fprintf (fp, "%s\n", nbar.datefmt); - - (void)fprintf (fp, - "\n# Format of the time to be displayed inside notify-bar :\n"); - (void)fprintf (fp, "notify-bar_clock=\n"); - (void)fprintf (fp, "%s\n", nbar.timefmt); - - (void)fprintf (fp, - "\n# Warn user if he has an appointment within next " - "'notify-bar_warning' seconds :\n"); - (void)fprintf (fp, "notify-bar_warning=\n"); - (void)fprintf (fp, "%d\n", nbar.cntdwn); - - (void)fprintf (fp, "\n# Command used to notify user of " - "an upcoming appointment :\n"); - (void)fprintf (fp, "notify-bar_command=\n"); - (void)fprintf (fp, "%s\n", nbar.cmd); - - (void)fprintf (fp, "\n# Format of the date to be displayed " - "in non-interactive mode :\n"); - (void)fprintf (fp, "output_datefmt=\n"); - (void)fprintf (fp, "%s\n", conf->output_datefmt); - - (void)fprintf (fp, "\n# Format to be used when entering a date " - "(1)mm/dd/yyyy (2)dd/mm/yyyy (3)yyyy/mm/dd) " - "(4)yyyy-mm-dd:\n"); - (void)fprintf (fp, "input_datefmt=\n"); - (void)fprintf (fp, "%d\n", conf->input_datefmt); - - if (ui_mode == UI_CURSES) - pthread_mutex_unlock (&nbar.mutex); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "calcurse will run in background to get notifications " - "after exiting\n"); - (void)fprintf (fp, "notify-daemon_enable=\n"); - (void)fprintf (fp, "%s\n", dmon.enable ? "yes" : "no"); - - (void)fprintf (fp, "\n# If this option is set to yes, " - "activity will be logged when running in background\n"); - (void)fprintf (fp, "notify-daemon_log=\n"); - (void)fprintf (fp, "%s\n", dmon.log ? "yes" : "no"); - - file_close (fp, __FILE_POS__); - - return 1; -} - /* * Save the apts data file, which contains the * appointments first, and then the events. * Recursive items are written first. */ -unsigned -io_save_apts (void) +unsigned io_save_apts(void) { llist_item_t *i; FILE *fp; - if ((fp = fopen (path_apts, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_apts, "w")) == NULL) return 0; - recur_save_data (fp); + recur_save_data(fp); if (ui_mode == UI_CURSES) - LLIST_TS_LOCK (&alist_p); - LLIST_TS_FOREACH (&alist_p, i) - { - struct apoint *apt = LLIST_TS_GET_DATA (i); - apoint_write (apt, fp); - } + LLIST_TS_LOCK(&alist_p); + LLIST_TS_FOREACH(&alist_p, i) { + struct apoint *apt = LLIST_TS_GET_DATA(i); + apoint_write(apt, fp); + } if (ui_mode == UI_CURSES) - LLIST_TS_UNLOCK (&alist_p); + LLIST_TS_UNLOCK(&alist_p); - LLIST_FOREACH (&eventlist, i) - { - struct event *ev = LLIST_TS_GET_DATA (i); - event_write (ev, fp); - } - file_close (fp, __FILE_POS__); + LLIST_FOREACH(&eventlist, i) { + struct event *ev = LLIST_TS_GET_DATA(i); + event_write(ev, fp); + } + file_close(fp, __FILE_POS__); return 1; } /* Save the todo data file. */ -unsigned -io_save_todo (void) +unsigned io_save_todo(void) { llist_item_t *i; FILE *fp; - if ((fp = fopen (path_todo, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_todo, "w")) == NULL) return 0; - LLIST_FOREACH (&todolist, i) - { - struct todo *todo = LLIST_TS_GET_DATA (i); - if (todo->note) - (void)fprintf (fp, "[%d]>%s %s\n", todo->id, todo->note, todo->mesg); - else - (void)fprintf (fp, "[%d] %s\n", todo->id, todo->mesg); - } - file_close (fp, __FILE_POS__); + LLIST_FOREACH(&todolist, i) { + struct todo *todo = LLIST_TS_GET_DATA(i); + todo_write(todo, fp); + } + file_close(fp, __FILE_POS__); return 1; } /* Save user-defined keys */ -unsigned -io_save_keys (void) +unsigned io_save_keys(void) { FILE *fp; - if ((fp = fopen (path_keys, "w")) == NULL) + if (read_only) + return 1; + + if ((fp = fopen(path_keys, "w")) == NULL) return 0; - keys_save_bindings (fp); - file_close (fp, __FILE_POS__); + keys_save_bindings(fp); + file_close(fp, __FILE_POS__); return 1; } /* Save the calendar data */ -void -io_save_cal (struct conf *conf, enum save_display display) +void io_save_cal(enum save_display display) { - char *access_pb = _("Problems accessing data file ..."); - char *save_success = _("The data files were successfully saved"); - char *enter = _("Press [ENTER] to continue"); + const char *access_pb = _("Problems accessing data file ..."); + const char *save_success = _("The data files were successfully saved"); + const char *enter = _("Press [ENTER] to continue"); int show_bar; - pthread_mutex_lock (&io_save_mutex); + if (read_only) + return; + + pthread_mutex_lock(&io_save_mutex); show_bar = 0; if (ui_mode == UI_CURSES && display == IO_SAVE_DISPLAY_BAR - && !conf->skip_progress_bar) + && conf.progress_bar) show_bar = 1; else if (ui_mode == UI_CURSES && display == IO_SAVE_DISPLAY_MARK) - display_mark (); + display_mark(); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_CONF); - if (!io_save_conf (conf)) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_CONF); + if (!config_save()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_TODO); - if (!io_save_todo ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_TODO); + if (!io_save_todo()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_APTS); - if (!io_save_apts ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_APTS); + if (!io_save_apts()) + ERROR_MSG("%s", access_pb); if (show_bar) - progress_bar (PROGRESS_BAR_SAVE, PROGRESS_BAR_KEYS); - if (!io_save_keys ()) - ERROR_MSG ("%s", access_pb); + progress_bar(PROGRESS_BAR_SAVE, PROGRESS_BAR_KEYS); + if (!io_save_keys()) + ERROR_MSG("%s", access_pb); /* Print a message telling data were saved */ - if (ui_mode == UI_CURSES && !conf->skip_system_dialogs - && display != IO_SAVE_DISPLAY_MARK) - { - status_mesg (save_success, enter); - (void)wgetch (win[STA].p); - } + if (ui_mode == UI_CURSES && conf.system_dialogs + && display != IO_SAVE_DISPLAY_MARK) { + status_mesg(save_success, enter); + wgetch(win[STA].p); + } - pthread_mutex_unlock (&io_save_mutex); + pthread_mutex_unlock(&io_save_mutex); } /* @@ -1107,8 +450,7 @@ io_save_cal (struct conf *conf, enum save_display display) * and then load either: a new appointment, a new event, or a new * recursive item (which can also be either an event or an appointment). */ -void -io_load_app (void) +void io_load_app(void) { FILE *data_file; int c, is_appointment, is_event, is_recursive; @@ -1118,251 +460,206 @@ io_load_app (void) int id = 0; int freq; char type, state = 0L; - char note[NOTESIZ + 1], *notep; + char note[MAX_NOTESIZ + 1], *notep; - t = time (NULL); - lt = localtime (&t); + t = time(NULL); + lt = localtime(&t); start = end = until = *lt; - data_file = fopen (path_apts, "r"); - for (;;) - { - LLIST_INIT (&exc); - is_appointment = is_event = is_recursive = 0; - c = getc (data_file); - if (c == EOF) - break; - (void)ungetc (c, data_file); - - /* Read the date first: it is common to both events - * and appointments. - */ - if (fscanf (data_file, "%u / %u / %u ", - &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) - { - EXIT (_("syntax error in the item date")); - } - - /* Read the next character : if it is an '@' then we have - * an appointment, else if it is an '[' we have en event. - */ - c = getc (data_file); - - if (c == '@') - is_appointment = 1; - else if (c == '[') - is_event = 1; - else - { - EXIT (_("no event nor appointment found")); - } - (void)ungetc (c, data_file); - - /* Read the remaining informations. */ - if (is_appointment) - { - fscanf (data_file, "@ %u : %u -> %u / %u / %u @ %u : %u ", - &start.tm_hour, &start.tm_min, - &end.tm_mon, &end.tm_mday, &end.tm_year, - &end.tm_hour, &end.tm_min); - } - else if (is_event) - { - fscanf (data_file, "[%d] ", &id); - } - else - { - EXIT (_("wrong format in the appointment or event")); - /* NOTREACHED */ - } + data_file = fopen(path_apts, "r"); + EXIT_IF(data_file == NULL, _("failed to open appointment file")); - /* Check if we have a recursive item. */ - c = getc (data_file); - - if (c == '{') - { - (void)ungetc (c, data_file); - is_recursive = 1; - fscanf (data_file, "{ %d%c ", &freq, &type); - - c = getc (data_file); - if (c == '}') - { /* endless recurrent item */ - (void)ungetc (c, data_file); - fscanf (data_file, "} "); - until.tm_year = 0; - } - else if (c == '-') - { - (void)ungetc (c, data_file); - fscanf (data_file, " -> %u / %u / %u ", - &until.tm_mon, &until.tm_mday, &until.tm_year); - c = getc (data_file); - if (c == '!') - { - (void)ungetc (c, data_file); - recur_exc_scan (&exc, data_file); - c = getc (data_file); - } - else - { - (void)ungetc (c, data_file); - fscanf (data_file, "} "); - } - } - else if (c == '!') - { // endless item with exceptions - (void)ungetc (c, data_file); - recur_exc_scan (&exc, data_file); - c = getc (data_file); - until.tm_year = 0; - } - else - { - EXIT (_("wrong format in the appointment or event")); - /* NOTREACHED */ - } - } - else - (void)ungetc (c, data_file); - - /* Check if a note is attached to the item. */ - c = getc (data_file); - if (c == '>') - { - (void)fgets (note, NOTESIZ + 1, data_file); - note[NOTESIZ] = '\0'; - notep = note; - getc (data_file); - } - else - { - notep = NULL; - (void)ungetc (c, data_file); - } + for (;;) { + LLIST_INIT(&exc); + is_appointment = is_event = is_recursive = 0; + c = getc(data_file); + if (c == EOF) + break; + ungetc(c, data_file); + + /* Read the date first: it is common to both events + * and appointments. + */ + if (fscanf(data_file, "%d / %d / %d ", + &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) + EXIT(_("syntax error in the item date")); + + /* Read the next character : if it is an '@' then we have + * an appointment, else if it is an '[' we have en event. + */ + c = getc(data_file); + + if (c == '@') + is_appointment = 1; + else if (c == '[') + is_event = 1; + else + EXIT(_("no event nor appointment found")); + + /* Read the remaining informations. */ + if (is_appointment) { + if (fscanf(data_file, " %d : %d -> %d / %d / %d @ %d : %d ", + &start.tm_hour, &start.tm_min, + &end.tm_mon, &end.tm_mday, &end.tm_year, + &end.tm_hour, &end.tm_min) != 7) + EXIT(_("syntax error in item time or duration")); + } else if (is_event) { + if (fscanf(data_file, " %d ", &id) != 1 || getc(data_file) != ']') + EXIT(_("syntax error in item identifier")); + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else { + EXIT(_("wrong format in the appointment or event")); + /* NOTREACHED */ + } - /* - * Last: read the item description and load it into its - * corresponding linked list, depending on the item type. - */ - if (is_appointment) - { - c = getc (data_file); - if (c == '!') - { - (void)ungetc (c, data_file); - fscanf (data_file, " ! "); - state |= APOINT_NOTIFY; - } - else - { - (void)ungetc (c, data_file); - fscanf (data_file, " | "); - state = 0L; - } - if (is_recursive) - { - recur_apoint_scan (data_file, start, end, - type, freq, until, notep, &exc, state); - } - else - { - apoint_scan (data_file, start, end, state, notep); - } - } - else if (is_event) - { - if (is_recursive) - { - recur_event_scan (data_file, start, id, type, - freq, until, notep, &exc); - } - else - { - event_scan (data_file, start, id, notep); - } - } - else - { - EXIT (_("wrong format in the appointment or event")); - /* NOTREACHED */ - } + /* Check if we have a recursive item. */ + c = getc(data_file); + + if (c == '{') { + is_recursive = 1; + if (fscanf(data_file, " %d%c ", &freq, &type) != 2) + EXIT(_("syntax error in item repetition")); + + c = getc(data_file); + if (c == '}') { /* endless recurrent item */ + until.tm_year = 0; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else if (c == '-' && getc(data_file) == '>') { + if (fscanf(data_file, " %d / %d / %d ", &until.tm_mon, + &until.tm_mday, &until.tm_year) != 3) + EXIT(_("syntax error in item repetition")); + c = getc(data_file); + if (c == '!') { + ungetc(c, data_file); + recur_exc_scan(&exc, data_file); + c = getc(data_file); + } else if (c == '}') { + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else + EXIT(_("syntax error in item repetition")); + } else if (c == '!') { /* endless item with exceptions */ + ungetc(c, data_file); + recur_exc_scan(&exc, data_file); + c = getc(data_file); + until.tm_year = 0; + } else { + EXIT(_("wrong format in the appointment or event")); + /* NOTREACHED */ + } + } else + ungetc(c, data_file); + + /* Check if a note is attached to the item. */ + c = getc(data_file); + if (c == '>') { + note_read(note, data_file); + notep = note; + } else { + notep = NULL; + ungetc(c, data_file); + } + + /* + * Last: read the item description and load it into its + * corresponding linked list, depending on the item type. + */ + if (is_appointment) { + c = getc(data_file); + if (c == '!') { + state |= APOINT_NOTIFY; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else if (c == '|') { + state = 0L; + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else + EXIT(_("syntax error in item repetition")); + if (is_recursive) { + recur_apoint_scan(data_file, start, end, + type, freq, until, notep, &exc, state); + } else { + apoint_scan(data_file, start, end, state, notep); + } + } else if (is_event) { + if (is_recursive) { + recur_event_scan(data_file, start, id, type, freq, until, notep, &exc); + } else { + event_scan(data_file, start, id, notep); + } + } else { + EXIT(_("wrong format in the appointment or event")); + /* NOTREACHED */ } - file_close (data_file, __FILE_POS__); + } + file_close(data_file, __FILE_POS__); } /* Load the todo data */ -void -io_load_todo (void) +void io_load_todo(void) { FILE *data_file; - char *mesg_line1 = _("Failed to open todo file"); - char *mesg_line2 = _("Press [ENTER] to continue"); char *newline; int nb_tod = 0; int c, id; - char buf[BUFSIZ], e_todo[BUFSIZ], note[NOTESIZ + 1]; + char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1]; - data_file = fopen (path_todo, "r"); - if (data_file == NULL) - { - status_mesg (mesg_line1, mesg_line2); - (void)wgetch (win[STA].p); - } - for (;;) - { - c = getc (data_file); - if (c == EOF) - { - break; - } - else if (c == '[') - { /* new style with id */ - fscanf (data_file, "%d]", &id); - } - else - { - id = 9; - (void)ungetc (c, data_file); - } - /* Now read the attached note, if any. */ - c = getc (data_file); - if (c == '>') - { - (void)fgets (note, NOTESIZ + 1, data_file); - note[NOTESIZ] = '\0'; - getc (data_file); - } - else - note[0] = '\0'; - /* Then read todo description. */ - (void)fgets (buf, sizeof buf, data_file); - newline = strchr (buf, '\n'); - if (newline) - *newline = '\0'; - io_extract_data (e_todo, buf, sizeof buf); - todo_add (e_todo, id, note); - ++nb_tod; - } - file_close (data_file, __FILE_POS__); - todo_set_nb (nb_tod); + data_file = fopen(path_todo, "r"); + EXIT_IF(data_file == NULL, _("failed to open todo file")); + + for (;;) { + c = getc(data_file); + if (c == EOF) + break; + else if (c == '[') { /* new style with id */ + if (fscanf(data_file, " %d ", &id) != 1 || getc(data_file) != ']') + EXIT(_("syntax error in item identifier")); + while ((c = getc(data_file)) == ' ') ; + ungetc(c, data_file); + } else { + id = 9; + ungetc(c, data_file); + } + /* Now read the attached note, if any. */ + c = getc(data_file); + if (c == '>') + note_read(note, data_file); + else { + note[0] = '\0'; + ungetc(c, data_file); + } + /* Then read todo description. */ + if (!fgets(buf, sizeof buf, data_file)) + buf[0] = '\0'; + newline = strchr(buf, '\n'); + if (newline) + *newline = '\0'; + io_extract_data(e_todo, buf, sizeof buf); + todo_add(e_todo, id, note); + ++nb_tod; + } + file_close(data_file, __FILE_POS__); + todo_set_nb(nb_tod); } static void -load_keys_ht_getkey (struct ht_keybindings_s *data, char **key, int *len) +load_keys_ht_getkey(struct ht_keybindings_s *data, const char **key, int *len) { *key = data->label; - *len = strlen (data->label); + *len = strlen(data->label); } static int -load_keys_ht_compare (struct ht_keybindings_s *data1, - struct ht_keybindings_s *data2) +load_keys_ht_compare(struct ht_keybindings_s *data1, + struct ht_keybindings_s *data2) { - const int KEYLEN = strlen (data1->label); + const int KEYLEN = strlen(data1->label); - if (strlen (data2->label) == KEYLEN - && !memcmp (data1->label, data2->label, KEYLEN)) + if (strlen(data2->label) == KEYLEN + && !memcmp(data1->label, data2->label, KEYLEN)) return 0; else return 1; @@ -1373,7 +670,7 @@ load_keys_ht_compare (struct ht_keybindings_s *data1, * visible in some specific cases. Thus replace it by the following is_blank() * function. */ -static int is_blank (int c) +static int is_blank(int c) { return c == ' ' || c == '\t'; } @@ -1385,8 +682,7 @@ static int is_blank (int c) * A log file is also built in case some errors were found in the key * configuration file. */ -void -io_load_keys (char *pager) +void io_load_keys(const char *pager) { struct ht_keybindings_s keys[NBKEYS]; FILE *keyfp; @@ -1395,187 +691,163 @@ io_load_keys (char *pager) int i, skipped, loaded, line; const int MAX_ERRORS = 5; - keys_init (); + keys_init(); -#define HSIZE 256 - HTABLE_HEAD (ht_keybindings, HSIZE, ht_keybindings_s) ht_keys = - HTABLE_INITIALIZER (&ht_keys); + struct ht_keybindings ht_keys = HTABLE_INITIALIZER(&ht_keys); - HTABLE_GENERATE (ht_keybindings, ht_keybindings_s, load_keys_ht_getkey, - load_keys_ht_compare); + for (i = 0; i < NBKEYS; i++) { + keys[i].key = (enum key)i; + keys[i].label = keys_get_label((enum key)i); + HTABLE_INSERT(ht_keybindings, &ht_keys, &keys[i]); + } - for (i = 0; i < NBKEYS; i++) - { - keys[i].key = (enum key)i; - keys[i].label = keys_get_label ((enum key)i); - HTABLE_INSERT (ht_keybindings, &ht_keys, &keys[i]); - } + keyfp = fopen(path_keys, "r"); + EXIT_IF(keyfp == NULL, _("failed to open key file")); - keyfp = fopen (path_keys, "r"); - EXIT_IF (keyfp == NULL, _("could not find any key file.")); - log = io_log_init (); + log = io_log_init(); skipped = loaded = line = 0; - while (fgets (buf, BUFSIZ, keyfp) != NULL) - { - char key_label[BUFSIZ], *p; - struct ht_keybindings_s *ht_elm, ht_entry; - const int AWAITED = 1; - int assigned; - - line++; - if (skipped > MAX_ERRORS) - { - char *too_many = - _("\nToo many errors while reading configuration file!\n" - "Please backup your keys file, remove it from directory, " - "and launch calcurse again.\n"); - - io_log_print (log, line, too_many); - break; - } - for (p = buf; is_blank ((int)*p); p++) - ; - if (p != buf) - memmove (buf, p, strlen (p)); - if (buf[0] == '#' || buf[0] == '\n') - continue; - - if (sscanf (buf, "%s", key_label) != AWAITED) - { - skipped++; - io_log_print (log, line, _("Could not read key label")); - continue; - } - ht_entry.label = key_label; - p = buf + strlen (key_label) + 1; - ht_elm = HTABLE_LOOKUP (ht_keybindings, &ht_keys, &ht_entry); - if (!ht_elm) - { + while (fgets(buf, BUFSIZ, keyfp) != NULL) { + char key_label[BUFSIZ], *p; + struct ht_keybindings_s *ht_elm, ht_entry; + const int AWAITED = 1; + int assigned; + + line++; + if (skipped > MAX_ERRORS) { + const char *too_many = + _("\nToo many errors while reading configuration file!\n" + "Please backup your keys file, remove it from directory, " + "and launch calcurse again.\n"); + + io_log_print(log, line, too_many); + break; + } + for (p = buf; is_blank((int)*p); p++) ; + if (p != buf) + memmove(buf, p, strlen(p)); + if (buf[0] == '#' || buf[0] == '\n') + continue; + + if (sscanf(buf, "%s", key_label) != AWAITED) { + skipped++; + io_log_print(log, line, _("Could not read key label")); + continue; + } + ht_entry.label = key_label; + p = buf + strlen(key_label) + 1; + ht_elm = HTABLE_LOOKUP(ht_keybindings, &ht_keys, &ht_entry); + if (!ht_elm) { + skipped++; + io_log_print(log, line, _("Key label not recognized")); + continue; + } + assigned = 0; + for (;;) { + char key_ch[BUFSIZ], tmpbuf[BUFSIZ]; + + while (*p == ' ') + p++; + (void)strncpy(tmpbuf, p, BUFSIZ); + if (sscanf(tmpbuf, "%s", key_ch) == AWAITED) { + int ch; + + if ((ch = keys_str2int(key_ch)) < 0) { + char unknown_key[BUFSIZ]; + skipped++; - io_log_print (log, line, _("Key label not recognized")); - continue; - } - assigned = 0; - for (;;) - { - char key_ch[BUFSIZ], tmpbuf[BUFSIZ]; - - while (*p == ' ') - p++; - (void)strncpy (tmpbuf, p, BUFSIZ); - if (sscanf (tmpbuf, "%s", key_ch) == AWAITED) - { - int ch; - - if ((ch = keys_str2int (key_ch)) < 0) - { - char unknown_key[BUFSIZ]; - - skipped++; - (void)snprintf (unknown_key, BUFSIZ, - _("Error reading key: \"%s\""), key_ch); - io_log_print (log, line, unknown_key); - } - else - { - int used; - - used = keys_assign_binding (ch, ht_elm->key); - if (used) - { - char already_assigned[BUFSIZ]; - - skipped++; - (void)snprintf (already_assigned, BUFSIZ, - _("\"%s\" assigned multiple times!"), key_ch); - io_log_print (log, line, already_assigned); - } - else - assigned++; - } - p += strlen (key_ch) + 1; - } - else - { - if (assigned) - loaded++; - break; - } - } + (void)snprintf(unknown_key, BUFSIZ, + _("Error reading key: \"%s\""), key_ch); + io_log_print(log, line, unknown_key); + } else { + int used; + + used = keys_assign_binding(ch, ht_elm->key); + if (used) { + char already_assigned[BUFSIZ]; + + skipped++; + (void)snprintf(already_assigned, BUFSIZ, + _("\"%s\" assigned multiple times!"), key_ch); + io_log_print(log, line, already_assigned); + } else + assigned++; + } + p += strlen(key_ch) + 1; + } else { + if (assigned) + loaded++; + break; + } } - file_close (keyfp, __FILE_POS__); - file_close (log->fd, __FILE_POS__); - if (skipped > 0) - { - char *view_log = + } + file_close(keyfp, __FILE_POS__); + file_close(log->fd, __FILE_POS__); + if (skipped > 0) { + const char *view_log = _("There were some errors when loading keys file, see log file ?"); - io_log_display (log, view_log, pager); - } - io_log_free (log); - EXIT_IF (skipped > MAX_ERRORS, - _("Too many errors while reading keys file, aborting...")); + io_log_display(log, view_log, pager); + } + io_log_free(log); + EXIT_IF(skipped > MAX_ERRORS, + _("Too many errors while reading keys file, aborting...")); if (loaded < NBKEYS) - keys_fill_missing (); - if (keys_check_missing_bindings ()) - WARN_MSG (_("Some actions do not have any associated key bindings!")); -#undef HSIZE + keys_fill_missing(); + if (keys_check_missing_bindings()) + WARN_MSG(_("Some actions do not have any associated key bindings!")); } -void -io_check_dir (char *dir, int *missing) +void io_check_dir(char *dir, int *missing) { + if (read_only) + return; + errno = 0; - if (mkdir (dir, 0700) != 0) - { - if (errno != EEXIST) - { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - dir, strerror (errno)); - exit_calcurse (EXIT_FAILURE); - } - } - else - { - if (missing) - (*missing)++; + if (mkdir(dir, 0700) != 0) { + if (errno != EEXIST) { + fprintf(stderr, _("FATAL ERROR: could not create %s: %s\n"), dir, + strerror(errno)); + exit_calcurse(EXIT_FAILURE); } + } else { + if (missing) + (*missing)++; + } } -unsigned -io_file_exist (char *file) +unsigned io_file_exist(char *file) { FILE *fd; if (!file) return 0; - if ((fd = fopen (file, "r")) == NULL) + if ((fd = fopen(file, "r")) == NULL) return 0; - (void)fclose (fd); + fclose(fd); return 1; } -void -io_check_file (char *file, int *missing) +void io_check_file(char *file, int *missing) { + if (read_only) + return; + errno = 0; - if (!io_file_exist (file)) - { - FILE *fd; - - if (missing) - (*missing)++; - if ((fd = fopen (file, "w")) == NULL) - { - (void)fprintf (stderr, _("FATAL ERROR: could not create %s: %s\n"), - file, strerror (errno)); - exit_calcurse (EXIT_FAILURE); - } - file_close (fd, __FILE_POS__); + if (!io_file_exist(file)) { + FILE *fd; + + if (missing) + (*missing)++; + if ((fd = fopen(file, "w")) == NULL) { + fprintf(stderr, _("FATAL ERROR: could not create %s: %s\n"), file, + strerror(errno)); + exit_calcurse(EXIT_FAILURE); } + file_close(fd, __FILE_POS__); + } } /* @@ -1590,1121 +862,127 @@ io_check_file (char *file, int *missing) * |___ apts * |___ todo */ -int -io_check_data_files (void) +int io_check_data_files(void) { int missing, missing_keys; missing = missing_keys = 0; errno = 0; - io_check_dir (path_dir, &missing); - io_check_dir (path_notes, &missing); - io_check_file (path_todo, &missing); - io_check_file (path_apts, &missing); - io_check_file (path_conf, &missing); - io_check_file (path_keys, &missing_keys); - if (missing_keys) - { - missing++; - keys_dump_defaults (path_keys); - } + io_check_dir(path_dir, &missing); + io_check_dir(path_notes, &missing); + io_check_file(path_todo, &missing); + io_check_file(path_apts, &missing); + io_check_file(path_conf, &missing); + io_check_file(path_keys, &missing_keys); + if (missing_keys) { + missing++; + keys_dump_defaults(path_keys); + } return missing; } /* Draw the startup screen */ -void -io_startup_screen (unsigned skip_dialogs, int no_data_file) +void io_startup_screen(int no_data_file) { - char *welcome_mesg = - _("Welcome to Calcurse. Missing data files were created."); - char *data_mesg = _("Data files found. Data will be loaded now."); - char *enter = _("Press [ENTER] to continue"); - - if (no_data_file != 0) - { - status_mesg (welcome_mesg, enter); - (void)wgetch (win[STA].p); - } - else if (!skip_dialogs) - { - status_mesg (data_mesg, enter); - (void)wgetch (win[STA].p); - } + const char *enter = _("Press [ENTER] to continue"); + + if (no_data_file) + status_mesg(_("Data files found. Data will be loaded now."), enter); + else + status_mesg(_("Welcome to Calcurse. Missing data files were created."), + enter); + + wgetch(win[STA].p); } /* Export calcurse data. */ -void -io_export_data (enum export_type type, struct conf *conf) +void io_export_data(enum export_type type) { FILE *stream; - char *success = _("The data were successfully exported"); - char *enter = _("Press [ENTER] to continue"); + const char *success = _("The data were successfully exported"); + const char *enter = _("Press [ENTER] to continue"); if (type < IO_EXPORT_ICAL || type >= IO_EXPORT_NBTYPES) - EXIT (_("unknown export type")); + EXIT(_("unknown export type")); stream = 0; - switch (ui_mode) - { - case UI_CMDLINE: - stream = stdout; - break; - case UI_CURSES: - stream = get_export_stream (type); - break; - default: - EXIT (_("wrong export mode")); - /* NOTREACHED */ - } + switch (ui_mode) { + case UI_CMDLINE: + stream = stdout; + break; + case UI_CURSES: + stream = get_export_stream(type); + break; + default: + EXIT(_("wrong export mode")); + /* NOTREACHED */ + } if (stream == NULL) return; - cb_export_header[type] (stream); - - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_EVENTS); - cb_export_recur_events[type] (stream); - cb_export_events[type] (stream); - - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_APOINTS); - cb_export_recur_apoints[type] (stream); - cb_export_apoints[type] (stream); + if (type == IO_EXPORT_ICAL) + ical_export_data(stream); + else if (type == IO_EXPORT_PCAL) + pcal_export_data(stream); - if (!conf->skip_progress_bar && ui_mode == UI_CURSES) - progress_bar (PROGRESS_BAR_EXPORT, PROGRESS_BAR_EXPORT_TODO); - cb_export_todo[type] (stream); - - cb_export_footer[type] (stream); - - if (stream != stdout) - file_close (stream, __FILE_POS__); - - if (!conf->skip_system_dialogs && ui_mode == UI_CURSES) - { - status_mesg (success, enter); - (void)wgetch (win[STA].p); - } + if (conf.system_dialogs && ui_mode == UI_CURSES) { + status_mesg(success, enter); + wgetch(win[STA].p); + } } /* Draws the export format selection bar */ -void -io_export_bar (void) +void io_export_bar(void) { int smlspc, spc; smlspc = 2; spc = 15; - custom_apply_attr (win[STA].p, ATTR_HIGHEST); - mvwprintw (win[STA].p, 0, 2, "Q"); - mvwprintw (win[STA].p, 1, 2, "I"); - mvwprintw (win[STA].p, 0, 2 + spc, "P"); - custom_remove_attr (win[STA].p, ATTR_HIGHEST); - - mvwprintw (win[STA].p, 0, 2 + smlspc, _("Exit")); - mvwprintw (win[STA].p, 1, 2 + smlspc, _("Ical")); - mvwprintw (win[STA].p, 0, 2 + spc + smlspc, _("Pcal")); - - wnoutrefresh (win[STA].p); - wmove (win[STA].p, 0, 0); - wins_doupdate (); -} - -/* Print a header to describe import log report format. */ -static void -ical_log_init (FILE *log, float version) -{ - const char *header = - "+-------------------------------------------------------------------+\n" - "| Calcurse icalendar import log. |\n" - "| |\n" - "| Items imported from icalendar file, version %1.1f |\n" - "| Some items could not be imported, they are described hereafter. |\n" - "| The log line format is as follows: |\n" - "| |\n" - "| TYPE [LINE]: DESCRIPTION |\n" - "| |\n" - "| where: |\n" - "| * TYPE represents the item type ('VEVENT' or 'VTODO') |\n" - "| * LINE is the line in the input stream at which this item begins |\n" - "| * DESCRIPTION indicates why the item could not be imported |\n" - "+-------------------------------------------------------------------+\n\n"; - - if (log) - (void)fprintf (log, header, version); -} - -/* - * Used to build a report of the import process. - * The icalendar item for which a problem occurs is mentioned (by giving its - * first line inside the icalendar file), together with a message describing the - * problem. - */ -static void -ical_log (FILE *log, ical_types_e type, unsigned lineno, char *msg) -{ - const char *typestr[ICAL_TYPES] = {"VEVENT", "VTODO"}; - - RETURN_IF (type < 0 || type >= ICAL_TYPES, _("unknown ical type")); - if (log) - (void)fprintf (log, "%s [%d]: %s\n", typestr[type], lineno, msg); -} - -static void -ical_store_todo (int priority, char *mesg, char *note) -{ - todo_add (mesg, priority, note); - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -static void -ical_store_event (char *mesg, char *note, long day, long end, ical_rpt_t *rpt, - llist_t *exc) -{ - const int EVENTID = 1; - - if (rpt) - { - recur_event_new (mesg, note, day, EVENTID, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else if (end && end != day) - { - /* Here we have an event that spans over several days. */ - rpt = mem_malloc (sizeof (ical_rpt_t)); - rpt->type = RECUR_DAILY; - rpt->freq = 1; - rpt->count = 0; - rpt->until = end; - recur_event_new (mesg, note, day, EVENTID, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else - { - event_new (mesg, note, day, EVENTID); - } - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -static void -ical_store_apoint (char *mesg, char *note, long start, long dur, - ical_rpt_t *rpt, llist_t *exc, int has_alarm) -{ - char state = 0L; - - if (has_alarm) - state |= APOINT_NOTIFY; - if (rpt) - { - recur_apoint_new (mesg, note, start, dur, state, rpt->type, rpt->freq, - rpt->until, exc); - mem_free (rpt); - } - else - { - apoint_new (mesg, note, start, dur, state); - } - mem_free (mesg); - erase_note (¬e, ERASE_FORCE_KEEP_NOTE); -} - -/* - * Returns an allocated string representing the string given in argument once - * unformatted. - * - * Note: - * Even if the RFC2445 recommends not to have more than 75 octets on one line of - * text, I prefer not to restrict the parsing to this size, thus I use a buffer - * of size BUFSIZ. - * - * Extract from RFC2445: - * Lines of text SHOULD NOT be longer than 75 octets, excluding the line - * break. - */ -static char * -ical_unformat_line (char *line) -{ - char *p, uline[BUFSIZ]; - int len; - - if (strlen (line) >= BUFSIZ) - return NULL; - - bzero (uline, BUFSIZ); - for (len = 0, p = line; *p; p++) - { - switch (*p) - { - case '\\': - switch (*(p + 1)) - { - case 'n': - uline[len++] = '\n'; - p++; - break; - case 't': - uline[len++] = '\t'; - p++; - break; - case ';': - case ':': - case ',': - uline[len++] = *(p + 1); - p++; - break; - default: - uline[len++] = *p; - break; - } - break; - default: - uline[len++] = *p; - break; - } - } - - return mem_strdup (uline); -} - -static void -ical_readline_init (FILE *fdi, char *buf, char *lstore, unsigned *ln) -{ - char *eol; - - *buf = *lstore = '\0'; - fgets (lstore, BUFSIZ, fdi); - if ((eol = strchr(lstore, '\n')) != NULL) - *eol = '\0'; - (*ln)++; -} - -static int -ical_readline (FILE *fdi, char *buf, char *lstore, unsigned *ln) -{ - char *eol; - - strncpy (buf, lstore, BUFSIZ); - (*ln)++; - - while (fgets (lstore, BUFSIZ, fdi) != NULL) - { - if ((eol = strchr(lstore, '\n')) != NULL) - *eol = '\0'; - if (*lstore != SPACE && *lstore != TAB) - break; - strncat (buf, lstore + 1, BUFSIZ); - buf[BUFSIZ - 1] = '\0'; - (*ln)++; - } - - if (feof (fdi)) - { - *lstore = '\0'; - if (*buf == '\0') - return 0; - } - - return 1; -} - -static float -ical_chk_header (FILE *fd, char *buf, char *lstore, unsigned *lineno) -{ - const int HEADER_MALFORMED = -1; - const struct string icalheader = STRING_BUILD ("BEGIN:VCALENDAR"); - float version; - - if (!ical_readline (fd, buf, lstore, lineno)) - return HEADER_MALFORMED; - - str_toupper (buf); - if (strncmp (buf, icalheader.str, icalheader.len) != 0) - return HEADER_MALFORMED; - - while (!sscanf (buf, "VERSION:%f", &version)) - { - if (!ical_readline (fd, buf, lstore, lineno)) - return HEADER_MALFORMED; - } - return version; -} - -/* - * iCalendar date-time format is based on the ISO 8601 complete - * representation. It should be something like : DATE 'T' TIME - * where DATE is 'YYYYMMDD' and TIME is 'HHMMSS'. - * The time and 'T' separator are optional (in the case of an day-long event). - * - * Optionnaly, if the type pointer is given, specify if it is an event - * (no time is given, meaning it is an all-day event), or an appointment - * (time is given). - * - * The timezone is not yet handled by calcurse. - */ -static long -ical_datetime2long (char *datestr, ical_vevent_e *type) -{ - const int NOTFOUND = 0, FORMAT_DATE = 3, FORMAT_DATETIME = 5; - struct date date; - unsigned hour, min; - long datelong; - int format; - - format = sscanf (datestr, "%04u%02u%02uT%02u%02u", - &date.yyyy, &date.mm, &date.dd, &hour, &min); - if (format == FORMAT_DATE) - { - if (type) - *type = EVENT; - datelong = date2sec (date, 0, 0); - } - else if (format == FORMAT_DATETIME) - { - if (type) - *type = APPOINTMENT; - datelong = date2sec (date, hour, min); - } - else - { - datelong = NOTFOUND; - } - return datelong; -} - -static long -ical_durtime2long (char *timestr) -{ - long timelong; - char *p; - - if ((p = strchr (timestr, 'T')) == NULL) - timelong = 0; - else - { - int nbmatch; - struct { - unsigned hour, min, sec; - } time; - - p++; - bzero (&time, sizeof time); - nbmatch = sscanf (p, "%uH%uM%uS", &time.hour, &time.min, &time.sec); - if (nbmatch < 1 || nbmatch > 3) - timelong = 0; - else - timelong = time.hour * HOURINSEC + time.min * MININSEC + time.sec; - } - return timelong; -} - -/* - * Extract from RFC2445: - * - * Value Name: DURATION - * - * Purpose: This value type is used to identify properties that contain - * duration of time. - * - * Formal Definition: The value type is defined by the following - * notation: - * - * dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week) - * dur-date = dur-day [dur-time] - * dur-time = "T" (dur-hour / dur-minute / dur-second) - * dur-week = 1*DIGIT "W" - * dur-hour = 1*DIGIT "H" [dur-minute] - * dur-minute = 1*DIGIT "M" [dur-second] - * dur-second = 1*DIGIT "S" - * dur-day = 1*DIGIT "D" - * - * Example: A duration of 15 days, 5 hours and 20 seconds would be: - * P15DT5H0M20S - * A duration of 7 weeks would be: - * P7W - */ -static long -ical_dur2long (char *durstr) -{ - const int NOTFOUND = -1; - long durlong; - char *p; - struct { - unsigned week, day; - } date; - - bzero (&date, sizeof date); - if ((p = strchr (durstr, 'P')) == NULL) - durlong = NOTFOUND; - else - { - p++; - if (*p == '-') - return NOTFOUND; - else if (*p == '+') - p++; - - if (*p == 'T') /* dur-time */ - durlong = ical_durtime2long (p); - else if (strchr (p, 'W')) /* dur-week */ - { - if (sscanf (p, "%u", &date.week) == 1) - durlong = date.week * WEEKINDAYS * DAYINSEC; - else - durlong = NOTFOUND; - } - else - { - if (strchr (p, 'D')) /* dur-date */ - { - if (sscanf (p, "%uD", &date.day) == 1) - { - durlong = date.day * DAYINSEC; - durlong += ical_durtime2long (p); - } - else - durlong = NOTFOUND; - } - else - durlong = NOTFOUND; - } - } - return durlong; -} - -/* - * Compute the vevent repetition end date from the repetition count. - * - * Extract from RFC2445: - * The COUNT rule part defines the number of occurrences at which to - * range-bound the recurrence. The "DTSTART" property value, if specified, - * counts as the first occurrence. - */ -static long -ical_compute_rpt_until (long start, ical_rpt_t *rpt) -{ - long until; - - switch (rpt->type) - { - case RECUR_DAILY: - until = date_sec_change (start, 0, rpt->freq * (rpt->count - 1)); - break; - case RECUR_WEEKLY: - until = date_sec_change (start, 0, - rpt->freq * WEEKINDAYS * (rpt->count - 1)); - break; - case RECUR_MONTHLY: - until = date_sec_change (start, rpt->freq * (rpt->count - 1), 0); - break; - case RECUR_YEARLY: - until = date_sec_change (start, rpt->freq * 12 * (rpt->count - 1), 0); - break; - default: - until = 0; - break; - /* NOTREACHED */ - } - return until; -} - -/* - * Read a recurrence rule from an iCalendar RRULE string. - * - * Value Name: RECUR - * - * Purpose: This value type is used to identify properties that contain - * a recurrence rule specification. - * - * Formal Definition: The value type is defined by the following - * notation: - * - * recur = "FREQ"=freq *( - * - * ; either UNTIL or COUNT may appear in a 'recur', - * ; but UNTIL and COUNT MUST NOT occur in the same 'recur' - * - * ( ";" "UNTIL" "=" enddate ) / - * ( ";" "COUNT" "=" 1*DIGIT ) / - * - * ; the rest of these keywords are optional, - * ; but MUST NOT occur more than - * ; once - * - * ( ";" "INTERVAL" "=" 1*DIGIT ) / - * ( ";" "BYSECOND" "=" byseclist ) / - * ( ";" "BYMINUTE" "=" byminlist ) / - * ( ";" "BYHOUR" "=" byhrlist ) / - * ( ";" "BYDAY" "=" bywdaylist ) / - * ( ";" "BYMONTHDAY" "=" bymodaylist ) / - * ( ";" "BYYEARDAY" "=" byyrdaylist ) / - * ( ";" "BYWEEKNO" "=" bywknolist ) / - * ( ";" "BYMONTH" "=" bymolist ) / - * ( ";" "BYSETPOS" "=" bysplist ) / - * ( ";" "WKST" "=" weekday ) / - * ( ";" x-name "=" text ) - * ) -*/ -static ical_rpt_t * -ical_read_rrule (FILE *log, char *rrulestr, unsigned *noskipped, - const int itemline) -{ - const struct string daily = STRING_BUILD ("DAILY"); - const struct string weekly = STRING_BUILD ("WEEKLY"); - const struct string monthly = STRING_BUILD ("MONTHLY"); - const struct string yearly = STRING_BUILD ("YEARLY"); - const struct string count = STRING_BUILD ("COUNT="); - const struct string interv = STRING_BUILD ("INTERVAL="); - unsigned interval; - ical_rpt_t *rpt; - char *p; - - rpt = NULL; - if ((p = strchr (rrulestr, ':')) != NULL) - { - char freqstr[BUFSIZ]; - - p++; - rpt = mem_malloc (sizeof (ical_rpt_t)); - bzero (rpt, sizeof (ical_rpt_t)); - if (sscanf (p, "FREQ=%s", freqstr) != 1) - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence frequence not found.")); - (*noskipped)++; - mem_free (rpt); - return NULL; - } - else - { - if (strncmp (freqstr, daily.str, daily.len) == 0) - rpt->type = RECUR_DAILY; - else if (strncmp (freqstr, weekly.str, weekly.len) == 0) - rpt->type = RECUR_WEEKLY; - else if (strncmp (freqstr, monthly.str, monthly.len) == 0) - rpt->type = RECUR_MONTHLY; - else if (strncmp (freqstr, yearly.str, yearly.len) == 0) - rpt->type = RECUR_YEARLY; - else - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence frequence not recognized.")); - (*noskipped)++; - mem_free (rpt); - return NULL; - } - } - /* - The UNTIL rule part defines a date-time value which bounds the - recurrence rule in an inclusive manner. If not present, and the - COUNT rule part is also not present, the RRULE is considered to - repeat forever. - - The COUNT rule part defines the number of occurrences at which to - range-bound the recurrence. The "DTSTART" property value, if - specified, counts as the first occurrence. - */ - if ((p = strstr (rrulestr, "UNTIL")) != NULL) - { - char *untilstr; - - untilstr = strchr (p, '='); - rpt->until = ical_datetime2long (++untilstr, NULL); - } - else - { - unsigned cnt; - char *countstr; - - if ((countstr = strstr (rrulestr, count.str)) != NULL) - { - countstr += count.len; - if (sscanf (countstr, "%u", &cnt) != 1) - { - rpt->until = 0; - /* endless repetition */ - } - else - { - rpt->count = cnt; - } - } - else - rpt->until = 0; - } - - if ((p = strstr (rrulestr, interv.str)) != NULL) - { - p += interv.len; - if (sscanf (p, "%u", &interval) != 1) - { - rpt->freq = 1; - /* default frequence if none specified */ - } - else - { - rpt->freq = interval; - } - } - else - { - rpt->freq = 1; - } - } - else - { - ical_log (log, ICAL_VEVENT, itemline, _("recurrence rule malformed.")); - (*noskipped)++; - } - return rpt; -} + custom_apply_attr(win[STA].p, ATTR_HIGHEST); + mvwprintw(win[STA].p, 0, 2, "Q"); + mvwprintw(win[STA].p, 1, 2, "I"); + mvwprintw(win[STA].p, 0, 2 + spc, "P"); + custom_remove_attr(win[STA].p, ATTR_HIGHEST); -static void -ical_add_exc (llist_t *exc_head, long date) -{ - if (date != 0) - { - struct excp *exc = mem_malloc (sizeof (struct excp)); - exc->st = date; + mvwprintw(win[STA].p, 0, 2 + smlspc, _("Exit")); + mvwprintw(win[STA].p, 1, 2 + smlspc, _("Ical")); + mvwprintw(win[STA].p, 0, 2 + spc + smlspc, _("Pcal")); - LLIST_ADD (exc_head, exc); - } + wnoutrefresh(win[STA].p); + wmove(win[STA].p, 0, 0); + wins_doupdate(); } -/* - * This property defines the list of date/time exceptions for a - * recurring calendar component. - */ -void -ical_read_exdate (llist_t *exc, FILE *log, char *exstr, unsigned *noskipped, - const int itemline) -{ - char *p, *q; - long date; - - LLIST_INIT (exc); - if ((p = strchr (exstr, ':')) != NULL) - { - p++; - while ((q = strchr (p, ',')) != NULL) - { - char buf[BUFSIZ]; - const int buflen = q - p; - - (void)strncpy (buf, p, buflen); - buf[buflen] = '\0'; - date = ical_datetime2long (buf, NULL); - ical_add_exc (exc, date); - p = ++q; - } - date = ical_datetime2long (p, NULL); - ical_add_exc (exc, date); - } - else - { - ical_log (log, ICAL_VEVENT, itemline, - _("recurrence exception dates malformed.")); - (*noskipped)++; - } -} - -/* Return an allocated string containing the name of the newly created note. */ -static char * -ical_read_note (char *line, unsigned *noskipped, ical_vevent_e item_type, - const int itemline, FILE *log) -{ - char *p, *notestr, *notename, fullnotename[BUFSIZ]; - FILE *fdo; - - if ((p = strchr (line, ':')) != NULL) - { - notename = new_tempfile (path_notes, NOTESIZ); - EXIT_IF (notename == NULL, - _("Warning: could not create new note file to store " - "description. Aborting...\n")); - (void)snprintf (fullnotename, BUFSIZ, "%s%s", path_notes, notename); - fdo = fopen (fullnotename, "w"); - EXIT_IF (fdo == NULL, _("Warning: could not open %s, Aborting..."), - fullnotename); - p++; - notestr = ical_unformat_line (p); - if (notestr == NULL) - { - ical_log (log, item_type, itemline, - _("could not get entire item description.")); - file_close (fdo, __FILE_POS__); - erase_note (¬ename, ERASE_FORCE); - (*noskipped)++; - return NULL; - } - else if (strlen (notestr) == 0) - { - file_close (fdo, __FILE_POS__); - erase_note (¬ename, ERASE_FORCE); - mem_free (notestr); - return NULL; - } - else - { - (void)fprintf (fdo, "%s", notestr); - file_close (fdo, __FILE_POS__); - mem_free (notestr); - return notename; - } - } - else - { - ical_log (log, item_type, itemline, _("description malformed.")); - (*noskipped)++; - return NULL; - } -} - -/* Returns an allocated string containing the ical item summary. */ -static char * -ical_read_summary (char *line) -{ - char *p, *summary; - - if ((p = strchr (line, ':')) != NULL) - { - p++; - summary = ical_unformat_line (p); - return summary; - } - else - return NULL; -} - -static void -ical_read_event (FILE *fdi, FILE *log, unsigned *noevents, unsigned *noapoints, - unsigned *noskipped, char *buf, char *lstore, - unsigned *lineno) -{ - const int ITEMLINE = *lineno; - const struct string endevent = STRING_BUILD ("END:VEVENT"); - const struct string summary = STRING_BUILD ("SUMMARY"); - const struct string dtstart = STRING_BUILD ("DTSTART"); - const struct string dtend = STRING_BUILD ("DTEND"); - const struct string duration = STRING_BUILD ("DURATION"); - const struct string rrule = STRING_BUILD ("RRULE"); - const struct string exdate = STRING_BUILD ("EXDATE"); - const struct string alarm = STRING_BUILD ("BEGIN:VALARM"); - const struct string endalarm = STRING_BUILD ("END:VALARM"); - const struct string desc = STRING_BUILD ("DESCRIPTION"); - ical_vevent_e vevent_type; - char *p, buf_upper[BUFSIZ]; - struct { - llist_t exc; - ical_rpt_t *rpt; - char *mesg, *note; - long start, end, dur; - int has_alarm; - } vevent; - int skip_alarm; - - vevent_type = UNDEFINED; - bzero (&vevent, sizeof vevent); - skip_alarm = 0; - while (ical_readline (fdi, buf, lstore, lineno)) - { - strncpy (buf_upper, buf, BUFSIZ); - buf_upper[BUFSIZ - 1] = '\0'; - str_toupper (buf_upper); - - if (skip_alarm) - { - /* Need to skip VALARM properties because some keywords could - interfere, such as DURATION, SUMMARY,.. */ - if (strncmp (buf_upper, endalarm.str, endalarm.len) == 0) - skip_alarm = 0; - continue; - } - if (strncmp (buf_upper, endevent.str, endevent.len) == 0) - { - if (vevent.mesg) - { - if (vevent.rpt && vevent.rpt->count) - vevent.rpt->until = ical_compute_rpt_until (vevent.start, - vevent.rpt); - - switch (vevent_type) - { - case APPOINTMENT: - if (vevent.start == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("appointment has no start time.")); - goto cleanup; - } - if (vevent.dur == 0) - { - if (vevent.end == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not compute duration " - "(no end time).")); - goto cleanup; - } - else if (vevent.start == vevent.end) - { - vevent_type = EVENT; - vevent.end = 0L; - ical_store_event (vevent.mesg, vevent.note, - vevent.start, vevent.end, - vevent.rpt, &vevent.exc); - (*noevents)++; - return; - } - else - { - vevent.dur = vevent.end - vevent.start; - if (vevent.dur < 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item has a negative duration.")); - goto cleanup; - } - } - } - ical_store_apoint (vevent.mesg, vevent.note, vevent.start, - vevent.dur, vevent.rpt, &vevent.exc, - vevent.has_alarm); - (*noapoints)++; - break; - case EVENT: - if (vevent.start == 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("event date is not defined.")); - goto cleanup; - } - ical_store_event (vevent.mesg, vevent.note, vevent.start, - vevent.end, vevent.rpt, &vevent.exc); - (*noevents)++; - break; - case UNDEFINED: - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item could not be identified.")); - goto cleanup; - break; - } - } - else - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve item summary.")); - goto cleanup; - } - return; - } - else - { - if (strncmp (buf_upper, dtstart.str, dtstart.len) == 0) - { - if ((p = strchr (buf, ':')) != NULL) - vevent.start = ical_datetime2long (++p, &vevent_type); - if (!vevent.start) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve event start time.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, dtend.str, dtend.len) == 0) - { - if ((p = strchr (buf, ':')) != NULL) - vevent.end = ical_datetime2long (++p, &vevent_type); - if (!vevent.end) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("could not retrieve event end time.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, duration.str, duration.len) == 0) - { - if ((vevent.dur = ical_dur2long (buf)) <= 0) - { - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("item duration malformed.")); - goto cleanup; - } - } - else if (strncmp (buf_upper, rrule.str, rrule.len) == 0) - { - vevent.rpt = ical_read_rrule (log, buf, noskipped, ITEMLINE); - } - else if (strncmp (buf_upper, exdate.str, exdate.len) == 0) - { - ical_read_exdate (&vevent.exc, log, buf, noskipped, ITEMLINE); - } - else if (strncmp (buf_upper, summary.str, summary.len) == 0) - { - vevent.mesg = ical_read_summary (buf); - } - else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) - { - skip_alarm = 1; - vevent.has_alarm = 1; - } - else if (strncmp (buf_upper, desc.str, desc.len) == 0) - { - vevent.note = ical_read_note (buf, noskipped, ICAL_VEVENT, - ITEMLINE, log); - } - } - } - ical_log (log, ICAL_VEVENT, ITEMLINE, - _("The ical file seems to be malformed. " - "The end of item was not found.")); - -cleanup: - - if (vevent.note) - mem_free (vevent.note); - if (vevent.mesg) - mem_free (vevent.mesg); - if (vevent.rpt) - mem_free (vevent.rpt); - LLIST_FREE (&vevent.exc); - (*noskipped)++; -} - -static void -ical_read_todo (FILE *fdi, FILE *log, unsigned *notodos, unsigned *noskipped, - char *buf, char *lstore, unsigned *lineno) -{ - const struct string endtodo = STRING_BUILD ("END:VTODO"); - const struct string summary = STRING_BUILD ("SUMMARY"); - const struct string alarm = STRING_BUILD ("BEGIN:VALARM"); - const struct string endalarm = STRING_BUILD ("END:VALARM"); - const struct string desc = STRING_BUILD ("DESCRIPTION"); - const int LOWEST = 9; - const int ITEMLINE = *lineno; - char buf_upper[BUFSIZ]; - struct { - char *mesg, *note; - int has_priority, priority; - } vtodo; - int skip_alarm; - - bzero (&vtodo, sizeof vtodo); - skip_alarm = 0; - while (ical_readline (fdi, buf, lstore, lineno)) - { - strncpy (buf_upper, buf, BUFSIZ); - buf_upper[BUFSIZ - 1] = '\0'; - str_toupper (buf_upper); - if (skip_alarm) - { - /* Need to skip VALARM properties because some keywords could - interfere, such as DURATION, SUMMARY,.. */ - if (strncmp (buf_upper, endalarm.str, endalarm.len) == 0) - skip_alarm = 0; - continue; - } - if (strncmp (buf_upper, endtodo.str, endtodo.len) == 0) - { - if (!vtodo.has_priority) - vtodo.priority = LOWEST; - if (vtodo.mesg) - { - ical_store_todo (vtodo.priority, vtodo.mesg, vtodo.note); - (*notodos)++; - } - else - { - ical_log (log, ICAL_VTODO, ITEMLINE, - _("could not retrieve item summary.")); - goto cleanup; - } - return; - } - else - { - int tmpint; - - if (sscanf (buf_upper, "PRIORITY:%d", &tmpint) == 1) - { - if (tmpint <= 9 && tmpint >= 1) - { - vtodo.priority = tmpint; - vtodo.has_priority = 1; - } - else - { - ical_log (log, ICAL_VTODO, ITEMLINE, - _("item priority is not acceptable " - "(must be between 1 and 9).")); - vtodo.priority = LOWEST; - } - } - else if (strncmp (buf_upper, summary.str, summary.len) == 0) - { - vtodo.mesg = ical_read_summary (buf); - } - else if (strncmp (buf_upper, alarm.str, alarm.len) == 0) - { - skip_alarm = 1; - } - else if (strncmp (buf_upper, desc.str, desc.len) == 0) - { - vtodo.note = ical_read_note (buf, noskipped, ICAL_VTODO, - ITEMLINE, log); - } - } - } - ical_log (log, ICAL_VTODO, ITEMLINE, - _("The ical file seems to be malformed. " - "The end of item was not found.")); - -cleanup: - - if (vtodo.note) - mem_free (vtodo.note); - if (vtodo.mesg) - mem_free (vtodo.mesg); - (*noskipped)++; -} - -static FILE * -get_import_stream (enum export_type type) +static FILE *get_import_stream(enum export_type type) { FILE *stream; char *stream_name; - char *ask_fname = _("Enter the file name to import data from:"); - char *wrong_file = - _("The file cannot be accessed, please enter another file name."); - char *press_enter = _("Press [ENTER] to continue."); + const char *ask_fname = _("Enter the file name to import data from:"); + const char *wrong_file = + _("The file cannot be accessed, please enter another file name."); + const char *press_enter = _("Press [ENTER] to continue."); int cancel; stream = NULL; - stream_name = mem_malloc (BUFSIZ); - bzero (stream_name, BUFSIZ); - while (stream == NULL) - { - status_mesg (ask_fname, ""); - cancel = updatestring (win[STA].p, &stream_name, 0, 1); - if (cancel) - { - mem_free (stream_name); - return NULL; - } - stream = fopen (stream_name, "r"); - if (stream == NULL) - { - status_mesg (wrong_file, press_enter); - (void)wgetch (win[STA].p); - } + stream_name = mem_malloc(BUFSIZ); + memset(stream_name, 0, BUFSIZ); + while (stream == NULL) { + status_mesg(ask_fname, ""); + cancel = updatestring(win[STA].p, &stream_name, 0, 1); + if (cancel) { + mem_free(stream_name); + return NULL; } - mem_free (stream_name); + stream = fopen(stream_name, "r"); + if (stream == NULL) { + status_mesg(wrong_file, press_enter); + wgetch(win[STA].p); + } + } + mem_free(stream_name); return stream; } @@ -2715,229 +993,182 @@ get_import_stream (enum export_type type) * A temporary log file is created in /tmp to store the import process report, * and is cleared at the end. */ -void -io_import_data (enum import_type type, struct conf *conf, char *stream_name) +void io_import_data(enum import_type type, const char *stream_name) { - const struct string vevent = STRING_BUILD ("BEGIN:VEVENT"); - const struct string vtodo = STRING_BUILD ("BEGIN:VTODO"); - char *proc_report = _("Import process report: %04d lines read "); - char *lines_stats = - _("%d apps / %d events / %d todos / %d skipped "); - char *lines_stats_interactive = - _("%d apps / %d events / %d todos / %d skipped ([ENTER] to continue)"); - char buf[BUFSIZ], lstore[BUFSIZ]; + const char *proc_report = _("Import process report: %04d lines read "); + char stats_str[4][BUFSIZ]; FILE *stream = NULL; struct io_file *log; - float ical_version; struct { unsigned events, apoints, todos, lines, skipped; } stats; - EXIT_IF (type < 0 || type >= IO_IMPORT_NBTYPES, _("unknown import type")); - switch (ui_mode) - { - case UI_CMDLINE: - stream = fopen (stream_name, "r"); - EXIT_IF (stream == NULL, - _("FATAL ERROR: the input file cannot be accessed, " - "Aborting...")); - break; - case UI_CURSES: - stream = get_import_stream (type); - break; - default: - EXIT (_("FATAL ERROR: wrong import mode")); - /* NOTREACHED */ - } + EXIT_IF(type < 0 || type >= IO_IMPORT_NBTYPES, _("unknown import type")); + switch (ui_mode) { + case UI_CMDLINE: + stream = fopen(stream_name, "r"); + EXIT_IF(stream == NULL, + _("FATAL ERROR: the input file cannot be accessed, " + "Aborting...")); + break; + case UI_CURSES: + stream = get_import_stream(type); + break; + default: + EXIT(_("FATAL ERROR: wrong import mode")); + /* NOTREACHED */ + } if (stream == NULL) return; - bzero (&stats, sizeof stats); - ical_readline_init (stream, buf, lstore, &stats.lines); - ical_version = ical_chk_header (stream, buf, lstore, &stats.lines); - RETURN_IF (ical_version < 0, - _("Warning: ical header malformed or wrong version number. " - "Aborting...")); - - log = io_log_init (); - if (log == NULL) - { - if (stream != stdin) - file_close (stream, __FILE_POS__); - return; - } - ical_log_init (log->fd, ical_version); - - while (ical_readline (stream, buf, lstore, &stats.lines)) - { - stats.lines++; - str_toupper (buf); - if (strncmp (buf, vevent.str, vevent.len) == 0) - { - ical_read_event (stream, log->fd, &stats.events, &stats.apoints, - &stats.skipped, buf, lstore, &stats.lines); - } - else if (strncmp (buf, vtodo.str, vtodo.len) == 0) - { - ical_read_todo (stream, log->fd, &stats.todos, &stats.skipped, - buf, lstore, &stats.lines); - } - } - if (stream != stdin) - file_close (stream, __FILE_POS__); + memset(&stats, 0, sizeof stats); - /* Update the number of todo items. */ - todo_set_nb (todo_nb () + stats.todos); + log = io_log_init(); + if (log == NULL) { + if (stream != stdin) + file_close(stream, __FILE_POS__); + return; + } - if (ui_mode == UI_CURSES && !conf->skip_system_dialogs) - { - char read[BUFSIZ], stat[BUFSIZ]; + if (type == IO_IMPORT_ICAL) + ical_import_data(stream, log->fd, &stats.events, &stats.apoints, + &stats.todos, &stats.lines, &stats.skipped); - (void)snprintf (read, BUFSIZ, proc_report, stats.lines); - (void)snprintf (stat, BUFSIZ, lines_stats_interactive, stats.apoints, - stats.events, stats.todos, stats.skipped); - status_mesg (read, stat); - (void)wgetch (win[STA].p); - } - else if (ui_mode == UI_CMDLINE) - { - printf (proc_report, stats.lines); - printf ("\n"); - printf (lines_stats, stats.apoints, stats.events, stats.todos, - stats.skipped); - printf ("\n"); - } + if (stream != stdin) + file_close(stream, __FILE_POS__); + + snprintf(stats_str[0], BUFSIZ, + ngettext("%d app", "%d apps", stats.apoints), stats.apoints); + snprintf(stats_str[1], BUFSIZ, + ngettext("%d event", "%d events", stats.events), stats.events); + snprintf(stats_str[2], BUFSIZ, + ngettext("%d todo", "%d todos", stats.todos), stats.todos); + snprintf(stats_str[3], BUFSIZ, _("%d skipped"), stats.skipped); + + /* Update the number of todo items. */ + todo_set_nb(todo_nb() + stats.todos); + + if (ui_mode == UI_CURSES && conf.system_dialogs) { + char read[BUFSIZ], stat[BUFSIZ]; + + snprintf(read, BUFSIZ, proc_report, stats.lines); + snprintf(stat, BUFSIZ, "%s / %s / %s / %s (%s)", stats_str[0], + stats_str[1], stats_str[2], stats_str[3], + _("Press [ENTER] to continue")); + status_mesg(read, stat); + wgetch(win[STA].p); + } else if (ui_mode == UI_CMDLINE) { + printf(proc_report, stats.lines); + printf("\n%s / %s / %s / %s\n", stats_str[0], stats_str[1], + stats_str[2], stats_str[3]); + } /* User has the choice to look at the log file if some items could not be imported. - */ - file_close (log->fd, __FILE_POS__); - if (stats.skipped > 0) - { - char *view_log = _("Some items could not be imported, see log file ?"); + */ + file_close(log->fd, __FILE_POS__); + if (stats.skipped > 0) { + const char *view_log = + _("Some items could not be imported, see log file ?"); - io_log_display (log, view_log, conf->pager); - } - io_log_free (log); + io_log_display(log, view_log, conf.pager); + } + io_log_free(log); } -struct io_file * -io_log_init (void) +struct io_file *io_log_init(void) { char logprefix[BUFSIZ]; char *logname; struct io_file *log; - snprintf (logprefix, BUFSIZ, "%s/calcurse_log.", get_tempdir ()); - logname = new_tempfile (logprefix, NOTESIZ); - RETVAL_IF (logname == NULL, 0, - _("Warning: could not create temporary log file, Aborting...")); - log = mem_malloc (sizeof (struct io_file)); - RETVAL_IF (log == NULL, 0, - _("Warning: could not open temporary log file, Aborting...")); - (void)snprintf (log->name, sizeof (log->name), "%s%s", logprefix, logname); - mem_free (logname); - log->fd = fopen (log->name, "w"); - if (log->fd == NULL) - { - ERROR_MSG (_("Warning: could not open temporary log file, Aborting...")); - mem_free (log); - return 0; - } + snprintf(logprefix, BUFSIZ, "%s/calcurse_log.", get_tempdir()); + logname = new_tempfile(logprefix, TMPEXTSIZ); + RETVAL_IF(logname == NULL, 0, + _("Warning: could not create temporary log file, Aborting...")); + log = mem_malloc(sizeof(struct io_file)); + RETVAL_IF(log == NULL, 0, + _("Warning: could not open temporary log file, Aborting...")); + snprintf(log->name, sizeof(log->name), "%s%s", logprefix, logname); + mem_free(logname); + log->fd = fopen(log->name, "w"); + if (log->fd == NULL) { + ERROR_MSG(_("Warning: could not open temporary log file, Aborting...")); + mem_free(log); + return 0; + } return log; } -void -io_log_print (struct io_file *log, int line, char *msg) +void io_log_print(struct io_file *log, int line, const char *msg) { if (log && log->fd) - (void)fprintf (log->fd, "line %d: %s\n", line, msg); + fprintf(log->fd, "line %d: %s\n", line, msg); } -void -io_log_display (struct io_file *log, char *msg, char *pager) +void io_log_display(struct io_file *log, const char *msg, const char *pager) { - char *choices = "[y/n] "; int ans; - RETURN_IF (log == NULL, _("No log file to display!")); - if (ui_mode == UI_CMDLINE) - { - printf ("\n%s %s", msg, choices); - ans = fgetc (stdin); - if (ans == 'y') - { - char cmd[BUFSIZ]; - - (void)snprintf (cmd, BUFSIZ, "%s %s", pager, log->name); - (void)system (cmd); - } - } - else - { - status_mesg (msg, choices); - do - { - ans = wgetch (win[STA].p); - if (ans == 'y') - { - wins_launch_external (log->name, pager); - } - } - while (ans != 'y' && ans != 'n'); - wins_erase_status_bar (); + RETURN_IF(log == NULL, _("No log file to display!")); + if (ui_mode == UI_CMDLINE) { + printf("\n%s [y/n] ", msg); + ans = fgetc(stdin); + if (ans == 'y') { + const char *arg[] = { pager, log->name, NULL }; + int pid; + + if ((pid = fork_exec(NULL, NULL, pager, arg))) + child_wait(NULL, NULL, pid); } + } else { + if (status_ask_bool(msg) == 1) + wins_launch_external(log->name, pager); + wins_erase_status_bar(); + } } -void -io_log_free (struct io_file *log) +void io_log_free(struct io_file *log) { if (!log) return; - EXIT_IF (unlink (log->name) != 0, - _("Warning: could not erase temporary log file %s, Aborting..."), - log->name); - mem_free (log); + EXIT_IF(unlink(log->name) != 0, + _("Warning: could not erase temporary log file %s, Aborting..."), + log->name); + mem_free(log); } static pthread_t io_t_psave; /* Thread used to periodically save data. */ -static void * -io_psave_thread (void *arg) +static void *io_psave_thread(void *arg) { - struct conf *config; int delay; - config = (struct conf *)arg; - delay = config->periodic_save; - EXIT_IF (delay < 0, _("Invalid delay")); + delay = conf.periodic_save; + EXIT_IF(delay < 0, _("Invalid delay")); - for (;;) - { - (void)sleep (delay * MININSEC); - io_save_cal (config, IO_SAVE_DISPLAY_MARK); - } + for (;;) { + sleep(delay * MININSEC); + io_save_cal(IO_SAVE_DISPLAY_MARK); + } } /* Launch the thread which handles periodic saves. */ -void -io_start_psave_thread (struct conf *conf) +void io_start_psave_thread(void) { - pthread_create (&io_t_psave, NULL, io_psave_thread, (void *)conf); + pthread_create(&io_t_psave, NULL, io_psave_thread, NULL); } /* Stop periodic data saves. */ -void -io_stop_psave_thread (void) +void io_stop_psave_thread(void) { - if (io_t_psave) - { - pthread_cancel (io_t_psave); - pthread_join (io_t_psave, NULL); - } + if (io_t_psave) { + pthread_cancel(io_t_psave); + pthread_join(io_t_psave, NULL); + } } /* @@ -2951,49 +1182,40 @@ io_stop_psave_thread (void) * Note: When creating the lock file, the interactive mode is not initialized * yet. */ -void -io_set_lock (void) +void io_set_lock(void) { - FILE *lock = fopen (path_cpid, "r"); + FILE *lock = fopen(path_cpid, "r"); int pid; - if (lock != NULL) - { - /* If there is a lock file, check whether the process exists. */ - if (fscanf(lock, "%d", &pid) == 1) - { - fclose(lock); - if (kill(pid, 0) != 0 && errno == ESRCH) - lock = NULL; - } - else - fclose(lock); - } - - if (lock != NULL) - { - (void)fprintf (stderr, - _("\nWARNING: it seems that another calcurse instance is " - "already running.\n" - "If this is not the case, please remove the following " - "lock file: \n\"%s\"\n" - "and restart calcurse.\n"), path_cpid); - exit (EXIT_FAILURE); - } - else - { - if (!io_dump_pid (path_cpid)) - EXIT (_("FATAL ERROR: could not create %s: %s\n"), - path_cpid, strerror (errno)); - } + if (lock != NULL) { + /* If there is a lock file, check whether the process exists. */ + if (fscanf(lock, "%d", &pid) == 1) { + fclose(lock); + if (kill(pid, 0) != 0 && errno == ESRCH) + lock = NULL; + } else + fclose(lock); + } + + if (lock != NULL) { + fprintf(stderr, + _("\nWARNING: it seems that another calcurse instance is " + "already running.\n" + "If this is not the case, please remove the following " + "lock file: \n\"%s\"\n" "and restart calcurse.\n"), path_cpid); + exit(EXIT_FAILURE); + } else { + if (!io_dump_pid(path_cpid)) + EXIT(_("FATAL ERROR: could not create %s: %s\n"), + path_cpid, strerror(errno)); + } } /* * Create a new file and write the process pid inside (used to create a simple * lock for example). Overwrite already existing files. */ -unsigned -io_dump_pid (char *file) +unsigned io_dump_pid(char *file) { pid_t pid; FILE *fp; @@ -3001,10 +1223,9 @@ io_dump_pid (char *file) if (!file) return 0; - pid = getpid (); - if (!(fp = fopen (file, "w")) - || fprintf (fp, "%ld\n", (long)pid) < 0 - || fclose (fp) != 0) + pid = getpid(); + if (!(fp = fopen(file, "w")) + || fprintf(fp, "%ld\n", (long)pid) < 0 || fclose(fp) != 0) return 0; return 1; @@ -3015,8 +1236,7 @@ io_dump_pid (char *file) * io_dump_pid (). * If no file was found, return 0. */ -unsigned -io_get_pid (char *file) +unsigned io_get_pid(char *file) { FILE *fp; unsigned pid; @@ -3024,13 +1244,13 @@ io_get_pid (char *file) if (!file) return 0; - if ((fp = fopen (file, "r")) == NULL) + if ((fp = fopen(file, "r")) == NULL) return 0; - if (fscanf (fp, "%u", &pid) != 1) + if (fscanf(fp, "%u", &pid) != 1) return 0; - (void)fclose (fp); + fclose(fp); return pid; } @@ -3038,24 +1258,48 @@ io_get_pid (char *file) /* * Check whether a file is empty. */ -int -io_file_is_empty (char *file) +int io_file_is_empty(char *file) { FILE *fp; - if (file && (fp = fopen (file, "r"))) - { - if ((fgetc (fp) == '\n' && fgetc (fp) == EOF) || feof (fp)) - { - fclose (fp); - return 1; - } - else - { - fclose (fp); - return 0; - } + if (file && (fp = fopen(file, "r"))) { + if ((fgetc(fp) == '\n' && fgetc(fp) == EOF) || feof(fp)) { + fclose(fp); + return 1; + } else { + fclose(fp); + return 0; } + } return -1; } + +/* + * Copy an existing file to a new location. + */ +int io_file_cp(const char *src, const char *dst) +{ + FILE *fp_src, *fp_dst; + char *buffer[BUFSIZ]; + unsigned int bytes_read; + + if (!(fp_src = fopen(src, "rb"))) + return 0; + if (!(fp_dst = fopen(dst, "wb"))) + return 0; + + while (!feof(fp_src)) { + bytes_read = fread(buffer, 1, BUFSIZ, fp_src); + if (bytes_read > 0) { + if (fwrite(buffer, 1, bytes_read, fp_dst) != bytes_read) + return 0; + } else + return 0; + } + + fclose(fp_dst); + fclose(fp_src); + + return 1; +} |