"Fossies" - the Fresh Open Source Software Archive 
Member "calcurse-4.5.1/src/day.c" (18 Oct 2019, 21133 Bytes) of package /linux/privat/calcurse-4.5.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "day.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
4.3.0_vs_4.4.0.
1 /*
2 * Calcurse - text-based organizer
3 *
4 * Copyright (c) 2004-2017 calcurse Development Team <misc@calcurse.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the
13 * following disclaimer.
14 *
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the
17 * following disclaimer in the documentation and/or other
18 * materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Send your feedback or comments to : misc@calcurse.org
33 * Calcurse home page : http://calcurse.org
34 *
35 */
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <ctype.h>
41 #include <time.h>
42
43 #include "calcurse.h"
44
45 static vector_t day_items;
46 static unsigned day_items_nb = 0;
47
48 struct day_item empty_day = { 0, 0, 0, {NULL}};
49
50 /*
51 * The day vector, day_items, is continuously rebuilt for display as the
52 * selected day changes, items are added, edited or deleted etc. To keep track
53 * of the selected item of the day vector across rebuilds, data are saved in
54 * here that may later be used to refind the item in the rebuilt day
55 * vector.
56 */
57 static struct day_item sel_data = { 0, 0, 0, {NULL}};
58
59 /*
60 * Save the item to become the selected APP item.
61 * Public function used to override the setting in do_storage().
62 */
63 int day_set_sel_data(struct day_item *d)
64 {
65 if (!d)
66 return 0;
67
68 sel_data = *d;
69 return 1;
70 }
71
72 /*
73 * Return selection data if available.
74 */
75 int day_check_sel_data()
76 {
77 return (sel_data.order || sel_data.item.apt) ? 1 : 0;
78 }
79
80 /*
81 * Return the position of the saved selection in the day vector.
82 */
83 int day_sel_index(void)
84 {
85 int i = 0;
86 struct day_item *p;
87
88 VECTOR_FOREACH(&day_items, i) {
89 p = VECTOR_NTH(&day_items, i);
90 if (p->order == sel_data.order &&
91 p->item.apt == sel_data.item.apt)
92 return i;
93 }
94 /* Needed as long as ui_day_item_paste() does not set order. */
95 VECTOR_FOREACH(&day_items, i) {
96 p = VECTOR_NTH(&day_items, i);
97 if (p->item.apt == sel_data.item.apt)
98 return i;
99 }
100 /* If still not found, stay on the same day. */
101 VECTOR_FOREACH(&day_items, i) {
102 p = VECTOR_NTH(&day_items, i);
103 if (p->order == update_time_in_date(sel_data.order, 0, 0))
104 return i;
105 }
106 return -1;
107 }
108
109 /*
110 * Return the number of days to load in the appointments panel.
111 */
112 int day_get_days(void)
113 {
114 int panel, day;
115
116 if (!conf.multiple_days)
117 return 1;
118
119 panel = win[APP].h - (conf.compact_panels ? 2 : 4);
120 /* Assume one event per day (no event separator). */
121 day = 2 + conf.header_line + conf.day_separator + conf.empty_appt_line;
122
123 if (panel <= day)
124 return 2;
125
126 /* Round up. */
127 return panel / day + (panel % day ? 1 : 0);
128 }
129
130 static void day_free(struct day_item *day)
131 {
132 mem_free(day);
133 }
134
135 static void day_init_vector(void)
136 {
137 day_items_nb = 0;
138 VECTOR_INIT(&day_items, 16);
139 }
140
141 /*
142 * Free the current day vector containing the events and appointments.
143 * Must not free associated message and note, because their are not dynamically
144 * allocated (only pointers to real objects are stored in this structure).
145 */
146 void day_free_vector(void)
147 {
148 VECTOR_FREE_INNER(&day_items, day_free);
149 VECTOR_FREE(&day_items);
150 }
151
152 static int day_cmp(struct day_item **pa, struct day_item **pb)
153 {
154 struct day_item *a = *pa;
155 struct day_item *b = *pb;
156 int a_state, b_state;
157
158 if (a->order < b->order)
159 return -1;
160 if (a->order > b->order)
161 return 1;
162
163 if ((a->type == APPT || a->type == RECUR_APPT) &&
164 (b->type == APPT || b->type == RECUR_APPT)) {
165 if (a->start < b->start)
166 return -1;
167 if (a->start > b->start)
168 return 1;
169
170 a_state = day_item_get_state(a);
171 b_state = day_item_get_state(b);
172 if ((a_state & APOINT_NOTIFY) && !(b_state & APOINT_NOTIFY))
173 return -1;
174 if (!(a_state & APOINT_NOTIFY) && (b_state & APOINT_NOTIFY))
175 return 1;
176
177 return strcmp(day_item_get_mesg(a), day_item_get_mesg(b));
178 } else if ((a->type == EVNT || a->type == RECUR_EVNT) &&
179 (b->type == EVNT || b->type == RECUR_EVNT)) {
180 return strcmp(day_item_get_mesg(a), day_item_get_mesg(b));
181 }
182
183 return a->type - b->type;
184 }
185
186 /* Add an item to the current day list. */
187 static void day_add_item(int type, time_t start, time_t order, union aptev_ptr item)
188 {
189 struct day_item *day = mem_malloc(sizeof(struct day_item));
190 day->type = type;
191 day->start = start;
192 day->order = order;
193 day->item = item;
194
195 VECTOR_ADD(&day_items, day);
196 }
197
198 /* Get the message of an item. */
199 char *day_item_get_mesg(struct day_item *day)
200 {
201 switch (day->type) {
202 case APPT:
203 return day->item.apt->mesg;
204 case EVNT:
205 return day->item.ev->mesg;
206 case RECUR_APPT:
207 return day->item.rapt->mesg;
208 case RECUR_EVNT:
209 return day->item.rev->mesg;
210 default:
211 return NULL;
212 }
213 }
214
215 /* Get the note attached to an item. */
216 char *day_item_get_note(struct day_item *day)
217 {
218 switch (day->type) {
219 case APPT:
220 return day->item.apt->note;
221 case EVNT:
222 return day->item.ev->note;
223 case RECUR_APPT:
224 return day->item.rapt->note;
225 case RECUR_EVNT:
226 return day->item.rev->note;
227 default:
228 return NULL;
229 }
230 }
231
232 /* Get the note attached to an item. */
233 void day_item_erase_note(struct day_item *day)
234 {
235 switch (day->type) {
236 case APPT:
237 erase_note(&day->item.apt->note);
238 break;
239 case EVNT:
240 erase_note(&day->item.ev->note);
241 break;
242 case RECUR_APPT:
243 erase_note(&day->item.rapt->note);
244 break;
245 case RECUR_EVNT:
246 erase_note(&day->item.rev->note);
247 break;
248 default:
249 break;
250 }
251 }
252
253 /* Get the duration of an item. */
254 long day_item_get_duration(struct day_item *day)
255 {
256 switch (day->type) {
257 case APPT:
258 return day->item.apt->dur;
259 case RECUR_APPT:
260 return day->item.rapt->dur;
261 default:
262 return 0;
263 }
264 }
265
266 /* Get the notification state of an item. */
267 int day_item_get_state(struct day_item *day)
268 {
269 switch (day->type) {
270 case APPT:
271 return day->item.apt->state;
272 case RECUR_APPT:
273 return day->item.rapt->state;
274 default:
275 return APOINT_NULL;
276 }
277 }
278
279 /* Add an exception to an item. */
280 void day_item_add_exc(struct day_item *day, time_t date)
281 {
282 switch (day->type) {
283 case RECUR_EVNT:
284 recur_event_add_exc(day->item.rev, date);
285 break;
286 case RECUR_APPT:
287 recur_apoint_add_exc(day->item.rapt, date);
288 break;
289 default:
290 break;
291 }
292 }
293
294 /* Clone the actual item. */
295 void day_item_fork(struct day_item *day_in, struct day_item *day_out)
296 {
297 day_out->type = day_in->type;
298 day_out->start = day_in->start;
299 day_out->order = day_in->order;
300
301 switch (day_in->type) {
302 case APPT:
303 day_out->item.apt = apoint_dup(day_in->item.apt);
304 break;
305 case EVNT:
306 day_out->item.ev = event_dup(day_in->item.ev);
307 break;
308 case RECUR_APPT:
309 day_out->item.rapt = recur_apoint_dup(day_in->item.rapt);
310 break;
311 case RECUR_EVNT:
312 day_out->item.rev = recur_event_dup(day_in->item.rev);
313 break;
314 default:
315 EXIT(_("unknown item type"));
316 /* NOTREACHED */
317 }
318 }
319
320 /*
321 * Store the events for the selected day in structure pointed
322 * by day_items. This is done by copying the events
323 * from the general structure pointed by eventlist to the structure
324 * dedicated to the selected day.
325 * Returns the number of events for the selected day.
326 */
327 static int day_store_events(time_t date)
328 {
329 llist_item_t *i;
330 union aptev_ptr p;
331 int e_nb = 0;
332
333 LLIST_FIND_FOREACH_CONT(&eventlist, &date, event_inday, i) {
334 struct event *ev = LLIST_TS_GET_DATA(i);
335
336 p.ev = ev;
337 day_add_item(EVNT, ev->day, ev->day, p);
338 e_nb++;
339 }
340
341 return e_nb;
342 }
343
344 /*
345 * Store the recurrent events for the selected day in structure pointed
346 * by day_items. This is done by copying the recurrent events
347 * from the general structure pointed by recur_elist to the structure
348 * dedicated to the selected day.
349 * Returns the number of recurrent events for the selected day.
350 */
351 static int day_store_recur_events(time_t date)
352 {
353 llist_item_t *i;
354 union aptev_ptr p;
355 int e_nb = 0;
356
357 LLIST_FIND_FOREACH(&recur_elist, &date, recur_event_inday, i) {
358 struct recur_event *rev = LLIST_TS_GET_DATA(i);
359
360 p.rev = rev;
361 time_t occurrence;
362 if (recur_event_find_occurrence(rev, date, &occurrence)) {
363 day_add_item(RECUR_EVNT, rev->day, occurrence, p);
364 e_nb++;
365 }
366 }
367
368 return e_nb;
369 }
370
371 /*
372 * Store the apoints for the selected day in structure pointed
373 * by day_items. This is done by copying the appointments
374 * from the general structure pointed by alist_p to the
375 * structure dedicated to the selected day.
376 * Returns the number of appointments for the selected day.
377 */
378 static int day_store_apoints(time_t date)
379 {
380 llist_item_t *i;
381 union aptev_ptr p;
382 int a_nb = 0;
383
384 LLIST_TS_LOCK(&alist_p);
385 LLIST_TS_FIND_FOREACH(&alist_p, &date, apoint_inday, i) {
386 struct apoint *apt = LLIST_TS_GET_DATA(i);
387
388 p.apt = apt;
389 /*
390 * For appointments continuing from the previous day, order is
391 * set to midnight to sort it before appointments of the day.
392 */
393 day_add_item(APPT,
394 apt->start,
395 apt->start < date ? date : apt->start,
396 p);
397 a_nb++;
398 }
399 LLIST_TS_UNLOCK(&alist_p);
400
401 return a_nb;
402 }
403
404 /*
405 * Store the recurrent apoints for the selected day in structure pointed
406 * by day_items. This is done by copying the appointments
407 * from the general structure pointed by recur_alist_p to the
408 * structure dedicated to the selected day.
409 * Returns the number of recurrent appointments for the selected day.
410 */
411 static int day_store_recur_apoints(time_t date)
412 {
413 llist_item_t *i;
414 union aptev_ptr p;
415 time_t occurrence;
416 int a_nb = 0;
417
418 LLIST_TS_LOCK(&recur_alist_p);
419 LLIST_TS_FIND_FOREACH(&recur_alist_p, &date, recur_apoint_inday, i) {
420 struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
421
422 p.rapt = rapt;
423 /* As for appointments */
424 if (recur_apoint_find_occurrence(rapt, date, &occurrence)) {
425 day_add_item(RECUR_APPT,
426 occurrence,
427 occurrence < date ? date : occurrence,
428 p);
429 a_nb++;
430 }
431 }
432 LLIST_TS_UNLOCK(&recur_alist_p);
433
434 return a_nb;
435 }
436
437 /*
438 * Store all of the items to be displayed for the selected day and the following
439 * (n - 1) days. Items are of four types: recursive events, normal events,
440 * recursive appointments and normal appointments.
441 * The items are stored in the day_items vector; the number of events and
442 * appointments in the vector is stored in day_items_nb,
443 */
444 void
445 day_store_items(time_t date, int include_captions, int n)
446 {
447 unsigned apts, events;
448 union aptev_ptr p = { NULL }, d;
449 int i;
450
451 day_free_vector();
452 day_init_vector();
453
454 for (i = 0; i < n; i++, date = NEXTDAY(date)) {
455 if (YEAR1902_2037 && !check_sec(&date))
456 break;
457
458 if (include_captions)
459 day_add_item(DAY_HEADING, 0, date, p);
460
461 events = day_store_recur_events(date);
462 events += day_store_events(date);
463 apts = day_store_recur_apoints(date);
464 apts += day_store_apoints(date);
465
466 if (include_captions && events > 0 && apts > 0)
467 day_add_item(EVNT_SEPARATOR, 0, date, p);
468
469 day_items_nb += events + apts;
470
471 if (include_captions && events == 0 && apts == 0) {
472 /* Insert dummy event. */
473 d.ev = &dummy;
474 dummy.mesg = _("(none)");
475 day_add_item(EVNT, DUMMY, date, d);
476 day_items_nb++;
477 }
478
479 if (include_captions) {
480 /* Empty line at end of day if appointments have one. */
481 if (apts == 0 && conf.empty_appt_line)
482 day_add_item(EMPTY_SEPARATOR, 0, ENDOFDAY(date), p);
483 day_add_item(END_SEPARATOR, 0, ENDOFDAY(date), p);
484 }
485 }
486
487 VECTOR_SORT(&day_items, day_cmp);
488 }
489
490 /*
491 * Print an item date in the appointment panel.
492 */
493 void
494 day_display_item_date(struct day_item *day, WINDOW *win, int incolor,
495 time_t date, int y, int x)
496 {
497 char a_st[100], a_end[100];
498 char ch_recur, ch_notify;
499
500 /* FIXME: Redesign apoint_sec2str() and remove the need for a temporary
501 * appointment item here. */
502 struct apoint apt_tmp;
503 apt_tmp.start = day->start;
504 apt_tmp.dur = day_item_get_duration(day);
505
506 apoint_sec2str(&apt_tmp, date, a_st, a_end);
507 if (incolor == 0)
508 custom_apply_attr(win, ATTR_HIGHEST);
509 ch_recur = (day->type == RECUR_EVNT ||
510 day->type == RECUR_APPT) ? '*' : '-';
511 ch_notify = (day_item_get_state(day) & APOINT_NOTIFY) ? '!' : ' ';
512 mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_notify, a_st);
513 if (apt_tmp.dur)
514 mvwprintw(win, y, x + 3 + strlen(a_st), " -> %s", a_end);
515 if (incolor == 0)
516 custom_remove_attr(win, ATTR_HIGHEST);
517 }
518
519 /*
520 * Print an item description in the corresponding panel window.
521 */
522 void
523 day_display_item(struct day_item *day, WINDOW *win, int incolor, int width,
524 int y, int x)
525 {
526 int ch_recur, ch_note;
527 char buf[width * UTF8_MAXLEN];
528
529 if (width <= 0)
530 return;
531
532 char *mesg = day_item_get_mesg(day);
533
534 ch_recur = (day->type == RECUR_EVNT) ? '*' : ' ';
535 ch_note = day_item_get_note(day) ? '>' : ' ';
536
537 strncpy(buf, mesg, width * UTF8_MAXLEN);
538 buf[sizeof(buf) - 1] = '\0';
539 utf8_chop(buf, width - 3);
540
541 if (!incolor)
542 custom_apply_attr(win, ATTR_HIGHEST);
543 mvwprintw(win, y, x, " %c%c%s", ch_recur, ch_note, buf);
544 if (!incolor)
545 custom_remove_attr(win, ATTR_HIGHEST);
546 }
547
548 /* Write the appointments and events for the selected day to stdout. */
549 void day_write_stdout(time_t date, const char *fmt_apt, const char *fmt_rapt,
550 const char *fmt_ev, const char *fmt_rev, int *limit)
551 {
552 int i;
553
554 VECTOR_FOREACH(&day_items, i) {
555 if (*limit == 0)
556 break;
557 struct day_item *day = VECTOR_NTH(&day_items, i);
558
559 switch (day->type) {
560 case APPT:
561 print_apoint(fmt_apt, date, day->item.apt);
562 break;
563 case EVNT:
564 print_event(fmt_ev, date, day->item.ev);
565 break;
566 case RECUR_APPT:
567 print_recur_apoint(fmt_rapt, date, day->start,
568 day->item.rapt);
569 break;
570 case RECUR_EVNT:
571 print_recur_event(fmt_rev, date, day->item.rev);
572 break;
573 default:
574 EXIT(_("unknown item type"));
575 /* NOTREACHED */
576 }
577 (*limit)--;
578 }
579 }
580
581 /* Display an item inside a popup window. */
582 void day_popup_item(struct day_item *day)
583 {
584 if (day->type == EVNT || day->type == RECUR_EVNT) {
585 item_in_popup(NULL, NULL, day_item_get_mesg(day),
586 _("Event:"));
587 } else if (day->type == APPT || day->type == RECUR_APPT) {
588 char a_st[100], a_end[100];
589
590 /* FIXME: Redesign apoint_sec2str() and remove the need for a temporary
591 * appointment item here. */
592 struct apoint apt_tmp;
593 apt_tmp.start = day->start;
594 apt_tmp.dur = day_item_get_duration(day);
595 apoint_sec2str(&apt_tmp, ui_day_sel_date(), a_st, a_end);
596 item_in_popup(a_st, a_end, day_item_get_mesg(day),
597 _("Appointment:"));
598 } else {
599 EXIT(_("unknown item type"));
600 /* NOTREACHED */
601 }
602 }
603
604 /*
605 * Check whether there is an item on a given day and return the colour
606 * attribute for the item:
607 * ATTR_TRUE if the selected day contains a regular event or appointment,
608 * ATTR_LOW if the selected day does not contain a regular event or
609 * appointment but an occurrence of a recurrent item. Returns 0 otherwise.
610 */
611 int day_check_if_item(struct date day)
612 {
613 const time_t t = date2sec(day, 0, 0);
614
615 if (LLIST_FIND_FIRST(&eventlist, (time_t *)&t, event_inday))
616 return ATTR_TRUE;
617
618 LLIST_TS_LOCK(&alist_p);
619 if (LLIST_TS_FIND_FIRST(&alist_p, (time_t *)&t, apoint_inday)) {
620 LLIST_TS_UNLOCK(&alist_p);
621 return ATTR_TRUE;
622 }
623 LLIST_TS_UNLOCK(&alist_p);
624
625 if (LLIST_FIND_FIRST(&recur_elist, (time_t *)&t, recur_event_inday))
626 return ATTR_LOW;
627
628 LLIST_TS_LOCK(&recur_alist_p);
629 if (LLIST_TS_FIND_FIRST(&recur_alist_p, (time_t *)&t,
630 recur_apoint_inday)) {
631 LLIST_TS_UNLOCK(&recur_alist_p);
632 return ATTR_LOW;
633 }
634 LLIST_TS_UNLOCK(&recur_alist_p);
635
636 return 0;
637 }
638
639 static unsigned fill_slices(int *slices, int slicesno, int first, int last)
640 {
641 int i;
642
643 if (first < 0 || last < first)
644 return 0;
645
646 if (last >= slicesno)
647 last = slicesno - 1; /* Appointment spanning more than one day. */
648
649 for (i = first; i <= last; i++)
650 slices[i] = 1;
651
652 return 1;
653 }
654
655 /*
656 * Fill in the 'slices' vector given as an argument with 1 if there is an
657 * appointment in the corresponding time slice, 0 otherwise.
658 * A 24 hours day is divided into 'slicesno' number of time slices.
659 */
660 unsigned day_chk_busy_slices(struct date day, int slicesno, int *slices)
661 {
662 const time_t t = date2sec(day, 0, 0);
663 llist_item_t *i;
664 int slicelen;
665
666 slicelen = DAYINSEC / slicesno;
667
668 #define SLICENUM(tsec) ((tsec) / slicelen % slicesno)
669
670 LLIST_TS_LOCK(&recur_alist_p);
671 LLIST_TS_FIND_FOREACH(&recur_alist_p, (time_t *)&t,
672 recur_apoint_inday, i) {
673 struct recur_apoint *rapt = LLIST_TS_GET_DATA(i);
674 time_t occurrence;
675 time_t start, end;
676
677 if (!recur_apoint_find_occurrence(rapt, t, &occurrence))
678 continue;
679
680 if (occurrence >= t)
681 start = get_item_time(occurrence);
682 else
683 start = 0;
684
685 if (occurrence + rapt->dur < t + DAYINSEC)
686 end = get_item_time(occurrence + rapt->dur);
687 else
688 end = DAYINSEC - 1;
689
690 /*
691 * If an item ends on 12:00, we do not want the 12:00 slot to
692 * be marked busy.
693 */
694 if (end > start)
695 end--;
696
697 if (!fill_slices(slices, slicesno, SLICENUM(start),
698 SLICENUM(end))) {
699 LLIST_TS_UNLOCK(&recur_alist_p);
700 return 0;
701 }
702 }
703 LLIST_TS_UNLOCK(&recur_alist_p);
704
705 LLIST_TS_LOCK(&alist_p);
706 LLIST_TS_FIND_FOREACH(&alist_p, (time_t *)&t, apoint_inday, i) {
707 struct apoint *apt = LLIST_TS_GET_DATA(i);
708 time_t start = get_item_time(apt->start);
709 time_t end = get_item_time(apt->start + apt->dur);
710
711 if (apt->start >= t + DAYINSEC)
712 break;
713 if (apt->start < t)
714 start = 0;
715 if (apt->start + apt->dur >= t + DAYINSEC)
716 end = DAYINSEC - 1;
717
718 /*
719 * If an item ends on 12:00, we do not want the 12:00 slot to
720 * be marked busy.
721 */
722 if (end > start)
723 end--;
724
725 if (!fill_slices(slices, slicesno, SLICENUM(start),
726 SLICENUM(end))) {
727 LLIST_TS_UNLOCK(&alist_p);
728 return 0;
729 }
730 }
731 LLIST_TS_UNLOCK(&alist_p);
732
733 #undef SLICENUM
734 return 1;
735 }
736
737 /* Cut an item so it can be pasted somewhere else later. */
738 struct day_item *day_cut_item(int item_number)
739 {
740 struct day_item *p = day_get_item(item_number);
741
742 switch (p->type) {
743 case EVNT:
744 event_delete(p->item.ev);
745 break;
746 case RECUR_EVNT:
747 recur_event_erase(p->item.rev);
748 break;
749 case APPT:
750 apoint_delete(p->item.apt);
751 break;
752 case RECUR_APPT:
753 recur_apoint_erase(p->item.rapt);
754 break;
755 default:
756 EXIT(_("unknown item type"));
757 /* NOTREACHED */
758 }
759
760 return p;
761 }
762
763 /* Paste a previously cut item. */
764 int day_paste_item(struct day_item *p, time_t date)
765 {
766 if (!p->type) {
767 /* No previously cut item. */
768 return 0;
769 }
770 /*
771 * Valid until date of recurrent items?
772 * Careful: p->start is not yet set.
773 */
774 time_t until;
775
776 switch (p->type) {
777 case EVNT:
778 event_paste_item(p->item.ev, date);
779 break;
780 case RECUR_EVNT:
781 /* want: until = shift + old_until */
782 if (p->item.rev->rpt->until &&
783 overflow_add(
784 date - p->item.rev->day,
785 p->item.rev->rpt->until,
786 &until)
787 )
788 return 0;
789 if (check_sec(&until))
790 recur_event_paste_item(p->item.rev, date);
791 else
792 return 0;
793 break;
794 case APPT:
795 apoint_paste_item(p->item.apt, date);
796 break;
797 case RECUR_APPT:
798 /* wanted: until = shift + old_until */
799 if (p->item.rapt->rpt->until &&
800 overflow_add(
801 date - update_time_in_date(p->item.rapt->start, 0, 0),
802 p->item.rapt->rpt->until,
803 &until)
804 )
805 return 0;
806 if (check_sec(&until))
807 recur_apoint_paste_item(p->item.rapt, date);
808 else
809 return 0;
810 break;
811 default:
812 EXIT(_("unknown item type"));
813 /* NOTREACHED */
814 }
815
816 return p->type;
817 }
818
819 /* Returns a structure containing the selected item. */
820 struct day_item *day_get_item(int item_number)
821 {
822 return VECTOR_NTH(&day_items, item_number);
823 }
824
825 unsigned day_item_count(int include_captions)
826 {
827 return (include_captions ? VECTOR_COUNT(&day_items) : day_items_nb);
828 }
829
830 /* Attach a note to an appointment or event. */
831 void day_edit_note(struct day_item *p, const char *editor)
832 {
833 char *note;
834
835 note = day_item_get_note(p);
836 edit_note(¬e, editor);
837
838 switch (p->type) {
839 case RECUR_EVNT:
840 p->item.rev->note = note;
841 break;
842 case EVNT:
843 p->item.ev->note = note;
844 break;
845 case RECUR_APPT:
846 p->item.rapt->note = note;
847 break;
848 case APPT:
849 p->item.apt->note = note;
850 break;
851 default:
852 break;
853 }
854 }
855
856 /* View a note previously attached to an appointment or event */
857 void day_view_note(struct day_item *p, const char *pager)
858 {
859 view_note(day_item_get_note(p), pager);
860 }
861
862 /* Switch notification state for an item. */
863 void day_item_switch_notify(struct day_item *p)
864 {
865 switch (p->type) {
866 case RECUR_APPT:
867 recur_apoint_switch_notify(p->item.rapt);
868 break;
869 case APPT:
870 apoint_switch_notify(p->item.apt);
871 break;
872 default:
873 break;
874 }
875 }