NeoMutt  2025-12-11-949-g4870ee
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <stdbool.h>
31#include <stddef.h>
32#include <stdio.h>
33#include "mutt/lib.h"
34#include "email/lib.h"
35#include "core/lib.h"
36#include "gui/lib.h"
37#include "functions.h"
38#include "lib.h"
39#include "key/lib.h"
40#include "menu/lib.h"
41#include "send/lib.h"
42#include "module_data.h"
43
45const struct ListAction ListActions[] = {
46 // clang-format off
47 { N_("Help"), OP_LIST_HELP, offsetof(struct Rfc2369ListHeaders, help) },
48 { N_("Post"), OP_LIST_POST, offsetof(struct Rfc2369ListHeaders, post) },
49 { N_("Subscribe"), OP_LIST_SUBSCRIBE, offsetof(struct Rfc2369ListHeaders, subscribe) },
50 { N_("Unsubscribe"), OP_LIST_UNSUBSCRIBE, offsetof(struct Rfc2369ListHeaders, unsubscribe) },
51 { N_("Archives"), OP_LIST_ARCHIVE, offsetof(struct Rfc2369ListHeaders, archive) },
52 { N_("Owner"), OP_LIST_OWNER, offsetof(struct Rfc2369ListHeaders, owner) },
53 // clang-format on
54};
55
58
59// clang-format off
63static const struct MenuFuncOp OpList[] = { /* map: list */
64 { "list-archive", OP_LIST_ARCHIVE },
65 { "list-help", OP_LIST_HELP },
66 { "list-owner", OP_LIST_OWNER },
67 { "list-post", OP_LIST_POST },
68 { "list-subscribe", OP_LIST_SUBSCRIBE },
69 { "list-unsubscribe", OP_LIST_UNSUBSCRIBE },
70 { NULL, 0 },
71};
72
76static const struct MenuOpSeq ListDefaultBindings[] = { /* map: list */
77 { OP_LIST_ARCHIVE, "a" },
78 { OP_LIST_HELP, "h" },
79 { OP_LIST_OWNER, "o" },
80 { OP_LIST_POST, "p" },
81 { OP_LIST_SUBSCRIBE, "s" },
82 { OP_LIST_UNSUBSCRIBE, "u" },
83 { 0, NULL },
84};
85// clang-format on
86
90void mlist_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
91{
92 struct MenuDefinition *md = NULL;
93 struct MenuDefinition *md_list = NULL;
94 struct SubMenu *sm_list = NULL;
95
96 sm_list = km_register_submenu(OpList);
97 md_list = km_register_menu(MENU_LIST, "list");
98 km_menu_add_submenu(md_list, sm_list);
99 km_menu_add_submenu(md_list, sm_generic);
101
103 ASSERT(mod_data);
104 mod_data->menu_mlist = md;
105}
106
113struct ListHead *mlist_action_value(struct Rfc2369ListHeaders *headers,
114 const struct ListAction *action)
115{
116 return (struct ListHead *) (((char *) headers) + action->offset);
117}
118
126static bool compose_list_action(struct ListData *ld, const struct ListEntry *entry)
127{
128 if (!entry || !entry->value)
129 {
130 mutt_error(_("No list action available"));
131 return false;
132 }
133
134 const char *uri = entry->value;
135 if (!mutt_istr_startswith(uri, "mailto:"))
136 return false;
137
138 struct Email *e = email_new();
139 e->env = mutt_env_new();
140
141 char *body = NULL;
142 if (!mutt_parse_mailto(e->env, &body, uri))
143 {
144 mutt_error(_("Could not parse mailto: URI"));
145 FREE(&body);
146 email_free(&e);
147 return true;
148 }
149
150 e->body = mutt_body_new();
151 char ctype[] = "text/plain";
152 mutt_parse_content_type(ctype, e->body);
153 e->body->use_disp = false;
155
156 struct Buffer *tempfile = buf_pool_get();
157 buf_mktemp_draft(tempfile);
158 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
159 if (!fp)
160 {
161 mutt_perror("%s", buf_string(tempfile));
162 FREE(&body);
163 email_free(&e);
164 buf_pool_release(&tempfile);
165 return true;
166 }
167
168 if (body)
169 fprintf(fp, "%s\n", body);
170 mutt_file_fclose(&fp);
171 FREE(&body);
172
173 e->body->filename = buf_strdup(tempfile);
174 e->body->unlink = true;
175 buf_pool_release(&tempfile);
176
177 (void) mutt_send_message(SEND_DRAFT_FILE, e, NULL, ld->mailbox, NULL, NeoMutt->sub);
178 return true;
179}
180
187static int op_quit(struct ListData *ld, const struct KeyEvent *event)
188{
189 ld->done = true;
190 return FR_SUCCESS;
191}
192
204static int op_select_action(struct ListData *ld, const struct KeyEvent *event)
205{
206 const struct ListEntry *entry = NULL;
207
208 if (event && (event->op != OP_GENERIC_SELECT_ENTRY))
209 {
210 int first_match = -1;
211 int num_matches = 0;
212 for (int i = 0; i < ARRAY_SIZE(&ld->entries); i++)
213 {
214 const struct ListEntry *candidate = ARRAY_GET(&ld->entries, i);
215 if (candidate && (candidate->action->op == event->op))
216 {
217 if (first_match < 0)
218 first_match = i;
219 num_matches++;
220 }
221 }
222
223 if (num_matches == 0)
224 return FR_NO_ACTION;
225
226 menu_set_index(ld->menu, first_match);
227
228 // Several matches: just select the first, let the user choose
229 if (num_matches > 1)
230 return FR_SUCCESS;
231
232 entry = ARRAY_GET(&ld->entries, first_match);
233 }
234 else
235 {
236 entry = ARRAY_GET(&ld->entries, menu_get_index(ld->menu));
237 }
238
239 if (!entry)
240 return FR_NO_ACTION;
241
242 ld->done = compose_list_action(ld, entry);
243 return FR_SUCCESS;
244}
245
246// -----------------------------------------------------------------------------
247
251static const struct MlistFunction MlistFunctions[] = {
252 // clang-format off
253 { OP_EXIT, op_quit },
254 { OP_GENERIC_SELECT_ENTRY, op_select_action },
255 { OP_LIST_ARCHIVE, op_select_action },
256 { OP_LIST_HELP, op_select_action },
257 { OP_LIST_OWNER, op_select_action },
258 { OP_LIST_POST, op_select_action },
259 { OP_LIST_SUBSCRIBE, op_select_action },
260 { OP_LIST_UNSUBSCRIBE, op_select_action },
261 { OP_QUIT, op_quit },
262 { 0, NULL },
263 // clang-format on
264};
265
269int mlist_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
270{
271 struct MuttWindow *dlg = dialog_find(win);
272 if (!event || !dlg || !dlg->wdata)
273 {
275 return FR_ERROR;
276 }
277
278 struct Menu *menu = dlg->wdata;
279 struct ListData *ld = menu->mdata;
280 if (!ld)
281 {
283 return FR_ERROR;
284 }
285
286 int rc = FR_UNKNOWN;
287 for (size_t i = 0; MlistFunctions[i].op != OP_NULL; i++)
288 {
289 if (MlistFunctions[i].op == event->op)
290 {
291 rc = MlistFunctions[i].function(ld, event);
292 break;
293 }
294 }
295
296 if (rc == FR_UNKNOWN)
297 return rc;
298
299 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(event->op),
302 return rc;
303}
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool candidate(struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition helpers.c:79
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:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
Structs that make up an email.
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:433
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition parse.c:1876
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
static int op_quit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Save changes and exit this dialog - Implements alias_function_t -.
Definition functions.c:308
int mlist_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a List dialog function - Implements function_dispatcher_t -.
Definition functions.c:269
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
static int op_select_action(struct ListData *ld, const struct KeyEvent *event)
Execute the selected mailing-list action - Implements mlist_function_t -.
Definition functions.c:204
Convenience wrapper for the gui headers.
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:88
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:105
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define countof(x)
Definition memory.h:49
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
GUI present the user with a selectable list.
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:167
@ DISP_INLINE
Content is inline.
Definition mime.h:62
static bool compose_list_action(struct ListData *ld, const struct ListEntry *entry)
Compose a message for a mailing-list action.
Definition functions.c:126
static const struct MenuFuncOp OpList[]
Functions for the List Dialog.
Definition functions.c:63
const int ListActionsCount
Number of entries in ListActions.
Definition functions.c:57
static const struct MenuOpSeq ListDefaultBindings[]
Key bindings for the List Dialog.
Definition functions.c:76
static const struct MlistFunction MlistFunctions[]
All the NeoMutt functions that the List Dialog supports.
Definition functions.c:251
const struct ListAction ListActions[]
Mailing-list actions shown in the dialog.
Definition functions.c:45
void mlist_init_keys(struct NeoMutt *n, struct SubMenu *sm_generic)
Initialise the Mlist Keybindings - Implements ::init_keys_api.
Definition functions.c:90
struct ListHead * mlist_action_value(struct Rfc2369ListHeaders *headers, const struct ListAction *action)
Get the stored value for a mailing-list action.
Definition functions.c:113
Mailing-list functions.
Mailing-list action dialog.
Mlist private Module data.
@ MODULE_ID_MLIST
ModuleMlist, Mailing-list
Definition module_api.h:80
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#define _(a)
Definition message.h:28
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
Convenience wrapper for the send headers.
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition send.c:2029
@ SEND_DRAFT_FILE
Used by the -H flag.
Definition send.h:56
#define ASSERT(COND)
Definition signal2.h:59
#define NONULL(x)
Definition string2.h:44
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
bool use_disp
Content-Disposition uses filename= ?
Definition body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
struct Body * body
List of MIME parts.
Definition email.h:69
An event such as a keypress.
Definition get.h:75
int op
Function opcode, e.g. OP_HELP.
Definition get.h:77
A mailing-list action in the dialog.
Definition functions.h:38
size_t offset
Offset into struct Rfc2369ListHeaders.
Definition functions.h:41
Private data for the Mailing-list action dialog.
Definition functions.h:64
struct Menu * menu
Dialog menu.
Definition functions.h:65
struct Mailbox * mailbox
Source mailbox.
Definition functions.h:66
struct ListEntryArray entries
Menu rows.
Definition functions.h:68
bool done
Exit the dialog.
Definition functions.h:70
A mailing-list action in the dialog.
Definition functions.h:48
const char * value
URI to use.
Definition functions.h:50
Functions for a Dialog or Window.
Definition menudef.h:44
Mapping between a function and an operation.
Definition menu.h:37
Mapping between an operation and a key sequence.
Definition menu.h:47
Definition lib.h:86
void * mdata
Private data.
Definition lib.h:155
A list dialog function.
Definition functions.h:92
Mlist private Module data.
Definition module_data.h:32
struct MenuDefinition * menu_mlist
Mlist menu definition.
Definition module_data.h:33
void * wdata
Private data.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Mailing-list actions from RFC 2369 headers.
Definition parse.h:41
Collection of related functions.
Definition menudef.h:33
#define buf_mktemp_draft(buf)
Definition tmp.h:34
@ MENU_LIST
Mailing-list actions.
Definition type.h:46