NeoMutt  2025-12-11-924-g64e75a
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
dlg_query.c File Reference

Routines for querying an external address book. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "lib.h"
#include "editor/lib.h"
#include "expando/lib.h"
#include "history/lib.h"
#include "key/lib.h"
#include "menu/lib.h"
#include "pattern/lib.h"
#include "send/lib.h"
#include "alias.h"
#include "expando.h"
#include "functions.h"
#include "gui.h"
#include "module_data.h"
#include "mutt_logging.h"
+ Include dependency graph for dlg_query.c:

Go to the source code of this file.

Functions

bool alias_to_addrlist (struct AddressList *al, struct Alias *alias)
 Turn an Alias into an AddressList.
 
static int query_make_entry (struct Menu *menu, int line, int max_cols, struct Buffer *buf)
 Format an Alias for the Menu - Implements Menu::make_entry() -.
 
static int query_tag (struct Menu *menu, int sel, int act)
 Tag an entry in the Query Menu - Implements Menu::tag() -.
 
int query_run (const char *s, bool verbose, struct AliasArray *aa, const struct ConfigSubset *sub)
 Run an external program to find Addresses.
 
static int query_window_observer (struct NotifyCallback *nc)
 Notification that a Window has changed - Implements observer_t -.
 
static struct SimpleDialogWindows query_dialog_new (struct AliasMenuData *mdata, const char *query)
 Create an Query Selection Dialog.
 
static bool dlg_query (struct Buffer *buf, struct AliasMenuData *mdata)
 Get the user to enter an Address Query -.
 
int query_complete (struct Buffer *buf, struct ConfigSubset *sub)
 Perform auto-complete using an Address Query.
 
void query_index (struct Mailbox *m, struct ConfigSubset *sub)
 Perform an Alias Query and display the results.
 

Variables

static const struct Mapping QueryHelp []
 Help Bar for the Address Query dialog.
 

Detailed Description

Routines for querying an external address book.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Dennis Schön
  • Tóth János

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file dlg_query.c.

Function Documentation

◆ alias_to_addrlist()

bool alias_to_addrlist ( struct AddressList * al,
struct Alias * alias )

Turn an Alias into an AddressList.

Parameters
alAddressList to fill (must be empty)
aliasAlias to use
Return values
trueSuccess

Definition at line 119 of file dlg_query.c.

120{
121 if (!al || !TAILQ_EMPTY(al) || !alias)
122 return false;
123
124 mutt_addrlist_copy(al, &alias->addr, false);
125 if (!TAILQ_EMPTY(al))
126 {
127 struct Address *first = TAILQ_FIRST(al);
128 struct Address *second = TAILQ_NEXT(first, entries);
129 if (!second && !first->personal)
130 {
131 first->personal = buf_new(alias->name);
132 }
133
134 mutt_addrlist_to_intl(al, NULL);
135 }
136
137 return true;
138}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1303
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:313
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_NEXT(elm, field)
Definition queue.h:889
#define TAILQ_EMPTY(head)
Definition queue.h:778
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
char * name
Short name.
Definition alias.h:36
struct AddressList addr
List of Addresses the Alias expands to.
Definition alias.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_run()

int query_run ( const char * s,
bool verbose,
struct AliasArray * aa,
const struct ConfigSubset * sub )

Run an external program to find Addresses.

Parameters
sString to match
verboseIf true, print progress messages
aaAlias list to fill
subConfig items
Return values
0Success
-1Error

Definition at line 188 of file dlg_query.c.

