summaryrefslogtreecommitdiffstats
path: root/src/io.c
Commit message (Collapse)AuthorAgeFilesLines
* Introduce macro DAYLars Henriksen2020-12-191-4/+4
| | | | | | | DAY(t) is midnight (the day) of time_t t. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Do not remove an empty note file after edit sessionLars Henriksen2020-11-151-16/+0
| | | | | Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Return failure if import skips any itemLars Henriksen2020-11-071-4/+7
| | | | | | | | | Other items may have been imported succesfully. Adresses Github issue #323, last part. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use dynamically allocated string in struct io_fileLukas Fleischer2020-10-111-1/+2
| | | | | | Avoid using fixed-size buffers and strncpy(). Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Improve event text for cancelled periodic saveLars Henriksen2020-07-261-1/+2
| | | | | Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Remove systemdialogs option from configurationLars Henriksen2020-06-131-18/+3
| | | | | | | | | The option controls the welcome window and the export/import result messages. The former is dropped. The latter are now always displayed unless calcurse is invoked with the "quiet" option (-q). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Recurrence rule extensionsLars Henriksen2020-04-281-1/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Improve data load error reportingLars Henriksen2020-04-281-10/+13
| | | | | | | | | | | 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-57/+42
| | | | | | | | | | | | | | | | | | | | | 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>
* Improve ical import loggingLars Henriksen2020-03-221-12/+13
| | | | | | | | | 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>
* Optimize error handling in io_check_dir()Nitroretro2019-12-291-12/+13
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Change documentation to reflect the new file structureNitroretro2019-12-231-3/+8
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add XDG Base Directory SupportNitroretro2019-12-231-8/+35
| | | | | | | | | | | * 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 io_check_dir() create parent directoriesNitroretro2019-12-231-5/+27
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Fix save of interactively imported dataLars Henriksen2019-11-031-0/+4
| | | | | | Adresses Github issue #249. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Close stream after exporting iCal itemcrvs2019-02-041-0/+1
| | | | | | Fixes GitHub issue #178. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Filter option: invertLars Henriksen2019-01-071-25/+21
| | | | | | | | | | | | | 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>
* Rewrite of io_init()Lars Henriksen2018-12-141-62/+33
| | | | | | | | | | | | | | 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>
* Fix default paths for configuration filesLukas Fleischer2018-11-101-3/+3
| | | | | | | Addresses a copy-paste typo introduced in commit 65064ce (Check if the configuration folder exists, 2018-08-25). Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Check if the configuration folder existsQuentin Hibon2018-10-211-10/+18
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Periodic save: report cancelled saveLars Henriksen2018-10-211-1/+3
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Error return code for io_reload_data()Lars Henriksen2018-10-211-8/+16
| | | | | | | | 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>
* New save/load mutex strategyLars Henriksen2018-10-211-39/+28
| | | | | | | | | | | | | | | | | | | | | | | A complete save or reload operation is made up of several cooperating lower level function calls. In stead of protecting the lower level read or write calls on the data files, the entire save or load operation is protected in order to ensure its integrity. Thus mutex protection has been moved from the level: io_load_data(), io_merge_data(), new_data(), to two functions at the higher level: io_save_cal(), io_reload_data(). The protection includes pre- and post-hooks. The function io_load_data() needs no protection when calcurse starts up (threads not yet started) or runs in non-interactive mode (no threads involved). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Periodic save mutexLars Henriksen2018-10-211-2/+6
| | | | | | | To protect the periodic save from being cancelled during a save operation. 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-4/+8
| | | | | | | | | | 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-117/+19
| | | | | | | | | | | | | | | | | 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-34/+26
| | | | | | | | | | | | | | | | | | | | | 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>
* A save refinement: no action if everything is unchangedLars Henriksen2018-10-211-2/+6
| | | | | | | | | | | | | A reload action will do nothing if in-memory data as well as data files are unchanged. This commit accomplishes the equivalent for a save action. Because saving of configuration data and key bindings are mixed up with saving of data files, any changes in those will only be saved if data files also have changed. Hence, configuration data and key bindings are also saved upon exit from the configuration menu. 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-36/+59
| | | | | | | | | | | | | | 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-29/+36
| | | | | | | | | | | | | | | 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>
* Handling of modified flagLars Henriksen2018-10-211-2/+2
| | | | | | | | | | The flag modified (io.c) keeps track of the memory state of data: modified == 0: unchanged since load or last save modified == 1: changed since load or last save It is now unset in io_load_data() and io_save_cal() only. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Update windows at the right levelLars Henriksen2018-10-211-1/+1
| | | | | | | | The wins_update() call is the responsibility of the caller of io_resolve_save_conflict(). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Stop/start the notify main thread at the right levelLars Henriksen2018-10-211-7/+0
| | | | | | | | | | | | | | | | | | | The thread is stopped/started in wins_prepare/unprepare_external() when hooks are run. There is no need to do it in io_reload_data(). In fact, because of the nested calls notify_stop_main_thread() <--- io_reload_data() ... notify_stop_main_thread() <--- hook/wins_prepare_external() ... notify_start_main_thread() <--- hook/wins_unprepare_external() ... notify_start_main_thread() <--- io_reload_data() the thread has been running after the first hook anyway. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Fix window update after hook executionLars Henriksen2018-10-211-11/+0
| | | | | | | | | | | | | | | | | | | | The introduction of hooks raised a problem with window updates. The diagnosis in commit feb059e8 (Fix segmentation fault on reload with pre-load hook) was right, the cure was wrong. The problem is wins_update(), not the listbox contents. The wins_update() call does not belong in wins_unprepare_external() (or in io_reload_data()), but at a higher level. It should be called _after_ reload, as indeed it is in key_generic_reload() when the listbox contents have been updated (todo as well as appointments). The call was introduced in commit 8ae75f3 without comment. The todo updates in io_reload_data() also belong in key_generic_reload() where they were before commit 7f06c252. When saving data, all panels must be updated in case a hook was executed. Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use a path instead of a file for -C optionQuentin Hibon2018-08-051-19/+22
| | | | | | | | | | | | Allows to specify a configuration directory containing: * conf * keys * hooks When used in combination with -D $ddir, $ddir contains all the other files not mentioned above. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Solve deadlock in notification barLars Henriksen2018-07-281-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* Only lock save mutex as short as possibleLukas Fleischer2018-06-031-3/+1
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Add option to specify the configuration file usedQuentin Hibon2018-05-281-3/+10
| | | | | | | | | 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>
* Always NUL-terminate buffer in io_load_keys()Lukas Fleischer2018-05-261-0/+1
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Run pre-load hook before testing for modificationsLukas Fleischer2018-05-231-2/+4
| | | | | | | | | | | The pre-load hook is often used to manipulate the data files before loading, such as by synchronizing with a remote calendar. Make sure we always execute the pre-load hook upon reloads, even if the data files have not been modified. Fixes GitHub issue #98. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Unlock the save mutex as early as possibleLukas Fleischer2018-05-191-4/+5
| | | | Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Do not prompt when non-interactive import failsLukas Fleischer2017-11-231-17/+11
| | | | | | | | | | When running calcurse in non-interactive mode, we should not expect any user input. This is even more important in the case of iCal imports which are used by calcurse-caldav to import events from CalDAV servers. Partly fixes GitHub issue #73. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Reload data after resolving save conflictLukas Fleischer2017-09-081-1/+10
| | | | | | | After resolving a save conflict with the merge tool, we need to reload the data files to import the result of the conflict resolution. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Unset modification flag after mergingLukas Fleischer2017-09-081-0/+2
| | | | | | | Turn off the local modification flag to avoid a bogus warning when reloading the data files immediately after the merge process. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Recompute hashes after savingLukas Fleischer2017-09-081-0/+3
| | | | | | | After saving the data files, we need to recompute and store the hashes to make sure the updated contents is reflected. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Factor out hash computationLukas Fleischer2017-09-081-7/+14
| | | | | | Move code to compute the hash of a data file to a separate function. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Use a shared input/output mutexLukas Fleischer2017-09-081-14/+23
| | | | | | | | | Replace the save mutex with a common mutex, which is locked whenever read or write operations on the data files are performed. Also, since this mutex is an implementation detail, mark the locking functions static and remove them from the header file. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Only reload if data files were changedLukas Fleischer2017-09-081-1/+8
| | | | | | | | Instead of blindly reloading data in io_reload_data(), compare the stored hashes of the data files with hashes of the current file contents and only reload if any of the hashes differs. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
* Factor out check for external modificationsLukas Fleischer2017-09-081-15/+20
| | | | | | | | Move the check to compare the stored hashes of the data files with the current hash to a separate function. This makes the code easier to read and reusable. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>