From 1674800d5fb26decfa74cb7a1d94e2154b7c27a6 Mon Sep 17 00:00:00 2001
From: Frederic Culot <calcurse@culot.org>
Date: Sun, 10 Aug 2008 09:24:46 +0000
Subject: pcal export added

---
 src/args.c     |   4 +-
 src/calcurse.c |  25 +++-
 src/calendar.c |  42 ++++++-
 src/calendar.h |   4 +-
 src/io.c       | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/io.h       |  15 ++-
 src/recur.c    |  21 +++-
 src/recur.h    |   5 +-
 src/utils.c    |  40 +++++-
 src/utils.h    |   4 +-
 10 files changed, 481 insertions(+), 54 deletions(-)

(limited to 'src')

diff --git a/src/args.c b/src/args.c
index c345da7..0b87aad 100755
--- a/src/args.c
+++ b/src/args.c
@@ -1,4 +1,4 @@
-/*	$calcurse: args.c,v 1.35 2008/08/06 17:44:34 culot Exp $	*/
+/*	$calcurse: args.c,v 1.36 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -731,7 +731,7 @@ parse_args (int argc, char **argv, conf_t *conf)
 	    {
 	      notify_init_vars ();
 	      custom_load_conf (conf, 0);
-	      io_export_data (IO_EXPORT_NONINTERACTIVE, conf);
+	      io_export_data (IO_EXPORT_NONINTERACTIVE, IO_EXPORT_ICAL, conf);
 	      non_interactive = 1;
 	      return (non_interactive);
 	    }
diff --git a/src/calcurse.c b/src/calcurse.c
index cd9b31c..91cc8d5 100755
--- a/src/calcurse.c
+++ b/src/calcurse.c
@@ -1,4 +1,4 @@
-/*	$calcurse: calcurse.c,v 1.64 2008/08/03 18:41:55 culot Exp $	*/
+/*	$calcurse: calcurse.c,v 1.65 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -384,7 +384,28 @@ main (int argc, char **argv)
 
 	case 'X':
 	case 'x':		/* Export function */
-	  io_export_data (IO_EXPORT_INTERACTIVE, &conf);
+          erase_status_bar ();
+          io_export_bar ();
+          while ((ch = wgetch (win[STA].p)) != 'q')
+	    {
+	      switch (ch)
+		{
+		case 'I':
+		case 'i':
+                  io_export_data (IO_EXPORT_INTERACTIVE, IO_EXPORT_ICAL, &conf);
+		  break;
+		case 'P':
+		case 'p':
+                  io_export_data (IO_EXPORT_INTERACTIVE, IO_EXPORT_PCAL, &conf);
+		  break;
+		}
+	      wins_reset ();
+	      wins_update ();
+	      do_storage = true;
+	      erase_status_bar ();
+	      io_export_bar ();
+	    }
+	  wins_update ();
 	  break;
 
         case KEY_RIGHT:
diff --git a/src/calendar.c b/src/calendar.c
index c6a4676..94dd870 100755
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -1,4 +1,4 @@
-/*	$calcurse: calendar.c,v 1.16 2008/08/03 18:41:55 culot Exp $	*/
+/*	$calcurse: calendar.c,v 1.17 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -399,7 +399,7 @@ calendar_change_day (int datefmt)
  * Used to change date by adding a certain amount of days or weeks.
  * Returns 0 on success, 1 otherwise.
  */
-int
+static int
 date_change (struct tm *date, int delta_month, int delta_day)
 {
   struct tm t;
@@ -485,6 +485,44 @@ calendar_move (move_t move)
     }
 }
 
