/*
* Calcurse - text-based organizer
*
* Copyright (c) 2004-2023 calcurse Development Team <misc@calcurse.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Send your feedback or comments to : misc@calcurse.org
* Calcurse home page : http://calcurse.org
*
*/
#include <sys/types.h>
#include "calcurse.h"
/* Static functions used to add export functionalities. */
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 *);
/* Type definition for callbacks to export functions. */
typedef void (*cb_dump_t) (FILE *, long, long, char *);
/*
* 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_start, 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_start;
localtime_r(&t, <);
lt.tm_hour = lt.tm_min = lt.tm_sec = 0;
lt.tm_isdst = -1;
date = mktime(<);
item_time = item_start - date;
while (date <= date_end && date <= rpt->until) {
if (recur_item_inday(item_start, item_dur, rpt, exc, 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;
}
}
}
static void pcal_export_header(FILE * stream)
{
fputs("# calcurse pcal export\n", stream);
fputs("\n# =======\n# options\n# =======\n", stream);
fprintf(stream, "opt -A -K -l -m -F %s\n", get_wday_default_string(
ui_calendar_get_wday_start()));
fputs("# Display week number (i.e. 1-52) on every Monday\n",
stream);
fprintf(stream, "all monday in all week %%w\n");
fputc('\n', stream);
}
static void pcal_export_footer(FILE * stream)
{
}
/* 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);
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);
fprintf(stream, "%s ", pcal_date);
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];
fputs("\n# =============", stream);
fputs("\n# Recur. Events", stream);
fputs("\n# =============\n", stream);
fputs("# (pcal does not support from..until dates specification\n",
stream);
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);
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);
fprintf(stream, "all %s on_or_after ",
pcal_date);
date_sec2date_fmt(rev->day, "%b %d",
pcal_date);
fprintf(stream, "%s %s\n", pcal_date,
rev->mesg);
break;
case RECUR_MONTHLY:
date_sec2date_fmt(rev->day, "%d",
pcal_date);
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);
fprintf(stream, "%s %s\n", pcal_date,
rev->mesg);
break;
default:
EXIT(_("incoherent repetition type"));
}
} else {
const long YEAR_START =
ui_calendar_start_of_year();
const long YEAR_END = ui_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);
}
}
}
static void pcal_export_events(FILE * stream)
{
llist_item_t *i;
fputs("\n# ======\n# Events\n# ======\n", stream);
LLIST_FOREACH(&eventlist, i) {
struct event *ev = LLIST_TS_GET_DATA(i);
pcal_dump_event(stream, ev->day, 0, ev->mesg);
}
fputc('\n', stream);
}
static void pcal_export_recur_apoints(FILE * stream)
{
llist_item_t *i;
char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ];
fputs("\n# ==============", stream);
fputs("\n# Recur. Apoints", stream);
fputs("\n# ==============\n", stream);
fputs("# (pcal does not support from..until dates specification\n",
stream);
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);
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);
fprintf(stream, "all %s on_or_after ",
pcal_date);
date_sec2date_fmt(rapt->start, "%b %d",
pcal_date);
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);
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);
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 =
ui_calendar_start_of_year();
const long YEAR_END = ui_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);
}
}
}
static void pcal_export_apoints(FILE * stream)
{
llist_item_t *i;
fputs("\n# ============\n# Appointments\n# ============\n",
stream);
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);
}
LLIST_TS_UNLOCK(&alist_p);
fputc('\n', stream);
}
static void pcal_export_todo(FILE * stream)
{
llist_item_t *i;
fputs("#\n# Todos\n#\n", stream);
LLIST_FOREACH(&todolist, i) {
struct todo *todo = LLIST_TS_GET_DATA(i);
if (todo->completed)
continue;
fputs("note all ", stream);
fprintf(stream, "%d. %s\n", todo->id, todo->mesg);
}
fputc('\n', stream);
}
/* Export calcurse data. */
void pcal_export_data(FILE * stream)
{
pcal_export_header(stream);
pcal_export_recur_events(stream);
pcal_export_events(stream);
pcal_export_recur_apoints(stream);
pcal_export_apoints(stream);
pcal_export_todo(stream);
pcal_export_footer(stream);
}