body.c mailer.c mbx_unixscan.c net.c tcp.c transcode.c
include/private/attribute0.h include/private/body0.h include/private/mailer0.h include/private/net0.h include/private/tcp.h include/public/body.h include/public/mailer.h include/public/net.h parsing and little of networking code, making a path for Pop and IMAP.
Showing
14 changed files
with
2492 additions
and
0 deletions
mailbox/body.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | |||
19 | #include <body0.h> | ||
20 | #include <io0.h> | ||
21 | |||
22 | #include <errno.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | |||
28 | static int body_read (stream_t is, char *buf, size_t buflen, | ||
29 | off_t off, size_t *pnread ); | ||
30 | static int body_write (stream_t os, const char *buf, size_t buflen, | ||
31 | off_t off, size_t *pnwrite); | ||
32 | static FILE *lazy_create (void); | ||
33 | static int body_get_fd (stream_t stream, int *pfd); | ||
34 | |||
35 | int | ||
36 | body_create (body_t *pbody, void *owner) | ||
37 | { | ||
38 | body_t body; | ||
39 | |||
40 | if (pbody == NULL || owner == NULL) | ||
41 | return EINVAL; | ||
42 | |||
43 | body = calloc (1, sizeof (*body)); | ||
44 | if (body == NULL) | ||
45 | return ENOMEM; | ||
46 | |||
47 | body->owner = owner; | ||
48 | *pbody = body; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | void | ||
53 | body_destroy (body_t *pbody, void *owner) | ||
54 | { | ||
55 | if (pbody && *pbody) | ||
56 | { | ||
57 | body_t body = *pbody; | ||
58 | if (body->owner == owner) | ||
59 | { | ||
60 | if (body->file) | ||
61 | { | ||
62 | fclose (body->file); | ||
63 | body->file = NULL; | ||
64 | } | ||
65 | free (body->filename); body->filename = NULL; | ||
66 | stream_destroy (&(body->stream), body); | ||
67 | } | ||
68 | *pbody = NULL; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | int | ||
73 | body_get_stream (body_t body, stream_t *pstream) | ||
74 | { | ||
75 | if (body == NULL || pstream == NULL) | ||
76 | return EINVAL; | ||
77 | |||
78 | if (body->stream == NULL) | ||
79 | { | ||
80 | stream_t stream; | ||
81 | int status; | ||
82 | /* lazy floating body it is created when | ||
83 | * doing the first body_write call | ||
84 | */ | ||
85 | status = stream_create (&stream, body); | ||
86 | if (status != 0) | ||
87 | return status; | ||
88 | stream_set_read (stream, body_read, body); | ||
89 | stream_set_write (stream, body_write, body); | ||
90 | stream_set_fd (stream, body_get_fd, body); | ||
91 | body->stream = stream; | ||
92 | } | ||
93 | |||
94 | *pstream = body->stream; | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | int | ||
99 | body_set_stream (body_t body, stream_t stream, void *owner) | ||
100 | { | ||
101 | if (body == NULL) | ||
102 | return EINVAL; | ||
103 | if (body->owner != owner) | ||
104 | return EACCES; | ||
105 | /* make sure we destroy the old one if it is own by the body */ | ||
106 | stream_destroy (&(body->stream), body); | ||
107 | if (body->file) | ||
108 | { | ||
109 | fclose (body->file); | ||
110 | body->file = NULL; | ||
111 | } | ||
112 | body->stream = stream; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | int | ||
117 | body_set_lines (body_t body, int (*_lines)(body_t, size_t *), void *owner) | ||
118 | { | ||
119 | if (body == NULL) | ||
120 | return EINVAL; | ||
121 | if (body->owner == owner) | ||
122 | return EACCES; | ||
123 | body->_lines = _lines; | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | int | ||
128 | body_lines (body_t body, size_t *plines) | ||
129 | { | ||
130 | if (body == NULL) | ||
131 | return EINVAL; | ||
132 | if (body->_lines) | ||
133 | return body->_lines (body, plines); | ||
134 | if (plines) | ||
135 | *plines = 0; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | int | ||
140 | body_size (body_t body, size_t *psize) | ||
141 | { | ||
142 | if (body == NULL) | ||
143 | return EINVAL; | ||
144 | |||
145 | /* Check to see if they want to doit themselves, | ||
146 | * it was probably not a floating message */ | ||
147 | if (body->_size) | ||
148 | return body->_size (body, psize); | ||
149 | |||
150 | /* ok we should handle this */ | ||
151 | if (body->file) | ||
152 | { | ||
153 | struct stat st; | ||
154 | if (fstat (fileno (body->file), &st) == -1) | ||
155 | return errno; | ||
156 | if (psize) | ||
157 | *psize = st.st_size; | ||
158 | } | ||
159 | else if (body->filename) | ||
160 | { | ||
161 | struct stat st; | ||
162 | if (stat (body->filename, &st) == -1) | ||
163 | return errno; | ||
164 | if (psize) | ||
165 | *psize = st.st_size; | ||
166 | } | ||
167 | else if (psize) | ||
168 | *psize = 0; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | int | ||
174 | body_set_size (body_t body, int (*_size)(body_t, size_t*) , void *owner) | ||
175 | { | ||
176 | if (body == NULL) | ||
177 | return EINVAL; | ||
178 | if (body->owner != owner) | ||
179 | return EACCES; | ||
180 | body->_size = _size; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int | ||
185 | body_read (stream_t is, char *buf, size_t buflen, | ||
186 | off_t off, size_t *pnread ) | ||
187 | { | ||
188 | body_t body; | ||
189 | size_t nread = 0; | ||
190 | |||
191 | if (is == NULL || (body = is->owner) == NULL) | ||
192 | return EINVAL; | ||
193 | |||
194 | /* check if they want to read from a file */ | ||
195 | if (body->file == NULL && body->filename) | ||
196 | { | ||
197 | /* try read only, we don't want to | ||
198 | * handle nasty security issues here. | ||
199 | */ | ||
200 | body->file = fopen (body->filename, "r"); | ||
201 | if (body->file == NULL) | ||
202 | { | ||
203 | if (pnread) | ||
204 | *pnread = 0; | ||
205 | return errno; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (body->file) | ||
210 | { | ||
211 | /* should we check the error of fseek for some handlers | ||
212 | * like socket where fseek () will fail. | ||
213 | * FIXME: Alternative is to check fseeck and errno == EBADF | ||
214 | * if not a seekable stream. | ||
215 | */ | ||
216 | if (fseek (body->file, off, SEEK_SET) == -1) | ||
217 | return errno; | ||
218 | |||
219 | nread = fread (buf, sizeof (char), buflen, body->file); | ||
220 | if (nread == 0) | ||
221 | { | ||
222 | if (ferror (body->file)) | ||
223 | return errno; | ||
224 | /* clear the error for feof() */ | ||
225 | clearerr (body->file); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if (pnread) | ||
230 | *pnread = nread; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int | ||
235 | body_write (stream_t os, const char *buf, size_t buflen, | ||
236 | off_t off, size_t *pnwrite) | ||
237 | { | ||
238 | body_t body; | ||
239 | size_t nwrite = 0; | ||
240 | |||
241 | if (os == NULL || (body = os->owner) == NULL) | ||
242 | return EINVAL; | ||
243 | |||
244 | /* FIXME: security issues, Refuse to write to an unknow file */ | ||
245 | if (body->file == NULL && body->filename) | ||
246 | return EINVAL; | ||
247 | |||
248 | /* Probably being lazy, then create a body for the stream */ | ||
249 | if (body->file == NULL) | ||
250 | { | ||
251 | body->file = lazy_create (); | ||
252 | if (body->file == NULL) | ||
253 | return errno; | ||
254 | } | ||
255 | |||
256 | /* should we check the error of fseek for some handlers | ||
257 | * like socket where it does not make sense. | ||
258 | * FIXME: Alternative is to check fseeck and errno == EBADF | ||
259 | * if not a seekable stream. | ||
260 | */ | ||
261 | if (fseek (body->file, off, SEEK_SET) == -1) | ||
262 | return errno; | ||
263 | |||
264 | nwrite = fwrite (buf, sizeof (char), buflen, body->file); | ||
265 | if (nwrite == 0) | ||
266 | { | ||
267 | if (ferror (body->file)) | ||
268 | return errno; | ||
269 | /* clear the error for feof() */ | ||
270 | clearerr (body->file); | ||
271 | } | ||
272 | |||
273 | if (pnwrite) | ||
274 | *pnwrite = nwrite; | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int | ||
279 | body_get_fd (stream_t stream, int *pfd) | ||
280 | { | ||
281 | body_t body; | ||
282 | |||
283 | if (stream == NULL || (body = stream->owner) == NULL) | ||
284 | return EINVAL; | ||
285 | |||
286 | /* Probably being lazy, then create a body for the stream */ | ||
287 | if (body->file == NULL) | ||
288 | { | ||
289 | body->file = lazy_create (); | ||
290 | if (body->file == 0) | ||
291 | return errno; | ||
292 | } | ||
293 | |||
294 | if (pfd) | ||
295 | *pfd = fileno (body->file); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static FILE * | ||
300 | lazy_create () | ||
301 | { | ||
302 | FILE *file; | ||
303 | #ifdef HAVE_MKSTEMP | ||
304 | char tmpbuf[L_tmpnam + 1]; | ||
305 | int fd; | ||
306 | |||
307 | if (tmpnam (tmpbuf) == NULL || | ||
308 | (fd = mkstemp (tmpbuf)) == -1 || | ||
309 | (file = fdopen(fd, "w+")) == NULL) | ||
310 | return NULL; | ||
311 | (void)remove(tmpbuf); | ||
312 | #else | ||
313 | file = tmpfile (); | ||
314 | /* make sure the mode is right */ | ||
315 | if (file) | ||
316 | fchmod (fileno (file), 0600); | ||
317 | #endif | ||
318 | return file; | ||
319 | } |
mailbox/include/private/attribute0.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #ifndef _ATTRIBUTE0_H | ||
19 | # define _ATTRIBUTE0_H | ||
20 | |||
21 | #include <attribute.h> | ||
22 | |||
23 | #ifdef __cplusplus | ||
24 | extern "C" { | ||
25 | #endif | ||
26 | |||
27 | #ifndef __P | ||
28 | # ifdef __STDC__ | ||
29 | # define __P(args) args | ||
30 | # else | ||
31 | # define __P(args) () | ||
32 | # endif | ||
33 | #endif /*__P */ | ||
34 | |||
35 | struct _attribute | ||
36 | { | ||
37 | size_t flag; | ||
38 | void *owner; | ||
39 | }; | ||
40 | |||
41 | #define MU_ATTRIBUTE_SEEN ((int)1) | ||
42 | #define MU_ATTRIBUTE_ANSWERED (MU_ATTRIBUTE_SEEN << 1) | ||
43 | #define MU_ATTRIBUTE_FLAGGED (MU_ATTRIBUTE_ANSWERED << 1) | ||
44 | #define MU_ATTRIBUTE_DELETED (MU_ATTRIBUTE_FLAGGED << 1) | ||
45 | #define MU_ATTRIBUTE_DRAFT (MU_ATTRIBUTE_DELETED << 1) | ||
46 | #define MU_ATTRIBUTE_RECENT (MU_ATTRIBUTE_DRAFT << 1) | ||
47 | #define MU_ATTRIBUTE_READ (MU_ATTRIBUTE_RECENT << 1) | ||
48 | |||
49 | #ifdef __cplusplus | ||
50 | } | ||
51 | #endif | ||
52 | |||
53 | #endif /* _ATTRIBUTE0_H */ |
mailbox/include/private/body0.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #ifndef _BODY0_H | ||
19 | #define _BODY0_H | ||
20 | |||
21 | #include <io.h> | ||
22 | #include <body.h> | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <sys/types.h> | ||
26 | |||
27 | #ifndef __P | ||
28 | # ifdef __STDC__ | ||
29 | # define __P(args) args | ||
30 | # else | ||
31 | # define __P(args) () | ||
32 | # endif | ||
33 | #endif /* __P */ | ||
34 | |||
35 | #ifdef _cplusplus | ||
36 | extern "C" { | ||
37 | #endif | ||
38 | |||
39 | struct _body | ||
40 | { | ||
41 | void *owner; | ||
42 | |||
43 | /* it's better and more portable to use stdio */ | ||
44 | FILE *file; | ||
45 | char *filename; | ||
46 | stream_t stream; | ||
47 | int (*_size) (body_t, size_t*); | ||
48 | int (*_lines) (body_t, size_t*); | ||
49 | }; | ||
50 | |||
51 | #ifdef _cplusplus | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | #endif /* _BODY0_H */ |
mailbox/include/private/mailer0.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU 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 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 _MAILER0_H | ||
19 | #define _MAILER0_H | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | #include <mailer.h> | ||
23 | |||
24 | #ifdef _cplusplus | ||
25 | extern "C" { | ||
26 | #endif | ||
27 | |||
28 | #ifndef __P | ||
29 | # ifdef __STDC__ | ||
30 | # define __P(args) args | ||
31 | # else | ||
32 | # define __P(args) () | ||
33 | # endif | ||
34 | #endif /*__P */ | ||
35 | |||
36 | // mailer states | ||
37 | #define MAILER_STATE_HDR 1 | ||
38 | #define MAILER_STATE_MSG 2 | ||
39 | #define MAILER_STATE_COMPLETE 3 | ||
40 | |||
41 | // mailer messages | ||
42 | #define MAILER_HELO 1 | ||
43 | #define MAILER_MAIL 2 | ||
44 | #define MAILER_RCPT 3 | ||
45 | #define MAILER_DATA 4 | ||
46 | #define MAILER_RSET 5 | ||
47 | #define MAILER_QUIT 6 | ||
48 | |||
49 | #define MAILER_LINE_BUF_SIZE 1000 | ||
50 | |||
51 | struct _mailer | ||
52 | { | ||
53 | int socket; | ||
54 | char *hostname; | ||
55 | char line_buf[MAILER_LINE_BUF_SIZE]; | ||
56 | int offset; | ||
57 | int state; | ||
58 | int add_dot; | ||
59 | stream_t stream; | ||
60 | char last_char; | ||
61 | }; | ||
62 | |||
63 | #ifdef _cplusplus | ||
64 | } | ||
65 | #endif | ||
66 | |||
67 | #endif /* MAILER0_H */ |
mailbox/include/private/net0.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU 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 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 _NET0_H | ||
19 | #define _NET0_H | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | |||
23 | #include <io.h> | ||
24 | #include <net.h> | ||
25 | |||
26 | #ifdef _cplusplus | ||
27 | extern "C" { | ||
28 | #endif | ||
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 | |||
39 | struct _net_api { | ||
40 | int (*new)(void *netdata, net_t parent, void **data); | ||
41 | int (*connect)(void *data, const char *host, int port); | ||
42 | int (*get_stream)(void *data, stream_t *iostr); | ||
43 | int (*close)(void *data); | ||
44 | int (*free)(void **data); | ||
45 | }; | ||
46 | |||
47 | struct _netregistrar { | ||
48 | const char *type; | ||
49 | |||
50 | int (*create)(void **netdata, struct _net_api **api); | ||
51 | int (*set_option)(void *netdata, const char *name, const char *value); | ||
52 | int (*destroy)(void **netdata); | ||
53 | }; | ||
54 | |||
55 | struct _net { | ||
56 | struct _net_api *api; | ||
57 | void *data; | ||
58 | struct _net *parent; | ||
59 | |||
60 | struct _netregistrar *net_reg; | ||
61 | }; | ||
62 | |||
63 | struct _netinstance { | ||
64 | struct _net_api *api; | ||
65 | void *data; | ||
66 | }; | ||
67 | |||
68 | int _tcp_create(void **data, struct _net_api **api); | ||
69 | int _tcp_set_option(void *data, const char *name, const char *value); | ||
70 | int _tcp_destroy(void **data); | ||
71 | |||
72 | #ifdef _cplusplus | ||
73 | } | ||
74 | #endif | ||
75 | |||
76 | #endif /* NET0_H */ |
mailbox/include/private/tcp.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU 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 General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #include <net0.h> | ||
19 | |||
20 | #define TCP_STATE_INIT 1 | ||
21 | #define TCP_STATE_RESOLVE 2 | ||
22 | #define TCP_STATE_RESOLVING 3 | ||
23 | #define TCP_STATE_CONNECTING 4 | ||
24 | #define TCP_STATE_CONNECTED 5 | ||
25 | |||
26 | struct _tcp_options { | ||
27 | int non_block; | ||
28 | int net_timeout; | ||
29 | }; | ||
30 | |||
31 | struct _tcp_instance { | ||
32 | struct _tcp_options *options; | ||
33 | int fd; | ||
34 | char *host; | ||
35 | int port; | ||
36 | int state; | ||
37 | stream_t stream; | ||
38 | unsigned long address; | ||
39 | }; |
mailbox/include/public/body.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #ifndef _BODY_H | ||
19 | #define _BODY_H | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | #include <io.h> | ||
23 | |||
24 | #ifndef __P | ||
25 | # ifdef __STDC__ | ||
26 | # define __P(args) args | ||
27 | # else | ||
28 | # define __P(args) () | ||
29 | # endif | ||
30 | #endif /* __P */ | ||
31 | |||
32 | #ifdef _cplusplus | ||
33 | extern "C" { | ||
34 | #endif | ||
35 | |||
36 | /* forward declaration */ | ||
37 | struct _body; | ||
38 | typedef struct _body *body_t; | ||
39 | |||
40 | extern int body_create __P ((body_t *, void *owner)); | ||
41 | extern void body_destroy __P ((body_t *, void *owner)); | ||
42 | |||
43 | extern int body_get_stream __P ((body_t, stream_t *)); | ||
44 | extern int body_set_stream __P ((body_t, stream_t, void *owner)); | ||
45 | |||
46 | extern int body_get_filename __P ((body_t, char *, size_t, size_t *)); | ||
47 | extern int body_set_filename __P ((body_t, const char*)); | ||
48 | |||
49 | extern int body_size __P ((body_t, size_t*)); | ||
50 | extern int body_set_size __P ((body_t, | ||
51 | int (*_size) __P ((body_t, size_t*)), | ||
52 | void *owner)); | ||
53 | extern int body_lines __P ((body_t, size_t *)); | ||
54 | extern int body_set_lines __P ((body_t, | ||
55 | int (*_lines) __P ((body_t, size_t*)), | ||
56 | void *owner)); | ||
57 | |||
58 | #ifdef _cplusplus | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | #endif /* _BODY_H */ |
mailbox/include/public/mailer.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU 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 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 _MAILER_H | ||
19 | #define _MAILER_H | ||
20 | |||
21 | #include "message.h" | ||
22 | #include <sys/types.h> | ||
23 | |||
24 | #ifndef __P | ||
25 | # ifdef __STDC__ | ||
26 | # define __P(args) args | ||
27 | # else | ||
28 | # define __P(args) () | ||
29 | # endif | ||
30 | #endif /* __P */ | ||
31 | |||
32 | #ifdef _cplusplus | ||
33 | extern "C" { | ||
34 | #endif | ||
35 | |||
36 | /* forward declaration */ | ||
37 | struct _mailer; | ||
38 | typedef struct _mailer *mailer_t; | ||
39 | |||
40 | extern int mailer_create __P ((mailer_t *, message_t)); | ||
41 | extern int mailer_connect __P ((mailer_t, char *host)); | ||
42 | extern int mailer_disconnect __P ((mailer_t)); | ||
43 | extern int mailer_send_header __P ((mailer_t, message_t)); | ||
44 | extern int mailer_send_message __P ((mailer_t, message_t)); | ||
45 | |||
46 | #ifdef _cplusplus | ||
47 | } | ||
48 | #endif | ||
49 | |||
50 | #endif /* _MAILER_H */ |
mailbox/include/public/net.h
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU 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 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 _NET_H | ||
19 | #define _NET_H | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | |||
23 | #include <io.h> | ||
24 | |||
25 | #ifdef _cplusplus | ||
26 | extern "C" { | ||
27 | #endif | ||
28 | |||
29 | #ifndef __P | ||
30 | #ifdef __STDC__ | ||
31 | #define __P(args) args | ||
32 | #else | ||
33 | #define __P(args) () | ||
34 | #endif | ||
35 | #endif /*__P */ | ||
36 | |||
37 | struct _net; | ||
38 | typedef struct _net *net_t; | ||
39 | |||
40 | extern int net_api_create __P((net_t *, net_t, const char *type)); | ||
41 | extern int net_api_set_option __P((net_t net, const char *name, const char *value)); | ||
42 | extern int net_api_destroy __P((net_t *)); | ||
43 | |||
44 | struct _netinstance; | ||
45 | typedef struct _netinstance *netinstance_t; | ||
46 | |||
47 | extern int net_new __P((net_t, netinstance_t *)); | ||
48 | extern int net_connect __P((netinstance_t, const char *host, int port)); | ||
49 | extern int net_get_stream __P((netinstance_t, stream_t *iostr)); | ||
50 | extern int net_close __P((netinstance_t)); | ||
51 | extern int net_free __P((netinstance_t *)); | ||
52 | |||
53 | #ifdef _cplusplus | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | #endif /* NET_H */ |
mailbox/mailer.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #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> | ||
28 | #include <stdarg.h> | ||
29 | #include <fcntl.h> | ||
30 | #include <ctype.h> | ||
31 | |||
32 | #include <mailer0.h> | ||
33 | |||
34 | int _mailer_sock_connect(char *host, int port); | ||
35 | char *_mailer_find_mailbox(char *addr); | ||
36 | int _mailer_send_command(mailer_t ml, message_t msg, int cmd); | ||
37 | char *nb_fgets(char *buf, int size, int s); | ||
38 | char *nb_fprintf(int s, char *format, ...); | ||
39 | |||
40 | #define nb_read read | ||
41 | #define nb_write write | ||
42 | #define BUFFSIZE 4096 | ||
43 | |||
44 | int | ||
45 | mailer_create(mailer_t *pml, message_t msg) | ||
46 | { | ||
47 | mailer_t ml; | ||
48 | |||
49 | (void)msg; | ||
50 | if (!pml) | ||
51 | return EINVAL; | ||
52 | |||
53 | ml = calloc (1, sizeof (*ml)); | ||
54 | if (ml == NULL) | ||
55 | return (ENOMEM); | ||
56 | |||
57 | *pml = ml; | ||
58 | |||
59 | return (0); | ||
60 | } | ||
61 | |||
62 | int | ||
63 | mailer_destroy(mailer_t *pml) | ||
64 | { | ||
65 | mailer_t ml; | ||
66 | |||
67 | if (!pml) | ||
68 | return (EINVAL); | ||
69 | ml = *pml; | ||
70 | if (ml->hostname) | ||
71 | free(ml->hostname); | ||
72 | mailer_disconnect(ml); | ||
73 | free(ml); | ||
74 | *pml = NULL; | ||
75 | |||
76 | return (0); | ||
77 | } | ||
78 | |||
79 | int | ||
80 | mailer_connect(mailer_t ml, char *host) | ||
81 | { | ||
82 | if (!ml || !host) | ||
83 | return (EINVAL); | ||
84 | |||
85 | if ((ml->socket = _mailer_sock_connect(host, 25)) < 0) | ||
86 | return (-1); | ||
87 | do | ||
88 | { | ||
89 | nb_fgets(ml->line_buf, MAILER_LINE_BUF_SIZE, ml->socket); /* read header line */ | ||
90 | } while ( strlen(ml->line_buf) > 4 && *(ml->line_buf+3) == '-'); | ||
91 | |||
92 | return (0); | ||
93 | } | ||
94 | |||
95 | int | ||
96 | mailer_disconnect(mailer_t ml) | ||
97 | { | ||
98 | if (!ml || (ml->socket != -1)) | ||
99 | return (EINVAL); | ||
100 | |||
101 | close(ml->socket); | ||
102 | return (0); | ||
103 | } | ||
104 | |||
105 | int | ||
106 | mailer_send_header(mailer_t ml, message_t msg) | ||
107 | { | ||
108 | header_t hdr; | ||
109 | char buf[64]; | ||
110 | |||
111 | if (!ml || !msg || (ml->socket == -1)) | ||
112 | return (EINVAL); | ||
113 | |||
114 | if (!ml->hostname) | ||
115 | { | ||
116 | if (gethostname(buf, 64) < 0) | ||
117 | return (-1); | ||
118 | ml->hostname = strdup(buf); | ||
119 | } | ||
120 | |||
121 | if (_mailer_send_command(ml, msg, MAILER_HELO) != 0) | ||
122 | return (-1); | ||
123 | if (_mailer_send_command(ml, msg, MAILER_MAIL) != 0) | ||
124 | return (-1); | ||
125 | if (_mailer_send_command(ml, msg, MAILER_RCPT) != 0) | ||
126 | return (-1); | ||
127 | if (_mailer_send_command(ml, msg, MAILER_DATA) != 0) | ||
128 | return (-1); | ||
129 | |||
130 | message_get_header(msg, &hdr); | ||
131 | header_get_stream(hdr, &(ml->stream)); | ||
132 | |||
133 | ml->state = MAILER_STATE_HDR; | ||
134 | |||
135 | return (0); | ||
136 | } | ||
137 | |||
138 | int | ||
139 | mailer_send_message(mailer_t ml, message_t msg) | ||
140 | { | ||
141 | int status, len = 0, data_len = 0, consumed = 0; | ||
142 | char *data, *p, *q; | ||
143 | |||
144 | if (!ml || !msg || (ml->socket == -1)) | ||
145 | return (EINVAL); | ||
146 | |||
147 | // alloca | ||
148 | if (!(data = alloca(MAILER_LINE_BUF_SIZE))) | ||
149 | return (ENOMEM); | ||
150 | |||
151 | memset(data, 0, 1000); | ||
152 | if ((status = stream_read(ml->stream, data, MAILER_LINE_BUF_SIZE, ml->offset, &len)) != 0) | ||
153 | return (-1); | ||
154 | |||
155 | if ((len == 0) && (ml->state == MAILER_STATE_HDR)) | ||
156 | { | ||
157 | ml->state = MAILER_STATE_MSG; | ||
158 | ml->offset = 0; | ||
159 | message_get_stream(msg, &(ml->stream)); | ||
160 | return (1); | ||
161 | } | ||
162 | else if (len == 0) | ||
163 | { | ||
164 | strcpy(ml->line_buf, "\r\n.\r\n"); | ||
165 | consumed = strlen(data); | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | p = data; | ||
170 | q = ml->line_buf; | ||
171 | memset(ml->line_buf, 0, MAILER_LINE_BUF_SIZE); | ||
172 | while (consumed < len) | ||
173 | { | ||
174 | // RFC821: if the first character on a line is a '.' you must add an | ||
175 | // extra '.' to the line which will get stipped off at the other end | ||
176 | if ((*p == '.') && (ml->last_char == '\n')) | ||
177 | ml->add_dot = 1; | ||
178 | ml->last_char = *p; | ||
179 | *q++ = *p++; // store the character | ||
180 | data_len++; // increase the length by 1 | ||
181 | consumed++; | ||
182 | if (((MAILER_LINE_BUF_SIZE - data_len) > 1) && (ml->add_dot == 1)) | ||
183 | { | ||
184 | *q++ = '.'; | ||
185 | data_len++; | ||
186 | ml->add_dot = 0; | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | ml->offset += consumed; | ||
192 | nb_fprintf(ml->socket, "%s\r\n", ml->line_buf); | ||
193 | |||
194 | if (len == 0) | ||
195 | { | ||
196 | ml->state = MAILER_STATE_COMPLETE; | ||
197 | return (0); | ||
198 | } | ||
199 | |||
200 | return (consumed); | ||
201 | } | ||
202 | |||
203 | int | ||
204 | _mailer_sock_connect(char *host, int port) | ||
205 | { | ||
206 | struct sockaddr_in saddr; | ||
207 | struct hostent *hp; | ||
208 | int s; | ||
209 | |||
210 | memset(&saddr, 0, sizeof(struct sockaddr_in)); | ||
211 | saddr.sin_family = AF_INET; | ||
212 | saddr.sin_port = htons(port); | ||
213 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) | ||
214 | return (-1); | ||
215 | if ((hp = gethostbyname(host)) == 0) | ||
216 | return (-1); | ||
217 | memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); | ||
218 | if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) == 0) | ||
219 | return (s); | ||
220 | close(s); | ||
221 | |||
222 | return (-1); | ||
223 | } | ||
224 | |||
225 | char * | ||
226 | _mailer_find_mailbox(char *addr) | ||
227 | { | ||
228 | char *p, *c; | ||
229 | p = addr; | ||
230 | if ( (c = strchr( p, '<')) != 0) | ||
231 | { | ||
232 | p = c+1; | ||
233 | if ( c = strchr( p, '>')) | ||
234 | *c = '\0'; | ||
235 | } | ||
236 | else if ( (c = strchr( p, '(' )) != 0 ) | ||
237 | { | ||
238 | --c; | ||
239 | while ( c > p && *c && isspace( *c ) ) { | ||
240 | *c = '\0'; | ||
241 | --c; | ||
242 | } | ||
243 | } | ||
244 | return p; | ||
245 | } | ||
246 | |||
247 | int | ||
248 | _mailer_rctp(mailer_t ml, char *str) | ||
249 | { | ||
250 | char *p, *c = NULL, *q = NULL; | ||
251 | |||
252 | for (q = p = str; q && *p; p = q+1) | ||
253 | { | ||
254 | if ( q = strchr( p, ',')) | ||
255 | *q = '\0'; | ||
256 | while ( p && *p && isspace( *p ) ) | ||
257 | p++; | ||
258 | c = strdup(p); | ||
259 | p = _mailer_find_mailbox(c); | ||
260 | nb_fprintf(ml->socket, "RCPT TO:<%s>\r\n", p); | ||
261 | free(c); | ||
262 | nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket); | ||
263 | if (strncmp(ml->line_buf, "250", 3)) | ||
264 | return (-strtol(ml->line_buf, 0, 10)); | ||
265 | } | ||
266 | return (0); | ||
267 | } | ||
268 | |||
269 | int | ||
270 | _mailer_send_command(mailer_t ml, message_t msg, int cmd) | ||
271 | { | ||
272 | header_t hdr; | ||
273 | char *p, *c = NULL, *q = NULL; | ||
274 | char str[128]; | ||
275 | size_t str_len; | ||
276 | char *success = "250"; | ||
277 | |||
278 | switch (cmd) | ||
279 | { | ||
280 | case MAILER_HELO: | ||
281 | nb_fprintf(ml->socket, "HELO %s\r\n", ml->hostname); | ||
282 | break; | ||
283 | case MAILER_MAIL: | ||
284 | message_get_header(msg, &hdr); | ||
285 | header_get_value(hdr, MU_HEADER_FROM, str, 128, &str_len); | ||
286 | str[str_len] = '\0'; | ||
287 | p = _mailer_find_mailbox(str); | ||
288 | nb_fprintf(ml->socket, "MAIL From: %s\r\n", p); | ||
289 | break; | ||
290 | case MAILER_RCPT: | ||
291 | message_get_header(msg, &hdr); | ||
292 | header_get_value(hdr, MU_HEADER_TO, str, 128, &str_len); | ||
293 | str[str_len] = '\0'; | ||
294 | if (_mailer_rctp(ml, str) == -1) | ||
295 | return (-1); | ||
296 | header_get_value(hdr, MU_HEADER_CC, str, 128, &str_len); | ||
297 | str[str_len] = '\0'; | ||
298 | if (_mailer_rctp(ml, str) == -1) | ||
299 | return (-1); | ||
300 | return (0); | ||
301 | break; | ||
302 | case MAILER_DATA: | ||
303 | nb_fprintf(ml->socket, "DATA\r\n"); | ||
304 | success = "354"; | ||
305 | break; | ||
306 | case MAILER_RSET: | ||
307 | nb_fprintf(ml->socket, "RSET\r\n"); | ||
308 | break; | ||
309 | case MAILER_QUIT: | ||
310 | nb_fprintf(ml->socket, "QUIT\r\n"); | ||
311 | success = "221"; | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket); | ||
316 | if (strncmp(ml->line_buf, success, 3) == 0) | ||
317 | return (0); | ||
318 | else | ||
319 | return (-strtol(ml->line_buf, 0, 10)); | ||
320 | } | ||
321 | |||
322 | char * | ||
323 | nb_fgets( char *buf, int size, int s ) | ||
324 | { | ||
325 | static char *buffer[25]; | ||
326 | char *p, *b, *d; | ||
327 | int bytes, i; | ||
328 | int flags; | ||
329 | |||
330 | if ( !buffer[s] && !( buffer[s] = calloc( BUFFSIZE+1, 1 ) ) ) | ||
331 | return 0; | ||
332 | bytes = i = strlen( p = b = buffer[s] ); | ||
333 | *( d = buf ) = '\0'; | ||
334 | for ( ; i-- > 0; p++ ) | ||
335 | { | ||
336 | if ( *p == '\n' ) | ||
337 | { | ||
338 | char c = *( p+1 ); | ||
339 | |||
340 | *( p+1 ) = '\0'; | ||
341 | strcat( d, b ); | ||
342 | *( p+1 ) = c; | ||
343 | memmove( b, p+1, i+1 ); | ||
344 | return buf; | ||
345 | } | ||
346 | } | ||
347 | flags = fcntl( s, F_GETFL ); | ||
348 | fcntl( s, F_SETFL, O_NONBLOCK ); | ||
349 | while ( bytes <= size ) | ||
350 | { | ||
351 | fd_set fds; | ||
352 | |||
353 | FD_ZERO( &fds ); | ||
354 | FD_SET( s, &fds ); | ||
355 | select( s+1, &fds, 0, 0, 0 ); /* we really don't care what it returns */ | ||
356 | if ( ( i = nb_read( s, p, BUFFSIZE - bytes ) ) == -1 ) | ||
357 | { | ||
358 | *b = '\0'; | ||
359 | return 0; | ||
360 | } | ||
361 | else if ( i == 0 ) | ||
362 | { | ||
363 | *( p+1 ) = '\0'; | ||
364 | strcat( d, b ); | ||
365 | *b = '\0'; | ||
366 | fcntl( s, F_SETFL, flags ); | ||
367 | return strlen( buf ) ? buf : 0; | ||
368 | } | ||
369 | *( p+i ) = '\0'; | ||
370 | bytes += i; | ||
371 | for ( ; i-- > 0; p++ ) | ||
372 | { | ||
373 | if ( *p == '\n' ) | ||
374 | { | ||
375 | char c = *( p+1 ); | ||
376 | |||
377 | *( p+1 ) = '\0'; | ||
378 | strcat( d, b ); | ||
379 | *( p+1 ) = c; | ||
380 | memmove( b, p+1, i+1 ); | ||
381 | fcntl( s, F_SETFL, flags ); | ||
382 | return buf; | ||
383 | } | ||
384 | } | ||
385 | if ( bytes == BUFFSIZE ) | ||
386 | { | ||
387 | memcpy( d, b, BUFFSIZE ); | ||
388 | d += BUFFSIZE; | ||
389 | size -= BUFFSIZE; | ||
390 | bytes = 0; | ||
391 | *( p = b ) = '\0'; | ||
392 | } | ||
393 | } | ||
394 | memcpy( d, b, size ); | ||
395 | memmove( b, b+size, strlen( b+size )+1 ); | ||
396 | fcntl( s, F_SETFL, flags ); | ||
397 | return buf; | ||
398 | } | ||
399 | |||
400 | char * | ||
401 | nb_fprintf( int s, char *format, ... ) | ||
402 | { | ||
403 | char buf[MAILER_LINE_BUF_SIZE]; | ||
404 | va_list vl; | ||
405 | int i; | ||
406 | |||
407 | va_start( vl, format ); | ||
408 | vsprintf( buf, format, vl ); | ||
409 | va_end( vl ); | ||
410 | i = strlen( buf ); | ||
411 | if ( nb_write( s, buf, i ) != i ) | ||
412 | return 0; | ||
413 | return format; | ||
414 | } |
mailbox/mbx_unixscan.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | /* Credits to the c-client and its Authors | ||
19 | * The notorius c-client VALID() macro, was written by Mark Crispin. | ||
20 | */ | ||
21 | |||
22 | /* Parsing. | ||
23 | * The approach is to detect the "From " as start of a | ||
24 | * new message, give the position of the header and scan | ||
25 | * until "\n" then set header_end, set body position, if we have | ||
26 | * a Content-Length field jump to the point if not | ||
27 | * scan until we it another "From " and set body_end. | ||
28 | * | ||
29 | ************************************ | ||
30 | * This is a classic case of premature optimisation | ||
31 | * being the root of all Evil(Donald E. Knuth). | ||
32 | * But I'm under "pressure" ;-) to come with | ||
33 | * something "faster". I think it's wastefull | ||
34 | * to spend time to gain a few seconds on 30Megs mailboxes | ||
35 | * ... but then again ... in computer time, 60 seconds, is eternity. | ||
36 | * | ||
37 | * If they use the event notification stuff | ||
38 | * to get some headers/messages early ... it's like pissing | ||
39 | * in the wind(sorry don't have the english equivalent). | ||
40 | * The worst is progress_bar it should be ... &*($^ nuke. | ||
41 | * For the events, we have to remove the *.LCK file, | ||
42 | * release the locks, flush the stream save the pointers | ||
43 | * etc ... hurry and wait... | ||
44 | * I this point I'm pretty much ranting. | ||
45 | * | ||
46 | */ | ||
47 | |||
48 | /* From the C-Client, part of pine */ | ||
49 | /* You are not expected to understand this macro, but read the next page if | ||
50 | * you are not faint of heart. | ||
51 | * | ||
52 | * Known formats to the VALID macro are: | ||
53 | * From user Wed Dec 2 05:53 1992 | ||
54 | * BSD From user Wed Dec 2 05:53:22 1992 | ||
55 | * SysV From user Wed Dec 2 05:53 PST 1992 | ||
56 | * rn From user Wed Dec 2 05:53:22 PST 1992 | ||
57 | * From user Wed Dec 2 05:53 -0700 1992 | ||
58 | * From user Wed Dec 2 05:53:22 -0700 1992 | ||
59 | * From user Wed Dec 2 05:53 1992 PST | ||
60 | * From user Wed Dec 2 05:53:22 1992 PST | ||
61 | * From user Wed Dec 2 05:53 1992 -0700 | ||
62 | * Solaris From user Wed Dec 2 05:53:22 1992 -0700 | ||
63 | * | ||
64 | * Plus all of the above with `` remote from xxx'' after it. Thank you very | ||
65 | * much, smail and Solaris, for making my life considerably more complicated. | ||
66 | */ | ||
67 | /* | ||
68 | * What? You want to understand the VALID macro anyway? Alright, since you | ||
69 | * insist. Actually, it isn't really all that difficult, provided that you | ||
70 | * take it step by step. | ||
71 | * | ||
72 | * Line 1 Initializes the return ti value to failure (0); | ||
73 | * Lines 2-3 Validates that the 1st-5th characters are ``From ''. | ||
74 | * Lines 4-6 Validates that there is an end of line and points x at it. | ||
75 | * Lines 7-14 First checks to see if the line is at least 41 characters long | ||
76 | . | ||
77 | * If so, it scans backwards to find the rightmost space. From | ||
78 | * that point, it scans backwards to see if the string matches | ||
79 | * `` remote from''. If so, it sets x to point to the space at | ||
80 | * the start of the string. | ||
81 | * Line 15 Makes sure that there are at least 27 characters in the line. | ||
82 | * Lines 16-21 Checks if the date/time ends with the year (there is a space | ||
83 | * five characters back). If there is a colon three characters | ||
84 | * further back, there is no timezone field, so zn is set to 0 | ||
85 | * and ti is set in front of the year. Otherwise, there must | ||
86 | * either to be a space four characters back for a three-letter | ||
87 | * timezone, or a space six characters back followed by a + or - | ||
88 | * for a numeric timezone; in either case, zn and ti become the | ||
89 | * offset of the space immediately before it. | ||
90 | * Lines 22-24 Are the failure case for line 14. If there is a space four | ||
91 | * characters back, it is a three-letter timezone; there must be | ||
92 | a | ||
93 | * space for the year nine characters back. zn is the zone | ||
94 | * offset; ti is the offset of the space. | ||
95 | * Lines 25-28 Are the failure case for line 20. If there is a space six | ||
96 | * characters back, it is a numeric timezone; there must be a | ||
97 | * space eleven characters back and a + or - five characters back | ||
98 | . | ||
99 | * zn is the zone offset; ti is the offset of the space. | ||
100 | * Line 29-32 If ti is valid, make sure that the string before ti is of the | ||
101 | * form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise | ||
102 | * invalidate ti. There must be a colon three characters back | ||
103 | * and a space six or nine characters back (depending upon | ||
104 | * whether or not the character six characters back is a colon). | ||
105 | * There must be a space three characters further back (in front | ||
106 | * of the day), one seven characters back (in front of the month) | ||
107 | , | ||
108 | * and one eleven characters back (in front of the day of week). | ||
109 | * ti is set to be the offset of the space before the time. | ||
110 | * | ||
111 | * Why a macro? It gets invoked a *lot* in a tight loop. On some of the | ||
112 | * newer pipelined machines it is faster being open-coded than it would be if | ||
113 | * subroutines are called. | ||
114 | * | ||
115 | * Why does it scan backwards from the end of the line, instead of doing the | ||
116 | * much easier forward scan? There is no deterministic way to parse the | ||
117 | * ``user'' field, because it may contain unquoted spaces! Yes, I tested it t | ||
118 | o | ||
119 | * see if unquoted spaces were possible. They are, and I've encountered enoug | ||
120 | h | ||
121 | * evil mail to be totally unwilling to trust that ``it will never happen''. | ||
122 | */ | ||
123 | #define VALID(s,x,ti,zn) { \ | ||
124 | ti = 0; \ | ||
125 | if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \ | ||
126 | (s[4] == ' ')) { \ | ||
127 | for (x = s + 5; *x && *x != '\n'; x++); \ | ||
128 | if (x) { \ | ||
129 | if (x - s >= 41) { \ | ||
130 | for (zn = -1; x[zn] != ' '; zn--); \ | ||
131 | if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \ | ||
132 | (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \ | ||
133 | (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \ | ||
134 | (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\ | ||
135 | x += zn - 12; \ | ||
136 | } \ | ||
137 | if (x - s >= 27) { \ | ||
138 | if (x[-5] == ' ') { \ | ||
139 | if (x[-8] == ':') zn = 0,ti = -5; \ | ||
140 | else if (x[-9] == ' ') ti = zn = -9; \ | ||
141 | else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \ | ||
142 | ti = zn = -11; \ | ||
143 | } \ | ||
144 | else if (x[-4] == ' ') { \ | ||
145 | if (x[-9] == ' ') zn = -4,ti = -9; \ | ||
146 | } \ | ||
147 | else if (x[-6] == ' ') { \ | ||
148 | if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \ | ||
149 | zn = -6,ti = -11; \ | ||
150 | } \ | ||
151 | if (ti && !((x[ti - 3] == ':') && \ | ||
152 | (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \ | ||
153 | (x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \ | ||
154 | (x[ti - 11] == ' '))) ti = 0; \ | ||
155 | } \ | ||
156 | } \ | ||
157 | } \ | ||
158 | } | ||
159 | |||
160 | #define STRLEN(s, i) \ | ||
161 | do \ | ||
162 | { \ | ||
163 | char *tmp = (s);\ | ||
164 | while (*tmp) tmp++; \ | ||
165 | i = tmp - s; \ | ||
166 | } while (0) | ||
167 | |||
168 | #define ATTRIBUTE_SET(s,buf,mum,c0,c1,type) \ | ||
169 | do \ | ||
170 | { \ | ||
171 | for (s = buf + 7; *s; s++) \ | ||
172 | { \ | ||
173 | if (*s == c0 || *s == c1) \ | ||
174 | { \ | ||
175 | mum->old_attr->flag |= 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 | /* notification */ | ||
190 | #define MAILBOX_NOTIFICATION(mbx, which) \ | ||
191 | do \ | ||
192 | { \ | ||
193 | size_t i; \ | ||
194 | event_t event; \ | ||
195 | for (i = 0; i < mbx->event_num; i++) \ | ||
196 | { \ | ||
197 | event = &(mbx->event[i]); \ | ||
198 | if ((event->_action) && (event->type & which)) \ | ||
199 | status |= event->_action (which, event->arg); \ | ||
200 | } \ | ||
201 | } while (0) | ||
202 | |||
203 | /* notifications ADD_MESG */ | ||
204 | #define DISPATCH_ADD_MSG() \ | ||
205 | do \ | ||
206 | { \ | ||
207 | mailbox_unix_iunlock (mbox); \ | ||
208 | MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_MSG_ADD); \ | ||
209 | if (status != 0) \ | ||
210 | { \ | ||
211 | if (pcount) \ | ||
212 | *pcount = mud->messages_count; \ | ||
213 | fclose (file); \ | ||
214 | mailbox_unix_unlock (mbox); \ | ||
215 | return EINTR; \ | ||
216 | } \ | ||
217 | mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \ | ||
218 | } while (0); | ||
219 | |||
220 | /* notification MBX_PROGRESS | ||
221 | * We do not want to fire up the progress notification | ||
222 | * every line, it will be too expensive, so we do it | ||
223 | * arbitrarely every 10 000 Lines. | ||
224 | * FIXME: maybe this should be configurable. | ||
225 | */ | ||
226 | /* | ||
227 | * This is more tricky we can not leave the mum | ||
228 | * struct incomplete. If they want to bailout | ||
229 | * they probably did not care about the last message | ||
230 | * we should free it; | ||
231 | */ | ||
232 | #define DISPATCH_PROGRESS() \ | ||
233 | do \ | ||
234 | { \ | ||
235 | { \ | ||
236 | mailbox_unix_iunlock (mbox); \ | ||
237 | MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_PROGRESS); \ | ||
238 | if (status != 0) \ | ||
239 | { \ | ||
240 | if (mum) \ | ||
241 | { \ | ||
242 | attribute_destroy (&(mum->old_attr), mbox); \ | ||
243 | attribute_destroy (&(mum->new_attr), mbox); \ | ||
244 | message_destroy (&(mum->message), mbox); \ | ||
245 | free (mum); \ | ||
246 | mud->umessages[mud->messages_count - 1] = NULL; \ | ||
247 | mud->messages_count--; \ | ||
248 | } \ | ||
249 | if (pcount) \ | ||
250 | *pcount = mud->messages_count; \ | ||
251 | fclose (file); \ | ||
252 | mailbox_unix_unlock (mbox); \ | ||
253 | return EINTR; \ | ||
254 | } \ | ||
255 | mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \ | ||
256 | } \ | ||
257 | } while (0) | ||
258 | |||
259 | /* skip a function call, ?? do we gain that much */ | ||
260 | #define ATTRIBUTE_CREATE(attr,own) \ | ||
261 | do \ | ||
262 | { \ | ||
263 | attr = calloc (1, sizeof(*(attr))); \ | ||
264 | if ((attr) == NULL) \ | ||
265 | { \ | ||
266 | fclose (file); \ | ||
267 | mailbox_unix_iunlock (mbox); \ | ||
268 | mailbox_unix_unlock (mbox); \ | ||
269 | return ENOMEM; \ | ||
270 | } \ | ||
271 | (attr)->owner = own; \ | ||
272 | } while (0) | ||
273 | |||
274 | /* allocate slots for the new messages */ | ||
275 | #define ALLOCATE_MSGS() \ | ||
276 | do \ | ||
277 | { \ | ||
278 | if (mud->messages_count >= mud->umessages_count) \ | ||
279 | { \ | ||
280 | mailbox_unix_message_t *m; \ | ||
281 | size_t i; \ | ||
282 | size_t num = 2 * (mud->messages_count) + 10; \ | ||
283 | m = realloc (mud->umessages, num * sizeof (*m)); \ | ||
284 | if (m == NULL) \ | ||
285 | { \ | ||
286 | fclose (file); \ | ||
287 | mailbox_unix_iunlock (mbox); \ | ||
288 | mailbox_unix_unlock (mbox); \ | ||
289 | return ENOMEM; \ | ||
290 | } \ | ||
291 | mud->umessages = m; \ | ||
292 | for (i = mud->umessages_count; i < num; i++) \ | ||
293 | { \ | ||
294 | mud->umessages[i] = calloc (1, sizeof (*mum)); \ | ||
295 | if (mud->umessages[i] == NULL) \ | ||
296 | { \ | ||
297 | fclose (file); \ | ||
298 | mailbox_unix_iunlock (mbox); \ | ||
299 | mailbox_unix_unlock (mbox); \ | ||
300 | return ENOMEM; \ | ||
301 | } \ | ||
302 | ATTRIBUTE_CREATE ((mud->umessages[i])->old_attr, mbox); \ | ||
303 | ATTRIBUTE_CREATE ((mud->umessages[i])->new_attr, mbox); \ | ||
304 | } \ | ||
305 | mud->umessages_count = num - 1; \ | ||
306 | mum = mud->umessages[mud->messages_count - 1]; \ | ||
307 | } \ | ||
308 | else \ | ||
309 | mum = mud->umessages[mud->messages_count - 1]; \ | ||
310 | mum->file = mud->file; \ | ||
311 | } while (0) | ||
312 | |||
313 | //fprintf (stderr, "%d %d %d\n", mud->umessages_count, mud->messages_count, (int)mum); | ||
314 | static int | ||
315 | mailbox_unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount) | ||
316 | { | ||
317 | #define MSGLINELEN 1024 | ||
318 | char buf[MSGLINELEN]; | ||
319 | int inheader; | ||
320 | int inbody; | ||
321 | off_t total; | ||
322 | mailbox_unix_data_t mud; | ||
323 | mailbox_unix_message_t mum = NULL; | ||
324 | int status = 0; | ||
325 | size_t lines; | ||
326 | int newline; | ||
327 | FILE *file; | ||
328 | |||
329 | int zn, isfrom = 0; | ||
330 | char *temp; | ||
331 | |||
332 | /* sanity */ | ||
333 | if (mbox == NULL || | ||
334 | (mud = (mailbox_unix_data_t)mbox->data) == NULL) | ||
335 | return EINVAL; | ||
336 | |||
337 | /* the simplest way to deal with reentrancy issues is to | ||
338 | * duplicate the FILE * pointer instead of the orignal. | ||
339 | * | ||
340 | * QnX4(and earlier ?) has a BUFSIZ of about 512 ??? | ||
341 | * we use setvbuf () to reset to something sane. | ||
342 | * Really something smaller would be counter productive. | ||
343 | */ | ||
344 | { | ||
345 | int fd = dup (fileno (mud->file)); | ||
346 | if (fd == -1) | ||
347 | return errno; | ||
348 | file = fdopen (fd, "r"); | ||
349 | if (file == NULL) | ||
350 | return errno; | ||
351 | #if BUFSIZ <= 1024 | ||
352 | { | ||
353 | char *iobuffer; | ||
354 | iobuffer = malloc (8192); | ||
355 | if (iobuffer != NULL) | ||
356 | if (setvbuf (file, iobuffer, _IOFBF, 8192) != 0) | ||
357 | free (iobuffer); | ||
358 | } | ||
359 | #endif | ||
360 | } | ||
361 | |||
362 | /* grab the locks */ | ||
363 | mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); | ||
364 | mailbox_unix_lock (mbox, MU_LOCKER_RDLOCK); | ||
365 | |||
366 | /* save the timestamp and size */ | ||
367 | { | ||
368 | struct stat st; | ||
369 | if (fstat (fileno (file), &st) != 0) | ||
370 | { | ||
371 | status = errno; | ||
372 | fclose (file); | ||
373 | mailbox_unix_iunlock (mbox); | ||
374 | mailbox_unix_unlock (mbox); | ||
375 | return status; | ||
376 | } | ||
377 | mud->mtime = st.st_mtime; | ||
378 | mud->size = st.st_size; | ||
379 | } | ||
380 | |||
381 | /* seek to the starting point */ | ||
382 | if (mud->umessages) | ||
383 | { | ||
384 | if (mud->messages_count > 0 && | ||
385 | msgno != 0 && | ||
386 | msgno <= mud->messages_count) | ||
387 | { | ||
388 | mum = mud->umessages[msgno - 1]; | ||
389 | if (mum) | ||
390 | fseek (file, mum->body_end, SEEK_SET); | ||
391 | mud->messages_count = msgno; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | rewind (file); | ||
396 | newline = 1; | ||
397 | errno = total = lines = inheader = inbody = 0; | ||
398 | |||
399 | while (fgets (buf, sizeof (buf), file)) | ||
400 | { | ||
401 | int over, nl; | ||
402 | STRLEN (buf, over); | ||
403 | total += over; | ||
404 | |||
405 | nl = (*buf == '\n') ? 1 : 0; | ||
406 | VALID(buf, temp, isfrom, zn); | ||
407 | isfrom = (isfrom) ? 1 : 0; | ||
408 | |||
409 | /* which part of the message are we in ? */ | ||
410 | inheader = isfrom | ((!nl) & inheader); | ||
411 | inbody = (!isfrom) & (!inheader); | ||
412 | |||
413 | lines++; | ||
414 | |||
415 | if (inheader) | ||
416 | { | ||
417 | /* new message */ | ||
418 | if (isfrom) | ||
419 | { | ||
420 | /* signal the end of the body */ | ||
421 | if (mum && !mum->body_end) | ||
422 | { | ||
423 | mum->body_end = total - over - newline; | ||
424 | mum->body_lines = --lines - newline; | ||
425 | DISPATCH_ADD_MSG(); | ||
426 | } | ||
427 | mud->messages_count++; | ||
428 | /* allocate_msgs will initialize mum */ | ||
429 | ALLOCATE_MSGS(); | ||
430 | mum->header_from = total - over; | ||
431 | mum->header_from_end = total; | ||
432 | lines = 0; | ||
433 | } | ||
434 | else if ((over > 7) && ISSTATUS(buf)) | ||
435 | { | ||
436 | char *s; | ||
437 | mum->header_status = total - over; | ||
438 | mum->header_status_end = total; | ||
439 | ATTRIBUTE_SET(s, buf, mum, 'r', 'R', MU_ATTRIBUTE_READ); | ||
440 | ATTRIBUTE_SET(s, buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN); | ||
441 | ATTRIBUTE_SET(s, buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED); | ||
442 | ATTRIBUTE_SET(s, buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED); | ||
443 | mum->new_attr->flag = mum->old_attr->flag; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /* body */ | ||
448 | if (inbody) | ||
449 | { | ||
450 | /* set the body position */ | ||
451 | if (!mum->body) | ||
452 | { | ||
453 | mum->body = total - over + nl; | ||
454 | mum->header_lines = lines; | ||
455 | lines = 0; | ||
456 | } | ||
457 | } | ||
458 | |||
459 | newline = nl; | ||
460 | /* every 50 mesgs update the lock, it should be every minute */ | ||
461 | if ((mud->messages_count % 50) == 0) | ||
462 | mailbox_unix_touchlock (mbox); | ||
463 | |||
464 | if (((lines +1) % 10000) == 0) | ||
465 | DISPATCH_PROGRESS(); | ||
466 | |||
467 | } /* while */ | ||
468 | |||
469 | status = errno; | ||
470 | |||
471 | /* not an error if we reach EOF */ | ||
472 | if (feof (file)) | ||
473 | status = 0; | ||
474 | clearerr (file); | ||
475 | |||
476 | if (mum) | ||
477 | { | ||
478 | //mailbox_notification (mbox, MU_EVT_MBX_MSG_ADD); | ||
479 | mum->body_end = total - newline; | ||
480 | mum->header_lines = lines - newline; | ||
481 | } | ||
482 | fclose (file); | ||
483 | mailbox_unix_iunlock (mbox); | ||
484 | mailbox_unix_unlock (mbox); | ||
485 | if (pcount) | ||
486 | *pcount = mud->messages_count; | ||
487 | return status; | ||
488 | } | ||
489 |
mailbox/net.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU Library General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU 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 | |||
19 | #include <stdlib.h> | ||
20 | #include <errno.h> | ||
21 | |||
22 | #include <net0.h> | ||
23 | |||
24 | static struct _netregistrar _netreg[1] = { "tcp", _tcp_create, _tcp_set_option, _tcp_destroy }; | ||
25 | |||
26 | int net_api_create(net_t *net, net_t parent, const char *type) | ||
27 | { | ||
28 | net_t n; | ||
29 | int i, napis, ret = 0; | ||
30 | |||
31 | if ( net == NULL || type == NULL ) | ||
32 | return EINVAL; | ||
33 | |||
34 | *net = NULL; | ||
35 | |||
36 | if ( ( n = calloc(1, sizeof(*n)) ) == NULL ) | ||
37 | return ENOMEM; | ||
38 | napis = sizeof(_netreg) / sizeof(_netreg[0]); | ||
39 | for( i = 0; i < napis; i++ ) { | ||
40 | if ( strcasecmp(_netreg[i].type, type) == 0 ) | ||
41 | break; | ||
42 | } | ||
43 | if ( i == napis ) | ||
44 | return ENOTSUP; | ||
45 | if ( ret = ( _netreg[i].create(&(n->data), &(n->api)) ) != 0 ) | ||
46 | free(n); | ||
47 | n->parent = parent; | ||
48 | n->net_reg = &_netreg[i]; | ||
49 | *net = n; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | int net_api_set_option(net_t net, const char *name, const char *value) | ||
54 | { | ||
55 | if ( net && name && value ) | ||
56 | return net->net_reg->set_option(net->data, name, value); | ||
57 | return EINVAL; | ||
58 | } | ||
59 | |||
60 | int net_api_destroy(net_t *net) | ||
61 | { | ||
62 | net_t n; | ||
63 | if ( net == NULL || *net == NULL ) | ||
64 | return EINVAL; | ||
65 | |||
66 | n = *net; | ||
67 | n->net_reg->destroy(&n->data); | ||
68 | free(n); | ||
69 | *net = NULL; | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | int net_new(net_t net, netinstance_t *inst) | ||
74 | { | ||
75 | netinstance_t netinst; | ||
76 | int ret = 0; | ||
77 | |||
78 | if ( net == NULL || inst == NULL ) | ||
79 | return EINVAL; | ||
80 | |||
81 | *inst = NULL; | ||
82 | |||
83 | if ( ( netinst = calloc(1, sizeof(*netinst)) ) == NULL ) | ||
84 | return ENOMEM; | ||
85 | netinst->api = net->api; | ||
86 | if ( ( ret = net->api->new(net->data, net->parent, &(netinst->data)) ) != 0 ) { | ||
87 | free(netinst); | ||
88 | return ret; | ||
89 | } | ||
90 | *inst = netinst; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | int net_connect(netinstance_t inst, const char *host, int port) | ||
95 | { | ||
96 | if ( inst == NULL || host == NULL ) | ||
97 | return EINVAL; | ||
98 | |||
99 | return inst->api->connect(inst->data, host, port); | ||
100 | } | ||
101 | |||
102 | int net_get_stream(netinstance_t inst, stream_t *iostr) | ||
103 | { | ||
104 | if ( inst == NULL || iostr == NULL ) | ||
105 | return EINVAL; | ||
106 | |||
107 | return inst->api->get_stream(inst->data, iostr); | ||
108 | } | ||
109 | |||
110 | int net_close(netinstance_t inst) | ||
111 | { | ||
112 | if ( inst == NULL ) | ||
113 | return EINVAL; | ||
114 | |||
115 | return inst->api->close(inst->data); | ||
116 | } | ||
117 | |||
118 | int net_free(netinstance_t *pinst) | ||
119 | { | ||
120 | int ret; | ||
121 | netinstance_t inst; | ||
122 | |||
123 | if ( pinst == NULL || *pinst == NULL ) | ||
124 | return EINVAL; | ||
125 | |||
126 | inst = *pinst; | ||
127 | ret = inst->api->free(&(inst->data)); | ||
128 | free(inst); | ||
129 | *pinst = NULL; | ||
130 | return ret; | ||
131 | } |
mailbox/tcp.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU Library General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | #include <stdlib.h> | ||
19 | #include <stdio.h> | ||
20 | #include <errno.h> | ||
21 | #include <netdb.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <string.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/socket.h> | ||
26 | #include <netinet/in.h> | ||
27 | #include <arpa/inet.h> | ||
28 | |||
29 | #include <net0.h> | ||
30 | #include <io0.h> | ||
31 | #include <tcp.h> | ||
32 | |||
33 | static int _tcp_close(void *data); | ||
34 | |||
35 | static int _tcp_doconnect(struct _tcp_instance *tcp) | ||
36 | { | ||
37 | int flgs, ret; | ||
38 | size_t namelen; | ||
39 | struct sockaddr_in peer_addr; | ||
40 | struct hostent *phe; | ||
41 | struct sockaddr_in soc_addr; | ||
42 | |||
43 | switch( tcp->state ) { | ||
44 | case TCP_STATE_INIT: | ||
45 | if ( tcp->fd == -1 ) { | ||
46 | if ( ( tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) | ||
47 | return errno; | ||
48 | } | ||
49 | if ( tcp->options->non_block ) { | ||
50 | flgs = fcntl(tcp->fd, F_GETFL); | ||
51 | flgs |= O_NONBLOCK; | ||
52 | fcntl(tcp->fd, F_SETFL, flgs); | ||
53 | } | ||
54 | tcp->state = TCP_STATE_RESOLVING; | ||
55 | case TCP_STATE_RESOLVING: | ||
56 | if ( tcp->host == NULL || tcp->port == -1 ) | ||
57 | return EINVAL; | ||
58 | tcp->address = inet_addr(tcp->host); | ||
59 | if (tcp->address == INADDR_NONE) { | ||
60 | phe = gethostbyname(tcp->host); | ||
61 | if ( !phe ) { | ||
62 | _tcp_close(tcp); | ||
63 | return EINVAL; | ||
64 | } | ||
65 | tcp->address = *(((unsigned long **)phe->h_addr_list)[0]); | ||
66 | } | ||
67 | tcp->state = TCP_STATE_RESOLVE; | ||
68 | case TCP_STATE_RESOLVE: | ||
69 | memset (&soc_addr, 0, sizeof (soc_addr)); | ||
70 | soc_addr.sin_family = AF_INET; | ||
71 | soc_addr.sin_port = htons(tcp->port); | ||
72 | soc_addr.sin_addr.s_addr = tcp->address; | ||
73 | |||
74 | if ( ( connect(tcp->fd, (struct sockaddr *) &soc_addr, sizeof(soc_addr)) ) == -1 ) { | ||
75 | ret = errno; | ||
76 | if ( ret == EINPROGRESS || ret == EAGAIN ) { | ||
77 | tcp->state = TCP_STATE_CONNECTING; | ||
78 | ret = EAGAIN; | ||
79 | } else | ||
80 | _tcp_close(tcp); | ||
81 | return ret; | ||
82 | } | ||
83 | tcp->state = TCP_STATE_CONNECTING; | ||
84 | case TCP_STATE_CONNECTING: | ||
85 | namelen = sizeof (peer_addr); | ||
86 | if ( getpeername (tcp->fd, (struct sockaddr *)&peer_addr, &namelen) == 0 ) | ||
87 | tcp->state = TCP_STATE_CONNECTED; | ||
88 | else { | ||
89 | ret = errno; | ||
90 | _tcp_close(tcp); | ||
91 | return ret; | ||
92 | } | ||
93 | break; | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int _tcp_get_fd(stream_t stream, int *fd) | ||
99 | { | ||
100 | struct _tcp_instance *tcp = stream->owner; | ||
101 | |||
102 | if ( fd == NULL ) | ||
103 | return EINVAL; | ||
104 | |||
105 | if ( tcp->fd == -1 ) { | ||
106 | if ( ( tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) | ||
107 | return errno; | ||
108 | } | ||
109 | *fd = tcp->fd; | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, size_t *br) | ||
114 | { | ||
115 | struct _tcp_instance *tcp = stream->owner; | ||
116 | |||
117 | offset; | ||
118 | if ( br == NULL ) | ||
119 | return EINVAL; | ||
120 | *br = 0; | ||
121 | if ( ( *br = recv(tcp->fd, buf, buf_size, 0) ) == -1 ) { | ||
122 | *br = 0; | ||
123 | return errno; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t offset, size_t *bw) | ||
129 | { | ||
130 | struct _tcp_instance *tcp = stream->owner; | ||
131 | |||
132 | offset; | ||
133 | if ( bw == NULL ) | ||
134 | return EINVAL; | ||
135 | *bw = 0; | ||
136 | if ( ( *bw = send(tcp->fd, buf, buf_size, 0) ) == -1 ) { | ||
137 | *bw = 0; | ||
138 | return errno; | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int _tcp_new(void *netdata, net_t parent, void **data) | ||
144 | { | ||
145 | struct _tcp_instance *tcp; | ||
146 | |||
147 | if ( parent ) /* tcp must be top level api */ | ||
148 | return EINVAL; | ||
149 | |||
150 | if ( ( tcp = malloc(sizeof(*tcp)) ) == NULL ) | ||
151 | return ENOMEM; | ||
152 | tcp->options = (struct _tcp_options *)netdata; | ||
153 | tcp->fd = -1; | ||
154 | tcp->host = NULL; | ||
155 | tcp->port = -1; | ||
156 | tcp->state = TCP_STATE_INIT; | ||
157 | stream_create(&tcp->stream, tcp); | ||
158 | stream_set_read(tcp->stream, _tcp_read, tcp); | ||
159 | stream_set_write(tcp->stream, _tcp_write, tcp); | ||
160 | stream_set_fd(tcp->stream, _tcp_get_fd, tcp); | ||
161 | *data = tcp; | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int _tcp_connect(void *data, const char *host, int port) | ||
166 | { | ||
167 | struct _tcp_instance *tcp = data; | ||
168 | |||
169 | if ( tcp->state == TCP_STATE_INIT ) { | ||
170 | tcp->port = port; | ||
171 | if ( ( tcp->host = strdup(host) ) == NULL ) | ||
172 | return ENOMEM; | ||
173 | } | ||
174 | if ( tcp->state < TCP_STATE_CONNECTED ) | ||
175 | return _tcp_doconnect(tcp); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int _tcp_get_stream(void *data, stream_t *stream) | ||
180 | { | ||
181 | struct _tcp_instance *tcp = data; | ||
182 | |||
183 | *stream = tcp->stream; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int _tcp_close(void *data) | ||
188 | { | ||
189 | struct _tcp_instance *tcp = data; | ||
190 | |||
191 | if ( tcp->fd != -1 ) | ||
192 | close(tcp->fd); | ||
193 | tcp->fd = -1; | ||
194 | tcp->state = TCP_STATE_INIT; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int _tcp_free(void **data) | ||
199 | { | ||
200 | struct _tcp_instance *tcp; | ||
201 | |||
202 | if ( data == NULL || *data == NULL ) | ||
203 | return EINVAL; | ||
204 | tcp = *data; | ||
205 | |||
206 | if ( tcp->host ) | ||
207 | free(tcp->host); | ||
208 | if ( tcp->fd != -1 ) | ||
209 | close(tcp->fd); | ||
210 | |||
211 | free(*data); | ||
212 | *data = NULL; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static struct _net_api _tcp_net_api = { | ||
217 | _tcp_new, | ||
218 | _tcp_connect, | ||
219 | _tcp_get_stream, | ||
220 | _tcp_close, | ||
221 | _tcp_free | ||
222 | }; | ||
223 | |||
224 | int _tcp_create(void **netdata, struct _net_api **netapi) | ||
225 | { | ||
226 | struct _tcp_options *options; | ||
227 | |||
228 | if ( ( options = malloc(sizeof(*options)) ) == NULL ) | ||
229 | return ENOMEM; | ||
230 | |||
231 | options->non_block = 0; | ||
232 | options->net_timeout = -1; /* system default */ | ||
233 | |||
234 | *netdata = options; | ||
235 | *netapi = &_tcp_net_api; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | int _tcp_set_option(void *netdata, const char *name, const char *value) | ||
240 | { | ||
241 | struct _tcp_options *options = netdata; | ||
242 | |||
243 | if ( strcasecmp(name, "tcp_non_block") == 0 ) { | ||
244 | if ( value[0] == 't' || value[0] == 'T' || value[0] == '1' || value[0] == 'y' || value[0] == 'Y') | ||
245 | options->non_block = 1; | ||
246 | else | ||
247 | options->non_block = 0; | ||
248 | } | ||
249 | else if ( strcasecmp(name, "tcp_timeout") == 0 ) | ||
250 | options->net_timeout = atoi(value); | ||
251 | else | ||
252 | return EINVAL; | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | int _tcp_destroy(void **netdata) | ||
257 | { | ||
258 | struct _tcp_options *options = *netdata; | ||
259 | |||
260 | free(options); | ||
261 | *netdata = NULL; | ||
262 | return 0; | ||
263 | } | ||
264 |
mailbox/transcode.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | |||
19 | #include <errno.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include <io0.h> | ||
25 | #include <transcode.h> | ||
26 | |||
27 | int _base64_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes); | ||
28 | int _base64_encode(stream_t stream, const char *optr, size_t osize, off_t offset, size_t *nbytes); | ||
29 | void _base64_destroy(transcoder_t tc); | ||
30 | int _qp_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes); | ||
31 | int _qp_encode(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes); | ||
32 | int _identity_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes); | ||
33 | int _identity_encode(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes); | ||
34 | |||
35 | struct _tc_desc { | ||
36 | const char *encoding; | ||
37 | int (*decode_read)(stream_t, char *, size_t, off_t, size_t *); | ||
38 | int (*encode_write)(stream_t, const char *, size_t, off_t, size_t *); | ||
39 | void (*destroy)(transcoder_t tc); | ||
40 | }; | ||
41 | |||
42 | #define NUM_TRANSCODERS 5 | ||
43 | struct _tc_desc tclist[NUM_TRANSCODERS] = { { "base64", _base64_decode, _base64_encode, _base64_destroy }, | ||
44 | { "quoted-printable", _qp_decode, _qp_encode, NULL }, | ||
45 | { "7bit", _identity_decode, _identity_encode, NULL }, | ||
46 | { "8bit", _identity_decode, _identity_encode, NULL }, | ||
47 | { "binary", _identity_decode, _identity_encode, NULL } | ||
48 | }; | ||
49 | |||
50 | int transcode_create(transcoder_t *ptc, char *encoding) | ||
51 | { | ||
52 | transcoder_t tc; | ||
53 | int i; | ||
54 | |||
55 | if ( ( tc = calloc(sizeof(struct _transcoder), 1) ) == NULL ) | ||
56 | return ENOMEM; | ||
57 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { | ||
58 | if ( strcasecmp( encoding, tclist[i].encoding ) == 0 ) | ||
59 | break; | ||
60 | } | ||
61 | if ( i == NUM_TRANSCODERS ) | ||
62 | return ENOTSUP; | ||
63 | |||
64 | stream_create(&tc->ustream, tc ); | ||
65 | stream_set_read(tc->ustream, tclist[i].decode_read, tc ); | ||
66 | stream_set_write(tc->ustream, tclist[i].encode_write, tc ); | ||
67 | tc->destroy = tclist[i].destroy; | ||
68 | *ptc = tc; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | void transcode_destroy(transcoder_t *ptc) | ||
73 | { | ||
74 | transcoder_t tc = *ptc; | ||
75 | |||
76 | if ( tc->destroy) | ||
77 | tc->destroy(tc); | ||
78 | stream_destroy(&tc->ustream, tc); | ||
79 | free(tc); | ||
80 | *ptc = NULL; | ||
81 | } | ||
82 | |||
83 | int transcode_get_stream(transcoder_t tc, stream_t *pstream) | ||
84 | { | ||
85 | if (tc == NULL || pstream == NULL) | ||
86 | return EINVAL; | ||
87 | *pstream = tc->ustream; | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | int transcode_set_stream(transcoder_t tc, stream_t stream) | ||
92 | { | ||
93 | if (tc == NULL || stream == NULL) | ||
94 | return EINVAL; | ||
95 | tc->stream = stream; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /*------------------------------------------------------ | ||
100 | * base64 encode/decode | ||
101 | *----------------------------------------------------*/ | ||
102 | |||
103 | struct _b64_decode | ||
104 | { | ||
105 | int cur_offset; | ||
106 | int offset; | ||
107 | int data_len; | ||
108 | char data[4]; | ||
109 | }; | ||
110 | |||
111 | static int _b64_input(char c) | ||
112 | { | ||
113 | const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
114 | int i; | ||
115 | |||
116 | for (i = 0; i < 64; i++) { | ||
117 | if (table[i] == c) | ||
118 | return i; | ||
119 | } | ||
120 | return -1; | ||
121 | } | ||
122 | |||
123 | #if 0 | ||
124 | static int _b64_output(int index) | ||
125 | { | ||
126 | const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
127 | |||
128 | if (index < 64) | ||
129 | return table[index]; | ||
130 | return -1; | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | void _base64_destroy(transcoder_t tc) | ||
135 | { | ||
136 | free(tc->tcdata); | ||
137 | tc->tcdata = NULL; | ||
138 | } | ||
139 | |||
140 | int _base64_decode(stream_t ustream, char *optr, size_t osize, off_t offset, size_t *nbytes) | ||
141 | { | ||
142 | int i, tmp = 0, ret; | ||
143 | size_t isize, consumed = 0; | ||
144 | char *iptr; | ||
145 | transcoder_t tc = (transcoder_t)ustream->owner; | ||
146 | struct _b64_decode *decode; | ||
147 | |||
148 | if ( nbytes == NULL || optr == NULL || osize == 0 ) | ||
149 | return EINVAL; | ||
150 | |||
151 | *nbytes = 0; | ||
152 | if ( ( decode = tc->tcdata ) == NULL ) { | ||
153 | if ( ( decode = calloc(1, sizeof(struct _b64_decode)) ) == NULL ) | ||
154 | return ENOMEM; | ||
155 | tc->tcdata = decode; | ||
156 | } | ||
157 | if ( decode->offset != offset ) | ||
158 | return ESPIPE; | ||
159 | |||
160 | if ( ( iptr = alloca(osize) ) == NULL ) | ||
161 | return ENOMEM; | ||
162 | isize = osize; | ||
163 | |||
164 | if ( ( ret = stream_read(tc->stream, iptr, isize, decode->cur_offset, &isize) ) != 0 ) | ||
165 | return ret; | ||
166 | |||
167 | decode->cur_offset += isize; | ||
168 | i = decode->data_len; | ||
169 | while ( consumed < isize ) { | ||
170 | while ( ( i < 4 ) && ( consumed < isize ) ) { | ||
171 | tmp = _b64_input(*iptr++); | ||
172 | consumed++; | ||
173 | if ( tmp != -1 ) | ||
174 | decode->data[i++] = tmp; | ||
175 | } | ||
176 | if ( i == 4 ) { // I have a entire block of data 32 bits | ||
177 | // get the output data | ||
178 | *optr++ = ( decode->data[0] << 2 ) | ( ( decode->data[1] & 0x30 ) >> 4 ); | ||
179 | *optr++ = ( ( decode->data[1] & 0xf ) << 4 ) | ( ( decode->data[2] & 0x3c ) >> 2 ); | ||
180 | *optr++ = ( ( decode->data[2] & 0x3 ) << 6 ) | decode->data[3]; | ||
181 | (*nbytes) += 3; | ||
182 | decode->data_len = 0; | ||
183 | } | ||
184 | else { // I did not get all the data | ||
185 | decode->data_len = i; | ||
186 | decode->offset += *nbytes; | ||
187 | return 0; | ||
188 | } | ||
189 | i = 0; | ||
190 | } | ||
191 | decode->offset += *nbytes; | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | int _base64_encode(stream_t ustream, const char *iptr, size_t osize, off_t offset, size_t *nbytes) | ||
196 | { | ||
197 | (void)ustream; (void)iptr; (void)osize; (void)offset; (void)nbytes; | ||
198 | return ENOTSUP; | ||
199 | } | ||
200 | |||
201 | /*------------------------------------------------------ | ||
202 | * quoted-printable decoder/encoder | ||
203 | *------------------------------------------------------*/ | ||
204 | struct _qp_decode | ||
205 | { | ||
206 | int cur_offset; | ||
207 | int offset; | ||
208 | int data_len; | ||
209 | char data[3]; | ||
210 | }; | ||
211 | |||
212 | static const char _hexdigits[16] = "0123456789ABCDEF"; | ||
213 | |||
214 | static int _ishex(int c) | ||
215 | { | ||
216 | int i; | ||
217 | |||
218 | if ((c == 0x0a) || (c == 0x0d)) | ||
219 | return 1; | ||
220 | |||
221 | for (i = 0; i < 16; i++) | ||
222 | if (c == _hexdigits[i]) | ||
223 | return 1; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | |||
229 | int _qp_decode(stream_t ustream, char *optr, size_t osize, off_t offset, size_t *nbytes) | ||
230 | { | ||
231 | transcoder_t tc = ustream->owner; | ||
232 | char c; | ||
233 | int last_char = 0, ret; | ||
234 | size_t isize, consumed = 0; | ||
235 | struct _qp_decode *decode; | ||
236 | char *iptr; | ||
237 | |||
238 | if ( nbytes == NULL || optr == NULL ) | ||
239 | return EINVAL; | ||
240 | |||
241 | *nbytes = 0; | ||
242 | if ( ( decode = tc->tcdata ) == NULL ) { | ||
243 | if ( ( decode = calloc(1, sizeof(struct _qp_decode)) ) == NULL ) | ||
244 | return ENOMEM; | ||
245 | tc->tcdata = decode; | ||
246 | } | ||
247 | if ( decode->offset != offset ) | ||
248 | return ESPIPE; | ||
249 | |||
250 | if ( ( iptr = alloca(osize) ) == NULL ) | ||
251 | return ENOMEM; | ||
252 | isize = osize; | ||
253 | |||
254 | if ( decode->data_len ) | ||
255 | memcpy( iptr, decode->data, decode->data_len); | ||
256 | |||
257 | if ( ( ret = stream_read(tc->stream, iptr + decode->data_len, isize - decode->data_len, decode->cur_offset, &isize) ) != 0 ) | ||
258 | return ret; | ||
259 | |||
260 | decode->data_len = 0; | ||
261 | decode->cur_offset += isize; | ||
262 | while (consumed < isize) { | ||
263 | c = *iptr++; | ||
264 | if ( ((c >= 33) && (c <= 60)) || ((c >= 62) && (c <= 126)) || ((c == '=') && !_ishex(*iptr)) ) { | ||
265 | *optr++ = c; | ||
266 | (*nbytes)++; | ||
267 | consumed++; | ||
268 | } | ||
269 | else if (c == '=') { | ||
270 | // there must be 2 more characters before I consume this | ||
271 | if ((isize - consumed) < 3) { | ||
272 | memcpy( decode->data, iptr-1, decode->data_len = isize - consumed + 1); | ||
273 | return 0; | ||
274 | } | ||
275 | else { | ||
276 | // you get =XX where XX are hex characters | ||
277 | char chr[2]; | ||
278 | int new_c; | ||
279 | |||
280 | chr[0] = *iptr++; | ||
281 | if (chr[0] != 0x0a) { // LF after = means soft line break, ignore it | ||
282 | chr[1] = *iptr++; | ||
283 | new_c = strtoul(chr, NULL, 16); | ||
284 | if (new_c == '\r') | ||
285 | new_c = '\n'; | ||
286 | *optr++ = new_c; | ||
287 | (*nbytes)++; | ||
288 | consumed += 3; | ||
289 | } | ||
290 | else | ||
291 | consumed += 2; | ||
292 | } | ||
293 | } | ||
294 | else if (c == 0x0d) { // CR character | ||
295 | // there must be at least 1 more character before I consume this | ||
296 | if ((isize - consumed) < 2) | ||
297 | return (consumed); | ||
298 | else { | ||
299 | iptr++; // skip the LF character | ||
300 | *optr++ = '\n'; | ||
301 | (*nbytes)++; | ||
302 | consumed += 2; | ||
303 | } | ||
304 | } | ||
305 | else if ((c == 9) || (c == 32)) { | ||
306 | if ((last_char == 9) || (last_char == 32)) | ||
307 | consumed++; | ||
308 | else { | ||
309 | *optr++ = c; | ||
310 | (*nbytes)++; | ||
311 | consumed++; | ||
312 | } | ||
313 | } | ||
314 | last_char = c; | ||
315 | } | ||
316 | decode->offset += *nbytes; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | |||
321 | #define QP_LINE_MAX 76 | ||
322 | struct _qp_encode | ||
323 | { | ||
324 | char *obuf; | ||
325 | int osize; | ||
326 | }; | ||
327 | |||
328 | int _qp_encode(stream_t ustream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) | ||
329 | { | ||
330 | #if 0 | ||
331 | transcoder_t tc = ustream->owner; | ||
332 | |||
333 | static int count = 0; | ||
334 | int consumed = 0, c, osize; | ||
335 | char *obuf; | ||
336 | struct _qp_encode *encode; | ||
337 | |||
338 | |||
339 | if ( nbytes == NULL || iptr == NULL ) | ||
340 | return EINVAL; | ||
341 | |||
342 | if ( isize == 0 ) | ||
343 | return 0; | ||
344 | |||
345 | *nbytes = 0; | ||
346 | if ( ( encode = tc->tcdata ) == NULL ) { | ||
347 | |||
348 | } | ||
349 | if ( ( encode->obuf = malloc(isize) ) == NULL ) | ||
350 | return ENOMEM; | ||
351 | |||
352 | optr = obuf; | ||
353 | while (consumed < isize) { | ||
354 | if (count == QP_LINE_MAX) { | ||
355 | *optr++ = '='; | ||
356 | *optr++ = '\n'; | ||
357 | osize += 2; | ||
358 | count = 0; | ||
359 | } | ||
360 | |||
361 | c = *iptr++; | ||
362 | if ( ((c >= 32) && (c <= 60)) || ((c >= 62) && (c <= 126)) || (c == 9)) { | ||
363 | *optr++ = c; | ||
364 | osize++; | ||
365 | count++; | ||
366 | } | ||
367 | else { | ||
368 | char chr[3]; | ||
369 | |||
370 | if (count >= (QP_LINE_MAX - 3)) { | ||
371 | // add spaces | ||
372 | while (count < QP_LINE_MAX) { | ||
373 | *optr++ = ' '; | ||
374 | osize++; | ||
375 | count++; | ||
376 | } | ||
377 | consumed--; | ||
378 | iptr--; | ||
379 | } | ||
380 | else { | ||
381 | *optr++ = '='; | ||
382 | sprintf(chr, "%02X", c); | ||
383 | *optr++ = chr[0]; | ||
384 | *optr++ = chr[1]; | ||
385 | osize += 3; | ||
386 | count += 3; | ||
387 | } | ||
388 | } | ||
389 | consumed++; | ||
390 | if ( osize + 4 >= isize ) { | ||
391 | if (stream_write( tc->stream, obuf, osize | ||
392 | } | ||
393 | } | ||
394 | #endif | ||
395 | (void)ustream; (void)iptr; (void)isize; (void)offset; (void)nbytes; | ||
396 | return EINVAL; | ||
397 | } | ||
398 | |||
399 | /*------------------------------------------------------ | ||
400 | * identity decoder/encoder for 7bit, 8bit & binary | ||
401 | *------------------------------------------------------*/ | ||
402 | int _identity_decode(stream_t ustream, char *optr, size_t osize, off_t offset, size_t *nbytes) | ||
403 | { | ||
404 | transcoder_t tc = ustream->owner; | ||
405 | if ( tc->stream ) | ||
406 | return stream_read(tc->stream, optr, osize, offset, nbytes ); | ||
407 | return EINVAL; | ||
408 | } | ||
409 | |||
410 | int _identity_encode(stream_t ustream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) | ||
411 | { | ||
412 | transcoder_t tc = ustream->owner; | ||
413 | if ( tc->stream ) | ||
414 | return stream_write(tc->stream, iptr, isize, offset, nbytes ); | ||
415 | return EINVAL; | ||
416 | } |
-
Please register or sign in to post a comment