Isolate iconv(3) usage in a single place..
[s-mailx.git] / macro.c
blobe4c9f8b40dd05256c2a37e6a9d1efd7ed2bc337c
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
6 */
7 /*
8 * Copyright (c) 2004
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #ifndef lint
41 #ifdef DOSCCS
42 static char sccsid[] = "@(#)macro.c 1.13 (gritter) 3/4/06";
43 #endif
44 #endif /* not lint */
46 #include "config.h"
48 #include "rcv.h"
49 #include "extern.h"
52 * Mail -- a mail program
54 * Macros.
57 #define MAPRIME 29
59 struct line {
60 struct line *l_next;
61 char *l_line;
62 size_t l_linesize;
65 struct macro {
66 struct macro *ma_next;
67 char *ma_name;
68 struct line *ma_contents;
69 enum maflags {
70 MA_NOFLAGS,
71 MA_ACCOUNT
72 } ma_flags;
75 static struct macro *macros[MAPRIME];
76 static struct macro *accounts[MAPRIME];
78 #define mahash(cp) (pjw(cp) % MAPRIME)
79 static void undef1(const char *name, struct macro **table);
80 static int maexec(struct macro *mp);
81 static int closingangle(const char *cp);
82 static struct macro *malook(const char *name, struct macro *data,
83 struct macro **table);
84 static void freelines(struct line *lp);
85 static void list0(FILE *fp, struct line *lp);
86 static int list1(FILE *fp, struct macro **table);
88 int
89 cdefine(void *v)
91 char **args = v;
93 if (args[0] == NULL) {
94 fprintf(stderr, "Missing macro name to define.\n");
95 return 1;
97 if (args[1] == NULL || strcmp(args[1], "{") || args[2] != NULL) {
98 fprintf(stderr, "Syntax is: define <name> {\n");
99 return 1;
101 return define1(args[0], 0);
104 int
105 define1(const char *name, int account)
107 struct macro *mp;
108 struct line *lp, *lst = NULL, *lnd = NULL;
109 char *linebuf = NULL;
110 size_t linesize = 0;
111 int n;
112 mp = scalloc(1, sizeof *mp);
113 mp->ma_name = sstrdup(name);
114 if (account)
115 mp->ma_flags |= MA_ACCOUNT;
116 for (;;) {
117 n = 0;
118 for (;;) {
119 n = readline_restart(input, &linebuf, &linesize, n);
120 if (n < 0)
121 break;
122 if (n == 0 || linebuf[n-1] != '\\')
123 break;
124 linebuf[n-1] = '\n';
126 if (n < 0) {
127 fprintf(stderr, "Unterminated %s definition: \"%s\".\n",
128 account ? "account" : "macro",
129 mp->ma_name);
130 if (sourcing)
131 unstack();
132 free(mp->ma_name);
133 free(mp);
134 return 1;
136 if (closingangle(linebuf))
137 break;
138 lp = scalloc(1, sizeof *lp);
139 lp->l_linesize = n+1;
140 lp->l_line = smalloc(lp->l_linesize);
141 memcpy(lp->l_line, linebuf, lp->l_linesize);
142 lp->l_line[n] = '\0';
143 if (lst && lnd) {
144 lnd->l_next = lp;
145 lnd = lp;
146 } else
147 lst = lnd = lp;
149 mp->ma_contents = lst;
150 if (malook(mp->ma_name, mp, account ? accounts : macros) != NULL) {
151 if (!account) {
152 fprintf(stderr,
153 "A macro named \"%s\" already exists.\n",
154 mp->ma_name);
155 freelines(mp->ma_contents);
156 free(mp->ma_name);
157 free(mp);
158 return 1;
160 undef1(mp->ma_name, accounts);
161 malook(mp->ma_name, mp, accounts);
163 return 0;
166 int
167 cundef(void *v)
169 char **args = v;
171 if (*args == NULL) {
172 fprintf(stderr, "Missing macro name to undef.\n");
173 return 1;
176 undef1(*args, macros);
177 while (*++args);
178 return 0;
181 static void
182 undef1(const char *name, struct macro **table)
184 struct macro *mp;
186 if ((mp = malook(name, NULL, table)) != NULL) {
187 freelines(mp->ma_contents);
188 free(mp->ma_name);
189 mp->ma_name = NULL;
193 int
194 ccall(void *v)
196 char **args = v;
197 struct macro *mp;
199 if (args[0] == NULL || (args[1] != NULL && args[2] != NULL)) {
200 fprintf(stderr, "Syntax is: call <name>\n");
201 return 1;
203 if ((mp = malook(*args, NULL, macros)) == NULL) {
204 fprintf(stderr, "Undefined macro called: \"%s\"\n", *args);
205 return 1;
207 return maexec(mp);
210 int
211 callaccount(const char *name)
213 struct macro *mp;
215 if ((mp = malook(name, NULL, accounts)) == NULL)
216 return CBAD;
217 return maexec(mp);
220 int
221 callhook(const char *name, int newmail)
223 struct macro *mp;
224 char *var, *cp;
225 int len, r;
227 var = ac_alloc(len = strlen(name) + 13);
228 snprintf(var, len, "folder-hook-%s", name);
229 if ((cp = value(var)) == NULL && (cp = value("folder-hook")) == NULL)
230 return 0;
231 if ((mp = malook(cp, NULL, macros)) == NULL) {
232 fprintf(stderr, "Cannot call hook for folder \"%s\": "
233 "Macro \"%s\" does not exist.\n",
234 name, cp);
235 return 1;
237 inhook = newmail ? 3 : 1;
238 r = maexec(mp);
239 inhook = 0;
240 return r;
243 static int
244 maexec(struct macro *mp)
246 struct line *lp;
247 const char *sp;
248 char *copy, *cp;
249 int r = 0;
251 unset_allow_undefined = 1;
252 for (lp = mp->ma_contents; lp; lp = lp->l_next) {
253 sp = lp->l_line;
254 while (sp < &lp->l_line[lp->l_linesize] &&
255 (blankchar(*sp&0377) || *sp == '\n' ||
256 *sp == '\0'))
257 sp++;
258 if (sp == &lp->l_line[lp->l_linesize])
259 continue;
260 cp = copy = smalloc(lp->l_linesize + (lp->l_line - sp));
262 *cp++ = *sp != '\n' ? *sp : ' ';
263 while (++sp < &lp->l_line[lp->l_linesize]);
264 r = execute(copy, 0, lp->l_linesize);
265 free(copy);
267 unset_allow_undefined = 0;
268 return r;
271 static int
272 closingangle(const char *cp)
274 while (spacechar(*cp&0377))
275 cp++;
276 if (*cp++ != '}')
277 return 0;
278 while (spacechar(*cp&0377))
279 cp++;
280 return *cp == '\0';
283 static struct macro *
284 malook(const char *name, struct macro *data, struct macro **table)
286 struct macro *mp;
287 unsigned h;
289 mp = table[h = mahash(name)];
290 while (mp != NULL) {
291 if (mp->ma_name && strcmp(mp->ma_name, name) == 0)
292 break;
293 mp = mp->ma_next;
295 if (data) {
296 if (mp != NULL)
297 return mp;
298 data->ma_next = table[h];
299 table[h] = data;
301 return mp;
304 static void
305 freelines(struct line *lp)
307 struct line *lq = NULL;
309 while (lp) {
310 free(lp->l_line);
311 free(lq);
312 lq = lp;
313 lp = lp->l_next;
315 free(lq);
319 listaccounts(FILE *fp)
321 return list1(fp, accounts);
324 static void
325 list0(FILE *fp, struct line *lp)
327 const char *sp;
328 int c;
330 for (sp = lp->l_line; sp < &lp->l_line[lp->l_linesize]; sp++) {
331 if ((c = *sp&0377) != '\0') {
332 if ((c = *sp&0377) == '\n')
333 putc('\\', fp);
334 putc(c, fp);
337 putc('\n', fp);
340 static int
341 list1(FILE *fp, struct macro **table)
343 struct macro **mp, *mq;
344 struct line *lp;
345 int mc = 0;
347 for (mp = table; mp < &table[MAPRIME]; mp++)
348 for (mq = *mp; mq; mq = mq->ma_next)
349 if (mq->ma_name) {
350 if (mc++)
351 fputc('\n', fp);
352 fprintf(fp, "%s %s {\n",
353 table == accounts ?
354 "account" : "define",
355 mq->ma_name);
356 for (lp = mq->ma_contents; lp; lp = lp->l_next)
357 list0(fp, lp);
358 fputs("}\n", fp);
360 return mc;
363 /*ARGSUSED*/
364 int
365 cdefines(void *v)
367 FILE *fp;
368 char *cp;
369 int mc;
370 (void)v;
372 if ((fp = Ftemp(&cp, "Ra", "w+", 0600, 1)) == NULL) {
373 perror("tmpfile");
374 return 1;
376 rm(cp);
377 Ftfree(&cp);
378 mc = list1(fp, macros);
379 if (mc)
380 try_pager(fp);
381 Fclose(fp);
382 return 0;
385 void
386 delaccount(const char *name)
388 undef1(name, accounts);