Commit 8be6084f 8be6084f1304aa64062065454dd2d138ebc6a9ca by Alain Magloire

Pff !!! And everything with one hand. Now I understand why people

use threads and things like aio_*() calls.  Pop in Nonblocking
mode should work properly, but the price to pay is big hairy code
Because we have to keep the state of the connection when return
EAGAIN.  There is lot of buffer copy all over the place .i.e when
we come back from a EAGAIN, we have to reset the same state.

We have two new files call bio.[ch] it stands for buffered I/O
Saves me from a lot of read()/write() calls by bufferring a bit
for me.

Attribute added 3 new functions, attribute_{set,get,unset,is}userflag()
to let someone else the library store certain attributes on a message.
They are keep in a different place the  the normal attributes.
1 parent 1152383e
...@@ -53,6 +53,8 @@ attribute_destroy (attribute_t *pattr, void *owner) ...@@ -53,6 +53,8 @@ attribute_destroy (attribute_t *pattr, void *owner)
53 int 53 int
54 attribute_get_flags (attribute_t attr, int *pflags) 54 attribute_get_flags (attribute_t attr, int *pflags)
55 { 55 {
56 if (attr == NULL)
57 return EINVAL;
56 if (attr->_get_flags) 58 if (attr->_get_flags)
57 return attr->_get_flags (attr, pflags); 59 return attr->_get_flags (attr, pflags);
58 if (pflags) 60 if (pflags)
...@@ -63,6 +65,8 @@ attribute_get_flags (attribute_t attr, int *pflags) ...@@ -63,6 +65,8 @@ attribute_get_flags (attribute_t attr, int *pflags)
63 int 65 int
64 attribute_set_flags (attribute_t attr, int flags) 66 attribute_set_flags (attribute_t attr, int flags)
65 { 67 {
68 if (attr == NULL)
69 return EINVAL;
66 if (attr->_set_flags) 70 if (attr->_set_flags)
67 return attr->_set_flags (attr, flags); 71 return attr->_set_flags (attr, flags);
68 attr->flags |= flags; 72 attr->flags |= flags;
...@@ -105,6 +109,17 @@ attribute_set_unset_flags (attribute_t attr, int (*_unset_flags) ...@@ -105,6 +109,17 @@ attribute_set_unset_flags (attribute_t attr, int (*_unset_flags)
105 return 0; 109 return 0;
106 } 110 }
107 111
112 /* We add support for "USER" flag, it is a way for external objects
113 Not being the owner to add custom flags. */
114 int
115 attribute_set_userflag (attribute_t attr, int flag)
116 {
117 if (attr == NULL)
118 return EINVAL;
119 attr->user_flags |= flag;
120 return 0;
121 }
122
108 int 123 int
109 attribute_set_seen (attribute_t attr) 124 attribute_set_seen (attribute_t attr)
110 { 125 {
...@@ -197,6 +212,14 @@ attribute_set_recent (attribute_t attr) ...@@ -197,6 +212,14 @@ attribute_set_recent (attribute_t attr)
197 } 212 }
198 213
199 int 214 int
215 attribute_is_userflag (attribute_t attr, int flag)
216 {
217 if (attr == NULL)
218 return 0;
219 return attr->user_flags & flag;
220 }
221
222 int
200 attribute_is_seen (attribute_t attr) 223 attribute_is_seen (attribute_t attr)
201 { 224 {
202 int status = 0; 225 int status = 0;
...@@ -277,6 +300,15 @@ attribute_is_recent (attribute_t attr) ...@@ -277,6 +300,15 @@ attribute_is_recent (attribute_t attr)
277 } 300 }
278 301
279 int 302 int
303 attribute_unset_userflag (attribute_t attr, int flag)
304 {
305 if (attr == NULL)
306 return 0;
307 attr->user_flags &= ~flag;
308 return 0;
309 }
310
311 int
280 attribute_unset_seen (attribute_t attr) 312 attribute_unset_seen (attribute_t attr)
281 { 313 {
282 int status = 0; 314 int status = 0;
...@@ -371,6 +403,7 @@ attribute_is_equal (attribute_t attr, attribute_t attr2) ...@@ -371,6 +403,7 @@ attribute_is_equal (attribute_t attr, attribute_t attr2)
371 return attr->flags == attr2->flags; 403 return attr->flags == attr2->flags;
372 } 404 }
373 405
406 /* Miscellaneous. */
374 int 407 int
375 attribute_copy (attribute_t dest, attribute_t src) 408 attribute_copy (attribute_t dest, attribute_t src)
376 { 409 {
......
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <sys/types.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdio.h>
23
24 #include "bio.h"
25
26 /* This is so annoying, we can not use the standard I/O(stdio) because a
27 socket may write/read less then requested and with the stdio functions
28 there is no way to know how much data was written/read, meaning also things
29 can get tricky in NONBLOCKING. */
30
31 struct _bio
32 {
33 char *read_buffer; /* Read Buffer. */
34 char *read_ptr;
35 size_t read_buflen;
36
37 char *write_buffer; /* Write Buffer. */
38 char *write_ptr;
39 size_t write_buflen;
40
41 stream_t stream;
42 };
43
44 int
45 bio_create (bio_t *pbio, stream_t stream)
46 {
47 bio_t bio;
48 /* 512 is the minimum for POP answer buffer. */
49 #define MIOBUF 512
50
51 if (pbio == NULL)
52 return EINVAL;
53
54 bio = calloc (1, sizeof (*bio));
55 if (bio == NULL)
56 return ENOMEM;
57
58 /* + 1 for the sentinel. */
59 bio->read_buffer = calloc (MIOBUF + 1, sizeof (char));
60 if (bio->read_buffer == NULL)
61 {
62 bio_destroy (&bio);
63 return ENOMEM;
64 }
65 bio->read_ptr = bio->read_buffer;
66 bio->read_buflen = MIOBUF;
67
68 /* + 1 for the sentinel. */
69 bio->write_buffer = calloc (MIOBUF/2 + 1, sizeof (char));
70 if (bio->write_buffer == NULL)
71 {
72 bio_destroy (&bio);
73 return ENOMEM;
74 }
75 bio->write_ptr = bio->write_buffer;
76 bio->write_buflen = MIOBUF;
77
78 bio->stream = stream;
79 *pbio = bio;
80 return 0;
81 }
82
83 void
84 bio_destroy (bio_t *pbio)
85 {
86 if (pbio && *pbio)
87 {
88 free ((*pbio)->read_buffer);
89 free ((*pbio)->write_buffer);
90 /* We don't close the file descriptor ? */
91 /* stream_close (stream); */
92 free ((*pbio));
93 *pbio = NULL;
94 }
95 }
96
97 /* buffered read */
98 int
99 bio_read (bio_t bio, char *ptr, size_t n, size_t *pnread)
100 {
101 int nleft;
102 size_t nread = 0;
103 size_t len = 0;
104
105 /* sanity check */
106 if (bio == NULL || pnread == NULL)
107 return EINVAL;
108
109 /* noop */
110 if (n == 0 || ptr == NULL)
111 {
112 *pnread = 0;
113 return 0;
114 }
115
116 /* fill up the global buffer */
117 if (bio->read_ptr == bio->read_buffer)
118 {
119 int err = stream_read (bio->stream, bio->read_buffer,
120 bio->read_buflen, 0, &len);
121 if (err != 0)
122 return err;
123 /* If len == read_buflen, read_ptr points to the sentinel. */
124 bio->read_ptr = bio->read_buffer + len;
125 }
126 else
127 len = bio->read_ptr - bio->read_buffer;
128
129 /* How much can wd copy out ? */
130 nleft = n - len;
131
132 /* We got more then requested. */
133 if (nleft < 0)
134 {
135 size_t sentinel;
136 nread = n;
137 /* where to move the sentinel to mark the end. */
138 sentinel = bio->read_ptr - (bio->read_buffer + nread);
139 memcpy (ptr, bio->read_buffer, nread);
140 memmove (bio->read_buffer, bio->read_buffer + nread, sentinel);
141 bio->read_ptr = bio->read_buffer + sentinel ;
142 }
143 else
144 {
145 /* Drain our buffer. */;
146 nread = len;
147 memcpy (ptr, bio->read_buffer, nread);
148 bio->read_ptr = bio->read_buffer;
149 }
150 if (pnread)
151 *pnread = nread;
152 return 0;
153 }
154
155 int
156 bio_write (bio_t bio, const char *ptr, size_t n, size_t *pnwriten)
157 {
158 int nleft;
159 int err;
160 size_t nwriten = 0;
161 size_t total = 0;
162
163 nleft = n;
164
165 /* First try to send it all. */
166 while (nleft > 0)
167 {
168 err = stream_write (bio->stream, ptr, nleft, 0, &nwriten);
169 if (err != 0)
170 break;
171 nleft -= nwriten;
172 total += nwriten;
173 ptr += nwriten;
174 }
175
176 /* Not recoverable. */
177 if (err != EAGAIN && err != EINTR)
178 bio->write_ptr = bio->write_buffer;
179
180 if (pnwriten)
181 *pnwriten = total;
182
183 return err;
184 }
185
186 /* Return the number of char read excluding the null char */
187 int
188 bio_readline (bio_t bio, char *ptr, size_t maxlen, size_t *pwriten)
189 {
190 int rc = 0;
191 size_t n = 0;
192 int err;
193 char c;
194
195 /* Noop. */
196 if (ptr == NULL || maxlen == 0)
197 {
198 if (pwriten)
199 *pwriten = 0;
200 return 0;
201 }
202
203 maxlen--;
204
205 while ((err = bio_read (bio, &c, 1, &rc)) == 0 && rc == 1)
206 {
207 *ptr++ = c;
208 n++;
209 if (c == '\n')
210 break; /* newline is stored, like fgets () */
211 if (n == maxlen)
212 break;
213 }
214 /* This is tricky, We may have data in the buffer, so we flush it
215 first and return success. On the next read if the error persist
216 it will be returned. This can happen for NONBLOCKING. */
217 if (n > 0)
218 err = 0;
219
220 *ptr = '\0';
221 if (pwriten)
222 *pwriten = n;
223 //fprintf (stderr, "\n%d %d BIO %s\n", n, *(ptr -n), (ptr -n ));
224 return err;
225 }
...@@ -461,7 +461,7 @@ fill_blurb (header_t header) ...@@ -461,7 +461,7 @@ fill_blurb (header_t header)
461 &nread); 461 &nread);
462 if (status != 0) 462 if (status != 0)
463 { 463 {
464 if (status != EAGAIN || status != EINTR) 464 if (status != EAGAIN && status != EINTR)
465 { 465 {
466 free (header->temp_blurb); 466 free (header->temp_blurb);
467 header->temp_blurb = NULL; 467 header->temp_blurb = NULL;
...@@ -481,7 +481,7 @@ fill_blurb (header_t header) ...@@ -481,7 +481,7 @@ fill_blurb (header_t header)
481 memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread); 481 memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread);
482 header->temp_blurb_len += nread; 482 header->temp_blurb_len += nread;
483 } 483 }
484 while (nread != 0); 484 while (nread > 0);
485 485
486 /* parse it. */ 486 /* parse it. */
487 status = header_parse (header, header->temp_blurb, header->temp_blurb_len); 487 status = header_parse (header, header->temp_blurb, header->temp_blurb_len);
......
...@@ -37,6 +37,8 @@ struct _attribute ...@@ -37,6 +37,8 @@ struct _attribute
37 void *owner; 37 void *owner;
38 38
39 int flags; 39 int flags;
40 int user_flags;
41
40 int (*_get_flags) __P ((attribute_t, int *)); 42 int (*_get_flags) __P ((attribute_t, int *));
41 int (*_set_flags) __P ((attribute_t, int)); 43 int (*_set_flags) __P ((attribute_t, int));
42 int (*_unset_flags) __P ((attribute_t, int)); 44 int (*_unset_flags) __P ((attribute_t, int));
......
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #ifndef _BIO_H
19 # define _BIO_H
20
21 #include <sys/types.h>
22 #include <mailutils/stream.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 #ifndef __P
29 # ifdef __STDC__
30 # define __P(args) args
31 # else
32 # define __P(args) ()
33 # endif
34 #endif /*__P */
35
36 typedef struct _bio * bio_t;
37
38 /* bufferred I/O */
39 extern ssize_t bio_create __P ((bio_t *pbio, stream_t));
40 extern void bio_destroy __P ((bio_t *pbio));
41 extern ssize_t bio_read __P ((bio_t bio, char *vptr,
42 size_t maxlen, size_t *pnread));
43 extern ssize_t bio_readline __P ((bio_t bio, char *vptr,
44 size_t maxlen, size_t *pnread));
45 extern ssize_t bio_write __P ((bio_t bio, const char *vptr,
46 size_t maxlen, size_t *pnwrite));
47
48 #ifdef __cplusplus
49 }
50 #endif
51
52 #endif /* _BIO_H */
...@@ -418,7 +418,7 @@ message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -418,7 +418,7 @@ message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
418 if (msg == NULL || buffer == NULL || buflen == 0) 418 if (msg == NULL || buffer == NULL || buflen == 0)
419 return EINVAL; 419 return EINVAL;
420 420
421 buffer[0] = '0'; 421 buffer[0] = '\0';
422 if (msg->_get_uidl) 422 if (msg->_get_uidl)
423 return msg->_get_uidl (msg, buffer, buflen, pwriten); 423 return msg->_get_uidl (msg, buffer, buflen, pwriten);
424 424
...@@ -430,18 +430,21 @@ message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -430,18 +430,21 @@ message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
430 || (status = header_get_value (header, "Message-ID", buffer, 430 || (status = header_get_value (header, "Message-ID", buffer,
431 buflen, &n)) == 0) 431 buflen, &n)) == 0)
432 { 432 {
433 /* We need to collapse the header if it was mutiline. */
434 /* FIXME: Is header_get_value suppose to do this ? */ 433 /* FIXME: Is header_get_value suppose to do this ? */
434 /* We need to collapse the header if it was mutiline. e points to the
435 last char meaning in a C string that's '\0', s to the start. We also
436 remove the spesky '<' '>' if they are around. */
435 char *s, *e; 437 char *s, *e;
436 for (s = buffer, e = buffer + n; s <= e; s++) 438 for (s = buffer, e = buffer + n; s <= e; s++)
437 { 439 {
438 if (isspace (*s)) 440 if (isspace (*s) || *s == '<' || *s == '>')
439 memmove (s, s + 1, e - s); 441 {
442 memmove (s, s + 1, e - (s + 1));
443 e -= 1;
444 *e = '\0';
445 }
440 } 446 }
441 return 0;
442 } 447 }
443 if (pwriten)
444 *pwriten = n;
445 return status; 448 return status;
446 } 449 }
447 450
......