NeoMutt  2025-01-09-41-g086358
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
preview.c
Go to the documentation of this file.
1
60#include "config.h"
61#include <stdbool.h>
62#include <stddef.h>
63#include <stdio.h>
64#include "private.h"
65#include "mutt/lib.h"
66#include "email/lib.h"
67#include "core/lib.h"
68#include "gui/lib.h"
69#include "color/lib.h"
70
71// Maxixum body size in bytes to show in preview.
72const long MAX_PREVIEW_BODY_SIZE = 1024 * 1024 * 5;
73
78{
79 struct Email *email;
81 struct MuttWindow *win;
82 struct MuttWindow *bar;
84};
85
96typedef int (*preview_function_t)(struct PreviewWindowData *wdata, int op);
97
102{
103 int op;
105};
106
110static void preview_wdata_free(struct MuttWindow *win, void **ptr)
111{
112 if (!ptr || !*ptr)
113 return;
114
115 FREE(ptr);
116}
117
123{
124 struct PreviewWindowData *wdata = mutt_mem_calloc(1, sizeof(struct PreviewWindowData));
125
126 return wdata;
127}
128
134static void draw_preview(struct MuttWindow *win, struct PreviewWindowData *wdata)
135{
136 struct Email *e = wdata->email;
137
138 // Reset preview window and status bar.
140 sbar_set_title(wdata->bar, _("-- Preview"));
141
142 // Check for valid content type and disposition
143 if ((e->body->disposition != DISP_INLINE) || (e->body->type != TYPE_TEXT))
144 {
145 mutt_error(_("Only inline attachments with content-type text/* can be previewed"));
146 return;
147 }
148
149 // Ensure file isn't to too large.
150 long file_size = mutt_file_get_size(e->body->filename);
151 if (file_size > MAX_PREVIEW_BODY_SIZE)
152 {
153 mutt_error(_("Email too large to preview"));
154 return;
155 }
156
157 FILE *fp = mutt_file_fopen(e->body->filename, "r");
158 if (!fp)
159 {
160 mutt_perror("%s", e->body->filename);
161 return;
162 }
163
164 wdata->more_content = false;
165
166 int content_lines = 0; // number of (wrapped) content lines
167 int row = 0; // window row to print
168 char *line = NULL;
169 size_t line_len = 0;
170 while ((line = mutt_file_read_line(line, &line_len, fp, NULL, MUTT_RL_NO_FLAGS)))
171 {
172 size_t pos = 0;
173 bool text_left = true;
174 while (text_left)
175 {
176 /* Text wrapping loop
177 *
178 * Note: We need to do the text wrapping also for text outside the visible
179 * area to ensure the scrolling works correctly.
180 */
181
182 content_lines++;
183
184 // Check how much of the string fits into the window width.
185 size_t width = 0;
186 size_t bytes = mutt_wstr_trunc(&line[pos], line_len - pos, win->state.cols, &width);
187
188 // If it doesn't fill the full width we're done wrapping.
189 if ((win->state.cols - width) > 0)
190 text_left = false;
191
192 // Only move the cursor and print if this line is currently visible.
193 if ((content_lines >= wdata->scroll_offset) && (row < win->state.rows))
194 {
195 int rc = mutt_window_move(win, row, 0);
196 if (rc == ERR)
197 mutt_warning(_("Failed to move cursor!"));
198
199 mutt_paddstr(win, win->state.cols, &line[pos]);
200
201 row++;
202 }
203
204 // Advance position in string.
205 pos += bytes;
206 }
207 }
208
209 FREE(&line);
210 mutt_file_fclose(&fp);
211
212 // Show the scroll percentage in the status bar
213 if ((content_lines != 0) && (content_lines > win->state.rows))
214 {
215 char title[256] = { 0 };
216 double percent = 100.0;
217 if ((wdata->scroll_offset + row) < content_lines)
218 percent = 100.0 / content_lines * (wdata->scroll_offset + row);
219
220 // TODO: having the percentage right-aligned would be nice
221 snprintf(title, sizeof(title), _("-- Preview (%.0f%%)"), percent);
222 sbar_set_title(wdata->bar, title);
223
224 if (content_lines > (wdata->scroll_offset + row))
225 wdata->more_content = true;
226 }
227}
228
233{
234 if (nc->event_type != NT_COLOR)
235 return 0;
236 if (!nc->global_data || !nc->event_data)
237 return -1;
238
239 struct EventColor *ev_c = nc->event_data;
240 struct MuttWindow *win = nc->global_data;
241
242 enum ColorId cid = ev_c->cid;
243
244 switch (cid)
245 {
246 case MT_COLOR_BOLD:
247 case MT_COLOR_NORMAL:
248 case MT_COLOR_STATUS:
249 case MT_COLOR_MAX: // Sent on `uncolor *`
250 mutt_debug(LL_DEBUG5, "color done, request WA_REPAINT\n");
251 win->actions |= WA_REPAINT;
252 break;
253
254 default:
255 break;
256 }
257 return 0;
258}
259
264{
265 if (nc->event_type != NT_EMAIL)
266 return 0;
267 if (!nc->global_data)
268 return -1;
269
270 struct MuttWindow *win = nc->global_data;
271
272 win->actions |= WA_RECALC;
273 mutt_debug(LL_DEBUG5, "email done, request WA_RECALC\n");
274 return 0;
275}
276
281{
282 if (nc->event_type != NT_WINDOW)
283 return 0;
284 if (!nc->global_data || !nc->event_data)
285 return -1;
286
287 struct MuttWindow *win = nc->global_data;
288 struct EventWindow *ev_w = nc->event_data;
289 if (ev_w->win != win)
290 return 0;
291
293 {
295 mutt_debug(LL_DEBUG5, "window state done, request WA_RECALC\n");
296 }
297 else if (nc->event_subtype == NT_WINDOW_DELETE)
298 {
299 struct PreviewWindowData *wdata = win->wdata;
300
304 mutt_debug(LL_DEBUG5, "window delete done\n");
305 }
306
307 return 0;
308}
309
313static int preview_repaint(struct MuttWindow *win)
314{
315 struct PreviewWindowData *wdata = win->wdata;
316 draw_preview(win, wdata);
317
318 mutt_debug(LL_DEBUG5, "repaint done\n");
319 return 0;
320}
321
325static int preview_recalc(struct MuttWindow *win)
326{
327 if (!win)
328 return -1;
329
331 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
332 return 0;
333}
334
340struct MuttWindow *preview_window_new(struct Email *e, struct MuttWindow *bar)
341{
345
349
350 struct PreviewWindowData *wdata = preview_wdata_new();
351 wdata->email = e;
352 wdata->scroll_offset = 0;
353 wdata->win = win;
354 wdata->bar = bar;
355
356 win->wdata = wdata;
360
361 return win;
362}
363
367static int preview_page_up(struct PreviewWindowData *wdata, int op)
368{
369 if (wdata->scroll_offset <= 0)
370 return FR_NO_ACTION;
371
372 wdata->scroll_offset -= MAX(wdata->win->state.rows - 1, 1);
373 draw_preview(wdata->win, wdata);
374
375 return FR_SUCCESS;
376}
377
381static int preview_page_down(struct PreviewWindowData *wdata, int op)
382{
383 if (!wdata->more_content)
384 return FR_NO_ACTION;
385
386 wdata->scroll_offset += MAX(wdata->win->state.rows - 1, 1);
387 draw_preview(wdata->win, wdata);
388
389 return FR_SUCCESS;
390}
391
395static const struct PreviewFunction PreviewFunctions[] = {
396 // clang-format off
397 { OP_PREVIEW_PAGE_DOWN, preview_page_down },
398 { OP_PREVIEW_PAGE_UP, preview_page_up },
399 { 0, NULL },
400 // clang-format on
401};
402
407{
408 if (!win || !win->wdata)
409 return FR_UNKNOWN;
410
411 int rc = FR_UNKNOWN;
412 for (size_t i = 0; PreviewFunctions[i].op != OP_NULL; i++)
413 {
414 const struct PreviewFunction *fn = &PreviewFunctions[i];
415 if (fn->op == op)
416 {
417 struct PreviewWindowData *wdata = win->wdata;
418 rc = fn->function(wdata, op);
419 break;
420 }
421 }
422
423 if (rc == FR_UNKNOWN) // Not our function
424 return rc;
425
426 const char *result = dispatcher_get_retval_name(rc);
427 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
428
429 return rc;
430}
Color and attribute parsing.
void mutt_color_observer_remove(observer_t callback, void *global_data)
Remove an observer.
Definition: notify.c:71
void mutt_color_observer_add(observer_t callback, void *global_data)
Add an observer.
Definition: notify.c:61
ColorId
List of all coloured objects.
Definition: color.h:36
@ MT_COLOR_MAX
Definition: color.h:99
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:80
@ MT_COLOR_BOLD
Bold text.
Definition: color.h:41
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:55
Convenience wrapper for the core headers.
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:384
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:342
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition: dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
Structs that make up an email.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:685
long mutt_file_get_size(const char *path)
Get the size of a file.
Definition: file.c:1412
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
int preview_function_dispatcher(struct MuttWindow *win, int op)
Perform a preview function - Implements function_dispatcher_t -.
Definition: preview.c:406
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
static int preview_email_observer(struct NotifyCallback *nc)
Notification that the Email has changed - Implements observer_t -.
Definition: preview.c:263
static int preview_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: preview.c:280
static int preview_color_observer(struct NotifyCallback *nc)
Notification that a Color has changed - Implements observer_t -.
Definition: preview.c:232
static int preview_page_up(struct PreviewWindowData *wdata, int op)
Show the previous page of the message - Implements preview_function_t -.
Definition: preview.c:367
static int preview_page_down(struct PreviewWindowData *wdata, int op)
Show the previous page of the message - Implements preview_function_t -.
Definition: preview.c:381
static int preview_recalc(struct MuttWindow *win)
Recalculate the Window data - Implements MuttWindow::recalc() -.
Definition: preview.c:325
static int preview_repaint(struct MuttWindow *win)
Repaint the Window - Implements MuttWindow::repaint() -.
Definition: preview.c:313
static void preview_wdata_free(struct MuttWindow *win, void **ptr)
Free the Preview Data - Implements MuttWindow::wdata_free() -.
Definition: preview.c:110
Convenience wrapper for the gui headers.
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:76
#define FREE(x)
Definition: memory.h:55
#define MAX(a, b)
Definition: memory.h:31
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:230
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:191
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:682
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:182
int mutt_window_move(struct MuttWindow *win, int row, int col)
Move the cursor in a Window.
Definition: mutt_window.c:297
#define WA_RECALC
Recalculate the contents of the Window.
Definition: mutt_window.h:110
@ WT_CUSTOM
Window with a custom drawing function.
Definition: mutt_window.h:95
@ MUTT_WIN_ORIENT_VERTICAL
Window uses all available vertical space.
Definition: mutt_window.h:39
@ NT_WINDOW_STATE
Window state has changed, e.g. WN_VISIBLE.
Definition: mutt_window.h:230
@ NT_WINDOW_DELETE
Window is about to be deleted.
Definition: mutt_window.h:229
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:53
@ MUTT_WIN_SIZE_MAXIMISE
Window wants as much space as possible.
Definition: mutt_window.h:49
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:57
@ NT_COLOR
Colour has changed, NotifyColor, EventColor.
Definition: notify_type.h:41
@ NT_EMAIL
Email has changed, NotifyEmail, EventEmail.
Definition: notify_type.h:44
@ NT_ALL
Register for all notifications.
Definition: notify_type.h:35
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
struct MuttWindow * preview_window_new(struct Email *e, struct MuttWindow *bar)
Create the preview window.
Definition: preview.c:340
static const struct PreviewFunction PreviewFunctions[]
All the functions that the preview window supports.
Definition: preview.c:395
int(* preview_function_t)(struct PreviewWindowData *wdata, int op)
Definition: preview.c:96
static void draw_preview(struct MuttWindow *win, struct PreviewWindowData *wdata)
Write the message preview to the compose window.
Definition: preview.c:134
const long MAX_PREVIEW_BODY_SIZE
Definition: preview.c:72
static struct PreviewWindowData * preview_wdata_new(void)
Create new Preview Data.
Definition: preview.c:122
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:227
GUI display the mailboxes in a side panel.
#define NONULL(x)
Definition: string2.h:37
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:59
The envelope/body of an email.
Definition: email.h:39
struct Body * body
List of MIME parts.
Definition: email.h:69
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:73
An Event that happened to a Colour.
Definition: notify2.h:55
enum ColorId cid
Colour ID that has changed.
Definition: notify2.h:56
An Event that happened to a Window.
Definition: mutt_window.h:239
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:240
int(* repaint)(struct MuttWindow *win)
Definition: mutt_window.h:187
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
int(* recalc)(struct MuttWindow *win)
Definition: mutt_window.h:173
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:159
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
Data passed to a notification function.
Definition: observer.h:34
void * event_data
Data from notify_send()
Definition: observer.h:38
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:37
void * global_data
Data from notify_observer_add()
Definition: observer.h:39
A message preview function.
Definition: preview.c:102
int op
Op code, e.g. OP_NEXT_PAGE.
Definition: preview.c:103
preview_function_t function
Function to call.
Definition: preview.c:104
Data to fill the Preview Window.
Definition: preview.c:78
struct MuttWindow * win
Window holding the message preview.
Definition: preview.c:81
struct MuttWindow * bar
Status bar above the preview window.
Definition: preview.c:82
int scroll_offset
Scroll offset.
Definition: preview.c:80
struct Email * email
Email being composed.
Definition: preview.c:79
bool more_content
Is there more content to scroll down to?
Definition: preview.c:83
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:62