+/* Returns the beginning of current year as a long. */
+long
+calendar_start_of_year (void)
+{
+  time_t timer;
+  struct tm *tm;
+
+  timer = time (NULL);
+  tm = localtime (&timer);
+  tm->tm_mon = 0;
+  tm->tm_mday = 1;
+  tm->tm_hour = 0;
+  tm->tm_min = 0;
+  tm->tm_sec = 0;
+  timer = mktime (tm);
+
+  return (long)timer;
+}
+
+long
+calendar_end_of_year (void)
+{
+  time_t timer;
+  struct tm *tm;
+
+  timer = time (NULL);
+  tm = localtime (&timer);
+  tm->tm_mon = 0;
+  tm->tm_mday = 1;
+  tm->tm_hour = 0;
+  tm->tm_min = 0;
+  tm->tm_sec = 0;
+  tm->tm_year++;
+  timer = mktime (tm);
+
+  return (long)(timer - 1);
+}
+
 /*
  * The pom, potm, dotr, adj360 are used to compute the current 
  * phase of the moon.
diff --git a/src/calendar.h b/src/calendar.h
index dab98a1..30762fc 100755
--- a/src/calendar.h
+++ b/src/calendar.h
@@ -1,4 +1,4 @@
-/*	$calcurse: calendar.h,v 1.11 2008/08/03 18:41:55 culot Exp $	*/
+/*	$calcurse: calendar.h,v 1.12 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -92,6 +92,8 @@ void    calendar_update_panel (WINDOW *);
 void    calendar_goto_today (void);
 void    calendar_change_day (int);
 void    calendar_move (move_t);
+long    calendar_start_of_year (void);
+long    calendar_end_of_year (void);
 char   *calendar_get_pom (time_t);
 
 #endif /* CALCURSE_CALENDAR_H */
diff --git a/src/io.c b/src/io.c
index 792a243..3ad64ea 100755
--- a/src/io.c
+++ b/src/io.c
@@ -1,4 +1,4 @@
-/*	$calcurse: io.c,v 1.30 2008/08/06 17:44:34 culot Exp $	*/
+/*	$calcurse: io.c,v 1.31 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -45,9 +45,46 @@ typedef enum
   PROGRESS_BAR_SAVE,
   PROGRESS_BAR_LOAD,
   PROGRESS_BAR_EXPORT
-}
-progress_bar_t;
-
+} progress_bar_t;
+
+/* 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" };
 
 /* Draw a progress bar while saving, loading or exporting data. */
 static void
@@ -107,34 +144,25 @@ progress_bar (progress_bar_t type, int progress)
   usleep (SLEEPTIME);
 }
 
-/* Return the recurrence type to dump in iCal format. */
-static char *
-io_recur_type (int type)
-{
-  char *recur_type[RECUR_TYPES] =
-      { "", "DAILY", "WEEKLY", "MONTHLY", "YEARLY" };
-
-  return (recur_type[type]);
-}
-
 /* Ask user for a file name to export data to. */
 static FILE *
