l2md: use XDG compliant paths for config file and work dir

Change the default locations of the config file and the work directory.
Prefered config file is taken from ~/${XDG_CONFIG_HOME}/config
('.config' as fallback for XDG_CONFIG_HOME), the old default location
~/.l2mdconfig is used as fallback.

To avoid breakage of old setups, use ~/.l2md/ as default base directory
iff it exists. Otherwise, use ~/${XDG_DATA_HOME}/l2md/.

Signed-off-by: Nicolas Schier <nicolas@fjasle.eu>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
diff --git a/README b/README
index e6ce997..a845a53 100644
--- a/README
+++ b/README
@@ -33,7 +33,7 @@
 $ make
 [...]
 
-After setting up ~/.l2mdconfig (see below), run as:
+After setting up ~/.config/l2md/config (see below), run as:
 
 $ ./l2md
 
@@ -65,7 +65,8 @@
 l2mdconfig.maildir and l2mdconfig.procmail. As the name says, the former
 is for exporting new mails in maildir format directly, and the latter is
 one example where l2md pipes new mails via stdin to an external MDA like
-procmail. Copy the one of your choice into ~/.l2mdconfig to get started.
+procmail. Copy the one of your choice either into ~/.config/l2md/config or
+~/.l2mdconfig to get started.
 
 Troubleshooting
 ---------------
@@ -85,19 +86,19 @@
 ----------------
 
 The l2mdconfig.maildir is an example l2md config which needs to be placed
-under ~/.l2mdconfig . The muttrc is an example config to get started for
-reading the maildir content.
+under ~/.config/l2md/config. The muttrc is an example config to get started
+for reading the maildir content.
 
-$ cat ~/.l2mdconfig
+$ cat ~/.config/l2md/config
 [general]
-	maildir = ~/.l2md/maildir/common
+	base = ~/.local/share/l2md/
+	maildir = ~/.local/share/l2md/maildir/common
 	period = 30
-	base = ~/.l2md/
 
 # bpf@vger.kernel.org list
 [repo bpf]
 	url = https://lore.kernel.org/bpf/0
-	maildir = ~/.l2md/maildir/bpf
+	maildir = ~/.local/share/l2md/maildir/bpf
 
 # netdev@vger.kernel.org list
 [repo netdev]
@@ -110,10 +111,12 @@
 maildirs. The maildir under general is a path to a shared maildir where
 l2md exports new mails into. This can also be specified on a per repository
 basis. Specifying the maildir under general is optional. It will default
-to ~/.l2md/maildir or <base-path>/maildir if the base deviates from the
-default one. Specifying base is optional as well. This is the working dir
-of l2md where it places its git repos and other meta data for record keeping.
-The default is at ~/.l2md/.
+to ~/.config/l2md/maildir or <base-path>/maildir if the base deviates from
+the default one. Specifying base is optional as well. This is the working
+dir of l2md where it places its git repos and other meta data for record
+keeping. The default is at ~/.local/share/l2md/. To not break configs based
+on the previous default base: Iff the base directory is not explicitly
+specified and ~/.l2md/ exists, it will be used instead.
 
 The repo sections with subsequent name define a repository (duh!) with
 one or more git urls to lore and optional maildir export path as mentioned.
@@ -124,15 +127,15 @@
 -----------------
 
 The l2mdconfig.procmail is an example l2md config which needs to be placed
