d9898ee8 |
1 | /* |
8d138742 |
2 | ** Copyright 2003-2009 Double Precision, Inc. See COPYING for |
d9898ee8 |
3 | ** distribution information. |
4 | */ |
5 | |
6 | /* |
8d138742 |
7 | ** $Id: encodeautodetect.c,v 1.2 2009/11/08 18:14:47 mrsam Exp $ |
d9898ee8 |
8 | */ |
9 | #include "encode.h" |
10 | #include <string.h> |
11 | #include <stdlib.h> |
d9898ee8 |
12 | #include "../unicode/unicode.h" |
d9898ee8 |
13 | |
14 | static const char *libmail_encode_autodetect(const char *charset, |
15 | int (*func)(void *), void *arg) |
16 | { |
17 | const char *encoding="7bit"; |
18 | int l=0; |
19 | int longline=0; |
20 | int c; |
d9898ee8 |
21 | const struct unicode_info *ci = unicode_find(charset); |
d9898ee8 |
22 | |
23 | while ((c = (*func)(arg)) != EOF) |
24 | { |
25 | unsigned char ch= (unsigned char)c; |
26 | |
27 | if (ch >= 0x80) |
28 | { |
29 | |
d9898ee8 |
30 | if (!charset || !*charset) |
31 | encoding="8bit"; |
32 | else if (ci && ci->flags & UNICODE_BODY_QUOPRI) |
33 | encoding="quoted-printable"; |
34 | else if (!ci || ci->flags & UNICODE_BODY_BASE64) |
35 | encoding="base64"; |
36 | else |
37 | encoding="8bit"; |
d9898ee8 |
38 | } |
39 | |
40 | if (ch < 0x20 && |
41 | ch != '\t' && ch != '\r' && ch != '\n') |
42 | { |
d9898ee8 |
43 | if (!charset || !*charset) |
44 | ; |
45 | else if (ci && ci->flags & UNICODE_BODY_QUOPRI) |
46 | encoding="quoted-printable"; |
47 | else if (!ci || ci->flags & UNICODE_BODY_BASE64) |
48 | encoding="base64"; |
d9898ee8 |
49 | } |
50 | |
51 | if (ch == 0) |
52 | return "base64"; |
53 | |
54 | if (ch == '\n') l=0; |
55 | else if (++l > 990) |
56 | { |
57 | longline=1; |
d9898ee8 |
58 | if (ci && ci->flags & UNICODE_BODY_QUOPRI) |
59 | encoding="quoted-printable"; |
d9898ee8 |
60 | } |
61 | |
62 | } |
63 | |
64 | if (longline) |
65 | { |
d9898ee8 |
66 | if (ci && ci->flags & UNICODE_BODY_QUOPRI) |
67 | encoding="quoted-printable"; |
68 | else |
69 | encoding="base64"; |
d9898ee8 |
70 | } |
71 | return encoding; |
72 | } |
73 | |
74 | struct file_info { |
75 | FILE *fp; |
76 | off_t pos; |
77 | off_t end; |
78 | }; |
79 | |
80 | static int read_file(void *arg) |
81 | { |
82 | int c; |
83 | struct file_info *fi = (struct file_info *)arg; |
84 | if (fi->end >= 0 && fi->pos > fi->end) |
85 | return EOF; |
86 | c = getc(fi->fp); |
87 | fi->pos++; |
88 | return c; |
89 | } |
90 | |
91 | static int read_string(void * arg) |
92 | { |
93 | int c; |
94 | unsigned char **strp = (unsigned char **)arg; |
95 | if (**strp == 0) |
96 | return EOF; |
97 | c = (int)**strp; |
98 | (*strp)++; |
99 | return c; |
100 | } |
101 | |
102 | const char *libmail_encode_autodetect_fp(FILE *fp, int okQp) |
103 | { |
104 | if (okQp) |
105 | return libmail_encode_autodetect_fppos(fp, "ISO-8859-1", 0, -1); |
106 | else |
107 | return libmail_encode_autodetect_fppos(fp, NULL, 0, -1); |
108 | } |
109 | |
110 | const char *libmail_encode_autodetect_fppos(FILE *fp, const char *charset, |
111 | off_t start_pos, off_t end_pos) |
112 | { |
113 | struct file_info fi; |
114 | off_t orig_pos = ftell(fp); |
115 | off_t pos = orig_pos; |
116 | const char *rc; |
117 | |
118 | if (start_pos >= 0) |
119 | { |
120 | if (fseek(fp, start_pos, SEEK_SET) == (off_t)-1) |
121 | return NULL; |
122 | else |
123 | pos = start_pos; |
124 | } |
125 | |
126 | fi.fp = fp; |
127 | fi.pos = pos; |
128 | fi.end = end_pos; |
129 | rc = libmail_encode_autodetect(charset, &read_file, &fi); |
130 | |
131 | if (fseek(fp, orig_pos, SEEK_SET) == (off_t)-1) |
132 | return NULL; |
133 | return rc; |
134 | } |
135 | |
136 | const char *libmail_encode_autodetect_str(const char *str, const char *charset) |
137 | { |
138 | return libmail_encode_autodetect(charset, &read_string, &str); |
139 | } |