5 /* bounce_append_service 3
7 /* append record to bounce log, server side
9 /* #include "bounce_service.h"
11 /* int bounce_append_service(flags, service, queue_id, rcpt, dsn),
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.
22 /* Fatal errors: all file access errors; memory allocation errors.
25 /* bounce(3) basic bounce service client interface
29 /* The Secure Mailer license must be distributed with this software.
32 /* IBM T.J. Watson Research
34 /* Yorktown Heights, NY 10598, USA
46 #ifdef STRCASECMP_IN_STRINGS_H
50 /* Utility library. */
55 #include <stringops.h>
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);
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);
88 msg_fatal("open file %s %s: %m", service
, queue_id
);
91 * Lock out other processes to avoid truncating someone else's data in
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
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
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
)),
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) {
157 if (ftruncate(vstream_fileno(log
), (off_t
) orig_length
) < 0)
158 msg_fatal("truncate file %s %s: %m", service
, queue_id
);
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
);