NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
enriched.c File Reference

Rich text handler. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include "mutt/lib.h"
#include "email/lib.h"
#include "enriched.h"
+ Include dependency graph for enriched.c:

Go to the source code of this file.

Data Structures

struct  Etags
 Enriched text tags. More...
 
struct  EnrichedState
 State of enriched-text parser. More...
 

Macros

#define INDENT_SIZE   4
 A (not so) minimal implementation of RFC1563.
 

Enumerations

enum  RichAttribs {
  RICH_PARAM = 0 , RICH_BOLD , RICH_UNDERLINE , RICH_ITALIC ,
  RICH_NOFILL , RICH_INDENT , RICH_INDENT_RIGHT , RICH_EXCERPT ,
  RICH_CENTER , RICH_FLUSHLEFT , RICH_FLUSHRIGHT , RICH_COLOR ,
  RICH_MAX
}
 Rich text attributes. More...
 

Functions

static void enriched_wrap (struct EnrichedState *enriched)
 Wrap enriched text.
 
static void enriched_flush (struct EnrichedState *enriched, bool wrap)
 Write enriched text to the State.
 
static void enriched_putwc (wchar_t c, struct EnrichedState *enriched)
 Write one wide character to the state.
 
static void enriched_puts (const char *s, struct EnrichedState *enriched)
 Write an enriched text string to the State.
 
static void enriched_set_flags (const wchar_t *tag, struct EnrichedState *enriched)
 Set flags on the enriched text state.
 
int text_enriched_handler (struct Body *b_email, struct State *state)
 Handler for enriched text - Implements handler_t -.
 

Variables

static const struct Etags EnrichedTags []
 EnrichedTags - Lookup table of tags allowed in enriched text.
 

Detailed Description

Rich text handler.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file enriched.c.

Macro Definition Documentation

◆ INDENT_SIZE

#define INDENT_SIZE   4

A (not so) minimal implementation of RFC1563.

Definition at line 42 of file enriched.c.

Enumeration Type Documentation

◆ RichAttribs

Rich text attributes.

Enumerator
RICH_PARAM 

Parameter label.

RICH_BOLD 

Bold text.

RICH_UNDERLINE 

Underlined text.

RICH_ITALIC 

Italic text.

RICH_NOFILL 

Text will not be reformatted.

RICH_INDENT 

Indented text.

RICH_INDENT_RIGHT 

Right-indented text.

RICH_EXCERPT 

Excerpt text.

RICH_CENTER 

Centred text.

RICH_FLUSHLEFT 

Left-justified text.

RICH_FLUSHRIGHT 

Right-justified text.

RICH_COLOR 

Coloured text.

RICH_MAX 

Definition at line 47 of file enriched.c.

48{
49 RICH_PARAM = 0,
50 RICH_BOLD,
62};
@ RICH_FLUSHRIGHT
Right-justified text.
Definition enriched.c:59
@ RICH_NOFILL
Text will not be reformatted.
Definition enriched.c:53
@ RICH_COLOR
Coloured text.
Definition enriched.c:60
@ RICH_PARAM
Parameter label.
Definition enriched.c:49
@ RICH_INDENT
Indented text.
Definition enriched.c:54
@ RICH_BOLD
Bold text.
Definition enriched.c:50
@ RICH_CENTER
Centred text.
Definition enriched.c:57
@ RICH_ITALIC
Italic text.
Definition enriched.c:52
@ RICH_UNDERLINE
Underlined text.
Definition enriched.c:51
@ RICH_EXCERPT
Excerpt text.
Definition enriched.c:56
@ RICH_INDENT_RIGHT
Right-indented text.
Definition enriched.c:55
@ RICH_MAX
Definition enriched.c:61
@ RICH_FLUSHLEFT
Left-justified text.
Definition enriched.c:58

Function Documentation

◆ enriched_wrap()

static void enriched_wrap ( struct EnrichedState * enriched)
static

Wrap enriched text.

Parameters
enrichedState of enriched text

Definition at line 120 of file enriched.c.

