header_parse(): wasn't ignoring LWSP after "bcc : ...", fixed.
header_set_value(): there was no way to remove a field, now calling set with a field value of NULL removes the field. header_get_value(): was concatenating the values of all the fields with the same name, now it doesn't. header_get_address(): convenience function to get an address_t from a header field. header.h: sorted API functions to top of header, and ones used in implementing header_t to the bottom.
Showing
2 changed files
with
156 additions
and
86 deletions
... | @@ -64,67 +64,68 @@ extern "C" { | ... | @@ -64,67 +64,68 @@ extern "C" { |
64 | 64 | ||
65 | /* Mime support header attribute */ | 65 | /* Mime support header attribute */ |
66 | 66 | ||
67 | extern int header_create __P ((header_t *, const char *, | 67 | extern int header_create __P ((header_t *, const char *, size_t, void *)); |
68 | size_t, void *)); | 68 | extern void header_destroy __P ((header_t *, void *)); |
69 | extern void header_destroy __P ((header_t *, void *)); | 69 | extern void *header_get_owner __P ((header_t)); |
70 | extern void *header_get_owner __P ((header_t)); | 70 | |
71 | 71 | extern int header_is_modified __P ((header_t)); | |
72 | extern int header_is_modified __P ((header_t)); | 72 | extern int header_clear_modified __P ((header_t)); |
73 | extern int header_clear_modified __P ((header_t)); | 73 | |
74 | 74 | /* Set and get field values by field name. */ | |
75 | extern int header_set_value __P ((header_t, const char *, | 75 | extern int header_set_value __P ((header_t, const char *, const char *, int)); |
76 | const char *, int)); | 76 | extern int header_get_value __P ((header_t, const char *, char *, size_t, size_t *)); |
77 | extern int header_set_set_value __P ((header_t, | 77 | extern int header_aget_value __P ((header_t, const char *, char **)); |
78 | int (*_set_value) __P ((header_t, | 78 | |
79 | const char *, | 79 | /* Get field values as an address_t. */ |
80 | const char *, | 80 | extern int header_get_address __P ((header_t, const char *, address_t *)); |
81 | int)), | 81 | |
82 | void *)); | 82 | /* Set and get field values by field index (1-based). */ |
83 | 83 | extern int header_get_field_count __P ((header_t, size_t *count)); | |
84 | extern int header_get_value __P ((header_t, const char *, char *, | 84 | extern int header_get_field_value __P ((header_t, size_t index, char *, size_t, size_t *)); |
85 | size_t, size_t *)); | 85 | extern int header_get_field_name __P ((header_t, size_t index, char *, size_t, size_t *)); |
86 | extern int header_aget_value __P ((header_t, const char *, char **)); | 86 | extern int header_aget_field_value __P ((header_t, size_t index, char **)); |
87 | extern int header_set_get_value __P ((header_t, | 87 | extern int header_aget_field_name __P ((header_t, size_t index, char **)); |
88 | int (*_get_value) __P ((header_t, | 88 | |
89 | const char *, | 89 | extern int header_get_stream __P ((header_t, stream_t *)); |
90 | char *, | 90 | extern int header_set_stream __P ((header_t, stream_t, void *)); |
91 | size_t, | 91 | |
92 | size_t *)), | 92 | extern int header_size __P ((header_t, size_t *)); |
93 | void *)); | 93 | extern int header_lines __P ((header_t, size_t *)); |
94 | extern int header_set_get_fvalue __P ((header_t, | 94 | |
95 | int (*_get_value) __P ((header_t, | 95 | |
96 | const char *, | 96 | extern int header_set_set_value __P ((header_t, |
97 | char *, | 97 | int (*_set_value) __P ((header_t, |
98 | size_t, | 98 | const char *, |
99 | size_t *)), | 99 | const char *, |
100 | void *)); | 100 | int)), void *)); |
101 | 101 | ||
102 | extern int header_get_field_count __P ((header_t, size_t *)); | 102 | extern int header_set_get_value __P ((header_t, |
103 | extern int header_get_field_value __P ((header_t, size_t, char *, | 103 | int (*_get_value) __P ((header_t, |
104 | size_t, size_t *)); | 104 | const char *, |
105 | extern int header_aget_field_value __P ((header_t, size_t, char **)); | 105 | char *, |
106 | extern int header_get_field_name __P ((header_t, size_t, char *, | 106 | size_t, |
107 | size_t, size_t *)); | 107 | size_t *)), |
108 | extern int header_aget_field_name __P ((header_t, size_t, char **)); | 108 | void *)); |
109 | 109 | extern int header_set_get_fvalue __P ((header_t, | |
110 | extern int header_get_stream __P ((header_t, stream_t *)); | 110 | int (*_get_value) __P ((header_t, |
111 | extern int header_set_stream __P ((header_t, stream_t, void *)); | 111 | const char *, |
112 | 112 | char *, | |
113 | extern int header_size __P ((header_t, size_t *)); | 113 | size_t, |
114 | extern int header_set_size __P ((header_t, int (*_size) | 114 | size_t *)), |
115 | __P ((header_t, size_t *)), void *)); | 115 | void *)); |
116 | 116 | ||
117 | extern int header_lines __P ((header_t, size_t *)); | 117 | extern int header_set_size __P ((header_t, int (*_size) |
118 | extern int header_set_lines __P ((header_t, | 118 | __P ((header_t, size_t *)), void *)); |
119 | int (*_lines) __P ((header_t, | 119 | |
120 | size_t *)), | 120 | extern int header_set_lines __P ((header_t, |
121 | void *)); | 121 | int (*_lines) __P ((header_t, |
122 | 122 | size_t *)), void *)); | |
123 | extern int header_set_fill __P ((header_t, | 123 | |
124 | int (*_fill) __P ((header_t, char *, | 124 | extern int header_set_fill __P ((header_t, |
125 | size_t, off_t, | 125 | int (*_fill) __P ((header_t, char *, |
126 | size_t *)), | 126 | size_t, off_t, |
127 | void *owner)); | 127 | size_t *)), void *owner)); |
128 | |||
128 | #ifdef __cplusplus | 129 | #ifdef __cplusplus |
129 | } | 130 | } |
130 | #endif | 131 | #endif | ... | ... |
... | @@ -30,6 +30,8 @@ | ... | @@ -30,6 +30,8 @@ |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #include <mailutils/stream.h> | 32 | #include <mailutils/stream.h> |
33 | #include <mailutils/address.h> | ||
34 | |||
33 | #include <header0.h> | 35 | #include <header0.h> |
34 | 36 | ||
35 | #define HEADER_MODIFIED 1 | 37 | #define HEADER_MODIFIED 1 |
... | @@ -147,6 +149,7 @@ header_parse (header_t header, const char *blurb, int len) | ... | @@ -147,6 +149,7 @@ header_parse (header_t header, const char *blurb, int len) |
147 | return 0; | 149 | return 0; |
148 | 150 | ||
149 | header->blurb_len = len; | 151 | header->blurb_len = len; |
152 | /* Why "+ 1", if for a terminating NULL, where is written? */ | ||
150 | header->blurb = calloc (1, header->blurb_len + 1); | 153 | header->blurb = calloc (1, header->blurb_len + 1); |
151 | if (header->blurb == NULL) | 154 | if (header->blurb == NULL) |
152 | return ENOMEM; | 155 | return ENOMEM; |
... | @@ -157,12 +160,13 @@ header_parse (header_t header, const char *blurb, int len) | ... | @@ -157,12 +160,13 @@ header_parse (header_t header, const char *blurb, int len) |
157 | header->hdr = NULL; | 160 | header->hdr = NULL; |
158 | header->hdr_count = 0; | 161 | header->hdr_count = 0; |
159 | 162 | ||
160 | /* Get a header, a header is : | 163 | /* Get a header, a header is: |
161 | field-name ':' ' ' field-value '\r' '\n' | 164 | field-name LWSP ':' |
162 | [ (' ' | '\t') field-value '\r' '\n' ] | 165 | LWSP field-value '\r' '\n' |
166 | *[ (' ' | '\t') field-value '\r' '\n' ] | ||
163 | */ | 167 | */ |
164 | /* First loop goes throught the blurb */ | 168 | /* First loop goes through the blurb */ |
165 | for (header_start = header->blurb;; header_start = ++header_end) | 169 | for (header_start = header->blurb; ; header_start = ++header_end) |
166 | { | 170 | { |
167 | char *fn, *fn_end, *fv, *fv_end; | 171 | char *fn, *fn_end, *fv, *fv_end; |
168 | 172 | ||
... | @@ -171,8 +175,8 @@ header_parse (header_t header, const char *blurb, int len) | ... | @@ -171,8 +175,8 @@ header_parse (header_t header, const char *blurb, int len) |
171 | || header_start[0] == '\n') | 175 | || header_start[0] == '\n') |
172 | break; | 176 | break; |
173 | 177 | ||
174 | /* Second loop extract one header field. */ | 178 | /* Second loop extract one header field. */ |
175 | for (header_start2 = header_start;;header_start2 = ++header_end) | 179 | for (header_start2 = header_start; ;header_start2 = ++header_end) |
176 | { | 180 | { |
177 | header_end = memchr (header_start2, '\n', len); | 181 | header_end = memchr (header_start2, '\n', len); |
178 | if (header_end == NULL) | 182 | if (header_end == NULL) |
... | @@ -210,18 +214,27 @@ header_parse (header_t header, const char *blurb, int len) | ... | @@ -210,18 +214,27 @@ header_parse (header_t header, const char *blurb, int len) |
210 | { | 214 | { |
211 | char *colon = memchr (header_start, ':', header_end - header_start); | 215 | char *colon = memchr (header_start, ':', header_end - header_start); |
212 | 216 | ||
217 | #define ISLWSP(c) (((c) == ' ' || (c) == '\t')) | ||
213 | /* Houston we have a problem. */ | 218 | /* Houston we have a problem. */ |
214 | if (colon == NULL) | 219 | if (colon == NULL) |
215 | break; /* Disregard the rest and bailout. */ | 220 | break; /* Disregard the rest and bailout. */ |
216 | 221 | ||
217 | fn = header_start; | 222 | fn = header_start; |
218 | fn_end = colon; | 223 | fn_end = colon; |
219 | /* Skip leading spaces. */ | 224 | /* Shrink any LWSP after the field name -- CRITICAL for |
220 | while (*(++colon) == ' '); | 225 | later name comparisons to work correctly! */ |
221 | fv = colon; | 226 | while(ISLWSP(fn_end[-1])) |
227 | fn_end--; | ||
228 | |||
229 | fv = colon + 1; | ||
222 | fv_end = header_end; | 230 | fv_end = header_end; |
223 | } | ||
224 | 231 | ||
232 | /* Skip any LWSP before the field value -- unnecessary, but | ||
233 | might make some field values look a little tidier. */ | ||
234 | while(ISLWSP(fv[0])) | ||
235 | fv++; | ||
236 | } | ||
237 | #undef ISLWSP | ||
225 | /* Allocate a new slot for the field:value. */ | 238 | /* Allocate a new slot for the field:value. */ |
226 | hdr = realloc (header->hdr, (header->hdr_count + 1) * sizeof (*hdr)); | 239 | hdr = realloc (header->hdr, (header->hdr_count + 1) * sizeof (*hdr)); |
227 | if (hdr == NULL) | 240 | if (hdr == NULL) |
... | @@ -246,12 +259,18 @@ header_parse (header_t header, const char *blurb, int len) | ... | @@ -246,12 +259,18 @@ header_parse (header_t header, const char *blurb, int len) |
246 | /* FIXME: grossly inneficient, to many copies and reallocating. | 259 | /* FIXME: grossly inneficient, to many copies and reallocating. |
247 | This all header business need a good rewrite. */ | 260 | This all header business need a good rewrite. */ |
248 | int | 261 | int |
249 | header_set_value (header_t header, const char *fn, const char *fv, int replace) | 262 | header_set_value (header_t header, const char *fn, const char *fv, |
263 | int replace) | ||
250 | { | 264 | { |
251 | char *blurb; | 265 | char *blurb; |
252 | size_t len; | 266 | size_t len; |
253 | 267 | ||
254 | if (header == NULL || fn == NULL || fv == NULL) | 268 | if (header == NULL || fn == NULL) |
269 | return EINVAL; | ||
270 | |||
271 | /* An fv of NULL means delete the field, but only do it if replace | ||
272 | was also set to true! */ | ||
273 | if (fv == NULL && !replace) | ||
255 | return EINVAL; | 274 | return EINVAL; |
256 | 275 | ||
257 | /* Overload. */ | 276 | /* Overload. */ |
... | @@ -270,13 +289,26 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) | ... | @@ -270,13 +289,26 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) |
270 | the pointers by calling header_parse () this is wastefull, we're just | 289 | the pointers by calling header_parse () this is wastefull, we're just |
271 | fragmenting the memory it can be done better. But that may imply a | 290 | fragmenting the memory it can be done better. But that may imply a |
272 | rewite of the headers ... for another day. */ | 291 | rewite of the headers ... for another day. */ |
292 | |||
293 | /* If replace, remove all fields in the header blurb that have the | ||
294 | same name as the field we are writing. | ||
295 | |||
296 | Algorithm: | ||
297 | |||
298 | for i = 0, ... i < max_hdrs | ||
299 | - if ith field has name 'fn' memmove() all following fields up over | ||
300 | this field | ||
301 | - reparse the headers | ||
302 | - restart the for loop at the ith field | ||
303 | */ | ||
273 | if (replace) | 304 | if (replace) |
274 | { | 305 | { |
275 | size_t name_len; | 306 | size_t name_len; |
276 | size_t i; | 307 | size_t i; |
277 | size_t fn_len; /* Field Name len. */ | 308 | size_t fn_len; /* Field Name len. */ |
278 | size_t fv_len; /* Field Value len. */ | 309 | size_t fv_len; /* Field Value len. */ |
279 | len = header->blurb_len; | 310 | len = header->blurb_len; |
311 | /* Find FN in the header fields... */ | ||
280 | for (name_len = strlen (fn), i = 0; i < header->hdr_count; i++) | 312 | for (name_len = strlen (fn), i = 0; i < header->hdr_count; i++) |
281 | { | 313 | { |
282 | fn_len = header->hdr[i].fn_end - header->hdr[i].fn; | 314 | fn_len = header->hdr[i].fn_end - header->hdr[i].fn; |
... | @@ -285,28 +317,41 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) | ... | @@ -285,28 +317,41 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) |
285 | strncasecmp (header->hdr[i].fn, fn, fn_len) == 0) | 317 | strncasecmp (header->hdr[i].fn, fn, fn_len) == 0) |
286 | { | 318 | { |
287 | blurb = header->blurb; | 319 | blurb = header->blurb; |
320 | /* ... and if its NOT the last field, move the next field | ||
321 | through to last field into its place, */ | ||
288 | if ((i + 1) < header->hdr_count) | 322 | if ((i + 1) < header->hdr_count) |
289 | { | 323 | { |
290 | memmove (header->hdr[i].fn, header->hdr[i + 1].fn, | 324 | memmove (header->hdr[i].fn, header->hdr[i + 1].fn, |
291 | header->hdr[header->hdr_count - 1].fv_end | 325 | header->hdr[header->hdr_count - 1].fv_end |
292 | - header->hdr[i + 1].fn + 3); | 326 | - header->hdr[i + 1].fn + 3); |
293 | } | 327 | } |
328 | /* or if it is the last, just truncate the fields. */ | ||
294 | else | 329 | else |
295 | { | 330 | { |
296 | header->hdr[i].fn[0] = '\n'; | 331 | header->hdr[i].fn[0] = '\n'; |
297 | header->hdr[i].fn[1] = '\0'; | 332 | header->hdr[i].fn[1] = '\0'; |
298 | } | 333 | } |
299 | /* readjust the pointers if move */ | 334 | /* Readjust the pointers. */ |
300 | len -= fn_len + fv_len + 3; /* :<sp>\n */ | 335 | /* FIXME: I'm not sure this 3 will work when the |
336 | original data looked like: | ||
337 | Field : Value | ||
338 | Test this... and why not just do a strlen(blurb)? | ||
339 | */ | ||
340 | len -= fn_len + fv_len + 3; /* :<sp>\n */ | ||
301 | i--; | 341 | i--; |
302 | blurb = header->blurb; | 342 | blurb = header->blurb; |
303 | header_parse (header, blurb, len); | 343 | header_parse (header, blurb, len); |
304 | free (blurb); | 344 | free (blurb); |
345 | header->flags |= HEADER_MODIFIED; | ||
305 | } | 346 | } |
306 | } | 347 | } |
307 | } | 348 | } |
308 | 349 | ||
309 | /* Replacing was taking care of above now just add to the end the new | 350 | /* If FV is NULL, then we are done. */ |
351 | if (!fv) | ||
352 | return 0; | ||
353 | |||
354 | /* Replacing was taken care of above, now write the new header. | ||
310 | header. Really not cute. | 355 | header. Really not cute. |
311 | COLON SPACE NL = 3 ; */ | 356 | COLON SPACE NL = 3 ; */ |
312 | len = strlen (fn) + strlen (fv) + 3; | 357 | len = strlen (fn) + strlen (fv) + 3; |
... | @@ -319,8 +364,10 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) | ... | @@ -319,8 +364,10 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) |
319 | 364 | ||
320 | sprintf (blurb, "%s: %s", fn, fv); | 365 | sprintf (blurb, "%s: %s", fn, fv); |
321 | 366 | ||
322 | /* Strip off trailing newlines. */ | 367 | /* Strip off trailing newlines and LWSP. */ |
323 | while (blurb[strlen (blurb) - 1] == '\n') | 368 | while (blurb[strlen (blurb) - 1] == '\n' || |
369 | blurb[strlen (blurb) - 1] == ' ' || | ||
370 | blurb[strlen (blurb) - 1] == '\t') | ||
324 | { | 371 | { |
325 | blurb[strlen (blurb) - 1] = '\0'; | 372 | blurb[strlen (blurb) - 1] = '\0'; |
326 | } | 373 | } |
... | @@ -336,7 +383,7 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) | ... | @@ -336,7 +383,7 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) |
336 | header->blurb = NULL; | 383 | header->blurb = NULL; |
337 | } | 384 | } |
338 | else | 385 | else |
339 | blurb [len] = '\n'; | 386 | blurb[len] = '\n'; |
340 | 387 | ||
341 | /* before parsing the new blurb make sure it is properly terminated | 388 | /* before parsing the new blurb make sure it is properly terminated |
342 | by \n\n. The trailing NL separator. */ | 389 | by \n\n. The trailing NL separator. */ |
... | @@ -515,7 +562,8 @@ header_get_value (header_t header, const char *name, char *buffer, | ... | @@ -515,7 +562,8 @@ header_get_value (header_t header, const char *name, char *buffer, |
515 | parsing (_parse()) is done it's not take to account. So we just stuff | 562 | parsing (_parse()) is done it's not take to account. So we just stuff |
516 | in the buffer all the field-values to a corresponding field-name. | 563 | in the buffer all the field-values to a corresponding field-name. |
517 | FIXME: Should we kosher the output ? meaning replace occurences of | 564 | FIXME: Should we kosher the output ? meaning replace occurences of |
518 | " \t\r\n" for spaces ? for now we don't. */ | 565 | " \t\r\n" for spaces ? for now we don't. |
566 | */ | ||
519 | for (name_len = strlen (name), i = 0; i < header->hdr_count; i++) | 567 | for (name_len = strlen (name), i = 0; i < header->hdr_count; i++) |
520 | { | 568 | { |
521 | fn_len = header->hdr[i].fn_end - header->hdr[i].fn; | 569 | fn_len = header->hdr[i].fn_end - header->hdr[i].fn; |
... | @@ -524,6 +572,7 @@ header_get_value (header_t header, const char *name, char *buffer, | ... | @@ -524,6 +572,7 @@ header_get_value (header_t header, const char *name, char *buffer, |
524 | { | 572 | { |
525 | fv_len = (header->hdr[i].fv_end - header->hdr[i].fv); | 573 | fv_len = (header->hdr[i].fv_end - header->hdr[i].fv); |
526 | /* FIXME:FIXME:PLEASE: hack, add a space/nl separator */ | 574 | /* FIXME:FIXME:PLEASE: hack, add a space/nl separator */ |
575 | /* | ||
527 | if (total && (threshold - 2) > 0) | 576 | if (total && (threshold - 2) > 0) |
528 | { | 577 | { |
529 | if (buffer) | 578 | if (buffer) |
... | @@ -534,6 +583,7 @@ header_get_value (header_t header, const char *name, char *buffer, | ... | @@ -534,6 +583,7 @@ header_get_value (header_t header, const char *name, char *buffer, |
534 | threshold -= 2; | 583 | threshold -= 2; |
535 | total += 2; | 584 | total += 2; |
536 | } | 585 | } |
586 | */ | ||
537 | total += fv_len; | 587 | total += fv_len; |
538 | /* Can everything fit in the buffer. */ | 588 | /* Can everything fit in the buffer. */ |
539 | if (buffer && threshold > 0) | 589 | if (buffer && threshold > 0) |
... | @@ -543,6 +593,9 @@ header_get_value (header_t header, const char *name, char *buffer, | ... | @@ -543,6 +593,9 @@ header_get_value (header_t header, const char *name, char *buffer, |
543 | buffer += buflen; | 593 | buffer += buflen; |
544 | threshold -= buflen; | 594 | threshold -= buflen; |
545 | } | 595 | } |
596 | |||
597 | /* Jump out after the first header we found. -sr */ | ||
598 | break; | ||
546 | } | 599 | } |
547 | } | 600 | } |
548 | if (buffer) | 601 | if (buffer) |
... | @@ -567,8 +620,23 @@ header_aget_value (header_t header, const char *name, char **pvalue) | ... | @@ -567,8 +620,23 @@ header_aget_value (header_t header, const char *name, char **pvalue) |
567 | header_get_value (header, name, value, n + 1, NULL); | 620 | header_get_value (header, name, value, n + 1, NULL); |
568 | *pvalue = value; | 621 | *pvalue = value; |
569 | } | 622 | } |
570 | else | 623 | |
571 | *pvalue = strdup (""); | 624 | return status; |
625 | } | ||
626 | |||
627 | int | ||
628 | header_get_address (header_t header, const char *name, address_t *addr) | ||
629 | { | ||
630 | char* value = NULL; | ||
631 | int status = header_aget_value(header, name, &value); | ||
632 | |||
633 | if(status) | ||
634 | return status; | ||
635 | |||
636 | status = address_create(addr, value); | ||
637 | |||
638 | free(value); | ||
639 | |||
572 | return status; | 640 | return status; |
573 | } | 641 | } |
574 | 642 | ||
... | @@ -654,7 +722,8 @@ header_get_field_value (header_t header, size_t num, char *buf, | ... | @@ -654,7 +722,8 @@ header_get_field_value (header_t header, size_t num, char *buf, |
654 | size_t buflen, size_t *nwritten) | 722 | size_t buflen, size_t *nwritten) |
655 | { | 723 | { |
656 | size_t len; | 724 | size_t len; |
657 | if (header == NULL) | 725 | |
726 | if (header == NULL || num < 1) | ||
658 | return EINVAL; | 727 | return EINVAL; |
659 | 728 | ||
660 | /* Try to fill out the buffer, if we know how. */ | 729 | /* Try to fill out the buffer, if we know how. */ | ... | ... |
-
Please register or sign in to post a comment