m_getfld2: ERR2 means a read error, thus name it IOERR2
[mmh] / sbr / m_getfld2.c
1 /*
2 ** m_getfld2 -- replacement for m_getfld()
3 **              read an RFC 822 message
4 */
5
6 #define _WITH_GETLINE
7 #define _POSIX_C_SOURCE 200809L
8
9 #include <h/mh.h>
10 #include <h/utils.h>
11 #include <stdio.h>
12 #include <ctype.h>
13
14
15 enum threestate {
16         B_TRUE = 1,
17         B_FALSE = 0,
18         FAIL = -1,
19 };
20
21 /*
22 ** static prototypes
23 */
24 static enum threestate is_falted(FILE *);
25 static size_t copyname(char *, char *);
26
27
28 /*
29 ** For the states FLD2, BODY2 and FMTERR2 memory is allocated for f->value.
30 ** For the states LENERR2, IOERR2 and FILEEOF2 no memory is allocated.
31 */
32 enum state
33 m_getfld2(enum state s, struct field *f, FILE *msg)
34 {
35         char *tmpline = NULL;
36         size_t len = 0;
37         ssize_t nchars;
38         enum threestate falted;
39
40         nchars = getline(&tmpline, &len, msg);
41         if (nchars == -1) {
42                 if (feof(msg)) {
43                         return FILEEOF2;
44                 } else {
45                         return IOERR2;
46                 }
47         }
48
49         if (nchars >= NAMESZ) {
50                 free(tmpline);
51                 return LENERR2;
52         }
53
54         *f->name = '\0';
55         f->namelen = 0;
56
57         switch (s) {
58         case FLD2:
59                 if (*(tmpline + nchars - 1) != '\n') {
60                         if (f->value) {
61                                 free(f->value);
62                         }
63                         f->value = tmpline;
64                         f->valuelen = nchars;
65                         f->alloclen = len;
66                         return FMTERR2;
67                 }
68
69                 if (nchars > 0 && (*tmpline == '\n' || *tmpline == '-')) {
70                         /* header/body separator found */
71                         free(tmpline);
72                         return m_getfld2(BODY2, f, msg);
73                 }
74
75                 f->namelen = copyname(f->name, tmpline);
76                 if (f->namelen < 1) {
77                         if (f->value) {
78                                 free(f->value);
79                         }
80                         f->value = tmpline;
81                         f->valuelen = nchars;
82                         f->alloclen = len;
83                         return FMTERR2;
84                 }
85
86                 /* copy the field's value */
87                 if (f->alloclen <= nchars - f->namelen) {
88                         f->value = mh_xrealloc(f->value, f->alloclen + len);
89                         f->alloclen += len;
90                 }
91                 strcpy(f->value, tmpline + f->namelen + 1);
92                 f->valuelen = nchars - f->namelen - 1;
93
94                 while ((falted = is_falted(msg)) == B_TRUE) {
95                         nchars = getline(&tmpline, &len, msg);
96                         if (nchars <= 0) {
97                                 free(tmpline);
98                                 return IOERR2;
99                         }
100
101                         if (nchars >= NAMESZ) {
102                                 free(tmpline);
103                                 return LENERR2;
104                         }
105
106                         if (*(tmpline + nchars - 1) != '\n') {
107                                 if (f->value) {
108                                         free(f->value);
109                                 }
110                                 f->value = tmpline;
111                                 f->valuelen = nchars;
112                                 f->alloclen = len;
113                                 return FMTERR2;
114                         }
115
116                         if (f->alloclen - f->valuelen <= nchars) {
117                                 f->value = mh_xrealloc(f->value,
118                                                 f->alloclen + len);
119                                 f->alloclen += len;
120                         }
121                         strcpy(f->value + f->valuelen, tmpline);
122                         f->valuelen += nchars;
123
124                 }
125
126                 if (falted == FAIL) {
127                         free(tmpline);
128                         return IOERR2;
129                 }
130
131                 free(tmpline);
132                 return FLD2;
133
134         case BODY2:
135                 if (f->value) {
136                         free(f->value);
137                 }
138                 f->value = tmpline;
139                 f->valuelen = nchars;
140                 f->alloclen = len;
141                 return BODY2;
142
143         default:
144                 /* give error states back as received */
145                 return s;
146         }
147 }
148
149 static enum threestate
150 is_falted(FILE *msg)
151 {
152         enum threestate ret;
153         int c;
154
155         if ((c = getc(msg)) < 0) {
156                 if (feof(msg)) {
157                         clearerr(msg);
158                         return B_FALSE;
159                 } else {
160                         return FAIL;
161                 }
162         }
163         if (isblank(c)) {
164                 ret = B_TRUE;
165         } else {
166                 ret = B_FALSE;
167         }
168         if (ungetc(c, msg) != c) {
169                 return FAIL;
170         }
171         return ret;
172 }
173
174 static size_t
175 copyname(char *dst, char *src)
176 {
177         size_t len;
178         char *cp, *sep;
179
180         if (!(sep = strchr(src, ':'))) {
181                 return 0;
182         }
183         /* whitespace is forbidden in name */
184         for (cp=src; cp<sep; cp++) {
185                 if (isspace(*cp)) {
186                         return 0;
187                 }
188         }
189
190         len = sep - src;
191         if (len >= NAMESZ) {
192                 return 0;
193         }
194
195         src[len] = '\0';
196         strcpy(dst, src);
197
198         return strlen(dst);
199 }