-io_get_export_stream (void)
+get_export_stream (export_type_t 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.");
-  int cancel;
+  const char *file_ext[IO_EXPORT_NBTYPES] = {"ical", "txt"};
 
   stream = NULL;
   stream_name = (char *) malloc (BUFSIZ);
   if ((home = getenv ("HOME")) != NULL)
-    snprintf (stream_name, BUFSIZ, "%s/calcurse.ics", home);
+    snprintf (stream_name, BUFSIZ, "%s/calcurse.%s", home, file_ext[type]);
   else
-    snprintf (stream_name, BUFSIZ, "/tmp/calcurse.ics");
+    snprintf (stream_name, BUFSIZ, "/tmp/calcurse.%s", file_ext[type]);
 
   while (stream == NULL)
     {
@@ -157,9 +185,50 @@ io_get_export_stream (void)
   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_s *rpt, struct days_s *exc,
+                   long item_first_date, long item_dur, char *item_mesg,
+                   cb_dump_t cb_dump, FILE *stream)
+{
+  long date;
+
+  date = item_first_date;
+  while (date <= date_end && date <= rpt->until)
+    {
+      if (!recur_day_is_exc (date, exc))
+        {
+          (*cb_dump)(stream, date, 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:
+          fputs (_("FATAL ERROR in foreach_date_dump: "
+                   "incoherent repetition type\n"), stderr);
+          exit (EXIT_FAILURE);
+          /* NOTREACHED */
+          break;
+        }
+    }
+}
+
 /* iCal alarm notification. */
 static void
-io_export_valarm (FILE *stream)
+ical_export_valarm (FILE *stream)
 {
   fprintf (stream, "BEGIN:VALARM\n");
   pthread_mutex_lock (&nbar->mutex);
@@ -171,23 +240,41 @@ io_export_valarm (FILE *stream)
 
 /* Export header. */
 static void
-io_export_header (FILE *stream)
+ical_export_header (FILE *stream)
 {
   fprintf (stream, "BEGIN:VCALENDAR\n");
   fprintf (stream, "PRODID:-//calcurse//NONSGML v%s//EN\n", VERSION);
   fprintf (stream, "VERSION:2.0\n");
 }
 
+static void
+pcal_export_header (FILE *stream)
+{
+  fprintf (stream, "# calcurse pcal export\n");
+  fprintf (stream, "\n# =======\n# options\n# =======\n");
+  fprintf (stream, "opt -A -K -l -m -F %s\n",
+           calendar_week_begins_on_monday () ?
+           "Monday" : "Sunday");
+  fprintf (stream, "# Display week number (i.e. 1-52) on every Monday\n");
+  fprintf (stream, "all monday in all  %s %%w\n", _("Week"));
+  fprintf (stream, "\n");
+}
+                 
 /* Export footer. */
 static void
-io_export_footer (FILE *stream)
+ical_export_footer (FILE *stream)
 {
   fprintf (stream, "END:VCALENDAR\n");
 }
 
+static void
+pcal_export_footer (FILE *stream)
+{
+}
+
 /* Export recurrent events. */
 static void
-io_export_recur_events (FILE *stream)
+ical_export_recur_events (FILE *stream)
 {
   struct recur_event_s *i;
   struct days_s *day;
@@ -199,7 +286,7 @@ io_export_recur_events (FILE *stream)
       fprintf (stream, "BEGIN:VEVENT\n");
       fprintf (stream, "DTSTART:%s\n", ical_date);
       fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d",
-	       io_recur_type (i->rpt->type), i->rpt->freq);
+	       ical_recur_type[i->rpt->type], i->rpt->freq);
 
       if (i->rpt->until != 0)
 	{
@@ -226,9 +313,90 @@ io_export_recur_events (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)
+{
+  struct recur_event_s *i;
+  char pcal_date[BUFSIZ];
+
+  fprintf (stream, "\n# =============");
+  fprintf (stream, "\n# Recur. Events");
+  fprintf (stream, "\n# =============\n");
+  fprintf (stream,
+           "# (pcal does not support from..until dates specification\n");
+
+  for (i = recur_elist; i != 0; i = i->next)
+    {
+      if (i->rpt->until == 0 && i->rpt->freq == 1)
+        {
+          switch (i->rpt->type)
+            {
+            case RECUR_DAILY:
+              date_sec2date_fmt (i->day, "%b %d", pcal_date);
+              fprintf (stream, "all day on_or_after %s  %s\n",
+                       pcal_date, i->mesg);
+              break;
+            case RECUR_WEEKLY:
+              date_sec2date_fmt (i->day, "%a", pcal_date);
+              fprintf (stream, "all %s on_or_after ", pcal_date);
+              date_sec2date_fmt (i->day, "%b %d", pcal_date);
+              fprintf (stream, "%s  %s\n", pcal_date, i->mesg);
+              break;
+            case RECUR_MONTHLY:
+              date_sec2date_fmt (i->day, "%d", pcal_date);
+              fprintf (stream, "day on all %s  %s\n", pcal_date, i->mesg);
+              break;
+            case RECUR_YEARLY:
+              date_sec2date_fmt (i->day, "%b %d", pcal_date);
+              fprintf (stream, "%s  %s\n", pcal_date, i->mesg);
+              break;
+            default:
+              fputs (_("FATAL ERROR in pcal_export_recur_events: "
+                       "incoherent repetition type\n"), stderr);
+              exit (EXIT_FAILURE);
+              break;
+            }
+        }
+      else
+        {
+          const long YEAR_START = calendar_start_of_year ();
+          const long YEAR_END = calendar_end_of_year ();
+
+          if (i->day < YEAR_END && i->day > YEAR_START)
+            foreach_date_dump (YEAR_END, i->rpt, i->exc, i->day, 0, i->mesg,
+                               (cb_dump_t) pcal_dump_event, stream);
+        }
+    }
+}
+
 /* Export events. */
 static void
-io_export_events (FILE *stream)
+ical_export_events (FILE *stream)
 {
   struct event_s *i;
   char ical_date[BUFSIZ];
@@ -243,9 +411,20 @@ io_export_events (FILE *stream)
     }
 }
 
+static void
+pcal_export_events (FILE *stream)
+{
+  struct event_s *i;
+  
+  fprintf (stream, "\n# ======\n# Events\n# ======\n");
+  for (i = eventlist; i != 0; i = i->next)
+    pcal_dump_event (stream, i->day, 0, i->mesg);
+  fprintf (stream, "\n");
+}
+     
 /* Export recurrent appointments. */
 static void
-io_export_recur_apoints (FILE *stream)
+ical_export_recur_apoints (FILE *stream)
 {
   recur_apoint_llist_node_t *i;
   struct days_s *day;
@@ -260,7 +439,7 @@ io_export_recur_apoints (FILE *stream)
       fprintf (stream, "DTSTART:%s\n", ical_datetime);
       fprintf (stream, "DURATION:P%ldS\n", i->dur);
       fprintf (stream, "RRULE:FREQ=%s;INTERVAL=%d",
-	       io_recur_type (i->rpt->type), i->rpt->freq);
+	       ical_recur_type[i->rpt->type], i->rpt->freq);
 
       if (i->rpt->until != 0)
 	{
@@ -284,15 +463,76 @@ io_export_recur_apoints (FILE *stream)
 
       fprintf (stream, "SUMMARY:%s\n", i->mesg);
       if (i->state & APOINT_NOTIFY)
-	io_export_valarm (stream);
+	ical_export_valarm (stream);
       fprintf (stream, "END:VEVENT\n");
     }
   pthread_mutex_unlock (&(recur_alist_p->mutex));
 }
 
+static void
+pcal_export_recur_apoints (FILE *stream)
+{
+  recur_apoint_llist_node_t *i;
+  char pcal_date[BUFSIZ], pcal_beg[BUFSIZ], pcal_end[BUFSIZ];
+  
+  fprintf (stream, "\n# ==============");
+  fprintf (stream, "\n# Recur. Apoints");
+  fprintf (stream, "\n# ==============\n");
+  fprintf (stream, 
+           "# (pcal does not support from..until dates specification\n");
+
+  for (i = recur_alist_p->root; i != 0; i = i->next)
+    {
+      if (i->rpt->until == 0 && i->rpt->freq == 1)
+        {
+          date_sec2date_fmt (i->start, "%R", pcal_beg);
+          date_sec2date_fmt (i->start + i->dur, "%R", pcal_end);
+          switch (i->rpt->type)
+            {
+            case RECUR_DAILY:
+              date_sec2date_fmt (i->start, "%b %d", pcal_date);
+              fprintf (stream, "all day on_or_after %s  (%s -> %s) %s\n",
+                       pcal_date, pcal_beg, pcal_end, i->mesg);
+              break;
+            case RECUR_WEEKLY:
+              date_sec2date_fmt (i->start, "%a", pcal_date);
+              fprintf (stream, "all %s on_or_after ", pcal_date);
+              date_sec2date_fmt (i->start, "%b %d", pcal_date);
+              fprintf (stream, "%s  (%s -> %s) %s\n", pcal_date,
+                       pcal_beg, pcal_end, i->mesg);
+              break;
+            case RECUR_MONTHLY:
+              date_sec2date_fmt (i->start, "%d", pcal_date);
+              fprintf (stream, "day on all %s  (%s -> %s) %s\n", pcal_date,
+                       pcal_beg, pcal_end, i->mesg);
+              break;
+            case RECUR_YEARLY:
+              date_sec2date_fmt (i->start, "%b %d", pcal_date);
+              fprintf (stream, "%s  (%s -> %s) %s\n", pcal_date,
+                       pcal_beg, pcal_end, i->mesg);
+              break;
+            default:
+              fputs (_("FATAL ERROR in pcal_export_recur_apoints: "
+                       "incoherent repetition type\n"), stderr);
+              exit (EXIT_FAILURE);
+              break;
+            }
+        }
+      else
+        {
+          const long YEAR_START = calendar_start_of_year ();
+          const long YEAR_END = calendar_end_of_year ();
+
+          if (i->start < YEAR_END && i->start > YEAR_START)
+            foreach_date_dump (YEAR_END, i->rpt, i->exc, i->start, i->dur,
+                               i->mesg, (cb_dump_t)pcal_dump_apoint, stream);
+        }
+    }
+}
+
 /* Export appointments. */
 static void
-io_export_apoints (FILE *stream)
+ical_export_apoints (FILE *stream)
 {
   apoint_llist_node_t *i;
   char ical_datetime[BUFSIZ];
@@ -306,15 +546,28 @@ io_export_apoints (FILE *stream)
       fprintf (stream, "DURATION:P%ldS\n", i->dur);
       fprintf (stream, "SUMMARY:%s\n", i->mesg);
       if (i->state & APOINT_NOTIFY)
-	io_export_valarm (stream);
+	ical_export_valarm (stream);
       fprintf (stream, "END:VEVENT\n");
     }
   pthread_mutex_unlock (&(alist_p->mutex));
 }
 