121{
122 if (!enriched)
123 return;
124
125 int x;
126
127 if (enriched->line_len)
128 {
129 if (enriched->tag_level[RICH_CENTER] || enriched->tag_level[RICH_FLUSHRIGHT])
130 {
131 /* Strip trailing white space */
132 size_t y = enriched->line_used - 1;
133
134 while (y && iswspace(enriched->line[y]))
135 {
136 enriched->line[y] = (wchar_t) '\0';
137 y--;
138 enriched->line_used--;
139 enriched->line_len--;
140 }
141 if (enriched->tag_level[RICH_CENTER])
142 {
143 /* Strip leading whitespace */
144 y = 0;
145
146 while (enriched->line[y] && iswspace(enriched->line[y]))
147 y++;
148 if (y)
149 {
150 for (size_t z = y; z <= enriched->line_used; z++)
151 {
152 enriched->line[z - y] = enriched->line[z];
153 }
154
155 enriched->line_len -= y;
156 enriched->line_used -= y;
157 }
158 }
159 }
160
161 const int extra = enriched->wrap_margin - enriched->line_len - enriched->indent_len -
163 if (extra > 0)
164 {
165 if (enriched->tag_level[RICH_CENTER])
166 {
167 x = extra / 2;
168 while (x)
169 {
170 state_putc(enriched->state, ' ');
171 x--;
172 }
173 }
174 else if (enriched->tag_level[RICH_FLUSHRIGHT])
175 {
176 x = extra - 1;
177 while (x)
178 {
179 state_putc(enriched->state, ' ');
180 x--;
181 }
182 }
183 }
184 state_putws(enriched->state, (const wchar_t *) enriched->line);
185 }
186
187 state_putc(enriched->state, '\n');
188 enriched->line[0] = (wchar_t) '\0';
189 enriched->line_len = 0;
190 enriched->line_used = 0;
191 enriched->indent_len = 0;
192 if (enriched->state->prefix)
193 {
194 state_puts(enriched->state, enriched->state->prefix);
195 enriched->indent_len += mutt_str_len(enriched->state->prefix);
196 }
197
198 if (enriched->tag_level[RICH_EXCERPT])
199 {
200 x = enriched->tag_level[RICH_EXCERPT];
201 while (x)
202 {
203 if (enriched->state->prefix)
204 {
205 state_puts(enriched->state, enriched->state->prefix);
206 enriched->indent_len += mutt_str_len(enriched->state->prefix);
207 }
208 else
209 {
210 state_puts(enriched->state, "> ");
211 enriched->indent_len += mutt_str_len("> ");
212 }
213 x--;
214 }
215 }
216 else
217 {
218 enriched->indent_len = 0;
219 }
220 if (enriched->tag_level[RICH_INDENT])
221 {
222 x = enriched->tag_level[RICH_INDENT] * INDENT_SIZE;
223 enriched->indent_len += x;
224 while (x)
225 {
226 state_putc(enriched->state, ' ');
227 x--;
228 }
229 }
230}
#define INDENT_SIZE
A (not so) minimal implementation of RFC1563.
Definition enriched.c:42
int state_putws(struct State *state, const wchar_t *ws)
Write a wide string to the state.
Definition state.c:147
#define state_puts(STATE, STR)
Definition state.h:58
#define state_putc(STATE, STR)
Definition state.h:59
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
wchar_t * line
Definition enriched.c:100
int tag_level[RICH_MAX]
Definition enriched.c:111
size_t line_used
Definition enriched.c:104
struct State * state
Definition enriched.c:113
size_t line_len
Definition enriched.c:103
size_t indent_len
Definition enriched.c:106
const char * prefix
String to add to the beginning of each output line.
Definition state.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_flush()

static void enriched_flush ( struct EnrichedState * enriched,
bool wrap )
static

Write enriched text to the State.

Parameters
enrichedState of Enriched text
wraptrue if the text should be wrapped

Definition at line 237 of file enriched.c.

238{
239 if (!enriched || !enriched->buffer)
240 return;
241
242 if (!enriched->tag_level[RICH_NOFILL] &&
243 ((enriched->line_len + enriched->word_len) >
244 (enriched->wrap_margin - (enriched->tag_level[RICH_INDENT_RIGHT] * INDENT_SIZE) -
245 enriched->indent_len)))
246 {
247 enriched_wrap(enriched);
248 }
249
250 if (enriched->buf_used)
251 {
252 enriched->buffer[enriched->buf_used] = (wchar_t) '\0';
253 enriched->line_used += enriched->buf_used;
254 if (enriched->line_used > enriched->line_max)
255 {
256 enriched->line_max = enriched->line_used;
257 MUTT_MEM_REALLOC(&enriched->line, enriched->line_max + 1, wchar_t);
258 }
259 wcscat(enriched->line, enriched->buffer);
260 enriched->line_len += enriched->word_len;
261 enriched->word_len = 0;
262 enriched->buf_used = 0;
263 }
264 if (wrap)
265 enriched_wrap(enriched);
266 fflush(enriched->state->fp_out);
267}
static void enriched_wrap(struct EnrichedState *enriched)
Wrap enriched text.
Definition enriched.c:120
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:50
wchar_t * buffer
Definition enriched.c:99
size_t buf_used
Definition enriched.c:108
size_t word_len
Definition enriched.c:107
size_t line_max
Definition enriched.c:105
FILE * fp_out
File to write to.
Definition state.h:50
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_putwc()

