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