Another big change we're trying, for the future to be able to load
via dlopen() different type of mailboxes and mailer. For that the client must register the mailbox. So in the future we can have something like plugin ... still a hack/draft. Commited some code to be able to send mail with sendmail or via SMTP.
Showing
55 changed files
with
6076 additions
and
2194 deletions
... | @@ -145,41 +145,61 @@ int message_save_attachment(message_t msg, const char *filename, void **data) | ... | @@ -145,41 +145,61 @@ int message_save_attachment(message_t msg, const char *filename, void **data) |
145 | if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &stream, data) ) != 0 ) | 145 | if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &stream, data) ) != 0 ) |
146 | return ret; | 146 | return ret; |
147 | 147 | ||
148 | |||
148 | if ( ret != EAGAIN && info ) | 149 | if ( ret != EAGAIN && info ) |
149 | _attachment_free(info, ret); | 150 | _attachment_free(info, ret); |
150 | return ret; | 151 | return ret; |
151 | } | 152 | } |
152 | 153 | ||
153 | #if 0 | ||
154 | int message_encapsulate(message_t msg, message_t *newmsg, void **data) | 154 | int message_encapsulate(message_t msg, message_t *newmsg, void **data) |
155 | { | 155 | { |
156 | stream_t stream; | 156 | stream_t istream, ostream; |
157 | char *header; | 157 | const char *header; |
158 | struct _msg_info *info = NULL; | 158 | struct _msg_info *info = NULL; |
159 | int ret; | 159 | int ret = 0; |
160 | size_t nbytes; | ||
161 | body_t body; | ||
160 | 162 | ||
161 | if ( msg == NULL || newmsg == NULL) | 163 | if ( msg == NULL || newmsg == NULL) |
162 | return EINVAL; | 164 | return EINVAL; |
163 | 165 | ||
164 | if ( ( ret = message_create(&(info->msg), NULL) ) == 0 ) { | 166 | if ( ( ret = _attachment_setup( &info, msg, &ostream, data) ) != 0 ) |
167 | return ret; | ||
168 | |||
169 | if ( info->msg == NULL && ( ret = message_create(&(info->msg), NULL) ) == 0 ) { | ||
165 | header = "Content-Type: message/rfc822\nContent-Transfer-Encoding: 7bit\n\n"; | 170 | header = "Content-Type: message/rfc822\nContent-Transfer-Encoding: 7bit\n\n"; |
166 | if ( ( ret = header_create( &(info->hdr), header, strlen(header), msg ) ) == 0 ) { | 171 | if ( ( ret = header_create( &(info->hdr), header, strlen(header), msg ) ) == 0 ) |
167 | message_set_header(info->msg, info->hdr, NULL); | 172 | ret = message_set_header(info->msg, info->hdr, NULL); |
173 | } | ||
174 | if ( ret == 0 && ( ret = message_get_stream(msg, &istream ) ) == 0 ) { | ||
175 | if ( ( ret = message_get_body(info->msg, &body) ) == 0 && | ||
176 | ( ret = body_get_stream(body, &ostream) ) == 0 ) { | ||
177 | if ( info->nbytes ) | ||
178 | memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes); | ||
179 | while ( (ret == 0 && info->nbytes) || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) { | ||
180 | info->ioffset += info->nbytes; | ||
181 | while( info->nbytes ) { | ||
182 | if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 ) | ||
183 | break; | ||
184 | info->nbytes -= nbytes; | ||
185 | info->ooffset += nbytes; | ||
186 | } | ||
187 | } | ||
168 | } | 188 | } |
169 | } | 189 | } |
190 | if ( ret == 0 ) | ||
191 | *newmsg = info->msg; | ||
192 | if ( ret != EAGAIN && info ) | ||
193 | _attachment_free(info, ret); | ||
170 | return ret; | 194 | return ret; |
171 | } | 195 | } |
172 | #endif | ||
173 | |||
174 | /* If the message interface parsed headers on write this would be easy */ | ||
175 | 196 | ||
176 | int message_unencapsulate(message_t msg, message_t *newmsg, void **data) | 197 | int message_unencapsulate(message_t msg, message_t *newmsg, void **data) |
177 | { | 198 | { |
178 | size_t size, nbytes; | 199 | size_t size, nbytes; |
179 | int ret = 0, header_done = 0; | 200 | int ret = 0; |
180 | char *content_type, *cp; | 201 | char *content_type; |
181 | header_t hdr; | 202 | header_t hdr; |
182 | body_t body; | ||
183 | stream_t istream, ostream; | 203 | stream_t istream, ostream; |
184 | struct _msg_info *info = NULL; | 204 | struct _msg_info *info = NULL; |
185 | 205 | ||
... | @@ -190,60 +210,22 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) | ... | @@ -190,60 +210,22 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) |
190 | header_get_value(hdr, "Content-Type", NULL, 0, &size); | 210 | header_get_value(hdr, "Content-Type", NULL, 0, &size); |
191 | if ( size ) { | 211 | if ( size ) { |
192 | if ( ( content_type = alloca(size+1) ) == NULL ) | 212 | if ( ( content_type = alloca(size+1) ) == NULL ) |
193 | ret = ENOMEM; | 213 | return ENOMEM; |
194 | header_get_value(hdr, "Content-Type", content_type, size+1, 0); | 214 | header_get_value(hdr, "Content-Type", content_type, size+1, 0); |
195 | if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 ) | 215 | if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 ) |
196 | ret = EINVAL; | 216 | return EINVAL; |
197 | } else | 217 | } else |
198 | return EINVAL; | 218 | return EINVAL; |
199 | } | 219 | } |
200 | if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 ) | 220 | if ( ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 ) |
201 | return ret; | 221 | return ret; |
202 | 222 | if ( info->msg == NULL ) | |
203 | if ( ret == 0 && info->hdr == NULL ) { | 223 | ret = message_create(&(info->msg), NULL); |
204 | while ( !header_done && ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) { | ||
205 | cp = info->buf; | ||
206 | while ( info->nbytes && !header_done ) { | ||
207 | info->line[info->line_ndx] = *cp; | ||
208 | info->line_ndx++; | ||
209 | if ( *cp == '\n' ) { | ||
210 | if ( info->header_len + info->line_ndx > info->header_size) { | ||
211 | char *nhb; | ||
212 | if ( ( nhb = realloc( info->header_buf, info->header_len + info->line_ndx + 128 ) ) == NULL ) { | ||
213 | header_done = 1; | ||
214 | ret = ENOMEM; | ||
215 | break; | ||
216 | } | ||
217 | info->header_buf = nhb; | ||
218 | info->header_size = info->header_len + info->line_ndx + 128; | ||
219 | } | ||
220 | info->header_len += info->line_ndx; | ||
221 | memcpy(info->header_buf, info->line, info->line_ndx); | ||
222 | if ( info->line_ndx == 1 ) { | ||
223 | header_done = 1; | ||
224 | break; | ||
225 | } | ||
226 | info->line_ndx = 0; | ||
227 | } | ||
228 | if ( info->line_ndx == MAX_HDR_LEN ) /* prevent overflow */ | ||
229 | info->line_ndx--; | ||
230 | info->ioffset++; | ||
231 | info->nbytes--; | ||
232 | cp++; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | if ( ret == 0 && info->msg == NULL ) { | ||
237 | if ( ( ret = message_create(&(info->msg), NULL) ) == 0) | ||
238 | if ( ( ret = header_create(&(info->hdr), info->header_buf, info->header_len, info->msg) ) == 0 ) | ||
239 | ret = message_set_header(info->msg, hdr, NULL); | ||
240 | } | ||
241 | if ( ret == 0 ) { | 224 | if ( ret == 0 ) { |
242 | message_get_body(info->msg, &body); | 225 | message_get_stream(info->msg, &ostream); |
243 | body_get_stream( body, &ostream); | ||
244 | if ( info->nbytes ) | 226 | if ( info->nbytes ) |
245 | memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes); | 227 | memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes); |
246 | while ( info->nbytes || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) { | 228 | while ( (ret == 0 && info->nbytes) || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) { |
247 | info->ioffset += info->nbytes; | 229 | info->ioffset += info->nbytes; |
248 | while( info->nbytes ) { | 230 | while( info->nbytes ) { |
249 | if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 ) | 231 | if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 ) |
... | @@ -253,6 +235,8 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) | ... | @@ -253,6 +235,8 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data) |
253 | } | 235 | } |
254 | } | 236 | } |
255 | } | 237 | } |
238 | if ( ret == 0 ) | ||
239 | *newmsg = info->msg; | ||
256 | if ( ret != EAGAIN && info ) | 240 | if ( ret != EAGAIN && info ) |
257 | _attachment_free(info, ret); | 241 | _attachment_free(info, ret); |
258 | return ret; | 242 | return ret; | ... | ... |
... | @@ -14,6 +14,9 @@ | ... | @@ -14,6 +14,9 @@ |
14 | You should have received a copy of the GNU Library General Public License | 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 | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
17 | 20 | ||
18 | #include <sys/types.h> | 21 | #include <sys/types.h> |
19 | #include <stdlib.h> | 22 | #include <stdlib.h> |
... | @@ -50,6 +53,12 @@ attribute_destroy (attribute_t *pattr, void *owner) | ... | @@ -50,6 +53,12 @@ attribute_destroy (attribute_t *pattr, void *owner) |
50 | return; | 53 | return; |
51 | } | 54 | } |
52 | 55 | ||
56 | void * | ||
57 | attribute_get_owner (attribute_t attr) | ||
58 | { | ||
59 | return (attr) ? attr->owner : NULL; | ||
60 | } | ||
61 | |||
53 | int | 62 | int |
54 | attribute_get_flags (attribute_t attr, int *pflags) | 63 | attribute_get_flags (attribute_t attr, int *pflags) |
55 | { | 64 | { | ... | ... |
... | @@ -14,96 +14,206 @@ | ... | @@ -14,96 +14,206 @@ |
14 | You should have received a copy of the GNU Library General Public License | 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 | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
17 | 20 | ||
18 | #include <errno.h> | 21 | #include <errno.h> |
19 | #include <sys/types.h> | 22 | #include <sys/types.h> |
20 | #include <string.h> | 23 | #include <string.h> |
21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <stdio.h> | ||
26 | #include <termios.h> | ||
22 | 27 | ||
28 | #include <mailutils/mailbox.h> | ||
23 | #include <auth0.h> | 29 | #include <auth0.h> |
24 | #include <cpystr.h> | 30 | #include <misc.h> |
31 | |||
32 | static void | ||
33 | echo_off(struct termios *stored_settings) | ||
34 | { | ||
35 | struct termios new_settings; | ||
36 | tcgetattr (0, stored_settings); | ||
37 | new_settings = *stored_settings; | ||
38 | new_settings.c_lflag &= (~ECHO); | ||
39 | tcsetattr (0, TCSANOW, &new_settings); | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | echo_on(struct termios *stored_settings) | ||
44 | { | ||
45 | tcsetattr (0, TCSANOW, stored_settings); | ||
46 | } | ||
25 | 47 | ||
26 | int | 48 | int |
27 | auth_create (auth_t *pauth, void *owner) | 49 | ticket_create (ticket_t *pticket, void *owner) |
28 | { | 50 | { |
29 | auth_t auth; | 51 | ticket_t ticket; |
30 | if (pauth == NULL) | 52 | if (pticket == NULL) |
31 | return EINVAL; | 53 | return EINVAL; |
32 | auth = calloc (1, sizeof (*auth)); | 54 | ticket = calloc (1, sizeof (*ticket)); |
33 | if (auth == NULL) | 55 | if (ticket == NULL) |
34 | return ENOMEM; | 56 | return ENOMEM; |
35 | auth->owner = owner; | 57 | ticket->owner = owner; |
36 | *pauth = auth; | 58 | *pticket = ticket; |
37 | return 0; | 59 | return 0; |
38 | } | 60 | } |
39 | 61 | ||
40 | void | 62 | void |
41 | auth_destroy (auth_t *pauth, void *owner) | 63 | ticket_destroy (ticket_t *pticket, void *owner) |
42 | { | 64 | { |
43 | if (pauth && *pauth) | 65 | if (pticket && *pticket) |
44 | { | 66 | { |
45 | auth_t auth = *pauth; | 67 | ticket_t ticket = *pticket; |
46 | if (auth->owner == owner) | 68 | if (ticket->owner == owner) |
47 | free (auth); | 69 | { |
48 | *pauth = NULL; | 70 | if (ticket->type) |
71 | free (ticket->type); | ||
72 | free (ticket); | ||
73 | } | ||
49 | } | 74 | } |
75 | *pticket = NULL; | ||
76 | } | ||
77 | |||
78 | void * | ||
79 | ticket_get_owner (ticket_t ticket) | ||
80 | { | ||
81 | return (ticket) ? ticket->owner : NULL; | ||
50 | } | 82 | } |
51 | 83 | ||
52 | int | 84 | int |
53 | auth_set_authenticate (auth_t auth, | 85 | ticket_pop (ticket_t ticket, const char *challenge, char **parg) |
54 | int (*_authenticate)(auth_t, char **, char **), | ||
55 | void *owner) | ||
56 | { | 86 | { |
57 | if (auth == NULL) | 87 | if (ticket == NULL || parg == NULL) |
58 | return EINVAL; | 88 | return EINVAL; |
59 | if (auth->owner != owner) | 89 | if (ticket->_pop) |
60 | return EPERM; | 90 | return ticket->_pop (ticket, challenge, parg); |
61 | auth->_authenticate = _authenticate; | 91 | else |
92 | { | ||
93 | char arg[256]; | ||
94 | struct termios stored_settings; | ||
95 | int echo = 1; | ||
96 | |||
97 | /* Being smart if we see "Passwd" and turning off echo. */ | ||
98 | if (strstr (challenge, "ass") != NULL | ||
99 | || strstr (challenge, "ASS") != NULL) | ||
100 | echo = 0; | ||
101 | printf ("%s", challenge); | ||
102 | fflush (stdout); | ||
103 | if (!echo) | ||
104 | echo_off (&stored_settings); | ||
105 | fgets (arg, sizeof (arg), stdin); | ||
106 | if (!echo) | ||
107 | echo_on (&stored_settings); | ||
108 | arg [strlen (arg) - 1] = '\0'; /* nuke the trailing line. */ | ||
109 | *parg = strdup (arg); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | int | ||
115 | ticket_get_type (ticket_t ticket, char *type, size_t len, size_t *pwriten) | ||
116 | { | ||
117 | size_t n; | ||
118 | if (ticket == NULL || type == NULL) | ||
119 | return EINVAL; | ||
120 | n = _cpystr (type, ticket->type, len); | ||
121 | if (pwriten) | ||
122 | *pwriten = n; | ||
62 | return 0; | 123 | return 0; |
63 | } | 124 | } |
64 | 125 | ||
65 | int | 126 | int |
66 | auth_authenticate (auth_t auth, char **user, char **passwd) | 127 | ticket_set_type (ticket_t ticket, char *type) |
67 | { | 128 | { |
68 | if (auth == NULL || auth->_authenticate == NULL) | 129 | if (ticket == NULL) |
69 | return EINVAL; | 130 | return EINVAL; |
70 | return auth->_authenticate (auth, user, passwd); | 131 | ticket->type = strdup ((type) ? type : ""); |
132 | return 0; | ||
71 | } | 133 | } |
72 | 134 | ||
73 | int | 135 | int |
74 | auth_set_epilogue (auth_t auth, int (*_epilogue)(auth_t), void *owner) | 136 | authority_create (authority_t *pauthority, ticket_t ticket, void *owner) |
75 | { | 137 | { |
76 | if (auth == NULL) | 138 | authority_t authority; |
139 | if (pauthority == NULL) | ||
77 | return EINVAL; | 140 | return EINVAL; |
78 | if (auth->owner != owner) | 141 | authority = calloc (1, sizeof (*authority)); |
79 | return EPERM; | 142 | if (authority == NULL) |
80 | auth->_epilogue = _epilogue; | 143 | return ENOMEM; |
144 | authority->ticket = ticket; | ||
145 | authority->owner = owner; | ||
146 | *pauthority = authority; | ||
81 | return 0; | 147 | return 0; |
82 | } | 148 | } |
83 | 149 | ||
150 | void | ||
151 | authority_destroy (authority_t *pauthority, void *owner) | ||
152 | { | ||
153 | if (pauthority && *pauthority) | ||
154 | { | ||
155 | authority_t authority = *pauthority; | ||
156 | if (authority->owner == owner) | ||
157 | { | ||
158 | ticket_destroy (&(authority->ticket), authority); | ||
159 | free (authority); | ||
160 | } | ||
161 | *pauthority = NULL; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void * | ||
166 | authority_get_owner (authority_t authority) | ||
167 | { | ||
168 | return (authority) ? authority->owner : NULL; | ||
169 | } | ||
170 | |||
84 | int | 171 | int |
85 | auth_epilogue (auth_t auth) | 172 | authority_set_ticket (authority_t authority, ticket_t ticket) |
86 | { | 173 | { |
87 | if (auth == NULL || auth->_epilogue == NULL) | 174 | if (authority == NULL) |
88 | return EINVAL; | 175 | return EINVAL; |
89 | return auth->_epilogue (auth); | 176 | ticket_destroy (&(authority->ticket), authority); |
177 | authority->ticket = ticket; | ||
178 | return 0; | ||
90 | } | 179 | } |
91 | 180 | ||
92 | int | 181 | int |
93 | auth_set_prologue (auth_t auth, int (*_prologue)(auth_t), void *owner) | 182 | authority_get_ticket (authority_t authority, ticket_t *pticket) |
94 | { | 183 | { |
95 | if (auth == NULL) | 184 | if (authority == NULL || pticket == NULL) |
96 | return EINVAL; | 185 | return EINVAL; |
97 | if (auth->owner != owner) | 186 | if (authority->ticket == NULL) |
98 | return EPERM; | 187 | { |
99 | auth->_prologue = _prologue; | 188 | int status = ticket_create (&(authority->ticket), authority); |
189 | if (status != 0) | ||
190 | return status; | ||
191 | } | ||
192 | *pticket = authority->ticket; | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | int | ||
198 | authority_authenticate (authority_t authority) | ||
199 | { | ||
200 | if (authority && authority->_authenticate) | ||
201 | { | ||
202 | return authority->_authenticate (authority); | ||
203 | } | ||
100 | return 0; | 204 | return 0; |
101 | } | 205 | } |
102 | 206 | ||
103 | int | 207 | int |
104 | auth_prologue (auth_t auth) | 208 | authority_set_authenticate (authority_t authority, |
209 | int (*_authenticate) __P ((authority_t)), | ||
210 | void *owner) | ||
105 | { | 211 | { |
106 | if (auth == NULL || auth->_prologue == NULL) | 212 | if (authority == NULL) |
107 | return EINVAL; | 213 | return EINVAL; |
108 | return auth->_prologue (auth); | 214 | |
215 | if (authority->owner != owner) | ||
216 | return EACCES; | ||
217 | authority->_authenticate = _authenticate; | ||
218 | return 0; | ||
109 | } | 219 | } | ... | ... |
... | @@ -14,6 +14,9 @@ | ... | @@ -14,6 +14,9 @@ |
14 | You should have received a copy of the GNU Library General Public License | 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 | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
17 | 20 | ||
18 | #include <sys/types.h> | 21 | #include <sys/types.h> |
19 | #include <stdlib.h> | 22 | #include <stdlib.h> |
... | @@ -187,7 +190,7 @@ bio_write (bio_t bio, const char *ptr, size_t n, size_t *pnwriten) | ... | @@ -187,7 +190,7 @@ bio_write (bio_t bio, const char *ptr, size_t n, size_t *pnwriten) |
187 | int | 190 | int |
188 | bio_readline (bio_t bio, char *ptr, size_t maxlen, size_t *pwriten) | 191 | bio_readline (bio_t bio, char *ptr, size_t maxlen, size_t *pwriten) |
189 | { | 192 | { |
190 | int rc = 0; | 193 | size_t rc = 0; |
191 | size_t n = 0; | 194 | size_t n = 0; |
192 | int err; | 195 | int err; |
193 | char c; | 196 | char c; | ... | ... |
... | @@ -14,6 +14,9 @@ | ... | @@ -14,6 +14,9 @@ |
14 | You should have received a copy of the GNU Library General Public License | 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 | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
17 | 20 | ||
18 | #include <errno.h> | 21 | #include <errno.h> |
19 | #include <stdio.h> | 22 | #include <stdio.h> |
... | @@ -21,8 +24,8 @@ | ... | @@ -21,8 +24,8 @@ |
21 | #include <sys/types.h> | 24 | #include <sys/types.h> |
22 | #include <sys/stat.h> | 25 | #include <sys/stat.h> |
23 | 26 | ||
27 | #include <mailutils/stream.h> | ||
24 | #include <body0.h> | 28 | #include <body0.h> |
25 | #include <stream0.h> | ||
26 | 29 | ||
27 | 30 | ||
28 | static int body_read (stream_t is, char *buf, size_t buflen, | 31 | static int body_read (stream_t is, char *buf, size_t buflen, |
... | @@ -66,6 +69,12 @@ body_destroy (body_t *pbody, void *owner) | ... | @@ -66,6 +69,12 @@ body_destroy (body_t *pbody, void *owner) |
66 | } | 69 | } |
67 | } | 70 | } |
68 | 71 | ||
72 | void * | ||
73 | body_get_owner (body_t body) | ||
74 | { | ||
75 | return (body) ? body->owner : NULL; | ||
76 | } | ||
77 | |||
69 | int | 78 | int |
70 | body_get_stream (body_t body, stream_t *pstream) | 79 | body_get_stream (body_t body, stream_t *pstream) |
71 | { | 80 | { |
... | @@ -182,10 +191,10 @@ static int | ... | @@ -182,10 +191,10 @@ static int |
182 | body_read (stream_t is, char *buf, size_t buflen, | 191 | body_read (stream_t is, char *buf, size_t buflen, |
183 | off_t off, size_t *pnread ) | 192 | off_t off, size_t *pnread ) |
184 | { | 193 | { |
185 | body_t body; | 194 | body_t body = stream_get_owner (is); |
186 | size_t nread = 0; | 195 | size_t nread = 0; |
187 | 196 | ||
188 | if (is == NULL || (body = is->owner) == NULL) | 197 | if (body == NULL) |
189 | return EINVAL; | 198 | return EINVAL; |
190 | 199 | ||
191 | /* check if they want to read from a file */ | 200 | /* check if they want to read from a file */ |
... | @@ -232,10 +241,10 @@ static int | ... | @@ -232,10 +241,10 @@ static int |
232 | body_write (stream_t os, const char *buf, size_t buflen, | 241 | body_write (stream_t os, const char *buf, size_t buflen, |
233 | off_t off, size_t *pnwrite) | 242 | off_t off, size_t *pnwrite) |
234 | { | 243 | { |
235 | body_t body; | 244 | body_t body = stream_get_owner (os); |
236 | size_t nwrite = 0; | 245 | size_t nwrite = 0; |
237 | 246 | ||
238 | if (os == NULL || (body = os->owner) == NULL) | 247 | if (body == NULL) |
239 | return EINVAL; | 248 | return EINVAL; |
240 | 249 | ||
241 | /* FIXME: security issues, Refuse to write to an unknow file */ | 250 | /* FIXME: security issues, Refuse to write to an unknow file */ |
... | @@ -275,9 +284,9 @@ body_write (stream_t os, const char *buf, size_t buflen, | ... | @@ -275,9 +284,9 @@ body_write (stream_t os, const char *buf, size_t buflen, |
275 | static int | 284 | static int |
276 | body_get_fd (stream_t stream, int *pfd) | 285 | body_get_fd (stream_t stream, int *pfd) |
277 | { | 286 | { |
278 | body_t body; | 287 | body_t body = stream_get_owner (stream); |
279 | 288 | ||
280 | if (stream == NULL || (body = stream->owner) == NULL) | 289 | if (body == NULL) |
281 | return EINVAL; | 290 | return EINVAL; |
282 | 291 | ||
283 | /* Probably being lazy, then create a body for the stream */ | 292 | /* Probably being lazy, then create a body for the stream */ | ... | ... |
mailbox/debug.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <string.h> | ||
26 | |||
27 | #include <debug0.h> | ||
28 | |||
29 | int | ||
30 | debug_create (debug_t *pdebug, void *owner) | ||
31 | { | ||
32 | debug_t debug; | ||
33 | if (pdebug == NULL) | ||
34 | return EINVAL; | ||
35 | debug = calloc (sizeof (*debug), 1); | ||
36 | if (debug == NULL) | ||
37 | return ENOMEM; | ||
38 | debug->owner = owner; | ||
39 | *pdebug = debug; | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | void | ||
44 | debug_destroy (debug_t *pdebug, void *owner) | ||
45 | { | ||
46 | if (pdebug && *pdebug) | ||
47 | { | ||
48 | debug_t debug = *pdebug; | ||
49 | if (debug->owner == owner) | ||
50 | { | ||
51 | free (*pdebug); | ||
52 | *pdebug = NULL; | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | |||
57 | void * | ||
58 | debug_get_owner (debug_t debug) | ||
59 | { | ||
60 | return (debug) ? debug->owner : NULL; | ||
61 | } | ||
62 | |||
63 | int | ||
64 | debug_set_level (debug_t debug, size_t level) | ||
65 | { | ||
66 | if (debug == NULL) | ||
67 | return EINVAL; | ||
68 | debug->level = level; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int | ||
73 | debug_get_level (debug_t debug, size_t *plevel) | ||
74 | { | ||
75 | if (debug == NULL) | ||
76 | return EINVAL; | ||
77 | if (plevel) | ||
78 | *plevel = debug->level; | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | debug_set_print (debug_t debug, int (*_print) | ||
84 | __P ((debug_t, const char *, va_list)), void *owner) | ||
85 | { | ||
86 | if (debug == NULL) | ||
87 | return EINVAL; | ||
88 | if (debug->owner != owner) | ||
89 | return EACCES; | ||
90 | debug->_print = _print; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* FIXME: We use a fix size, we should use vasprinf or something | ||
95 | similar to get rid of this arbitrary limitation. */ | ||
96 | int | ||
97 | debug_print (debug_t debug, size_t level, const char *format, ...) | ||
98 | { | ||
99 | va_list ap; | ||
100 | if (debug == NULL) | ||
101 | return EINVAL; | ||
102 | |||
103 | if (!(debug->level & level)) | ||
104 | return 0; | ||
105 | |||
106 | va_start (ap, format); | ||
107 | if (debug->_print) | ||
108 | debug->_print (debug, format, ap); | ||
109 | else | ||
110 | vfprintf (stderr, format, ap); | ||
111 | va_end (ap); | ||
112 | return 0; | ||
113 | } |
... | @@ -15,6 +15,9 @@ | ... | @@ -15,6 +15,9 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
18 | 21 | ||
19 | #include <errno.h> | 22 | #include <errno.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
... | @@ -26,7 +29,7 @@ | ... | @@ -26,7 +29,7 @@ |
26 | #include <fcntl.h> | 29 | #include <fcntl.h> |
27 | #include <unistd.h> | 30 | #include <unistd.h> |
28 | 31 | ||
29 | #include <stream0.h> | 32 | #include <mailutils/stream.h> |
30 | 33 | ||
31 | struct _file_stream | 34 | struct _file_stream |
32 | { | 35 | { |
... | @@ -37,7 +40,7 @@ struct _file_stream | ... | @@ -37,7 +40,7 @@ struct _file_stream |
37 | static void | 40 | static void |
38 | _file_destroy (stream_t stream) | 41 | _file_destroy (stream_t stream) |
39 | { | 42 | { |
40 | struct _file_stream *fs = stream->owner; | 43 | struct _file_stream *fs = stream_get_owner (stream); |
41 | 44 | ||
42 | if (fs && fs->file) | 45 | if (fs && fs->file) |
43 | fclose (fs->file); | 46 | fclose (fs->file); |
... | @@ -48,7 +51,7 @@ static int | ... | @@ -48,7 +51,7 @@ static int |
48 | _file_read (stream_t stream, char *optr, size_t osize, | 51 | _file_read (stream_t stream, char *optr, size_t osize, |
49 | off_t offset, size_t *nbytes) | 52 | off_t offset, size_t *nbytes) |
50 | { | 53 | { |
51 | struct _file_stream *fs = stream->owner; | 54 | struct _file_stream *fs = stream_get_owner (stream); |
52 | size_t n; | 55 | size_t n; |
53 | int err = 0; | 56 | int err = 0; |
54 | 57 | ||
... | @@ -80,7 +83,7 @@ static int | ... | @@ -80,7 +83,7 @@ static int |
80 | _file_readline (stream_t stream, char *optr, size_t osize, | 83 | _file_readline (stream_t stream, char *optr, size_t osize, |
81 | off_t offset, size_t *nbytes) | 84 | off_t offset, size_t *nbytes) |
82 | { | 85 | { |
83 | struct _file_stream *fs = stream->owner; | 86 | struct _file_stream *fs = stream_get_owner (stream); |
84 | size_t n = 0; | 87 | size_t n = 0; |
85 | int err = 0; | 88 | int err = 0; |
86 | 89 | ||
... | @@ -116,7 +119,7 @@ static int | ... | @@ -116,7 +119,7 @@ static int |
116 | _file_write (stream_t stream, const char *iptr, size_t isize, | 119 | _file_write (stream_t stream, const char *iptr, size_t isize, |
117 | off_t offset, size_t *nbytes) | 120 | off_t offset, size_t *nbytes) |
118 | { | 121 | { |
119 | struct _file_stream *fs = stream->owner; | 122 | struct _file_stream *fs = stream_get_owner (stream); |
120 | size_t n; | 123 | size_t n; |
121 | int err; | 124 | int err; |
122 | 125 | ||
... | @@ -147,7 +150,7 @@ _file_write (stream_t stream, const char *iptr, size_t isize, | ... | @@ -147,7 +150,7 @@ _file_write (stream_t stream, const char *iptr, size_t isize, |
147 | static int | 150 | static int |
148 | _file_truncate (stream_t stream, off_t len) | 151 | _file_truncate (stream_t stream, off_t len) |
149 | { | 152 | { |
150 | struct _file_stream *fs = stream->owner; | 153 | struct _file_stream *fs = stream_get_owner (stream); |
151 | 154 | ||
152 | if (fs == NULL) | 155 | if (fs == NULL) |
153 | return EINVAL; | 156 | return EINVAL; |
... | @@ -159,7 +162,7 @@ _file_truncate (stream_t stream, off_t len) | ... | @@ -159,7 +162,7 @@ _file_truncate (stream_t stream, off_t len) |
159 | static int | 162 | static int |
160 | _file_size (stream_t stream, off_t *psize) | 163 | _file_size (stream_t stream, off_t *psize) |
161 | { | 164 | { |
162 | struct _file_stream *fs = stream->owner; | 165 | struct _file_stream *fs = stream_get_owner (stream); |
163 | struct stat stbuf; | 166 | struct stat stbuf; |
164 | 167 | ||
165 | if (fs == NULL) | 168 | if (fs == NULL) |
... | @@ -175,7 +178,7 @@ _file_size (stream_t stream, off_t *psize) | ... | @@ -175,7 +178,7 @@ _file_size (stream_t stream, off_t *psize) |
175 | static int | 178 | static int |
176 | _file_flush (stream_t stream) | 179 | _file_flush (stream_t stream) |
177 | { | 180 | { |
178 | struct _file_stream *fs = stream->owner; | 181 | struct _file_stream *fs = stream_get_owner (stream); |
179 | 182 | ||
180 | if (fs == NULL) | 183 | if (fs == NULL) |
181 | return EINVAL; | 184 | return EINVAL; |
... | @@ -185,7 +188,7 @@ _file_flush (stream_t stream) | ... | @@ -185,7 +188,7 @@ _file_flush (stream_t stream) |
185 | static int | 188 | static int |
186 | _file_get_fd (stream_t stream, int *pfd) | 189 | _file_get_fd (stream_t stream, int *pfd) |
187 | { | 190 | { |
188 | struct _file_stream *fs = stream->owner; | 191 | struct _file_stream *fs = stream_get_owner (stream); |
189 | 192 | ||
190 | if (fs == NULL) | 193 | if (fs == NULL) |
191 | return EINVAL; | 194 | return EINVAL; |
... | @@ -197,7 +200,7 @@ _file_get_fd (stream_t stream, int *pfd) | ... | @@ -197,7 +200,7 @@ _file_get_fd (stream_t stream, int *pfd) |
197 | static int | 200 | static int |
198 | _file_close (stream_t stream) | 201 | _file_close (stream_t stream) |
199 | { | 202 | { |
200 | struct _file_stream *fs = stream->owner; | 203 | struct _file_stream *fs = stream_get_owner (stream); |
201 | int err = 0; | 204 | int err = 0; |
202 | 205 | ||
203 | if (fs == NULL) | 206 | if (fs == NULL) |
... | @@ -214,7 +217,7 @@ _file_close (stream_t stream) | ... | @@ -214,7 +217,7 @@ _file_close (stream_t stream) |
214 | static int | 217 | static int |
215 | _file_open (stream_t stream, const char *filename, int port, int flags) | 218 | _file_open (stream_t stream, const char *filename, int port, int flags) |
216 | { | 219 | { |
217 | struct _file_stream *fs = stream->owner; | 220 | struct _file_stream *fs = stream_get_owner (stream); |
218 | int flg; | 221 | int flg; |
219 | int fd; | 222 | int fd; |
220 | const char *mode; | 223 | const char *mode; |
... | @@ -313,7 +316,7 @@ _file_open (stream_t stream, const char *filename, int port, int flags) | ... | @@ -313,7 +316,7 @@ _file_open (stream_t stream, const char *filename, int port, int flags) |
313 | free (iobuffer); | 316 | free (iobuffer); |
314 | } | 317 | } |
315 | #endif | 318 | #endif |
316 | stream_set_flags (stream, flags |MU_STREAM_NO_CHECK, fs); | 319 | stream_set_flags (stream, flags |MU_STREAM_NO_CHECK); |
317 | return 0; | 320 | return 0; |
318 | } | 321 | } |
319 | 322 | ... | ... |
... | @@ -19,13 +19,14 @@ | ... | @@ -19,13 +19,14 @@ |
19 | #ifdef HAVE_CONFIG_H | 19 | #ifdef HAVE_CONFIG_H |
20 | # include "config.h" | 20 | # include "config.h" |
21 | #endif | 21 | #endif |
22 | |||
22 | #include <string.h> | 23 | #include <string.h> |
23 | #include <stdlib.h> | 24 | #include <stdlib.h> |
24 | #include <stdio.h> | 25 | #include <stdio.h> |
25 | #include <errno.h> | 26 | #include <errno.h> |
26 | 27 | ||
28 | #include <mailutils/stream.h> | ||
27 | #include <header0.h> | 29 | #include <header0.h> |
28 | #include <stream0.h> | ||
29 | 30 | ||
30 | static int header_parse (header_t h, const char *blurb, int len); | 31 | static int header_parse (header_t h, const char *blurb, int len); |
31 | static int header_read (stream_t is, char *buf, size_t buflen, | 32 | static int header_read (stream_t is, char *buf, size_t buflen, |
... | @@ -72,6 +73,12 @@ header_destroy (header_t *ph, void *owner) | ... | @@ -72,6 +73,12 @@ header_destroy (header_t *ph, void *owner) |
72 | } | 73 | } |
73 | } | 74 | } |
74 | 75 | ||
76 | void * | ||
77 | header_get_owner (header_t header) | ||
78 | { | ||
79 | return (header) ? header->owner : NULL; | ||
80 | } | ||
81 | |||
75 | /* Parsing is done in a rather simple fashion. | 82 | /* Parsing is done in a rather simple fashion. |
76 | meaning we just consider an entry to be | 83 | meaning we just consider an entry to be |
77 | a field-name an a field-value. So they | 84 | a field-name an a field-value. So they |
... | @@ -243,14 +250,29 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) | ... | @@ -243,14 +250,29 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) |
243 | } | 250 | } |
244 | 251 | ||
245 | /* Replacing was taking care of above now just add to the end the new | 252 | /* Replacing was taking care of above now just add to the end the new |
246 | header. Really not cute. */ | 253 | header. Really not cute. |
247 | len = strlen (fn) + strlen (fv) + 1 + 1 + 1 + 1; | 254 | COLON SPACE NL = 3 ; */ |
248 | blurb = calloc (header->blurb_len + len, 1); | 255 | len = strlen (fn) + strlen (fv) + 3; |
256 | /* Add one for the NULL and leak a bit by adding one more | ||
257 | it will be the separtor \n from the body if the first | ||
258 | blurb did not have it. */ | ||
259 | blurb = calloc (header->blurb_len + len + 2, 1); | ||
249 | if (blurb == NULL) | 260 | if (blurb == NULL) |
250 | return ENOMEM; | 261 | return ENOMEM; |
251 | sprintf (blurb, "%s: %s\n", fn, fv); | 262 | sprintf (blurb, "%s: %s\n", fn, fv); |
252 | memcpy (blurb + len - 1, header->blurb, header->blurb_len); | 263 | if (header->blurb) |
253 | free (header->blurb); | 264 | { |
265 | memcpy (blurb + len, header->blurb, header->blurb_len); | ||
266 | free (header->blurb); | ||
267 | } | ||
268 | /* before parsing the new blurb make sure it is properly terminated | ||
269 | by \n\n. The trailing NL separtor. */ | ||
270 | if (blurb[header->blurb_len + len - 1] != '\n' | ||
271 | || blurb[header->blurb_len + len - 2] != '\n') | ||
272 | { | ||
273 | blurb[header->blurb_len + len] = '\n'; | ||
274 | len++; | ||
275 | } | ||
254 | header_parse (header, blurb, len + header->blurb_len); | 276 | header_parse (header, blurb, len + header->blurb_len); |
255 | free (blurb); | 277 | free (blurb); |
256 | return 0; | 278 | return 0; |
... | @@ -469,17 +491,20 @@ fill_blurb (header_t header) | ... | @@ -469,17 +491,20 @@ fill_blurb (header_t header) |
469 | } | 491 | } |
470 | return status; | 492 | return status; |
471 | } | 493 | } |
472 | tbuf = realloc (header->temp_blurb, header->temp_blurb_len + nread); | 494 | if (nread > 0) |
473 | if (tbuf == NULL) | ||
474 | { | 495 | { |
475 | free (header->temp_blurb); | 496 | tbuf = realloc (header->temp_blurb, header->temp_blurb_len + nread); |
476 | header->temp_blurb = NULL; | 497 | if (tbuf == NULL) |
477 | header->temp_blurb_len = 0; | 498 | { |
478 | return ENOMEM; | 499 | free (header->temp_blurb); |
500 | header->temp_blurb = NULL; | ||
501 | header->temp_blurb_len = 0; | ||
502 | return ENOMEM; | ||
503 | } | ||
504 | header->temp_blurb = tbuf; | ||
505 | memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread); | ||
506 | header->temp_blurb_len += nread; | ||
479 | } | 507 | } |
480 | header->temp_blurb = tbuf; | ||
481 | memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread); | ||
482 | header->temp_blurb_len += nread; | ||
483 | } | 508 | } |
484 | while (nread > 0); | 509 | while (nread > 0); |
485 | 510 | ||
... | @@ -495,8 +520,8 @@ static int | ... | @@ -495,8 +520,8 @@ static int |
495 | header_write (stream_t os, const char *buf, size_t buflen, | 520 | header_write (stream_t os, const char *buf, size_t buflen, |
496 | off_t off, size_t *pnwrite) | 521 | off_t off, size_t *pnwrite) |
497 | { | 522 | { |
498 | header_t header; | 523 | header_t header = stream_get_owner (os); |
499 | if (os == NULL || (header = (header_t)os->owner) == NULL) | 524 | if (os == NULL || header == NULL) |
500 | return EINVAL; | 525 | return EINVAL; |
501 | 526 | ||
502 | (void)buf; (void)off; | 527 | (void)buf; (void)off; |
... | @@ -513,10 +538,10 @@ static int | ... | @@ -513,10 +538,10 @@ static int |
513 | header_read (stream_t is, char *buf, size_t buflen, | 538 | header_read (stream_t is, char *buf, size_t buflen, |
514 | off_t off, size_t *pnread) | 539 | off_t off, size_t *pnread) |
515 | { | 540 | { |
516 | header_t header; | 541 | header_t header = stream_get_owner (is); |
517 | int len; | 542 | int len; |
518 | 543 | ||
519 | if (is == NULL || (header = (header_t)is->owner) == NULL) | 544 | if (is == NULL || header == NULL) |
520 | return EINVAL; | 545 | return EINVAL; |
521 | 546 | ||
522 | len = header->blurb_len - off; | 547 | len = header->blurb_len - off; | ... | ... |
... | @@ -33,13 +33,19 @@ | ... | @@ -33,13 +33,19 @@ |
33 | extern "C" { | 33 | extern "C" { |
34 | #endif | 34 | #endif |
35 | 35 | ||
36 | struct _auth | 36 | struct _ticket |
37 | { | 37 | { |
38 | void *owner; | 38 | void *owner; |
39 | char *challenge; | ||
40 | char *type; | ||
41 | int (*_pop) __P ((ticket_t, const char *challenge, char **)); | ||
42 | }; | ||
39 | 43 | ||
40 | int (*_prologue) (auth_t); | 44 | struct _authority |
41 | int (*_authenticate) (auth_t, char **user, char **passwd); | 45 | { |
42 | int (*_epilogue) (auth_t); | 46 | void *owner; |
47 | ticket_t ticket; | ||
48 | int (*_authenticate) __P ((authority_t)); | ||
43 | }; | 49 | }; |
44 | 50 | ||
45 | 51 | ... | ... |
mailbox/include/debug0.h
0 → 100644
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 _MAILUTILS_DEBUG0_H | ||
19 | #define _MAILUTILS_DEBUG0_H | ||
20 | |||
21 | #ifndef __P | ||
22 | #ifdef __STDC__ | ||
23 | #define __P(args) args | ||
24 | #else | ||
25 | #define __P(args) () | ||
26 | #endif | ||
27 | #endif /*__P */ | ||
28 | |||
29 | #include <mailutils/debug.h> | ||
30 | |||
31 | #ifdef _cplusplus | ||
32 | extern "C" { | ||
33 | #endif | ||
34 | |||
35 | struct _debug | ||
36 | { | ||
37 | size_t level; | ||
38 | char *buffer; | ||
39 | size_t buflen; | ||
40 | void *owner; | ||
41 | int (*_print) __P ((debug_t, const char *, va_list)); | ||
42 | }; | ||
43 | |||
44 | #ifdef _cplusplus | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | #endif /* _MAILUTILS_DEBUG0_H */ |
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
3 | 3 | ||
4 | This program is free software; you can redistribute it and/or modify | 4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU Library General Public License as published by | 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) | 6 | the Free Software Foundation; either version 2, or (at your option) |
7 | any later version. | 7 | any later version. |
8 | 8 | ||
... | @@ -15,22 +15,33 @@ | ... | @@ -15,22 +15,33 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifndef _MBX_UNIX_H | 18 | #ifndef _ITERATOR0_H |
19 | #define _MBX_UNIX_H 1 | 19 | #define _ITERATOR0_H |
20 | 20 | ||
21 | #include <mailbox0.h> | 21 | #include <mailutils/iterator.h> |
22 | 22 | ||
23 | #ifdef __cplucplus | 23 | #ifndef __P |
24 | #ifdef __STDC__ | ||
25 | #define __P(args) args | ||
26 | #else | ||
27 | #define __P(args) () | ||
28 | #endif | ||
29 | #endif /*__P */ | ||
30 | |||
31 | #ifdef _cplusplus | ||
24 | extern "C" { | 32 | extern "C" { |
25 | #endif | 33 | #endif |
26 | 34 | ||
27 | extern int mailbox_unix_create __P ((mailbox_t *mbox, const char *name)); | 35 | struct _iterator |
28 | extern void mailbox_unix_destroy __P ((mailbox_t *mbox)); | 36 | { |
37 | list_t list; | ||
38 | size_t index; | ||
39 | |||
40 | }; | ||
29 | 41 | ||
30 | extern struct mailbox_type _mailbox_unix_type; | ||
31 | 42 | ||
32 | #ifdef __cplucplus | 43 | #ifdef _cplusplus |
33 | } | 44 | } |
34 | #endif | 45 | #endif |
35 | 46 | ||
36 | #endif /* _MBX_UNIX_H */ | 47 | #endif /* _ITERATOR0_H */ | ... | ... |
mailbox/include/list0.h
0 → 100644
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 _LIST0_H | ||
19 | #define _LIST0_H | ||
20 | |||
21 | #ifdef HAVE_PTHREAD_H | ||
22 | # define __USE_UNIX98 /* ?? */ | ||
23 | # include <pthread.h> | ||
24 | #endif | ||
25 | |||
26 | #include <mailutils/list.h> | ||
27 | #include <sys/types.h> | ||
28 | |||
29 | |||
30 | #ifndef __P | ||
31 | #ifdef __STDC__ | ||
32 | #define __P(args) args | ||
33 | #else | ||
34 | #define __P(args) () | ||
35 | #endif | ||
36 | #endif /*__P */ | ||
37 | |||
38 | #ifdef _cplusplus | ||
39 | extern "C" { | ||
40 | #endif | ||
41 | |||
42 | struct list_data | ||
43 | { | ||
44 | void *item; | ||
45 | struct list_data *next; | ||
46 | struct list_data *prev; | ||
47 | }; | ||
48 | |||
49 | struct _list | ||
50 | { | ||
51 | struct list_data head; | ||
52 | size_t count; | ||
53 | #ifdef WITH_PTHREAD | ||
54 | pthread_rwlock_t rwlock; | ||
55 | #endif | ||
56 | }; | ||
57 | |||
58 | |||
59 | #ifdef _cplusplus | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | #endif /* _LIST0_H */ |
... | @@ -18,12 +18,16 @@ | ... | @@ -18,12 +18,16 @@ |
18 | #ifndef _MAILBOX0_H | 18 | #ifndef _MAILBOX0_H |
19 | #define _MAILBOX0_H | 19 | #define _MAILBOX0_H |
20 | 20 | ||
21 | #include <mailutils/mailbox.h> | 21 | #ifdef HAVE_PTHREAD_H |
22 | #include <mailutils/event.h> | 22 | # define __USE_UNIX98 /* ?? */ |
23 | # include <pthread.h> | ||
24 | #endif | ||
23 | 25 | ||
24 | #include <sys/types.h> | 26 | #include <sys/types.h> |
25 | #include <stdio.h> | 27 | #include <stdio.h> |
26 | 28 | ||
29 | #include <mailutils/mailbox.h> | ||
30 | |||
27 | #ifdef __cplusplus | 31 | #ifdef __cplusplus |
28 | extern "C" { | 32 | extern "C" { |
29 | #endif | 33 | #endif |
... | @@ -39,30 +43,26 @@ extern "C" { | ... | @@ -39,30 +43,26 @@ extern "C" { |
39 | struct _mailbox | 43 | struct _mailbox |
40 | { | 44 | { |
41 | /* Data */ | 45 | /* Data */ |
42 | char *name; | 46 | observable_t observable; |
43 | auth_t auth; | 47 | debug_t debug; |
48 | ticket_t ticket; | ||
49 | authority_t authority; | ||
44 | locker_t locker; | 50 | locker_t locker; |
45 | stream_t stream; | 51 | stream_t stream; |
46 | url_t url; | 52 | url_t url; |
53 | int flags; | ||
47 | 54 | ||
48 | /* register events */ | 55 | #ifdef WITH_PTHREAD |
49 | event_t event; | 56 | pthread_rwlock_t rwlock; |
50 | size_t event_num; | 57 | #endif |
51 | |||
52 | /* debug information */ | ||
53 | int debug_level; | ||
54 | void *debug_arg; | ||
55 | char *debug_buffer; | ||
56 | size_t debug_bufsize; | ||
57 | int (*debug_print) __P ((void *arg, const char *, size_t)); | ||
58 | 58 | ||
59 | /* Back pointer to the specific mailbox */ | 59 | /* Back pointer to the specific mailbox */ |
60 | void *data; | 60 | void *data; |
61 | 61 | ||
62 | /* Public methods */ | 62 | /* Public methods */ |
63 | 63 | ||
64 | int (*_create) __P ((mailbox_t *, const char *)); | 64 | int (*_init) __P ((mailbox_t)); |
65 | void (*_destroy) __P ((mailbox_t *)); | 65 | void (*_destroy) __P ((mailbox_t)); |
66 | 66 | ||
67 | int (*_open) __P ((mailbox_t, int flag)); | 67 | int (*_open) __P ((mailbox_t, int flag)); |
68 | int (*_close) __P ((mailbox_t)); | 68 | int (*_close) __P ((mailbox_t)); |
... | @@ -78,16 +78,27 @@ struct _mailbox | ... | @@ -78,16 +78,27 @@ struct _mailbox |
78 | 78 | ||
79 | int (*_size) __P ((mailbox_t, off_t *size)); | 79 | int (*_size) __P ((mailbox_t, off_t *size)); |
80 | 80 | ||
81 | /* private */ | ||
82 | int (*_num_deleted) __P ((mailbox_t, size_t *)); | ||
83 | }; | 81 | }; |
84 | 82 | ||
85 | /* private */ | 83 | /* To manipulate mailbox rwlock. */ |
86 | extern int mailbox_num_deleted __P ((mailbox_t, size_t *)); | 84 | extern int mailbox_rdlock __P ((mailbox_t)); |
87 | 85 | extern int mailbox_wrlock __P ((mailbox_t)); | |
88 | extern int mailbox_notification __P ((mailbox_t mbox, size_t type)); | 86 | extern int mailbox_unlock __P ((mailbox_t)); |
89 | 87 | ||
90 | extern int mailbox_debug __P ((mailbox_t, int level, const char *fmt, ...)); | 88 | #define MAILBOX_NOTIFY(mbox, type) \ |
89 | if (mbox->observer) observer_notify (mbox->observer, type) | ||
90 | |||
91 | /* Moro(?)ic kluge. */ | ||
92 | #define MAILBOX_DEBUG0(mbox, type, format) \ | ||
93 | if (mbox->debug) debug_print (mbox->debug, type, format) | ||
94 | #define MAILBOX_DEBUG1(mbox, type, format, arg1) \ | ||
95 | if (mbox->debug) debug_print (mbox->debug, type, format, arg1) | ||
96 | #define MAILBOX_DEBUG2(mbox, type, format, arg1, arg2) \ | ||
97 | if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2) | ||
98 | #define MAILBOX_DEBUG3(mbox, type, format, arg1, arg2, arg3) \ | ||
99 | if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2, arg3) | ||
100 | #define MAILBOX_DEBUG4(mbox, type, format, arg1, arg2, arg3, arg4) \ | ||
101 | if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2, arg3, arg4) | ||
91 | 102 | ||
92 | #ifdef __cplusplus | 103 | #ifdef __cplusplus |
93 | } | 104 | } | ... | ... |
... | @@ -20,7 +20,10 @@ | ... | @@ -20,7 +20,10 @@ |
20 | 20 | ||
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | #include <mailutils/mailer.h> | 22 | #include <mailutils/mailer.h> |
23 | 23 | #ifdef HAVE_PTHREAD_H | |
24 | # define __USE_UNIX98 /* ?? */ | ||
25 | # include <pthread.h> | ||
26 | #endif | ||
24 | #ifdef _cplusplus | 27 | #ifdef _cplusplus |
25 | extern "C" { | 28 | extern "C" { |
26 | #endif | 29 | #endif |
... | @@ -50,16 +53,32 @@ extern "C" { | ... | @@ -50,16 +53,32 @@ extern "C" { |
50 | 53 | ||
51 | struct _mailer | 54 | struct _mailer |
52 | { | 55 | { |
53 | int socket; | 56 | stream_t stream; |
54 | char *hostname; | 57 | observable_t observable; |
55 | char line_buf[MAILER_LINE_BUF_SIZE]; | 58 | debug_t debug; |
56 | int offset; | 59 | url_t url; |
57 | int state; | 60 | int flags; |
58 | int add_dot; | 61 | #ifdef WITH_PTHREAD |
59 | stream_t stream; | 62 | pthread_rwlock_t rwlock; |
60 | char last_char; | 63 | #endif |
64 | |||
65 | /* Pointer to the specific mailer data. */ | ||
66 | void *data; | ||
67 | |||
68 | /* Public methods. */ | ||
69 | int (*_init) __P ((mailer_t)); | ||
70 | void (*_destroy) __P ((mailer_t)); | ||
71 | int (*_open) __P ((mailer_t, int flags)); | ||
72 | int (*_close) __P ((mailer_t)); | ||
73 | int (*_send_message) __P ((mailer_t, const char *from, const char *rcpt, | ||
74 | int dsn, message_t)); | ||
61 | }; | 75 | }; |
62 | 76 | ||
77 | /* Mail locks. */ | ||
78 | extern int mailer_rdlock __P ((mailer_t)); | ||
79 | extern int mailer_wrlock __P ((mailer_t)); | ||
80 | extern int mailer_unlock __P ((mailer_t)); | ||
81 | |||
63 | #ifdef _cplusplus | 82 | #ifdef _cplusplus |
64 | } | 83 | } |
65 | #endif | 84 | #endif | ... | ... |
mailbox/include/mbx_imap.h
deleted
100644 → 0
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 Library General 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 _MBX_IMAP_H | ||
19 | #define _MBX_IMAP_H 1 | ||
20 | |||
21 | #include <mailbox0.h> | ||
22 | |||
23 | extern int mailbox_imap_create __P ((mailbox_t *mbox, const char *name)); | ||
24 | extern void mailbox_imap_destroy __P ((mailbox_t *mbox)); | ||
25 | |||
26 | extern struct mailbox_type _mailbox_imap_type; | ||
27 | |||
28 | #endif /* _MBX_IMAP_H */ |
mailbox/include/mbx_mbox.h
deleted
100644 → 0
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999 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 Library General 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 _MBX_MBOX_H | ||
19 | #define _MBX_MBOX_H 1 | ||
20 | |||
21 | #include <mailutils/mailbox.h> | ||
22 | |||
23 | extern int mailbox_mbox_create __P ((mailbox_t *mbox, const char *name)); | ||
24 | extern void mailbox_mbox_destroy __P ((mailbox_t *mbox)); | ||
25 | |||
26 | extern struct mailbox_type _mailbox_mbox_type; | ||
27 | |||
28 | #endif /* _MBX_MBOX_H */ |
mailbox/include/mbx_mdir.h
deleted
100644 → 0
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 Library General 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 _MBX_MDIR_H | ||
19 | #define _MBX_MDIR_H 1 | ||
20 | |||
21 | #include <mailbox0.h> | ||
22 | |||
23 | extern int mailbox_maildir_create __P ((mailbox_t *mbox, const char *name)); | ||
24 | extern void mailbox_maildir_destroy __P ((mailbox_t *mbox)); | ||
25 | |||
26 | extern struct mailbox_type _mailbox_maildir_type; | ||
27 | |||
28 | #endif /* _MBX_MDIR_H */ |
mailbox/include/mbx_mmdf.h
deleted
100644 → 0
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 Library General 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 _MBX_MMDF_H | ||
19 | #define _MBX_MMDF_H 1 | ||
20 | |||
21 | #include <mailbox0.h> | ||
22 | |||
23 | extern int mailbox_mmdf_create __P ((mailbox_t *mbox, const char *name)); | ||
24 | extern void mailbox_mmdf_destroy __P ((mailbox_t *mbox)); | ||
25 | |||
26 | extern struct mailbox_type _mailbox_mmdf_type; | ||
27 | |||
28 | #endif /* _MBX_MMDF_H */ |
mailbox/include/mbx_pop.h
deleted
100644 → 0
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 Library General 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 _MBX_POP_H | ||
19 | #define _MBX_POP_H 1 | ||
20 | |||
21 | #include <mailbox0.h> | ||
22 | |||
23 | extern int mailbox_pop_create __P ((mailbox_t *mbox, const char *name)); | ||
24 | extern void mailbox_pop_destroy __P ((mailbox_t *mbox)); | ||
25 | |||
26 | extern struct mailbox_type _mailbox_pop_type; | ||
27 | |||
28 | #endif /* _MBX_POP_H */ |
... | @@ -18,12 +18,8 @@ | ... | @@ -18,12 +18,8 @@ |
18 | #ifndef _MESSAGE0_H | 18 | #ifndef _MESSAGE0_H |
19 | #define _MESSAGE0_H | 19 | #define _MESSAGE0_H |
20 | 20 | ||
21 | #include <mailutils/attribute.h> | ||
22 | #include <mailutils/header.h> | ||
23 | #include <mailutils/message.h> | 21 | #include <mailutils/message.h> |
24 | #include <mailutils/mime.h> | 22 | #include <mailutils/mime.h> |
25 | #include <mailutils/mailbox.h> | ||
26 | #include <mailutils/event.h> | ||
27 | 23 | ||
28 | #include <sys/types.h> | 24 | #include <sys/types.h> |
29 | #include <stdio.h> | 25 | #include <stdio.h> |
... | @@ -50,9 +46,7 @@ struct _message | ... | @@ -50,9 +46,7 @@ struct _message |
50 | body_t body; | 46 | body_t body; |
51 | attribute_t attribute; | 47 | attribute_t attribute; |
52 | mime_t mime; | 48 | mime_t mime; |
53 | 49 | observable_t observable; | |
54 | event_t event; | ||
55 | size_t event_num; | ||
56 | 50 | ||
57 | /* Holder for message_write. */ | 51 | /* Holder for message_write. */ |
58 | char *hdr_buf; | 52 | char *hdr_buf; |
... | @@ -73,5 +67,4 @@ struct _message | ... | @@ -73,5 +67,4 @@ struct _message |
73 | } | 67 | } |
74 | #endif | 68 | #endif |
75 | 69 | ||
76 | extern void message_notification (message_t msg, size_t type); | 70 | #endif /* _MESSAGE0_H */ |
77 | #endif /* _MESSAGE_H */ | ... | ... |
... | @@ -47,6 +47,9 @@ extern "C" { | ... | @@ -47,6 +47,9 @@ extern "C" { |
47 | #define MIME_PARSER_ACTIVE 0x80000000 | 47 | #define MIME_PARSER_ACTIVE 0x80000000 |
48 | #define MIME_PARSER_HAVE_CR 0x40000000 | 48 | #define MIME_PARSER_HAVE_CR 0x40000000 |
49 | #define MIME_NEW_MESSAGE 0x20000000 | 49 | #define MIME_NEW_MESSAGE 0x20000000 |
50 | #define MIME_ADDED_CONTENT_TYPE 0x10000000 | ||
51 | #define MIME_ADDED_MULTIPART 0x08000000 | ||
52 | #define MIME_INSERT_BOUNDARY 0x04000000 | ||
50 | 53 | ||
51 | struct _mime | 54 | struct _mime |
52 | { | 55 | { |
... | @@ -59,12 +62,14 @@ struct _mime | ... | @@ -59,12 +62,14 @@ struct _mime |
59 | int tparts; | 62 | int tparts; |
60 | int nmtp_parts; | 63 | int nmtp_parts; |
61 | struct _mime_part **mtp_parts; /* list of parts in the msg */ | 64 | struct _mime_part **mtp_parts; /* list of parts in the msg */ |
62 | 65 | char *boundary; | |
66 | int cur_offset; | ||
67 | int cur_part; | ||
68 | int part_offset; | ||
69 | |||
63 | /* parser state */ | 70 | /* parser state */ |
64 | char *boundary; | ||
65 | char *cur_line; | 71 | char *cur_line; |
66 | int line_ndx; | 72 | int line_ndx; |
67 | int cur_offset; | ||
68 | char *cur_buf; | 73 | char *cur_buf; |
69 | int buf_size; | 74 | int buf_size; |
70 | char *header_buf; | 75 | char *header_buf; |
... | @@ -72,17 +77,17 @@ struct _mime | ... | @@ -72,17 +77,17 @@ struct _mime |
72 | int header_length; | 77 | int header_length; |
73 | int body_offset; | 78 | int body_offset; |
74 | int body_length; | 79 | int body_length; |
80 | int body_lines; | ||
75 | int parser_state; | 81 | int parser_state; |
76 | }; | 82 | }; |
77 | 83 | ||
78 | struct _mime_part | 84 | struct _mime_part |
79 | { | 85 | { |
80 | char sig[4]; | ||
81 | mime_t mime; | 86 | mime_t mime; |
82 | header_t hdr; | ||
83 | message_t msg; | 87 | message_t msg; |
84 | int body_offset; | 88 | int offset; |
85 | int body_len; | 89 | size_t len; |
90 | size_t lines; | ||
86 | }; | 91 | }; |
87 | 92 | ||
88 | #ifdef _cplusplus | 93 | #ifdef _cplusplus | ... | ... |
... | @@ -15,8 +15,12 @@ | ... | @@ -15,8 +15,12 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifndef _CPYSTR_H | 18 | #ifndef _MISC_H |
19 | #define _CPYSTR_H | 19 | #define _MISC_H |
20 | |||
21 | #ifdef HAVE_CONFIG_H | ||
22 | # include <config.h> | ||
23 | #endif | ||
20 | 24 | ||
21 | #include <sys/types.h> | 25 | #include <sys/types.h> |
22 | 26 | ||
... | @@ -32,9 +36,45 @@ extern "C" { | ... | @@ -32,9 +36,45 @@ extern "C" { |
32 | # endif | 36 | # endif |
33 | #endif | 37 | #endif |
34 | extern size_t _cpystr __P ((char *dst, const char *src, size_t size)); | 38 | extern size_t _cpystr __P ((char *dst, const char *src, size_t size)); |
39 | extern int parseaddr __P ((const char *addr, char *buf, size_t bufsz)); | ||
40 | |||
41 | #ifdef HAVE_PTHREAD_H | ||
42 | # define __USE_UNIX98 | ||
43 | # include <pthread.h> | ||
44 | #endif | ||
45 | |||
46 | #ifdef WITH_PTHREAD | ||
47 | # if 0 | ||
48 | # define RWLOCK_INIT(rwl, attr) pthread_mutex_init (rwl, attr) | ||
49 | # define RWLOCK_DESTROY(rwl) pthread_mutex_destroy (rwl) | ||
50 | # define RWLOCK_RDLOCK(rwl) pthread_mutex_lock (rwl) | ||
51 | # define RWLOCK_TRYRDLOCK(rwl) pthread_mutex_trylock (rwl) | ||
52 | # define RWLOCK_WRLOCK(rwl) pthread_mutex_lock (rwl) | ||
53 | # define RWLOCK_TRYWRLOCK(rwl) pthread_mutex_trylock (rwl) | ||
54 | # define RWLOCK_UNLOCK(rwl) pthread_mutex_unlock (rwl) | ||
55 | # else | ||
56 | # define RWLOCK_INIT(rwl, attr) pthread_rwlock_init (rwl, attr) | ||
57 | # define RWLOCK_DESTROY(rwl) pthread_rwlock_destroy (rwl) | ||
58 | # define RWLOCK_RDLOCK(rwl) pthread_rwlock_rdlock (rwl) | ||
59 | # define RWLOCK_TRYRDLOCK(rwl) pthread_rwlock_tryrdlock (rwl) | ||
60 | # define RWLOCK_WRLOCK(rwl) pthread_rwlock_wrlock (rwl) | ||
61 | # define RWLOCK_TRYWRLOCK(rwl) pthread_rwlock_trywrlock (rwl) | ||
62 | # define RWLOCK_UNLOCK(rwl) pthread_rwlock_unlock (rwl) | ||
63 | # endif | ||
64 | #else | ||
65 | # define RWLOCK_INIT(rwl, attr) 0 | ||
66 | # define RWLOCK_DESTROY(rwl) | ||
67 | # define RWLOCK_RDLOCK(rwl) | ||
68 | # define RWLOCK_TRYRDLOCK(rwl) | ||
69 | # define RWLOCK_WRLOCK(rwl) | ||
70 | # define RWLOCK_TRYWRLOCK(rwl) | ||
71 | # define RWLOCK_UNLOCK(rwl) | ||
72 | # define flockfile(arg) | ||
73 | # define funlockfile(arg) | ||
74 | #endif | ||
35 | 75 | ||
36 | #ifdef __cplusplus | 76 | #ifdef __cplusplus |
37 | } | 77 | } |
38 | #endif | 78 | #endif |
39 | 79 | ||
40 | #endif | 80 | #endif /* _MISC_H */ | ... | ... |
mailbox/include/observer0.h
0 → 100644
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 _OBSERVER0_H | ||
19 | #define _OBSERVER0_H | ||
20 | |||
21 | #include <mailutils/observer.h> | ||
22 | |||
23 | #ifndef __P | ||
24 | #ifdef __STDC__ | ||
25 | #define __P(args) args | ||
26 | #else | ||
27 | #define __P(args) () | ||
28 | #endif | ||
29 | #endif /*__P */ | ||
30 | |||
31 | #ifdef _cplusplus | ||
32 | extern "C" { | ||
33 | #endif | ||
34 | |||
35 | struct _observer | ||
36 | { | ||
37 | int flags; | ||
38 | void *owner; | ||
39 | int (*_action) __P ((observer_t, size_t)); | ||
40 | int (*_destroy) __P ((observer_t)); | ||
41 | }; | ||
42 | |||
43 | struct _observable | ||
44 | { | ||
45 | void *owner; | ||
46 | list_t list; | ||
47 | }; | ||
48 | |||
49 | |||
50 | #ifdef _cplusplus | ||
51 | } | ||
52 | #endif | ||
53 | |||
54 | #endif /* _OBSERVER0_H */ |
... | @@ -20,7 +20,6 @@ | ... | @@ -20,7 +20,6 @@ |
20 | 20 | ||
21 | #include <mailutils/registrar.h> | 21 | #include <mailutils/registrar.h> |
22 | 22 | ||
23 | |||
24 | #ifdef __cplusplus | 23 | #ifdef __cplusplus |
25 | extern "C" { | 24 | extern "C" { |
26 | #endif | 25 | #endif |
... | @@ -33,58 +32,18 @@ extern "C" { | ... | @@ -33,58 +32,18 @@ extern "C" { |
33 | # endif | 32 | # endif |
34 | #endif /*__P */ | 33 | #endif /*__P */ |
35 | 34 | ||
36 | /* | 35 | struct _record |
37 | Builtin mailbox types. | ||
38 | A circular list is use for the builtin. | ||
39 | Proper locking is not done when accessing the list. | ||
40 | FIXME: not thread-safe. */ | ||
41 | struct _registrar | ||
42 | { | 36 | { |
43 | struct url_registrar *ureg; | 37 | const char *scheme; |
44 | struct mailbox_registrar *mreg; | 38 | mailbox_entry_t mailbox; |
39 | mailer_entry_t mailer; | ||
45 | int is_allocated; | 40 | int is_allocated; |
46 | struct _registrar *next; | 41 | void *onwer; |
42 | int (*_is_scheme) __P ((record_t, const char *)); | ||
43 | int (*_get_mailbox) __P ((record_t, mailbox_entry_t *_mailbox)); | ||
44 | int (*_get_mailer) __P ((record_t, mailer_entry_t *_mailer)); | ||
47 | }; | 45 | }; |
48 | 46 | ||
49 | |||
50 | /* This is function is obsolete use the registrar_entry_*() ones */ | ||
51 | extern int registrar_list __P ((struct url_registrar **ureg, | ||
52 | struct mailbox_registrar **mreg, | ||
53 | int *id, registrar_t *reg)); | ||
54 | extern int registrar_entry_count __P ((size_t *num)); | ||
55 | extern int registrar_entry __P ((size_t num, struct url_registrar **ureg, | ||
56 | struct mailbox_registrar **mreg, | ||
57 | int *id)); | ||
58 | /* IMAP */ | ||
59 | extern struct mailbox_registrar _mailbox_imap_registrar; | ||
60 | extern struct url_registrar _url_imap_registrar; | ||
61 | |||
62 | /* FILE */ | ||
63 | extern struct url_registrar _url_file_registrar; | ||
64 | /* MBOX */ | ||
65 | extern struct mailbox_registrar _mailbox_mbox_registrar; | ||
66 | extern struct url_registrar _url_mbox_registrar; | ||
67 | |||
68 | /* MAILTO */ | ||
69 | extern struct mailbox_registrar _mailbox_mailto_registrar; | ||
70 | extern struct url_registrar _url_mailto_registrar; | ||
71 | |||
72 | /* MDIR */ | ||
73 | extern struct mailbox_registrar _mailbox_maildir_registrar; | ||
74 | extern struct url_registrar _url_maildir_registrar; | ||
75 | |||
76 | /* MMDF */ | ||
77 | extern struct mailbox_registrar _mailbox_mmdf_registrar; | ||
78 | extern struct url_registrar _url_mmdf_registrar; | ||
79 | |||
80 | /* UNIX */ | ||
81 | extern struct mailbox_registrar _mailbox_unix_registrar; | ||
82 | extern struct url_registrar _url_unix_registrar; | ||
83 | |||
84 | /* POP */ | ||
85 | extern struct mailbox_registrar _mailbox_pop_registrar; | ||
86 | extern struct url_registrar _url_pop_registrar; | ||
87 | |||
88 | #ifdef __cplusplus | 47 | #ifdef __cplusplus |
89 | } | 48 | } |
90 | #endif | 49 | #endif | ... | ... |
... | @@ -35,62 +35,34 @@ extern "C" { | ... | @@ -35,62 +35,34 @@ extern "C" { |
35 | struct _url | 35 | struct _url |
36 | { | 36 | { |
37 | /* Data */ | 37 | /* Data */ |
38 | char *name; | ||
38 | char *scheme; | 39 | char *scheme; |
39 | char *user; | 40 | char *user; |
40 | char *passwd; /* encoded ?? */ | 41 | char *passwd; /* encoded ?? */ |
42 | char *auth; | ||
41 | char *host; | 43 | char *host; |
42 | long port; | 44 | long port; |
43 | char *path; | 45 | char *path; |
44 | char *query; | 46 | char *query; |
45 | int id; | ||
46 | 47 | ||
47 | 48 | ||
48 | void *data; | 49 | void *data; |
49 | 50 | ||
50 | int (*_create) __P ((url_t *url, const char *name)); | 51 | int (*_init) __P ((url_t url)); |
51 | void (*_destroy) __P ((url_t *url)); | 52 | void (*_destroy) __P ((url_t url)); |
52 | 53 | ||
53 | /* Methods */ | 54 | /* Methods */ |
54 | int (*_get_id) __P ((const url_t, int *id)); | 55 | int (*_get_scheme) __P ((const url_t, char *, size_t, size_t *)); |
55 | 56 | int (*_get_user) __P ((const url_t, char *, size_t, size_t *)); | |
56 | int (*_get_scheme) __P ((const url_t, char *scheme, | 57 | int (*_get_passwd) __P ((const url_t, char *, size_t, size_t *)); |
57 | size_t len, size_t *n)); | 58 | int (*_get_auth) __P ((const url_t, char *, size_t, size_t *)); |
58 | 59 | int (*_get_host) __P ((const url_t, char *, size_t, size_t *)); | |
59 | int (*_get_user) __P ((const url_t, char *user, | 60 | int (*_get_port) __P ((const url_t, long *)); |
60 | size_t len, size_t *n)); | 61 | int (*_get_path) __P ((const url_t, char *, size_t, size_t *)); |
61 | 62 | int (*_get_query) __P ((const url_t, char *, size_t, size_t *)); | |
62 | int (*_get_passwd) __P ((const url_t, char *passwd, | ||
63 | size_t len, size_t *n)); | ||
64 | |||
65 | int (*_get_host) __P ((const url_t, char *host, | ||
66 | size_t len, size_t *n)); | ||
67 | |||
68 | int (*_get_port) __P ((const url_t, long *port)); | ||
69 | |||
70 | int (*_get_path) __P ((const url_t, char *path, | ||
71 | size_t len, size_t *n)); | ||
72 | |||
73 | int (*_get_query) __P ((const url_t, char *query, | ||
74 | size_t len, size_t *n)); | ||
75 | }; | 63 | }; |
76 | 64 | ||
77 | 65 | ||
78 | /* IMAP */ | ||
79 | |||
80 | /* Mailto */ | ||
81 | |||
82 | /* UNIX MBOX */ | ||
83 | |||
84 | /* Maildir */ | ||
85 | |||
86 | /* MMDF */ | ||
87 | |||
88 | /* POP3 */ | ||
89 | |||
90 | #define MU_POP_PORT 110 | ||
91 | |||
92 | /* UNIX MBOX */ | ||
93 | |||
94 | #ifdef __cplusplus | 66 | #ifdef __cplusplus |
95 | } | 67 | } |
96 | #endif | 68 | #endif | ... | ... |
mailbox/iterator.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include <iterator0.h> | ||
26 | |||
27 | int | ||
28 | iterator_create (iterator_t *piterator, list_t list) | ||
29 | { | ||
30 | iterator_t iterator; | ||
31 | if (piterator == NULL || list == NULL) | ||
32 | return EINVAL; | ||
33 | iterator = calloc (sizeof (*iterator), 1); | ||
34 | if (iterator == NULL) | ||
35 | return ENOMEM; | ||
36 | iterator->list = list; | ||
37 | *piterator = iterator; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | void | ||
42 | iterator_destroy (iterator_t *piterator) | ||
43 | { | ||
44 | if (piterator && *piterator) | ||
45 | { | ||
46 | free (*piterator); | ||
47 | *piterator = NULL; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | int | ||
52 | iterator_first (iterator_t iterator) | ||
53 | { | ||
54 | iterator->index = 0; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | int | ||
59 | iterator_next (iterator_t iterator) | ||
60 | { | ||
61 | iterator->index++; | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | int | ||
66 | iterator_current (iterator_t iterator, void **pitem) | ||
67 | { | ||
68 | return list_get (iterator->list, iterator->index, pitem); | ||
69 | } | ||
70 | |||
71 | int | ||
72 | iterator_is_done (iterator_t iterator) | ||
73 | { | ||
74 | size_t count; | ||
75 | int status; | ||
76 | if (iterator == NULL) | ||
77 | return 1; | ||
78 | status = list_count (iterator->list, &count); | ||
79 | if (status != 0) | ||
80 | return 1; | ||
81 | return (iterator->index >= count); | ||
82 | } |
mailbox/list.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include <misc.h> | ||
26 | #include <list0.h> | ||
27 | |||
28 | int | ||
29 | list_create (list_t *plist) | ||
30 | { | ||
31 | list_t list; | ||
32 | int status; | ||
33 | if (plist == NULL) | ||
34 | return EINVAL; | ||
35 | list = calloc (sizeof (*list), 1); | ||
36 | if (list == NULL) | ||
37 | return ENOMEM; | ||
38 | status = RWLOCK_INIT (&(list->rwlock), NULL); | ||
39 | if (status != 0) | ||
40 | { | ||
41 | free (list); | ||
42 | return status; | ||
43 | } | ||
44 | list->head.next = &(list->head); | ||
45 | list->head.prev = &(list->head); | ||
46 | *plist = list; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | void | ||
51 | list_destroy (list_t *plist) | ||
52 | { | ||
53 | if (plist && *plist) | ||
54 | { | ||
55 | list_t list = *plist; | ||
56 | struct list_data *current; | ||
57 | struct list_data *previous; | ||
58 | RWLOCK_WRLOCK (&(list->rwlock)); | ||
59 | for (current = list->head.next; current != &(list->head);) | ||
60 | { | ||
61 | previous = current; | ||
62 | current = current->next; | ||
63 | free (previous); | ||
64 | } | ||
65 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
66 | RWLOCK_DESTROY (&(list->rwlock)); | ||
67 | free (list); | ||
68 | *plist = NULL; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | int | ||
73 | list_append (list_t list, void *item) | ||
74 | { | ||
75 | struct list_data *ldata; | ||
76 | struct list_data *last = list->head.prev; | ||
77 | ldata = calloc (sizeof (*ldata), 1); | ||
78 | if (ldata == NULL) | ||
79 | return ENOMEM; | ||
80 | ldata->item = item; | ||
81 | RWLOCK_WRLOCK (&(list->rwlock)); | ||
82 | ldata->next = &(list->head); | ||
83 | ldata->prev = list->head.prev; | ||
84 | last->next = ldata; | ||
85 | list->head.prev = ldata; | ||
86 | list->count++; | ||
87 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | int | ||
92 | list_prepend (list_t list, void *item) | ||
93 | { | ||
94 | struct list_data *ldata; | ||
95 | struct list_data *first = list->head.next; | ||
96 | ldata = calloc (sizeof (*ldata), 1); | ||
97 | if (ldata == NULL) | ||
98 | return ENOMEM; | ||
99 | ldata->item = item; | ||
100 | RWLOCK_WRLOCK (&(list->rwlock)); | ||
101 | ldata->prev = &(list->head); | ||
102 | ldata->next = list->head.next; | ||
103 | first->prev = ldata; | ||
104 | list->head.next = ldata; | ||
105 | list->count++; | ||
106 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | int | ||
111 | list_count (list_t list, size_t *pcount) | ||
112 | { | ||
113 | if (list == NULL || pcount == NULL) | ||
114 | return EINVAL; | ||
115 | *pcount = list->count; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | int | ||
120 | list_remove (list_t list, void *item) | ||
121 | { | ||
122 | struct list_data *current, *previous; | ||
123 | if (list == NULL) | ||
124 | return EINVAL; | ||
125 | RWLOCK_WRLOCK (&(list->rwlock)); | ||
126 | for (previous = &(list->head), current = list->head.next; | ||
127 | current != &(list->head); previous = current, current = current->next) | ||
128 | { | ||
129 | if ((int)current->item == (int)item) | ||
130 | { | ||
131 | previous->next = current->next; | ||
132 | free (current); | ||
133 | list->count--; | ||
134 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
135 | return 0; | ||
136 | } | ||
137 | } | ||
138 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
139 | return ENOENT; | ||
140 | } | ||
141 | |||
142 | int | ||
143 | list_get (list_t list, size_t index, void **pitem) | ||
144 | { | ||
145 | struct list_data *current; | ||
146 | size_t count; | ||
147 | if (list == NULL || pitem == NULL) | ||
148 | return EINVAL; | ||
149 | RWLOCK_RDLOCK (&(list->rwlock)); | ||
150 | for (current = list->head.next, count = 0; current != &(list->head); | ||
151 | current = current->next, count++) | ||
152 | { | ||
153 | if (count == index) | ||
154 | { | ||
155 | *pitem = current->item; | ||
156 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
157 | return 0; | ||
158 | } | ||
159 | } | ||
160 | RWLOCK_UNLOCK (&(list->rwlock)); | ||
161 | return ENOENT; | ||
162 | } |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
18 | #include <errno.h> | 22 | #include <errno.h> |
19 | #include <sys/types.h> | 23 | #include <sys/types.h> |
20 | #include <stdlib.h> | 24 | #include <stdlib.h> | ... | ... |
... | @@ -19,56 +19,92 @@ | ... | @@ -19,56 +19,92 @@ |
19 | #include <config.h> | 19 | #include <config.h> |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | 22 | #include <stdlib.h> |
24 | #include <string.h> | ||
25 | #include <stdarg.h> | ||
26 | #include <errno.h> | 23 | #include <errno.h> |
27 | 24 | ||
28 | #include <mailbox0.h> | ||
29 | #include <message0.h> | ||
30 | #include <mailutils/registrar.h> | ||
31 | #include <mailutils/locker.h> | 25 | #include <mailutils/locker.h> |
26 | #include <mailutils/iterator.h> | ||
27 | #include <mailutils/registrar.h> | ||
28 | #include <misc.h> | ||
29 | #include <mailbox0.h> | ||
32 | 30 | ||
33 | /* | 31 | /* The Mailbox Factory. |
34 | * Point of entry. | 32 | We create an iterator for the mailbox_register and see if any scheme |
35 | * Simple, first check if they ask for something specific; with the ID. | 33 | match, if not we check in the mailbox_manager register for a match. |
36 | * Then try to discover the type of mailbox with the url(name). | 34 | Then we call the mailbox's >url_create() to parse the URL. Last |
37 | * Then we call the appropriate mailbox_*type*_create() function. | 35 | initiliaze the concrete mailbox. */ |
38 | */ | ||
39 | int | 36 | int |
40 | mailbox_create (mailbox_t *pmbox, const char *name, int id) | 37 | mailbox_create (mailbox_t *pmbox, const char *name, int id) |
41 | { | 38 | { |
42 | int status = EINVAL; | 39 | int status = EINVAL; |
43 | struct mailbox_registrar *mreg; | 40 | record_t record = NULL; |
44 | url_t url = NULL; | 41 | mailbox_entry_t entry = NULL; |
42 | iterator_t iterator; | ||
43 | list_t list; | ||
44 | int found = 0; | ||
45 | 45 | ||
46 | (void)id; | ||
46 | if (pmbox == NULL) | 47 | if (pmbox == NULL) |
47 | return EINVAL; | 48 | return EINVAL; |
48 | 49 | ||
49 | url_create (&url, name); | 50 | /* Look in the mailbox_register, for a match */ |
50 | 51 | registrar_get_list (&list); | |
51 | /* 1st guest: if an ID is specify, shortcut */ | 52 | status = iterator_create (&iterator, list); |
52 | if (id) | 53 | if (status != 0) |
54 | return status; | ||
55 | for (iterator_first (iterator); !iterator_is_done (iterator); | ||
56 | iterator_next (iterator)) | ||
53 | { | 57 | { |
54 | status = registrar_get (id, NULL, &mreg); | 58 | iterator_current (iterator, (void **)&record); |
55 | if (status == 0) | 59 | if (record_is_scheme (record, name)) |
56 | status = mreg->_create (pmbox, name); | 60 | { |
61 | status = record_get_mailbox (record, &entry); | ||
62 | if (status == 0) | ||
63 | found = 1; | ||
64 | break; | ||
65 | } | ||
57 | } | 66 | } |
58 | /* 2nd fallback: Use the URL */ | 67 | iterator_destroy (&iterator); |
59 | else if (url != NULL) | 68 | |
69 | if (found) | ||
60 | { | 70 | { |
61 | url_get_id (url, &id); | 71 | url_t url = NULL; |
62 | status = registrar_get (id, NULL, &mreg); | 72 | mailbox_t mbox = NULL; |
63 | if (status == 0) | 73 | |
64 | status = mreg->_create (pmbox, name); | 74 | /* Allocate memory for mbox. */ |
75 | mbox = calloc (1, sizeof (*mbox)); | ||
76 | if (mbox == NULL) | ||
77 | return ENOMEM; | ||
78 | |||
79 | /* Initialize the internal lock, now so the concrete mailbox | ||
80 | could use it. */ | ||
81 | status = RWLOCK_INIT (&(mbox->rwlock), NULL); | ||
82 | if (status != 0) | ||
83 | { | ||
84 | mailbox_destroy (&mbox); | ||
85 | return status; | ||
86 | } | ||
87 | |||
88 | /* Parse the url, it may be a bad one and we should bailout if this | ||
89 | failed. */ | ||
90 | if ((status = url_create (&url, name)) != 0 | ||
91 | || (status = entry->_url_init (url)) != 0) | ||
92 | { | ||
93 | mailbox_destroy (&mbox); | ||
94 | return status; | ||
95 | } | ||
96 | mbox->url = url; | ||
97 | |||
98 | /* Create the concrete mailbox type. */ | ||
99 | status = entry->_mailbox_init (mbox); | ||
100 | if (status != 0) | ||
101 | { | ||
102 | mailbox_destroy (&mbox); | ||
103 | } | ||
104 | else | ||
105 | *pmbox = mbox; | ||
65 | } | 106 | } |
66 | 107 | ||
67 | /* set the URL */ | ||
68 | if (status == 0) | ||
69 | (*pmbox)->url = url; | ||
70 | else | ||
71 | url_destroy (&url); | ||
72 | return status; | 108 | return status; |
73 | } | 109 | } |
74 | 110 | ||
... | @@ -76,9 +112,52 @@ void | ... | @@ -76,9 +112,52 @@ void |
76 | mailbox_destroy (mailbox_t *pmbox) | 112 | mailbox_destroy (mailbox_t *pmbox) |
77 | { | 113 | { |
78 | if (pmbox && *pmbox) | 114 | if (pmbox && *pmbox) |
79 | (*pmbox)->_destroy (pmbox); | 115 | { |
116 | mailbox_t mbox = *pmbox; | ||
117 | #ifdef WITH_PTHREAD | ||
118 | pthread_rwlock_t rwlock = mbox->rwlock; | ||
119 | #endif | ||
120 | |||
121 | /* Notify the observers. */ | ||
122 | if (mbox->observable) | ||
123 | { | ||
124 | observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY); | ||
125 | observable_destroy (&(mbox->observable), mbox); | ||
126 | } | ||
127 | |||
128 | /* Call the concrete mailbox. */ | ||
129 | if (mbox->_destroy) | ||
130 | mbox->_destroy (mbox); | ||
131 | |||
132 | RWLOCK_WRLOCK (&(rwlock)); | ||
133 | |||
134 | /* Nuke the stream and close it */ | ||
135 | if (mbox->stream) | ||
136 | { | ||
137 | stream_close (mbox->stream); | ||
138 | stream_destroy (&(mbox->stream), mbox); | ||
139 | } | ||
140 | |||
141 | if (mbox->authority) | ||
142 | authority_destroy (&(mbox->authority), mbox); | ||
143 | |||
144 | if (mbox->url) | ||
145 | url_destroy (&(mbox->url)); | ||
146 | |||
147 | if (mbox->locker) | ||
148 | locker_destroy (&(mbox->locker)); | ||
149 | |||
150 | if (mbox->debug) | ||
151 | debug_destroy (&(mbox->debug), mbox); | ||
152 | |||
153 | free (mbox); | ||
154 | *pmbox = NULL; | ||
155 | RWLOCK_UNLOCK (&(rwlock)); | ||
156 | RWLOCK_DESTROY (&(rwlock)); | ||
157 | } | ||
80 | } | 158 | } |
81 | 159 | ||
160 | |||
82 | /* -------------- stub functions ------------------- */ | 161 | /* -------------- stub functions ------------------- */ |
83 | 162 | ||
84 | int | 163 | int |
... | @@ -131,14 +210,6 @@ mailbox_expunge (mailbox_t mbox) | ... | @@ -131,14 +210,6 @@ mailbox_expunge (mailbox_t mbox) |
131 | } | 210 | } |
132 | 211 | ||
133 | int | 212 | int |
134 | mailbox_num_deleted (mailbox_t mbox, size_t *num) | ||
135 | { | ||
136 | if (mbox == NULL || mbox->_num_deleted == NULL) | ||
137 | return ENOSYS; | ||
138 | return mbox->_num_deleted (mbox, num); | ||
139 | } | ||
140 | |||
141 | int | ||
142 | mailbox_is_updated (mailbox_t mbox) | 213 | mailbox_is_updated (mailbox_t mbox) |
143 | { | 214 | { |
144 | if (mbox == NULL || mbox->_is_updated == NULL) | 215 | if (mbox == NULL || mbox->_is_updated == NULL) |
... | @@ -185,21 +256,21 @@ mailbox_get_locker (mailbox_t mbox, locker_t *plocker) | ... | @@ -185,21 +256,21 @@ mailbox_get_locker (mailbox_t mbox, locker_t *plocker) |
185 | } | 256 | } |
186 | 257 | ||
187 | int | 258 | int |
188 | mailbox_set_auth (mailbox_t mbox, auth_t auth) | 259 | mailbox_set_ticket (mailbox_t mbox, ticket_t ticket) |
189 | { | 260 | { |
190 | if (mbox == NULL) | 261 | if (mbox == NULL) |
191 | return EINVAL; | 262 | return EINVAL; |
192 | mbox->auth = auth; | 263 | mbox->ticket = ticket; |
193 | return 0; | 264 | return 0; |
194 | } | 265 | } |
195 | 266 | ||
196 | int | 267 | int |
197 | mailbox_get_auth (mailbox_t mbox, auth_t *pauth) | 268 | mailbox_get_ticket (mailbox_t mbox, ticket_t *pticket) |
198 | { | 269 | { |
199 | if (mbox == NULL || pauth == NULL) | 270 | if (mbox == NULL || pticket == NULL) |
200 | return EINVAL; | 271 | return EINVAL; |
201 | if (pauth) | 272 | if (pticket) |
202 | *pauth = mbox->auth; | 273 | *pticket = mbox->ticket; |
203 | return 0; | 274 | return 0; |
204 | } | 275 | } |
205 | 276 | ||
... | @@ -223,132 +294,81 @@ mailbox_get_stream (mailbox_t mbox, stream_t *pstream) | ... | @@ -223,132 +294,81 @@ mailbox_get_stream (mailbox_t mbox, stream_t *pstream) |
223 | } | 294 | } |
224 | 295 | ||
225 | int | 296 | int |
226 | mailbox_register (mailbox_t mbox, size_t type, | 297 | mailbox_get_observable (mailbox_t mbox, observable_t *pobservable) |
227 | int (*action) (size_t type, void *arg), | ||
228 | void *arg) | ||
229 | { | 298 | { |
230 | size_t i; | 299 | if (mbox == NULL || pobservable == NULL) |
231 | event_t event; | ||
232 | |||
233 | /* FIXME: I should check for invalid types */ | ||
234 | if (mbox == NULL || action == NULL) | ||
235 | return EINVAL; | 300 | return EINVAL; |
236 | 301 | ||
237 | /* find a free spot */ | 302 | if (mbox->observable == NULL) |
238 | for (i = 0; i < mbox->event_num; i++) | ||
239 | { | 303 | { |
240 | event = &(mbox->event[i]); | 304 | int status = observable_create (&(mbox->observable), mbox); |
241 | if (event->_action == NULL) | 305 | if (status != 0) |
242 | { | 306 | return status; |
243 | event->_action = action; | ||
244 | event->type = type; | ||
245 | event->arg = arg; | ||
246 | return 0; | ||
247 | } | ||
248 | } | 307 | } |
249 | 308 | *pobservable = mbox->observable; | |
250 | /* a new one */ | ||
251 | event = realloc (mbox->event, (mbox->event_num + 1) * sizeof (*event)); | ||
252 | if (event == NULL) | ||
253 | return ENOMEM; | ||
254 | |||
255 | mbox->event = event; | ||
256 | event[mbox->event_num]._action = action; | ||
257 | event[mbox->event_num].type = type; | ||
258 | event[mbox->event_num].arg = arg; | ||
259 | mbox->event_num++; | ||
260 | return 0; | 309 | return 0; |
261 | } | 310 | } |
262 | 311 | ||
263 | int | 312 | int |
264 | mailbox_deregister (mailbox_t mbox, void *action) | 313 | mailbox_set_debug (mailbox_t mbox, debug_t debug) |
265 | { | 314 | { |
266 | size_t i; | 315 | if (mbox == NULL) |
267 | event_t event; | 316 | return EINVAL; |
268 | 317 | debug_destroy (&(mbox->debug), mbox); | |
269 | for (i = 0; i < mbox->event_num; i++) | 318 | mbox->debug = debug; |
270 | { | 319 | return 0; |
271 | event = &(mbox->event[i]); | ||
272 | if ((int)event->_action == (int)action) | ||
273 | { | ||
274 | event->type = 0; | ||
275 | event->_action = NULL; | ||
276 | event->arg = NULL; | ||
277 | return 0; | ||
278 | } | ||
279 | } | ||
280 | return ENOENT; | ||
281 | } | 320 | } |
282 | 321 | ||
283 | int | 322 | int |
284 | mailbox_notification (mailbox_t mbox, size_t type) | 323 | mailbox_get_debug (mailbox_t mbox, debug_t *pdebug) |
285 | { | 324 | { |
286 | size_t i; | 325 | if (mbox == NULL || pdebug == NULL) |
287 | event_t event; | 326 | return EINVAL; |
288 | int status = 0; | 327 | if (mbox->debug == NULL) |
289 | for (i = 0; i < mbox->event_num; i++) | ||
290 | { | 328 | { |
291 | event = &(mbox->event[i]); | 329 | int status = debug_create (&(mbox->debug), mbox); |
292 | if ((event->_action) && (event->type & type)) | 330 | if (status != 0) |
293 | status |= event->_action (type, event->arg); | 331 | return status; |
294 | } | 332 | } |
295 | return status; | 333 | *pdebug = mbox->debug; |
296 | } | ||
297 | |||
298 | int | ||
299 | mailbox_set_debug_level (mailbox_t mbox, size_t level) | ||
300 | { | ||
301 | if (mbox == NULL) | ||
302 | return EINVAL; | ||
303 | mbox->debug_level = level; | ||
304 | return 0; | 334 | return 0; |
305 | } | 335 | } |
306 | 336 | ||
337 | /* Mailbox Internal Locks. Put the name of the functions in parenteses To make | ||
338 | sure it will not be redefine by a macro. If the flags was non-blocking we | ||
339 | should not block on the lock, so we try with pthread_rwlock_try*lock(). */ | ||
307 | int | 340 | int |
308 | mailbox_get_debug_level (mailbox_t mbox, size_t *plevel) | 341 | (mailbox_rdlock) (mailbox_t mbox) |
309 | { | 342 | { |
310 | if (mbox == NULL || plevel == NULL) | 343 | #ifdef WITH_PTHREAD |
311 | return EINVAL; | 344 | int err = (mbox->flags & MU_STREAM_NONBLOCK) ? |
312 | *plevel = mbox->debug_level; | 345 | RWLOCK_TRYRDLOCK (&(mbox->rwlock)) : |
346 | RWLOCK_RDLOCK (&(mbox->rwlock)) ; | ||
347 | if (err != 0 && err != EDEADLK) | ||
348 | return err; | ||
349 | #endif | ||
313 | return 0; | 350 | return 0; |
314 | } | 351 | } |
315 | 352 | ||
316 | int | 353 | int |
317 | mailbox_set_debug_print (mailbox_t mbox, int (*debug_print) | 354 | (mailbox_wrlock) (mailbox_t mbox) |
318 | (void *arg, const char *, size_t), void *arg) | ||
319 | { | 355 | { |
320 | if (mbox == NULL) | 356 | #ifdef WITH_PTHREAD |
321 | return EINVAL; | 357 | int err = (mbox->flags & MU_STREAM_NONBLOCK) ? |
322 | mbox->debug_print = debug_print; | 358 | RWLOCK_TRYWRLOCK (&(mbox->rwlock)) : |
323 | mbox->debug_arg = arg; | 359 | RWLOCK_WRLOCK (&(mbox->rwlock)) ; |
360 | if (err != 0 && err != EDEADLK) | ||
361 | return err; | ||
362 | #endif | ||
324 | return 0; | 363 | return 0; |
325 | } | 364 | } |
326 | 365 | ||
327 | int | 366 | int |
328 | mailbox_debug (mailbox_t mbox, int level, const char *fmt, ...) | 367 | (mailbox_unlock) (mailbox_t mbox) |
329 | { | 368 | { |
330 | va_list ap; | 369 | #ifdef WITH_PTHREAD |
331 | if (mbox == NULL) | 370 | return RWLOCK_UNLOCK (&(mbox->rwlock)); |
332 | return EINVAL; | 371 | #else |
333 | |||
334 | if (!(mbox->debug_level & level)) | ||
335 | return 0; | ||
336 | |||
337 | va_start (ap, fmt); | ||
338 | if (mbox->debug_print) | ||
339 | { | ||
340 | int writen; | ||
341 | if (mbox->debug_buffer == NULL) | ||
342 | { | ||
343 | mbox->debug_bufsize = 255; | ||
344 | mbox->debug_buffer = malloc (mbox->debug_bufsize); | ||
345 | if (mbox->debug_buffer) | ||
346 | return ENOMEM; } | ||
347 | writen = vsnprintf (mbox->debug_buffer, mbox->debug_bufsize, fmt, ap); | ||
348 | mbox->debug_print (mbox->debug_arg, mbox->debug_buffer, writen); | ||
349 | } | ||
350 | else | ||
351 | vfprintf (stderr, fmt, ap); | ||
352 | va_end (ap); | ||
353 | return 0; | 372 | return 0; |
373 | #endif | ||
354 | } | 374 | } | ... | ... |
... | @@ -15,402 +15,260 @@ | ... | @@ -15,402 +15,260 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | #include <config.h> | ||
20 | #endif | ||
21 | |||
18 | #include <stdio.h> | 22 | #include <stdio.h> |
19 | #include <sys/types.h> | ||
20 | #include <sys/socket.h> | ||
21 | #include <netinet/in.h> | ||
22 | #include <netdb.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | #include <sys/select.h> | ||
26 | #include <errno.h> | ||
27 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <string.h> | ||
28 | #include <stdarg.h> | 25 | #include <stdarg.h> |
29 | #include <fcntl.h> | 26 | #include <errno.h> |
30 | #include <ctype.h> | ||
31 | 27 | ||
28 | #include <mailutils/registrar.h> | ||
29 | #include <mailutils/iterator.h> | ||
30 | #include <misc.h> | ||
32 | #include <mailer0.h> | 31 | #include <mailer0.h> |
33 | 32 | ||
34 | int _mailer_sock_connect(char *host, int port); | 33 | /* |
35 | char *_mailer_find_mailbox(char *addr); | 34 | */ |
36 | int _mailer_send_command(mailer_t ml, message_t msg, int cmd); | ||
37 | char *nb_fgets(char *buf, int size, int s); | ||
38 | const char *nb_fprintf(int s, const char *format, ...); | ||
39 | static int _mailer_rctp(mailer_t ml, char *str); | ||
40 | |||
41 | #define nb_read read | ||
42 | #define nb_write write | ||
43 | #define BUFFSIZE 4096 | ||
44 | |||
45 | int | 35 | int |
46 | mailer_create(mailer_t *pml, message_t msg) | 36 | mailer_create (mailer_t *pmailer, const char *name, int id) |
47 | { | 37 | { |
48 | mailer_t ml; | 38 | int status = EINVAL; |
49 | 39 | record_t record = NULL; | |
50 | (void)msg; | 40 | mailer_entry_t entry = NULL; |
51 | if (!pml) | 41 | list_t list = NULL; |
52 | return EINVAL; | 42 | iterator_t iterator; |
43 | int found; | ||
44 | |||
45 | (void)id; | ||
46 | if (pmailer == NULL) | ||
47 | return EINVAL; | ||
48 | |||
49 | registrar_get_list (&list); | ||
50 | status = iterator_create (&iterator, list); | ||
51 | if (status != 0) | ||
52 | return status; | ||
53 | for (iterator_first (iterator); !iterator_is_done (iterator); | ||
54 | iterator_next (iterator)) | ||
55 | { | ||
56 | iterator_current (iterator, (void **)&record); | ||
57 | if (record_is_scheme (record, name)) | ||
58 | { | ||
59 | status = record_get_mailer (record, &entry); | ||
60 | if (status == 0) | ||
61 | found = 1; | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | iterator_destroy (&iterator); | ||
53 | 66 | ||
54 | ml = calloc (1, sizeof (*ml)); | 67 | if (found) |
55 | if (ml == NULL) | 68 | { |
56 | return (ENOMEM); | 69 | url_t url = NULL; |
70 | mailer_t mailer = NULL; | ||
71 | |||
72 | /* Allocate memory for mailer. */ | ||
73 | mailer = calloc (1, sizeof (*mailer)); | ||
74 | if (mailer == NULL) | ||
75 | return ENOMEM; | ||
76 | |||
77 | RWLOCK_INIT (&(mailer->rwlock), NULL); | ||
78 | |||
79 | /* Parse the url, it may be a bad one and we should bailout if this | ||
80 | failed. */ | ||
81 | if ((status = url_create (&url, name)) != 0 | ||
82 | || (status = entry->_url_init (url)) != 0) | ||
83 | { | ||
84 | mailer_destroy (&mailer); | ||
85 | return status; | ||
86 | } | ||
87 | mailer->url = url; | ||
57 | 88 | ||
58 | *pml = ml; | 89 | status = entry->_mailer_init (mailer); |
90 | if (status != 0) | ||
91 | { | ||
92 | mailer_destroy (&mailer); | ||
93 | } | ||
94 | else | ||
95 | *pmailer = mailer; | ||
96 | } | ||
59 | 97 | ||
60 | return (0); | 98 | return status; |
61 | } | 99 | } |
62 | 100 | ||
63 | int | 101 | void |
64 | mailer_destroy(mailer_t *pml) | 102 | mailer_destroy (mailer_t *pmailer) |
65 | { | 103 | { |
66 | mailer_t ml; | 104 | if (pmailer && *pmailer) |
67 | 105 | { | |
68 | if (!pml) | 106 | mailer_t mailer = *pmailer; |
69 | return (EINVAL); | 107 | #ifdef WITH_PTHREAD |
70 | ml = *pml; | 108 | pthread_rwlock_t rwlock = mailer->rwlock; |
71 | if (ml->hostname) | 109 | #endif |
72 | free(ml->hostname); | 110 | if (mailer->observable) |
73 | mailer_disconnect(ml); | 111 | { |
74 | free(ml); | 112 | observable_notify (mailer->observable, MU_EVT_MAILER_DESTROY); |
75 | *pml = NULL; | 113 | observable_destroy (&(mailer->observable), mailer); |
76 | 114 | } | |
77 | return (0); | 115 | /* Call the object. */ |
78 | } | 116 | if (mailer->_destroy) |
117 | mailer->_destroy (mailer); | ||
79 | 118 | ||
80 | int | 119 | RWLOCK_WRLOCK (&rwlock); |
81 | mailer_connect(mailer_t ml, char *host) | ||
82 | { | ||
83 | if (!ml || !host) | ||
84 | return (EINVAL); | ||
85 | 120 | ||
86 | if ((ml->socket = _mailer_sock_connect(host, 25)) < 0) | 121 | if (mailer->stream) |
87 | return (-1); | ||
88 | do | ||
89 | { | 122 | { |
90 | nb_fgets(ml->line_buf, MAILER_LINE_BUF_SIZE, ml->socket); /* read header line */ | 123 | stream_close (mailer->stream); |
91 | } while ( strlen(ml->line_buf) > 4 && *(ml->line_buf+3) == '-'); | 124 | stream_destroy (&(mailer->stream), mailer); |
92 | 125 | } | |
93 | return (0); | 126 | if (mailer->url) |
127 | url_destroy (&(mailer->url)); | ||
128 | if (mailer->debug) | ||
129 | debug_destroy (&(mailer->debug), mailer); | ||
130 | |||
131 | free (mailer); | ||
132 | *pmailer = NULL; | ||
133 | RWLOCK_UNLOCK (&rwlock); | ||
134 | RWLOCK_DESTROY (&rwlock); | ||
135 | } | ||
94 | } | 136 | } |
95 | 137 | ||
138 | |||
139 | /* -------------- stub functions ------------------- */ | ||
140 | |||
96 | int | 141 | int |
97 | mailer_disconnect(mailer_t ml) | 142 | mailer_open (mailer_t mailer, int flag) |
98 | { | 143 | { |
99 | if (!ml || (ml->socket != -1)) | 144 | if (mailer == NULL || mailer->_open == NULL) |
100 | return (EINVAL); | 145 | return ENOSYS; |
101 | 146 | return mailer->_open (mailer, flag); | |
102 | close(ml->socket); | ||
103 | return (0); | ||
104 | } | 147 | } |
105 | 148 | ||
106 | int | 149 | int |
107 | mailer_send_header(mailer_t ml, message_t msg) | 150 | mailer_close (mailer_t mailer) |
108 | { | 151 | { |
109 | header_t hdr; | 152 | if (mailer == NULL || mailer->_close == NULL) |
110 | char buf[64]; | 153 | return ENOSYS; |
111 | 154 | return mailer->_close (mailer); | |
112 | if (!ml || !msg || (ml->socket == -1)) | ||
113 | return (EINVAL); | ||
114 | |||
115 | if (!ml->hostname) | ||
116 | { | ||
117 | if (gethostname(buf, 64) < 0) | ||
118 | return (-1); | ||
119 | ml->hostname = strdup(buf); | ||
120 | } | ||
121 | |||
122 | if (_mailer_send_command(ml, msg, MAILER_HELO) != 0) | ||
123 | return (-1); | ||
124 | if (_mailer_send_command(ml, msg, MAILER_MAIL) != 0) | ||
125 | return (-1); | ||
126 | if (_mailer_send_command(ml, msg, MAILER_RCPT) != 0) | ||
127 | return (-1); | ||
128 | if (_mailer_send_command(ml, msg, MAILER_DATA) != 0) | ||
129 | return (-1); | ||
130 | |||
131 | message_get_header(msg, &hdr); | ||
132 | header_get_stream(hdr, &(ml->stream)); | ||
133 | |||
134 | ml->state = MAILER_STATE_HDR; | ||
135 | |||
136 | return (0); | ||
137 | } | 155 | } |
138 | 156 | ||
157 | /* messages */ | ||
139 | int | 158 | int |
140 | mailer_send_message(mailer_t ml, message_t msg) | 159 | mailer_send_message (mailer_t mailer, const char *from, const char *rcpt, |
160 | int dsn, message_t msg) | ||
141 | { | 161 | { |
142 | int status, data_len = 0; | 162 | if (mailer == NULL || mailer->_send_message == NULL) |
143 | size_t consumed = 0, len = 0; | 163 | return ENOSYS; |
144 | char *data, *p, *q; | 164 | return mailer->_send_message (mailer, from, rcpt, dsn, msg); |
145 | 165 | } | |
146 | if (!ml || !msg || (ml->socket == -1)) | ||
147 | return (EINVAL); | ||
148 | |||
149 | // alloca | ||
150 | if (!(data = alloca(MAILER_LINE_BUF_SIZE))) | ||
151 | return (ENOMEM); | ||
152 | |||
153 | memset(data, 0, 1000); | ||
154 | if ((status = stream_read(ml->stream, data, MAILER_LINE_BUF_SIZE, ml->offset, &len)) != 0) | ||
155 | return (-1); | ||
156 | |||
157 | if ((len == 0) && (ml->state == MAILER_STATE_HDR)) | ||
158 | { | ||
159 | ml->state = MAILER_STATE_MSG; | ||
160 | ml->offset = 0; | ||
161 | message_get_stream(msg, &(ml->stream)); | ||
162 | return (1); | ||
163 | } | ||
164 | else if (len == 0) | ||
165 | { | ||
166 | strcpy(ml->line_buf, "\r\n.\r\n"); | ||
167 | consumed = strlen(data); | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | p = data; | ||
172 | q = ml->line_buf; | ||
173 | memset(ml->line_buf, 0, MAILER_LINE_BUF_SIZE); | ||
174 | while (consumed < len) | ||
175 | { | ||
176 | // RFC821: if the first character on a line is a '.' you must add an | ||
177 | // extra '.' to the line which will get stipped off at the other end | ||
178 | if ((*p == '.') && (ml->last_char == '\n')) | ||
179 | ml->add_dot = 1; | ||
180 | ml->last_char = *p; | ||
181 | *q++ = *p++; // store the character | ||
182 | data_len++; // increase the length by 1 | ||
183 | consumed++; | ||
184 | if (((MAILER_LINE_BUF_SIZE - data_len) > 1) && (ml->add_dot == 1)) | ||
185 | { | ||
186 | *q++ = '.'; | ||
187 | data_len++; | ||
188 | ml->add_dot = 0; | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | ml->offset += consumed; | ||
194 | nb_fprintf(ml->socket, "%s\r\n", ml->line_buf); | ||
195 | |||
196 | if (len == 0) | ||
197 | { | ||
198 | ml->state = MAILER_STATE_COMPLETE; | ||
199 | return (0); | ||
200 | } | ||
201 | 166 | ||
202 | return (consumed); | 167 | int |
168 | mailer_set_stream (mailer_t mailer, stream_t stream) | ||
169 | { | ||
170 | if (mailer == NULL) | ||
171 | return EINVAL; | ||
172 | mailer->stream = stream; | ||
173 | return 0; | ||
203 | } | 174 | } |
204 | 175 | ||
205 | int | 176 | int |
206 | _mailer_sock_connect(char *host, int port) | 177 | mailer_get_stream (mailer_t mailer, stream_t *pstream) |
207 | { | 178 | { |
208 | struct sockaddr_in saddr; | 179 | if (mailer == NULL || pstream == NULL) |
209 | struct hostent *hp; | 180 | return EINVAL; |
210 | int s; | 181 | if (pstream) |
211 | 182 | *pstream = mailer->stream; | |
212 | memset(&saddr, 0, sizeof(struct sockaddr_in)); | 183 | return 0; |
213 | saddr.sin_family = AF_INET; | ||
214 | saddr.sin_port = htons(port); | ||
215 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) | ||
216 | return (-1); | ||
217 | if ((hp = gethostbyname(host)) == 0) | ||
218 | return (-1); | ||
219 | memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); | ||
220 | if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) == 0) | ||
221 | return (s); | ||
222 | close(s); | ||
223 | |||
224 | return (-1); | ||
225 | } | 184 | } |
226 | 185 | ||
227 | char * | 186 | int |
228 | _mailer_find_mailbox(char *addr) | 187 | mailer_attach (mailer_t mailer, observer_t observer) |
229 | { | 188 | { |
230 | char *p, *c; | 189 | /* FIXME: I should check for invalid types */ |
231 | p = addr; | 190 | if (mailer == NULL || observer == NULL) |
232 | if ( (c = strchr( p, '<')) != 0) | 191 | return EINVAL; |
233 | { | 192 | |
234 | p = c+1; | 193 | if (mailer->observable == NULL) |
235 | if ( (c = strchr( p, '>')) ) | ||
236 | *c = '\0'; | ||
237 | } | ||
238 | else if ( (c = strchr( p, '(' )) != 0 ) | ||
239 | { | 194 | { |
240 | --c; | 195 | int status = observable_create (&(mailer->observable), mailer); |
241 | while ( c > p && *c && isspace( *c ) ) { | 196 | if (status != 0) |
242 | *c = '\0'; | 197 | return status; |
243 | --c; | ||
244 | } | ||
245 | } | 198 | } |
246 | return p; | 199 | return observable_attach (mailer->observable, observer); |
247 | } | 200 | } |
248 | 201 | ||
249 | static int | 202 | int |
250 | _mailer_rctp(mailer_t ml, char *str) | 203 | mailer_detach (mailer_t mailer, observer_t observer) |
251 | { | 204 | { |
252 | char *p, *c = NULL, *q = NULL; | 205 | /* FIXME: I should check for invalid types */ |
253 | 206 | if (mailer == NULL || observer == NULL) | |
254 | for (q = p = str; q && *p; p = q+1) | 207 | return EINVAL; |
255 | { | 208 | if (mailer->observable == NULL) |
256 | if ( (q = strchr( p, ',')) ) | 209 | return 0; |
257 | *q = '\0'; | 210 | return observable_detach (mailer->observable, observer); |
258 | while ( p && *p && isspace( *p ) ) | ||
259 | p++; | ||
260 | c = strdup(p); | ||
261 | p = _mailer_find_mailbox(c); | ||
262 | nb_fprintf(ml->socket, "RCPT TO:<%s>\r\n", p); | ||
263 | free(c); | ||
264 | nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket); | ||
265 | if (strncmp(ml->line_buf, "250", 3)) | ||
266 | return (-strtol(ml->line_buf, 0, 10)); | ||
267 | } | ||
268 | return (0); | ||
269 | } | 211 | } |
270 | 212 | ||
271 | int | 213 | int |
272 | _mailer_send_command(mailer_t ml, message_t msg, int cmd) | 214 | mailer_set_debug (mailer_t mailer, debug_t debug) |
273 | { | 215 | { |
274 | header_t hdr; | 216 | if (mailer == NULL) |
275 | char *p; | 217 | return EINVAL; |
276 | char str[128]; | 218 | debug_destroy (&(mailer->debug), mailer); |
277 | size_t str_len; | 219 | mailer->debug = debug; |
278 | const char *success = "250"; | 220 | return 0; |
279 | 221 | } | |
280 | switch (cmd) | ||
281 | { | ||
282 | case MAILER_HELO: | ||
283 | nb_fprintf(ml->socket, "HELO %s\r\n", ml->hostname); | ||
284 | break; | ||
285 | case MAILER_MAIL: | ||
286 | message_get_header(msg, &hdr); | ||
287 | header_get_value(hdr, MU_HEADER_FROM, str, 128, &str_len); | ||
288 | str[str_len] = '\0'; | ||
289 | p = _mailer_find_mailbox(str); | ||
290 | nb_fprintf(ml->socket, "MAIL From: %s\r\n", p); | ||
291 | break; | ||
292 | case MAILER_RCPT: | ||
293 | message_get_header(msg, &hdr); | ||
294 | header_get_value(hdr, MU_HEADER_TO, str, 128, &str_len); | ||
295 | str[str_len] = '\0'; | ||
296 | if (_mailer_rctp(ml, str) == -1) | ||
297 | return (-1); | ||
298 | header_get_value(hdr, MU_HEADER_CC, str, 128, &str_len); | ||
299 | str[str_len] = '\0'; | ||
300 | if (_mailer_rctp(ml, str) == -1) | ||
301 | return (-1); | ||
302 | return (0); | ||
303 | break; | ||
304 | case MAILER_DATA: | ||
305 | nb_fprintf(ml->socket, "DATA\r\n"); | ||
306 | success = "354"; | ||
307 | break; | ||
308 | case MAILER_RSET: | ||
309 | nb_fprintf(ml->socket, "RSET\r\n"); | ||
310 | break; | ||
311 | case MAILER_QUIT: | ||
312 | nb_fprintf(ml->socket, "QUIT\r\n"); | ||
313 | success = "221"; | ||
314 | break; | ||
315 | } | ||
316 | 222 | ||
317 | nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket); | 223 | int |
318 | if (strncmp(ml->line_buf, success, 3) == 0) | 224 | mailer_get_debug (mailer_t mailer, debug_t *pdebug) |
319 | return (0); | 225 | { |
320 | else | 226 | if (mailer == NULL || pdebug == NULL) |
321 | return (-strtol(ml->line_buf, 0, 10)); | 227 | return EINVAL; |
228 | if (mailer->debug == NULL) | ||
229 | { | ||
230 | int status = debug_create (&(mailer->debug), mailer); | ||
231 | if (status != 0) | ||
232 | return status; | ||
233 | } | ||
234 | *pdebug = mailer->debug; | ||
235 | return 0; | ||
322 | } | 236 | } |
323 | 237 | ||
324 | char * | 238 | /* Mailer Internal Locks. Put the name of the functions in parenteses To make |
325 | nb_fgets( char *buf, int size, int s ) | 239 | they will not be redefine by the macro. If the flags was non-blocking we |
240 | should not block on the lock, so we try with pthread_rwlock_try*lock(). */ | ||
241 | int | ||
242 | (mailer_wrlock) (mailer_t mailer) | ||
326 | { | 243 | { |
327 | static char *buffer[25]; | 244 | #ifdef WITH_PTHREAD |
328 | char *p, *b, *d; | 245 | int err = (mailer->flags & MU_STREAM_NONBLOCK) ? |
329 | int bytes, i; | 246 | RWLOCK_TRYWRLOCK (&(mailer->rwlock)) : |
330 | int flags; | 247 | RWLOCK_WRLOCK (&(mailer->rwlock)) ; |
331 | 248 | if (err != 0 && err != EDEADLK) | |
332 | if ( !buffer[s] && !( buffer[s] = calloc( BUFFSIZE+1, 1 ) ) ) | 249 | return err; |
333 | return 0; | 250 | #endif |
334 | bytes = i = strlen( p = b = buffer[s] ); | 251 | return 0; |
335 | *( d = buf ) = '\0'; | 252 | } |
336 | for ( ; i-- > 0; p++ ) | 253 | int |
337 | { | 254 | (mailer_rdlock) (mailer_t mailer) |
338 | if ( *p == '\n' ) | 255 | { |
339 | { | 256 | #ifdef WITH_PTHREAD |
340 | char c = *( p+1 ); | 257 | int err = (mailer->flags & MU_STREAM_NONBLOCK) ? |
341 | 258 | RWLOCK_TRYRDLOCK (&(mailer->rwlock)) : | |
342 | *( p+1 ) = '\0'; | 259 | RWLOCK_RDLOCK (&(mailer->rwlock)) ; |
343 | strcat( d, b ); | 260 | if (err != 0 && err != EDEADLK) |
344 | *( p+1 ) = c; | 261 | return err; |
345 | memmove( b, p+1, i+1 ); | 262 | #endif |
346 | return buf; | 263 | return 0; |
347 | } | ||
348 | } | ||
349 | flags = fcntl( s, F_GETFL ); | ||
350 | fcntl( s, F_SETFL, O_NONBLOCK ); | ||
351 | while ( bytes <= size ) | ||
352 | { | ||
353 | fd_set fds; | ||
354 | |||
355 | FD_ZERO( &fds ); | ||
356 | FD_SET( s, &fds ); | ||
357 | select( s+1, &fds, 0, 0, 0 ); /* we really don't care what it returns */ | ||
358 | if ( ( i = nb_read( s, p, BUFFSIZE - bytes ) ) == -1 ) | ||
359 | { | ||
360 | *b = '\0'; | ||
361 | return 0; | ||
362 | } | ||
363 | else if ( i == 0 ) | ||
364 | { | ||
365 | *( p+1 ) = '\0'; | ||
366 | strcat( d, b ); | ||
367 | *b = '\0'; | ||
368 | fcntl( s, F_SETFL, flags ); | ||
369 | return strlen( buf ) ? buf : 0; | ||
370 | } | ||
371 | *( p+i ) = '\0'; | ||
372 | bytes += i; | ||
373 | for ( ; i-- > 0; p++ ) | ||
374 | { | ||
375 | if ( *p == '\n' ) | ||
376 | { | ||
377 | char c = *( p+1 ); | ||
378 | |||
379 | *( p+1 ) = '\0'; | ||
380 | strcat( d, b ); | ||
381 | *( p+1 ) = c; | ||
382 | memmove( b, p+1, i+1 ); | ||
383 | fcntl( s, F_SETFL, flags ); | ||
384 | return buf; | ||
385 | } | ||
386 | } | ||
387 | if ( bytes == BUFFSIZE ) | ||
388 | { | ||
389 | memcpy( d, b, BUFFSIZE ); | ||
390 | d += BUFFSIZE; | ||
391 | size -= BUFFSIZE; | ||
392 | bytes = 0; | ||
393 | *( p = b ) = '\0'; | ||
394 | } | ||
395 | } | ||
396 | memcpy( d, b, size ); | ||
397 | memmove( b, b+size, strlen( b+size )+1 ); | ||
398 | fcntl( s, F_SETFL, flags ); | ||
399 | return buf; | ||
400 | } | 264 | } |
401 | 265 | ||
402 | const char * | 266 | int |
403 | nb_fprintf( int s, const char *format, ... ) | 267 | (mailer_unlock) (mailer_t mailer) |
404 | { | 268 | { |
405 | char buf[MAILER_LINE_BUF_SIZE]; | 269 | #ifdef WITH_PTHREAD |
406 | va_list vl; | 270 | return RWLOCK_UNLOCK (&(mailer->rwlock)); |
407 | int i; | 271 | #else |
408 | 272 | return 0; | |
409 | va_start( vl, format ); | 273 | #endif |
410 | vsprintf( buf, format, vl ); | ||
411 | va_end( vl ); | ||
412 | i = strlen( buf ); | ||
413 | if ( nb_write( s, buf, i ) != i ) | ||
414 | return 0; | ||
415 | return format; | ||
416 | } | 274 | } | ... | ... |
... | @@ -15,6 +15,9 @@ | ... | @@ -15,6 +15,9 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
18 | 21 | ||
19 | #include <errno.h> | 22 | #include <errno.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
... | @@ -26,12 +29,12 @@ | ... | @@ -26,12 +29,12 @@ |
26 | #include <fcntl.h> | 29 | #include <fcntl.h> |
27 | #include <unistd.h> | 30 | #include <unistd.h> |
28 | 31 | ||
29 | #include <stream0.h> | 32 | #include <mailutils/stream.h> |
30 | 33 | ||
31 | #ifdef _POSIX_MAPPED_FILES | 34 | #ifdef _POSIX_MAPPED_FILES |
32 | |||
33 | #include <sys/mman.h> | 35 | #include <sys/mman.h> |
34 | 36 | ||
37 | |||
35 | struct _mapfile_stream | 38 | struct _mapfile_stream |
36 | { | 39 | { |
37 | int fd; | 40 | int fd; |
... | @@ -43,7 +46,7 @@ struct _mapfile_stream | ... | @@ -43,7 +46,7 @@ struct _mapfile_stream |
43 | static void | 46 | static void |
44 | _mapfile_destroy (stream_t stream) | 47 | _mapfile_destroy (stream_t stream) |
45 | { | 48 | { |
46 | struct _mapfile_stream *mfs = stream->owner; | 49 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
47 | 50 | ||
48 | if (mfs && mfs->ptr) | 51 | if (mfs && mfs->ptr) |
49 | { | 52 | { |
... | @@ -57,7 +60,7 @@ static int | ... | @@ -57,7 +60,7 @@ static int |
57 | _mapfile_read (stream_t stream, char *optr, size_t osize, | 60 | _mapfile_read (stream_t stream, char *optr, size_t osize, |
58 | off_t offset, size_t *nbytes) | 61 | off_t offset, size_t *nbytes) |
59 | { | 62 | { |
60 | struct _mapfile_stream *mfs = stream->owner; | 63 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
61 | size_t n; | 64 | size_t n; |
62 | 65 | ||
63 | if (mfs == NULL || mfs->ptr == NULL) | 66 | if (mfs == NULL || mfs->ptr == NULL) |
... | @@ -82,7 +85,7 @@ static int | ... | @@ -82,7 +85,7 @@ static int |
82 | _mapfile_readline (stream_t stream, char *optr, size_t osize, | 85 | _mapfile_readline (stream_t stream, char *optr, size_t osize, |
83 | off_t offset, size_t *nbytes) | 86 | off_t offset, size_t *nbytes) |
84 | { | 87 | { |
85 | struct _mapfile_stream *mfs = stream->owner; | 88 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
86 | char *nl; | 89 | char *nl; |
87 | size_t n = 0; | 90 | size_t n = 0; |
88 | 91 | ||
... | @@ -111,7 +114,7 @@ static int | ... | @@ -111,7 +114,7 @@ static int |
111 | _mapfile_write (stream_t stream, const char *iptr, size_t isize, | 114 | _mapfile_write (stream_t stream, const char *iptr, size_t isize, |
112 | off_t offset, size_t *nbytes) | 115 | off_t offset, size_t *nbytes) |
113 | { | 116 | { |
114 | struct _mapfile_stream *mfs = stream->owner; | 117 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
115 | 118 | ||
116 | if (mfs == NULL || mfs->ptr == NULL) | 119 | if (mfs == NULL || mfs->ptr == NULL) |
117 | return EINVAL; | 120 | return EINVAL; |
... | @@ -151,7 +154,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize, | ... | @@ -151,7 +154,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize, |
151 | static int | 154 | static int |
152 | _mapfile_truncate (stream_t stream, off_t len) | 155 | _mapfile_truncate (stream_t stream, off_t len) |
153 | { | 156 | { |
154 | struct _mapfile_stream *mfs = stream->owner; | 157 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
155 | if (mfs == NULL || mfs->ptr == NULL) | 158 | if (mfs == NULL || mfs->ptr == NULL) |
156 | return EINVAL; | 159 | return EINVAL; |
157 | /* Remap. */ | 160 | /* Remap. */ |
... | @@ -178,7 +181,7 @@ _mapfile_truncate (stream_t stream, off_t len) | ... | @@ -178,7 +181,7 @@ _mapfile_truncate (stream_t stream, off_t len) |
178 | static int | 181 | static int |
179 | _mapfile_size (stream_t stream, off_t *psize) | 182 | _mapfile_size (stream_t stream, off_t *psize) |
180 | { | 183 | { |
181 | struct _mapfile_stream *mfs = stream->owner; | 184 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
182 | struct stat stbuf; | 185 | struct stat stbuf; |
183 | 186 | ||
184 | if (mfs == NULL || mfs->ptr == NULL) | 187 | if (mfs == NULL || mfs->ptr == NULL) |
... | @@ -194,7 +197,7 @@ _mapfile_size (stream_t stream, off_t *psize) | ... | @@ -194,7 +197,7 @@ _mapfile_size (stream_t stream, off_t *psize) |
194 | static int | 197 | static int |
195 | _mapfile_flush (stream_t stream) | 198 | _mapfile_flush (stream_t stream) |
196 | { | 199 | { |
197 | struct _mapfile_stream *mfs = stream->owner; | 200 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
198 | if (mfs == NULL) | 201 | if (mfs == NULL) |
199 | return EINVAL; | 202 | return EINVAL; |
200 | return msync (mfs->ptr, mfs->size, MS_SYNC); | 203 | return msync (mfs->ptr, mfs->size, MS_SYNC); |
... | @@ -203,7 +206,7 @@ _mapfile_flush (stream_t stream) | ... | @@ -203,7 +206,7 @@ _mapfile_flush (stream_t stream) |
203 | static int | 206 | static int |
204 | _mapfile_get_fd (stream_t stream, int *pfd) | 207 | _mapfile_get_fd (stream_t stream, int *pfd) |
205 | { | 208 | { |
206 | struct _mapfile_stream *mfs = stream->owner; | 209 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
207 | if (mfs == NULL) | 210 | if (mfs == NULL) |
208 | return EINVAL; | 211 | return EINVAL; |
209 | if (pfd) | 212 | if (pfd) |
... | @@ -214,7 +217,7 @@ _mapfile_get_fd (stream_t stream, int *pfd) | ... | @@ -214,7 +217,7 @@ _mapfile_get_fd (stream_t stream, int *pfd) |
214 | static int | 217 | static int |
215 | _mapfile_close (stream_t stream) | 218 | _mapfile_close (stream_t stream) |
216 | { | 219 | { |
217 | struct _mapfile_stream *mfs = stream->owner; | 220 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
218 | int err = 0; | 221 | int err = 0; |
219 | if (mfs && mfs->ptr) | 222 | if (mfs && mfs->ptr) |
220 | { | 223 | { |
... | @@ -231,7 +234,7 @@ _mapfile_close (stream_t stream) | ... | @@ -231,7 +234,7 @@ _mapfile_close (stream_t stream) |
231 | static int | 234 | static int |
232 | _mapfile_open (stream_t stream, const char *filename, int port, int flags) | 235 | _mapfile_open (stream_t stream, const char *filename, int port, int flags) |
233 | { | 236 | { |
234 | struct _mapfile_stream *mfs = stream->owner; | 237 | struct _mapfile_stream *mfs = stream_get_owner (stream); |
235 | int mflag, flg; | 238 | int mflag, flg; |
236 | struct stat st; | 239 | struct stat st; |
237 | 240 | ||
... | @@ -277,7 +280,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags) | ... | @@ -277,7 +280,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags) |
277 | return err; | 280 | return err; |
278 | } | 281 | } |
279 | mfs->flags = mflag; | 282 | mfs->flags = mflag; |
280 | stream_set_flags (stream, flags |MU_STREAM_NO_CHECK, mfs); | 283 | stream_set_flags (stream, flags |MU_STREAM_NO_CHECK); |
281 | return 0; | 284 | return 0; |
282 | } | 285 | } |
283 | 286 | ... | ... |
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
1 | #include <string.h> | 22 | #include <string.h> |
2 | #include <stdlib.h> | 23 | #include <stdlib.h> |
3 | #include <paths.h> | 24 | #include <paths.h> |
4 | #include <errno.h> | 25 | #include <errno.h> |
5 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | |||
6 | #include <mailutils/mailbox.h> | 28 | #include <mailutils/mailbox.h> |
7 | 29 | ||
8 | #ifndef _PATH_MAILDIR | 30 | #ifndef _PATH_MAILDIR | ... | ... |
mailbox/mbx_file.c
0 → 100644
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 Library General 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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <string.h> | ||
23 | #include <errno.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <sys/stat.h> | ||
26 | |||
27 | #include <mailbox0.h> | ||
28 | #include <registrar0.h> | ||
29 | |||
30 | static int mailbox_file_init (mailbox_t mbox); | ||
31 | |||
32 | /* Register variables. */ | ||
33 | static struct mailbox_entry _file_entry = | ||
34 | { | ||
35 | url_file_init, mailbox_file_init | ||
36 | }; | ||
37 | mailbox_entry_t file_entry = &_file_entry; | ||
38 | |||
39 | static struct _record _file_record = | ||
40 | { | ||
41 | MU_FILE_SCHEME, | ||
42 | &_file_entry, /* Mailbox entry. */ | ||
43 | NULL, /* Mailer entry. */ | ||
44 | 0, /* Not malloc()ed. */ | ||
45 | NULL, /* No need for an owner. */ | ||
46 | NULL, /* is_scheme method. */ | ||
47 | NULL, /* get_mailbox method. */ | ||
48 | NULL /* get_mailer method. */ | ||
49 | }; | ||
50 | record_t file_record = &_file_record; | ||
51 | |||
52 | /* Register variables. */ | ||
53 | static struct mailbox_entry _path_entry = | ||
54 | { | ||
55 | url_path_init, mailbox_file_init | ||
56 | }; | ||
57 | mailbox_entry_t path_entry = &_path_entry; | ||
58 | |||
59 | static struct _record _path_record = | ||
60 | { | ||
61 | MU_PATH_SCHEME, | ||
62 | &_path_entry, /* Mailbox entry. */ | ||
63 | NULL, /* Mailer entry. */ | ||
64 | 0, /* Not malloc()ed. */ | ||
65 | NULL, /* No need for an owner. */ | ||
66 | NULL, /* is_scheme method. */ | ||
67 | NULL, /* get_mailbox method. */ | ||
68 | NULL /* get_mailer method. */ | ||
69 | }; | ||
70 | record_t path_record = &_path_record; | ||
71 | |||
72 | /* | ||
73 | Caveat there is no specific URL for file mailbox or simple path name, | ||
74 | <path_name> | ||
75 | file:<path_name> | ||
76 | |||
77 | It would be preferrable to use : | ||
78 | maildir:<path> | ||
79 | unix:<path> | ||
80 | mmdf:<path> | ||
81 | This would eliminate heuristic discovery that would turn | ||
82 | out to be wrong. | ||
83 | */ | ||
84 | |||
85 | static int | ||
86 | mailbox_file_init (mailbox_t mbox) | ||
87 | { | ||
88 | struct stat st; | ||
89 | size_t len = 0; | ||
90 | char *path; | ||
91 | int status; | ||
92 | |||
93 | status = url_get_path (mbox->url, NULL, 0, &len); | ||
94 | if (status != 0) | ||
95 | return status; | ||
96 | path = calloc (len + 1, sizeof (char)); | ||
97 | if (path == NULL) | ||
98 | return ENOMEM; | ||
99 | status = url_get_path (mbox->url, path, len + 1, NULL); | ||
100 | if (status != 0) | ||
101 | { | ||
102 | free (path); | ||
103 | return status; | ||
104 | } | ||
105 | |||
106 | /* Sigh, if they want to creat ??? they should know the type of ??? | ||
107 | What is the best course of action ? For the default is mbox if the | ||
108 | file does not exist. */ | ||
109 | if (stat (path, &st) < 0) | ||
110 | { | ||
111 | status = mbox_entry->_mailbox_init (mbox); | ||
112 | } | ||
113 | else if (S_ISREG (st.st_mode)) | ||
114 | { | ||
115 | /* | ||
116 | FIXME: We should do an open() and try | ||
117 | to do a better reconnaissance of the type, | ||
118 | maybe MMDF. For now assume Unix MBox */ | ||
119 | status = mbox_entry->_mailbox_init (mbox); | ||
120 | } | ||
121 | /* Is that true ? Are all directories Maildir ?? */ | ||
122 | else if (S_ISDIR (st.st_mode)) | ||
123 | { | ||
124 | /*status = maildir_entry._mailbox_init (mbox);*/ | ||
125 | status = EINVAL; | ||
126 | } | ||
127 | |||
128 | free (path); | ||
129 | return status; | ||
130 | } |
... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
3 | 3 | ||
4 | This program is free software; you can redistribute it and/or modify | 4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU Library General Public License as published by | 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) | 6 | the Free Software Foundation; either version 2, or (at your option) |
7 | any later version. | 7 | any later version. |
8 | 8 | ||
... | @@ -14,122 +14,1381 @@ | ... | @@ -14,122 +14,1381 @@ |
14 | You should have received a copy of the GNU Library General Public License | 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 | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | |||
18 | /* First draft by Alain Magloire */ | ||
19 | |||
20 | #ifdef HAVE_CONFIG_H | ||
21 | # include <config.h> | ||
22 | #endif | ||
23 | |||
24 | #include <stdlib.h> | ||
25 | #include <stdio.h> | ||
26 | #include <time.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <fcntl.h> | ||
29 | #include <unistd.h> | ||
30 | #include <signal.h> | ||
31 | #include <time.h> | ||
17 | #include <string.h> | 32 | #include <string.h> |
33 | #include <ctype.h> | ||
34 | #include <limits.h> | ||
18 | #include <errno.h> | 35 | #include <errno.h> |
19 | #include <sys/stat.h> | ||
20 | 36 | ||
21 | #include <mailbox0.h> | 37 | #include <mailutils/message.h> |
38 | #include <mailutils/stream.h> | ||
39 | #include <mailutils/body.h> | ||
40 | #include <mailutils/header.h> | ||
41 | #include <mailutils/attribute.h> | ||
22 | #include <registrar0.h> | 42 | #include <registrar0.h> |
43 | #include <mailbox0.h> | ||
44 | |||
45 | |||
46 | #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED) | ||
47 | #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2) | ||
48 | |||
49 | static int mbox_init (mailbox_t mailbox); | ||
50 | |||
51 | /* Register variables. */ | ||
52 | static struct mailbox_entry _mbox_entry = | ||
53 | { | ||
54 | url_mbox_init, mbox_init | ||
55 | }; | ||
56 | mailbox_entry_t mbox_entry = &_mbox_entry; | ||
57 | |||
58 | static struct _record _mbox_record = | ||
59 | { | ||
60 | MU_MBOX_SCHEME, | ||
61 | &_mbox_entry, /* Mailbox entry. */ | ||
62 | NULL, /* Mailer entry. */ | ||
63 | 0, /* Not malloc()ed. */ | ||
64 | NULL, /* No need for an owner. */ | ||
65 | NULL, /* is_scheme method. */ | ||
66 | NULL, /* get_mailbox method. */ | ||
67 | NULL /* get_mailer method. */ | ||
68 | }; | ||
69 | record_t mbox_record = &_mbox_record; | ||
70 | |||
71 | static void mbox_destroy (mailbox_t); | ||
72 | |||
73 | struct _mbox_message; | ||
74 | struct _mbox_data; | ||
75 | |||
76 | typedef struct _mbox_data* mbox_data_t; | ||
77 | typedef struct _mbox_message* mbox_message_t; | ||
78 | |||
79 | /* Keep the position of where the header and body starts and ends. | ||
80 | old_flags is the "Status:" message. */ | ||
81 | struct _mbox_message | ||
82 | { | ||
83 | /* Offset of the parts of the messages in the mailbox. */ | ||
84 | off_t header_from; | ||
85 | off_t header_from_end; | ||
86 | /* Little hack to make things easier when updating the attribute. */ | ||
87 | off_t header_status; | ||
88 | off_t header_status_end; | ||
89 | off_t body; | ||
90 | off_t body_end; | ||
91 | |||
92 | /* The old_flags contains the definition of Header. */ | ||
93 | int old_flags; | ||
94 | /* The new_flags holds the attributes changes for the current session. We | ||
95 | use this so when expunging we can tell when an attribute been modified. | ||
96 | This is a big help so we can jump to the first modify email for speed | ||
97 | in expunging (see mark dirty). */ | ||
98 | int new_flags; | ||
23 | 99 | ||
100 | size_t header_lines; | ||
101 | size_t body_lines; | ||
102 | stream_t stream; | ||
24 | 103 | ||
25 | static int mailbox_mbox_create (mailbox_t *mbox, const char *name); | 104 | /* A message attach to it. */ |
26 | static void mailbox_mbox_destroy (mailbox_t *mbox); | 105 | message_t message; |
106 | mbox_data_t mud; /* Back pointer. */ | ||
107 | }; | ||
27 | 108 | ||
28 | struct mailbox_registrar _mailbox_mbox_registrar = | 109 | /* The umessages is an array of pointers that contains umessages_count of |
110 | mbox_message_t*; umessages[umessages_count]. We do it this way because | ||
111 | realloc() can move everything to a new memory region and invalidate all | ||
112 | the pointers. Thanks to <Dave Inglis> for pointing this out. The | ||
113 | messages_count is the count number of messages parsed so far. */ | ||
114 | struct _mbox_data | ||
29 | { | 115 | { |
30 | "UNIX_MBOX/Maildir/MMDF", | 116 | mbox_message_t *umessages; /* Array. */ |
31 | mailbox_mbox_create, mailbox_mbox_destroy | 117 | size_t umessages_count; /* How big is the umessages[]. */ |
118 | size_t messages_count; /* How many valid entry in umessages[]. */ | ||
119 | stream_t stream; | ||
120 | off_t size; | ||
121 | char *name; | ||
122 | |||
123 | /* The variables below are use to hold the state when appending messages. */ | ||
124 | enum mbox_state | ||
125 | { | ||
126 | MBOX_NO_STATE=0, MBOX_STATE_FROM, MBOX_STATE_DATE, MBOX_STATE_APPEND | ||
127 | } state ; | ||
128 | char *from; | ||
129 | char *date; | ||
130 | off_t off; | ||
131 | mailbox_t mailbox; /* Back pointer. */ | ||
32 | }; | 132 | }; |
33 | 133 | ||
34 | /* | 134 | /* Mailbox concrete implementation. */ |
35 | Caveat there is no specific URL for file mailbox or simple path name, | 135 | static int mbox_open (mailbox_t, int); |
36 | <path_name> | 136 | static int mbox_close (mailbox_t); |
37 | file:<path_name> | 137 | static int mbox_get_message (mailbox_t, size_t, message_t *); |
138 | static int mbox_append_message (mailbox_t, message_t); | ||
139 | static int mbox_messages_count (mailbox_t, size_t *); | ||
140 | static int mbox_expunge (mailbox_t); | ||
141 | static int mbox_scan (mailbox_t, size_t, size_t *); | ||
142 | static int mbox_is_updated (mailbox_t); | ||
143 | static int mbox_size (mailbox_t, off_t *); | ||
144 | |||
145 | |||
146 | /* private stuff */ | ||
147 | static int mbox_scan0 (mailbox_t, size_t, size_t *, int); | ||
148 | static int mbox_get_header_read (stream_t, char *, size_t, off_t, size_t *); | ||
149 | static int mbox_get_hdr_fd (stream_t, int *); | ||
150 | static int mbox_get_body_fd (stream_t, int *); | ||
151 | static int mbox_get_fd (mbox_message_t, int *); | ||
152 | static int mbox_get_attr_flags (attribute_t, int *); | ||
153 | static int mbox_set_attr_flags (attribute_t, int); | ||
154 | static int mbox_unset_attr_flags (attribute_t, int); | ||
155 | static int mbox_readstream (stream_t, char *, size_t, off_t, size_t *); | ||
156 | static int mbox_header_size (header_t, size_t *); | ||
157 | static int mbox_header_lines (header_t, size_t *); | ||
158 | static int mbox_body_size (body_t, size_t *); | ||
159 | static int mbox_body_lines (body_t, size_t *); | ||
160 | static int mbox_msg_from (message_t, char *, size_t, size_t *); | ||
161 | static int mbox_msg_received (message_t, char *, size_t, size_t *); | ||
162 | static int mbox_lock (mailbox_t, int); | ||
163 | static int mbox_touchlock (mailbox_t); | ||
164 | static int mbox_unlock (mailbox_t); | ||
165 | |||
166 | /* We allocate the mbox_data_t struct, but don't do any parsing on the name or | ||
167 | even test for existence. However we do strip any leading "mbox:" part of | ||
168 | the name, this is suppose to be the protocol/scheme name. */ | ||
169 | static int | ||
170 | mbox_init (mailbox_t mailbox) | ||
171 | { | ||
172 | mbox_data_t mud; | ||
173 | size_t name_len; | ||
174 | |||
175 | if (mailbox == NULL) | ||
176 | return EINVAL; | ||
177 | |||
178 | /* Allocate specific mbox data. */ | ||
179 | mud = mailbox->data = calloc (1, sizeof (*mud)); | ||
180 | if (mailbox->data == NULL) | ||
181 | return ENOMEM; | ||
182 | |||
183 | /* Back pointer. */ | ||
184 | mud->mailbox = mailbox; | ||
185 | |||
186 | /* Copy the name. | ||
187 | We do not do any further interpretation after the scheme "mbox:" | ||
188 | Because for example on distributed system like QnX4 a file name is | ||
189 | //390/etc/passwd. So the best approach is to let the OS handle it | ||
190 | for example if we receive: "mbox:///var/mail/alain" the mailbox name | ||
191 | will be "///var/mail/alain", we let open() do the right thing. | ||
192 | So it will let things like this "mbox://390/var/mail/alain" where | ||
193 | "//390/var/mail/alain" _is_ the filename, pass correctely. */ | ||
194 | url_get_path (mailbox->url, NULL, 0, &name_len); | ||
195 | mud->name = calloc (name_len + 1, sizeof (char)); | ||
196 | if (mud->name == NULL) | ||
197 | { | ||
198 | mbox_destroy (mailbox); | ||
199 | return ENOMEM; | ||
200 | } | ||
201 | url_get_path (mailbox->url, mud->name, name_len + 1, NULL); | ||
202 | |||
203 | mud->state = MBOX_NO_STATE; | ||
204 | |||
205 | /* Overloading the default. */ | ||
206 | mailbox->_init = mbox_init; | ||
207 | mailbox->_destroy = mbox_destroy; | ||
208 | |||
209 | mailbox->_open = mbox_open; | ||
210 | mailbox->_close = mbox_close; | ||
211 | |||
212 | /* Messages. */ | ||
213 | mailbox->_get_message = mbox_get_message; | ||
214 | mailbox->_append_message = mbox_append_message; | ||
215 | mailbox->_messages_count = mbox_messages_count; | ||
216 | mailbox->_expunge = mbox_expunge; | ||
217 | |||
218 | mailbox->_scan = mbox_scan; | ||
219 | mailbox->_is_updated = mbox_is_updated; | ||
220 | |||
221 | mailbox->_size = mbox_size; | ||
222 | |||
223 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_init(%s)\n", mud->name); | ||
224 | return 0; /* okdoke */ | ||
225 | } | ||
226 | |||
227 | /* Free all ressources associated with Unix mailbox. */ | ||
228 | static void | ||
229 | mbox_destroy (mailbox_t mailbox) | ||
230 | { | ||
231 | mbox_close (mailbox); | ||
232 | if (mailbox->data) | ||
233 | { | ||
234 | size_t i; | ||
235 | mbox_data_t mud = mailbox->data; | ||
236 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, | ||
237 | "mbox_destroy (%s/%s)\n", mud->name); | ||
238 | mailbox_wrlock (mailbox); | ||
239 | for (i = 0; i < mud->umessages_count; i++) | ||
240 | { | ||
241 | mbox_message_t mum = mud->umessages[i]; | ||
242 | if (mum == NULL) | ||
243 | { | ||
244 | message_destroy (&(mum->message), mum); | ||
245 | free (mum); | ||
246 | } | ||
247 | } | ||
248 | if (mud->umessages) | ||
249 | free (mud->umessages); | ||
250 | if (mud->name) | ||
251 | free (mud->name); | ||
252 | free (mailbox->data); | ||
253 | mailbox->data = NULL; | ||
254 | mailbox_unlock (mailbox); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | /* Open the file. */ | ||
259 | static int | ||
260 | mbox_open (mailbox_t mailbox, int flags) | ||
261 | { | ||
262 | mbox_data_t mud = mailbox->data; | ||
263 | int status = 0; | ||
264 | |||
265 | if (mud == NULL) | ||
266 | return EINVAL; | ||
267 | |||
268 | mailbox->flags = flags | MU_STREAM_FILE; | ||
269 | mailbox_rdlock (mailbox); | ||
270 | |||
271 | /* Get a stream. */ | ||
272 | if (mailbox->stream == NULL) | ||
273 | { | ||
274 | /* FIXME: for small mbox we should try to mmap (). */ | ||
275 | |||
276 | status = (flags & MU_STREAM_CREAT) || (mailbox->flags & MU_STREAM_APPEND); | ||
277 | if (status == 0) | ||
278 | status = mapfile_stream_create (&(mailbox->stream)); | ||
279 | if (status != 0) | ||
280 | { | ||
281 | status = file_stream_create (&(mailbox->stream)); | ||
282 | if (status != 0) | ||
283 | { | ||
284 | mailbox_unlock (mailbox); | ||
285 | return status; | ||
286 | } | ||
287 | } | ||
288 | status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags); | ||
289 | if (status != 0) | ||
290 | { | ||
291 | mailbox_unlock (mailbox); | ||
292 | return status; | ||
293 | } | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags); | ||
298 | if (status != 0) | ||
299 | { | ||
300 | mailbox_unlock (mailbox); | ||
301 | return status; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_open(%s, %d)\n", | ||
306 | mud->name, mailbox->flags); | ||
307 | |||
308 | /* Give an appopriate way to lock. */ | ||
309 | if (mailbox->locker == NULL) | ||
310 | locker_create (&(mailbox->locker), mud->name, strlen (mud->name), | ||
311 | MU_LOCKER_PID | MU_LOCKER_FCNTL); | ||
312 | mailbox_unlock (mailbox); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int | ||
317 | mbox_close (mailbox_t mailbox) | ||
318 | { | ||
319 | mbox_data_t mud = mailbox->data; | ||
320 | size_t i; | ||
321 | |||
322 | if (mud == NULL) | ||
323 | return EINVAL; | ||
324 | |||
325 | /* Make sure we do not hold any lock for that file. */ | ||
326 | mbox_unlock (mailbox); | ||
327 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_close(%s)\n", mud->name); | ||
38 | 328 | ||
39 | It would be preferrable to use : | 329 | mailbox_wrlock (mailbox); |
40 | maildir:<path> | 330 | /* Before closing we need to remove all the messages |
41 | unix:<path> | 331 | - to reclaim the memory |
42 | mmdf:<path> | 332 | - to prepare for another scan. */ |
43 | This would eliminate heuristic discovery that would turn | 333 | for (i = 0; i < mud->umessages_count; i++) |
44 | out to be wrong. | 334 | { |
45 | */ | 335 | mbox_message_t mum = mud->umessages[i]; |
336 | /* Destroy the attach messages. */ | ||
337 | if (mum == NULL) | ||
338 | { | ||
339 | message_destroy (&(mum->message), mum); | ||
340 | free (mum); | ||
341 | } | ||
342 | } | ||
343 | free (mud->umessages); | ||
344 | mud->umessages = NULL; | ||
345 | mud->messages_count = mud->umessages_count = 0; | ||
346 | mud->size = 0; | ||
347 | mailbox_unlock (mailbox); | ||
348 | return stream_close (mailbox->stream); | ||
349 | } | ||
350 | |||
351 | /* Mailbox Parsing. */ | ||
352 | #include "mbx_mboxscan.c" | ||
353 | |||
354 | static int | ||
355 | mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) | ||
356 | { | ||
357 | mbox_data_t mud = mailbox->data; | ||
358 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_scan(%s)\n", mud->name); | ||
359 | return mbox_scan0 (mailbox, msgno, pcount, 1); | ||
360 | } | ||
361 | |||
362 | |||
363 | /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two | ||
364 | browsers and delete files in one. My views is that we should scream | ||
365 | bloody murder and hunt them with a machette. But for now just play dumb, | ||
366 | but maybe the best approach is to pack our things and leave .i.e exit(). */ | ||
367 | static int | ||
368 | mbox_is_updated (mailbox_t mailbox) | ||
369 | { | ||
370 | off_t size; | ||
371 | mbox_data_t mud = mailbox->data; | ||
372 | int status; | ||
373 | |||
374 | if (mud == NULL) | ||
375 | return EINVAL; | ||
376 | mailbox_rdlock (mailbox); | ||
377 | if (stream_size (mailbox->stream, &size) != 0) | ||
378 | { | ||
379 | mailbox_unlock (mailbox); | ||
380 | return 0; | ||
381 | } | ||
382 | status = (mud->size == size); | ||
383 | mailbox_unlock (mailbox); | ||
384 | return status; | ||
385 | } | ||
386 | |||
387 | /* FIXME: the use of tmpfile() on some system can lead to race condition, We | ||
388 | should use a safer approach. */ | ||
389 | static FILE * | ||
390 | mbox_tmpfile (mailbox_t mailbox, char **pbox) | ||
391 | { | ||
392 | const char *tmpdir; | ||
393 | int fd; | ||
394 | FILE *fp; | ||
395 | const char *basename; | ||
396 | mbox_data_t mud = mailbox->data; | ||
46 | 397 | ||
398 | /* P_tmpdir should be define in <stdio.h>. */ | ||
399 | #ifndef P_tmpdir | ||
400 | # define P_tmpdir "/tmp" | ||
401 | #endif | ||
402 | |||
403 | tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir; | ||
404 | basename = strrchr (mud->name, '/'); | ||
405 | if (basename) | ||
406 | basename++; | ||
407 | else | ||
408 | basename = mud->name; | ||
409 | *pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") + | ||
410 | strlen (basename) + 1, sizeof (char)); | ||
411 | if (*pbox == NULL) | ||
412 | return NULL; | ||
413 | sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename); | ||
414 | |||
415 | /* FIXME: I don't think this is the righ approach, creating an anonymous | ||
416 | file would be better ? no trace left behind. */ | ||
417 | /* Create the file. It must not exist. If it does exist, fail. */ | ||
418 | fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600); | ||
419 | if (fd < 0) | ||
420 | { | ||
421 | fprintf (stderr,"Can't create %s\n", *pbox); | ||
422 | fprintf (stderr,"delete file <%s>, Please\n", *pbox); | ||
423 | fprintf (stderr, "It was likely due to an error when expunging\n"); | ||
424 | return NULL; | ||
425 | } | ||
426 | fp = fdopen (fd, "w+"); | ||
427 | if (fp == 0) | ||
428 | { | ||
429 | close(fd); | ||
430 | free (*pbox); | ||
431 | *pbox = NULL; | ||
432 | } | ||
433 | |||
434 | /* Really I should just remove the file here. */ | ||
435 | /* remove(*pbox); */ | ||
436 | return fp; | ||
437 | } | ||
438 | |||
439 | /* For the expunge bits we took a very cautionnary approach, meaning | ||
440 | we create temporary file in the tmpdir copy all the file not mark deleted, | ||
441 | and skip the deleted ones, truncate the real mailbox to the desired size | ||
442 | and overwrite with the tmp mailbox. The approach to do everyting | ||
443 | in core is tempting but require to much memory, it is not rare now | ||
444 | a day to have 30 Megs mailbox, also there is danger for filesystems | ||
445 | with quotas, or some program may not respect the advisory lock and | ||
446 | decide to append a new message while your expunging etc ... | ||
447 | The real downside to the approach we take is that when things go wrong | ||
448 | the temporary file bay be left in /tmp, which is not all that bad | ||
449 | because at least have something to recuparate when failure. */ | ||
47 | static int | 450 | static int |
48 | mailbox_mbox_create (mailbox_t *mbox, const char *name) | 451 | mbox_expunge (mailbox_t mailbox) |
49 | { | 452 | { |
50 | struct stat st; | 453 | mbox_data_t mud = mailbox->data; |
51 | size_t len; | 454 | mbox_message_t mum; |
455 | int status = 0; | ||
456 | sigset_t signalset; | ||
457 | FILE *tempfile; | ||
458 | size_t nread; | ||
459 | size_t i, j, dirty, first; | ||
460 | off_t marker = 0; | ||
461 | off_t total = 0; | ||
462 | char buffer [BUFSIZ]; | ||
463 | char *tmpmbox = NULL; | ||
52 | 464 | ||
53 | if (name == NULL || mbox == NULL) | 465 | if (mud == NULL) |
54 | return EINVAL; | 466 | return EINVAL; |
55 | 467 | ||
56 | len = strlen (name); | 468 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_expunge (%s)\n", mud->name); |
57 | if (len >= 5 && | 469 | |
58 | (name[0] == 'f' || name[0] == 'F') && | 470 | /* Noop. */ |
59 | (name[1] == 'i' || name[1] == 'I') && | 471 | if (mud->messages_count == 0) |
60 | (name[2] == 'l' || name[2] == 'L') && | 472 | return 0; |
61 | (name[3] == 'e' || name[3] == 'E') && | 473 | |
62 | name[4] == ':') | 474 | /* Do we have a consistent view of the mailbox. */ |
475 | if (! mbox_is_updated (mailbox)) | ||
476 | { | ||
477 | fprintf (stderr, "mailbox is not updated, try again.\n"); | ||
478 | return EAGAIN; | ||
479 | } | ||
480 | |||
481 | mailbox_wrlock (mailbox); | ||
482 | |||
483 | /* Mark dirty the first mail with an attribute change. */ | ||
484 | for (dirty = 0; dirty < mud->messages_count; dirty++) | ||
485 | { | ||
486 | mum = mud->umessages[dirty]; | ||
487 | if (mum->new_flags && | ||
488 | ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)) | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | /* Did something change ? */ | ||
493 | if (dirty == mud->messages_count) | ||
494 | { | ||
495 | mailbox_unlock (mailbox); | ||
496 | return 0; /* Nothing change, bail out. */ | ||
497 | } | ||
498 | |||
499 | |||
500 | /* This is redundant, we go to the loop again. But it's more secure here | ||
501 | since we don't want to be disturb when expunging. */ | ||
502 | for (j = 0; j < mud->messages_count; j++) | ||
503 | { | ||
504 | mum = mud->umessages[j]; | ||
505 | if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags)) | ||
506 | message_destroy (&(mum->message), mum); | ||
507 | } | ||
508 | |||
509 | /* Create a tempory file. */ | ||
510 | tempfile = mbox_tmpfile (mailbox, &tmpmbox); | ||
511 | if (tempfile == NULL) | ||
63 | { | 512 | { |
64 | name += 5; | 513 | fprintf (stderr, "Failed to create temporary file when expunging.\n"); |
514 | free (tmpmbox); | ||
515 | mailbox_unlock (mailbox); | ||
516 | return errno; | ||
65 | } | 517 | } |
66 | /* | ||
67 | * If they want to creat ?? should they know the type ??? | ||
68 | * What is the best course of action ?? | ||
69 | * For the default is unix if the file does not exist. | ||
70 | */ | ||
71 | if (stat (name, &st) < 0) | ||
72 | return _mailbox_unix_registrar._create (mbox, name); | ||
73 | 518 | ||
74 | if (S_ISREG (st.st_mode)) | 519 | /* Get the lock. */ |
520 | if (mbox_lock (mailbox, MU_LOCKER_WRLOCK) < 0) | ||
75 | { | 521 | { |
76 | /* | 522 | fclose (tempfile); |
77 | FIXME: We should do an open() and try | 523 | remove (tmpmbox); |
78 | to do a better reconnaissance of the type, | 524 | free (tmpmbox); |
79 | maybe MMDF. For now assume Unix MBox */ | 525 | fprintf (stderr, "Failed to grab the lock\n"); |
80 | #if 0 | 526 | mailbox_unlock (mailbox); |
81 | char head[6]; | 527 | return ENOLCK; |
82 | ssize_t cout; | 528 | } |
83 | int fd; | 529 | |
530 | /* Critical section, we can not allowed signal here. */ | ||
531 | sigemptyset (&signalset); | ||
532 | sigaddset (&signalset, SIGTERM); | ||
533 | sigaddset (&signalset, SIGHUP); | ||
534 | sigaddset (&signalset, SIGTSTP); | ||
535 | sigaddset (&signalset, SIGINT); | ||
536 | sigaddset (&signalset, SIGWINCH); | ||
537 | sigprocmask (SIG_BLOCK, &signalset, 0); | ||
538 | |||
539 | /* Set the marker position. */ | ||
540 | total = marker = mud->umessages[dirty]->header_from; | ||
541 | |||
542 | /* Copy to tempfile emails not mark deleted. */ | ||
543 | for (first = 1, i = dirty; i < mud->messages_count; i++) | ||
544 | { | ||
545 | mum = mud->umessages[i]; | ||
546 | |||
547 | /* Skip it, if mark for deletion. */ | ||
548 | if (ATTRIBUTE_IS_DELETED (mum->new_flags)) | ||
549 | continue; | ||
84 | 550 | ||
85 | fd = open (name, O_RDONLY); | 551 | /* Add a NL separator between messages. */ |
86 | if (fd == -1) | 552 | if (first) |
553 | first = 0; | ||
554 | else | ||
87 | { | 555 | { |
88 | /* Oops !! wrong permission ? file deleted ? */ | 556 | fputc ('\n', tempfile); |
89 | return errno; /* errno set by open () */ | 557 | total++; |
90 | } | 558 | } |
91 | 559 | ||
92 | /* Read a small chunck */ | 560 | /* Begining of header copy. */ |
93 | count = read (fd, head, sizeof(head)); | 561 | { |
562 | off_t current; | ||
563 | /* This is done in two parts first we check if the attribute changed, | ||
564 | if yes then we have to update the "Status:" field. Unfortunately | ||
565 | there is no requirement for the "Status:" to be the last field, so | ||
566 | we take the long approach; Copy up to the Status, update the | ||
567 | Status and copy the rest. */ | ||
94 | 568 | ||
95 | /* Try Unix Mbox */ | 569 | /* Attribute change ? */ |
570 | if (mum->new_flags | ||
571 | &&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags) | ||
572 | && mum->header_status > mum->header_from) | ||
573 | { | ||
574 | size_t n = 0; | ||
575 | off_t offset = mum->header_from; | ||
576 | size_t len = mum->header_status - mum->header_from; | ||
577 | current = mum->header_status_end; | ||
578 | while (len > 0) | ||
579 | { | ||
580 | nread = (len < sizeof (buffer)) ? len : sizeof (buffer); | ||
581 | if ((status = stream_read (mailbox->stream, buffer, | ||
582 | nread, offset, &n) != 0) | ||
583 | || fwrite(buffer, sizeof(*buffer), n, tempfile) != n) | ||
584 | { | ||
585 | if (status == 0) | ||
586 | status = errno; | ||
587 | fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__, | ||
588 | strerror (status)); | ||
589 | goto bailout0; | ||
590 | } | ||
591 | len -= n; | ||
592 | total += n; | ||
593 | offset += n; | ||
594 | } | ||
96 | 595 | ||
97 | /* FIXME: | 596 | /* Put the new attributes. */ |
98 | What happen if the file is empty ??? | 597 | { |
99 | Do we default to Unix ?? | 598 | char abuf[64]; |
100 | */ | 599 | size_t na = 0; |
101 | if (count == 0) /*empty file*/ | 600 | abuf[0] = '\0'; |
601 | flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na); | ||
602 | fputs (abuf, tempfile); | ||
603 | total += na; | ||
604 | } | ||
605 | } | ||
606 | else /* Attribute did not change. */ | ||
607 | current = mum->header_from; | ||
608 | |||
609 | /* Copy the rest of header without changes. */ | ||
102 | { | 610 | { |
103 | close (fd); | 611 | size_t n = 0; |
104 | return _mailbox_unix_registrar._create (mbox, name); | 612 | off_t offset = current; |
613 | size_t len = mum->body - current; | ||
614 | while (len > 0) | ||
615 | { | ||
616 | nread = (len < sizeof (buffer)) ? len : sizeof (buffer); | ||
617 | if ((status = stream_read (mailbox->stream, buffer, nread, | ||
618 | offset, &n) != 0) | ||
619 | || fwrite(buffer, sizeof(*buffer), n, tempfile) != n) | ||
620 | { | ||
621 | if (status == 0) | ||
622 | status = errno; | ||
623 | fprintf (stderr, "Error expunge:%d: %s", __LINE__, | ||
624 | strerror (status)); | ||
625 | goto bailout0; | ||
626 | } | ||
627 | len -= n; | ||
628 | total += n; | ||
629 | offset += n; | ||
630 | } | ||
105 | } | 631 | } |
632 | } /* End of header copy. */ | ||
106 | 633 | ||
107 | if (count >= 5) | 634 | /* Copy the body. */ |
635 | { | ||
636 | size_t n = 0; | ||
637 | off_t offset = mum->body; | ||
638 | size_t len = mum->body_end - mum->body; | ||
639 | while (len > 0) | ||
640 | { | ||
641 | nread = (len < sizeof (buffer)) ? len : sizeof (buffer); | ||
642 | if ((status = stream_read (mailbox->stream, buffer, nread, | ||
643 | offset, &n) != 0) | ||
644 | || fwrite(buffer, sizeof(*buffer), n, tempfile) != n) | ||
645 | { | ||
646 | if (status == 0) | ||
647 | status = errno; | ||
648 | fprintf (stderr, "Error expunge:%d: %s", __LINE__, | ||
649 | strerror (status)); | ||
650 | goto bailout0; | ||
651 | } | ||
652 | len -= n; | ||
653 | total += n; | ||
654 | offset += n; | ||
655 | } | ||
656 | } /* End of body copy. */ | ||
657 | } /* for (;;) */ | ||
658 | |||
659 | /* Caution: before ftruncate()ing the file see if we've receiving new mail | ||
660 | Some program may not respect the lock, or the lock was held for too | ||
661 | long. */ | ||
662 | { | ||
663 | off_t size = 0; | ||
664 | if (stream_size (mailbox->stream, &size) == 0) | ||
665 | { | ||
666 | size_t n = 0; | ||
667 | off_t offset = size; | ||
668 | size_t len = size - mud->size; | ||
669 | while (len > 0) | ||
670 | { | ||
671 | nread = (len < sizeof (buffer)) ? len : sizeof (buffer); | ||
672 | if ((status = stream_read (mailbox->stream, buffer, nread, | ||
673 | offset, &n) != 0) | ||
674 | || fwrite(buffer, sizeof(*buffer), n, tempfile) != n) | ||
675 | { | ||
676 | if (status == 0) | ||
677 | status = errno; | ||
678 | fprintf (stderr, "Error expunge:%d: %s", __LINE__, | ||
679 | strerror (status)); | ||
680 | goto bailout0; | ||
681 | } | ||
682 | len -= n; | ||
683 | total += n; | ||
684 | offset += n; | ||
685 | } | ||
686 | } | ||
687 | } /* End of precaution. */ | ||
688 | |||
689 | /* Seek and rewrite it. */ | ||
690 | rewind (tempfile); | ||
691 | if (total > 0) | ||
692 | { | ||
693 | size_t n = 0; | ||
694 | off_t offset = marker; | ||
695 | while ((nread = fread (buffer, sizeof (*buffer), | ||
696 | sizeof (buffer), tempfile)) != 0) | ||
108 | { | 697 | { |
109 | if (strncmp (head, "From ", 5) == 0) | 698 | while (nread) |
110 | { | 699 | { |
111 | /* This is a Unix Mbox */ | 700 | status = stream_write (mailbox->stream, buffer, nread, offset, &n); |
112 | close (fd); | 701 | if (status != 0) |
113 | return _mailbox_unix_registrar._create (mbox, name); | 702 | { |
703 | fprintf (stderr, "Error expunge:%d: %s\n", __LINE__, | ||
704 | strerror (status)); | ||
705 | goto bailout; | ||
706 | } | ||
707 | nread -= n; | ||
708 | offset += n; | ||
114 | } | 709 | } |
115 | } | 710 | } |
711 | } | ||
116 | 712 | ||
117 | /* Try MMDF */ | 713 | /* How can I handle error here ?? */ |
118 | close (fd); | 714 | clearerr (tempfile); |
119 | #endif | 715 | |
120 | return _mailbox_unix_registrar._create (mbox, name); | 716 | /* Flush/truncation. */ |
717 | stream_flush (mailbox->stream); | ||
718 | status = stream_truncate (mailbox->stream, total); | ||
719 | if (status != 0) | ||
720 | { | ||
721 | fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status)); | ||
722 | goto bailout; | ||
121 | } | 723 | } |
122 | /* Is that true ? Are all directories Maildir ?? */ | ||
123 | else if (S_ISDIR (st.st_mode)) | ||
124 | return _mailbox_maildir_registrar._create (mbox, name); | ||
125 | 724 | ||
126 | /* Why can't a mailbox be FIFO ? or a DOOR/Portal ??? */ | 725 | bailout0: |
127 | return EINVAL; | 726 | /* Don't remove the tmp mbox in case of errors, when writing back. */ |
727 | remove (tmpmbox); | ||
728 | |||
729 | bailout: | ||
730 | |||
731 | free (tmpmbox); | ||
732 | /* Release the locks. */ | ||
733 | mbox_unlock (mailbox); | ||
734 | fclose (tempfile); | ||
735 | sigprocmask (SIG_UNBLOCK, &signalset, 0); | ||
736 | |||
737 | /* We need to readjust the pointers. */ | ||
738 | if (status == 0) | ||
739 | { | ||
740 | size_t dlast; | ||
741 | for (j = dirty, dlast = mud->messages_count - 1; | ||
742 | j < mud->messages_count; j++) | ||
743 | { | ||
744 | /* Clear all the references, any attach messages been already | ||
745 | destroy above. */ | ||
746 | mum = mud->umessages[j]; | ||
747 | if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags)) | ||
748 | { | ||
749 | memmove (mud->umessages + j, mud->umessages + j + 1, | ||
750 | (dlast - dirty) * sizeof (mum)); | ||
751 | mum->header_from = mum->header_from_end = 0; | ||
752 | mum->header_status = mum->header_status_end = 0; | ||
753 | mum->body = mum->body_end = 0; | ||
754 | mum->header_lines = mum->body_lines = 0; | ||
755 | mud->umessages[dlast] = mum; | ||
756 | dlast--; | ||
757 | mum = mud->umessages[j]; | ||
758 | } | ||
759 | mum->header_from = mum->header_from_end = 0; | ||
760 | mum->header_status = mum->header_status_end = 0; | ||
761 | mum->body = mum->body_end = 0; | ||
762 | mum->header_lines = mum->body_lines = 0; | ||
763 | } | ||
764 | /* This is should reset the messages_count, the last argument 0 means | ||
765 | not to send event notification. */ | ||
766 | mailbox_unlock (mailbox); | ||
767 | mbox_scan0 (mailbox, dirty, NULL, 0); | ||
768 | } | ||
769 | else | ||
770 | mailbox_unlock (mailbox); | ||
771 | return status; | ||
128 | } | 772 | } |
129 | 773 | ||
130 | static void | 774 | static int |
131 | mailbox_mbox_destroy (mailbox_t *pmbox) | 775 | mbox_get_body_fd (stream_t is, int *pfd) |
776 | { | ||
777 | body_t body = stream_get_owner (is); | ||
778 | message_t msg = body_get_owner (body); | ||
779 | mbox_message_t mum = message_get_owner (msg); | ||
780 | return mbox_get_fd (mum, pfd); | ||
781 | } | ||
782 | |||
783 | static int | ||
784 | mbox_get_hdr_fd (stream_t is, int *pfd) | ||
785 | { | ||
786 | header_t header = stream_get_owner (is); | ||
787 | message_t msg = header_get_owner (header); | ||
788 | mbox_message_t mum = message_get_owner (msg); | ||
789 | return mbox_get_fd (mum, pfd); | ||
790 | } | ||
791 | |||
792 | static int | ||
793 | mbox_get_fd (mbox_message_t mum, int *pfd) | ||
132 | { | 794 | { |
133 | if (pmbox && *pmbox) | 795 | int status; |
134 | _mailbox_unix_registrar._destroy (pmbox); | 796 | if (mum == NULL) |
797 | return EINVAL; | ||
798 | mailbox_rdlock (mum->mud->mailbox); | ||
799 | status = stream_get_fd (mum->stream, pfd); | ||
800 | mailbox_unlock (mum->mud->mailbox); | ||
801 | return status; | ||
802 | } | ||
803 | |||
804 | static int | ||
805 | mbox_get_attr_flags (attribute_t attr, int *pflags) | ||
806 | { | ||
807 | message_t msg = attribute_get_owner (attr); | ||
808 | mbox_message_t mum = message_get_owner (msg); | ||
809 | |||
810 | if (mum == NULL) | ||
811 | return EINVAL; | ||
812 | |||
813 | mailbox_rdlock (mum->mud->mailbox); | ||
814 | if (pflags) | ||
815 | *pflags = mum->new_flags; | ||
816 | mailbox_unlock (mum->mud->mailbox); | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int | ||
821 | mbox_set_attr_flags (attribute_t attr, int flags) | ||
822 | { | ||
823 | message_t msg = attribute_get_owner (attr); | ||
824 | mbox_message_t mum = message_get_owner (msg); | ||
825 | |||
826 | if (mum == NULL) | ||
827 | return EINVAL; | ||
828 | |||
829 | mailbox_rdlock (mum->mud->mailbox); | ||
830 | mum->new_flags |= flags; | ||
831 | mailbox_unlock (mum->mud->mailbox); | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static int | ||
836 | mbox_unset_attr_flags (attribute_t attr, int flags) | ||
837 | { | ||
838 | message_t msg = attribute_get_owner (attr); | ||
839 | mbox_message_t mum = message_get_owner (msg); | ||
840 | |||
841 | if (mum == NULL) | ||
842 | return EINVAL; | ||
843 | |||
844 | mailbox_rdlock (mum->mud->mailbox); | ||
845 | mum->new_flags &= ~flags; | ||
846 | mailbox_unlock (mum->mud->mailbox); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | static int | ||
851 | mbox_readstream (stream_t is, char *buffer, size_t buflen, | ||
852 | off_t off, size_t *pnread) | ||
853 | { | ||
854 | body_t body = stream_get_owner (is); | ||
855 | message_t msg = body_get_owner (body); | ||
856 | mbox_message_t mum = message_get_owner (msg); | ||
857 | size_t nread = 0; | ||
858 | |||
859 | if (mum == NULL) | ||
860 | return EINVAL; | ||
861 | |||
862 | if (buffer == NULL || buflen == 0) | ||
863 | { | ||
864 | if (pnread) | ||
865 | *pnread = nread; | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | mailbox_rdlock (mum->mud->mailbox); | ||
870 | { | ||
871 | off_t ln = mum->body_end - (mum->body + off); | ||
872 | size_t n = 0; | ||
873 | int status; | ||
874 | if (ln > 0) | ||
875 | { | ||
876 | nread = ((size_t)ln < buflen) ? ln : buflen; | ||
877 | /* Position the file pointer and the buffer. */ | ||
878 | status = stream_read (mum->stream, buffer, nread, mum->body + off, &n); | ||
879 | if (status != 0) | ||
880 | { | ||
881 | mailbox_unlock (mum->mud->mailbox); | ||
882 | return status; | ||
883 | } | ||
884 | } | ||
885 | } | ||
886 | mailbox_unlock (mum->mud->mailbox); | ||
887 | |||
888 | if (pnread) | ||
889 | *pnread = nread; | ||
890 | return 0; | ||
891 | } | ||
892 | |||
893 | static int | ||
894 | mbox_get_header_read (stream_t is, char *buffer, size_t len, | ||
895 | off_t off, size_t *pnread) | ||
896 | { | ||
897 | header_t header = stream_get_owner (is); | ||
898 | message_t msg = header_get_owner (header); | ||
899 | mbox_message_t mum = message_get_owner (msg); | ||
900 | size_t nread = 0; | ||
901 | int status = 0; | ||
902 | off_t ln; | ||
903 | |||
904 | if (mum == NULL) | ||
905 | return EINVAL; | ||
906 | |||
907 | mailbox_rdlock (mum->mud->mailbox); | ||
908 | ln = mum->body - (mum->header_from_end + off); | ||
909 | if (ln > 0) | ||
910 | { | ||
911 | nread = ((size_t)ln < len) ? ln : len; | ||
912 | /* Position the file pointer and the buffer. */ | ||
913 | status = stream_read (mum->stream, buffer, nread, | ||
914 | mum->header_from_end + off, &nread); | ||
915 | } | ||
916 | if (pnread) | ||
917 | *pnread = nread; | ||
918 | mailbox_unlock (mum->mud->mailbox); | ||
919 | return status; | ||
920 | } | ||
921 | |||
922 | static int | ||
923 | mbox_header_size (header_t header, size_t *psize) | ||
924 | { | ||
925 | message_t msg = header_get_owner (header); | ||
926 | mbox_message_t mum = message_get_owner (msg); | ||
927 | if (mum == NULL) | ||
928 | return EINVAL; | ||
929 | mailbox_rdlock (mum->mud->mailbox); | ||
930 | if (psize) | ||
931 | *psize = mum->body - mum->header_from_end; | ||
932 | mailbox_unlock (mum->mud->mailbox); | ||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static int | ||
937 | mbox_header_lines (header_t header, size_t *plines) | ||
938 | { | ||
939 | message_t msg = header_get_owner (header); | ||
940 | mbox_message_t mum = message_get_owner (msg); | ||
941 | if (mum == NULL) | ||
942 | return EINVAL; | ||
943 | mailbox_rdlock (mum->mud->mailbox); | ||
944 | if (plines) | ||
945 | *plines = mum->header_lines; | ||
946 | mailbox_unlock (mum->mud->mailbox); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int | ||
951 | mbox_body_size (body_t body, size_t *psize) | ||
952 | { | ||
953 | message_t msg = body_get_owner (body); | ||
954 | mbox_message_t mum = message_get_owner (msg); | ||
955 | if (mum == NULL) | ||
956 | return EINVAL; | ||
957 | if (psize) | ||
958 | *psize = mum->body_end - mum->body + 1; | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static int | ||
963 | mbox_body_lines (body_t body, size_t *plines) | ||
964 | { | ||
965 | message_t msg = body_get_owner (body); | ||
966 | mbox_message_t mum = message_get_owner (msg); | ||
967 | if (mum == NULL) | ||
968 | return EINVAL; | ||
969 | mailbox_rdlock (mum->mud->mailbox); | ||
970 | if (plines) | ||
971 | *plines = mum->body_lines; | ||
972 | mailbox_unlock (mum->mud->mailbox); | ||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | static int | ||
977 | mbox_msg_received (message_t msg, char *buf, size_t len, | ||
978 | size_t *pnwrite) | ||
979 | { | ||
980 | mbox_message_t mum = message_get_owner (msg); | ||
981 | size_t n = 0; | ||
982 | int status; | ||
983 | char buffer[512]; | ||
984 | |||
985 | if (mum == NULL) | ||
986 | return EINVAL; | ||
987 | |||
988 | mailbox_rdlock (mum->mud->mailbox); | ||
989 | status = stream_readline (mum->stream, buffer, sizeof(buffer), | ||
990 | mum->header_from, &n); | ||
991 | mailbox_unlock (mum->mud->mailbox); | ||
992 | if (status != 0) | ||
993 | { | ||
994 | if (pnwrite) | ||
995 | *pnwrite = 0; | ||
996 | if (buf) | ||
997 | *buf = '\0'; | ||
998 | return status; | ||
999 | } | ||
1000 | |||
1001 | if (n > 5) | ||
1002 | { | ||
1003 | char *s = strchr (buffer + 5, ' '); | ||
1004 | if (s) | ||
1005 | { | ||
1006 | if (buf && len > 0) | ||
1007 | { | ||
1008 | strncpy (buf, s + 1, len); | ||
1009 | buffer [len - 1] = '\0'; | ||
1010 | } | ||
1011 | if (pnwrite) | ||
1012 | *pnwrite = strlen (s + 1); | ||
1013 | return 0; | ||
1014 | } | ||
1015 | } | ||
1016 | if (pnwrite) | ||
1017 | *pnwrite = 0; | ||
1018 | if (buf) | ||
1019 | *buf = '\0'; | ||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int | ||
1024 | mbox_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite) | ||
1025 | { | ||
1026 | mbox_message_t mum = message_get_owner (msg); | ||
1027 | size_t n = 0; | ||
1028 | int status; | ||
1029 | char buffer[512]; | ||
1030 | |||
1031 | if (mum == NULL) | ||
1032 | return EINVAL; | ||
1033 | |||
1034 | mailbox_rdlock (mum->mud->mailbox); | ||
1035 | status = stream_readline (mum->stream, buffer, sizeof(buffer), | ||
1036 | mum->header_from, &n); | ||
1037 | mailbox_unlock (mum->mud->mailbox); | ||
1038 | if (status != 0) | ||
1039 | { | ||
1040 | if (pnwrite) | ||
1041 | *pnwrite = 0; | ||
1042 | if (buf) | ||
1043 | *buf = '\0'; | ||
1044 | return status; | ||
1045 | } | ||
1046 | |||
1047 | if (n > 5) | ||
1048 | { | ||
1049 | char *s = strchr (buffer + 5, ' '); | ||
1050 | if (s) | ||
1051 | { | ||
1052 | *s = '\0'; | ||
1053 | if (buf && len > 0) | ||
1054 | { | ||
1055 | strncpy (buf, buffer + 5, len); | ||
1056 | buffer [len - 1] = '\0'; | ||
1057 | } | ||
1058 | if (pnwrite) | ||
1059 | *pnwrite = strlen (buffer + 5); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | } | ||
1063 | if (pnwrite) | ||
1064 | *pnwrite = 0; | ||
1065 | if (buf) | ||
1066 | *buf = '\0'; | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int | ||
1071 | mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) | ||
1072 | { | ||
1073 | int status; | ||
1074 | mbox_data_t mud = mailbox->data; | ||
1075 | mbox_message_t mum; | ||
1076 | message_t msg = NULL; | ||
1077 | |||
1078 | /* Sanity checks. */ | ||
1079 | if (pmsg == NULL || mud == NULL || (!(mud->messages_count > 0 && msgno > 0 | ||
1080 | && msgno <= mud->messages_count))) | ||
1081 | return EINVAL; | ||
1082 | |||
1083 | mum = mud->umessages[msgno - 1]; | ||
1084 | |||
1085 | /* Check if we already have it. */ | ||
1086 | if (mum->message) | ||
1087 | { | ||
1088 | if (pmsg) | ||
1089 | *pmsg = mum->message; | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message(%s, %d)\n", | ||
1094 | mud->name, msgno); | ||
1095 | |||
1096 | /* Get an empty message struct. */ | ||
1097 | status = message_create (&msg, mum); | ||
1098 | if (status != 0) | ||
1099 | return status; | ||
1100 | |||
1101 | /* Set the header. */ | ||
1102 | { | ||
1103 | header_t header = NULL; | ||
1104 | stream_t stream = NULL; | ||
1105 | if ((status = header_create (&header, NULL, 0, msg)) != 0 | ||
1106 | || (status = stream_create (&stream, mailbox->flags, header)) != 0) | ||
1107 | { | ||
1108 | stream_destroy (&stream, header); | ||
1109 | header_destroy (&header, msg); | ||
1110 | message_destroy (&msg, mum); | ||
1111 | return status; | ||
1112 | } | ||
1113 | stream_set_read (stream, mbox_get_header_read, header); | ||
1114 | stream_set_fd (stream, mbox_get_hdr_fd, header); | ||
1115 | header_set_stream (header, stream, msg); | ||
1116 | header_set_size (header, mbox_header_size, msg); | ||
1117 | header_set_lines (header, mbox_header_lines, msg); | ||
1118 | message_set_header (msg, header, mum); | ||
1119 | } | ||
1120 | |||
1121 | /* Set the attribute. */ | ||
1122 | { | ||
1123 | attribute_t attribute; | ||
1124 | status = attribute_create (&attribute, msg); | ||
1125 | if (status != 0) | ||
1126 | { | ||
1127 | message_destroy (&msg, mum); | ||
1128 | return status; | ||
1129 | } | ||
1130 | mum->new_flags = mum->old_flags; | ||
1131 | attribute_set_get_flags (attribute, mbox_get_attr_flags, msg); | ||
1132 | attribute_set_set_flags (attribute, mbox_set_attr_flags, msg); | ||
1133 | attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg); | ||
1134 | message_set_attribute (msg, attribute, mum); | ||
1135 | } | ||
1136 | |||
1137 | /* Prepare the body. */ | ||
1138 | { | ||
1139 | body_t body = NULL; | ||
1140 | stream_t stream = NULL; | ||
1141 | if ((status = body_create (&body, msg)) != 0 | ||
1142 | || (status = stream_create (&stream, mailbox->flags, body)) != 0) | ||
1143 | { | ||
1144 | body_destroy (&body, msg); | ||
1145 | stream_destroy (&stream, body); | ||
1146 | message_destroy (&msg, mum); | ||
1147 | return status; | ||
1148 | } | ||
1149 | stream_set_read (stream, mbox_readstream, body); | ||
1150 | stream_set_fd (stream, mbox_get_body_fd, body); | ||
1151 | body_set_stream (body, stream, msg); | ||
1152 | body_set_size (body, mbox_body_size, msg); | ||
1153 | body_set_lines (body, mbox_body_lines, msg); | ||
1154 | message_set_body (msg, body, mum); | ||
1155 | } | ||
1156 | |||
1157 | /* Set the envelope. */ | ||
1158 | message_set_from (msg, mbox_msg_from, mum); | ||
1159 | message_set_received (msg, mbox_msg_received, mum); | ||
1160 | |||
1161 | /* Attach the message to the mailbox mbox data. */ | ||
1162 | mum->message = msg; | ||
1163 | |||
1164 | if (pmsg) | ||
1165 | *pmsg = msg; | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static int | ||
1170 | mbox_append_message (mailbox_t mailbox, message_t msg) | ||
1171 | { | ||
1172 | mbox_data_t mud = mailbox->data; | ||
1173 | if (msg == NULL || mud == NULL) | ||
1174 | return EINVAL; | ||
1175 | |||
1176 | MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_append_message (%s)\n", | ||
1177 | mud->name); | ||
1178 | |||
1179 | mailbox_wrlock (mailbox); | ||
1180 | mbox_lock (mailbox, MU_LOCKER_WRLOCK); | ||
1181 | { | ||
1182 | off_t size; | ||
1183 | int status; | ||
1184 | size_t n = 0; | ||
1185 | char nl = '\n'; | ||
1186 | |||
1187 | /* Move to the end of the file, not necesary if _APPEND mode. */ | ||
1188 | status = stream_size (mailbox->stream, &size); | ||
1189 | if (status != 0) | ||
1190 | { | ||
1191 | mailbox_unlock (mailbox); | ||
1192 | mbox_unlock (mailbox); | ||
1193 | return status; | ||
1194 | } | ||
1195 | |||
1196 | switch (mud->state) | ||
1197 | { | ||
1198 | case MBOX_NO_STATE: | ||
1199 | mud->from = calloc (128, sizeof (char)); | ||
1200 | if (mud->from == NULL) | ||
1201 | { | ||
1202 | mbox_unlock (mailbox); | ||
1203 | mailbox_unlock (mailbox); | ||
1204 | return ENOMEM; | ||
1205 | } | ||
1206 | mud->date = calloc (128, sizeof (char)); | ||
1207 | if (mud->date == NULL) | ||
1208 | { | ||
1209 | free (mud->from); | ||
1210 | mud->from = NULL; | ||
1211 | mud->state = MBOX_NO_STATE; | ||
1212 | mbox_unlock (mailbox); | ||
1213 | mailbox_unlock (mailbox); | ||
1214 | return ENOMEM; | ||
1215 | } | ||
1216 | mud->off = 0; | ||
1217 | mud->state = MBOX_STATE_FROM; | ||
1218 | |||
1219 | case MBOX_STATE_FROM: | ||
1220 | /* Generate a "From " separator. */ | ||
1221 | { | ||
1222 | char *s; | ||
1223 | size_t len = 0; | ||
1224 | status = message_from (msg, mud->from, 127, &len); | ||
1225 | if (status != 0) | ||
1226 | { | ||
1227 | if (status != EAGAIN) | ||
1228 | { | ||
1229 | free (mud->from); | ||
1230 | free (mud->date); | ||
1231 | mud->date = mud->from = NULL; | ||
1232 | mud->state = MBOX_NO_STATE; | ||
1233 | mbox_unlock (mailbox); | ||
1234 | } | ||
1235 | mailbox_unlock (mailbox); | ||
1236 | return status; | ||
1237 | } | ||
1238 | /* Nuke trailing newline. */ | ||
1239 | s = memchr (mud->from, nl, len); | ||
1240 | if (s) | ||
1241 | *s = '\0'; | ||
1242 | mud->state = MBOX_STATE_DATE; | ||
1243 | } | ||
1244 | |||
1245 | case MBOX_STATE_DATE: | ||
1246 | /* Generate a date for the "From " separator. */ | ||
1247 | { | ||
1248 | char *s; | ||
1249 | size_t len = 0; | ||
1250 | status = message_received (msg, mud->date, 127, &len); | ||
1251 | if (status != 0) | ||
1252 | { | ||
1253 | if (status != EAGAIN) | ||
1254 | { | ||
1255 | free (mud->from); | ||
1256 | free (mud->date); | ||
1257 | mud->date = mud->from = NULL; | ||
1258 | mud->state = MBOX_NO_STATE; | ||
1259 | mbox_unlock (mailbox); | ||
1260 | } | ||
1261 | mailbox_unlock (mailbox); | ||
1262 | return status; | ||
1263 | } | ||
1264 | /* Nuke trailing newline. */ | ||
1265 | s = memchr (mud->date, nl, len); | ||
1266 | if (s) | ||
1267 | *s = '\0'; | ||
1268 | /* Write the separator to the mailbox. */ | ||
1269 | stream_write (mailbox->stream, "From ", 5, size, &n); | ||
1270 | size += n; | ||
1271 | stream_write (mailbox->stream, mud->from, strlen (mud->from), size, &n); | ||
1272 | size += n; | ||
1273 | stream_write (mailbox->stream, " ", 1, size, &n); | ||
1274 | size += n; | ||
1275 | stream_write (mailbox->stream, mud->date, strlen (mud->date), size, &n); | ||
1276 | size += n; | ||
1277 | stream_write (mailbox->stream, &nl , 1, size, &n); | ||
1278 | size += n; | ||
1279 | free (mud->from); | ||
1280 | free (mud->date); | ||
1281 | mud->from = mud->date = NULL; | ||
1282 | mud->state = MBOX_STATE_APPEND; | ||
1283 | } | ||
1284 | |||
1285 | case MBOX_STATE_APPEND: | ||
1286 | /* Append the Message. */ | ||
1287 | { | ||
1288 | char buffer[BUFSIZ]; | ||
1289 | size_t nread = 0; | ||
1290 | stream_t is; | ||
1291 | message_get_stream (msg, &is); | ||
1292 | do | ||
1293 | { | ||
1294 | status = stream_read (is, buffer, sizeof (buffer), mud->off, | ||
1295 | &nread); | ||
1296 | if (status != 0) | ||
1297 | { | ||
1298 | if (status != EAGAIN) | ||
1299 | { | ||
1300 | free (mud->from); | ||
1301 | free (mud->date); | ||
1302 | mud->date = mud->from = NULL; | ||
1303 | mud->state = MBOX_NO_STATE; | ||
1304 | mbox_unlock (mailbox); | ||
1305 | } | ||
1306 | stream_flush (mailbox->stream); | ||
1307 | mailbox_unlock (mailbox); | ||
1308 | return status; | ||
1309 | } | ||
1310 | stream_write (mailbox->stream, buffer, nread, size, &n); | ||
1311 | mud->off += nread; | ||
1312 | size += n; | ||
1313 | } | ||
1314 | while (nread > 0); | ||
1315 | stream_write (mailbox->stream, &nl, 1, size, &n); | ||
1316 | } | ||
1317 | |||
1318 | default: | ||
1319 | break; | ||
1320 | } | ||
1321 | } | ||
1322 | stream_flush (mailbox->stream); | ||
1323 | mud->state = MBOX_NO_STATE; | ||
1324 | mbox_unlock (mailbox); | ||
1325 | mailbox_unlock (mailbox); | ||
1326 | return 0; | ||
1327 | } | ||
1328 | |||
1329 | static int | ||
1330 | mbox_size (mailbox_t mailbox, off_t *psize) | ||
1331 | { | ||
1332 | off_t size; | ||
1333 | int status; | ||
1334 | |||
1335 | /* Maybe was not open yet ?? */ | ||
1336 | mailbox_rdlock (mailbox); | ||
1337 | status = stream_size (mailbox->stream, &size); | ||
1338 | mailbox_unlock (mailbox); | ||
1339 | if (status != 0) | ||
1340 | return status; | ||
1341 | if (psize) | ||
1342 | *psize = size; | ||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | static int | ||
1347 | mbox_messages_count (mailbox_t mailbox, size_t *pcount) | ||
1348 | { | ||
1349 | mbox_data_t mud = mailbox->data; | ||
1350 | if (mud == NULL) | ||
1351 | return EINVAL; | ||
1352 | |||
1353 | if (! mbox_is_updated (mailbox)) | ||
1354 | return mbox_scan0 (mailbox, 1, pcount, 1); | ||
1355 | |||
1356 | if (pcount) | ||
1357 | *pcount = mud->messages_count; | ||
1358 | |||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | /* Locking. */ | ||
1363 | static int | ||
1364 | mbox_lock (mailbox_t mailbox, int flag) | ||
1365 | { | ||
1366 | if (mailbox && mailbox->locker != NULL) | ||
1367 | { | ||
1368 | locker_t locker = mailbox->locker; | ||
1369 | locker_lock (locker, flag); | ||
1370 | } | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int | ||
1375 | mbox_touchlock (mailbox_t mailbox) | ||
1376 | { | ||
1377 | if (mailbox && mailbox->locker != NULL) | ||
1378 | { | ||
1379 | locker_t locker = mailbox->locker; | ||
1380 | locker_touchlock (locker); | ||
1381 | } | ||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | static int | ||
1386 | mbox_unlock (mailbox_t mailbox) | ||
1387 | { | ||
1388 | if (mailbox && mailbox->locker != NULL) | ||
1389 | { | ||
1390 | locker_t locker = mailbox->locker; | ||
1391 | locker_unlock (locker); | ||
1392 | } | ||
1393 | return 0; | ||
135 | } | 1394 | } | ... | ... |
mailbox/mbx_mboxscan.c
0 → 100644
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 | /* Credits to the c-client and its Authors | ||
19 | * The notorius c-client VALID() macro, was written by Mark Crispin. | ||
20 | */ | ||
21 | |||
22 | /* Parsing. | ||
23 | * The approach is to detect the "From " as start of a | ||
24 | * new message, give the position of the header and scan | ||
25 | * until "\n" then set header_end, set body position, | ||
26 | * scan until we it another "From " and set body_end. | ||
27 | * | ||
28 | ************************************ | ||
29 | * This is a classic case of premature optimisation | ||
30 | * being the root of all Evil(Donald E. Knuth). | ||
31 | * But I'm under "pressure" ;-) to come with | ||
32 | * something "faster". I think it's wastefull | ||
33 | * to spend time to gain a few seconds on 30Megs mailboxes | ||
34 | * ... but then again ... in computer time, 60 seconds, is eternity. | ||
35 | * | ||
36 | * If they use the event notification stuff | ||
37 | * to get some headers/messages early ... it's like pissing | ||
38 | * in the wind(sorry don't have the english equivalent). | ||
39 | * The worst is progress_bar it should be ... &*($^ nuke. | ||
40 | * For the events, we have to remove the *.LCK file, | ||
41 | * release the locks, flush the stream save the pointers | ||
42 | * etc ... hurry and wait... | ||
43 | * I this point I'm pretty much ranting. | ||
44 | * | ||
45 | */ | ||
46 | |||
47 | /* From the C-Client, part of pine */ | ||
48 | /* You are not expected to understand this macro, but read the next page if | ||
49 | * you are not faint of heart. | ||
50 | * | ||
51 | * Known formats to the VALID macro are: | ||
52 | * From user Wed Dec 2 05:53 1992 | ||
53 | * BSD From user Wed Dec 2 05:53:22 1992 | ||
54 | * SysV From user Wed Dec 2 05:53 PST 1992 | ||
55 | * rn From user Wed Dec 2 05:53:22 PST 1992 | ||
56 | * From user Wed Dec 2 05:53 -0700 1992 | ||
57 | * From user Wed Dec 2 05:53:22 -0700 1992 | ||
58 | * From user Wed Dec 2 05:53 1992 PST | ||
59 | * From user Wed Dec 2 05:53:22 1992 PST | ||
60 | * From user Wed Dec 2 05:53 1992 -0700 | ||
61 | * Solaris From user Wed Dec 2 05:53:22 1992 -0700 | ||
62 | * | ||
63 | * Plus all of the above with `` remote from xxx'' after it. Thank you very | ||
64 | * much, smail and Solaris, for making my life considerably more complicated. | ||
65 | */ | ||
66 | /* | ||
67 | * What? You want to understand the VALID macro anyway? Alright, since you | ||
68 | * insist. Actually, it isn't really all that difficult, provided that you | ||
69 | * take it step by step. | ||
70 | * | ||
71 | * Line 1 Initializes the return ti value to failure (0); | ||
72 | * Lines 2-3 Validates that the 1st-5th characters are ``From ''. | ||
73 | * Lines 4-6 Validates that there is an end of line and points x at it. | ||
74 | * Lines 7-14 First checks to see if the line is at least 41 characters long | ||
75 | . | ||
76 | * If so, it scans backwards to find the rightmost space. From | ||
77 | * that point, it scans backwards to see if the string matches | ||
78 | * `` remote from''. If so, it sets x to point to the space at | ||
79 | * the start of the string. | ||
80 | * Line 15 Makes sure that there are at least 27 characters in the line. | ||
81 | * Lines 16-21 Checks if the date/time ends with the year (there is a space | ||
82 | * five characters back). If there is a colon three characters | ||
83 | * further back, there is no timezone field, so zn is set to 0 | ||
84 | * and ti is set in front of the year. Otherwise, there must | ||
85 | * either to be a space four characters back for a three-letter | ||
86 | * timezone, or a space six characters back followed by a + or - | ||
87 | * for a numeric timezone; in either case, zn and ti become the | ||
88 | * offset of the space immediately before it. | ||
89 | * Lines 22-24 Are the failure case for line 14. If there is a space four | ||
90 | * characters back, it is a three-letter timezone; there must be | ||
91 | a | ||
92 | * space for the year nine characters back. zn is the zone | ||
93 | * offset; ti is the offset of the space. | ||
94 | * Lines 25-28 Are the failure case for line 20. If there is a space six | ||
95 | * characters back, it is a numeric timezone; there must be a | ||
96 | * space eleven characters back and a + or - five characters back | ||
97 | . | ||
98 | * zn is the zone offset; ti is the offset of the space. | ||
99 | * Line 29-32 If ti is valid, make sure that the string before ti is of the | ||
100 | * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise | ||
101 | * invalidate ti. There must be a colon three characters back | ||
102 | * and a space six or nine characters back (depending upon | ||
103 | * whether or not the character six characters back is a colon). | ||
104 | * There must be a space three characters further back (in front | ||
105 | * of the day), one seven characters back (in front of the month) | ||
106 | , | ||
107 | * and one eleven characters back (in front of the day of week). | ||
108 | * ti is set to be the offset of the space before the time. | ||
109 | * | ||
110 | * Why a macro? It gets invoked a *lot* in a tight loop. On some of the | ||
111 | * newer pipelined machines it is faster being open-coded than it would be if | ||
112 | * subroutines are called. | ||
113 | * | ||
114 | * Why does it scan backwards from the end of the line, instead of doing the | ||
115 | * much easier forward scan? There is no deterministic way to parse the | ||
116 | * ``user'' field, because it may contain unquoted spaces! Yes, I tested it t | ||
117 | o | ||
118 | * see if unquoted spaces were possible. They are, and I've encountered enoug | ||
119 | h | ||
120 | * evil mail to be totally unwilling to trust that ``it will never happen''. | ||
121 | */ | ||
122 | #define VALID(s,x,ti,zn) { \ | ||
123 | ti = 0; \ | ||
124 | if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ | ||
125 | (s[4] == ' ')) { \ | ||
126 | for (x = s + 5; *x && *x != '\n'; x++); \ | ||
127 | if (x) { \ | ||
128 | if (x - s >= 41) { \ | ||
129 | for (zn = -1; x[zn] != ' '; zn--); \ | ||
130 | if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ | ||
131 | (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ | ||
132 | (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ | ||
133 | (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ | ||
134 | x += zn - 12; \ | ||
135 | } \ | ||
136 | if (x - s >= 27) { \ | ||
137 | if (x[-5] == ' ') { \ | ||
138 | if (x[-8] == ':') zn = 0,ti = -5; \ | ||
139 | else if (x[-9] == ' ') ti = zn = -9; \ | ||
140 | else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ | ||
141 | ti = zn = -11; \ | ||
142 | } \ | ||
143 | else if (x[-4] == ' ') { \ | ||
144 | if (x[-9] == ' ') zn = -4,ti = -9; \ | ||
145 | } \ | ||
146 | else if (x[-6] == ' ') { \ | ||
147 | if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ | ||
148 | zn = -6,ti = -11; \ | ||
149 | } \ | ||
150 | if (ti && !((x[ti - 3] == ':') && \ | ||
151 | (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ | ||
152 | (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ | ||
153 | (x[ti - 11] == ' '))) ti = 0; \ | ||
154 | } \ | ||
155 | } \ | ||
156 | } \ | ||
157 | } | ||
158 | |||
159 | #define STRLEN(s, i) \ | ||
160 | do \ | ||
161 | { \ | ||
162 | char *tmp = (s);\ | ||
163 | while (*tmp) tmp++; \ | ||
164 | i = tmp - s; \ | ||
165 | } while (0) | ||
166 | |||
167 | #define ATTRIBUTE_SET(buf,mum,c0,c1,type) \ | ||
168 | do \ | ||
169 | { \ | ||
170 | char *s; \ | ||
171 | for (s = (buf) + 7; *s; s++) \ | ||
172 | { \ | ||
173 | if (*s == c0 || *s == c1) \ | ||
174 | { \ | ||
175 | (mum)->old_flags |= (type); \ | ||
176 | break; \ | ||
177 | } \ | ||
178 | } \ | ||
179 | } while (0) | ||
180 | |||
181 | #define ISSTATUS(buf) (\ | ||
182 | (buf[0] == 'S' || buf[0] == 's') && \ | ||
183 | (buf[1] == 'T' || buf[1] == 't') && \ | ||
184 | (buf[2] == 'A' || buf[2] == 'a') && \ | ||
185 | (buf[3] == 'T' || buf[3] == 't') && \ | ||
186 | (buf[4] == 'U' || buf[4] == 'u') && \ | ||
187 | (buf[5] == 'S' || buf[5] == 's') && (buf[6] == ':')) | ||
188 | |||
189 | /* Notifications ADD_MESG. */ | ||
190 | #define DISPATCH_ADD_MSG(mbox,mud) \ | ||
191 | do \ | ||
192 | { \ | ||
193 | int bailing = 0; \ | ||
194 | mailbox_unlock (mbox); \ | ||
195 | if (mbox->observable) \ | ||
196 | bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \ | ||
197 | if (bailing != 0) \ | ||
198 | { \ | ||
199 | if (pcount) \ | ||
200 | *pcount = (mud)->messages_count; \ | ||
201 | mbox_unlock (mbox); \ | ||
202 | return EINTR; \ | ||
203 | } \ | ||
204 | mailbox_wrlock (mbox); \ | ||
205 | } while (0); | ||
206 | |||
207 | /* Notification MBX_PROGRESS | ||
208 | We do not want to fire up the progress notification every line, it will be | ||
209 | too expensive, so we do it arbitrarely every 10 000 Lines. | ||
210 | FIXME: maybe this should be configurable. */ | ||
211 | /* This is more tricky we can not leave the mum struct incomplete. So we | ||
212 | only tell them about the complete messages. */ | ||
213 | #define DISPATCH_PROGRESS(mbox,mud) \ | ||
214 | do \ | ||
215 | { \ | ||
216 | { \ | ||
217 | int bailing = 0; \ | ||
218 | mailbox_unlock (mbox); \ | ||
219 | mud->messages_count--; \ | ||
220 | if (mbox->observable) \ | ||
221 | bailing = observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS); \ | ||
222 | if (bailing != 0) \ | ||
223 | { \ | ||
224 | if (pcount) \ | ||
225 | *pcount = (mud)->messages_count; \ | ||
226 | mbox_unlock (mbox); \ | ||
227 | return EINTR; \ | ||
228 | } \ | ||
229 | mud->messages_count++; \ | ||
230 | mailbox_wrlock (mbox); \ | ||
231 | } \ | ||
232 | } while (0) | ||
233 | |||
234 | /* Allocate slots for the new messages. */ | ||
235 | /* size_t num = 2 * ((mud)->messages_count) + 10; */ | ||
236 | #define ALLOCATE_MSGS(mbox,mud) \ | ||
237 | do \ | ||
238 | { \ | ||
239 | if ((mud)->messages_count >= (mud)->umessages_count) \ | ||
240 | { \ | ||
241 | mbox_message_t *m; \ | ||
242 | size_t num = ((mud)->umessages_count) + 1; \ | ||
243 | m = realloc ((mud)->umessages, num * sizeof (*m)); \ | ||
244 | if (m == NULL) \ | ||
245 | { \ | ||
246 | mbox_unlock (mbox); \ | ||
247 | mailbox_unlock (mbox); \ | ||
248 | return ENOMEM; \ | ||
249 | } \ | ||
250 | (mud)->umessages = m; \ | ||
251 | (mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \ | ||
252 | if ((mud)->umessages[num - 1] == NULL) \ | ||
253 | { \ | ||
254 | mbox_unlock (mbox); \ | ||
255 | mailbox_unlock (mbox); \ | ||
256 | return ENOMEM; \ | ||
257 | } \ | ||
258 | (mud)->umessages_count = num; \ | ||
259 | } \ | ||
260 | } while (0) | ||
261 | |||
262 | static int | ||
263 | mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif) | ||
264 | { | ||
265 | #define MSGLINELEN 1024 | ||
266 | char buf[MSGLINELEN]; | ||
267 | int inheader; | ||
268 | int inbody; | ||
269 | off_t total = 0; | ||
270 | mbox_data_t mud = mailbox->data; | ||
271 | mbox_message_t mum = NULL; | ||
272 | int status = 0; | ||
273 | size_t lines; | ||
274 | int newline; | ||
275 | size_t n = 0; | ||
276 | |||
277 | int zn, isfrom = 0; | ||
278 | char *temp; | ||
279 | |||
280 | /* Sanity. */ | ||
281 | if (mud == NULL) | ||
282 | return EINVAL; | ||
283 | |||
284 | /* Grab the lock. */ | ||
285 | mailbox_wrlock (mailbox); | ||
286 | |||
287 | /* Save the timestamp and size. */ | ||
288 | status = stream_size (mailbox->stream, &(mud->size)); | ||
289 | if (status != 0) | ||
290 | { | ||
291 | mailbox_unlock (mailbox); | ||
292 | return status; | ||
293 | } | ||
294 | |||
295 | mbox_lock (mailbox, MU_LOCKER_RDLOCK); | ||
296 | |||
297 | /* Seek to the starting point. */ | ||
298 | if (mud->umessages && msgno > 0 && mud->messages_count > 0 | ||
299 | && msgno <= mud->messages_count) | ||
300 | { | ||
301 | mum = mud->umessages[msgno - 1]; | ||
302 | if (mum) | ||
303 | total = mum->header_from; | ||
304 | mud->messages_count = msgno - 1; | ||
305 | } | ||
306 | else | ||
307 | mud->messages_count = 0; | ||
308 | |||
309 | newline = 1; | ||
310 | errno = lines = inheader = inbody = 0; | ||
311 | |||
312 | while ((status = stream_readline (mailbox->stream, buf, sizeof (buf), | ||
313 | total, &n)) == 0 && n != 0) | ||
314 | { | ||
315 | int nl; | ||
316 | total += n; | ||
317 | |||
318 | nl = (*buf == '\n') ? 1 : 0; | ||
319 | VALID(buf, temp, isfrom, zn); | ||
320 | isfrom = (isfrom) ? 1 : 0; | ||
321 | |||
322 | /* Which part of the message are we in ? */ | ||
323 | inheader = isfrom | ((!nl) & inheader); | ||
324 | inbody = (!isfrom) & (!inheader); | ||
325 | |||
326 | lines++; | ||
327 | |||
328 | if (inheader) | ||
329 | { | ||
330 | /* New message. */ | ||
331 | if (isfrom) | ||
332 | { | ||
333 | /* Signal the end of the body. */ | ||
334 | if (mum && !mum->body_end) | ||
335 | { | ||
336 | mum->body_end = total - n - newline; | ||
337 | mum->body_lines = --lines - newline; | ||
338 | if (do_notif) | ||
339 | DISPATCH_ADD_MSG(mailbox, mud); | ||
340 | } | ||
341 | /* Allocate_msgs will initialize mum. */ | ||
342 | ALLOCATE_MSGS(mailbox, mud); | ||
343 | mud->messages_count++; | ||
344 | mum = mud->umessages[mud->messages_count - 1]; | ||
345 | mum->stream = mailbox->stream; | ||
346 | mum->mud = mud; | ||
347 | mum->header_from = total - n; | ||
348 | mum->header_from_end = total; | ||
349 | lines = 0; | ||
350 | } | ||
351 | else if ((n > 7) && ISSTATUS(buf)) | ||
352 | { | ||
353 | mum->header_status = total - n; | ||
354 | mum->header_status_end = total; | ||
355 | ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ); | ||
356 | ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN); | ||
357 | ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED); | ||
358 | ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* Body. */ | ||
363 | if (inbody) | ||
364 | { | ||
365 | /* Set the body position. */ | ||
366 | if (mum && !mum->body) | ||
367 | { | ||
368 | mum->body = total - n + nl; | ||
369 | mum->header_lines = lines; | ||
370 | lines = 0; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | newline = nl; | ||
375 | |||
376 | /* Every 50 mesgs update the lock, it should be every minute. */ | ||
377 | if ((mud->messages_count % 50) == 0) | ||
378 | mbox_touchlock (mailbox); | ||
379 | |||
380 | /* Ping them every 1000 lines. */ | ||
381 | if (do_notif) | ||
382 | if (((lines +1) % 1000) == 0) | ||
383 | DISPATCH_PROGRESS(mailbox, mud); | ||
384 | |||
385 | } /* while */ | ||
386 | |||
387 | if (mum) | ||
388 | { | ||
389 | mum->body_end = total - newline; | ||
390 | mum->body_lines = lines - newline; | ||
391 | if (do_notif) | ||
392 | DISPATCH_ADD_MSG(mailbox, mud); | ||
393 | } | ||
394 | mbox_unlock (mailbox); | ||
395 | if (pcount) | ||
396 | *pcount = mud->messages_count; | ||
397 | mailbox_unlock (mailbox); | ||
398 | return status; | ||
399 | } |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
18 | #include <termios.h> | 22 | #include <termios.h> |
19 | #include <errno.h> | 23 | #include <errno.h> |
20 | #include <stdlib.h> | 24 | #include <stdlib.h> |
... | @@ -24,16 +28,40 @@ | ... | @@ -24,16 +28,40 @@ |
24 | #include <fcntl.h> | 28 | #include <fcntl.h> |
25 | #include <stdarg.h> | 29 | #include <stdarg.h> |
26 | 30 | ||
31 | #include <mailutils/stream.h> | ||
32 | #include <mailutils/body.h> | ||
33 | #include <mailutils/message.h> | ||
34 | #include <mailutils/header.h> | ||
35 | #include <mailutils/attribute.h> | ||
36 | #include <mailutils/url.h> | ||
37 | #include <mailutils/auth.h> | ||
27 | #include <mailbox0.h> | 38 | #include <mailbox0.h> |
28 | #include <stream0.h> | ||
29 | #include <body0.h> | ||
30 | #include <message0.h> | ||
31 | #include <registrar0.h> | 39 | #include <registrar0.h> |
32 | #include <auth0.h> | ||
33 | #include <header0.h> | ||
34 | #include <attribute0.h> | ||
35 | #include <bio.h> | 40 | #include <bio.h> |
36 | 41 | ||
42 | static int pop_init (mailbox_t); | ||
43 | |||
44 | static struct mailbox_entry _pop_entry = | ||
45 | { | ||
46 | url_pop_init, pop_init | ||
47 | }; | ||
48 | static struct _record _pop_record = | ||
49 | { | ||
50 | MU_POP_SCHEME, | ||
51 | &_pop_entry, /* Mailbox entry. */ | ||
52 | NULL, /* Mailer entry. */ | ||
53 | 0, /* Not malloc()ed. */ | ||
54 | NULL, /* No need for an owner. */ | ||
55 | NULL, /* is_scheme method. */ | ||
56 | NULL, /* get_mailbox method. */ | ||
57 | NULL /* get_mailer method. */ | ||
58 | }; | ||
59 | |||
60 | /* We export two functions: url parsing and the initialisation of | ||
61 | the mailbox, via the register entry/record. */ | ||
62 | record_t pop_record = &_pop_record; | ||
63 | mailbox_entry_t pop_entry = &_pop_entry; | ||
64 | |||
37 | /* Advance declarations. */ | 65 | /* Advance declarations. */ |
38 | struct _pop_data; | 66 | struct _pop_data; |
39 | struct _pop_message; | 67 | struct _pop_message; |
... | @@ -45,34 +73,25 @@ typedef struct _pop_message * pop_message_t; | ... | @@ -45,34 +73,25 @@ typedef struct _pop_message * pop_message_t; |
45 | reentrant. It is only one channel. */ | 73 | reentrant. It is only one channel. */ |
46 | enum pop_state | 74 | enum pop_state |
47 | { | 75 | { |
48 | POP_NO_STATE = 0, POP_STATE_DONE, | 76 | POP_NO_STATE, POP_STATE_DONE, |
49 | POP_OPEN_CONNECTION, | 77 | POP_OPEN_CONNECTION, |
50 | POP_GREETINGS, | 78 | POP_GREETINGS, |
51 | POP_APOP_TX, POP_APOP_ACK, | 79 | POP_APOP, POP_APOP_ACK, |
52 | POP_DELE_TX, POP_DELE_ACK, | 80 | POP_DELE, POP_DELE_ACK, |
53 | POP_LIST_TX, POP_LIST_ACK, POP_LIST_RX, | 81 | POP_LIST, POP_LIST_ACK, POP_LIST_RX, |
54 | POP_PASS_TX, POP_PASS_ACK, | 82 | POP_QUIT, POP_QUIT_ACK, |
55 | POP_QUIT_TX, POP_QUIT_ACK, | 83 | POP_NOOP, POP_NOOP_ACK, |
56 | POP_NOOP_TX, POP_NOOP_ACK, | 84 | POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY, |
57 | POP_RETR_TX, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY, | 85 | POP_RSET, POP_RSET_ACK, |
58 | POP_RSET_TX, POP_RSET_ACK, | 86 | POP_STAT, POP_STAT_ACK, |
59 | POP_STAT_TX, POP_STAT_ACK, | 87 | POP_TOP, POP_TOP_ACK, POP_TOP_RX, |
60 | POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX, | 88 | POP_UIDL, POP_UIDL_ACK, |
61 | POP_UIDL_TX, POP_UIDL_ACK, | 89 | POP_AUTH, POP_AUTH_DONE, |
62 | POP_USER_TX, POP_USER_ACK, | 90 | POP_AUTH_USER, POP_AUTH_USER_ACK, |
91 | POP_AUTH_PASS, POP_AUTH_PASS_ACK | ||
63 | }; | 92 | }; |
64 | 93 | ||
65 | /* Those two are exportable funtions i.e. they are visible/call when you | 94 | static void pop_destroy (mailbox_t); |
66 | call a URL "pop://..." to mailbox_create. */ | ||
67 | |||
68 | static int pop_create (mailbox_t *, const char *); | ||
69 | static void pop_destroy (mailbox_t *); | ||
70 | |||
71 | struct mailbox_registrar _mailbox_pop_registrar = | ||
72 | { | ||
73 | "POP3", | ||
74 | pop_create, pop_destroy | ||
75 | }; | ||
76 | 95 | ||
77 | /* Functions/Methods that implements the mailbox_t API. */ | 96 | /* Functions/Methods that implements the mailbox_t API. */ |
78 | static int pop_open (mailbox_t, int); | 97 | static int pop_open (mailbox_t, int); |
... | @@ -80,27 +99,31 @@ static int pop_close (mailbox_t); | ... | @@ -80,27 +99,31 @@ static int pop_close (mailbox_t); |
80 | static int pop_get_message (mailbox_t, size_t, message_t *); | 99 | static int pop_get_message (mailbox_t, size_t, message_t *); |
81 | static int pop_messages_count (mailbox_t, size_t *); | 100 | static int pop_messages_count (mailbox_t, size_t *); |
82 | static int pop_expunge (mailbox_t); | 101 | static int pop_expunge (mailbox_t); |
83 | static int pop_num_deleted (mailbox_t, size_t *); | ||
84 | static int pop_scan (mailbox_t, size_t, size_t *); | 102 | static int pop_scan (mailbox_t, size_t, size_t *); |
85 | static int pop_is_updated (mailbox_t); | 103 | static int pop_is_updated (mailbox_t); |
86 | 104 | ||
87 | /* The implementation of message_t */ | 105 | /* The implementation of message_t */ |
106 | static int pop_user (authority_t); | ||
88 | static int pop_size (mailbox_t, off_t *); | 107 | static int pop_size (mailbox_t, off_t *); |
108 | static int pop_header_read (stream_t, char *, size_t, off_t, size_t *); | ||
109 | static int pop_header_fd (stream_t, int *); | ||
110 | static int pop_body_fd (stream_t, int *); | ||
111 | static int pop_body_size (body_t, size_t *); | ||
112 | static int pop_body_lines (body_t, size_t *); | ||
113 | static int pop_body_read (stream_t, char *, size_t, off_t, size_t *); | ||
114 | static int pop_message_read (stream_t, char *, size_t, off_t, size_t *); | ||
115 | static int pop_message_size (message_t, size_t *); | ||
116 | static int pop_message_fd (stream_t, int *); | ||
89 | static int pop_top (stream_t, char *, size_t, off_t, size_t *); | 117 | static int pop_top (stream_t, char *, size_t, off_t, size_t *); |
90 | static int pop_read_header (stream_t, char *, size_t, off_t, size_t *); | ||
91 | static int pop_read_body (stream_t, char *, size_t, off_t, size_t *); | ||
92 | static int pop_read_message (stream_t, char *, size_t, off_t, size_t *); | ||
93 | static int pop_retr (pop_message_t, char *, size_t, off_t, size_t *); | 118 | static int pop_retr (pop_message_t, char *, size_t, off_t, size_t *); |
94 | static int pop_get_fd (stream_t, int *); | 119 | static int pop_get_fd (pop_message_t, int *); |
95 | static int pop_get_flags (attribute_t, int *); | 120 | static int pop_attr_flags (attribute_t, int *); |
96 | static int pop_body_size (body_t, size_t *); | ||
97 | static int pop_body_lines (body_t body, size_t *plines); | ||
98 | static int pop_uidl (message_t, char *, size_t, size_t *); | 121 | static int pop_uidl (message_t, char *, size_t, size_t *); |
99 | static int fill_buffer (pop_data_t mpd, char *buffer, size_t buflen); | 122 | static int fill_buffer (pop_data_t, char *, size_t); |
100 | static int pop_readline (pop_data_t mpd); | 123 | static int pop_readline (pop_data_t); |
101 | static int pop_read_ack (pop_data_t mpd); | 124 | static int pop_read_ack (pop_data_t); |
102 | static int pop_writeline (pop_data_t mpd, const char *format, ...); | 125 | static int pop_writeline (pop_data_t, const char *, ...); |
103 | static int pop_write (pop_data_t mpd); | 126 | static int pop_write (pop_data_t); |
104 | 127 | ||
105 | /* This structure holds the info for a pop_get_message(). The pop_message_t | 128 | /* This structure holds the info for a pop_get_message(). The pop_message_t |
106 | type, will serve as the owner of the message_t and contains the command to | 129 | type, will serve as the owner of the message_t and contains the command to |
... | @@ -116,7 +139,10 @@ struct _pop_message | ... | @@ -116,7 +139,10 @@ struct _pop_message |
116 | int skip_header; | 139 | int skip_header; |
117 | int skip_body; | 140 | int skip_body; |
118 | size_t body_size; | 141 | size_t body_size; |
142 | size_t header_size; | ||
119 | size_t body_lines; | 143 | size_t body_lines; |
144 | size_t header_lines; | ||
145 | size_t message_size; | ||
120 | size_t num; | 146 | size_t num; |
121 | message_t message; | 147 | message_t message; |
122 | pop_data_t mpd; /* Back pointer. */ | 148 | pop_data_t mpd; /* Back pointer. */ |
... | @@ -126,19 +152,13 @@ struct _pop_message | ... | @@ -126,19 +152,13 @@ struct _pop_message |
126 | many messages we have so far etc ... */ | 152 | many messages we have so far etc ... */ |
127 | struct _pop_data | 153 | struct _pop_data |
128 | { | 154 | { |
129 | /* Pop is a serial protocol, we need only one global mutex. */ | ||
130 | #ifdef HAVE_PTHREAD_H | ||
131 | pthread_mutex_t mutex; | ||
132 | #else | ||
133 | void *func; /* Indicate a command is in operation, busy. */ | 155 | void *func; /* Indicate a command is in operation, busy. */ |
134 | #endif | ||
135 | size_t id; /* Use in pop_expunge to hold the message num, if EAGAIN. */ | 156 | size_t id; /* Use in pop_expunge to hold the message num, if EAGAIN. */ |
136 | enum pop_state state; | 157 | enum pop_state state; |
137 | pop_message_t *pmessages; | 158 | pop_message_t *pmessages; |
138 | size_t pmessages_count; | 159 | size_t pmessages_count; |
139 | size_t messages_count; | 160 | size_t messages_count; |
140 | size_t size; | 161 | size_t size; |
141 | int flags; /* Flags of for the stream_t object. */ | ||
142 | 162 | ||
143 | /* Working I/O buffers. */ | 163 | /* Working I/O buffers. */ |
144 | bio_t bio; | 164 | bio_t bio; |
... | @@ -154,9 +174,46 @@ struct _pop_data | ... | @@ -154,9 +174,46 @@ struct _pop_data |
154 | } ; | 174 | } ; |
155 | 175 | ||
156 | /* Usefull little Macros, since these are very repetitive. */ | 176 | /* Usefull little Macros, since these are very repetitive. */ |
177 | |||
178 | /* Check if we're busy ? */ | ||
179 | /* POP is a one channel dowload protocol, so if someone | ||
180 | is trying to do another command while another is running | ||
181 | something is seriously incorrect, So the best course | ||
182 | of action is to close down the connection and start a new one. | ||
183 | For example mime_t only reads part of the message. If a client | ||
184 | wants to read different part of the message via mime it should | ||
185 | download it first. POP does not have the features of IMAP for | ||
186 | multipart messages. */ | ||
187 | #define CHECK_BUSY(mbox, mpd, function, identity) \ | ||
188 | do \ | ||
189 | { \ | ||
190 | int err = mailbox_wrlock (mbox); \ | ||
191 | if (err != 0) \ | ||
192 | return err; \ | ||
193 | if ((mpd->func && mpd->func != function) \ | ||
194 | || (mpd->id && mpd->id != (size_t)identity)) \ | ||
195 | { \ | ||
196 | mpd->id = 0; \ | ||
197 | mpd->func = pop_open; \ | ||
198 | mpd->state = POP_NO_STATE; \ | ||
199 | mailbox_unlock (mbox); \ | ||
200 | err = pop_open (mbox, mbox->flags); \ | ||
201 | if (err != 0) \ | ||
202 | { \ | ||
203 | return err; \ | ||
204 | } \ | ||
205 | } \ | ||
206 | else \ | ||
207 | { \ | ||
208 | mpd->id = (size_t)identity; \ | ||
209 | mpd->func = func; \ | ||
210 | mailbox_unlock (mbox); \ | ||
211 | } \ | ||
212 | } \ | ||
213 | while (0) | ||
214 | |||
157 | #define CLEAR_STATE(mpd) \ | 215 | #define CLEAR_STATE(mpd) \ |
158 | mpd->id = 0, mpd->func = NULL, \ | 216 | mpd->id = 0, mpd->func = NULL, mpd->state = POP_NO_STATE |
159 | mpd->state = POP_NO_STATE | ||
160 | 217 | ||
161 | /* Clear the state and close the stream. */ | 218 | /* Clear the state and close the stream. */ |
162 | #define CHECK_ERROR_CLOSE(mbox, mpd, status) \ | 219 | #define CHECK_ERROR_CLOSE(mbox, mpd, status) \ |
... | @@ -201,67 +258,21 @@ while (0) | ... | @@ -201,67 +258,21 @@ while (0) |
201 | 258 | ||
202 | /* Parse the url, allocate mailbox_t, allocate pop internal structures. */ | 259 | /* Parse the url, allocate mailbox_t, allocate pop internal structures. */ |
203 | static int | 260 | static int |
204 | pop_create (mailbox_t *pmbox, const char *name) | 261 | pop_init (mailbox_t mbox) |
205 | { | 262 | { |
206 | mailbox_t mbox; | ||
207 | pop_data_t mpd; | 263 | pop_data_t mpd; |
208 | size_t name_len; | ||
209 | |||
210 | /* Sanity check. */ | ||
211 | if (name == NULL || *name == '\0') | ||
212 | return EINVAL; | ||
213 | |||
214 | name_len = strlen (name); | ||
215 | |||
216 | #define POP_SCHEME "pop://" | ||
217 | #define POP_SCHEME_LEN 6 | ||
218 | #define SEPARATOR '/' | ||
219 | |||
220 | /* Skip the url scheme. */ | ||
221 | if (name_len > POP_SCHEME_LEN | ||
222 | && (name[0] == 'p' || name[0] == 'P') | ||
223 | && (name[1] == 'o' || name[1] == 'O') | ||
224 | && (name[2] == 'p' || name[2] == 'P') | ||
225 | && (name[3] == ':' && name[4] == '/' && name[5] == '/')) | ||
226 | { | ||
227 | name += POP_SCHEME_LEN; | ||
228 | name_len -= POP_SCHEME_LEN; | ||
229 | } | ||
230 | |||
231 | /* Allocate memory for mbox. */ | ||
232 | mbox = calloc (1, sizeof (*mbox)); | ||
233 | if (mbox == NULL) | ||
234 | return ENOMEM; | ||
235 | 264 | ||
236 | /* Allocate specifics for pop data. */ | 265 | /* Allocate specifics for pop data. */ |
237 | mpd = mbox->data = calloc (1, sizeof (*mpd)); | 266 | mpd = mbox->data = calloc (1, sizeof (*mpd)); |
238 | if (mbox->data == NULL) | 267 | if (mbox->data == NULL) |
239 | { | 268 | return ENOMEM; |
240 | pop_destroy (&mbox); | ||
241 | return ENOMEM; | ||
242 | } | ||
243 | mpd->state = POP_NO_STATE; | ||
244 | mpd->mbox = mbox; | ||
245 | 269 | ||
246 | /* Copy the name. */ | 270 | mpd->mbox = mbox; /* Back pointer. */ |
247 | mbox->name = calloc (name_len + 1, sizeof (char)); | 271 | |
248 | if (mbox->name == NULL) | 272 | mpd->state = POP_NO_STATE; /* Init with no state. */ |
249 | { | ||
250 | pop_destroy (&mbox); | ||
251 | return ENOMEM; | ||
252 | } | ||
253 | memcpy (mbox->name, name, name_len); | ||
254 | |||
255 | #ifdef HAVE_PHTREAD_H | ||
256 | /* Mutex when accessing the structure fields. */ | ||
257 | /* FIXME: should we use rdwr locks instead ?? */ | ||
258 | /* XXXX: This is not use yet and the library is still not thread safe. This | ||
259 | is more a gentle remider that I got more work to do. */ | ||
260 | pthread_mutex_init (&(mpd->mutex), NULL); | ||
261 | #endif | ||
262 | 273 | ||
263 | /* Initialize the structure. */ | 274 | /* Initialize the structure. */ |
264 | mbox->_create = pop_create; | 275 | mbox->_init = pop_init; |
265 | mbox->_destroy = pop_destroy; | 276 | mbox->_destroy = pop_destroy; |
266 | 277 | ||
267 | mbox->_open = pop_open; | 278 | mbox->_open = pop_open; |
... | @@ -271,128 +282,123 @@ pop_create (mailbox_t *pmbox, const char *name) | ... | @@ -271,128 +282,123 @@ pop_create (mailbox_t *pmbox, const char *name) |
271 | mbox->_get_message = pop_get_message; | 282 | mbox->_get_message = pop_get_message; |
272 | mbox->_messages_count = pop_messages_count; | 283 | mbox->_messages_count = pop_messages_count; |
273 | mbox->_expunge = pop_expunge; | 284 | mbox->_expunge = pop_expunge; |
274 | mbox->_num_deleted = pop_num_deleted; | ||
275 | 285 | ||
276 | mbox->_scan = pop_scan; | 286 | mbox->_scan = pop_scan; |
277 | mbox->_is_updated = pop_is_updated; | 287 | mbox->_is_updated = pop_is_updated; |
278 | 288 | ||
279 | mbox->_size = pop_size; | 289 | mbox->_size = pop_size; |
280 | 290 | ||
281 | (*pmbox) = mbox; | ||
282 | |||
283 | return 0; /* Okdoke. */ | 291 | return 0; /* Okdoke. */ |
284 | } | 292 | } |
285 | 293 | ||
286 | /* Cleaning up all the ressources associate with a pop mailbox. */ | 294 | /* Cleaning up all the ressources associate with a pop mailbox. */ |
287 | static void | 295 | static void |
288 | pop_destroy (mailbox_t *pmbox) | 296 | pop_destroy (mailbox_t mbox) |
289 | { | 297 | { |
290 | if (pmbox && *pmbox) | 298 | if (mbox->data) |
291 | { | 299 | { |
292 | mailbox_t mbox = *pmbox; | 300 | pop_data_t mpd = mbox->data; |
293 | if (mbox->data) | 301 | size_t i; |
302 | mailbox_wrlock (mbox); | ||
303 | /* Destroy the pop messages and ressources associated to them. */ | ||
304 | for (i = 0; i < mpd->pmessages_count; i++) | ||
294 | { | 305 | { |
295 | pop_data_t mpd = mbox->data; | 306 | if (mpd->pmessages[i]) |
296 | size_t i; | ||
297 | /* Destroy the pop messages and ressources associated to them. */ | ||
298 | for (i = 0; i < mpd->pmessages_count; i++) | ||
299 | { | 307 | { |
300 | if (mpd->pmessages[i]) | 308 | message_destroy (&(mpd->pmessages[i]->message), |
301 | { | 309 | mpd->pmessages[i]); |
302 | message_destroy (&(mpd->pmessages[i]->message), | 310 | free (mpd->pmessages[i]); |
303 | mpd->pmessages[i]); | 311 | mpd->pmessages[i] = NULL; |
304 | free (mpd->pmessages[i]); | ||
305 | mpd->pmessages[i] = NULL; | ||
306 | } | ||
307 | } | 312 | } |
308 | bio_destroy (&(mpd->bio)); | ||
309 | free (mpd->buffer); | ||
310 | mpd->buffer = NULL; | ||
311 | free (mpd->pmessages); | ||
312 | mpd->pmessages = NULL; | ||
313 | #ifdef HAVE_PHTREAD_H | ||
314 | pthread_mutex_destroy (&(mpd->mutex)); | ||
315 | #endif | ||
316 | free (mpd); | ||
317 | mbox->data = NULL; | ||
318 | } | ||
319 | /* Since the mailbox is destroy, close the stream but not via | ||
320 | pop_close () which can return EAGAIN, or other unpleasant side | ||
321 | effects, but rather the hard way. */ | ||
322 | stream_close (mbox->stream); | ||
323 | stream_destroy (&(mbox->stream), mbox); | ||
324 | auth_destroy (&(mbox->auth), mbox); | ||
325 | if (mbox->name) | ||
326 | { | ||
327 | free (mbox->name); | ||
328 | mbox->name = NULL; | ||
329 | } | 313 | } |
330 | if (mbox->event) | 314 | bio_destroy (&(mpd->bio)); |
331 | { | 315 | free (mpd->buffer); |
332 | free (mbox->event); | 316 | mpd->buffer = NULL; |
333 | mbox->event = NULL; | 317 | free (mpd->pmessages); |
334 | } | 318 | mpd->pmessages = NULL; |
335 | if (mbox->url) | 319 | free (mpd); |
336 | url_destroy (&(mbox->url)); | 320 | mbox->data = NULL; |
337 | free (mbox); | 321 | mailbox_unlock (mbox); |
338 | *pmbox = NULL; | ||
339 | } | 322 | } |
340 | } | 323 | } |
341 | 324 | ||
342 | static void | ||
343 | echo_off(struct termios *stored_settings) | ||
344 | { | ||
345 | struct termios new_settings; | ||
346 | tcgetattr (0, stored_settings); | ||
347 | new_settings = *stored_settings; | ||
348 | new_settings.c_lflag &= (~ECHO); | ||
349 | tcsetattr (0, TCSANOW, &new_settings); | ||
350 | } | ||
351 | |||
352 | static void | ||
353 | echo_on(struct termios *stored_settings) | ||
354 | { | ||
355 | tcsetattr (0, TCSANOW, stored_settings); | ||
356 | } | ||
357 | |||
358 | /* User/pass authentication for pop. */ | 325 | /* User/pass authentication for pop. */ |
359 | static int | 326 | int |
360 | pop_authenticate (auth_t auth, char **user, char **passwd) | 327 | pop_user (authority_t auth) |
361 | { | 328 | { |
362 | /* FIXME: This incorrect and goes against GNU style: having a limitation on | 329 | mailbox_t mbox = authority_get_owner (auth); |
363 | the user/passwd length, it should be fix. */ | 330 | pop_data_t mpd = mbox->data; |
364 | char u[128]; | 331 | ticket_t ticket; |
365 | char p[128]; | ||
366 | mailbox_t mbox = auth->owner; | ||
367 | int status; | 332 | int status; |
368 | /* We should probably use getpass () or something similar. */ | ||
369 | struct termios stored_settings; | ||
370 | 333 | ||
371 | *u = '\0'; | 334 | switch (mpd->state) |
372 | *p = '\0'; | ||
373 | memset (&stored_settings, 0, sizeof (stored_settings)); | ||
374 | |||
375 | /* Prompt for the user/login name. */ | ||
376 | status = url_get_user (mbox->url, u, sizeof (u), NULL); | ||
377 | if (status != 0 || *u == '\0') | ||
378 | { | ||
379 | printf ("Pop User: "); fflush (stdout); | ||
380 | fgets (u, sizeof (u), stdin); | ||
381 | u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */ | ||
382 | } | ||
383 | /* Prompt for the passwd. */ | ||
384 | status = url_get_passwd (mbox->url, p, sizeof (p), NULL); | ||
385 | if (status != 0 || *p == '\0' || *p == '*') | ||
386 | { | 335 | { |
387 | printf ("Pop Passwd: "); | 336 | case POP_AUTH: |
388 | fflush (stdout); | 337 | authority_get_ticket (auth, &ticket); |
389 | echo_off (&stored_settings); | 338 | /* Fetch the user/passwd from them. */ |
390 | fgets (p, sizeof(p), stdin); | 339 | ticket_pop (ticket, "Pop User: ", &mpd->user); |
391 | echo_on (&stored_settings); | 340 | ticket_pop (ticket, "Pop Passwd: ", &mpd->passwd); |
392 | p [strlen (p) - 1] = '\0'; | 341 | status = pop_writeline (mpd, "USER %s\r\n", mpd->user); |
342 | CHECK_ERROR_CLOSE(mbox, mpd, status); | ||
343 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
344 | free (mpd->user); | ||
345 | mpd->user = NULL; | ||
346 | mpd->state = POP_AUTH_USER; | ||
347 | |||
348 | case POP_AUTH_USER: | ||
349 | /* Send username. */ | ||
350 | status = pop_write (mpd); | ||
351 | CHECK_EAGAIN (mpd, status); | ||
352 | mpd->state = POP_AUTH_USER_ACK; | ||
353 | |||
354 | case POP_AUTH_USER_ACK: | ||
355 | /* Get the user ack. */ | ||
356 | status = pop_read_ack (mpd); | ||
357 | CHECK_EAGAIN (mpd, status); | ||
358 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
359 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | ||
360 | { | ||
361 | observable_t observable = NULL; | ||
362 | mailbox_get_observable (mbox, &observable); | ||
363 | observable_notify (observable, MU_EVT_AUTHORITY_FAILED); | ||
364 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | ||
365 | } | ||
366 | status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd); | ||
367 | CHECK_ERROR_CLOSE (mbox, mpd, status); | ||
368 | /* We have to nuke the passwd. */ | ||
369 | memset (mpd->passwd, 0, strlen (mpd->passwd)); | ||
370 | free (mpd->passwd); | ||
371 | mpd->passwd = NULL; | ||
372 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n"); | ||
373 | mpd->state = POP_AUTH_PASS; | ||
374 | |||
375 | case POP_AUTH_PASS: | ||
376 | /* Send passwd. */ | ||
377 | status = pop_write (mpd); | ||
378 | CHECK_EAGAIN (mpd, status); | ||
379 | /* We have to nuke the passwd. */ | ||
380 | memset (mpd->buffer, 0, mpd->buflen); | ||
381 | mpd->state = POP_AUTH_PASS_ACK; | ||
382 | |||
383 | case POP_AUTH_PASS_ACK: | ||
384 | /* Get the ack from passwd. */ | ||
385 | status = pop_read_ack (mpd); | ||
386 | CHECK_EAGAIN (mpd, status); | ||
387 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
388 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | ||
389 | { | ||
390 | observable_t observable = NULL; | ||
391 | mailbox_get_observable (mbox, &observable); | ||
392 | observable_notify (observable, MU_EVT_AUTHORITY_FAILED); | ||
393 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | ||
394 | } | ||
395 | mpd->state = POP_AUTH_DONE; | ||
396 | break; /* We're outta here. */ | ||
397 | |||
398 | default: | ||
399 | break; | ||
393 | } | 400 | } |
394 | *user = strdup (u); | 401 | CLEAR_STATE (mpd); |
395 | *passwd = strdup (p); | ||
396 | return 0; | 402 | return 0; |
397 | } | 403 | } |
398 | 404 | ||
... | @@ -412,24 +418,14 @@ pop_open (mailbox_t mbox, int flags) | ... | @@ -412,24 +418,14 @@ pop_open (mailbox_t mbox, int flags) |
412 | if (mbox->url == NULL || mpd == NULL) | 418 | if (mbox->url == NULL || mpd == NULL) |
413 | return EINVAL; | 419 | return EINVAL; |
414 | 420 | ||
421 | mbox->flags = flags | MU_STREAM_POP; | ||
422 | |||
415 | /* Fetch the pop server name and the port in the url_t. */ | 423 | /* Fetch the pop server name and the port in the url_t. */ |
416 | if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0 | 424 | if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0 |
417 | || (status = url_get_port (mbox->url, &port)) != 0) | 425 | || (status = url_get_port (mbox->url, &port)) != 0) |
418 | return status; | 426 | return status; |
419 | 427 | ||
420 | /* Dealing whith Authentication. So far only normal user/pass supported. */ | 428 | CHECK_BUSY (mbox, mpd, func, 0); |
421 | if (mbox->auth == NULL) | ||
422 | { | ||
423 | status = auth_create (&(mbox->auth), mbox); | ||
424 | if (status != 0) | ||
425 | return status; | ||
426 | auth_set_authenticate (mbox->auth, pop_authenticate, mbox); | ||
427 | } | ||
428 | |||
429 | /* Flag busy. */ | ||
430 | if (mpd->func && mpd->func != func) | ||
431 | return EBUSY; | ||
432 | mpd->func = func; | ||
433 | 429 | ||
434 | /* Enter the pop state machine, and boogy: AUTHORISATION State. */ | 430 | /* Enter the pop state machine, and boogy: AUTHORISATION State. */ |
435 | switch (mpd->state) | 431 | switch (mpd->state) |
... | @@ -447,31 +443,21 @@ pop_open (mailbox_t mbox, int flags) | ... | @@ -447,31 +443,21 @@ pop_open (mailbox_t mbox, int flags) |
447 | mpd->ptr = mpd->buffer; | 443 | mpd->ptr = mpd->buffer; |
448 | } | 444 | } |
449 | 445 | ||
450 | /* Spawn auth prologue. */ | ||
451 | auth_prologue (mbox->auth); | ||
452 | |||
453 | /* Create the networking stack. */ | 446 | /* Create the networking stack. */ |
454 | if (mbox->stream == NULL) | 447 | if (mbox->stream == NULL) |
455 | { | 448 | { |
456 | status = tcp_stream_create (&(mbox->stream)); | 449 | status = tcp_stream_create (&(mbox->stream)); |
457 | CHECK_ERROR(mpd, status); | 450 | CHECK_ERROR(mpd, status); |
458 | } | 451 | } |
452 | else | ||
453 | stream_close (mbox->stream); | ||
459 | mpd->state = POP_OPEN_CONNECTION; | 454 | mpd->state = POP_OPEN_CONNECTION; |
460 | 455 | ||
461 | case POP_OPEN_CONNECTION: | 456 | case POP_OPEN_CONNECTION: |
462 | /* Establish the connection. */ | 457 | /* Establish the connection. */ |
463 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, "open (%s:%d)\n", | 458 | MAILBOX_DEBUG2 (mbox, MU_DEBUG_PROT, "open (%s:%d)\n", host, port); |
464 | host, port); | 459 | status = stream_open (mbox->stream, host, port, mbox->flags); |
465 | status = stream_open (mbox->stream, host, port, flags); | 460 | CHECK_EAGAIN (mpd, status); |
466 | if (status != 0) | ||
467 | { | ||
468 | /* Clear the state for non recoverable error. */ | ||
469 | if (status != EAGAIN && status != EINPROGRESS && status != EINTR) | ||
470 | { | ||
471 | CLEAR_STATE (mpd); | ||
472 | } | ||
473 | return status; | ||
474 | } | ||
475 | /* Need to destroy the old bio maybe a different stream. */ | 461 | /* Need to destroy the old bio maybe a different stream. */ |
476 | bio_destroy (&(mpd->bio)); | 462 | bio_destroy (&(mpd->bio)); |
477 | /* Allocate the struct for buffered I/O. */ | 463 | /* Allocate the struct for buffered I/O. */ |
... | @@ -481,67 +467,42 @@ pop_open (mailbox_t mbox, int flags) | ... | @@ -481,67 +467,42 @@ pop_open (mailbox_t mbox, int flags) |
481 | mpd->state = POP_GREETINGS; | 467 | mpd->state = POP_GREETINGS; |
482 | 468 | ||
483 | case POP_GREETINGS: | 469 | case POP_GREETINGS: |
484 | /* Swallow the greetings. */ | 470 | { |
485 | status = pop_read_ack (mpd); | 471 | char auth[64] = ""; |
486 | CHECK_EAGAIN (mpd, status); | 472 | size_t n = 0; |
487 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 473 | /* Swallow the greetings. */ |
488 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | 474 | status = pop_read_ack (mpd); |
489 | { | 475 | CHECK_EAGAIN (mpd, status); |
490 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | 476 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
491 | } | 477 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) |
492 | 478 | { | |
493 | /* Fetch the user/passwd from them. */ | 479 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); |
494 | auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd); | 480 | } |
495 | |||
496 | status = pop_writeline (mpd, "USER %s\r\n", mpd->user); | ||
497 | CHECK_ERROR_CLOSE(mbox, mpd, status); | ||
498 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | ||
499 | free (mpd->user); | ||
500 | mpd->user = NULL; | ||
501 | mpd->state = POP_USER_TX; | ||
502 | |||
503 | case POP_USER_TX: | ||
504 | /* Send username. */ | ||
505 | status = pop_write (mpd); | ||
506 | CHECK_EAGAIN (mpd, status); | ||
507 | mpd->state = POP_USER_ACK; | ||
508 | 481 | ||
509 | case POP_USER_ACK: | 482 | url_get_auth (mbox->url, auth, 64, &n); |
510 | /* Get the user ack. */ | 483 | if (n == 0 || strcasecmp (auth, "*") == 0) |
511 | status = pop_read_ack (mpd); | 484 | { |
512 | CHECK_EAGAIN (mpd, status); | 485 | authority_create (&(mbox->authority), mbox->ticket, mbox); |
513 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 486 | authority_set_authenticate (mbox->authority, pop_user, mbox); |
514 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | 487 | } |
515 | { | 488 | else if (strcasecmp (auth, "+apop") == 0) |
516 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | 489 | { |
517 | } | 490 | /* Not supported. */ |
518 | status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd); | 491 | } |
519 | CHECK_ERROR_CLOSE (mbox, mpd, status); | 492 | else |
520 | /* We have to nuke the passwd. */ | 493 | { |
521 | memset (mpd->passwd, 0, strlen (mpd->passwd)); | 494 | /* What can do flag an error ? */ |
522 | free (mpd->passwd); | 495 | } |
523 | mpd->passwd = NULL; | 496 | mpd->state = POP_AUTH; |
524 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, "PASS *\n"); | 497 | } |
525 | mpd->state = POP_PASS_TX; | ||
526 | 498 | ||
527 | case POP_PASS_TX: | 499 | case POP_AUTH: |
528 | /* Send passwd. */ | 500 | status = authority_authenticate (mbox->authority); |
529 | status = pop_write (mpd); | 501 | if (status != 0) |
530 | CHECK_EAGAIN (mpd, status); | 502 | return status; |
531 | /* We have to nuke the passwd. */ | ||
532 | memset (mpd->buffer, 0, mpd->buflen); | ||
533 | mpd->state = POP_PASS_ACK; | ||
534 | 503 | ||
535 | case POP_PASS_ACK: | 504 | case POP_AUTH_DONE: |
536 | /* Get the ack from passwd. */ | 505 | break; |
537 | status = pop_read_ack (mpd); | ||
538 | CHECK_EAGAIN (mpd, status); | ||
539 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | ||
540 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | ||
541 | { | ||
542 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | ||
543 | } | ||
544 | break; /* We're outta here. */ | ||
545 | 506 | ||
546 | default: | 507 | default: |
547 | /* | 508 | /* |
... | @@ -550,9 +511,6 @@ pop_open (mailbox_t mbox, int flags) | ... | @@ -550,9 +511,6 @@ pop_open (mailbox_t mbox, int flags) |
550 | break; | 511 | break; |
551 | }/* End AUTHORISATION state. */ | 512 | }/* End AUTHORISATION state. */ |
552 | 513 | ||
553 | /* Spawn cleanup functions. */ | ||
554 | auth_epilogue (mbox->auth); | ||
555 | |||
556 | /* Clear any state. */ | 514 | /* Clear any state. */ |
557 | CLEAR_STATE (mpd); | 515 | CLEAR_STATE (mpd); |
558 | return 0; | 516 | return 0; |
... | @@ -570,11 +528,13 @@ pop_close (mailbox_t mbox) | ... | @@ -570,11 +528,13 @@ pop_close (mailbox_t mbox) |
570 | if (mpd == NULL) | 528 | if (mpd == NULL) |
571 | return EINVAL; | 529 | return EINVAL; |
572 | 530 | ||
573 | /* Flag busy ? */ | 531 | /* CHECK_BUSY (mbox, mpd, func, 0); */ |
532 | mailbox_wrlock (mbox); | ||
574 | if (mpd->func && mpd->func != func) | 533 | if (mpd->func && mpd->func != func) |
575 | return EBUSY; | 534 | mpd->state = POP_NO_STATE; |
576 | 535 | mpd->id = 0; | |
577 | mpd->func = func; | 536 | mpd->func = func; |
537 | mailbox_unlock (mbox); | ||
578 | 538 | ||
579 | /* Ok boys, it's a wrap: UPDATE State. */ | 539 | /* Ok boys, it's a wrap: UPDATE State. */ |
580 | switch (mpd->state) | 540 | switch (mpd->state) |
... | @@ -582,10 +542,10 @@ pop_close (mailbox_t mbox) | ... | @@ -582,10 +542,10 @@ pop_close (mailbox_t mbox) |
582 | case POP_NO_STATE: | 542 | case POP_NO_STATE: |
583 | /* Initiate the close. */ | 543 | /* Initiate the close. */ |
584 | status = pop_writeline (mpd, "QUIT\r\n"); | 544 | status = pop_writeline (mpd, "QUIT\r\n"); |
585 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 545 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
586 | mpd->state = POP_QUIT_TX; | 546 | mpd->state = POP_QUIT; |
587 | 547 | ||
588 | case POP_QUIT_TX: | 548 | case POP_QUIT: |
589 | /* Send the quit. */ | 549 | /* Send the quit. */ |
590 | status = pop_write (mpd); | 550 | status = pop_write (mpd); |
591 | CHECK_EAGAIN (mpd, status); | 551 | CHECK_EAGAIN (mpd, status); |
... | @@ -595,7 +555,7 @@ pop_close (mailbox_t mbox) | ... | @@ -595,7 +555,7 @@ pop_close (mailbox_t mbox) |
595 | /* Glob the acknowledge. */ | 555 | /* Glob the acknowledge. */ |
596 | status = pop_read_ack (mpd); | 556 | status = pop_read_ack (mpd); |
597 | CHECK_EAGAIN (mpd, status); | 557 | CHECK_EAGAIN (mpd, status); |
598 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 558 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
599 | /* Now what ! and how can we tell them about errors ? So far now | 559 | /* Now what ! and how can we tell them about errors ? So far now |
600 | lets just be verbose about the error but close the connection | 560 | lets just be verbose about the error but close the connection |
601 | anyway. */ | 561 | anyway. */ |
... | @@ -649,6 +609,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -649,6 +609,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
649 | if (pmsg == NULL || mpd == NULL) | 609 | if (pmsg == NULL || mpd == NULL) |
650 | return EINVAL; | 610 | return EINVAL; |
651 | 611 | ||
612 | mailbox_rdlock (mbox); | ||
652 | /* See if we have already this message. */ | 613 | /* See if we have already this message. */ |
653 | for (i = 0; i < mpd->pmessages_count; i++) | 614 | for (i = 0; i < mpd->pmessages_count; i++) |
654 | { | 615 | { |
... | @@ -657,10 +618,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -657,10 +618,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
657 | if (mpd->pmessages[i]->num == msgno) | 618 | if (mpd->pmessages[i]->num == msgno) |
658 | { | 619 | { |
659 | *pmsg = mpd->pmessages[i]->message; | 620 | *pmsg = mpd->pmessages[i]->message; |
621 | mailbox_unlock (mbox); | ||
660 | return 0; | 622 | return 0; |
661 | } | 623 | } |
662 | } | 624 | } |
663 | } | 625 | } |
626 | mailbox_unlock (mbox); | ||
664 | 627 | ||
665 | mpm = calloc (1, sizeof (*mpm)); | 628 | mpm = calloc (1, sizeof (*mpm)); |
666 | if (mpm == NULL) | 629 | if (mpm == NULL) |
... | @@ -674,51 +637,49 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -674,51 +637,49 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
674 | { | 637 | { |
675 | stream_t stream = NULL; | 638 | stream_t stream = NULL; |
676 | if ((status = message_create (&msg, mpm)) != 0 | 639 | if ((status = message_create (&msg, mpm)) != 0 |
677 | || (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0) | 640 | || (status = stream_create (&stream, mbox->flags, msg)) != 0) |
678 | { | 641 | { |
642 | stream_destroy (&stream, msg); | ||
679 | message_destroy (&msg, mpm); | 643 | message_destroy (&msg, mpm); |
680 | stream_destroy (&stream, mpm); | ||
681 | free (mpm); | 644 | free (mpm); |
682 | return status; | 645 | return status; |
683 | } | 646 | } |
684 | stream_set_read (stream, pop_read_message, mpm); | 647 | stream_set_read (stream, pop_message_read, msg); |
685 | stream_set_fd (stream, pop_get_fd, mpm); | 648 | stream_set_fd (stream, pop_message_fd, msg); |
686 | stream_set_flags (stream, MU_STREAM_READ, mpm); | ||
687 | message_set_stream (msg, stream, mpm); | 649 | message_set_stream (msg, stream, mpm); |
650 | message_set_size (msg, pop_message_size, mpm); | ||
688 | } | 651 | } |
689 | 652 | ||
690 | /* Create the header. */ | 653 | /* Create the header. */ |
691 | { | 654 | { |
692 | header_t header = NULL; | 655 | header_t header = NULL; |
693 | stream_t stream = NULL; | 656 | stream_t stream = NULL; |
694 | if ((status = header_create (&header, NULL, 0, mpm)) != 0 | 657 | if ((status = header_create (&header, NULL, 0, msg)) != 0 |
695 | || (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0) | 658 | || (status = stream_create (&stream, mbox->flags, header)) != 0) |
696 | { | 659 | { |
697 | header_destroy (&header, mpm); | 660 | stream_destroy (&stream, header); |
698 | stream_destroy (&stream, mpm); | 661 | header_destroy (&header, msg); |
699 | message_destroy (&msg, mpm); | 662 | message_destroy (&msg, mpm); |
700 | free (mpm); | 663 | free (mpm); |
701 | return status; | 664 | return status; |
702 | } | 665 | } |
703 | stream_set_read (stream, pop_top, mpm); | 666 | stream_set_read (stream, pop_top, header); |
704 | //stream_set_read (stream, pop_read_header, mpm); | 667 | stream_set_fd (stream, pop_header_fd, header); |
705 | stream_set_fd (stream, pop_get_fd, mpm); | 668 | header_set_stream (header, stream, msg); |
706 | stream_set_flags (stream, MU_STREAM_READ, mpm); | ||
707 | header_set_stream (header, stream, mpm); | ||
708 | message_set_header (msg, header, mpm); | 669 | message_set_header (msg, header, mpm); |
709 | } | 670 | } |
710 | 671 | ||
711 | /* Create the attribute. */ | 672 | /* Create the attribute. */ |
712 | { | 673 | { |
713 | attribute_t attribute; | 674 | attribute_t attribute; |
714 | status = attribute_create (&attribute, mpm); | 675 | status = attribute_create (&attribute, msg); |
715 | if (status != 0) | 676 | if (status != 0) |
716 | { | 677 | { |
717 | message_destroy (&msg, mpm); | 678 | message_destroy (&msg, mpm); |
718 | free (mpm); | 679 | free (mpm); |
719 | return status; | 680 | return status; |
720 | } | 681 | } |
721 | attribute_set_get_flags (attribute, pop_get_flags, mpm); | 682 | attribute_set_get_flags (attribute, pop_attr_flags, msg); |
722 | message_set_attribute (msg, attribute, mpm); | 683 | message_set_attribute (msg, attribute, mpm); |
723 | } | 684 | } |
724 | 685 | ||
... | @@ -726,21 +687,20 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -726,21 +687,20 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
726 | { | 687 | { |
727 | body_t body = NULL; | 688 | body_t body = NULL; |
728 | stream_t stream = NULL; | 689 | stream_t stream = NULL; |
729 | if ((status = body_create (&body, mpm)) != 0 | 690 | if ((status = body_create (&body, msg)) != 0 |
730 | || (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0) | 691 | || (status = stream_create (&stream, mbox->flags, body)) != 0) |
731 | { | 692 | { |
732 | body_destroy (&body, mpm); | 693 | body_destroy (&body, msg); |
733 | stream_destroy (&stream, mpm); | 694 | stream_destroy (&stream, body); |
734 | message_destroy (&msg, mpm); | 695 | message_destroy (&msg, mpm); |
735 | free (mpm); | 696 | free (mpm); |
736 | return status; | 697 | return status; |
737 | } | 698 | } |
738 | stream_set_read (stream, pop_read_body, mpm); | 699 | stream_set_read (stream, pop_body_read, body); |
739 | stream_set_fd (stream, pop_get_fd, mpm); | 700 | stream_set_fd (stream, pop_body_fd, body); |
740 | stream_set_flags (stream, mpd->flags, mpm); | 701 | body_set_size (body, pop_body_size, msg); |
741 | body_set_size (body, pop_body_size, mpm); | 702 | body_set_lines (body, pop_body_lines, msg); |
742 | body_set_lines (body, pop_body_lines, mpm); | 703 | body_set_stream (body, stream, msg); |
743 | body_set_stream (body, stream, mpm); | ||
744 | message_set_body (msg, body, mpm); | 704 | message_set_body (msg, body, mpm); |
745 | } | 705 | } |
746 | 706 | ||
... | @@ -748,6 +708,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -748,6 +708,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
748 | message_set_uidl (msg, pop_uidl, mpm); | 708 | message_set_uidl (msg, pop_uidl, mpm); |
749 | 709 | ||
750 | /* Add it to the list. */ | 710 | /* Add it to the list. */ |
711 | mailbox_wrlock (mbox); | ||
751 | { | 712 | { |
752 | pop_message_t *m ; | 713 | pop_message_t *m ; |
753 | m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m)); | 714 | m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m)); |
... | @@ -755,12 +716,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) | ... | @@ -755,12 +716,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) |
755 | { | 716 | { |
756 | message_destroy (&msg, mpm); | 717 | message_destroy (&msg, mpm); |
757 | free (mpm); | 718 | free (mpm); |
719 | mailbox_unlock (mbox); | ||
758 | return ENOMEM; | 720 | return ENOMEM; |
759 | } | 721 | } |
760 | mpd->pmessages = m; | 722 | mpd->pmessages = m; |
761 | mpd->pmessages[mpd->pmessages_count] = mpm; | 723 | mpd->pmessages[mpd->pmessages_count] = mpm; |
762 | mpd->pmessages_count++; | 724 | mpd->pmessages_count++; |
763 | } | 725 | } |
726 | mailbox_unlock (mbox); | ||
764 | 727 | ||
765 | /* Save The message. */ | 728 | /* Save The message. */ |
766 | *pmsg = mpm->message = msg; | 729 | *pmsg = mpm->message = msg; |
... | @@ -788,10 +751,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) | ... | @@ -788,10 +751,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) |
788 | } | 751 | } |
789 | 752 | ||
790 | /* Flag busy. */ | 753 | /* Flag busy. */ |
791 | if (mpd->func && mpd->func != func) | 754 | CHECK_BUSY (mbox, mpd, func, 0); |
792 | return EBUSY; | ||
793 | |||
794 | mpd->func = func; | ||
795 | 755 | ||
796 | /* TRANSACTION state. */ | 756 | /* TRANSACTION state. */ |
797 | switch (mpd->state) | 757 | switch (mpd->state) |
... | @@ -799,10 +759,10 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) | ... | @@ -799,10 +759,10 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) |
799 | case POP_NO_STATE: | 759 | case POP_NO_STATE: |
800 | status = pop_writeline (mpd, "STAT\r\n"); | 760 | status = pop_writeline (mpd, "STAT\r\n"); |
801 | CHECK_ERROR (mpd, status); | 761 | CHECK_ERROR (mpd, status); |
802 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 762 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
803 | mpd->state = POP_STAT_TX; | 763 | mpd->state = POP_STAT; |
804 | 764 | ||
805 | case POP_STAT_TX: | 765 | case POP_STAT: |
806 | /* Send the STAT. */ | 766 | /* Send the STAT. */ |
807 | status = pop_write (mpd); | 767 | status = pop_write (mpd); |
808 | CHECK_EAGAIN (mpd, status); | 768 | CHECK_EAGAIN (mpd, status); |
... | @@ -812,7 +772,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) | ... | @@ -812,7 +772,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount) |
812 | /* Get the ACK. */ | 772 | /* Get the ACK. */ |
813 | status = pop_read_ack (mpd); | 773 | status = pop_read_ack (mpd); |
814 | CHECK_EAGAIN (mpd, status); | 774 | CHECK_EAGAIN (mpd, status); |
815 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 775 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
816 | break; | 776 | break; |
817 | 777 | ||
818 | default: | 778 | default: |
... | @@ -850,33 +810,6 @@ pop_is_updated (mailbox_t mbox) | ... | @@ -850,33 +810,6 @@ pop_is_updated (mailbox_t mbox) |
850 | return mpd->is_updated; | 810 | return mpd->is_updated; |
851 | } | 811 | } |
852 | 812 | ||
853 | /* We do not send anything to the server since, no DELE command is sent but | ||
854 | the only the attribute flag is modified. | ||
855 | DELE is sent only when expunging. */ | ||
856 | static int | ||
857 | pop_num_deleted (mailbox_t mbox, size_t *pnum) | ||
858 | { | ||
859 | pop_data_t mpd = mbox->data; | ||
860 | size_t i, total; | ||
861 | attribute_t attr; | ||
862 | |||
863 | if (mpd == NULL) | ||
864 | return EINVAL; | ||
865 | |||
866 | for (i = total = 0; i < mpd->messages_count; i++) | ||
867 | { | ||
868 | if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0) | ||
869 | { | ||
870 | if (attribute_is_deleted (attr)) | ||
871 | total++; | ||
872 | } | ||
873 | } | ||
874 | |||
875 | if (pnum) | ||
876 | *pnum = total; | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | /* We just simulated. By sending a notification for the total msgno. */ | 813 | /* We just simulated. By sending a notification for the total msgno. */ |
881 | /* FIXME is message is set deleted should we sent a notif ? */ | 814 | /* FIXME is message is set deleted should we sent a notif ? */ |
882 | static int | 815 | static int |
... | @@ -888,8 +821,10 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) | ... | @@ -888,8 +821,10 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) |
888 | status = pop_messages_count (mbox, pcount); | 821 | status = pop_messages_count (mbox, pcount); |
889 | if (status != 0) | 822 | if (status != 0) |
890 | return status; | 823 | return status; |
824 | if (mbox->observable == NULL) | ||
825 | return 0; | ||
891 | for (i = msgno; i <= *pcount; i++) | 826 | for (i = msgno; i <= *pcount; i++) |
892 | if (mailbox_notification (mbox, MU_EVT_MBX_MSG_ADD) != 0) | 827 | if (observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0) |
893 | break; | 828 | break; |
894 | return 0; | 829 | return 0; |
895 | } | 830 | } |
... | @@ -908,10 +843,7 @@ pop_expunge (mailbox_t mbox) | ... | @@ -908,10 +843,7 @@ pop_expunge (mailbox_t mbox) |
908 | return EINVAL; | 843 | return EINVAL; |
909 | 844 | ||
910 | /* Busy ? */ | 845 | /* Busy ? */ |
911 | if (mpd->func && mpd->func != func) | 846 | CHECK_BUSY (mbox, mpd, func, 0); |
912 | return EBUSY; | ||
913 | |||
914 | mpd->func = func; | ||
915 | 847 | ||
916 | for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i) | 848 | for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i) |
917 | { | 849 | { |
... | @@ -925,10 +857,10 @@ pop_expunge (mailbox_t mbox) | ... | @@ -925,10 +857,10 @@ pop_expunge (mailbox_t mbox) |
925 | status = pop_writeline (mpd, "DELE %d\r\n", | 857 | status = pop_writeline (mpd, "DELE %d\r\n", |
926 | mpd->pmessages[i]->num); | 858 | mpd->pmessages[i]->num); |
927 | CHECK_ERROR (mpd, status); | 859 | CHECK_ERROR (mpd, status); |
928 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 860 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
929 | mpd->state = POP_DELE_TX; | 861 | mpd->state = POP_DELE; |
930 | 862 | ||
931 | case POP_DELE_TX: | 863 | case POP_DELE: |
932 | /* Send DELETE. */ | 864 | /* Send DELETE. */ |
933 | status = pop_write (mpd); | 865 | status = pop_write (mpd); |
934 | CHECK_EAGAIN (mpd, status); | 866 | CHECK_EAGAIN (mpd, status); |
... | @@ -937,7 +869,7 @@ pop_expunge (mailbox_t mbox) | ... | @@ -937,7 +869,7 @@ pop_expunge (mailbox_t mbox) |
937 | case POP_DELE_ACK: | 869 | case POP_DELE_ACK: |
938 | status = pop_read_ack (mpd); | 870 | status = pop_read_ack (mpd); |
939 | CHECK_EAGAIN (mpd, status); | 871 | CHECK_EAGAIN (mpd, status); |
940 | mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 872 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); |
941 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | 873 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) |
942 | { | 874 | { |
943 | CHECK_ERROR (mpd, ERANGE); | 875 | CHECK_ERROR (mpd, ERANGE); |
... | @@ -952,9 +884,7 @@ pop_expunge (mailbox_t mbox) | ... | @@ -952,9 +884,7 @@ pop_expunge (mailbox_t mbox) |
952 | } /* if attribute_is_deleted() */ | 884 | } /* if attribute_is_deleted() */ |
953 | } /* message_get_attribute() */ | 885 | } /* message_get_attribute() */ |
954 | } /* for */ | 886 | } /* for */ |
955 | mpd->id = 0; | 887 | CLEAR_STATE (mpd); |
956 | mpd->func = NULL; | ||
957 | mpd->state = POP_NO_STATE; | ||
958 | /* Invalidate. But Really they should shutdown the channel POP protocol | 888 | /* Invalidate. But Really they should shutdown the channel POP protocol |
959 | is not meant for this like IMAP. */ | 889 | is not meant for this like IMAP. */ |
960 | mpd->is_updated = 0; | 890 | mpd->is_updated = 0; |
... | @@ -978,21 +908,111 @@ pop_size (mailbox_t mbox, off_t *psize) | ... | @@ -978,21 +908,111 @@ pop_size (mailbox_t mbox, off_t *psize) |
978 | return status; | 908 | return status; |
979 | } | 909 | } |
980 | 910 | ||
911 | /* Form the RFC: | ||
912 | "It is important to note that the octet count for a message on the | ||
913 | server host may differ from the octet count assigned to that message | ||
914 | due to local conventions for designating end-of-line. Usually, | ||
915 | during the AUTHORIZATION state of the POP3 session, the POP3 server | ||
916 | can calculate the size of each message in octets when it opens the | ||
917 | maildrop. For example, if the POP3 server host internally represents | ||
918 | end-of-line as a single character, then the POP3 server simply counts | ||
919 | each occurrence of this character in a message as two octets." | ||
920 | |||
921 | This is not perfect if we do not know the number of lines in the message | ||
922 | then the octets returned will not be correct so we do our best. | ||
923 | */ | ||
981 | static int | 924 | static int |
982 | pop_body_size (body_t body, size_t *psize) | 925 | pop_message_size (message_t msg, size_t *psize) |
983 | { | 926 | { |
984 | pop_message_t mpm = body->owner; | 927 | pop_message_t mpm = message_get_owner (msg); |
928 | pop_data_t mpd; | ||
929 | int status = 0; | ||
930 | void *func = (void *)pop_message_size; | ||
931 | size_t num; | ||
932 | |||
985 | if (mpm == NULL) | 933 | if (mpm == NULL) |
986 | return EINVAL; | 934 | return EINVAL; |
935 | |||
936 | /* Did we have it already ? */ | ||
937 | if (mpm->message_size != 0) | ||
938 | { | ||
939 | *psize = mpm->message_size; | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | mpd = mpm->mpd; | ||
944 | /* Busy ? */ | ||
945 | CHECK_BUSY (mpd->mbox, mpd, func, msg); | ||
946 | |||
947 | /* Get the size. */ | ||
948 | switch (mpd->state) | ||
949 | { | ||
950 | case POP_NO_STATE: | ||
951 | status = pop_writeline (mpd, "LIST %d\r\n", mpm->num); | ||
952 | CHECK_ERROR (mpd, status); | ||
953 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); | ||
954 | mpd->state = POP_LIST; | ||
955 | |||
956 | case POP_LIST: | ||
957 | /* Send the LIST. */ | ||
958 | status = pop_write (mpd); | ||
959 | CHECK_EAGAIN (mpd, status); | ||
960 | mpd->state = POP_LIST_ACK; | ||
961 | |||
962 | case POP_LIST_ACK: | ||
963 | /* Resp from LIST. */ | ||
964 | status = pop_read_ack (mpd); | ||
965 | CHECK_EAGAIN (mpd, status); | ||
966 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); | ||
967 | break; | ||
968 | |||
969 | default: | ||
970 | /* | ||
971 | fprintf (stderr, "pop_uidl state\n"); | ||
972 | */ | ||
973 | break; | ||
974 | } | ||
975 | |||
976 | status = sscanf (mpd->buffer, "+OK %d %d\n", &num, &mpm->message_size); | ||
977 | CLEAR_STATE (mpd); | ||
978 | |||
979 | if (status != 2) | ||
980 | status = EINVAL; | ||
981 | |||
987 | if (psize) | 982 | if (psize) |
988 | *psize = mpm->body_size; | 983 | *psize = mpm->message_size; |
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int | ||
988 | pop_body_size (body_t body, size_t *psize) | ||
989 | { | ||
990 | message_t msg = body_get_owner (body); | ||
991 | pop_message_t mpm = message_get_owner (msg); | ||
992 | |||
993 | if (mpm == NULL) | ||
994 | return EINVAL; | ||
995 | |||
996 | /* Did we have it already ? */ | ||
997 | if (mpm->body_size != 0) | ||
998 | { | ||
999 | *psize = mpm->body_size; | ||
1000 | } | ||
1001 | else if (mpm->message_size != 0) | ||
1002 | { | ||
1003 | *psize = mpm->message_size - mpm->header_size - mpm->body_lines; | ||
1004 | } | ||
1005 | else | ||
1006 | *psize = 0; | ||
1007 | |||
989 | return 0; | 1008 | return 0; |
990 | } | 1009 | } |
991 | 1010 | ||
992 | static int | 1011 | static int |
993 | pop_body_lines (body_t body, size_t *plines) | 1012 | pop_body_lines (body_t body, size_t *plines) |
994 | { | 1013 | { |
995 | pop_message_t mpm = body->owner; | 1014 | message_t msg = body_get_owner (body); |
1015 | pop_message_t mpm = message_get_owner (msg); | ||
996 | if (mpm == NULL) | 1016 | if (mpm == NULL) |
997 | return EINVAL; | 1017 | return EINVAL; |
998 | if (plines) | 1018 | if (plines) |
... | @@ -1005,9 +1025,10 @@ pop_body_lines (body_t body, size_t *plines) | ... | @@ -1005,9 +1025,10 @@ pop_body_lines (body_t body, size_t *plines) |
1005 | because we call header_get_value the function may return EAGAIN... | 1025 | because we call header_get_value the function may return EAGAIN... |
1006 | uncool. */ | 1026 | uncool. */ |
1007 | static int | 1027 | static int |
1008 | pop_get_flags (attribute_t attr, int *pflags) | 1028 | pop_attr_flags (attribute_t attr, int *pflags) |
1009 | { | 1029 | { |
1010 | pop_message_t mpm = attr->owner; | 1030 | message_t msg = attribute_get_owner (attr); |
1031 | pop_message_t mpm = message_get_owner (msg); | ||
1011 | char hdr_status[64]; | 1032 | char hdr_status[64]; |
1012 | header_t header = NULL; | 1033 | header_t header = NULL; |
1013 | int err; | 1034 | int err; |
... | @@ -1023,10 +1044,38 @@ pop_get_flags (attribute_t attr, int *pflags) | ... | @@ -1023,10 +1044,38 @@ pop_get_flags (attribute_t attr, int *pflags) |
1023 | return err; | 1044 | return err; |
1024 | } | 1045 | } |
1025 | 1046 | ||
1047 | /* stub to call from body object. */ | ||
1048 | static int | ||
1049 | pop_body_fd (stream_t stream, int *pfd) | ||
1050 | { | ||
1051 | body_t body = stream_get_owner (stream); | ||
1052 | message_t msg = body_get_owner (body); | ||
1053 | pop_message_t mpm = message_get_owner (msg); | ||
1054 | return pop_get_fd (mpm, pfd); | ||
1055 | } | ||
1056 | |||
1057 | /* stub to call from header object. */ | ||
1026 | static int | 1058 | static int |
1027 | pop_get_fd (stream_t stream, int *pfd) | 1059 | pop_header_fd (stream_t stream, int *pfd) |
1060 | { | ||
1061 | header_t header = stream_get_owner (stream); | ||
1062 | message_t msg = header_get_owner (header); | ||
1063 | pop_message_t mpm = message_get_owner (msg); | ||
1064 | return pop_get_fd (mpm, pfd); | ||
1065 | } | ||
1066 | |||
1067 | /* stub to call from message object. */ | ||
1068 | static int | ||
1069 | pop_message_fd (stream_t stream, int *pfd) | ||
1070 | { | ||
1071 | message_t msg = stream_get_owner (stream); | ||
1072 | pop_message_t mpm = message_get_owner (msg); | ||
1073 | return pop_get_fd (mpm, pfd); | ||
1074 | } | ||
1075 | |||
1076 | static int | ||
1077 | pop_get_fd (pop_message_t mpm, int *pfd) | ||
1028 | { | 1078 | { |
1029 | pop_message_t mpm = stream->owner; | ||
1030 | if (mpm && mpm->mpd && mpm->mpd->mbox) | 1079 | if (mpm && mpm->mpd && mpm->mpd->mbox) |
1031 | return stream_get_fd (mpm->mpd->mbox->stream, pfd); | 1080 | return stream_get_fd (mpm->mpd->mbox->stream, pfd); |
1032 | return EINVAL; | 1081 | return EINVAL; |
... | @@ -1039,7 +1088,7 @@ pop_get_fd (stream_t stream, int *pfd) | ... | @@ -1039,7 +1088,7 @@ pop_get_fd (stream_t stream, int *pfd) |
1039 | static int | 1088 | static int |
1040 | pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | 1089 | pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1041 | { | 1090 | { |
1042 | pop_message_t mpm = msg->owner; | 1091 | pop_message_t mpm = message_get_owner (msg); |
1043 | pop_data_t mpd; | 1092 | pop_data_t mpd; |
1044 | int status = 0; | 1093 | int status = 0; |
1045 | void *func = (void *)pop_uidl; | 1094 | void *func = (void *)pop_uidl; |
... | @@ -1053,10 +1102,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1053,10 +1102,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1053 | mpd = mpm->mpd; | 1102 | mpd = mpm->mpd; |
1054 | 1103 | ||
1055 | /* Busy ? */ | 1104 | /* Busy ? */ |
1056 | if (mpd->func && mpd->func != func) | 1105 | CHECK_BUSY (mpd->mbox, mpd, func, 0); |
1057 | return EBUSY; | ||
1058 | |||
1059 | mpd->func = func; | ||
1060 | 1106 | ||
1061 | /* Get the UIDL. */ | 1107 | /* Get the UIDL. */ |
1062 | switch (mpd->state) | 1108 | switch (mpd->state) |
... | @@ -1064,10 +1110,10 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1064,10 +1110,10 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1064 | case POP_NO_STATE: | 1110 | case POP_NO_STATE: |
1065 | status = pop_writeline (mpd, "UIDL %d\r\n", mpm->num); | 1111 | status = pop_writeline (mpd, "UIDL %d\r\n", mpm->num); |
1066 | CHECK_ERROR (mpd, status); | 1112 | CHECK_ERROR (mpd, status); |
1067 | mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 1113 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1068 | mpd->state = POP_UIDL_TX; | 1114 | mpd->state = POP_UIDL; |
1069 | 1115 | ||
1070 | case POP_UIDL_TX: | 1116 | case POP_UIDL: |
1071 | /* Send the UIDL. */ | 1117 | /* Send the UIDL. */ |
1072 | status = pop_write (mpd); | 1118 | status = pop_write (mpd); |
1073 | CHECK_EAGAIN (mpd, status); | 1119 | CHECK_EAGAIN (mpd, status); |
... | @@ -1077,7 +1123,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1077,7 +1123,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1077 | /* Resp from UIDL. */ | 1123 | /* Resp from UIDL. */ |
1078 | status = pop_read_ack (mpd); | 1124 | status = pop_read_ack (mpd); |
1079 | CHECK_EAGAIN (mpd, status); | 1125 | CHECK_EAGAIN (mpd, status); |
1080 | mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 1126 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1081 | break; | 1127 | break; |
1082 | 1128 | ||
1083 | default: | 1129 | default: |
... | @@ -1089,6 +1135,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1089,6 +1135,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1089 | 1135 | ||
1090 | CLEAR_STATE (mpd); | 1136 | CLEAR_STATE (mpd); |
1091 | 1137 | ||
1138 | /* FIXME: I should cache the result. */ | ||
1092 | *uniq = '\0'; | 1139 | *uniq = '\0'; |
1093 | status = sscanf (mpd->buffer, "+OK %d %127s\n", &num, uniq); | 1140 | status = sscanf (mpd->buffer, "+OK %d %127s\n", &num, uniq); |
1094 | if (status != 2) | 1141 | if (status != 2) |
... | @@ -1115,9 +1162,11 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1115,9 +1162,11 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1115 | NOTE: offset is meaningless. */ | 1162 | NOTE: offset is meaningless. */ |
1116 | static int | 1163 | static int |
1117 | pop_top (stream_t is, char *buffer, size_t buflen, | 1164 | pop_top (stream_t is, char *buffer, size_t buflen, |
1118 | off_t offset, size_t *pnread) | 1165 | off_t offset, size_t *pnread) |
1119 | { | 1166 | { |
1120 | pop_message_t mpm = is->owner; | 1167 | header_t header = stream_get_owner (is); |
1168 | message_t msg = header_get_owner (header); | ||
1169 | pop_message_t mpm = message_get_owner (msg); | ||
1121 | pop_data_t mpd; | 1170 | pop_data_t mpd; |
1122 | size_t nread = 0; | 1171 | size_t nread = 0; |
1123 | int status = 0; | 1172 | int status = 0; |
... | @@ -1126,15 +1175,14 @@ pop_top (stream_t is, char *buffer, size_t buflen, | ... | @@ -1126,15 +1175,14 @@ pop_top (stream_t is, char *buffer, size_t buflen, |
1126 | if (mpm == NULL) | 1175 | if (mpm == NULL) |
1127 | return EINVAL; | 1176 | return EINVAL; |
1128 | 1177 | ||
1129 | /* We do not carry the offset(for pop), should be doc somewhere. */ | ||
1130 | (void)offset; | ||
1131 | mpd = mpm->mpd; | 1178 | mpd = mpm->mpd; |
1132 | 1179 | ||
1133 | /* Busy ? */ | 1180 | /* We do not carry the offset backward(for pop), should be doc somewhere. */ |
1134 | if (mpd->func && mpd->func != func) | 1181 | if ((size_t)offset < mpm->header_size) |
1135 | return EBUSY; | 1182 | return ESPIPE; |
1136 | 1183 | ||
1137 | mpd->func = func; | 1184 | /* Busy ? */ |
1185 | CHECK_BUSY (mpd->mbox, mpd, func, msg); | ||
1138 | 1186 | ||
1139 | /* Get the header. */ | 1187 | /* Get the header. */ |
1140 | switch (mpd->state) | 1188 | switch (mpd->state) |
... | @@ -1145,10 +1193,10 @@ pop_top (stream_t is, char *buffer, size_t buflen, | ... | @@ -1145,10 +1193,10 @@ pop_top (stream_t is, char *buffer, size_t buflen, |
1145 | fall to a second scheme. */ | 1193 | fall to a second scheme. */ |
1146 | status = pop_writeline (mpd, "TOP %d 0\r\n", mpm->num); | 1194 | status = pop_writeline (mpd, "TOP %d 0\r\n", mpm->num); |
1147 | CHECK_ERROR (mpd, status); | 1195 | CHECK_ERROR (mpd, status); |
1148 | mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 1196 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1149 | mpd->state = POP_TOP_TX; | 1197 | mpd->state = POP_TOP; |
1150 | 1198 | ||
1151 | case POP_TOP_TX: | 1199 | case POP_TOP: |
1152 | /* Send the TOP. */ | 1200 | /* Send the TOP. */ |
1153 | status = pop_write (mpd); | 1201 | status = pop_write (mpd); |
1154 | CHECK_EAGAIN (mpd, status); | 1202 | CHECK_EAGAIN (mpd, status); |
... | @@ -1158,7 +1206,7 @@ pop_top (stream_t is, char *buffer, size_t buflen, | ... | @@ -1158,7 +1206,7 @@ pop_top (stream_t is, char *buffer, size_t buflen, |
1158 | /* Ack from TOP. */ | 1206 | /* Ack from TOP. */ |
1159 | status = pop_read_ack (mpd); | 1207 | status = pop_read_ack (mpd); |
1160 | CHECK_EAGAIN (mpd, status); | 1208 | CHECK_EAGAIN (mpd, status); |
1161 | mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 1209 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1162 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | 1210 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) |
1163 | { | 1211 | { |
1164 | /* fprintf (stderr, "TOP not implemented\n"); */ | 1212 | /* fprintf (stderr, "TOP not implemented\n"); */ |
... | @@ -1172,13 +1220,25 @@ pop_top (stream_t is, char *buffer, size_t buflen, | ... | @@ -1172,13 +1220,25 @@ pop_top (stream_t is, char *buffer, size_t buflen, |
1172 | 1220 | ||
1173 | case POP_TOP_RX: | 1221 | case POP_TOP_RX: |
1174 | /* Get the header. */ | 1222 | /* Get the header. */ |
1175 | /* Do we need to fill up. */ | 1223 | do |
1176 | if (mpd->nl == NULL || mpd->ptr == mpd->buffer) | ||
1177 | { | 1224 | { |
1178 | status = pop_readline (mpd); | 1225 | /* Seek in position. */ |
1179 | CHECK_EAGAIN (mpd, status); | 1226 | ssize_t pos = offset - mpm->header_size; |
1227 | /* Do we need to fill up. */ | ||
1228 | if (mpd->nl == NULL || mpd->ptr == mpd->buffer) | ||
1229 | { | ||
1230 | status = pop_readline (mpd); | ||
1231 | CHECK_EAGAIN (mpd, status); | ||
1232 | mpm->header_lines++; | ||
1233 | } | ||
1234 | /* If we have to skip some data to get to the offet. */ | ||
1235 | if (pos > 0) | ||
1236 | nread = fill_buffer (mpd, NULL, pos); | ||
1237 | else | ||
1238 | nread = fill_buffer (mpd, buffer, buflen); | ||
1239 | mpm->header_size += nread; | ||
1180 | } | 1240 | } |
1181 | nread = fill_buffer (mpd, buffer, buflen); | 1241 | while (nread > 0 && (size_t)offset > mpm->header_size); |
1182 | break; | 1242 | break; |
1183 | 1243 | ||
1184 | default: | 1244 | default: |
... | @@ -1199,67 +1259,65 @@ pop_top (stream_t is, char *buffer, size_t buflen, | ... | @@ -1199,67 +1259,65 @@ pop_top (stream_t is, char *buffer, size_t buflen, |
1199 | 1259 | ||
1200 | /* Stub to call pop_retr (). */ | 1260 | /* Stub to call pop_retr (). */ |
1201 | static int | 1261 | static int |
1202 | pop_read_header (stream_t is, char *buffer, size_t buflen, off_t offset, | 1262 | pop_header_read (stream_t is, char *buffer, size_t buflen, off_t offset, |
1203 | size_t *pnread) | 1263 | size_t *pnread) |
1204 | { | 1264 | { |
1205 | pop_message_t mpm = is->owner; | 1265 | message_t msg = stream_get_owner (is); |
1266 | pop_message_t mpm = message_get_owner (msg); | ||
1206 | pop_data_t mpd; | 1267 | pop_data_t mpd; |
1207 | void *func = (void *)pop_read_header; | 1268 | void *func = (void *)pop_header_read; |
1208 | 1269 | ||
1209 | if (mpm == NULL) | 1270 | if (mpm == NULL) |
1210 | return EINVAL; | 1271 | return EINVAL; |
1211 | mpd = mpm->mpd; | 1272 | mpd = mpm->mpd; |
1212 | 1273 | ||
1213 | /* Busy ? */ | 1274 | /* Busy ? */ |
1214 | if (mpd->func && mpd->func != func) | 1275 | CHECK_BUSY (mpd->mbox, mpd, func, msg); |
1215 | return EBUSY; | ||
1216 | mpd->func = func; | ||
1217 | 1276 | ||
1218 | mpm->skip_header = 0; | 1277 | mpm->skip_header = 0; |
1219 | mpm->skip_body = 1; | 1278 | mpm->skip_body = 1; |
1220 | return pop_retr (mpm, buffer, buflen, offset, pnread); | 1279 | return pop_retr (mpm, buffer, buflen, offset, pnread); |
1221 | } | 1280 | } |
1222 | 1281 | ||
1223 | /* Stub to call pop_retr (). */ | 1282 | /* Stub to call pop_retr (). Call from the stream object of the body. */ |
1224 | static int | 1283 | static int |
1225 | pop_read_body (stream_t is, char *buffer, size_t buflen, off_t offset, | 1284 | pop_body_read (stream_t is, char *buffer, size_t buflen, off_t offset, |
1226 | size_t *pnread) | 1285 | size_t *pnread) |
1227 | { | 1286 | { |
1228 | pop_message_t mpm = is->owner; | 1287 | body_t body = stream_get_owner (is); |
1288 | message_t msg = body_get_owner (body); | ||
1289 | pop_message_t mpm = message_get_owner (msg); | ||
1229 | pop_data_t mpd; | 1290 | pop_data_t mpd; |
1230 | void *func = (void *)pop_read_body; | 1291 | void *func = (void *)pop_body_read; |
1231 | 1292 | ||
1232 | if (mpm == NULL) | 1293 | if (mpm == NULL) |
1233 | return EINVAL; | 1294 | return EINVAL; |
1234 | mpd = mpm->mpd; | 1295 | mpd = mpm->mpd; |
1235 | 1296 | ||
1236 | /* Busy ? */ | 1297 | /* Busy ? */ |
1237 | if (mpd->func && mpd->func != func) | 1298 | CHECK_BUSY (mpd->mbox, mpd, func, msg); |
1238 | return EBUSY; | ||
1239 | mpd->func = func; | ||
1240 | 1299 | ||
1241 | mpm->skip_header = 1; | 1300 | mpm->skip_header = 1; |
1242 | mpm->skip_body = 0; | 1301 | mpm->skip_body = 0; |
1243 | return pop_retr (mpm, buffer, buflen, offset, pnread); | 1302 | return pop_retr (mpm, buffer, buflen, offset, pnread); |
1244 | } | 1303 | } |
1245 | 1304 | ||
1246 | /* Stub to call pop_retr (). */ | 1305 | /* Stub to call pop_retr (), calling from the stream object of a message. */ |
1247 | static int | 1306 | static int |
1248 | pop_read_message (stream_t is, char *buffer, size_t buflen, off_t offset, | 1307 | pop_message_read (stream_t is, char *buffer, size_t buflen, off_t offset, |
1249 | size_t *pnread) | 1308 | size_t *pnread) |
1250 | { | 1309 | { |
1251 | pop_message_t mpm = is->owner; | 1310 | message_t msg = stream_get_owner (is); |
1311 | pop_message_t mpm = message_get_owner (msg); | ||
1252 | pop_data_t mpd; | 1312 | pop_data_t mpd; |
1253 | void *func = (void *)pop_read_message; | 1313 | void *func = (void *)pop_message_read; |
1254 | 1314 | ||
1255 | if (mpm == NULL) | 1315 | if (mpm == NULL) |
1256 | return EINVAL; | 1316 | return EINVAL; |
1257 | mpd = mpm->mpd; | 1317 | mpd = mpm->mpd; |
1258 | 1318 | ||
1259 | /* Busy ? */ | 1319 | /* Busy ? */ |
1260 | if (mpd->func && mpd->func != func) | 1320 | CHECK_BUSY (mpd->mbox, mpd, func, msg); |
1261 | return EBUSY; | ||
1262 | mpd->func = func; | ||
1263 | 1321 | ||
1264 | mpm->skip_header = mpm->skip_body = 0; | 1322 | mpm->skip_header = mpm->skip_body = 0; |
1265 | return pop_retr (mpm, buffer, buflen, offset, pnread); | 1323 | return pop_retr (mpm, buffer, buflen, offset, pnread); |
... | @@ -1281,7 +1339,8 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen) | ... | @@ -1281,7 +1339,8 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen) |
1281 | size_t sentinel; | 1339 | size_t sentinel; |
1282 | nread = buflen; | 1340 | nread = buflen; |
1283 | sentinel = mpd->ptr - (mpd->buffer + nread); | 1341 | sentinel = mpd->ptr - (mpd->buffer + nread); |
1284 | memcpy (buffer, mpd->buffer, nread); | 1342 | if (buffer) |
1343 | memcpy (buffer, mpd->buffer, nread); | ||
1285 | memmove (mpd->buffer, mpd->buffer + nread, sentinel); | 1344 | memmove (mpd->buffer, mpd->buffer + nread, sentinel); |
1286 | mpd->ptr = mpd->buffer + sentinel; | 1345 | mpd->ptr = mpd->buffer + sentinel; |
1287 | } | 1346 | } |
... | @@ -1289,7 +1348,8 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen) | ... | @@ -1289,7 +1348,8 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen) |
1289 | { | 1348 | { |
1290 | /* Drain our buffer. */; | 1349 | /* Drain our buffer. */; |
1291 | nread = n; | 1350 | nread = n; |
1292 | memcpy (buffer, mpd->buffer, nread); | 1351 | if (buffer) |
1352 | memcpy (buffer, mpd->buffer, nread); | ||
1293 | mpd->ptr = mpd->buffer; | 1353 | mpd->ptr = mpd->buffer; |
1294 | } | 1354 | } |
1295 | 1355 | ||
... | @@ -1308,24 +1368,35 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1308,24 +1368,35 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1308 | 1368 | ||
1309 | (void)offset; | 1369 | (void)offset; |
1310 | 1370 | ||
1371 | mpd = mpm->mpd; | ||
1372 | |||
1311 | if (pnread) | 1373 | if (pnread) |
1312 | *pnread = nread; | 1374 | *pnread = nread; |
1375 | |||
1313 | /* Take care of the obvious. */ | 1376 | /* Take care of the obvious. */ |
1314 | if (buffer == NULL || buflen == 0) | 1377 | if (buffer == NULL || buflen == 0) |
1315 | return 0; | 1378 | { |
1379 | CLEAR_STATE (mpd); | ||
1380 | return 0; | ||
1381 | } | ||
1316 | 1382 | ||
1317 | mpd = mpm->mpd; | 1383 | /* We do not carry the offset backward(for pop), should be doc somewhere. */ |
1384 | /*if (offset < mpm->header_size) | ||
1385 | return ESPIPE; | ||
1386 | */ | ||
1387 | |||
1388 | /* pop_retr() is not call directly so we assume that the locks were set. */ | ||
1318 | 1389 | ||
1319 | switch (mpd->state) | 1390 | switch (mpd->state) |
1320 | { | 1391 | { |
1321 | case POP_NO_STATE: | 1392 | case POP_NO_STATE: |
1322 | mpm->body_lines = mpm->body_size = 0; | 1393 | mpm->body_lines = mpm->body_size = 0; |
1323 | status = pop_writeline (mpd, "RETR %d\r\n", mpm->num); | 1394 | status = pop_writeline (mpd, "RETR %d\r\n", mpm->num); |
1324 | mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer); | 1395 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1325 | CHECK_ERROR (mpd, status); | 1396 | CHECK_ERROR (mpd, status); |
1326 | mpd->state = POP_RETR_TX; | 1397 | mpd->state = POP_RETR; |
1327 | 1398 | ||
1328 | case POP_RETR_TX: | 1399 | case POP_RETR: |
1329 | /* Send the RETR command. */ | 1400 | /* Send the RETR command. */ |
1330 | status = pop_write (mpd); | 1401 | status = pop_write (mpd); |
1331 | CHECK_EAGAIN (mpd, status); | 1402 | CHECK_EAGAIN (mpd, status); |
... | @@ -1347,6 +1418,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1347,6 +1418,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1347 | { | 1418 | { |
1348 | /* Do we need to fill up. */ | 1419 | /* Do we need to fill up. */ |
1349 | if (mpd->nl == NULL || mpd->ptr == mpd->buffer) | 1420 | if (mpd->nl == NULL || mpd->ptr == mpd->buffer) |
1421 | |||
1350 | { | 1422 | { |
1351 | status = pop_readline (mpd); | 1423 | status = pop_readline (mpd); |
1352 | if (status != 0) | 1424 | if (status != 0) |
... | @@ -1356,12 +1428,18 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1356,12 +1428,18 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1356 | return 0; | 1428 | return 0; |
1357 | CHECK_EAGAIN (mpd, status); | 1429 | CHECK_EAGAIN (mpd, status); |
1358 | } | 1430 | } |
1431 | mpm->header_lines++; | ||
1359 | } | 1432 | } |
1360 | /* Oops !! Hello houston we have a major problem here. */ | 1433 | /* Oops !! Hello houston we have a major problem here. */ |
1361 | if (mpd->buffer[0] == '\0') | 1434 | if (mpd->buffer[0] == '\0') |
1362 | { | 1435 | { |
1363 | /* Still Do the right thing. */ | 1436 | /* Still Do the right thing. */ |
1364 | mpd->state = POP_STATE_DONE; | 1437 | if (buflen != oldbuflen) |
1438 | { | ||
1439 | CLEAR_STATE (mpd); | ||
1440 | } | ||
1441 | else | ||
1442 | mpd->state = POP_STATE_DONE; | ||
1365 | return 0; | 1443 | return 0; |
1366 | } | 1444 | } |
1367 | /* The problem is that we are using RETR instead of TOP to retreive | 1445 | /* The problem is that we are using RETR instead of TOP to retreive |
... | @@ -1372,16 +1450,26 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1372,16 +1450,26 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1372 | hack below will suffice. */ | 1450 | hack below will suffice. */ |
1373 | if (mpd->buffer[0] == '\n' && mpd->buffer[1] == '\0') | 1451 | if (mpd->buffer[0] == '\n' && mpd->buffer[1] == '\0') |
1374 | mpm->inbody = 1; /* break out of the while. */ | 1452 | mpm->inbody = 1; /* break out of the while. */ |
1375 | if (mpm->skip_header == 0) | 1453 | if (!mpm->skip_header) |
1376 | { | 1454 | { |
1377 | nread = fill_buffer (mpd, buffer, buflen); | 1455 | ssize_t pos = offset - mpm->header_size; |
1378 | if (pnread) | 1456 | if (pos) |
1379 | *pnread += nread; | 1457 | { |
1380 | buflen -= nread ; | 1458 | nread = fill_buffer (mpd, NULL, pos); |
1381 | if (buflen > 0) | 1459 | mpm->header_size += nread; |
1382 | buffer += nread; | 1460 | } |
1383 | else | 1461 | else |
1384 | return 0; | 1462 | { |
1463 | nread = fill_buffer (mpd, buffer, buflen); | ||
1464 | mpm->header_size += nread; | ||
1465 | if (pnread) | ||
1466 | *pnread += nread; | ||
1467 | buflen -= nread ; | ||
1468 | if (buflen > 0) | ||
1469 | buffer += nread; | ||
1470 | else | ||
1471 | return 0; | ||
1472 | } | ||
1385 | } | 1473 | } |
1386 | else | 1474 | else |
1387 | mpd->ptr = mpd->buffer; | 1475 | mpd->ptr = mpd->buffer; |
... | @@ -1409,17 +1497,26 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1409,17 +1497,26 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1409 | if (mpd->buffer[0] == '\0') | 1497 | if (mpd->buffer[0] == '\0') |
1410 | mpm->inbody = 0; /* Breakout of the while. */ | 1498 | mpm->inbody = 0; /* Breakout of the while. */ |
1411 | 1499 | ||
1412 | if (mpm->skip_body == 0) | 1500 | if (!mpm->skip_body) |
1413 | { | 1501 | { |
1414 | nread = fill_buffer (mpd, buffer, buflen); | 1502 | ssize_t pos = offset - mpm->body_size; |
1415 | mpm->body_size += nread; | 1503 | if (pos > 0) |
1416 | if (pnread) | 1504 | { |
1417 | *pnread += nread; | 1505 | nread = fill_buffer (mpd, NULL, pos); |
1418 | buflen -= nread ; | 1506 | mpm->body_size += nread; |
1419 | if (buflen > 0) | 1507 | } |
1420 | buffer += nread; | ||
1421 | else | 1508 | else |
1422 | return 0; | 1509 | { |
1510 | nread = fill_buffer (mpd, buffer, buflen); | ||
1511 | mpm->body_size += nread; | ||
1512 | if (pnread) | ||
1513 | *pnread += nread; | ||
1514 | buflen -= nread ; | ||
1515 | if (buflen > 0) | ||
1516 | buffer += nread; | ||
1517 | else | ||
1518 | return 0; | ||
1519 | } | ||
1423 | } | 1520 | } |
1424 | else | 1521 | else |
1425 | { | 1522 | { |
... | @@ -1427,6 +1524,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, | ... | @@ -1427,6 +1524,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset, |
1427 | mpd->ptr = mpd->buffer; | 1524 | mpd->ptr = mpd->buffer; |
1428 | } | 1525 | } |
1429 | } | 1526 | } |
1527 | mpm->message_size = mpm->body_size + mpm->header_size; | ||
1430 | mpd->state = POP_STATE_DONE; | 1528 | mpd->state = POP_STATE_DONE; |
1431 | /* Return here earlier, because we want to return nread = 0 to notify | 1529 | /* Return here earlier, because we want to return nread = 0 to notify |
1432 | the callee that we've finish, since there is already data in the | 1530 | the callee that we've finish, since there is already data in the | ... | ... |
... | @@ -15,9 +15,9 @@ | ... | @@ -15,9 +15,9 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | 18 | #ifdef HAVE_CONFIG_H | |
19 | #include <stream0.h> | 19 | # include <config.h> |
20 | #include <message0.h> | 20 | #endif |
21 | 21 | ||
22 | #include <errno.h> | 22 | #include <errno.h> |
23 | #include <stdio.h> | 23 | #include <stdio.h> |
... | @@ -28,9 +28,10 @@ | ... | @@ -28,9 +28,10 @@ |
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <ctype.h> | 29 | #include <ctype.h> |
30 | 30 | ||
31 | /* FIXME: This should be part of the address_t object when implemented. */ | 31 | #include <mailutils/stream.h> |
32 | static int extract_addr(const char *s, size_t n, char **presult, | 32 | #include <misc.h> |
33 | size_t *pnwrite); | 33 | #include <message0.h> |
34 | |||
34 | static int message_read (stream_t is, char *buf, size_t buflen, | 35 | static int message_read (stream_t is, char *buf, size_t buflen, |
35 | off_t off, size_t *pnread ); | 36 | off_t off, size_t *pnread ); |
36 | static int message_write (stream_t os, const char *buf, size_t buflen, | 37 | static int message_write (stream_t os, const char *buf, size_t buflen, |
... | @@ -64,34 +65,26 @@ message_destroy (message_t *pmsg, void *owner) | ... | @@ -64,34 +65,26 @@ message_destroy (message_t *pmsg, void *owner) |
64 | { | 65 | { |
65 | /* Notify the listeners. */ | 66 | /* Notify the listeners. */ |
66 | /* FIXME: to be removed since we do not supoort this event. */ | 67 | /* FIXME: to be removed since we do not supoort this event. */ |
67 | if (msg->event_num) | 68 | if (msg->observable) |
68 | { | 69 | { |
69 | message_notification (msg, MU_EVT_MSG_DESTROY); | 70 | observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY); |
70 | free (msg->event); | 71 | observable_destroy (&(msg->observable), msg); |
71 | } | 72 | } |
72 | 73 | ||
73 | /* Header. */ | 74 | /* Header. */ |
74 | if (msg->header) | 75 | if (msg->header) |
75 | header_destroy (&(msg->header), owner); | ||
76 | if (msg->header) | ||
77 | header_destroy (&(msg->header), msg); | 76 | header_destroy (&(msg->header), msg); |
78 | 77 | ||
79 | /* Attribute. */ | 78 | /* Attribute. */ |
80 | if (msg->attribute) | 79 | if (msg->attribute) |
81 | attribute_destroy (&(msg->attribute), owner); | ||
82 | if (msg->attribute) | ||
83 | attribute_destroy (&(msg->attribute), msg); | 80 | attribute_destroy (&(msg->attribute), msg); |
84 | 81 | ||
85 | /* Stream. */ | 82 | /* Stream. */ |
86 | if (msg->stream) | 83 | if (msg->stream) |
87 | stream_destroy (&(msg->stream), owner); | ||
88 | if (msg->stream) | ||
89 | stream_destroy (&(msg->stream), msg); | 84 | stream_destroy (&(msg->stream), msg); |
90 | 85 | ||
91 | /* Body. */ | 86 | /* Body. */ |
92 | if (msg->body) | 87 | if (msg->body) |
93 | body_destroy (&(msg->body), owner); | ||
94 | if (msg->body) | ||
95 | body_destroy (&(msg->body), msg); | 88 | body_destroy (&(msg->body), msg); |
96 | 89 | ||
97 | /* Mime. */ | 90 | /* Mime. */ |
... | @@ -105,6 +98,12 @@ message_destroy (message_t *pmsg, void *owner) | ... | @@ -105,6 +98,12 @@ message_destroy (message_t *pmsg, void *owner) |
105 | } | 98 | } |
106 | } | 99 | } |
107 | 100 | ||
101 | void * | ||
102 | message_get_owner (message_t msg) | ||
103 | { | ||
104 | return (msg == NULL) ? NULL : msg->owner; | ||
105 | } | ||
106 | |||
108 | int | 107 | int |
109 | message_get_header (message_t msg, header_t *phdr) | 108 | message_get_header (message_t msg, header_t *phdr) |
110 | { | 109 | { |
... | @@ -198,7 +197,7 @@ message_get_stream (message_t msg, stream_t *pstream) | ... | @@ -198,7 +197,7 @@ message_get_stream (message_t msg, stream_t *pstream) |
198 | stream_set_read (stream, message_read, msg); | 197 | stream_set_read (stream, message_read, msg); |
199 | stream_set_write (stream, message_write, msg); | 198 | stream_set_write (stream, message_write, msg); |
200 | stream_set_fd (stream, message_get_fd, msg); | 199 | stream_set_fd (stream, message_get_fd, msg); |
201 | stream_set_flags (stream, MU_STREAM_RDWR, msg); | 200 | stream_set_flags (stream, MU_STREAM_RDWR); |
202 | msg->stream = stream; | 201 | msg->stream = stream; |
203 | } | 202 | } |
204 | 203 | ||
... | @@ -222,6 +221,8 @@ int | ... | @@ -222,6 +221,8 @@ int |
222 | message_lines (message_t msg, size_t *plines) | 221 | message_lines (message_t msg, size_t *plines) |
223 | { | 222 | { |
224 | size_t hlines, blines; | 223 | size_t hlines, blines; |
224 | int ret = 0; | ||
225 | |||
225 | if (msg == NULL) | 226 | if (msg == NULL) |
226 | return EINVAL; | 227 | return EINVAL; |
227 | /* Overload. */ | 228 | /* Overload. */ |
... | @@ -230,11 +231,11 @@ message_lines (message_t msg, size_t *plines) | ... | @@ -230,11 +231,11 @@ message_lines (message_t msg, size_t *plines) |
230 | if (plines) | 231 | if (plines) |
231 | { | 232 | { |
232 | hlines = blines = 0; | 233 | hlines = blines = 0; |
233 | header_lines (msg->header, &hlines); | 234 | if ( ( ret = header_lines (msg->header, &hlines) ) == 0 ) |
234 | body_lines (msg->body, &blines); | 235 | ret = body_lines (msg->body, &blines); |
235 | *plines = hlines + blines; | 236 | *plines = hlines + blines; |
236 | } | 237 | } |
237 | return 0; | 238 | return ret; |
238 | } | 239 | } |
239 | 240 | ||
240 | int | 241 | int |
... | @@ -253,6 +254,8 @@ int | ... | @@ -253,6 +254,8 @@ int |
253 | message_size (message_t msg, size_t *psize) | 254 | message_size (message_t msg, size_t *psize) |
254 | { | 255 | { |
255 | size_t hsize, bsize; | 256 | size_t hsize, bsize; |
257 | int ret = 0; | ||
258 | |||
256 | if (msg == NULL) | 259 | if (msg == NULL) |
257 | return EINVAL; | 260 | return EINVAL; |
258 | /* Overload ? */ | 261 | /* Overload ? */ |
... | @@ -261,11 +264,11 @@ message_size (message_t msg, size_t *psize) | ... | @@ -261,11 +264,11 @@ message_size (message_t msg, size_t *psize) |
261 | if (psize) | 264 | if (psize) |
262 | { | 265 | { |
263 | hsize = bsize = 0; | 266 | hsize = bsize = 0; |
264 | header_size (msg->header, &hsize); | 267 | if ( ( ret = header_size (msg->header, &hsize) ) == 0 ) |
265 | body_size (msg->body, &bsize); | 268 | ret = body_size (msg->body, &bsize); |
266 | *psize = hsize + bsize; | 269 | *psize = hsize + bsize; |
267 | } | 270 | } |
268 | return 0; | 271 | return ret; |
269 | } | 272 | } |
270 | 273 | ||
271 | int | 274 | int |
... | @@ -300,12 +303,22 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite) | ... | @@ -300,12 +303,22 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite) |
300 | status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &n); | 303 | status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &n); |
301 | if (status == 0 && n != 0) | 304 | if (status == 0 && n != 0) |
302 | { | 305 | { |
303 | char *from = calloc (1, n + 1); | 306 | char *from; |
304 | char *addr; | 307 | char *addr; |
308 | from = calloc (1, n + 1); | ||
309 | if (from == NULL) | ||
310 | return ENOMEM; | ||
311 | addr = calloc (1, n + 1); | ||
312 | if (addr == NULL) | ||
313 | { | ||
314 | free (from); | ||
315 | return ENOMEM; | ||
316 | } | ||
305 | header_get_value (header, MU_HEADER_FROM, from, n + 1, NULL); | 317 | header_get_value (header, MU_HEADER_FROM, from, n + 1, NULL); |
306 | if (extract_addr (from, n, &addr, &n) == 0) | 318 | if (parseaddr (from, addr, n + 1) == 0) |
307 | { | 319 | { |
308 | n = (n > len) ? len : n; | 320 | size_t i = strlen (addr); |
321 | n = (i > len) ? len : i; | ||
309 | if (buf && len > 0) | 322 | if (buf && len > 0) |
310 | { | 323 | { |
311 | memcpy (buf, addr, n); | 324 | memcpy (buf, addr, n); |
... | @@ -563,77 +576,26 @@ message_set_get_part (message_t msg, int (*_get_part) | ... | @@ -563,77 +576,26 @@ message_set_get_part (message_t msg, int (*_get_part) |
563 | } | 576 | } |
564 | 577 | ||
565 | int | 578 | int |
566 | message_register (message_t msg, size_t type, | 579 | message_get_observable (message_t msg, observable_t *pobservable) |
567 | int (*action) (size_t typ, void *arg), void *arg) | ||
568 | { | 580 | { |
569 | event_t event; | 581 | if (msg == NULL || pobservable == NULL) |
570 | size_t i; | ||
571 | if (msg == NULL || action == NULL || type == 0) | ||
572 | return EINVAL; | 582 | return EINVAL; |
573 | 583 | ||
574 | /* Find a free spot. */ | 584 | if (msg->observable == NULL) |
575 | for (i = 0; i < msg->event_num; i++) | ||
576 | { | 585 | { |
577 | event = &(msg->event[i]); | 586 | int status = observable_create (&(msg->observable), msg); |
578 | if (event->_action == NULL) | 587 | if (status != 0) |
579 | { | 588 | return status; |
580 | event->type = type; | ||
581 | event->_action = action; | ||
582 | event->arg = arg; | ||
583 | return 0; | ||
584 | } | ||
585 | } | 589 | } |
586 | event = realloc (msg->event, (msg->event_num + 1)*sizeof (*event)); | 590 | *pobservable = msg->observable; |
587 | if (event == NULL) | ||
588 | return ENOMEM; | ||
589 | msg->event = event; | ||
590 | event[msg->event_num]._action = action; | ||
591 | event[msg->event_num].type = type; | ||
592 | event[msg->event_num].arg = arg; | ||
593 | msg->event_num++; | ||
594 | return 0; | 591 | return 0; |
595 | } | 592 | } |
596 | 593 | ||
597 | int | ||
598 | message_deregister (message_t msg, void *action) | ||
599 | { | ||
600 | size_t i; | ||
601 | event_t event; | ||
602 | if (msg == NULL || action == NULL) | ||
603 | return EINVAL; | ||
604 | |||
605 | for (i = 0; i < msg->event_num; i++) | ||
606 | { | ||
607 | event = &(msg->event[i]); | ||
608 | if ((int)event->_action == (int)action) | ||
609 | { | ||
610 | event->type = 0; | ||
611 | event->_action = NULL; | ||
612 | event->arg = NULL; | ||
613 | return 0; | ||
614 | } | ||
615 | } | ||
616 | return ENOENT; | ||
617 | } | ||
618 | |||
619 | void | ||
620 | message_notification (message_t msg, size_t type) | ||
621 | { | ||
622 | size_t i; | ||
623 | event_t event; | ||
624 | for (i = 0; i < msg->event_num; i++) | ||
625 | { | ||
626 | event = &(msg->event[i]); | ||
627 | if ((event->_action) && (event->type & type)) | ||
628 | event->_action (type, event->arg); | ||
629 | } | ||
630 | } | ||
631 | |||
632 | static int | 594 | static int |
633 | message_read (stream_t is, char *buf, size_t buflen, | 595 | message_read (stream_t is, char *buf, size_t buflen, |
634 | off_t off, size_t *pnread ) | 596 | off_t off, size_t *pnread ) |
635 | { | 597 | { |
636 | message_t msg = is->owner; | 598 | message_t msg = stream_get_owner (is); |
637 | stream_t his, bis; | 599 | stream_t his, bis; |
638 | size_t hread, hsize, bread, bsize; | 600 | size_t hread, hsize, bread, bsize; |
639 | 601 | ||
... | @@ -670,11 +632,11 @@ static int | ... | @@ -670,11 +632,11 @@ static int |
670 | message_write (stream_t os, const char *buf, size_t buflen, | 632 | message_write (stream_t os, const char *buf, size_t buflen, |
671 | off_t off, size_t *pnwrite) | 633 | off_t off, size_t *pnwrite) |
672 | { | 634 | { |
673 | message_t msg; | 635 | message_t msg = stream_get_owner (os); |
674 | int status = 0; | 636 | int status = 0; |
675 | size_t bufsize = buflen; | 637 | size_t bufsize = buflen; |
676 | 638 | ||
677 | if (os == NULL || (msg = os->owner) == NULL) | 639 | if (msg == NULL) |
678 | return EINVAL; | 640 | return EINVAL; |
679 | 641 | ||
680 | /* Skip the obvious. */ | 642 | /* Skip the obvious. */ |
... | @@ -772,11 +734,11 @@ message_write (stream_t os, const char *buf, size_t buflen, | ... | @@ -772,11 +734,11 @@ message_write (stream_t os, const char *buf, size_t buflen, |
772 | static int | 734 | static int |
773 | message_get_fd (stream_t stream, int *pfd) | 735 | message_get_fd (stream_t stream, int *pfd) |
774 | { | 736 | { |
775 | message_t msg; | 737 | message_t msg = stream_get_owner (stream); |
776 | body_t body; | 738 | body_t body; |
777 | stream_t is; | 739 | stream_t is; |
778 | 740 | ||
779 | if (stream == NULL || (msg = stream->owner) == NULL) | 741 | if (msg == NULL) |
780 | return EINVAL; | 742 | return EINVAL; |
781 | 743 | ||
782 | /* Probably being lazy, then create a body for the stream. */ | 744 | /* Probably being lazy, then create a body for the stream. */ |
... | @@ -794,72 +756,3 @@ message_get_fd (stream_t stream, int *pfd) | ... | @@ -794,72 +756,3 @@ message_get_fd (stream_t stream, int *pfd) |
794 | body_get_stream (body, &is); | 756 | body_get_stream (body, &is); |
795 | return stream_get_fd (is, pfd); | 757 | return stream_get_fd (is, pfd); |
796 | } | 758 | } |
797 | |||
798 | static int | ||
799 | extract_addr (const char *s, size_t n, char **presult, size_t *pnwrite) | ||
800 | { | ||
801 | char *p, *p1, *p2; | ||
802 | |||
803 | if (s == NULL || n == 0 || presult == NULL) | ||
804 | return EINVAL; | ||
805 | |||
806 | /* Skip the double quotes. */ | ||
807 | p = memchr (s, '\"', n); | ||
808 | if (p != NULL) | ||
809 | { | ||
810 | p1 = memchr (s, '<', p - s); | ||
811 | p2 = memchr (s, '@', p - s); | ||
812 | if (p1 == NULL && p2 == NULL) | ||
813 | { | ||
814 | p1 = memchr (p + 1, '\"', n - ((p + 1) - s)); | ||
815 | if (p1 != NULL) | ||
816 | { | ||
817 | n -= (p1 + 1) - s; | ||
818 | s = p1 + 1; | ||
819 | } | ||
820 | } | ||
821 | } | ||
822 | |||
823 | /* <name@hostname> ?? */ | ||
824 | p = memchr (s, '<', n); | ||
825 | if (p != NULL) | ||
826 | { | ||
827 | p1 = memchr (p, '>', n - (p - s)); | ||
828 | if (p1 != NULL && (p1 - p) > 1) | ||
829 | { | ||
830 | p2 = memchr (p, ' ', p1 - p); | ||
831 | if (p2 == NULL) | ||
832 | { | ||
833 | /* The NULL is already accounted for. */ | ||
834 | *presult = calloc (1, p1 - p); | ||
835 | if (*presult == NULL) | ||
836 | return ENOMEM; | ||
837 | memcpy (*presult, p + 1, (p1 - p) - 1); | ||
838 | if (pnwrite) | ||
839 | *pnwrite = (p1 - p) - 1; | ||
840 | return 0; | ||
841 | } | ||
842 | } | ||
843 | } | ||
844 | /* name@domain */ | ||
845 | p = memchr (s, '@', n); | ||
846 | if (p != NULL) | ||
847 | { | ||
848 | p1 = p; | ||
849 | while (*p != ' ' && p != s) | ||
850 | p--; | ||
851 | while (*p1 != ' ' && p1 < (s + n)) | ||
852 | p1++; | ||
853 | *presult = calloc (1, (p1 - p) + 1); | ||
854 | if (*presult == NULL) | ||
855 | return ENOMEM; | ||
856 | memcpy (*presult, p, p1 - p); | ||
857 | if (pnwrite) | ||
858 | *pnwrite = p1 - p; | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | *presult = NULL; | ||
863 | return EINVAL; | ||
864 | |||
865 | } | ... | ... |
... | @@ -16,17 +16,18 @@ | ... | @@ -16,17 +16,18 @@ |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | 18 | ||
19 | #include <message0.h> | ||
20 | #include <mime0.h> | ||
21 | #include <stream0.h> | ||
22 | #include <body0.h> | ||
23 | |||
24 | #include <errno.h> | 19 | #include <errno.h> |
25 | #include <stdio.h> | 20 | #include <stdio.h> |
26 | #include <stdlib.h> | 21 | #include <stdlib.h> |
27 | #include <string.h> | 22 | #include <string.h> |
28 | #include <ctype.h> | 23 | #include <ctype.h> |
29 | 24 | ||
25 | #include <mailutils/message.h> | ||
26 | #include <mailutils/stream.h> | ||
27 | #include <mailutils/body.h> | ||
28 | #include <mailutils/header.h> | ||
29 | #include <mime0.h> | ||
30 | |||
30 | #ifndef TRUE | 31 | #ifndef TRUE |
31 | #define TRUE (1) | 32 | #define TRUE (1) |
32 | #define FALSE (0) | 33 | #define FALSE (0) |
... | @@ -34,11 +35,8 @@ | ... | @@ -34,11 +35,8 @@ |
34 | 35 | ||
35 | /* TODO: | 36 | /* TODO: |
36 | * Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib. | 37 | * Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib. |
37 | * Define mbx i/f for protocols that support mime parsing (IMAP). | ||
38 | */ | 38 | */ |
39 | 39 | ||
40 | #define DIGEST_TYPE "Content-Type: message/rfc822" | ||
41 | |||
42 | static int _mime_is_multipart_digest(mime_t mime) | 40 | static int _mime_is_multipart_digest(mime_t mime) |
43 | { | 41 | { |
44 | if ( mime->content_type ) | 42 | if ( mime->content_type ) |
... | @@ -46,16 +44,16 @@ static int _mime_is_multipart_digest(mime_t mime) | ... | @@ -46,16 +44,16 @@ static int _mime_is_multipart_digest(mime_t mime) |
46 | return 0; | 44 | return 0; |
47 | } | 45 | } |
48 | 46 | ||
49 | static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int body_len) | 47 | static int _mime_append_part(mime_t mime, message_t msg, int offset, int len, int lines) |
50 | { | 48 | { |
51 | struct _mime_part *mime_part, **part_arr; | 49 | struct _mime_part *mime_part, **part_arr; |
52 | int ret; | 50 | int ret; |
53 | size_t size; | 51 | size_t size; |
52 | header_t hdr; | ||
54 | 53 | ||
55 | if ( ( mime_part = calloc(1, sizeof(*mime_part)) ) == NULL ) | 54 | if ( ( mime_part = calloc(1, sizeof(*mime_part)) ) == NULL ) |
56 | return ENOMEM; | 55 | return ENOMEM; |
57 | 56 | ||
58 | memcpy(mime_part->sig,"MIME", 4); | ||
59 | if ( mime->nmtp_parts >= mime->tparts ) { | 57 | if ( mime->nmtp_parts >= mime->tparts ) { |
60 | if ( ( part_arr = realloc(mime->mtp_parts, ( mime->tparts + 5 ) * sizeof(mime_part)) ) == NULL ) { | 58 | if ( ( part_arr = realloc(mime->mtp_parts, ( mime->tparts + 5 ) * sizeof(mime_part)) ) == NULL ) { |
61 | free(mime_part); | 59 | free(mime_part); |
... | @@ -66,21 +64,34 @@ static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int bo | ... | @@ -66,21 +64,34 @@ static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int bo |
66 | } | 64 | } |
67 | mime->mtp_parts[mime->nmtp_parts++] = mime_part; | 65 | mime->mtp_parts[mime->nmtp_parts++] = mime_part; |
68 | if ( msg == NULL ) { | 66 | if ( msg == NULL ) { |
69 | if ( ( ret = header_create(&mime_part->hdr, mime->header_buf, mime->header_length, mime_part) ) != 0 ) { | 67 | if ( ( ret = message_create(&(mime_part->msg), mime_part) ) == 0 ) { |
68 | if ( ( ret = header_create(&hdr, mime->header_buf, mime->header_length, mime_part->msg) ) != 0 ) { | ||
69 | message_destroy(&mime_part->msg, mime_part); | ||
70 | free(mime_part); | ||
71 | return ret; | ||
72 | } | ||
73 | message_set_header(mime_part->msg, hdr, mime_part); | ||
74 | } else { | ||
70 | free(mime_part); | 75 | free(mime_part); |
71 | return ret; | 76 | return ret; |
72 | } | 77 | } |
73 | mime->header_length = 0; | 78 | mime->header_length = 0; |
74 | if ( ( ret = header_get_value(mime_part->hdr, "Content-Type", NULL, 0, &size) ) != 0 || size == 0 ) { | 79 | if ( ( ret = header_get_value(hdr, "Content-Type", NULL, 0, &size) ) != 0 || size == 0 ) { |
75 | if ( _mime_is_multipart_digest(mime) ) | 80 | if ( _mime_is_multipart_digest(mime) ) |
76 | header_set_value(mime_part->hdr, "Content-Type", "message/rfc822", 0); | 81 | header_set_value(hdr, "Content-Type", "message/rfc822", 0); |
77 | else | 82 | else |
78 | header_set_value(mime_part->hdr, "Content-Type", "text/plain", 0); | 83 | header_set_value(hdr, "Content-Type", "text/plain", 0); |
79 | } | 84 | } |
85 | mime_part->len = len; | ||
86 | mime_part->lines = lines; | ||
87 | mime_part->offset = offset; | ||
88 | } else { | ||
89 | message_size(msg, &mime_part->len); | ||
90 | message_lines(msg, &mime_part->lines); | ||
91 | if ( mime->nmtp_parts > 1 ) | ||
92 | mime_part->offset = mime->mtp_parts[mime->nmtp_parts-2]->len; | ||
93 | mime_part->msg = msg; | ||
80 | } | 94 | } |
81 | mime_part->body_len = body_len; | ||
82 | mime_part->body_offset = body_offset; | ||
83 | mime_part->msg = msg; | ||
84 | mime_part->mime = mime; | 95 | mime_part->mime = mime; |
85 | return 0; | 96 | return 0; |
86 | } | 97 | } |
... | @@ -170,7 +181,7 @@ static char *_mime_get_param(char *field_body, const char *param, int *len) | ... | @@ -170,7 +181,7 @@ static char *_mime_get_param(char *field_body, const char *param, int *len) |
170 | continue; | 181 | continue; |
171 | } | 182 | } |
172 | else | 183 | else |
173 | return was_quoted ? v + 1 : v; /* return unquted value */ | 184 | return was_quoted ? v + 1 : v; /* return unquoted value */ |
174 | } | 185 | } |
175 | return NULL; | 186 | return NULL; |
176 | } | 187 | } |
... | @@ -203,7 +214,7 @@ static void _mime_append_header_line(mime_t mime) | ... | @@ -203,7 +214,7 @@ static void _mime_append_header_line(mime_t mime) |
203 | static int _mime_parse_mpart_message(mime_t mime) | 214 | static int _mime_parse_mpart_message(mime_t mime) |
204 | { | 215 | { |
205 | char *cp, *cp2; | 216 | char *cp, *cp2; |
206 | int blength, body_length, body_offset, ret; | 217 | int blength, body_length, body_offset, body_lines, ret; |
207 | size_t nbytes; | 218 | size_t nbytes; |
208 | 219 | ||
209 | if ( !(mime->flags & MIME_PARSER_ACTIVE) ) { | 220 | if ( !(mime->flags & MIME_PARSER_ACTIVE) ) { |
... | @@ -225,6 +236,7 @@ static int _mime_parse_mpart_message(mime_t mime) | ... | @@ -225,6 +236,7 @@ static int _mime_parse_mpart_message(mime_t mime) |
225 | } | 236 | } |
226 | body_length = mime->body_length; | 237 | body_length = mime->body_length; |
227 | body_offset = mime->body_offset; | 238 | body_offset = mime->body_offset; |
239 | body_lines = mime->body_lines; | ||
228 | 240 | ||
229 | while ( ( ret = stream_read(mime->stream, mime->cur_buf, mime->buf_size, mime->cur_offset, &nbytes) ) == 0 && nbytes ) { | 241 | while ( ( ret = stream_read(mime->stream, mime->cur_buf, mime->buf_size, mime->cur_offset, &nbytes) ) == 0 && nbytes ) { |
230 | cp = mime->cur_buf; | 242 | cp = mime->cur_buf; |
... | @@ -240,6 +252,8 @@ static int _mime_parse_mpart_message(mime_t mime) | ... | @@ -240,6 +252,8 @@ static int _mime_parse_mpart_message(mime_t mime) |
240 | case MIME_STATE_SCAN_BOUNDARY: | 252 | case MIME_STATE_SCAN_BOUNDARY: |
241 | cp2 = mime->cur_line[0] == '\n' ? mime->cur_line + 1 : mime->cur_line; | 253 | cp2 = mime->cur_line[0] == '\n' ? mime->cur_line + 1 : mime->cur_line; |
242 | blength = strlen(mime->boundary); | 254 | blength = strlen(mime->boundary); |
255 | if ( mime->header_length ) | ||
256 | body_lines++; | ||
243 | if ( mime->line_ndx >= blength ) { | 257 | if ( mime->line_ndx >= blength ) { |
244 | if ( ( !strncasecmp(cp2,"--", 2) && !strncasecmp(cp2+2, mime->boundary, blength) ) | 258 | if ( ( !strncasecmp(cp2,"--", 2) && !strncasecmp(cp2+2, mime->boundary, blength) ) |
245 | || !strncasecmp(cp2, mime->boundary, blength) ) { | 259 | || !strncasecmp(cp2, mime->boundary, blength) ) { |
... | @@ -247,7 +261,7 @@ static int _mime_parse_mpart_message(mime_t mime) | ... | @@ -247,7 +261,7 @@ static int _mime_parse_mpart_message(mime_t mime) |
247 | mime->flags &= ~MIME_PARSER_HAVE_CR; | 261 | mime->flags &= ~MIME_PARSER_HAVE_CR; |
248 | body_length = mime->cur_offset - body_offset - mime->line_ndx + 1; | 262 | body_length = mime->cur_offset - body_offset - mime->line_ndx + 1; |
249 | if ( mime->header_length ) /* this skips the preamble */ | 263 | if ( mime->header_length ) /* this skips the preamble */ |
250 | _mime_append_part(mime, NULL, body_offset, body_length); | 264 | _mime_append_part(mime, NULL, body_offset, body_length, body_lines); |
251 | if ( ( cp2 + blength + 2 < cp && !strncasecmp(cp2+2+blength, "--",2) ) || | 265 | if ( ( cp2 + blength + 2 < cp && !strncasecmp(cp2+2+blength, "--",2) ) || |
252 | !strncasecmp(cp2+blength, "--",2) ) { /* very last boundary */ | 266 | !strncasecmp(cp2+blength, "--",2) ) { /* very last boundary */ |
253 | mime->parser_state = MIME_STATE_BEGIN_LINE; | 267 | mime->parser_state = MIME_STATE_BEGIN_LINE; |
... | @@ -267,6 +281,7 @@ static int _mime_parse_mpart_message(mime_t mime) | ... | @@ -267,6 +281,7 @@ static int _mime_parse_mpart_message(mime_t mime) |
267 | if ( mime->line_ndx == 1 || mime->cur_line[0] == '\r' ) { | 281 | if ( mime->line_ndx == 1 || mime->cur_line[0] == '\r' ) { |
268 | mime->parser_state = MIME_STATE_BEGIN_LINE; | 282 | mime->parser_state = MIME_STATE_BEGIN_LINE; |
269 | body_offset = mime->cur_offset + 1; | 283 | body_offset = mime->cur_offset + 1; |
284 | body_lines = 0; | ||
270 | } | 285 | } |
271 | mime->line_ndx = -1; | 286 | mime->line_ndx = -1; |
272 | break; | 287 | break; |
... | @@ -281,59 +296,225 @@ static int _mime_parse_mpart_message(mime_t mime) | ... | @@ -281,59 +296,225 @@ static int _mime_parse_mpart_message(mime_t mime) |
281 | nbytes--; | 296 | nbytes--; |
282 | cp++; | 297 | cp++; |
283 | } | 298 | } |
284 | if ( mime->flags & MIME_INCREAMENTAL_PARSER ) { | ||
285 | /* | ||
286 | * can't really do this since returning EAGAIN will make the MUA think | ||
287 | * it should select on the messages stream fd. re-think this whole | ||
288 | * non-blocking thing..... | ||
289 | |||
290 | ret = EAGAIN; | ||
291 | break; | ||
292 | */ | ||
293 | } | ||
294 | } | 299 | } |
300 | mime->body_lines = body_lines; | ||
295 | mime->body_length = body_length; | 301 | mime->body_length = body_length; |
296 | mime->body_offset = body_offset; | 302 | mime->body_offset = body_offset; |
297 | if ( ret != EAGAIN ) { /* finished cleanup */ | 303 | if ( ret != EAGAIN ) { /* finished cleanup */ |
298 | if ( mime->header_length ) /* this skips the preamble */ | 304 | if ( mime->header_length ) /* this skips the preamble */ |
299 | _mime_append_part(mime, NULL, body_offset, body_length); | 305 | _mime_append_part(mime, NULL, body_offset, body_length, body_lines); |
300 | mime->flags &= ~MIME_PARSER_ACTIVE; | 306 | mime->flags &= ~MIME_PARSER_ACTIVE; |
301 | mime->body_offset = mime->body_length = mime->header_length = 0; | 307 | mime->body_offset = mime->body_length = mime->header_length = mime->body_lines = 0; |
302 | } | 308 | } |
303 | return ret; | 309 | return ret; |
304 | } | 310 | } |
305 | 311 | ||
306 | static int _mime_message_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes) | 312 | /*------ Mime message functions for READING a multipart message -----*/ |
313 | |||
314 | static int _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes) | ||
307 | { | 315 | { |
308 | struct _mime_part *mime_part = stream->owner; | 316 | body_t body = stream_get_owner(stream); |
309 | size_t read_len; | 317 | message_t msg = body_get_owner(body); |
318 | struct _mime_part *mime_part = message_get_owner(msg); | ||
319 | size_t read_len; | ||
310 | 320 | ||
311 | if ( nbytes == NULL ) | 321 | if ( nbytes == NULL ) |
312 | return(EINVAL); | 322 | return(EINVAL); |
313 | 323 | ||
314 | *nbytes = 0; | 324 | *nbytes = 0; |
315 | read_len = (int)mime_part->body_len - (int)off; | 325 | read_len = (int)mime_part->len - (int)off; |
316 | if ( read_len <= 0 ) | 326 | if ( read_len <= 0 ) |
317 | return 0; | 327 | return 0; |
318 | read_len = (buflen <= read_len)? buflen : read_len; | 328 | read_len = (buflen <= read_len)? buflen : read_len; |
319 | 329 | ||
320 | return stream_read(mime_part->mime->stream, buf, read_len, mime_part->body_offset + off, nbytes ); | 330 | return stream_read(mime_part->mime->stream, buf, read_len, mime_part->offset + off, nbytes ); |
321 | } | 331 | } |
322 | 332 | ||
323 | static int _mime_message_fd(stream_t stream, int *fd) | 333 | static int _mimepart_body_fd(stream_t stream, int *fd) |
324 | { | 334 | { |
325 | struct _mime_part *mime_part = stream->owner; | 335 | body_t body = stream_get_owner(stream); |
336 | message_t msg = body_get_owner(body); | ||
337 | struct _mime_part *mime_part = message_get_owner(msg); | ||
326 | 338 | ||
327 | return stream_get_fd(mime_part->mime->stream, fd); | 339 | return stream_get_fd(mime_part->mime->stream, fd); |
328 | } | 340 | } |
329 | 341 | ||
330 | static int _mime_body_size (body_t body, size_t *psize) | 342 | static int _mimepart_body_size (body_t body, size_t *psize) |
331 | { | 343 | { |
332 | struct _mime_part *mime_part = body->owner; | 344 | message_t msg = body_get_owner(body); |
345 | struct _mime_part *mime_part = message_get_owner(msg); | ||
346 | |||
333 | if (mime_part == NULL) | 347 | if (mime_part == NULL) |
334 | return EINVAL; | 348 | return EINVAL; |
335 | if (psize) | 349 | if (psize) |
336 | *psize = mime_part->body_len; | 350 | *psize = mime_part->len; |
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int _mimepart_body_lines (body_t body, size_t *plines) | ||
355 | { | ||
356 | message_t msg = body_get_owner(body); | ||
357 | struct _mime_part *mime_part = message_get_owner(msg); | ||
358 | |||
359 | if (mime_part == NULL) | ||
360 | return EINVAL; | ||
361 | if (plines) | ||
362 | *plines = mime_part->lines; | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /*------ Mime message/header functions for CREATING multipart message -----*/ | ||
367 | static int _mime_set_content_type(mime_t mime) | ||
368 | { | ||
369 | char content_type[256]; | ||
370 | char boundary[128]; | ||
371 | |||
372 | if ( mime->nmtp_parts > 1 ) { | ||
373 | if ( mime->flags & MIME_ADDED_MULTIPART ) | ||
374 | return 0; | ||
375 | if ( mime->flags & MIME_MULTIPART_MIXED ) | ||
376 | strcpy(content_type, "multipart/mixed; boundary="); | ||
377 | else | ||
378 | strcpy(content_type, "multipart/alternative; boundary="); | ||
379 | if ( mime->boundary == NULL ) { | ||
380 | sprintf (boundary,"%ld-%ld=:%ld",random (),time (0), getpid ()); | ||
381 | if ( ( mime->boundary = strdup(boundary) ) == NULL ) | ||
382 | return ENOMEM; | ||
383 | } | ||
384 | strcat(content_type, "\""); | ||
385 | strcat(content_type, mime->boundary); | ||
386 | strcat(content_type, "\""); | ||
387 | mime->flags |= MIME_ADDED_MULTIPART; | ||
388 | } else { | ||
389 | if ( (mime->flags & (MIME_ADDED_CONTENT_TYPE|MIME_ADDED_MULTIPART)) == MIME_ADDED_CONTENT_TYPE ) | ||
390 | return 0; | ||
391 | mime->flags &= ~MIME_ADDED_MULTIPART; | ||
392 | strcpy(content_type, "text/plain; charset=us-ascii"); | ||
393 | } | ||
394 | mime->flags |= MIME_ADDED_CONTENT_TYPE; | ||
395 | return header_set_value(mime->hdrs, "Content-Type", content_type, 1); | ||
396 | } | ||
397 | |||
398 | static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes) | ||
399 | { | ||
400 | body_t body = stream_get_owner(stream); | ||
401 | message_t msg = body_get_owner(body); | ||
402 | mime_t mime = message_get_owner(msg); | ||
403 | int ret = 0, len; | ||
404 | size_t part_nbytes = 0; | ||
405 | stream_t msg_stream = NULL; | ||
406 | |||
407 | if ( mime->nmtp_parts == 0 ) | ||
408 | return EINVAL; | ||
409 | |||
410 | if ( off == 0 ) { /* reset message */ | ||
411 | mime->cur_offset = 0; | ||
412 | mime->cur_part = 0; | ||
413 | } | ||
414 | |||
415 | if ( off != mime->cur_offset ) | ||
416 | return ESPIPE; | ||
417 | |||
418 | if ( nbytes ) | ||
419 | *nbytes = 0; | ||
420 | |||
421 | if ( mime->cur_part == mime->nmtp_parts ) | ||
422 | return 0; | ||
423 | |||
424 | if ( ( ret = _mime_set_content_type(mime) ) == 0 ) { | ||
425 | do { | ||
426 | len = 0; | ||
427 | if ( mime->nmtp_parts > 1 && ( mime->flags & MIME_INSERT_BOUNDARY || mime->cur_offset == 0 ) ) { | ||
428 | mime->cur_part++; | ||
429 | len = 2; | ||
430 | buf[0] = buf[1] = '-'; | ||
431 | buf+=2; | ||
432 | len += strlen(mime->boundary); | ||
433 | strcpy(buf, mime->boundary); | ||
434 | buf+= strlen(mime->boundary); | ||
435 | if ( mime->cur_part == mime->nmtp_parts ) { | ||
436 | len+=2; | ||
437 | buf[0] = buf[1] = '-'; | ||
438 | buf+=2; | ||
439 | } | ||
440 | len++; | ||
441 | buf[0] = '\n'; | ||
442 | buf++; | ||
443 | mime->flags &= ~MIME_INSERT_BOUNDARY; | ||
444 | buflen =- len; | ||
445 | mime->part_offset = 0; | ||
446 | if ( mime->cur_part == mime->nmtp_parts ) { | ||
447 | if ( nbytes ) | ||
448 | *nbytes += len; | ||
449 | mime->cur_offset +=len; | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | message_get_stream(mime->mtp_parts[mime->cur_part]->msg, &msg_stream); | ||
454 | ret = stream_read(msg_stream, buf, buflen, mime->part_offset, &part_nbytes ); | ||
455 | len += part_nbytes; | ||
456 | mime->part_offset += part_nbytes; | ||
457 | if ( nbytes ) | ||
458 | *nbytes += len; | ||
459 | mime->cur_offset += len; | ||
460 | if ( ret == 0 && part_nbytes == 0 ) | ||
461 | mime->flags |= MIME_INSERT_BOUNDARY; | ||
462 | } while( ret == 0 && part_nbytes == 0 ); | ||
463 | } | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | static int _mime_body_fd(stream_t stream, int *fd) | ||
468 | { | ||
469 | body_t body = stream_get_owner(stream); | ||
470 | message_t msg = body_get_owner(body); | ||
471 | mime_t mime = message_get_owner(msg); | ||
472 | stream_t msg_stream = NULL; | ||
473 | |||
474 | if ( mime->nmtp_parts == 0 || mime->cur_offset == 0 ) | ||
475 | return EINVAL; | ||
476 | message_get_stream(mime->mtp_parts[mime->cur_part]->msg, &msg_stream); | ||
477 | return stream_get_fd(msg_stream, fd); | ||
478 | } | ||
479 | |||
480 | static int _mime_body_size (body_t body, size_t *psize) | ||
481 | { | ||
482 | message_t msg = body_get_owner(body); | ||
483 | mime_t mime = message_get_owner(msg); | ||
484 | int i; | ||
485 | size_t size; | ||
486 | |||
487 | if ( mime->nmtp_parts == 0 ) | ||
488 | return EINVAL; | ||
489 | |||
490 | for ( i=0;i<mime->nmtp_parts;i++ ) { | ||
491 | message_size(mime->mtp_parts[i]->msg, &size); | ||
492 | *psize+=size; | ||
493 | if ( mime->nmtp_parts > 1 ) /* boundary line */ | ||
494 | *psize+= strlen(mime->boundary) + 3; | ||
495 | } | ||
496 | if ( mime->nmtp_parts > 1 ) /* ending boundary line */ | ||
497 | *psize+= 2; | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int _mime_body_lines (body_t body, size_t *plines) | ||
503 | { | ||
504 | message_t msg = body_get_owner(body); | ||
505 | mime_t mime = message_get_owner(msg); | ||
506 | int i; | ||
507 | size_t lines; | ||
508 | |||
509 | if ( mime->nmtp_parts == 0 ) | ||
510 | return EINVAL; | ||
511 | |||
512 | for ( i = 0; i < mime->nmtp_parts; i++ ) { | ||
513 | message_lines(mime->mtp_parts[i]->msg, &lines); | ||
514 | plines+=lines; | ||
515 | if ( mime->nmtp_parts > 1 ) /* boundary line */ | ||
516 | plines++; | ||
517 | } | ||
337 | return 0; | 518 | return 0; |
338 | } | 519 | } |
339 | 520 | ||
... | @@ -342,11 +523,12 @@ int mime_create(mime_t *pmime, message_t msg, int flags) | ... | @@ -342,11 +523,12 @@ int mime_create(mime_t *pmime, message_t msg, int flags) |
342 | mime_t mime = NULL; | 523 | mime_t mime = NULL; |
343 | int ret = 0; | 524 | int ret = 0; |
344 | size_t size; | 525 | size_t size; |
526 | body_t body; | ||
345 | 527 | ||
346 | if (pmime == NULL) | 528 | if (pmime == NULL) |
347 | return EINVAL; | 529 | return EINVAL; |
348 | *pmime = NULL; | 530 | *pmime = NULL; |
349 | if ( ( mime = calloc (1, sizeof (*mime)) ) == NULL ) | 531 | if ( ( mime = calloc(1, sizeof (*mime)) ) == NULL ) |
350 | return ENOMEM; | 532 | return ENOMEM; |
351 | if ( msg ) { | 533 | if ( msg ) { |
352 | if ( ( ret = message_get_header(msg, &(mime->hdrs)) ) == 0 ) { | 534 | if ( ( ret = message_get_header(msg, &(mime->hdrs)) ) == 0 ) { |
... | @@ -363,14 +545,13 @@ int mime_create(mime_t *pmime, message_t msg, int flags) | ... | @@ -363,14 +545,13 @@ int mime_create(mime_t *pmime, message_t msg, int flags) |
363 | if (ret == 0 ) { | 545 | if (ret == 0 ) { |
364 | mime->msg = msg; | 546 | mime->msg = msg; |
365 | mime->buf_size = MIME_DFLT_BUF_SIZE; | 547 | mime->buf_size = MIME_DFLT_BUF_SIZE; |
366 | message_get_stream(msg, &(mime->stream)); | 548 | message_get_body(msg, &body); |
549 | body_get_stream(body, &(mime->stream)); | ||
367 | } | 550 | } |
368 | } | 551 | } |
369 | } | 552 | } |
370 | else { | 553 | else { |
371 | if ( ( ret = message_create( &(mime->msg), mime ) ) == 0 ) { | 554 | mime->flags |= MIME_NEW_MESSAGE; |
372 | mime->flags |= MIME_NEW_MESSAGE; | ||
373 | } | ||
374 | } | 555 | } |
375 | if ( ret != 0 ) { | 556 | if ( ret != 0 ) { |
376 | if ( mime->content_type ) | 557 | if ( mime->content_type ) |
... | @@ -378,7 +559,7 @@ int mime_create(mime_t *pmime, message_t msg, int flags) | ... | @@ -378,7 +559,7 @@ int mime_create(mime_t *pmime, message_t msg, int flags) |
378 | free(mime); | 559 | free(mime); |
379 | } | 560 | } |
380 | else { | 561 | else { |
381 | mime->flags = (flags & MIME_FLAG_MASK); | 562 | mime->flags |= (flags & MIME_FLAG_MASK); |
382 | *pmime = mime; | 563 | *pmime = mime; |
383 | } | 564 | } |
384 | return ret; | 565 | return ret; |
... | @@ -397,8 +578,6 @@ void mime_destroy(mime_t *pmime) | ... | @@ -397,8 +578,6 @@ void mime_destroy(mime_t *pmime) |
397 | mime_part = mime->mtp_parts[i]; | 578 | mime_part = mime->mtp_parts[i]; |
398 | if ( mime_part->msg ) | 579 | if ( mime_part->msg ) |
399 | message_destroy(&mime_part->msg, mime_part); | 580 | message_destroy(&mime_part->msg, mime_part); |
400 | else if ( mime_part->hdr ) | ||
401 | header_destroy(&mime_part->hdr, mime_part); | ||
402 | } | 581 | } |
403 | } | 582 | } |
404 | if ( mime->content_type ) | 583 | if ( mime->content_type ) |
... | @@ -419,7 +598,6 @@ void mime_destroy(mime_t *pmime) | ... | @@ -419,7 +598,6 @@ void mime_destroy(mime_t *pmime) |
419 | int mime_get_part(mime_t mime, int part, message_t *msg) | 598 | int mime_get_part(mime_t mime, int part, message_t *msg) |
420 | { | 599 | { |
421 | int nmtp_parts, ret = 0; | 600 | int nmtp_parts, ret = 0; |
422 | size_t hsize = 0; | ||
423 | stream_t stream; | 601 | stream_t stream; |
424 | body_t body; | 602 | body_t body; |
425 | struct _mime_part *mime_part; | 603 | struct _mime_part *mime_part; |
... | @@ -431,21 +609,17 @@ int mime_get_part(mime_t mime, int part, message_t *msg) | ... | @@ -431,21 +609,17 @@ int mime_get_part(mime_t mime, int part, message_t *msg) |
431 | *msg = mime->msg; | 609 | *msg = mime->msg; |
432 | else { | 610 | else { |
433 | mime_part = mime->mtp_parts[part-1]; | 611 | mime_part = mime->mtp_parts[part-1]; |
434 | if ( ( ret = message_create(&(mime_part->msg), mime_part) ) == 0 ) { | 612 | if ( ( ret = body_create(&body, mime_part->msg) ) == 0 ) { |
435 | message_set_header(mime_part->msg, mime_part->hdr, mime_part); | 613 | body_set_size (body, _mimepart_body_size, mime_part->msg); |
436 | header_size(mime_part->hdr, &hsize); | 614 | body_set_lines (body, _mimepart_body_lines, mime_part->msg); |
437 | if ( ( ret = body_create(&body, mime_part) ) == 0 ) { | 615 | if ( ( ret = stream_create(&stream, MU_STREAM_READ, body) ) == 0 ) { |
438 | if ( ( ret = stream_create(&stream, MU_STREAM_READ, mime_part) ) == 0 ) { | 616 | stream_set_read(stream, _mimepart_body_read, body); |
439 | body_set_size (body, _mime_body_size, mime_part); | 617 | stream_set_fd(stream, _mimepart_body_fd, body); |
440 | stream_set_read(stream, _mime_message_read, mime_part); | 618 | body_set_stream(body, stream, mime_part->msg); |
441 | stream_set_fd(stream, _mime_message_fd, mime_part); | 619 | message_set_body(mime_part->msg, body, mime_part); |
442 | body_set_stream(body, stream, mime_part); | 620 | *msg = mime_part->msg; |
443 | message_set_body(mime_part->msg, body, mime_part); | 621 | return 0; |
444 | *msg = mime_part->msg; | ||
445 | return 0; | ||
446 | } | ||
447 | } | 622 | } |
448 | message_destroy(&mime_part->msg, mime_part); | ||
449 | } | 623 | } |
450 | } | 624 | } |
451 | } | 625 | } |
... | @@ -472,15 +646,45 @@ int mime_add_part(mime_t mime, message_t msg) | ... | @@ -472,15 +646,45 @@ int mime_add_part(mime_t mime, message_t msg) |
472 | { | 646 | { |
473 | if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 ) | 647 | if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 ) |
474 | return EINVAL; | 648 | return EINVAL; |
475 | return _mime_append_part(mime, msg, 0, 0); | 649 | return _mime_append_part(mime, msg, 0, 0, 0); |
476 | } | 650 | } |
477 | 651 | ||
478 | int mime_get_message(mime_t mime, message_t *msg) | 652 | int mime_get_message(mime_t mime, message_t *msg) |
479 | { | 653 | { |
654 | stream_t body_stream; | ||
655 | body_t body; | ||
656 | int ret = 0; | ||
657 | |||
480 | if ( mime == NULL || msg == NULL ) | 658 | if ( mime == NULL || msg == NULL ) |
481 | return EINVAL; | 659 | return EINVAL; |
482 | *msg = mime->msg; | 660 | if ( mime->msg == NULL ) { |
483 | return 0; | 661 | if ( ( mime->flags & MIME_NEW_MESSAGE ) == 0 ) |
662 | return EINVAL; | ||
663 | if ( ( ret = message_create(&(mime->msg), mime) ) == 0 ) { | ||
664 | if ( ( ret = header_create(&(mime->hdrs), NULL, 0, mime->msg) ) == 0 ) { | ||
665 | message_set_header(mime->msg, mime->hdrs, mime); | ||
666 | header_set_value(mime->hdrs, "MIME-Version", "1.0", 0); | ||
667 | if ( ( ret = _mime_set_content_type(mime) ) == 0 ) { | ||
668 | if ( ( ret = body_create(&body, mime->msg) ) == 0 ) { | ||
669 | message_set_body(mime->msg, body, mime); | ||
670 | body_set_size (body, _mime_body_size, mime->msg); | ||
671 | body_set_lines (body, _mime_body_lines, mime->msg); | ||
672 | if ( ( ret = stream_create(&body_stream, MU_STREAM_READ, body) ) == 0 ) { | ||
673 | stream_set_read(body_stream, _mime_body_read, body); | ||
674 | stream_set_fd(body_stream, _mime_body_fd, body); | ||
675 | body_set_stream(body, body_stream, mime->msg); | ||
676 | *msg = mime->msg; | ||
677 | return 0; | ||
678 | } | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | message_destroy(&(mime->msg), mime); | ||
683 | } | ||
684 | } | ||
685 | if ( ret == 0 ) | ||
686 | *msg = mime->msg; | ||
687 | return ret; | ||
484 | } | 688 | } |
485 | 689 | ||
486 | int mime_is_multipart(mime_t mime) | 690 | int mime_is_multipart(mime_t mime) | ... | ... |
mailbox/misc.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <misc.h> | ||
23 | #include <string.h> | ||
24 | #include <stdio.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <string.h> | ||
27 | #include <ctype.h> | ||
28 | #include <stdlib.h> | ||
29 | |||
30 | size_t | ||
31 | _cpystr (char *dst, const char *src, size_t size) | ||
32 | { | ||
33 | size_t len = src ? strlen (src) : 0 ; | ||
34 | if (dst == NULL || size == 0) | ||
35 | return len; | ||
36 | if (len >= size) | ||
37 | len = size - 1; | ||
38 | memcpy (dst, src, len); | ||
39 | dst[len] = '\0'; | ||
40 | return len; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * parseaddr.c Read a valid RFC822 address with all the comments | ||
45 | * etc in it, and return _just_ the email address. | ||
46 | * | ||
47 | * Version: @(#)parseaddr.c 1.00 02-Apr-1999 miquels@cistron.nl | ||
48 | * | ||
49 | */ | ||
50 | |||
51 | |||
52 | struct token | ||
53 | { | ||
54 | struct token *next; | ||
55 | char word[1]; | ||
56 | }; | ||
57 | |||
58 | #define SKIPSPACE(p) do { while(*p && isspace(*p)) p++; } while(0) | ||
59 | |||
60 | /* Skip everything between quotes. */ | ||
61 | static void | ||
62 | quotes (char **ptr) | ||
63 | { | ||
64 | char *p = *ptr; | ||
65 | |||
66 | p++; | ||
67 | while (*p && *p != '"') | ||
68 | { | ||
69 | if (*p == '\\' && p[1]) | ||
70 | p++; | ||
71 | p++; | ||
72 | } | ||
73 | *ptr = p; | ||
74 | } | ||
75 | |||
76 | /* Return the next token. A token can be "<>()," or any "word". */ | ||
77 | static struct token * | ||
78 | gettoken (char **ptr) | ||
79 | { | ||
80 | struct token *tok; | ||
81 | char *p = *ptr; | ||
82 | char *begin; | ||
83 | int l, quit = 0; | ||
84 | |||
85 | SKIPSPACE(p); | ||
86 | begin = p; | ||
87 | |||
88 | while (!quit) | ||
89 | { | ||
90 | switch (*p) | ||
91 | { | ||
92 | case 0: | ||
93 | case ' ': | ||
94 | case '\t': | ||
95 | case '\n': | ||
96 | quit = 1; | ||
97 | break; | ||
98 | case '(': | ||
99 | case ')': | ||
100 | case '<': | ||
101 | case '>': | ||
102 | case ',': | ||
103 | if (p == begin) | ||
104 | p++; | ||
105 | quit = 1; | ||
106 | break; | ||
107 | case '\\': | ||
108 | if (p[1]) | ||
109 | p++; | ||
110 | break; | ||
111 | case '"': | ||
112 | quotes (&p); | ||
113 | break; | ||
114 | } | ||
115 | if (!quit) | ||
116 | p++; | ||
117 | } | ||
118 | |||
119 | l = p - begin; | ||
120 | if (l == 0) | ||
121 | return NULL; | ||
122 | tok = malloc (sizeof (struct token) + l); | ||
123 | if (tok == NULL) | ||
124 | return NULL; | ||
125 | tok->next = NULL; | ||
126 | strncpy (tok->word, begin, l); | ||
127 | tok->word[l] = 0; | ||
128 | |||
129 | SKIPSPACE (p); | ||
130 | *ptr = p; | ||
131 | |||
132 | return tok; | ||
133 | } | ||
134 | |||
135 | /* Get email address from rfc822 address. */ | ||
136 | int | ||
137 | parseaddr (const char *addr, char *buf, size_t bufsz) | ||
138 | { | ||
139 | const char *p; | ||
140 | struct token *t, *tok, *last; | ||
141 | struct token *brace = NULL; | ||
142 | int comment = 0; | ||
143 | |||
144 | tok = last = NULL; | ||
145 | |||
146 | /* Read address, remove comments right away. */ | ||
147 | p = addr; | ||
148 | while ((t = gettoken(&p)) != NULL && t->word[0] != ',') | ||
149 | { | ||
150 | if (t->word[0] == '(' || t->word[0] == ')' || comment) | ||
151 | { | ||
152 | free (t); | ||
153 | if (t->word[0] == '(') | ||
154 | comment++; | ||
155 | if (t->word[0] == ')') | ||
156 | comment--; | ||
157 | continue; | ||
158 | } | ||
159 | if (t->word[0] == '<') | ||
160 | brace = t; | ||
161 | if (tok) | ||
162 | last->next = t; | ||
163 | else | ||
164 | tok = t; | ||
165 | last = t; | ||
166 | } | ||
167 | |||
168 | /* Put extracted address into "buf" */ | ||
169 | buf[0] = 0; | ||
170 | t = brace ? brace->next : tok; | ||
171 | for (; t && t->word[0] != ',' && t->word[0] != '>'; t = t->next) | ||
172 | { | ||
173 | if (strlen (t->word) >= bufsz) | ||
174 | return -1; | ||
175 | bufsz -= strlen (t->word); | ||
176 | strcat (buf, t->word); | ||
177 | } | ||
178 | |||
179 | /* Free list of tokens. */ | ||
180 | for (t = tok; t; t = last) | ||
181 | { | ||
182 | last = t->next; | ||
183 | free (t); | ||
184 | } | ||
185 | |||
186 | return 0; | ||
187 | } |
mailbox/observer.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <mailutils/iterator.h> | ||
25 | #include <observer0.h> | ||
26 | |||
27 | int | ||
28 | observer_create (observer_t *pobserver, void *owner) | ||
29 | { | ||
30 | observer_t observer; | ||
31 | observer = calloc (sizeof (*observer), 1); | ||
32 | if (observer == NULL) | ||
33 | return ENOMEM; | ||
34 | observer->owner = owner; | ||
35 | *pobserver = observer; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | void | ||
40 | observer_destroy (observer_t *pobserver, void *owner) | ||
41 | { | ||
42 | if (pobserver && *pobserver) | ||
43 | { | ||
44 | observer_t observer = *pobserver; | ||
45 | if (observer->owner == owner || observer->flags & MU_OBSERVER_NO_CHECK) | ||
46 | { | ||
47 | if (observer->_destroy) | ||
48 | observer->_destroy (observer); | ||
49 | free (observer); | ||
50 | } | ||
51 | *pobserver = NULL; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | void * | ||
56 | observer_get_owner (observer_t observer) | ||
57 | { | ||
58 | return (observer) ? observer->owner : NULL; | ||
59 | } | ||
60 | |||
61 | int | ||
62 | observer_action (observer_t observer, size_t type) | ||
63 | { | ||
64 | if (observer == NULL) | ||
65 | return EINVAL; | ||
66 | if (observer->_action) | ||
67 | return observer->_action (observer, type); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | int | ||
72 | observer_set_action (observer_t observer, int (*_action) | ||
73 | __P ((observer_t, size_t)), void *owner) | ||
74 | { | ||
75 | if (observer == NULL) | ||
76 | return EINVAL; | ||
77 | if (observer->owner != owner) | ||
78 | return EACCES; | ||
79 | observer->_action = _action; | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | int | ||
84 | observer_set_destroy (observer_t observer, int (*_destroy) __P((observer_t)), | ||
85 | void *owner) | ||
86 | { | ||
87 | if (observer == NULL) | ||
88 | return EINVAL; | ||
89 | if (observer->owner != owner) | ||
90 | return EACCES; | ||
91 | observer->_destroy = _destroy; | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int | ||
96 | observer_set_flags (observer_t observer, int flags) | ||
97 | { | ||
98 | if (observer == NULL) | ||
99 | return EINVAL; | ||
100 | observer->flags |= flags; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | int | ||
105 | observable_create (observable_t *pobservable, void *owner) | ||
106 | { | ||
107 | observable_t observable; | ||
108 | int status; | ||
109 | if (pobservable == NULL) | ||
110 | return EINVAL; | ||
111 | observable = calloc (sizeof (*observable), 1); | ||
112 | if (observable == NULL) | ||
113 | return ENOMEM; | ||
114 | status = list_create (&(observable->list)); | ||
115 | if (status != 0 ) | ||
116 | { | ||
117 | free (observable); | ||
118 | return status; | ||
119 | } | ||
120 | observable->owner = owner; | ||
121 | *pobservable = observable; | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | void | ||
126 | observable_destroy (observable_t *pobservable, void *owner) | ||
127 | { | ||
128 | iterator_t iterator; | ||
129 | if (pobservable && *pobservable) | ||
130 | { | ||
131 | observable_t observable = *pobservable; | ||
132 | if (observable->owner == owner) | ||
133 | { | ||
134 | int status = iterator_create (&iterator, observable->list); | ||
135 | if (status == 0) | ||
136 | { | ||
137 | observer_t observer = NULL; | ||
138 | for (iterator_first (iterator); !iterator_is_done (iterator); | ||
139 | iterator_next (iterator)) | ||
140 | { | ||
141 | iterator_current (iterator, (void **)&observer); | ||
142 | if (observer != NULL) | ||
143 | observer_destroy (&observer, NULL); | ||
144 | } | ||
145 | } | ||
146 | list_destroy (&((*pobservable)->list)); | ||
147 | free (*pobservable); | ||
148 | } | ||
149 | *pobservable = NULL; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | void * | ||
154 | observable_get_owner (observable_t observable) | ||
155 | { | ||
156 | return (observable) ? observable->owner : NULL; | ||
157 | } | ||
158 | |||
159 | int | ||
160 | observable_attach (observable_t observable, observer_t observer) | ||
161 | { | ||
162 | if (observable == NULL || observer == NULL) | ||
163 | return EINVAL; | ||
164 | return list_append (observable->list, observer); | ||
165 | } | ||
166 | |||
167 | int | ||
168 | observable_detach (observable_t observable, observer_t observer) | ||
169 | { | ||
170 | iterator_t iterator; | ||
171 | int status; | ||
172 | int found = 0; | ||
173 | observer_t current; | ||
174 | if (observable == NULL ||observer == NULL) | ||
175 | return EINVAL; | ||
176 | status = iterator_create (&iterator, observable->list); | ||
177 | if (status != 0) | ||
178 | return status; | ||
179 | for (iterator_first (iterator); !iterator_is_done (iterator); | ||
180 | iterator_next (iterator)) | ||
181 | { | ||
182 | iterator_current (iterator, (void **)¤t); | ||
183 | if ((int)(current) == (int)observer) | ||
184 | { | ||
185 | found = 1; | ||
186 | break; | ||
187 | } | ||
188 | } | ||
189 | iterator_destroy (&iterator); | ||
190 | return (found) ? list_remove (observable->list, observer) : ENOENT; | ||
191 | } | ||
192 | |||
193 | int | ||
194 | observable_notify (observable_t observable, int type) | ||
195 | { | ||
196 | iterator_t iterator; | ||
197 | observer_t observer = NULL; | ||
198 | int status = 0; | ||
199 | if (observable == NULL) | ||
200 | return EINVAL; | ||
201 | status = iterator_create (&iterator, observable->list); | ||
202 | if (status != 0) | ||
203 | return status; | ||
204 | for (iterator_first (iterator); !iterator_is_done (iterator); | ||
205 | iterator_next (iterator)) | ||
206 | { | ||
207 | iterator_current (iterator, (void **)&observer); | ||
208 | if (observer) | ||
209 | { | ||
210 | status |= observer_action (observer, type); | ||
211 | observer = NULL; | ||
212 | } | ||
213 | } | ||
214 | iterator_destroy (&iterator); | ||
215 | return status; | ||
216 | } |
... | @@ -19,225 +19,73 @@ | ... | @@ -19,225 +19,73 @@ |
19 | #include <config.h> | 19 | #include <config.h> |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <registrar0.h> | ||
23 | |||
24 | #include <stdlib.h> | 22 | #include <stdlib.h> |
25 | #include <string.h> | 23 | #include <string.h> |
26 | #include <errno.h> | 24 | #include <errno.h> |
27 | 25 | ||
28 | /* Builtin mailbox types. A circular list is use for the builtin. | 26 | #include <mailutils/iterator.h> |
29 | Proper locking is not done when accessing the list. | 27 | #include <registrar0.h> |
30 | FIXME: not thread-safe. */ | ||
31 | 28 | ||
32 | static struct _registrar registrar [] = | 29 | static list_t reg_list; |
33 | { | ||
34 | { NULL, NULL, 0, ®istrar[1] }, /* sentinel, head list */ | ||
35 | { &_url_file_registrar, &_mailbox_mbox_registrar, 0, ®istrar[2] }, | ||
36 | { &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, ®istrar[3] }, | ||
37 | { &_url_unix_registrar, &_mailbox_unix_registrar, 0, ®istrar[4] }, | ||
38 | { &_url_maildir_registrar, &_mailbox_maildir_registrar, 0, ®istrar[5] }, | ||
39 | { &_url_mmdf_registrar, &_mailbox_mmdf_registrar, 0, ®istrar[6] }, | ||
40 | { &_url_pop_registrar, &_mailbox_pop_registrar, 0, ®istrar[7] }, | ||
41 | { &_url_imap_registrar, &_mailbox_imap_registrar, 0, ®istrar[0] }, | ||
42 | }; | ||
43 | |||
44 | static void | ||
45 | free_ureg (struct url_registrar *ureg) | ||
46 | { | ||
47 | if (ureg) | ||
48 | { | ||
49 | free ((char *)ureg->scheme); | ||
50 | free (ureg); | ||
51 | } | ||
52 | } | ||
53 | 30 | ||
54 | static void | 31 | int |
55 | free_mreg (struct mailbox_registrar *mreg) | 32 | registrar_get_list (list_t *plist) |
56 | { | 33 | { |
57 | if (mreg) | 34 | if (plist == NULL) |
35 | return EINVAL; | ||
36 | if (reg_list == NULL) | ||
58 | { | 37 | { |
59 | free ((char *)mreg->name); | 38 | int status = list_create (®_list); |
60 | free (mreg); | 39 | if (status != 0) |
40 | return status; | ||
61 | } | 41 | } |
42 | *plist = reg_list; | ||
43 | return 0; | ||
62 | } | 44 | } |
63 | 45 | ||
64 | int | 46 | int |
65 | registrar_add (struct url_registrar *new_ureg, | 47 | record_is_scheme (record_t record, const char *scheme) |
66 | struct mailbox_registrar *new_mreg, int *id) | ||
67 | { | 48 | { |
68 | struct _registrar *entry; | 49 | if (record == NULL) |
69 | struct url_registrar *ureg = NULL; | 50 | return 0; |
70 | struct mailbox_registrar *mreg; | ||
71 | 51 | ||
72 | /* Must registrar a mailbox */ | 52 | /* Overload. */ |
73 | if (new_mreg == NULL) | 53 | if (record->_is_scheme) |
74 | return EINVAL; | 54 | return record->_is_scheme (record, scheme); |
75 | |||
76 | /* Mailbox */ | ||
77 | mreg = calloc (1, sizeof (*mreg)); | ||
78 | if (mreg == NULL) | ||
79 | return ENOMEM; | ||
80 | 55 | ||
81 | if (new_mreg->name) | 56 | if (record->scheme && strncasecmp (record->scheme, scheme, |
82 | { | 57 | strlen (record->scheme)) == 0) |
83 | mreg->name = strdup (new_mreg->name); | 58 | return 1; |
84 | if (mreg->name == NULL) | ||
85 | { | ||
86 | free (mreg); | ||
87 | return ENOMEM; | ||
88 | } | ||
89 | } | ||
90 | mreg->_create = new_mreg->_create; | ||
91 | mreg->_destroy = new_mreg->_destroy; | ||
92 | 59 | ||
93 | /* URL */ | ||
94 | if (new_ureg) | ||
95 | { | ||
96 | ureg = calloc (1, sizeof (*ureg)); | ||
97 | if (ureg == NULL) | ||
98 | { | ||
99 | free_mreg (mreg); | ||
100 | return ENOMEM; | ||
101 | } | ||
102 | if (new_ureg->scheme) | ||
103 | { | ||
104 | ureg->scheme = strdup (new_ureg->scheme); | ||
105 | if (ureg->scheme == NULL) | ||
106 | { | ||
107 | free_mreg (mreg); | ||
108 | free_ureg (ureg); | ||
109 | return ENOMEM; | ||
110 | } | ||
111 | } | ||
112 | ureg->_create = new_ureg->_create; | ||
113 | ureg->_destroy = new_ureg->_destroy; | ||
114 | } | ||
115 | |||
116 | /* Register them to the list */ | ||
117 | entry = calloc (1, sizeof (*entry)); | ||
118 | if (entry == NULL) | ||
119 | { | ||
120 | free_mreg (mreg); | ||
121 | free_ureg (ureg); | ||
122 | return ENOMEM; | ||
123 | } | ||
124 | entry->ureg = ureg; | ||
125 | entry->mreg = mreg; | ||
126 | entry->is_allocated = 1; | ||
127 | entry->next = registrar->next; | ||
128 | registrar->next = entry; | ||
129 | if (id) | ||
130 | *id = (int)entry; | ||
131 | return 0; | 60 | return 0; |
132 | } | 61 | } |
133 | 62 | ||
134 | int | 63 | int |
135 | registrar_remove (int id) | 64 | record_get_mailbox (record_t record, mailbox_entry_t *pmbox) |
136 | { | 65 | { |
137 | struct _registrar *current, *previous; | 66 | if (record == NULL) |
138 | for (previous = registrar, current = registrar->next; | 67 | return EINVAL; |
139 | current != registrar; | ||
140 | previous = current, current = current->next) | ||
141 | { | ||
142 | if ((int)current == id) | ||
143 | { | ||
144 | previous->next = current->next; | ||
145 | if (current->is_allocated) | ||
146 | { | ||
147 | free_ureg (current->ureg); | ||
148 | free_mreg (current->mreg); | ||
149 | } | ||
150 | free (current); | ||
151 | return 0;; | ||
152 | } | ||
153 | } | ||
154 | return EINVAL; | ||
155 | } | ||
156 | 68 | ||
157 | int | 69 | /* Overload. */ |
158 | registrar_get (int id, | 70 | if (record->_get_mailbox) |
159 | struct url_registrar **ureg, struct mailbox_registrar **mreg) | 71 | return record->_get_mailbox (record, pmbox); |
160 | { | ||
161 | struct _registrar *current; | ||
162 | for (current = registrar->next; current != registrar; | ||
163 | current = current->next) | ||
164 | { | ||
165 | if ((int)current == id) | ||
166 | { | ||
167 | if (mreg) | ||
168 | *mreg = current->mreg; | ||
169 | if (ureg) | ||
170 | *ureg = current->ureg; | ||
171 | return 0; | ||
172 | } | ||
173 | } | ||
174 | return EINVAL; | ||
175 | } | ||
176 | 72 | ||
177 | int | 73 | if (pmbox) |
178 | registrar_entry_count (size_t *num) | 74 | *pmbox = record->mailbox; |
179 | { | ||
180 | struct _registrar *current; | ||
181 | size_t count; | ||
182 | for (count = 0, current = registrar->next; current != registrar; | ||
183 | current = current->next, count++) | ||
184 | ; | ||
185 | if (num) | ||
186 | *num = count; | ||
187 | return 0; | 75 | return 0; |
188 | } | 76 | } |
189 | 77 | ||
190 | int | 78 | int |
191 | registrar_entry (size_t num, struct url_registrar **ureg, | 79 | record_get_mailer (record_t record, mailer_entry_t *pml) |
192 | struct mailbox_registrar **mreg, int *id) | ||
193 | { | ||
194 | struct _registrar *current; | ||
195 | size_t count, status; | ||
196 | for (status = ENOENT, count = 0, current = registrar->next; | ||
197 | current != registrar; current = current->next, count++) | ||
198 | { | ||
199 | if (num == count) | ||
200 | { | ||
201 | if (ureg) | ||
202 | *ureg = current->ureg; | ||
203 | if (mreg) | ||
204 | *mreg = current->mreg; | ||
205 | if (id) | ||
206 | *id = (int)current; | ||
207 | status = 0; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | return status; | ||
212 | } | ||
213 | |||
214 | int | ||
215 | registrar_list (struct url_registrar **ureg, struct mailbox_registrar **mreg, | ||
216 | int *id, registrar_t *reg) | ||
217 | { | 80 | { |
218 | struct _registrar *current; | 81 | if (record == NULL) |
219 | |||
220 | if (reg == NULL) | ||
221 | return EINVAL; | 82 | return EINVAL; |
222 | 83 | ||
223 | current = *reg; | 84 | /* Overload. */ |
224 | 85 | if (record->_get_mailer) | |
225 | if (current == NULL) | 86 | return record->_get_mailer (record, pml); |
226 | current = registrar; | ||
227 | |||
228 | if (current->next == registrar) | ||
229 | return -1; | ||
230 | |||
231 | if (ureg) | ||
232 | *ureg = current->ureg; | ||
233 | |||
234 | if (mreg) | ||
235 | *mreg = current->mreg; | ||
236 | |||
237 | if (id) | ||
238 | *id = (int)current; | ||
239 | |||
240 | *reg = current->next; | ||
241 | 87 | ||
88 | if (pml) | ||
89 | *pml = record->mailer; | ||
242 | return 0; | 90 | return 0; |
243 | } | 91 | } | ... | ... |
mailbox/sendmail.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <stdio.h> | ||
24 | #include <unistd.h> | ||
25 | #include <sys/wait.h> | ||
26 | #include <errno.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | |||
30 | #include <mailutils/stream.h> | ||
31 | #include <mailer0.h> | ||
32 | #include <registrar0.h> | ||
33 | #include <misc.h> | ||
34 | |||
35 | static int sendmail_init (mailer_t); | ||
36 | |||
37 | static struct mailer_entry _sendmail_entry = | ||
38 | { | ||
39 | url_sendmail_init, sendmail_init | ||
40 | }; | ||
41 | static struct _record _sendmail_record = | ||
42 | { | ||
43 | MU_SENDMAIL_SCHEME, | ||
44 | NULL, /* Mailbox entry. */ | ||
45 | &_sendmail_entry, /* Mailer entry. */ | ||
46 | 0, /* Not malloc()ed. */ | ||
47 | NULL, /* No need for an owner. */ | ||
48 | NULL, /* is_scheme method. */ | ||
49 | NULL, /* get_mailbox method. */ | ||
50 | NULL /* get_mailer method. */ | ||
51 | }; | ||
52 | |||
53 | /* We export two functions: url parsing and the initialisation of | ||
54 | the mailbox, via the register entry/record. */ | ||
55 | record_t sendmail_record = &_sendmail_record; | ||
56 | mailer_entry_t sendmail_entry = &_sendmail_entry; | ||
57 | |||
58 | struct _sendmail | ||
59 | { | ||
60 | int dsn; | ||
61 | char *path; | ||
62 | pid_t pid; | ||
63 | off_t offset; | ||
64 | int fd; | ||
65 | enum sendmail_state { SENDMAIL_NO_STATE, SENDMAIL_SEND } state; | ||
66 | }; | ||
67 | |||
68 | typedef struct _sendmail * sendmail_t; | ||
69 | |||
70 | static void sendmail_destroy (mailer_t); | ||
71 | static int sendmail_open (mailer_t, int); | ||
72 | static int sendmail_close (mailer_t); | ||
73 | static int sendmail_send_message (mailer_t, const char *from, const char *rcpt, | ||
74 | int dsn, message_t); | ||
75 | |||
76 | int | ||
77 | sendmail_init (mailer_t mailer) | ||
78 | { | ||
79 | sendmail_t sendmail; | ||
80 | |||
81 | /* Allocate memory specific to sendmail mailer. */ | ||
82 | sendmail = mailer->data = calloc (1, sizeof (*sendmail)); | ||
83 | if (mailer->data == NULL) | ||
84 | return ENOMEM; | ||
85 | sendmail->state = SENDMAIL_NO_STATE; | ||
86 | mailer->_init = sendmail_init; | ||
87 | mailer->_destroy = sendmail_destroy; | ||
88 | |||
89 | mailer->_open = sendmail_open; | ||
90 | mailer->_close = sendmail_close; | ||
91 | mailer->_send_message = sendmail_send_message; | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void | ||
97 | sendmail_destroy(mailer_t mailer) | ||
98 | { | ||
99 | sendmail_t sendmail = mailer->data; | ||
100 | if (sendmail) | ||
101 | { | ||
102 | if (sendmail->path) | ||
103 | free (sendmail->path); | ||
104 | free (sendmail); | ||
105 | mailer->data = NULL; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static int | ||
110 | sendmail_open (mailer_t mailer, int flags) | ||
111 | { | ||
112 | sendmail_t sendmail = mailer->data; | ||
113 | int status; | ||
114 | size_t pathlen = 0; | ||
115 | char *path; | ||
116 | |||
117 | /* Sanity checks. */ | ||
118 | if (sendmail == NULL) | ||
119 | return EINVAL; | ||
120 | |||
121 | mailer->flags = flags | MU_STREAM_SENDMAIL; | ||
122 | |||
123 | /* Fetch the mailer server name and the port in the url_t. */ | ||
124 | if ((status = url_get_path (mailer->url, NULL, 0, &pathlen)) != 0 | ||
125 | || pathlen == 0) | ||
126 | return status; | ||
127 | |||
128 | path = calloc (pathlen + 1, sizeof (char)); | ||
129 | url_get_path (mailer->url, path, pathlen + 1, NULL); | ||
130 | |||
131 | if (access (path, X_OK) == -1) | ||
132 | { | ||
133 | free (path); | ||
134 | return errno; | ||
135 | } | ||
136 | sendmail->path = path; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int | ||
141 | sendmail_close (mailer_t mailer) | ||
142 | { | ||
143 | (void)mailer; | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int | ||
148 | sendmail_send_message (mailer_t mailer, const char *from, const char *rcpt, | ||
149 | int dsn, message_t msg) | ||
150 | { | ||
151 | sendmail_t sendmail = mailer->data; | ||
152 | int status = 0; | ||
153 | |||
154 | if (sendmail == NULL || msg == NULL) | ||
155 | return EINVAL; | ||
156 | |||
157 | sendmail->dsn = dsn; | ||
158 | |||
159 | switch (sendmail->state) | ||
160 | { | ||
161 | case SENDMAIL_NO_STATE: | ||
162 | { | ||
163 | int tunnel[2]; | ||
164 | int argc = 3; | ||
165 | char **argvec = NULL; | ||
166 | |||
167 | argvec = realloc (argvec, argc * (sizeof (*argvec))); | ||
168 | argvec[0] = sendmail->path; | ||
169 | /* do not treat '.' as message terminator*/ | ||
170 | argvec[1] = strdup ("-oi"); | ||
171 | argvec[2] = strdup ("-t"); | ||
172 | |||
173 | if (from) | ||
174 | { | ||
175 | size_t len = strlen (from) + 1; | ||
176 | char *addr = calloc (len, sizeof (char)); | ||
177 | if (parseaddr (from, addr, len) == 0) | ||
178 | { | ||
179 | argc++; | ||
180 | argvec = realloc (argvec, argc * (sizeof (*argvec))); | ||
181 | argvec[argc - 1] = strdup ("-f"); | ||
182 | argc++; | ||
183 | argvec = realloc (argvec, argc * (sizeof (*argvec))); | ||
184 | argvec[argc - 1] = addr; | ||
185 | } | ||
186 | else | ||
187 | free (addr); | ||
188 | } | ||
189 | |||
190 | if (rcpt) | ||
191 | { | ||
192 | const char *p = rcpt; | ||
193 | do | ||
194 | { | ||
195 | size_t len = strlen (p) + 1; | ||
196 | char *addr = calloc (len, sizeof (char)); | ||
197 | if (parseaddr (rcpt, addr, len) == 0) | ||
198 | { | ||
199 | argc++; | ||
200 | argvec = realloc (argvec, argc * (sizeof (*argvec))); | ||
201 | argvec[argc - 1] = addr; | ||
202 | } | ||
203 | else | ||
204 | free (addr); | ||
205 | p = strchr (p, ','); | ||
206 | if (p != NULL) | ||
207 | p++; | ||
208 | } | ||
209 | while (p != NULL && *p != '\0'); | ||
210 | } | ||
211 | |||
212 | argc++; | ||
213 | argvec = realloc (argvec, argc * (sizeof (*argvec))); | ||
214 | argvec[argc - 1] = NULL; | ||
215 | |||
216 | if (pipe (tunnel) == 0) | ||
217 | { | ||
218 | sendmail->fd = tunnel [1]; | ||
219 | sendmail->pid = fork (); | ||
220 | if (sendmail->pid == 0) /* Child. */ | ||
221 | { | ||
222 | close (STDIN_FILENO); | ||
223 | close (STDOUT_FILENO); | ||
224 | close (STDERR_FILENO); | ||
225 | close (tunnel[1]); | ||
226 | dup2 (tunnel[0], STDIN_FILENO); | ||
227 | execv (sendmail->path, argvec); | ||
228 | exit (1); | ||
229 | } | ||
230 | else if (sendmail->pid == -1) | ||
231 | status = errno; | ||
232 | } | ||
233 | else | ||
234 | status = errno; | ||
235 | for (argc = 0; argvec[argc]; argc++) | ||
236 | free (argvec[argc]); | ||
237 | free (argvec); | ||
238 | close (tunnel[0]); | ||
239 | if (status != 0) | ||
240 | { | ||
241 | close (sendmail->fd); | ||
242 | break; | ||
243 | } | ||
244 | sendmail->state = SENDMAIL_SEND; | ||
245 | } | ||
246 | |||
247 | case SENDMAIL_SEND: /* Parent. */ | ||
248 | { | ||
249 | stream_t stream = NULL; | ||
250 | char buffer[512]; | ||
251 | size_t len = 0; | ||
252 | int rc; | ||
253 | |||
254 | message_get_stream (msg, &stream); | ||
255 | while ((status = stream_read (stream, buffer, sizeof (buffer), | ||
256 | sendmail->offset, &len)) == 0 | ||
257 | && len != 0) | ||
258 | { | ||
259 | if (write (sendmail->fd, buffer, len) == -1) | ||
260 | { | ||
261 | status = errno; | ||
262 | break; | ||
263 | } | ||
264 | sendmail->offset += len; | ||
265 | } | ||
266 | if (status == EAGAIN) | ||
267 | return status; | ||
268 | close (sendmail->fd); | ||
269 | rc = waitpid(sendmail->pid, &status, 0); | ||
270 | if (rc < 0) | ||
271 | status = errno; | ||
272 | else if (WIFEXITED(status)) | ||
273 | status = WEXITSTATUS(status); | ||
274 | } | ||
275 | default: | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | sendmail->state = SENDMAIL_NO_STATE; | ||
280 | return status; | ||
281 | } |
mailbox/smtp.c
0 → 100644
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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <stdio.h> | ||
24 | #include <pwd.h> | ||
25 | #include <unistd.h> | ||
26 | #include <errno.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include <netdb.h> | ||
30 | |||
31 | #include <mailutils/stream.h> | ||
32 | #include <mailer0.h> | ||
33 | #include <registrar0.h> | ||
34 | #include <bio.h> | ||
35 | #include <misc.h> | ||
36 | |||
37 | static int smtp_init (mailer_t); | ||
38 | |||
39 | static struct mailer_entry _smtp_entry = | ||
40 | { | ||
41 | url_smtp_init, smtp_init | ||
42 | }; | ||
43 | static struct _record _smtp_record = | ||
44 | { | ||
45 | MU_SMTP_SCHEME, | ||
46 | NULL, /* Mailbox entry. */ | ||
47 | &_smtp_entry, /* Mailer entry. */ | ||
48 | 0, /* Not malloc()ed. */ | ||
49 | NULL, /* No need for an owner. */ | ||
50 | NULL, /* is_scheme method. */ | ||
51 | NULL, /* get_mailbox method. */ | ||
52 | NULL /* get_mailer method. */ | ||
53 | }; | ||
54 | |||
55 | /* We export two functions: url parsing and the initialisation of | ||
56 | the mailbox, via the register entry/record. */ | ||
57 | record_t smtp_record = &_smtp_record; | ||
58 | mailer_entry_t smtp_entry = &_smtp_entry; | ||
59 | |||
60 | struct _smtp | ||
61 | { | ||
62 | char *mailhost; | ||
63 | char *localhost; | ||
64 | bio_t bio; | ||
65 | char *ptr; | ||
66 | char *nl; | ||
67 | char *buffer; | ||
68 | size_t buflen; | ||
69 | enum smtp_state | ||
70 | { | ||
71 | SMTP_NO_STATE, SMTP_OPEN, SMTP_GREETINGS, SMTP_EHLO, SMTP_EHLO_ACK, | ||
72 | SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM, | ||
73 | SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO, | ||
74 | SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK, | ||
75 | SMTP_SEND_DOT | ||
76 | } state; | ||
77 | int extended; | ||
78 | char *from; | ||
79 | char *to; | ||
80 | off_t offset; | ||
81 | int dsn; | ||
82 | message_t message; | ||
83 | }; | ||
84 | |||
85 | typedef struct _smtp * smtp_t; | ||
86 | |||
87 | /* Usefull little Macros, since these are very repetitive. */ | ||
88 | #define CLEAR_STATE(smtp) \ | ||
89 | smtp->state = SMTP_NO_STATE | ||
90 | |||
91 | /* Clear the state and close the stream. */ | ||
92 | #define CHECK_ERROR_CLOSE(mailer, smtp, status) \ | ||
93 | do \ | ||
94 | { \ | ||
95 | if (status != 0) \ | ||
96 | { \ | ||
97 | stream_close (mailer->stream); \ | ||
98 | CLEAR_STATE (smtp); \ | ||
99 | return status; \ | ||
100 | } \ | ||
101 | } \ | ||
102 | while (0) | ||
103 | |||
104 | /* Clear the state. */ | ||
105 | #define CHECK_ERROR(smtp, status) \ | ||
106 | do \ | ||
107 | { \ | ||
108 | if (status != 0) \ | ||
109 | { \ | ||
110 | CLEAR_STATE (smtp); \ | ||
111 | return status; \ | ||
112 | } \ | ||
113 | } \ | ||
114 | while (0) | ||
115 | |||
116 | /* Clear the state for non recoverable error. */ | ||
117 | #define CHECK_EAGAIN(smtp, status) \ | ||
118 | do \ | ||
119 | { \ | ||
120 | if (status != 0) \ | ||
121 | { \ | ||
122 | if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \ | ||
123 | { \ | ||
124 | CLEAR_STATE (smtp); \ | ||
125 | } \ | ||
126 | return status; \ | ||
127 | } \ | ||
128 | } \ | ||
129 | while (0) | ||
130 | |||
131 | static void smtp_destroy (mailer_t); | ||
132 | static int smtp_open (mailer_t, int); | ||
133 | static int smtp_close (mailer_t); | ||
134 | static int smtp_send_message (mailer_t, const char *from, const char *rcpt, | ||
135 | int dsn, message_t); | ||
136 | static int smtp_writeline (smtp_t smtp, const char *format, ...); | ||
137 | static int smtp_readline (smtp_t); | ||
138 | static int smtp_read_ack (smtp_t); | ||
139 | static int smtp_write (smtp_t); | ||
140 | |||
141 | int | ||
142 | smtp_init (mailer_t mailer) | ||
143 | { | ||
144 | smtp_t smtp; | ||
145 | |||
146 | /* Allocate memory specific to smtp mailer. */ | ||
147 | smtp = mailer->data = calloc (1, sizeof (*smtp)); | ||
148 | if (mailer->data == NULL) | ||
149 | return ENOMEM; | ||
150 | |||
151 | mailer->_init = smtp_init; | ||
152 | mailer->_destroy = smtp_destroy; | ||
153 | |||
154 | mailer->_open = smtp_open; | ||
155 | mailer->_close = smtp_close; | ||
156 | mailer->_send_message = smtp_send_message; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | smtp_destroy(mailer_t mailer) | ||
163 | { | ||
164 | smtp_t smtp = mailer->data; | ||
165 | smtp_close (mailer); | ||
166 | if (smtp->mailhost) | ||
167 | free (smtp->mailhost); | ||
168 | if (smtp->localhost) | ||
169 | free (smtp->localhost); | ||
170 | if (smtp->bio) | ||
171 | bio_destroy (&(smtp->bio)); | ||
172 | if (smtp->buffer) | ||
173 | free (smtp->buffer); | ||
174 | if (smtp->from) | ||
175 | free (smtp->from); | ||
176 | if (smtp->to) | ||
177 | free (smtp->to); | ||
178 | free (smtp); | ||
179 | mailer->data = NULL; | ||
180 | } | ||
181 | |||
182 | static int | ||
183 | smtp_open (mailer_t mailer, int flags) | ||
184 | { | ||
185 | smtp_t smtp = mailer->data; | ||
186 | int status; | ||
187 | long port; | ||
188 | size_t buf_len = 0; | ||
189 | |||
190 | /* Sanity checks. */ | ||
191 | if (smtp == NULL) | ||
192 | return EINVAL; | ||
193 | |||
194 | mailer->flags = flags | MU_STREAM_SMTP; | ||
195 | |||
196 | /* Fetch the mailer server name and the port in the url_t. */ | ||
197 | if ((status = url_get_host (mailer->url, NULL, 0, &buf_len)) != 0 | ||
198 | || buf_len == 0 || (status = url_get_port (mailer->url, &port)) != 0) | ||
199 | return status; | ||
200 | |||
201 | switch (smtp->state) | ||
202 | { | ||
203 | case SMTP_NO_STATE: | ||
204 | /* Get the mailhost. */ | ||
205 | if (smtp->mailhost) | ||
206 | { | ||
207 | free (smtp->mailhost); | ||
208 | smtp->mailhost = NULL; | ||
209 | } | ||
210 | smtp->mailhost = calloc (buf_len + 1, sizeof (char)); | ||
211 | if (smtp->mailhost == NULL) | ||
212 | return ENOMEM; | ||
213 | url_get_host (mailer->url, smtp->mailhost, buf_len + 1, NULL); | ||
214 | |||
215 | if (smtp->localhost) | ||
216 | { | ||
217 | free (smtp->localhost); | ||
218 | smtp->localhost = NULL; | ||
219 | } | ||
220 | /* Fetch our localhost name. */ | ||
221 | buf_len = 64; | ||
222 | do | ||
223 | { | ||
224 | char *tmp; | ||
225 | errno = 0; | ||
226 | buf_len *= 2; /* Initial guess */ | ||
227 | tmp = realloc (smtp->localhost, buf_len); | ||
228 | if (tmp == NULL) | ||
229 | { | ||
230 | if (smtp->localhost) | ||
231 | free (smtp->localhost); | ||
232 | smtp->localhost = NULL; | ||
233 | free (smtp->mailhost); | ||
234 | smtp->mailhost = NULL; | ||
235 | return ENOMEM; | ||
236 | } | ||
237 | smtp->localhost = tmp; | ||
238 | } | ||
239 | while (((status = gethostname(smtp->localhost, buf_len)) == 0 | ||
240 | && !memchr (smtp->localhost, '\0', buf_len)) | ||
241 | #ifdef ENAMETOOLONG | ||
242 | || errno == ENAMETOOLONG | ||
243 | #endif | ||
244 | ); | ||
245 | if (status != 0 && errno != 0) | ||
246 | { | ||
247 | /* gethostname failed, abort. */ | ||
248 | free (smtp->localhost); | ||
249 | smtp->localhost = NULL; | ||
250 | free (smtp->mailhost); | ||
251 | smtp->mailhost = NULL; | ||
252 | return EINVAL; | ||
253 | } | ||
254 | |||
255 | /* Many SMTP servers prefer a FQDN. */ | ||
256 | if (strchr (smtp->localhost, '.') == NULL) | ||
257 | { | ||
258 | struct hostent *hp = gethostbyname (smtp->localhost); | ||
259 | if (hp == NULL) | ||
260 | { | ||
261 | /* Don't flag it as an error some SMTP servers can get the FQDN | ||
262 | by themselves even if the client is lying, probably | ||
263 | with getpeername(). */ | ||
264 | // return EINVAL; | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | free (smtp->localhost); | ||
269 | smtp->localhost = strdup (hp->h_name); | ||
270 | if (smtp->localhost == NULL) | ||
271 | { | ||
272 | free (smtp->mailhost); | ||
273 | smtp->mailhost = NULL; | ||
274 | return ENOMEM; | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | /* allocate a working io buffer. */ | ||
280 | if (smtp->buffer == NULL) | ||
281 | { | ||
282 | smtp->buflen = 255; /* Initial guess. */ | ||
283 | smtp->buffer = malloc (smtp->buflen + 1); | ||
284 | if (smtp->buffer == NULL) | ||
285 | { | ||
286 | CHECK_ERROR (smtp, ENOMEM); | ||
287 | } | ||
288 | smtp->ptr = smtp->buffer; | ||
289 | } | ||
290 | status = bio_create (&(smtp->bio), mailer->stream); | ||
291 | CHECK_ERROR (smtp, status); | ||
292 | |||
293 | /* Create a TCP stack if one is not given. */ | ||
294 | if (mailer->stream == NULL) | ||
295 | { | ||
296 | status = tcp_stream_create (&(mailer->stream)); | ||
297 | CHECK_ERROR (smtp, status); | ||
298 | } | ||
299 | smtp->state = SMTP_OPEN; | ||
300 | |||
301 | case SMTP_OPEN: | ||
302 | status = stream_open (mailer->stream, smtp->mailhost, port, | ||
303 | mailer->flags); | ||
304 | CHECK_EAGAIN (smtp, status); | ||
305 | smtp->state = SMTP_GREETINGS; | ||
306 | |||
307 | case SMTP_GREETINGS: | ||
308 | /* Swallow the greetings. */ | ||
309 | status = smtp_read_ack (smtp); | ||
310 | CHECK_EAGAIN (smtp, status); | ||
311 | if (smtp->buffer[0] != '2') | ||
312 | { | ||
313 | stream_close (mailer->stream); | ||
314 | return EACCES; | ||
315 | } | ||
316 | status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost); | ||
317 | CHECK_ERROR (smtp, status); | ||
318 | smtp->state = SMTP_EHLO; | ||
319 | |||
320 | case SMTP_EHLO: | ||
321 | /* We first try Extended SMTP. */ | ||
322 | status = smtp_write (smtp); | ||
323 | CHECK_EAGAIN (smtp, status); | ||
324 | smtp->state = SMTP_EHLO_ACK; | ||
325 | |||
326 | case SMTP_EHLO_ACK: | ||
327 | status = smtp_read_ack (smtp); | ||
328 | CHECK_EAGAIN (smtp, status); | ||
329 | if (smtp->buffer[0] != '2') | ||
330 | { | ||
331 | smtp->extended = 0; | ||
332 | status = smtp_writeline (smtp, "HELO %s\r\n", smtp->localhost); | ||
333 | CHECK_ERROR (smtp, status); | ||
334 | smtp->state = SMTP_HELO; | ||
335 | } | ||
336 | else | ||
337 | { | ||
338 | smtp->extended = 1; | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | case SMTP_HELO: | ||
343 | if (!smtp->extended) | ||
344 | { | ||
345 | status = smtp_write (smtp); | ||
346 | CHECK_EAGAIN (smtp, status); | ||
347 | } | ||
348 | smtp->state = SMTP_HELO_ACK; | ||
349 | |||
350 | case SMTP_HELO_ACK: | ||
351 | if (!smtp->extended) | ||
352 | { | ||
353 | status = smtp_read_ack (smtp); | ||
354 | CHECK_EAGAIN (smtp, status); | ||
355 | if (smtp->buffer[0] != '2') | ||
356 | { | ||
357 | stream_close (mailer->stream); | ||
358 | CLEAR_STATE (smtp); | ||
359 | return EACCES; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | default: | ||
364 | break; | ||
365 | } | ||
366 | smtp->state = SMTP_NO_STATE; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int | ||
371 | smtp_close (mailer_t mailer) | ||
372 | { | ||
373 | smtp_t smtp = mailer->data; | ||
374 | int status; | ||
375 | switch (smtp->state) | ||
376 | { | ||
377 | case SMTP_NO_STATE: | ||
378 | status = smtp_writeline (smtp, "Quit\r\n"); | ||
379 | CHECK_ERROR (smtp, status); | ||
380 | smtp->state = SMTP_QUIT; | ||
381 | |||
382 | case SMTP_QUIT: | ||
383 | status = smtp_write (smtp); | ||
384 | CHECK_EAGAIN (smtp, status); | ||
385 | smtp->state = SMTP_QUIT_ACK; | ||
386 | |||
387 | case SMTP_QUIT_ACK: | ||
388 | status = smtp_read_ack (smtp); | ||
389 | CHECK_EAGAIN (smtp, status); | ||
390 | |||
391 | default: | ||
392 | break; | ||
393 | } | ||
394 | return stream_close (mailer->stream); | ||
395 | } | ||
396 | |||
397 | static int | ||
398 | smtp_send_message(mailer_t mailer, const char *from, const char *rcpt, | ||
399 | int dsn, message_t msg) | ||
400 | { | ||
401 | smtp_t smtp = mailer->data; | ||
402 | int status; | ||
403 | |||
404 | if (smtp == NULL || msg == NULL) | ||
405 | return EINVAL; | ||
406 | |||
407 | switch (smtp->state) | ||
408 | { | ||
409 | case SMTP_NO_STATE: | ||
410 | smtp->dsn = dsn; | ||
411 | smtp->state = SMTP_ENV_FROM; | ||
412 | |||
413 | case SMTP_ENV_FROM: | ||
414 | if (smtp->from) | ||
415 | { | ||
416 | free (smtp->from); | ||
417 | smtp->from = NULL; | ||
418 | } | ||
419 | /* Try to fetch it from the header. */ | ||
420 | if (from == NULL) | ||
421 | { | ||
422 | header_t header; | ||
423 | size_t size; | ||
424 | message_get_header (msg, &header); | ||
425 | status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &size); | ||
426 | if (status == EAGAIN) | ||
427 | return status; | ||
428 | /* If it's not in the header create one form the passwd. */ | ||
429 | if (status != 0) | ||
430 | { | ||
431 | struct passwd *pwd = getpwuid (getuid ()); | ||
432 | /* Not in the passwd ???? We have a problem. */ | ||
433 | if (pwd == 0 || pwd->pw_name == NULL) | ||
434 | { | ||
435 | size_t len = 10 + strlen (smtp->localhost) + 1; | ||
436 | smtp->from = calloc (len, sizeof (char)); | ||
437 | if (smtp->from == NULL) | ||
438 | { | ||
439 | CHECK_ERROR (smtp, ENOMEM); | ||
440 | } | ||
441 | snprintf (smtp->from, len, "%d@%s", getuid(), | ||
442 | smtp->localhost); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | smtp->from = calloc (strlen (pwd->pw_name) + 1 | ||
447 | + strlen (smtp->localhost) + 1, | ||
448 | sizeof (char)); | ||
449 | if (smtp->from == NULL) | ||
450 | { | ||
451 | CHECK_ERROR (smtp, ENOMEM); | ||
452 | } | ||
453 | sprintf(smtp->from, "%s@%s", pwd->pw_name, smtp->localhost); | ||
454 | } | ||
455 | } | ||
456 | else | ||
457 | { | ||
458 | smtp->from = calloc (size + 1, sizeof (char)); | ||
459 | if (smtp->from == NULL) | ||
460 | { | ||
461 | CHECK_ERROR (smtp, ENOMEM); | ||
462 | } | ||
463 | status = header_get_value (header, MU_HEADER_FROM, smtp->from, | ||
464 | size + 1, NULL); | ||
465 | CHECK_EAGAIN (smtp, status); | ||
466 | } | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | smtp->from = strdup (from); | ||
471 | if (smtp->from == NULL) | ||
472 | { | ||
473 | CHECK_ERROR (smtp, ENOMEM); | ||
474 | } | ||
475 | } | ||
476 | /* Check if a Fully Qualified Name, some smtp servers | ||
477 | notably sendmail insists on it, for good reasons. */ | ||
478 | if (strchr (smtp->from, '@') == NULL) | ||
479 | { | ||
480 | char *tmp; | ||
481 | tmp = malloc (strlen (smtp->from) + 1 +strlen (smtp->localhost) + 1); | ||
482 | if (tmp == NULL) | ||
483 | { | ||
484 | free (smtp->from); | ||
485 | smtp->from = NULL; | ||
486 | CHECK_ERROR (smtp, ENOMEM); | ||
487 | } | ||
488 | sprintf (tmp, "%s@%s", smtp->from, smtp->localhost); | ||
489 | free (smtp->from); | ||
490 | smtp->from = tmp; | ||
491 | } | ||
492 | smtp->state = SMTP_ENV_RCPT; | ||
493 | |||
494 | case SMTP_ENV_RCPT: | ||
495 | if (smtp->to) | ||
496 | { | ||
497 | free (smtp->to); | ||
498 | smtp->to = NULL; | ||
499 | } | ||
500 | if (rcpt == NULL) | ||
501 | { | ||
502 | header_t header; | ||
503 | size_t size; | ||
504 | message_get_header (msg, &header); | ||
505 | status = header_get_value (header, MU_HEADER_TO, NULL, 0, &size); | ||
506 | CHECK_EAGAIN (smtp, status); | ||
507 | smtp->to = calloc (size + 1, sizeof (char)); | ||
508 | if (smtp->to == NULL) | ||
509 | { | ||
510 | CHECK_ERROR (smtp, ENOMEM); | ||
511 | } | ||
512 | status = header_get_value (header, MU_HEADER_TO, smtp->to, | ||
513 | size + 1, NULL); | ||
514 | CHECK_EAGAIN (smtp, status); | ||
515 | } | ||
516 | else | ||
517 | { | ||
518 | smtp->to = strdup (rcpt); | ||
519 | if (smtp->to == NULL) | ||
520 | { | ||
521 | CHECK_ERROR (smtp, ENOMEM); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", smtp->from); | ||
526 | free (smtp->from); | ||
527 | smtp->from = NULL; | ||
528 | CHECK_ERROR (smtp, status); | ||
529 | smtp->state = SMTP_MAIL_FROM; | ||
530 | |||
531 | case SMTP_MAIL_FROM: | ||
532 | status = smtp_write (smtp); | ||
533 | CHECK_EAGAIN (smtp, status); | ||
534 | smtp->state = SMTP_MAIL_FROM_ACK; | ||
535 | |||
536 | case SMTP_MAIL_FROM_ACK: | ||
537 | status = smtp_read_ack (smtp); | ||
538 | CHECK_EAGAIN (smtp, status); | ||
539 | if (smtp->buffer[0] != '2') | ||
540 | { | ||
541 | stream_close (mailer->stream); | ||
542 | CLEAR_STATE (smtp); | ||
543 | return EACCES; | ||
544 | } | ||
545 | /* We use a goto, since we may have multiple recipients, | ||
546 | we come back here and doit all over again ... Not pretty. */ | ||
547 | RCPT_TO: | ||
548 | { | ||
549 | char *buf; | ||
550 | size_t len = strlen (smtp->to) + 1; | ||
551 | buf = calloc (len, sizeof (char)); | ||
552 | if (buf == NULL) | ||
553 | { | ||
554 | CHECK_ERROR (smtp, ENOMEM); | ||
555 | } | ||
556 | if (parseaddr (smtp->to, buf, len) != 0) | ||
557 | { | ||
558 | free (buf); | ||
559 | CHECK_ERROR (smtp, EINVAL); | ||
560 | } | ||
561 | status = smtp_writeline (smtp, "RCPT TO: %s\r\n", buf); | ||
562 | free (buf); | ||
563 | CHECK_ERROR (smtp, status); | ||
564 | smtp->state = SMTP_RCPT_TO; | ||
565 | } | ||
566 | |||
567 | case SMTP_RCPT_TO: | ||
568 | status = smtp_write (smtp); | ||
569 | CHECK_EAGAIN (smtp, status); | ||
570 | smtp->state = SMTP_RCPT_TO_ACK; | ||
571 | |||
572 | case SMTP_RCPT_TO_ACK: | ||
573 | { | ||
574 | char *p; | ||
575 | status = smtp_read_ack (smtp); | ||
576 | CHECK_EAGAIN (smtp, status); | ||
577 | if (smtp->buffer[0] != '2') | ||
578 | { | ||
579 | stream_close (mailer->stream); | ||
580 | CLEAR_STATE (smtp); | ||
581 | return EACCES; | ||
582 | } | ||
583 | /* Do we have multiple recipients ? */ | ||
584 | p = strchr (smtp->to, ','); | ||
585 | if (p != NULL) | ||
586 | { | ||
587 | char *tmp = smtp->to; | ||
588 | smtp->to = strdup (p++); | ||
589 | if (smtp->to == NULL) | ||
590 | { | ||
591 | free (tmp); | ||
592 | CHECK_ERROR (smtp, ENOMEM); | ||
593 | } | ||
594 | free (tmp); | ||
595 | goto RCPT_TO; | ||
596 | } | ||
597 | /* We are done with the rcpt. */ | ||
598 | free (smtp->to); | ||
599 | smtp->to = NULL; | ||
600 | status = smtp_writeline (smtp, "DATA\r\n"); | ||
601 | CHECK_ERROR (smtp, status); | ||
602 | smtp->state = SMTP_DATA; | ||
603 | } | ||
604 | |||
605 | case SMTP_DATA: | ||
606 | status = smtp_write (smtp); | ||
607 | CHECK_EAGAIN (smtp, status); | ||
608 | smtp->state = SMTP_DATA_ACK; | ||
609 | |||
610 | case SMTP_DATA_ACK: | ||
611 | status = smtp_read_ack (smtp); | ||
612 | CHECK_EAGAIN (smtp, status); | ||
613 | if (smtp->buffer[0] != '3') | ||
614 | { | ||
615 | stream_close (mailer->stream); | ||
616 | CLEAR_STATE (smtp); | ||
617 | return EACCES; | ||
618 | } | ||
619 | smtp->offset = 0; | ||
620 | smtp->state = SMTP_SEND; | ||
621 | |||
622 | case SMTP_SEND: | ||
623 | { | ||
624 | stream_t stream; | ||
625 | size_t n = 0; | ||
626 | char data[256] = ""; | ||
627 | /* We may be here after an EAGAIN so check if we have something | ||
628 | in the buffer and flush it. */ | ||
629 | status = smtp_write (smtp); | ||
630 | CHECK_EAGAIN (smtp, status); | ||
631 | message_get_stream (msg, &stream); | ||
632 | while ((status = stream_readline (stream, data, sizeof (data) - 1, | ||
633 | smtp->offset, &n)) == 0 && n > 0) | ||
634 | { | ||
635 | if (data [n - 1] == '\n') | ||
636 | data [n -1] = '\0'; | ||
637 | if (data[0] == '.') | ||
638 | { | ||
639 | status = smtp_writeline (smtp, ".%s\r\n", data); | ||
640 | CHECK_ERROR (smtp, status); | ||
641 | } | ||
642 | else | ||
643 | { | ||
644 | status = smtp_writeline (smtp, "%s\r\n", data); | ||
645 | CHECK_ERROR (smtp, status); | ||
646 | } | ||
647 | smtp->offset += n; | ||
648 | status = smtp_write (smtp); | ||
649 | CHECK_EAGAIN (smtp, status); | ||
650 | } | ||
651 | smtp->offset = 0; | ||
652 | status = smtp_writeline (smtp, ".\r\n"); | ||
653 | CHECK_ERROR (smtp, status); | ||
654 | smtp->state = SMTP_SEND_DOT; | ||
655 | } | ||
656 | |||
657 | case SMTP_SEND_DOT: | ||
658 | status = smtp_write (smtp); | ||
659 | CHECK_EAGAIN (smtp, status); | ||
660 | smtp->state = SMTP_SEND_ACK; | ||
661 | |||
662 | case SMTP_SEND_ACK: | ||
663 | status = smtp_read_ack (smtp); | ||
664 | CHECK_EAGAIN (smtp, status); | ||
665 | if (smtp->buffer[0] != '2') | ||
666 | { | ||
667 | stream_close (mailer->stream); | ||
668 | CLEAR_STATE (smtp); | ||
669 | return EACCES; | ||
670 | } | ||
671 | |||
672 | default: | ||
673 | break; | ||
674 | } | ||
675 | CLEAR_STATE (smtp); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int | ||
680 | smtp_writeline (smtp_t smtp, const char *format, ...) | ||
681 | { | ||
682 | int len; | ||
683 | va_list ap; | ||
684 | |||
685 | va_start(ap, format); | ||
686 | do | ||
687 | { | ||
688 | len = vsnprintf (smtp->buffer, smtp->buflen - 1, format, ap); | ||
689 | if (len >= (int)smtp->buflen) | ||
690 | { | ||
691 | smtp->buflen *= 2; | ||
692 | smtp->buffer = realloc (smtp->buffer, smtp->buflen); | ||
693 | if (smtp->buffer == NULL) | ||
694 | return ENOMEM; | ||
695 | } | ||
696 | } | ||
697 | while (len > (int)smtp->buflen); | ||
698 | va_end(ap); | ||
699 | smtp->ptr = smtp->buffer + len; | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static int | ||
704 | smtp_write (smtp_t smtp) | ||
705 | { | ||
706 | int status = 0; | ||
707 | size_t len; | ||
708 | if (smtp->ptr > smtp->buffer) | ||
709 | { | ||
710 | len = smtp->ptr - smtp->buffer; | ||
711 | status = bio_write (smtp->bio, smtp->buffer, len, &len); | ||
712 | if (status == 0) | ||
713 | { | ||
714 | memmove (smtp->buffer, smtp->buffer + len, len); | ||
715 | smtp->ptr -= len; | ||
716 | } | ||
717 | } | ||
718 | else | ||
719 | { | ||
720 | smtp->ptr = smtp->buffer; | ||
721 | len = 0; | ||
722 | } | ||
723 | return status; | ||
724 | } | ||
725 | |||
726 | static int | ||
727 | smtp_read_ack (smtp_t smtp) | ||
728 | { | ||
729 | int status; | ||
730 | int multi; | ||
731 | |||
732 | do | ||
733 | { | ||
734 | multi = 0; | ||
735 | status = smtp_readline (smtp); | ||
736 | if ((smtp->ptr - smtp->buffer) > 4 | ||
737 | && smtp->buffer[3] == '-') | ||
738 | multi = 1; | ||
739 | if (status == 0) | ||
740 | smtp->ptr = smtp->buffer; | ||
741 | } | ||
742 | while (multi && status == 0); | ||
743 | |||
744 | if (status == 0) | ||
745 | smtp->ptr = smtp->buffer; | ||
746 | return status; | ||
747 | } | ||
748 | |||
749 | /* Read a complete line form the pop server. Transform CRLF to LF, | ||
750 | put a null in the buffer when done. */ | ||
751 | static int | ||
752 | smtp_readline (smtp_t smtp) | ||
753 | { | ||
754 | size_t n = 0; | ||
755 | size_t total = smtp->ptr - smtp->buffer; | ||
756 | int status; | ||
757 | |||
758 | /* Must get a full line before bailing out. */ | ||
759 | do | ||
760 | { | ||
761 | status = bio_readline (smtp->bio, smtp->buffer + total, | ||
762 | smtp->buflen - total, &n); | ||
763 | if (status != 0) | ||
764 | return status; | ||
765 | |||
766 | total += n; | ||
767 | smtp->nl = memchr (smtp->buffer, '\n', total); | ||
768 | if (smtp->nl == NULL) /* Do we have a full line. */ | ||
769 | { | ||
770 | /* Allocate a bigger buffer ? */ | ||
771 | if (total >= smtp->buflen -1) | ||
772 | { | ||
773 | smtp->buflen *= 2; | ||
774 | smtp->buffer = realloc (smtp->buffer, smtp->buflen + 1); | ||
775 | if (smtp->buffer == NULL) | ||
776 | return ENOMEM; | ||
777 | } | ||
778 | } | ||
779 | smtp->ptr = smtp->buffer + total; | ||
780 | } | ||
781 | while (smtp->nl == NULL); | ||
782 | |||
783 | /* \r\n --> \n\0 */ | ||
784 | if (smtp->nl > smtp->buffer) | ||
785 | { | ||
786 | *(smtp->nl - 1) = '\n'; | ||
787 | *(smtp->nl) = '\0'; | ||
788 | smtp->ptr = smtp->nl; | ||
789 | } | ||
790 | return 0; | ||
791 | } |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
18 | #include <errno.h> | 22 | #include <errno.h> |
19 | #include <stdlib.h> | 23 | #include <stdlib.h> |
20 | #include <stdio.h> | 24 | #include <stdio.h> |
... | @@ -65,6 +69,13 @@ stream_set_destroy (stream_t stream, void (*_destroy) (stream_t), void *owner) | ... | @@ -65,6 +69,13 @@ stream_set_destroy (stream_t stream, void (*_destroy) (stream_t), void *owner) |
65 | return 0; | 69 | return 0; |
66 | } | 70 | } |
67 | 71 | ||
72 | void * | ||
73 | stream_get_owner (stream_t stream) | ||
74 | { | ||
75 | return (stream) ? stream->owner : NULL; | ||
76 | } | ||
77 | |||
78 | |||
68 | int | 79 | int |
69 | stream_open (stream_t stream, const char *name, int port, int flags) | 80 | stream_open (stream_t stream, const char *name, int port, int flags) |
70 | { | 81 | { |
... | @@ -253,13 +264,11 @@ stream_get_flags (stream_t stream, int *pfl) | ... | @@ -253,13 +264,11 @@ stream_get_flags (stream_t stream, int *pfl) |
253 | } | 264 | } |
254 | 265 | ||
255 | int | 266 | int |
256 | stream_set_flags (stream_t stream, int fl, void *owner) | 267 | stream_set_flags (stream_t stream, int fl) |
257 | { | 268 | { |
258 | if (stream == NULL) | 269 | if (stream == NULL) |
259 | return EINVAL; | 270 | return EINVAL; |
260 | if (stream->owner != owner) | 271 | stream->flags |= fl; |
261 | return EACCES; | ||
262 | stream->flags = fl; | ||
263 | return 0; | 272 | return 0; |
264 | } | 273 | } |
265 | 274 | ... | ... |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
18 | #include <stdlib.h> | 22 | #include <stdlib.h> |
19 | #include <stdio.h> | 23 | #include <stdio.h> |
20 | #include <errno.h> | 24 | #include <errno.h> |
... | @@ -27,12 +31,12 @@ | ... | @@ -27,12 +31,12 @@ |
27 | #include <arpa/inet.h> | 31 | #include <arpa/inet.h> |
28 | #include <unistd.h> | 32 | #include <unistd.h> |
29 | 33 | ||
30 | #include <stream0.h> | 34 | #include <mailutils/stream.h> |
31 | #include <tcp0.h> | 35 | #include <tcp0.h> |
32 | 36 | ||
33 | static int _tcp_close(stream_t stream) | 37 | static int _tcp_close(stream_t stream) |
34 | { | 38 | { |
35 | struct _tcp_instance *tcp = stream->owner; | 39 | struct _tcp_instance *tcp = stream_get_owner(stream); |
36 | 40 | ||
37 | if ( tcp->fd != -1 ) | 41 | if ( tcp->fd != -1 ) |
38 | close(tcp->fd); | 42 | close(tcp->fd); |
... | @@ -43,7 +47,7 @@ static int _tcp_close(stream_t stream) | ... | @@ -43,7 +47,7 @@ static int _tcp_close(stream_t stream) |
43 | 47 | ||
44 | static int _tcp_open(stream_t stream, const char *host, int port, int flags) | 48 | static int _tcp_open(stream_t stream, const char *host, int port, int flags) |
45 | { | 49 | { |
46 | struct _tcp_instance *tcp = stream->owner; | 50 | struct _tcp_instance *tcp = stream_get_owner(stream); |
47 | int flgs, ret; | 51 | int flgs, ret; |
48 | size_t namelen; | 52 | size_t namelen; |
49 | struct sockaddr_in peer_addr; | 53 | struct sockaddr_in peer_addr; |
... | @@ -66,7 +70,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags) | ... | @@ -66,7 +70,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags) |
66 | flgs = fcntl(tcp->fd, F_GETFL); | 70 | flgs = fcntl(tcp->fd, F_GETFL); |
67 | flgs |= O_NONBLOCK; | 71 | flgs |= O_NONBLOCK; |
68 | fcntl(tcp->fd, F_SETFL, flgs); | 72 | fcntl(tcp->fd, F_SETFL, flgs); |
69 | stream->flags |= MU_STREAM_NONBLOCK; | 73 | stream_set_flags (stream, MU_STREAM_NONBLOCK); |
70 | } | 74 | } |
71 | tcp->state = TCP_STATE_RESOLVING; | 75 | tcp->state = TCP_STATE_RESOLVING; |
72 | case TCP_STATE_RESOLVING: | 76 | case TCP_STATE_RESOLVING: |
... | @@ -115,7 +119,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags) | ... | @@ -115,7 +119,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags) |
115 | 119 | ||
116 | static int _tcp_get_fd(stream_t stream, int *fd) | 120 | static int _tcp_get_fd(stream_t stream, int *fd) |
117 | { | 121 | { |
118 | struct _tcp_instance *tcp = stream->owner; | 122 | struct _tcp_instance *tcp = stream_get_owner(stream); |
119 | 123 | ||
120 | if ( fd == NULL || tcp->fd == EINVAL ) | 124 | if ( fd == NULL || tcp->fd == EINVAL ) |
121 | return EINVAL; | 125 | return EINVAL; |
... | @@ -126,7 +130,7 @@ static int _tcp_get_fd(stream_t stream, int *fd) | ... | @@ -126,7 +130,7 @@ static int _tcp_get_fd(stream_t stream, int *fd) |
126 | 130 | ||
127 | static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, size_t *br) | 131 | static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, size_t *br) |
128 | { | 132 | { |
129 | struct _tcp_instance *tcp = stream->owner; | 133 | struct _tcp_instance *tcp = stream_get_owner(stream); |
130 | int bytes; | 134 | int bytes; |
131 | 135 | ||
132 | offset = offset; | 136 | offset = offset; |
... | @@ -143,7 +147,7 @@ static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, | ... | @@ -143,7 +147,7 @@ static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, |
143 | 147 | ||
144 | static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t offset, size_t *bw) | 148 | static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t offset, size_t *bw) |
145 | { | 149 | { |
146 | struct _tcp_instance *tcp = stream->owner; | 150 | struct _tcp_instance *tcp = stream_get_owner(stream); |
147 | int bytes; | 151 | int bytes; |
148 | 152 | ||
149 | offset = offset; | 153 | offset = offset; |
... | @@ -160,7 +164,7 @@ static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t o | ... | @@ -160,7 +164,7 @@ static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t o |
160 | 164 | ||
161 | static void _tcp_destroy(stream_t stream) | 165 | static void _tcp_destroy(stream_t stream) |
162 | { | 166 | { |
163 | struct _tcp_instance *tcp = stream->owner; | 167 | struct _tcp_instance *tcp = stream_get_owner(stream); |
164 | 168 | ||
165 | if ( tcp->host ) | 169 | if ( tcp->host ) |
166 | free(tcp->host); | 170 | free(tcp->host); | ... | ... |
... | @@ -15,13 +15,16 @@ | ... | @@ -15,13 +15,16 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
18 | 21 | ||
19 | #include <errno.h> | 22 | #include <errno.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
22 | #include <string.h> | 25 | #include <string.h> |
23 | 26 | ||
24 | #include <stream0.h> | 27 | #include <mailutils/stream.h> |
25 | 28 | ||
26 | struct _ts_desc { | 29 | struct _ts_desc { |
27 | const char *encoding; | 30 | const char *encoding; |
... | @@ -45,7 +48,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ... | @@ -45,7 +48,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes); |
45 | int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | 48 | int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes); |
46 | 49 | ||
47 | #define NUM_TRANSCODERS 5 | 50 | #define NUM_TRANSCODERS 5 |
48 | struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode, _base64_encode}, | 51 | struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode, _base64_encode}, |
49 | { "quoted-printable", _qp_decode, _qp_encode}, | 52 | { "quoted-printable", _qp_decode, _qp_encode}, |
50 | { "7bit", NULL, NULL}, | 53 | { "7bit", NULL, NULL}, |
51 | { "8bit", NULL, NULL}, | 54 | { "8bit", NULL, NULL}, |
... | @@ -54,28 +57,28 @@ struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode, | ... | @@ -54,28 +57,28 @@ struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode, |
54 | 57 | ||
55 | static void _trans_destroy(stream_t stream) | 58 | static void _trans_destroy(stream_t stream) |
56 | { | 59 | { |
57 | struct _trans_stream *ts = stream->owner; | 60 | struct _trans_stream *ts = stream_get_owner(stream); |
58 | 61 | ||
59 | stream_destroy(&(ts->stream), NULL); | 62 | stream_destroy(&(ts->stream), NULL); |
60 | if ( ts->leftover ) | 63 | if ( ts->leftover ) |
61 | free(ts->leftover); | 64 | free(ts->leftover); |
62 | free(ts); | 65 | free(ts); |
63 | } | 66 | } |
64 | 67 | ||
65 | static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes) | 68 | static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes) |
66 | { | 69 | { |
67 | struct _trans_stream *ts = stream->owner; | 70 | struct _trans_stream *ts = stream_get_owner(stream); |
68 | size_t isize = osize; | 71 | size_t isize = osize; |
69 | char *iptr; | 72 | char *iptr; |
70 | int consumed, ret; | 73 | int consumed, ret; |
71 | 74 | ||
72 | if ( nbytes == NULL || optr == NULL || osize == 0 ) | 75 | if ( nbytes == NULL || optr == NULL || osize == 0 ) |
73 | return EINVAL; | 76 | return EINVAL; |
74 | 77 | ||
75 | *nbytes = 0; | 78 | *nbytes = 0; |
76 | 79 | ||
77 | if ( offset == 0 ) | 80 | if ( offset == 0 ) |
78 | ts->cur_offset = 0; | 81 | ts->cur_offset = 0; |
79 | if ( ( iptr = alloca(isize) ) == NULL ) | 82 | if ( ( iptr = alloca(isize) ) == NULL ) |
80 | return ENOMEM; | 83 | return ENOMEM; |
81 | if ( ts->leftover ) { | 84 | if ( ts->leftover ) { |
... | @@ -83,16 +86,16 @@ static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, | ... | @@ -83,16 +86,16 @@ static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, |
83 | free( ts->leftover ); | 86 | free( ts->leftover ); |
84 | ts->leftover = NULL; | 87 | ts->leftover = NULL; |
85 | ts->offset = 0; // encase of error; | 88 | ts->offset = 0; // encase of error; |
86 | } | 89 | } |
87 | if ( ( ret = stream_read(ts->stream, iptr + ts->llen, isize - ts->llen, ts->cur_offset, &osize) ) != 0 ) | 90 | if ( ( ret = stream_read(ts->stream, iptr + ts->llen, isize - ts->llen, ts->cur_offset, &osize) ) != 0 ) |
88 | return ret; | 91 | return ret; |
89 | ts->cur_offset += osize; | 92 | ts->cur_offset += osize; |
90 | consumed = ts->transcoder(iptr, osize + ts->llen, optr, nbytes); | 93 | consumed = ts->transcoder(iptr, osize + ts->llen, optr, nbytes); |
91 | if ( ( ts->llen = ((osize + ts->llen) - consumed ) ) ) | 94 | if ( ( ts->llen = ((osize + ts->llen) - consumed ) ) ) |
92 | { | 95 | { |
93 | if ( ( ts->leftover = malloc(ts->llen) ) == NULL ) | 96 | if ( ( ts->leftover = malloc(ts->llen) ) == NULL ) |
94 | return ENOMEM; | 97 | return ENOMEM; |
95 | memcpy(ts->leftover, iptr + consumed, ts->llen); | 98 | memcpy(ts->leftover, iptr + consumed, ts->llen); |
96 | } | 99 | } |
97 | return 0; | 100 | return 0; |
98 | } | 101 | } |
... | @@ -100,11 +103,11 @@ static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, | ... | @@ -100,11 +103,11 @@ static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, |
100 | 103 | ||
101 | static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) | 104 | static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) |
102 | { | 105 | { |
103 | struct _trans_stream *ts = stream->owner; | 106 | struct _trans_stream *ts = stream_get_owner(stream); |
104 | size_t osize = isize; | 107 | size_t osize = isize; |
105 | char *optr; | 108 | char *optr; |
106 | int ret; | 109 | int ret; |
107 | 110 | ||
108 | if ( nbytes == NULL || iptr == NULL || isize == 0 ) | 111 | if ( nbytes == NULL || iptr == NULL || isize == 0 ) |
109 | return EINVAL; | 112 | return EINVAL; |
110 | 113 | ||
... | @@ -113,16 +116,16 @@ static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t o | ... | @@ -113,16 +116,16 @@ static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t o |
113 | if ( offset && ts->cur_offset != offset ) | 116 | if ( offset && ts->cur_offset != offset ) |
114 | return ESPIPE; | 117 | return ESPIPE; |
115 | if ( offset == 0 ) | 118 | if ( offset == 0 ) |
116 | ts->cur_offset = 0; | 119 | ts->cur_offset = 0; |
117 | if ( ( optr = alloca(osize) ) == NULL ) | 120 | if ( ( optr = alloca(osize) ) == NULL ) |
118 | return ENOMEM; | 121 | return ENOMEM; |
119 | 122 | ||
120 | *nbytes = ts->transcoder(iptr, isize, optr, &osize); | 123 | *nbytes = ts->transcoder(iptr, isize, optr, &osize); |
121 | if ( ( ret = stream_write(ts->stream, optr, osize, ts->cur_offset, &osize) ) != 0 ) | 124 | if ( ( ret = stream_write(ts->stream, optr, osize, ts->cur_offset, &osize) ) != 0 ) |
122 | return ret; | 125 | return ret; |
123 | 126 | ||
124 | ts->cur_offset += osize; | 127 | ts->cur_offset += osize; |
125 | 128 | ||
126 | return 0; | 129 | return 0; |
127 | } | 130 | } |
128 | 131 | ||
... | @@ -130,10 +133,10 @@ int encoder_stream_create(stream_t *stream, stream_t iostream, const char *encod | ... | @@ -130,10 +133,10 @@ int encoder_stream_create(stream_t *stream, stream_t iostream, const char *encod |
130 | { | 133 | { |
131 | struct _trans_stream *ts; | 134 | struct _trans_stream *ts; |
132 | int i, ret; | 135 | int i, ret; |
133 | 136 | ||
134 | if ( stream == NULL || iostream == NULL || encoding == NULL ) | 137 | if ( stream == NULL || iostream == NULL || encoding == NULL ) |
135 | return EINVAL; | 138 | return EINVAL; |
136 | 139 | ||
137 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) | 140 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) |
138 | return ENOMEM; | 141 | return ENOMEM; |
139 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { | 142 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { |
... | @@ -145,7 +148,7 @@ int encoder_stream_create(stream_t *stream, stream_t iostream, const char *encod | ... | @@ -145,7 +148,7 @@ int encoder_stream_create(stream_t *stream, stream_t iostream, const char *encod |
145 | 148 | ||
146 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) | 149 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) |
147 | return ret; | 150 | return ret; |
148 | ts->transcoder = tslist[i].encode; | 151 | ts->transcoder = tslist[i].encode; |
149 | stream_set_read(*stream, _trans_read, ts ); | 152 | stream_set_read(*stream, _trans_read, ts ); |
150 | stream_set_write(*stream, _trans_write, ts ); | 153 | stream_set_write(*stream, _trans_write, ts ); |
151 | stream_set_destroy(*stream, _trans_destroy, ts ); | 154 | stream_set_destroy(*stream, _trans_destroy, ts ); |
... | @@ -157,10 +160,10 @@ int decoder_stream_create(stream_t *stream, stream_t iostream, const char *encod | ... | @@ -157,10 +160,10 @@ int decoder_stream_create(stream_t *stream, stream_t iostream, const char *encod |
157 | { | 160 | { |
158 | struct _trans_stream *ts; | 161 | struct _trans_stream *ts; |
159 | int i, ret; | 162 | int i, ret; |
160 | 163 | ||
161 | if ( stream == NULL || iostream == NULL || encoding == NULL ) | 164 | if ( stream == NULL || iostream == NULL || encoding == NULL ) |
162 | return EINVAL; | 165 | return EINVAL; |
163 | 166 | ||
164 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) | 167 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) |
165 | return ENOMEM; | 168 | return ENOMEM; |
166 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { | 169 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { |
... | @@ -172,7 +175,7 @@ int decoder_stream_create(stream_t *stream, stream_t iostream, const char *encod | ... | @@ -172,7 +175,7 @@ int decoder_stream_create(stream_t *stream, stream_t iostream, const char *encod |
172 | 175 | ||
173 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) | 176 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) |
174 | return ret; | 177 | return ret; |
175 | ts->transcoder = tslist[i].decode; | 178 | ts->transcoder = tslist[i].decode; |
176 | stream_set_read(*stream, _trans_read, ts ); | 179 | stream_set_read(*stream, _trans_read, ts ); |
177 | stream_set_write(*stream, _trans_write, ts ); | 180 | stream_set_write(*stream, _trans_write, ts ); |
178 | stream_set_destroy(*stream, _trans_destroy, ts ); | 181 | stream_set_destroy(*stream, _trans_destroy, ts ); |
... | @@ -209,7 +212,7 @@ int _base64_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ... | @@ -209,7 +212,7 @@ int _base64_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) |
209 | int i = 0, tmp = 0; | 212 | int i = 0, tmp = 0; |
210 | size_t consumed = 0; | 213 | size_t consumed = 0; |
211 | char data[4]; | 214 | char data[4]; |
212 | 215 | ||
213 | while ( consumed < isize ) { | 216 | while ( consumed < isize ) { |
214 | while ( ( i < 4 ) && ( consumed < isize ) ) { | 217 | while ( ( i < 4 ) && ( consumed < isize ) ) { |
215 | tmp = _b64_input(*iptr++); | 218 | tmp = _b64_input(*iptr++); |
... | @@ -273,7 +276,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ... | @@ -273,7 +276,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) |
273 | char c; | 276 | char c; |
274 | int last_char = 0; | 277 | int last_char = 0; |
275 | size_t consumed = 0; | 278 | size_t consumed = 0; |
276 | 279 | ||
277 | while (consumed < isize) { | 280 | while (consumed < isize) { |
278 | c = *iptr++; | 281 | c = *iptr++; |
279 | if ( ((c >= 33) && (c <= 60)) || ((c >= 62) && (c <= 126)) || ((c == '=') && !_ishex(*iptr)) ) { | 282 | if ( ((c >= 33) && (c <= 60)) || ((c >= 62) && (c <= 126)) || ((c == '=') && !_ishex(*iptr)) ) { |
... | @@ -285,7 +288,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ... | @@ -285,7 +288,7 @@ int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) |
285 | // there must be 2 more characters before I consume this | 288 | // there must be 2 more characters before I consume this |
286 | if ((isize - consumed) < 3) { | 289 | if ((isize - consumed) < 3) { |
287 | return consumed; | 290 | return consumed; |
288 | } | 291 | } |
289 | else { | 292 | else { |
290 | // you get =XX where XX are hex characters | 293 | // you get =XX where XX are hex characters |
291 | char chr[2]; | 294 | char chr[2]; |
... | @@ -336,7 +339,7 @@ int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ... | @@ -336,7 +339,7 @@ int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes) |
336 | { | 339 | { |
337 | int count = 0, c; | 340 | int count = 0, c; |
338 | size_t consumed = 0; | 341 | size_t consumed = 0; |
339 | 342 | ||
340 | while (consumed < isize && (*nbytes + 4) < isize) { | 343 | while (consumed < isize && (*nbytes + 4) < isize) { |
341 | if (count == QP_LINE_MAX) { | 344 | if (count == QP_LINE_MAX) { |
342 | *optr++ = '='; | 345 | *optr++ = '='; | ... | ... |
... | @@ -15,13 +15,16 @@ | ... | @@ -15,13 +15,16 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
18 | 21 | ||
19 | #include <errno.h> | 22 | #include <errno.h> |
20 | #include <stdio.h> | 23 | #include <stdio.h> |
21 | #include <stdlib.h> | 24 | #include <stdlib.h> |
22 | #include <string.h> | 25 | #include <string.h> |
23 | 26 | ||
24 | #include <steam0.h> | 27 | #include <mailutils/sys/steam0.h> |
25 | #include <mailutils/transcode.h> | 28 | #include <mailutils/transcode.h> |
26 | 29 | ||
27 | int _base64_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes); | 30 | int _base64_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes); | ... | ... |
... | @@ -19,98 +19,23 @@ | ... | @@ -19,98 +19,23 @@ |
19 | # include <config.h> | 19 | # include <config.h> |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <url0.h> | ||
23 | #include <registrar0.h> | ||
24 | #include <cpystr.h> | ||
25 | |||
26 | #include <string.h> | 22 | #include <string.h> |
27 | #include <stdlib.h> | 23 | #include <stdlib.h> |
28 | #include <errno.h> | 24 | #include <errno.h> |
29 | 25 | ||
30 | 26 | #include <mailutils/registrar.h> | |
31 | /* Forward prototypes */ | 27 | #include <misc.h> |
32 | static int get_scheme (const url_t, char *, size_t, size_t *); | 28 | #include <url0.h> |
33 | static int get_user (const url_t, char *, size_t, size_t *); | ||
34 | static int get_passwd (const url_t, char *, size_t, size_t *); | ||
35 | static int get_host (const url_t, char *, size_t, size_t *); | ||
36 | static int get_port (const url_t, long *); | ||
37 | static int get_path (const url_t, char *, size_t, size_t *); | ||
38 | static int get_query (const url_t, char *, size_t, size_t *); | ||
39 | static int get_id (const url_t, int *); | ||
40 | 29 | ||
41 | int | 30 | int |
42 | url_create (url_t * purl, const char *name) | 31 | url_create (url_t *purl, const char *name) |
43 | { | 32 | { |
44 | int status = EINVAL; | 33 | url_t url = calloc(1, sizeof (*url)); |
45 | struct url_registrar *ureg; | 34 | if (url == NULL) |
46 | struct mailbox_registrar *mreg; | 35 | return ENOMEM; |
47 | size_t name_len; | 36 | url->name = strdup (name); |
48 | int id; | 37 | *purl = url; |
49 | size_t i, entry_count = 0; | 38 | return 0; |
50 | |||
51 | /* Sanity checks */ | ||
52 | if (name == NULL || *name == '\0') | ||
53 | return status; | ||
54 | |||
55 | name_len = strlen (name); | ||
56 | |||
57 | /* Search for a known scheme */ | ||
58 | registrar_entry_count (&entry_count); | ||
59 | for (i = 0; i < entry_count; i++) | ||
60 | { | ||
61 | if (registrar_entry (i, &ureg, &mreg, &id) == 0) | ||
62 | { | ||
63 | size_t scheme_len; | ||
64 | if (ureg && ureg->scheme && | ||
65 | name_len > (scheme_len = strlen (ureg->scheme)) && | ||
66 | memcmp (name, ureg->scheme, scheme_len) == 0) | ||
67 | { | ||
68 | status = 0; | ||
69 | break; | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | /* | ||
74 | while (registrar_list (&ureg, &mreg, &id, ®) == 0) | ||
75 | { | ||
76 | size_t scheme_len; | ||
77 | if (ureg && ureg->scheme && | ||
78 | name_len > (scheme_len = strlen (ureg->scheme)) && | ||
79 | memcmp (name, ureg->scheme, scheme_len) == 0) | ||
80 | { | ||
81 | status = 0; | ||
82 | break; | ||
83 | } | ||
84 | } | ||
85 | */ | ||
86 | |||
87 | /* Found one initialize it */ | ||
88 | if (status == 0) | ||
89 | { | ||
90 | status = ureg->_create (purl, name); | ||
91 | if (status == 0) | ||
92 | { | ||
93 | url_t url = *purl; | ||
94 | url->id = id; | ||
95 | if (url->_get_id == NULL) | ||
96 | url->_get_id = get_id; | ||
97 | if (url->_get_scheme == NULL) | ||
98 | url->_get_scheme = get_scheme; | ||
99 | if (url->_get_user == NULL) | ||
100 | url->_get_user = get_user; | ||
101 | if (url->_get_passwd == NULL) | ||
102 | url->_get_passwd = get_passwd; | ||
103 | if (url->_get_host == NULL) | ||
104 | url->_get_host = get_host; | ||
105 | if (url->_get_port == NULL) | ||
106 | url->_get_port = get_port; | ||
107 | if (url->_get_path == NULL) | ||
108 | url->_get_path = get_path; | ||
109 | if (url->_get_query == NULL) | ||
110 | url->_get_query = get_query; | ||
111 | } | ||
112 | } | ||
113 | return status; | ||
114 | } | 39 | } |
115 | 40 | ||
116 | void | 41 | void |
... | @@ -118,142 +43,144 @@ url_destroy (url_t *purl) | ... | @@ -118,142 +43,144 @@ url_destroy (url_t *purl) |
118 | { | 43 | { |
119 | if (purl && *purl) | 44 | if (purl && *purl) |
120 | { | 45 | { |
121 | struct url_registrar *ureg; | 46 | url_t url = (*purl); |
122 | int id; | 47 | if (url->_destroy) |
123 | url_get_id (*purl, &id); | 48 | url->_destroy (url); |
124 | registrar_get (id, &ureg, NULL); | ||
125 | ureg->_destroy(purl); | ||
126 | (*purl) = NULL; | ||
127 | } | ||
128 | } | ||
129 | 49 | ||
130 | int (url_get_scheme) (const url_t url, char *scheme, size_t len, size_t *n) | 50 | if (url->name) |
131 | { | 51 | free (url->name); |
132 | return (url) ? url->_get_scheme(url, scheme, len, n) : EINVAL; | ||
133 | } | ||
134 | 52 | ||
135 | int (url_get_user) (const url_t url, char *user, size_t len, size_t *n) | 53 | if (url->scheme) |
136 | { | 54 | free (url->scheme); |
137 | return (url) ? url->_get_user(url, user, len, n) : EINVAL; | ||
138 | } | ||
139 | |||
140 | int (url_get_passwd) (const url_t url, char *passwd, size_t len, size_t *n) | ||
141 | { | ||
142 | return (url) ? url->_get_passwd(url, passwd, len, n) : EINVAL; | ||
143 | } | ||
144 | 55 | ||
145 | int (url_get_host) (const url_t url, char *host, size_t len, size_t *n) | 56 | if (url->user) |
146 | { | 57 | free (url->user); |
147 | return (url) ? url->_get_host(url, host, len, n) : EINVAL; | ||
148 | } | ||
149 | 58 | ||
150 | int (url_get_port) (const url_t url, long *port) | 59 | if (url->passwd) |
151 | { | 60 | free (url->passwd); |
152 | return (url) ? url->_get_port(url, port) : EINVAL; | ||
153 | } | ||
154 | 61 | ||
155 | int (url_get_path) (const url_t url, char *path, size_t len, size_t *n) | 62 | if (url->host) |
156 | { | 63 | free (url->host); |
157 | return (url) ? url->_get_path(url, path, len, n) : EINVAL; | ||
158 | } | ||
159 | 64 | ||
160 | int (url_get_query) (const url_t url, char *query, size_t len, size_t *n) | 65 | *purl = NULL; |
161 | { | 66 | } |
162 | return (url) ? url->_get_query(url, query, len, n) : EINVAL; | ||
163 | } | 67 | } |
164 | 68 | ||
165 | int (url_get_id) (const url_t url, int *id) | 69 | int |
70 | url_get_scheme (const url_t url, char *scheme, size_t len, size_t *n) | ||
166 | { | 71 | { |
167 | return (url) ? url->_get_id (url, id) : EINVAL; | 72 | size_t i; |
73 | if (url == NULL) | ||
74 | return EINVAL; | ||
75 | if (url->_get_scheme) | ||
76 | return url->_get_scheme (url, scheme, len, n); | ||
77 | i = _cpystr (scheme, url->scheme, len); | ||
78 | if (n) | ||
79 | *n = i; | ||
80 | return 0; | ||
168 | } | 81 | } |
169 | 82 | ||
170 | /* Simple stub functions they all call _cpystr */ | 83 | int |
171 | 84 | url_get_user (const url_t url, char *user, size_t len, size_t *n) | |
172 | static int | ||
173 | get_scheme (const url_t u, char *s, size_t len, size_t *n) | ||
174 | { | 85 | { |
175 | size_t i; | 86 | size_t i; |
176 | if (u == NULL) | 87 | if (url == NULL) |
177 | return EINVAL; | 88 | return EINVAL; |
178 | i = _cpystr (s, u->scheme, len); | 89 | if (url->_get_user) |
90 | return url->_get_user (url, user, len, n); | ||
91 | i = _cpystr (user, url->user, len); | ||
179 | if (n) | 92 | if (n) |
180 | *n = i; | 93 | *n = i; |
181 | return 0; | 94 | return 0; |
182 | } | 95 | } |
183 | 96 | ||
184 | static int | 97 | /* FIXME: We should not store passwd in clear, but rather |
185 | get_user (const url_t u, char *s, size_t len, size_t *n) | 98 | have a simple encoding, and decoding mechanism */ |
99 | int | ||
100 | url_get_passwd (const url_t url, char *passwd, size_t len, size_t *n) | ||
186 | { | 101 | { |
187 | size_t i; | 102 | size_t i; |
188 | if (u == NULL) | 103 | if (url == NULL) |
189 | return EINVAL; | 104 | return EINVAL; |
190 | i = _cpystr (s, u->user, len); | 105 | if (url->_get_passwd) |
106 | return url->_get_passwd (url, passwd, len, n); | ||
107 | i = _cpystr (passwd, url->passwd, len); | ||
191 | if (n) | 108 | if (n) |
192 | *n = i; | 109 | *n = i; |
193 | return 0; | 110 | return 0; |
194 | } | 111 | } |
195 | 112 | ||
196 | /* FIXME: We should not store passwd in clear, but rather | 113 | int |
197 | have a simple encoding, and decoding mechanism */ | 114 | url_get_auth (const url_t url, char *auth, size_t len, size_t *n) |
198 | static int | ||
199 | get_passwd (const url_t u, char *s, size_t len, size_t *n) | ||
200 | { | 115 | { |
201 | size_t i; | 116 | size_t i; |
202 | if (u == NULL) | 117 | if (url == NULL) |
203 | return EINVAL; | 118 | return EINVAL; |
204 | i = _cpystr (s, u->passwd, len); | 119 | if (url->_get_auth) |
120 | return url->_get_auth (url, auth, len, n); | ||
121 | i = _cpystr (auth, url->auth, len); | ||
205 | if (n) | 122 | if (n) |
206 | *n = i; | 123 | *n = i; |
207 | return 0; | 124 | return 0; |
208 | } | 125 | } |
209 | 126 | ||
210 | static int | 127 | int |
211 | get_host (const url_t u, char *s, size_t len, size_t *n) | 128 | url_get_host (const url_t url, char *host, size_t len, size_t *n) |
212 | { | 129 | { |
213 | size_t i; | 130 | size_t i; |
214 | if (u == NULL) | 131 | if (url == NULL) |
215 | return EINVAL; | 132 | return EINVAL; |
216 | i = _cpystr (s, u->host, len); | 133 | if (url->_get_host) |
134 | return url->_get_host (url, host, len, n); | ||
135 | i = _cpystr (host, url->host, len); | ||
217 | if (n) | 136 | if (n) |
218 | *n = i; | 137 | *n = i; |
219 | return 0; | 138 | return 0; |
220 | } | 139 | } |
221 | 140 | ||
222 | static int | 141 | int |
223 | get_port (const url_t u, long * p) | 142 | url_get_port (const url_t url, long *pport) |
224 | { | 143 | { |
225 | *p = u->port; | 144 | if (url == NULL) |
145 | return EINVAL; | ||
146 | if (url->_get_port) | ||
147 | return url->_get_port (url, pport); | ||
148 | *pport = url->port; | ||
226 | return 0; | 149 | return 0; |
227 | } | 150 | } |
228 | 151 | ||
229 | static int | 152 | int |
230 | get_path (const url_t u, char *s, size_t len, size_t *n) | 153 | url_get_path (const url_t url, char *path, size_t len, size_t *n) |
231 | { | 154 | { |
232 | size_t i; | 155 | size_t i; |
233 | if (u == NULL) | 156 | if (url == NULL) |
234 | return EINVAL; | 157 | return EINVAL; |
235 | i = _cpystr(s, u->path, len); | 158 | if (url->_get_path) |
159 | return url->_get_path (url, path, len, n); | ||
160 | i = _cpystr(path, url->path, len); | ||
236 | if (n) | 161 | if (n) |
237 | *n = i; | 162 | *n = i; |
238 | return 0; | 163 | return 0; |
239 | } | 164 | } |
240 | 165 | ||
241 | static int | 166 | int |
242 | get_query (const url_t u, char *s, size_t len, size_t *n) | 167 | url_get_query (const url_t url, char *query, size_t len, size_t *n) |
243 | { | 168 | { |
244 | size_t i; | 169 | size_t i; |
245 | if (u == NULL) | 170 | if (url == NULL) |
246 | return EINVAL; | 171 | return EINVAL; |
247 | i = _cpystr(s, u->query, len); | 172 | if (url->_get_query) |
173 | return url->_get_query (url, query, len, n); | ||
174 | i = _cpystr(query, url->query, len); | ||
248 | if (n) | 175 | if (n) |
249 | *n = i; | 176 | *n = i; |
250 | return 0; | 177 | return 0; |
251 | } | 178 | } |
252 | 179 | ||
253 | static int | 180 | const char * |
254 | get_id (const url_t u, int *id) | 181 | url_to_string (const url_t url) |
255 | { | 182 | { |
256 | if (id) | 183 | if (url == NULL || url->name == NULL) |
257 | *id = u->id; | 184 | return ""; |
258 | return 0; | 185 | return url->name; |
259 | } | 186 | } | ... | ... |
... | @@ -15,74 +15,63 @@ | ... | @@ -15,74 +15,63 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #include <url0.h> | 18 | #ifdef HAVE_CONFIG_H |
19 | #include <registrar0.h> | 19 | # include <config.h> |
20 | #endif | ||
20 | 21 | ||
21 | #include <errno.h> | 22 | #include <errno.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <string.h> | 24 | #include <string.h> |
24 | 25 | ||
25 | static void url_file_destroy (url_t *purl); | 26 | #include <mailutils/registrar.h> |
26 | static int url_file_create (url_t *purl, const char *name); | 27 | #include <url0.h> |
27 | 28 | ||
28 | struct url_registrar _url_file_registrar = | 29 | int url_file_init (url_t purl); |
29 | { | 30 | static void url_file_destroy (url_t purl); |
30 | "file:", | ||
31 | url_file_create, url_file_destroy | ||
32 | }; | ||
33 | 31 | ||
34 | static void | 32 | static void |
35 | url_file_destroy (url_t *purl) | 33 | url_file_destroy (url_t url) |
36 | { | 34 | { |
37 | if (purl && *purl) | 35 | (void) url; |
38 | { | ||
39 | url_t url = *purl; | ||
40 | free (url->scheme); | ||
41 | free (url->path); | ||
42 | free (url); | ||
43 | *purl = NULL; | ||
44 | } | ||
45 | } | 36 | } |
46 | 37 | ||
47 | /* | 38 | /* |
48 | UNIX box | 39 | UNIX File |
40 | file:path | ||
49 | */ | 41 | */ |
50 | static int | 42 | int |
51 | url_file_create (url_t *purl, const char *name) | 43 | url_file_init (url_t url) |
52 | { | 44 | { |
53 | url_t url; | 45 | const char *name = url_to_string (url); |
54 | struct url_registrar *ureg = &_url_mbox_registrar; | 46 | size_t len = strlen (name); |
55 | 47 | ||
56 | /* reject the obvious */ | 48 | /* reject the obvious */ |
57 | if (name == NULL || *name == '\0') | 49 | if (name == NULL || strncmp (MU_FILE_SCHEME, name, MU_FILE_SCHEME_LEN) != 0 |
50 | || len < (MU_FILE_SCHEME_LEN + 1) /* (scheme)+1(path)*/) | ||
58 | return EINVAL; | 51 | return EINVAL; |
59 | 52 | ||
60 | /* FIXME: do I need to decode url encoding '% hex hex' ? */ | 53 | /* do I need to decode url encoding '% hex hex' ? */ |
61 | |||
62 | url = calloc(1, sizeof (*url)); | ||
63 | if (url == NULL) | ||
64 | return ENOMEM; | ||
65 | 54 | ||
66 | /* TYPE */ | 55 | /* TYPE */ |
67 | url->_create = ureg->_create; | 56 | url->_init = url_file_init; |
68 | url->_destroy = ureg->_destroy; | 57 | url->_destroy = url_file_destroy; |
69 | 58 | ||
70 | /* SCHEME */ | 59 | /* SCHEME */ |
71 | url->scheme = strdup (ureg->scheme); | 60 | url->scheme = strdup (MU_FILE_SCHEME); |
72 | if (url->scheme == NULL) | 61 | if (url->scheme == NULL) |
73 | { | 62 | { |
74 | ureg->_destroy (&url); | 63 | url_file_destroy (url); |
75 | return ENOMEM; | 64 | return ENOMEM; |
76 | } | 65 | } |
77 | 66 | ||
78 | /* PATH */ | 67 | /* PATH */ |
68 | name += MU_FILE_SCHEME_LEN; /* pass the scheme */ | ||
79 | url->path = strdup (name); | 69 | url->path = strdup (name); |
80 | if (url->path == NULL) | 70 | if (url->path == NULL) |
81 | { | 71 | { |
82 | ureg->_destroy (&url); | 72 | url_file_destroy (url); |
83 | return ENOMEM; | 73 | return ENOMEM; |
84 | } | 74 | } |
85 | 75 | ||
86 | *purl = url; | ||
87 | return 0; | 76 | return 0; |
88 | } | 77 | } | ... | ... |
... | @@ -15,74 +15,63 @@ | ... | @@ -15,74 +15,63 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #include <url0.h> | 18 | #ifdef HAVE_CONFIG_H |
19 | #include <mailutils/registrar.h> | 19 | # include <config.h> |
20 | #endif | ||
20 | 21 | ||
21 | #include <errno.h> | 22 | #include <errno.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <string.h> | 24 | #include <string.h> |
24 | 25 | ||
25 | static void url_mbox_destroy (url_t *purl); | 26 | #include <mailutils/registrar.h> |
26 | static int url_mbox_create (url_t *purl, const char *name); | 27 | #include <url0.h> |
27 | 28 | ||
28 | struct url_registrar _url_mbox_registrar = | 29 | int url_mbox_init (url_t purl); |
29 | { | 30 | static void url_mbox_destroy (url_t purl); |
30 | "/", | ||
31 | url_mbox_create, url_mbox_destroy | ||
32 | }; | ||
33 | 31 | ||
34 | static void | 32 | static void |
35 | url_mbox_destroy (url_t *purl) | 33 | url_mbox_destroy (url_t url) |
36 | { | 34 | { |
37 | if (purl && *purl) | 35 | (void) url; |
38 | { | ||
39 | url_t url = *purl; | ||
40 | free (url->scheme); | ||
41 | free (url->path); | ||
42 | free (url); | ||
43 | *purl = NULL; | ||
44 | } | ||
45 | } | 36 | } |
46 | 37 | ||
47 | /* | 38 | /* |
48 | UNIX box | 39 | UNIX Mbox |
40 | mbox:path | ||
49 | */ | 41 | */ |
50 | static int | 42 | int |
51 | url_mbox_create (url_t *purl, const char *name) | 43 | url_mbox_init (url_t url) |
52 | { | 44 | { |
53 | url_t url; | 45 | const char *name = url_to_string (url); |
54 | struct url_registrar *ureg = &_url_mbox_registrar; | 46 | size_t len = strlen (name); |
55 | 47 | ||
56 | /* reject the obvious */ | 48 | /* reject the obvious */ |
57 | if (name == NULL || *name == '\0') | 49 | if (name == NULL || strncmp (MU_MBOX_SCHEME, name, MU_MBOX_SCHEME_LEN) != 0 |
50 | || len < (MU_MBOX_SCHEME_LEN + 1) /* (scheme)+1(path)*/) | ||
58 | return EINVAL; | 51 | return EINVAL; |
59 | 52 | ||
60 | /* FIXME: do I need to decode url encoding '% hex hex' ? */ | 53 | /* do I need to decode url encoding '% hex hex' ? */ |
61 | |||
62 | url = calloc(1, sizeof (*url)); | ||
63 | if (url == NULL) | ||
64 | return ENOMEM; | ||
65 | 54 | ||
66 | /* TYPE */ | 55 | /* TYPE */ |
67 | url->_create = ureg->_create; | 56 | url->_init = url_mbox_init; |
68 | url->_destroy = ureg->_destroy; | 57 | url->_destroy = url_mbox_destroy; |
69 | 58 | ||
70 | /* SCHEME */ | 59 | /* SCHEME */ |
71 | url->scheme = strdup (ureg->scheme); | 60 | url->scheme = strdup (MU_MBOX_SCHEME); |
72 | if (url->scheme == NULL) | 61 | if (url->scheme == NULL) |
73 | { | 62 | { |
74 | ureg->_destroy (&url); | 63 | url_mbox_destroy (url); |
75 | return ENOMEM; | 64 | return ENOMEM; |
76 | } | 65 | } |
77 | 66 | ||
78 | /* PATH */ | 67 | /* PATH */ |
68 | name += MU_MBOX_SCHEME_LEN; /* pass the scheme */ | ||
79 | url->path = strdup (name); | 69 | url->path = strdup (name); |
80 | if (url->path == NULL) | 70 | if (url->path == NULL) |
81 | { | 71 | { |
82 | ureg->_destroy (&url); | 72 | url_mbox_destroy (url); |
83 | return ENOMEM; | 73 | return ENOMEM; |
84 | } | 74 | } |
85 | 75 | ||
86 | *purl = url; | ||
87 | return 0; | 76 | return 0; |
88 | } | 77 | } | ... | ... |
mailbox/url_path.c
0 → 100644
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 Library General 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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include <mailutils/registrar.h> | ||
27 | #include <url0.h> | ||
28 | |||
29 | static void url_path_destroy (url_t); | ||
30 | int url_path_init (url_t); | ||
31 | |||
32 | static void | ||
33 | url_path_destroy (url_t url) | ||
34 | { | ||
35 | (void)url; | ||
36 | } | ||
37 | |||
38 | int | ||
39 | url_path_init (url_t url) | ||
40 | { | ||
41 | const char *name = url_to_string (url); | ||
42 | /* reject the obvious */ | ||
43 | if (name == NULL || *name == '\0') | ||
44 | return EINVAL; | ||
45 | |||
46 | /* FIXME: do I need to decode url encoding '% hex hex' ? */ | ||
47 | |||
48 | /* TYPE */ | ||
49 | url->_init = url_path_init; | ||
50 | url->_destroy = url_path_destroy; | ||
51 | |||
52 | /* SCHEME */ | ||
53 | url->scheme = strdup (MU_PATH_SCHEME); | ||
54 | if (url->scheme == NULL) | ||
55 | { | ||
56 | url_path_destroy (url); | ||
57 | return ENOMEM; | ||
58 | } | ||
59 | |||
60 | /* PATH */ | ||
61 | url->path = strdup (name); | ||
62 | if (url->path == NULL) | ||
63 | { | ||
64 | url_path_destroy (url); | ||
65 | return ENOMEM; | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } |
... | @@ -15,73 +15,55 @@ | ... | @@ -15,73 +15,55 @@ |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
17 | 17 | ||
18 | #include <url0.h> | 18 | #ifdef HAVE_CONFIG_H |
19 | #include <mailutils/registrar.h> | 19 | # include <config.h> |
20 | #endif | ||
20 | 21 | ||
21 | #include <errno.h> | 22 | #include <errno.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <string.h> | 24 | #include <string.h> |
24 | #include <errno.h> | 25 | #include <errno.h> |
25 | 26 | ||
26 | static void url_pop_destroy (url_t *purl); | 27 | #include <mailutils/registrar.h> |
27 | static int url_pop_create (url_t *purl, const char *name); | 28 | #include <url0.h> |
28 | 29 | ||
29 | struct url_registrar _url_pop_registrar = | 30 | static void url_pop_destroy (url_t url); |
30 | { | ||
31 | "pop://", | ||
32 | url_pop_create, url_pop_destroy | ||
33 | }; | ||
34 | 31 | ||
35 | static void | 32 | static void |
36 | url_pop_destroy (url_t *purl) | 33 | url_pop_destroy (url_t url) |
37 | { | 34 | { |
38 | if (purl && *purl) | 35 | (void)url; |
39 | { | ||
40 | url_t url = *purl; | ||
41 | free (url->scheme); | ||
42 | free (url->user); | ||
43 | free (url->passwd); | ||
44 | free (url->host); | ||
45 | free (url); | ||
46 | *purl = NULL; | ||
47 | } | ||
48 | } | 36 | } |
49 | 37 | ||
50 | /* | 38 | /* |
51 | POP URL | 39 | POP URL |
52 | pop://[<user>;AUTH=<auth>@]<host>[:<port>] | 40 | pop://[<user>;AUTH=<auth>@]<host>[:<port>] |
53 | */ | 41 | */ |
54 | static int | 42 | int |
55 | url_pop_create (url_t *purl, const char *name) | 43 | url_pop_init (url_t url) |
56 | { | 44 | { |
57 | const char *host_port, *indexe; | 45 | const char *host_port, *indexe; |
58 | struct url_registrar *ureg = &_url_pop_registrar; | 46 | char *name = url->name; |
59 | size_t scheme_len = strlen (ureg->scheme); | ||
60 | url_t url; | ||
61 | 47 | ||
62 | /* reject the obvious */ | 48 | /* reject the obvious */ |
63 | if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0) | 49 | if (name == NULL || strncmp (MU_POP_SCHEME, name, MU_POP_SCHEME_LEN) != 0) |
64 | return EINVAL; | 50 | return EINVAL; |
65 | 51 | ||
66 | /* do I need to decode url encoding '% hex hex' ? */ | 52 | /* do I need to decode url encoding '% hex hex' ? */ |
67 | 53 | ||
68 | url = calloc(1, sizeof (*url)); | ||
69 | if (url == NULL) | ||
70 | return ENOMEM; | ||
71 | |||
72 | /* TYPE */ | 54 | /* TYPE */ |
73 | url->_create = _url_pop_registrar._create; | 55 | url->_init = url_pop_init; |
74 | url->_destroy = _url_pop_registrar._destroy; | 56 | url->_destroy = url_pop_destroy; |
75 | 57 | ||
76 | /* SCHEME */ | 58 | /* SCHEME */ |
77 | url->scheme = strdup ("pop://"); | 59 | url->scheme = strdup (MU_POP_SCHEME); |
78 | if (url->scheme == NULL) | 60 | if (url->scheme == NULL) |
79 | { | 61 | { |
80 | url_pop_destroy (&url); | 62 | url_pop_destroy (url); |
81 | return ENOMEM; | 63 | return ENOMEM; |
82 | } | 64 | } |
83 | 65 | ||
84 | name += scheme_len; /* pass the scheme */ | 66 | name += MU_POP_SCHEME_LEN; /* pass the scheme */ |
85 | 67 | ||
86 | host_port = strchr (name, '@'); | 68 | host_port = strchr (name, '@'); |
87 | if (host_port == NULL) | 69 | if (host_port == NULL) |
... | @@ -103,7 +85,7 @@ url_pop_create (url_t *purl, const char *name) | ... | @@ -103,7 +85,7 @@ url_pop_create (url_t *purl, const char *name) |
103 | url->user = malloc(indexe - name + 1); | 85 | url->user = malloc(indexe - name + 1); |
104 | if (url->user == NULL) | 86 | if (url->user == NULL) |
105 | { | 87 | { |
106 | url_pop_destroy (&url); | 88 | url_pop_destroy (url); |
107 | return -1; | 89 | return -1; |
108 | } | 90 | } |
109 | ((char *)memcpy(url->user, name, indexe - name))[indexe - name] = '\0'; | 91 | ((char *)memcpy(url->user, name, indexe - name))[indexe - name] = '\0'; |
... | @@ -112,28 +94,28 @@ url_pop_create (url_t *purl, const char *name) | ... | @@ -112,28 +94,28 @@ url_pop_create (url_t *purl, const char *name) |
112 | if (indexe == host_port) | 94 | if (indexe == host_port) |
113 | { | 95 | { |
114 | /* Use default AUTH '*' */ | 96 | /* Use default AUTH '*' */ |
115 | url->passwd = malloc (1 + 1); | 97 | url->auth = malloc (1 + 1); |
116 | if (url->passwd) | 98 | if (url->auth) |
117 | { | 99 | { |
118 | url->passwd[0] = '*'; | 100 | url->auth[0] = '*'; |
119 | url->passwd[1] = '\0'; | 101 | url->auth[1] = '\0'; |
120 | } | 102 | } |
121 | } | 103 | } |
122 | else | 104 | else |
123 | { | 105 | { |
124 | /* move pass AUTH= */ | 106 | /* move pass AUTH= */ |
125 | indexe += 6; | 107 | indexe += 6; |
126 | url->passwd = malloc (host_port - indexe + 1); | 108 | url->auth = malloc (host_port - indexe + 1); |
127 | if (url->passwd) | 109 | if (url->auth) |
128 | { | 110 | { |
129 | ((char *)memcpy (url->passwd, indexe, host_port - indexe)) | 111 | ((char *)memcpy (url->auth, indexe, host_port - indexe)) |
130 | [host_port - indexe] = '\0'; | 112 | [host_port - indexe] = '\0'; |
131 | } | 113 | } |
132 | } | 114 | } |
133 | 115 | ||
134 | if (url->passwd == NULL) | 116 | if (url->auth == NULL) |
135 | { | 117 | { |
136 | url_pop_destroy (&url); | 118 | url_pop_destroy (url); |
137 | return -1; | 119 | return -1; |
138 | } | 120 | } |
139 | 121 | ||
... | @@ -161,7 +143,7 @@ url_pop_create (url_t *purl, const char *name) | ... | @@ -161,7 +143,7 @@ url_pop_create (url_t *purl, const char *name) |
161 | 143 | ||
162 | if (url->host == NULL) | 144 | if (url->host == NULL) |
163 | { | 145 | { |
164 | url_pop_destroy (&url); | 146 | url_pop_destroy (url); |
165 | return ENOMEM; | 147 | return ENOMEM; |
166 | } | 148 | } |
167 | else | 149 | else |
... | @@ -172,6 +154,5 @@ url_pop_create (url_t *purl, const char *name) | ... | @@ -172,6 +154,5 @@ url_pop_create (url_t *purl, const char *name) |
172 | url->host[len - 1] = '\0'; /* leak a bit */ | 154 | url->host[len - 1] = '\0'; /* leak a bit */ |
173 | } | 155 | } |
174 | 156 | ||
175 | *purl = url; | ||
176 | return 0; | 157 | return 0; |
177 | } | 158 | } | ... | ... |
mailbox/url_sendmail.c
0 → 100644
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 Library General 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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include <mailutils/registrar.h> | ||
27 | #include <url0.h> | ||
28 | |||
29 | int url_sendmail_init (url_t purl); | ||
30 | static void url_sendmail_destroy (url_t purl); | ||
31 | |||
32 | static void | ||
33 | url_sendmail_destroy (url_t url) | ||
34 | { | ||
35 | (void) url; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | UNIX Sendmail | ||
40 | sendmail:path | ||
41 | */ | ||
42 | int | ||
43 | url_sendmail_init (url_t url) | ||
44 | { | ||
45 | const char *name = url_to_string (url); | ||
46 | size_t len = strlen (name); | ||
47 | |||
48 | /* reject the obvious */ | ||
49 | if (name == NULL || strncmp (MU_SENDMAIL_SCHEME, name, MU_SENDMAIL_SCHEME_LEN) != 0 | ||
50 | || len < (MU_SENDMAIL_SCHEME_LEN + 1) /* (scheme)+1(path)*/) | ||
51 | return EINVAL; | ||
52 | |||
53 | /* do I need to decode url encoding '% hex hex' ? */ | ||
54 | |||
55 | /* TYPE */ | ||
56 | url->_init = url_sendmail_init; | ||
57 | url->_destroy = url_sendmail_destroy; | ||
58 | |||
59 | /* SCHEME */ | ||
60 | url->scheme = strdup (MU_SENDMAIL_SCHEME); | ||
61 | if (url->scheme == NULL) | ||
62 | { | ||
63 | url_sendmail_destroy (url); | ||
64 | return ENOMEM; | ||
65 | } | ||
66 | |||
67 | /* PATH */ | ||
68 | name += MU_SENDMAIL_SCHEME_LEN; /* pass the scheme */ | ||
69 | url->path = strdup (name); | ||
70 | if (url->path == NULL) | ||
71 | { | ||
72 | url_sendmail_destroy (url); | ||
73 | return ENOMEM; | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } |
mailbox/url_smtp.c
0 → 100644
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 Library General 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 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include <mailutils/registrar.h> | ||
27 | #include <url0.h> | ||
28 | |||
29 | int url_smtp_init (url_t purl); | ||
30 | static void url_smtp_destroy (url_t purl); | ||
31 | |||
32 | static void | ||
33 | url_smtp_destroy (url_t url) | ||
34 | { | ||
35 | (void) url; | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | UNIX File | ||
40 | file:path | ||
41 | */ | ||
42 | int | ||
43 | url_smtp_init (url_t url) | ||
44 | { | ||
45 | const char *name = url_to_string (url); | ||
46 | size_t len = strlen (name); | ||
47 | |||
48 | /* reject the obvious */ | ||
49 | if (name == NULL || strncmp (MU_SMTP_SCHEME, name, MU_SMTP_SCHEME_LEN) != 0 | ||
50 | || len < (MU_SMTP_SCHEME_LEN + 1) /* (scheme)+1(path)*/) | ||
51 | return EINVAL; | ||
52 | |||
53 | /* do I need to decode url encoding '% hex hex' ? */ | ||
54 | |||
55 | /* TYPE */ | ||
56 | url->_init = url_smtp_init; | ||
57 | url->_destroy = url_smtp_destroy; | ||
58 | |||
59 | /* SCHEME */ | ||
60 | url->scheme = strdup (MU_SMTP_SCHEME); | ||
61 | if (url->scheme == NULL) | ||
62 | { | ||
63 | url_smtp_destroy (url); | ||
64 | return ENOMEM; | ||
65 | } | ||
66 | |||
67 | /* PATH */ | ||
68 | name += MU_SMTP_SCHEME_LEN; /* pass the scheme */ | ||
69 | url->host = strdup (name); | ||
70 | if (url->host == NULL) | ||
71 | { | ||
72 | url_smtp_destroy (url); | ||
73 | return ENOMEM; | ||
74 | } | ||
75 | url->port = MU_SMTP_PORT; | ||
76 | |||
77 | return 0; | ||
78 | } |
-
Please register or sign in to post a comment