between short queue ID and message status). File:
showq/showq.c.
-20031216-7
+20031216-20
Cleanup: the SMTP client now moves on to the next MX host
or fallback relay when delivery fails in the middle of an
- SMTP session. This includes not only broken connections
- (easy) but also includes 4xx SMTP server replies (not easy).
- Files: smtp/smtp.c, smtp/smtp_connect.c, smtp_trouble.c.
+ SMTP session. This includes both broken connections and
+ 4xx SMTP server replies. Files: smtp/smtp.c, smtp_rcpt.c,
+ smtp/smtp_connect.c, smtp_trouble.c.
+
+ Configuration parameters: smtp_mx_address_limit (limit the
+ list of IP addresses from MX lookup), and smtp_mx_session_limit
+ (limit the number of actual SMTP sessions per delivery
+ attempt, ignoring unusable MX IP addresses).
20031217
Low: postconf -e edits parameters that postconf won't list.
- Low: while convering 8bit text to quoted-printable, perhaps
+ Low: while converting 8bit text to quoted-printable, perhaps
use =46rom instead of >From.
virtual_mailbox_path expression like forward_path, so that
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
-Major changes with Postfix snapshot 2.0.16-20031217
+Major changes with Postfix snapshot 2.0.16-20031221
===================================================
The SMTP client now moves on to the next MX host (or fallback relay)
when delivery fails in the middle of a session. This includes both
-broken connections as well as 4XX replies to SMTP commands.
+broken connections as well as 4XX replies to SMTP commands. Finally,
+fallback_relay works as expected.
Incompatible changes with Postfix snapshot 2.0.16-20031215
==========================================================
#
smtp_defer_if_no_mx_address_found = no
+# The smtp_mx_address_limit parameter limits the number of MX (mail
+# exchanger) IP addresses that can result from DNS or host lookups.
+#
+# Specify zero to disable the limit. This is also the default.
+#
+smtp_mx_address_limit = 0
+
+# The smtp_mx_session_limit parameter limits the number of SMTP
+# sessions that the client will engage in, skipping over MX IP
+# addresses that fail to complete the SMTP initial handshake.
+#
+# By default, Postfix SMTP client gives up after two SMTP sessions.
+#
+# Specify zero to disable the limit.
+#
+smtp_mx_session_limit = 2
+
# The smtp_send_xforward_command parameter controls whether the Postfix
# SMTP client will send an XFORWARD command to the SMTP server, when
# the ESMTP HELO response of the remote host indicates XFORWARD support.
<b>smtp_mx_address_limit</b>
An upper bound on the number of MX (mail exchanger)
- IP addresses that the SMTP client will try to con-
- nect to, before giving up or sending the mail to a
- fall-back relay host.
+ IP addresses that that can result from DNS or host
+ lookups.
Specify zero to disable the limit.
+ Note: by default, equal preference MX addresses are
+ sorted into random order.
+
<b>smtp_mx_session_limit</b>
An upper bound on the number of SMTP sessions that
- the SMTP client will engage in before giving up or
- sending the mail to a fall-back relay host.
+ the SMTP client will engage in per message delivery
+ (ignoring MX IP addresses that fail to complete the
+ SMTP initial handshake).
Specify zero to disable the limit.
- <b>smtp_backup_on_soft_error</b>
- The types of recoverable error that qualify for
- sending a recipient to a backup mail server or to a
- fall-back relay host. Specify zero or more of <b>ses-</b>
- <b>sion</b> (SMTP handshake failure, connection loss),
- <b>message</b> (failure of MAIL FROM, DATA or "."), or
- <b>recipient</b> (failure of RCPT TO).
-
- Recipients that do not qualify are deferred.
-
<b>Timeout controls</b>
The default time unit is seconds; an explicit time unit
can be specified by appending a one-letter suffix to the
\fBdefault_destination_recipient_limit\fR parameter.
.IP \fBsmtp_mx_address_limit\fR
An upper bound on the number of MX (mail exchanger) IP addresses
-that the SMTP client will try to connect to, before giving up or
-sending the mail to a fall-back relay host.
+that that can result from DNS or host lookups.
.sp
Specify zero to disable the limit.
+.sp
+Note: by default, equal preference MX addresses are sorted into
+random order.
.IP \fBsmtp_mx_session_limit\fR
-An upper bound on the number of SMTP sessions that the SMTP client
-will engage in before giving up or sending the mail to a fall-back
-relay host.
+An upper bound on the number of SMTP sessions that the SMTP
+client will engage in per message delivery (ignoring MX IP
+addresses that fail to complete the SMTP initial handshake).
.sp
Specify zero to disable the limit.
-.IP \fBsmtp_backup_on_soft_error\fR
-The types of recoverable error that qualify for sending a
-recipient to a backup mail server or to a fall-back relay host.
-Specify zero or more of \fBsession\fR (SMTP handshake failure,
-connection loss), \fBmessage\fR (failure of MAIL FROM, DATA or
-"."), or \fBrecipient\fR (failure of RCPT TO).
-.sp
-Recipients that do not qualify are deferred.
.SH "Timeout controls"
.ad
.fi
#define DEF_SMTP_HOST_LOOKUP SMTP_HOST_LOOKUP_DNS
extern int var_smtp_dns_lookup;
-#define SMTP_BACKUP_SESSION "session"
-#define SMTP_BACKUP_MESSAGE "message"
-#define SMTP_BACKUP_RECIPIENT "recipient"
-
-#define VAR_SMTP_BACKUP_MASK "smtp_backup_on_soft_error"
-#define DEF_SMTP_BACKUP_MASK SMTP_BACKUP_SESSION \
- " " SMTP_BACKUP_MESSAGE \
- " " SMTP_BACKUP_RECIPIENT
-
#define VAR_SMTP_MXADDR_LIMIT "smtp_mx_address_limit"
#define DEF_SMTP_MXADDR_LIMIT 0
extern int var_smtp_mxaddr_limit;
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20031220"
+#define MAIL_RELEASE_DATE "20031221"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
+++ /dev/null
-/*++
-/* NAME
-/* peer_name 3
-/* SUMMARY
-/* produce printable peer name and address
-/* SYNOPSIS
-/* #include <peer_name.h>
-/*
-/* typedef struct {
-/* .in +4
-/* int type;
-/* char name;
-/* char addr;
-/* .in -4
-/* } PEER_NAME;
-/*
-/* PEER_NAME *peer_name(sock)
-/* int sock;
-/* DESCRIPTION
-/* The \fIpeer_name\fR() routine attempts to produce a printable
-/* version of the peer name and address of the specified socket.
-/* The result is in static memory that will be overwritten.
-/* Make a copy if the result is to be used for an appreciable
-/* amount of time.
-/*
-/* Where information is unavailable, the name and/or address
-/* are set to "unknown".
-/* The \fItype\fR result field specifies how the name and address
-/* should be interpreted:
-/* .IP PEER_TYPE_INET
-/* The socket specifies a TCP/IP endpoint.
-/* The result is a hostname (from the DNS, a local hosts file or
-/* other); the address a dotted quad.
-/* .IP PEER_TYPE_LOCAL
-/* The socket argument specifies a local transport.
-/* The result name is "localhost"; the result address is "127.0.0.1".
-/* .IP PEER_TYPE_UNKNOWN
-/* The socket argument does not specify a socket.
-/* The result name is "localhost"; the result address is "127.0.0.1".
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netdb.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <valid_hostname.h>
-#include <peer_name.h>
-
-/* peer_name - produce printable peer name and address */
-
-PEER_NAME *peer_name(int sock)
-{
- static PEER_NAME peer;
- struct sockaddr_in sin;
- SOCKADDR_SIZE len = sizeof(sin);
- struct hostent *hp;
-
- if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) {
- switch (sin.sin_family) {
- case AF_INET:
- peer.type = PEER_TYPE_INET;
- hp = gethostbyaddr((char *) &(sin.sin_addr),
- sizeof(sin.sin_addr), AF_INET);
- peer.name = (hp && valid_hostname(hp->h_name, DO_GRIPE) ?
- hp->h_name : "unknown");
- peer.addr = inet_ntoa(sin.sin_addr);
- return (&peer);
- case AF_UNSPEC:
- case AF_UNIX:
- peer.type = PEER_TYPE_LOCAL;
- peer.name = "localhost";
- peer.addr = "127.0.0.1";
- return (&peer);
- }
- }
- peer.type = PEER_TYPE_UNKNOWN;
- peer.name = "localhost";
- peer.addr = "127.0.0.1";
- return (&peer);
-
-}
-
-#ifdef TEST
-
-#include <unistd.h>
-
-int main(int unused_argc, char **unused_argv)
-{
- PEER_NAME *peer;
-
- peer = peer_name(STDIN_FILENO);
- msg_info("name %s addr %s", peer->name, peer->addr);
-}
-
-#endif
+++ /dev/null
-#ifndef _PEER_NAME_H_INCLUDED_
-#define _PEER_NAME_H_INCLUDED_
-
-/*++
-/* NAME
-/* peer_name 3h
-/* SUMMARY
-/* produce printable peer name and address
-/* SYNOPSIS
-/* #include <peer_name.h>
-/* DESCRIPTION
-
- /*
- * External interface.
- */
-typedef struct {
- int type; /* IPC type, see below */
- char *name; /* peer official name */
- char *addr; /* peer address */
-} PEER_NAME;
-
-#define PEER_TYPE_UNKNOWN 0
-#define PEER_TYPE_INET 1
-#define PEER_TYPE_LOCAL 2
-
-extern PEER_NAME *peer_name(int);
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-#endif
/* const char *orig_rcpt;
/* const char *recipient;
/*
-/* void recipient_list_truncate(list)
-/* RECIPIENT_LIST *list;
-/*
/* void recipient_list_free(list)
/* RECIPIENT_LIST *list;
/* DESCRIPTION
/* recipient_list_add() adds a recipient to the specified list.
/* The recipient address is copied with mystrdup().
/*
-/* recipient_list_truncate() truncates the specified list to
-/* the specified length.
-/*
/* recipient_list_free() releases memory for the specified list
/* of recipient structures.
/*
/* System library. */
#include <sys_defs.h>
-#include <msg.h>
/* Utility library. */
list->len++;
}
-/* recipient_list_truncate - release memory for unused recipient structures */
+/* recipient_list_free - release memory for in-core recipient structure */
-void recipient_list_truncate(RECIPIENT_LIST *list, int new_len)
+void recipient_list_free(RECIPIENT_LIST *list)
{
RECIPIENT *rcpt;
- if (new_len < 0 || new_len > list->len)
- msg_panic("recipient_list_truncate: bad length %d", new_len);
-
- for (rcpt = list->info + new_len; rcpt < list->info + list->len; rcpt++) {
+ for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) {
myfree(rcpt->orig_addr);
myfree(rcpt->address);
}
- list->len = new_len;
-}
-
-/* recipient_list_free - release memory for in-core recipient structure */
-
-void recipient_list_free(RECIPIENT_LIST *list)
-{
- if (list->len > 0)
- recipient_list_truncate(list, 0);
myfree((char *) list->info);
}
extern void recipient_list_init(RECIPIENT_LIST *);
extern void recipient_list_add(RECIPIENT_LIST *, long, const char *, const char *);
-extern void recipient_list_truncate(RECIPIENT_LIST *, int);
extern void recipient_list_free(RECIPIENT_LIST *);
/* LICENSE
lmtp_proto.o: ../../include/vstring_vstream.h
lmtp_proto.o: ../../include/stringops.h
lmtp_proto.o: ../../include/mymalloc.h
+lmtp_proto.o: ../../include/name_code.h
lmtp_proto.o: ../../include/mail_params.h
lmtp_proto.o: ../../include/smtp_stream.h
lmtp_proto.o: ../../include/mail_queue.h
SHELL = /bin/sh
SRCS = smtp.c smtp_connect.c smtp_proto.c smtp_chat.c smtp_session.c \
- smtp_addr.c smtp_trouble.c smtp_state.c smtp_misc.c \
+ smtp_addr.c smtp_trouble.c smtp_state.c smtp_rcpt.c \
smtp_sasl_proto.c smtp_sasl_glue.c
OBJS = smtp.o smtp_connect.o smtp_proto.o smtp_chat.o smtp_session.o \
- smtp_addr.o smtp_trouble.o smtp_state.o smtp_misc.o \
+ smtp_addr.o smtp_trouble.o smtp_state.o smtp_rcpt.o \
smtp_sasl_proto.o smtp_sasl_glue.o
HDRS = smtp.h smtp_sasl.h
TESTSRC =
smtp_connect.o: smtp.h
smtp_connect.o: ../../include/argv.h
smtp_connect.o: smtp_addr.h
-smtp_misc.o: smtp_misc.c
-smtp_misc.o: ../../include/sys_defs.h
-smtp_misc.o: ../../include/msg.h
-smtp_misc.o: ../../include/deliver_request.h
-smtp_misc.o: ../../include/vstring.h
-smtp_misc.o: ../../include/vbuf.h
-smtp_misc.o: ../../include/vstream.h
-smtp_misc.o: ../../include/recipient_list.h
-smtp_misc.o: ../../include/deliver_completed.h
-smtp_misc.o: ../../include/sent.h
-smtp_misc.o: smtp.h
-smtp_misc.o: ../../include/argv.h
smtp_proto.o: smtp_proto.c
smtp_proto.o: ../../include/sys_defs.h
smtp_proto.o: ../../include/msg.h
smtp_proto.o: smtp.h
smtp_proto.o: ../../include/argv.h
smtp_proto.o: smtp_sasl.h
+smtp_rcpt.o: smtp_rcpt.c
+smtp_rcpt.o: ../../include/sys_defs.h
+smtp_rcpt.o: ../../include/msg.h
+smtp_rcpt.o: ../../include/deliver_request.h
+smtp_rcpt.o: ../../include/vstring.h
+smtp_rcpt.o: ../../include/vbuf.h
+smtp_rcpt.o: ../../include/vstream.h
+smtp_rcpt.o: ../../include/recipient_list.h
+smtp_rcpt.o: ../../include/deliver_completed.h
+smtp_rcpt.o: ../../include/sent.h
+smtp_rcpt.o: smtp.h
+smtp_rcpt.o: ../../include/argv.h
smtp_sasl_glue.o: smtp_sasl_glue.c
smtp_sasl_glue.o: ../../include/sys_defs.h
smtp_sasl_glue.o: ../../include/msg.h
/* \fBdefault_destination_recipient_limit\fR parameter.
/* .IP \fBsmtp_mx_address_limit\fR
/* An upper bound on the number of MX (mail exchanger) IP addresses
-/* that the SMTP client will try to connect to, before giving up or
-/* sending the mail to a fall-back relay host.
+/* that that can result from DNS or host lookups.
/* .sp
/* Specify zero to disable the limit.
+/* .sp
+/* Note: by default, equal preference MX addresses are sorted into
+/* random order.
/* .IP \fBsmtp_mx_session_limit\fR
-/* An upper bound on the number of SMTP sessions that the SMTP client
-/* will engage in before giving up or sending the mail to a fall-back
-/* relay host.
+/* An upper bound on the number of SMTP sessions that the SMTP
+/* client will engage in per message delivery (ignoring MX IP
+/* addresses that fail to complete the SMTP initial handshake).
/* .sp
/* Specify zero to disable the limit.
-/* .IP \fBsmtp_backup_on_soft_error\fR
-/* The types of recoverable error that qualify for sending a
-/* recipient to a backup mail server or to a fall-back relay host.
-/* Specify zero or more of \fBsession\fR (SMTP handshake failure,
-/* connection loss), \fBmessage\fR (failure of MAIL FROM, DATA or
-/* "."), or \fBrecipient\fR (failure of RCPT TO).
-/* .sp
-/* Recipients that do not qualify are deferred.
/* .SH "Timeout controls"
/* .ad
/* .fi
int var_smtp_line_limit;
char *var_smtp_helo_name;
char *var_smtp_host_lookup;
-char *var_smtp_backup_mask;
bool var_smtp_quote_821_env;
bool var_smtp_defer_mxaddr;
bool var_smtp_send_xforward;
*/
int smtp_errno;
int smtp_host_lookup_mask;
-int smtp_backup_mask;
/* deliver_message - deliver message with extreme prejudice */
state = smtp_state_alloc();
state->request = request;
state->src = request->fp;
+ SMTP_RCPT_INIT(state);
/*
* Establish an SMTP session and deliver this message to all requested
}
}
-/* post_init - post-jail initialization */
+/* pre_init - pre-jail initialization */
-static void post_init(char *unused_name, char **unused_argv)
+static void pre_init(char *unused_name, char **unused_argv)
{
static NAME_MASK lookup_masks[] = {
SMTP_HOST_LOOKUP_DNS, SMTP_MASK_DNS,
SMTP_HOST_LOOKUP_NATIVE, SMTP_MASK_NATIVE,
0,
};
- static NAME_MASK backup_masks[] = {
- SMTP_BACKUP_SESSION, SMTP_BACKUP_SESSION_FAILURE,
- SMTP_BACKUP_MESSAGE, SMTP_BACKUP_MESSAGE_FAILURE,
- SMTP_BACKUP_RECIPIENT, SMTP_BACKUP_RECIPIENT_FAILURE,
- 0,
- };
/*
* Turn on per-peer debugging.
str_name_mask(VAR_SMTP_HOST_LOOKUP, lookup_masks,
smtp_host_lookup_mask));
- /*
- * When to choose a backup host after a temporary failure.
- */
- smtp_backup_mask = name_mask(VAR_SMTP_BACKUP_MASK, backup_masks,
- var_smtp_backup_mask);
- if (msg_verbose)
- msg_info("when to try backup host: %s",
- str_name_mask(VAR_SMTP_BACKUP_MASK, backup_masks,
- smtp_backup_mask));
-
-}
-
-/* pre_init - pre-jail initialization */
-
-static void pre_init(char *unused_name, char **unused_argv)
-{
-
/*
* SASL initialization.
*/
VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
- VAR_SMTP_BACKUP_MASK, DEF_SMTP_BACKUP_MASK, &var_smtp_backup_mask, 0, 0,
0,
};
static CONFIG_TIME_TABLE time_table[] = {
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_BOOL_TABLE, bool_table,
MAIL_SERVER_PRE_INIT, pre_init,
- MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
MAIL_SERVER_EXIT, pre_exit,
0);
* session all recipients should be marked one way or the other.
*/
int final_server; /* final mail server */
- int drop_count; /* recipients marked as drop */
- int keep_count; /* recipients marked as keep */
+ int rcpt_left; /* recipients left over */
+ int rcpt_drop; /* recipients marked as drop */
+ int rcpt_keep; /* recipients marked as keep */
} SMTP_STATE;
/*
#define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
#define SMTP_FEATURE_XFORWARD_HELO (1<<10)
- /*
- * Application-specific per-recipient status. At the end of each delivery
- * attempt each recipient is marked as DROP (remove from recipient list) or
- * KEEP (deliver to backup mail server). The ones marked DROP are deleted
- * before trying to deliver the remainder to a backup server. There's a bit
- * of redundcancy to ensure that all recipients are marked.
- *
- * The single recipient list abstraction dates from the time that the SMTP
- * client would give up after one SMTP session, so that each recipient was
- * either bounced, delivered or deferred. Implicitly, all recipients were
- * marked as DROP.
- *
- * This abstraction is less convenient when an SMTP client must be able to
- * deliver left-over recipients to a backup host. It might be more natural
- * to have an input list with recipients to deliver, and an output list with
- * the left-over recipients.
- */
-#define SMTP_RCPT_KEEP 1 /* send to backup host */
-#define SMTP_RCPT_DROP 2 /* remove from request */
-
-#define SMTP_RCPT_MARK_INIT(state) do { \
- (state)->drop_count = (state)->keep_count = 0; \
- } while (0)
-
-#define SMTP_RCPT_MARK_DROP(state, rcpt) do { \
- (rcpt)->status = SMTP_RCPT_DROP; (state)->drop_count++; \
- } while (0)
-
-#define SMTP_RCPT_MARK_KEEP(state, rcpt) do { \
- (rcpt)->status = SMTP_RCPT_KEEP; (state)->keep_count++; \
- } while (0)
-
-#define SMTP_RCPT_MARK_ISSET(rcpt) ((rcpt)->status != 0)
-
-extern int smtp_rcpt_mark_finish(SMTP_STATE *);
-
/*
* smtp.c
*/
extern int smtp_errno; /* XXX can we get rid of this? */
-
+
#define SMTP_NONE 0 /* no error */
#define SMTP_FAIL 1 /* permanent error */
#define SMTP_RETRY 2 /* temporary error */
extern void smtp_chat_notify(SMTP_STATE *);
/*
- * smtp_misc.c.
+ * These operations are extensively documented in smtp_rcpt.c
*/
+#define SMTP_RCPT_STATE_KEEP 1 /* send to backup host */
+#define SMTP_RCPT_STATE_DROP 2 /* remove from request */
+
+#define SMTP_RCPT_INIT(state) do { \
+ (state)->rcpt_drop = (state)->rcpt_keep = 0; \
+ (state)->rcpt_left = state->request->rcpt_list.len; \
+ } while (0)
+
+#define SMTP_RCPT_DROP(state, rcpt) do { \
+ (rcpt)->status = SMTP_RCPT_STATE_DROP; (state)->rcpt_drop++; \
+ } while (0)
+
+#define SMTP_RCPT_KEEP(state, rcpt) do { \
+ (rcpt)->status = SMTP_RCPT_STATE_KEEP; (state)->rcpt_keep++; \
+ } while (0)
+
+#define SMTP_RCPT_ISMARKED(rcpt) ((rcpt)->status != 0)
+
+#define SMTP_RCPT_LEFT(state) (state)->rcpt_left
+
+extern void smtp_rcpt_cleanup(SMTP_STATE *);
extern void smtp_rcpt_done(SMTP_STATE *, const char *, RECIPIENT *);
/*
* then is to build this into the pre-existing SMTP client without
* getting lost in the complexity.
*/
- for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
+ for (cpp = sites->argv; SMTP_RCPT_LEFT(state) > 0 && (dest = *cpp) != 0; cpp++) {
state->final_server = (cpp[1] == 0);
smtp_errno = SMTP_NONE;
* list. Unmark any left-over recipients and try to deliver them to a
* backup mail server.
*/
- for (sess_count = addr_count = 0, addr = addr_list; addr; addr = next) {
+ sess_count = addr_count = 0;
+ for (addr = addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) {
next = addr->next;
if (++addr_count == var_smtp_mxaddr_limit)
next = 0;
if ((state->session = smtp_connect_addr(addr, port, why)) != 0) {
if (++sess_count == var_smtp_mxsess_limit)
next = 0;
- SMTP_RCPT_MARK_INIT(state);
state->final_server = (cpp[1] == 0 && next == 0);
state->session->best = (addr->pref == addr_list->pref);
debug_peer_check(state->session->host, state->session->addr);
/* XXX smtp_xfer() may abort in the middle of DATA. */
smtp_session_free(state->session);
debug_peer_restore();
- if (smtp_rcpt_mark_finish(state) == 0)
- break;
+ smtp_rcpt_cleanup(state);
} else {
msg_info("%s (port %d)", vstring_str(why), ntohs(port));
}
* Pay attention to what could be configuration problems, and pretend that
* these are recoverable rather than bouncing the mail.
*/
- if (request->rcpt_list.len > 0) {
+ if (SMTP_RCPT_LEFT(state) > 0) {
switch (smtp_errno) {
default:
state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
var_bestmx_transp,
request);
+ SMTP_RCPT_LEFT(state) = 0; /* XXX */
break;
}
/* FALLTHROUGH */
* We still need to bounce or defer some left-over recipients:
* either mail loops or some backup mail server was unavailable.
*/
+ state->final_server = 1;
smtp_site_fail(state, smtp_errno == SMTP_RETRY ? 450 : 550,
"%s", vstring_str(why));
- break;
+
+ /*
+ * Sanity check. Don't silently lose recipients.
+ */
+ smtp_rcpt_cleanup(state);
+ if (SMTP_RCPT_LEFT(state) > 0)
+ msg_panic("smtp_connect: left-over recipients");
}
}
+++ /dev/null
-/*++
-/* NAME
-/* smtp_misc 3
-/* SUMMARY
-/* assorted routines
-/* SYNOPSIS
-/* #include <smtp.h>
-/*
-/* void smtp_rcpt_done(state, reply, rcpt)
-/* SMTP_STATE *state;
-/* const char *reply;
-/* RECIPIENT *rcpt;
-/*
-/* int smtp_rcpt_mark_finish(SMTP_STATE *state)
-/* SMTP_STATE *state;
-/* DESCRIPTION
-/* smtp_rcpt_done() logs that a recipient is completed and upon
-/* success it marks the recipient as done in the queue file.
-/* Finally, it marks the in-memory recipient as DROP.
-/*
-/* smtp_rcpt_mark_finish() cleans up the in-memory recipient list.
-/* It deletes recipients marked DROP, and unmarks recipients marked KEEP.
-/* It enforces the requirement that all recipients are marked one way
-/* or the other. The result value is the number of left-over recipients.
-/* DIAGNOSTICS
-/* Panic: interface violation.
-/*
-/* When a recipient can't be logged as completed, the recipient is
-/* logged as deferred instead.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdlib.h> /* smtp_rcpt_mark_finish */
-
-/* Utility library. */
-
-#include <msg.h>
-
-/* Global library. */
-
-#include <deliver_request.h> /* smtp_rcpt_done */
-#include <deliver_completed.h> /* smtp_rcpt_done */
-#include <sent.h> /* smtp_rcpt_done */
-
-/* Application-specific. */
-
-#include <smtp.h>
-
-/* smtp_rcpt_done - mark recipient as done or else */
-
-void smtp_rcpt_done(SMTP_STATE *state, const char *reply, RECIPIENT *rcpt)
-{
- DELIVER_REQUEST *request = state->request;
- SMTP_SESSION *session = state->session;
- int status;
-
- /*
- * Report success and delete the recipient from the delivery request.
- * Defer if the success can't be reported.
- */
- status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, rcpt->orig_addr,
- rcpt->address, rcpt->offset,
- session->namaddr,
- request->arrival_time,
- "%s", reply);
- if (status == 0)
- if (request->flags & DEL_REQ_FLAG_SUCCESS)
- deliver_completed(state->src, rcpt->offset);
- SMTP_RCPT_MARK_DROP(state, rcpt);
- state->status |= status;
-}
-
-/* smtp_rcpt_mark_finish_callback - qsort callback */
-
-static int smtp_rcpt_mark_finish_callback(const void *a, const void *b)
-{
- return (((RECIPIENT *) a)->status - ((RECIPIENT *) b)->status);
-}
-
-/* smtp_rcpt_mark_finish - purge completed recipients from request */
-
-int smtp_rcpt_mark_finish(SMTP_STATE *state)
-{
- RECIPIENT_LIST *rcpt_list = &state->request->rcpt_list;
- RECIPIENT *rcpt;
-
- /*
- * Sanity checks.
- */
- if (state->drop_count + state->keep_count != rcpt_list->len)
- msg_panic("smtp_rcpt_mark_finish: recipient count mismatch: %d+%d!=%d",
- state->drop_count, state->keep_count, rcpt_list->len);
-
- /*
- * Recipients marked KEEP sort before recipients marked DROP. Skip the
- * sorting in the common case that all recipients are marked the same.
- */
- if (state->drop_count > 0 && state->keep_count > 0)
- qsort((void *) rcpt_list->info, rcpt_list->len,
- sizeof(rcpt_list->info), smtp_rcpt_mark_finish_callback);
-
- /*
- * Truncate the recipient list and unmark the left-over recipients so
- * that the result looks like a brand-new recipient list.
- */
- if (state->keep_count < rcpt_list->len)
- recipient_list_truncate(rcpt_list, state->keep_count);
- for (rcpt = rcpt_list->info; rcpt < rcpt_list->info + rcpt_list->len; rcpt++)
- rcpt->status = 0;
-
- return (rcpt_list->len);
-}
/*
* Sanity check. Recipients should be unmarked at this point.
*/
- if (request->rcpt_list.len <= 0)
+ if (SMTP_RCPT_LEFT(state) <= 0)
msg_panic("smtp_xfer: bad recipient count: %d",
- request->rcpt_list.len);
- if (SMTP_RCPT_MARK_ISSET(request->rcpt_list.info))
+ SMTP_RCPT_LEFT(state));
+ if (SMTP_RCPT_ISMARKED(request->rcpt_list.info))
msg_panic("smtp_xfer: bad recipient status: %d",
request->rcpt_list.info->status);
QUOTE_ADDRESS(state->scratch, rcpt->address);
vstring_sprintf(next_command, "RCPT TO:<%s>",
vstring_str(state->scratch));
- if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
+ if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state))
next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
SMTP_STATE_ABORT : SMTP_STATE_DATA;
break;
}
}
/* If trace-only, send RSET instead of DATA. */
- if (++recv_rcpt == request->rcpt_list.len)
+ if (++recv_rcpt == SMTP_RCPT_LEFT(state))
recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
SMTP_STATE_ABORT : SMTP_STATE_DATA;
break;
} else {
for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (!SMTP_RCPT_MARK_ISSET(rcpt))
+ if (!SMTP_RCPT_ISMARKED(rcpt))
smtp_rcpt_done(state, resp->str, rcpt);
}
}
--- /dev/null
+/*++
+/* NAME
+/* smtp_rcpt 3
+/* SUMMARY
+/* application-specific recipient list operations
+/* SYNOPSIS
+/* #include <smtp.h>
+/*
+/* SMTP_RCPT_INIT(state)
+/* SMTP_STATE *state;
+/*
+/* SMTP_RCPT_DROP(state, rcpt)
+/* SMTP_STATE *state;
+/* RECIPIENT *rcpt;
+/*
+/* SMTP_RCPT_KEEP(state, rcpt)
+/* SMTP_STATE *state;
+/* RECIPIENT *rcpt;
+/*
+/* SMTP_RCPT_ISMARKED(rcpt)
+/* RECIPIENT *rcpt;
+/*
+/* void smtp_rcpt_cleanup(SMTP_STATE *state)
+/* SMTP_STATE *state;
+/*
+/* int SMTP_RCPT_LEFT(state)
+/* SMTP_STATE *state;
+/*
+/* void smtp_rcpt_done(state, reply, rcpt)
+/* SMTP_STATE *state;
+/* const char *reply;
+/* RECIPIENT *rcpt;
+/* DESCRIPTION
+/* This module implements application-specific mark and sweep
+/* operations on recipient lists. Operation is as follows:
+/* .IP \(bu
+/* In the course of a delivery attempt each recipient is
+/* marked either as DROP (remove from recipient list) or KEEP
+/* (deliver to backup mail server).
+/* .IP \(bu
+/* After a delivery attempt any recipients marked DROP are deleted
+/* from the request, and the left-over recipients are unmarked.
+/* .PP
+/* Operations with upper case names are implemented by macros
+/* whose arguments may be evaluated more than once.
+/*
+/* SMTP_RCPT_INIT() initializes application-specific recipient
+/* information and must be called before the first delivery attempt.
+/*
+/* SMTP_RCPT_DROP() marks the specified recipient as DROP (remove
+/* from recipient list). It is an error to mark an already marked
+/* recipient.
+/*
+/* SMTP_RCPT_KEEP() marks the specified recipient as KEEP (deliver
+/* to alternate mail server). It is an error to mark an already
+/* marked recipient.
+/*
+/* SMTP_RCPT_ISMARKED() returns non-zero when the specified
+/* recipient is marked.
+/*
+/* SMTP_RCPT_LEFT() returns the number of left_over recipients
+/* (the total number of marked and non-marked recipients).
+/*
+/* smtp_rcpt_cleanup() cleans up the in-memory recipient list.
+/* It removes the recipients marked DROP from the left-over
+/* recipients, unmarks the left-over recipients, and enforces
+/* the requirement that all recipients are marked upon entry.
+/*
+/* smtp_rcpt_done() logs that a recipient is completed and upon
+/* success it marks the recipient as done in the queue file.
+/* Finally, it marks the in-memory recipient as DROP.
+/*
+/* Note: smtp_rcpt_done() may change the order of the recipient
+/* list.
+/* DIAGNOSTICS
+/* Panic: interface violation.
+/*
+/* When a recipient can't be logged as completed, the recipient is
+/* logged as deferred instead.
+/* BUGS
+/* The single recipient list abstraction dates from the time
+/* that the SMTP client would give up after one SMTP session,
+/* so that each recipient was either bounced, delivered or
+/* deferred. Implicitly, all recipients were marked as DROP.
+/*
+/* This abstraction is less convenient when an SMTP client
+/* must be able to deliver left-over recipients to a backup
+/* host. It might be more natural to have an input list with
+/* recipients to deliver, and an output list with left-over
+/* recipients.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h> /* smtp_rcpt_cleanup */
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* Global library. */
+
+#include <deliver_request.h> /* smtp_rcpt_done */
+#include <deliver_completed.h> /* smtp_rcpt_done */
+#include <sent.h> /* smtp_rcpt_done */
+
+/* Application-specific. */
+
+#include <smtp.h>
+
+/* smtp_rcpt_done - mark recipient as done or else */
+
+void smtp_rcpt_done(SMTP_STATE *state, const char *reply, RECIPIENT *rcpt)
+{
+ DELIVER_REQUEST *request = state->request;
+ SMTP_SESSION *session = state->session;
+ int status;
+
+ /*
+ * Report success and delete the recipient from the delivery request.
+ * Defer if the success can't be reported.
+ */
+ status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, rcpt->orig_addr,
+ rcpt->address, rcpt->offset,
+ session->namaddr,
+ request->arrival_time,
+ "%s", reply);
+ if (status == 0)
+ if (request->flags & DEL_REQ_FLAG_SUCCESS)
+ deliver_completed(state->src, rcpt->offset);
+ SMTP_RCPT_DROP(state, rcpt);
+ state->status |= status;
+}
+
+/* smtp_rcpt_cleanup_callback - qsort callback */
+
+static int smtp_rcpt_cleanup_callback(const void *a, const void *b)
+{
+ return (((RECIPIENT *) a)->status - ((RECIPIENT *) b)->status);
+}
+
+/* smtp_rcpt_cleanup - purge completed recipients from request */
+
+void smtp_rcpt_cleanup(SMTP_STATE *state)
+{
+ RECIPIENT_LIST *rcpt_list = &state->request->rcpt_list;
+ RECIPIENT *rcpt;
+
+ /*
+ * Sanity checks.
+ */
+ if (state->rcpt_drop + state->rcpt_keep != state->rcpt_left)
+ msg_panic("smtp_rcpt_cleanup: recipient count mismatch: %d+%d!=%d",
+ state->rcpt_drop, state->rcpt_keep, state->rcpt_left);
+
+ /*
+ * Recipients marked KEEP sort before recipients marked DROP. Skip the
+ * sorting in the common case that all recipients are marked the same.
+ */
+ if (state->rcpt_drop > 0 && state->rcpt_keep > 0)
+ qsort((void *) rcpt_list->info, state->rcpt_left,
+ sizeof(rcpt_list->info), smtp_rcpt_cleanup_callback);
+
+ /*
+ * Truncate the recipient list and unmark the left-over recipients.
+ */
+ state->rcpt_left = state->rcpt_keep;
+ for (rcpt = rcpt_list->info; rcpt < rcpt_list->info + state->rcpt_left; rcpt++)
+ rcpt->status = 0;
+ state->rcpt_drop = state->rcpt_keep = 0;
+}
/* of all messages to the same domain is deferred, or one or more
/* recipients are given up as non-deliverable and a bounce log is
/* updated. In any case, the recipient is marked as either KEEP
-/* (try again with a backup host) or DROP (delete recipient from
+/* (try again with a backup host) or DROP (delete recipient from
/* delivery request).
/*
/* In addition, when an unexpected response code is seen such
/*
/* In case of a soft error, action depends on whether the error
/* qualifies for trying the request with other mail servers (log
-/* an informational record only and try the a backup server) or
+/* an informational record only and try a backup server) or
/* whether this is the final server (log recipient delivery status
/* records and delete the recipient from the request).
/*
/* The policy is: soft error, non-final server: log an informational
/* record why the host is being skipped; soft error, final server:
/* defer delivery of all remaining recipients and mark the destination
-/* a problematic; hard error: bounce all remaining recipients.
+/* as problematic; hard error: bounce all remaining recipients.
/* The result is non-zero.
/*
/* smtp_mesg_fail() handles the case where the smtp server
* delivery to a backup server. Just log something informative to show
* why we're skipping this host.
*/
- if (soft_error && state->final_server == 0
- && (smtp_backup_mask & SMTP_BACKUP_SESSION_FAILURE)) {
+ if (soft_error && state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
- SMTP_RCPT_MARK_KEEP(state, rcpt);
+ SMTP_RCPT_KEEP(state, rcpt);
}
}
* the recipient for delivery to a backup server.
*/
else {
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
request->arrival_time, "%s", vstring_str(why));
if (status == 0)
deliver_completed(state->src, rcpt->offset);
- SMTP_RCPT_MARK_DROP(state, rcpt);
+ SMTP_RCPT_DROP(state, rcpt);
state->status |= status;
}
/* XXX This assumes no fall-back relay. */
* delivery to a backup server. Just log something informative to show
* why we're skipping this host.
*/
- if (soft_error && state->final_server == 0
- && (smtp_backup_mask & SMTP_BACKUP_MESSAGE_FAILURE)) {
+ if (soft_error && state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
- SMTP_RCPT_MARK_KEEP(state, rcpt);
+ SMTP_RCPT_KEEP(state, rcpt);
}
}
* the recipient for delivery to a backup server.
*/
else {
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
"%s", vstring_str(why));
if (status == 0)
deliver_completed(state->src, rcpt->offset);
- SMTP_RCPT_MARK_DROP(state, rcpt);
+ SMTP_RCPT_DROP(state, rcpt);
state->status |= status;
}
}
/*
* Sanity check.
*/
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
msg_panic("smtp_rcpt_fail: recipient <%s> is marked", rcpt->address);
/*
* for trying other mail servers. Just log something informative to show
* why we're skipping this recipient now.
*/
- if (soft_error && state->final_server == 0
- && (smtp_backup_mask & SMTP_BACKUP_RECIPIENT_FAILURE)) {
+ if (soft_error && state->final_server == 0) {
VSTRING *buf = vstring_alloc(100);
va_start(ap, format);
vstring_vsprintf(buf, format, ap);
va_end(ap);
msg_info("%s: %s", request->queue_id, vstring_str(buf));
- SMTP_RCPT_MARK_KEEP(state, rcpt);
+ SMTP_RCPT_KEEP(state, rcpt);
vstring_free(buf);
}
va_end(ap);
if (status == 0)
deliver_completed(state->src, rcpt->offset);
- SMTP_RCPT_MARK_DROP(state, rcpt);
+ SMTP_RCPT_DROP(state, rcpt);
state->status |= status;
}
smtp_check_code(state, code);
* delivery to a backup server. Just log something informative to show
* why we're skipping this host.
*/
- if (state->final_server == 0
- && (smtp_backup_mask & SMTP_BACKUP_SESSION_FAILURE)) {
+ if (state->final_server == 0) {
msg_info("%s: %s", request->queue_id, vstring_str(why));
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
- SMTP_RCPT_MARK_KEEP(state, rcpt);
+ SMTP_RCPT_KEEP(state, rcpt);
}
}
* request.
*/
else {
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
+ for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
- if (SMTP_RCPT_MARK_ISSET(rcpt))
+ if (SMTP_RCPT_ISMARKED(rcpt))
continue;
state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id,
rcpt->offset, session->namaddr,
request->arrival_time,
"%s", vstring_str(why));
- SMTP_RCPT_MARK_DROP(state, rcpt);
+ SMTP_RCPT_DROP(state, rcpt);
}
}
+++ /dev/null
-/*++
-/* NAME
-/* smtpd_xclient 3
-/* SUMMARY
-/* maintain XCLIENT information
-/* SYNOPSIS
-/* #include "smtpd.h"
-/*
-/* void smtpd_xclient_init(state)
-/* SMTPD_STATE *state;
-/*
-/* void smtpd_xclient_reset(state)
-/* SMTPD_STATE *state;
-/* DESCRIPTION
-/* smtpd_xclient_init() zeroes the attributes for storage of XCLIENT
-/* FORWARD command parameters.
-/*
-/* smtpd_xclient_preset() takes the result from smtpd_xclient_init()
-/* and sets all fields to the same "unknown" value that regular
-/* client attributes would have.
-/*
-/* smtpd_xclient_reset() restores the state from smtpd_xclient_init().
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <mymalloc.h>
-#include <msg.h>
-
-/* Global library. */
-
-#include <mail_proto.h>
-
-/* Application-specific. */
-
-#include <smtpd.h>
-
-/* smtpd_xclient_init - initialize XCLIENT attributes */
-
-void smtpd_xclient_init(SMTPD_STATE *state)
-{
- state->xclient.used = 0;
- state->xclient.name = 0;
- state->xclient.addr = 0;
- state->xclient.namaddr = 0;
- state->xclient.peer_code = 0;
- state->xclient.protocol = 0;
- state->xclient.helo_name = 0;
-}
-
-/* smtpd_xclient_preset - set xclient attributes to "unknown" */
-
-void smtpd_xclient_preset(SMTPD_STATE *state)
-{
-
- /*
- * This is a temporary solution. Unknown forwarded attributes get the
- * same values as unknown normal attributes, so that we don't break
- * assumptions in pre-existing code.
- */
- state->xclient.used = 1;
- state->xclient.name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
- state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
- state->xclient.protocol = mystrdup(CLIENT_PROTO_UNKNOWN);
-}
-
-/* smtpd_xclient_reset - reset XCLIENT attributes */
-
-void smtpd_xclient_reset(SMTPD_STATE *state)
-{
-#define FREE_AND_WIPE(s) { if (s) myfree(s); s = 0; }
-
- state->xclient.used = 0;
- FREE_AND_WIPE(state->xclient.name);
- FREE_AND_WIPE(state->xclient.addr);
- FREE_AND_WIPE(state->xclient.namaddr);
- state->xclient.peer_code = 0;
- FREE_AND_WIPE(state->xclient.protocol);
- FREE_AND_WIPE(state->xclient.helo_name);
-}
+++ /dev/null
-/*++
-/* NAME
-/* intv 3
-/* SUMMARY
-/* integer array utilities
-/* SYNOPSIS
-/* #include <intv.h>
-/*
-/* INTV *intv_alloc(len)
-/* int len;
-/*
-/* INTV *intv_free(intvp)
-/* INTV *intvp;
-/*
-/* void intv_add(intvp, count, arg, ...)
-/* INTV *intvp;
-/* int count;
-/* int *arg;
-/* DESCRIPTION
-/* The functions in this module manipulate arrays of integers.
-/* An INTV structure contains the following members:
-/* .IP len
-/* The actual length of the \fIintv\fR array.
-/* .IP intc
-/* The number of \fIintv\fR elements used.
-/* .IP intv
-/* An array of integer values.
-/* .PP
-/* intv_alloc() returns an empty integer array of the requested
-/* length. The result is ready for use by intv_add().
-/*
-/* intv_add() copies zero or more integers and adds them to the
-/* specified integer array.
-/*
-/* intv_free() releases storage for an integer array, and conveniently
-/* returns a null pointer.
-/* SEE ALSO
-/* msg(3) diagnostics interface
-/* DIAGNOSTICS
-/* Fatal errors: memory allocation problem.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System libraries. */
-
-#include <sys_defs.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-
-/* Application-specific. */
-
-#include "mymalloc.h"
-#include "msg.h"
-#include "intv.h"
-
-/* intv_free - destroy integer array */
-
-INTV *intv_free(INTV *intvp)
-{
- myfree((char *) intvp->intv);
- myfree((char *) intvp);
- return (0);
-}
-
-/* intv_alloc - initialize integer array */
-
-INTV *intv_alloc(int len)
-{
- INTV *intvp;
-
- /*
- * Sanity check.
- */
- if (len < 1)
- msg_panic("intv_alloc: bad array length %d", len);
-
- /*
- * Initialize.
- */
- intvp = (INTV *) mymalloc(sizeof(*intvp));
- intvp->len = 0;
- intvp->intv = (int *) mymalloc(len * sizeof(intvp->intv[0]));
- intvp->len = len;
- intvp->intc = 0;
- return (intvp);
-}
-
-/* intv_add - add integer to vector */
-
-void intv_add(INTV *intvp, int count,...)
-{
- va_list ap;
- int new_len;
-
- /*
- * Make sure that always intvp->intc < intvp->len.
- */
- va_start(ap, count);
- while (count-- > 0) {
- if (intvp->intc >= intvp->len) {
- new_len = intvp->len * 2;
- intvp->intv = (int *) myrealloc((char *) intvp->intv,
- new_len * sizeof(int));
- intvp->len = new_len;
- }
- intvp->intv[intvp->intc++] = va_arg(ap, int);
- }
- va_end(ap);
-}
+++ /dev/null
-#ifndef _INTV_H_INCLUDED_
-#define _INTV_H_INCLUDED_
-
-/*++
-/* NAME
-/* intv 3h
-/* SUMMARY
-/* string array utilities
-/* SYNOPSIS
-/* #include "intv.h"
- DESCRIPTION
- .nf
-
- /*
- * External interface.
- */
-typedef struct INTV {
- int len; /* number of array elements */
- int intc; /* array elements in use */
- int *intv; /* integer array */
-} INTV;
-
-extern INTV *intv_alloc(int);
-extern void intv_add(INTV *, int,...);
-extern INTV *intv_free(INTV *);
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-#endif