Commit 15f1743e 15f1743ef4e2ab917761fa4f9e0007dcd6f29b35 by Sam Roberts

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.
1 parent 1e3420de
...@@ -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. */
......