Commit 91905487 9190548774e3ae77363f993d5f603a394c8815b1 by Alain Magloire

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.
1 parent d9a9b601
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 }
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 */
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 */
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 */
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 */
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 };
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 */
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 */
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 */
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 }
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
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 }
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
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 }