sample.html revision 90792
190792Sgshapiro<html>
290792Sgshapiro<head><title>A Sample Filter</title></head>
390792Sgshapiro<body>
490792Sgshapiro<h1>A Sample Filter</h1>
590792Sgshapiro
690792SgshapiroThe following sample logs each message to a separate temporary file,
790792Sgshapiroadds a recipient given with the -a flag, and rejects a disallowed
890792Sgshapirorecipient address given with the -r flag.  It recognizes the following
990792Sgshapirooptions:
1090792Sgshapiro<p>
1190792Sgshapiro<center>
1290792Sgshapiro<table border="1" cellpadding=2 cellspacing=1>
1390792Sgshapiro<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr>
1490792Sgshapiro<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr>
1590792Sgshapiro<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr>
1690792Sgshapiro<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr>
1790792Sgshapiro</table>
1890792Sgshapiro</center>
1990792Sgshapiro<hr>
2090792Sgshapiro<pre>
2190792Sgshapiro#include "mfapi.h"
2290792Sgshapiro
2390792Sgshapiro#include &lt;stdio.h&gt;
2490792Sgshapiro#include &lt;stdlib.h&gt;
2590792Sgshapiro#include &lt;string.h&gt;
2690792Sgshapiro#include &lt;sys/types.h&gt;
2790792Sgshapiro#include &lt;sys/stat.h&gt;
2890792Sgshapiro#include &lt;sysexits.h&gt;
2990792Sgshapiro#include &lt;unistd.h&gt;
3090792Sgshapiro#ifndef bool
3190792Sgshapiro#define bool char
3290792Sgshapiro#define TRUE 1
3390792Sgshapiro#define FALSE 0
3490792Sgshapiro#endif
3590792Sgshapiro
3690792Sgshapiroextern int errno;
3790792Sgshapiro
3890792Sgshapiro
3990792Sgshapirostruct mlfiPriv
4090792Sgshapiro{
4190792Sgshapiro    char    *mlfi_fname;
4290792Sgshapiro    char    *mlfi_connectfrom;
4390792Sgshapiro    char    *mlfi_helofrom;
4490792Sgshapiro    FILE    *mlfi_fp;
4590792Sgshapiro};
4690792Sgshapiro
4790792Sgshapiro#define MLFIPRIV        ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx))
4890792Sgshapiro
4990792Sgshapiroextern sfsistat  mlfi_cleanup(SMFICTX *, bool);
5090792Sgshapiro/* recipients to add and reject (set with -a and -r options) */
5190792Sgshapirochar *add, *reject;
5290792Sgshapiro
5390792Sgshapirosfsistat
5490792Sgshapiro<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr)
5590792Sgshapiro     SMFICTX *ctx;
5690792Sgshapiro     char *hostname;
5790792Sgshapiro     _SOCK_ADDR *hostaddr;
5890792Sgshapiro{
5990792Sgshapiro    struct mlfiPriv *priv;
6090792Sgshapiro    char *ident;
6190792Sgshapiro
6290792Sgshapiro    /* allocate some private memory */
6390792Sgshapiro    priv = malloc(sizeof *priv);
6490792Sgshapiro    if (priv == NULL)
6590792Sgshapiro    {
6690792Sgshapiro	/* can't accept this message right now */
6790792Sgshapiro	return SMFIS_TEMPFAIL;
6890792Sgshapiro    }
6990792Sgshapiro    memset(priv, '\0', sizeof *priv);
7090792Sgshapiro
7190792Sgshapiro    /* save the private data */
7290792Sgshapiro    <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv);
7390792Sgshapiro        
7490792Sgshapiro    ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_");
7590792Sgshapiro    if(!ident) ident = "???";
7690792Sgshapiro    if(!(priv-&gt;mlfi_connectfrom = strdup(ident))) {
7790792Sgshapiro	return SMFIS_TEMPFAIL;
7890792Sgshapiro    }
7990792Sgshapiro    /* Continue processing. */
8090792Sgshapiro    return SMFIS_CONTINUE;
8190792Sgshapiro}
8290792Sgshapiro
8390792Sgshapirosfsistat
8490792Sgshapiro<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost)
8590792Sgshapiro     SMFICTX *ctx;
8690792Sgshapiro     char *helohost;
8790792Sgshapiro{
8890792Sgshapiro    char *tls;
8990792Sgshapiro    char *buf;
9090792Sgshapiro    struct mlfiPriv *priv = MLFIPRIV;
9190792Sgshapiro    tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}");
9290792Sgshapiro    if(!tls) tls = "No TLS";
9390792Sgshapiro    if(!helohost) helohost = "???";
9490792Sgshapiro    if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) {
9590792Sgshapiro	return SMFIS_TEMPFAIL;
9690792Sgshapiro    }
9790792Sgshapiro    sprintf(buf, "%s, %s", helohost, tls);
9890792Sgshapiro    if(priv-&gt;mlfi_helofrom)
9990792Sgshapiro	free(priv-&gt;mlfi_helofrom);
10090792Sgshapiro    priv-&gt;mlfi_helofrom = buf;
10190792Sgshapiro    /* Continue processing. */
10290792Sgshapiro    return SMFIS_CONTINUE;
10390792Sgshapiro}
10490792Sgshapiro
10590792Sgshapirosfsistat
10690792Sgshapiro<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv)
10790792Sgshapiro     SMFICTX *ctx;
10890792Sgshapiro     char **argv;
10990792Sgshapiro{
11090792Sgshapiro    struct mlfiPriv *priv = MLFIPRIV;
11190792Sgshapiro    char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}");
11290792Sgshapiro    int argc = 0;
11390792Sgshapiro
11490792Sgshapiro    /* open a file to store this message */
11590792Sgshapiro    priv-&gt;mlfi_fname = strdup("/tmp/msg.XXXXXX");
11690792Sgshapiro    mkstemp(priv-&gt;mlfi_fname);
11790792Sgshapiro    if (priv-&gt;mlfi_fname == NULL)
11890792Sgshapiro	return SMFIS_TEMPFAIL;
11990792Sgshapiro    if ((priv-&gt;mlfi_fp = fopen(priv-&gt;mlfi_fname, "w+")) == NULL)
12090792Sgshapiro    {
12190792Sgshapiro	free(priv-&gt;mlfi_fname);
12290792Sgshapiro	return SMFIS_TEMPFAIL;
12390792Sgshapiro    }
12490792Sgshapiro
12590792Sgshapiro    /* count the arguments */
12690792Sgshapiro    while(*argv++) ++argc;
12790792Sgshapiro    /* log the connection information we stored earlier: */
12890792Sgshapiro    if(fprintf(priv-&gt;mlfi_fp, "Connect from %s (%s)\n\n", 
12990792Sgshapiro	       priv-&gt;mlfi_helofrom, priv-&gt;mlfi_connectfrom) == EOF) {
13090792Sgshapiro	(void) mlfi_cleanup(ctx, FALSE);
13190792Sgshapiro	return SMFIS_TEMPFAIL;
13290792Sgshapiro    }
13390792Sgshapiro    /* log the sender */
13490792Sgshapiro    if(fprintf(priv-&gt;mlfi_fp, "FROM %s (%d argument%s)\n", 
13590792Sgshapiro	       mailaddr?mailaddr:"???", argc,
13690792Sgshapiro	       (argc == 1)?"":"s")
13790792Sgshapiro       == EOF) {
13890792Sgshapiro	(void) mlfi_cleanup(ctx, FALSE);
13990792Sgshapiro	return SMFIS_TEMPFAIL;
14090792Sgshapiro    }
14190792Sgshapiro    /* continue processing */
14290792Sgshapiro    return SMFIS_CONTINUE;
14390792Sgshapiro}
14490792Sgshapiro
14590792Sgshapirosfsistat
14690792Sgshapiro<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv)
14790792Sgshapiro     SMFICTX *ctx;
14890792Sgshapiro     char **argv;
14990792Sgshapiro{
15090792Sgshapiro    struct mlfiPriv *priv = MLFIPRIV;
15190792Sgshapiro    char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}");
15290792Sgshapiro    int argc = 0;
15390792Sgshapiro    /* count the arguments */
15490792Sgshapiro    while(*argv++) ++argc;
15590792Sgshapiro    /* log this recipient */
15690792Sgshapiro    if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) {
15790792Sgshapiro	if(fprintf(priv-&gt;mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr)
15890792Sgshapiro	   == EOF) {
15990792Sgshapiro	    (void) mlfi_cleanup(ctx, FALSE);
16090792Sgshapiro	    return SMFIS_TEMPFAIL;
16190792Sgshapiro	}
16290792Sgshapiro	return SMFIS_REJECT;
16390792Sgshapiro    }
16490792Sgshapiro    if(fprintf(priv-&gt;mlfi_fp, "RCPT %s (%d argument%s)\n", 
16590792Sgshapiro	       rcptaddr?rcptaddr:"???", argc, 
16690792Sgshapiro	       (argc == 1)?"":"s")
16790792Sgshapiro       == EOF) {
16890792Sgshapiro	(void) mlfi_cleanup(ctx, FALSE);
16990792Sgshapiro	return SMFIS_TEMPFAIL;
17090792Sgshapiro    }
17190792Sgshapiro    /* continue processing */
17290792Sgshapiro    return SMFIS_CONTINUE;
17390792Sgshapiro}
17490792Sgshapiro
17590792Sgshapirosfsistat
17690792Sgshapiro<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv)
17790792Sgshapiro     SMFICTX *ctx;
17890792Sgshapiro     char *headerf;
17990792Sgshapiro     unsigned char *headerv;
18090792Sgshapiro{
18190792Sgshapiro    /* write the header to the log file */
18290792Sgshapiro    fprintf(MLFIPRIV-&gt;mlfi_fp, "%s: %s\n", headerf, headerv);
18390792Sgshapiro
18490792Sgshapiro    /* continue processing */
18590792Sgshapiro    return SMFIS_CONTINUE;
18690792Sgshapiro}
18790792Sgshapiro
18890792Sgshapirosfsistat
18990792Sgshapiro<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx)
19090792Sgshapiro     SMFICTX *ctx;
19190792Sgshapiro{
19290792Sgshapiro    /* output the blank line between the header and the body */
19390792Sgshapiro    fprintf(MLFIPRIV-&gt;mlfi_fp, "\n");
19490792Sgshapiro
19590792Sgshapiro    /* continue processing */
19690792Sgshapiro    return SMFIS_CONTINUE;
19790792Sgshapiro}
19890792Sgshapiro
19990792Sgshapirosfsistat
20090792Sgshapiro<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen)
20190792Sgshapiro     SMFICTX *ctx;
20290792Sgshapiro     unsigned char *bodyp;
20390792Sgshapiro     size_t bodylen;
20490792Sgshapiro{
20590792Sgshapiro    /* output body block to log file */
20690792Sgshapiro    int nwritten;
20790792Sgshapiro    if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV-&gt;mlfi_fp)) != 1)
20890792Sgshapiro    {
20990792Sgshapiro	/* write failed */
21090792Sgshapiro	perror("error logging body");
21190792Sgshapiro	(void) mlfi_cleanup(ctx, FALSE);
21290792Sgshapiro	return SMFIS_TEMPFAIL;
21390792Sgshapiro    }
21490792Sgshapiro
21590792Sgshapiro    /* continue processing */
21690792Sgshapiro    return SMFIS_CONTINUE;
21790792Sgshapiro}
21890792Sgshapiro
21990792Sgshapirosfsistat
22090792Sgshapiro<a href="xxfi_eom.html">mlfi_eom</a>(ctx)
22190792Sgshapiro     SMFICTX *ctx;
22290792Sgshapiro{
22390792Sgshapiro    bool ok = TRUE;
22490792Sgshapiro    /* change recipients, if requested */
22590792Sgshapiro    if(add)
22690792Sgshapiro	ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS);
22790792Sgshapiro    return mlfi_cleanup(ctx, ok);
22890792Sgshapiro}
22990792Sgshapiro
23090792Sgshapirosfsistat
23190792Sgshapiro<a href="xxfi_abort.html">mlfi_abort</a>(ctx)
23290792Sgshapiro     SMFICTX *ctx;
23390792Sgshapiro{
23490792Sgshapiro    return mlfi_cleanup(ctx, FALSE);
23590792Sgshapiro}
23690792Sgshapiro
23790792Sgshapirosfsistat
23890792Sgshapiromlfi_cleanup(ctx, ok)
23990792Sgshapiro     SMFICTX *ctx;
24090792Sgshapiro     bool ok;
24190792Sgshapiro{
24290792Sgshapiro    sfsistat rstat = SMFIS_CONTINUE;
24390792Sgshapiro    struct mlfiPriv *priv = MLFIPRIV;
24490792Sgshapiro    char *p;
24590792Sgshapiro    char host[512];
24690792Sgshapiro    char hbuf[1024];
24790792Sgshapiro
24890792Sgshapiro    if (priv == NULL)
24990792Sgshapiro	return rstat;
25090792Sgshapiro
25190792Sgshapiro    /* close the archive file */
25290792Sgshapiro    if (priv-&gt;mlfi_fp != NULL && fclose(priv-&gt;mlfi_fp) == EOF)
25390792Sgshapiro    {
25490792Sgshapiro	/* failed; we have to wait until later */
25590792Sgshapiro	fprintf(stderr, "Couldn't close archive file %s: %s\n",
25690792Sgshapiro		priv-&gt;mlfi_fname, strerror(errno));
25790792Sgshapiro	rstat = SMFIS_TEMPFAIL;
25890792Sgshapiro	(void) unlink(priv-&gt;mlfi_fname);
25990792Sgshapiro    }
26090792Sgshapiro    else if (ok)
26190792Sgshapiro    {
26290792Sgshapiro	/* add a header to the message announcing our presence */
26390792Sgshapiro	if (gethostname(host, sizeof host) &lt; 0)
26490792Sgshapiro	    strncpy(host, "localhost", sizeof host);
26590792Sgshapiro	p = strrchr(priv-&gt;mlfi_fname, '/');
26690792Sgshapiro	if (p == NULL)
26790792Sgshapiro	    p = priv-&gt;mlfi_fname;
26890792Sgshapiro	else
26990792Sgshapiro	    p++;
27090792Sgshapiro	snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
27190792Sgshapiro	<a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf);
27290792Sgshapiro    }
27390792Sgshapiro    else
27490792Sgshapiro    {
27590792Sgshapiro	/* message was aborted -- delete the archive file */
27690792Sgshapiro	fprintf(stderr, "Message aborted.  Removing %s\n",
27790792Sgshapiro		priv-&gt;mlfi_fname);
27890792Sgshapiro	rstat = SMFIS_TEMPFAIL;
27990792Sgshapiro	(void) unlink(priv-&gt;mlfi_fname);
28090792Sgshapiro    }
28190792Sgshapiro
28290792Sgshapiro    /* release private memory */
28390792Sgshapiro    free(priv-&gt;mlfi_fname);
28490792Sgshapiro
28590792Sgshapiro    /* return status */
28690792Sgshapiro    return rstat;
28790792Sgshapiro}
28890792Sgshapiro
28990792Sgshapirosfsistat
29090792Sgshapiro<a href="xxfi_close.html">mlfi_close</a>(ctx)
29190792Sgshapiro     SMFICTX *ctx;
29290792Sgshapiro{
29390792Sgshapiro    struct mlfiPriv *priv = MLFIPRIV;
29490792Sgshapiro    if(priv-&gt;mlfi_connectfrom)
29590792Sgshapiro	free(priv-&gt;mlfi_connectfrom);
29690792Sgshapiro    if(priv-&gt;mlfi_helofrom)
29790792Sgshapiro	free(priv-&gt;mlfi_helofrom);
29890792Sgshapiro    free(priv);
29990792Sgshapiro    <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL);
30090792Sgshapiro    return SMFIS_CONTINUE;
30190792Sgshapiro}
30290792Sgshapiro
30390792Sgshapirostruct smfiDesc smfilter =
30490792Sgshapiro{
30590792Sgshapiro    "SampleFilter", /* filter name */
30690792Sgshapiro    SMFI_VERSION,   /* version code -- do not change */
30790792Sgshapiro    SMFIF_ADDHDRS,  /* flags */
30890792Sgshapiro    <a href="xxfi_connect.html">mlfi_connect</a>,   /* connection info filter */
30990792Sgshapiro    <a href="xxfi_helo.html">mlfi_helo</a>,      /* SMTP HELO command filter */
31090792Sgshapiro    <a href="xxfi_envfrom.html">mlfi_envfrom</a>,   /* envelope sender filter */
31190792Sgshapiro    <a href="xxfi_envrcpt.html">mlfi_envrcpt</a>,   /* envelope recipient filter */
31290792Sgshapiro    <a href="xxfi_header.html">mlfi_header</a>,    /* header filter */
31390792Sgshapiro    <a href="xxfi_eoh.html">mlfi_eoh</a>,       /* end of header */
31490792Sgshapiro    <a href="xxfi_body.html">mlfi_body</a>,      /* body block filter */
31590792Sgshapiro    <a href="xxfi_eom.html">mlfi_eom</a>,       /* end of message */
31690792Sgshapiro    <a href="xxfi_abort.html">mlfi_abort</a>,     /* message aborted */
31790792Sgshapiro    <a href="xxfi_close.html">mlfi_close</a>,     /* connection cleanup */
31890792Sgshapiro};
31990792Sgshapiro
32090792Sgshapirostatic void 
32190792Sgshapirousage()
32290792Sgshapiro{
32390792Sgshapiro    fprintf(stderr, 
32490792Sgshapiro	    "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\
32590792Sgshapiro\t[-a accept-addr]\n");
32690792Sgshapiro}
32790792Sgshapiro
32890792Sgshapiroint
32990792Sgshapiromain(argc, argv)
33090792Sgshapiro     int argc;
33190792Sgshapiro     char *argv[];
33290792Sgshapiro{
33390792Sgshapiro    int retval;
33490792Sgshapiro    char c;
33590792Sgshapiro    const char *args = "p:t:r:a:h";
33690792Sgshapiro    extern char *optarg;
33790792Sgshapiro
33890792Sgshapiro    /* Process command line options */
33990792Sgshapiro    while ((c = getopt(argc, argv, args)) != (char)EOF)
34090792Sgshapiro    {
34190792Sgshapiro	switch (c)
34290792Sgshapiro	{
34390792Sgshapiro	case 'p':
34490792Sgshapiro	    if (optarg == NULL || *optarg == '\0')
34590792Sgshapiro	    {
34690792Sgshapiro		(void) fprintf(stderr, "Illegal conn: %s\n",
34790792Sgshapiro			       optarg);
34890792Sgshapiro		exit(EX_USAGE);
34990792Sgshapiro	    }
35090792Sgshapiro	    if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE)
35190792Sgshapiro	    {
35290792Sgshapiro		(void) fputs("smfi_setconn failed", stderr);
35390792Sgshapiro		exit(EX_SOFTWARE);
35490792Sgshapiro	    }
35590792Sgshapiro	    /* 
35690792Sgshapiro	    ** If we're using a local socket, make sure it doesn't
35790792Sgshapiro	    ** already exist.
35890792Sgshapiro	    */
35990792Sgshapiro	    if(strncmp(optarg, "unix:", 5) == 0)
36090792Sgshapiro		unlink(optarg + 5);
36190792Sgshapiro	    else if(strncmp(optarg, "local:", 6) == 0)
36290792Sgshapiro		unlink(optarg + 6);
36390792Sgshapiro	    break;
36490792Sgshapiro
36590792Sgshapiro	case 't':
36690792Sgshapiro	    if (optarg == NULL || *optarg == '\0')
36790792Sgshapiro	    {
36890792Sgshapiro		(void) fprintf(stderr, "Illegal timeout: %s\n",
36990792Sgshapiro			       optarg);
37090792Sgshapiro		exit(EX_USAGE);
37190792Sgshapiro	    }
37290792Sgshapiro	    if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE)
37390792Sgshapiro	    {
37490792Sgshapiro		(void) fputs("smfi_settimeout failed", stderr);
37590792Sgshapiro		exit(EX_SOFTWARE);
37690792Sgshapiro	    }
37790792Sgshapiro	    break;
37890792Sgshapiro
37990792Sgshapiro	case 'r':
38090792Sgshapiro	    if (optarg == NULL)
38190792Sgshapiro	    {
38290792Sgshapiro		(void) fprintf(stderr, "Illegal reject rcpt: %s\n",
38390792Sgshapiro			       optarg);
38490792Sgshapiro		exit(EX_USAGE);
38590792Sgshapiro	    }
38690792Sgshapiro	    reject = optarg;
38790792Sgshapiro	    break;
38890792Sgshapiro
38990792Sgshapiro	case 'a':
39090792Sgshapiro	    if (optarg == NULL)
39190792Sgshapiro	    {
39290792Sgshapiro		(void) fprintf(stderr, "Illegal add rcpt: %s\n",
39390792Sgshapiro			       optarg);
39490792Sgshapiro		exit(EX_USAGE);
39590792Sgshapiro	    }
39690792Sgshapiro	    add = optarg;
39790792Sgshapiro	    smfilter.xxfi_flags |= SMFIF_ADDRCPT;
39890792Sgshapiro	    break;
39990792Sgshapiro	case 'h':
40090792Sgshapiro	default:
40190792Sgshapiro	    usage();
40290792Sgshapiro	    exit(0);
40390792Sgshapiro	}
40490792Sgshapiro    }
40590792Sgshapiro    if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE)
40690792Sgshapiro    {
40790792Sgshapiro	fprintf(stderr, "smfi_register failed\n");
40890792Sgshapiro	exit(EX_UNAVAILABLE);
40990792Sgshapiro    }
41090792Sgshapiro    retval = <a href="smfi_main.html">smfi_main</a>();
41190792Sgshapiro    return retval;
41290792Sgshapiro}
41390792Sgshapiro
41490792Sgshapiro/* eof */
41590792Sgshapiro
41690792Sgshapiro</pre>
41790792Sgshapiro<hr size="1">
41890792Sgshapiro<font size="-1">
41990792SgshapiroCopyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
42090792SgshapiroAll rights reserved.
42190792Sgshapiro<br>
42290792SgshapiroBy using this file, you agree to the terms and conditions set
42390792Sgshapiroforth in the <a href="LICENSE.txt">LICENSE</a>.
42490792Sgshapiro</font>
42590792Sgshapiro</body>
42690792Sgshapiro</html>
427