NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
icommands.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <limits.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include "mutt/lib.h"
36 #include "config/lib.h"
37 #include "core/lib.h"
38 #include "mutt.h"
39 #include "icommands.h"
40 #include "menu/lib.h"
41 #include "pager/lib.h"
42 #include "functions.h"
43 #include "init.h"
44 #include "keymap.h"
45 #include "muttlib.h"
46 #include "opcodes.h"
47 #include "version.h"
48 
49 // clang-format off
50 static enum CommandResult icmd_bind (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err);
51 static enum CommandResult icmd_set (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err);
52 static enum CommandResult icmd_version(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err);
53 
59 static const struct ICommand ICommandList[] = {
60  { "bind", icmd_bind, 0 },
61  { "macro", icmd_bind, 1 },
62  { "set", icmd_set, 0 },
63  { "version", icmd_version, 0 },
64  { NULL, NULL, 0 },
65 };
66 // clang-format on
67 
78 enum CommandResult mutt_parse_icommand(/* const */ char *line, struct Buffer *err)
79 {
80  if (!line || (*line == '\0') || !err)
81  return MUTT_CMD_ERROR;
82 
83  enum CommandResult rc = MUTT_CMD_ERROR;
84 
85  struct Buffer *token = mutt_buffer_pool_get();
86  struct Buffer expn = mutt_buffer_make(0);
87  mutt_buffer_addstr(&expn, line);
88  mutt_buffer_seek(&expn, 0);
89 
90  mutt_buffer_reset(err);
91 
92  SKIPWS(expn.dptr);
94  for (size_t i = 0; ICommandList[i].name; i++)
95  {
96  if (!mutt_str_equal(token->data, ICommandList[i].name))
97  continue;
98 
99  rc = ICommandList[i].parse(token, &expn, ICommandList[i].data, err);
100  if (rc != 0)
101  goto finish;
102 
103  break; /* Continue with next command */
104  }
105 
106 finish:
107  mutt_buffer_pool_release(&token);
108  mutt_buffer_dealloc(&expn);
109  return rc;
110 }
111 
118 static void dump_bind(struct Buffer *buf, struct Mapping *menu, struct Keymap *map)
119 {
120  char key_binding[32];
121  const char *fn_name = NULL;
122 
123  km_expand_key(key_binding, sizeof(key_binding), map);
124  if (map->op == OP_NULL)
125  {
126  mutt_buffer_add_printf(buf, "bind %s %s noop\n", menu->name, key_binding);
127  return;
128  }
129 
130  /* The pager and editor menus don't use the generic map,
131  * however for other menus try generic first. */
132  if ((menu->value != MENU_PAGER) && (menu->value != MENU_EDITOR) && (menu->value != MENU_GENERIC))
133  {
134  fn_name = mutt_get_func(OpGeneric, map->op);
135  }
136 
137  /* if it's one of the menus above or generic doesn't find
138  * the function, try with its own menu. */
139  if (!fn_name)
140  {
141  const struct Binding *bindings = km_get_table(menu->value);
142  if (!bindings)
143  return;
144 
145  fn_name = mutt_get_func(bindings, map->op);
146  }
147 
148  mutt_buffer_add_printf(buf, "bind %s %s %s\n", menu->name, key_binding, fn_name);
149 }
150 
157 static void dump_macro(struct Buffer *buf, struct Mapping *menu, struct Keymap *map)
158 {
159  char key_binding[MAX_SEQ];
160  km_expand_key(key_binding, MAX_SEQ, map);
161 
162  struct Buffer tmp = mutt_buffer_make(0);
163  escape_string(&tmp, map->macro);
164 
165  if (map->desc)
166  {
167  mutt_buffer_add_printf(buf, "macro %s %s \"%s\" \"%s\"\n", menu->name,
168  key_binding, tmp.data, map->desc);
169  }
170  else
171  {
172  mutt_buffer_add_printf(buf, "macro %s %s \"%s\"\n", menu->name, key_binding, tmp.data);
173  }
174 
175  mutt_buffer_dealloc(&tmp);
176 }
177 
186 static bool dump_menu(struct Buffer *buf, struct Mapping *menu, bool bind)
187 {
188  bool empty = true;
189  struct Keymap *map = NULL;
190 
191  STAILQ_FOREACH(map, &Keymaps[menu->value], entries)
192  {
193  if (bind && (map->op != OP_MACRO))
194  {
195  empty = false;
196  dump_bind(buf, menu, map);
197  }
198  else if (!bind && (map->op == OP_MACRO))
199  {
200  empty = false;
201  dump_macro(buf, menu, map);
202  }
203  }
204 
205  return empty;
206 }
207 
213 static void dump_all_menus(struct Buffer *buf, bool bind)
214 {
215  for (int i = 0; i < MENU_MAX; i++)
216  {
217  const char *menu_name = mutt_map_get_name(i, MenuNames);
218  struct Mapping menu = { menu_name, i };
219 
220  const bool empty = dump_menu(buf, &menu, bind);
221 
222  /* Add a new line for readability between menus. */
223  if (!empty && (i < (MENU_MAX - 1)))
224  mutt_buffer_addch(buf, '\n');
225  }
226 }
227 
231 static enum CommandResult icmd_bind(struct Buffer *buf, struct Buffer *s,
232  intptr_t data, struct Buffer *err)
233 {
234  FILE *fp_out = NULL;
235  char tempfile[PATH_MAX];
236  bool dump_all = false, bind = (data == 0);
237 
238  if (!MoreArgs(s))
239  dump_all = true;
240  else
242 
243  if (MoreArgs(s))
244  {
245  /* More arguments potentially means the user is using the
246  * ::command_t :bind command thus we delegate the task. */
247  return MUTT_CMD_ERROR;
248  }
249 
250  struct Buffer filebuf = mutt_buffer_make(4096);
251  if (dump_all || mutt_istr_equal(buf->data, "all"))
252  {
253  dump_all_menus(&filebuf, bind);
254  }
255  else
256  {
257  const int menu_index = mutt_map_get_value(buf->data, MenuNames);
258  if (menu_index == -1)
259  {
260  // L10N: '%s' is the (misspelled) name of the menu, e.g. 'index' or 'pager'
261  mutt_buffer_printf(err, _("%s: no such menu"), buf->data);
262  mutt_buffer_dealloc(&filebuf);
263  return MUTT_CMD_ERROR;
264  }
265 
266  struct Mapping menu = { buf->data, menu_index };
267  dump_menu(&filebuf, &menu, bind);
268  }
269 
270  if (mutt_buffer_is_empty(&filebuf))
271  {
272  // L10N: '%s' is the name of the menu, e.g. 'index' or 'pager',
273  // it might also be 'all' when all menus are affected.
274  mutt_buffer_printf(err, bind ? _("%s: no binds for this menu") : _("%s: no macros for this menu"),
275  dump_all ? "all" : buf->data);
276  mutt_buffer_dealloc(&filebuf);
277  return MUTT_CMD_ERROR;
278  }
279 
280  mutt_mktemp(tempfile, sizeof(tempfile));
281  fp_out = mutt_file_fopen(tempfile, "w");
282  if (!fp_out)
283  {
284  // L10N: '%s' is the file name of the temporary file
285  mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile);
286  mutt_buffer_dealloc(&filebuf);
287  return MUTT_CMD_ERROR;
288  }
289  fputs(filebuf.data, fp_out);
290 
291  mutt_file_fclose(&fp_out);
292  mutt_buffer_dealloc(&filebuf);
293 
294  struct PagerData pdata = { 0 };
295  struct PagerView pview = { &pdata };
296 
297  pdata.fname = tempfile;
298 
299  pview.banner = (bind) ? "bind" : "macro";
300  pview.flags = MUTT_PAGER_NO_FLAGS;
301  pview.mode = PAGER_MODE_OTHER;
302 
303  if (mutt_do_pager(&pview, NULL) == -1)
304  {
305  // L10N: '%s' is the file name of the temporary file
306  mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile);
307  return MUTT_CMD_ERROR;
308  }
309 
310  return MUTT_CMD_SUCCESS;
311 }
312 
316 static enum CommandResult icmd_set(struct Buffer *buf, struct Buffer *s,
317  intptr_t data, struct Buffer *err)
318 {
319  const bool set = mutt_str_equal(s->data, "set");
320  const bool set_all = mutt_str_equal(s->data, "set all");
321 
322  if (!set && !set_all)
323  return MUTT_CMD_ERROR;
324 
325  char tempfile[PATH_MAX];
326  mutt_mktemp(tempfile, sizeof(tempfile));
327 
328  FILE *fp_out = mutt_file_fopen(tempfile, "w");
329  if (!fp_out)
330  {
331  // L10N: '%s' is the file name of the temporary file
332  mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile);
333  return MUTT_CMD_ERROR;
334  }
335 
336  if (set_all)
338  else
340 
341  mutt_file_fclose(&fp_out);
342 
343  struct PagerData pdata = { 0 };
344  struct PagerView pview = { &pdata };
345 
346  pdata.fname = tempfile;
347 
348  pview.banner = "set";
349  pview.flags = MUTT_PAGER_NO_FLAGS;
350  pview.mode = PAGER_MODE_OTHER;
351 
352  mutt_do_pager(&pview, NULL);
353 
354  return MUTT_CMD_SUCCESS;
355 }
356 
360 static enum CommandResult icmd_version(struct Buffer *buf, struct Buffer *s,
361  intptr_t data, struct Buffer *err)
362 {
363  char tempfile[PATH_MAX];
364  mutt_mktemp(tempfile, sizeof(tempfile));
365 
366  FILE *fp_out = mutt_file_fopen(tempfile, "w");
367  if (!fp_out)
368  {
369  // L10N: '%s' is the file name of the temporary file
370  mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile);
371  return MUTT_CMD_ERROR;
372  }
373 
374  print_version(fp_out);
375  mutt_file_fclose(&fp_out);
376 
377  struct PagerData pdata = { 0 };
378  struct PagerView pview = { &pdata };
379 
380  pdata.fname = tempfile;
381 
382  pview.banner = "version";
383  pview.flags = MUTT_PAGER_NO_FLAGS;
384  pview.mode = PAGER_MODE_OTHER;
385 
386  if (mutt_do_pager(&pview, NULL) == -1)
387  {
388  // L10N: '%s' is the file name of the temporary file
389  mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile);
390  return MUTT_CMD_ERROR;
391  }
392 
393  return MUTT_CMD_SUCCESS;
394 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
Manage keymappings.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
CommandResult
Error codes for command_t parse functions.
Definition: mutt_commands.h:34
Config/command parsing.
#define CS_DUMP_ONLY_CHANGED
Only show config that the user has changed.
Definition: dump.h:36
struct KeymapList Keymaps[MENU_MAX]
Array of Keymap keybindings, one for each Menu.
Definition: keymap.c:126
Error: Can&#39;t help the user.
Definition: mutt_commands.h:36
Generic selection list.
Definition: type.h:45
char * name
Name of the command.
Definition: icommands.h:37
static enum CommandResult icmd_version(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse &#39;version&#39; command - Implements ICommand::parse()
Definition: icommands.c:360
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void print_version(FILE *fp)
Print system and compile info to a file.
Definition: version.c:424
String manipulation buffer.
Definition: buffer.h:33
Paged view into some data.
Definition: lib.h:154
static void dump_bind(struct Buffer *buf, struct Mapping *menu, struct Keymap *map)
Dump a bind map to a buffer.
Definition: icommands.c:118
#define _(a)
Definition: message.h:28
static bool dump_menu(struct Buffer *buf, struct Mapping *menu, bool bind)
Dumps all the binds or macros maps of a menu into a buffer.
Definition: icommands.c:186
An Informational Command.
Definition: icommands.h:35
Information commands.
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int value
Definition: mapping.h:34
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:36
enum CommandResult mutt_parse_icommand(char *line, struct Buffer *err)
Parse an informational command.
Definition: icommands.c:78
Convenience wrapper for the config headers.
Some miscellaneous functions.
Definition: type.h:59
Pager pager (email viewer)
Definition: type.h:54
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
#define MoreArgs(buf)
Definition: buffer.h:40
const char * mutt_get_func(const struct Binding *bindings, int op)
Get the name of a function.
Definition: keymap.c:516
Data to be displayed by PagerView.
Definition: lib.h:143
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
static enum CommandResult icmd_set(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse &#39;set&#39; command to display config - Implements ICommand::parse()
Definition: icommands.c:316
Many unsorted constants and some structs.
Text entry area.
Definition: type.h:43
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
const struct Binding OpGeneric[]
Key bindings for the generic menu.
Definition: functions.c:53
Convenience wrapper for the core headers.
short op
operation to perform
Definition: keymap.h:52
#define SKIPWS(ch)
Definition: string2.h:46
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
static void dump_all_menus(struct Buffer *buf, bool bind)
Dumps all the binds or macros inside every menu.
Definition: icommands.c:213
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
enum PagerMode mode
Pager mode.
Definition: lib.h:157
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:71
enum CommandResult(* parse)(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Function to parse information commands.
Definition: icommands.h:47
#define PATH_MAX
Definition: mutt.h:40
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:395
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: keymap.c:918
#define CS_DUMP_NO_FLAGS
No flags are set.
Definition: dump.h:35
char * macro
macro expansion (op == OP_MACRO)
Definition: keymap.h:50
char * dptr
Current read/write position.
Definition: buffer.h:36
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:120
char * data
Pointer to data.
Definition: buffer.h:35
bool dump_config(struct ConfigSet *cs, ConfigDumpFlags flags, FILE *fp)
Write all the config to a file.
Definition: dump.c:165
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
PagerFlags flags
Additional settings to tweak pager&#39;s function.
Definition: lib.h:158
Display version and copyright about NeoMutt.
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
char * desc
description of a macro for the help menu
Definition: keymap.h:51
const struct Binding * km_get_table(enum MenuType mtype)
Lookup a menu&#39;s keybindings.
Definition: keymap.c:1313
A keyboard mapping.
Definition: keymap.h:48
Success: Command worked.
Definition: mutt_commands.h:38
Definitions of user functions.
size_t escape_string(struct Buffer *buf, const char *src)
Write a string to a buffer, escaping special characters.
Definition: dump.c:46
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:31
static enum CommandResult icmd_bind(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse &#39;bind&#39; and &#39;macro&#39; commands - Implements ICommand::parse()
Definition: icommands.c:231
Mapping between user-readable string and a constant.
Definition: mapping.h:31
#define MAX_SEQ
Definition: keymap.h:36
static void dump_macro(struct Buffer *buf, struct Mapping *menu, struct Keymap *map)
Dump a macro map to a buffer.
Definition: icommands.c:157
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
const char * name
Definition: mapping.h:33
const char * fname
Name of the file to read.
Definition: lib.h:148
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
set current read/write position to offset from beginning
Definition: buffer.c:466
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:54
const char * banner
Title to display in status bar.
Definition: lib.h:159
GUI display a file/email/help in a viewport with paging.
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:135
Mapping between a user key and a function.
Definition: keymap.h:91
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition: mapping.c:85