2 * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
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.
9 * $Id: example.c,v 8.4 2008/07/22 15:12:47 ca Exp $
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.
18 #include <sys/types.h>
25 #include "libmilter/mfapi.h"
26 #include "libmilter/mfdef.h"
39 #define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))
41 static unsigned long mta_caps
= 0;
48 sfsistat rstat
= SMFIS_CONTINUE
;
49 struct mlfiPriv
*priv
= MLFIPRIV
;
57 /* close the archive file */
58 if (priv
->mlfi_fp
!= NULL
&& fclose(priv
->mlfi_fp
) == EOF
)
60 /* failed; we have to wait until later */
61 rstat
= SMFIS_TEMPFAIL
;
62 (void) unlink(priv
->mlfi_fname
);
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
, '/');
74 snprintf(hbuf
, sizeof hbuf
, "%s@%s", p
, host
);
75 smfi_addheader(ctx
, "X-Archived", hbuf
);
79 /* message was aborted -- delete the archive file */
80 (void) unlink(priv
->mlfi_fname
);
83 /* release private memory */
84 free(priv
->mlfi_fname
);
86 smfi_setpriv(ctx
, NULL
);
94 mlfi_envfrom(ctx
, envfrom
)
98 struct mlfiPriv
*priv
;
101 /* allocate some private memory */
102 priv
= malloc(sizeof *priv
);
105 /* can't accept this message right now */
106 return SMFIS_TEMPFAIL
;
108 memset(priv
, '\0', sizeof *priv
);
110 /* open a file to store this message */
111 priv
->mlfi_fname
= strdup("/tmp/msg.XXXXXXXX");
112 if (priv
->mlfi_fname
== NULL
)
115 return SMFIS_TEMPFAIL
;
117 if ((fd
= mkstemp(priv
->mlfi_fname
)) < 0 ||
118 (priv
->mlfi_fp
= fdopen(fd
, "w+")) == NULL
)
122 free(priv
->mlfi_fname
);
124 return SMFIS_TEMPFAIL
;
127 /* save the private data */
128 smfi_setpriv(ctx
, priv
);
130 /* continue processing */
131 return SMFIS_CONTINUE
;
135 mlfi_header(ctx
, headerf
, headerv
)
140 /* write the header to the log file */
141 fprintf(MLFIPRIV
->mlfi_fp
, "%s: %s\r\n", headerf
, headerv
);
143 /* continue processing */
144 return ((mta_caps
& SMFIP_NR_HDR
) != 0)
145 ? SMFIS_NOREPLY
: SMFIS_CONTINUE
;
152 /* output the blank line between the header and the body */
153 fprintf(MLFIPRIV
->mlfi_fp
, "\r\n");
155 /* continue processing */
156 return SMFIS_CONTINUE
;
160 mlfi_body(ctx
, bodyp
, bodylen
)
165 /* output body block to log file */
166 if (fwrite(bodyp
, bodylen
, 1, MLFIPRIV
->mlfi_fp
) <= 0)
169 (void) mlfi_cleanup(ctx
, false);
170 return SMFIS_TEMPFAIL
;
173 /* continue processing */
174 return SMFIS_CONTINUE
;
181 return mlfi_cleanup(ctx
, true);
195 return mlfi_cleanup(ctx
, false);
199 mlfi_unknown(ctx
, cmd
)
203 return SMFIS_CONTINUE
;
210 return SMFIS_CONTINUE
;
214 mlfi_negotiate(ctx
, f0
, f1
, f2
, f3
, pf0
, pf1
, pf2
, pf3
)
225 /* milter actions: add headers */
226 *pf0
= SMFIF_ADDHDRS
;
228 /* milter protocol steps: all but connect, HELO, RCPT */
229 *pf1
= SMFIP_NOCONNECT
|SMFIP_NOHELO
|SMFIP_NORCPT
;
231 if ((mta_caps
& SMFIP_NR_HDR
) != 0)
232 *pf1
|= SMFIP_NR_HDR
;
235 return SMFIS_CONTINUE
;
238 struct smfiDesc smfilter
=
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 */
268 /* Process command line options */
269 while ((c
= getopt(argc
, argv
, "p:")) != -1)
274 if (optarg
== NULL
|| *optarg
== '\0')
276 (void) fprintf(stderr
, "Illegal conn: %s\n",
280 (void) smfi_setconn(optarg
);
288 fprintf(stderr
, "%s: Missing required -p argument\n", argv
[0]);
291 if (smfi_register(smfilter
) == MI_FAILURE
)
293 fprintf(stderr
, "smfi_register failed\n");
294 exit(EX_UNAVAILABLE
);