+static void
+pcal_export_apoints (FILE *stream)
+{
+  fprintf (stream, "\n# ============\n# Appointments\n# ============\n");
+  apoint_llist_node_t *i;
+
+  pthread_mutex_lock (&(alist_p->mutex));
+  for (i = alist_p->root; i != 0; i = i->next)
+      pcal_dump_apoint (stream, i->start, i->dur, i->mesg);
+  pthread_mutex_unlock (&(alist_p->mutex));
+  fprintf (stream, "\n");
+}
+
 /* Export todo items. */
 static void
-io_export_todo (FILE *stream)
+ical_export_todo (FILE *stream)
 {
   struct todo_s *i;
 
@@ -327,6 +580,20 @@ io_export_todo (FILE *stream)
     }
 }
 
+static void
+pcal_export_todo (FILE *stream)
+{
+  struct todo_s *i;
+
+  fprintf (stream, "#\n# Todos\n#\n");
+  for (i = todolist; i != 0; i = i->next)
+    {
+      fprintf (stream, "note all  ");
+      fprintf (stream, "%d. %s\n", i->id, i->mesg);
+    }
+  fprintf (stream, "\n");
+}
+
 /* 
  * Initialization of data paths. The cfile argument is the variable
  * which contains the calendar file. If none is given, then the default
@@ -943,20 +1210,26 @@ io_startup_screen (bool skip_dialogs, int no_data_file)
 
 /* Export calcurse data. */
 void
