Add new implementation m_getfld2()
[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 memory is allocated for f->value.
30 ** For the states LENERR2, FMTERR2, ERR2 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 ERR2;
46                 }
47         }
48
49         if (nchars >= NAMESZ) {
50                 free(tmpline);
51                 return LENERR2;
52         }
53
54         switch (s) {
55         case FLD2:
56                 if (*(tmpline + nchars - 1) != '\n') {
57                         free(tmpline);
58                         return FMTERR2;
59                 }
60
61                 if (nchars > 0 && (*tmpline == '\n' || *tmpline == '-')) {
62                         /* header/body separator found */
63                         free(tmpline);
64                         return m_getfld2(BODY2, f, msg);
65                 }
66
67                 f->namelen = copyname(f->name, tmpline);
68                 if (f->namelen < 1) {
69                         free(tmpline);
70                         return FMTERR2;
71                 }
72
73                 /* copy the field's value */
74                 if (f->alloclen <= nchars - f->namelen) {
75                         f->value = mh_xrealloc(f->value, f->alloclen + len);
76                         f->alloclen += len;
77                 }
78                 strcpy(f->value, tmpline + f->namelen + 1);
79                 f->valuelen = nchars - f->namelen - 1;
80
81                 while ((falted = is_falted(msg)) == B_TRUE) {
82                         nchars = getline(&tmpline, &len, msg);
83                         if (nchars <= 0) {
84                                 free(tmpline);
85                                 return ERR2;
86                         }
87
88                         if (nchars >= NAMESZ) {
89                                 free(tmpline);
90                                 return LENERR2;
91                         }
92
93                         if (*(tmpline + nchars - 1) != '\n') {
94                                 free(tmpline);
95                                 return FMTERR2;
96                         }
97
98                         if (f->alloclen - f->valuelen <= nchars) {
99                                 f->value = mh_xrealloc(f->value,
100                                                 f->alloclen + len);
101                                 f->alloclen += len;
102                         }
103                         strcpy(f->value + f->valuelen, tmpline);
104                         f->valuelen += nchars;
105
106                 }
107
108                 if (falted == FAIL) {
109                         free(tmpline);
110                         return ERR2;
111                 }
112
113                 free(tmpline);
114                 return FLD2;
115
116         case BODY2:
117                 *f->name = '\0';
118                 f->namelen = 0;
119                 if (f->value) {
120                         free(f->value);
121                 }
122                 f->value = tmpline;
123                 f->valuelen = nchars;
124                 f->alloclen = len;
125                 return BODY2;
126
127         default:
128                 /* give error states back as received */
129                 return s;
130         }
131 }
132
133 static enum threestate
134 is_falted(FILE *msg)
135 {
136         enum threestate ret;
137         int c;
138
139         if ((c = getc(msg)) < 0) {
140                 if (feof(msg)) {
141                         clearerr(msg);
142                         return B_FALSE;
143                 } else {
144                         return FAIL;
145                 }
146         }
147         if (isblank(c)) {
148                 ret = B_TRUE;
149         } else {
150                 ret = B_FALSE;
151         }
152         if (ungetc(c, msg) != c) {
153                 return FAIL;
154         }
155         return ret;
156 }
157
158 static size_t
159 copyname(char *dst, char *src)
160 {
161         size_t len;
162         char *sep = strchr(src, ':');
163
164         if (!sep) {
165                 return 0;
166         }
167
168         len = sep - src;
169         if (len >= NAMESZ) {
170                 return 0;
171         }
172
173         src[len] = '\0';
174         strcpy(dst, src);
175
176         return strlen(dst);
177 }