NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
convert.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <errno.h>
31#include <iconv.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <string.h>
35#include "mutt/lib.h"
36#include "email/lib.h"
37#include "lib.h"
38
63size_t mutt_convert_file_to(FILE *fp, const char *fromcode, struct Slist const *const tocodes,
64 int *tocode, struct Content *info)
65{
66 char bufi[256], bufu[512], bufo[4 * sizeof(bufi)];
67 size_t rc;
68
69 const iconv_t cd1 = mutt_ch_iconv_open("utf-8", fromcode, MUTT_ICONV_NO_FLAGS);
70 if (!iconv_t_valid(cd1))
71 return -1;
72
73 int ncodes = tocodes->count;
74 iconv_t *cd = mutt_mem_calloc(ncodes, sizeof(iconv_t));
75 size_t *score = mutt_mem_calloc(ncodes, sizeof(size_t));
76 struct ContentState *states = mutt_mem_calloc(ncodes, sizeof(struct ContentState));
77 struct Content *infos = mutt_mem_calloc(ncodes, sizeof(struct Content));
78
79 struct ListNode *np = NULL;
80 int ni = 0;
81 STAILQ_FOREACH(np, &tocodes->head, entries)
82 {
83 if (!mutt_istr_equal(np->data, "utf-8"))
84 {
85 cd[ni] = mutt_ch_iconv_open(np->data, "utf-8", MUTT_ICONV_NO_FLAGS);
86 }
87 else
88 {
89 /* Special case for conversion to UTF-8 */
90 cd[ni] = ICONV_T_INVALID;
91 score[ni] = ICONV_ILLEGAL_SEQ;
92 }
93 ni += 1;
94 }
95
96 rewind(fp);
97 size_t ibl = 0;
98 while (true)
99 {
100 /* Try to fill input buffer */
101 size_t n = fread(bufi + ibl, 1, sizeof(bufi) - ibl, fp);
102 ibl += n;
103
104 /* Convert to UTF-8 */
105 const char *ib = bufi;
106 char *ob = bufu;
107 size_t obl = sizeof(bufu);
108 n = iconv(cd1, (ICONV_CONST char **) ((ibl != 0) ? &ib : 0), &ibl, &ob, &obl);
109 if ((n == ICONV_ILLEGAL_SEQ) && (((errno != EINVAL) && (errno != E2BIG)) || (ib == bufi)))
110 {
112 break;
113 }
114 const size_t ubl1 = ob - bufu;
115
116 /* Convert from UTF-8 */
117 for (int i = 0; i < ncodes; i++)
118 {
119 if (iconv_t_valid(cd[i]) && (score[i] != ICONV_ILLEGAL_SEQ))
120 {
121 const char *ub = bufu;
122 size_t ubl = ubl1;
123 ob = bufo;
124 obl = sizeof(bufo);
125 n = iconv(cd[i], (ICONV_CONST char **) ((ibl || ubl) ? &ub : 0), &ubl, &ob, &obl);
126 if (n == ICONV_ILLEGAL_SEQ)
127 {
128 score[i] = ICONV_ILLEGAL_SEQ;
129 }
130 else
131 {
132 score[i] += n;
133 mutt_update_content_info(&infos[i], &states[i], bufo, ob - bufo);
134 }
135 }
136 else if (!iconv_t_valid(cd[i]) && (score[i] == ICONV_ILLEGAL_SEQ))
137 {
138 /* Special case for conversion to UTF-8 */
139 mutt_update_content_info(&infos[i], &states[i], bufu, ubl1);
140 }
141 }
142
143 if (ibl)
144 {
145 /* Save unused input */
146 memmove(bufi, ib, ibl);
147 }
148 else if (!ubl1 && (ib < bufi + sizeof(bufi)))
149 {
150 rc = 0;
151 break;
152 }
153 }
154
155 if (rc == 0)
156 {
157 /* Find best score */
159 for (int i = 0; i < ncodes; i++)
160 {
161 if (!iconv_t_valid(cd[i]) && (score[i] == ICONV_ILLEGAL_SEQ))
162 {
163 /* Special case for conversion to UTF-8 */
164 *tocode = i;
165 rc = 0;
166 break;
167 }
168 else if (!iconv_t_valid(cd[i]) || (score[i] == ICONV_ILLEGAL_SEQ))
169 {
170 continue;
171 }
172 else if ((rc == ICONV_ILLEGAL_SEQ) || (score[i] < rc))
173 {
174 *tocode = i;
175 rc = score[i];
176 if (rc == 0)
177 break;
178 }
179 }
180 if (rc != ICONV_ILLEGAL_SEQ)
181 {
182 memcpy(info, &infos[*tocode], sizeof(struct Content));
183 mutt_update_content_info(info, &states[*tocode], 0, 0); /* EOF */
184 }
185 }
186
187 FREE(&cd);
188 FREE(&infos);
189 FREE(&score);
190 FREE(&states);
191
192 return rc;
193}
194
212size_t mutt_convert_file_from_to(FILE *fp, const struct Slist *fromcodes,
213 const struct Slist *tocodes, char **fromcode,
214 char **tocode, struct Content *info)
215{
216 char **tcode = NULL;
217 size_t rc;
218 int cn;
219 struct ListNode *np = NULL;
220
221 /* Copy them */
222 tcode = mutt_mem_calloc(tocodes->count, sizeof(char *));
223 np = NULL;
224 cn = 0;
225 STAILQ_FOREACH(np, &tocodes->head, entries)
226 {
227 tcode[cn++] = mutt_str_dup(np->data);
228 }
229
231 np = NULL;
232 cn = 0;
233 STAILQ_FOREACH(np, &fromcodes->head, entries)
234 {
235 /* Try each fromcode in turn */
236 rc = mutt_convert_file_to(fp, np->data, tocodes, &cn, info);
237 if (rc != ICONV_ILLEGAL_SEQ)
238 {
239 *fromcode = np->data;
240 *tocode = tcode[cn];
241 tcode[cn] = 0;
242 break;
243 }
244 }
245
246 /* Free memory */
247 for (cn = 0; cn < tocodes->count; cn++)
248 FREE(&tcode[cn]);
249
250 FREE(&tcode);
251
252 return rc;
253}
void mutt_update_content_info(struct Content *info, struct ContentState *s, char *buf, size_t buflen)
Cache some info about an email.
Definition: content_info.c:48
size_t mutt_convert_file_to(FILE *fp, const char *fromcode, struct Slist const *const tocodes, int *tocode, struct Content *info)
Change the encoding of a file.
Definition: convert.c:63
size_t mutt_convert_file_from_to(FILE *fp, const struct Slist *fromcodes, const struct Slist *tocodes, char **fromcode, char **tocode, struct Content *info)
Convert a file between encodings.
Definition: convert.c:212
Structs that make up an email.
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:45
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, uint8_t flags)
Set up iconv for conversions.
Definition: charset.c:589
#define ICONV_T_INVALID
Error value for iconv functions.
Definition: charset.h:100
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:103
static bool iconv_t_valid(const iconv_t cd)
Is the conversion descriptor valid?
Definition: charset.h:112
Convenience wrapper for the library headers.
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
Key value store.
Info about the body of an email.
Definition: content.h:56
Info about an attachment.
Definition: content.h:35
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
String list.
Definition: slist.h:47
struct ListHead head
List containing values.
Definition: slist.h:48
size_t count
Number of values in list.
Definition: slist.h:49