If *record* is set, avoid writing dead content twice..
[s-mailx.git] / macro.c
blob741343b80f7f7b78257f48428350ed1c9872fa12
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 2004
8 * Gunnar Ritter. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Gunnar Ritter
21 * and his contributors.
22 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #ifndef lint
40 #ifdef DOSCCS
41 static char sccsid[] = "@(#)macro.c 1.13 (gritter) 3/4/06";
42 #endif
43 #endif /* not lint */
45 #include "config.h"
47 #include "rcv.h"
48 #include "extern.h"
51 * Mail -- a mail program
53 * Macros.
56 #define MAPRIME 29
58 struct line {
59 struct line *l_next;
60 char *l_line;
61 size_t l_linesize;
64 struct macro {
65 struct macro *ma_next;
66 char *ma_name;
67 struct line *ma_contents;
68 enum maflags {
69 MA_NOFLAGS,
70 MA_ACCOUNT
71 } ma_flags;
74 static struct macro *macros[MAPRIME];
75 static struct macro *accounts[MAPRIME];
77 #define mahash(cp) (pjw(cp) % MAPRIME)
78 static void undef1(const char *name, struct macro **table);
79 static int maexec(struct macro *mp);
80 static int closingangle(const char *cp);
81 static struct macro *malook(const char *name, struct macro *data,
82 struct macro **table);
83 static void freelines(struct line *lp);
84 static void list0(FILE *fp, struct line *lp);
85 static int list1(FILE *fp, struct macro **table);
87 int
88 cdefine(void *v)
90 char **args = v;
92 if (args[0] == NULL) {
93 fprintf(stderr, "Missing macro name to define.\n");
94 return 1;
96 if (args[1] == NULL || strcmp(args[1], "{") || args[2] != NULL) {
97 fprintf(stderr, "Syntax is: define <name> {\n");
98 return 1;
100 return define1(args[0], 0);
103 int
104 define1(const char *name, int account)
106 struct macro *mp;
107 struct line *lp, *lst = NULL, *lnd = NULL;
108 char *linebuf = NULL;
109 size_t linesize = 0;
110 int n;
111 mp = scalloc(1, sizeof *mp);
112 mp->ma_name = sstrdup(name);
113 if (account)
114 mp->ma_flags |= MA_ACCOUNT;
115 for (;;) {
116 n = 0;
117 for (;;) {
118 n = readline_restart(input, &linebuf, &linesize, n);
119 if (n < 0)
120 break;
121 if (n == 0 || linebuf[n-1] != '\\')
122 break;
123 linebuf[n-1] = '\n';
125 if (n < 0) {
126 fprintf(stderr, "Unterminated %s definition: \"%s\".\n",
127 account ? "account" : "macro",
128 mp->ma_name);
129 if (sourcing)
130 unstack();
131 free(mp->ma_name);
132 free(mp);
133 return 1;
135 if (closingangle(linebuf))
136 break;
137 lp = scalloc(1, sizeof *lp);
138 lp->l_linesize = n+1;
139 lp->l_line = smalloc(lp->l_linesize);
140 memcpy(lp->l_line, linebuf, lp->l_linesize);
141 lp->l_line[n] = '\0';
142 if (lst && lnd) {
143 lnd->l_next = lp;
144 lnd = lp;
145 } else
146 lst = lnd = lp;
148 mp->ma_contents = lst;
149 if (malook(mp->ma_name, mp, account ? accounts : macros) != NULL) {
150 if (!account) {
151 fprintf(stderr,
152 "A macro named \"%s\" already exists.\n",
153 mp->ma_name);
154 freelines(mp->ma_contents);
155 free(mp->ma_name);
156 free(mp);
157 return 1;
159 undef1(mp->ma_name, accounts);
160 malook(mp->ma_name, mp, accounts);
162 return 0;
165 int
166 cundef(void *v)
168 char **args = v;
170 if (*args == NULL) {
171 fprintf(stderr, "Missing macro name to undef.\n");
172 return 1;
175 undef1(*args, macros);
176 while (*++args);
177 return 0;
180 static void
181 undef1(const char *name, struct macro **table)
183 struct macro *mp;
185 if ((mp = malook(name, NULL, table)) != NULL) {
186 freelines(mp->ma_contents);
187 free(mp->ma_name);
188 mp->ma_name = NULL;
192 int
193 ccall(void *v)
195 char **args = v;
196 struct macro *mp;
198 if (args[0] == NULL || args[1] != NULL && args[2] != NULL) {
199 fprintf(stderr, "Syntax is: call <name>\n");
200 return 1;
202 if ((mp = malook(*args, NULL, macros)) == NULL) {
203 fprintf(stderr, "Undefined macro called: \"%s\"\n", *args);
204 return 1;
206 return maexec(mp);
209 int
210 callaccount(const char *name)
212 struct macro *mp;
214 if ((mp = malook(name, NULL, accounts)) == NULL)
215 return CBAD;
216 return maexec(mp);
219 int
220 callhook(const char *name, int newmail)
222 struct macro *mp;
223 char *var, *cp;
224 int len, r;
226 var = ac_alloc(len = strlen(name) + 13);
227 snprintf(var, len, "folder-hook-%s", name);
228 if ((cp = value(var)) == NULL && (cp = value("folder-hook")) == NULL)
229 return 0;
230 if ((mp = malook(cp, NULL, macros)) == NULL) {
231 fprintf(stderr, "Cannot call hook for folder \"%s\": "
232 "Macro \"%s\" does not exist.\n",
233 name, cp);
234 return 1;
236 inhook = newmail ? 3 : 1;
237 r = maexec(mp);
238 inhook = 0;
239 return r;
242 static int
243 maexec(struct macro *mp)
245 struct line *lp;
246 const char *sp;
247 char *copy, *cp;
248 int r = 0;
250 unset_allow_undefined = 1;
251 for (lp = mp->ma_contents; lp; lp = lp->l_next) {
252 sp = lp->l_line;
253 while (sp < &lp->l_line[lp->l_linesize] &&
254 (blankchar(*sp&0377) || *sp == '\n' ||
255 *sp == '\0'))
256 sp++;
257 if (sp == &lp->l_line[lp->l_linesize])
258 continue;
259 cp = copy = smalloc(lp->l_linesize + (lp->l_line - sp));
261 *cp++ = *sp != '\n' ? *sp : ' ';
262 while (++sp < &lp->l_line[lp->l_linesize]);
263 r = execute(copy, 0, lp->l_linesize);
264 free(copy);
266 unset_allow_undefined = 0;
267 return r;
270 static int
271 closingangle(const char *cp)
273 while (spacechar(*cp&0377))
274 cp++;
275 if (*cp++ != '}')
276 return 0;
277 while (spacechar(*cp&0377))
278 cp++;
279 return *cp == '\0';
282 static struct macro *
283 malook(const char *name, struct macro *data, struct macro **table)
285 struct macro *mp;
286 unsigned h;
288 mp = table[h = mahash(name)];
289 while (mp != NULL) {
290 if (mp->ma_name && strcmp(mp->ma_name, name) == 0)
291 break;
292 mp = mp->ma_next;
294 if (data) {
295 if (mp != NULL)
296 return mp;
297 data->ma_next = table[h];
298 table[h] = data;
300 return mp;
303 static void
304 freelines(struct line *lp)
306 struct line *lq = NULL;
308 while (lp) {
309 free(lp->l_line);
310 free(lq);
311 lq = lp;
312 lp = lp->l_next;
314 free(lq);
318 listaccounts(FILE *fp)
320 return list1(fp, accounts);
323 static void
324 list0(FILE *fp, struct line *lp)
326 const char *sp;
327 int c;
329 for (sp = lp->l_line; sp < &lp->l_line[lp->l_linesize]; sp++) {
330 if ((c = *sp&0377) != '\0') {
331 if ((c = *sp&0377) == '\n')
332 putc('\\', fp);
333 putc(c, fp);
336 putc('\n', fp);
339 static int
340 list1(FILE *fp, struct macro **table)
342 struct macro **mp, *mq;
343 struct line *lp;
344 int mc = 0;
346 for (mp = table; mp < &table[MAPRIME]; mp++)
347 for (mq = *mp; mq; mq = mq->ma_next)
348 if (mq->ma_name) {
349 if (mc++)
350 fputc('\n', fp);
351 fprintf(fp, "%s %s {\n",
352 table == accounts ?
353 "account" : "define",
354 mq->ma_name);
355 for (lp = mq->ma_contents; lp; lp = lp->l_next)
356 list0(fp, lp);
357 fputs("}\n", fp);
359 return mc;
362 /*ARGSUSED*/
363 int
364 cdefines(void *v)
366 FILE *fp;
367 char *cp;
368 int mc;
370 if ((fp = Ftemp(&cp, "Ra", "w+", 0600, 1)) == NULL) {
371 perror("tmpfile");
372 return 1;
374 rm(cp);
375 Ftfree(&cp);
376 mc = list1(fp, macros);
377 if (mc)
378 try_pager(fp);
379 Fclose(fp);
380 return 0;
383 void
384 delaccount(const char *name)
386 undef1(name, accounts);