"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(&note, 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 }