X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=sbr%2Fpath.c;h=f95a758fe35fae162c3c8ed0a8d2115614b8f8ff;hp=0ae27d39e1dcafb23e93a933d929dcc0b7ae7dc7;hb=cf1205b5cbea2f0cd6ea710ec16c637df85b647c;hpb=6c42153ad9362cc676ea66563bf400d7511b3b68 diff --git a/sbr/path.c b/sbr/path.c index 0ae27d3..f95a758 100644 --- a/sbr/path.c +++ b/sbr/path.c @@ -1,165 +1,304 @@ - /* - * path.c -- return a pathname - * - * $Id$ - * - * This code is Copyright (c) 2002, by the authors of nmh. See the - * COPYRIGHT file in the root directory of the nmh distribution for - * complete copyright information. - */ +** 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 +** complete copyright information. +*/ +#include #include +#include +#include + + +/* +** 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. +*/ +char * +etcpath(char *file) +{ + static char epath[PATH_MAX]; + char *cp; + char *pp; + struct passwd *pw; + + /* 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; + } + } + + snprintf(epath, sizeof epath, "%s/%s", pp, cp ? cp : ""); + if (cp) + *--cp = '/'; + + if (access(epath, R_OK) != NOTOK) + return epath; /* else fall */ + } + +try_it: + if (*file == '/') { + /* absolute pathname, return it */ + return file; + } + + /* Check mmh directory */ + snprintf(epath, sizeof epath, "%s/%s", mmhpath, file); + if (access(epath, R_OK) != NOTOK) + return epath; + + /* Check nmh `etc' directory */ + snprintf(epath, sizeof epath, "%s/%s", mhetcdir, file); + if (access(epath, R_OK) != NOTOK) + return epath; + + /* The fall-back */ + return file; +} + + +/* +** 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) +{ + char *cp, *dp; + int abspath; + + if (!f || !*f) { + return; + } + abspath = (*f == '/'); + + for (cp=f; *cp; ) { + if (*cp != '/') { + /* Skip. Interesting places are only after slashes. */ + /* We don't care about "./" beginnings */ + cp++; + continue; + } + + /* Let's see what follows the slash ... */ + switch (*++cp) { + case '\0': + *--cp = '\0'; + continue; /* ... and thus exit the loop */ + + case '/': + /* reduce subsequent slashes to one */ + for (dp = cp; *dp == '/'; dp++) { + continue; + } + strcpy(cp, dp); + cp--; + continue; /* ... at the slash */ + + case '.': + if (cp[1] == '/' || cp[1] == '\0') { + /* one-dot element */ + strcpy(cp-1, cp+1); + cp--; + continue; + } else if ((strncmp(cp, "../", 3) == 0) || + (strcmp(cp, "..") == 0)) { + /* dot-dot element */ + /* crop out previous path element */ + for (dp=cp-2; dp>f && *dp!='/'; dp--) { + continue; + } + if (dp < f) { + /* path starts with "/.." */ + dp = f; + } + strcpy(dp, cp+2); + cp = dp; + continue; + } else { + /* a normal hidden file */ + cp++; + continue; + } + + default: + /* nothing special */ + cp++; + continue; + } + } -#define CWD "./" -#define NCWD (sizeof(CWD) - 1) -#define DOT "." -#define DOTDOT ".." -#define PWD "../" -#define NPWD (sizeof(PWD) - 1) + if (!strlen(f)) { + /* We have removed everything, but need something. */ + 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; +} -static char *pwds; /* - * static prototypes - */ -static char *expath(char *,int); -static void compath(char *); +** 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 * -path(char *name, int flag) +expandfol(char *f) { - register char *cp, *ep; + static char buf[BUFSIZ]; + + if (*f == '@') { + /* f = concat(getcurfol(), "/", f+1, NULL); */ + snprintf(buf, sizeof buf, "%s/%s", getcurfol(), f+1); - if ((cp = expath (name, flag)) - && (ep = cp + strlen (cp) - 1) > cp - && *ep == '/') - *ep = '\0'; + } else if (*f == '+') { + strcpy(buf, f+1); - return cp; + } else { + strcpy(buf, f); + } + packpath(buf); + return buf; } -static char * -expath (char *name, int flag) +/* +** 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) { - register char *cp, *ep; - char buffer[BUFSIZ]; - - if (flag == TSUBCWF) { - snprintf (buffer, sizeof(buffer), "%s/%s", getfolder (1), name); - name = m_mailpath (buffer); - compath (name); - snprintf (buffer, sizeof(buffer), "%s/", m_maildir ("")); - if (ssequal (buffer, name)) { - cp = name; - name = getcpy (name + strlen (buffer)); - free (cp); + 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); } - flag = TFOLDER; - } - - if (*name == '/' - || (flag == TFOLDER - && (strncmp (name, CWD, NCWD) - && strcmp (name, DOT) - && strcmp (name, DOTDOT) - && strncmp (name, PWD, NPWD)))) - return getcpy (name); - - if (pwds == NULL) - pwds = pwd (); - - if (strcmp (name, DOT) == 0 || strcmp (name, CWD) == 0) - return getcpy (pwds); - - ep = pwds + strlen (pwds); - if ((cp = strrchr(pwds, '/')) == NULL) - cp = ep; - else - if (cp == pwds) - cp++; - - if (strncmp (name, CWD, NCWD) == 0) - name += NCWD; - - if (strcmp (name, DOTDOT) == 0 || strcmp (name, PWD) == 0) { - snprintf (buffer, sizeof(buffer), "%.*s", cp - pwds, pwds); - return getcpy (buffer); - } - - if (strncmp (name, PWD, NPWD) == 0) - name += NPWD; - else - cp = ep; - - snprintf (buffer, sizeof(buffer), "%.*s/%s", cp - pwds, pwds, name); - return getcpy (buffer); + packpath(buf); + return buf; } -static void -compath (char *f) +/* +** 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) { - register char *cp, *dp; + static char buf[BUFSIZ]; - if (*f != '/') - return; + if (*path == '/') { + /* nothing to do */ + strncpy(buf, path, sizeof buf); + packpath(buf); + return buf; - for (cp = f; *cp;) - if (*cp == '/') { - switch (*++cp) { - case 0: - if (--cp > f) - *cp = '\0'; - break; + } else if (*path == '.') { + /* rel dir path */ + strncpy(buf, expanddir(path), sizeof buf); + return buf; - case '/': - for (dp = cp; *dp == '/'; dp++) - continue; - strcpy (cp--, dp); - continue; - - case '.': - if (strcmp (cp, DOT) == 0) { - if (cp > f + 1) - cp--; - *cp = '\0'; - break; - } - if (strcmp (cp, DOTDOT) == 0) { - for (cp -= 2; cp > f; cp--) - if (*cp == '/') - break; - if (cp <= f) - cp = f + 1; - *cp = '\0'; - break; - } - if (strncmp (cp, PWD, NPWD) == 0) { - for (dp = cp - 2; dp > f; dp--) - if (*dp == '/') - break; - if (dp <= f) - dp = f; - strcpy (dp, cp + NPWD - 1); - cp = dp; - continue; - } - if (strncmp (cp, CWD, NCWD) == 0) { - strcpy (cp - 1, cp + NCWD - 1); - cp--; - continue; - } - continue; - - default: - cp++; - continue; - } - break; + } else { + /* folder path */ + char *cp=buf, *pp; + + if (!(pp = context_find("path")) || !*pp) { + adios(EX_CONFIG, 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; } - else - cp++; }