talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

quoted-printable.c (4224B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team
      4  *
      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 3 of the License, or
      8  * (at your option) any later version.
      9  *
     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.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  *
     18  */
     19 
     20 #include <glib.h>
     21 #include <ctype.h>
     22 
     23 #include "utils.h"
     24 
     25 #define MAX_LINELEN	76
     26 
     27 #define IS_LBREAK(p) \
     28 	(*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n'))
     29 
     30 #define SOFT_LBREAK_IF_REQUIRED(n)					\
     31 	if (len + (n) > MAX_LINELEN ||					\
     32 	    (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) {	\
     33 		*outp++ = '=';						\
     34 		*outp++ = '\n';						\
     35 		len = 0;						\
     36 	}
     37 
     38 void qp_encode_line(gchar *out, const guchar *in)
     39 {
     40 	const guchar *inp = in;
     41 	gchar *outp = out;
     42 	guchar ch;
     43 	gint len = 0;
     44 
     45 	while (*inp != '\0') {
     46 		ch = *inp;
     47 
     48 		if (IS_LBREAK(inp)) {
     49 			*outp++ = '\n';
     50 			len = 0;
     51 			if (*inp == '\r')
     52 				inp++;
     53 			inp++;
     54 		} else if (ch == '\t' || ch == ' ') {
     55 			if (IS_LBREAK(inp + 1)) {
     56 				SOFT_LBREAK_IF_REQUIRED(3);
     57 				*outp++ = '=';
     58 				get_hex_str(outp, ch);
     59 				outp += 2;
     60 				len += 3;
     61 				inp++;
     62 			} else {
     63 				SOFT_LBREAK_IF_REQUIRED(1);
     64 				*outp++ = *inp++;
     65 				len++;
     66 			}
     67 		} else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) {
     68 			SOFT_LBREAK_IF_REQUIRED(1);
     69 			*outp++ = *inp++;
     70 			len++;
     71 		} else {
     72 			SOFT_LBREAK_IF_REQUIRED(3);
     73 			*outp++ = '=';
     74 			get_hex_str(outp, ch);
     75 			outp += 2;
     76 			len += 3;
     77 			inp++;
     78 		}
     79 	}
     80 
     81 	if (len > 0)
     82 		*outp++ = '\n';
     83 
     84 	*outp = '\0';
     85 }
     86 
     87 gint qp_decode_line(gchar *str)
     88 {
     89 	gchar *inp = str, *outp = str;
     90 
     91 	while (*inp != '\0') {
     92 		if (*inp == '=') {
     93 			if (inp[1] && inp[2] &&
     94 			    get_hex_value((guchar *)outp, inp[1], inp[2])
     95 			    == TRUE) {
     96 				inp += 3;
     97 			} else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
     98 				/* soft line break */
     99 				break;
    100 			} else {
    101 				/* broken QP string */
    102 				*outp = *inp++;
    103 			}
    104 		} else {
    105 			*outp = *inp++;
    106 		}
    107 		outp++;
    108 	}
    109 
    110 	*outp = '\0';
    111 
    112 	return outp - str;
    113 }
    114 
    115 gint qp_decode_const(gchar *out, gint avail, const gchar *str)
    116 {
    117 	const gchar *inp = str;
    118 	gchar *outp = out;
    119 
    120 	while (*inp != '\0' && avail > 0) {
    121 		if (*inp == '=') {
    122 			if (inp[1] && inp[2] &&
    123 			    get_hex_value((guchar *)outp, inp[1], inp[2])
    124 			    == TRUE) {
    125 				inp += 3;
    126 			} else if (inp[1] == '\0' || g_ascii_isspace(inp[1])) {
    127 				/* soft line break */
    128 				break;
    129 			} else {
    130 				/* broken QP string */
    131 				*outp = *inp++;
    132 			}
    133 		} else {
    134 			*outp = *inp++;
    135 		}
    136 		outp++;
    137 		avail--;
    138 	}
    139 
    140 	*outp = '\0';
    141 
    142 	return outp - out;
    143 }
    144 
    145 gint qp_decode_q_encoding(guchar *out, const gchar *in, gint inlen)
    146 {
    147 	const gchar *inp = in;
    148 	guchar *outp = out;
    149 
    150 	if (inlen < 0)
    151 		inlen = G_MAXINT;
    152 
    153 	while (inp - in < inlen && *inp != '\0') {
    154 		if (*inp == '=' && inp + 3 - in <= inlen) {
    155 			if (get_hex_value(outp, inp[1], inp[2]) == TRUE) {
    156 				inp += 3;
    157 			} else {
    158 				*outp = *inp++;
    159 			}
    160 		} else if (*inp == '_') {
    161 			*outp = ' ';
    162 			inp++;
    163 		} else {
    164 			*outp = *inp++;
    165 		}
    166 		outp++;
    167 	}
    168 
    169 	*outp = '\0';
    170 
    171 	return outp - out;
    172 }
    173 
    174 gint qp_get_q_encoding_len(const guchar *str)
    175 {
    176 	const guchar *inp = str;
    177 	gint len = 0;
    178 
    179 	while (*inp != '\0') {
    180 		if (*inp == 0x20)
    181 			len++;
    182 		else if (*inp == '=' || *inp == '?' || *inp == '_' ||
    183 			 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp))
    184 			len += 3;
    185 		else
    186 			len++;
    187 
    188 		inp++;
    189 	}
    190 
    191 	return len;
    192 }
    193 
    194 void qp_q_encode(gchar *out, const guchar *in)
    195 {
    196 	const guchar *inp = in;
    197 	gchar *outp = out;
    198 
    199 	while (*inp != '\0') {
    200 		if (*inp == 0x20)
    201 			*outp++ = '_';
    202 		else if (*inp == '=' || *inp == '?' || *inp == '_' ||
    203 			 *inp < 32 || *inp > 127 || g_ascii_isspace(*inp)) {
    204 			*outp++ = '=';
    205 			get_hex_str(outp, *inp);
    206 			outp += 2;
    207 		} else
    208 			*outp++ = *inp;
    209 
    210 		inp++;
    211 	}
    212 
    213 	*outp = '\0';
    214 }