summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFrederic Culot <calcurse@culot.org>2006-07-31 21:00:02 +0000
committerFrederic Culot <calcurse@culot.org>2006-07-31 21:00:02 +0000
commitac36e94341ca73d581f0df39f1c7bbf2138b2845 (patch)
tree47de561cd962ff8f47f6d811109907f15b9ff989 /src
downloadcalcurse-ac36e94341ca73d581f0df39f1c7bbf2138b2845.tar.gz
calcurse-ac36e94341ca73d581f0df39f1c7bbf2138b2845.zip
Initial revision
Diffstat (limited to 'src')
-rwxr-xr-xsrc/Makefile.am14
-rwxr-xr-xsrc/apoint.c235
-rwxr-xr-xsrc/apoint.h56
-rwxr-xr-xsrc/args.c431
-rwxr-xr-xsrc/args.h41
-rwxr-xr-xsrc/calcurse.1158
-rwxr-xr-xsrc/calcurse.c1156
-rwxr-xr-xsrc/calendar.c227
-rwxr-xr-xsrc/calendar.h41
-rwxr-xr-xsrc/custom.c178
-rwxr-xr-xsrc/custom.h42
-rwxr-xr-xsrc/day.c362
-rwxr-xr-xsrc/day.h66
-rwxr-xr-xsrc/event.c135
-rwxr-xr-xsrc/event.h48
-rwxr-xr-xsrc/help.c375
-rwxr-xr-xsrc/help.h41
-rwxr-xr-xsrc/i18n.h54
-rwxr-xr-xsrc/io.c484
-rwxr-xr-xsrc/io.h42
-rwxr-xr-xsrc/recur.c355
-rwxr-xr-xsrc/recur.h87
-rwxr-xr-xsrc/todo.c80
-rwxr-xr-xsrc/todo.h41
-rwxr-xr-xsrc/utils.c614
-rwxr-xr-xsrc/utils.h55
-rwxr-xr-xsrc/vars.c85
-rwxr-xr-xsrc/vars.h69
28 files changed, 5572 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100755
index 0000000..1614db1
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,14 @@
+# $calcurse: Makefile.am,v 1.1 2006/07/31 21:00:02 culot Exp $
+
+AUTOMAKE_OPTIONS= gnu
+bin_PROGRAMS= calcurse
+calcurse_SOURCES= calcurse.c apoint.c event.c todo.c utils.c\
+ calendar.c vars.c io.c help.c custom.c args.c\
+ day.c recur.c\
+ apoint.h event.h todo.h utils.h calendar.h\
+ vars.h io.h help.h custom.h args.h i18n.h\
+ day.h recur.h
+LIBS= -lncurses -lm
+LDADD= @LTLIBINTL@
+man_MANS= calcurse.1
+EXTRA_DIST= calcurse.1
diff --git a/src/apoint.c b/src/apoint.c
new file mode 100755
index 0000000..5cbc62e
--- /dev/null
+++ b/src/apoint.c
@@ -0,0 +1,235 @@
+/* $calcurse: apoint.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "vars.h"
+#include "event.h"
+#include "apoint.h"
+#include "day.h"
+#include "custom.h"
+#include "utils.h"
+
+struct apoint_s *apointlist;
+
+struct apoint_s *apoint_new(char *mesg, long start, long dur)
+{
+ struct apoint_s *o, **i;
+ o = (struct apoint_s *) malloc(sizeof(struct apoint_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->start = start;
+ o->dur = dur;
+ i = &apointlist;
+ for (;;) {
+ if (*i == 0 || (*i)->start > start) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+unsigned apoint_inday(struct apoint_s *i, long start)
+{
+ if (i->start <= start + 3600 * 24 && i->start + i->dur > start) {
+ return 1;
+ }
+ return 0;
+}
+
+void apoint_sec2str(struct apoint_s *o, int type, long day, char *start, char *end)
+{
+ struct tm *lt;
+ time_t t;
+
+ if (o->start < day && type == APPT) {
+ strcpy(start, "..:..");
+ } else {
+ t = o->start;
+ lt = localtime(&t);
+ snprintf(start, HRMIN_SIZE, "%02u:%02u", lt->tm_hour,
+ lt->tm_min);
+ }
+ if (o->start + o->dur > day + 24 * 3600 && type == APPT) {
+ strcpy(end, "..:..");
+ } else {
+ t = o->start + o->dur;
+ lt = localtime(&t);
+ snprintf(end, HRMIN_SIZE, "%02u:%02u", lt->tm_hour,
+ lt->tm_min);
+ }
+}
+
+void apoint_write(struct apoint_s *o, FILE * f)
+{
+ struct tm *lt;
+ time_t t;
+
+ t = o->start;
+ lt = localtime(&t);
+ fprintf(f, "%02u/%02u/%04u @ %02u:%02u",
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year,
+ lt->tm_hour, lt->tm_min);
+
+ t = o->start + o->dur;
+ lt = localtime(&t);
+ fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u |%s\n",
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year,
+ lt->tm_hour, lt->tm_min, o->mesg);
+}
+
+struct apoint_s *apoint_scan(FILE * f, struct tm start, struct tm end)
+{
+ struct tm *lt;
+ char buf[MESG_MAXSIZE], *nl;
+ time_t tstart, tend, t;
+
+ t = time(NULL);
+ lt = localtime(&t);
+
+ /* Read the appointment description */
+ fgets(buf, MESG_MAXSIZE, f);
+ nl = strchr(buf, '\n');
+ if (nl) {
+ *nl = '\0';
+ }
+
+ start.tm_sec = end.tm_sec = 0;
+ start.tm_isdst = end.tm_isdst = -1;
+ start.tm_year -= 1900;
+ start.tm_mon--;
+ end.tm_year -= 1900;
+ end.tm_mon--;
+
+ tstart = mktime(&start);
+ tend = mktime(&end);
+ if (tstart == -1 || tend == -1 || tstart > tend) {
+ fputs(_("FATAL ERROR in apoint_scan: date error in the appointment\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+ return apoint_new(buf, tstart, tend - tstart);
+}
+
+void apoint_delete_bynum(long start, unsigned num)
+{
+ unsigned n;
+ struct apoint_s *i, **iptr;
+
+ n = 0;
+ iptr = &apointlist;
+ for (i = apointlist; i != 0; i = i->next) {
+ if (apoint_inday(i, start)) {
+ if (n == num) {
+ *iptr = i->next;
+ free(i->mesg);
+ free(i);
+ return;
+ }
+ n++;
+ }
+ iptr = &i->next;
+ }
+ /* NOTREACHED */
+ fputs(_("FATAL ERROR in apoint_delete_bynum: no such appointment\n"), stderr);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Print an item date in the appointment panel.
+ */
+void display_item_date(WINDOW *win, int incolor, struct apoint_s *i,
+ int type, long date, int y, int x)
+{
+ char a_st[100], a_end[100];
+
+ apoint_sec2str(i, type, date, a_st, a_end);
+
+ if (incolor == 0)
+ custom_apply_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, y, x, " - %s -> %s", a_st, a_end);
+ if (incolor == 0)
+ custom_remove_attr(awin, ATTR_HIGHEST);
+}
+
+/*
+ * Return the line number of an item (either an appointment or an event) in
+ * the appointment panel. This is to help the appointment scroll function
+ * to place beggining of the pad correctly.
+ */
+int get_item_line(int item_nb, int nb_events_inday)
+{
+ int separator = 2;
+ int line = 0;
+
+ if (item_nb <= nb_events_inday)
+ line = item_nb - 1;
+ else
+ line = nb_events_inday + separator +
+ (item_nb - (nb_events_inday + 1))*3 - 1;
+ return line;
+}
+
+/*
+ * Update (if necessary) the first displayed pad line to make the
+ * appointment panel scroll down next time pnoutrefresh is called.
+ */
+void scroll_pad_down(int item_nb, int nb_events_inday, int win_length)
+{
+ int pad_last_line = 0;
+ int item_first_line = 0, item_last_line = 0;
+ int borders = 6;
+ int awin_length = win_length - borders;
+
+ item_first_line = get_item_line(item_nb, nb_events_inday);
+ if (item_nb < nb_events_inday)
+ item_last_line = item_first_line;
+ else
+ item_last_line = item_first_line + 1;
+ pad_last_line = apad->first_onscreen + awin_length;
+ if (item_last_line >= pad_last_line)
+ apad->first_onscreen = item_last_line - awin_length;
+}
+
+/*
+ * Update (if necessary) the first displayed pad line to make the
+ * appointment panel scroll up next time pnoutrefresh is called.
+ */
+void scroll_pad_up(int item_nb, int nb_events_inday)
+{
+ int item_first_line = 0;
+
+ item_first_line = get_item_line(item_nb, nb_events_inday);
+ if (item_first_line < apad->first_onscreen)
+ apad->first_onscreen = item_first_line;
+}
diff --git a/src/apoint.h b/src/apoint.h
new file mode 100755
index 0000000..e9dbe82
--- /dev/null
+++ b/src/apoint.h
@@ -0,0 +1,56 @@
+/* $calcurse: apoint.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_APOINT_H
+#define CALCURSE_APOINT_H
+
+#include <ncurses.h>
+
+#define HRMIN_SIZE 6
+#define MESG_MAXSIZE 256
+
+struct apoint_s {
+ struct apoint_s *next;
+ long start; /* seconds since 1 jan 1970 */
+ long dur; /* duration of the appointment in seconds */
+ char *mesg;
+};
+
+extern struct apoint_s *apointlist;
+
+struct apoint_s *apoint_new(char *, long, long);
+unsigned apoint_inday(struct apoint_s *o, long start);
+void apoint_sec2str(struct apoint_s *o, int type, long day, char *start, char *end);
+void apoint_write(struct apoint_s *o, FILE * f);
+struct apoint_s *apoint_scan(FILE * f, struct tm start, struct tm end);
+void apoint_delete_bynum(long start, unsigned num);
+void display_item_date(WINDOW *win, int color, struct apoint_s *i,
+ int type, long date, int y, int x);
+int get_item_line(int item_nb, int nb_events_inday);
+void scroll_pad_down(int item_nb, int nb_events_inday, int win_length);
+void scroll_pad_up(int item_nb, int nb_events_inday);
+
+#endif /* CALCURSE_APOINT_H */
diff --git a/src/args.c b/src/args.c
new file mode 100755
index 0000000..2261640
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,431 @@
+/* $calcurse: args.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "args.h"
+#include "vars.h"
+#include "event.h"
+#include "apoint.h"
+#include "recur.h"
+#include "day.h"
+#include "todo.h"
+#include "io.h"
+
+/*
+ * Parse the command-line arguments and call the appropriate
+ * routines to handle those arguments. Also initialize the data paths.
+ */
+int parse_args(int argc, char **argv, int colr)
+{
+ int ch, add_line = 0;
+ int unknown_flag = 0, app_found = 0;
+ int aflag = 0, cflag = 0, dflag = 0, vflag = 0, hflag = 0, tflag = 0;
+ int non_interactive = 0, multiple_flag = 0, load_data = 0;
+ int no_file = 1;
+ char *ddate = "", *cfile = NULL;
+
+ while ((ch = getopt(argc, argv, "hvtad:c:")) != -1) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ multiple_flag++;
+ load_data++;
+ break;
+ case 'd':
+ dflag = 1;
+ multiple_flag++;
+ load_data++;
+ ddate = optarg;
+ break;
+ case 'c':
+ cflag = 1;
+ multiple_flag++;
+ load_data++;
+ cfile = optarg;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ multiple_flag++;
+ load_data++;
+ add_line = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ usage();
+ usage_try();
+ unknown_flag = 1;
+ non_interactive = 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc >= 1) { /* incorrect arguments */
+ usage();
+ usage_try();
+ return 1;
+ } else {
+ if (unknown_flag) {
+ non_interactive = 1;
+ } else if (hflag) {
+ help_arg();
+ non_interactive = 1;
+ } else if (vflag) {
+ version_arg();
+ non_interactive = 1;
+ } else if (multiple_flag) {
+ if (load_data) {
+ io_init(cfile);
+ no_file = check_data_files();
+ if (dflag || aflag)
+ load_app(colr);
+ }
+ if (tflag) {
+ todo_arg(colr);
+ non_interactive = 1;
+ }
+ if (dflag) {
+ date_arg(ddate, add_line);
+ non_interactive = 1;
+ } else if (aflag) {
+ app_found = app_arg(add_line,0,0,0,0);
+ non_interactive = 1;
+ }
+ } else {
+ non_interactive = 0;
+ io_init(cfile);
+ no_file = check_data_files();
+ }
+ return non_interactive;
+ }
+}
+
+/*
+ * Print Calcurse version with a short copyright text and exit.
+ */
+void version_arg()
+{
+ char vtitle[50];
+ char *vtext =
+ _("\nCopyright (c) 2004-2006 Frederic Culot.\n"
+ "This is free software; see the source for copying conditions.\n");
+
+ sprintf(vtitle, _("Calcurse %s - text-based organizer\n"), VERSION);
+ fputs(vtitle, stdout);
+ fputs(vtext, stdout);
+}
+
+/*
+ * Print the command line options and exit.
+ */
+void help_arg()
+{
+ char htitle[50];
+ char *htext =
+ _("\nMiscellaneous:\n"
+ " -h print this help and exit.\n"
+ " -v print calcurse version and exit.\n"
+ "\nOptions:\n"
+ " -c <file> specify the calendar <file> to use.\n"
+ "\nNon-interactive:\n"
+ " -a print events and appointments for current day and exit.\n"
+ " -d <date|num> print events and appointments for <date> "
+ "or <num> upcoming\n\t\tdays and exit. Possible formats are: "
+ "'mm/dd/yyyy' or 'n'.\n"
+ " -t print todo list and exit.\n"
+ "\nFor more information, type '?' from within Calcurse, "
+ "or read the manpage.\n"
+ "Mail bug reports and suggestions to <calcurse@culot.org>.\n");
+
+ sprintf(htitle, _("Calcurse %s - text-based organizer\n"), VERSION);
+ fputs(htitle, stdout);
+ usage();
+ fputs(htext, stdout);
+}
+
+/*
+ * Print todo list and exit.
+ */
+void todo_arg(int colr)
+{
+ struct todo_s *i;
+ int nb_tod;
+
+ nb_tod = load_todo(colr);
+ fputs(_("to do:\n"),stdout);
+ for (i = todolist; i != 0; i = i->next) {
+ fputs(" - ",stdout);
+ fputs(i->mesg,stdout);
+ fputs("\n",stdout);
+ }
+}
+
+/*
+ * Print appointments for given day and exit.
+ * If no year, month, and day is given, the given date is used.
+ * If there is also no date given, current date is considered.
+ */
+int app_arg(int add_line, int year, int month, int day, long date)
+{
+ struct recur_event_s *re;
+ struct event_s *j;
+ struct recur_apoint_s *ra;
+ struct apoint_s *i;
+ long today;
+ bool print_date = true;
+ int app_found = 0;
+ char apoint_start_time[100];
+ char apoint_end_time[100];
+
+ if (date == 0) {
+ today = get_sec_date(year, month, day);
+ } else today = date;
+
+ /*
+ * Calculate and print the selected date if there is an event for
+ * that date and it is the first one, and then print all the events for
+ * that date.
+ */
+ for (re = recur_elist; re != 0; re = re->next) {
+ if (recur_item_inday(re->day, re->rpt->type, re->rpt->freq,
+ re->rpt->until, today)) {
+ app_found = 1;
+ if (add_line) {
+ fputs("\n", stdout);
+ add_line = 0;
+ }
+ if (print_date) {
+ arg_print_date(today);
+ print_date = false;
+ }
+ fputs(" o ", stdout);
+ fputs(re->mesg, stdout); fputs("\n", stdout);
+ }
+ }
+
+ for (j = eventlist; j != 0; j = j->next) {
+ if (event_inday(j, today)) {
+ app_found = 1;
+ if (add_line) {
+ fputs("\n",stdout);
+ add_line = 0;
+ }
+ if (print_date) {
+ arg_print_date(today);
+ print_date = false;
+ }
+ fputs(" o ",stdout);
+ fputs(j->mesg,stdout); fputs("\n",stdout);
+ }
+ }
+
+ /* Same process is performed but this time on the appointments. */
+ for (ra = recur_alist; ra != 0; ra = ra->next) {
+ if (recur_item_inday(ra->start, ra->rpt->type, ra->rpt->freq,
+ ra->rpt->until, today)) {
+ app_found = 1;
+ if (add_line) {
+ fputs("\n",stdout);
+ add_line = 0;
+ }
+ if (print_date) {
+ arg_print_date(today);
+ print_date = false;
+ }
+ apoint_sec2str(recur_apoint_s2apoint_s(ra),
+ RECUR_APPT, today, apoint_start_time,
+ apoint_end_time);
+ fputs(" - ",stdout);
+ fputs(apoint_start_time,stdout);
+ fputs(" -> ",stdout);
+ fputs(apoint_end_time,stdout); fputs("\n\t",stdout);
+ fputs(ra->mesg,stdout); fputs("\n",stdout);
+ }
+ }
+
+ for (i = apointlist; i != 0; i = i->next) {
+ if (apoint_inday(i, today)) {
+ app_found = 1;
+ if (add_line) {
+ fputs("\n",stdout);
+ add_line = 0;
+ }
+ if (print_date) {
+ arg_print_date(today);
+ print_date = false;
+ }
+ apoint_sec2str(i, APPT, today, apoint_start_time,
+ apoint_end_time);
+ fputs(" - ",stdout);
+ fputs(apoint_start_time,stdout);
+ fputs(" -> ",stdout);
+ fputs(apoint_end_time,stdout); fputs("\n\t",stdout);
+ fputs(i->mesg,stdout); fputs("\n",stdout);
+ }
+ }
+ return app_found;
+}
+
+/*
+ * Print appointment for the given date or for the given n upcoming
+ * days.
+ */
+void date_arg(char *ddate, int add_line)
+{
+ int i;
+ int year = 0, month = 0, day = 0;
+ int numdays = 0, num_digit = 0;
+ int arg_len = 0, app_found = 0;
+ int date_valid = 0;
+ long today, ind;
+ int sec_in_day = 86400;
+
+ /*
+ * Check (with the argument length) if a date or a number of days
+ * was entered, and then call app_arg() to print appointments
+ */
+ arg_len = strlen(ddate);
+ if (arg_len <= 4) { /* a number of days was entered */
+ for (i = 0; i <= arg_len-1; i++) {
+ if (isdigit(ddate[i])) num_digit++;
+ }
+ if (num_digit == arg_len) numdays = atoi(ddate);
+
+ /*
+ * Get current date, and print appointments for each day
+ * in the chosen interval. app_found and add_line are used
+ * to format the output correctly.
+ */
+ today = get_sec_date(year, month, day);
+ ind = today;
+ for (i = 0; i < numdays; i++) {
+ app_found = app_arg(add_line, 0, 0, 0, ind);
+ add_line = app_found;
+ ind = ind + sec_in_day;
+ }
+ } else { /* a date was entered */
+ date_valid = check_date(ddate);
+ if (date_valid) {
+ sscanf(ddate, "%d / %d / %d", &month, &day, &year);
+ app_found = app_arg(add_line, year, month, day, 0);
+ } else {
+ fputs(_("Argument to the '-d' flag is not valid\n"),stdout);
+ fputs(_("Possible argument formats are : 'mm/dd/yyyy' or 'n'\n"),stdout);
+ fputs(_("\nFor more information, type '?' from within Calcurse, or read the manpage.\n"),stdout);
+ fputs
+ (_("Mail bug reports and suggestions to <calcurse@culot.org>.\n"),
+ stdout);
+ }
+ }
+}
+
+/*
+ * Check if the entered date is of a valid format.
+ * First check the format by itself, and then check the
+ * numbers correctness.
+ */
+int
+check_date(char *date)
+{
+ int ok = 0;
+ char month[] = " ";
+ char day[] = " ";
+ char year[] = " ";
+ if (
+ (strlen(date) == 10) &
+ (isdigit(date[0]) != 0) &
+ (isdigit(date[1]) != 0) &
+ (date[2] == '/') &
+ (isdigit(date[3]) != 0) &
+ (isdigit(date[4]) != 0) &
+ (date[5] == '/') &
+ (isdigit(date[6])!=0) & (isdigit(date[7])!=0) &
+ (isdigit(date[8])!=0) & (isdigit(date[9])!=0)
+ ) {
+ strncpy(month, date, 2);
+ strncpy(day, date + 3, 2);
+ strncpy(year, date + 6, 4);
+ if ( (atoi(month) <= 12) &
+ (atoi(month) >= 1) &
+ (atoi(day) <= 31) &
+ (atoi(day) >= 1) &
+ (atoi(year) <= 9999) &
+ (atoi(year) > 1))
+ ok = 1;
+ }
+ return ok;
+}
+
+/*
+ * Print the date on stdout.
+ */
+void arg_print_date(long date)
+{
+ char date_str[30];
+ time_t t;
+ struct tm *lt;
+
+ t = date;
+ lt = localtime(&t);
+ sprintf(date_str,"%02u/%02u/%04u",lt->tm_mon+1,
+ lt->tm_mday, 1900+lt->tm_year);
+ fputs(date_str,stdout);
+ fputs(":\n",stdout);
+}
+
+/*
+ * Print Calcurse usage and exit.
+ */
+void usage()
+{
+ char *arg_usage =
+ _("Usage: calcurse [-h | -v] [-at] [-d date|num] [-c file]\n");
+
+ fputs(arg_usage, stdout);
+}
+
+void usage_try()
+{
+ char *arg_usage_try =
+ _("Try 'calcurse -h' for more information.\n");
+
+ fputs(arg_usage_try, stdout);
+}
diff --git a/src/args.h b/src/args.h
new file mode 100755
index 0000000..995cc20
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,41 @@
+/* $calcurse: args.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_ARGS_H
+#define CALCURSE_ARGS_H
+
+void usage();
+void usage_try();
+int parse_args(int argc, char **argv, int colr);
+void version_arg();
+void help_arg();
+void todo_arg(int colr);
+int app_arg(int add_line, int year, int month, int day, long date);
+void date_arg(char *ddate, int add_line);
+int check_date(char *date);
+void arg_print_date(long date);
+
+#endif /* CALCURSE_ARGS_H */
diff --git a/src/calcurse.1 b/src/calcurse.1
new file mode 100755
index 0000000..5ae929c
--- /dev/null
+++ b/src/calcurse.1
@@ -0,0 +1,158 @@
+.\" $calcurse: calcurse.1,v 1.1 2006/07/31 21:00:03 culot Exp $
+.\"
+.\" Copyright (c) 2004-2006 Frederic Culot
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place - Suite 330,
+.\" Boston, MA 02111-1307, USA.
+.\"
+.TH CALCURSE 1 "May 07, 2006" "Version 1.4" "Calcurse Manual"
+.SH NAME
+Calcurse \- text-based organizer
+.PP
+.SH SYNOPSIS
+.B "calcurse "
+[
+.B "-h "
+|
+.B "-v "
+] [
+.B "-at "
+] [
+.B "-d "
+\fIdate\fP|\fInum\fP ] [
+.B "-c "
+\fIfile\fP ]
+.PP
+.SH DESCRIPTION
+Calcurse is a text-based personal organizer which helps keeping track of
+events and everyday tasks. It contains a calendar, a 'todo' list, and
+puts your appointments in order. The user interface is configurable,
+and one can choose between different color schemes and layouts.
+All of the commands are documented within an online help system.
+.PP
+.SH OPTIONS
+The following options are supported:
+.TP
+.B \-a
+Print the appointments and events for the current day and exit.
+.br
+\fINote:\fP the calendar from which to read the appointments can be specified using
+the '\-c' flag.
+.TP
+.B \-c
+Specify the calendar file to use. The default calendar is
+.B "'~/.calcurse/apts'"
+(see section \fIFILES\fP below).
+.TP
+.B \-d
+Print the appointments and events for the given date or for
+the given number of upcoming days, depending on the argument format.
+Two possible formats are supported:
+.RS 9
+.TP 2
+\(bu a date of the form 'mm/dd/yyyy'.
+.TP 2
+\(bu a number 'n'.
+.RE
+.RS 7
+.LP
+In the first case, the appointments and events list for the specified
+date will be returned, while in the second case the appointments and events
+list for the 'n' upcoming days will be returned.
+.br
+As an example, typing 'calcurse -d 3' will display your appointments
+and events for today, tomorrow, and the day after tomorrow.
+.br
+\fINote:\fP as for the '-a' flag, the calendar from which to read the
+appointments can be specified using the '\-c' flag.
+.RE
+.TP
+.B \-h
+Print a short help text describing the supported command-line options,
+and then exit.
+.TP
+.B \-t
+Print the 'todo' list and exit.
+.TP
+.B \-v
+Display calcurse version and exit.
+.SH NOTES
+Calcurse interface contains three different panels (calendar,
+appointment list, and todo list) on which you can perform different
+actions. All the possible actions, together with their associated
+keystrokes, are listed on the status bar. This status bar
+takes place at the bottom of the screen.
+.PP
+At any time, the built-in help system can be invoked by pressing the '?'
+key. Once viewing the help screens, informations on a specific command
+can be accessed by pressing the keystroke corresponding to that command.
+.PP
+.SH CONFIGURATION
+The calcurse options can be changed from the configuration menu (shown
+when 'C' is hit). Three possible categories are to be chosen from : the
+color scheme, the layout (the location of the three panels on the
+screen), and more general options (such as automatic save before
+quitting). All of these options are detailed in the configuration menu.
+.PP
+.SH FILES
+The following structure is created in your $HOME directory the first
+time calcurse is run :
+.PP
+.HP 10
+$HOME/.calcurse/
+.br
+|___conf
+.br
+|___apts
+.br
+|___todo
+.PP
+The \fIconf\fP file contains the user configuration. The \fIapts\fP
+file contains all of the user's appointments, and the \fItodo\fP
+file contains the todo list.
+.PP
+.SH LICENCE
+Copyright (c) 2004-2006 by Frederic Culot.
+.br
+This software is released under the GNU General Public License. Please
+read the COPYING file for more information.
+.PP
+.SH BUGS
+Incorrect highlighting of items appear when using calcurse black and
+white theme together with a \fB$TERM\fP variable set to
+\fIxterm-color\fP.
+To fix this bug, and as advised by Thomas E. Dickey (xterm maintainer),
+\fIxterm-xfree86\fP should be used instead of \fIxterm-color\fP to set
+the \fB$TERM\fP variable:
+ "The xterm-color value for $TERM is a bad choice for XFree86
+ xterm because it is commonly used for a terminfo entry which
+ happens to not support bce. Use the xterm-xfree86 entry
+ which is distributed with XFree86 xterm (or the similar one
+ distributed with ncurses)."
+.PP
+If you find other bugs, please send a report to calcurse@culot.org or to the
+author, below.
+.PP
+.SH AUTHOR
+\fBFrederic Culot\fP <frederic@culot.org>.
+.PP
+.SH SEE ALSO
+ncurses(3), gettext(3)
+.br
+Calcurse home page : http://culot.org/calcurse/
+.br
+Calcurse manual found in the doc/ directory of the source package, or
+at:
+http://culot.org/calcurse/manual.html
diff --git a/src/calcurse.c b/src/calcurse.c
new file mode 100755
index 0000000..7432daf
--- /dev/null
+++ b/src/calcurse.c
@@ -0,0 +1,1156 @@
+/* $calcurse: calcurse.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <ncurses.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include <locale.h>
+
+#include "i18n.h"
+#include "io.h"
+#include "help.h"
+#include "calendar.h"
+#include "custom.h"
+#include "utils.h"
+#include "vars.h"
+#include "day.h"
+#include "apoint.h"
+#include "event.h"
+#include "todo.h"
+#include "args.h"
+
+
+/* Variables for calendar */
+struct tm *ptrtime;
+time_t timer;
+char current_day[3];
+char current_month[3];
+char current_year[5];
+char current_time[15];
+char cal_date[30];
+int year, month, day;
+int sel_year, sel_month, sel_day;
+
+/* Variables for appointments */
+int number_apoints_inday;
+int number_events_inday;
+int first_app_onscreen = 0;
+int hilt_app = 0, sav_hilt_app;
+
+/* Variables for todo list */
+int nb_tod = 0, hilt_tod = 0, sav_hilt_tod;
+int first_todo_onscreen = 1;
+char *saved_t_mesg;
+
+/* Variables for user configuration */
+int colr = 1, layout = 1;
+int no_data_file = 1;
+int really_quit = 0;
+bool confirm_quit;
+bool confirm_delete;
+bool auto_save;
+bool skip_system_dialogs;
+bool skip_progress_bar;
+bool week_begins_on_monday;
+
+/*
+ * Variables to handle calcurse windows
+ */
+int x_cal, y_cal, x_app, y_app, x_tod, y_tod, x_bar, y_bar;
+int nl_cal, nc_cal, nl_app, nc_app, nl_tod, nc_tod, nl_bar, nc_bar;
+int which_pan = 0;
+enum window_number {CALENDAR, APPOINTMENT, TODO};
+
+/* External functions */
+void get_date(void);
+void init_vars(int colr);
+void init_wins(void), reinit_wins(void);
+void add_item(void);
+void add_todo(void);
+void load_conf(void);
+bool fill_config_var(char *string);
+void update_todo_panel(void);
+void update_app_panel(int yeat, int month, int day);
+void store_day(int year, int month, int day, bool day_changed);
+void get_screen_config(void);
+void update_windows(int surrounded_window);
+void general_config(void);
+void print_general_options(WINDOW *win);
+void print_option_incolor(WINDOW *win, bool option, int pos_x, int pos_y);
+void del_apoint(void);
+
+/*
+ * Calcurse is a text-based personal organizer which helps keeping track
+ * of events and everyday tasks. It contains a calendar, a 'todo' list,
+ * and puts your appointments in order. The user interface is configurable,
+ * and one can choose between different color schemes and layouts.
+ * All of the commands are documented within an online help system.
+ */
+int main(int argc, char **argv)
+{
+ int ch;
+ int non_interactive;
+ bool do_storage = false;
+ bool day_changed = false;
+ char *no_color_support =
+ _("Sorry, colors are not supported by your terminal\n"
+ "(Press [ENTER] to continue)");
+ char *quit_message = _("Do you really want to quit ?");
+ char choices[] = "[y/n] ";
+
+#if ENABLE_NLS
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif /* ENABLE_NLS */
+
+ /*
+ * Begin by parsing and handling command line arguments.
+ * The data path is also initialized here.
+ */
+ non_interactive = parse_args(argc, argv, colr);
+ if (non_interactive) return EXIT_SUCCESS;
+
+ /* Begin of interactive mode with ncurses interface. */
+ initscr(); /* start the curses mode */
+ cbreak(); /* control chars generate a signal */
+ noecho(); /* controls echoing of typed chars */
+ curs_set(0); /* make cursor invisible */
+ get_date();
+ get_screen_config();
+
+ /* Check if terminal supports color. */
+ if (has_colors()) {
+ colorize = true;
+ start_color();
+
+ /* Color assignment */
+ init_pair(1, COLOR_RED, COLOR_BLACK);
+ init_pair(2, COLOR_GREEN, COLOR_BLACK);
+ init_pair(3, COLOR_BLUE, COLOR_BLACK);
+ init_pair(4, COLOR_CYAN, COLOR_BLACK);
+ init_pair(5, COLOR_YELLOW, COLOR_BLACK);
+ init_pair(6, COLOR_BLACK, COLOR_GREEN);
+ init_pair(7, COLOR_BLACK, COLOR_YELLOW);
+ init_pair(8, COLOR_RED, COLOR_BLUE);
+ init_pair(9, COLOR_WHITE, COLOR_BLACK);
+ } else {
+ colorize = false;
+ use_default_colors();
+ }
+
+ init_vars(colr);
+ init_wins();
+ update_windows(which_pan);
+
+ /*
+ * Read the data from files : first the user
+ * configuration (the display is then updated), and then
+ * the todo list, appointments and events.
+ */
+ no_data_file = check_data_files();
+ load_conf();
+ custom_init_attr(colr);
+ nb_tod = load_todo(colr);
+ load_app();
+ get_screen_config();
+ reinit_wins();
+ startup_screen(skip_system_dialogs, no_data_file, colr);
+ store_day(year, month, day, day_changed);
+ update_windows(CALENDAR);
+
+ /* User input */
+ for (;;) {
+
+ /* Check terminal size. */
+ getmaxyx(stdscr, row, col);
+ if ((col < 80) | (row < 24)) {
+ endwin();
+ fputs(_("Please resize your terminal screen\n"
+ "(to at least 80x24),\n"
+ "and restart calcurse.\n"), stderr);
+ return EXIT_FAILURE;
+ }
+
+ /* Get user input. */
+ ch = wgetch(swin);
+ switch (ch) {
+
+ case 9: /* The TAB key was hit. */
+ /* Save previously highlighted event. */
+ if (which_pan == TODO) {
+ sav_hilt_tod = hilt_tod;
+ hilt_tod = 0;
+ }
+ if (which_pan == APPOINTMENT) {
+ sav_hilt_app = hilt_app;
+ hilt_app = 0;
+ }
+ /* Switch to the selected panel. */
+ if (which_pan == TODO) which_pan = CALENDAR;
+ else ++which_pan;
+
+ /* Select the event to highlight. */
+ if (which_pan == APPOINTMENT) {
+ if ((sav_hilt_app == 0)
+ & ( (number_events_inday +
+ number_apoints_inday) != 0))
+ hilt_app = 1;
+ else
+ hilt_app = sav_hilt_app;
+ } else if (which_pan == TODO) {
+ if ((sav_hilt_tod == 0) & (nb_tod != 0))
+ hilt_tod = 1;
+ else
+ hilt_tod = sav_hilt_tod;
+ }
+ break;
+
+ case 'R':
+ case 'r':
+ reinit_wins();
+ break;
+
+ case 'G':
+ case 'g': /* Goto function */
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ get_date();
+ goto_day(colr, day, month, year,
+ &sel_day, &sel_month, &sel_year);
+ do_storage = true;
+ day_changed = true;
+ break;
+
+ case 'V':
+ case 'v': /* View function */
+ if ((which_pan == APPOINTMENT) & (hilt_app != 0))
+ day_popup_item();
+ else if ((which_pan == TODO) & (hilt_tod != 0))
+ item_in_popup(NULL, NULL, saved_t_mesg,
+ _("To do :"));
+ break;
+
+ case 'C':
+ case 'c': /* Configuration menu */
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ config_bar();
+ while ((ch = wgetch(swin)) != 'q') {
+ switch (ch) {
+ case 'C':
+ case 'c':
+ if (has_colors()) {
+ colorize = true;
+ colr = color_config(colr);
+ custom_init_attr(colr);
+ } else {
+ colorize = false;
+ erase_window_part(swin, 0, 0,
+ nc_bar,
+ nl_bar);
+ mvwprintw(swin, 0, 0,
+ _(no_color_support));
+ wgetch(swin);
+ }
+ break;
+ case 'L':
+ case 'l':
+ layout = layout_config(layout, colr);
+ break;
+ case 'G':
+ case 'g':
+ general_config();
+ break;
+ }
+ reinit_wins();
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ config_bar();
+ }
+ update_windows(which_pan);
+ break;
+
+ case 'A':
+ case 'a': /* Add an item */
+ if (which_pan == APPOINTMENT) {
+ add_item();
+ do_storage = true;
+ }
+ if (which_pan == TODO) add_todo();
+ break;
+
+ case 'D':
+ case 'd': /* Delete an item */
+ del_apoint();
+ do_storage = true;
+ break;
+
+ case '?': /* Online help system */
+ status_bar(which_pan, colr, nc_bar, nl_bar);
+ help_screen(which_pan, colr);
+ break;
+
+ case 'S':
+ case 's': /* Save function */
+ save_cal(auto_save, confirm_quit,
+ confirm_delete, skip_system_dialogs,
+ skip_progress_bar, week_begins_on_monday,
+ colr, layout);
+ break;
+
+ case (261): /* right arrow */
+ case ('L'):
+ case ('l'):
+ if (which_pan == CALENDAR) {
+ do_storage = true;
+ day_changed = true;
+ if ((sel_day == 31) & (sel_month == 12))
+ { /* goto next year */
+ sel_day = 0;
+ sel_month = 1;
+ sel_year++;
+ }
+ if (sel_day == days[sel_month - 1])
+ { /* goto next month */
+ sel_month = sel_month + 1;
+ sel_day = 1;
+ } else
+ sel_day = sel_day + 1;
+ }
+ break;
+
+ case (260): /* left arrow */
+ case ('H'):
+ case ('h'):
+ if (which_pan == CALENDAR) {
+ do_storage = true;
+ day_changed = true;
+ if ((sel_day == 1) & (sel_month == 1))
+ { /* goto previous year */
+ sel_day = 32;
+ sel_month = 12;
+ sel_year--;
+ }
+ if (sel_day == 1)
+ { /* goto previous month */
+ sel_day = days[sel_month - 2];
+ sel_month = sel_month - 1;
+ } else
+ sel_day = sel_day - 1;
+ }
+ break;
+
+ case (259): /* up arrow */
+ case ('K'):
+ case ('k'):
+ if (which_pan == CALENDAR) {
+ do_storage = true;
+ day_changed = true;
+ if ((sel_day <= 7) & (sel_month == 1))
+ { /* goto previous year */
+ sel_day = 31 - (7 - sel_day);
+ sel_month = 12;
+ sel_year--;
+ break;
+ }
+ if (sel_day <= 7)
+ { /* goto previous month */
+ sel_day = days[sel_month - 2] -
+ (7 - sel_day);
+ sel_month = sel_month - 1;
+ } else /* previous week */
+ sel_day = sel_day - 7;
+ } else {
+ if ((which_pan == APPOINTMENT) & (hilt_app > 1)) {
+ hilt_app--;
+ scroll_pad_up(hilt_app,
+ number_events_inday);
+ }
+ if ((which_pan == TODO) & (hilt_tod > 1)) {
+ hilt_tod--;
+ if (hilt_tod < first_todo_onscreen)
+ first_todo_onscreen--;
+ }
+ }
+ break;
+
+ case (258): /* down arrow */
+ case ('J'):
+ case ('j'):
+ if (which_pan == CALENDAR) {
+ do_storage = true;
+ day_changed = true;
+ if ((sel_day > days[sel_month - 1] - 7) &
+ (sel_month == 12))
+ { /* next year */
+ sel_day = (7 - (31 - sel_day));
+ sel_month = 1;
+ sel_year++;
+ break;
+ }
+ if (sel_day > days[sel_month - 1] - 7)
+ { /* next month */
+ sel_day = (7 - (days[sel_month - 1] -
+ sel_day));
+ sel_month = sel_month + 1;
+ } else /* next week */
+ sel_day = sel_day + 7;
+ } else {
+ if ((which_pan == APPOINTMENT) & (hilt_app < number_events_inday + number_apoints_inday))
+ {
+ hilt_app++;
+ scroll_pad_down(hilt_app,
+ number_events_inday,
+ nl_app);
+ }
+ if ((which_pan == TODO) & (hilt_tod < nb_tod)) {
+ ++hilt_tod;
+ if (hilt_tod - first_todo_onscreen ==
+ nl_tod - 4)
+ ++first_todo_onscreen;
+ }
+ }
+ break;
+
+ case ('Q'): /* Quit calcurse :-( */
+ case ('q'):
+ if (auto_save)
+ save_cal(auto_save,confirm_quit,
+ confirm_delete, skip_system_dialogs,
+ skip_progress_bar,
+ week_begins_on_monday,
+ colr, layout);
+ if (confirm_quit) {
+ status_mesg(_(quit_message), choices);
+ ch = wgetch(swin);
+ if ( ch == 'y' ) {
+ endwin();
+ erase();
+ return EXIT_SUCCESS;
+ } else {
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ break;
+ }
+ } else {
+ endwin();
+ erase();
+ return EXIT_SUCCESS;
+ }
+ break;
+
+ } /* end case statement */
+ if (do_storage) {
+ store_day(sel_year, sel_month, sel_day, day_changed);
+ do_storage = !do_storage;
+ if (day_changed) {
+ sav_hilt_app = 0;
+ day_changed = !day_changed;
+ }
+ }
+ update_windows(which_pan);
+ }
+} /* end of interactive mode */
+
+/*
+ * EXTERNAL FUNCTIONS
+ */
+
+/*
+ * Variables init
+ */
+void init_vars(int colr)
+{
+ // Variables for user configuration
+ confirm_quit = true;
+ confirm_delete = true;
+ auto_save = true;
+ skip_system_dialogs = false;
+ skip_progress_bar = false;
+ week_begins_on_monday = true;
+
+ // Pad structure for scrolling text inside the appointment panel
+ apad = (struct pad_s *) malloc(sizeof(struct pad_s));
+ apad->width = nc_app - 3;
+ apad->length = 1;
+ apad->first_onscreen = 0;
+ apad->ptrwin = newpad(apad->length, apad->width);
+
+ // Attribute definitions for color and non-color terminals
+ custom_init_attr(colr);
+}
+
+/*
+ * Update all of the three windows and put a border around the
+ * selected window.
+ */
+void update_windows(int surrounded_window)
+{
+ if (surrounded_window == CALENDAR) {
+ border_color(cwin, colr);
+ border_nocolor(awin);
+ border_nocolor(twin);
+ } else if (surrounded_window == APPOINTMENT) {
+ border_color(awin, colr);
+ border_nocolor(cwin);
+ border_nocolor(twin);
+ } else if (surrounded_window == TODO) {
+ border_color(twin, colr);
+ border_nocolor(awin);
+ border_nocolor(cwin);
+ } else {
+ /* NOTREACHED */
+ fputs(_("FATAL ERROR in update_windows: no window selected\n"),stderr);
+ exit(EXIT_FAILURE);
+ }
+ update_app_panel(sel_year, sel_month, sel_day);
+ update_todo_panel();
+ update_cal_panel(cwin, nl_cal, nc_cal, sel_month,
+ sel_year, sel_day, day, month, year,
+ week_begins_on_monday);
+ status_bar(surrounded_window, colr, nc_bar, nl_bar);
+ wmove(swin, 0, 0);
+ doupdate();
+}
+
+/*
+ * Get the screen size and recalculate the windows configurations.
+ */
+void get_screen_config(void)
+{
+ /* Get the screen configuration */
+ getmaxyx(stdscr, row, col);
+
+ /* window size definition */
+ nl_cal = 12;
+ nc_cal = 30;
+ nc_app = col - nc_cal;
+ nl_app = row - 2;
+ nc_tod = nc_cal;
+ nl_tod = row - (nl_cal + 2);
+ nl_app = row - 2;
+ nl_bar = 2; y_bar = row - 2;
+ nc_bar = col; x_bar = 0;
+
+ /* defining the layout */
+ switch (layout) {
+ case 1:
+ y_app = 0; x_app = 0; y_cal = 0;
+ x_tod = nc_app; y_tod = nl_cal; x_cal = nc_app;
+ break;
+ case 2:
+ y_app = 0; x_app = 0; y_tod = 0;
+ x_tod = nc_app; x_cal = nc_app; y_cal = nl_tod;
+ break;
+ case 3:
+ y_app = 0; x_tod = 0; x_cal = 0; y_cal = 0;
+ x_app = nc_cal; y_tod = nl_cal;
+ break;
+ case 4:
+ y_app = 0; x_tod = 0; y_tod = 0; x_cal = 0;
+ x_app = nc_cal; y_cal = nl_tod;
+ break;
+ }
+}
+
+
+
+/* Get current date */
+void get_date(void)
+{
+ timer = time(NULL);
+ ptrtime = localtime(&timer);
+ strftime(current_time, 15, "%H:%M%p", ptrtime);
+ strftime(cal_date, 30, "%a %B %Y", ptrtime);
+ strftime(current_day, 3, "%d", ptrtime);
+ strftime(current_month, 3, "%m", ptrtime);
+ strftime(current_year, 5, "%Y", ptrtime);
+ month = atoi(current_month);
+ day = atoi(current_day);
+ year = atoi(current_year);
+ sel_year = year;
+ sel_month = month;
+ sel_day = day;
+}
+
+/* Create all the windows */
+void init_wins(void)
+{
+ char label[80];
+
+ /* Create the three main windows plus the status bar. */
+ cwin = newwin(nl_cal, nc_cal, y_cal, x_cal);
+ sprintf(label, _("Calendar"));
+ win_show(cwin, label);
+ awin = newwin(nl_app, nc_app, y_app, x_app);
+ sprintf(label, _("Appointments"));
+ win_show(awin, label);
+ twin = newwin(nl_tod, nc_tod, y_tod, x_tod);
+ sprintf(label, _("ToDo"));
+ win_show(twin, label);
+ swin = newwin(nl_bar, nc_bar, y_bar, x_bar);
+
+ /* Enable function keys (i.e. arrow keys) in those windows */
+ keypad(swin, TRUE);
+ keypad(twin, TRUE);
+ keypad(awin, TRUE);
+ keypad(cwin, TRUE);
+}
+
+/*
+ * Delete the existing windows and recreate them with their new
+ * size and placement.
+ */
+void reinit_wins(void)
+{
+ clear();
+ delwin(swin);
+ delwin(cwin);
+ delwin(awin);
+ delwin(twin);
+ get_screen_config();
+ init_wins();
+ update_windows(which_pan);
+}
+
+/* General configuration */
+void general_config(void)
+{
+ WINDOW *conf_win;
+ char label[80];
+ char *number_str = _("Enter an option number to change its value [Q to quit] ");
+ int ch;
+
+ clear();
+ conf_win = newwin(row - 2, col, 0, 0);
+ box(conf_win, 0, 0);
+ sprintf(label, _("CalCurse %s | general options"), VERSION);
+ win_show(conf_win, label);
+ status_mesg(number_str, "");
+ print_general_options(conf_win);
+ while ((ch = wgetch(swin)) != 'q') {
+ switch (ch) {
+ case '1':
+ auto_save = !auto_save;
+ break;
+ case '2':
+ confirm_quit = !confirm_quit;
+ break;
+ case '3':
+ confirm_delete = !confirm_delete;
+ break;
+ case '4':
+ skip_system_dialogs =
+ !skip_system_dialogs;
+ break;
+ case '5':
+ skip_progress_bar =
+ !skip_progress_bar;
+ break;
+ case '6':
+ week_begins_on_monday =
+ !week_begins_on_monday;
+ break;
+ }
+ print_general_options(conf_win);
+ }
+ delwin(conf_win);
+}
+
+/* prints the general options */
+void print_general_options(WINDOW *win)
+{
+ int x_pos, y_pos;
+ char *option1 = _("auto_save = ");
+ char *option2 = _("confirm_quit = ");
+ char *option3 = _("confirm_delete = ");
+ char *option4 = _("skip_system_dialogs = ");
+ char *option5 = _("skip_progress_bar = ");
+ char *option6 = _("week_begins_on_monday = ");
+
+ x_pos = 3;
+ y_pos = 4;
+
+ mvwprintw(win, y_pos, x_pos, "[1] %s ", option1);
+ print_option_incolor(win, auto_save, y_pos,
+ x_pos + 4 + strlen(option1));
+ mvwprintw(win, y_pos + 1, x_pos,
+ _("(if set to YES, automatic save is done when quitting)"));
+
+ mvwprintw(win, y_pos + 3, x_pos, "[2] %s ", option2);
+ print_option_incolor(win, confirm_quit, y_pos + 3,
+ x_pos + 4 + strlen(option2));
+ mvwprintw(win, y_pos + 4, x_pos,
+ _("(if set to YES, confirmation is required before quitting)"));
+
+ mvwprintw(win, y_pos + 6, x_pos, "[3] %s ", option3);
+ print_option_incolor(win, confirm_delete, y_pos + 6,
+ x_pos + 4 + strlen(option3));
+ mvwprintw(win, y_pos + 7, x_pos,
+ _("(if set to YES, confirmation is required before deleting an event)"));
+
+ mvwprintw(win, y_pos + 9, x_pos, "[4] %s ", option4);
+ print_option_incolor(win, skip_system_dialogs, y_pos + 9,
+ x_pos + 4 + strlen(option4));
+ mvwprintw(win, y_pos + 10, x_pos,
+ _("(if set to YES, messages about loaded and saved data will not be displayed)"));
+
+ mvwprintw(win, y_pos + 12, x_pos, "[5] %s ", option5);
+ print_option_incolor(win, skip_progress_bar , y_pos + 12,
+ x_pos + 4 + strlen(option5));
+ mvwprintw(win, y_pos + 13, x_pos,
+ _("(if set to YES, progress bar will not be displayed when saving data)"));
+
+ mvwprintw(win, y_pos + 15, x_pos, "[6] %s ", option6);
+ print_option_incolor(win, week_begins_on_monday , y_pos + 15,
+ x_pos + 4 + strlen(option6));
+ mvwprintw(win, y_pos + 16, x_pos,
+ _("(if set to YES, monday is the first day of the week, else it is sunday)"));
+
+ wmove(swin, 1, 0);
+ wnoutrefresh(win);
+ doupdate();
+}
+
+/* print the option value with appropriate color */
+void print_option_incolor(WINDOW *win, bool option, int pos_y, int pos_x)
+{
+ int color;
+ char *option_value;
+
+ if (option == true) {
+ color = ATTR_TRUE;
+ option_value = _("yes");
+ } else if (option == false) {
+ color = ATTR_FALSE;
+ option_value = _("no");
+ } else {
+ erase_window_part(win, 0, 0, col, row - 2);
+ mvwprintw(win, 1, 1,
+ _("option not defined - Problem in print_option_incolor()"));
+ wnoutrefresh(win);
+ doupdate();
+ wgetch(win);
+ exit(EXIT_FAILURE);
+ }
+ custom_apply_attr(win, color);
+ mvwprintw(win, pos_y, pos_x, "%s", option_value);
+ custom_remove_attr(win, color);
+ wnoutrefresh(win);
+ doupdate();
+}
+
+ /* Delete an event from the ToDo or Appointment lists */
+void del_apoint(void)
+{
+ char *choices = "[y/n] ";
+ char *del_app_str = _("Do you really want to delete this item ?");
+ char *del_todo_str = _("Do you really want to delete this task ?");
+ long date;
+ int nb_items = number_apoints_inday + number_events_inday;
+ bool go_for_deletion = false;
+ bool go_for_todo_del = false;
+ int to_be_removed = 0;
+ int answer = 0;
+
+ /* delete an appointment */
+ if (which_pan == APPOINTMENT && hilt_app != 0) {
+ date = date2sec(sel_year, sel_month, sel_day, 0, 0);
+
+ if (confirm_delete) {
+ status_mesg(del_app_str, choices);
+ answer = wgetch(swin);
+ if ( (answer == 'y') && (nb_items != 0) )
+ go_for_deletion = true;
+ else {
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ return;
+ }
+ } else
+ if (nb_items != 0)
+ go_for_deletion = true;
+
+ if (go_for_deletion) {
+ if (nb_items != 0) {
+ if (hilt_app <= number_events_inday) {
+ event_delete_bynum(date, hilt_app - 1);
+ number_events_inday--;
+ to_be_removed = 1;
+ } else {
+ apoint_delete_bynum(date,
+ hilt_app -
+ number_events_inday - 1);
+ number_apoints_inday--;
+ to_be_removed = 3;
+ }
+ if (hilt_app > 1) --hilt_app;
+ if (apad->first_onscreen >= to_be_removed)
+ apad->first_onscreen =
+ apad->first_onscreen -
+ to_be_removed;
+ }
+ }
+
+ /* delete a todo */
+ } else if (which_pan == TODO && hilt_tod != 0) {
+ if (confirm_delete) {
+ status_mesg(del_todo_str, choices);
+ answer = wgetch(swin);
+ if ( (answer == 'y') && (nb_tod > 0) ) {
+ go_for_todo_del = true;
+ } else {
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ return;
+ }
+ } else
+ if (nb_tod > 0)
+ go_for_todo_del = true;
+
+ if (go_for_todo_del) {
+ todo_delete_bynum(hilt_tod - 1);
+ nb_tod--;
+ if (hilt_tod > 1) hilt_tod--;
+ }
+ }
+}
+
+ /* Add an item in the ToDo list */
+void add_todo(void)
+{
+ char *mesg = _("Enter the new ToDo item : ");
+ char todo_input[500];
+
+ status_mesg(mesg, "");
+ getstring(swin, colr, todo_input, 0, 1);
+ if (strlen(todo_input) != 0) {
+ todo_insert(todo_input);
+ ++nb_tod;
+ update_todo_panel();
+ }
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ status_bar(which_pan, colr, nc_bar, nl_bar);
+ doupdate();
+}
+
+/*
+ * Add an item in either the appointment or the event list,
+ * depending if the start time is entered or not.
+ */
+void add_item(void)
+{
+ char *mesg_1 = _("Enter start time ([hh:mm] or [h:mm]), leave blank for an all-day event : ");
+ char *mesg_2 = _("Enter end time ([hh:mm] or [h:mm]) or duration (in minutes) : ");
+ char *mesg_3 = _("Enter description :");
+ char *format_message_1 = _("You entered an invalid start time, should be [h:mm] or [hh:mm]");
+ char *format_message_2 = _("You entered an invalid end time, should be [h:mm] or [hh:mm] or [mm]");
+ char *enter_str = _("Press [Enter] to continue");
+ int Id;
+ char item_time[500];
+ char item_mesg[500];
+ long apoint_duration;
+ struct apoint_s *apoint_pointeur;
+ struct event_s *event_pointeur;
+ unsigned heures, minutes;
+ unsigned end_h, end_m;
+ int is_appointment = 1;
+
+ /* Get the starting time */
+ strcpy(item_time, " ");
+ while (check_time(item_time) == 0) {
+ status_mesg(mesg_1, "");
+ getstring(swin, colr, item_time, 0, 1);
+ if (strlen(item_time) == 0){
+ is_appointment = 0;
+ break;
+ } else if (check_time(item_time) != 1) {
+ status_mesg(format_message_1, enter_str);
+ wgetch(swin);
+ } else
+ sscanf(item_time, "%u:%u", &heures, &minutes);
+ }
+ /*
+ * Check if an event or appointment is entered,
+ * depending on the starting time, and record the
+ * corresponding item.
+ */
+ if (is_appointment){ /* Get the appointment duration */
+ strcpy(item_time, " ");
+ while (check_time(item_time) == 0) {
+ status_mesg(mesg_2, "");
+ getstring(swin, colr, item_time, 0, 1);
+ if (strlen(item_time) == 0)
+ return; //nothing entered, cancel adding of event
+ else if (check_time(item_time) == 0) {
+ status_mesg(format_message_2, enter_str);
+ wgetch(swin);
+ } else {
+ if (check_time(item_time) == 2)
+ apoint_duration = atoi(item_time);
+ else if (check_time(item_time) == 1) {
+ sscanf(item_time, "%u:%u",
+ &end_h, &end_m);
+ if (end_h < heures){
+ apoint_duration =
+ (60 - minutes + end_m) +
+ (24 + end_h - (heures + 1))*60;
+ } else {
+ apoint_duration =
+ (60 - minutes + end_m) +
+ (end_h - (heures + 1))*60;
+ }
+ }
+ }
+ }
+ } else { /* Insert the event Id */
+ Id = 1;
+ }
+ // get the item description
+ status_mesg(mesg_3, "");
+ getstring(swin, colr, item_mesg, 0, 1);
+ if (strlen(item_mesg) != 0) {
+ if (is_appointment){
+ // insert the appointment in list
+ apoint_pointeur =
+ apoint_new(item_mesg,
+ date2sec(sel_year, sel_month, sel_day,
+ heures, minutes),
+ min2sec(apoint_duration));
+ // insert the event in list
+ } else {
+ event_pointeur = event_new(item_mesg, date2sec(
+ sel_year,
+ sel_month,
+ sel_day,
+ 12, 0),
+ Id);
+ }
+ update_app_panel(sel_year, sel_month, sel_day);
+ }
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ status_bar(which_pan, colr, nc_bar, nl_bar);
+ doupdate();
+}
+
+/* Updates the ToDo panel */
+void update_todo_panel(void)
+{
+ struct todo_s *i;
+ int len = nc_tod - 5;
+ int num_todo = 0;
+ int y_offset = 3, x_offset = 1;
+ int t_realpos = -1;
+ int title_lines = 3;
+ int todo_lines = 1;
+ int max_items = nl_tod - 4;
+ int incolor = -1;
+
+ /* Print todo item in the panel. */
+ erase_window_part(twin, 1, title_lines, nc_tod - 2, nl_tod - 2);
+ for (i = todolist; i != 0; i = i->next) {
+ num_todo++;
+ t_realpos = num_todo - first_todo_onscreen;
+ incolor = num_todo - hilt_tod;
+ if (incolor == 0) saved_t_mesg = i->mesg;
+ if (t_realpos >= 0 && t_realpos < max_items) {
+ display_item(twin, incolor, i->mesg,
+ len, y_offset, x_offset);
+ y_offset = y_offset + todo_lines;
+ }
+ }
+
+ /* Draw the scrollbar if necessary. */
+ if (nb_tod > max_items){
+ float ratio = ((float) max_items) / ((float) nb_tod);
+ int sbar_length = (int) (ratio * (max_items + 1));
+ int highend = (int) (ratio * first_todo_onscreen);
+ bool hilt_bar = (which_pan == TODO) ? true : false;
+ int sbar_top = highend + title_lines;
+
+ if ((sbar_top + sbar_length) > nl_tod - 1)
+ sbar_length = nl_tod - 1 - sbar_top;
+ draw_scrollbar(twin, sbar_top, nc_tod - 2,
+ sbar_length, title_lines, nl_tod - 1, hilt_bar);
+ }
+
+ wnoutrefresh(twin);
+}
+
+/* Updates the Appointment panel */
+void update_app_panel(int year, int month, int day)
+{
+ int title_xpos;
+ int bordr = 1;
+ int title_lines = 3;
+ int app_width = nc_app - bordr;
+ int app_length = nl_app - bordr - title_lines;
+ long date;
+
+ /* variable inits */
+ title_xpos = nc_app - (strlen(_(monthnames[sel_month - 1])) + 11);
+ if (sel_day < 10) title_xpos++;
+ date = date2sec(year, month, day, 0, 0);
+ day_write_pad(date, app_width, app_length, hilt_app, colr);
+
+ /* Print current date in the top right window corner. */
+ erase_window_part(awin, 1, title_lines, nc_app - 2, nl_app - 2);
+ custom_apply_attr(awin, ATTR_HIGHEST);
+ mvwprintw(awin, title_lines, title_xpos, "%s %d, %d",
+ _(monthnames[sel_month - 1]), sel_day, sel_year);
+ custom_remove_attr(awin, ATTR_HIGHEST);
+
+ /* Draw the scrollbar if necessary. */
+ if ((apad->length >= app_length)||(apad->first_onscreen > 0)) {
+ float ratio = ((float) app_length) / ((float) apad->length);
+ int sbar_length = (int) (ratio * app_length);
+ int highend = (int) (ratio * apad->first_onscreen);
+ bool hilt_bar = (which_pan == APPOINTMENT) ? true : false;
+ int sbar_top = highend + title_lines + 1;
+
+ if ((sbar_top + sbar_length) > nl_app - 1)
+ sbar_length = nl_app - 1 - sbar_top;
+ draw_scrollbar(awin, sbar_top, nc_app - 2, sbar_length,
+ title_lines + 1, nl_app - 1, hilt_bar);
+ }
+
+ wnoutrefresh(awin);
+ pnoutrefresh(apad->ptrwin, apad->first_onscreen, 0,
+ y_app + title_lines + 1, x_app + bordr,
+ y_app + nl_app - 2*bordr, x_app + nc_app - 2*bordr);
+}
+
+/*
+ * Store the events and appointments for the selected day, and write
+ * those items in a pad.
+ * This is useful to speed up the appointment panel update.
+ */
+void store_day(int year, int month, int day, bool day_changed)
+{
+ long date;
+ date = date2sec(year, month, day, 0, 0);
+
+ /* Inits */
+ if (apad->length != 0)
+ delwin(apad->ptrwin);
+
+ /* Store the events and appointments (recursive and normal items). */
+ apad->length = day_store_items(date,
+ &number_events_inday, &number_apoints_inday);
+
+ /* Create the new pad with its new length. */
+ if (day_changed) apad->first_onscreen = 0;
+ apad->ptrwin = newpad(apad->length, apad->width);
+}
+
+/* Load the user configuration */
+void load_conf(void)
+{
+ FILE *data_file;
+ char *mesg_line1 = _("Failed to open config file");
+ char *mesg_line2 = _("Press [ENTER] to continue");
+ char buf[100], e_conf[100];
+ int var;
+
+ data_file = fopen(path_conf, "r");
+ if (data_file == NULL) {
+ status_mesg(mesg_line1, mesg_line2);
+ wnoutrefresh(swin);
+ doupdate();
+ wgetch(swin);
+ }
+ var = 0;
+ for (;;) {
+ if (fgets(buf, 99, data_file) == NULL) {
+ break;
+ }
+ extract_data(e_conf, buf, strlen(buf));
+ if (var == 1) {
+ auto_save =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 2) {
+ confirm_quit =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 3) {
+ confirm_delete =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 4) {
+ skip_system_dialogs =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 5) {
+ skip_progress_bar =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 6) {
+ week_begins_on_monday =
+ fill_config_var(e_conf);
+ var = 0;
+ } else if (var == 7) {
+ colr = atoi(e_conf);
+ if (colr == 0) colorize = false;
+ var = 0;
+ } else if (var == 8) {
+ layout = atoi(e_conf);
+ var = 0;
+ }
+ if (strncmp(e_conf, "auto_save=", 10) == 0)
+ var = 1;
+ else if (strncmp(e_conf, "confirm_quit=", 13) == 0)
+ var = 2;
+ else if (strncmp(e_conf, "confirm_delete=", 15) == 0)
+ var = 3;
+ else if (strncmp(e_conf, "skip_system_dialogs=", 20) == 0)
+ var = 4;
+ else if (strncmp(e_conf, "skip_progress_bar=", 18) == 0)
+ var = 5;
+ else if (strncmp(e_conf, "week_begins_on_monday=", 23) == 0)
+ var = 6;
+ else if (strncmp(e_conf, "color-theme=", 12) == 0)
+ var = 7;
+ else if (strncmp(e_conf, "layout=", 7) == 0)
+ var = 8;
+ }
+ fclose(data_file);
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+}
+
+bool fill_config_var (char *string) {
+ if (strncmp(string, "yes", 3) == 0)
+ return true;
+ else if (strncmp(string, "no", 2) == 0)
+ return false;
+ else {
+ fputs(_("FATAL ERROR in fill_config_var: "
+ "wrong configuration variable format.\n"), stderr);
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/calendar.c b/src/calendar.c
new file mode 100755
index 0000000..c147e47
--- /dev/null
+++ b/src/calendar.c
@@ -0,0 +1,227 @@
+/* $calcurse: calendar.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "day.h"
+#include "apoint.h"
+#include "event.h"
+#include "calendar.h"
+#include "custom.h"
+#include "vars.h"
+#include "utils.h"
+
+static unsigned months_to_days(unsigned);
+static long years_to_days(unsigned);
+
+ /* Load the calendar */
+void
+update_cal_panel(WINDOW *cwin, int nl_cal,
+ int nc_cal, int sel_month, int sel_year, int sel_day,
+ int day, int month, int year,
+ bool monday_first)
+{
+ int c_day, c_day_1, day_1_sav, numdays, j;
+ unsigned yr, mo;
+ int ofs_x, ofs_y;
+ int item_this_day = 0;
+ int title_lines = 3;
+ int sunday_first = 0;
+
+ // Inits
+ erase_window_part(cwin, 1, title_lines, nc_cal - 2, nl_cal - 2);
+ mo = sel_month;
+ yr = sel_year;
+ if (!monday_first) sunday_first = 1;
+
+ // Offset for centering calendar in window
+ ofs_y = 2 + (nl_cal - 9) / 2;
+ ofs_x = (nc_cal - 27) / 2;
+
+
+ //checking the number of days in february
+ numdays = days[mo - 1];
+ if (2 == mo && isBissextile(yr))
+ ++numdays;
+
+ //the first calendar day will be monday or sunday, depending on the
+ //value of week_begins_on_monday
+ c_day_1 = (int) ((ymd_to_scalar(yr, mo, 1 + sunday_first)
+ - (long) 1) % 7L);
+
+ //Write the current month and year on top of the calendar
+ custom_apply_attr(cwin, ATTR_HIGH);
+ mvwprintw(cwin, ofs_y,
+ (nc_cal - (strlen(_(monthnames[mo - 1])) + 5)) / 2,
+ "%s %d", _(monthnames[mo - 1]), sel_year);
+ custom_remove_attr(cwin, ATTR_HIGH);
+ ++ofs_y;
+
+ //prints the days, with regards to the first day of the week
+ custom_apply_attr(cwin, ATTR_HIGH);
+ for (j = 0; j < 7; j++) {
+ mvwprintw(cwin, ofs_y, ofs_x + 4 * j, "%s",
+ _(daynames[1 + j - sunday_first]));
+ }
+ custom_remove_attr(cwin, ATTR_HIGH);
+
+ day_1_sav = (c_day_1 + 1) * 3 + c_day_1 - 7;
+
+ for (c_day = 1; c_day <= numdays; ++c_day, ++c_day_1, c_day_1 %= 7) {
+ //check if the day contains an event or an appointment
+ item_this_day = day_check_if_item(sel_year, sel_month, c_day);
+
+ /* Go to next line, the week is over. */
+ if (!c_day_1 && 1 != c_day) {
+ ++ofs_y;
+ ofs_x = 2 - day_1_sav - 4 * c_day - 1;
+ }
+ /* This is today, so print it in yellow. */
+ if (c_day == day && month == sel_month
+ && year == sel_year && day != sel_day)
+ {
+ custom_apply_attr(cwin, ATTR_LOWEST);
+ mvwprintw(cwin, ofs_y + 1,
+ ofs_x + day_1_sav + 4 * c_day + 1, "%2d",
+ c_day);
+ custom_remove_attr(cwin, ATTR_LOWEST);
+ } else if (c_day == sel_day && ( (day != sel_day) |
+ (month != sel_month) | (year != sel_year) ))
+ /* This is the selected day, print it in red. */
+ {
+ custom_apply_attr(cwin, ATTR_MIDDLE);
+ mvwprintw(cwin, ofs_y + 1,
+ ofs_x + day_1_sav + 4 * c_day + 1, "%2d",
+ c_day);
+ custom_remove_attr(cwin, ATTR_MIDDLE);
+ } else if (c_day == sel_day && day == sel_day && month == sel_month && year == sel_year) //today is the selected day
+ {
+ custom_apply_attr(cwin, ATTR_MIDDLE);
+ mvwprintw(cwin, ofs_y + 1,
+ ofs_x + day_1_sav + 4 * c_day + 1, "%2d",
+ c_day);
+ custom_remove_attr(cwin, ATTR_MIDDLE);
+ } else if (item_this_day) {
+ custom_apply_attr(cwin, ATTR_LOW);
+ mvwprintw(cwin, ofs_y + 1,
+ ofs_x + day_1_sav + 4 * c_day + 1, "%2d",
+ c_day);
+ custom_remove_attr(cwin, ATTR_LOW);
+ }
+
+ else // otherwise, print normal days in black
+ mvwprintw(cwin, ofs_y + 1,
+ ofs_x + day_1_sav + 4 * c_day + 1, "%2d",
+ c_day);
+
+ }
+ wnoutrefresh(cwin);
+}
+
+int isBissextile(unsigned annee)
+{
+ return annee % 400 == 0 || (annee % 4 == 0 && annee % 100 != 0);
+}
+
+// convertion functions
+unsigned months_to_days(unsigned mois)
+{
+ return (mois * 3057 - 3007) / 100;
+}
+
+
+long years_to_days(unsigned annee)
+{
+ return annee * 365L + annee / 4 - annee / 100 + annee / 400;
+}
+
+long ymd_to_scalar(unsigned annee, unsigned mois, unsigned jour)
+{
+ long scalaire;
+ scalaire = jour + months_to_days(mois);
+ if (mois > 2)
+ scalaire -= isBissextile(annee) ? 1 : 2;
+ annee--;
+ scalaire += years_to_days(annee);
+ return scalaire;
+}
+
+/*
+ * Ask for a date to jump to, then check the correctness of that date
+ * and jump to it.
+ * If the entered date is empty, automatically jump to the current date.
+ * day, month, year are the current day given to that routine, and
+ * sel_day, sel_month and sel_year represent the day given back.
+ */
+void
+goto_day(int colr, int day, int month, int year,
+ int *sel_day, int *sel_month, int *sel_year)
+{
+ char selected_day[50] = "";
+ int dday, dmonth, dyear;
+ int wrong_day = 0;
+ char *mesg_line1 = _("The day you entered is not valid");
+ char *mesg_line2 = _("Press [ENTER] to continue");
+ char *request_date = _("Enter the day to go to [ENTER for today] : dd/mm/yyyy");
+
+ while (wrong_day != 1) {
+ status_mesg(request_date, "");
+ getstring(swin, colr, selected_day, 0, 1);
+ if (strlen(selected_day) == 0) // go to today
+ {
+ *sel_day = day;
+ *sel_month = month;
+ *sel_year = year;
+ break;
+ } else {
+ sscanf(selected_day, "%u/%u/%u", &dday, &dmonth,
+ &dyear);
+ //check if the entered day is correct
+ if ((dday <= 0) | (dday >= 32))
+ wrong_day = 1;
+ if ((dmonth <= 0) | (dmonth >= 13))
+ wrong_day = 1;
+ if ((dyear <= 0) | (dyear >= 3000))
+ wrong_day = 1;
+ //go to chosen day
+ if (wrong_day != 1) {
+ *sel_day = dday;
+ *sel_month = dmonth;
+ *sel_year = dyear;
+ } else {
+ status_mesg(mesg_line1, mesg_line2);
+ wgetch(swin);
+ }
+ break;
+ }
+ }
+ return;
+}
diff --git a/src/calendar.h b/src/calendar.h
new file mode 100755
index 0000000..a8cb3ea
--- /dev/null
+++ b/src/calendar.h
@@ -0,0 +1,41 @@
+/* $calcurse: calendar.h,v 1.1 2006/07/31 21:00:02 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_CALENDAR_H
+#define CALCURSE_CALENDAR_H
+
+#include <stdbool.h>
+
+void update_cal_panel(WINDOW *cwin, int nl_cal,
+ int nc_cal, int sel_month, int sel_year, int sel_day,
+ int day, int month, int year,
+ bool monday_first);
+int isBissextile(unsigned);
+long ymd_to_scalar(unsigned, unsigned, unsigned);
+void goto_day(int colr, int day, int month, int year,
+ int *sel_day, int *sel_month, int *sel_year);
+
+#endif /* CALCURSE_CALENDAR_H */
diff --git a/src/custom.c b/src/custom.c
new file mode 100755
index 0000000..4a2ea72
--- /dev/null
+++ b/src/custom.c
@@ -0,0 +1,178 @@
+/* $calcurse: custom.c,v 1.1 2006/07/31 21:00:02 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "custom.h"
+#include "vars.h"
+
+static struct attribute_s attr;
+
+/*
+ * Define window attributes (for both color and non-color terminals):
+ * ATTR_HIGHEST are for window titles
+ * ATTR_HIGH are for month and days names
+ * ATTR_MIDDLE are for the selected day inside calendar panel
+ * ATTR_LOW are for days inside calendar panel which contains an event
+ * ATTR_LOWEST are for current day inside calendar panel
+ */
+void custom_init_attr(int colr)
+{
+ attr.color[ATTR_HIGHEST] = COLOR_PAIR(colr);
+ attr.color[ATTR_HIGH] = COLOR_PAIR(6);
+ attr.color[ATTR_MIDDLE] = COLOR_PAIR(1);
+ attr.color[ATTR_LOW] = COLOR_PAIR(4);
+ attr.color[ATTR_LOWEST] = COLOR_PAIR(5);
+ attr.color[ATTR_TRUE] = COLOR_PAIR(2);
+ attr.color[ATTR_FALSE] = COLOR_PAIR(1);
+
+ attr.nocolor[ATTR_HIGHEST] = A_BOLD;
+ attr.nocolor[ATTR_HIGH] = A_REVERSE;
+ attr.nocolor[ATTR_MIDDLE] = A_REVERSE;
+ attr.nocolor[ATTR_LOW] = A_UNDERLINE;
+ attr.nocolor[ATTR_LOWEST] = A_BOLD;
+ attr.nocolor[ATTR_TRUE] = A_BOLD;
+ attr.nocolor[ATTR_FALSE] = A_DIM;
+}
+
+/* Apply window attribute */
+void custom_apply_attr(WINDOW *win, int attr_num)
+{
+ if (colorize)
+ wattron(win, attr.color[attr_num]);
+ else
+ wattron(win, attr.nocolor[attr_num]);
+}
+
+/* Remove window attribute */
+void custom_remove_attr(WINDOW *win, int attr_num)
+{
+ if (colorize)
+ wattroff(win, attr.color[attr_num]);
+ else
+ wattroff(win, attr.nocolor[attr_num]);
+}
+
+/* Draws the configuration bar */
+void config_bar()
+{
+ int smlspc, spc;
+
+ smlspc = 2;
+ spc = 15;
+
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ mvwprintw(swin, 0, 2, "Q");
+ mvwprintw(swin, 1, 2, "G");
+ mvwprintw(swin, 0, 2 + spc, "L");
+ mvwprintw(swin, 1, 2 + spc, "C");
+ custom_remove_attr(swin, ATTR_HIGHEST);
+
+ mvwprintw(swin, 0, 2 + smlspc, _("Exit"));
+ mvwprintw(swin, 1, 2 + smlspc, _("General"));
+ mvwprintw(swin, 0, 2 + spc + smlspc, _("Layout"));
+ mvwprintw(swin, 1, 2 + spc + smlspc, _("Color"));
+
+ wnoutrefresh(swin);
+ wmove(swin, 0, 0);
+ doupdate();
+}
+
+/* Choose the layout */
+int layout_config(int layout, int colr)
+{
+ int ch, old_layout;
+ char *layout_mesg = _("Pick the desired layout on next screen [press ENTER]");
+ char *choice_mesg = _("('A'= Appointment panel, 'c'= calendar panel, 't'= todo panel)");
+ char *layout_up_mesg = _(" |Ac| |At| |cA| |tA|");
+ char *layout_down_mesg = _("[1]|At| [2]|Ac| [3]|tA| [4]|cA|");
+
+ old_layout = layout;
+ status_mesg(layout_mesg, choice_mesg);
+ wgetch(swin);
+ status_mesg(layout_up_mesg, layout_down_mesg);
+ wnoutrefresh(swin);
+ doupdate();
+ while ((ch = wgetch(swin)) != 'q') {
+ switch (ch) {
+ case '1':
+ layout = 1;
+ return layout;
+ case '2':
+ layout = 2;
+ return layout;
+ case '3':
+ layout = 3;
+ return layout;
+ case '4':
+ layout = 4;
+ return layout;
+ }
+ }
+ layout = old_layout;
+ return layout;
+}
+
+/* Choose the color theme */
+int color_config(int colr)
+{
+ int ascii2dec = 48;
+ int i, ch, old_colr;
+ int max_colors = 9;
+ int spc = 6;
+ char *choose_color = _("Pick the number corresponding to the color scheme "
+ "(Q to exit) :");
+
+ old_colr = colr;
+ erase_window_part(swin, 0, 0, col, 2);
+ for (i = 1; i < max_colors; i++) {
+ wattron(swin, COLOR_PAIR(i));
+ mvwprintw(swin, 1, (i - 1) * spc, "[>%d<]", i);
+ wattroff(swin, COLOR_PAIR(i));
+ }
+ mvwprintw(swin, 1, 50, _("([>0<] for black & white)"));
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ mvwprintw(swin, 0, 0, choose_color);
+ custom_remove_attr(swin, ATTR_HIGHEST);
+ wnoutrefresh(swin);
+ doupdate();
+ while ((ch = wgetch(swin)) != 'q') {
+ ch = ch - ascii2dec;
+ if ( (ch > 0) && (ch <= max_colors) ) {
+ colorize = true;
+ return ch;
+ } else if (ch == 0) {
+ colorize = false;
+ return 0;
+ } else {
+ colr = old_colr;
+ }
+ }
+ if (colr == 0) colorize = false;
+ return colr;
+}
diff --git a/src/custom.h b/src/custom.h
new file mode 100755
index 0000000..a7f133b
--- /dev/null
+++ b/src/custom.h
@@ -0,0 +1,42 @@
+/* $calcurse: custom.h,v 1.1 2006/07/31 21:00:02 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_CUSTOM_H
+#define CALCURSE_CUSTOM_H
+
+struct attribute_s {
+ int color[7];
+ int nocolor[7];
+};
+
+void custom_init_attr(int colr);
+void custom_apply_attr(WINDOW *win, int attr_num);
+void custom_remove_attr(WINDOW *win, int attr_num);
+void config_bar();
+int layout_config(int layout, int colr);
+int color_config(int colr);
+
+#endif /* CALCURSE_CUSTOM_H */
diff --git a/src/day.c b/src/day.c
new file mode 100755
index 0000000..8fd7981
--- /dev/null
+++ b/src/day.c
@@ -0,0 +1,362 @@
+/* $calcurse: day.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "apoint.h"
+#include "event.h"
+#include "recur.h"
+#include "day.h"
+#include "vars.h"
+
+static struct day_item_s *day_items_ptr;
+static struct day_saved_item_s *day_saved_item = NULL;
+
+/*
+ * Store all of the items to be displayed for the selected day.
+ * Items are of four types: recursive events, normal events,
+ * recursive appointments and normal appointments.
+ * The items are stored in the linked list pointed by *day_items_ptr
+ * and the length of the new pad to write is returned.
+ * The number of events and appointments in the current day are also updated.
+ */
+int day_store_items(long date, int *pnb_events, int *pnb_apoints)
+{
+ int pad_length;
+ int nb_events, nb_recur_events;
+ int nb_apoints, nb_recur_apoints;
+
+ pad_length = nb_events = nb_apoints = 0;
+ nb_recur_events = nb_recur_apoints = 0;
+
+ if (day_items_ptr != 0)
+ day_free_list();
+ nb_recur_events = day_store_recur_events(date);
+ nb_events = day_store_events(date);
+ *pnb_events = nb_events;
+ nb_recur_apoints = day_store_recur_apoints(date);
+ nb_apoints = day_store_apoints(date);
+ *pnb_apoints = nb_apoints;
+ pad_length = nb_recur_events + nb_events + 1 +
+ 3*(nb_recur_apoints + nb_apoints);
+ *pnb_apoints += nb_recur_apoints;
+ *pnb_events += nb_recur_events;
+
+ return pad_length;
+}
+
+/* Free the current day linked list containing the events and appointments. */
+void day_free_list(void)
+{
+ struct day_item_s *p, *q;
+
+ for (p = day_items_ptr; p != 0; p = q) {
+ q = p->next;
+ free(p->mesg);
+ free(p);
+ }
+ day_items_ptr = NULL;
+}
+
+/*
+ * Store the recurrent events for the selected day in structure pointed
+ * by day_items_ptr. This is done by copying the recurrent events
+ * from the general structure pointed by recur_elist to the structure
+ * dedicated to the selected day.
+ * Returns the number of recurrent events for the selected day.
+ */
+int day_store_recur_events(long date)
+{
+ struct recur_event_s *j;
+ struct day_item_s *ptr;
+ int e_nb = 0;
+
+ for (j = recur_elist; j != 0; j = j->next) {
+ if (recur_item_inday(j->day, j->rpt->type, j->rpt->freq,
+ j->rpt->until, date)) {
+ e_nb++;
+ ptr = day_add_event(RECUR_EVNT, j->mesg, j->day, j->id);
+ }
+ }
+
+ return e_nb;
+}
+
+/*
+ * Store the events for the selected day in structure pointed
+ * by day_items_ptr. This is done by copying the events
+ * from the general structure pointed by eventlist to the structure
+ * dedicated to the selected day.
+ * Returns the number of events for the selected day.
+ */
+int day_store_events(long date)
+{
+ struct event_s *j;
+ struct day_item_s *ptr;
+ int e_nb = 0;
+
+ for (j = eventlist; j != 0; j = j->next) {
+ if (event_inday(j, date)) {
+ e_nb++;
+ ptr = day_add_event(EVNT, j->mesg, j->day, j->id);
+ }
+ }
+
+ return e_nb;
+}
+
+/*
+ * Store the recurrent apoints for the selected day in structure pointed
+ * by day_items_ptr. This is done by copying the appointments
+ * from the general structure pointed by recur_alist to the structure
+ * dedicated to the selected day.
+ * Returns the number of recurrent appointments for the selected day.
+ */
+int day_store_recur_apoints(long date)
+{
+ struct recur_apoint_s *j;
+ struct day_item_s *ptr;
+ int a_nb = 0;
+
+ for (j = recur_alist; j != 0; j = j->next) {
+ if (recur_item_inday(j->start, j->rpt->type, j->rpt->freq,
+ j->rpt->until, date)) {
+ a_nb++;
+ ptr = day_add_apoint(RECUR_APPT, j->mesg, j->start, j->dur);
+ }
+ }
+
+ return a_nb;
+}
+
+/*
+ * Store the apoints for the selected day in structure pointed
+ * by day_items_ptr. This is done by copying the appointments
+ * from the general structure pointed by apointlist to the structure
+ * dedicated to the selected day.
+ * Returns the number of appointments for the selected day.
+ */
+int day_store_apoints(long date)
+{
+ struct apoint_s *j;
+ struct day_item_s *ptr;
+ int a_nb = 0;
+
+ for (j = apointlist; j != 0; j = j->next) {
+ if (apoint_inday(j, date)) {
+ a_nb++;
+ ptr = day_add_apoint(APPT, j->mesg, j->start, j->dur);
+ }
+ }
+
+ return a_nb;
+}
+
+/* Add an event in the current day list */
+struct day_item_s *day_add_event(int type, char *mesg, long day, int id)
+{
+ struct day_item_s *o, **i;
+ o = (struct day_item_s *) malloc(sizeof(struct day_item_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->type = type;
+ o->appt_dur = 0;
+ o->start = day;
+ o->evnt_id = id;
+ i = &day_items_ptr;
+ for (;;) {
+ if (*i == 0 || (*i)->start > day) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+/* Add an appointment in the current day list. */
+struct day_item_s *day_add_apoint(int type, char *mesg, long start, long dur)
+{
+ struct day_item_s *o, **i;
+ o = (struct day_item_s *) malloc(sizeof(struct day_item_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->start = start;
+ o->appt_dur = dur;
+ o->type = type;
+ o->evnt_id = 0;
+ i = &day_items_ptr;
+ for (;;) {
+ if (*i == 0 || (*i)->start > start) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+/*
+ * Write the appointments and events for the selected day in a pad.
+ * An horizontal line is drawn between events and appointments, and the
+ * item selected by user is highlighted. This item is also saved inside
+ * structure (pointed by day_saved_item), to be later displayed in a
+ * popup window if requested.
+ */
+void day_write_pad(long date, int width, int length, int incolor, int colr)
+{
+ struct day_item_s *p;
+ int line, item_number, max_pos;
+ const int x_pos = 0;
+ bool draw_line = true;
+
+ line = item_number = 0;
+ max_pos = length;
+
+ /* Initialize the structure used to store highlited item. */
+ if (day_saved_item == NULL) {
+ day_saved_item = (struct day_saved_item_s *)
+ malloc(sizeof(struct day_saved_item_s));
+ day_saved_item->mesg = (char *) malloc(1);
+ }
+
+ for (p = day_items_ptr; p != 0; p = p->next) {
+
+ /* First print the events for current day. */
+ if (p->type < RECUR_APPT) {
+ item_number++;
+ if (item_number - incolor == 0) {
+ day_saved_item->type = p->type;
+ day_saved_item->mesg = (char *)
+ realloc(day_saved_item->mesg,
+ strlen(p->mesg) + 1);
+ day_saved_item->mesg = p->mesg;
+ }
+ display_item(apad->ptrwin, item_number - incolor, p->mesg,
+ width - 4, line, x_pos);
+ line++;
+ } else {
+ /* Draw a line between events and appointments. */
+ if (line > 0 && draw_line){
+ wmove(apad->ptrwin, line, x_pos);
+ whline(apad->ptrwin, 0, width);
+ draw_line = false;
+ }
+
+ /* Last print the appointments for current day. */
+ item_number++;
+ if (item_number - incolor == 0) {
+ day_saved_item->type = p->type;
+ day_saved_item->mesg = (char *)
+ realloc(day_saved_item->mesg,
+ strlen(p->mesg) + 1);
+ day_saved_item->mesg = p->mesg;
+ apoint_sec2str(day_item_s2apoint_s(p),
+ p->type, date,
+ day_saved_item->start,
+ day_saved_item->end);
+ }
+ display_item_date(apad->ptrwin, item_number - incolor,
+ day_item_s2apoint_s(p), p->type, date,
+ line + 1, x_pos);
+ display_item(apad->ptrwin, item_number - incolor, p->mesg,
+ width - 6, line + 2, x_pos + 2);
+ line = line + 3;
+ }
+ }
+}
+
+/* Returns a structure of type apoint_s given a structure of type day_item_s */
+struct apoint_s *day_item_s2apoint_s(struct day_item_s *p)
+{
+ struct apoint_s *a;
+
+ a = (struct apoint_s *) malloc(sizeof(struct apoint_s));
+ a->mesg = (char *) malloc(strlen(p->mesg) + 1);
+ a->start = p->start;
+ a->dur = p->appt_dur;
+ a->mesg = p->mesg;
+ return a;
+}
+
+/* Display an item inside a popup window. */
+void day_popup_item(void)
+{
+ char *error =
+ _("FATAL ERROR in day_popup_item: unknown item type\n");
+
+ if (day_saved_item->type == EVNT || day_saved_item->type == RECUR_EVNT)
+ item_in_popup(NULL, NULL, day_saved_item->mesg, _("Event :"));
+ else if (day_saved_item->type == APPT ||
+ day_saved_item->type == RECUR_APPT)
+ item_in_popup(day_saved_item->start, day_saved_item->end,
+ day_saved_item->mesg, _("Appointment :"));
+ else { /* NOT REACHED */
+ fputs(error, stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+/*
+ * Need to know if there is an item for the current selected day inside
+ * calendar. This is used to put the correct colors inside calendar panel.
+ */
+ int day_check_if_item(int year, int month, int day) {
+ struct recur_event_s *re;
+ struct recur_apoint_s *ra;
+ struct event_s *e;
+ struct apoint_s *a;
+ const long date = date2sec(year, month, day, 0, 0);
+
+ for (re = recur_elist; re != 0; re = re->next)
+ if (recur_item_inday(re->day, re->rpt->type, re->rpt->freq,
+ re->rpt->until, date))
+ return 1;
+
+ for (ra = recur_alist; ra != 0; ra = ra->next)
+ if (recur_item_inday(ra->start, ra->rpt->type, ra->rpt->freq,
+ ra->rpt->until, date))
+ return 1;
+
+ for (e = eventlist; e != 0; e = e->next)
+ if (event_inday(e, date))
+ return 1;
+
+ for (a = apointlist; a != 0; a = a->next)
+ if (apoint_inday(a, date))
+ return 1;
+
+ return 0;
+}
diff --git a/src/day.h b/src/day.h
new file mode 100755
index 0000000..8426704
--- /dev/null
+++ b/src/day.h
@@ -0,0 +1,66 @@
+/* $calcurse: day.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_DAY_H
+#define CALCURSE_DAY_H
+
+#include "apoint.h"
+
+#define RECUR_EVNT 1
+#define EVNT 2
+#define RECUR_APPT 3
+#define APPT 4
+
+struct day_item_s {
+ struct day_item_s *next;
+ int type; /* (recursive or normal) event or appointment */
+ long start; /* seconds since 1 jan 1970 */
+ char *mesg; /* item description */
+ int evnt_id; /* event identifier */
+ long appt_dur; /* appointment duration in seconds */
+};
+
+struct day_saved_item_s {
+ int type ;
+ char *mesg;
+ char start[100];
+ char end[100];
+};
+
+int day_store_items(long date, int *pnb_events, int *pnb_apoints);
+void day_free_list(void);
+int day_store_recur_events(long date);
+int day_store_events(long date);
+int day_store_recur_apoints(long date);
+int day_store_apoints(long date);
+struct day_item_s *day_add_event(int type, char *mesg, long day, int id);
+struct day_item_s *day_add_apoint(int type, char *mesg, long start, long dur);
+void day_write_pad(long date, int width, int length, int incolor, int colr);
+struct apoint_s *day_item_s2apoint_s(struct day_item_s *p);
+void day_popup_item(void);
+int day_check_if_item(int year, int month, int day);
+
+#endif /* CALCURSE_DAY_H */
diff --git a/src/event.c b/src/event.c
new file mode 100755
index 0000000..4cf3953
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,135 @@
+/* $calcurse: event.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "event.h"
+#include "utils.h"
+
+struct event_s *eventlist;
+
+/* Create a new event */
+struct event_s *event_new(char *mesg, long day, int id)
+{
+ struct event_s *o, **i;
+ o = (struct event_s *) malloc(sizeof(struct event_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->day = day;
+ o->id = id;
+ i = &eventlist;
+ for (;;) {
+ if (*i == 0 || (*i)->day > day) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+/* Check if the event belongs to the selected day */
+unsigned event_inday(struct event_s *i, long start)
+{
+ if (i->day <= start + 3600 * 24 && i->day > start) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Write to file the event in user-friendly format */
+void event_write(struct event_s *o, FILE * f)
+{
+ struct tm *lt;
+ time_t t;
+
+ t = o->day;
+ lt = localtime(&t);
+ fprintf(f, "%02u/%02u/%04u [%d] %s\n",
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year, o->id, o->mesg);
+}
+
+/* Load the events from file */
+struct event_s *event_scan(FILE * f, struct tm start, int id)
+{
+ struct tm *lt;
+ char buf[MESG_MAXSIZE], *nl;
+ time_t tstart, t;
+
+ t = time(NULL);
+ lt = localtime(&t);
+
+ /* Read the event description */
+ fgets(buf, MESG_MAXSIZE, f);
+ nl = strchr(buf, '\n');
+ if (nl) {
+ *nl = '\0';
+ }
+ start.tm_hour = 12;
+ start.tm_min = 0;
+ start.tm_sec = 0;
+ start.tm_isdst = -1;
+ start.tm_year -= 1900;
+ start.tm_mon--;
+
+ tstart = mktime(&start);
+ if (tstart == -1) {
+ fputs(_("FATAL ERROR in event_scan: date error in the event\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+ return event_new(buf, tstart, id);
+}
+
+/* Delete an event from the list */
+void event_delete_bynum(long start, unsigned num)
+{
+ unsigned n;
+ struct event_s *i, **iptr;
+
+ n = 0;
+ iptr = &eventlist;
+ for (i = eventlist; i != 0; i = i->next) {
+ if (event_inday(i, start)) {
+ if (n == num) {
+ *iptr = i->next;
+ free(i->mesg);
+ free(i);
+ return;
+ }
+ n++;
+ }
+ iptr = &i->next;
+ }
+ /* NOTREACHED */
+ fputs(_("FATAL ERROR in event_delete_bynum: no such event\n"), stderr);
+ exit(EXIT_FAILURE);
+}
diff --git a/src/event.h b/src/event.h
new file mode 100755
index 0000000..6e06691
--- /dev/null
+++ b/src/event.h
@@ -0,0 +1,48 @@
+/* $calcurse: event.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_EVENT_H
+#define CALCURSE_EVENT_H
+
+#define HRMIN_SIZE 6
+#define MESG_MAXSIZE 256
+
+struct event_s {
+ struct event_s *next;
+ int id; /* event identifier */
+ long day; /* seconds since 1 jan 1970 */
+ char *mesg;
+};
+
+extern struct event_s *eventlist;
+
+struct event_s *event_new(char *, long, int);
+unsigned event_inday(struct event_s *o, long start);
+void event_write(struct event_s *o, FILE * f);
+struct event_s *event_scan(FILE * f, struct tm start, int id);
+void event_delete_bynum(long start, unsigned num);
+
+#endif /* CALCURSE_EVENT_H */
diff --git a/src/help.c b/src/help.c
new file mode 100755
index 0000000..f586e74
--- /dev/null
+++ b/src/help.c
@@ -0,0 +1,375 @@
+/* $calcurse: help.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "i18n.h"
+#include "help.h"
+#include "custom.h"
+#include "vars.h"
+#include "utils.h"
+
+/*
+ * Write the desired help text inside the help pad, and return the number
+ * of lines that were written.
+ * */
+int write_help_pad(WINDOW *win, char *title, char *text, int pad_width)
+{
+ int nl_title = 0;
+ int nl_text = 0;
+
+ nl_text = get_help_lines(text);
+ nl_title = get_help_lines(title);
+ erase_window_part(win, 0, 0, MAX_LENGTH, pad_width);
+ custom_apply_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, 0, 0, "%s", title);
+ custom_remove_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, nl_title, 0, "%s", text);
+ return nl_text + nl_title;
+}
+
+int get_help_lines(char *text)
+{
+ int i;
+ int nl = 0;
+
+ for (i = 0; text[i]; i++) {
+ if (text[i] == '\n') nl++;
+ }
+ return nl + 1;
+}
+
+/* Draws the help screen */
+void help_screen(int which_pan, int colr)
+{
+ WINDOW *help_win = NULL;
+ WINDOW *help_pad = NULL;
+ char label[80];
+ int ch = '?';
+ int help_row = row - 2; //size of the help window
+ int help_col = col;
+ int title_lines = 3;
+ int pad_offset = 4;
+ int text_lines = help_row - (pad_offset + 1);
+ int pad_width = help_col - 2*pad_offset + 1;
+ int first_line = 0, nl = 0;
+
+ help_page_t help_main;
+ help_page_t help_redraw;
+ help_page_t help_save;
+ help_page_t help_displacement;
+ help_page_t help_view;
+ help_page_t help_tab;
+ help_page_t help_goto;
+ help_page_t help_delete;
+ help_page_t help_add;
+ help_page_t help_config;
+ help_page_t help_credits;
+
+ help_main.title =
+ _(" Welcome to Calcurse. This is the main help screen.\n");
+ help_main.text =
+ _(" Moving around: Press CTRL-P or CTRL-N to scroll text upward or\n"
+ " downward inside help screens, if necessary.\n\n"
+ " Exit help: When finished, press 'Q' to exit help and go back\n"
+ " to the main Calcurse screen.\n\n"
+ " Help topic: At the bottom of this screen you can see a panel\n"
+ " with different fields, represented by a letter and\n"
+ " a short title. This panel contains all the available\n"
+ " actions you can perform when using Calcurse.\n"
+ " By pressing one of the letters appearing in this\n"
+ " panel, you will be shown a short description of the\n"
+ " corresponding action.\n\n"
+ " Credits: Press '@' for credits.");
+
+ help_redraw.title = _("Redraw:\n");
+ help_redraw.text =
+ _("Pressing 'R' redraws the Calcurse panels.\n\n"
+ "You might want to use this function when you resize your terminal\n"
+ "screen for example, and you want Calcurse to take into account the new\n"
+ "size of the terminal.\n\n"
+ "This function can also be useful when garbage appears in the display,\n"
+ "and you want to clean it.");
+
+ help_save.title = _("Save:\n");
+ help_save.text =
+ _("Pressing 'S' saves the Calcurse data.\n\n"
+ "The data is splitted into three different files which contains :"
+ "\n\n"
+ " / ~/.calcurse/conf -> the user configuration\n"
+ " | (layout, color, general options)\n"
+ " | ~/.calcurse/apts -> the data related to the appointments\n"
+ " \\ ~/.calcurse/todo -> the data related to the todo list\n"
+ "\nIn the config menu, you can choose to save the Calcurse data\n"
+ "automatically before quitting.");
+
+ help_displacement.title = _("Displacement keys:\n");
+ help_displacement.text =
+ _("You can use either 'H','J','K','L' or the arrow keys '<','v','^','>'\n"
+ "to move into the calendar.\n\n"
+ "The following scheme explains how :\n\n"
+ " move to previous week\n"
+ " K ^ \n"
+ " move to previous day H < > L move to next day\n"
+ " J v \n"
+ " move to next week\n"
+ "\nWhen the Appointment or ToDo panel is selected, the up and down keys\n"
+ "(respectively K or up arrow, and J or down arrow) allows you to select\n"
+ "an item from those lists.");
+
+ help_view.title = _("View:\n");
+ help_view.text =
+ _("Pressing 'V' allows you to view the item you select in either the ToDo\n"
+ "or Appointment panel.\n"
+ "\nThis is usefull when an event description is longer than the available\n"
+ "space to display it. If that is the case, the description will be\n"
+ "shortened and its end replaced by '...'. To be able to read the entire\n"
+ "description, just press 'V' and a popup window will appear, containing\n"
+ "the whole event.\n"
+ "\nPress any key to close the popup window and go back to the main\n"
+ "Calcurse screen.");
+
+ help_tab.title = _("Tab:\n");
+ help_tab.text =
+ _("Pressing 'Tab' allows you to switch between panels.\n"
+ "The panel currently in use has its border colorized.\n"
+ "\nSome actions are possible only if the right panel is selected.\n"
+ "For example, if you want to add a task in the TODO list, you need first\n"
+ "to press the 'Tab' key to get the TODO panel selected. Then you can\n"
+ "press 'A' to add your item.\n"
+ "\nNotice that at the bottom of the screen the list of possible actions\n"
+ "change while pressing 'Tab', so you always know what action can be\n"
+ "performed on the selected panel.");
+
+ help_goto.title = _("Goto:\n");
+ help_goto.text =
+ _("Pressing 'G' allows you to jump to a specific day in the calendar.\n"
+ "\nUsing this command, you do not need to travel to that day using\n"
+ "the displacement keys inside the calendar panel.\n"
+ "If you hit [ENTER] without specifying any date, Calcurse checks the\n"
+ "system current date and you will be taken to that date.");
+
+ help_delete.title = _("Delete:\n");
+ help_delete.text =
+ _("Pressing 'D' deletes an element in the ToDo or Appointment list.\n"
+ "\nDepending on which panel is selected when you press the delete key,\n"
+ "the hilighted item of either the ToDo or Appointment list will be \n"
+ "removed from this list.\n"
+ "\nIf the general option 'confirm_delete' is set to 'YES', then you will\n"
+ "be asked for confirmation before deleting the selected event.\n"
+ "Do not forget to save the calendar data to retrieve the modifications\n"
+ "next time you launch Calcurse.");
+
+ help_add.title = _("Add:\n");
+ help_add.text =
+ _("Pressing 'A' allows you to add an item in either the ToDo or Appointment\n"
+ "list, depending on which panel is selected when you press 'A'.\n"
+ "\nTo enter a new item in the TODO list, you only need to enter the\n"
+ "description of this new item.\n"
+ "\nIf the APPOINTMENT panel is selected while pressing 'A', you will be\n"
+ "able to enter either a new appointment or a new all-day long event.\n"
+ "To enter a new event, press [ENTER] instead of the item start time, and\n"
+ "just fill in the event description.\n"
+ "To enter a new appointment to be added in the APPOINTMENT list, you\n"
+ "will need to enter successively the time at which the appointment\n"
+ "begins, the appointment length (either by specifying the duration in\n"
+ "minutes, or the end time in [hh:mm] or [h:mm] format), and the\n"
+ "description of the event.\n"
+ "\nThe day at which occurs the event or appointment is the day currently\n"
+ "selected in the calendar, so you need to move to the desired day before\n"
+ "pressing 'A'.\n"
+ "\nNotes:\n"
+ " o if an appointment lasts for such a long time that it continues\n"
+ " on the next days, this event will be indicated on all the\n"
+ " corresponding days, and the beginning or ending hour will be\n"
+ " replaced by '..' if the event does not begin or end on the day.\n"
+ " o if you only press [ENTER] at the APPOINTMENT or TODO event\n"
+ " description prompt, without any description, no item will be\n"
+ " added.\n"
+ " o do not forget to save the calendar data to retrieve the new\n"
+ " event next time you launch Calcurse.");
+
+ help_config.title = _("Config:\n");
+ help_config.text =
+ _("Pressing 'C' leads to the configuration submenu, from which you can\n"
+ "select between color, layout, and general options.\n"
+ "\nThe color submenu lets you choose the color theme.\n"
+ "\nThe layout submenu lets you choose the Calcurse screen layout, in other\n"
+ "words where to place the three different panels on the screen.\n"
+ "\nThe general options submenu brings a screen with the different options\n"
+ "which modifies the way Calcurse interacts with the user.\n"
+ "\nDo not forget to save the calendar data to retrieve your configuration\n"
+ "next time you launch Calcurse.");
+
+ help_credits.title = _("Calcurse - text-based organizer");
+ help_credits.text =
+ _("Copyright (c) 2004-2006 Frederic Culot\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\nThis program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n\n"
+ "Send your feedback or comments to : calcurse@culot.org\n"
+ "Calcurse home page : http://culot.org/calcurse");
+
+ /*
+ * Create the help window and panel. The panel is used to make
+ * the scrolling faster.
+ */
+ help_win = newwin(help_row, help_col, 0, 0);
+ help_pad = newpad(MAX_LENGTH, pad_width);
+ box(help_win, 0, 0);
+ sprintf(label, _("CalCurse %s | help"), VERSION);
+ win_show(help_win, label);
+
+ /* Display the main help screen. */
+/* nl = write_help_pad(help_pad, help_main.title, help_main.text, pad_width);
+ status_bar(which_pan, colr, col, 2);
+ wmove(swin, 0, 0);
+ wnoutrefresh(help_win);
+ pnoutrefresh(help_pad, first_line, 0, pad_offset, pad_offset,
+ help_row - 2, help_col - pad_offset);
+ doupdate();
+*/
+
+ /* Display the help screen related to user input. */
+ while ( ch != 'q' ) {
+ erase_window_part(help_win, 1, title_lines,
+ help_col - 2, help_row - 2);
+
+ switch (ch) {
+
+ case CTRL('N') :
+ if (nl > first_line + text_lines) first_line++;
+ break;
+
+ case CTRL('P') :
+ if (first_line > 0) first_line--;
+ break;
+
+ case '?':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_main.title,
+ help_main.text, pad_width);
+ break;
+ case 'r':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_redraw.title,
+ help_redraw.text, pad_width);
+ break;
+ case 's':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_save.title,
+ help_save.text, pad_width);
+ break;
+ case 'h':
+ case 'l':
+ case 'j':
+ case 'k':
+ case 259:
+ case 258:
+ case 260:
+ case 261:
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_displacement.title,
+ help_displacement.text, pad_width);
+ break;
+
+ case 'a':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_add.title,
+ help_add.text, pad_width);
+ break;
+
+ case 'g':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_goto.title,
+ help_goto.text, pad_width);
+ break;
+
+ case 'd':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_delete.title,
+ help_delete.text, pad_width);
+ break;
+
+ case 'c':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_config.title,
+ help_config.text, pad_width);
+ break;
+
+ case 'v':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_view.title,
+ help_view.text, pad_width);
+ break;
+
+ case 9:
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_tab.title,
+ help_tab.text, pad_width);
+ break;
+
+ case '@':
+ first_line = 0;
+ nl = write_help_pad(help_pad, help_credits.title,
+ help_credits.text, pad_width);
+ break;
+ }
+
+ /* Draw the scrollbar if necessary. */
+ if (nl > text_lines){
+ float ratio = ((float) text_lines + 1) / ((float) nl);
+ int sbar_length = (int) (ratio * text_lines);
+ int highend = (int) (ratio * first_line);
+ int sbar_top = highend + title_lines + 1;
+
+ draw_scrollbar(help_win, sbar_top, help_col - 2,
+ sbar_length, title_lines + 1,
+ help_row - 1, true);
+ }
+
+ wmove(swin, 0, 0);
+ wnoutrefresh(help_win);
+ pnoutrefresh(help_pad, first_line, 0,
+ pad_offset, pad_offset,
+ help_row - 2, help_col - pad_offset);
+ doupdate();
+ ch = wgetch(swin);
+ }
+ delwin(help_pad);
+ delwin(help_win);
+}
diff --git a/src/help.h b/src/help.h
new file mode 100755
index 0000000..5aa830f
--- /dev/null
+++ b/src/help.h
@@ -0,0 +1,41 @@
+/* $calcurse: help.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_HELP_H
+#define CALCURSE_HELP_H
+
+#include <ncurses.h>
+
+typedef struct {
+ char *title;
+ char *text;
+} help_page_t;
+
+int write_help_pad(WINDOW *win, char *title, char *text, int pad_width);
+int get_help_lines(char *text);
+void help_screen(int which_pan, int colr);
+
+#endif /* CALCURSE_HELP_H */
diff --git a/src/i18n.h b/src/i18n.h
new file mode 100755
index 0000000..454a084
--- /dev/null
+++ b/src/i18n.h
@@ -0,0 +1,54 @@
+/* $calcurse: i18n.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_I18N_H
+#define CALCURSE_I18N_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if ENABLE_NLS
+ #include <libintl.h>
+ #undef _
+ #define _(String) gettext(String)
+ #ifdef gettext_noop
+ #define N_(String) gettext_noop(String)
+ #else
+ #define N_(String) (String)
+ #endif
+#else /* NLS disabled */
+ #define _(String) (String)
+ #define N_(String) (String)
+ #define textdomain(String) (String)
+ #define gettext(String) (String)
+ #define dgettext(String) (String)
+ #define dcgettext(String) (String)
+ #define bindtextdomain(String) (String)
+ #define bind_textdomain_codeset(Domain,Codeset) (Codeset)
+#endif /* ENABLE_NLS */
+
+#endif /* CALCURSE_I18N_H */
diff --git a/src/io.c b/src/io.c
new file mode 100755
index 0000000..35c5802
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,484 @@
+/* $calcurse: io.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "custom.h"
+#include "todo.h"
+#include "event.h"
+#include "apoint.h"
+#include "recur.h"
+#include "io.h"
+#include "vars.h"
+
+/*
+ * Initialization of data paths. The argument cfile is the variable
+ * which contains the calendar file. If none is given, then the default
+ * one (~/.calcurse/apts) is taken. If the one given does not exist, it
+ * is created.
+ */
+void
+io_init(char *cfile)
+{
+ FILE *data_file;
+ char *home;
+ char apts_file[MAX_LENGTH] = "";
+ int ch;
+
+ home = getenv("HOME");
+ if (home == NULL) {
+ home = ".";
+ }
+ snprintf(path_dir, MAX_LENGTH, "%s/" DIR_NAME, home);
+ snprintf(path_todo, MAX_LENGTH, "%s/" TODO_PATH, home);
+ snprintf(path_conf, MAX_LENGTH, "%s/" CONF_PATH, home);
+ if (cfile == NULL) {
+ snprintf(path_apts, MAX_LENGTH, "%s/" APTS_PATH, home);
+ } else {
+ snprintf(apts_file, MAX_LENGTH, "%s", cfile);
+ strncpy(path_apts, apts_file, MAX_LENGTH);
+ /* 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(EXIT_FAILURE);
+ break;
+
+ case 'Y':
+ case 'y':
+ data_file = fopen(path_apts, "w");
+ if (data_file == NULL) {
+ perror(path_apts);
+ exit(EXIT_FAILURE);
+ } else {
+ printf(_("%s successfully created\n"),path_apts);
+ printf(_("starting interactive mode...\n"));
+ }
+ break;
+
+ default:
+ printf(_("aborting...\n"));
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ fclose(data_file);
+ }
+}
+
+ /* get data from file */
+void extract_data(char *dst_data, const char *org, int len)
+{
+ for (;;) {
+ if (*org == '\n' || *org == '\0')
+ break;
+ *dst_data++ = *org++;
+ }
+ *dst_data = '\0';
+}
+
+/* Save the calendar data */
+void
+save_cal(bool auto_save, bool confirm_quit,
+ bool confirm_delete, bool skip_system_dialogs,
+ bool skip_progress_bar, bool week_begins_on_monday,
+ int colr, int layout)
+{
+ FILE *data_file;
+ struct event_s *k;
+ struct apoint_s *j;
+ struct todo_s *i;
+ char *access_pb = _("Problems accessing data file ...");
+ 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 *save_success = _("The data files were successfully saved");
+ char *enter = _("Press [ENTER] to continue");
+ bool save = true, show_bar = false;
+
+ if (!skip_progress_bar) show_bar = true;
+
+ /* Save the user configuration. */
+
+ if (show_bar) progress_bar(save, 1);
+ data_file = fopen(path_conf, "w");
+ if (data_file == (FILE *) 0)
+ status_mesg(access_pb, "");
+ else {
+ fprintf(data_file, "%s\n", config_txt);
+
+ fprintf(data_file,
+ "# If this option is set to yes, automatic save is done when quitting\n");
+ fprintf(data_file, "auto_save=\n");
+ fprintf(data_file, "%s\n",
+ (auto_save) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# If this option is set to yes, confirmation is required before quitting\n");
+ fprintf(data_file, "confirm_quit=\n");
+ fprintf(data_file, "%s\n",
+ (confirm_quit) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# If this option is set to yes, confirmation is required before deleting an event\n");
+ fprintf(data_file, "confirm_delete=\n");
+ fprintf(data_file, "%s\n",
+ (confirm_delete) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# If this option is set to yes, messages about loaded and saved data will not be displayed\n");
+ fprintf(data_file, "skip_system_dialogs=\n");
+ fprintf(data_file, "%s\n",
+ (skip_system_dialogs) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# If this option is set to yes, progress bar appearing when saving data will not be displayed\n");
+ fprintf(data_file, "skip_progress_bar=\n");
+ fprintf(data_file, "%s\n",
+ (skip_progress_bar) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# If this option is set to yes, monday is the first day of the week, else it is sunday\n");
+ fprintf(data_file, "week_begins_on_monday=\n");
+ fprintf(data_file, "%s\n",
+ (week_begins_on_monday) ? "yes" : "no");
+
+ fprintf(data_file,
+ "\n# This is the color theme used for menus (1 to 8) :\n");
+ fprintf(data_file, "color-theme=\n");
+ fprintf(data_file, "%d\n", colr);
+
+ fprintf(data_file,
+ "\n# This is the layout of the calendar (1 to 4) :\n");
+ fprintf(data_file, "layout=\n");
+ fprintf(data_file, "%d\n", layout);
+ fclose(data_file);
+ }
+
+ /* Save the todo data file. */
+ if (show_bar) progress_bar(save, 2);
+ data_file = fopen(path_todo, "w");
+ if (data_file == (FILE *) 0)
+ status_mesg(access_pb, "");
+ else {
+ for (i = todolist; i != 0; i = i->next)
+ fprintf(data_file, "%s\n", i->mesg);
+ fclose(data_file);
+ }
+
+ /*
+ * Save the apts data file, which contains the
+ * appointments first, and then the events.
+ * Recursive items are written first.
+ */
+ if (show_bar) progress_bar(save, 3);
+ data_file = fopen(path_apts, "w");
+ if (data_file == (FILE *) 0)
+ status_mesg(access_pb, "");
+ else {
+ recur_save_data(data_file);
+ for (j = apointlist; j != 0; j = j->next)
+ apoint_write(j, data_file);
+ for (k = eventlist; k != 0; k = k->next)
+ event_write(k, data_file);
+ fclose(data_file);
+ }
+
+
+ /* Print a message telling data were saved */
+ if (!skip_system_dialogs){
+ status_mesg(save_success, enter);
+ wgetch(swin);
+ }
+}
+
+/*
+ * Check what type of data is written in the appointment file,
+ * 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 load_app()
+{
+ FILE *data_file;
+ int c, is_appointment, is_event, is_recursive;
+ struct tm start, end, until, *lt;
+ time_t t;
+ int id = 0;
+ int freq;
+ char type;
+ char *error =
+ _("FATAL ERROR in load_app: wrong format in the appointment or event\n");
+
+ t = time(NULL);
+ lt = localtime(&t);
+ start = end = until = *lt;
+
+ data_file = fopen(path_apts, "r");
+ for (;;) {
+ 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, "%u / %u / %u ",
+ &start.tm_mon, &start.tm_mday, &start.tm_year) != 3) {
+ fputs(_("FATAL ERROR in load_app: "
+ "syntax error in the item date\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* 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 {
+ fputs(_("FATAL ERROR in load_app: "
+ "no event nor appointment found\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+ 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 { /* NOT REACHED */
+ fputs(error, stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Check if we have a recursive item. */
+ c = getc(data_file);
+
+ if (c == '{') {
+ ungetc(c, data_file);
+ is_recursive = 1;
+ fscanf(data_file, "{ %d%c ", &freq, &type);
+ /* Check if we have an endless recurrent item. */
+ c = getc(data_file);
+ if (c == '}') {
+ ungetc(c, data_file);
+ fscanf(data_file, "} ");
+ until.tm_year = 0;
+ if (is_appointment)
+ c = getc(data_file); // useless '|'
+ } else if (c == '-') {
+ ungetc(c, data_file);
+ fscanf(data_file, " -> %u / %u / %u } ",
+ &until.tm_mon, &until.tm_mday,
+ &until.tm_year);
+ if (is_appointment)
+ c = getc(data_file); // useless '|'
+ } else { /* NOT REACHED */
+ fputs(error, stderr);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if (is_event) // if appointment we have a useless '|'
+ 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) {
+ if (is_recursive) {
+ recur_apoint_scan(data_file, start, end,
+ type, freq, until);
+ } else {
+ apoint_scan(data_file, start, end);
+ }
+ } else if (is_event) {
+ if (is_recursive) {
+ recur_event_scan(data_file, start, id,
+ type, freq, until);
+ } else {
+ event_scan(data_file, start, id);
+ }
+ } else { /* NOT REACHED */
+ fputs(error, stderr);
+ exit(EXIT_FAILURE);
+ }
+ }
+ fclose(data_file);
+}
+
+/* Load the todo data */
+int
+load_todo(int colr)
+{
+ FILE *data_file;
+ char *mesg_line1 = _("Failed to open todo file");
+ char *mesg_line2 = _("Press [ENTER] to continue");
+ int nb_tod = 0;
+ char buf[100], e_todo[100];
+
+ data_file = fopen(path_todo, "r");
+ if (data_file == NULL) {
+ status_mesg(mesg_line1, mesg_line2);
+ wgetch(swin);
+ }
+ for (;;) {
+ if (fgets(buf, 99, data_file) == NULL) {
+ break;
+ }
+ extract_data(e_todo, buf, strlen(buf));
+ todo_add(e_todo);
+ ++nb_tod;
+ }
+ fclose(data_file);
+ return nb_tod;
+}
+
+/* Checks if data files exist. If not, create them */
+int check_data_files()
+{
+ FILE *data_file;
+ int no_data_file;
+
+ no_data_file = 0;
+ /* Create the calcurse repertory if not present. */
+ mkdir(path_dir, 0700);
+
+ data_file = fopen(path_todo, "r");
+ if (data_file == NULL) {
+ no_data_file++;
+ data_file = fopen(path_todo, "w");
+ if (data_file == NULL) {
+ perror(path_todo);
+ return no_data_file;
+ }
+ }
+ fclose(data_file);
+
+ data_file = fopen(path_apts, "r");
+ if (data_file == NULL) {
+ no_data_file++;
+ data_file = fopen(path_apts, "w");
+ if (data_file == NULL) {
+ perror(path_apts);
+ return no_data_file;
+ }
+ }
+ fclose(data_file);
+
+ data_file = fopen(path_conf, "r");
+ if (data_file == NULL) {
+ no_data_file++;
+ data_file = fopen(path_conf, "w");
+ if (data_file == NULL) {
+ perror(path_conf);
+ return no_data_file;
+ }
+ }
+ fclose(data_file);
+ return no_data_file;
+}
+
+/* Draw the startup screen */
+void startup_screen(bool skip_dialogs, int no_data_file, int colr)
+{
+ 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);
+ wgetch(swin);
+ } else if (!skip_dialogs){
+ status_mesg(data_mesg, enter);
+ wgetch(swin);
+ }
+}
+
+/* Draw a progress bar while saving or loading data. */
+void progress_bar(bool save, int progress)
+{
+ int i, nbd = 4;
+ char *mesg_sav = _("Saving...");
+ char *mesg_load = _("Loading...");
+ char *barchar = "|";
+ char *data[4] = {
+ "[ ]",
+ "[ conf ]",
+ "[ todo ]",
+ "[ apts ]"};
+ int ipos = strlen(data[1]) + 2;
+ int epos[4];
+ int sleep_time = 125000;
+
+ /* progress bar length init. */
+ epos[0] = floor(col / nbd);
+ epos[1] = 2*epos[0];
+ epos[2] = 3*epos[0];
+ epos[3] = col - 2;
+
+ /* Display which data is being saved. */
+ if (save)
+ status_mesg(mesg_sav, data[progress]);
+ else
+ status_mesg(mesg_load, data[progress]);
+
+ /* Draw the progress bar. */
+ mvwprintw(swin, 1, ipos, barchar);
+ mvwprintw(swin, 1, epos[nbd - 1], barchar);
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ for (i = ipos + 1; i < epos[progress]; i++)
+ mvwaddch(swin, 1, i, ' ' | A_REVERSE);
+ custom_remove_attr(swin, ATTR_HIGHEST);
+ wmove(swin, 0, 0);
+ wrefresh(swin);
+ usleep(sleep_time);
+}
diff --git a/src/io.h b/src/io.h
new file mode 100755
index 0000000..8cc7788
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,42 @@
+/* $calcurse: io.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_IO_H
+#define CALCURSE_IO_H
+
+void io_init(char *cfile);
+void extract_data(char *dst_data, const char *org, int len);
+void save_cal(bool auto_save, bool confirm_quit,
+ bool confirm_delete, bool skip_system_dialogs,
+ bool skip_progress_bar, bool week_begins_on_monday,
+ int colr, int layout);
+void load_app();
+int load_todo(int colr);
+int check_data_files();
+void startup_screen(bool skip_dialogs, int no_data_file, int colr);
+void progress_bar(bool save, int progress);
+
+#endif /* CALCURSE_IO_H */
diff --git a/src/recur.c b/src/recur.c
new file mode 100755
index 0000000..d0629aa
--- /dev/null
+++ b/src/recur.c
@@ -0,0 +1,355 @@
+/* $calcurse: recur.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "apoint.h"
+#include "event.h"
+#include "recur.h"
+
+struct recur_apoint_s *recur_alist;
+struct recur_event_s *recur_elist;
+
+/* Insert a new recursive appointment in the general linked list */
+struct recur_apoint_s *recur_apoint_new(char *mesg, long start, long dur,
+ int type, int freq, long until)
+{
+ struct recur_apoint_s *o, **i;
+ o = (struct recur_apoint_s *) malloc(sizeof(struct recur_apoint_s));
+ o->rpt = (struct rpt_s *) malloc(sizeof(struct rpt_s));
+ o->exc = (struct days_s *) malloc(sizeof(struct days_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->start = start;
+ o->dur = dur;
+ o->rpt->type = type;
+ o->rpt->freq = freq;
+ o->rpt->until = until;
+ i = &recur_alist;
+ for (;;) {
+ if (*i == 0 || (*i)->start > start) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+/* Insert a new recursive event in the general linked list */
+struct recur_event_s *recur_event_new(char *mesg, long day, int id,
+ int type, int freq, long until)
+{
+ struct recur_event_s *o, **i;
+ o = (struct recur_event_s *) malloc(sizeof(struct recur_event_s));
+ o->rpt = (struct rpt_s *) malloc(sizeof(struct rpt_s));
+ o->exc = (struct days_s *) malloc(sizeof(struct days_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->day = day;
+ o->id = id;
+ o->rpt->type = type;
+ o->rpt->freq = freq;
+ o->rpt->until = until;
+ i = &recur_elist;
+ for (;;) {
+ if (*i == 0 || (*i)->day > day) {
+ o->next = *i;
+ *i = o;
+ break;
+ }
+ i = &(*i)->next;
+ }
+ return o;
+}
+
+/*
+ * Correspondance between the defines on recursive type,
+ * and the letter to be written in file.
+ */
+char recur_def2char(int define){
+ char recur_char;
+
+ switch (define) {
+ case 1:
+ recur_char = 'D';
+ break;
+ case 2:
+ recur_char = 'W';
+ break;
+ case 3:
+ recur_char = 'M';
+ break;
+ case 4:
+ recur_char = 'Y';
+ break;
+ }
+ return recur_char;
+}
+
+/*
+ * Correspondance between the letters written in file and the defines
+ * concerning the recursive type.
+ */
+int recur_char2def(char type){
+ int recur_def;
+
+ switch (type) {
+ case 'D':
+ recur_def = RECUR_DAILY;
+ break;
+ case 'W':
+ recur_def = RECUR_WEEKLY;
+ break;
+ case 'M':
+ recur_def = RECUR_MONTHLY;
+ break;
+ case 'Y':
+ recur_def = RECUR_YEARLY;
+ break;
+ }
+ return recur_def;
+}
+
+/* Writting of a recursive appointment into file. */
+void recur_apoint_write(struct recur_apoint_s *o, FILE *f)
+{
+ struct tm *lt;
+ time_t t;
+
+ t = o->start;
+ lt = localtime(&t);
+ fprintf(f, "%02u/%02u/%04u @ %02u:%02u",
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year,
+ lt->tm_hour, lt->tm_min);
+
+ t = o->start + o->dur;
+ lt = localtime(&t);
+ fprintf(f, " -> %02u/%02u/%04u @ %02u:%02u",
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year,
+ lt->tm_hour, lt->tm_min);
+
+ t = o->rpt->until;
+ if (t == 0) { /* We have an endless recurrent appointment. */
+ fprintf(f, " {%d%c} |%s\n", o->rpt->freq,
+ recur_def2char(o->rpt->type), o->mesg);
+ } else {
+ lt = localtime(&t);
+ fprintf(f, " {%d%c -> %02u/%02u/%04u} |%s\n",
+ o->rpt->freq, recur_def2char(o->rpt->type),
+ lt->tm_mon + 1, lt->tm_mday, 1900 + lt->tm_year,
+ o->mesg);
+ }
+}
+
+/* Writting of a recursive event into file. */
+void recur_event_write(struct recur_event_s *o, FILE *f)
+{
+ struct tm *lt;
+ time_t t;
+ int st_mon, st_day, st_year;
+ int end_mon, end_day, end_year;
+
+ t = o->day;
+ lt = localtime(&t);
+ st_mon = lt->tm_mon + 1;
+ st_day = lt->tm_mday;
+ st_year = lt->tm_year + 1900;
+ t = o->rpt->until;
+ if (t == 0) { /* We have an endless recurrent event. */
+ fprintf(f, "%02u/%02u/%04u [%d] {%d%c} %s\n",
+ st_mon, st_day, st_year, o->id, o->rpt->freq,
+ recur_def2char(o->rpt->type), o->mesg);
+ } else {
+ lt = localtime(&t);
+ end_mon = lt->tm_mon + 1;
+ end_day = lt->tm_mday;
+ end_year = lt->tm_year + 1900;
+ fprintf(f, "%02u/%02u/%04u [%d] {%d%c -> %02u/%02u/%04u} %s\n",
+ st_mon, st_day, st_year, o->id,
+ o->rpt->freq, recur_def2char(o->rpt->type),
+ end_mon, end_day, end_year, o->mesg);
+ }
+}
+
+/* Load the recursive appointment description */
+struct recur_apoint_s *recur_apoint_scan(FILE * f, struct tm start,
+ struct tm end, char type, int freq, struct tm until)
+{
+ struct tm *lt;
+ char buf[MESG_MAXSIZE], *nl;
+ time_t tstart, tend, t, tuntil;
+
+ t = time(NULL);
+ lt = localtime(&t);
+
+ /* Read the appointment description */
+ fgets(buf, MESG_MAXSIZE, f);
+ nl = strchr(buf, '\n');
+ if (nl) {
+ *nl = '\0';
+ }
+
+ start.tm_sec = end.tm_sec = 0;
+ start.tm_isdst = end.tm_isdst = -1;
+ start.tm_year -= 1900;
+ start.tm_mon--;
+ end.tm_year -= 1900;
+ end.tm_mon--;
+ tstart = mktime(&start);
+ tend = mktime(&end);
+
+ if (until.tm_year != 0) {
+ until.tm_hour = 12;
+ until.tm_min = 0;
+ until.tm_sec = 0;
+ until.tm_isdst = -1;
+ until.tm_year -= 1900;
+ until.tm_mon--;
+ tuntil = mktime(&until);
+ } else {
+ tuntil = 0;
+ }
+
+ if (tstart == -1 || tend == -1 || tstart > tend || tuntil == -1) {
+ fputs(_("FATAL ERROR in apoint_scan: date error in the appointment\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ return recur_apoint_new(buf, tstart, tend - tstart,
+ recur_char2def(type), freq, tuntil);
+}
+
+/* Load the recursive events from file */
+struct recur_event_s *recur_event_scan(FILE * f, struct tm start, int id,
+ char type, int freq, struct tm until)
+{
+ struct tm *lt;
+ char buf[MESG_MAXSIZE], *nl;
+ time_t tstart, t, tuntil;
+
+ t = time(NULL);
+ lt = localtime(&t);
+
+ /* Read the event description */
+ fgets(buf, MESG_MAXSIZE, f);
+ nl = strchr(buf, '\n');
+ if (nl) {
+ *nl = '\0';
+ }
+
+ start.tm_hour = until.tm_hour = 12;
+ start.tm_min = until.tm_min = 0;
+ start.tm_sec = until.tm_sec = 0;
+ start.tm_isdst = until.tm_isdst = -1;
+ start.tm_year -= 1900;
+ start.tm_mon--;
+ if (until.tm_year != 0) {
+ until.tm_year -= 1900;
+ until.tm_mon--;
+ tuntil = mktime(&until);
+ } else {
+ tuntil = 0;
+ }
+ tstart = mktime(&start);
+ if ( (tstart == -1) || (tuntil == -1) ) {
+ fputs(_("FATAL ERROR in recur_event_scan: date error in the event\n"), stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ return recur_event_new(buf, tstart, id, recur_char2def(type), freq, tuntil);
+}
+
+/* Write recursive items to file. */
+void recur_save_data(FILE *f)
+{
+ struct recur_event_s *re;
+ struct recur_apoint_s *ra;
+
+ for (re = recur_elist; re != 0; re = re->next)
+ recur_event_write(re, f);
+ for (ra = recur_alist; ra != 0; ra = ra->next)
+ recur_apoint_write(ra, f);
+}
+
+/* Check if the recurrent item belongs to the selected day. */
+unsigned recur_item_inday(long item_start, int rpt_type, int rpt_freq,
+ long rpt_until, long day_start)
+{
+ const int DAYINSEC = 86400;
+ long day_end = day_start + DAYINSEC;
+ int inday = 0;
+ struct tm *lt;
+ time_t t;
+ char *error =
+ _("FATAL ERROR in recur_item_inday: unknown item type\n");
+
+ if (rpt_until == 0) /* we have an endless recurrent item */
+ rpt_until = day_end;
+ while (item_start <= day_end && item_start <= rpt_until) {
+ if (item_start < day_end && item_start >= day_start) {
+ inday = 1;
+ break;
+ }
+ t = item_start;
+ lt = localtime(&t);
+ if (rpt_type == RECUR_DAILY) {
+ lt->tm_mday += rpt_freq;
+ } else if (rpt_type == RECUR_WEEKLY) {
+ lt->tm_mday += rpt_freq * 7;
+ } else if (rpt_type == RECUR_MONTHLY) {
+ lt->tm_mon += rpt_freq;
+ } else if (rpt_type == RECUR_YEARLY) {
+ lt->tm_year += rpt_freq;
+ } else { /* NOT REACHED */
+ fputs(error, stderr);
+ exit(EXIT_FAILURE);
+ }
+ item_start = date2sec(lt->tm_year + 1900, lt->tm_mon + 1,
+ lt->tm_mday, 0, 0);
+ }
+ return inday;
+}
+
+/* Returns a structure of type apoint_s given a structure of type recur_apoint_s */
+struct apoint_s *recur_apoint_s2apoint_s(struct recur_apoint_s *p)
+{
+ struct apoint_s *a;
+
+ a = (struct apoint_s *) malloc(sizeof(struct apoint_s));
+ a->mesg = (char *) malloc(strlen(p->mesg) + 1);
+ a->start = p->start;
+ a->dur = p->dur;
+ a->mesg = p->mesg;
+ return a;
+}
diff --git a/src/recur.h b/src/recur.h
new file mode 100755
index 0000000..611197c
--- /dev/null
+++ b/src/recur.h
@@ -0,0 +1,87 @@
+/* $calcurse: recur.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_RECUR_H
+#define CALCURSE_RECUR_H
+
+#include "apoint.h"
+
+#define RECUR_NO 0
+#define RECUR_DAILY 1
+#define RECUR_WEEKLY 2
+#define RECUR_MONTHLY 3
+#define RECUR_YEARLY 4
+
+struct days_s {
+ struct days_s *next;
+ long st; /* beggining of the considered day, in seconds */
+};
+
+struct rpt_s {
+ int type; /* repetition type, see RECUR_* defines */
+ int freq; /* repetition frequence */
+ long until; /* ending date for repeated event */
+};
+
+struct recur_apoint_s {
+ struct recur_apoint_s *next;
+ struct rpt_s *rpt; /* information about repetition */
+ struct days_s *exc; /* days when the item should not be repeated */
+ long start; /* beggining of the appointment */
+ long dur; /* duration of the appointment */
+ char *mesg; /* appointment description */
+};
+
+struct recur_event_s {
+ struct recur_event_s *next;
+ struct rpt_s *rpt; /* information about repetition */
+ struct days_s *exc; /* days when the item should not be repeated */
+ int id; /* event type */
+ long day; /* day at which event occurs */
+ char *mesg; /* event description */
+};
+
+extern struct recur_apoint_s *recur_alist;
+extern struct recur_event_s *recur_elist;
+
+struct recur_apoint_s *recur_apoint_new(char *mesg, long start, long duration,
+ int type, int freq, long until);
+struct recur_event_s *recur_event_new(char *mesg, long day, int id,
+ int type, int freq, long until);
+char recur_def2char(int define);
+int recur_char2def(char type);
+void recur_apoint_write(struct recur_apoint_s *o, FILE * f);
+void recur_event_write(struct recur_event_s *o, FILE * f);
+struct recur_apoint_s *recur_apoint_scan(FILE * f, struct tm start,
+ struct tm end, char type, int freq, struct tm until);
+struct recur_event_s *recur_event_scan(FILE * f, struct tm start, int id,
+ char type, int freq, struct tm until);
+void recur_save_data(FILE *f);
+unsigned recur_item_inday(long item_start, int rpt_type, int rpt_freq,
+ long rpt_until, long day_start);
+struct apoint_s *recur_apoint_s2apoint_s(struct recur_apoint_s *p);
+
+#endif /* CALCURSE_RECUR_H */
diff --git a/src/todo.c b/src/todo.c
new file mode 100755
index 0000000..b9419ec
--- /dev/null
+++ b/src/todo.c
@@ -0,0 +1,80 @@
+/* $calcurse: todo.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "i18n.h"
+#include "todo.h"
+
+struct todo_s *todolist;
+
+struct todo_s *todo_insert(char *mesg)
+{
+ struct todo_s *o;
+ o = (struct todo_s *) malloc(sizeof(struct todo_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ o->next = todolist;
+ todolist = o;
+ return o;
+}
+
+struct todo_s *todo_add(char *mesg)
+{
+ struct todo_s *o, **i;
+ o = (struct todo_s *) malloc(sizeof(struct todo_s));
+ o->mesg = (char *) malloc(strlen(mesg) + 1);
+ strcpy(o->mesg, mesg);
+ for (i = &todolist; *i != 0; i = &(*i)->next) {
+ }
+ o->next = *i;
+ *i = o;
+ return o;
+}
+
+void todo_delete_bynum(unsigned num)
+{
+ unsigned n;
+ struct todo_s *i, **iptr;
+
+ n = 0;
+ iptr = &todolist;
+ for (i = todolist; i != 0; i = i->next) {
+ if (n == num) {
+ *iptr = i->next;
+ free(i->mesg);
+ free(i);
+ return;
+ }
+ iptr = &i->next;
+ n++;
+ }
+ /* not reached */
+ fputs(_("FATAL ERROR in todo_delete_bynum: no such todo\n"), stderr);
+ exit(EXIT_FAILURE);
+}
diff --git a/src/todo.h b/src/todo.h
new file mode 100755
index 0000000..9e2af31
--- /dev/null
+++ b/src/todo.h
@@ -0,0 +1,41 @@
+/* $calcurse: todo.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_TODO_H
+#define CALCURSE_TODO_H
+
+struct todo_s {
+ struct todo_s *next;
+ char *mesg;
+};
+
+extern struct todo_s *todolist;
+
+struct todo_s *todo_insert(char *mesg);
+struct todo_s *todo_add(char *mesg);
+void todo_delete_bynum(unsigned num);
+
+#endif /* CALCURSE_TODO_H */
diff --git a/src/utils.c b/src/utils.c
new file mode 100755
index 0000000..ded00fb
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,614 @@
+/* $calcurse: utils.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include <ncurses.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <math.h>
+
+#include "i18n.h"
+#include "utils.h"
+#include "custom.h"
+#include "vars.h"
+
+
+/*
+ * Print a message in the status bar.
+ * Message texts for first line and second line are to be provided.
+ */
+
+void status_mesg(char *mesg_line1, char *mesg_line2)
+{
+ erase_window_part(swin, 0, 0, col, 2);
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ mvwprintw(swin, 0, 0, mesg_line1);
+ mvwprintw(swin, 1, 0, mesg_line2);
+ custom_remove_attr(swin, ATTR_HIGHEST);
+}
+
+/*
+ * Erase part of a window
+ */
+void erase_window_part(WINDOW *win, int first_col, int first_row,
+ int last_col, int last_row)
+{
+ int c, r;
+
+ for (r = first_row; r <= last_row; r++){
+ for (c = first_col; c <= last_col; c++){
+ mvwprintw(win, r, c, " ");
+ }
+ }
+ wnoutrefresh(win);
+}
+
+/* draws a popup window */
+WINDOW * popup(int pop_row, int pop_col,
+ int pop_y, int pop_x, char *pop_lab)
+{
+ char *txt_pop = _("Press any key to continue...");
+ char label[80];
+ WINDOW *popup_win;
+
+ popup_win = newwin(pop_row, pop_col, pop_y, pop_x);
+ custom_apply_attr(popup_win, ATTR_HIGHEST);
+ box(popup_win, 0, 0);
+ sprintf(label, "%s", pop_lab);
+ win_show(popup_win, label);
+ mvwprintw(popup_win, pop_row - 2, pop_col - (strlen(txt_pop) + 1), "%s",
+ txt_pop);
+ custom_remove_attr(popup_win, ATTR_HIGHEST);
+ wnoutrefresh(popup_win);
+ doupdate();
+ return popup_win;
+}
+
+/* prints in middle of a panel */
+void
+print_in_middle(WINDOW * win, int starty, int startx, int width, char *string)
+{
+ int length, x, y;
+ float temp;
+
+ if (win == NULL)
+ win = stdscr;
+ getyx(win, y, x);
+ if (startx != 0)
+ x = startx;
+ if (starty != 0)
+ y = starty;
+ if (width == 0)
+ width = 80;
+
+ length = strlen(string);
+ temp = (width - length) / 2;
+ x = startx + (int) temp;
+ custom_apply_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, y, x, "%s", string);
+ custom_remove_attr(win, ATTR_HIGHEST);
+}
+
+/*
+ * Getstring allows to get user input and to print it on a window,
+ * even if noecho() is on.
+ */
+void getstring(win, colr, string, start_x, start_y)
+WINDOW *win;
+int colr;
+char *string;
+int start_x, start_y;
+{
+ int ch;
+ int charcount = 0;
+
+ custom_apply_attr(win, ATTR_HIGHEST);
+ if (start_x != -1)
+ wmove(win, start_y, start_x);
+
+ while ((ch = wgetch(win)) != '\n') {
+ if ((ch == KEY_BACKSPACE) ||
+ (ch == 330) ||
+ (ch == 263) ||
+ (ch == 127) ||
+ (ch == CTRL('H')) ) {
+ if (charcount > 0) {
+ string--;
+ charcount--;
+ wmove(win, start_y, start_x + charcount);
+ waddch(win, ' ');
+ wmove(win, start_y, start_x + charcount);
+ }
+ } else {
+ *string++ = ch;
+ charcount++;
+ waddch(win, ch);
+ }
+ doupdate();
+ }
+ *string = 0;
+ custom_remove_attr(win, ATTR_HIGHEST);
+ return;
+}
+
+/* checks if a string is only made of digits */
+int is_all_digit(char *string)
+{
+ int digit, i;
+ int all_digit;
+
+ digit = 0;
+ all_digit = 0;
+
+ for (i = 0; i <= strlen(string); i++)
+ if (isdigit(string[i]) != 0)
+ digit++;
+ if (digit == strlen(string))
+ all_digit = 1;
+ return all_digit;
+}
+
+/* draw panel border in color */
+void border_color(WINDOW * window, int bcolr)
+{
+ int color_attr = A_BOLD;
+ int no_color_attr = A_BOLD;
+
+ if (colorize) {
+ wattron(window, color_attr | COLOR_PAIR(bcolr));
+ box(window, 0, 0);
+ } else {
+ wattron(window, no_color_attr);
+ box(window, 0, 0);
+ }
+
+ if (colorize) {
+ wattroff(window, color_attr | COLOR_PAIR(bcolr));
+ } else {
+ wattroff(window, no_color_attr);
+ }
+
+ wnoutrefresh(window);
+}
+
+/* draw panel border without any color */
+void border_nocolor(WINDOW * window)
+{
+ int colr = 9;
+ int color_attr = A_BOLD;
+ int no_color_attr = A_DIM;
+
+ if (colorize) {
+ wattron(window, color_attr | COLOR_PAIR(colr));
+ } else {
+ wattron(window, no_color_attr);
+ }
+
+ box(window, 0, 0);
+
+ if (colorize) {
+ wattroff(window, color_attr | COLOR_PAIR(colr));
+ } else {
+ wattroff(window, no_color_attr);
+ }
+
+ wnoutrefresh(window);
+}
+
+ /* prints and scroll text in a window */
+void scroller(WINDOW *win, char *mesg, int x, int y, int nb_row, int nb_col)
+{
+ int x_offset = 3;
+ int y_offset = 3;
+ int text_len = nb_col - 2 * x_offset;
+ int text_max_row = nb_row - 3;
+ int nlin, i, j, k;
+ int last_blank_i, last_blank_j;
+ char buf[] = " ";
+ char *next_mesg = _("-- Press 'N' for next page --");
+ char *prev_mesg = _("-- Press 'P' for previous page --");
+ int ch;
+ int which_page; //first page : 0, second page : 1
+
+ i = 0; //position in the message
+ j = 0; //x position on the current line
+ nlin = 1; //line number
+ last_blank_j = 0;
+ last_blank_i = 0;
+ which_page = 0;
+
+ while (i <= strlen(mesg)) {
+ if ((i == strlen(mesg)) & (which_page == 1)) {
+ // we have finished writing text and we are on second page
+ custom_apply_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, nb_row - 2,
+ nb_col - (strlen(prev_mesg) + 2), "%s",
+ prev_mesg);
+ custom_remove_attr(win, ATTR_HIGHEST);
+ wmove(swin, 0, 0);
+ wnoutrefresh(win);
+ wnoutrefresh(swin);
+ doupdate();
+ ch = wgetch(win);
+ if ( (ch == 'P') | (ch == 'p') ) {
+ erase_window_part(win, y + 1, x + 3, nb_col - 2, nb_row - 2);
+ nlin = 1;
+ j = 0;
+ i = 0;
+ which_page = 0;
+ } else { //erase last line and exit next-prev page mode
+ for (k = 1; k < nb_col - 2; k++)
+ mvwprintw(win, nb_row - 2, k, " ");
+ break;
+ }
+ }
+ if (nlin == text_max_row - 2) { // we reach the last line
+ custom_apply_attr(win, ATTR_HIGHEST);
+ mvwprintw(win, nb_row - 2,
+ nb_col - (strlen(next_mesg) + 2), "%s",
+ next_mesg);
+ custom_remove_attr(win, ATTR_HIGHEST);
+ wmove(swin, 0, 0);
+ wnoutrefresh(win);
+ wnoutrefresh(swin);
+ doupdate();
+ ch = wgetch(win);
+ if ( (ch == 'N') | (ch == 'n') ) {
+ erase_window_part(win, y + 1, x + 3, nb_col - 2, nb_row - 2);
+ nlin = 1;
+ j = 0;
+ which_page = 1;
+ } else {
+ for (k = 1; k < nb_col - 2; k++)
+ mvwprintw(win, nb_row - 2, k, " ");
+ break;
+ }
+ }
+ //write text
+ strncpy(buf, mesg + i, 1);
+ i++;
+ j++;
+ if ((strncmp(buf, "§", 1) == 0)) { //§ is the character for a new line
+ buf[0] = '\0';
+ mvwprintw(win, x + x_offset + nlin, y + y_offset + j,
+ "%s", buf);
+ nlin++;
+ j = 0;
+ } else {
+ if (j == text_len - 1) { // if we reach the terminal border
+ for (k = last_blank_j; k <= text_len - 1;
+ k++)
+ mvwprintw(win, x + x_offset + nlin,
+ y + y_offset + k, " ");
+ nlin++;
+ i = last_blank_i;
+ j = 0;
+ } else {
+ if ((strncmp(buf, " ", 1) == 0)) //space between words
+ {
+ last_blank_j = j; //save position
+ last_blank_i = i;
+ }
+ mvwprintw(win, x + x_offset + nlin,
+ y + y_offset + j, "%s", buf);
+ }
+ }
+ }
+ wmove(swin, 0, 0);
+ wnoutrefresh(win);
+ wnoutrefresh(swin);
+}
+
+/* Draws the status bar */
+void status_bar(int which_pan, int colr, int nc_bar, int nl_bar)
+{
+ int nb_item_cal, nb_item_oth;
+ int len_let, len_des, spc_lad;
+ int spc_bet_cal_itm, spc_bet_oth_itm;
+ int len_cal_itm, len_oth_itm;
+
+ nb_item_cal = 10; /* max item number to display in status bar */
+ nb_item_cal = ceil(nb_item_cal / 2); /* two lines to display items */
+ nb_item_oth = 12;
+ nb_item_oth = ceil(nb_item_oth / 2);
+ len_let = 3;
+ len_des = 8;
+ spc_lad = 1;
+
+ spc_bet_cal_itm =
+ floor((col -
+ nb_item_cal * (len_let + len_des +
+ spc_lad)) / nb_item_cal);
+ spc_bet_oth_itm =
+ floor((col -
+ nb_item_oth * (len_let + len_des +
+ spc_lad)) / nb_item_oth);
+ len_cal_itm = len_let + spc_lad + len_des + spc_bet_cal_itm;
+ len_oth_itm = len_let + spc_lad + len_des + spc_bet_oth_itm;
+
+ erase_window_part(swin, 0, 0, nc_bar, nl_bar);
+ if (which_pan == 0) {
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ mvwprintw(swin, 0, 0, " ?");
+ mvwprintw(swin, 1, 0, " Q");
+ mvwprintw(swin, 0, len_cal_itm, " R");
+ mvwprintw(swin, 1, len_cal_itm, " S");
+ mvwprintw(swin, 0, 2 * len_cal_itm, "H/L");
+ mvwprintw(swin, 1, 2 * len_cal_itm, "J/K");
+ mvwprintw(swin, 0, 3 * len_cal_itm, " G");
+ mvwprintw(swin, 1, 3 * len_cal_itm, "Tab");
+ mvwprintw(swin, 0, 4 * len_cal_itm, " C");
+ custom_remove_attr(swin, ATTR_HIGHEST);
+ wnoutrefresh(swin);
+
+ mvwprintw(swin, 0, len_let + spc_lad, _("Help"));
+ mvwprintw(swin, 1, len_let + spc_lad, _("Quit"));
+ mvwprintw(swin, 0, len_cal_itm + len_let + spc_lad,
+ _("Redraw"));
+ mvwprintw(swin, 1, len_cal_itm + len_let + spc_lad, _("Save"));
+ mvwprintw(swin, 0, 2 * len_cal_itm + len_let + spc_lad,
+ _("-/+1 Day"));
+ mvwprintw(swin, 1, 2 * len_cal_itm + len_let + spc_lad,
+ _("-/+1 Week"));
+ mvwprintw(swin, 0, 3 * len_cal_itm + len_let + spc_lad,
+ _("GoTo"));
+ mvwprintw(swin, 1, 3 * len_cal_itm + len_let + spc_lad,
+ _("Chg View"));
+ mvwprintw(swin, 0, 4 * len_cal_itm + len_let + spc_lad,
+ _("Config"));
+ } else {
+ custom_apply_attr(swin, ATTR_HIGHEST);
+ mvwprintw(swin, 0, 0, " ?");
+ mvwprintw(swin, 1, 0, " Q");
+ mvwprintw(swin, 0, len_oth_itm, " R");
+ mvwprintw(swin, 1, len_oth_itm, " S");
+ mvwprintw(swin, 0, 2 * len_oth_itm, "J/K");
+ mvwprintw(swin, 1, 2 * len_oth_itm, "Tab");
+ mvwprintw(swin, 0, 3 * len_oth_itm, " A");
+ mvwprintw(swin, 1, 3 * len_oth_itm, " D");
+ mvwprintw(swin, 0, 4 * len_oth_itm, " G");
+ mvwprintw(swin, 1, 4 * len_oth_itm, " V");
+ mvwprintw(swin, 0, 5 * len_oth_itm, " C");
+ custom_remove_attr(swin, ATTR_HIGHEST);
+ wnoutrefresh(swin);
+
+ mvwprintw(swin, 0, len_let + spc_lad, _("Help"));
+ mvwprintw(swin, 1, len_let + spc_lad, _("Quit"));
+ mvwprintw(swin, 0, len_oth_itm + len_let + spc_lad,
+ _("Redraw"));
+ mvwprintw(swin, 1, len_oth_itm + len_let + spc_lad, _("Save"));
+ mvwprintw(swin, 0, 2 * len_oth_itm + len_let + spc_lad,
+ _("Up/Down"));
+ mvwprintw(swin, 1, 2 * len_oth_itm + len_let + spc_lad,
+ _("Chg View"));
+ mvwprintw(swin, 0, 3 * len_oth_itm + len_let + spc_lad,
+ _("Add Item"));
+ mvwprintw(swin, 1, 3 * len_oth_itm + len_let + spc_lad,
+ _("Del Item"));
+ mvwprintw(swin, 0, 4 * len_oth_itm + len_let + spc_lad,
+ _( "GoTo"));
+ mvwprintw(swin, 1, 4 * len_oth_itm + len_let + spc_lad,
+ _("View"));
+ mvwprintw(swin, 0, 5 * len_oth_itm + len_let + spc_lad,
+ _("Config"));
+ }
+ wnoutrefresh(swin);
+}
+
+long date2sec(unsigned year, unsigned month, unsigned day, unsigned hour,
+ unsigned min)
+{
+ struct tm start, *lt;
+ time_t tstart, t;
+
+ t = time(NULL);
+ lt = localtime(&t);
+ start = *lt;
+
+ start.tm_mon = month;
+ start.tm_mday = day;
+ start.tm_year = year;
+ start.tm_hour = hour;
+ start.tm_min = min;
+ start.tm_sec = 0;
+ start.tm_isdst = -1;
+ start.tm_year -= 1900;
+ start.tm_mon--;
+ tstart = mktime(&start);
+ if (tstart == -1) {
+ fputs(_("FATAL ERROR in date2sec: failure in mktime\n"), stderr);
+ fprintf(stderr, "%u %u %u %u %u\n", year, month, day, hour, min);
+ exit(EXIT_FAILURE);
+ }
+ return tstart;
+}
+
+/*
+ * Returns the date in seconds from year 1900.
+ * If no date is entered, current date is chosen.
+ */
+long
+get_sec_date(int year, int month, int day)
+{
+ struct tm *ptrtime;
+ time_t timer;
+ long long_date;
+ char current_day[3], current_month[3] ,current_year[5];
+
+ if (year == 0 && month == 0 && day == 0) {
+ timer = time(NULL);
+ ptrtime = localtime(&timer);
+ strftime(current_day, 3, "%d", ptrtime);
+ strftime(current_month, 3, "%m", ptrtime);
+ strftime(current_year, 5, "%Y", ptrtime);
+ month = atoi(current_month);
+ day = atoi(current_day);
+ year = atoi(current_year);
+
+ }
+ long_date = date2sec(year, month, day, 0, 0);
+ return long_date;
+}
+
+long min2sec(unsigned minutes)
+{
+ return minutes * 60;
+}
+
+/*
+ * Checks if a time has a good format.
+ * The format could be either HH:MM or H:MM or MM, and we should have:
+ * 0 <= HH <= 24 and 0 <= MM < 999.
+ * This function returns 1 if the entered time is correct and in
+ * [h:mm] or [hh:mm] format, and 2 if the entered time is correct and entered
+ * in [mm] format.
+ */
+int check_time(char *string)
+{
+ int ok = 0;
+ char hour[] = " ";
+ char minutes[] = " ";
+
+ if ( // format test [MM]
+ ((strlen(string) == 2) || (strlen(string) == 3)) &
+ (isdigit(string[0]) != 0) &
+ (isdigit(string[1]) != 0)
+ ) { // check if we have a valid time
+ strncpy(minutes, string, 2);
+ if ( atoi(minutes) >= 0)
+ ok = 2;
+ }
+
+ else if ( // format test [H:MM]
+ (strlen(string) == 4) &
+ (isdigit(string[0]) != 0) &
+ (isdigit(string[2]) != 0) &
+ (isdigit(string[3]) != 0) & (string[1] == ':')
+ ) { // check if we have a valid time
+ strncpy(hour, string, 1);
+ strncpy(minutes, string + 2, 2);
+ if ((atoi(hour) <= 24) & (atoi(hour) >=
+ 0) & (atoi(minutes) <
+ 60) & (atoi(minutes) >= 0))
+ ok = 1;
+ }
+
+ else if ( //format test [HH:MM]
+ (strlen(string) == 5) &
+ (isdigit(string[0]) != 0) &
+ (isdigit(string[1]) != 0) &
+ (isdigit(string[3]) != 0) &
+ (isdigit(string[4]) != 0) & (string[2] == ':')
+ ) { // check if we have a valid time
+ strncpy(hour, string, 2);
+ strncpy(minutes, string + 3, 2);
+ if ((atoi(hour) <= 24) & (atoi(hour) >=
+ 0) & (atoi(minutes) <
+ 60) & (atoi(minutes) >= 0))
+ ok = 1;
+ }
+
+ return ok;
+}
+
+/*
+ * Display a scroll bar when there are so many items that they
+ * can not be displayed inside the corresponding panel.
+ */
+void draw_scrollbar(WINDOW *win, int y, int x, int length,
+ int bar_top, int bar_bottom, bool hilt)
+{
+ mvwvline(win, bar_top, x, ACS_VLINE, bar_bottom - bar_top);
+ if (hilt)
+ custom_apply_attr(win, ATTR_HIGHEST);
+ wattron(win, A_REVERSE);
+ mvwvline(win, y, x, ' ', length);
+ wattroff(win, A_REVERSE);
+ if (hilt)
+ custom_remove_attr(win, ATTR_HIGHEST);
+}
+
+/*
+ * Print an item (either an appointment, event, or todo) in a
+ * popup window. This is useful if an item description is too
+ * long to fit in its corresponding panel window.
+ */
+void item_in_popup(char *saved_a_start, char *saved_a_end, char *msg,
+ char *pop_title)
+{
+ WINDOW *popup_win;
+
+ popup_win = popup(row - 4, col - 2, 1, 1, pop_title);
+ if (strncmp(pop_title, _("Appointment"), 11) == 0) {
+ mvwprintw(popup_win, 4, 4, " - %s -> %s",
+ saved_a_start, saved_a_end);
+ }
+ scroller(popup_win, msg, 1, 1, row - 4, col - 2);
+ wmove(swin, 0, 0);
+ doupdate();
+ wgetch(popup_win);
+ delwin(popup_win);
+}
+
+/* Show the window with a border and a label */
+void win_show(WINDOW * win, char *label)
+{
+ int startx, starty, height, width;
+
+ getbegyx(win, starty, startx);
+ getmaxyx(win, height, width);
+
+ box(win, 0, 0);
+ mvwaddch(win, 2, 0, ACS_LTEE);
+ mvwhline(win, 2, 1, ACS_HLINE, width - 2);
+ mvwaddch(win, 2, width - 1, ACS_RTEE);
+
+ print_in_middle(win, 1, 0, width, label);
+}
+
+/*
+ * Print an item description in the corresponding panel window.
+ */
+void display_item(WINDOW *win, int incolor, char *msg, int len,
+ int y, int x)
+{
+ char buf[len];
+
+ if (incolor == 0)
+ custom_apply_attr(win, ATTR_HIGHEST);
+ if (strlen(msg) < len) {
+ mvwprintw(win, y, x, "%s", msg);
+ } else {
+ strncpy(buf, msg, len - 1);
+ buf[len - 1] = '\0';
+ mvwprintw(win, y, x, "%s...", buf);
+ }
+ if (incolor == 0)
+ custom_remove_attr(win, ATTR_HIGHEST);
+}
diff --git a/src/utils.h b/src/utils.h
new file mode 100755
index 0000000..e7bdeff
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,55 @@
+/* $calcurse: utils.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_UTILS_H
+#define CALCURSE_UTILS_H
+
+void status_mesg(char *mesg_line1, char *mesg_line2);
+void erase_window_part(WINDOW *win, int first_col, int first_row,
+ int last_col, int last_row);
+WINDOW *popup(int pop_row, int pop_col,
+ int pop_y, int pop_x, char *pop_lab);
+void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string);
+void getstring(WINDOW *win, int colr, char *string, int start_x, int start_y);
+int is_all_digit(char *string);
+void border_color(WINDOW *window, int bcolr);
+void border_nocolor(WINDOW *window);
+void scroller(WINDOW *win, char *, int x, int y, int nb_row, int nb_col);
+void status_bar(int which_pan, int colr, int nc_bar, int nl_bar);
+long date2sec(unsigned year, unsigned month, unsigned day, unsigned hour,
+ unsigned min);
+long get_sec_date(int year, int month, int day);
+long min2sec(unsigned minutes);
+int check_time(char *string);
+void draw_scrollbar(WINDOW *win, int y, int x, int length,
+ int bar_top, int bar_bottom, bool hilt);
+void item_in_popup(char *saved_a_start, char *saved_a_end, char *msg,
+ char *pop_title);
+void win_show(WINDOW * win, char *label);
+void display_item(WINDOW *win, int incolor, char *msg,
+ int len, int y, int x);
+
+#endif /* CALCURSE_UTILS_H */
diff --git a/src/vars.c b/src/vars.c
new file mode 100755
index 0000000..524d944
--- /dev/null
+++ b/src/vars.c
@@ -0,0 +1,85 @@
+/* $calcurse: vars.c,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#include "i18n.h"
+#include "vars.h"
+
+/*
+ * variables to store window size
+ */
+int col = 0, row = 0;
+
+/* variable to tell if the terminal supports color */
+bool colorize = false;
+
+/*
+ * variables to store calendar names
+ */
+int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+char *monthnames[12] =
+ { N_("January"),
+ N_("February"),
+ N_("March"),
+ N_("April"),
+ N_("May"),
+ N_("June"),
+ N_("July"),
+ N_("August"),
+ N_("September"),
+ N_("October"),
+ N_("November"),
+ N_("December") };
+
+char *daynames[8] =
+ { N_("Sun"),
+ N_("Mon"),
+ N_("Tue"),
+ N_("Wed"),
+ N_("Thu"),
+ N_("Fri"),
+ N_("Sat"),
+ N_("Sun") };
+
+/*
+ * variables to store data path names, which are initialized in
+ * io_init()
+ */
+char path_dir[] = "";
+char path_todo[] = "";
+char path_apts[] = "";
+char path_conf[] = "";
+
+/*
+ * Variables to handle calcurse windows:
+ * cwin = calendar window
+ * awin = appointment window
+ * twin = todo window
+ * swin = status bar window
+ */
+WINDOW *awin = NULL, *cwin = NULL, *twin = NULL, *swin = NULL;
+
+/* Variable to handle pads. */
+struct pad_s *apad;
diff --git a/src/vars.h b/src/vars.h
new file mode 100755
index 0000000..d9bb13e
--- /dev/null
+++ b/src/vars.h
@@ -0,0 +1,69 @@
+/* $calcurse: vars.h,v 1.1 2006/07/31 21:00:03 culot Exp $ */
+
+/*
+ * Calcurse - text-based organizer
+ * Copyright (c) 2004-2006 Frederic Culot
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Send your feedback or comments to : calcurse@culot.org
+ * Calcurse home page : http://culot.org/calcurse
+ *
+ */
+
+#ifndef CALCURSE_VARS_H
+#define CALCURSE_VARS_H
+
+#include <ncurses.h>
+#include <stdbool.h>
+
+#define DIR_NAME ".calcurse"
+#define TODO_PATH ".calcurse/todo"
+#define APTS_PATH ".calcurse/apts"
+#define CONF_PATH ".calcurse/conf"
+
+#define MAX_LENGTH 512
+
+#define CTRL(x) ((x) & 0x1f)
+
+#define ATTR_FALSE 0
+#define ATTR_TRUE 1
+#define ATTR_LOWEST 2
+#define ATTR_LOW 3
+#define ATTR_MIDDLE 4
+#define ATTR_HIGH 5
+#define ATTR_HIGHEST 6
+
+struct pad_s {
+ int width;
+ int length;
+ int first_onscreen; /* first line to be displayed inside window */
+ WINDOW *ptrwin; /* pointer to the pad window */
+};
+
+extern int col, row;
+extern bool colorize;
+extern int days[12];
+extern char *monthnames[12];
+extern char *daynames[8];
+extern char path_dir[MAX_LENGTH];
+extern char path_todo[MAX_LENGTH];
+extern char path_apts[MAX_LENGTH];
+extern char path_conf[MAX_LENGTH];
+extern WINDOW *awin, *cwin, *twin, *swin;
+extern struct pad_s *apad;
+
+#endif /* CALCURSE_VARS_H */