2002-02-17 21:56:45 +00:00

427 lines
11 KiB
HTML

<html>
<head><title>A Sample Filter</title></head>
<body>
<h1>A Sample Filter</h1>
The following sample logs each message to a separate temporary file,
adds a recipient given with the -a flag, and rejects a disallowed
recipient address given with the -r flag. It recognizes the following
options:
<p>
<center>
<table border="1" cellpadding=2 cellspacing=1>
<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr>
<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr>
<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr>
<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr>
</table>
</center>
<hr>
<pre>
#include "mfapi.h"
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sysexits.h&gt;
#include &lt;unistd.h&gt;
#ifndef bool
#define bool char
#define TRUE 1
#define FALSE 0
#endif
extern int errno;
struct mlfiPriv
{
char *mlfi_fname;
char *mlfi_connectfrom;
char *mlfi_helofrom;
FILE *mlfi_fp;
};
#define MLFIPRIV ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx))
extern sfsistat mlfi_cleanup(SMFICTX *, bool);
/* recipients to add and reject (set with -a and -r options) */
char *add, *reject;
sfsistat
<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr)
SMFICTX *ctx;
char *hostname;
_SOCK_ADDR *hostaddr;
{
struct mlfiPriv *priv;
char *ident;
/* allocate some private memory */
priv = malloc(sizeof *priv);
if (priv == NULL)
{
/* can't accept this message right now */
return SMFIS_TEMPFAIL;
}
memset(priv, '\0', sizeof *priv);
/* save the private data */
<a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv);
ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_");
if(!ident) ident = "???";
if(!(priv-&gt;mlfi_connectfrom = strdup(ident))) {
return SMFIS_TEMPFAIL;
}
/* Continue processing. */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost)
SMFICTX *ctx;
char *helohost;
{
char *tls;
char *buf;
struct mlfiPriv *priv = MLFIPRIV;
tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}");
if(!tls) tls = "No TLS";
if(!helohost) helohost = "???";
if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) {
return SMFIS_TEMPFAIL;
}
sprintf(buf, "%s, %s", helohost, tls);
if(priv-&gt;mlfi_helofrom)
free(priv-&gt;mlfi_helofrom);
priv-&gt;mlfi_helofrom = buf;
/* Continue processing. */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv)
SMFICTX *ctx;
char **argv;
{
struct mlfiPriv *priv = MLFIPRIV;
char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}");
int argc = 0;
/* open a file to store this message */
priv-&gt;mlfi_fname = strdup("/tmp/msg.XXXXXX");
mkstemp(priv-&gt;mlfi_fname);
if (priv-&gt;mlfi_fname == NULL)
return SMFIS_TEMPFAIL;
if ((priv-&gt;mlfi_fp = fopen(priv-&gt;mlfi_fname, "w+")) == NULL)
{
free(priv-&gt;mlfi_fname);
return SMFIS_TEMPFAIL;
}
/* count the arguments */
while(*argv++) ++argc;
/* log the connection information we stored earlier: */
if(fprintf(priv-&gt;mlfi_fp, "Connect from %s (%s)\n\n",
priv-&gt;mlfi_helofrom, priv-&gt;mlfi_connectfrom) == EOF) {
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}
/* log the sender */
if(fprintf(priv-&gt;mlfi_fp, "FROM %s (%d argument%s)\n",
mailaddr?mailaddr:"???", argc,
(argc == 1)?"":"s")
== EOF) {
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}
/* continue processing */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv)
SMFICTX *ctx;
char **argv;
{
struct mlfiPriv *priv = MLFIPRIV;
char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}");
int argc = 0;
/* count the arguments */
while(*argv++) ++argc;
/* log this recipient */
if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) {
if(fprintf(priv-&gt;mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr)
== EOF) {
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}
return SMFIS_REJECT;
}
if(fprintf(priv-&gt;mlfi_fp, "RCPT %s (%d argument%s)\n",
rcptaddr?rcptaddr:"???", argc,
(argc == 1)?"":"s")
== EOF) {
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}
/* continue processing */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv)
SMFICTX *ctx;
char *headerf;
unsigned char *headerv;
{
/* write the header to the log file */
fprintf(MLFIPRIV-&gt;mlfi_fp, "%s: %s\n", headerf, headerv);
/* continue processing */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx)
SMFICTX *ctx;
{
/* output the blank line between the header and the body */
fprintf(MLFIPRIV-&gt;mlfi_fp, "\n");
/* continue processing */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen)
SMFICTX *ctx;
unsigned char *bodyp;
size_t bodylen;
{
/* output body block to log file */
int nwritten;
if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV-&gt;mlfi_fp)) != 1)
{
/* write failed */
perror("error logging body");
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}
/* continue processing */
return SMFIS_CONTINUE;
}
sfsistat
<a href="xxfi_eom.html">mlfi_eom</a>(ctx)
SMFICTX *ctx;
{
bool ok = TRUE;
/* change recipients, if requested */
if(add)
ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS);
return mlfi_cleanup(ctx, ok);
}
sfsistat
<a href="xxfi_abort.html">mlfi_abort</a>(ctx)
SMFICTX *ctx;
{
return mlfi_cleanup(ctx, FALSE);
}
sfsistat
mlfi_cleanup(ctx, ok)
SMFICTX *ctx;
bool ok;
{
sfsistat rstat = SMFIS_CONTINUE;
struct mlfiPriv *priv = MLFIPRIV;
char *p;
char host[512];
char hbuf[1024];
if (priv == NULL)
return rstat;
/* close the archive file */
if (priv-&gt;mlfi_fp != NULL && fclose(priv-&gt;mlfi_fp) == EOF)
{
/* failed; we have to wait until later */
fprintf(stderr, "Couldn't close archive file %s: %s\n",
priv-&gt;mlfi_fname, strerror(errno));
rstat = SMFIS_TEMPFAIL;
(void) unlink(priv-&gt;mlfi_fname);
}
else if (ok)
{
/* add a header to the message announcing our presence */
if (gethostname(host, sizeof host) &lt; 0)
strncpy(host, "localhost", sizeof host);
p = strrchr(priv-&gt;mlfi_fname, '/');
if (p == NULL)
p = priv-&gt;mlfi_fname;
else
p++;
snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
<a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf);
}
else
{
/* message was aborted -- delete the archive file */
fprintf(stderr, "Message aborted. Removing %s\n",
priv-&gt;mlfi_fname);
rstat = SMFIS_TEMPFAIL;
(void) unlink(priv-&gt;mlfi_fname);
}
/* release private memory */
free(priv-&gt;mlfi_fname);
/* return status */
return rstat;
}
sfsistat
<a href="xxfi_close.html">mlfi_close</a>(ctx)
SMFICTX *ctx;
{
struct mlfiPriv *priv = MLFIPRIV;
if(priv-&gt;mlfi_connectfrom)
free(priv-&gt;mlfi_connectfrom);
if(priv-&gt;mlfi_helofrom)
free(priv-&gt;mlfi_helofrom);
free(priv);
<a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL);
return SMFIS_CONTINUE;
}
struct smfiDesc smfilter =
{
"SampleFilter", /* filter name */
SMFI_VERSION, /* version code -- do not change */
SMFIF_ADDHDRS, /* flags */
<a href="xxfi_connect.html">mlfi_connect</a>, /* connection info filter */
<a href="xxfi_helo.html">mlfi_helo</a>, /* SMTP HELO command filter */
<a href="xxfi_envfrom.html">mlfi_envfrom</a>, /* envelope sender filter */
<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>, /* envelope recipient filter */
<a href="xxfi_header.html">mlfi_header</a>, /* header filter */
<a href="xxfi_eoh.html">mlfi_eoh</a>, /* end of header */
<a href="xxfi_body.html">mlfi_body</a>, /* body block filter */
<a href="xxfi_eom.html">mlfi_eom</a>, /* end of message */
<a href="xxfi_abort.html">mlfi_abort</a>, /* message aborted */
<a href="xxfi_close.html">mlfi_close</a>, /* connection cleanup */
};
static void
usage()
{
fprintf(stderr,
"Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\
\t[-a accept-addr]\n");
}
int
main(argc, argv)
int argc;
char *argv[];
{
int retval;
char c;
const char *args = "p:t:r:a:h";
extern char *optarg;
/* Process command line options */
while ((c = getopt(argc, argv, args)) != (char)EOF)
{
switch (c)
{
case 'p':
if (optarg == NULL || *optarg == '\0')
{
(void) fprintf(stderr, "Illegal conn: %s\n",
optarg);
exit(EX_USAGE);
}
if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE)
{
(void) fputs("smfi_setconn failed", stderr);
exit(EX_SOFTWARE);
}
/*
** If we're using a local socket, make sure it doesn't
** already exist.
*/
if(strncmp(optarg, "unix:", 5) == 0)
unlink(optarg + 5);
else if(strncmp(optarg, "local:", 6) == 0)
unlink(optarg + 6);
break;
case 't':
if (optarg == NULL || *optarg == '\0')
{
(void) fprintf(stderr, "Illegal timeout: %s\n",
optarg);
exit(EX_USAGE);
}
if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE)
{
(void) fputs("smfi_settimeout failed", stderr);
exit(EX_SOFTWARE);
}
break;
case 'r':
if (optarg == NULL)
{
(void) fprintf(stderr, "Illegal reject rcpt: %s\n",
optarg);
exit(EX_USAGE);
}
reject = optarg;
break;
case 'a':
if (optarg == NULL)
{
(void) fprintf(stderr, "Illegal add rcpt: %s\n",
optarg);
exit(EX_USAGE);
}
add = optarg;
smfilter.xxfi_flags |= SMFIF_ADDRCPT;
break;
case 'h':
default:
usage();
exit(0);
}
}
if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE)
{
fprintf(stderr, "smfi_register failed\n");
exit(EX_UNAVAILABLE);
}
retval = <a href="smfi_main.html">smfi_main</a>();
return retval;
}
/* eof */
</pre>
<hr size="1">
<font size="-1">
Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
All rights reserved.
<br>
By using this file, you agree to the terms and conditions set
forth in the <a href="LICENSE.txt">LICENSE</a>.
</font>
</body>
</html>