add free_field as standard for struct field
[mmh] / sbr / m_getfld2.c
index 6d96bdd..6545d0f 100644 (file)
@@ -10,6 +10,7 @@
 #include <h/utils.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <stdbool.h>
 
 
 enum threestate {
@@ -23,6 +24,9 @@ enum threestate {
 */
 static enum threestate is_falted(FILE *);
 static size_t copyname(char *, char *);
+static bool is_separator(char *);
+
+struct field free_field = { "\0", 0, NULL, 0, 0 };
 
 
 /*
@@ -45,42 +49,31 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
        char *tmpline = NULL;
        size_t len = 0;
        ssize_t nchars;
-       enum threestate falted;
+       enum threestate falted = B_FALSE;
+       enum state ret = s;
 
-       nchars = getline(&tmpline, &len, msg);
-       if (nchars == -1) {
-               if (feof(msg)) {
-                       return FILEEOF2;
-               } else {
-                       return IOERR2;
+       switch (s) {
+       case FLD2:
+               nchars = getline(&tmpline, &len, msg);
+               if (nchars < 1) {
+                       free(f->value);
+                       *f = free_field;
+                       if (feof(msg)) {
+                               return FILEEOF2;
+                       } else {
+                               return IOERR2;
+                       }
                }
-       }
-
-       *f->name = '\0';
-       f->namelen = 0;
 
-       if (nchars >= NAMESZ) {
-               if (f->value) {
-                       free(f->value);
+               if (nchars >= NAMESZ) {
+                       ret = LENERR2;
                }
-               f->value = tmpline;
-               f->valuelen = nchars;
-               return LENERR2;
-       }
 
-       switch (s) {
-       case FLD2:
                if (*(tmpline + nchars - 1) != '\n') {
-                       if (f->value) {
-                               free(f->value);
-                       }
-                       f->value = tmpline;
-                       f->valuelen = nchars;
-                       f->alloclen = len;
-                       return FMTERR2;
+                       ret = FMTERR2;
                }
 
-               if (nchars > 0 && (*tmpline == '\n' || *tmpline == '-')) {
+               if (ret == FLD2 && is_separator(tmpline)) {
                        /* header/body separator found */
                        free(tmpline);
                        return m_getfld2(BODY2, f, msg);
@@ -88,13 +81,9 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
 
                f->namelen = copyname(f->name, tmpline);
                if (f->namelen < 1) {
-                       if (f->value) {
-                               free(f->value);
-                       }
-                       f->value = tmpline;
-                       f->valuelen = nchars;
-                       f->alloclen = len;
-                       return FMTERR2;
+                       *f->name = '\0';
+                       f->namelen = 0;
+                       ret = FMTERR2;
                }
 
                /* copy the field's value */
@@ -102,10 +91,15 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
                        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;
+               if (f->namelen != 0) {
+                       strcpy(f->value, tmpline + f->namelen + 1);
+                       f->valuelen = nchars - f->namelen - 1;
+               } else {
+                       strcpy(f->value, tmpline);
+                       f->valuelen = nchars;
+               }
 
-               while ((falted = is_falted(msg)) == B_TRUE) {
+               while (ret == FLD2 && (falted = is_falted(msg)) == B_TRUE) {
                        nchars = getline(&tmpline, &len, msg);
                        if (nchars <= 0) {
                                free(tmpline);
@@ -113,22 +107,11 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
                        }
 
                        if (nchars >= NAMESZ) {
-                               if (f->value) {
-                                       free(f->value);
-                               }
-                               f->value = tmpline;
-                               f->valuelen = nchars;
-                               return LENERR2;
+                               ret = LENERR2;
                        }
 
                        if (*(tmpline + nchars - 1) != '\n') {
-                               if (f->value) {
-                                       free(f->value);
-                               }
-                               f->value = tmpline;
-                               f->valuelen = nchars;
-                               f->alloclen = len;
-                               return FMTERR2;
+                               ret = FMTERR2;
                        }
 
                        if (f->alloclen - f->valuelen <= nchars) {
@@ -142,21 +125,34 @@ m_getfld2(enum state s, struct field *f, FILE *msg)
                }
 
                if (falted == FAIL) {
-                       free(tmpline);
-                       return IOERR2;
+                       ret = IOERR2;
                }
 
                free(tmpline);
-               return FLD2;
+               return ret;
 
        case BODY2:
-               if (f->value) {
-                       free(f->value);
+               free(f->value);
+               *f = free_field;
+
+               nchars = getline(&tmpline, &len, msg);
+               if (nchars < 1) {
+                       free(tmpline);
+                       if (feof(msg)) {
+                               return FILEEOF2;
+                       } else {
+                               return IOERR2;
+                       }
+               }
+
+               if (nchars >= NAMESZ) {
+                       ret = LENERR2;
                }
+
                f->value = tmpline;
                f->valuelen = nchars;
                f->alloclen = len;
-               return BODY2;
+               return ret;
 
        default:
                /* give error states back as received */
@@ -215,3 +211,19 @@ copyname(char *dst, char *src)
 
        return strlen(dst);
 }
+
+static bool
+is_separator(char *line)
+{
+       /*
+       ** In MH, lines that are consists of dashes only are
+       ** separators as well ... not so in RFC 822.
+       */
+       while (*line == '-') {
+               line++;
+       }
+       if (strcmp("\n", line) == 0 || strcmp("\r\n", line) == 0 ) {
+               return true;
+       }
+       return false;
+}