/* $calcurse: day.c,v 1.34 2008/01/20 10:45:38 culot Exp $ */
/*
* Calcurse - text-based organizer
* Copyright (c) 2004-2008 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 <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include <time.h>
#include "i18n.h"
#include "apoint.h"
#include "event.h"
#include "custom.h"
#include "day.h"
static struct day_item_s *day_items_ptr;
static struct day_saved_item_s *day_saved_item = NULL;
/* Free the current day linked list containing the events and appointments. */
static 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;
}
/* Add an event in the current day list */
static struct day_item_s *
day_add_event(int type, char *mesg, char *note, 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);
strncpy(o->mesg, mesg, strlen(mesg) + 1);
o->note = note;
o->type = type;
o->appt_dur = 0;
o->appt_pos = 0;
o->start = day;
o->evnt_id = id;
i = &day_items_ptr;
for (;;) {
if (*i == 0) {
o->next = *i;
*i = o;
break;
}
i = &(*i)->next;
}
return o;
}
/* Add an appointment in the current day list. */
static struct day_item_s *
day_add_apoint(int type, char *mesg, char *note, long start, long dur,
char state, int real_pos)
{
struct day_item_s *o, **i;
int insert_item = 0;
o = (struct day_item_s *) malloc(sizeof(struct day_item_s));
o->mesg = (char *) malloc(strlen(mesg) + 1);
strncpy(o->mesg, mesg, strlen(mesg) + 1);
o->note = note;
o->start = start;
o->appt_dur = dur;
o->appt_pos = real_pos;
o->state = state;
o->type = type;
o->evnt_id = 0;
i = &day_items_ptr;
for (;;) {
if (*i == 0) {
insert_item = 1;
} else if ( ((*i)->start > start) &&
((*i)->type > EVNT) ) {
insert_item = 1;
}
if (insert_item) {
o->next = *i;
*i = o;
break;
}
i = &(*i)->next;
}
return o;
}
/*
* 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.
*/
static 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->note, j->day,
j->id);
}
}
return e_nb;
}
/*
* 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.
*/
static 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->exc, j->rpt->type, j->rpt->freq,
j->rpt->until, date)) {
e_nb++;
ptr = day_add_event(RECUR_EVNT, j->mesg, j->note,
j->day, j->id);
}
}
return e_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 alist_p->root to the
* structure dedicated to the selected day.
* Returns the number of appointments for the selected day.
*/
static int
day_store_apoints(long date)
{
apoint_llist_node_t *j;
struct day_item_s *ptr;
int a_nb = 0;
pthread_mutex_lock(&(alist_p->mutex));
for (j = alist_p->root; j != 0; j = j->next) {
if (apoint_inday(j, date)) {
a_nb++;
ptr = day_add_apoint(APPT, j->mesg, j->note, j->start,
j->dur, j->state, 0);
}
}
pthread_mutex_unlock(&(alist_p->mutex));
return a_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_p->root to the
* structure dedicated to the selected day.
* Returns the number of recurrent appointments for the selected day.
*/
static int
day_store_recur_apoints(long date)
{
recur_apoint_llist_node_t *j;
struct day_item_s *ptr;
long real_start;
int a_nb = 0, n = 0;
pthread_mutex_lock(&(recur_alist_p->mutex));
for (j = recur_alist_p->root; j != 0; j = j->next) {
if ((real_start = recur_item_inday(j->start, j->exc,
j->rpt->type, j->rpt->freq, j->rpt->until, date)) ){
a_nb++;
ptr = day_add_apoint(RECUR_APPT, j->mesg, j->note,
real_start, j->dur, j->state, n);
n++;
}
}
pthread_mutex_unlock(&(recur_alist_p->mutex));
return a_nb;
}
/*
* 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.
*/
static int
day_store_items(long date, unsigned *pnb_events, unsigned *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;
}
/*
* Store the events and appointments for the selected day, and write
* those items in a pad. If selected day is null, then store items for current
* day. This is useful to speed up the appointment panel update.
*/
day_items_nb_t *
day_process_storage(date_t *slctd_date, bool day_changed, day_items_nb_t *inday)
{
long date;
date_t day;
if (slctd_date)
day = *slctd_date;
else
calendar_store_current_date(&day);
date = date2sec(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,
&inday->nb_events, &inday->nb_apoints);
/* Create the new pad with its new length. */
if (day_changed)
apad->first_onscreen = 0;
apad->ptrwin = newpad(apad->length, apad->width);
return (inday);
}
/*
* Returns a structure of type apoint_llist_node_t given a structure of type
* day_item_s
*/
static void
day_item_s2apoint_s(apoint_llist_node_t *a, struct day_item_s *p)
{
a->state = p->state;
a->start = p->start;
a->dur = p->appt_dur;
a->mesg = p->mesg;
}
/*
* Print an item date in the appointment panel.
*/
static void
display_item_date(int incolor, apoint_llist_node_t *i, int type, long date,
int y, int x)
{
WINDOW *win;
char a_st[100], a_end[100];
int recur = 0;
win = apad->ptrwin;
apoint_sec2str(i, type, date, a_st, a_end);
if (type == RECUR_EVNT || type == RECUR_APPT)
recur = 1;
if (incolor == 0)
custom_apply_attr(win, ATTR_HIGHEST);
if (recur)
if (i->state & APOINT_NOTIFY)
mvwprintw(win, y, x, " *!%s -> %s", a_st, a_end);
else
mvwprintw(win, y, x, " * %s -> %s", a_st, a_end);
else
if (i->state & APOINT_NOTIFY)
mvwprintw(win, y, x, " -!%s -> %s", a_st, a_end);
else
mvwprintw(win, y, x, " - %s -> %s", a_st, a_end);
if (incolor == 0)
custom_remove_attr(win, ATTR_HIGHEST);
}
/*
* Print an item description in the corresponding panel window.
*/
static void
display_item(int incolor, char *msg, int recur, int note, int len, int y, int x)
{
WINDOW *win;
int ch_recur, ch_note;
char buf[len];
win = apad->ptrwin;
ch_recur = (recur) ? '*' : ' ';
ch_note = (note) ? '>' : ' ';
if (incolor == 0)
custom_apply_attr(win, ATTR_HIGHEST);
if (strlen(msg) < len)
mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_note, msg);
else {
strncpy(buf, msg, len - 1);
buf[len - 1] = '\0';
mvwprintw(win, y, x, " %c%c%s...", ch_recur, ch_note, buf);
}
if (incolor == 0)
custom_remove_attr(win, ATTR_HIGHEST);
}
/*
* 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)
{
struct day_item_s *p;
apoint_llist_node_t a;
int line, item_number, max_pos, recur;
const int x_pos = 0;
bool draw_line = false;
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(sizeof(char));
}
for (p = day_items_ptr; p != 0; p = p->next) {
if (p->type == RECUR_EVNT || p->type == RECUR_APPT)
recur = 1;
else
recur = 0;
/* 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 = p->mesg;
}
display_item(item_number - incolor, p->mesg, recur,
(p->note != NULL) ? 1 : 0, width - 7, line, x_pos);
line++;
draw_line = true;
} else {
/* Draw a line between events and appointments. */
if (line > 0 && draw_line){
wmove(apad->ptrwin, line, 0);
whline(apad->ptrwin, 0, width);
draw_line = false;
}
/* Last print the appointments for current day. */
item_number++;
day_item_s2apoint_s(&a, p);
if (item_number - incolor == 0) {
day_saved_item->type = p->type;
day_saved_item->mesg = p->mesg;
apoint_sec2str(&a, p->type, date,
day_saved_item->start, day_saved_item->end);
}
display_item_date(item_number - incolor, &a, p->type,
date, line + 1, x_pos);
display_item(item_number - incolor, p->mesg, 0,
(p->note != NULL) ? 1 : 0, width - 7, line + 2,
x_pos);
line += 3;
}
}
}
/* 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
ierror(error, IERROR_FATAL);
/* NOTREACHED */
}
/*
* 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(date_t day)
{
struct recur_event_s *re;
recur_apoint_llist_node_t *ra;
struct event_s *e;
apoint_llist_node_t *a;
const long date = date2sec(day, 0, 0);
for (re = recur_elist; re != 0; re = re->next)
if (recur_item_inday(re->day, re->exc, re->rpt->type,
re->rpt->freq, re->rpt->until, date))
return 1;
pthread_mutex_lock(&(recur_alist_p->mutex));
for (ra = recur_alist_p->root; ra != 0; ra = ra->next)
if (recur_item_inday(ra->start, ra->exc, ra->rpt->type,
ra->rpt->freq, ra->rpt->until, date)) {
pthread_mutex_unlock(
&(recur_alist_p->mutex));
return 1;
}
pthread_mutex_unlock(&(recur_alist_p->mutex));
for (e = eventlist; e != 0; e = e->next)
if (event_inday(e, date))
return 1;
pthread_mutex_lock(&(alist_p->mutex));
for (a = alist_p->root; a != 0; a = a->next)
if (apoint_inday(a, date)) {
pthread_mutex_unlock(&(alist_p->mutex));
return 1;
}
pthread_mutex_unlock(&(alist_p->mutex));
return 0;
}
/* Request the user to enter a new time. */
static char *
day_edit_time(long time)
{
char *timestr;
char *msg_time = _("Enter the new time ([hh:mm] or [h:mm]) : ");
char *enter_str = _("Press [Enter] to continue");
char *fmt_msg =
_("You entered an invalid time, should be [h:mm] or [hh:mm]");
while (1) {
status_mesg(msg_time, "");
timestr = date_sec2hour_str(time);
updatestring(win[STA].p, ×tr, 0, 1);
if (check_time(timestr) != 1 || strlen(timestr) == 0) {
status_mesg(fmt_msg, enter_str);
wgetch(win[STA].p);
} else
return (timestr);
}
}
static void
update_start_time(long *start, long *dur)
{
long newtime;
unsigned hr, mn;
int valid_date;
char *timestr;
char *msg_wrong_time =
_("Invalid time: start time must be before end time!");
char *msg_enter = _("Press [Enter] to continue");
do {
timestr = day_edit_time(*start);
sscanf(timestr, "%u:%u", &hr, &mn);
free(timestr);
newtime = update_time_in_date(*start, hr, mn);
if (newtime < *start + *dur) {
*dur -= (newtime - *start);
*start = newtime;
valid_date = 1;
} else {
status_mesg(msg_wrong_time, msg_enter);
wgetch(win[STA].p);
valid_date = 0;
}
} while (valid_date == 0);
}
static void
update_duration(long *start, long *dur)
{
long newtime;
unsigned hr, mn;
char *timestr;
timestr = day_edit_time(*start + *dur);
sscanf(timestr, "%u:%u", &hr, &mn);
free(timestr);
newtime = update_time_in_date(*start, hr, mn);
*dur = (newtime > *start) ? newtime - *start :
DAYINSEC + newtime - *start;
}
static void
update_desc(char **desc)
{
status_mesg(_("Enter the new item description:"), "");
updatestring(win[STA].p, desc, 0, 1);
}
static void
update_rept(struct rpt_s **rpt, const long start)
{
const int SINGLECHAR = 2;
int ch, cancel, newfreq, date_entered, valid_date;
long newuntil;
char *typstr, *freqstr, *timstr;
char *msg_rpt_type =
_("Enter the new repetition type: (D)aily, (W)eekly, "
"(M)onthly, (Y)early");
char *msg_rpt_ans = _("[D/W/M/Y] ");
char *msg_wrong_freq = _("The frequence you entered is not valid.");
char *msg_wrong_time =
_("Invalid time: start time must be before end time!");
char *msg_wrong_date = _("The entered date is not valid.");
char *msg_fmts = _("Possible formats are [mm/dd/yyyy] or '0' "
"for an endless repetetition");
char *msg_enter = _("Press [Enter] to continue");
do {
status_mesg(msg_rpt_type, msg_rpt_ans);
typstr = (char *)malloc(sizeof(char) * SINGLECHAR);
snprintf(typstr, SINGLECHAR, "%c", recur_def2char((*rpt)->type));
cancel = updatestring(win[STA].p, &typstr, 0, 1);
if (cancel) {
free(typstr);
return;
} else {
ch = toupper(*typstr);
free(typstr);
}
} while ((ch != 'D') && (ch != 'W') && (ch != 'M') && (ch != 'Y'));
do {
status_mesg(_("Enter the new repetition frequence:"), "");
freqstr = (char *)malloc(BUFSIZ);
snprintf(freqstr, BUFSIZ, "%d", (*rpt)->freq);
cancel = updatestring(win[STA].p, &freqstr, 0, 1);
if (cancel) {
free(freqstr);
return;
} else {
newfreq = atoi(freqstr);
free(freqstr);
if (newfreq == 0) {
status_mesg(msg_wrong_freq, msg_enter);
wgetch(win[STA].p);
}
}
} while (newfreq == 0);
do {
status_mesg(_("Enter the new ending date: [mm/dd/yyyy] or '0'"),
"");
timstr = date_sec2date_str((*rpt)->until);
cancel = updatestring(win[STA].p, &timstr, 0, 1);
if (cancel) {
free(timstr);
return;
}
if (strcmp(timstr, "0") == 0) {
newuntil = 0;
date_entered = 1;
} else {
struct tm *lt;
time_t t;
date_t new_date;
int newmonth, newday, newyear;
valid_date = check_date(timstr);
if (valid_date) {
sscanf(timstr, "%d / %d / %d",
&newmonth, &newday, &newyear);
t = start;
lt = localtime(&t);
new_date.dd = newday;
new_date.mm = newmonth;
new_date.yyyy = newyear;
newuntil = date2sec(new_date, lt->tm_hour,
lt->tm_min);
if (newuntil < start) {
status_mesg(msg_wrong_time, msg_enter);
wgetch(win[STA].p);
date_entered = 0;
} else
date_entered = 1;
} else {
status_mesg(msg_wrong_date, msg_fmts);
wgetch(win[STA].p);
date_entered = 0;
}
}
} while (date_entered == 0);
free(timstr);
(*rpt)->type = recur_char2def(ch);
(*rpt)->freq = newfreq;
(*rpt)->until = newuntil;
}
/* Edit an already existing item. */
void
day_edit_item(void)
{
#define STRT '1'
#define END '2'
#define DESC '3'
#define REPT '4'
struct day_item_s *p;
struct recur_event_s *re;
struct event_s *e;
recur_apoint_llist_node_t *ra;
apoint_llist_node_t *a;
long date;
int item_num, ch;
item_num = apoint_hilt();
p = day_get_item(item_num);
date = calendar_get_slctd_day_sec();
ch = 0;
switch (p->type) {
case RECUR_EVNT:
re = recur_get_event(date,
day_item_nb(date, item_num, RECUR_EVNT));
status_mesg(_("Edit: (1)Description or (2)Repetition?"),
"[1/2] ");
while (ch != '1' && ch != '2' && ch != ESCAPE)
ch = wgetch(win[STA].p);
switch (ch) {
case '1':
update_desc(&re->mesg);
break;
case '2':
update_rept(&re->rpt, re->day);
break;
default:
return;
}
break;
case EVNT:
e = event_get(date, day_item_nb(date, item_num, EVNT));
update_desc(&e->mesg);
break;
case RECUR_APPT:
ra = recur_get_apoint(date,
day_item_nb(date, item_num, RECUR_APPT));
status_mesg(_("Edit: (1)Start time, (2)End time, "
"(3)Description or (4)Repetition?"), "[1/2/3/4] ");
while (ch != STRT && ch != END && ch != DESC &&
ch != REPT && ch != ESCAPE)
ch = wgetch(win[STA].p);
switch (ch) {
case STRT:
update_start_time(&ra->start, &ra->dur);
break;
case END:
update_duration(&ra->start, &ra->dur);
break;
case DESC:
update_desc(&ra->mesg);
break;
case REPT:
update_rept(&ra->rpt, ra->start);
break;
case ESCAPE:
return;
}
break;
case APPT:
a = apoint_get(date, day_item_nb(date, item_num, APPT));
status_mesg(_("Edit: (1)Start time, (2)End time "
"or (3)Description?"), "[1/2/3] ");
while (ch != STRT && ch != END && ch != DESC && ch != ESCAPE)
ch = wgetch(win[STA].p);
switch (ch) {
case STRT:
update_start_time(&a->start, &a->dur);
break;
case END:
update_duration(&a->start, &a->dur);
break;
case DESC:
update_desc(&a->mesg);
break;
case ESCAPE:
return;
}
break;
}
}
/*
* In order to erase an item, we need to count first the number of
* items for each type (in order: recurrent events, events,
* recurrent appointments and appointments) and then to test the
* type of the item to be deleted.
*/
int
day_erase_item(long date, int item_number, erase_flag_e flag)
{
struct day_item_s *p;
char *erase_warning =
_("This item is recurrent. "
"Delete (a)ll occurences or just this (o)ne ?");
char *note_warning =
_("This item has a note attached to it. "
"Delete (i)tem or just its (n)ote ?");
char *note_choice = _("[i/n] ");
char *erase_choice = _("[a/o] ");
int ch = 0, ans;
unsigned delete_whole;
p = day_get_item(item_number);
if (flag == ERASE_DONT_FORCE) {
ans = 0;
if (p->note == NULL)
ans = 'i';
while (ans != 'i' && ans != 'n') {
status_mesg(note_warning, note_choice);
ans = wgetch(win[STA].p);
}
if (ans == 'i')
flag = ERASE_FORCE;
else
flag = ERASE_FORCE_ONLY_NOTE;
}
if (p->type == EVNT) {
event_delete_bynum(date, day_item_nb(date, item_number, EVNT),
flag);
} else if (p->type == APPT) {
apoint_delete_bynum(date, day_item_nb(date, item_number, APPT),
flag);
} else {
if (flag == ERASE_FORCE_ONLY_NOTE)
ch = 'a';
while ( (ch != 'a') && (ch != 'o') && (ch != ESCAPE)) {
status_mesg(erase_warning, erase_choice);
ch = wgetch(win[STA].p);
}
if (ch == 'a') {
delete_whole = 1;
} else if (ch == 'o') {
delete_whole = 0;
} else {
return 0;
}
if (p->type == RECUR_EVNT) {
recur_event_erase(date,
day_item_nb(date, item_number, RECUR_EVNT),
delete_whole, flag);
} else {
recur_apoint_erase(date, p->appt_pos, delete_whole,
flag);
}
}
return (p->type);
}
/* Returns a structure containing the selected item. */
struct day_item_s *day_get_item(int item_number)
{
struct day_item_s *o;
int i;
o = day_items_ptr;
for (i = 1; i < item_number; i++) {
o = o->next;
}
return o;
}
/* Returns the real item number, given its type. */
int
day_item_nb(long date, int day_num, int type)
{
int i, nb_item[MAX_TYPES];
struct day_item_s *p;
for (i = 0; i < MAX_TYPES; i++)
nb_item[i] = 0;
p = day_items_ptr;
for (i = 1; i < day_num; i++) {
nb_item[p->type - 1]++;
p = p->next;
}
return (nb_item[type - 1]);
}
/* Attach a note to an appointment or event. */
void
day_edit_note(char *editor)
{
struct day_item_s *p;
recur_apoint_llist_node_t *ra;
apoint_llist_node_t *a;
struct recur_event_s *re;
struct event_s *e;
char fullname[BUFSIZ];
char *filename;
long date;
int item_num;
item_num = apoint_hilt();
p = day_get_item(item_num);
if (p->note == NULL) {
if ((filename = new_tempfile(path_notes, NOTESIZ)) == NULL)
return;
else
p->note = filename;
}
snprintf(fullname, BUFSIZ, "%s%s", path_notes, p->note);
wins_launch_external(fullname, editor);
date = calendar_get_slctd_day_sec();
switch (p->type) {
case RECUR_EVNT:
re = recur_get_event(date,
day_item_nb(date, item_num, RECUR_EVNT));
re->note = p->note;
break;
case EVNT:
e = event_get(date, day_item_nb(date, item_num, EVNT));
e->note = p->note;
break;
case RECUR_APPT:
ra = recur_get_apoint(date,
day_item_nb(date, item_num, RECUR_APPT));
ra->note = p->note;
break;
case APPT:
a = apoint_get(date, day_item_nb(date, item_num, APPT));
a->note = p->note;
break;
}
}
/* View a note previously attached to an appointment or event */
void
day_view_note(char *pager)
{
struct day_item_s *p;
char fullname[BUFSIZ];
p = day_get_item(apoint_hilt());
if (p->note == NULL)
return;
snprintf(fullname, BUFSIZ, "%s%s", path_notes, p->note);
wins_launch_external(fullname, pager);
}