190{
191 FILE *fp = NULL;
192 char *buf = NULL;
193 size_t buflen;
194 char *msg = NULL;
195 size_t msglen = 0;
196 char *tok = NULL;
197 char *next_tok = NULL;
198 struct Buffer *cmd = buf_pool_get();
199
200 const char *const c_query_command = cs_subset_string(sub, "query_command");
201 buf_file_expand_fmt_quote(cmd, c_query_command, s);
202
203 pid_t pid = filter_create(buf_string(cmd), NULL, &fp, NULL, NeoMutt->env);
204 if (pid < 0)
205 {
206 mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", buf_string(cmd));
207 buf_pool_release(&cmd);
208 return -1;
209 }
210 buf_pool_release(&cmd);
211
212 if (verbose)
213 mutt_message(_("Waiting for response..."));
214
215 struct Buffer *addr = buf_pool_get();
216 /* The query protocol first reads one NL-terminated line. If an error
217 * occurs, this is assumed to be an error message. Otherwise it's ignored. */
218 msg = mutt_file_read_line(msg, &msglen, fp, NULL, MUTT_RL_NONE);
219 while ((buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NONE)))
220 {
221 tok = buf;
222 next_tok = strchr(tok, '\t');
223 if (next_tok)
224 *next_tok++ = '\0';
225
226 if (*tok == '\0')
227 continue;
228
229 struct Alias *alias = alias_new();
230
231 if (next_tok)
232 {
233 tok = next_tok;
234 next_tok = strchr(tok, '\t');
235 if (next_tok)
236 *next_tok++ = '\0';
237
238 // The address shouldn't be wrapped with <>s, but historically, this was supported
239 if (buf[0] == '<')
240 buf_printf(addr, "\"%s\" %s", tok, buf);
241 else
242 buf_printf(addr, "\"%s\" <%s>", tok, buf);
243
245
246 parse_alias_comments(alias, next_tok);
247 }
248 else
249 {
250 mutt_addrlist_parse(&alias->addr, buf); // Email address
251 }
252
253 ARRAY_ADD(aa, alias);
254 }
256
257 FREE(&buf);
258 mutt_file_fclose(&fp);
259 if (filter_wait(pid))
260 {
261 mutt_debug(LL_DEBUG1, "Error: %s\n", NONULL(msg));
262 if (verbose)
263 mutt_error("%s", NONULL(msg));
264 }
265 else
266 {
267 if (verbose)
268 mutt_message("%s", NONULL(msg));
269 }
270 FREE(&msg);
271
272 return 0;
273}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
void parse_alias_comments(struct Alias *alias, const char *com)
Parse the alias/query comment field.
Definition commands.c:135
struct Alias * alias_new(void)
Create a new Alias.
Definition alias.c:661
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:170
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
void buf_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition file.c:1351
#define mutt_file_fclose(FP)
Definition file.h:144
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
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:217
#define _(a)
Definition message.h:28
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
#define NONULL(x)
Definition string2.h:44
A shortcut for an email address or addresses.
Definition alias.h:35
String manipulation buffer.
Definition buffer.h:36
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_dialog_new()

static struct SimpleDialogWindows query_dialog_new ( struct AliasMenuData * mdata,
const char * query )
static

Create an Query Selection Dialog.

Parameters
mdataMenu data holding Aliases
queryInitial query string
Return values
objSimpleDialogWindows Tuple containing Dialog, SimpleBar and Menu pointers

Definition at line 307 of file dlg_query.c.

