NeoMutt  2024-12-12-14-g7b49f7
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pattern.c File Reference

Match patterns to emails. More...

#include "config.h"
#include <stdbool.h>
#include <stddef.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/gui.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "imap/lib.h"
#include "menu/lib.h"
#include "progress/lib.h"
#include "mutt_logging.h"
#include "mview.h"
#include "mx.h"
#include "protos.h"
#include "search_state.h"
#include <sys/stat.h>
+ Include dependency graph for pattern.c:

Go to the source code of this file.

Typedefs

typedef bool(* eat_arg_t) (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
 

Functions

static void quote_simple (const char *str, struct Buffer *buf)
 Apply simple quoting to a string.
 
void mutt_check_simple (struct Buffer *buf, const char *simple)
 Convert a simple search into a real request.
 
int mutt_pattern_alias_func (char *prompt, struct AliasMenuData *mdata, enum PatternAlias action, struct Menu *menu)
 Perform some Pattern matching for Alias.
 
int mutt_pattern_func (struct MailboxView *mv, int op, char *prompt)
 Perform some Pattern matching.
 
int mutt_search_command (struct MailboxView *mv, struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
 Perform a search.
 
int mutt_search_alias_command (struct Menu *menu, int cur, struct SearchState *state, SearchFlags flags)
 Perform a search.
 

Variables

struct RangeRegex RangeRegexes []
 Set of Regexes for various range types.
 

Detailed Description

Match patterns to emails.

Authors
  • Pietro Cerutti
  • R Primus
  • Romeu Vieira
  • Richard Russon
  • Dennis Schön

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 pattern.c.

Typedef Documentation

◆ eat_arg_t

typedef bool(* eat_arg_t) (struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)

Definition at line 86 of file pattern.c.

Function Documentation

◆ quote_simple()

static void quote_simple ( const char *  str,
struct Buffer buf 
)
static

Apply simple quoting to a string.

Parameters
strString to quote
bufBuffer for the result

Definition at line 94 of file pattern.c.

95{
96 buf_reset(buf);
97 buf_addch(buf, '"');
98 while (*str)
99 {
100 if ((*str == '\\') || (*str == '"'))
101 buf_addch(buf, '\\');
102 buf_addch(buf, *str++);
103 }
104 buf_addch(buf, '"');
105}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_simple()

void mutt_check_simple ( struct Buffer buf,
const char *  simple 
)

Convert a simple search into a real request.

Parameters
bufBuffer for the result
simpleSearch string to convert

Definition at line 112 of file pattern.c.

113{
114 bool do_simple = true;
115
116 for (const char *p = buf_string(buf); p && (p[0] != '\0'); p++)
117 {
118 if ((p[0] == '\\') && (p[1] != '\0'))
119 {
120 p++;
121 }
122 else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
123 {
124 do_simple = false;
125 break;
126 }
127 }
128
129 /* XXX - is mutt_istr_cmp() right here, or should we use locale's
130 * equivalences? */
131
132 if (do_simple) /* yup, so spoof a real request */
133 {
134 /* convert old tokens into the new format */
135 if (mutt_istr_equal("all", buf_string(buf)) || mutt_str_equal("^", buf_string(buf)) ||
136 mutt_str_equal(".", buf_string(buf))) /* ~A is more efficient */
137 {
138 buf_strcpy(buf, "~A");
139 }
140 else if (mutt_istr_equal("del", buf_string(buf)))
141 {
142 buf_strcpy(buf, "~D");
143 }
144 else if (mutt_istr_equal("flag", buf_string(buf)))
145 {
146 buf_strcpy(buf, "~F");
147 }
148 else if (mutt_istr_equal("new", buf_string(buf)))
149 {
150 buf_strcpy(buf, "~N");
151 }
152 else if (mutt_istr_equal("old", buf_string(buf)))
153 {
154 buf_strcpy(buf, "~O");
155 }
156 else if (mutt_istr_equal("repl", buf_string(buf)))
157 {
158 buf_strcpy(buf, "~Q");
159 }
160 else if (mutt_istr_equal("read", buf_string(buf)))
161 {
162 buf_strcpy(buf, "~R");
163 }
164 else if (mutt_istr_equal("tag", buf_string(buf)))
165 {
166 buf_strcpy(buf, "~T");
167 }
168 else if (mutt_istr_equal("unread", buf_string(buf)))
169 {
170 buf_strcpy(buf, "~U");
171 }
172 else
173 {
174 struct Buffer *tmp = buf_pool_get();
175 quote_simple(buf_string(buf), tmp);
176 mutt_file_expand_fmt(buf, simple, buf_string(tmp));
177 buf_pool_release(&tmp);
178 }
179 }
180}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1471
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
static void quote_simple(const char *str, struct Buffer *buf)
Apply simple quoting to a string.
Definition: pattern.c:94
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
String manipulation buffer.
Definition: buffer.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_alias_func()

int mutt_pattern_alias_func ( char *  prompt,
struct AliasMenuData mdata,
enum PatternAlias  action,
struct Menu menu 
)

Perform some Pattern matching for Alias.

Parameters
promptPrompt to show the user
mdataMenu data holding Aliases
actionWhat to do with the results, e.g. PAA_TAG
menuCurrent menu
Return values
0Success
-1Failure

Definition at line 191 of file pattern.c.

193{
194 int rc = -1;
195 struct Progress *progress = NULL;
196 struct Buffer *buf = buf_pool_get();
197
198 buf_strcpy(buf, mdata->limit);
199 if (prompt)
200 {
201 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_PATTERN, &CompletePatternOps, NULL) != 0) ||
202 buf_is_empty(buf))
203 {
204 buf_pool_release(&buf);
205 return -1;
206 }
207 }
208
209 mutt_message(_("Compiling search pattern..."));
210
211 bool match_all = false;
212 struct PatternList *pat = NULL;
213 char *simple = buf_strdup(buf);
214 if (simple)
215 {
217 const char *pbuf = buf->data;
218 while (*pbuf == ' ')
219 pbuf++;
220 match_all = mutt_str_equal(pbuf, "~A");
221
222 struct Buffer *err = buf_pool_get();
223 pat = mutt_pattern_comp(NULL, menu, buf->data, MUTT_PC_FULL_MSG, err);
224 if (!pat)
225 {
226 mutt_error("%s", buf_string(err));
227 buf_pool_release(&err);
228 goto bail;
229 }
230 }
231 else
232 {
233 match_all = true;
234 }
235
236 progress = progress_new(MUTT_PROGRESS_READ, ARRAY_SIZE(&mdata->ava));
237 progress_set_message(progress, _("Executing command on matching messages..."));
238
239 int vcounter = 0;
240 struct AliasView *avp = NULL;
241 ARRAY_FOREACH(avp, &mdata->ava)
242 {
243 progress_update(progress, ARRAY_FOREACH_IDX, -1);
244
245 if (match_all ||
247 {
248 switch (action)
249 {
250 case PAA_TAG:
251 avp->is_tagged = true;
252 break;
253 case PAA_UNTAG:
254 avp->is_tagged = false;
255 break;
256 case PAA_VISIBLE:
257 avp->is_visible = true;
258 vcounter++;
259 break;
260 }
261 }
262 else
263 {
264 switch (action)
265 {
266 case PAA_TAG:
267 case PAA_UNTAG:
268 // Do nothing
269 break;
270 case PAA_VISIBLE:
271 avp->is_visible = false;
272 break;
273 }
274 }
275 }
276 progress_free(&progress);
277
278 FREE(&mdata->limit);
279 if (!match_all)
280 {
281 mdata->limit = simple;
282 simple = NULL;
283 }
284
285 if (menu && (action == PAA_VISIBLE))
286 {
287 menu->max = vcounter;
288 menu_set_index(menu, 0);
289 }
290
292
293 rc = 0;
294
295bail:
296 buf_pool_release(&buf);
297 FREE(&simple);
298 mutt_pattern_free(&pat);
299
300 return rc;
301}
#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
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: compile.c:906
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: compile.c:778
bool mutt_pattern_alias_exec(struct Pattern *pat, PatternExecFlags flags, struct AliasView *av, struct PatternCache *cache)
Match a pattern against an alias.
Definition: exec.c:1174
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
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
@ HC_PATTERN
Patterns.
Definition: lib.h:57
#define FREE(x)
Definition: memory.h:55
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
#define _(a)
Definition: message.h:28
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
const struct CompleteOps CompletePatternOps
Auto-Completion of Patterns.
Definition: complete.c:82
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: lib.h:69
@ 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
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: lib.h:106
#define MUTT_ALIAS_SIMPLESEARCH
Definition: lib.h:63
void mutt_check_simple(struct Buffer *buf, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:112
@ MUTT_PROGRESS_READ
Progress tracks elements, according to $read_inc
Definition: lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
#define SLIST_FIRST(head)
Definition: queue.h:227
char * limit
Limit being used.
Definition: gui.h:60
struct AliasViewArray ava
All Aliases/Queries.
Definition: gui.h:55
GUI data wrapping an Alias.
Definition: gui.h:38
bool is_visible
Is visible?
Definition: gui.h:45
bool is_tagged
Is it tagged?
Definition: gui.h:43
char * data
Pointer to data.
Definition: buffer.h:37
int max
Number of entries in the menu.
Definition: lib.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_func()

int mutt_pattern_func ( struct MailboxView mv,
int  op,
char *  prompt 
)

Perform some Pattern matching.

Parameters
mvMailbox View
opOperation to perform, e.g. MUTT_LIMIT
promptPrompt to show the user
Return values
0Success
-1Failure

Definition at line 311 of file pattern.c.

312{
313 if (!mv || !mv->mailbox)
314 return -1;
315
316 struct Mailbox *m = mv->mailbox;
317
318 struct Buffer *err = NULL;
319 int rc = -1;
320 struct Progress *progress = NULL;
321 struct Buffer *buf = buf_pool_get();
322 bool interrupted = false;
323
324 buf_strcpy(buf, mv->pattern);
325 if (prompt || (op != MUTT_LIMIT))
326 {
327 if ((mw_get_field(prompt, buf, MUTT_COMP_CLEAR, HC_PATTERN, &CompletePatternOps, NULL) != 0) ||
328 buf_is_empty(buf))
329 {
330 buf_pool_release(&buf);
331 return -1;
332 }
333 }
334
335 mutt_message(_("Compiling search pattern..."));
336
337 char *simple = buf_strdup(buf);
338 const char *const c_simple_search = cs_subset_string(NeoMutt->sub, "simple_search");
339 mutt_check_simple(buf, NONULL(c_simple_search));
340 const char *pbuf = buf->data;
341 while (*pbuf == ' ')
342 pbuf++;
343 const bool match_all = mutt_str_equal(pbuf, "~A");
344
345 err = buf_pool_get();
346 struct PatternList *pat = mutt_pattern_comp(mv, mv->menu, buf->data, MUTT_PC_FULL_MSG, err);
347 if (!pat)
348 {
349 mutt_error("%s", buf_string(err));
350 goto bail;
351 }
352
353 if ((m->type == MUTT_IMAP) && (!imap_search(m, pat)))
354 goto bail;
355
356 progress = progress_new(MUTT_PROGRESS_READ, (op == MUTT_LIMIT) ? m->msg_count : m->vcount);
357 progress_set_message(progress, _("Executing command on matching messages..."));
358
359 if (op == MUTT_LIMIT)
360 {
361 m->vcount = 0;
362 mv->vsize = 0;
363 mv->collapsed = false;
364 int padding = mx_msg_padding_size(m);
365
366 for (int i = 0; i < m->msg_count; i++)
367 {
368 struct Email *e = m->emails[i];
369 if (!e)
370 break;
371
372 if (SigInt)
373 {
374 interrupted = true;
375 SigInt = false;
376 break;
377 }
378 progress_update(progress, i, -1);
379 /* new limit pattern implicitly uncollapses all threads */
380 e->vnum = -1;
381 e->visible = false;
382 e->limit_visited = true;
383 e->collapsed = false;
384 e->num_hidden = 0;
385
386 if (match_all ||
388 {
389 e->vnum = m->vcount;
390 e->visible = true;
391 m->v2r[m->vcount] = i;
392 m->vcount++;
393 struct Body *b = e->body;
394 mv->vsize += b->length + b->offset - b->hdr_offset + padding;
395 }
396 }
397 }
398 else
399 {
400 for (int i = 0; i < m->vcount; i++)
401 {
402 struct Email *e = mutt_get_virt_email(m, i);
403 if (!e)
404 continue;
405
406 if (SigInt)
407 {
408 interrupted = true;
409 SigInt = false;
410 break;
411 }
412 progress_update(progress, i, -1);
414 {
415 switch (op)
416 {
417 case MUTT_UNDELETE:
418 mutt_set_flag(m, e, MUTT_PURGE, false, true);
420
421 case MUTT_DELETE:
422 mutt_set_flag(m, e, MUTT_DELETE, (op == MUTT_DELETE), true);
423 break;
424 case MUTT_TAG:
425 case MUTT_UNTAG:
426 mutt_set_flag(m, e, MUTT_TAG, (op == MUTT_TAG), true);
427 break;
428 }
429 }
430 }
431 }
432 progress_free(&progress);
433
435
436 if (op == MUTT_LIMIT)
437 {
438 /* drop previous limit pattern */
439 FREE(&mv->pattern);
441
442 if (m->msg_count && !m->vcount)
443 mutt_error(_("No messages matched criteria"));
444
445 /* record new limit pattern, unless match all */
446 if (!match_all)
447 {
448 mv->pattern = simple;
449 simple = NULL; /* don't clobber it */
450 mv->limit_pattern = mutt_pattern_comp(mv, mv->menu, buf->data, MUTT_PC_FULL_MSG, err);
451 }
452 }
453
454 if (interrupted)
455 mutt_error(_("Search interrupted"));
456
457 rc = 0;
458
459bail:
460 buf_pool_release(&buf);
461 buf_pool_release(&err);
462 FREE(&simple);
463 mutt_pattern_free(&pat);
464
465 return rc;
466}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
bool mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: exec.c:1147
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:57
bool imap_search(struct Mailbox *m, const struct PatternList *pat)
Find messages in mailbox matching a pattern.
Definition: search.c:227
#define FALLTHROUGH
Definition: lib.h:111
@ MUTT_UNDELETE
Messages to be un-deleted.
Definition: mutt.h:76
@ MUTT_LIMIT
Messages in limited view.
Definition: mutt.h:82
@ MUTT_UNTAG
Messages to be un-tagged.
Definition: mutt.h:81
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: mview.c:417
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1505
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:66
#define NONULL(x)
Definition: string2.h:37
The body of an email.
Definition: body.h:36
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:81
The envelope/body of an email.
Definition: email.h:39
bool visible
Is this message part of the view?
Definition: email.h:121
bool limit_visited
Has the limit pattern been applied to this message?
Definition: email.h:122
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:120
struct Body * body
List of MIME parts.
Definition: email.h:69
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:123
int vnum
Virtual message number.
Definition: email.h:114
bool collapsed
Are all threads collapsed?
Definition: mview.h:49
struct Menu * menu
Needed for pattern compilation.
Definition: mview.h:47
off_t vsize
Size (in bytes) of the messages shown.
Definition: mview.h:41
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: mview.h:43
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:51
char * pattern
Limit pattern string.
Definition: mview.h:42
A mailbox.
Definition: mailbox.h:79
int vcount
The number of virtual messages.
Definition: mailbox.h:99
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:98
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_search_command()

int mutt_search_command ( struct MailboxView mv,
struct Menu menu,
int  cur,
struct SearchState state,
SearchFlags  flags 
)

Perform a search.

Parameters
mvMailbox view to search through
menuCurrent Menu
curIndex number of current email
stateCurrent search state
flagsSearch flags, e.g. SEARCH_PROMPT
Return values
>=0Index of matching email
-1No match, or error

Definition at line 478 of file pattern.c.

480{
481 struct Progress *progress = NULL;
482 int rc = -1;
483 struct Mailbox *m = mv ? mv->mailbox : NULL;
484 if (!m)
485 return -1;
486 bool pattern_changed = false;
487
488 if (buf_is_empty(state->string) || (flags & SEARCH_PROMPT))
489 {
490 if ((mw_get_field((state->reverse) ? _("Reverse search for: ") : _("Search for: "),
492 &CompletePatternOps, NULL) != 0) ||
493 buf_is_empty(state->string))
494 {
495 goto done;
496 }
497
498 /* compare the *expanded* version of the search pattern in case
499 * $simple_search has changed while we were searching */
500 struct Buffer *tmp = buf_pool_get();
501 buf_copy(tmp, state->string);
502 const char *const c_simple_search = cs_subset_string(NeoMutt->sub, "simple_search");
503 mutt_check_simple(tmp, NONULL(c_simple_search));
504 if (!buf_str_equal(tmp, state->string_expn))
505 {
506 mutt_pattern_free(&state->pattern);
507 buf_copy(state->string_expn, tmp);
508 buf_pool_release(&tmp);
509 }
510 }
511
512 if (!state->pattern)
513 {
514 mutt_message(_("Compiling search pattern..."));
515 mutt_pattern_free(&state->pattern);
516 struct Buffer *err = buf_pool_get();
517 state->pattern = mutt_pattern_comp(mv, menu, state->string_expn->data,
518 MUTT_PC_FULL_MSG, err);
519 pattern_changed = true;
520 if (!state->pattern)
521 {
522 mutt_error("%s", buf_string(err));
523 buf_free(&err);
524 buf_reset(state->string);
525 buf_reset(state->string_expn);
526 return -1;
527 }
528 buf_free(&err);
530 }
531
532 if (pattern_changed)
533 {
534 for (int i = 0; i < m->msg_count; i++)
535 m->emails[i]->searched = false;
536 if ((m->type == MUTT_IMAP) && (!imap_search(m, state->pattern)))
537 return -1;
538 }
539
540 int incr = state->reverse ? -1 : 1;
541 if (flags & SEARCH_OPPOSITE)
542 incr = -incr;
543
544 progress = progress_new(MUTT_PROGRESS_READ, m->vcount);
545 progress_set_message(progress, _("Searching..."));
546
547 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
548 for (int i = cur + incr, j = 0; j != m->vcount; j++)
549 {
550 const char *msg = NULL;
551 progress_update(progress, j, -1);
552 if (i > m->vcount - 1)
553 {
554 i = 0;
555 if (c_wrap_search)
556 {
557 msg = _("Search wrapped to top");
558 }
559 else
560 {
561 mutt_message(_("Search hit bottom without finding match"));
562 goto done;
563 }
564 }
565 else if (i < 0)
566 {
567 i = m->vcount - 1;
568 if (c_wrap_search)
569 {
570 msg = _("Search wrapped to bottom");
571 }
572 else
573 {
574 mutt_message(_("Search hit top without finding match"));
575 goto done;
576 }
577 }
578
579 struct Email *e = mutt_get_virt_email(m, i);
580 if (!e)
581 goto done;
582
583 if (e->searched)
584 {
585 /* if we've already evaluated this message, use the cached value */
586 if (e->matched)
587 {
589 if (msg && *msg)
590 mutt_message("%s", msg);
591 rc = i;
592 goto done;
593 }
594 }
595 else
596 {
597 /* remember that we've already searched this message */
598 e->searched = true;
600 MUTT_MATCH_FULL_ADDRESS, m, e, NULL);
601 if (e->matched)
602 {
604 if (msg && *msg)
605 mutt_message("%s", msg);
606 rc = i;
607 goto done;
608 }
609 }
610
611 if (SigInt)
612 {
613 mutt_error(_("Search interrupted"));
614 SigInt = false;
615 goto done;
616 }
617
618 i += incr;
619 }
620
621 mutt_error(_("Not found"));
622done:
623 progress_free(&progress);
624 return rc;
625}
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:319
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:685
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
#define SEARCH_OPPOSITE
Search in the opposite direction.
Definition: search_state.h:46
#define SEARCH_PROMPT
Ask for search input.
Definition: search_state.h:45
bool searched
Email has been searched.
Definition: email.h:105
bool matched
Search matches this Email.
Definition: email.h:102
struct Buffer * string
search string
Definition: search_state.h:38
struct Buffer * string_expn
expanded search string
Definition: search_state.h:39
bool reverse
search backwards
Definition: search_state.h:40
struct PatternList * pattern
compiled search pattern
Definition: search_state.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_search_alias_command()

int mutt_search_alias_command ( struct Menu menu,
int  cur,
struct SearchState state,
SearchFlags  flags 
)

Perform a search.

Parameters
menuMenu to search through
curIndex number of current email
stateCurrent search state
flagsSearch flags, e.g. SEARCH_PROMPT
Return values
>=0Index of matching alias
-1No match, or error

Definition at line 636 of file pattern.c.

638{
639 struct Progress *progress = NULL;
640 const struct AliasMenuData *mdata = menu->mdata;
641 const struct AliasViewArray *ava = &mdata->ava;
642 int rc = -1;
643 bool pattern_changed = false;
644
645 if (buf_is_empty(state->string) || flags & SEARCH_PROMPT)
646 {
647 if ((mw_get_field((flags & OP_SEARCH_REVERSE) ? _("Reverse search for: ") : _("Search for: "),
649 &CompletePatternOps, NULL) != 0) ||
650 buf_is_empty(state->string))
651 {
652 goto done;
653 }
654
655 /* compare the *expanded* version of the search pattern in case
656 * $simple_search has changed while we were searching */
657 struct Buffer *tmp = buf_pool_get();
658 buf_copy(tmp, state->string);
660 if (!buf_str_equal(tmp, state->string_expn))
661 {
662 mutt_pattern_free(&state->pattern);
663 buf_copy(state->string_expn, tmp);
664 buf_pool_release(&tmp);
665 }
666 }
667
668 if (!state->pattern)
669 {
670 mutt_message(_("Compiling search pattern..."));
671 struct Buffer *err = buf_pool_get();
672 state->pattern = mutt_pattern_comp(NULL, menu, state->string_expn->data,
673 MUTT_PC_FULL_MSG, err);
674 pattern_changed = true;
675 if (!state->pattern)
676 {
677 mutt_error("%s", buf_string(err));
678 buf_free(&err);
679 buf_reset(state->string);
680 buf_reset(state->string_expn);
681 return -1;
682 }
683 buf_free(&err);
685 }
686
687 if (pattern_changed)
688 {
689 struct AliasView *av = NULL;
690 ARRAY_FOREACH(av, ava)
691 {
692 av->is_searched = false;
693 }
694 }
695
696 int incr = state->reverse ? -1 : 1;
697 if (flags & SEARCH_OPPOSITE)
698 incr = -incr;
699
701 progress_set_message(progress, _("Searching..."));
702
703 const bool c_wrap_search = cs_subset_bool(NeoMutt->sub, "wrap_search");
704 for (int i = cur + incr, j = 0; j != ARRAY_SIZE(ava); j++)
705 {
706 const char *msg = NULL;
707 progress_update(progress, j, -1);
708 if (i > ARRAY_SIZE(ava) - 1)
709 {
710 i = 0;
711 if (c_wrap_search)
712 {
713 msg = _("Search wrapped to top");
714 }
715 else
716 {
717 mutt_message(_("Search hit bottom without finding match"));
718 goto done;
719 }
720 }
721 else if (i < 0)
722 {
723 i = ARRAY_SIZE(ava) - 1;
724 if (c_wrap_search)
725 {
726 msg = _("Search wrapped to bottom");
727 }
728 else
729 {
730 mutt_message(_("Search hit top without finding match"));
731 goto done;
732 }
733 }
734
735 struct AliasView *av = ARRAY_GET(ava, i);
736 if (av->is_searched)
737 {
738 /* if we've already evaluated this message, use the cached value */
739 if (av->is_matched)
740 {
742 if (msg && *msg)
743 mutt_message("%s", msg);
744 rc = i;
745 goto done;
746 }
747 }
748 else
749 {
750 /* remember that we've already searched this message */
751 av->is_searched = true;
753 MUTT_MATCH_FULL_ADDRESS, av, NULL);
754 if (av->is_matched)
755 {
757 if (msg && *msg)
758 mutt_message("%s", msg);
759 rc = i;
760 goto done;
761 }
762 }
763
764 if (SigInt)
765 {
766 mutt_error(_("Search interrupted"));
767 SigInt = false;
768 goto done;
769 }
770
771 i += incr;
772 }
773
774 mutt_error(_("Not found"));
775done:
776 progress_free(&progress);
777 return rc;
778}
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
AliasView array wrapper with Pattern information -.
Definition: gui.h:54
struct Menu * menu
Menu.
Definition: gui.h:58
bool is_matched
Search matches this Alias.
Definition: gui.h:42
bool is_searched
Alias has been searched.
Definition: gui.h:41
void * mdata
Private data.
Definition: lib.h:147
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ RangeRegexes

