Commit 0d65dd09 0d65dd09b50588c3546bfe2a4131bd10fdd77a8f by Alain Magloire

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.
1 parent 9924892e
...@@ -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 */
......
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
......
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 */
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
19 #define _HEADER0_H 19 #define _HEADER0_H
20 20
21 #include <mailutils/header.h> 21 #include <mailutils/header.h>
22 #include <stream0.h>
23 #include <sys/types.h> 22 #include <sys/types.h>
24 23
25 #ifdef _cplusplus 24 #ifdef _cplusplus
......
...@@ -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 */
......
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
......
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 */
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 */
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 */
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 */
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 */
......
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
......
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 }
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
......
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 }
......
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)
......
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 }
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 **)&current);
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, &registrar[1] }, /* sentinel, head list */
35 { &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
36 { &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] },
37 { &_url_unix_registrar, &_mailbox_unix_registrar, 0, &registrar[4] },
38 { &_url_maildir_registrar, &_mailbox_maildir_registrar, 0, &registrar[5] },
39 { &_url_mmdf_registrar, &_mailbox_mmdf_registrar, 0, &registrar[6] },
40 { &_url_pop_registrar, &_mailbox_pop_registrar, 0, &registrar[7] },
41 { &_url_imap_registrar, &_mailbox_imap_registrar, 0, &registrar[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 (&reg_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 }
......
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 }
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, &reg) == 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 }
......
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 }
......
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 }
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 }