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