Imported Debian patch 0.66.1-1
[hcoop/debian/courier-authlib.git] / libs / rfc822 / encode.c
CommitLineData
d9898ee8 1/*
2** Copyright 2003-2004 Double Precision, Inc. See COPYING for
3** distribution information.
4*/
5
6/*
d9898ee8 7*/
8#include "encode.h"
9#include <string.h>
10#include <stdlib.h>
11
12static int quoted_printable(struct libmail_encode_info *,
13 const char *, size_t);
14static int base64(struct libmail_encode_info *,
15 const char *, size_t);
16static int eflush(struct libmail_encode_info *,
17 const char *, size_t);
18
19void libmail_encode_start(struct libmail_encode_info *info,
20 const char *transfer_encoding,
21 int (*callback_func)(const char *, size_t, void *),
22 void *callback_arg)
23{
24 info->output_buf_cnt=0;
25 info->input_buf_cnt=0;
26
27 switch (*transfer_encoding) {
28 case 'q':
29 case 'Q':
30 info->encoding_func=quoted_printable;
31 info->input_buffer[0]=0; /* Recycle for qp encoding */
32 break;
33 case 'b':
34 case 'B':
35 info->encoding_func=base64;
36 break;
37 default:
38 info->encoding_func=eflush;
39 break;
40 }
41 info->callback_func=callback_func;
42 info->callback_arg=callback_arg;
43}
44
45int libmail_encode(struct libmail_encode_info *info,
46 const char *ptr,
47 size_t cnt)
48{
49 return ((*info->encoding_func)(info, ptr, cnt));
50}
51
52int libmail_encode_end(struct libmail_encode_info *info)
53{
54 int rc=(*info->encoding_func)(info, NULL, 0);
55
56 if (rc == 0 && info->output_buf_cnt > 0)
57 {
58 rc= (*info->callback_func)(info->output_buffer,
59 info->output_buf_cnt,
60 info->callback_arg);
61 info->output_buf_cnt=0;
62 }
63
64 return rc;
65}
66
67static int eflush(struct libmail_encode_info *info, const char *ptr, size_t n)
68{
69 while (n > 0)
70 {
71 size_t i;
72
73 if (info->output_buf_cnt == sizeof(info->output_buffer))
74 {
75 int rc= (*info->callback_func)(info->output_buffer,
76 info->output_buf_cnt,
77 info->callback_arg);
78
79 info->output_buf_cnt=0;
80 if (rc)
81 return rc;
82 }
83
84 i=n;
85
86 if (i > sizeof(info->output_buffer) - info->output_buf_cnt)
87 i=sizeof(info->output_buffer) - info->output_buf_cnt;
88
89 memcpy(info->output_buffer + info->output_buf_cnt, ptr, i);
90 info->output_buf_cnt += i;
91 ptr += i;
92 n -= i;
93 }
94 return 0;
95}
96
97static int base64_flush(struct libmail_encode_info *);
98
99static int base64(struct libmail_encode_info *info,
100 const char *buf, size_t n)
101{
102 if (!buf)
103 {
104 int rc=0;
105
106 if (info->input_buf_cnt > 0)
107 rc=base64_flush(info);
108
109 return rc;
110 }
111
112 while (n)
113 {
114 size_t i;
115
116 if (info->input_buf_cnt == sizeof(info->input_buffer))
117 {
118 int rc=base64_flush(info);
119
120 if (rc != 0)
121 return rc;
122 }
123
124 i=n;
125 if (i > sizeof(info->input_buffer) - info->input_buf_cnt)
126 i=sizeof(info->input_buffer) - info->input_buf_cnt;
127
128 memcpy(info->input_buffer + info->input_buf_cnt,
129 buf, i);
130 info->input_buf_cnt += i;
131 buf += i;
132 n -= i;
133 }
134 return 0;
135}
136
137static const char base64tab[]=
138"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139
140static int base64_flush(struct libmail_encode_info *info)
141{
142 int a=0,b=0,c=0;
143 int i, j;
144 int d, e, f, g;
145 char output_buf[ sizeof(info->input_buffer) / 3 * 4+1];
146
147 for (j=i=0; i<info->input_buf_cnt; i += 3)
148 {
149 a=(unsigned char)info->input_buffer[i];
150 b= i+1 < info->input_buf_cnt ?
151 (unsigned char)info->input_buffer[i+1]:0;
152 c= i+2 < info->input_buf_cnt ?
153 (unsigned char)info->input_buffer[i+2]:0;
154
155 d=base64tab[ a >> 2 ];
156 e=base64tab[ ((a & 3 ) << 4) | (b >> 4)];
157 f=base64tab[ ((b & 15) << 2) | (c >> 6)];
158 g=base64tab[ c & 63 ];
159 if (i + 1 >= info->input_buf_cnt) f='=';
160 if (i + 2 >= info->input_buf_cnt) g='=';
161 output_buf[j++]=d;
162 output_buf[j++]=e;
163 output_buf[j++]=f;
164 output_buf[j++]=g;
165 }
166
167 info->input_buf_cnt=0;
168
169 output_buf[j++]='\n';
170 return eflush(info, output_buf, j);
171}
172
173static const char xdigit[]="0123456789ABCDEF";
174
175static int quoted_printable(struct libmail_encode_info *info,
176 const char *p, size_t n)
177{
178 char local_buf[256];
179 int local_buf_cnt=0;
180
181#define QPUT(c) do { if (local_buf_cnt == sizeof(local_buf)) \
182 { int rc=eflush(info, local_buf, local_buf_cnt); \
183 local_buf_cnt=0; if (rc) return (rc); } \
184 local_buf[local_buf_cnt]=(c); ++local_buf_cnt; } while(0)
185
186 if (!p)
187 return (0);
188
189 while (n)
190 {
191
192
193 /*
194 ** Repurpose input_buffer[0] as a flag whether the previous
195 ** character was a space.
196 **
197 ** A space before a newline gets escaped.
198 */
199
200 if (info->input_buffer[0])
201 {
202 if (*p == '\n')
203 {
204 QPUT('=');
205 QPUT('2');
206 QPUT('0');
207 }
208 else
209 {
210 QPUT(' ');
211 }
212 ++info->input_buf_cnt;
213 }
214
215 info->input_buffer[0]=0;
216
217 if (*p == ' ')
218 {
219 info->input_buffer[0]=1;
220 p++;
221 --n;
222 continue;
223 }
224
225 if (info->input_buf_cnt > 72 && *p != '\n')
226 {
227 QPUT('=');
228 QPUT('\n');
229 info->input_buf_cnt=0;
230 }
231
232 if ( *p == '\n')
233 info->input_buf_cnt=0;
234 else if (*p < ' ' || *p == '=' || *p >= 0x7F)
235 {
236 QPUT('=');
237 QPUT(xdigit[ (*p >> 4) & 15]);
238 QPUT(xdigit[ *p & 15 ]);
239 info->input_buf_cnt += 3;
240 p++;
241 --n;
242 continue;
243 }
244 else info->input_buf_cnt++;
245
246 QPUT( *p);
247 p++;
248 --n;
249 }
250
251 if (local_buf_cnt > 0)
252 return eflush(info, local_buf, local_buf_cnt);
253
254 return 0;
255}