/*
-** path.c -- return a pathname
+** path.c -- return or convert paths
**
** This code is Copyright (c) 2002, by the authors of nmh. See the
** COPYRIGHT file in the root directory of the nmh distribution for
*/
#include <h/mh.h>
+#include <pwd.h>
-static char *pwds;
/*
-** static prototypes
+** Find the location of a format or configuration
+** file, and return its absolute pathname.
+**
+** 1) If it begins with ~user, then expand it.
+** 2) Next, if already absolute pathname, then leave unchanged.
+** 3) Next, check in mmh directory.
+** 4) Next, check in mmh `etc' directory.
+** 5) As fall-back, return `file' unchanged.
*/
-static char *expath(char *, int);
-static void packpath(char *);
-
-char *
-pluspath(char *name)
-{
- return path(name + 1, *name == '+' ? TFOLDER : TSUBCWF);
-}
-
char *
-path(char *name, int type)
+etcpath(char *file)
{
- char *cp, *ep;
-
- if ((cp = expath(name, type)) &&
- (ep = cp+strlen(cp)-1) > cp &&
- *ep == '/') {
- *ep = '\0';
- }
-
- return cp;
-}
-
+ static char epath[PATH_MAX];
+ char *cp;
+ char *pp;
+ struct passwd *pw;
-static char *
-expath(char *name, int type)
-{
- char *cp, *ep;
- char buffer[BUFSIZ];
-
- if (type == TSUBCWF) {
- /* @folder to +folder */
- snprintf(buffer, sizeof(buffer), "%s/%s", getfolder(1), name);
- name = m_mailpath(buffer);
- packpath(name);
- snprintf(buffer, sizeof(buffer), "%s/", m_maildir(""));
- if (isprefix(buffer, name)) {
- cp = name;
- name = getcpy(name + strlen(buffer));
- free(cp);
+ /* XXX: here was: ``context_read();'' -- why? */
+ if (*file == '~') {
+ /* Expand `~user' */
+ if ((cp = strchr(pp = file + 1, '/')))
+ *cp++ = '\0';
+ if (*pp == '\0') {
+ pp = mypath;
+ } else {
+ if ((pw = getpwnam(pp)))
+ pp = pw->pw_dir;
+ else {
+ if (cp)
+ *--cp = '/';
+ goto try_it;
+ }
}
- type = TFOLDER;
- }
- if (*name == '/') {
- return getcpy(name);
- }
-
- if (type == TFOLDER &&
- (strncmp(name, "./", 2) && strcmp(name, ".") &&
- strcmp(name, "..") && strncmp(name, "../", 3))) {
- /*
- ** FIXME: Seems as if this check does not catch names like:
- ** ``foo/../../..''.
- */
- return getcpy(name);
- }
+ snprintf(epath, sizeof epath, "%s/%s", pp, cp ? cp : "");
+ if (cp)
+ *--cp = '/';
- if (pwds == NULL) {
- pwds = pwd();
+ if (access(epath, R_OK) != NOTOK)
+ return epath; /* else fall */
}
- if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0) {
- return getcpy(pwds);
+try_it:
+ if (*file == '/') {
+ /* absolute pathname, return it */
+ return file;
}
- ep = pwds + strlen(pwds);
- if ((cp = strrchr(pwds, '/')) == NULL) {
- cp = ep;
- } else if (cp == pwds) {
- cp++;
- }
-
- if (strncmp(name, "./", 2) == 0) {
- name += 2;
- }
-
- if (strcmp(name, "..") == 0 || strcmp(name, "../") == 0) {
- snprintf(buffer, sizeof(buffer), "%.*s",
- (int)(cp - pwds), pwds);
- return getcpy(buffer);
- }
+ /* Check mmh directory */
+ snprintf(epath, sizeof epath, "%s/%s", mmhpath, file);
+ if (access(epath, R_OK) != NOTOK)
+ return epath;
- if (strncmp(name, "../", 3) == 0) {
- name += 3;
- } else {
- cp = ep;
- }
+ /* Check nmh `etc' directory */
+ snprintf(epath, sizeof epath, "%s/%s", mhetcdir, file);
+ if (access(epath, R_OK) != NOTOK)
+ return epath;
- snprintf(buffer, sizeof(buffer), "%.*s/%s",
- (int)(cp - pwds), pwds, name);
- return getcpy(buffer);
+ /* The fall-back */
+ return file;
}
/*
-** Compactify an absolute path name by removing unneccessary parts.
-** Removes trailing slashes, but not if it would empty the string then.
-** Modifies f.
+** Compactify a path name by removing unneccessary parts.
+** Removes trailing slashes. Cares to never remove all characters.
+** Modifies f (never enlarges it).
+**
+** FIXME: Cannot use strcpy() as the areas overlap!
*/
static void
packpath(char *f)
strcpy(f, abspath ? "/" : ".");
}
}
+
+
+
+
+/*
+** Get the default folder
+** Return the Inbox profile entry or, as fallback, the compile time default
+** Returns a pointer to the abs folpath
+*/
+char *
+getdeffol(void)
+{
+ char *folder = context_find(inbox);
+
+ if (!folder || !*folder) {
+ folder = defaultfolder; /* the compile time default */
+ }
+ if (*folder == '+') {
+ folder++;
+ }
+ return folder;
+}
+
+
+/*
+** Get the current folder
+** Return the Current-Folder context entry or, as fallback, the default folder
+** Returns a pointer to the abs folpath
+**
+** Equivalent to: expandfol("@")
+*/
+char *
+getcurfol(void)
+{
+ char *folder = context_find(curfolder);
+
+ if (!folder || !*folder) {
+ folder = getdeffol();
+ }
+ return folder;
+}
+
+
+/*
+** Expand folder path
+** Convert rel folpaths (@) into abs folpaths
+** dir paths are simply passed through
+** Returns the abs folpath (without prefix), in static mem
+**
+** TODO: Always copy into the static buffer, or just return the pointer?
+*/
+char *
+expandfol(char *f)
+{
+ static char buf[BUFSIZ];
+
+ if (*f == '@') {
+ /* f = concat(getcurfol(), "/", f+1, NULL); */
+ snprintf(buf, sizeof buf, "%s/%s", getcurfol(), f+1);
+
+ } else if (*f == '+') {
+ strcpy(buf, f+1);
+
+ } else {
+ strcpy(buf, f);
+ }
+ packpath(buf);
+ return buf;
+}
+
+
+/*
+** Expand directory path
+** Convert rel dirpath into abs dirpath
+** The argument is assumed to be a dir path relative to the cwd,
+** except when beginning with '/' (then it will be passed through).
+** Returns the abs dirpath, in static mem
+**
+** TODO: Always copy into the static buffer, or just return the pointer?
+*/
+char *
+expanddir(char *d)
+{
+ static char buf[BUFSIZ];
+ int len;
+
+ if (*d == '/') {
+ strcpy(buf, d);
+ } else {
+ getcwd(buf, sizeof buf);
+ len = strlen(buf);
+ snprintf(buf+len, sizeof buf - len, "/%s", d);
+ }
+ packpath(buf);
+ return buf;
+}
+
+
+/*
+** Anypath to absolute directory path
+** Convert any kind of path into an abs dirpath
+** A path without distinguishing prefix is assumed to be an abs folpath
+** Abs dirpaths are passed unchanged
+** Rel dirpaths ('.') get prefixed with the (abs) cwd
+** Return pointer to static memory
+**
+** To get the dir path of the mail storage root, call: toabsdir("+")
+**
+** TODO: check lengths for copies
+*/
+char *
+toabsdir(char *path)
+{
+ static char buf[BUFSIZ];
+
+ if (*path == '/') {
+ /* nothing to do */
+ strncpy(buf, path, sizeof buf);
+ packpath(buf);
+ return buf;
+
+ } else if (*path == '.') {
+ /* rel dir path */
+ strncpy(buf, expanddir(path), sizeof buf);
+ return buf;
+
+ } else {
+ /* folder path */
+ char *cp=buf, *pp;
+
+ if (!(pp = context_find("path")) || !*pp) {
+ adios(NULL, "Non-empty profile entry `Path' required");
+ }
+ if (*pp != '/') {
+ /* Path is relative to $HOME */
+ snprintf(buf, sizeof buf, "%s/", mypath);
+ cp += strlen(buf);
+ }
+ strcpy(cp, pp);
+ packpath(buf);
+ /* append the mail folder */
+ cp = buf + strlen(buf);
+ *cp++ = '/';
+ strcpy(cp, expandfol(path));
+ return buf;
+ }
+}