2 rfc2047e.c - encode a string as per RFC-2047
3 Copyright (C) 2004 Matthias Andree
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "fetchmail.h"
30 static const char noenc[] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
31 static const char encchars[] = "!\"#$%&'*+,-./0123456789:;<>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^`abcdefghijklmnopqrstuvwxyz{|}~";
32 static const char ws[] = " \t\r\n";
35 void report (FILE *fp, const char *format, ...) { (void)fp; (void)format;}
38 static int needs_enc(const char *string) {
39 if (strspn(string, noenc) < strlen(string))
41 if (strncmp(string, "=?", 2) == 0
42 && strcmp(string + strlen(string) - 2, "?=") == 0)
47 static char *encode_words(char *const *words, int nwords, const char *charset)
53 for (i = 0; i < nwords; i++)
54 l += strlen(words[i]) * 3; /* worst case, encode everything */
55 l += (strlen(charset) + 8) * (l/60 + 1);
57 out = v = (char *)xmalloc(l);
58 t = stpcpy(out, "=?");
59 t = stpcpy(t, charset);
61 for (i = 0; i < nwords; i++) {
63 for (u = words[i]; *u; u++) {
65 t = stpcpy(t, "?=\r\n=?");
67 t = stpcpy(t, charset);
70 if (*u == ' ') { *t++ = '_'; continue; }
71 if (strchr(encchars, *u)) { *t++ = *u; continue; }
72 sprintf(t, "=%02X", (unsigned int)((unsigned char)*u));
80 /** RFC-2047 encode string with given charset. Only the Q encoding
81 * (quoted-printable) supported at this time.
82 * WARNING: this code returns a static buffer!
84 char *rfc2047e(const char *string, const char *charset) {
88 int count, minlen, idx, i;
92 assert(strlen(charset) < 40);
98 /* phase 1: split original into words */
99 /* 1a: count, 1b: copy */
109 words = (char **)xmalloc(sizeof(char *) * (count + 1));
115 words[idx] = (char *)xmalloc(l+1);
116 memcpy(words[idx], r, l);
117 words[idx][l] = '\0';
122 words[idx] = (char *)xmalloc(l+1);
123 memcpy(words[idx], r, l);
124 words[idx][l] = '\0';
129 /* phase 2: encode words */
130 /* a: find ranges of adjacent words to need encoding */
131 /* b: encode ranges */
134 while (idx < count) {
137 if (!needs_enc(words[idx])) {
141 for (end = idx + 2; end < count; end += 2) {
142 if (!needs_enc(words[end]))
146 tmp = encode_words(&words[idx], end - idx + 1, charset);
149 for (i = idx + 1; i <= end; i++)
155 for (idx = 0; idx < count; idx++) {
156 l += strlen(words[idx]);
159 /* phase 3: limit lengths */
160 minlen = strlen(charset) + 7;
161 /* allocate ample memory */
162 out = (char *)xmalloc(l + (l / (72 - minlen) + 1) * (minlen + 2) + 1);
165 t = stpcpy(out, words[0]);
171 for (i = 1; i < count; i+=2) {
175 m = strlen(words[i]);
177 m += strcspn(words[i+1], "\r\n");
179 t = stpcpy(t, "\r\n");
180 t = stpcpy(t, words[i]);
182 t = stpcpy(t, words[i+1]);
184 tmp = strrchr(out, '\n');
193 for (i = 0; i < count; i++) free(words[i]);
199 int main(int argc, char **argv) {
203 t = rfc2047e(argv[1], argc > 2 ? argv[2] : "utf-8");
204 printf( " input: \"%s\"\n"
205 "output: \"%s\"\n", argv[1], t);