]> diplodocus.org Git - mdeliver/blob - processor.c
2c015c68e69a465219c6435e5a99bce9bd85a7dd
[mdeliver] / processor.c
1 static char ident[] = "$Id$";
2
3 // Configuration
4 #define T_TYPE TRANSPORT_LOCALHOST
5 #define T_SOCK NULL /* for TRANSPORT_UNIX */
6 #define T_HOST NULL /* for TRANSPORT_TCP */
7 #define T_PORT 7783 /* for TRANSPORT_{LOCALHOST,TCP} */
8 #define M_TIME 30 /* call it ham if no answer in 30 seconds */
9
10 #include <sys/types.h>
11
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <pwd.h>
15 #include <stdarg.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sysexits.h>
21 #include <unistd.h>
22
23 #include "libspamc.h"
24
25 static char *errfn;
26
27 static int flags = SPAMC_CHECK_ONLY | SPAMC_RAW_MODE;
28
29 #define err(n, ...) _err(n, true, __FILE__, __LINE__, __VA_ARGS__)
30 #define errx(n, ...) _err(n, false, __FILE__, __LINE__, __VA_ARGS__)
31
32 void
33 _err(int exitcode, bool want_strerror, char *fn, int lineno, char *format, ...)
34 {
35 FILE *fp;
36 va_list ap;
37
38 /* If anything fails in here, we're fucked, so just exit. If
39 * exitcode is greather than 0 (i.e. the caller is trying to exit
40 * with a failure code), use that, else use EX_IOERR. */
41
42 if ((fp = fopen(errfn, "a")) == NULL) {
43 exit(exitcode > 0 ? exitcode : EX_IOERR);
44 }
45
46 if (fprintf(fp, ".mdeliver-processor:%s:%d:", fn, lineno) < 0) {
47 exit(exitcode > 0 ? exitcode : EX_IOERR);
48 }
49
50 va_start(ap, format);
51 if (vfprintf(fp, format, ap) < 0) {
52 exit(exitcode > 0 ? exitcode : EX_IOERR);
53 }
54 va_end(ap);
55
56 if (want_strerror) {
57 if (fputs(": ", fp) == EOF) {
58 exit(exitcode > 0 ? exitcode : EX_IOERR);
59 }
60 if (fputs(strerror(errno), fp) == EOF) {
61 exit(exitcode > 0 ? exitcode : EX_IOERR);
62 }
63 }
64 if (fputs("\n", fp) == EOF) {
65 exit(exitcode > 0 ? exitcode : EX_IOERR);
66 }
67
68 if (fclose(fp) == EOF) {
69 exit(exitcode > 0 ? exitcode : EX_IOERR);
70 }
71
72 if (exitcode >= 0) {
73 exit(exitcode);
74 }
75 }
76
77 static char *
78 logname()
79 {
80 char *logname;
81 struct passwd *p;
82
83 if ((logname = getenv("LOGNAME")) != NULL) {
84 return logname;
85 }
86
87 errno = 0;
88 if ((p = getpwuid(getuid())) == NULL) {
89 if (errno != 0) {
90 err(EX_OSERR, "getpwuid(getuid())");
91 }
92 errx(EX_NOUSER, "Who are you? What do you want? Why are you here? Where are you going?");
93 }
94
95 return p->pw_name;
96 }
97
98 static void
99 get_transport(struct transport *t)
100 {
101 int status;
102
103 t->type = T_TYPE;
104 t->socketpath = T_SOCK;
105 t->hostname = T_HOST;
106 t->port = T_PORT;
107
108 if ((status = transport_setup(t, 0)) != EX_OK) {
109 errx(status, "transport_setup");
110 }
111 }
112
113 static void
114 get_message(char *fn, struct message *m)
115 {
116 int fd;
117 int status;
118
119 m->timeout = M_TIME;
120 /* message_filter stupidly allocates a buffer a little bigger than
121 * max_len for reading the processed message back from spamd even
122 * when told not to. It never uses the buffer. */
123 m->max_len = 0;
124
125 if ((fd = open(fn, O_RDONLY)) == -1) {
126 err(EX_IOERR, "open(%s)", fn);
127 }
128
129 if ((status = message_read(fd, flags, m)) != EX_OK) {
130 errx(status, "message_read");
131 }
132 }
133
134 static bool
135 is_spam(char *message)
136 {
137 struct transport t;
138 struct message m;
139 int status;
140
141 get_transport(&t);
142 get_message(message, &m);
143
144 if ((status = message_filter(&t, logname(), flags, &m)) != EX_OK) {
145 errx(status, "message_filter");
146 }
147
148 if (m.is_spam == EX_ISSPAM) {
149 return true;
150 } else if (m.is_spam == EX_NOTSPAM) {
151 return false;
152 }
153
154 errx(m.is_spam, "message_filter");
155 /*NOTREACHED*/
156 return false;
157 }
158
159 static int
160 process(char *tmp)
161 {
162 size_t len = strlen(tmp);
163 errfn = malloc(len + 1);
164 /* 5 for spam/ and 1 for terminating null */
165 char *new = malloc(len + 5 + 1);
166
167 strcpy(errfn, "err");
168 strcat(errfn, tmp + 3);
169
170 new[0] = '\0';
171 if (is_spam(tmp)) {
172 strcpy(new, "spam/");
173 }
174 strcat(new, "new");
175 strcat(new, tmp + 3);
176
177 if (rename(tmp, new) == -1) {
178 err(EX_OSERR, "rename(%s, %s)", tmp, new);
179 }
180
181 return 0;
182 }
183
184
185 int
186 main(int argc, char *argv[])
187 {
188 if (argc < 2) {
189 exit(EX_USAGE);
190 }
191
192 if (argv[1][0] == '-' && argv[1][1] == 'v') {
193 puts(ident);
194 return 0;
195 }
196
197 return process(argv[1]);
198 }