Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / bounce / bounce_append_service.c
blobdf541ca3fb356a483395a9c03e7d7bfd2ae7772e
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* bounce_append_service 3
6 /* SUMMARY
7 /* append record to bounce log, server side
8 /* SYNOPSIS
9 /* #include "bounce_service.h"
11 /* int bounce_append_service(flags, service, queue_id, rcpt, dsn),
12 /* int flags;
13 /* char *service;
14 /* char *queue_id;
15 /* RECIPIENT *rcpt;
16 /* DSN *dsn;
17 /* DESCRIPTION
18 /* This module implements the server side of the bounce_append()
19 /* (append bounce log) request. This routine either succeeds or
20 /* it raises a fatal error.
21 /* DIAGNOSTICS
22 /* Fatal errors: all file access errors; memory allocation errors.
23 /* BUGS
24 /* SEE ALSO
25 /* bounce(3) basic bounce service client interface
26 /* LICENSE
27 /* .ad
28 /* .fi
29 /* The Secure Mailer license must be distributed with this software.
30 /* AUTHOR(S)
31 /* Wietse Venema
32 /* IBM T.J. Watson Research
33 /* P.O. Box 704
34 /* Yorktown Heights, NY 10598, USA
35 /*--*/
37 /* System library. */
39 #include <sys_defs.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <ctype.h>
44 #include <string.h>
46 #ifdef STRCASECMP_IN_STRINGS_H
47 #include <strings.h>
48 #endif
50 /* Utility library. */
52 #include <msg.h>
53 #include <vstring.h>
54 #include <vstream.h>
55 #include <stringops.h>
57 /* Global library. */
59 #include <mail_params.h>
60 #include <mail_queue.h>
61 #include <quote_822_local.h>
62 #include <deliver_flock.h>
63 #include <mail_proto.h>
65 /* Application-specific. */
67 #include "bounce_service.h"
69 /* bounce_append_service - append bounce log */
71 int bounce_append_service(int unused_flags, char *service, char *queue_id,
72 RECIPIENT *rcpt, DSN *dsn)
74 VSTRING *in_buf = vstring_alloc(100);
75 VSTREAM *log;
76 long orig_length;
79 * This code is paranoid for a good reason. Once the bounce service takes
80 * responsibility, the mail system will make no further attempts to
81 * deliver this recipient. Whenever file access fails, assume that the
82 * system is under stress or that something has been mis-configured, and
83 * force a backoff by raising a fatal run-time error.
85 log = mail_queue_open(service, queue_id,
86 O_WRONLY | O_APPEND | O_CREAT, 0600);
87 if (log == 0)
88 msg_fatal("open file %s %s: %m", service, queue_id);
91 * Lock out other processes to avoid truncating someone else's data in
92 * case of trouble.
94 if (deliver_flock(vstream_fileno(log), INTERNAL_LOCK, (VSTRING *) 0) < 0)
95 msg_fatal("lock file %s %s: %m", service, queue_id);
98 * Now, go for it. Append a record. Truncate the log to the original
99 * length when the append operation fails. We use the plain stream-lf
100 * file format because we do not need anything more complicated. As a
101 * benefit, we can still recover some data when the file is a little
102 * garbled.
104 * XXX addresses in defer logfiles are in printable quoted form, while
105 * addresses in message envelope records are in raw unquoted form. This
106 * may change once we replace the present ad-hoc bounce/defer logfile
107 * format by one that is transparent for control etc. characters. See
108 * also: showq/showq.c.
110 * While migrating from old format to new format, allow backwards
111 * compatibility by writing an old-style record before the new-style
112 * records.
114 if ((orig_length = vstream_fseek(log, 0L, SEEK_END)) < 0)
115 msg_fatal("seek file %s %s: %m", service, queue_id);
117 #define NOT_NULL_EMPTY(s) ((s) != 0 && *(s) != 0)
118 #define STR(x) vstring_str(x)
120 vstream_fputs("\n", log);
121 if (var_oldlog_compat) {
122 vstream_fprintf(log, "<%s>: %s\n", *rcpt->address == 0 ? "" :
123 STR(quote_822_local(in_buf, rcpt->address)),
124 dsn->reason);
126 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_RECIP, *rcpt->address ?
127 STR(quote_822_local(in_buf, rcpt->address)) : "<>");
128 if (NOT_NULL_EMPTY(rcpt->orig_addr)
129 && strcasecmp(rcpt->address, rcpt->orig_addr) != 0)
130 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_ORCPT,
131 STR(quote_822_local(in_buf, rcpt->orig_addr)));
132 if (rcpt->offset > 0)
133 vstream_fprintf(log, "%s=%ld\n", MAIL_ATTR_OFFSET, rcpt->offset);
134 if (NOT_NULL_EMPTY(rcpt->dsn_orcpt))
135 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ORCPT, rcpt->dsn_orcpt);
136 if (rcpt->dsn_notify != 0)
137 vstream_fprintf(log, "%s=%d\n", MAIL_ATTR_DSN_NOTIFY, rcpt->dsn_notify);
139 if (NOT_NULL_EMPTY(dsn->status))
140 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_STATUS, dsn->status);
141 if (NOT_NULL_EMPTY(dsn->action))
142 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_ACTION, dsn->action);
143 if (NOT_NULL_EMPTY(dsn->dtype) && NOT_NULL_EMPTY(dsn->dtext)) {
144 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTYPE, dsn->dtype);
145 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_DTEXT, dsn->dtext);
147 if (NOT_NULL_EMPTY(dsn->mtype) && NOT_NULL_EMPTY(dsn->mname)) {
148 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MTYPE, dsn->mtype);
149 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_DSN_MNAME, dsn->mname);
151 if (NOT_NULL_EMPTY(dsn->reason))
152 vstream_fprintf(log, "%s=%s\n", MAIL_ATTR_WHY, dsn->reason);
153 vstream_fputs("\n", log);
155 if (vstream_fflush(log) != 0 || fsync(vstream_fileno(log)) < 0) {
156 #ifndef NO_TRUNCATE
157 if (ftruncate(vstream_fileno(log), (off_t) orig_length) < 0)
158 msg_fatal("truncate file %s %s: %m", service, queue_id);
159 #endif
160 msg_fatal("append file %s %s: %m", service, queue_id);
164 * Darn. If closing the log detects a problem, the only way to undo the
165 * damage is to open the log once more, and to truncate the log to the
166 * original length. But, this could happen only when the log is kept on a
167 * remote file system, and that is not recommended practice anyway.
169 if (vstream_fclose(log) != 0)
170 msg_warn("append file %s %s: %m", service, queue_id);
172 vstring_free(in_buf);
173 return (0);