sample.html revision 90792
1<html>
2<head><title>A Sample Filter</title></head>
3<body>
4<h1>A Sample Filter</h1>
5
6The following sample logs each message to a separate temporary file,
7adds a recipient given with the -a flag, and rejects a disallowed
8recipient address given with the -r flag.  It recognizes the following
9options:
10<p>
11<center>
12<table border="1" cellpadding=2 cellspacing=1>
13<tr><td><code>-p port</code></td><td>The port through which the MTA will connect to the filter.</td></tr>
14<tr><td><code>-t sec</code></td><td>The timeout value.</td></tr>
15<tr><td><code>-r addr</code></td><td>A recipient to reject.</td></tr>
16<tr><td><code>-a addr</code></td><td>A recipient to add.</td></tr>
17</table>
18</center>
19<hr>
20<pre>
21#include "mfapi.h"
22
23#include &lt;stdio.h&gt;
24#include &lt;stdlib.h&gt;
25#include &lt;string.h&gt;
26#include &lt;sys/types.h&gt;
27#include &lt;sys/stat.h&gt;
28#include &lt;sysexits.h&gt;
29#include &lt;unistd.h&gt;
30#ifndef bool
31#define bool char
32#define TRUE 1
33#define FALSE 0
34#endif
35
36extern int errno;
37
38
39struct mlfiPriv
40{
41    char    *mlfi_fname;
42    char    *mlfi_connectfrom;
43    char    *mlfi_helofrom;
44    FILE    *mlfi_fp;
45};
46
47#define MLFIPRIV        ((struct mlfiPriv *) <a href="smfi_getpriv.html">smfi_getpriv</a>(ctx))
48
49extern sfsistat  mlfi_cleanup(SMFICTX *, bool);
50/* recipients to add and reject (set with -a and -r options) */
51char *add, *reject;
52
53sfsistat
54<a href="xxfi_connect.html">mlfi_connect</a>(ctx, hostname, hostaddr)
55     SMFICTX *ctx;
56     char *hostname;
57     _SOCK_ADDR *hostaddr;
58{
59    struct mlfiPriv *priv;
60    char *ident;
61
62    /* allocate some private memory */
63    priv = malloc(sizeof *priv);
64    if (priv == NULL)
65    {
66	/* can't accept this message right now */
67	return SMFIS_TEMPFAIL;
68    }
69    memset(priv, '\0', sizeof *priv);
70
71    /* save the private data */
72    <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, priv);
73        
74    ident = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "_");
75    if(!ident) ident = "???";
76    if(!(priv-&gt;mlfi_connectfrom = strdup(ident))) {
77	return SMFIS_TEMPFAIL;
78    }
79    /* Continue processing. */
80    return SMFIS_CONTINUE;
81}
82
83sfsistat
84<a href="xxfi_helo.html">mlfi_helo</a>(ctx, helohost)
85     SMFICTX *ctx;
86     char *helohost;
87{
88    char *tls;
89    char *buf;
90    struct mlfiPriv *priv = MLFIPRIV;
91    tls = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{tls_version}");
92    if(!tls) tls = "No TLS";
93    if(!helohost) helohost = "???";
94    if(!(buf = (char*)malloc(strlen(tls) + strlen(helohost) + 3))) {
95	return SMFIS_TEMPFAIL;
96    }
97    sprintf(buf, "%s, %s", helohost, tls);
98    if(priv-&gt;mlfi_helofrom)
99	free(priv-&gt;mlfi_helofrom);
100    priv-&gt;mlfi_helofrom = buf;
101    /* Continue processing. */
102    return SMFIS_CONTINUE;
103}
104
105sfsistat
106<a href="xxfi_envfrom.html">mlfi_envfrom</a>(ctx, argv)
107     SMFICTX *ctx;
108     char **argv;
109{
110    struct mlfiPriv *priv = MLFIPRIV;
111    char *mailaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{mail_addr}");
112    int argc = 0;
113
114    /* open a file to store this message */
115    priv-&gt;mlfi_fname = strdup("/tmp/msg.XXXXXX");
116    mkstemp(priv-&gt;mlfi_fname);
117    if (priv-&gt;mlfi_fname == NULL)
118	return SMFIS_TEMPFAIL;
119    if ((priv-&gt;mlfi_fp = fopen(priv-&gt;mlfi_fname, "w+")) == NULL)
120    {
121	free(priv-&gt;mlfi_fname);
122	return SMFIS_TEMPFAIL;
123    }
124
125    /* count the arguments */
126    while(*argv++) ++argc;
127    /* log the connection information we stored earlier: */
128    if(fprintf(priv-&gt;mlfi_fp, "Connect from %s (%s)\n\n", 
129	       priv-&gt;mlfi_helofrom, priv-&gt;mlfi_connectfrom) == EOF) {
130	(void) mlfi_cleanup(ctx, FALSE);
131	return SMFIS_TEMPFAIL;
132    }
133    /* log the sender */
134    if(fprintf(priv-&gt;mlfi_fp, "FROM %s (%d argument%s)\n", 
135	       mailaddr?mailaddr:"???", argc,
136	       (argc == 1)?"":"s")
137       == EOF) {
138	(void) mlfi_cleanup(ctx, FALSE);
139	return SMFIS_TEMPFAIL;
140    }
141    /* continue processing */
142    return SMFIS_CONTINUE;
143}
144
145sfsistat
146<a href="xxfi_envrcpt.html">mlfi_envrcpt</a>(ctx, argv)
147     SMFICTX *ctx;
148     char **argv;
149{
150    struct mlfiPriv *priv = MLFIPRIV;
151    char *rcptaddr = <a href="smfi_getsymval.html">smfi_getsymval</a>(ctx, "{rcpt_addr}");
152    int argc = 0;
153    /* count the arguments */
154    while(*argv++) ++argc;
155    /* log this recipient */
156    if(reject && rcptaddr && (strcmp(rcptaddr, reject) == 0)) {
157	if(fprintf(priv-&gt;mlfi_fp, "RCPT %s -- REJECTED\n", rcptaddr)
158	   == EOF) {
159	    (void) mlfi_cleanup(ctx, FALSE);
160	    return SMFIS_TEMPFAIL;
161	}
162	return SMFIS_REJECT;
163    }
164    if(fprintf(priv-&gt;mlfi_fp, "RCPT %s (%d argument%s)\n", 
165	       rcptaddr?rcptaddr:"???", argc, 
166	       (argc == 1)?"":"s")
167       == EOF) {
168	(void) mlfi_cleanup(ctx, FALSE);
169	return SMFIS_TEMPFAIL;
170    }
171    /* continue processing */
172    return SMFIS_CONTINUE;
173}
174
175sfsistat
176<a href="xxfi_header.html">mlfi_header</a>(ctx, headerf, headerv)
177     SMFICTX *ctx;
178     char *headerf;
179     unsigned char *headerv;
180{
181    /* write the header to the log file */
182    fprintf(MLFIPRIV-&gt;mlfi_fp, "%s: %s\n", headerf, headerv);
183
184    /* continue processing */
185    return SMFIS_CONTINUE;
186}
187
188sfsistat
189<a href="xxfi_eoh.html">mlfi_eoh</a>(ctx)
190     SMFICTX *ctx;
191{
192    /* output the blank line between the header and the body */
193    fprintf(MLFIPRIV-&gt;mlfi_fp, "\n");
194
195    /* continue processing */
196    return SMFIS_CONTINUE;
197}
198
199sfsistat
200<a href="xxfi_body.html">mlfi_body</a>(ctx, bodyp, bodylen)
201     SMFICTX *ctx;
202     unsigned char *bodyp;
203     size_t bodylen;
204{
205    /* output body block to log file */
206    int nwritten;
207    if ((nwritten = fwrite(bodyp, bodylen, 1, MLFIPRIV-&gt;mlfi_fp)) != 1)
208    {
209	/* write failed */
210	perror("error logging body");
211	(void) mlfi_cleanup(ctx, FALSE);
212	return SMFIS_TEMPFAIL;
213    }
214
215    /* continue processing */
216    return SMFIS_CONTINUE;
217}
218
219sfsistat
220<a href="xxfi_eom.html">mlfi_eom</a>(ctx)
221     SMFICTX *ctx;
222{
223    bool ok = TRUE;
224    /* change recipients, if requested */
225    if(add)
226	ok = ok && (<a href="smfi_addrcpt.html">smfi_addrcpt</a>(ctx, add) == MI_SUCCESS);
227    return mlfi_cleanup(ctx, ok);
228}
229
230sfsistat
231<a href="xxfi_abort.html">mlfi_abort</a>(ctx)
232     SMFICTX *ctx;
233{
234    return mlfi_cleanup(ctx, FALSE);
235}
236
237sfsistat
238mlfi_cleanup(ctx, ok)
239     SMFICTX *ctx;
240     bool ok;
241{
242    sfsistat rstat = SMFIS_CONTINUE;
243    struct mlfiPriv *priv = MLFIPRIV;
244    char *p;
245    char host[512];
246    char hbuf[1024];
247
248    if (priv == NULL)
249	return rstat;
250
251    /* close the archive file */
252    if (priv-&gt;mlfi_fp != NULL && fclose(priv-&gt;mlfi_fp) == EOF)
253    {
254	/* failed; we have to wait until later */
255	fprintf(stderr, "Couldn't close archive file %s: %s\n",
256		priv-&gt;mlfi_fname, strerror(errno));
257	rstat = SMFIS_TEMPFAIL;
258	(void) unlink(priv-&gt;mlfi_fname);
259    }
260    else if (ok)
261    {
262	/* add a header to the message announcing our presence */
263	if (gethostname(host, sizeof host) &lt; 0)
264	    strncpy(host, "localhost", sizeof host);
265	p = strrchr(priv-&gt;mlfi_fname, '/');
266	if (p == NULL)
267	    p = priv-&gt;mlfi_fname;
268	else
269	    p++;
270	snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
271	<a href="smfi_addheader.html">smfi_addheader</a>(ctx, "X-Archived", hbuf);
272    }
273    else
274    {
275	/* message was aborted -- delete the archive file */
276	fprintf(stderr, "Message aborted.  Removing %s\n",
277		priv-&gt;mlfi_fname);
278	rstat = SMFIS_TEMPFAIL;
279	(void) unlink(priv-&gt;mlfi_fname);
280    }
281
282    /* release private memory */
283    free(priv-&gt;mlfi_fname);
284
285    /* return status */
286    return rstat;
287}
288
289sfsistat
290<a href="xxfi_close.html">mlfi_close</a>(ctx)
291     SMFICTX *ctx;
292{
293    struct mlfiPriv *priv = MLFIPRIV;
294    if(priv-&gt;mlfi_connectfrom)
295	free(priv-&gt;mlfi_connectfrom);
296    if(priv-&gt;mlfi_helofrom)
297	free(priv-&gt;mlfi_helofrom);
298    free(priv);
299    <a href="smfi_setpriv.html">smfi_setpriv</a>(ctx, NULL);
300    return SMFIS_CONTINUE;
301}
302
303struct smfiDesc smfilter =
304{
305    "SampleFilter", /* filter name */
306    SMFI_VERSION,   /* version code -- do not change */
307    SMFIF_ADDHDRS,  /* flags */
308    <a href="xxfi_connect.html">mlfi_connect</a>,   /* connection info filter */
309    <a href="xxfi_helo.html">mlfi_helo</a>,      /* SMTP HELO command filter */
310    <a href="xxfi_envfrom.html">mlfi_envfrom</a>,   /* envelope sender filter */
311    <a href="xxfi_envrcpt.html">mlfi_envrcpt</a>,   /* envelope recipient filter */
312    <a href="xxfi_header.html">mlfi_header</a>,    /* header filter */
313    <a href="xxfi_eoh.html">mlfi_eoh</a>,       /* end of header */
314    <a href="xxfi_body.html">mlfi_body</a>,      /* body block filter */
315    <a href="xxfi_eom.html">mlfi_eom</a>,       /* end of message */
316    <a href="xxfi_abort.html">mlfi_abort</a>,     /* message aborted */
317    <a href="xxfi_close.html">mlfi_close</a>,     /* connection cleanup */
318};
319
320static void 
321usage()
322{
323    fprintf(stderr, 
324	    "Usage: sample [-p socket-addr] [-t timeout] [-r reject-addr] \n\
325\t[-a accept-addr]\n");
326}
327
328int
329main(argc, argv)
330     int argc;
331     char *argv[];
332{
333    int retval;
334    char c;
335    const char *args = "p:t:r:a:h";
336    extern char *optarg;
337
338    /* Process command line options */
339    while ((c = getopt(argc, argv, args)) != (char)EOF)
340    {
341	switch (c)
342	{
343	case 'p':
344	    if (optarg == NULL || *optarg == '\0')
345	    {
346		(void) fprintf(stderr, "Illegal conn: %s\n",
347			       optarg);
348		exit(EX_USAGE);
349	    }
350	    if(<a href="smfi_setconn.html">smfi_setconn</a>(optarg) == MI_FAILURE)
351	    {
352		(void) fputs("smfi_setconn failed", stderr);
353		exit(EX_SOFTWARE);
354	    }
355	    /* 
356	    ** If we're using a local socket, make sure it doesn't
357	    ** already exist.
358	    */
359	    if(strncmp(optarg, "unix:", 5) == 0)
360		unlink(optarg + 5);
361	    else if(strncmp(optarg, "local:", 6) == 0)
362		unlink(optarg + 6);
363	    break;
364
365	case 't':
366	    if (optarg == NULL || *optarg == '\0')
367	    {
368		(void) fprintf(stderr, "Illegal timeout: %s\n",
369			       optarg);
370		exit(EX_USAGE);
371	    }
372	    if(<a href="smfi_settimeout.html">smfi_settimeout</a>(atoi(optarg)) == MI_FAILURE)
373	    {
374		(void) fputs("smfi_settimeout failed", stderr);
375		exit(EX_SOFTWARE);
376	    }
377	    break;
378
379	case 'r':
380	    if (optarg == NULL)
381	    {
382		(void) fprintf(stderr, "Illegal reject rcpt: %s\n",
383			       optarg);
384		exit(EX_USAGE);
385	    }
386	    reject = optarg;
387	    break;
388
389	case 'a':
390	    if (optarg == NULL)
391	    {
392		(void) fprintf(stderr, "Illegal add rcpt: %s\n",
393			       optarg);
394		exit(EX_USAGE);
395	    }
396	    add = optarg;
397	    smfilter.xxfi_flags |= SMFIF_ADDRCPT;
398	    break;
399	case 'h':
400	default:
401	    usage();
402	    exit(0);
403	}
404    }
405    if (<a href="smfi_register.html">smfi_register</a>(smfilter) == MI_FAILURE)
406    {
407	fprintf(stderr, "smfi_register failed\n");
408	exit(EX_UNAVAILABLE);
409    }
410    retval = <a href="smfi_main.html">smfi_main</a>();
411    return retval;
412}
413
414/* eof */
415
416</pre>
417<hr size="1">
418<font size="-1">
419Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
420All rights reserved.
421<br>
422By using this file, you agree to the terms and conditions set
423forth in the <a href="LICENSE.txt">LICENSE</a>.
424</font>
425</body>
426</html>
427