struct RangeRegex RangeRegexes[]
Initial value:
= {
[RANGE_K_REL] = { RANGE_REL_RX, 1, 3, 0, { 0 } },
[RANGE_K_ABS] = { RANGE_ABS_RX, 1, 3, 0, { 0 } },
[RANGE_K_LT] = { RANGE_LT_RX, 1, 2, 0, { 0 } },
[RANGE_K_GT] = { RANGE_GT_RX, 2, 1, 0, { 0 } },
[RANGE_K_BARE] = { RANGE_BARE_RX, 1, 1, 0, { 0 } },
}
#define RANGE_GT_RX
Definition: private.h:110
#define RANGE_ABS_RX
Definition: private.h:106
#define RANGE_LT_RX
Definition: private.h:109
#define RANGE_BARE_RX
Definition: private.h:113
#define RANGE_REL_RX
Definition: private.h:102
@ RANGE_K_REL
Relative range.
Definition: private.h:90
@ RANGE_K_ABS
Absolute range.
Definition: private.h:91
@ RANGE_K_LT
Less-than range.
Definition: private.h:92
@ RANGE_K_BARE
Single symbol.
Definition: private.h:94
@ RANGE_K_GT
Greater-than range.
Definition: private.h:93

Set of Regexes for various range types.

This array, will also contain the compiled regexes.

Definition at line 65 of file pattern.c.