+static void
+mhl_format(char *file, int width)
+{
+ int i;
+ char *bp, *cp;
+ char *ap, buffer[BUFSIZ], name[NAMESZ];
+ struct mcomp *c1;
+ struct stat st;
+ FILE *fp;
+ static dev_t dev = 0;
+ static ino_t ino = 0;
+ static time_t mtime = 0;
+
+ if (fmthd != NULL) {
+ if (stat(etcpath(file), &st) != NOTOK
+ && mtime == st.st_mtime
+ && dev == st.st_dev
+ && ino == st.st_ino)
+ goto out;
+ else
+ free_queue(&fmthd, &fmttl);
+ }
+
+ if ((fp = fopen(etcpath(file), "r")) == NULL)
+ adios(file, "unable to open format file");
+
+ if (fstat(fileno(fp), &st) != NOTOK) {
+ mtime = st.st_mtime;
+ dev = st.st_dev;
+ ino = st.st_ino;
+ }
+
+ global.c_ovtxt = global.c_fstr = NULL;
+ global.c_fmt = NULL;
+ global.c_offset = 0;
+ global.c_ovoff = -1;
+ if ((i = sc_width()) > 5)
+ global.c_width = i;
+ global.c_cwidth = -1;
+ global.c_flags = 0;
+ *ignores = NULL;
+
+ while (vfgets(fp, &ap) == OK) {
+ bp = ap;
+ if (*bp == ';')
+ continue;
+
+ if ((cp = strchr(bp, '\n')))
+ *cp = 0;
+
+ if (*bp == ':') {
+ c1 = add_queue(&fmthd, &fmttl, NULL, bp + 1,
+ CLEARTEXT);
+ continue;
+ }
+
+ parptr = bp;
+ strncpy(name, parse(), sizeof(name));
+ switch(*parptr) {
+ case '\0':
+ case ',':
+ case '=':
+ /*
+ ** Split this list of fields to ignore, and copy
+ ** it to the end of the current "ignores" list.
+ */
+ if (!mh_strcasecmp(name, "ignores")) {
+ char **tmparray;
+ int n = 0;
+
+ /* split the fields */
+ tmparray = brkstring(getcpy(++parptr), ",",
+ NULL);
+ /*
+ ** copy pointers to split fields
+ ** to ignores array
+ */
+ while (tmparray[n] && num_ignores<MAXARGS-1) {
+ ignores[num_ignores++] = tmparray[n++];
+ }
+ ignores[num_ignores] = NULL;
+ continue;
+ }
+ parptr = bp;
+ while (*parptr) {
+ if (evalvar(&global))
+ adios(NULL, "format file syntax error: %s", bp);
+ if (*parptr)
+ parptr++;
+ }
+ continue;
+
+ case ':':
+ c1 = add_queue(&fmthd, &fmttl, name, NULL, INIT);
+ while (*parptr == ':' || *parptr == ',') {
+ parptr++;
+ if (evalvar(c1))
+ adios(NULL, "format file syntax error: %s", bp);
+ }
+ if (!c1->c_fstr && global.c_fstr) {
+ if ((c1->c_flags & DATEFMT) &&
+ (global.c_flags & DATEFMT)) {
+ c1->c_fstr = getcpy(global.c_fstr);
+ } else if ((c1->c_flags & ADDRFMT) &&
+ (global.c_flags & ADDRFMT)) {
+ c1->c_fstr = getcpy(global.c_fstr);
+ }
+ }
+ continue;
+
+ default:
+ adios(NULL, "format file syntax error: %s", bp);
+ }
+ }
+ fclose(fp);
+
+ if (mhldebug) {
+ for (c1 = fmthd; c1; c1 = c1->c_next) {
+ fprintf(stderr, "c1: name=\"%s\" text=\"%s\" ovtxt=\"%s\"\n", c1->c_name, c1->c_text, c1->c_ovtxt);
+ fprintf(stderr, "\tfstr=0x%x fmt=0x%x\n", (unsigned int)(unsigned long) c1->c_fstr, (unsigned int)(unsigned long) c1->c_fmt);
+ fprintf(stderr, "\toffset=%d ovoff=%d width=%d cwidth=%d\n", c1->c_offset, c1->c_ovoff, c1->c_width, c1->c_cwidth);
+ fprintf (stderr, "\tflags=%s\n", snprintb(buffer, sizeof(buffer), (unsigned) c1->c_flags, LBITS));
+ }
+ }
+
+out:
+ if (width)
+ global.c_width = width;
+ if (global.c_width < 5)
+ global.c_width = 10000;
+}
+
+
+static int
+evalvar(struct mcomp *c1)
+{
+ char *cp, name[NAMESZ];
+ struct triple *ap;
+
+ if (!*parptr)
+ return 0;
+ strncpy(name, parse(), sizeof(name));
+
+ if (!mh_strcasecmp(name, "component")) {
+ if (ptos(name, &c1->c_text))
+ return 1;
+ c1->c_flags &= ~NOCOMPONENT;
+ return 0;
+ }
+
+ if (!mh_strcasecmp(name, "overflowtext"))
+ return ptos(name, &c1->c_ovtxt);
+
+ if (!mh_strcasecmp(name, "formatfield")) {
+ char *fmtstr;
+
+ if (ptos(name, &cp))
+ return 1;
+ cp = concat("=", cp, NULL);
+ fmtstr = new_fs(cp, NULL);
+ free(cp);
+ c1->c_fstr = getcpy(fmtstr);
+ c1->c_flags |= FORMAT;
+ return 0;
+ }
+
+ if (!mh_strcasecmp(name, "decode")) {
+ char *fmtstr;
+
+ fmtstr = new_fs("=%(decode{text})", NULL);
+ c1->c_fstr = getcpy(fmtstr);
+ c1->c_flags |= FORMAT;
+ return 0;
+ }
+
+ if (!mh_strcasecmp(name, "offset"))
+ return ptoi(name, &c1->c_offset);
+ if (!mh_strcasecmp(name, "overflowoffset"))
+ return ptoi(name, &c1->c_ovoff);
+ if (!mh_strcasecmp(name, "width"))
+ return ptoi(name, &c1->c_width);
+ if (!mh_strcasecmp(name, "compwidth"))
+ return ptoi(name, &c1->c_cwidth);
+
+ for (ap = triples; ap->t_name; ap++)
+ if (!mh_strcasecmp(ap->t_name, name)) {
+ c1->c_flags |= ap->t_on;
+ c1->c_flags &= ~ap->t_off;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int
+ptoi(char *name, int *i)
+{
+ char *cp;
+
+ if (*parptr++ != '=' || !*(cp = parse())) {
+ advise(NULL, "missing argument to variable %s", name);
+ return 1;
+ }
+
+ *i = atoi(cp);
+ return 0;
+}
+
+
+static int
+ptos(char *name, char **s)
+{
+ char c, *cp;
+
+ if (*parptr++ != '=') {
+ advise(NULL, "missing argument to variable %s", name);
+ return 1;
+ }
+
+ if (*parptr != '"') {
+ for (cp = parptr; *parptr && *parptr != ':' && *parptr != ',';
+ parptr++)
+ continue;
+ } else {
+ for (cp = ++parptr; *parptr && *parptr != '"'; parptr++)
+ if (*parptr == QUOTE)
+ if (!*++parptr)
+ parptr--;
+ }
+ c = *parptr;
+ *parptr = 0;
+ *s = getcpy(cp);
+ if ((*parptr = c) == '"')
+ parptr++;
+ return 0;
+}
+
+
+static char *
+parse(void)
+{
+ int c;
+ char *cp;
+ static char result[NAMESZ];
+
+ for (cp = result; *parptr && (cp - result < NAMESZ); parptr++) {
+ c = *parptr;
+ if (isalnum(c)
+ || c == '.'
+ || c == '-'
+ || c == '_'
+ || c == '['
+ || c == ']')
+ *cp++ = c;
+ else
+ break;
+ }
+ *cp = '\0';
+
+ return result;
+}
+
+
+static void
+process(char *folder, char *fname, int ofilen, int ofilec)
+{
+ char *cp = NULL;
+ FILE *fp = NULL;
+ struct mcomp *c1;
+
+ switch (setjmp(env)) {
+ case OK:
+ if (fname) {
+ fp = mhl_action ? (*mhl_action) (fname) :
+ fopen(fname, "r");
+ if (fp == NULL) {
+ advise(fname, "unable to open");
+ exitstat++;
+ return;
+ }
+ } else {
+ fname = "(stdin)";
+ fp = stdin;
+ }
+ cp = folder ? concat(folder, ":", fname, NULL) : getcpy(fname);
+ if (ontty != PITTY)
+ SIGNAL(SIGINT, intrser);
+ mhlfile(fp, cp, ofilen, ofilec);
+ /* FALL THROUGH! */
+ default:
+ if (ontty != PITTY)
+ SIGNAL(SIGINT, SIG_IGN);
+ if (mhl_action == NULL && fp != stdin)
+ fclose(fp);
+ free(cp);
+ if (holder.c_text) {
+ free(holder.c_text);
+ holder.c_text = NULL;
+ }
+ free_queue(&msghd, &msgtl);
+ for (c1 = fmthd; c1; c1 = c1->c_next)
+ c1->c_flags &= ~HDROUTPUT;
+ break;
+ }
+}
+
+
+static void
+mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
+{
+ int state;
+ struct mcomp *c1, *c2, *c3;
+ char **ip, name[NAMESZ], buf[BUFSIZ];
+
+ if (forwall) {
+ if (digest)
+ printf("%s", ofilen == 1 ? delim3 : delim4);
+ else {
+ printf("\n-------");
+ if (ofilen == 1)
+ printf(" Forwarded Message%s",
+ ofilec > 1 ? "s" : "");
+ else
+ printf(" Message %d", ofilen);
+ printf("\n\n");
+ }
+ } else if (ofilec > 1) {
+ if (ofilen > 1) {
+ printf("\n\n\n");
+ }
+ printf(">>> %s\n\n", mname);
+ }
+
+ for (state = FLD;;) {
+ switch (state = m_getfld(state, name, buf, sizeof(buf), fp)) {
+ case FLD:
+ case FLDPLUS:
+ for (ip = ignores; *ip; ip++)
+ if (!mh_strcasecmp(name, *ip)) {
+ while (state == FLDPLUS)
+ state = m_getfld(state, name, buf, sizeof(buf), fp);
+ break;
+ }
+ if (*ip)
+ continue;
+
+ for (c2 = fmthd; c2; c2 = c2->c_next)
+ if (!mh_strcasecmp(c2->c_name, name))
+ break;
+ c1 = NULL;
+ if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT))
+ for (c1 = msghd; c1; c1 = c1->c_next)
+ if (!mh_strcasecmp(c1->c_name,
+ c3->c_name)) {
+ c1->c_text = mcomp_add(c1->c_flags, buf, c1->c_text);
+ break;
+ }
+ if (c1 == NULL)
+ c1 = add_queue(&msghd, &msgtl, name, buf, 0);
+ while (state == FLDPLUS) {
+ state = m_getfld(state, name, buf,
+ sizeof(buf), fp);
+ c1->c_text = add(buf, c1->c_text);
+ }
+ if (c2 == NULL)
+ c1->c_flags |= EXTRA;
+ continue;
+
+ case BODY:
+ case FILEEOF:
+ column = 0;
+ for (c1 = fmthd; c1; c1 = c1->c_next) {
+ if (c1->c_flags & CLEARTEXT) {
+ putcomp(c1, c1, ONECOMP);
+ continue;
+ }
+ if (!mh_strcasecmp(c1->c_name, "messagename")) {
+ holder.c_text = concat("(Message ",
+ mname, ")\n", NULL);
+ putcomp(c1, &holder, ONECOMP);
+ free(holder.c_text);
+ holder.c_text = NULL;
+ continue;
+ }
+ if (!mh_strcasecmp(c1->c_name, "extras")) {
+ for (c2 = msghd; c2; c2 = c2->c_next)
+ if (c2->c_flags & EXTRA)
+ putcomp(c1, c2, TWOCOMP);
+ continue;
+ }
+ if (dobody && !mh_strcasecmp(c1->c_name, "body")) {
+ holder.c_text = mh_xmalloc(sizeof(buf));
+ strncpy(holder.c_text, buf, sizeof(buf));
+ while (state == BODY) {
+ putcomp(c1, &holder, BODYCOMP);
+ state = m_getfld(state, name, holder.c_text, sizeof(buf), fp);
+ }
+ free(holder.c_text);
+ holder.c_text = NULL;
+ continue;
+ }
+ for (c2 = msghd; c2; c2 = c2->c_next)
+ if (!mh_strcasecmp(c2->c_name,
+ c1->c_name)) {
+ putcomp(c1, c2, ONECOMP);
+ if (!(c1->c_flags & SPLIT))
+ break;
+ }
+ }
+ return;