|
Line 0
Link Here
|
|
|
1 |
/* A trivial filter that logs all email to a file. */ |
| 2 |
|
| 3 |
#include <sys/types.h> |
| 4 |
#include <stdio.h> |
| 5 |
#include <stdlib.h> |
| 6 |
#include <string.h> |
| 7 |
#include <sysexits.h> |
| 8 |
#include <unistd.h> |
| 9 |
|
| 10 |
#include "libmilter/mfapi.h" |
| 11 |
|
| 12 |
typedef int bool; |
| 13 |
|
| 14 |
#ifndef FALSE |
| 15 |
# define FALSE 0 |
| 16 |
#endif /* ! FALSE*/ |
| 17 |
#ifndef TRUE |
| 18 |
# define TRUE 1 |
| 19 |
#endif /* ! TRUE*/ |
| 20 |
|
| 21 |
struct mlfiPriv |
| 22 |
{ |
| 23 |
char *mlfi_fname; |
| 24 |
FILE *mlfi_fp; |
| 25 |
}; |
| 26 |
|
| 27 |
#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx)) |
| 28 |
|
| 29 |
extern sfsistat mlfi_cleanup(SMFICTX *, bool); |
| 30 |
|
| 31 |
sfsistat |
| 32 |
mlfi_envfrom(ctx, envfrom) |
| 33 |
SMFICTX *ctx; |
| 34 |
char **envfrom; |
| 35 |
{ |
| 36 |
struct mlfiPriv *priv; |
| 37 |
int fd; |
| 38 |
|
| 39 |
/* allocate some private memory */ |
| 40 |
priv = malloc(sizeof *priv); |
| 41 |
if (priv == NULL) |
| 42 |
{ |
| 43 |
/* can't accept this message right now */ |
| 44 |
return SMFIS_TEMPFAIL; |
| 45 |
} |
| 46 |
memset(priv, '\0', sizeof *priv); |
| 47 |
|
| 48 |
/* open a file to store this message */ |
| 49 |
priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX"); |
| 50 |
if (priv->mlfi_fname == NULL) |
| 51 |
{ |
| 52 |
free(priv); |
| 53 |
return SMFIS_TEMPFAIL; |
| 54 |
} |
| 55 |
if ((fd = mkstemp(priv->mlfi_fname)) < 0 || |
| 56 |
(priv->mlfi_fp = fdopen(fd, "w+")) == NULL) |
| 57 |
{ |
| 58 |
free(priv->mlfi_fname); |
| 59 |
free(priv); |
| 60 |
return SMFIS_TEMPFAIL; |
| 61 |
} |
| 62 |
|
| 63 |
/* save the private data */ |
| 64 |
smfi_setpriv(ctx, priv); |
| 65 |
|
| 66 |
/* continue processing */ |
| 67 |
return SMFIS_CONTINUE; |
| 68 |
} |
| 69 |
|
| 70 |
sfsistat |
| 71 |
mlfi_header(ctx, headerf, headerv) |
| 72 |
SMFICTX *ctx; |
| 73 |
char *headerf; |
| 74 |
char *headerv; |
| 75 |
{ |
| 76 |
/* write the header to the log file */ |
| 77 |
fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv); |
| 78 |
|
| 79 |
/* continue processing */ |
| 80 |
return SMFIS_CONTINUE; |
| 81 |
} |
| 82 |
|
| 83 |
sfsistat |
| 84 |
mlfi_eoh(ctx) |
| 85 |
SMFICTX *ctx; |
| 86 |
{ |
| 87 |
/* output the blank line between the header and the body */ |
| 88 |
fprintf(MLFIPRIV->mlfi_fp, "\r\n"); |
| 89 |
|
| 90 |
/* continue processing */ |
| 91 |
return SMFIS_CONTINUE; |
| 92 |
} |
| 93 |
|
| 94 |
sfsistat |
| 95 |
mlfi_body(ctx, bodyp, bodylen) |
| 96 |
SMFICTX *ctx; |
| 97 |
u_char *bodyp; |
| 98 |
size_t bodylen; |
| 99 |
{ |
| 100 |
/* output body block to log file */ |
| 101 |
if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0) |
| 102 |
{ |
| 103 |
/* write failed */ |
| 104 |
(void) mlfi_cleanup(ctx, FALSE); |
| 105 |
return SMFIS_TEMPFAIL; |
| 106 |
} |
| 107 |
|
| 108 |
/* continue processing */ |
| 109 |
return SMFIS_CONTINUE; |
| 110 |
} |
| 111 |
|
| 112 |
sfsistat |
| 113 |
mlfi_eom(ctx) |
| 114 |
SMFICTX *ctx; |
| 115 |
{ |
| 116 |
return mlfi_cleanup(ctx, TRUE); |
| 117 |
} |
| 118 |
|
| 119 |
sfsistat |
| 120 |
mlfi_close(ctx) |
| 121 |
SMFICTX *ctx; |
| 122 |
{ |
| 123 |
return SMFIS_ACCEPT; |
| 124 |
} |
| 125 |
|
| 126 |
sfsistat |
| 127 |
mlfi_abort(ctx) |
| 128 |
SMFICTX *ctx; |
| 129 |
{ |
| 130 |
return mlfi_cleanup(ctx, FALSE); |
| 131 |
} |
| 132 |
|
| 133 |
sfsistat |
| 134 |
mlfi_cleanup(ctx, ok) |
| 135 |
SMFICTX *ctx; |
| 136 |
bool ok; |
| 137 |
{ |
| 138 |
sfsistat rstat = SMFIS_CONTINUE; |
| 139 |
struct mlfiPriv *priv = MLFIPRIV; |
| 140 |
char *p; |
| 141 |
char host[512]; |
| 142 |
char hbuf[1024]; |
| 143 |
|
| 144 |
if (priv == NULL) |
| 145 |
return rstat; |
| 146 |
|
| 147 |
/* close the archive file */ |
| 148 |
if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF) |
| 149 |
{ |
| 150 |
/* failed; we have to wait until later */ |
| 151 |
rstat = SMFIS_TEMPFAIL; |
| 152 |
(void) unlink(priv->mlfi_fname); |
| 153 |
} |
| 154 |
else if (ok) |
| 155 |
{ |
| 156 |
/* add a header to the message announcing our presence */ |
| 157 |
if (gethostname(host, sizeof host) < 0) |
| 158 |
strlcpy(host, "localhost", sizeof host); |
| 159 |
p = strrchr(priv->mlfi_fname, '/'); |
| 160 |
if (p == NULL) |
| 161 |
p = priv->mlfi_fname; |
| 162 |
else |
| 163 |
p++; |
| 164 |
snprintf(hbuf, sizeof hbuf, "%s@%s", p, host); |
| 165 |
smfi_addheader(ctx, "X-Archived", hbuf); |
| 166 |
} |
| 167 |
else |
| 168 |
{ |
| 169 |
/* message was aborted -- delete the archive file */ |
| 170 |
(void) unlink(priv->mlfi_fname); |
| 171 |
} |
| 172 |
|
| 173 |
/* release private memory */ |
| 174 |
free(priv->mlfi_fname); |
| 175 |
free(priv); |
| 176 |
smfi_setpriv(ctx, NULL); |
| 177 |
|
| 178 |
/* return status */ |
| 179 |
return rstat; |
| 180 |
} |
| 181 |
|
| 182 |
struct smfiDesc smfilter = |
| 183 |
{ |
| 184 |
"SampleFilter", /* filter name */ |
| 185 |
SMFI_VERSION, /* version code -- do not change */ |
| 186 |
SMFIF_ADDHDRS, /* flags */ |
| 187 |
NULL, /* connection info filter */ |
| 188 |
NULL, /* SMTP HELO command filter */ |
| 189 |
mlfi_envfrom, /* envelope sender filter */ |
| 190 |
NULL, /* envelope recipient filter */ |
| 191 |
mlfi_header, /* header filter */ |
| 192 |
mlfi_eoh, /* end of header */ |
| 193 |
mlfi_body, /* body block filter */ |
| 194 |
mlfi_eom, /* end of message */ |
| 195 |
mlfi_abort, /* message aborted */ |
| 196 |
mlfi_close /* connection cleanup */ |
| 197 |
}; |
| 198 |
|
| 199 |
|
| 200 |
int |
| 201 |
main(argc, argv) |
| 202 |
int argc; |
| 203 |
char *argv[]; |
| 204 |
{ |
| 205 |
int c; |
| 206 |
const char *args = "p:"; |
| 207 |
|
| 208 |
/* Process command line options */ |
| 209 |
while ((c = getopt(argc, argv, args)) != -1) |
| 210 |
{ |
| 211 |
switch (c) |
| 212 |
{ |
| 213 |
case 'p': |
| 214 |
if (optarg == NULL || *optarg == '\0') |
| 215 |
{ |
| 216 |
(void) fprintf(stderr, "Illegal conn: %s\n", |
| 217 |
optarg); |
| 218 |
exit(EX_USAGE); |
| 219 |
} |
| 220 |
(void) smfi_setconn(optarg); |
| 221 |
break; |
| 222 |
|
| 223 |
} |
| 224 |
} |
| 225 |
if (smfi_register(smfilter) == MI_FAILURE) |
| 226 |
{ |
| 227 |
fprintf(stderr, "smfi_register failed\n"); |
| 228 |
exit(EX_UNAVAILABLE); |
| 229 |
} |
| 230 |
return smfi_main(); |
| 231 |
} |
| 232 |
|
| 233 |
/* eof */ |