attachment.c file_stream.c trans_stream.c
misc function done by D.I.
Showing
3 changed files
with
743 additions
and
0 deletions
mailbox/attachment.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 <message.h> | ||
19 | #include <io.h> | ||
20 | |||
21 | #include <errno.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #define MAX_HDR_LEN 256 | ||
27 | #define BUF_SIZE 2048 | ||
28 | |||
29 | struct _msg_info { | ||
30 | char *buf; | ||
31 | size_t nbytes; | ||
32 | char *header_buf; | ||
33 | int header_len; | ||
34 | int header_size; | ||
35 | header_t hdr; | ||
36 | message_t msg; | ||
37 | int ioffset; | ||
38 | int ooffset; | ||
39 | char line[MAX_HDR_LEN]; | ||
40 | int line_ndx; | ||
41 | }; | ||
42 | |||
43 | #define MSG_HDR "Content-Type: %s\nContent-Transfer-Encoding: %s\n\n" | ||
44 | |||
45 | int message_create_attachment(const char *content_type, const char *encoding, const char *filename, message_t *newmsg) | ||
46 | { | ||
47 | header_t hdr; | ||
48 | body_t body; | ||
49 | stream_t fstream = NULL, tstream = NULL; | ||
50 | char *header; | ||
51 | int ret; | ||
52 | |||
53 | if ( ( ret = message_create(newmsg, NULL) ) == 0 ) { | ||
54 | if ( content_type == NULL ) | ||
55 | content_type = "text/plain"; | ||
56 | if ( encoding == NULL ) | ||
57 | encoding = "7bit"; | ||
58 | if ( ( header = alloca(strlen(MSG_HDR) + strlen(content_type) + strlen(encoding)) ) == NULL ) | ||
59 | ret = ENOMEM; | ||
60 | else { | ||
61 | sprintf(header, MSG_HDR, content_type, encoding); | ||
62 | if ( ( ret = header_create( &hdr, header, strlen(header), *newmsg ) ) == 0 ) { | ||
63 | message_get_body(*newmsg, &body); | ||
64 | if ( ( ret = file_stream_create(&fstream, filename, MU_STREAM_READ) ) == 0 ) { | ||
65 | if ( ( ret = encoder_stream_create(&tstream, fstream, encoding) ) == 0 ) { | ||
66 | body_set_stream(body, tstream, *newmsg); | ||
67 | message_set_header(*newmsg, hdr, NULL); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | if ( ret ) { | ||
74 | if ( *newmsg ) | ||
75 | message_destroy(newmsg, NULL); | ||
76 | if ( hdr ) | ||
77 | header_destroy(&hdr, NULL); | ||
78 | if ( fstream ) | ||
79 | stream_destroy(&fstream, NULL); | ||
80 | } | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | |||
85 | static int _attachment_setup(struct _msg_info **info, message_t msg, stream_t *stream, void **data) | ||
86 | { | ||
87 | int sfl, ret; | ||
88 | body_t body; | ||
89 | |||
90 | if ( ( ret = message_get_body(msg, &body) ) != 0 || | ||
91 | ( ret = body_get_stream(body, stream) ) != 0 ) | ||
92 | return ret; | ||
93 | stream_get_flags(*stream, &sfl); | ||
94 | if ( data == NULL && (sfl & MU_STREAM_NONBLOCK) ) | ||
95 | return EINVAL; | ||
96 | if ( data ) | ||
97 | *info = *data; | ||
98 | if ( *info == NULL ) { | ||
99 | if ( ( *info = calloc(1, sizeof(struct _msg_info)) ) == NULL ) | ||
100 | return ENOMEM; | ||
101 | } | ||
102 | if ( ( (*info)->buf = malloc(BUF_SIZE) ) == NULL ) { | ||
103 | free(*info); | ||
104 | return ENOMEM; | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void _attachment_free(struct _msg_info *info, int free_message) { | ||
110 | if ( info->buf ) | ||
111 | free(info->buf); | ||
112 | if ( info->header_buf ) | ||
113 | free(info->header_buf); | ||
114 | if ( free_message ) { | ||
115 | if ( info->msg ) | ||
116 | message_destroy(&(info->msg), NULL); | ||
117 | else if ( info->hdr ) | ||
118 | header_destroy(&(info->hdr), NULL); | ||
119 | } | ||
120 | free(info); | ||
121 | } | ||
122 | |||
123 | int message_save_attachment(message_t msg, const char *filename, void **data) | ||
124 | { | ||
125 | stream_t stream; | ||
126 | header_t hdr; | ||
127 | struct _msg_info *info = NULL; | ||
128 | int ret; | ||
129 | size_t size; | ||
130 | char *content_encoding; | ||
131 | |||
132 | if ( msg == NULL || filename == NULL) | ||
133 | return EINVAL; | ||
134 | |||
135 | if ( ( data == NULL || *data == NULL) && ( ret = message_get_header(msg, &hdr) ) == 0 ) { | ||
136 | header_get_value(hdr, "Content-Transfer-Encoding", NULL, 0, &size); | ||
137 | if ( size ) { | ||
138 | if ( ( content_encoding = alloca(size+1) ) == NULL ) | ||
139 | ret = ENOMEM; | ||
140 | header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0); | ||
141 | } | ||
142 | } | ||
143 | if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &stream, data) ) != 0 ) | ||
144 | return ret; | ||
145 | |||
146 | if ( ret != EAGAIN && info ) | ||
147 | _attachment_free(info, ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | #if 0 | ||
152 | int message_encapsulate(message_t msg, message_t *newmsg, void **data) | ||
153 | { | ||
154 | stream_t stream; | ||
155 | char *header; | ||
156 | struct _msg_info *info = NULL; | ||
157 | int ret; | ||
158 | |||
159 | if ( msg == NULL || newmsg == NULL) | ||
160 | return EINVAL; | ||
161 | |||
162 | if ( ( ret = message_create(&(info->msg), NULL) ) == 0 ) { | ||
163 | header = "Content-Type: message/rfc822\nContent-Transfer-Encoding: 7bit\n\n"; | ||
164 | if ( ( ret = header_create( &(info->hdr), header, strlen(header), msg ) ) == 0 ) { | ||
165 | message_set_header(info->msg, info->hdr, NULL); | ||
166 | } | ||
167 | } | ||
168 | return ret; | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | /* If the message interface parsed headers on write this would be easy */ | ||
173 | |||
174 | int message_unencapsulate(message_t msg, message_t *newmsg, void **data) | ||
175 | { | ||
176 | size_t size, nbytes; | ||
177 | int ret = 0, header_done = 0; | ||
178 | char *content_type, *cp; | ||
179 | header_t hdr; | ||
180 | body_t body; | ||
181 | stream_t istream, ostream; | ||
182 | struct _msg_info *info = NULL; | ||
183 | |||
184 | if ( msg == NULL || newmsg == NULL) | ||
185 | return EINVAL; | ||
186 | |||
187 | if ( (data == NULL || *data == NULL ) && ( ret = message_get_header(msg, &hdr) ) == 0 ) { | ||
188 | header_get_value(hdr, "Content-Type", NULL, 0, &size); | ||
189 | if ( size ) { | ||
190 | if ( ( content_type = alloca(size+1) ) == NULL ) | ||
191 | ret = ENOMEM; | ||
192 | header_get_value(hdr, "Content-Type", content_type, size+1, 0); | ||
193 | if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 ) | ||
194 | ret = EINVAL; | ||
195 | } else | ||
196 | return EINVAL; | ||
197 | } | ||
198 | if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 ) | ||
199 | return ret; | ||
200 | |||
201 | if ( ret == 0 && info->hdr == NULL ) { | ||
202 | while ( !header_done && ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) { | ||
203 | cp = info->buf; | ||
204 | while ( info->nbytes && !header_done ) { | ||
205 | info->line[info->line_ndx] = *cp; | ||
206 | info->line_ndx++; | ||
207 | if ( *cp == '\n' ) { | ||
208 | if ( info->header_len + info->line_ndx > info->header_size) { | ||
209 | char *nhb; | ||
210 | if ( ( nhb = realloc( info->header_buf, info->header_len + info->line_ndx + 128 ) ) == NULL ) { | ||
211 | header_done = 1; | ||
212 | ret = ENOMEM; | ||
213 | break; | ||
214 | } | ||
215 | info->header_buf = nhb; | ||
216 | info->header_size = info->header_len + info->line_ndx + 128; | ||
217 | } | ||
218 | info->header_len += info->line_ndx; | ||
219 | memcpy(info->header_buf, info->line, info->line_ndx); | ||
220 | if ( info->line_ndx == 1 ) { | ||
221 | header_done = 1; | ||
222 | break; | ||
223 | } | ||
224 | info->line_ndx = 0; | ||
225 | } | ||
226 | info->ioffset++; | ||
227 | info->nbytes--; | ||
228 | cp++; | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | if ( ret == 0 && info->msg == NULL ) { | ||
233 | if ( ( ret = message_create(&(info->msg), NULL) ) == 0) | ||
234 | if ( ( ret = header_create(&(info->hdr), info->header_buf, info->header_len, info->msg) ) == 0 ) | ||
235 | ret = message_set_header(info->msg, hdr, NULL); | ||
236 | } | ||
237 | if ( ret == 0 ) { | ||
238 | message_get_body(info->msg, &body); | ||
239 | body_get_stream( body, &ostream); | ||
240 | if ( info->nbytes ) | ||
241 | memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes); | ||
242 | while ( info->nbytes || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) { | ||
243 | info->ioffset += info->nbytes; | ||
244 | while( info->nbytes ) { | ||
245 | if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 ) | ||
246 | break; | ||
247 | info->nbytes -= nbytes; | ||
248 | info->ooffset += nbytes; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | if ( ret != EAGAIN && info ) | ||
253 | _attachment_free(info, ret); | ||
254 | return ret; | ||
255 | } | ||
256 |
mailbox/file_stream.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 | |||
26 | struct _file_stream | ||
27 | { | ||
28 | FILE *file; | ||
29 | int offset; | ||
30 | }; | ||
31 | |||
32 | static void _file_destroy(stream_t stream) | ||
33 | { | ||
34 | struct _file_stream *fs = stream->owner; | ||
35 | |||
36 | if ( fs->file ) | ||
37 | fclose(fs->file); | ||
38 | free(fs); | ||
39 | } | ||
40 | |||
41 | static int _file_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes) | ||
42 | { | ||
43 | struct _file_stream *fs = stream->owner; | ||
44 | |||
45 | if ( fs->offset != offset ) { | ||
46 | fseek( fs->file, offset, SEEK_SET ); | ||
47 | fs->offset = offset; | ||
48 | } | ||
49 | *nbytes = fread( optr, osize, 1, fs->file); | ||
50 | if ( *nbytes == 0 ) { | ||
51 | if ( ferror( fs->file ) ) | ||
52 | return errno; | ||
53 | } else | ||
54 | fs->offset += *nbytes; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | static int _file_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) | ||
60 | { | ||
61 | struct _file_stream *fs = stream->owner; | ||
62 | |||
63 | if ( fs->offset != offset ) { | ||
64 | fseek( fs->file, offset, SEEK_SET ); | ||
65 | fs->offset = offset; | ||
66 | } | ||
67 | *nbytes = fwrite( iptr, isize, 1, fs->file); | ||
68 | if ( *nbytes == 0 ) { | ||
69 | if ( ferror( fs->file ) ) | ||
70 | return errno; | ||
71 | } else | ||
72 | fs->offset += *nbytes; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | int file_stream_create(stream_t *stream, const char *filename, int flags) | ||
77 | { | ||
78 | struct _file_stream *fs; | ||
79 | char *mode; | ||
80 | int ret; | ||
81 | |||
82 | if ( stream == NULL || filename == NULL ) | ||
83 | return EINVAL; | ||
84 | |||
85 | if ( ( fs = calloc(sizeof(struct _file_stream), 1) ) == NULL ) | ||
86 | return ENOMEM; | ||
87 | |||
88 | if ( ( flags & ( MU_STREAM_READ|MU_STREAM_WRITE ) ) == ( MU_STREAM_READ|MU_STREAM_WRITE ) ) | ||
89 | mode = "r+b"; | ||
90 | else if ( flags & MU_STREAM_READ ) | ||
91 | mode = "rb"; | ||
92 | else if ( flags & MU_STREAM_WRITE ) | ||
93 | mode = "wb"; | ||
94 | else | ||
95 | return EINVAL; | ||
96 | |||
97 | if ( ( fs->file = fopen(filename, mode) ) == NULL ) { | ||
98 | ret = errno; | ||
99 | free( fs ); | ||
100 | return ret; | ||
101 | } | ||
102 | if ( ( ret = stream_create(stream, flags, fs) ) != 0 ) { | ||
103 | fclose( fs->file ); | ||
104 | free( fs ); | ||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | stream_set_read(*stream, _file_read, fs ); | ||
109 | stream_set_write(*stream, _file_write, fs ); | ||
110 | stream_set_destroy(*stream, _file_destroy, fs ); | ||
111 | return 0; | ||
112 | } | ||
113 |
mailbox/trans_stream.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 | |||
26 | struct _ts_desc { | ||
27 | const char *encoding; | ||
28 | int (*decode)(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
29 | int (*encode)(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
30 | }; | ||
31 | |||
32 | struct _trans_stream | ||
33 | { | ||
34 | stream_t stream; /* encoder/decoder read/writes data to here */ | ||
35 | int cur_offset; | ||
36 | int offset; | ||
37 | char *leftover; | ||
38 | int llen; | ||
39 | int (*transcoder)(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
40 | }; | ||
41 | |||
42 | int _base64_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
43 | int _base64_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
44 | int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
45 | int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes); | ||
46 | |||
47 | #define NUM_TRANSCODERS 5 | ||
48 | struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode, _base64_encode}, | ||
49 | { "quoted-printable", _qp_decode, _qp_encode}, | ||
50 | { "7bit", NULL, NULL}, | ||
51 | { "8bit", NULL, NULL}, | ||
52 | { "binary", NULL, NULL} | ||
53 | }; | ||
54 | |||
55 | static void _trans_destroy(stream_t stream) | ||
56 | { | ||
57 | struct _trans_stream *ts = stream->owner; | ||
58 | |||
59 | stream_destroy(&(ts->stream), NULL); | ||
60 | if ( ts->leftover ) | ||
61 | free(ts->leftover); | ||
62 | free(ts); | ||
63 | } | ||
64 | |||
65 | static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes) | ||
66 | { | ||
67 | struct _trans_stream *ts = stream->owner; | ||
68 | size_t isize = osize; | ||
69 | char *iptr; | ||
70 | int consumed, ret; | ||
71 | |||
72 | if ( nbytes == NULL || optr == NULL || osize == 0 ) | ||
73 | return EINVAL; | ||
74 | |||
75 | *nbytes = 0; | ||
76 | |||
77 | if ( offset && ts->offset != offset ) | ||
78 | return ESPIPE; | ||
79 | if ( offset == 0 ) | ||
80 | ts->cur_offset = 0; | ||
81 | if ( ( iptr = alloca(isize) ) == NULL ) | ||
82 | return ENOMEM; | ||
83 | if ( ts->leftover ) { | ||
84 | memcpy( iptr, ts->leftover, ts->llen); | ||
85 | free( ts->leftover ); | ||
86 | ts->leftover = NULL; | ||
87 | ts->offset = 0; // encase of error; | ||
88 | } | ||
89 | if ( ( ret = stream_read(ts->stream, iptr + ts->llen, isize - ts->llen, ts->cur_offset, &osize) ) != 0 ) | ||
90 | return ret; | ||
91 | ts->cur_offset += osize; | ||
92 | consumed = ts->transcoder(iptr, isize, optr, nbytes); | ||
93 | if ( ts->llen = (isize - consumed ) ) { | ||
94 | if ( ( ts->leftover = malloc(ts->llen) ) == NULL ) | ||
95 | return ENOMEM; | ||
96 | memcpy(ts->leftover, iptr + consumed, ts->llen); | ||
97 | } | ||
98 | ts->offset = offset; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | |||
103 | static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes) | ||
104 | { | ||
105 | struct _trans_stream *ts = stream->owner; | ||
106 | size_t osize = isize; | ||
107 | char *optr; | ||
108 | int ret; | ||
109 | |||
110 | if ( nbytes == NULL || iptr == NULL || isize == 0 ) | ||
111 | return EINVAL; | ||
112 | |||
113 | *nbytes = 0; | ||
114 | |||
115 | if ( offset && ts->offset != offset ) | ||
116 | return ESPIPE; | ||
117 | if ( offset == 0 ) | ||
118 | ts->cur_offset = 0; | ||
119 | if ( ( optr = alloca(osize) ) == NULL ) | ||
120 | return ENOMEM; | ||
121 | |||
122 | *nbytes = ts->transcoder(iptr, isize, optr, &osize); | ||
123 | if ( ( ret = stream_write(ts->stream, optr, osize, ts->cur_offset, &osize) ) != 0 ) | ||
124 | return ret; | ||
125 | |||
126 | ts->cur_offset += osize; | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | int encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) | ||
132 | { | ||
133 | struct _trans_stream *ts; | ||
134 | int i, ret; | ||
135 | |||
136 | if ( stream == NULL || iostream == NULL || encoding == NULL ) | ||
137 | return EINVAL; | ||
138 | |||
139 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) | ||
140 | return ENOMEM; | ||
141 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { | ||
142 | if ( strcasecmp( encoding, tslist[i].encoding ) == 0 ) | ||
143 | break; | ||
144 | } | ||
145 | if ( i == NUM_TRANSCODERS ) | ||
146 | return ENOTSUP; | ||
147 | |||
148 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) | ||
149 | return ret; | ||
150 | ts->transcoder = tslist[i].encode; | ||
151 | stream_set_read(*stream, _trans_read, ts ); | ||
152 | stream_set_write(*stream, _trans_write, ts ); | ||
153 | stream_set_destroy(*stream, _trans_destroy, ts ); | ||
154 | ts->stream = iostream; | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | int decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding) | ||
159 | { | ||
160 | struct _trans_stream *ts; | ||
161 | int i, ret; | ||
162 | |||
163 | if ( stream == NULL || iostream == NULL || encoding == NULL ) | ||
164 | return EINVAL; | ||
165 | |||
166 | if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL ) | ||
167 | return ENOMEM; | ||
168 | for( i = 0; i < NUM_TRANSCODERS; i++ ) { | ||
169 | if ( strcasecmp( encoding, tslist[i].encoding ) == 0 ) | ||
170 | break; | ||
171 | } | ||
172 | if ( i == NUM_TRANSCODERS ) | ||
173 | return ENOTSUP; | ||
174 | |||
175 | if ( ( ret = stream_create(stream, MU_STREAM_RDWR, ts) ) != 0 ) | ||
176 | return ret; | ||
177 | ts->transcoder = tslist[i].decode; | ||
178 | stream_set_read(*stream, _trans_read, ts ); | ||
179 | stream_set_write(*stream, _trans_write, ts ); | ||
180 | stream_set_destroy(*stream, _trans_destroy, ts ); | ||
181 | ts->stream = iostream; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /*------------------------------------------------------ | ||
186 | * base64 encode/decode | ||
187 | *----------------------------------------------------*/ | ||
188 | static int _b64_input(char c) | ||
189 | { | ||
190 | const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
191 | int i; | ||
192 | |||
193 | for (i = 0; i < 64; i++) { | ||
194 | if (table[i] == c) | ||
195 | return i; | ||
196 | } | ||
197 | return -1; | ||
198 | } | ||
199 | |||
200 | static int _b64_output(int index) | ||
201 | { | ||
202 | const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
203 | |||
204 | if (index < 64) | ||
205 | return table[index]; | ||
206 | return -1; | ||
207 | } | ||
208 | |||
209 | int _base64_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ||
210 | { | ||
211 | int i, tmp = 0; | ||
212 | int consumed = 0; | ||
213 | char data[4]; | ||
214 | |||
215 | while ( consumed < isize ) { | ||
216 | while ( ( i < 4 ) && ( consumed < isize ) ) { | ||
217 | tmp = _b64_input(*iptr++); | ||
218 | consumed++; | ||
219 | if ( tmp != -1 ) | ||
220 | data[i++] = tmp; | ||
221 | } | ||
222 | if ( i == 4 ) { // I have a entire block of data 32 bits | ||
223 | // get the output data | ||
224 | *optr++ = ( data[0] << 2 ) | ( ( data[1] & 0x30 ) >> 4 ); | ||
225 | *optr++ = ( ( data[1] & 0xf ) << 4 ) | ( ( data[2] & 0x3c ) >> 2 ); | ||
226 | *optr++ = ( ( data[2] & 0x3 ) << 6 ) | data[3]; | ||
227 | (*nbytes) += 3; | ||
228 | } | ||
229 | else // I did not get all the data | ||
230 | return consumed; | ||
231 | i = 0; | ||
232 | } | ||
233 | return consumed; | ||
234 | } | ||
235 | |||
236 | int _base64_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ||
237 | { | ||
238 | int consumed = 0; | ||
239 | |||
240 | while (consumed < (isize - 3) && (*nbytes + 4) < isize) { | ||
241 | *optr++ = _b64_output(*iptr >> 2); | ||
242 | *optr++ = _b64_output(((*iptr++ & 0x3) << 4) | ((*iptr & 0xf0) >> 4)); | ||
243 | *optr++ = _b64_output(((*iptr++ & 0xf) << 2) | ((*iptr & 0xc0) >> 6)); | ||
244 | *optr++ = _b64_output(*iptr++ & 0x3f); | ||
245 | consumed += 3; | ||
246 | (*nbytes) += 4; | ||
247 | } | ||
248 | return consumed; | ||
249 | } | ||
250 | |||
251 | /*------------------------------------------------------ | ||
252 | * quoted-printable decoder/encoder | ||
253 | *------------------------------------------------------*/ | ||
254 | static const char _hexdigits[16] = "0123456789ABCDEF"; | ||
255 | |||
256 | static int _ishex(int c) | ||
257 | { | ||
258 | int i; | ||
259 | |||
260 | if ((c == 0x0a) || (c == 0x0d)) | ||
261 | return 1; | ||
262 | |||
263 | for (i = 0; i < 16; i++) | ||
264 | if (c == _hexdigits[i]) | ||
265 | return 1; | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | int _qp_decode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ||
271 | { | ||
272 | char c; | ||
273 | int last_char = 0, consumed = 0; | ||
274 | |||
275 | while (consumed < isize) { | ||
276 | c = *iptr++; | ||
277 | if ( ((c >= 33) && (c <= 60)) || ((c >= 62) && (c <= 126)) || ((c == '=') && !_ishex(*iptr)) ) { | ||
278 | *optr++ = c; | ||
279 | (*nbytes)++; | ||
280 | consumed++; | ||
281 | } | ||
282 | else if (c == '=') { | ||
283 | // there must be 2 more characters before I consume this | ||
284 | if ((isize - consumed) < 3) { | ||
285 | return consumed; | ||
286 | } | ||
287 | else { | ||
288 | // you get =XX where XX are hex characters | ||
289 | char chr[2]; | ||
290 | int new_c; | ||
291 | |||
292 | chr[0] = *iptr++; | ||
293 | if (chr[0] != 0x0a) { // LF after = means soft line break, ignore it | ||
294 | chr[1] = *iptr++; | ||
295 | new_c = strtoul(chr, NULL, 16); | ||
296 | if (new_c == '\r') | ||
297 | new_c = '\n'; | ||
298 | *optr++ = new_c; | ||
299 | (*nbytes)++; | ||
300 | consumed += 3; | ||
301 | } | ||
302 | else | ||
303 | consumed += 2; | ||
304 | } | ||
305 | } | ||
306 | else if (c == 0x0d) { // CR character | ||
307 | // there must be at least 1 more character before I consume this | ||
308 | if ((isize - consumed) < 2) | ||
309 | return (consumed); | ||
310 | else { | ||
311 | iptr++; // skip the LF character | ||
312 | *optr++ = '\n'; | ||
313 | (*nbytes)++; | ||
314 | consumed += 2; | ||
315 | } | ||
316 | } | ||
317 | else if ((c == 9) || (c == 32)) { | ||
318 | if ((last_char == 9) || (last_char == 32)) | ||
319 | consumed++; | ||
320 | else { | ||
321 | *optr++ = c; | ||
322 | (*nbytes)++; | ||
323 | consumed++; | ||
324 | } | ||
325 | } | ||
326 | last_char = c; | ||
327 | } | ||
328 | return consumed; | ||
329 | } | ||
330 | |||
331 | |||
332 | #define QP_LINE_MAX 76 | ||
333 | int _qp_encode(const char *iptr, size_t isize, char *optr, size_t *nbytes) | ||
334 | { | ||
335 | int count = 0; | ||
336 | int consumed = 0, c; | ||
337 | |||
338 | while (consumed < isize && (*nbytes + 4) < isize) { | ||
339 | if (count == QP_LINE_MAX) { | ||
340 | *optr++ = '='; | ||
341 | *optr++ = '\n'; | ||
342 | (*nbytes) += 2; | ||
343 | count = 0; | ||
344 | } | ||
345 | |||
346 | c = *iptr++; | ||
347 | consumed++; | ||
348 | if ( ((c >= 32) && (c <= 60)) || ((c >= 62) && (c <= 126)) || (c == 9)) { | ||
349 | *optr++ = c; | ||
350 | (*nbytes)++; | ||
351 | count++; | ||
352 | } | ||
353 | else { | ||
354 | if (count >= (QP_LINE_MAX - 3)) { | ||
355 | // add spaces | ||
356 | while (count < QP_LINE_MAX) { | ||
357 | *optr++ = ' '; | ||
358 | (*nbytes)++; | ||
359 | count++; | ||
360 | } | ||
361 | consumed--; | ||
362 | iptr--; | ||
363 | } | ||
364 | else { | ||
365 | *optr++ = '='; | ||
366 | *optr++ = _hexdigits[c & 0xf]; | ||
367 | *optr++ = _hexdigits[(c/16) & 0xf]; | ||
368 | (*nbytes) += 3; | ||
369 | count += 3; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | return consumed; | ||
374 | } |
-
Please register or sign in to post a comment