41328964660c8e3504803d710351b33f8688640c
[mmh] / sbr / path.c
1 /*
2 ** path.c -- return or convert paths
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10
11
12 /*
13 **  Compactify a path name by removing unneccessary parts.
14 **  Removes trailing slashes. Cares to never remove all characters.
15 **  Modifies f (never enlarges it).
16 **
17 **  FIXME: Cannot use strcpy() as the areas overlap!
18 */
19 static void
20 packpath(char *f)
21 {
22         char *cp, *dp;
23         int abspath;
24
25         if (!f || !*f) {
26                 return;
27         }
28         abspath = (*f == '/');
29
30         for (cp=f; *cp; ) {
31                 if (*cp != '/') {
32                         /* Skip. Interesting places are only after slashes. */
33                         /* We don't care about "./" beginnings */
34                         cp++;
35                         continue;
36                 }
37
38                 /* Let's see what follows the slash ... */
39                 switch (*++cp) {
40                 case '\0':
41                         *--cp = '\0';
42                         continue;  /* ... and thus exit the loop */
43
44                 case '/':
45                         /* reduce subsequent slashes to one */
46                         for (dp = cp; *dp == '/'; dp++) {
47                                 continue;
48                         }
49                         strcpy(cp, dp);
50                         cp--;
51                         continue;  /* ... at the slash */
52
53                 case '.':
54                         if (cp[1] == '/' || cp[1] == '\0') {
55                                 /* one-dot element */
56                                 strcpy(cp-1, cp+1);
57                                 cp--;
58                                 continue;
59                         } else if ((strncmp(cp, "../", 3) == 0) ||
60                                         (strcmp(cp, "..") == 0)) {
61                                 /* dot-dot element */
62                                 /* crop out previous path element */
63                                 for (dp=cp-2; dp>f && *dp!='/'; dp--) {
64                                         continue;
65                                 }
66                                 if (dp < f) {
67                                         /* path starts with "/.." */
68                                         dp = f;
69                                 }
70                                 strcpy(dp, cp+2);
71                                 cp = dp;
72                                 continue;
73                         } else {
74                                 /* a normal hidden file */
75                                 cp++;
76                                 continue;
77                         }
78
79                 default:
80                         /* nothing special */
81                         cp++;
82                         continue;
83                 }
84         }
85
86         if (!strlen(f)) {
87                 /* We have removed everything, but need something. */
88                 strcpy(f, abspath ? "/" : ".");
89         }
90 }
91
92
93
94
95 /*
96 **  Get the default folder
97 **  Return the Inbox profile entry or, as fallback, the compile time default
98 **  Returns a pointer to the abs folpath
99 */
100 char *
101 getdeffol(void)
102 {
103         char *folder = context_find(inbox);
104
105         if (!folder || !*folder) {
106                 folder = defaultfolder;  /* the compile time default */
107         }
108         if (*folder == '+') {
109                 folder++;
110         }
111         return folder;
112 }
113
114
115 /*
116 **  Get the current folder
117 **  Return the Current-Folder context entry or, as fallback, the default folder
118 **  Returns a pointer to the abs folpath
119 **
120 **  Equivalent to: expandfol("@")
121 */
122 char *
123 getcurfol(void)
124 {
125         char *folder = context_find(pfolder);
126
127         if (!folder || !*folder) {
128                 folder = getdeffol();
129         }
130         return folder;
131 }
132
133
134 /*
135 **  Expand folder path
136 **  Convert rel folpaths (@) into abs folpaths
137 **  dir paths are simply passed through
138 **  Returns the abs folpath (without prefix), in static mem
139 **
140 **  TODO: Always copy into the static buffer, or just return the pointer?
141 */
142 char *
143 expandfol(char *f)
144 {
145         static char buf[BUFSIZ];
146
147         if (*f == '@') {
148                 /* f = concat(getcurfol(), "/", f+1, NULL); */
149                 snprintf(buf, sizeof buf, "%s/%s", getcurfol(), f+1);
150
151         } else if (*f == '+') {
152                 strcpy(buf, f+1);
153
154         } else {
155                 strcpy(buf, f);
156         }
157         packpath(buf);
158         return buf;
159 }
160
161
162 /*
163 **  Expand directory path
164 **  Convert rel dirpath into abs dirpath
165 **  The argument is assumed to be a dir path relative to the cwd,
166 **  except when beginning with '/' (then it will be passed through).
167 **  Returns the abs dirpath, in static mem
168 **
169 **  TODO: Always copy into the static buffer, or just return the pointer?
170 */
171 char *
172 expanddir(char *d)
173 {
174         static char buf[BUFSIZ];
175
176         if (*d == '/') {
177                 strcpy(buf, d);
178         } else {
179                 getcwd(buf, sizeof buf);
180                 int len = strlen(buf);
181                 snprintf(buf+len, sizeof buf - len, "/%s", d);
182         }
183         packpath(buf);
184         return buf;
185 }
186
187
188 /*
189 **  Anypath to absolute directory path
190 **  Convert any kind of path into an abs dirpath
191 **  A path without distinguishing prefix is assumed to be an abs folpath
192 **  Abs dirpaths are passed unchanged
193 **  Rel dirpaths ('.') get prefixed with the (abs) cwd
194 **  Return pointer to static memory
195 **
196 **  To get the dir path of the mail storage root, call: toabsdir("+")
197 **
198 **  TODO: check lengths for copies
199 */
200 char *
201 toabsdir(char *path)
202 {
203         static char buf[BUFSIZ];
204
205         if (*path == '/') {
206                 /* nothing to do */
207                 strncpy(buf, path, sizeof buf);
208                 packpath(buf);
209                 return buf;
210
211         } else if (*path == '.') {
212                 /* rel dir path */
213                 strncpy(buf, expanddir(path), sizeof buf);
214                 return buf;
215
216         } else {
217                 /* folder path */
218                 char *cp=buf, *pp;
219
220                 if (!(pp = context_find("path")) || !*pp) {
221                         adios(NULL, "Non-empty profile entry `Path' required");
222                 }
223                 if (*pp != '/') {
224                         /* Path is relative to $HOME */
225                         snprintf(buf, sizeof buf, "%s/", mypath);
226                         cp += strlen(buf);
227                 }
228                 strcpy(cp, pp);
229                 packpath(buf);
230                 /* append the mail folder */
231                 cp = buf + strlen(buf);
232                 *cp++ = '/';
233                 strcpy(cp, expandfol(path));
234                 return buf;
235         }
236 }