2 ** Copyright 2003-2004 Double Precision, Inc. See COPYING for
3 ** distribution information.
7 ** $Id: encode.c,v 1.5 2005/11/16 02:23:15 mrsam Exp $
13 static int quoted_printable(struct libmail_encode_info
*,
14 const char *, size_t);
15 static int base64(struct libmail_encode_info
*,
16 const char *, size_t);
17 static int eflush(struct libmail_encode_info
*,
18 const char *, size_t);
20 void libmail_encode_start(struct libmail_encode_info
*info
,
21 const char *transfer_encoding
,
22 int (*callback_func
)(const char *, size_t, void *),
25 info
->output_buf_cnt
=0;
26 info
->input_buf_cnt
=0;
28 switch (*transfer_encoding
) {
31 info
->encoding_func
=quoted_printable
;
32 info
->input_buffer
[0]=0; /* Recycle for qp encoding */
36 info
->encoding_func
=base64
;
39 info
->encoding_func
=eflush
;
42 info
->callback_func
=callback_func
;
43 info
->callback_arg
=callback_arg
;
46 int libmail_encode(struct libmail_encode_info
*info
,
50 return ((*info
->encoding_func
)(info
, ptr
, cnt
));
53 int libmail_encode_end(struct libmail_encode_info
*info
)
55 int rc
=(*info
->encoding_func
)(info
, NULL
, 0);
57 if (rc
== 0 && info
->output_buf_cnt
> 0)
59 rc
= (*info
->callback_func
)(info
->output_buffer
,
62 info
->output_buf_cnt
=0;
68 static int eflush(struct libmail_encode_info
*info
, const char *ptr
, size_t n
)
74 if (info
->output_buf_cnt
== sizeof(info
->output_buffer
))
76 int rc
= (*info
->callback_func
)(info
->output_buffer
,
80 info
->output_buf_cnt
=0;
87 if (i
> sizeof(info
->output_buffer
) - info
->output_buf_cnt
)
88 i
=sizeof(info
->output_buffer
) - info
->output_buf_cnt
;
90 memcpy(info
->output_buffer
+ info
->output_buf_cnt
, ptr
, i
);
91 info
->output_buf_cnt
+= i
;
98 static int base64_flush(struct libmail_encode_info
*);
100 static int base64(struct libmail_encode_info
*info
,
101 const char *buf
, size_t n
)
107 if (info
->input_buf_cnt
> 0)
108 rc
=base64_flush(info
);
117 if (info
->input_buf_cnt
== sizeof(info
->input_buffer
))
119 int rc
=base64_flush(info
);
126 if (i
> sizeof(info
->input_buffer
) - info
->input_buf_cnt
)
127 i
=sizeof(info
->input_buffer
) - info
->input_buf_cnt
;
129 memcpy(info
->input_buffer
+ info
->input_buf_cnt
,
131 info
->input_buf_cnt
+= i
;
138 static const char base64tab
[]=
139 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
141 static int base64_flush(struct libmail_encode_info
*info
)
146 char output_buf
[ sizeof(info
->input_buffer
) / 3 * 4+1];
148 for (j
=i
=0; i
<info
->input_buf_cnt
; i
+= 3)
150 a
=(unsigned char)info
->input_buffer
[i
];
151 b
= i
+1 < info
->input_buf_cnt
?
152 (unsigned char)info
->input_buffer
[i
+1]:0;
153 c
= i
+2 < info
->input_buf_cnt
?
154 (unsigned char)info
->input_buffer
[i
+2]:0;
156 d
=base64tab
[ a
>> 2 ];
157 e
=base64tab
[ ((a
& 3 ) << 4) | (b
>> 4)];
158 f
=base64tab
[ ((b
& 15) << 2) | (c
>> 6)];
159 g
=base64tab
[ c
& 63 ];
160 if (i
+ 1 >= info
->input_buf_cnt
) f
='=';
161 if (i
+ 2 >= info
->input_buf_cnt
) g
='=';
168 info
->input_buf_cnt
=0;
170 output_buf
[j
++]='\n';
171 return eflush(info
, output_buf
, j
);
174 static const char xdigit
[]="0123456789ABCDEF";
176 static int quoted_printable(struct libmail_encode_info
*info
,
177 const char *p
, size_t n
)
182 #define QPUT(c) do { if (local_buf_cnt == sizeof(local_buf)) \
183 { int rc=eflush(info, local_buf, local_buf_cnt); \
184 local_buf_cnt=0; if (rc) return (rc); } \
185 local_buf[local_buf_cnt]=(c); ++local_buf_cnt; } while(0)
195 ** Repurpose input_buffer[0] as a flag whether the previous
196 ** character was a space.
198 ** A space before a newline gets escaped.
201 if (info
->input_buffer
[0])
213 ++info
->input_buf_cnt
;
216 info
->input_buffer
[0]=0;
220 info
->input_buffer
[0]=1;
226 if (info
->input_buf_cnt
> 72 && *p
!= '\n')
230 info
->input_buf_cnt
=0;
234 info
->input_buf_cnt
=0;
235 else if (*p
< ' ' || *p
== '=' || *p
>= 0x7F)
238 QPUT(xdigit
[ (*p
>> 4) & 15]);
239 QPUT(xdigit
[ *p
& 15 ]);
240 info
->input_buf_cnt
+= 3;
245 else info
->input_buf_cnt
++;
252 if (local_buf_cnt
> 0)
253 return eflush(info
, local_buf
, local_buf_cnt
);