NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
filter.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <errno.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/types.h>
35#include "mutt/lib.h"
36#include "gui/lib.h"
37#include "expando.h"
38#include "node.h"
39#include "render.h"
40
49bool check_for_pipe(struct ExpandoNode *root)
50{
51 if (!root)
52 return false;
53
54 struct ExpandoNode *last = node_last(root);
55 if (!last || (last->type != ENT_TEXT))
56 return false;
57
58 size_t len = mutt_str_len(last->text);
59 if (len < 1)
60 return false;
61
62 if (last->text[len - 1] != '|')
63 return false;
64
65 // Count any preceding backslashes
66 int count = 0;
67 for (int i = len - 2; i >= 0; i--)
68 {
69 if (last->text[i] == '\\')
70 count++;
71 }
72
73 // The pipe character is escaped with a backslash
74 if ((count % 2) != 0)
75 return false;
76
77 return true;
78}
79
88void filter_text(struct Buffer *buf, char **env_list)
89{
90 // Trim the | (pipe) character
91 size_t len = buf_len(buf);
92 if (len == 0)
93 return;
94
95 if (buf->data[len - 1] == '|')
96 buf->data[len - 1] = '\0';
97
98 mutt_debug(LL_DEBUG3, "execute: %s\n", buf_string(buf));
99 FILE *fp_filter = NULL;
100 pid_t pid = filter_create(buf_string(buf), NULL, &fp_filter, NULL, env_list);
101 if (pid < 0)
102 return; // LCOV_EXCL_LINE
103
104 buf_reset(buf);
105 size_t n = fread(buf->data, 1, buf->dsize - 1, fp_filter);
106 mutt_file_fclose(&fp_filter);
107 buf_fix_dptr(buf);
108
109 int rc = filter_wait(pid);
110 if (rc != 0)
111 mutt_debug(LL_DEBUG1, "filter cmd exited code %d\n", rc);
112
113 if (n == 0)
114 {
115 mutt_debug(LL_DEBUG1, "error reading from filter: %s (errno=%d)\n",
116 strerror(errno), errno);
117 buf_reset(buf);
118 return;
119 }
120
121 char *nl = (char *) buf_find_char(buf, '\n');
122 if (nl)
123 *nl = '\0';
124 mutt_debug(LL_DEBUG3, "received: %s\n", buf_string(buf));
125}
126
138int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc,
139 void *data, MuttFormatFlags flags, int max_cols,
140 char **env_list, struct Buffer *buf)
141{
142 if (!exp || !exp->node)
143 return 0;
144
145 struct ExpandoNode *node = exp->node;
146
147 bool is_pipe = check_for_pipe(node);
148 int old_cols = max_cols;
149 if (is_pipe)
150 max_cols = -1;
151
152 int rc = expando_render(exp, erc, data, flags, max_cols, buf);
153
154 if (!is_pipe)
155 return rc;
156
157 filter_text(buf, env_list);
158
159 // Strictly truncate to size
160 size_t width = 0;
161 size_t bytes = mutt_wstr_trunc(buf_string(buf), buf_len(buf), old_cols, &width);
162 buf->data[bytes] = '\0';
163
164 return width;
165}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
const char * buf_find_char(const struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition buffer.c:653
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
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:385
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition expando.c:118
Parsed Expando.
bool check_for_pipe(struct ExpandoNode *root)
Should the Expando be piped to an external command?
Definition filter.c:49
int expando_filter(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, char **env_list, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition filter.c:138
void filter_text(struct Buffer *buf, char **env_list)
Filter the text through an external command.
Definition filter.c:88
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
Convenience wrapper for the gui headers.
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:44
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:209
Convenience wrapper for the library headers.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
struct ExpandoNode * node_last(struct ExpandoNode *node)
Find the last Node in a tree.
Definition node.c:108
Basic Expando Node.
@ ENT_TEXT
Plain text.
Definition node.h:38
Render Expandos using Data.
uint8_t MuttFormatFlags
Flags for expando_render(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition render.h:32
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
Basic Expando Node.
Definition node.h:67
const char * text
Node-specific text.
Definition node.h:73
enum ExpandoNodeType type
Type of Node, e.g. ENT_EXPANDO.
Definition node.h:68
Parsed Expando trees.
Definition expando.h:41
struct ExpandoNode * node
Parsed tree.
Definition expando.h:43