NeoMutt  2023-05-17-16-g61469c
Teaching an old dog new tricks
DOXYGEN
functions.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <stddef.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include "mutt/lib.h"
34#include "address/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "gui/lib.h"
38#include "mutt.h"
39#include "functions.h"
40#include "lib.h"
41#include "enter/lib.h"
42#include "menu/lib.h"
43#include "pattern/lib.h"
44#include "question/lib.h"
45#include "alias.h"
46#include "gui.h"
47#include "opcodes.h"
48
52static int op_create_alias(struct AliasMenuData *mdata, int op)
53{
54 struct Menu *menu = mdata->menu;
55
56 if (menu->tag_prefix)
57 {
58 struct AddressList naddr = TAILQ_HEAD_INITIALIZER(naddr);
59
60 struct AliasView *avp = NULL;
61 ARRAY_FOREACH(avp, &mdata->ava)
62 {
63 if (!avp->is_tagged)
64 continue;
65
66 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
67 if (alias_to_addrlist(&al, avp->alias))
68 {
69 mutt_addrlist_copy(&naddr, &al, false);
71 }
72 }
73
74 alias_create(&naddr, mdata->sub);
75 mutt_addrlist_clear(&naddr);
76 }
77 else
78 {
79 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
80 if (alias_to_addrlist(&al, ARRAY_GET(&mdata->ava, menu_get_index(menu))->alias))
81 {
82 alias_create(&al, mdata->sub);
84 }
85 }
86 return FR_SUCCESS;
87}
88
92static int op_delete(struct AliasMenuData *mdata, int op)
93{
94 struct Menu *menu = mdata->menu;
95
96 if (menu->tag_prefix)
97 {
98 struct AliasView *avp = NULL;
99 ARRAY_FOREACH(avp, &mdata->ava)
100 {
101 if (avp->is_tagged)
102 avp->is_deleted = (op == OP_DELETE);
103 }
105 }
106 else
107 {
108 int index = menu_get_index(menu);
109 ARRAY_GET(&mdata->ava, index)->is_deleted = (op == OP_DELETE);
111 const bool c_resolve = cs_subset_bool(mdata->sub, "resolve");
112 if (c_resolve && (index < (menu->max - 1)))
113 {
114 menu_set_index(menu, index + 1);
116 }
117 }
118 return FR_SUCCESS;
119}
120
124static int op_exit(struct AliasMenuData *mdata, int op)
125{
126 return FR_DONE;
127}
128
138static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
139{
140 struct Menu *menu = mdata->menu;
141 if (menu->tag_prefix)
142 {
143 // Untag any non-visible aliases
144 struct AliasView *avp = NULL;
145 ARRAY_FOREACH(avp, &mdata->ava)
146 {
147 if (avp->is_tagged && !avp->is_visible)
148 avp->is_tagged = false;
149 }
150 }
151 else
152 {
153 // Untag all but the current alias
154 struct AliasView *avp = NULL;
155 const int idx = menu_get_index(menu);
156 ARRAY_FOREACH(avp, &mdata->ava)
157 {
158 avp->is_tagged = (ARRAY_FOREACH_IDX == idx);
159 }
160 }
161
162 return FR_CONTINUE;
163}
164
168static int op_main_limit(struct AliasMenuData *mdata, int op)
169{
170 struct Menu *menu = mdata->menu;
171 int rc = mutt_pattern_alias_func(_("Limit to addresses matching: "), mdata, menu);
172 if (rc != 0)
173 return FR_NO_ACTION;
174
175 alias_array_sort(&mdata->ava, mdata->sub);
176 alias_set_title(mdata->sbar, mdata->title, mdata->limit);
178 window_redraw(NULL);
179
180 return FR_SUCCESS;
181}
182
190static int op_query(struct AliasMenuData *mdata, int op)
191{
192 struct Buffer *buf = mdata->query;
193 if ((buf_get_field(_("Query: "), buf, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0) ||
194 buf_is_empty(buf))
195 {
196 return FR_NO_ACTION;
197 }
198
199 if (op == OP_QUERY)
200 {
201 ARRAY_FREE(&mdata->ava);
202 aliaslist_free(mdata->al);
203 }
204
205 struct Menu *menu = mdata->menu;
206 struct AliasList al = TAILQ_HEAD_INITIALIZER(al);
207
208 query_run(buf_string(buf), true, &al, mdata->sub);
210 char title[256] = { 0 };
211 snprintf(title, sizeof(title), "%s%s", _("Query: "), buf_string(buf));
212 sbar_set_title(mdata->sbar, title);
213
214 if (TAILQ_EMPTY(&al))
215 {
216 if (op == OP_QUERY)
217 menu->max = 0;
218 return FR_NO_ACTION;
219 }
220
221 struct Alias *np = NULL;
222 struct Alias *tmp = NULL;
223 TAILQ_FOREACH_SAFE(np, &al, entries, tmp)
224 {
225 alias_array_alias_add(&mdata->ava, np);
226 TAILQ_REMOVE(&al, np, entries);
227 TAILQ_INSERT_TAIL(mdata->al, np, entries); // Transfer
228 }
229 alias_array_sort(&mdata->ava, mdata->sub);
230 menu->max = ARRAY_SIZE(&mdata->ava);
231 return FR_SUCCESS;
232}
233
243static int op_search(struct AliasMenuData *mdata, int op)
244{
245 struct Menu *menu = mdata->menu;
246 int index = mutt_search_alias_command(menu, menu_get_index(menu), op);
247 if (index == -1)
248 return FR_NO_ACTION;
249
250 menu_set_index(menu, index);
251 return FR_SUCCESS;
252}
253
261static int op_sort(struct AliasMenuData *mdata, int op)
262{
263 int sort = cs_subset_sort(mdata->sub, "sort_alias");
264 bool resort = true;
265 bool reverse = (op == OP_SORT_REVERSE);
266
267 switch (mutt_multi_choice(reverse ?
268 /* L10N: The highlighted letters must match the "Sort" options */
269 _("Rev-Sort (a)lias, a(d)dress or (u)nsorted?") :
270 /* L10N: The highlighted letters must match the "Rev-Sort" options */
271 _("Sort (a)lias, a(d)dress or (u)nsorted?"),
272 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
273 _("adu")))
274 {
275 case -1: /* abort */
276 resort = false;
277 break;
278
279 case 1: /* (a)lias */
280 sort = SORT_ALIAS;
281 break;
282
283 case 2: /* a(d)dress */
284 sort = SORT_ADDRESS;
285 break;
286
287 case 3: /* (u)nsorted */
288 sort = SORT_ORDER;
289 break;
290 }
291
292 if (resort)
293 {
294 sort |= reverse ? SORT_REVERSE : 0;
295
296 // This will trigger a WA_RECALC
297 cs_subset_str_native_set(mdata->sub, "sort_alias", sort, NULL);
298 }
299
300 return FR_SUCCESS;
301}
302
303// -----------------------------------------------------------------------------
304
308static const struct AliasFunction AliasFunctions[] = {
309 // clang-format off
310 { OP_CREATE_ALIAS, op_create_alias },
311 { OP_DELETE, op_delete },
312 { OP_EXIT, op_exit },
313 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
314 { OP_MAIL, op_generic_select_entry },
315 { OP_MAIN_LIMIT, op_main_limit },
316 { OP_QUERY, op_query },
317 { OP_QUERY_APPEND, op_query },
318 { OP_SEARCH, op_search },
319 { OP_SEARCH_NEXT, op_search },
320 { OP_SEARCH_OPPOSITE, op_search },
321 { OP_SEARCH_REVERSE, op_search },
322 { OP_SORT, op_sort },
323 { OP_SORT_REVERSE, op_sort },
324 { OP_UNDELETE, op_delete },
325 { 0, NULL },
326 // clang-format on
327};
328
333{
334 if (!win || !win->wdata)
335 return FR_UNKNOWN;
336
337 struct Menu *menu = win->wdata;
338 struct AliasMenuData *mdata = menu->mdata;
339 int rc = FR_UNKNOWN;
340 for (size_t i = 0; AliasFunctions[i].op != OP_NULL; i++)
341 {
342 const struct AliasFunction *fn = &AliasFunctions[i];
343 if (fn->op == op)
344 {
345 rc = fn->function(mdata, op);
346 break;
347 }
348 }
349
350 if (rc == FR_UNKNOWN) // Not our function
351 return rc;
352
353 const char *result = dispacher_get_retval_name(rc);
354 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
355
356 return rc;
357}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:752
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1450
Email Address Handling.
static const struct AliasFunction AliasFunctions[]
All the NeoMutt functions that the Alias supports.
Definition: functions.c:308
void alias_array_sort(struct AliasViewArray *ava, const struct ConfigSubset *sub)
Sort and reindex an AliasViewArray.
Definition: sort.c:169
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:369
void aliaslist_free(struct AliasList *al)
Free a List of Aliases.
Definition: alias.c:657
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:211
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:301
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
const char * dispacher_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_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:256
bool alias_to_addrlist(struct AddressList *al, struct Alias *alias)
Turn an Alias into an AddressList.
Definition: dlg_query.c:118
Enter a string.
int buf_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
static int op_delete(struct AliasMenuData *mdata, int op)
delete the current entry - Implements alias_function_t -
Definition: functions.c:92
static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
select the current entry - Implements alias_function_t -
Definition: functions.c:138
static int op_main_limit(struct AliasMenuData *mdata, int op)
show only messages matching a pattern - Implements alias_function_t -
Definition: functions.c:168
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:124
static int op_query(struct AliasMenuData *mdata, int op)
query external program for addresses - Implements alias_function_t -
Definition: functions.c:190
static int op_search(struct AliasMenuData *mdata, int op)
search for a regular expression - Implements alias_function_t -
Definition: functions.c:243
static int op_create_alias(struct AliasMenuData *mdata, int op)
create an alias from a message sender - Implements alias_function_t -
Definition: functions.c:52
static int op_sort(struct AliasMenuData *mdata, int op)
sort aliases - Implements alias_function_t -
Definition: functions.c:261
int alias_function_dispatcher(struct MuttWindow *win, int op)
Perform a Alias function - Implements function_dispatcher_t -.
Definition: functions.c:332
#define mutt_debug(LEVEL,...)
Definition: logging2.h:84
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:69
Shared code for the Alias and Query Dialogs.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:40
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:179
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:155
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:59
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:169
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:55
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:605
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
All user-callable functions.
Match patterns to emails.
int mutt_search_alias_command(struct Menu *menu, int cur, int op)
Perform a search.
Definition: pattern.c:609
int mutt_pattern_alias_func(char *prompt, struct AliasMenuData *mdata, struct Menu *menu)
Perform some Pattern matching for Alias.
Definition: pattern.c:193
Ask the user a question.
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:224
Sidebar functions.
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:44
@ SORT_ALIAS
Sort by email alias.
Definition: sort2.h:49
@ SORT_ADDRESS
Sort by email address.
Definition: sort2.h:50
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:75
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:52
struct AliasViewArray ava
All Aliases/Queries.
Definition: gui.h:53
struct MuttWindow * sbar
Status Bar.
Definition: gui.h:59
struct Menu * menu
Menu.
Definition: gui.h:56
struct Buffer * query
Query string.
Definition: gui.h:57
struct AliasList * al
Alias data.
Definition: gui.h:54
struct ConfigSubset * sub
Config items.
Definition: gui.h:55
GUI data wrapping an Alias.
Definition: gui.h:36
bool is_visible
Is visible?
Definition: gui.h:43
struct Alias * alias
Alias.
Definition: gui.h:44
bool is_deleted
Is it deleted?
Definition: gui.h:42
bool is_tagged
Is it tagged?
Definition: gui.h:41
A shortcut for an email address or addresses.
Definition: alias.h:34
String manipulation buffer.
Definition: buffer.h:34
Definition: lib.h:70
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:77
void * mdata
Private data.
Definition: lib.h:138
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:76
int max
Number of entries in the menu.
Definition: lib.h:72
void * wdata
Private data.
Definition: mutt_window.h:145
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:310