-under ~/.l2mdconfig . The procmailrc is an example config to get started
-with a basic config for procmail. The provided muttrc can also be used here
-in order to get started for reading the maildir content preprocessed via
-procmail (the folder needs to point to procmail's MAILDIR of course). Other
-MDAs should work as well, but not tested at this point.
+under ~/.config/l2md/config . The procmailrc is an example config to get
+started with a basic config for procmail. The provided muttrc can also be
+used here in order to get started for reading the maildir content preprocessed
+via procmail (the folder needs to point to procmail's MAILDIR of course).
+Other MDAs should work as well, but not tested at this point.
 
-$ cat ~/.l2mdconfig
+$ cat ~/.config/l2md/config
 [general]
-	base = ~/.l2md/
+	base = ~/.local/share/l2md/
 	pipe = /usr/bin/procmail
 	period = 30
 
diff --git a/config.c b/config.c
index e48baf8..0aadf35 100644
--- a/config.c
+++ b/config.c
@@ -154,12 +154,27 @@
 
 static void config_set_defaults(struct config *cfg, const char *homedir)
 {
-	char path[PATH_MAX];
+	char default_data_dir[PATH_MAX];
+	char *data_dir;
 
 	cfg->general.period = 60;
 
-	slprintf(path, sizeof(path), "%s/.l2md", homedir);
-	strlcpy(cfg->general.base, path, sizeof(cfg->general.base));
+	/* Default base is ~/.l2md/ if it exists, otherwise
+	 * ~/${XDG_DATA_HOME}/l2md/. Fallback for empty XDG_DATA_DIR is
+	 * ~/.local/share/.
+	 */
+	slprintf(default_data_dir, sizeof(default_data_dir), "%s/.l2md",
+		 homedir);
+	if (access(default_data_dir, F_OK) >= 0)
+		data_dir = default_data_dir;
+	else if (!(data_dir = getenv("XDG_DATA_HOME"))) {
+		slprintf(default_data_dir, sizeof(default_data_dir),
+			 "%s/.local/share/l2md", homedir);
+		data_dir = default_data_dir;
+	}
+
+	verbose("Using base dir %s\n", default_data_dir);
+	strlcpy(cfg->general.base, data_dir, sizeof(cfg->general.base));
 
 	config_set_ops(cfg, &ops_maildir);
 	cfg->ops->set_defaults(cfg);
@@ -201,11 +216,54 @@
 	xfree(cfg);
 }
 
+static FILE *config_open(const char *homedir)
+{
+	struct dirinfo {
+		const char *env;
+		const char *suffix;
+		const char *fallback;
+		bool prefix_home_to_fallback;
+	};
+	struct dirinfo dirinfo[] = {
+		{ "XDG_CONFIG_HOME", "l2md/config", ".config", true, },
+		{ "HOME", ".l2mdconfig", },
+		{ },
+	};
+	struct dirinfo *cur;
+	char path[PATH_MAX];
+	FILE *fp;
+
+	for (cur = dirinfo; cur->suffix; cur++) {
+		char *env = getenv(cur->env);
+
+		if (env)
+			slprintf(path, sizeof(path), "%s/%s", env,
+				 cur->suffix);
+		else if (cur->fallback) {
+			if (cur->prefix_home_to_fallback)
+				slprintf(path, sizeof(path), "%s/%s/%s",
+					 homedir, cur->fallback, cur->suffix);
+			else
+				slprintf(path, sizeof(path), "%s/%s",
+					 cur->fallback, cur->suffix);
+		}
+
+		verbose("Attempting to open config file %s\n", path);
+		fp = fopen(path, "r");
+		if (fp)
+			return fp;
+		if (errno != ENOENT)
+			panic("Cannot open config %s: %s\n", path, strerror(errno));
+	}
+
+	return panic("Unable to find config. Please check l2md README.\n"),
+	       NULL;
+}
+
 struct config *config_init(int argc, char **argv)
 {
 	const char *homedir = getenv("HOME");
 	char buff[1024], tmp[1024] = {};
-	char path[PATH_MAX];
 	bool seen[STATE_MAX] = {};
 	int state = STATE_NONE;
 	struct config *cfg;
@@ -222,10 +280,7 @@
 	if (!homedir)
 		panic("Cannot retrieve $HOME from env!\n");
 
-	slprintf(path, sizeof(path), "%s/.l2mdconfig", homedir);
-	fp = fopen(path, "r");
-	if (!fp)
-		panic("Cannot open config %s: %s\n", path, strerror(errno));
+	fp = config_open(homedir);
 
 	config_ulimits();