-io_export_data (export_mode_t mode, conf_t *conf)
+io_export_data (export_mode_t mode, export_type_t type, conf_t *conf)
 {
   FILE *stream;
   char *wrong_mode = _("FATAL ERROR in io_export_data: wrong export mode\n");
+  char *wrong_type = _("FATAL ERROR in io_export_data: unknown export type\n");
   char *success = _("The data were successfully exported");
   char *enter = _("Press [ENTER] to continue");
 
+  if (type < IO_EXPORT_ICAL || type >= IO_EXPORT_NBTYPES)
+    {
+      fputs (wrong_type, stderr);
+      exit (EXIT_FAILURE);
+    }
   switch (mode)
     {
     case IO_EXPORT_NONINTERACTIVE:
       stream = stdout;
       break;
     case IO_EXPORT_INTERACTIVE:
-      stream = io_get_export_stream ();
+      stream = get_export_stream (type);
       break;
     default:
       fputs (wrong_mode, stderr);
@@ -967,23 +1240,23 @@ io_export_data (export_mode_t mode, conf_t *conf)
   if (stream == NULL)
     return;
 
-  io_export_header (stream);
+  cb_export_header[type] (stream);
 
   if (!conf->skip_progress_bar && mode == IO_EXPORT_INTERACTIVE)
     progress_bar (PROGRESS_BAR_EXPORT, 0);
-  io_export_recur_events (stream);
-  io_export_events (stream);
+  cb_export_recur_events[type] (stream);
+  cb_export_events[type] (stream);
 
   if (!conf->skip_progress_bar && mode == IO_EXPORT_INTERACTIVE)
     progress_bar (PROGRESS_BAR_EXPORT, 1);
-  io_export_recur_apoints (stream);
-  io_export_apoints (stream);
+  cb_export_recur_apoints[type] (stream);
+  cb_export_apoints[type] (stream);
 
   if (!conf->skip_progress_bar && mode == IO_EXPORT_INTERACTIVE)
     progress_bar (PROGRESS_BAR_EXPORT, 2);
-  io_export_todo (stream);
+  cb_export_todo[type] (stream);
 
-  io_export_footer (stream);
+  cb_export_footer[type] (stream);
 
   if (stream != stdout)
     fclose (stream);
@@ -994,3 +1267,27 @@ io_export_data (export_mode_t mode, conf_t *conf)
       wgetch (win[STA].p);
     }
 }
