2005-12-06 [paul] 1.9.100cvs69
[claws.git] / src / plugins / spamassassin / utils.c
1 /* <@LICENSE>
2  * Copyright 2004 Apache Software Foundation
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  * </@LICENSE>
16  */
17
18 #ifndef _WIN32
19 #include <unistd.h>
20 #include <sys/uio.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #else
24
25 #ifdef _MSC_VER
26 /* ignore MSVC++ warnings that are annoying and hard to remove:
27  4115 named type definition in parentheses
28  4127 conditional expression is constant
29  4514 unreferenced inline function removed
30  */
31 #pragma warning( disable : 4115 4127 4514 )
32 #endif
33
34 #include <io.h>
35 #endif
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include "utils.h"
40
41 /* Dec 13 2001 jm: added safe full-read and full-write functions.  These
42  * can cope with networks etc., where a write or read may not read all
43  * the data that's there, in one call.
44  */
45 /* Aug 14, 2002 bj: EINTR and EAGAIN aren't fatal, are they? */
46 /* Aug 14, 2002 bj: moved these to utils.c */
47 /* Jan 13, 2003 ym: added timeout functionality */
48 /* Apr 24, 2003 sjf: made full_read and full_write void* params */
49
50 /* -------------------------------------------------------------------------- */
51 #ifndef _WIN32
52 typedef void sigfunc(int);      /* for signal handlers */
53
54 sigfunc *sig_catch(int sig, void (*f) (int))
55 {
56     struct sigaction act, oact;
57     act.sa_handler = f;
58     act.sa_flags = 0;
59     sigemptyset(&act.sa_mask);
60     sigaction(sig, &act, &oact);
61     return oact.sa_handler;
62 }
63
64 static void catch_alrm(int x)
65 {
66     UNUSED_VARIABLE(x);
67 }
68 #endif
69
70 int fd_timeout_read(int fd, char fdflag, void *buf, size_t nbytes)
71 {
72     int nred;
73     int origerr;
74 #ifndef _WIN32
75     sigfunc *sig;
76
77     sig = sig_catch(SIGALRM, catch_alrm);
78     if (libspamc_timeout > 0) {
79         alarm(libspamc_timeout);
80     }
81 #endif
82
83     do {
84         if (fdflag) {
85             nred = (int)read(fd, buf, nbytes);
86             origerr = errno;
87         }
88         else {
89             nred = (int)recv(fd, buf, nbytes, 0);
90 #ifndef _WIN32
91             origerr = errno;
92 #else
93             origerr = WSAGetLastError();
94 #endif
95         }
96     } while (nred < 0 && origerr == EWOULDBLOCK);
97
98 #ifndef _WIN32
99     if (nred < 0 && origerr == EINTR)
100         errno = ETIMEDOUT;
101
102     if (libspamc_timeout > 0) {
103         alarm(0);
104     }
105
106     /* restore old signal handler */
107     sig_catch(SIGALRM, sig);
108 #endif
109
110     return nred;
111 }
112
113 int ssl_timeout_read(SSL * ssl, void *buf, int nbytes)
114 {
115     int nred;
116
117 #ifndef _WIN32
118     sigfunc *sig;
119
120     sig = sig_catch(SIGALRM, catch_alrm);
121     if (libspamc_timeout > 0) {
122         alarm(libspamc_timeout);
123     }
124 #endif
125
126     do {
127
128 #ifdef SPAMC_SSL
129         nred = SSL_read(ssl, buf, nbytes);
130 #else
131         UNUSED_VARIABLE(ssl);
132         UNUSED_VARIABLE(buf);
133         UNUSED_VARIABLE(nbytes);
134         nred = 0;               /* never used */
135 #endif
136
137     } while (nred < 0 && errno == EWOULDBLOCK);
138
139 #ifndef _WIN32
140     if (nred < 0 && errno == EINTR)
141         errno = ETIMEDOUT;
142
143     if (libspamc_timeout > 0) {
144         alarm(0);
145     }
146
147     /* restore old signal handler */
148     sig_catch(SIGALRM, sig);
149 #endif
150
151     return nred;
152 }
153
154 /* -------------------------------------------------------------------------- */
155
156 int full_read(int fd, char fdflag, void *vbuf, int min, int len)
157 {
158     unsigned char *buf = (unsigned char *) vbuf;
159     int total;
160     int thistime;
161
162     for (total = 0; total < min;) {
163         thistime = fd_timeout_read(fd, fdflag, buf + total, len - total);
164
165         if (thistime < 0) {
166             if (total >= min) {
167                 /* error, but we read *some*.  return what we've read
168                  * so far and next read (if there is one) will return -1. */
169                 return total;
170             } else {
171                 return -1;
172             }
173         }
174         else if (thistime == 0) {
175             /* EOF, but we didn't read the minimum.  return what we've read
176              * so far and next read (if there is one) will return 0. */
177             return total;
178         }
179
180         total += thistime;
181     }
182     return total;
183 }
184
185 int full_read_ssl(SSL * ssl, unsigned char *buf, int min, int len)
186 {
187     int total;
188     int thistime;
189
190     for (total = 0; total < min;) {
191         thistime = ssl_timeout_read(ssl, buf + total, len - total);
192
193         if (thistime < 0) {
194             if (total >= min) {
195                 /* error, but we read *some*.  return what we've read
196                  * so far and next read (if there is one) will return -1. */
197                 return total;
198             } else {
199                 return -1;
200             }
201         }
202         else if (thistime == 0) {
203             /* EOF, but we didn't read the minimum.  return what we've read
204              * so far and next read (if there is one) will return 0. */
205             return total;
206         }
207
208         total += thistime;
209     }
210     return total;
211 }
212
213 int full_write(int fd, char fdflag, const void *vbuf, int len)
214 {
215     const char *buf = (const char *) vbuf;
216     int total;
217     int thistime;
218     int origerr;
219
220     for (total = 0; total < len;) {
221         if (fdflag) {
222             thistime = write(fd, buf + total, len - total);
223             origerr = errno;
224         }
225         else {
226             thistime = send(fd, buf + total, len - total, 0);
227 #ifndef _WIN32
228             origerr = errno;
229 #else
230             origerr = WSAGetLastError();
231 #endif
232         }
233         if (thistime < 0) {
234             if (EINTR == origerr || EWOULDBLOCK == origerr)
235                 continue;
236             return thistime;    /* always an error for writes */
237         }
238         total += thistime;
239     }
240     return total;
241 }