aboutsummaryrefslogtreecommitdiffstats
path: root/src/calcurse.h
Commit message (Collapse)AuthorAgeFilesLines
* User interface for recurrence rulesLars Henriksen2020-04-281-0/+12
| | | | | | | | | | | | | | | | | | | | | | | | The function update_rept() is extended with editing of the three recurrence rule lists for BYMONTH, BYMONTHDAY and BYDAY. The integers of the bymonth and bymonthday lists are edited directly as integers, while those of the bywday list are mapped to localized weekday names (as they appear in the calendar panel) with an optional integer prefix (in RFC5545 style: 1MO, -2SA). The RFC5545 (icalendar) requirement that the start day must be the first occurrence and must match the recurrence rule, is met by testing that an occurrence indeed appears on the start day, in these circumstances: - when a recurrent item is loaded from file - when the recurrence rule of an item is edited interactively - when a recurrent appointment gets a new start time - when a recurrent appointment is moved Copy and paste of a recurrent item will only retain the basic recurrence properties of type, frequency, until and exception days. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Recurrence rule extensionsLars Henriksen2020-04-281-0/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Terms and concepts are from RFC 5545 (the iCalendar specification). Overall design -------------- Calcurse is extended with full support for BYMONTH, BYDAY and BYMONTHDAY recurrence rule (rrule) parts. The three rule parts are lists of, respectively, months, weekdays and monthdays. The lists are added to 'struct rpt' as linked lists of integers, and the data file format is extended accordingly (details below). Load and save of the lists follow the pattern of the existing list of exception dates, also in 'struct rpt'. The function recur_item_find_occurence() is split into a front-end and a back-end. The back-end, called find_occurrence(), is the original function extended with rrule reductions; the front-end retains the original name and performs rrule expansions. Front-end plus back-end are backwards compatible and require no changes in calling functions. There is no user interface in this patch. Data file extensions -------------------- The BYMONTH, BYDAY and BYMONTHDAY lists are added to that part of an item line which describes the recurrence rule (the "{...}" part). Each list is - like the list of exception days - a space-separated string of values identified by the initial character. Each list is optional and, if present, must follow the until date and precede the exception day list. The lists must appear in order BYMONTHDAY list, BYDAY list and BYMONTH list. The possible list values are - BYMONTH: m1, m2, ..., m12 - BYDAY: w0, w1, ..., w6, w7, w-7, w8, w-8, ..., w377, w-377 - BYMONTHDAY: d1, d2, ..., d31, d-1, d-2, ..., d-31 which are interpreted as (cf. RFC 5545) - BYMONTH: January, February, ..., December. - BYDAY: SU, MO, ..., SA, +1SU, -1SU, +1MO, -1MO, ..., +53SA, -53SA - BYMONTHDAY: the first, the second, ..., the 31st, the last, the last but one, ..., the last but 30 day of the month Examples: Thursday, TH, is w4; Saturday, SA, is w6. The seventh Thursday, +7TH, is w53 (7 * 7 + 4 = 53); the last but second Saturday, -2SA, is w-20 (2 * 7 + 6 = 20); the last day of the month is d-1. Note that the values w-1, w-2, ..., w-6 are not used. A recurrent appointment with a BYDAY rule part: 06/23/2019 @ 12:00 -> 06/23/2019 @ 13:00 {1W w0 w6} |every week on Sunday and Saturday An event with a BYDAY and a BYMONTH rule part: 10/27/2019 [1] {1Y w-7 m10} every year on last Sunday in October An event with until date, a BYMONTH rule part and an exception day: 06/23/2019 [1] {1Y -> 08/31/2021 m5 m6 m7 !07/23/2020} every year on the 23rd in May, June and July for three years, starting on Sunday, 23 June 2019, but not on 23 July 2020. Recurrence set expansion and reduction --------------------------------------- In calcurse a recurrence rule is a quadruple (s, d, r, e) consisting of start, duration, repetition pattern and exception days and is implemented as: (time_t start, long dur, struct rpt *rpt, llist_t *exc) In RFC 5545 parlance, a recurrence rule defines a recurrence set consisting of all recurrence instances (occurrences) not earlier than start which match the rule pattern. With this concept in mind, recur_item_find_occurremce() may be thought of as a membership function for a recurrence set. The call recur_item_find_occurrence(s, d, r, e, day, occurrence) returns true if day belongs to the recurrence set of (s, d, r, e); if so occurrence points to the recurrence instance (the set member). For a recurrence rule with only the basic DAYLY, WEEKLY, MONTHLY or YEARLY type and frequency the recurrence set consists of periodically repeated instances. The BYxxx rule parts modify the recurrence set by reducing or expanding it as specified by RFC 5545. Expansion is implemented in the front-end by modifications of start and/or frequency of the rule (s, d, r, e), often several times, in such a way that the desired recurrence instances are included in the recurrence set. This is possible because the front-end as the very first thing checks for early days (day < s). When day is known not to be early, start (s) can safely be moved backwards. Likewise, if frequency must be changed, the front-end checks whether the frequency repetition applies to the week, month or year of day. Reduction is easier and is performed in the back-end along with the existing validity checks. It consists in checking whether month, day of month or weekday of a found occurrence is on the appropriate list. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Refactor edit of exception daysLars Henriksen2020-04-281-1/+3
| | | | | | | | | | | | | | | The patch contains no functional changes, but is a necessary precondition for extensions of update_rept() (in ui-day.c) with further recurrence rules. The reason is that recurrence parameters must be treated as a whole: if an edit session is cancelled at any point, no value should change, and all parameters should remain as they were. Hence, the new values must only be set after all of them have been determined. This was not the case for the list of exception days, but as long as it was treated last, it did not matter. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Improve data load error reportingLars Henriksen2020-04-281-4/+4
| | | | | | | | | | | The last part of loading appointments and events is performed by four "scan" functions called from io_load_app(). Failure in this part of data load does not use io_load_error(). The four "scan" functions are changed to return an error message on failure and NULL otherwise (the previous return value was not used). Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Refactor function calls: recurrence parameters as a single argumentLars Henriksen2020-04-281-28/+31
| | | | | | | | | | | | | | | | | | | | | The recurrence parameters are type, frequency, until date and exception list (in RFC 5545 parlance FREQ, INTERVAL, UNTIL and EXDATE's). When these are passed in a function call, the argument list becomes long and not very readable. When support for extended recurrence rules is implemented, the number of recurrence parameters increases, and function signatures must be amended. Solution: The "struct rpt" is extended with the exception list; any future recurrence parameters are added here. A pointer to this structure replaces the recurrence parameters in function calls. Note: Each recurrent event and appoinment instance has (a pointer to) a "struct rpt" and in addition an exception list. The latter is retained to avoid the derived changes, and the exception list in the structure is initialized to an empty list when the recurrent instance is created. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use "struct rpt" to shorten argument listsLars Henriksen2020-04-281-3/+3
| | | | | | | Also, prepare for extension of the structure, shorten names and rearrange comments. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Improve ical import loggingLars Henriksen2020-03-221-4/+4
| | | | | | | | | The log file is not deleted if items were skipped (adresses Github issue #269). The log file includes the import file name and time. The import line numbers have been corrected (and tests amended). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Update copyright rangesLukas Fleischer2020-01-301-1/+1
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Refactor cut and paste registersLars Henriksen2020-01-131-2/+6
| | | | | | | | | | Register REG_BLACK_HOLE can neither be copied into nor pasted from and has been removed from the input routine. Register 36 was not used. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add XDG Base Directory SupportNitroretro2019-12-231-1/+2
| | | | | | | | | | | * Use "$XDG_DATA_HOME/calcurse" for data files * Use "$XDG_CONFIG_HOME/calcurse" for config files * "$XDG_DATA_HOME" defaults to "$HOME/.local/share" * "$XDG_CONFIG_HOME" defaults to "$HOME/.config" * If "$HOME/.calcurse" exists, then it will be used instead for backward compatibility. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Make the text for empty days configurableLars Henriksen2019-11-031-0/+3
| | | | | | | The default is "--"; a single space makes the text invisible. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Treat recurrence item parameters as a unitLars Henriksen2019-06-161-1/+1
| | | | | | | | An edit session, and in particular, a cancelled edit session should encompass all parameters. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Fix sidebar width to accommodate calendar week columnLars Henriksen2019-05-281-1/+1
| | | | | Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Make separation of days conspicuousLars Henriksen2019-05-261-2/+4
| | | | | | | | | | | | | | | ... by adding a horizontal line from border to border above the day heading and turning the event separator into an empty line. The horizontal line is left out for the first day loaded. Also reduce the number of empty lines at the end of a day to at most one. A new configuration variable, header_line, turns the horizontal line on and off. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Derive selected day from selected itemLars Henriksen2019-05-221-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Previously, with only one day visible at a time, the appointments panel displayed the details of the day selected in the calendar (slctd_day); information required for operations on items (day_items) can often be derived from the selected day. The items available are derived from the selected day. In particular, the selected item is derived from the selected day. With multiple days in the APP panel, the relation between selected day (in the calendar) and the selected item (in the APP panel) has, in a way, been turned around. The selected item may now be moved between days without explicitly changing the selected day. Implicitly it is changed when the target day of a move is unavailable. This commit draws the full consequence: the selected day in the calendar is always (set to) the day of the selected item in the APP panel. The static variable 'struct date slctd_day' lives in ui_calendar.c and is accessible through various public functions. To these are added ui_calendar_set_slctd_day() which sets slctd_day directly. The selected day retains its significance for load of the day vector (in day_store_items()): the range of loaded days begins with the selected day. Movements (up/down) in the APP panel will change the selected day as the selected item moves among the already loaded days. Only when the target of a movement is unreachable, will further days be loaded. On the other hand, if the same range of days must be reloaded because of a changed item, the selected item - and with it the selected day - must be reset to the first day item (see do_storage()). Movements in the calendar (generic-next-day, etc.) are not affected and behave as previously, i.e. they will cause a range of days to be loaded with the selected day as the first and the selected item as the first of the selected day. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add configuration variables for multiple daysLars Henriksen2019-05-221-0/+3
| | | | | | | | | | | | | | | The number of days displayed in the APP panel has been made configurable, maximum 21 days, default seven days. With several days in the APP panel, it may be desirable to "squeeze" the entries by leaving out the final empty line of each appointment and lower the number of lines between consecutive days (0, 1, or 2). Both are made general configuration options. To make a uniform display, an empty line is added to a day without appointments, if appointments have an empty line. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add week numbers in the calendar and full first and last weekLars Henriksen2019-05-221-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | Much in the calendar is based on the selected day, struct date slctd_day, in ui-calendar.c. On the screen it is highlighted with a deviating colour. The highlight effect has been changed to a pair of red square brackets that do not obscure the day colour. The week number (in the frame) used to be that of the selected day, but has no obvious relation to the days in the APP panel. It has been replaced by the year day number of the selected day. The week numbers of all visible weeks are displayed to the left of the calendar. Dates are displayed also for the overlapping parts of the first and last week of the month (which do not belong to the month). Days are accessible in the appointments panel as well as in the calendar. Hence, validation of days (= inside UNIX time limits) must be extended from the calendar (in ui_calendar_move()) to include loaded days (in day_store_items()). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Implement scrolling in the appointments panelLars Henriksen2019-05-221-3/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | With multiple days in the APP panel, up/down movements should change behaviour at the top and bottom of the list displayed, and load the previous/next lot of days. This requires that the move function returns the result of the operation. Furthermore, the ability to move the selection to the beginning of a day is needed when moving down (in order to move from the first day to the last day). For this reason a DAY_SEPARATOR has been inserted also after the last day of a lot. Appointments have a listbox height of three to separate them clearly when there is more than one in a day. This leaves a spurious empty line at the end of a day with appointments. The DAY_SEPARATOR height is reduced from two to one, and a new EMPTY_SEPARATOR of height one is inserted in any day with only events. When scrolling up the DAY_HEADING becomes visible when the selection reaches the first item of the day. The length of the separator (between events and appointments) is adjusted to leave a space to the window border at both ends, thereby making it a part of the day, not a separation between days. The dummy event must also be recognisable when not the selected item and is only inserted in interactive mode. The test for a saved selection must also recognise caption items which have item pointer NULL. The function day_get_nb() has been renamed day_get_days(). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Redesign selected-item implementation for the APP panelLars Henriksen2019-05-221-6/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The day vector, day_items, is displayed in the appointments panel; the selected day_item object is highlighted (when the panel has the focus). When items are inserted, edited, moved etc., and when the day is changed, the day vector is rebuilt and displayed anew. Problem: How shall the selection be set automatically in the context of the new day vector? In previous versions all of the above is mostly handled by the function do_storage() in calcurse.c The function saves data about the selection as needed, rebuilds the day vector, loads the listbox and sets the selection from the saved selection data. This works well in "single day" calcurse in cases where the selected item is present in the day vector both before and after the rebuild, or when the item ordering in the listbox is unaffected by the changes. But when a new item is added the selection cannot be set to the new object by do_storage(). Instead the necessary operations are performed by ui_day_item_add(), and do_storage() is bypassed. In general, when an item cannot be found in the new vector, the item which occupies the old place in the list gets selected, e.g. when an item is deleted. When an item is turned into a repeating one, the old item is deleted and a new is created. Here the new selection is not always the affected item, but in any case not far away. Generally, with only one day in the panel an erronous selection might not be noticed or be accurate by chance. In "multiple day" calcurse the existing scheme works less well; in addition the day vector may now contain more than one object that refer to the same event or appointment (recurrent items or multi-day appointments). The scheme has therefore been modified. The do_storage() function is no longer bypassed, but handles day vector rebuild, load of listbox and item selection exclusively. To make that possible, data about the selected item is no longer saved in a local automatic variable, private to do_storage(), but in an external static variable in day.c, which may be set not only by do_storage(). The variable is declared as static struct day_item sel_data; and used as follows: 1. On startup sel_data is initialized to empty (i.e. no selection). 2. In any operation involving the appointments panel: 2.1 Do the work and if necessary set sel_data. This is the case when deleting, adding or pasting an item, and when turning an ordinary item into a recurrent one. 2.2 Call do_storage(). 3. In do_storage(): 3.1 If sel_data is empty, set it to the current selection. 3.2 Rebuild the day vector. 3.3 Set the selection from sel_data. 3.4 Set sel_data to empty. Further remarks --------------- The selection is found in the new day vector by searching for the saved (order, item.<pointer>) pair. Previously the item.<pointer> alone sufficed and in some cases it still does. In case the item cannot be found, the selection stays in the same day as before the rebuild. An attempt at more consistently named APP-related functions has led to: ui_day_sel_date() replaces ui_day_sel_day() ui_day_get_sel() replaces ui_day_selitem() Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Introduce multiple days in the appointments panelLars Henriksen2019-05-221-3/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Overview of existing implementation ----------------------------------- The APP panel displays the 'day_items' vector in the 'lb_apt' listbox. A listbox consists of a scrollwin (structure) in which a number of items is displayed. The listbox keeps track of: - the number of items - the selected item - the type of each item in an array type[] - the height of each item (ie. how many screen lines) in an array ch[] - how to display an item (on the screen) The latter three are handled by functions fn_type(), fn_height(), fn_draw(). The first two are used to fill in the corresponding array entry, type[] or ch[], for item number i, the third draws item number i. The items are taken from the global variables vector_t day_items int day_items_nb in day.c. Items include captions (DAY_HEADING, DAY_SEPARATOR). Everything is sorted for display (DAY_HEADING, events, DAY_SEPARATOR, appts). These are filled in ("stored") [by day_store_items() for the selected day in the calendar], before being "loaded" into the listbox. See do_storage() in calcurse.c and ui_day_item_add() in ui-day.c. New APP panel design -------------------- Several days are displayed in the APP panel by loading them with day_store_items(). With several days come several headings and separators. DAY_SEPARATOR is reinterpreted to separate days, and a new separator, EVNT_SEPARATOR, separates events from appointments. To sort everything, an 'order' member of type time_t is added to the day_item structure. It is set for headings and separators as well as for appointments and events as follows: item order --------------------- DAY_HEADING BGNOFDAY (= midnight) EVNT_SEPARATOR BGNOFDAY DAY_SEPARATOR ENDOFDAY event start time (midnight) appointment start time (first day) BGNOFDAY (following days, if any) The sort function day_cmp() (used by vector_sort) is extended to sort by order first. The order field always indicates the day to which an item belongs. This comes in handy, because with several days in the APP panel it is necessary to distinguish between the selected day in the calendar and the selected day in the APP panel. This raises the question which day should actions (commands) operate on: the one selected in the calendar or the one selected in the APP panel? Unquestionably the one on the APP panel which is the one tacitly implied. In most cases it is not a problem, though, because actions work on the selected item and the selected day does not come into play. But in some cases it does: delete item When deleting an occurrence of a repeated item, the selected day is the exception day to add. view item day_popup_item() needs the day of the selected item for display of correct start/end times. cut/paste item Paste needs the selected day in which to paste. add item The day of the new item is taken from the calendar. Instead a dummy event is inserted in an empty day. This makes the day selectable, which is otherwise impossible with only the DAY_HEADING displayed. The dummy event is selectable but cannot be edited or deleted (but viewed or piped). With more than one day in the day_items vecter, an appointment spanning more than one day may occur more than once in the vector (with start/end times suitably adjusted for display). A day_item is no longer (always) identified by the aptev_ptr (item) value. Instead the combination (order, item.<ptr>) is used; order is roughly the day. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Simplify day storageLars Henriksen2019-05-221-2/+1
| | | | | | | | | | | The function day_process_storage() is a wrapper for day_store_items(). It has an unused second argument, and is only used twice to load the selected day. It has been removed. A new function, get_slctd_day(), is the equivalant of get_today() and replaces the very awkwardly named ui_calendar_get_slctd_day_sec(). Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Refactor listbox codeLars Henriksen2019-05-221-4/+5
| | | | | | | | | | | | | | | | | | | | | | | | | The changes are related to the selected item and the visible lines in the scroll window viewport. In particular, the function listbox_fix_visible_region() has been eliminated, and functions previously only called by it have been removed. It performed several tasks that are now elsewhere. One was removed in an earlier commit (scroll window pad improvement). The task of making a multi-line item visible has been moved to listbox_item_in_view(). The task of making a caption line above a text line visible is listbox specific (for the ap_list) and will be moved to ui_day_sel_move(), where it is needed. Boundary checks for the listbox selection have been moved to listbox_fix_sel(). For future use listbox_sel_move() returns success or failure. The function wins_scrollwin_ensure_visible() has been renamed wins_scrollwin_in_view(). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Improve scroll window padLars Henriksen2019-05-221-3/+1
| | | | | | | | | | | | | | | | | | | A scroll window consists of a pad to write on, and a window through which to view the pad, the viewport. The pad may change in size when new contents are loaded into the scroll window. If so, the pad size is set with wins_scrollwin_set_linecount(). But the offset into the pad (the top line to be displayed in the viewport) is not adjusted, although it may not be appropriate for the new pad size. The same is the case when a scroll window is resized and the viewport changes size. This is probably the cause of the problem solved by commit 0b46ad4, Avoid blank space after the last list box item, and the fix has been removed. The wins_scrollwin_set_linecount() has been renamed wins_scrollwin_set_pad() and sets size as well as offset. The offset is only changed if necessary. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* View or edit exception days of a recurrent itemLars Henriksen2019-02-281-0/+2
| | | | | | | | | | | | The exception days are presented for viewing/editing as a string of space-separated dates (in the user-preferred input format). After editing the string is checked for valid dates, but there is no check that a date is meaningful (an occurrence day of the item between start day and until day). Although possible, it is best to add exception days in the usual way by deletion of occurrences. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use portable default day heading formatLukas Fleischer2019-02-101-1/+1
| | | | | | | | The %-d format string is not standards-compliant. Use %e instead. Reported-by: Mikolaj Kucharski <mikolaj@kucharski.name> Suggested-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Overflow check for 32-bit types onlyLars Henriksen2019-01-181-2/+2
| | | | | | | Included is a check of the 'until' date for pasted recurrent items. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use time_t for system time valuesLukas Fleischer2019-01-141-54/+54
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Fix next recurring appointmentLars Henriksen2019-01-111-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Recurring appointments do not show up in the notification bar as next appointment. This was partly corrected by 2084f35 (Fix notification of recurrent appointments, 2017-02-09) and 5aa7a09 (Fix another error in the notification code, 2017-02-11). The search function recur_apoint_starts_before() had a wrong second argument, but is really of no use: the start time of a recurring appointment is the start time of the very first occurrence (in the past). A comparison against the item in the notify_app structure tells nothing of the start time of the current day; at most it eliminates some future recurring appointments. The function can be dropped, and the entire recurring appointment list looked through. The proper start time is found in the main search loop (and called real_recur_start_time) and must be compared against the item in the notify_app structure. But because recur_apoint_find_occurrence() is limited to a particular day (second argument), two searches are necessary to cover 24 hours. Unrelated cleanups: removed function return value; changed long to time_t. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Explicit calendar and todo view configurationLars Henriksen2019-01-071-14/+17
| | | | | | | | | | | | | | | | | | | The configuration settings for calendar view (monthly/weekly) and todo view (hide/show completed) used to be saved automatically on calcurse exit, with values taken from the current interactive settings. They could not be set explicitly in the configuration menues. Configuration settings are no longer saved on program exit, but on exit from the configuration menu. This means that the saved values are those that were current when the configuration menu was entered. To change a saved value, you must set the view as desired and then enter/exit the configuration menu. The preferred calendar and todo views are no longer automatically taken from the interactive settings, but are explicitly set in the general options menu. Default values are monthly view and hide completed view. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Filter option: invertLars Henriksen2019-01-071-0/+1
| | | | | | | | | | | | | New filter option: --filter-invert. When present it inverts (negates) the other filter options combined. This is mostly useful with the -G option (with -Q the output is limited by the query range (day range)). The ouput from "calcurse -G <filter options>" is the (set) complement of "calcurse -G <filter options> --filter-invert". Here <filter options> may be any combination of filter options. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* CLI: Revert to and update of parse_datetimearg()Lars Henriksen2019-01-071-2/+5
| | | | | | | | | | | | | | | | | | | | | An earlier commit ("CLI: take input date format from configuration file, do not accept time") replaced parse_datetimearg() with parse_datearg() and eliminated time-of-day from command line date arguments. This made the full use of filter options impossible. That earlier commit is reverted and updated. The parse_datearg() function is replaced by an updated parse_datetimearg() function that - takes the date format from the configuration file - accepts date, date-time or time The updated parse_datetimearg() function has been extended to report back the type of the date string received in order to set (filter) options correctly. Input dates for query ranges (--from, --to, --days) are still limited to dates only. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Rewrite of io_init()Lars Henriksen2018-12-141-23/+13
| | | | | | | | | | | | | | The introduction of the "-C <confdir>" option is an opportunity to review the initialization of data paths. It lead to a rewrite. Two "root" directories are used (data and configuration files); by default they are identical. The statically allocated path buffers are turned into dynamically allocated buffers. Missing files/directories now include hooks. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* DST fix: daylength v. DAYINSECLars Henriksen2018-11-101-0/+6
| | | | | | | | | | | | | | | The number of seconds in a day and daylength in seconds differ when Daylight Saving Time is in effect on two days of the year. The day when DST takes effect is 23 hours long, and the day when DST ends is 25 hours long. In the latter case the date changing thread wóuld enter a loop in the last hour before midnight (in the former it would set the date an hour too late). The next midnight is calculated through mktime(), invoked by date2sec(). Wrong daylength prevented appointments from being stored in the day vector and caused them to be displayed wrongly in the appts panel. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Check if the configuration folder existsQuentin Hibon2018-10-211-0/+1
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Configuration variable for system eventsLars Henriksen2018-10-211-0/+1
| | | | | | | | After user acknowledgement a system event is deleted from the event queue. The configuration variable determines whether it is turned into an appointment (for later inspection) or not. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* System message queueLars Henriksen2018-10-211-0/+7
| | | | | | | | | | | | | | | The screen and user interaction is managed by the main thread. Other parts of calcurse (threads) wishing to use the screen or communicate with the user, must do it via the main thread. For this purpose the main input loop is extended with a message queue. A thread may insert a message in the queue. The main thread tests for messages before listening for user commands. If a message is present, it is displayed (in a popup window) for the user to acknowledge. Depending on the message other actions may be performed, e.g. the message could be turned into a "system appointment/event" and inserted among the usual appointments. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Remove the configuraton variable conf.progress_barLars Henriksen2018-10-211-1/+0
| | | | | | | | When loading/saving the configuration file the entry is silently ignored (which means it is removed by the first save). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Error return code for io_reload_data()Lars Henriksen2018-10-211-1/+2
| | | | | | | | The return code from new_data() and io_load_data() is explicitly defined as a bit mask. A file access error is recognised and reported back to the user. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Distinguish between interactive and periodic saveLars Henriksen2018-10-211-2/+6
| | | | | | | | | | A new argument to io_save_cal() makes it possible for the periodic save thread to avoid 1) user interaction and 2) overwriting new data. At the moment the thread has no way to report on the result of the save. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Data save and removal of the progress barLars Henriksen2018-10-211-8/+3
| | | | | | | | | | | | | | | | | The function io_save_cal() saves apts, todos, configuration data and key bindings. The configuration and key files do not belong with the two data files, but the progress bar function assumes that all four files are saved in a fixed sequence. Since it is used nowhere else and contains unused parts, the function has been removed. A return code for file access error is introduced, and the EXIT macro moved to the command level in calcurse.c. Save of configuration and key data were already moved to the configuration menu in commit 0124618, A save refinement: no action if everything is unchanged. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Move user information after save/reload to the command levelLars Henriksen2018-10-211-2/+12
| | | | | | | | | | | | | | | | | | | | | Moving user information to calcurse.c makes it easier to perform the actual save/reload operatons in io.c, e.g. it is possible to load instead of reload after a merge in conflict resolving. The save/reload operations are of such importance that the user should always be informed of the result (it's a bit disquieting when there is no reaction to a save or reload command). Hence, the save/reload status messages are no longer conditioned by show_dialogs(). No confirmation is asked for, so a message stays until the status bar is updated by another action. Care is taken to inform about save/reload actions that result in no change. Texts are kept concise because of the limited message area. When conflicts are present, whether saving or reloading, the "continue/merge/cancel" pattern seems easier to grasp. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Only reload if data files were changed (replacement)Lars Henriksen2018-10-211-1/+3
| | | | | | | | | | | | | | This is a replacement for commits 57dd3d6 and 912124b. The idea is to move the check for modified files and the list initialization into io_load_data(), and let io_load_data() decide what to load. A new argument is used to force a load. The return code from new_data() (the renamed version of io_check_data_files_modified()) tells which files have changed. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Reload data after resolving save conflict (improved)Lars Henriksen2018-10-211-1/+8
| | | | | | | | | | | | | | | After resolving a save conflict with the merge tool, a save operation has, in effect, occurred, and data files must be reloaded to import the result of the conflict resolution. This is a replacement for commit 2fe9c7e. The operations concerned with the user interface are kept out the io-operations (as in all other cases) and take place at the command-level in calcurse.c. and not at the io-level (io.c). Shorter, more concise prompt texts. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Start and end time validation.Lars Henriksen2018-08-251-3/+3
| | | | | | | | | | All appointment times are checked for validity. Overflow by time arithmetic is detected. End times are checked when appointments are moved. Three functions are involved: parse_datetime(), parse_duration() and parse_date_duration(); they all have a new argument for validation purposes. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* New support functions for input validation.Lars Henriksen2018-08-251-0/+3
| | | | | | check_sec(), overflow_add(), overflow_mul() Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Solve deadlock in notification barLars Henriksen2018-07-281-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | calcurse deadlocks when 1) an upcoming appointment is on display in the notification bar, 2) an external command (like help) is started, 3) the time for the upcoming appointment arrives, and 4) the external command is exited. The notification bar thread is stopped while the external command is running. Upon exit from the external command, the n-bar thread is restarted and calcurse locks. The cause is the way in which the main notification bar thread is stopped: static pthread_t notify_t_main; void notify_stop_main_thread(void) { if (notify_t_main) { pthread_cancel(notify_t_main); pthread_join(notify_t_main, NULL); } } Objects of type pthread_t are opaque and should not be accessed directly. Initially notify_t_main is an uninitialised static variable (0), but later it has a value, which may or may not be the thread id of the notification main thread. Note that the thread id after exit of a thread may become the thread id of a new thread. Thus the variable set when the thread is created, is invalid after exit of the thread. Specifically, the first time notify_stop_main_thread() is called (by notify_start_main_thread() before the thread is created) is harmless (because notify_t_main is 0). Calling notify_stop_main_thread() later may be either OK because the main thread is running, or harmless because no thread with id notify_t_main is running: the two functions will fail with return value ESRCH (no such process), or fatal because an unrelated thread with this thread id is running: it will be cancelled, and the join may or may not succeed depending on whether the thread is joinable or detached. The "unrelated thread" could be the next-appointment thread, notify_thread_app, launched by notify_check_next_app(). Always calling notify_stop_main_thread() before starting the main thread becomes fatal when notify_check_next_app() is called shortly before notify_start_main_thread(). This is the case in the scenario described. The next-app-thread is then running when notify_stop_main_thread() is called, and apparently it has the thread id of the old main thread (confirmed by logging the return values from pthread_cancel() and pthread_join(); the first succeeds while the second fails with EINVALID which means that the thread is not joinable). The next-app-thread will therefore exit without unlocking mutexes. Ensure that notify_t_main, in case the notify main thread is not running, has a value that it will never have when it is running. A possibility is the thread id of the main() calcurse process (returned by pthread_self()). Check for this condition in notify_stop_main_thread() and set notify_t_main when the thread is stopped. Similar changes have been introduced for the periodic save thread and the calendar date thread. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Key bindings for UTF-8 encoded charactersLars Henriksen2018-06-031-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Internally characters (keys) have two representations: integers and key names. Key names are characters strings, usually the name of the character; e.g., the character A has the representations 65 and "A", and the tab character the representations 9 and "TAB". The function keys_int2str() turns the integer representation of a key/character into the key name. For display purposes the key names are usually confined to have display width at most three. Some curses pseudo-keys have longer key names; e.g., the back-tab character is "KEY_BTAB". A long key name makes a character difficult to recognize in the status bar menu. The key name of a multibyte, UTF-8 encoded character is the conventional Unicode name of the code point; e.g., the character ü has key name "U+00FC" because ü is the code point 0xFC. Most of these look alike in the status bar menu. The patch makes the key name of a multibyte character look like that of a singlebyte character: the character itself, i.e. the key name of the character ü is "ü". The main tool is implementation of a utf8_encode() routine. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Rename utf8_ord() to utf8_decode()Lars Henriksen2018-06-031-1/+1
| | | | | | | Purely for readability and in preparation for the counterpart utf8_encode(). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add option to specify the configuration file usedQuentin Hibon2018-05-281-1/+1
| | | | | | | | | The configuration file (~/.calcurse/conf by default) can now be specified with -C or --conf. Workaround for GitHub issue #86. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Scrollbar and right window border (corrected)Lars Henriksen2018-05-261-3/+6
| | | | | | | | | | | | | | | | | When a scrollbar is on display in APP or TOD windows, the right vertical border (outside the scrollbar) is not highlighted when the window is selected. The scrollbar is always highlighted: - when APP or TOD is deselected - in configuration windows where borders otherwise are not The patch moves the scrollbar parameters (except highlight) from arguments of draw_scrollbar() to the function itself. The highlight argument was 1; instead it is set higher in the call hierarchy (wins_update_panels()) and passed on down. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>