309{
311 ASSERT(mod_data);
312
313 struct SimpleDialogWindows sdw = simple_dialog_new(mod_data->menu_query,
315
316 struct Menu *menu = sdw.menu;
317
319 menu->tag = query_tag;
320 menu->max = ARRAY_SIZE(&mdata->ava);
321 mdata->title = mutt_str_dup(_("Query"));
322 menu->mdata = mdata;
323 menu->mdata_free = NULL; // Menu doesn't own the data
324
325 struct MuttWindow *win_menu = menu->win;
326
327 // Override the Simple Dialog's recalc()
328 win_menu->recalc = alias_recalc;
329
330 char title[256] = { 0 };
331 snprintf(title, sizeof(title), "%s: %s", mdata->title, query);
332 sbar_set_title(sdw.sbar, title);
333
334 // NT_COLOR is handled by the SimpleDialog
337
338 return sdw;
339}
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
static const struct Mapping QueryHelp[]
Help Bar for the Address Query dialog.
Definition dlg_query.c:99
static int query_make_entry(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Format an Alias for the Menu - Implements Menu::make_entry() -.
Definition dlg_query.c:145
static int query_tag(struct Menu *menu, int sel, int act)
Tag an entry in the Query Menu - Implements Menu::tag() -.
Definition dlg_query.c:167
static int query_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition dlg_query.c:278
int alias_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition gui.c:43
int alias_recalc(struct MuttWindow *win)
Recalculate the display of the Alias Window - Implements MuttWindow::recalc() -.
Definition gui.c:96
struct SimpleDialogWindows simple_dialog_new(const struct MenuDefinition *md, enum WindowType wtype, const struct Mapping *help_data)
Create a simple index Dialog.
Definition simple.c:132
@ MODULE_ID_ALIAS
ModuleAlias, Alias
Definition module_api.h:48
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition notify.c:191
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
@ WT_DLG_QUERY
Query Dialog, dlg_query()
Definition mutt_window.h:91
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition notify_type.h:58
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition notify_type.h:43
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition sbar.c:227
#define ASSERT(COND)
Definition signal2.h:59
char * title
Title for the status bar.
Definition gui.h:63
Alias private Module data.
Definition module_data.h:33
struct MenuDefinition * menu_query
Query menu definition.
Definition module_data.h:43
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition subset.h:51
Definition lib.h:86
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:94
void(* mdata_free)(struct Menu *menu, void **ptr)
Definition lib.h:169
int(* tag)(struct Menu *menu, int sel, int act)
Definition lib.h:139
int(* make_entry)(struct Menu *menu, int line, int max_cols, struct Buffer *buf)
Definition lib.h:114
void * mdata
Private data.
Definition lib.h:155
int max
Number of entries in the menu.
Definition lib.h:88
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
int(* recalc)(struct MuttWindow *win)
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Tuple for the results of simple_dialog_new()
Definition simple.h:35
struct MuttWindow * sbar
Simple Bar.
Definition simple.h:37
struct Menu * menu
Menu.
Definition simple.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_complete()

int query_complete ( struct Buffer * buf,
struct ConfigSubset * sub )

Perform auto-complete using an Address Query.

Parameters
bufBuffer for completion
subConfig item
Return values
0Always

Definition at line 414 of file dlg_query.c.

415{
416 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
418
419 struct AliasArray aa = ARRAY_HEAD_INITIALIZER;
420 const char *const c_query_command = cs_subset_string(sub, "query_command");
421 if (!c_query_command)
422 {
423 mutt_warning(_("Query command not defined"));
424 goto done;
425 }
426
427 query_run(buf_string(buf), true, &aa, sub);
428 if (ARRAY_EMPTY(&aa))
429 goto done;
430
431 mdata.aa = &aa;
432
433 struct Alias **a_first = ARRAY_FIRST(&aa);
434 if (ARRAY_SIZE(&aa) == 1) // only one response?
435 {
436 struct AddressList addr = TAILQ_HEAD_INITIALIZER(addr);
437 if (alias_to_addrlist(&addr, *a_first))
438 {
440 buf_reset(buf);
441 mutt_addrlist_write(&addr, buf, false);
442 mutt_addrlist_clear(&addr);
444 buf_addstr(buf, ", ");
445 }
446 goto done;
447 }
448
449 struct Alias **ap = NULL;
450 ARRAY_FOREACH(ap, mdata.aa)
451 {
452 alias_array_alias_add(&mdata.ava, *ap);
453 }
454
455 /* multiple results, choose from query menu */
456 if (!dlg_query(buf, &mdata))
457 goto done;
458
459 buf_reset(buf);
460 buf_alloc(buf, 8192);
461 struct AliasView *avp = NULL;
462 ARRAY_FOREACH(avp, &mdata.ava)
463 {
464 if (!avp->is_tagged)
465 continue;
466
467 struct AddressList al_copy = TAILQ_HEAD_INITIALIZER(al_copy);
468 if (alias_to_addrlist(&al_copy, avp->alias))
469 {
470 mutt_addrlist_to_local(&al_copy);
471 mutt_addrlist_write(&al_copy, buf, false);
472 mutt_addrlist_clear(&al_copy);
473 }
474 buf_addstr(buf, ", ");
475 }
476
477done:
478 ARRAY_FREE(&mdata.ava);
479 FREE(&mdata.title);
480 FREE(&mdata.limit);
482 aliaslist_clear(&aa);
483 return 0;
484}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1470
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1388
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1216
void aliaslist_clear(struct AliasArray *aa)
Empty a List of Aliases.
Definition alias.c:698
int alias_array_alias_add(struct AliasViewArray *ava, struct Alias *alias)
Add an Alias to the AliasViewArray.
Definition array.c:47
#define ARRAY_FIRST(head)
Convenience method to get the first element.
Definition array.h:136
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:91
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:235
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:344
int query_run(const char *s, bool verbose, struct AliasArray *aa, const struct ConfigSubset *sub)
Run an external program to find Addresses.
Definition dlg_query.c:188
bool alias_to_addrlist(struct AddressList *al, struct Alias *alias)
Turn an Alias into an AddressList.
Definition dlg_query.c:119
static bool dlg_query(struct Buffer *buf, struct AliasMenuData *mdata)
Get the user to enter an Address Query -.
Definition dlg_query.c:352
#define mutt_warning(...)
Definition logging2.h:92
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
void search_state_free(struct SearchState **ptr)
Free a SearchState.
struct SearchState * search_state_new(void)
Create a new SearchState.
AliasView array wrapper with Pattern information -.
Definition gui.h:55
char * limit
Limit being used.
Definition gui.h:61
struct AliasViewArray ava
All Aliases/Queries.
Definition gui.h:56
struct AliasArray * aa
Alias data.
Definition gui.h:57
struct SearchState * search_state
State of the current search.
Definition gui.h:64
struct ConfigSubset * sub
Config items.
Definition gui.h:58
GUI data wrapping an Alias.
Definition gui.h:38
struct Alias * alias
Alias.
Definition gui.h:46
bool is_tagged
Is it tagged?
Definition gui.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_index()

void query_index ( struct Mailbox * m,
struct ConfigSubset * sub )

Perform an Alias Query and display the results.

Parameters
mMailbox
subConfig item

Definition at line 491 of file dlg_query.c.

492{
493 const char *const c_query_command = cs_subset_string(sub, "query_command");
494 if (!c_query_command)
495 {
496 mutt_warning(_("Query command not defined"));
497 return;
498 }
499
500 struct AliasArray aa = ARRAY_HEAD_INITIALIZER;
501 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
502 mdata.aa = &aa;
503 mdata.search_state = search_state_new();
504
505 struct Buffer *buf = buf_pool_get();
506 if ((mw_get_field(_("Query: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
507 buf_is_empty(buf))
508 {
509 goto done;
510 }
511
512 query_run(buf_string(buf), false, &aa, sub);
513 if (ARRAY_EMPTY(&aa))
514 goto done;
515
516 struct Alias **ap = NULL;
517 ARRAY_FOREACH(ap, mdata.aa)
518 {
519 alias_array_alias_add(&mdata.ava, *ap);
520 }
521
522 if (!dlg_query(buf, &mdata))
523 goto done;
524
525 // Prepare the "To:" field of a new email
526 struct Email *e = email_new();
527 e->env = mutt_env_new();
528
529 struct AliasView *avp = NULL;
530 ARRAY_FOREACH(avp, &mdata.ava)
531 {
532 if (!avp->is_tagged)
533 continue;
534
535 struct AddressList al_copy = TAILQ_HEAD_INITIALIZER(al_copy);
536 if (alias_to_addrlist(&al_copy, avp->alias))
537 {
538 mutt_addrlist_copy(&e->env->to, &al_copy, false);
539 mutt_addrlist_clear(&al_copy);
540 }
541 }
542
543 mutt_send_message(SEND_REVIEW_TO, e, NULL, m, NULL, sub);
544
545done:
546 ARRAY_FREE(&mdata.ava);
547 FREE(&mdata.title);
548 FREE(&mdata.limit);
550 aliaslist_clear(&aa);
551 buf_pool_release(&buf);
552}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:300
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
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:502
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
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:2030
@ SEND_REVIEW_TO
Allow the user to edit the To field.
Definition send.h:60
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ QueryHelp

const struct Mapping QueryHelp[]
static
Initial value:
= {
{ N_("Exit"), OP_EXIT },
{ N_("Mail"), OP_MAIL },
{ N_("New Query"), OP_QUERY },
{ N_("Make Alias"), OP_CREATE_ALIAS },
{ N_("Sort"), OP_SORT },
{ N_("Rev-Sort"), OP_SORT_REVERSE },
{ N_("Search"), OP_SEARCH },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition message.h:32

Help Bar for the Address Query dialog.

Definition at line 99 of file dlg_query.c.

99 {
100 // clang-format off
101 { N_("Exit"), OP_EXIT },
102 { N_("Mail"), OP_MAIL },
103 { N_("New Query"), OP_QUERY },
104 { N_("Make Alias"), OP_CREATE_ALIAS },
105 { N_("Sort"), OP_SORT },
106 { N_("Rev-Sort"), OP_SORT_REVERSE },
107 { N_("Search"), OP_SEARCH },
108 { N_("Help"), OP_HELP },
109 { NULL, 0 },
110 // clang-format on
111};