1 /*
2 * This file is part of libESMTP, a library for submission of RFC 2822
3 * formatted electronic mail messages using the SMTP protocol described
4 * in RFC 2821.
5 *
6 * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <assert.h>
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <time.h>
35 #ifdef HAVE_GETTIMEOFDAY
36 # include <sys/time.h>
37 #endif
38 #include <errno.h>
39
40 #include <missing.h>
41
42 #include "libesmtp-private.h"
43 #include "headers.h"
44 #include "htable.h"
45 #include "rfc2822date.h"
46 #include "api.h"
47
48 struct rfc2822_header
49 {
50 struct rfc2822_header *next;
51 struct header_info *info; /* Info for setting and printing */
52 char *header; /* Header name */
53 void *value; /* Header value */
54 };
55
56 typedef int (*hdrset_t) (struct rfc2822_header *, va_list);
57 typedef void (*hdrprint_t) (smtp_message_t, struct rfc2822_header *);
58 typedef void (*hdrdestroy_t) (struct rfc2822_header *);
59
60 struct header_actions
61 {
62 const char *name; /* Header for which the action is specified */
63 unsigned int flags; /* Header flags */
64 hdrset_t set; /* Function to set header value from API */
65 hdrprint_t print; /* Function to print the header value */
66 hdrdestroy_t destroy; /* Function to destroy the header value */
67 };
68
69 struct header_info
70 {
71 const struct header_actions *action;
72 struct rfc2822_header *hdr; /* Pointer to most recently defined header */
73 unsigned int seen : 1; /* Header has been seen in the message */
74 unsigned int override : 1; /* LibESMTP is overriding the message */
75 unsigned int prohibit : 1; /* Header may not appear in the message */
76 };
77
78 #define NELT(x) ((int) (sizeof x / sizeof x[0]))
79
80 #define OPTIONAL 0
81 #define SHOULD 1
82 #define REQUIRE 2
83 #define PROHIBIT 4
84 #define PRESERVE 8
85 #define LISTVALUE 16
86 #define MULTIPLE 32
87
88 static struct rfc2822_header *create_header (smtp_message_t message,
89 const char *header,
90 struct header_info *info);
91 void destroy_string (struct rfc2822_header *header);
92 void destroy_mbox_list (struct rfc2822_header *header);
93 struct header_info *find_header (smtp_message_t message,
94 const char *name, int len);
95 struct header_info *insert_header (smtp_message_t message, const char *name);
96
97 /* RFC 2822 headers processing */
98
99 /****************************************************************************
100 * Functions for setting and printing header values
101 ****************************************************************************/
102
103 static int
set_string(struct rfc2822_header * header,va_list alist)104 set_string (struct rfc2822_header *header, va_list alist)
105 {
106 const char *value;
107
108 assert (header != NULL);
109
110 if (header->value != NULL) /* Already set */
111 return 0;
112
113 value = va_arg (alist, const char *);
114 if (value == NULL)
115 return 0;
116 header->value = strdup (value);
117 return header->value != NULL;
118 }
119
120 static int
set_string_null(struct rfc2822_header * header,va_list alist)121 set_string_null (struct rfc2822_header *header, va_list alist)
122 {
123 const char *value;
124
125 assert (header != NULL);
126
127 if (header->value != NULL) /* Already set */
128 return 0;
129
130 value = va_arg (alist, const char *);
131 if (value == NULL)
132 return 1;
133 header->value = strdup (value);
134 return header->value != NULL;
135 }
136
137 /* Print header-name ": " header-value "\r\n" */
138 static void
print_string(smtp_message_t message,struct rfc2822_header * header)139 print_string (smtp_message_t message, struct rfc2822_header *header)
140 {
141 assert (message != NULL && header != NULL);
142
143 /* TODO: implement line folding at white spaces */
144 vconcatenate (&message->hdr_buffer, header->header, ": ",
145 (header->value != NULL) ? header->value : "", "\r\n", NULL);
146 }
147
148 void
destroy_string(struct rfc2822_header * header)149 destroy_string (struct rfc2822_header *header)
150 {
151 assert (header != NULL);
152
153 if (header->value != NULL)
154 free (header->value);
155 }
156
157 /* Print header-name ": <" message-id ">\r\n" */
158 static void
print_message_id(smtp_message_t message,struct rfc2822_header * header)159 print_message_id (smtp_message_t message, struct rfc2822_header *header)
160 {
161 const char *message_id;
162 char buf[64];
163 #ifdef HAVE_GETTIMEOFDAY
164 struct timeval tv;
165 #endif
166
167 assert (message != NULL && header != NULL);
168
169 message_id = header->value;
170 if (message_id == NULL)
171 {
172 #ifdef HAVE_GETTIMEOFDAY
173 if (gettimeofday (&tv, NULL) != -1) /* This shouldn't fail ... */
174 snprintf (buf, sizeof buf, "%ld.%ld.%d@%s", tv.tv_sec, tv.tv_usec,
175 getpid (), message->session->localhost);
176 else /* ... but if it does fall back to using time() */
177 #endif
178 snprintf (buf, sizeof buf, "%ld.%d@%s", time (NULL),
179 getpid (), message->session->localhost);
180 message_id = buf;
181 }
182 /* TODO: implement line folding at white spaces */
183 vconcatenate (&message->hdr_buffer,
184 header->header, ": <", message_id, ">\r\n",
185 NULL);
186 }
187
188 /****/
189
190 static int
set_date(struct rfc2822_header * header,va_list alist)191 set_date (struct rfc2822_header *header, va_list alist)
192 {
193 const time_t *value;
194
195 assert (header != NULL);
196
197 if ((time_t) header->value != (time_t) 0) /* Already set */
198 return 0;
199
200 value = va_arg (alist, const time_t *);
201 header->value = (void *) *value;
202 return 1;
203 }
204
205 /* Print header-name ": " formatted-date "\r\n" */
206 static void
print_date(smtp_message_t message,struct rfc2822_header * header)207 print_date (smtp_message_t message, struct rfc2822_header *header)
208 {
209 char buf[64];
210 time_t when;
211
212 assert (message != NULL && header != NULL);
213
214 when = (time_t) header->value;
215 if (when == (time_t) 0)
216 time (&when);
217 vconcatenate (&message->hdr_buffer, header->header, ": ",
218 rfc2822date (buf, sizeof buf, &when), "\r\n", NULL);
219 }
220
221 /****/
222
223 struct mbox
224 {
225 struct mbox *next;
226 char *mailbox;
227 char *phrase;
228 };
229
230 void
destroy_mbox_list(struct rfc2822_header * header)231 destroy_mbox_list (struct rfc2822_header *header)
232 {
233 struct mbox *mbox, *next;
234
235 assert (header != NULL);
236
237 mbox = header->value;
238 while (mbox != NULL)
239 {
240 next = mbox->next;
241 if (mbox->phrase != NULL)
242 free ((void *) mbox->phrase);
243 if (mbox->mailbox != NULL)
244 free ((void *) mbox->mailbox);
245 free (mbox);
246 mbox = next;
247 }
248 }
249
250 static int
set_from(struct rfc2822_header * header,va_list alist)251 set_from (struct rfc2822_header *header, va_list alist)
252 {
253 struct mbox *mbox;
254 const char *mailbox;
255 const char *phrase;
256
257 assert (header != NULL);
258
259 phrase = va_arg (alist, const char *);
260 mailbox = va_arg (alist, const char *);
261
262 /* Allow this to succeed as a special case. Effectively requesting
263 default action in print_from(). Fails if explicit values have
264 already been set. */
265 if (phrase == NULL && mailbox == NULL)
266 return header->value == NULL;
267
268 mbox = malloc (sizeof (struct mbox));
269 if (mbox == NULL)
270 return 0;
271 mbox->phrase = (phrase != NULL) ? strdup (phrase) : NULL;
272 mbox->mailbox = strdup (mailbox);
273
274 mbox->next = header->value;
275 header->value = mbox;
276 return 1;
277 }
278
279 /* Print header-name ": " mailbox "\r\n"
280 or header-name ": \"" phrase "\" <" mailbox ">\r\n" */
281 static void
print_from(smtp_message_t message,struct rfc2822_header * header)282 print_from (smtp_message_t message, struct rfc2822_header *header)
283 {
284 struct mbox *mbox;
285 const char *mailbox;
286
287 assert (message != NULL && header != NULL);
288
289 vconcatenate (&message->hdr_buffer, header->header, ": ", NULL);
290 /* TODO: implement line folding at white spaces */
291 if (header->value == NULL)
292 {
293 mailbox = message->reverse_path_mailbox;
294 vconcatenate (&message->hdr_buffer,
295 (mailbox != NULL && *mailbox != '\0') ? mailbox : "<>",
296 "\r\n", NULL);
297 }
298 else
299 for (mbox = header->value; mbox != NULL; mbox = mbox->next)
300 {
301 mailbox = mbox->mailbox;
302 if (mbox->phrase == NULL)
303 vconcatenate (&message->hdr_buffer,
304 (mailbox != NULL && *mailbox != '\0') ? mailbox : "<>",
305 NULL);
306 else
307 vconcatenate (&message->hdr_buffer, "\"", mbox->phrase, "\""
308 " <", (mailbox != NULL) ? mailbox : "", ">", NULL);
309 vconcatenate (&message->hdr_buffer,
310 (mbox->next != NULL) ? ",\r\n " : "\r\n", NULL);
311 }
312 }
313
314 /* Same arguments and syntax as from: except that only one value is
315 allowed. */
316 static int
set_sender(struct rfc2822_header * header,va_list alist)317 set_sender (struct rfc2822_header *header, va_list alist)
318 {
319 struct mbox *mbox;
320 const char *mailbox;
321 const char *phrase;
322
323 assert (header != NULL);
324
325 if (header->value != NULL)
326 return 0;
327
328 phrase = va_arg (alist, const char *);
329 mailbox = va_arg (alist, const char *);
330 if (phrase == NULL && mailbox == NULL)
331 return 0;
332
333 mbox = malloc (sizeof (struct mbox));
334 if (mbox == NULL)
335 return 0;
336 mbox->phrase = (phrase != NULL) ? strdup (phrase) : NULL;
337 mbox->mailbox = strdup (mailbox);
338 mbox->next = NULL;
339
340 mbox->next = header->value;
341 return 1;
342 }
343
344 /* TODO: do nothing if the mailbox is NULL. Check this doesn't fool
345 the protocol engine into thinking it has seen end of file. */
346 /* Print header-name ": " mailbox "\r\n"
347 or header-name ": \"" phrase "\" <" mailbox ">\r\n"
348 */
349 static void
print_sender(smtp_message_t message,struct rfc2822_header * header)350 print_sender (smtp_message_t message, struct rfc2822_header *header)
351 {
352 struct mbox *mbox;
353 const char *mailbox;
354
355 assert (message != NULL && header != NULL);
356
357 vconcatenate (&message->hdr_buffer, header->header, ": ", NULL);
358 mbox = header->value;
359 mailbox = mbox->mailbox;
360 if (mbox->phrase == NULL)
361 vconcatenate (&message->hdr_buffer,
362 (mailbox != NULL && *mailbox != '\0') ? mailbox : "<>",
363 "\r\n", NULL);
364 else
365 vconcatenate (&message->hdr_buffer, "\"", mbox->phrase, "\""
366 " <", (mailbox != NULL) ? mailbox : "", ">\r\n", NULL);
367 }
368
369 static int
set_to(struct rfc2822_header * header,va_list alist)370 set_to (struct rfc2822_header *header, va_list alist)
371 {
372 struct mbox *mbox;
373 const char *mailbox;
374 const char *phrase;
375
376 assert (header != NULL);
377
378 phrase = va_arg (alist, const char *);
379 mailbox = va_arg (alist, const char *);
380 if (phrase == NULL && mailbox == NULL)
381 mbox = NULL;
382 else
383 {
384 mbox = malloc (sizeof (struct mbox));
385 if (mbox == NULL)
386 return 0;
387 mbox->phrase = (phrase != NULL) ? strdup (phrase) : NULL;
388 mbox->mailbox = strdup (mailbox);
389
390 mbox->next = header->value;
391 }
392 header->value = mbox;
393 return 1;
394 }
395
396 static int
set_cc(struct rfc2822_header * header,va_list alist)397 set_cc (struct rfc2822_header *header, va_list alist)
398 {
399 struct mbox *mbox;
400 const char *mailbox;
401 const char *phrase;
402
403 assert (header != NULL);
404
405 phrase = va_arg (alist, const char *);
406 mailbox = va_arg (alist, const char *);
407 if (mailbox == NULL)
408 return 0;
409 mbox = malloc (sizeof (struct mbox));
410 if (mbox == NULL)
411 return 0;
412 mbox->phrase = (phrase != NULL) ? strdup (phrase) : NULL;
413 mbox->mailbox = strdup (mailbox);
414
415 mbox->next = header->value;
416 header->value = mbox;
417 return 1;
418 }
419
420 /* Print header-name ": " mailbox "\r\n"
421 or header-name ": \"" phrase "\" <" mailbox ">\r\n"
422 ad nauseum. */
423 static void
print_cc(smtp_message_t message,struct rfc2822_header * header)424 print_cc (smtp_message_t message, struct rfc2822_header *header)
425 {
426 struct mbox *mbox;
427
428 assert (message != NULL && header != NULL);
429
430 vconcatenate (&message->hdr_buffer, header->header, ": ", NULL);
431 for (mbox = header->value; mbox != NULL; mbox = mbox->next)
432 {
433 if (mbox->phrase == NULL)
434 vconcatenate (&message->hdr_buffer, mbox->mailbox, NULL);
435 else
436 vconcatenate (&message->hdr_buffer,
437 "\"", mbox->phrase, "\" <", mbox->mailbox, ">",
438 NULL);
439 vconcatenate (&message->hdr_buffer,
440 (mbox->next != NULL) ? ",\r\n " : "\r\n", NULL);
441 }
442 }
443
444 /* As above but generate a default value from the recipient list.
445 */
446 static void
print_to(smtp_message_t message,struct rfc2822_header * header)447 print_to (smtp_message_t message, struct rfc2822_header *header)
448 {
449 smtp_recipient_t recipient;
450
451 assert (header != NULL);
452
453 if (header->value != NULL)
454 {
455 print_cc (message, header);
456 return;
457 }
458
459 /* TODO: implement line folding at white spaces */
460 vconcatenate (&message->hdr_buffer, header->header, ": ", NULL);
461 for (recipient = message->recipients;
462 recipient != NULL;
463 recipient = recipient->next)
464 vconcatenate (&message->hdr_buffer, recipient->mailbox,
465 (recipient->next != NULL) ? ",\r\n " : "\r\n",
466 NULL);
467 }
468
469
470 /* Header actions placed here to avoid the need for many akward forward
471 declarations for set_xxx/print_xxx. */
472
473 static const struct header_actions header_actions[] =
474 {
475 /* This is the default header info for a simple string value.
476 */
477 { NULL, OPTIONAL,
478 set_string, print_string, destroy_string},
479 /* A number of headers should be present in every message
480 */
481 { "Date", REQUIRE,
482 set_date, print_date, NULL, },
483 { "From", REQUIRE | LISTVALUE,
484 set_from, print_from, destroy_mbox_list, },
485 /* Certain headers are added when a message is delivered and
486 should not be present in a message being posted or which
487 is in transit. If present in the message they will be stripped
488 and if specified by the API, the relevant APIs will fail. */
489 { "Return-Path", PROHIBIT, NULL, NULL, NULL, },
490 /* RFC 2298 - Delivering MTA may add the Original-Recipient: header
491 using DSN ORCPT parameter and may discard
492 Original-Recipient: headers present in the message.
493 No point in sending it then. */
494 { "Original-Recipient", PROHIBIT, NULL, NULL, NULL, },
495 /* MIME-*: and Content-*: are MIME headers and must not be generated
496 or processed by libESMTP. Similarly, Resent-*: and Received: must
497 be retained unaltered. */
498 { "Content-", PRESERVE, NULL, NULL, NULL, },
499 { "MIME-", PRESERVE, NULL, NULL, NULL, },
500 { "Resent-", PRESERVE, NULL, NULL, NULL, },
501 { "Received", PRESERVE, NULL, NULL, NULL, },
502 /* Headers which are optional but which are recommended to be
503 present. Default action is to provide a default unless the
504 application explicitly requests not to. */
505 { "Message-Id", SHOULD,
506 set_string_null,print_message_id, destroy_string, },
507 /* Remaining headers are known to libESMTP to simplify handling them
508 for the application. All other headers are reaated as simple
509 string values. */
510 { "Sender", OPTIONAL,
511 set_sender, print_sender, destroy_mbox_list, },
512 { "To", OPTIONAL | LISTVALUE,
513 set_to, print_to, destroy_mbox_list, },
514 { "Cc", OPTIONAL | LISTVALUE,
515 set_cc, print_cc, destroy_mbox_list, },
516 { "Bcc", OPTIONAL | LISTVALUE,
517 set_cc, print_cc, destroy_mbox_list, },
518 { "Reply-To", OPTIONAL | LISTVALUE,
519 set_cc, print_cc, destroy_mbox_list, },
520 /* RFC 2298 - MDN request. Syntax is the same as the From: header and
521 default when set to NULL is the same as From: */
522 { "Disposition-Notification-To", OPTIONAL,
523 set_from, print_from, destroy_mbox_list, },
524 /* TODO:
525 In-Reply-To: *(phrase / msgid)
526 References: *(phrase / msgid)
527 Keywords: #phrase
528
529 Handle Resent- versions of
530 To Cc Bcc Message-ID Date Reply-To From Sender
531 */
532 };
533
534 static int
init_header_table(smtp_message_t message)535 init_header_table (smtp_message_t message)
536 {
537 int i;
538 struct header_info *hi;
539
540 assert (message != NULL);
541
542 if (message->hdr_action != NULL)
543 return -1;
544
545 message->hdr_action = h_create ();
546 if (message->hdr_action == NULL)
547 return 0;
548 for (i = 0; i < NELT (header_actions); i++)
549 if (header_actions[i].name != NULL)
550 {
551 hi = h_insert (message->hdr_action, header_actions[i].name, -1,
552 sizeof (struct header_info));
553 if (hi == NULL)
554 return 0;
555 hi->action = &header_actions[i];
556
557 /* REQUIREd headers must be present in the message. SHOULD
558 means the header is optional but its presence is recommended.
559 Create a NULL valued header. This will either be set later
560 with the API, or the print_xxx function will handle the NULL
561 value as a special case, e.g, the To: header is generated
562 from the recipient_t list. */
563 if (hi->action->flags & (REQUIRE | SHOULD))
564 {
565 if (create_header (message, header_actions[i].name, hi) == NULL)
566 return 0;
567 }
568 }
569 return 1;
570 }
571
572 void
destroy_header_table(smtp_message_t message)573 destroy_header_table (smtp_message_t message)
574 {
575 struct rfc2822_header *header, *next;
576
577 assert (message != NULL);
578
579 /* Take out the linked list */
580 for (header = message->headers; header!= NULL; header = next)
581 {
582 next = header->next;
583 if (header->info->action->destroy != NULL)
584 (*header->info->action->destroy) (header);
585 free (header->header);
586 free (header);
587 }
588
589 /* Take out the hash table */
590 if (message->hdr_action != NULL)
591 {
592 h_destroy (message->hdr_action, NULL, NULL);
593 message->hdr_action = NULL;
594 }
595
596 message->headers = message->end_headers = NULL;
597 }
598
599 struct header_info *
find_header(smtp_message_t message,const char * name,int len)600 find_header (smtp_message_t message, const char *name, int len)
601 {
602 struct header_info *info;
603 const char *p;
604
605 assert (message != NULL && name != NULL);
606
607 if (len < 0)
608 len = strlen (name);
609 if (len == 0)
610 return NULL;
611 info = h_search (message->hdr_action, name, len);
612 if (info == NULL && (p = memchr (name, '-', len)) != NULL)
613 info = h_search (message->hdr_action, name, p - name + 1);
614 return info;
615 }
616
617 struct header_info *
insert_header(smtp_message_t message,const char * name)618 insert_header (smtp_message_t message, const char *name)
619 {
620 struct header_info *info;
621
622 assert (message != NULL && name != NULL);
623
624 info = h_insert (message->hdr_action, name, -1, sizeof (struct header_info));
625 if (info == NULL)
626 return NULL;
627 info->action = &header_actions[0];
628 return info;
629 }
630
631 static struct rfc2822_header *
create_header(smtp_message_t message,const char * header,struct header_info * info)632 create_header (smtp_message_t message, const char *header,
633 struct header_info *info)
634 {
635 struct rfc2822_header *hdr;
636
637 assert (message != NULL && header != NULL && info != NULL);
638
639 if ((hdr = malloc (sizeof (struct rfc2822_header))) == NULL)
640 return NULL;
641
642 memset (hdr, 0, sizeof (struct rfc2822_header));
643 hdr->header = strdup (header);
644 hdr->info = info;
645 info->hdr = hdr;
646 APPEND_LIST (message->headers, message->end_headers, hdr);
647 return hdr;
648 }
649
650 /****************************************************************************
651 * Header processing
652 ****************************************************************************/
653
654 /* Called just before copying the messge from the application.
655 Resets the seen flag for headers libESMTP is interested in */
656
657 static void
reset_headercb(const char * name,void * data,void * arg)658 reset_headercb (const char *name __attribute__ ((unused)),
659 void *data, void *arg __attribute__ ((unused)))
660 {
661 struct header_info *info = data;
662
663 assert (info != NULL);
664
665 info->seen = 0;
666 }
667
668 int
reset_header_table(smtp_message_t message)669 reset_header_table (smtp_message_t message)
670 {
671 int status;
672
673 assert (message != NULL);
674
675 if ((status = init_header_table (message)) < 0)
676 h_enumerate (message->hdr_action, reset_headercb, NULL);
677 return status;
678 }
679
680 /* This is called to process headers present in the application supplied
681 message. */
682 const char *
process_header(smtp_message_t message,const char * header,int * len)683 process_header (smtp_message_t message, const char *header, int *len)
684 {
685 const char *p;
686 struct header_info *info;
687 const struct header_actions *action;
688 hdrprint_t print;
689
690 assert (message != NULL && header != NULL && len != NULL);
691
692 if (*len > 0
693 && (p = memchr (header, ':', *len)) != NULL
694 && (info = find_header (message, header, p - header)) != NULL)
695 {
696 if ((action = info->action) != NULL)
697 {
698 /* RFC 2822 states that headers may only appear once in a
699 message with the exception of a few special headers.
700 This restriction is enforced here. */
701 if (info->seen && !(action->flags & (MULTIPLE | PRESERVE)))
702 header = NULL;
703 if (info->prohibit || (action->flags & PROHIBIT))
704 header = NULL;
705
706 /* When libESMTP is overriding headers in the message with
707 ones supplied in the API, the substitution is done here
708 to preserve the original ordering of the headers. */
709 if (header != NULL && info->override)
710 {
711 if ((print = action->print) == NULL)
712 print = print_string;
713 cat_reset (&message->hdr_buffer, 0);
714 (*print) (message, info->hdr);
715 header = cat_buffer (&message->hdr_buffer, len);
716 }
717 }
718 else if (info->seen)
719 header = NULL;
720 info->seen = 1;
721 }
722 return header;
723 }
724
725 /* This is called to supply headers not present in the application supplied
726 message. */
727 const char *
missing_header(smtp_message_t message,int * len)728 missing_header (smtp_message_t message, int *len)
729 {
730 struct header_info *info;
731 hdrprint_t print;
732
733 assert (message != NULL && len != NULL);
734
735 /* Move on to the next header */
736 if (message->current_header == NULL)
737 message->current_header = message->headers;
738 else
739 message->current_header = message->current_header->next;
740
741 /* Look for the next header that is actually required */
742 print = NULL;
743 while (message->current_header != NULL)
744 {
745 info = message->current_header->info;
746 if (info == NULL) /* shouldn't happen */
747 break;
748 if (!info->seen)
749 {
750 if (info->action != NULL)
751 print = info->action->print;
752 break;
753 }
754 message->current_header = message->current_header->next;
755 }
756 if (message->current_header == NULL)
757 {
758 /* Free the buffer created by concatenate() and return NULL to
759 mark the end of the headers */
760 cat_free (&message->hdr_buffer);
761 return NULL;
762 }
763
764 if (print == NULL)
765 print = print_string;
766
767 cat_reset (&message->hdr_buffer, 0);
768 (*print) (message, message->current_header);
769 return cat_buffer (&message->hdr_buffer, len);
770 }
771
772 /****************************************************************************
773 * Header API
774 ****************************************************************************/
775
776 int
smtp_set_header(smtp_message_t message,const char * header,...)777 smtp_set_header (smtp_message_t message, const char *header, ...)
778 {
779 va_list alist;
780 struct rfc2822_header *hdr;
781 struct header_info *info;
782 hdrset_t set;
783
784 SMTPAPI_CHECK_ARGS (message != NULL && header != NULL, 0);
785
786 if (!init_header_table (message))
787 {
788 set_errno (ENOMEM);
789 return 0;
790 }
791
792 info = find_header (message, header, -1);
793 if (info == NULL && (info = insert_header (message, header)) == NULL)
794 {
795 set_errno (ENOMEM);
796 return 0;
797 }
798
799 /* Cannot specify a value for headers that must pass unchanged (MIME)
800 or which may not appear in a posted message (Return-Path:). */
801 if (info->prohibit || (info->action->flags & (PROHIBIT | PRESERVE)))
802 {
803 set_error (SMTP_ERR_INVAL);
804 return 0;
805 }
806
807 set = info->action->set;
808 if (set == NULL)
809 {
810 set_error (SMTP_ERR_INVAL);
811 return 0;
812 }
813
814 if (info->hdr == NULL)
815 hdr = create_header (message, header, info);
816 else if (info->hdr->value == NULL)
817 hdr = info->hdr;
818 else
819 {
820 /* Header has a previous value. If multiple headers are permitted,
821 create a new value. If the header has a list value, the value
822 is appended to the iost. If neither condition applies, this
823 is an error. */
824 if (info->action->flags & MULTIPLE)
825 hdr = create_header (message, header, info);
826 else if (info->action->flags & LISTVALUE)
827 hdr = info->hdr;
828 else
829 {
830 set_error (SMTP_ERR_INVAL);
831 return 0;
832 }
833 }
834
835 /* Set its value */
836 va_start (alist, header);
837 (*set) (hdr, alist);
838 va_end (alist);
839
840 return 1;
841 }
842
843 int
smtp_set_header_option(smtp_message_t message,const char * header,enum header_option option,...)844 smtp_set_header_option (smtp_message_t message, const char *header,
845 enum header_option option, ...)
846 {
847 va_list alist;
848 struct header_info *info;
849
850 SMTPAPI_CHECK_ARGS (message != NULL && header != NULL, 0);
851
852 if (!init_header_table (message))
853 {
854 set_errno (ENOMEM);
855 return 0;
856 }
857
858 info = find_header (message, header, -1);
859 if (info == NULL && (info = insert_header (message, header)) == NULL)
860 {
861 set_errno (ENOMEM);
862 return 0;
863 }
864
865 /* Don't permit options to be set on headers that must pass intact or
866 which are prohibited. */
867 if (info->action->flags & (PROHIBIT | PRESERVE))
868 {
869 set_error (SMTP_ERR_INVAL);
870 return 0;
871 }
872
873 /* There is an odd quirk when setting options. Setting an option for
874 the OPTIONAL headers known to libESMTP causes default values to be
875 generated automatically when not found in the message, so long as
876 there is no other reason to prevent them appearing in the message! */
877
878 /* Don't allow the user to set override on prohibited headers. */
879 if (option == Hdr_OVERRIDE && !info->prohibit)
880 {
881 va_start (alist, option);
882 info->override = !!va_arg (alist, int);
883 va_end (alist);
884 return 1;
885 }
886 /* Don't allow the user to prohibit required headers. */
887 if (option == Hdr_PROHIBIT && !(info->action->flags & REQUIRE))
888 {
889 va_start (alist, option);
890 info->prohibit = !!va_arg (alist, int);
891 va_end (alist);
892 return 1;
893 }
894
895 set_error (SMTP_ERR_INVAL);
896 return 0;
897 }
898
899 int
smtp_set_resent_headers(smtp_message_t message,int onoff)900 smtp_set_resent_headers (smtp_message_t message, int onoff)
901 {
902 SMTPAPI_CHECK_ARGS (message != NULL, 0);
903
904 /* TODO: place holder, implement real functionality here.
905 For now, succeed if the onoff argument is zero. */
906 SMTPAPI_CHECK_ARGS (onoff == 0, 0);
907
908 return 1;
909 }
910