NeoMutt  2024-12-12-19-ge4b57e
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
30#include "config.h"
31#ifdef _MAKEDOC
32#include "docs/makedoc_defs.h"
33#else
34#include <stdbool.h>
35#include <stddef.h>
36#include <stdio.h>
37#include "mutt/lib.h"
38#include "address/lib.h"
39#include "config/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "mutt.h"
43#include "lib.h"
44#include "editor/lib.h"
45#include "history/lib.h"
46#include "key/lib.h"
47#include "menu/lib.h"
48#include "pattern/lib.h"
49#include "question/lib.h"
50#include "alias.h"
51#include "functions.h"
52#include "gui.h"
53#include "sort.h"
54#endif
55
56// clang-format off
60const struct MenuFuncOp OpAlias[] = { /* map: alias */
61 { "delete-entry", OP_DELETE },
62 { "exit", OP_EXIT },
63 { "limit", OP_MAIN_LIMIT },
64 { "mail", OP_MAIL },
65 { "sort-alias", OP_SORT },
66 { "sort-alias-reverse", OP_SORT_REVERSE },
67 { "tag-pattern", OP_MAIN_TAG_PATTERN },
68 { "undelete-entry", OP_UNDELETE },
69 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
70 { NULL, 0 },
71};
72
76const struct MenuFuncOp OpQuery[] = { /* map: query */
77 { "create-alias", OP_CREATE_ALIAS },
78 { "exit", OP_EXIT },
79 { "limit", OP_MAIN_LIMIT },
80 { "mail", OP_MAIL },
81 { "query", OP_QUERY },
82 { "query-append", OP_QUERY_APPEND },
83 { "sort", OP_SORT },
84 { "sort-reverse", OP_SORT_REVERSE },
85 { "tag-pattern", OP_MAIN_TAG_PATTERN },
86 { "untag-pattern", OP_MAIN_UNTAG_PATTERN },
87 { NULL, 0 },
88};
89
93const struct MenuOpSeq AliasDefaultBindings[] = { /* map: alias */
94 { OP_DELETE, "d" },
95 { OP_EXIT, "q" },
96 { OP_MAIL, "m" },
97 { OP_MAIN_LIMIT, "l" },
98 { OP_MAIN_TAG_PATTERN, "T" },
99 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
100 { OP_SORT, "o" },
101 { OP_SORT_REVERSE, "O" },
102 { OP_TAG, "<space>" },
103 { OP_UNDELETE, "u" },
104 { 0, NULL },
105};
106
110const struct MenuOpSeq QueryDefaultBindings[] = { /* map: query */
111 { OP_CREATE_ALIAS, "a" },
112 { OP_EXIT, "q" },
113 { OP_MAIL, "m" },
114 { OP_MAIN_LIMIT, "l" },
115 { OP_MAIN_TAG_PATTERN, "T" },
116 { OP_MAIN_UNTAG_PATTERN, "\024" }, // <Ctrl-T>
117 { OP_QUERY, "Q" },
118 { OP_QUERY_APPEND, "A" },
119 { OP_SORT, "o" },
120 { OP_SORT_REVERSE, "O" },
121 { OP_TAG, "<space>" },
122 { 0, NULL },
123};
124// clang-format on
125
129static int op_create_alias(struct AliasMenuData *mdata, int op)
130{
131 struct Menu *menu = mdata->menu;
132
133 if (menu->tag_prefix)
134 {
135 struct AddressList naddr = TAILQ_HEAD_INITIALIZER(naddr);
136
137 struct AliasView *avp = NULL;
138 ARRAY_FOREACH(avp, &mdata->ava)
139 {
140 if (!avp->is_tagged)
141 continue;
142
143 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
144 if (alias_to_addrlist(&al, avp->alias))
145 {
146 mutt_addrlist_copy(&naddr, &al, false);
148 }
149 }
150
151 alias_create(&naddr, mdata->sub);
152 mutt_addrlist_clear(&naddr);
153 }
154 else
155 {
156 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
157 if (alias_to_addrlist(&al, ARRAY_GET(&mdata->ava, menu_get_index(menu))->alias))
158 {
159 alias_create(&al, mdata->sub);
161 }
162 }
163 return FR_SUCCESS;
164}
165
169static int op_delete(struct AliasMenuData *mdata, int op)
170{
171 struct Menu *menu = mdata->menu;
172
173 if (menu->tag_prefix)
174 {
175 struct AliasView *avp = NULL;
176 ARRAY_FOREACH(avp, &mdata->ava)
177 {
178 if (avp->is_tagged)
179 avp->is_deleted = (op == OP_DELETE);
180 }
182 }
183 else
184 {
185 int index = menu_get_index(menu);
186 ARRAY_GET(&mdata->ava, index)->is_deleted = (op == OP_DELETE);
188 const bool c_resolve = cs_subset_bool(mdata->sub, "resolve");
189 if (c_resolve && (index < (menu->max - 1)))
190 {
191 menu_set_index(menu, index + 1);
193 }
194 }
195 return FR_SUCCESS;
196}
197
201static int op_exit(struct AliasMenuData *mdata, int op)
202{
203 return FR_DONE;
204}
205
215static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
216{
217 struct Menu *menu = mdata->menu;
218 if (menu->tag_prefix)
219 {
220 // Untag any non-visible aliases
221 struct AliasView *avp = NULL;
222 ARRAY_FOREACH(avp, &mdata->ava)
223 {
224 if (avp->is_tagged && !avp->is_visible)
225 avp->is_tagged = false;
226 }
227 }
228 else
229 {
230 // Untag all but the current alias
231 struct AliasView *avp = NULL;
232 const int idx = menu_get_index(menu);
233 ARRAY_FOREACH(avp, &mdata->ava)
234 {
235 avp->is_tagged = (ARRAY_FOREACH_IDX == idx);
236 }
237 }
238
239 return FR_CONTINUE;
240}
241
245static int op_main_limit(struct AliasMenuData *mdata, int op)
246{
247 struct Menu *menu = mdata->menu;
248 int rc = mutt_pattern_alias_func(_("Limit to addresses matching: "), mdata,
249 PAA_VISIBLE, menu);
250 if (rc != 0)
251 return FR_NO_ACTION;
252
253 alias_array_sort(&mdata->ava, mdata->sub);
254 alias_set_title(mdata->sbar, mdata->title, mdata->limit);
256 window_redraw(NULL);
257
258 return FR_SUCCESS;
259}
260
264static int op_main_tag_pattern(struct AliasMenuData *mdata, int op)
265{
266 struct Menu *menu = mdata->menu;
267 int rc = mutt_pattern_alias_func(_("Tag addresses matching: "), mdata, PAA_TAG, menu);
268 if (rc != 0)
269 return FR_NO_ACTION;
270
272 window_redraw(NULL);
273
274 return FR_SUCCESS;
275}
276
280static int op_main_untag_pattern(struct AliasMenuData *mdata, int op)
281{
282 struct Menu *menu = mdata->menu;
283 int rc = mutt_pattern_alias_func(_("Untag addresses matching: "), mdata, PAA_UNTAG, menu);
284 if (rc != 0)
285 return FR_NO_ACTION;
286
288 window_redraw(NULL);
289
290 return FR_SUCCESS;
291}
292
300static int op_query(struct AliasMenuData *mdata, int op)
301{
302 struct Buffer *buf = mdata->query;
303 if ((mw_get_field(_("Query: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
304 buf_is_empty(buf))
305 {
306 return FR_NO_ACTION;
307 }
308
309 if (op == OP_QUERY)
310 {
311 ARRAY_FREE(&mdata->ava);
312 aliaslist_clear(mdata->al);
313 }
314
315 struct Menu *menu = mdata->menu;
316 struct AliasList al = TAILQ_HEAD_INITIALIZER(al);
317
318 query_run(buf_string(buf), true, &al, mdata->sub);
320 char title[256] = { 0 };
321 snprintf(title, sizeof(title), "%s%s", _("Query: "), buf_string(buf));
322 sbar_set_title(mdata->sbar, title);
323
324 if (TAILQ_EMPTY(&al))
325 {
326 if (op == OP_QUERY)
327 menu->max = 0;
328 return FR_NO_ACTION;
329 }
330
331 struct Alias *np = NULL;
332 struct Alias *tmp = NULL;
333 TAILQ_FOREACH_SAFE(np, &al, entries, tmp)
334 {
335 alias_array_alias_add(&mdata->ava, np);
336 TAILQ_REMOVE(&al, np, entries);
337 TAILQ_INSERT_TAIL(mdata->al, np, entries); // Transfer
338 }
339 alias_array_sort(&mdata->ava, mdata->sub);
340 menu->max = ARRAY_SIZE(&mdata->ava);
341 return FR_SUCCESS;
342}
343
353static int op_search(struct AliasMenuData *mdata, int op)
354{
356 switch (op)
357 {
358 case OP_SEARCH:
359 flags |= SEARCH_PROMPT;
360 mdata->search_state->reverse = false;
361 break;
362 case OP_SEARCH_REVERSE:
363 flags |= SEARCH_PROMPT;
364 mdata->search_state->reverse = true;
365 break;
366 case OP_SEARCH_NEXT:
367 break;
368 case OP_SEARCH_OPPOSITE:
369 flags |= SEARCH_OPPOSITE;
370 break;
371 }
372
373 struct Menu *menu = mdata->menu;
374 int index = menu_get_index(menu);
375 index = mutt_search_alias_command(menu, index, mdata->search_state, flags);
376 if (index == -1)
377 return FR_NO_ACTION;
378
379 menu_set_index(menu, index);
380 return FR_SUCCESS;
381}
382
390static int op_sort(struct AliasMenuData *mdata, int op)
391{
392 int sort = cs_subset_sort(mdata->sub, "alias_sort");
393 bool resort = true;
394 bool reverse = (op == OP_SORT_REVERSE);
395
396 switch (mw_multi_choice(reverse ?
397 /* L10N: The highlighted letters must match the "Sort" options */
398 _("Rev-Sort (a)lias, (n)ame, (e)mail or (u)nsorted?") :
399 /* L10N: The highlighted letters must match the "Rev-Sort" options */
400 _("Sort (a)lias, (n)ame, (e)mail or (u)nsorted?"),
401 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
402 _("aneu")))
403 {
404 case -1: /* abort */
405 resort = false;
406 break;
407
408 case 1: /* (a)lias */
409 sort = ALIAS_SORT_ALIAS;
410 break;
411
412 case 2: /* (n)ame */
413 sort = ALIAS_SORT_NAME;
414 break;
415
416 case 3: /* (e)mail */
417 sort = ALIAS_SORT_EMAIL;
418 break;
419
420 case 4: /* (u)nsorted */
421 sort = ALIAS_SORT_UNSORTED;
422 break;
423 }
424
425 if (resort)
426 {
427 sort |= reverse ? SORT_REVERSE : 0;
428
429 // This will trigger a WA_RECALC
430 cs_subset_str_native_set(mdata->sub, "alias_sort", sort, NULL);
431 }
432
433 return FR_SUCCESS;
434}
435
436// -----------------------------------------------------------------------------
437
441static const struct AliasFunction AliasFunctions[] = {
442 // clang-format off
443 { OP_CREATE_ALIAS, op_create_alias },
444 { OP_DELETE, op_delete },
445 { OP_EXIT, op_exit },
446 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
447 { OP_MAIL, op_generic_select_entry },
448 { OP_MAIN_LIMIT, op_main_limit },
449 { OP_MAIN_TAG_PATTERN, op_main_tag_pattern },
450 { OP_MAIN_UNTAG_PATTERN, op_main_untag_pattern },
451 { OP_QUERY, op_query },
452 { OP_QUERY_APPEND, op_query },
453 { OP_SEARCH, op_search },
454 { OP_SEARCH_NEXT, op_search },
455 { OP_SEARCH_OPPOSITE, op_search },
456 { OP_SEARCH_REVERSE, op_search },
457 { OP_SORT, op_sort },
458 { OP_SORT_REVERSE, op_sort },
459 { OP_UNDELETE, op_delete },
460 { 0, NULL },
461 // clang-format on
462};
463
468{
469 // The Dispatcher may be called on any Window in the Dialog
470 struct MuttWindow *dlg = dialog_find(win);
471 if (!dlg || !dlg->wdata)
472 return FR_ERROR;
473
474 struct Menu *menu = dlg->wdata;
475 struct AliasMenuData *mdata = menu->mdata;
476
477 int rc = FR_UNKNOWN;
478 for (size_t i = 0; AliasFunctions[i].op != OP_NULL; i++)
479 {
480 const struct AliasFunction *fn = &AliasFunctions[i];
481 if (fn->op == op)
482 {
483 rc = fn->function(mdata, op);
484 break;
485 }
486 }
487
488 if (rc == FR_UNKNOWN) // Not our function
489 return rc;
490
491 const char *result = dispatcher_get_retval_name(rc);
492 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
493
494 return rc;
495}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
Email Address Handling.
const struct MenuFuncOp OpQuery[]
Functions for the external Query Menu.
Definition: functions.c:76
const struct MenuOpSeq QueryDefaultBindings[]
Key bindings for the external Query Menu.
Definition: functions.c:110
const struct MenuOpSeq AliasDefaultBindings[]
Key bindings for the Alias Menu.
Definition: functions.c:93
static const struct AliasFunction AliasFunctions[]
All the NeoMutt functions that the Alias supports.
Definition: functions.c:441
const struct MenuFuncOp OpAlias[]
Functions for the Alias Menu.
Definition: functions.c:60
void alias_array_sort(struct AliasViewArray *ava, const struct ConfigSubset *sub)
Sort and reindex an AliasViewArray.
Definition: sort.c:235
@ ALIAS_SORT_UNSORTED
Sort by the order the Aliases were configured.
Definition: sort.h:34
@ ALIAS_SORT_NAME
Sort by Real Name.
Definition: sort.h:33
@ ALIAS_SORT_EMAIL
Sort by Email Address.
Definition: sort.h:32
@ ALIAS_SORT_ALIAS
Sort by Alias short name.
Definition: sort.h:31
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:367
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:697
Representation of a single alias to an email address.
int alias_array_alias_add(struct AliasViewArray *ava, struct Alias *alias)
Add an Alias to the AliasViewArray.
Definition: array.c:47
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:266
Convenience wrapper for the config headers.
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort.h:39
Convenience wrapper for the core headers.
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
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_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_CONTINUE
Remain in the Dialog.
Definition: dispatcher.h:34
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
int query_run(const char *s, bool verbose, struct AliasList *al, const struct ConfigSubset *sub)
Run an external program to find Addresses.
Definition: dlg_query.c:189
bool alias_to_addrlist(struct AddressList *al, struct Alias *alias)
Turn an Alias into an AddressList.
Definition: dlg_query.c:120
Edit a string.
static int op_delete(struct AliasMenuData *mdata, int op)
delete the current entry - Implements alias_function_t -
Definition: functions.c:169
static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
select the current entry - Implements alias_function_t -
Definition: functions.c:215
static int op_main_tag_pattern(struct AliasMenuData *mdata, int op)
Tag messages matching a pattern - Implements alias_function_t -.
Definition: functions.c:264
static int op_main_limit(struct AliasMenuData *mdata, int op)
show only messages matching a pattern - Implements alias_function_t -
Definition: functions.c:245
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:201
static int op_main_untag_pattern(struct AliasMenuData *mdata, int op)
Untag messages matching a pattern - Implements alias_function_t -.
Definition: functions.c:280
static int op_query(struct AliasMenuData *mdata, int op)
query external program for addresses - Implements alias_function_t -
Definition: functions.c:300
static int op_search(struct AliasMenuData *mdata, int op)
search for a regular expression - Implements alias_function_t -
Definition: functions.c:353
static int op_create_alias(struct AliasMenuData *mdata, int op)
create an alias from a message sender - Implements alias_function_t -
Definition: functions.c:129
static int op_sort(struct AliasMenuData *mdata, int op)
sort aliases - Implements alias_function_t -
Definition: functions.c:390
int alias_function_dispatcher(struct MuttWindow *win, int op)
Perform a Alias function - Implements function_dispatcher_t -.
Definition: functions.c:467
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
Convenience wrapper for the gui headers.
void alias_set_title(struct MuttWindow *sbar, char *menu_name, char *limit)
Create a title string for the Menu.
Definition: gui.c:72
Shared code for the Alias and Query Dialogs.
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:58
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
Match patterns to emails.
@ PAA_VISIBLE
Set AliasView.is_visible and hide the rest.
Definition: lib.h:190
@ PAA_TAG
Set AliasView.is_tagged, but don't touch the others.
Definition: lib.h:188
@ PAA_UNTAG
Unset AliasView.is_tagged, but don't touch the others.
Definition: lib.h:189
int mutt_pattern_alias_func(char *prompt, struct AliasMenuData *mdata, enum PatternAlias action, struct Menu *menu)
Perform some Pattern matching for Alias.
Definition: pattern.c:191
int mutt_search_alias_command(struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
Perform a search.
Definition: pattern.c:636
Ask the user a question.
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:753
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:827
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:862
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:655
#define TAILQ_EMPTY(head)
Definition: queue.h:739
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:227
#define SEARCH_OPPOSITE
Search in the opposite direction.
Definition: search_state.h:46
uint8_t SearchFlags
Flags for a specific search, e.g. SEARCH_PROMPT.
Definition: search_state.h:43
#define SEARCH_NO_FLAGS
No flags are set.
Definition: search_state.h:44
#define SEARCH_PROMPT
Ask for search input.
Definition: search_state.h:45
Sidebar functions.
Sidebar sorting functions.
Key value store.
#define NONULL(x)
Definition: string2.h:37
A NeoMutt function.
Definition: functions.h:52
int op
Op code, e.g. OP_SEARCH.
Definition: functions.h:53
alias_function_t function
Function to call.
Definition: functions.h:54
AliasView array wrapper with Pattern information -.
Definition: gui.h:54
struct AliasViewArray ava
All Aliases/Queries.
Definition: gui.h:55
struct SearchState * search_state
State of the current search.
Definition: gui.h:63
struct MuttWindow * sbar
Status Bar.
Definition: gui.h:61
struct Menu * menu
Menu.
Definition: gui.h:58
struct Buffer * query
Query string.
Definition: gui.h:59
struct AliasList * al
Alias data.
Definition: gui.h:56
struct ConfigSubset * sub
Config items.
Definition: gui.h:57
GUI data wrapping an Alias.
Definition: gui.h:38
bool is_visible
Is visible?
Definition: gui.h:45
struct Alias * alias
Alias.
Definition: gui.h:46
bool is_deleted
Is it deleted?
Definition: gui.h:44
bool is_tagged
Is it tagged?
Definition: gui.h:43
A shortcut for an email address or addresses.
Definition: alias.h:35
String manipulation buffer.
Definition: buffer.h:36
Mapping between a function and an operation.
Definition: lib.h:101
Mapping between an operation and a key sequence.
Definition: lib.h:110
int op
Operation, e.g. OP_DELETE.
Definition: lib.h:111
Definition: lib.h:79
void * mdata
Private data.
Definition: lib.h:147
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:85
int max
Number of entries in the menu.
Definition: lib.h:81
void * wdata
Private data.
Definition: mutt_window.h:145
bool reverse
search backwards
Definition: search_state.h:40
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:297