NeoMutt  2024-04-25-100-gcb3684
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
filter.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <errno.h>
31#include <stdbool.h>
32#include <stddef.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/types.h>
36#include "mutt/lib.h"
37#include "gui/lib.h"
38#include "expando.h"
39#include "globals.h"
40#include "node.h"
41#include "render.h"
42
51bool check_for_pipe(struct ExpandoNode *root)
52{
53 if (!root)
54 return false;
55
56 struct ExpandoNode *last = node_last(root);
57 if (!last || (last->type != ENT_TEXT))
58 return false;
59
60 if (!last->start || !last->end)
61 return false;
62
63 int len = last->end - last->start;
64 if (len < 1)
65 return false;
66
67 if (last->start[len - 1] != '|')
68 return false;
69
70 // Count any preceding backslashes
71 int count = 0;
72 for (int i = len - 2; i >= 0; i--)
73 {
74 if (last->start[i] == '\\')
75 count++;
76 }
77
78 // The pipe character is escaped with a backslash
79 if ((count % 2) != 0)
80 return false;
81
82 return true;
83}
84
92void filter_text(struct Buffer *buf)
93{
94 if (buf_is_empty(buf))
95 return;
96
97 // Trim the | (pipe) character
98 size_t len = buf_len(buf);
99 if (buf->data[len - 1] == '|')
100 buf->data[len - 1] = '\0';
101
102 mutt_debug(LL_DEBUG3, "execute: %s\n", buf_string(buf));
103 FILE *fp_filter = NULL;
104 pid_t pid = filter_create(buf_string(buf), NULL, &fp_filter, NULL, EnvList);
105 if (pid < 0)
106 return; // LCOV_EXCL_LINE
107
108 buf_reset(buf);
109 size_t n = fread(buf->data, 1, buf->dsize - 1, fp_filter);
110 mutt_file_fclose(&fp_filter);
111 buf_fix_dptr(buf);
112
113 int rc = filter_wait(pid);
114 if (rc != 0)
115 mutt_debug(LL_DEBUG1, "filter cmd exited code %d\n", rc);
116
117 if (n == 0)
118 {
119 mutt_debug(LL_DEBUG1, "error reading from filter: %s (errno=%d)\n",
120 strerror(errno), errno);
121 buf_reset(buf);
122 return;
123 }
124
125 char *nl = (char *) buf_find_char(buf, '\n');
126 if (nl)
127 *nl = '\0';
128 mutt_debug(LL_DEBUG3, "received: %s\n", buf_string(buf));
129}
130
141int expando_filter(const struct Expando *exp, const struct ExpandoRenderData *rdata,
142 void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
143{
144 if (!exp || !exp->node)
145 return 0;
146
147 struct ExpandoNode *node = exp->node;
148
149 bool is_pipe = check_for_pipe(node);
150 int old_cols = max_cols;
151 if (is_pipe)
152 max_cols = -1;
153
154 int rc = expando_render(exp, rdata, data, flags, max_cols, buf);
155
156 if (!is_pipe)
157 return rc;
158
159 filter_text(buf);
160
161 // Strictly truncate to size
162 size_t width = 0;
163 size_t bytes = mutt_wstr_trunc(buf_string(buf), buf_len(buf), old_cols, &width);
164 buf->data[bytes] = '\0';
165
166 return width;
167}
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
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
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:655
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:383
int expando_filter(const struct Expando *exp, const struct ExpandoRenderData *rdata, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando and run the result through a filter.
Definition: filter.c:141
bool check_for_pipe(struct ExpandoNode *root)
Should the Expando be piped to an external command?
Definition: filter.c:51
void filter_text(struct Buffer *buf)
Filter the text through an external command.
Definition: filter.c:92
int expando_render(const struct Expando *exp, const struct ExpandoRenderData *rdata, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition: expando.c:109
Parsed Expando.
#define mutt_file_fclose(FP)
Definition: file.h:149
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
Convenience wrapper for the gui headers.
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
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.
struct ExpandoNode * node_last(struct ExpandoNode *node)
Find the last Node in a tree.
Definition: node.c:138
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:69
const char * end
End of string data.
Definition: node.h:80
enum ExpandoNodeType type
Type of Node, e.g. ENT_EXPANDO.
Definition: node.h:70
const char * start
Start of string data.
Definition: node.h:79
Parsed Expando trees.
Definition: expando.h:41
struct ExpandoNode * node
Parsed tree.
Definition: expando.h:43