b67ca673e06a88ce6d23e02c59d09f43a6289be4
[claws.git] / src / plugins / spamassassin / utils.c
1 /*
2  * This code is copyright 2001 by Craig Hughes
3  * Portions copyright 2002 by Brad Jorsch
4  * It is licensed under the same license as Perl itself.  The text of this
5  * license is included in the SpamAssassin distribution in the file named
6  * "License".
7  */
8
9 #include <unistd.h>
10 #include <errno.h>
11 #include <signal.h>
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include "utils.h"
17
18 /* Dec 13 2001 jm: added safe full-read and full-write functions.  These
19  * can cope with networks etc., where a write or read may not read all
20  * the data that's there, in one call.
21  */
22 /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */
23 /* Aug 14, 2002 bj: moved these to utils.c */
24 /* Jan 13, 2003 ym: added timeout functionality */
25 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
26
27 /* -------------------------------------------------------------------------- */
28
29 typedef void    sigfunc(int);   /* for signal handlers */
30
31 sigfunc* sig_catch(int sig, void (*f)(int))
32 {
33   struct sigaction act, oact;
34   act.sa_handler = f;
35   act.sa_flags = 0;
36   sigemptyset(&act.sa_mask);
37   sigaction(sig, &act, &oact);
38   return oact.sa_handler;
39 }
40
41 static void catch_alrm(int x) {
42   UNUSED_VARIABLE(x);
43 }
44
45 ssize_t
46 fd_timeout_read (int fd, void *buf, size_t nbytes)
47 {
48   ssize_t nred;
49   sigfunc* sig;
50
51   sig = sig_catch(SIGALRM, catch_alrm);
52   if (libspamc_timeout > 0) {
53     alarm(libspamc_timeout);
54   }
55
56   do {
57     nred = read (fd, buf, nbytes);
58   } while(nred < 0 && errno == EAGAIN);
59
60   if(nred < 0 && errno == EINTR)
61     errno = ETIMEDOUT;
62
63   if (libspamc_timeout > 0) {
64     alarm(0);
65   }
66
67   /* restore old signal handler */
68   sig_catch(SIGALRM, sig);
69
70   return nred;
71 }
72
73 int
74 ssl_timeout_read (SSL *ssl, void *buf, int nbytes)
75 {
76   int nred;
77   sigfunc* sig;
78
79 #ifndef SPAMC_SSL
80   UNUSED_VARIABLE(ssl);
81   UNUSED_VARIABLE(buf);
82   UNUSED_VARIABLE(nbytes);
83 #endif
84
85   sig = sig_catch(SIGALRM, catch_alrm);
86   if (libspamc_timeout > 0) {
87     alarm(libspamc_timeout);
88   }
89
90   do {
91 #ifdef SPAMC_SSL
92     nred = SSL_read (ssl, buf, nbytes);
93 #else
94     nred = 0;                   /* never used */
95 #endif
96   } while(nred < 0 && errno == EAGAIN);
97
98   if(nred < 0 && errno == EINTR)
99     errno = ETIMEDOUT;
100
101   if (libspamc_timeout > 0) {
102     alarm(0);
103   }
104
105   /* restore old signal handler */
106   sig_catch(SIGALRM, sig);
107
108   return nred;
109 }
110
111 /* -------------------------------------------------------------------------- */
112
113 int
114 full_read (int fd, void *vbuf, int min, int len)
115 {
116   unsigned char *buf = (unsigned char *)vbuf;
117   int total;
118   int thistime;
119
120   for (total = 0; total < min; ) {
121     thistime = fd_timeout_read (fd, buf+total, len-total);
122
123     if (thistime < 0) {
124       return -1;
125     } else if (thistime == 0) {
126       /* EOF, but we didn't read the minimum.  return what we've read
127        * so far and next read (if there is one) will return 0. */
128       return total;
129     }
130
131     total += thistime;
132   }
133   return total;
134 }
135
136 int
137 full_read_ssl (SSL *ssl, unsigned char *buf, int min, int len)
138 {
139   int total;
140   int thistime;
141
142   for (total = 0; total < min; ) {
143     thistime = ssl_timeout_read (ssl, buf+total, len-total);
144
145     if (thistime < 0) {
146       return -1;
147     } else if (thistime == 0) {
148       /* EOF, but we didn't read the minimum.  return what we've read
149        * so far and next read (if there is one) will return 0. */
150       return total;
151     }
152
153     total += thistime;
154   }
155   return total;
156 }
157
158 int
159 full_write (int fd, const void *vbuf, int len)
160 {
161   const unsigned char *buf = (const unsigned char *)vbuf;
162   int total;
163   int thistime;
164
165   for (total = 0; total < len; ) {
166     thistime = write (fd, buf+total, len-total);
167
168     if (thistime < 0) {
169       if(EINTR == errno || EAGAIN == errno) continue;
170       return thistime;        /* always an error for writes */
171     }
172     total += thistime;
173   }
174   return total;
175 }