+
+/* Draws the export format selection bar */
+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);
+  doupdate ();
+}
diff --git a/src/io.h b/src/io.h
index 7578c11..e65fdbd 100755
--- a/src/io.h
+++ b/src/io.h
@@ -1,4 +1,4 @@
-/*	$calcurse: io.h,v 1.10 2008/08/06 17:44:34 culot Exp $	*/
+/*	$calcurse: io.h,v 1.11 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -34,8 +34,14 @@ typedef enum
   IO_EXPORT_NONINTERACTIVE,
   IO_EXPORT_INTERACTIVE,
   IO_EXPORT_NBMODES
-}
-export_mode_t;
+} export_mode_t;
+
+typedef enum
+{
+  IO_EXPORT_ICAL,
+  IO_EXPORT_PCAL,
+  IO_EXPORT_NBTYPES
+} export_type_t;
 
 void io_init (char *, char *);
 void io_extract_data (char *, const char *, int);
@@ -44,6 +50,7 @@ void io_load_app (void);
 void io_load_todo (void);
 int  io_check_data_files (void);
 void io_startup_screen (bool, int);
-void io_export_data (export_mode_t, conf_t *);
+void io_export_data (export_mode_t, export_type_t, conf_t *);
+void io_export_bar (void);
 
 #endif /* CALCURSE_IO_H */
