62d9c688dd301c1ce0656e51b21ba9c1fc807dd6
[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
26 typedef void    sigfunc(int);   /* for signal handlers */
27
28 sigfunc* sig_catch(int sig, void (*f)(int))
29 {
30   struct sigaction act, oact;
31   act.sa_handler = f;
32   act.sa_flags = 0;
33   sigemptyset(&act.sa_mask);
34   sigaction(sig, &act, &oact);
35   return oact.sa_handler;
36 }
37
38 static void catch_alrm(int x) {
39   /* dummy */
40 }
41
42 ssize_t timeout_read(ssize_t (*reader)(int d, void *buf, size_t nbytes),
43                      int fd, void *buf, size_t nbytes) {
44   ssize_t nred;
45   sigfunc* sig;
46
47   sig = sig_catch(SIGALRM, catch_alrm);
48   if (libspamc_timeout > 0) {
49     alarm(libspamc_timeout);
50   }
51
52   do {
53     nred = reader(fd, buf, nbytes);
54   } while(nred < 0 && errno == EAGAIN);
55
56   if(nred < 0 && errno == EINTR)
57     errno = ETIMEDOUT;
58
59   if (libspamc_timeout > 0) {
60     alarm(0);
61   }
62
63   /* restore old signal handler */
64   sig_catch(SIGALRM, sig);
65
66   return nred;
67 }
68
69 int
70 full_read (int fd, unsigned char *buf, int min, int len)
71 {
72   int total;
73   int thistime;
74
75
76   for (total = 0; total < min; ) {
77     thistime = timeout_read (read, fd, buf+total, len-total);
78
79     if (thistime < 0) {
80       return -1;
81     } else if (thistime == 0) {
82       /* EOF, but we didn't read the minimum.  return what we've read
83        * so far and next read (if there is one) will return 0. */
84       return total;
85     }
86
87     total += thistime;
88   }
89   return total;
90 }
91
92 int
93 full_write (int fd, const unsigned char *buf, int len)
94 {
95   int total;
96   int thistime;
97
98   for (total = 0; total < len; ) {
99     thistime = write (fd, buf+total, len-total);
100
101     if (thistime < 0) {
102       if(EINTR == errno || EAGAIN == errno) continue;
103       return thistime;        /* always an error for writes */
104     }
105     total += thistime;
106   }
107   return total;
108 }