static void enriched_putwc ( wchar_t c,
struct EnrichedState * enriched )
static

Write one wide character to the state.

Parameters
cCharacter to write
enrichedState of Enriched text

Definition at line 274 of file enriched.c.

275{
276 if (!enriched)
277 return;
278
279 if (enriched->tag_level[RICH_PARAM])
280 {
281 if (enriched->tag_level[RICH_COLOR])
282 {
283 if ((enriched->param_used + 1) >= enriched->param_len)
284 {
285 enriched->param_len += 256;
286 MUTT_MEM_REALLOC(&enriched->param, enriched->param_len, wchar_t);
287 }
288
289 enriched->param[enriched->param_used++] = c;
290 }
291 return; /* nothing to do */
292 }
293
294 /* see if more space is needed (plus extra for possible rich characters) */
295 if ((enriched->buf_len < (enriched->buf_used + 3)) || !enriched->buffer)
296 {
297 enriched->buf_len += 1024;
298 MUTT_MEM_REALLOC(&enriched->buffer, enriched->buf_len + 1, wchar_t);
299 }
300
301 if ((!enriched->tag_level[RICH_NOFILL] && iswspace(c)) || (c == (wchar_t) '\0'))
302 {
303 if (c == (wchar_t) '\t')
304 enriched->word_len += 8 - (enriched->line_len + enriched->word_len) % 8;
305 else
306 enriched->word_len++;
307
308 enriched->buffer[enriched->buf_used++] = c;
309 enriched_flush(enriched, false);
310 }
311 else
312 {
313 if (enriched->state->flags & STATE_DISPLAY)
314 {
315 if (enriched->tag_level[RICH_BOLD])
316 {
317 enriched->buffer[enriched->buf_used++] = c;
318 enriched->buffer[enriched->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
319 enriched->buffer[enriched->buf_used++] = c;
320 }
321 else if (enriched->tag_level[RICH_UNDERLINE])
322 {
323 enriched->buffer[enriched->buf_used++] = '_';
324 enriched->buffer[enriched->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
325 enriched->buffer[enriched->buf_used++] = c;
326 }
327 else if (enriched->tag_level[RICH_ITALIC])
328 {
329 enriched->buffer[enriched->buf_used++] = c;
330 enriched->buffer[enriched->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
331 enriched->buffer[enriched->buf_used++] = '_';
332 }
333 else
334 {
335 enriched->buffer[enriched->buf_used++] = c;
336 }
337 }
338 else
339 {
340 enriched->buffer[enriched->buf_used++] = c;
341 }
342 enriched->word_len++;
343 }
344}
static void enriched_flush(struct EnrichedState *enriched, bool wrap)
Write enriched text to the State.
Definition enriched.c:237
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
size_t buf_len
Definition enriched.c:102
size_t param_used
Definition enriched.c:109
wchar_t * param
Definition enriched.c:101
size_t param_len
Definition enriched.c:110
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_puts()

static void enriched_puts ( const char * s,
struct EnrichedState * enriched )
static

Write an enriched text string to the State.

Parameters
sString to write
enrichedState of Enriched text

Definition at line 351 of file enriched.c.

352{
353 if (!enriched)
354 return;
355
356 const char *c = NULL;
357
358 if ((enriched->buf_len < (enriched->buf_used + mutt_str_len(s))) || !enriched->buffer)
359 {
360 enriched->buf_len += 1024;
361 MUTT_MEM_REALLOC(&enriched->buffer, enriched->buf_len + 1, wchar_t);
362 }
363 c = s;
364 while (*c)
365 {
366 enriched->buffer[enriched->buf_used++] = (wchar_t) *c;
367 c++;
368 }
369}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_set_flags()

static void enriched_set_flags ( const wchar_t * tag,
struct EnrichedState * enriched )
static

Set flags on the enriched text state.

Parameters
tagTag to set
enrichedState of Enriched text

Definition at line 376 of file enriched.c.

377{
378 if (!enriched)
379 return;
380
381 const wchar_t *tagptr = tag;
382 int i, j;
383
384 if (*tagptr == (wchar_t) '/')
385 tagptr++;
386
387 for (i = 0, j = -1; EnrichedTags[i].tag_name; i++)
388 {
389 if (wcscasecmp(EnrichedTags[i].tag_name, tagptr) == 0)
390 {
391 j = EnrichedTags[i].index;
392 break;
393 }
394 }
395
396 if (j != -1)
397 {
398 if ((j == RICH_CENTER) || (j == RICH_FLUSHLEFT) || (j == RICH_FLUSHRIGHT))
399 enriched_flush(enriched, true);
400
401 if (*tag == (wchar_t) '/')
402 {
403 if (enriched->tag_level[j]) /* make sure not to go negative */
404 enriched->tag_level[j]--;
405 if ((enriched->state->flags & STATE_DISPLAY) && (j == RICH_PARAM) &&
406 enriched->tag_level[RICH_COLOR])
407 {
408 enriched->param[enriched->param_used] = (wchar_t) '\0';
409 if (wcscasecmp(L"black", enriched->param) == 0)
410 {
411 enriched_puts("\033[30m", enriched); // Escape
412 }
413 else if (wcscasecmp(L"red", enriched->param) == 0)
414 {
415 enriched_puts("\033[31m", enriched); // Escape
416 }
417 else if (wcscasecmp(L"green", enriched->param) == 0)
418 {
419 enriched_puts("\033[32m", enriched); // Escape
420 }
421 else if (wcscasecmp(L"yellow", enriched->param) == 0)
422 {
423 enriched_puts("\033[33m", enriched); // Escape
424 }
425 else if (wcscasecmp(L"blue", enriched->param) == 0)
426 {
427 enriched_puts("\033[34m", enriched); // Escape
428 }
429 else if (wcscasecmp(L"magenta", enriched->param) == 0)
430 {
431 enriched_puts("\033[35m", enriched); // Escape
432 }
433 else if (wcscasecmp(L"cyan", enriched->param) == 0)
434 {
435 enriched_puts("\033[36m", enriched); // Escape
436 }
437 else if (wcscasecmp(L"white", enriched->param) == 0)
438 {
439 enriched_puts("\033[37m", enriched); // Escape
440 }
441 }
442 if ((enriched->state->flags & STATE_DISPLAY) && (j == RICH_COLOR))
443 {
444 enriched_puts("\033[0m", enriched); // Escape
445 }
446
447 /* flush parameter buffer when closing the tag */
448 if (j == RICH_PARAM)
449 {
450 enriched->param_used = 0;
451 enriched->param[0] = (wchar_t) '\0';
452 }
453 }
454 else
455 {
456 enriched->tag_level[j]++;
457 }
458
459 if (j == RICH_EXCERPT)
460 enriched_flush(enriched, true);
461 }
462}
static const struct Etags EnrichedTags[]
EnrichedTags - Lookup table of tags allowed in enriched text.
Definition enriched.c:74
static void enriched_puts(const char *s, struct EnrichedState *enriched)
Write an enriched text string to the State.
Definition enriched.c:351
int wcscasecmp(const wchar_t *a, const wchar_t *b)
Compare two wide-character strings, ignoring case.
Definition wcscasecmp.c:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ EnrichedTags

const struct Etags EnrichedTags[]
static
Initial value:
= {
{ L"param", RICH_PARAM },
{ L"bold", RICH_BOLD },
{ L"italic", RICH_ITALIC },
{ L"underline", RICH_UNDERLINE },
{ L"nofill", RICH_NOFILL },
{ L"excerpt", RICH_EXCERPT },
{ L"indent", RICH_INDENT },
{ L"indentright", RICH_INDENT_RIGHT },
{ L"center", RICH_CENTER },
{ L"flushleft", RICH_FLUSHLEFT },
{ L"flushright", RICH_FLUSHRIGHT },
{ L"flushboth", RICH_FLUSHLEFT },
{ L"color", RICH_COLOR },
{ L"x-color", RICH_COLOR },
{ NULL, -1 },
}

EnrichedTags - Lookup table of tags allowed in enriched text.

Definition at line 74 of file enriched.c.

74 {
75 // clang-format off
76 { L"param", RICH_PARAM },
77 { L"bold", RICH_BOLD },
78 { L"italic", RICH_ITALIC },
79 { L"underline", RICH_UNDERLINE },
80 { L"nofill", RICH_NOFILL },
81 { L"excerpt", RICH_EXCERPT },
82 { L"indent", RICH_INDENT },
83 { L"indentright", RICH_INDENT_RIGHT },
84 { L"center", RICH_CENTER },
85 { L"flushleft", RICH_FLUSHLEFT },
86 { L"flushright", RICH_FLUSHRIGHT },
87 { L"flushboth", RICH_FLUSHLEFT },
88 { L"color", RICH_COLOR },
89 { L"x-color", RICH_COLOR },
90 { NULL, -1 },
91 // clang-format on
92};