]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/sendmail/libmilter/example.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / sendmail / libmilter / example.c
1 /*
2  *  Copyright (c) 2006 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  * $Id: example.c,v 8.4 2008/07/22 15:12:47 ca Exp $
10  */
11
12 /*
13 **  A trivial example filter that logs all email to a file.
14 **  This milter also has some callbacks which it does not really use,
15 **  but they are defined to serve as an example.
16 */
17
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sysexits.h>
23 #include <unistd.h>
24
25 #include "libmilter/mfapi.h"
26 #include "libmilter/mfdef.h"
27
28 #ifndef true
29 # define false  0
30 # define true   1
31 #endif /* ! true */
32
33 struct mlfiPriv
34 {
35         char    *mlfi_fname;
36         FILE    *mlfi_fp;
37 };
38
39 #define MLFIPRIV        ((struct mlfiPriv *) smfi_getpriv(ctx))
40
41 static unsigned long mta_caps = 0;
42
43 sfsistat
44 mlfi_cleanup(ctx, ok)
45         SMFICTX *ctx;
46         bool ok;
47 {
48         sfsistat rstat = SMFIS_CONTINUE;
49         struct mlfiPriv *priv = MLFIPRIV;
50         char *p;
51         char host[512];
52         char hbuf[1024];
53
54         if (priv == NULL)
55                 return rstat;
56
57         /* close the archive file */
58         if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF)
59         {
60                 /* failed; we have to wait until later */
61                 rstat = SMFIS_TEMPFAIL;
62                 (void) unlink(priv->mlfi_fname);
63         }
64         else if (ok)
65         {
66                 /* add a header to the message announcing our presence */
67                 if (gethostname(host, sizeof host) < 0)
68                         snprintf(host, sizeof host, "localhost");
69                 p = strrchr(priv->mlfi_fname, '/');
70                 if (p == NULL)
71                         p = priv->mlfi_fname;
72                 else
73                         p++;
74                 snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
75                 smfi_addheader(ctx, "X-Archived", hbuf);
76         }
77         else
78         {
79                 /* message was aborted -- delete the archive file */
80                 (void) unlink(priv->mlfi_fname);
81         }
82
83         /* release private memory */
84         free(priv->mlfi_fname);
85         free(priv);
86         smfi_setpriv(ctx, NULL);
87
88         /* return status */
89         return rstat;
90 }
91
92
93 sfsistat
94 mlfi_envfrom(ctx, envfrom)
95         SMFICTX *ctx;
96         char **envfrom;
97 {
98         struct mlfiPriv *priv;
99         int fd = -1;
100
101         /* allocate some private memory */
102         priv = malloc(sizeof *priv);
103         if (priv == NULL)
104         {
105                 /* can't accept this message right now */
106                 return SMFIS_TEMPFAIL;
107         }
108         memset(priv, '\0', sizeof *priv);
109
110         /* open a file to store this message */
111         priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX");
112         if (priv->mlfi_fname == NULL)
113         {
114                 free(priv);
115                 return SMFIS_TEMPFAIL;
116         }
117         if ((fd = mkstemp(priv->mlfi_fname)) < 0 ||
118             (priv->mlfi_fp = fdopen(fd, "w+")) == NULL)
119         {
120                 if (fd >= 0)
121                         (void) close(fd);
122                 free(priv->mlfi_fname);
123                 free(priv);
124                 return SMFIS_TEMPFAIL;
125         }
126
127         /* save the private data */
128         smfi_setpriv(ctx, priv);
129
130         /* continue processing */
131         return SMFIS_CONTINUE;
132 }
133
134 sfsistat
135 mlfi_header(ctx, headerf, headerv)
136         SMFICTX *ctx;
137         char *headerf;
138         char *headerv;
139 {
140         /* write the header to the log file */
141         fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv);
142
143         /* continue processing */
144         return ((mta_caps & SMFIP_NR_HDR) != 0)
145                 ? SMFIS_NOREPLY : SMFIS_CONTINUE;
146 }
147
148 sfsistat
149 mlfi_eoh(ctx)
150         SMFICTX *ctx;
151 {
152         /* output the blank line between the header and the body */
153         fprintf(MLFIPRIV->mlfi_fp, "\r\n");
154
155         /* continue processing */
156         return SMFIS_CONTINUE;
157 }
158
159 sfsistat
160 mlfi_body(ctx, bodyp, bodylen)
161         SMFICTX *ctx;
162         u_char *bodyp;
163         size_t bodylen;
164 {
165         /* output body block to log file */
166         if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0)
167         {
168                 /* write failed */
169                 (void) mlfi_cleanup(ctx, false);
170                 return SMFIS_TEMPFAIL;
171         }
172
173         /* continue processing */
174         return SMFIS_CONTINUE;
175 }
176
177 sfsistat
178 mlfi_eom(ctx)
179         SMFICTX *ctx;
180 {
181         return mlfi_cleanup(ctx, true);
182 }
183
184 sfsistat
185 mlfi_close(ctx)
186         SMFICTX *ctx;
187 {
188         return SMFIS_ACCEPT;
189 }
190
191 sfsistat
192 mlfi_abort(ctx)
193         SMFICTX *ctx;
194 {
195         return mlfi_cleanup(ctx, false);
196 }
197
198 sfsistat
199 mlfi_unknown(ctx, cmd)
200         SMFICTX *ctx;
201         char *cmd;
202 {
203         return SMFIS_CONTINUE;
204 }
205
206 sfsistat
207 mlfi_data(ctx)
208         SMFICTX *ctx;
209 {
210         return SMFIS_CONTINUE;
211 }
212
213 sfsistat
214 mlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3)
215         SMFICTX *ctx;
216         unsigned long f0;
217         unsigned long f1;
218         unsigned long f2;
219         unsigned long f3;
220         unsigned long *pf0;
221         unsigned long *pf1;
222         unsigned long *pf2;
223         unsigned long *pf3;
224 {
225         /* milter actions: add headers */
226         *pf0 = SMFIF_ADDHDRS;
227
228         /* milter protocol steps: all but connect, HELO, RCPT */
229         *pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT;
230         mta_caps = f1;
231         if ((mta_caps & SMFIP_NR_HDR) != 0)
232                 *pf1 |= SMFIP_NR_HDR;
233         *pf2 = 0;
234         *pf3 = 0;
235         return SMFIS_CONTINUE;
236 }
237
238 struct smfiDesc smfilter =
239 {
240         "SampleFilter", /* filter name */
241         SMFI_VERSION,   /* version code -- do not change */
242         SMFIF_ADDHDRS,  /* flags */
243         NULL,           /* connection info filter */
244         NULL,           /* SMTP HELO command filter */
245         mlfi_envfrom,   /* envelope sender filter */
246         NULL,           /* envelope recipient filter */
247         mlfi_header,    /* header filter */
248         mlfi_eoh,       /* end of header */
249         mlfi_body,      /* body block filter */
250         mlfi_eom,       /* end of message */
251         mlfi_abort,     /* message aborted */
252         mlfi_close,     /* connection cleanup */
253         mlfi_unknown,   /* unknown/unimplemented SMTP commands */
254         mlfi_data,      /* DATA command filter */
255         mlfi_negotiate  /* option negotiation at connection startup */
256 };
257
258 int
259 main(argc, argv)
260         int argc;
261         char *argv[];
262 {
263         bool setconn;
264         int c;
265
266         setconn = false;
267
268         /* Process command line options */
269         while ((c = getopt(argc, argv, "p:")) != -1)
270         {
271                 switch (c)
272                 {
273                   case 'p':
274                         if (optarg == NULL || *optarg == '\0')
275                         {
276                                 (void) fprintf(stderr, "Illegal conn: %s\n",
277                                                optarg);
278                                 exit(EX_USAGE);
279                         }
280                         (void) smfi_setconn(optarg);
281                         setconn = true;
282                         break;
283
284                 }
285         }
286         if (!setconn)
287         {
288                 fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);
289                 exit(EX_USAGE);
290         }
291         if (smfi_register(smfilter) == MI_FAILURE)
292         {
293                 fprintf(stderr, "smfi_register failed\n");
294                 exit(EX_UNAVAILABLE);
295         }
296         return smfi_main();
297 }
298