--- /dev/null
+/*
+** m_getfld2 -- replacement for m_getfld()
+** read an RFC 822 message
+*/
+
+#define _WITH_GETLINE
+#define _POSIX_C_SOURCE 200809L
+
+#include <h/mh.h>
+#include <h/utils.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+enum threestate {
+ B_TRUE = 1,
+ B_FALSE = 0,
+ FAIL = -1,
+};
+
+/*
+** static prototypes
+*/
+static enum threestate is_falted(FILE *);
+static size_t copyname(char *, char *);
+
+
+/*
+** For the states FLD2, BODY2 memory is allocated for f->value.
+** For the states LENERR2, FMTERR2, ERR2 and FILEEOF2 no memory is allocated.
+*/
+enum state
+m_getfld2(enum state s, struct field *f, FILE *msg)
+{
+ char *tmpline = NULL;
+ size_t len = 0;
+ ssize_t nchars;
+ enum threestate falted;
+
+ nchars = getline(&tmpline, &len, msg);
+ if (nchars == -1) {
+ if (feof(msg)) {
+ return FILEEOF2;
+ } else {
+ return ERR2;
+ }
+ }
+
+ if (nchars >= NAMESZ) {
+ free(tmpline);
+ return LENERR2;
+ }
+
+ switch (s) {
+ case FLD2:
+ if (*(tmpline + nchars - 1) != '\n') {
+ free(tmpline);
+ return FMTERR2;
+ }
+
+ if (nchars > 0 && (*tmpline == '\n' || *tmpline == '-')) {
+ /* header/body separator found */
+ free(tmpline);
+ return m_getfld2(BODY2, f, msg);
+ }
+
+ f->namelen = copyname(f->name, tmpline);
+ if (f->namelen < 1) {
+ free(tmpline);
+ return FMTERR2;
+ }
+
+ /* copy the field's value */
+ if (f->alloclen <= nchars - f->namelen) {
+ f->value = mh_xrealloc(f->value, f->alloclen + len);
+ f->alloclen += len;
+ }
+ strcpy(f->value, tmpline + f->namelen + 1);
+ f->valuelen = nchars - f->namelen - 1;
+
+ while ((falted = is_falted(msg)) == B_TRUE) {
+ nchars = getline(&tmpline, &len, msg);
+ if (nchars <= 0) {
+ free(tmpline);
+ return ERR2;
+ }
+
+ if (nchars >= NAMESZ) {
+ free(tmpline);
+ return LENERR2;
+ }
+
+ if (*(tmpline + nchars - 1) != '\n') {
+ free(tmpline);
+ return FMTERR2;
+ }
+
+ if (f->alloclen - f->valuelen <= nchars) {
+ f->value = mh_xrealloc(f->value,
+ f->alloclen + len);
+ f->alloclen += len;
+ }
+ strcpy(f->value + f->valuelen, tmpline);
+ f->valuelen += nchars;
+
+ }
+
+ if (falted == FAIL) {
+ free(tmpline);
+ return ERR2;
+ }
+
+ free(tmpline);
+ return FLD2;
+
+ case BODY2:
+ *f->name = '\0';
+ f->namelen = 0;
+ if (f->value) {
+ free(f->value);
+ }
+ f->value = tmpline;
+ f->valuelen = nchars;
+ f->alloclen = len;
+ return BODY2;
+
+ default:
+ /* give error states back as received */
+ return s;
+ }
+}
+
+static enum threestate
+is_falted(FILE *msg)
+{
+ enum threestate ret;
+ int c;
+
+ if ((c = getc(msg)) < 0) {
+ if (feof(msg)) {
+ clearerr(msg);
+ return B_FALSE;
+ } else {
+ return FAIL;
+ }
+ }
+ if (isblank(c)) {
+ ret = B_TRUE;
+ } else {
+ ret = B_FALSE;
+ }
+ if (ungetc(c, msg) != c) {
+ return FAIL;
+ }
+ return ret;
+}
+
+static size_t
+copyname(char *dst, char *src)
+{
+ size_t len;
+ char *sep = strchr(src, ':');
+
+ if (!sep) {
+ return 0;
+ }
+
+ len = sep - src;
+ if (len >= NAMESZ) {
+ return 0;
+ }
+
+ src[len] = '\0';
+ strcpy(dst, src);
+
+ return strlen(dst);
+}