diff --git a/src/recur.c b/src/recur.c
index 3188678..c014025 100755
--- a/src/recur.c
+++ b/src/recur.c
@@ -1,4 +1,4 @@
-/*	$calcurse: recur.c,v 1.36 2008/05/03 19:54:14 culot Exp $	*/
+/*	$calcurse: recur.c,v 1.37 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -402,6 +402,24 @@ recur_save_data (FILE *f)
   pthread_mutex_unlock (&(recur_alist_p->mutex));
 }
 
+/* Given a day as long, check if this day belongs to the list of exceptions for
+ * the considered item.
+ */
+int
+recur_day_is_exc (long day, struct days_s *item_exc)
+{
+  const int NOT_EXC = 0;
+  const int EXC = 1;
+  struct days_s *exc;
+
+  for (exc = item_exc; exc != 0; exc = exc->next)
+    {
+      if (exc->st == day)
+        return EXC;
+    }
+  return NOT_EXC;
+}
+
 /* 
  * Check if the recurrent item belongs to the selected day,
  * and if yes, return the real start time.
@@ -939,3 +957,4 @@ recur_apoint_switch_notify (long date, int recur_nb)
 	 stderr);
   exit (EXIT_FAILURE);
 }
+
diff --git a/src/recur.h b/src/recur.h
index dd81724..d4af3e8 100755
--- a/src/recur.h
+++ b/src/recur.h
@@ -1,4 +1,4 @@
-/*	$calcurse: recur.h,v 1.19 2008/04/12 21:14:03 culot Exp $	*/
+/*	$calcurse: recur.h,v 1.20 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -81,6 +81,8 @@ struct recur_event_s
   char                 *note;	/* note attached to event */
 };
 
+typedef void (*recur_cb_foreach_date_t)(FILE *, long, char *);
+
 extern recur_apoint_llist_t *recur_alist_p;
 extern struct recur_event_s *recur_elist;
 
@@ -94,6 +96,7 @@ struct recur_event_s      *recur_event_scan (FILE *, struct tm, int, char,
                                              int, struct tm, char *,
                                              struct days_s *);
 void                       recur_save_data (FILE *);
+int                        recur_day_is_exc (long, struct days_s *);
 unsigned                   recur_item_inday (long, struct days_s *, int, int,
                                              long, long);
 void                       recur_event_erase (long, unsigned, unsigned,
diff --git a/src/utils.c b/src/utils.c
index 0263482..dadd52a 100755
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.c,v 1.46 2008/08/03 18:41:55 culot Exp $	*/
+/*	$calcurse: utils.c,v 1.47 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -591,6 +591,44 @@ date_sec2ical_datetime (long sec, char *ical_datetime)
   strftime (ical_datetime, DATETIMELENGTH, "%Y%m%dT%H%M%S", lt);
 }
 
+/*
+ * At least a generic function to format date...
+ * I promise I will learn how to code someday.
+ */
+void
+date_sec2date_fmt (long sec, const char *fmt, char *datef)
+{
+  struct tm *lt;
+  time_t t;
+
+  t = sec;
+  lt = localtime (&t);
+  strftime (datef, BUFSIZ, fmt, lt);
+}
+
+/* 
+ * Used to change date by adding a certain amount of days or weeks.
+ */
+long
+date_sec_change (long date, int delta_month, int delta_day)
+{
+  struct tm *lt;
+  time_t t;
+  
+  t = date;
+  lt = localtime (&t);
+  lt->tm_mon += delta_month;
+  lt->tm_mday += delta_day;
+  t = mktime (lt);
+  if (t == -1)
+    {
+      fputs (_("FATAL ERROR in date_sec_change: failure in mktime\n"), stderr);
+      exit (EXIT_FAILURE);
+    }
+
+  return t;
+}
+
 /* 
  * Return a long containing the date which is updated taking into account
  * the new time and date entered by the user.
diff --git a/src/utils.h b/src/utils.h
index 35e4c96..c457581 100755
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.h,v 1.30 2008/08/03 18:41:55 culot Exp $	*/
+/*	$calcurse: utils.h,v 1.31 2008/08/10 09:24:46 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -91,6 +91,8 @@ char   *date_sec2hour_str (long);
 char   *date_sec2date_str (long, char *);
 void    date_sec2ical_date (long, char *);
 void    date_sec2ical_datetime (long, char *);
+void    date_sec2date_fmt (long, const char *, char *);
+long    date_sec_change (long, int, int);
 long    update_time_in_date (long, unsigned, unsigned);
 long    get_sec_date (date_t);
 long    min2sec (unsigned);
-- 
cgit v1.2.3-70-g09d2