Fix -u, change meaning of $USER to be EQ -u etc..
[s-mailx.git] / acmava.c
blob89138b0420438ffe544990af5afc1adbeef91592
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Account, macro and variable handling.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. 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 the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its 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 THE REGENTS 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 THE REGENTS 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 #include "nail.h"
43 * TODO in general it would be nice if it would be possible to define "macros"
44 * TODO etc. inside of other "macros"
47 #define MA_PRIME HSHSIZE
48 #define MA_HASH(S) (strhash(S) % MA_PRIME)
50 enum ma_flags {
51 MA_NONE = 0,
52 MA_ACC = 1<<0,
53 MA_TYPE_MASK = MA_ACC,
54 MA_UNDEF = 1<<1 /* Unlink after lookup */
57 struct macro {
58 struct macro *ma_next;
59 char *ma_name;
60 struct line *ma_contents;
61 size_t ma_maxlen; /* Maximum line length */
62 enum ma_flags ma_flags;
63 struct var *ma_localopts; /* `account' unroll list, for `localopts' */
66 struct line {
67 struct line *l_next;
68 size_t l_length;
69 char l_line[VFIELD_SIZE(sizeof(size_t))];
72 struct var {
73 struct var *v_link;
74 char *v_name;
75 char *v_value;
78 struct lostack {
79 struct lostack *s_up; /* Outer context */
80 struct macro *s_mac; /* Context (`account' or `define') */
81 struct var *s_localopts;
82 bool_t s_unroll; /* Unroll? */
85 static struct macro *_acc_curr; /* Currently active account */
86 static struct lostack *_localopts; /* Currently executing macro unroll list */
88 /* TODO once we have a dynamically sized hashtable we could unite _macros and
89 * TODO _variables into a single hashtable, stripping down fun interface;
90 * TODO also, setting and clearing a variable can be easily joined */
91 static struct macro *_macros[MA_PRIME]; /* TODO dynamically spaced */
92 static struct var *_vars[MA_PRIME]; /* TODO dynamically spaced */
94 /* Special cased value string allocation */
95 static char * _vcopy(char const *str);
96 static void _vfree(char *cp);
98 /* Check for special housekeeping. */
99 static bool_t _check_special_vars(char const *name, bool_t enable,
100 char **val);
102 /* If a variable name begins with a lowercase-character and contains at
103 * least one '@', it is converted to all-lowercase. This is necessary
104 * for lookups of names based on email addresses.
106 * Following the standard, only the part following the last '@' should
107 * be lower-cased, but practice has established otherwise here */
108 static char const * _canonify(char const *vn);
110 /* Locate a variable and return its variable node */
111 static struct var * _lookup(char const *name, ui_it h, bool_t hisset);
113 /* Line *cp* consists solely of WS and a } */
114 static bool_t _is_closing_angle(char const *cp);
116 /* Lookup for macros/accounts */
117 static struct macro *_malook(char const *name, struct macro *data,
118 enum ma_flags mafl);
120 /* Walk all lines of a macro and execute() them */
121 static int _maexec(struct macro const *mp, struct var **unroll_store);
123 /* User display helpers */
124 static int _list_macros(enum ma_flags mafl);
126 /* */
127 static bool_t _define1(char const *name, enum ma_flags mafl);
128 static void _undef1(char const *name, enum ma_flags mafl);
129 static void _freelines(struct line *lp);
131 /* qsort(3) helper */
132 static int __var_list_all_cmp(void const *s1, void const *s2);
134 /* Update replay-log */
135 static void _localopts_add(struct lostack *losp, char const *name,
136 struct var *ovap);
137 static void _localopts_unroll(struct var **vapp);
139 static char *
140 _vcopy(char const *str)
142 char *news;
143 size_t len;
145 if (*str == '\0')
146 news = UNCONST("");
147 else {
148 len = strlen(str) + 1;
149 news = smalloc(len);
150 memcpy(news, str, len);
152 return news;
155 static void
156 _vfree(char *cp)
158 if (*cp != '\0')
159 free(cp);
162 static bool_t
163 _check_special_vars(char const *name, bool_t enable, char **val)
165 /* TODO _check_special_vars --> value cache */
166 char *cp = NULL;
167 bool_t rv = TRU1;
168 int flag = 0;
170 if (strcmp(name, "debug") == 0)
171 flag = OPT_DEBUG;
172 else if (strcmp(name, "header") == 0)
173 flag = OPT_N_FLAG, enable = ! enable;
174 else if (strcmp(name, "skipemptybody") == 0)
175 flag = OPT_E_FLAG;
176 else if (strcmp(name, "verbose") == 0)
177 flag = OPT_VERBOSE;
178 else if (strcmp(name, "prompt") == 0)
179 flag = OPT_NOPROMPT, enable = ! enable;
180 else if (strcmp(name, "folder") == 0) {
181 rv = var_folder_updated(*val, &cp);
182 if (rv && cp != NULL) {
183 _vfree(*val);
184 /* It's smalloc()ed, but ensure we don't leak */
185 if (*cp == '\0') {
186 *val = UNCONST("");
187 free(cp);
188 } else
189 *val = cp;
192 #if ! defined HAVE_READLINE && ! defined HAVE_EDITLINE &&\
193 defined HAVE_LINE_EDITOR
194 else if (strcmp(name, "line-editor-cursor-right") == 0) {
195 char const *x = cp = *val;
196 int c;
197 while (*x != '\0') {
198 c = expand_shell_escape(&x, FAL0);
199 if (c < 0)
200 break;
201 *cp++ = (char)c;
203 *cp++ = '\0';
205 #endif
207 if (flag) {
208 if (enable)
209 options |= flag;
210 else
211 options &= ~flag;
213 return rv;
216 static char const *
217 _canonify(char const *vn)
219 if (! upperchar(*vn)) {
220 char const *vp;
222 for (vp = vn; *vp != '\0' && *vp != '@'; ++vp)
224 vn = (*vp == '@') ? i_strdup(vn) : vn;
226 return vn;
229 static struct var *
230 _lookup(char const *name, ui_it h, bool_t hisset)
232 struct var **vap, *lvp, *vp;
234 if (! hisset)
235 h = MA_HASH(name);
236 vap = _vars + h;
238 for (lvp = NULL, vp = *vap; vp != NULL; lvp = vp, vp = vp->v_link)
239 if (*vp->v_name == *name && strcmp(vp->v_name, name) == 0) {
240 /* Relink as head, hope it "sorts on usage" over time */
241 if (lvp != NULL) {
242 lvp->v_link = vp->v_link;
243 vp->v_link = *vap;
244 *vap = vp;
246 goto jleave;
248 vp = NULL;
249 jleave:
250 return vp;
253 static bool_t
254 _is_closing_angle(char const *cp)
256 bool_t rv = FAL0;
257 while (spacechar(*cp))
258 ++cp;
259 if (*cp++ != '}')
260 goto jleave;
261 while (spacechar(*cp))
262 ++cp;
263 rv = (*cp == '\0');
264 jleave:
265 return rv;
268 static struct macro *
269 _malook(char const *name, struct macro *data, enum ma_flags mafl)
271 enum ma_flags save_mafl;
272 ui_it h;
273 struct macro *lmp, *mp;
275 save_mafl = mafl;
276 mafl &= MA_TYPE_MASK;
277 h = MA_HASH(name);
279 for (lmp = NULL, mp = _macros[h]; mp != NULL; lmp = mp, mp = mp->ma_next) {
280 if ((mp->ma_flags & MA_TYPE_MASK) == mafl &&
281 strcmp(mp->ma_name, name) == 0) {
282 if (save_mafl & MA_UNDEF) {
283 if (lmp == NULL)
284 _macros[h] = mp->ma_next;
285 else
286 lmp->ma_next = mp->ma_next;
288 goto jleave;
292 if (data != NULL) {
293 data->ma_next = _macros[h];
294 _macros[h] = data;
295 mp = NULL;
297 jleave:
298 return mp;
301 static int
302 _maexec(struct macro const *mp, struct var **unroll_store)
304 struct lostack los;
305 int rv = 0;
306 struct line const *lp;
307 char *buf = ac_alloc(mp->ma_maxlen + 1);
309 los.s_up = _localopts;
310 los.s_mac = UNCONST(mp);
311 los.s_localopts = NULL;
312 los.s_unroll = FAL0;
313 _localopts = &los;
315 for (lp = mp->ma_contents; lp; lp = lp->l_next) {
316 unset_allow_undefined = TRU1;
317 memcpy(buf, lp->l_line, lp->l_length + 1);
318 rv |= execute(buf, 0, lp->l_length); /* XXX break if != 0 ? */
319 unset_allow_undefined = FAL0;
322 _localopts = los.s_up;
323 if (unroll_store == NULL)
324 _localopts_unroll(&los.s_localopts);
325 else
326 *unroll_store = los.s_localopts;
328 ac_free(buf);
329 return rv;
332 static int
333 _list_macros(enum ma_flags mafl)
335 FILE *fp;
336 char *cp;
337 char const *typestr;
338 struct macro *mq;
339 ui_it ti, mc;
340 struct line *lp;
342 if ((fp = Ftemp(&cp, "Ra", "w+", 0600, 1)) == NULL) {
343 perror("tmpfile");
344 return 1;
346 rm(cp);
347 Ftfree(&cp);
349 mafl &= MA_TYPE_MASK;
350 typestr = (mafl & MA_ACC) ? "account" : "define";
352 for (ti = mc = 0; ti < MA_PRIME; ++ti)
353 for (mq = _macros[ti]; mq; mq = mq->ma_next)
354 if ((mq->ma_flags & MA_TYPE_MASK) == mafl) {
355 if (++mc > 1)
356 fputc('\n', fp);
357 fprintf(fp, "%s %s {\n", typestr, mq->ma_name);
358 for (lp = mq->ma_contents; lp; lp = lp->l_next)
359 fprintf(fp, " %s\n", lp->l_line);
360 fputs("}\n", fp);
362 if (mc)
363 page_or_print(fp, 0);
365 mc = (ui_it)ferror(fp);
366 Fclose(fp);
367 return (int)mc;
370 static bool_t
371 _define1(char const *name, enum ma_flags mafl)
373 bool_t rv = FAL0;
374 struct macro *mp;
375 struct line *lp, *lst = NULL, *lnd = NULL;
376 char *linebuf = NULL, *cp;
377 size_t linesize = 0, maxlen = 0;
378 int n, i;
380 mp = scalloc(1, sizeof *mp);
381 mp->ma_name = sstrdup(name);
382 mp->ma_flags = mafl;
384 for (;;) {
385 n = readline_input(LNED_LF_ESC, "", &linebuf, &linesize);
386 if (n <= 0) {
387 fprintf(stderr, tr(75, "Unterminated %s definition: \"%s\".\n"),
388 (mafl & MA_ACC ? "account" : "macro"), mp->ma_name);
389 if (sourcing)
390 unstack();
391 goto jerr;
393 if (_is_closing_angle(linebuf))
394 break;
396 /* Trim WS */
397 for (cp = linebuf, i = 0; i < n; ++cp, ++i)
398 if (! whitechar(*cp))
399 break;
400 if (i == n)
401 continue;
402 n -= i;
403 while (whitechar(cp[n - 1]))
404 if (--n == 0)
405 break;
406 if (n == 0)
407 continue;
409 maxlen = MAX(maxlen, (size_t)n);
410 cp[n++] = '\0';
412 lp = scalloc(1, sizeof(*lp) - VFIELD_SIZEOF(struct line, l_line) + n);
413 memcpy(lp->l_line, cp, n);
414 lp->l_length = (size_t)--n;
415 if (lst != NULL) {
416 lnd->l_next = lp;
417 lnd = lp;
418 } else
419 lst = lnd = lp;
421 mp->ma_contents = lst;
422 mp->ma_maxlen = maxlen;
424 if (_malook(mp->ma_name, mp, mafl) != NULL) {
425 if (! (mafl & MA_ACC)) {
426 fprintf(stderr, tr(76, "A macro named \"%s\" already exists.\n"),
427 mp->ma_name);
428 lst = mp->ma_contents;
429 goto jerr;
431 _undef1(mp->ma_name, MA_ACC);
432 _malook(mp->ma_name, mp, MA_ACC);
435 rv = TRU1;
436 jleave:
437 if (linebuf != NULL)
438 free(linebuf);
439 return rv;
440 jerr:
441 if (lst != NULL)
442 _freelines(lst);
443 free(mp->ma_name);
444 free(mp);
445 goto jleave;
448 static void
449 _undef1(char const *name, enum ma_flags mafl)
451 struct macro *mp;
453 if ((mp = _malook(name, NULL, mafl | MA_UNDEF)) != NULL) {
454 _freelines(mp->ma_contents);
455 free(mp->ma_name);
456 free(mp);
460 static void
461 _freelines(struct line *lp)
463 struct line *lq;
465 for (lq = NULL; lp != NULL; ) {
466 if (lq != NULL)
467 free(lq);
468 lq = lp;
469 lp = lp->l_next;
471 if (lq)
472 free(lq);
475 static int
476 __var_list_all_cmp(void const *s1, void const *s2)
478 return strcmp(*(char**)UNCONST(s1), *(char**)UNCONST(s2));
481 static void
482 _localopts_add(struct lostack *losp, char const *name, struct var *ovap)
484 struct var *vap;
485 size_t nl, vl;
487 /* Propagate unrolling up the stack, as necessary */
488 while (! losp->s_unroll && (losp = losp->s_up) != NULL)
490 if (losp == NULL)
491 goto jleave;
493 /* We have found a level that wants to unroll; check wether it does it yet */
494 for (vap = losp->s_localopts; vap != NULL; vap = vap->v_link)
495 if (strcmp(vap->v_name, name) == 0)
496 goto jleave;
498 nl = strlen(name) + 1;
499 vl = (ovap != NULL) ? strlen(ovap->v_value) + 1 : 0;
500 vap = smalloc(sizeof(*vap) + nl + vl);
501 vap->v_link = losp->s_localopts;
502 losp->s_localopts = vap;
503 vap->v_name = (char*)(vap + 1);
504 memcpy(vap->v_name, name, nl);
505 if (vl == 0)
506 vap->v_value = NULL;
507 else {
508 vap->v_value = (char*)(vap + 1) + nl;
509 memcpy(vap->v_value, ovap->v_value, vl);
511 jleave:
515 static void
516 _localopts_unroll(struct var **vapp)
518 struct lostack *save_los;
519 struct var *x, *vap;
521 vap = *vapp;
522 *vapp = NULL;
524 save_los = _localopts;
525 _localopts = NULL;
526 while (vap != NULL) {
527 x = vap;
528 vap = vap->v_link;
529 var_assign(x->v_name, x->v_value);
530 free(x);
532 _localopts = save_los;
535 void
536 var_assign(char const *name, char const *val)
538 struct var *vp;
539 ui_it h;
540 char *oval;
542 if (val == NULL) {
543 bool_t tmp = unset_allow_undefined;
544 unset_allow_undefined = TRU1;
545 var_unset(name);
546 unset_allow_undefined = tmp;
547 goto jleave;
550 name = _canonify(name);
551 h = MA_HASH(name);
552 vp = _lookup(name, h, TRU1);
554 /* Don't care what happens later on, store this in the unroll list */
555 if (_localopts != NULL)
556 _localopts_add(_localopts, name, vp);
558 if (vp == NULL) {
559 vp = (struct var*)scalloc(1, sizeof *vp);
560 vp->v_name = _vcopy(name);
561 vp->v_link = _vars[h];
562 _vars[h] = vp;
563 oval = UNCONST("");
564 } else
565 oval = vp->v_value;
566 vp->v_value = _vcopy(val);
568 /* Check if update allowed XXX wasteful on error! */
569 if (! _check_special_vars(name, TRU1, &vp->v_value)) {
570 char *cp = vp->v_value;
571 vp->v_value = oval;
572 oval = cp;
574 if (*oval != '\0')
575 _vfree(oval);
576 jleave:
581 var_unset(char const *name)
583 int ret = 1;
584 ui_it h;
585 struct var *vp;
587 name = _canonify(name);
588 h = MA_HASH(name);
589 vp = _lookup(name, h, TRU1);
591 if (vp == NULL) {
592 if (! sourcing && ! unset_allow_undefined) {
593 fprintf(stderr, tr(203, "\"%s\": undefined variable\n"), name);
594 goto jleave;
596 } else {
597 if (_localopts != NULL)
598 _localopts_add(_localopts, name, vp);
600 /* Always listhead after _lookup() */
601 _vars[h] = _vars[h]->v_link;
602 _vfree(vp->v_name);
603 _vfree(vp->v_value);
604 free(vp);
606 _check_special_vars(name, FAL0, NULL);
608 ret = 0;
609 jleave:
610 return ret;
613 char *
614 var_lookup(char const *name, bool_t look_environ)
616 struct var *vp;
617 char *rv;
619 name = _canonify(name);
620 if ((vp = _lookup(name, 0, FAL0)) != NULL)
621 rv = vp->v_value;
622 else if (! look_environ)
623 rv = NULL;
624 else if ((rv = getenv(name)) != NULL && *rv != '\0')
625 rv = savestr(rv);
626 return rv;
629 void
630 var_list_all(void)
632 FILE *fp;
633 char *cp, **vacp, **cap;
634 struct var *vp;
635 size_t no, i;
636 char const *fmt;
638 if ((fp = Ftemp(&cp, "Ra", "w+", 0600, 1)) == NULL) {
639 perror("tmpfile");
640 goto jleave;
642 rm(cp);
643 Ftfree(&cp);
645 for (no = i = 0; i < MA_PRIME; ++i)
646 for (vp = _vars[i]; vp != NULL; vp = vp->v_link)
647 ++no;
648 vacp = salloc(no * sizeof(*vacp));
649 for (cap = vacp, i = 0; i < MA_PRIME; ++i)
650 for (vp = _vars[i]; vp != NULL; vp = vp->v_link)
651 *cap++ = vp->v_name;
653 if (no > 1)
654 qsort(vacp, no, sizeof *vacp, &__var_list_all_cmp);
656 i = (boption("bsdcompat") || boption("bsdset"));
657 fmt = (i != 0) ? "%s\t%s\n" : "%s=\"%s\"\n";
659 for (cap = vacp; no != 0; ++cap, --no) {
660 cp = value(*cap); /* TODO internal lookup; binary? value? */
661 if (cp == NULL)
662 cp = UNCONST("");
663 if (i || *cp != '\0')
664 fprintf(fp, fmt, *cap, cp);
665 else
666 fprintf(fp, "%s\n", *cap);
669 page_or_print(fp, (size_t)(cap - vacp));
670 Fclose(fp);
671 jleave:
676 cdefine(void *v)
678 int rv = 1;
679 char **args = v;
680 char const *errs;
682 if (args[0] == NULL) {
683 errs = tr(504, "Missing macro name to `define'");
684 goto jerr;
686 if (args[1] == NULL || strcmp(args[1], "{") || args[2] != NULL) {
687 errs = tr(505, "Syntax is: define <name> {");
688 goto jerr;
690 rv = ! _define1(args[0], MA_NONE);
691 jleave:
692 return rv;
693 jerr:
694 fprintf(stderr, "%s\n", errs);
695 goto jleave;
699 cundef(void *v)
701 int rv = 1;
702 char **args = v;
704 if (*args == NULL) {
705 fprintf(stderr, tr(506, "Missing macro name to `undef'\n"));
706 goto jleave;
709 _undef1(*args, MA_NONE);
710 while (*++args);
711 rv = 0;
712 jleave:
713 return rv;
717 ccall(void *v)
719 int rv = 1;
720 char **args = v;
721 char const *errs, *name;
722 struct macro *mp;
724 if (args[0] == NULL || (args[1] != NULL && args[2] != NULL)) {
725 errs = tr(507, "Syntax is: call <%s>\n");
726 name = "name";
727 goto jerr;
730 if ((mp = _malook(*args, NULL, MA_NONE)) == NULL) {
731 errs = tr(508, "Undefined macro called: \"%s\"\n");
732 name = *args;
733 goto jerr;
736 rv = _maexec(mp, NULL);
737 jleave:
738 return rv;
739 jerr:
740 fprintf(stderr, errs, name);
741 goto jleave;
745 callhook(char const *name, int nmail)
747 int len, rv;
748 struct macro *mp;
749 char *var, *cp;
751 var = ac_alloc(len = strlen(name) + 13);
752 snprintf(var, len, "folder-hook-%s", name);
753 if ((cp = value(var)) == NULL && (cp = value("folder-hook")) == NULL) {
754 rv = 0;
755 goto jleave;
757 if ((mp = _malook(cp, NULL, MA_NONE)) == NULL) {
758 fprintf(stderr, tr(49, "Cannot call hook for folder \"%s\": "
759 "Macro \"%s\" does not exist.\n"), name, cp);
760 rv = 1;
761 goto jleave;
764 inhook = nmail ? 3 : 1;
765 rv = _maexec(mp, NULL);
766 inhook = 0;
767 jleave:
768 ac_free(var);
769 return rv;
773 cdefines(void *v)
775 (void)v;
776 return _list_macros(MA_NONE);
780 c_account(void *v)
782 char **args = v, *cp;
783 struct macro *mp;
784 int rv = 1, i, oqf, nqf;
786 if (args[0] == NULL) {
787 rv = _list_macros(MA_ACC);
788 goto jleave;
791 if (args[1] && args[1][0] == '{' && args[1][1] == '\0') {
792 if (args[2] != NULL) {
793 fprintf(stderr, tr(517, "Syntax is: account <name> {\n"));
794 goto jleave;
796 if (asccasecmp(args[0], ACCOUNT_NULL) == 0) {
797 fprintf(stderr, tr(521, "Error: `%s' is a reserved name.\n"),
798 ACCOUNT_NULL);
799 goto jleave;
801 rv = ! _define1(args[0], MA_ACC);
802 goto jleave;
805 if (inhook) {
806 fprintf(stderr, tr(518, "Cannot change account from within a hook.\n"));
807 goto jleave;
810 if ((cp = expand("&")) == NULL)
811 goto jleave;
812 n_strlcpy(mboxname, cp, sizeof mboxname);
814 mp = NULL;
815 if (asccasecmp(args[0], ACCOUNT_NULL) != 0 &&
816 (mp = _malook(args[0], NULL, MA_ACC)) == NULL) {
817 fprintf(stderr, tr(519, "Account `%s' does not exist.\n"), args[0]);
818 goto jleave;
821 oqf = savequitflags();
822 if (_acc_curr != NULL)
823 _localopts_unroll(&_acc_curr->ma_localopts);
824 account_name = (mp != NULL) ? mp->ma_name : NULL;
825 _acc_curr = mp;
827 if (mp != NULL && _maexec(mp, &mp->ma_localopts) == CBAD) {
828 /* XXX account switch incomplete, unroll? */
829 fprintf(stderr, tr(520, "Switching to account `%s' failed.\n"), args[0]);
830 goto jleave;
833 if (! starting && ! inhook) {
834 nqf = savequitflags(); /* TODO obsolete (leave -> void -> new box!) */
835 restorequitflags(oqf);
836 if ((i = setfile("%", 0)) < 0)
837 goto jleave;
838 callhook(mailname, 0);
839 if (i > 0 && ! boption("emptystart"))
840 goto jleave;
841 announce(boption("bsdcompat") || boption("bsdannounce"));
842 restorequitflags(nqf);
844 rv = 0;
845 jleave:
846 return rv;
850 c_localopts(void *v)
852 int rv = 1;
853 char **c = v;
855 if (_localopts == NULL) {
856 fprintf(stderr, tr(522,
857 "Cannot use `localopts' but from within a `define' or `account'\n"));
858 goto jleave;
861 _localopts->s_unroll = (**c == '0') ? FAL0 : TRU1;
862 rv = 0;
863 jleave:
864 return rv;
867 /* vim:set fenc=utf-8:s-it-mode */