chiark / gitweb /
xtitle.c: Shut up warnings about ignoring the return from write(2).
[misc] / qmail-checkspam.c
1 /* -*-c-*-
2  *
3  * $Id: qmail-checkspam.c,v 1.2 2004/04/08 01:36:26 mdw Exp $
4  *
5  * Filter messages for spam
6  *
7  * (c) 2003 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <sys/types.h>
37 #include <sys/unistd.h>
38
39 #include <libspamc.h>
40
41 /*----- Main code ---------------------------------------------------------*/
42
43 static const char *strenv(const char *e, const char *d)
44 {
45   const char *p = getenv(e);
46   if (!p) return (d);
47   return (p);
48 }
49
50 static double dblenv(const char *e, double d)
51 {
52   const char *p = getenv(e);
53   char *q;
54   int err = errno;
55   double f;
56   if (!p) return (d);
57   errno = 0;
58   f = strtod(p, &q);
59   if (errno) return (d);
60   errno = err;
61   return (f);
62 }
63
64 static int intenv(const char *e, int d)
65 {
66   const char *p = getenv(e);
67   char *q;
68   int err = errno;
69   long l;
70   if (!p) return (d);
71   errno = 0;
72   l = strtol(p, &q, 0);
73   if (errno) return (d);
74   errno = err;
75   if (l < 0 || l > INT_MAX) return (d);
76   return ((int)l);
77 }
78
79 int shovel(int from, int to)
80 {
81   char buf[4096];
82   ssize_t n;
83   char *p;
84   size_t r;
85
86   for (;;) {
87     n = read(from, buf, sizeof(buf));
88     if (n < 0 && errno != EINTR && errno != EAGAIN)
89       return (-1);
90     else if (!n)
91       return (0);
92     p = buf;
93     r = n;
94     while (r) {
95       n = write(to, p, n);
96       if (n <= 0 && errno != EINTR && errno != EAGAIN)
97         return (-1);
98       r -= n;
99       p += n;
100     }
101   }
102 }
103
104 int main(int argc, char *argv[])
105 {
106   struct sockaddr sa;
107   struct message m;
108   int fd_m[2], fd_e[2];
109   pid_t kid;
110   const char *qmq;
111   int rc;
112
113   if (getenv("RELAYCLIENT")) goto exec;
114   m.max_len = intenv("QMAIL_CHECKSPAM_MAXLEN", 2 * 1024 * 1024);
115   m.timeout = intenv("QMAIL_CHECKSPAM_TIMEOUT", 300);
116   rc = message_read(0, 0, &m);
117   if (rc != 0 && rc != EX_TOOBIG)
118     return (54);
119   if (!rc) {
120     if (lookup_host(strenv("QMAIL_CHECKSPAM_SPAMDHOST", "localhost"),
121                     intenv("QMAIL_CHECKSPAM_SPAMDPORT", 783),
122                     &sa))
123       return (56);
124     if (message_filter(&sa, "spamd", 0, &m))
125       return (74);
126     if (m.score >= dblenv("QMAIL_CHECKSPAM_THRESH", m.threshold))
127       return (31);
128   }
129   if (pipe(fd_m) || pipe(fd_e))
130     return (56);
131   if ((kid = fork()) < 0)
132     return (56);
133   if (!kid) {
134     close(fd_m[0]);
135     close(fd_e[0]);
136     if (message_write(fd_m[1], &m) < 0)
137       _exit(127);
138     if (rc == EX_TOOBIG && shovel(0, fd_m[1]))
139       _exit(127);
140     close(fd_m[1]);
141     if (shovel(1, fd_e[1]))
142       _exit(127);
143     close(fd_e[1]);
144     _exit(0);
145   }
146
147   dup2(fd_m[0], 0);
148   dup2(fd_e[0], 1);
149   close(fd_m[0]);
150   close(fd_e[0]);
151   close(fd_m[1]);
152   close(fd_e[1]);
153 exec:
154   qmq = strenv("QMAIL_CHECKSPAM_QUEUE", "/var/qmail/bin/qmail-queue");
155   execlp(qmq, qmq, (char *)0);
156   fprintf(stderr, "failed to exec: %s\n", strerror(errno));
157   return (56);
158 }
159
160 /*----- That's all, folks -------------------------------------------------*/