NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
pattern.c File Reference

Match patterns to emails. More...

#include "config.h"
#include <stddef.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "pattern.h"
#include "context.h"
#include "copy.h"
#include "handler.h"
#include "hdrline.h"
#include "init.h"
#include "maillist.h"
#include "mutt_globals.h"
#include "mutt_logging.h"
#include "mutt_menu.h"
#include "mutt_parse.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "progress.h"
#include "protos.h"
#include "state.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include <sys/stat.h>
#include "imap/lib.h"
+ Include dependency graph for pattern.c:

Go to the source code of this file.

Data Structures

struct  RangeRegex
 Regular expression representing a range. More...
 
struct  PatternFlags
 Mapping between user character and internal constant. More...
 

Macros

#define RANGE_NUM_RX   "([[:digit:]]+|0x[[:xdigit:]]+)[MmKk]?"
 
#define RANGE_REL_SLOT_RX   "[[:blank:]]*([.^$]|-?" RANGE_NUM_RX ")?[[:blank:]]*"
 
#define RANGE_REL_RX   "^" RANGE_REL_SLOT_RX "," RANGE_REL_SLOT_RX
 
#define RANGE_ABS_SLOT_RX   "[[:blank:]]*([.^$]|" RANGE_NUM_RX ")?[[:blank:]]*"
 
#define RANGE_ABS_RX   "^" RANGE_ABS_SLOT_RX "-" RANGE_ABS_SLOT_RX
 
#define RANGE_LT_RX   "^()[[:blank:]]*(<[[:blank:]]*" RANGE_NUM_RX ")[[:blank:]]*"
 
#define RANGE_GT_RX   "^()[[:blank:]]*(>[[:blank:]]*" RANGE_NUM_RX ")[[:blank:]]*"
 
#define RANGE_BARE_RX   "^[[:blank:]]*([.^$]|" RANGE_NUM_RX ")[[:blank:]]*"
 
#define RANGE_RX_GROUPS   5
 
#define KILO   1024
 
#define MEGA   1048576
 
#define EMSG(e)   (((e)->msgno) + 1)
 
#define MUTT_MAXRANGE   -1
 
#define MUTT_PDR_NO_FLAGS   0
 No flags are set. More...
 
#define MUTT_PDR_MINUS   (1 << 0)
 Pattern contains a range. More...
 
#define MUTT_PDR_PLUS   (1 << 1)
 Extend the range using '+'. More...
 
#define MUTT_PDR_WINDOW   (1 << 2)
 Extend the range in both directions using '*'. More...
 
#define MUTT_PDR_ABSOLUTE   (1 << 3)
 Absolute pattern range. More...
 
#define MUTT_PDR_DONE   (1 << 4)
 Pattern parse successfully. More...
 
#define MUTT_PDR_ERROR   (1 << 8)
 Invalid pattern. More...
 
#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)
 
#define RANGE_DOT   '.'
 
#define RANGE_CIRCUM   '^'
 
#define RANGE_DOLLAR   '$'
 
#define RANGE_LT   '<'
 
#define RANGE_GT   '>'
 

Typedefs

typedef uint16_t ParseDateRangeFlags
 Flags for parse_date_range(), e.g. MUTT_PDR_MINUS. More...
 
typedef bool(* addr_predicate_t) (const struct Address *a)
 Test an Address for some condition. More...
 

Enumerations

enum  EatRangeError { RANGE_E_OK, RANGE_E_SYNTAX, RANGE_E_CTX }
 Error codes for eat_range_by_regex() More...
 
enum  RangeType {
  RANGE_K_REL, RANGE_K_ABS, RANGE_K_LT, RANGE_K_GT,
  RANGE_K_BARE, RANGE_K_INVALID
}
 Type of range. More...
 
enum  RangeSide { RANGE_S_LEFT, RANGE_S_RIGHT }
 Which side of the range. More...
 

Functions

static bool eat_regex (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a regex - Implements Pattern::eat_arg() More...
 
static bool add_query_msgid (char *line, int line_num, void *user_data)
 Parse a Message-Id and add it to a list - Implements mutt_file_map_t. More...
 
static bool eat_query (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a query for an external search program - Implements Pattern::eat_arg() More...
 
static const char * get_offset (struct tm *tm, const char *s, int sign)
 Calculate a symbolic offset. More...
 
static const char * get_date (const char *s, struct tm *t, struct Buffer *err)
 Parse a (partial) date in dd/mm/yyyy format. More...
 
static const char * parse_date_range (const char *pc, struct tm *min, struct tm *max, bool have_min, struct tm *base_min, struct Buffer *err)
 Parse a date range. More...
 
static void adjust_date_range (struct tm *min, struct tm *max)
 Put a date range in the correct order. More...
 
static bool eval_date_minmax (struct Pattern *pat, const char *s, struct Buffer *err)
 Evaluate a date-range pattern against 'now'. More...
 
static bool eat_range (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a number range - Implements Pattern::eat_arg() More...
 
static int report_regerror (int regerr, regex_t *preg, struct Buffer *err)
 Create a regex error message. More...
 
static bool is_context_available (struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err)
 Do we need a Context for this Pattern? More...
 
static int scan_range_num (struct Buffer *s, regmatch_t pmatch[], int group, int kind)
 Parse a number range. More...
 
static int scan_range_slot (struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind)
 Parse a range of message numbers. More...
 
static void order_range (struct Pattern *pat)
 Put a range in order. More...
 
static int eat_range_by_regex (struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err)
 Parse a range given as a regex. More...
 
static bool eat_message_range (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a range of message numbers - Implements Pattern::eat_arg() More...
 
static bool eat_date (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a date pattern - Implements Pattern::eat_arg() More...
 
static bool patmatch (const struct Pattern *pat, const char *buf)
 Compare a string to a Pattern. More...
 
static bool msg_search (struct Mailbox *m, struct Pattern *pat, int msgno)
 Search an email. More...
 
static const struct PatternFlagslookup_tag (char tag)
 Lookup a pattern modifier. More...
 
static char * find_matching_paren (char *s)
 Find the matching parenthesis. More...
 
void mutt_pattern_free (struct PatternList **pat)
 Free a Pattern. More...
 
static struct PatternList * mutt_pattern_node_new (void)
 Create a new list containing a Pattern. More...
 
struct PatternList * mutt_pattern_comp (const char *s, PatternCompFlags flags, struct Buffer *err)
 Create a Pattern. More...
 
static bool perform_and (struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
 Perform a logical AND on a set of Patterns. More...
 
static int perform_or (struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
 Perform a logical OR on a set of Patterns. More...
 
static int match_addrlist (struct Pattern *pat, bool match_personal, int n,...)
 Match a Pattern against and Address list. More...
 
static bool match_reference (struct Pattern *pat, struct ListHead *refs)
 Match references against a Pattern. More...
 
static int mutt_is_predicate_recipient (bool all_addr, struct Envelope *e, addr_predicate_t p)
 Test an Envelopes Addresses using a predicate function. More...
 
int mutt_is_subscribed_list_recipient (bool all_addr, struct Envelope *e)
 Matches subscribed mailing lists. More...
 
int mutt_is_list_recipient (bool all_addr, struct Envelope *e)
 Matches known mailing lists. More...
 
static int match_user (int all_addr, struct AddressList *al1, struct AddressList *al2)
 Matches the user's email Address. More...
 
static int match_threadcomplete (struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t, int left, int up, int right, int down)
 Match a Pattern against an email thread. More...
 
static int match_threadparent (struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
 Match Pattern against an email's parent. More...
 
static int match_threadchildren (struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
 Match Pattern against an email's children. More...
 
static bool match_content_type (const struct Pattern *pat, struct Body *b)
 Match a Pattern against an Attachment's Content-Type. More...
 
static bool match_update_dynamic_date (struct Pattern *pat)
 Update a dynamic date pattern. More...
 
static bool match_mime_content_type (const struct Pattern *pat, struct Mailbox *m, struct Email *e)
 Match a Pattern against an email's Content-Type. More...
 
static void set_pattern_cache_value (int *cache_entry, int value)
 Sets a value in the PatternCache cache entry. More...
 
static int get_pattern_cache_value (int cache_entry)
 Get pattern cache value. More...
 
static int is_pattern_cache_set (int cache_entry)
 Is a given Pattern cached? More...
 
static int msg_search_sendmode (struct Email *e, struct Pattern *pat)
 Search in send-mode. More...
 
int mutt_pattern_exec (struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
 Match a pattern against an email header. More...
 
static void quote_simple (const char *str, struct Buffer *buf)
 Apply simple quoting to a string. More...
 
void mutt_check_simple (struct Buffer *buf, const char *simple)
 Convert a simple search into a real request. More...
 
static struct MuttThreadtop_of_thread (struct Email *e)
 Find the first email in the current thread. More...
 
bool mutt_limit_current_thread (struct Email *e)
 Limit the email view to the current thread. More...
 
int mutt_pattern_func (int op, char *prompt)
 Perform some Pattern matching. More...
 
int mutt_search_command (int cur, int op)
 Perform a search. More...
 

Variables

bool C_ThoroughSearch
 Config: Decode headers and messages before searching them. More...
 
static struct RangeRegex range_regexes []
 Set of Regexes for various range types. More...
 
static struct PatternList * SearchPattern = NULL
 current search pattern More...
 
static char LastSearch [256] = { 0 }
 last pattern searched for More...
 
static char LastSearchExpn [1024] = { 0 }
 expanded version of LastSearch More...
 
static const struct PatternFlags Flags []
 Lookup table for all patterns. More...
 

Detailed Description

Match patterns to emails.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

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.

Macro Definition Documentation

◆ RANGE_NUM_RX

#define RANGE_NUM_RX   "([[:digit:]]+|0x[[:xdigit:]]+)[MmKk]?"

Definition at line 79 of file pattern.c.

◆ RANGE_REL_SLOT_RX

#define RANGE_REL_SLOT_RX   "[[:blank:]]*([.^$]|-?" RANGE_NUM_RX ")?[[:blank:]]*"

Definition at line 80 of file pattern.c.

◆ RANGE_REL_RX

#define RANGE_REL_RX   "^" RANGE_REL_SLOT_RX "," RANGE_REL_SLOT_RX

Definition at line 81 of file pattern.c.

◆ RANGE_ABS_SLOT_RX

#define RANGE_ABS_SLOT_RX   "[[:blank:]]*([.^$]|" RANGE_NUM_RX ")?[[:blank:]]*"

Definition at line 84 of file pattern.c.

◆ RANGE_ABS_RX

#define RANGE_ABS_RX   "^" RANGE_ABS_SLOT_RX "-" RANGE_ABS_SLOT_RX

Definition at line 85 of file pattern.c.

◆ RANGE_LT_RX

#define RANGE_LT_RX   "^()[[:blank:]]*(<[[:blank:]]*" RANGE_NUM_RX ")[[:blank:]]*"

Definition at line 88 of file pattern.c.

◆ RANGE_GT_RX

#define RANGE_GT_RX   "^()[[:blank:]]*(>[[:blank:]]*" RANGE_NUM_RX ")[[:blank:]]*"

Definition at line 89 of file pattern.c.

◆ RANGE_BARE_RX

#define RANGE_BARE_RX   "^[[:blank:]]*([.^$]|" RANGE_NUM_RX ")[[:blank:]]*"

Definition at line 92 of file pattern.c.

◆ RANGE_RX_GROUPS

#define RANGE_RX_GROUPS   5

Definition at line 93 of file pattern.c.

◆ KILO

#define KILO   1024

Definition at line 95 of file pattern.c.

◆ MEGA

#define MEGA   1048576

Definition at line 96 of file pattern.c.

◆ EMSG

#define EMSG (   e)    (((e)->msgno) + 1)

Definition at line 97 of file pattern.c.

◆ MUTT_MAXRANGE

#define MUTT_MAXRANGE   -1

Definition at line 99 of file pattern.c.

◆ MUTT_PDR_NO_FLAGS

#define MUTT_PDR_NO_FLAGS   0

No flags are set.

Definition at line 102 of file pattern.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 103 of file pattern.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 104 of file pattern.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 105 of file pattern.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 106 of file pattern.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 107 of file pattern.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 108 of file pattern.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 110 of file pattern.c.

◆ RANGE_DOT

#define RANGE_DOT   '.'

Definition at line 112 of file pattern.c.

◆ RANGE_CIRCUM

#define RANGE_CIRCUM   '^'

Definition at line 113 of file pattern.c.

◆ RANGE_DOLLAR

#define RANGE_DOLLAR   '$'

Definition at line 114 of file pattern.c.

◆ RANGE_LT

#define RANGE_LT   '<'

Definition at line 115 of file pattern.c.

◆ RANGE_GT

#define RANGE_GT   '>'

Definition at line 116 of file pattern.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.

Definition at line 101 of file pattern.c.

◆ addr_predicate_t

typedef bool(* addr_predicate_t) (const struct Address *a)

Test an Address for some condition.

Parameters
aAddress to test
Return values
boolTrue if Address matches the test

Definition at line 208 of file pattern.c.

Enumeration Type Documentation

◆ EatRangeError

Error codes for eat_range_by_regex()

Enumerator
RANGE_E_OK 

Range is valid.

RANGE_E_SYNTAX 

Range contains syntax error.

RANGE_E_CTX 

Range requires Context, but none available.

Definition at line 122 of file pattern.c.

123 {
124  RANGE_E_OK,
126  RANGE_E_CTX,
127 };
Range is valid.
Definition: pattern.c:124
Range contains syntax error.
Definition: pattern.c:125
Range requires Context, but none available.
Definition: pattern.c:126

◆ RangeType

enum RangeType

Type of range.

Enumerator
RANGE_K_REL 

Relative range.

RANGE_K_ABS 

Absolute range.

RANGE_K_LT 

Less-than range.

RANGE_K_GT 

Greater-than range.

RANGE_K_BARE 

Single symbol.

RANGE_K_INVALID 

Range is invalid.

Definition at line 144 of file pattern.c.

145 {
146  RANGE_K_REL,
147  RANGE_K_ABS,
148  RANGE_K_LT,
149  RANGE_K_GT,
150  RANGE_K_BARE,
151  /* add new ones HERE */
153 };
Single symbol.
Definition: pattern.c:150
Greater-than range.
Definition: pattern.c:149
Range is invalid.
Definition: pattern.c:152
Absolute range.
Definition: pattern.c:147
Less-than range.
Definition: pattern.c:148
Relative range.
Definition: pattern.c:146

◆ RangeSide

enum RangeSide

Which side of the range.

Enumerator
RANGE_S_LEFT 

Left side of range.

RANGE_S_RIGHT 

Right side of range.

Definition at line 158 of file pattern.c.

159 {
160  RANGE_S_LEFT,
161  RANGE_S_RIGHT,
162 };
Left side of range.
Definition: pattern.c:160
Right side of range.
Definition: pattern.c:161

Function Documentation

◆ eat_regex()

static bool eat_regex ( struct Pattern pat,
int  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a regex - Implements Pattern::eat_arg()

Definition at line 213 of file pattern.c.

214 {
215  struct Buffer buf;
216 
217  mutt_buffer_init(&buf);
218  char *pexpr = s->dptr;
219  if ((mutt_extract_token(&buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) || !buf.data)
220  {
221  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
222  FREE(&buf.data);
223  return false;
224  }
225  if (buf.data[0] == '\0')
226  {
227  mutt_buffer_printf(err, "%s", _("Empty expression"));
228  FREE(&buf.data);
229  return false;
230  }
231 
232  if (pat->string_match)
233  {
234  pat->p.str = mutt_str_dup(buf.data);
235  pat->ign_case = mutt_mb_is_lower(buf.data);
236  FREE(&buf.data);
237  }
238  else if (pat->group_match)
239  {
240  pat->p.group = mutt_pattern_group(buf.data);
241  FREE(&buf.data);
242  }
243  else
244  {
245  pat->p.regex = mutt_mem_malloc(sizeof(regex_t));
246  int case_flags = mutt_mb_is_lower(buf.data) ? REG_ICASE : 0;
247  int rc = REG_COMP(pat->p.regex, buf.data, REG_NEWLINE | REG_NOSUB | case_flags);
248  if (rc != 0)
249  {
250  char errmsg[256];
251  regerror(rc, pat->p.regex, errmsg, sizeof(errmsg));
252  mutt_buffer_add_printf(err, "'%s': %s", buf.data, errmsg);
253  FREE(&buf.data);
254  FREE(&pat->p.regex);
255  return false;
256  }
257  FREE(&buf.data);
258  }
259 
260  return true;
261 }
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:65
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:76
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
bool string_match
Check a string for a match.
Definition: pattern.h:54
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
bool ign_case
Ignore case for local string_match searches.
Definition: pattern.h:56
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:422
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
union Pattern::@1 p
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
char * str
String, if string_match is set.
Definition: pattern.h:67
struct Group * group
Address group if group_match is set.
Definition: pattern.h:66
#define FREE(x)
Definition: memory.h:40
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:358
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:75
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
Definition: group.c:65
+ Here is the call graph for this function:

◆ add_query_msgid()

static bool add_query_msgid ( char *  line,
int  line_num,
void *  user_data 
)
static

Parse a Message-Id and add it to a list - Implements mutt_file_map_t.

Return values
trueAlways

Definition at line 267 of file pattern.c.

268 {
269  struct ListHead *msgid_list = (struct ListHead *) (user_data);
270  char *nows = mutt_str_skip_whitespace(line);
271  if (*nows == '\0')
272  return true;
274  mutt_list_insert_tail(msgid_list, mutt_str_dup(nows));
275  return true;
276 }
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:691
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:705
int const char int line
Definition: acutest.h:617
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_query()

static bool eat_query ( struct Pattern pat,
int  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a query for an external search program - Implements Pattern::eat_arg()

Definition at line 281 of file pattern.c.

282 {
283  struct Buffer cmd_buf;
284  struct Buffer tok_buf;
285  FILE *fp = NULL;
286 
288  {
289  mutt_buffer_printf(err, "%s", _("No search command defined"));
290  return false;
291  }
292 
293  mutt_buffer_init(&tok_buf);
294  char *pexpr = s->dptr;
295  if ((mutt_extract_token(&tok_buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) ||
296  !tok_buf.data)
297  {
298  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
299  return false;
300  }
301  if (*tok_buf.data == '\0')
302  {
303  mutt_buffer_printf(err, "%s", _("Empty expression"));
304  FREE(&tok_buf.data);
305  return false;
306  }
307 
308  mutt_buffer_init(&cmd_buf);
310  mutt_buffer_addch(&cmd_buf, ' ');
311  if (!Context || !Context->mailbox)
312  {
313  mutt_buffer_addch(&cmd_buf, '/');
314  }
315  else
316  {
317  char *escaped_folder = mutt_path_escape(mailbox_path(Context->mailbox));
318  mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
319  mutt_buffer_addch(&cmd_buf, '\'');
320  mutt_buffer_addstr(&cmd_buf, escaped_folder);
321  mutt_buffer_addch(&cmd_buf, '\'');
322  }
323  mutt_buffer_addch(&cmd_buf, ' ');
324  mutt_buffer_addstr(&cmd_buf, tok_buf.data);
325  FREE(&tok_buf.data);
326 
327  mutt_message(_("Running search command: %s ..."), cmd_buf.data);
328  pat->is_multi = true;
330  pid_t pid = filter_create(cmd_buf.data, NULL, &fp, NULL);
331  if (pid < 0)
332  {
333  mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf.data);
334  FREE(&cmd_buf.data);
335  return false;
336  }
337 
339  mutt_file_fclose(&fp);
340  filter_wait(pid);
341  FREE(&cmd_buf.data);
342  return true;
343 }
The "current" mailbox.
Definition: context.h:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:196
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_message(...)
Definition: logging.h:83
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:76
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:60
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
struct Mailbox * mailbox
Definition: context.h:50
Log at debug level 2.
Definition: logging.h:41
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
bool mutt_file_map_lines(mutt_file_map_t func, void *user_data, FILE *fp, int flags)
Process lines of text read from a file pointer.
Definition: file.c:767
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:522
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:422
union Pattern::@1 p
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
static bool add_query_msgid(char *line, int line_num, void *user_data)
Parse a Message-Id and add it to a list - Implements mutt_file_map_t.
Definition: pattern.c:267
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:68
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
WHERE char * C_ExternalSearchCommand
Config: External search command.
Definition: mutt_globals.h:93
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:167
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:75
+ Here is the call graph for this function:

◆ get_offset()

static const char* get_offset ( struct tm *  tm,
const char *  s,
int  sign 
)
static

Calculate a symbolic offset.

Parameters
tmStore the time here
sstring to parse
signSign of range, 1 for positive, -1 for negative
Return values
ptrNext char after parsed offset
  • Ny years
  • Nm months
  • Nw weeks
  • Nd days

Definition at line 357 of file pattern.c.

358 {
359  char *ps = NULL;
360  int offset = strtol(s, &ps, 0);
361  if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
362  offset = -offset;
363 
364  switch (*ps)
365  {
366  case 'y':
367  tm->tm_year += offset;
368  break;
369  case 'm':
370  tm->tm_mon += offset;
371  break;
372  case 'w':
373  tm->tm_mday += 7 * offset;
374  break;
375  case 'd':
376  tm->tm_mday += offset;
377  break;
378  case 'H':
379  tm->tm_hour += offset;
380  break;
381  case 'M':
382  tm->tm_min += offset;
383  break;
384  case 'S':
385  tm->tm_sec += offset;
386  break;
387  default:
388  return s;
389  }
391  return ps + 1;
392 }
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition: date.c:294
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_date()

static const char* get_date ( const char *  s,
struct tm *  t,
struct Buffer err 
)
static

Parse a (partial) date in dd/mm/yyyy format.

Parameters
sString to parse
tStore the time here
errBuffer for error messages
Return values
ptrFirst character after the date

This function parses a (partial) date separated by '/'. The month and year are optional and if the year is less than 70 it's assumed to be after 2000.

Examples:

  • "10" = 10 of this month, this year
  • "10/12" = 10 of December, this year
  • "10/12/04" = 10 of December, 2004
  • "10/12/2008" = 10 of December, 2008
  • "20081210" = 10 of December, 2008

Definition at line 411 of file pattern.c.

412 {
413  char *p = NULL;
414  struct tm tm = mutt_date_localtime(MUTT_DATE_NOW);
415  bool iso8601 = true;
416 
417  for (int v = 0; v < 8; v++)
418  {
419  if (s[v] && (s[v] >= '0') && (s[v] <= '9'))
420  continue;
421 
422  iso8601 = false;
423  break;
424  }
425 
426  if (iso8601)
427  {
428  int year = 0;
429  int month = 0;
430  int mday = 0;
431  sscanf(s, "%4d%2d%2d", &year, &month, &mday);
432 
433  t->tm_year = year;
434  if (t->tm_year > 1900)
435  t->tm_year -= 1900;
436  t->tm_mon = month - 1;
437  t->tm_mday = mday;
438 
439  if ((t->tm_mday < 1) || (t->tm_mday > 31))
440  {
441  snprintf(err->data, err->dsize, _("Invalid day of month: %s"), s);
442  return NULL;
443  }
444  if ((t->tm_mon < 0) || (t->tm_mon > 11))
445  {
446  snprintf(err->data, err->dsize, _("Invalid month: %s"), s);
447  return NULL;
448  }
449 
450  return (s + 8);
451  }
452 
453  t->tm_mday = strtol(s, &p, 10);
454  if ((t->tm_mday < 1) || (t->tm_mday > 31))
455  {
456  mutt_buffer_printf(err, _("Invalid day of month: %s"), s);
457  return NULL;
458  }
459  if (*p != '/')
460  {
461  /* fill in today's month and year */
462  t->tm_mon = tm.tm_mon;
463  t->tm_year = tm.tm_year;
464  return p;
465  }
466  p++;
467  t->tm_mon = strtol(p, &p, 10) - 1;
468  if ((t->tm_mon < 0) || (t->tm_mon > 11))
469  {
470  mutt_buffer_printf(err, _("Invalid month: %s"), p);
471  return NULL;
472  }
473  if (*p != '/')
474  {
475  t->tm_year = tm.tm_year;
476  return p;
477  }
478  p++;
479  t->tm_year = strtol(p, &p, 10);
480  if (t->tm_year < 70) /* year 2000+ */
481  t->tm_year += 100;
482  else if (t->tm_year > 1900)
483  t->tm_year -= 1900;
484  return p;
485 }
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:641
#define _(a)
Definition: message.h:28
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:37
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_date_range()

static const char* parse_date_range ( const char *  pc,
struct tm *  min,
struct tm *  max,
bool  have_min,
struct tm *  base_min,
struct Buffer err 
)
static

Parse a date range.

Parameters
pcString to parse
minEarlier date
maxLater date
have_minDo we have a base minimum date?
base_minBase minimum date
errBuffer for error messages
Return values
ptrFirst character after the date

Definition at line 497 of file pattern.c.

499 {
501  while (*pc && ((flags & MUTT_PDR_DONE) == 0))
502  {
503  const char *pt = NULL;
504  char ch = *pc++;
505  SKIPWS(pc);
506  switch (ch)
507  {
508  case '-':
509  {
510  /* try a range of absolute date minus offset of Ndwmy */
511  pt = get_offset(min, pc, -1);
512  if (pc == pt)
513  {
514  if (flags == MUTT_PDR_NO_FLAGS)
515  { /* nothing yet and no offset parsed => absolute date? */
516  if (!get_date(pc, max, err))
517  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
518  else
519  {
520  /* reestablish initial base minimum if not specified */
521  if (!have_min)
522  memcpy(min, base_min, sizeof(struct tm));
523  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
524  }
525  }
526  else
527  flags |= MUTT_PDR_ERRORDONE;
528  }
529  else
530  {
531  pc = pt;
532  if ((flags == MUTT_PDR_NO_FLAGS) && !have_min)
533  { /* the very first "-3d" without a previous absolute date */
534  max->tm_year = min->tm_year;
535  max->tm_mon = min->tm_mon;
536  max->tm_mday = min->tm_mday;
537  }
538  flags |= MUTT_PDR_MINUS;
539  }
540  break;
541  }
542  case '+':
543  { /* enlarge plus range */
544  pt = get_offset(max, pc, 1);
545  if (pc == pt)
546  flags |= MUTT_PDR_ERRORDONE;
547  else
548  {
549  pc = pt;
550  flags |= MUTT_PDR_PLUS;
551  }
552  break;
553  }
554  case '*':
555  { /* enlarge window in both directions */
556  pt = get_offset(min, pc, -1);
557  if (pc == pt)
558  flags |= MUTT_PDR_ERRORDONE;
559  else
560  {
561  pc = get_offset(max, pc, 1);
562  flags |= MUTT_PDR_WINDOW;
563  }
564  break;
565  }
566  default:
567  flags |= MUTT_PDR_ERRORDONE;
568  }
569  SKIPWS(pc);
570  }
571  if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
572  { /* get_date has its own error message, don't overwrite it here */
573  mutt_buffer_printf(err, _("Invalid relative date: %s"), pc - 1);
574  }
575  return (flags & MUTT_PDR_ERROR) ? NULL : pc;
576 }
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition: pattern.c:106
#define MUTT_PDR_WINDOW
Extend the range in both directions using &#39;*&#39;.
Definition: pattern.c:105
#define MUTT_PDR_NO_FLAGS
No flags are set.
Definition: pattern.c:102
#define MUTT_PDR_ERROR
Invalid pattern.
Definition: pattern.c:108
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * get_date(const char *s, struct tm *t, struct Buffer *err)
Parse a (partial) date in dd/mm/yyyy format.
Definition: pattern.c:411
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: pattern.c:357
#define MUTT_PDR_PLUS
Extend the range using &#39;+&#39;.
Definition: pattern.c:104
#define SKIPWS(ch)
Definition: string2.h:46
#define MUTT_PDR_MINUS
Pattern contains a range.
Definition: pattern.c:103
#define MUTT_PDR_ERRORDONE
Definition: pattern.c:110
#define MUTT_PDR_DONE
Pattern parse successfully.
Definition: pattern.c:107
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
Definition: pattern.c:101
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ adjust_date_range()

static void adjust_date_range ( struct tm *  min,
struct tm *  max 
)
static

Put a date range in the correct order.

Parameters
[in,out]minEarlier date
[in,out]maxLater date

Definition at line 583 of file pattern.c.

584 {
585  if ((min->tm_year > max->tm_year) ||
586  ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
587  ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
588  (min->tm_mday > max->tm_mday)))
589  {
590  int tmp;
591 
592  tmp = min->tm_year;
593  min->tm_year = max->tm_year;
594  max->tm_year = tmp;
595 
596  tmp = min->tm_mon;
597  min->tm_mon = max->tm_mon;
598  max->tm_mon = tmp;
599 
600  tmp = min->tm_mday;
601  min->tm_mday = max->tm_mday;
602  max->tm_mday = tmp;
603 
604  min->tm_hour = 0;
605  min->tm_min = 0;
606  min->tm_sec = 0;
607  max->tm_hour = 23;
608  max->tm_min = 59;
609  max->tm_sec = 59;
610  }
611 }
+ Here is the caller graph for this function:

◆ eval_date_minmax()

static bool eval_date_minmax ( struct Pattern pat,
const char *  s,
struct Buffer err 
)
static

Evaluate a date-range pattern against 'now'.

Parameters
patPattern to modify
sPattern string to use
errBuffer for error messages
Return values
truePattern valid and updated
falsePattern invalid

Definition at line 621 of file pattern.c.

622 {
623  /* the '0' time is Jan 1, 1970 UTC, so in order to prevent a negative time
624  * when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */
625  struct tm min = { 0 };
626  min.tm_mday = 2;
627  min.tm_year = 70;
628 
629  /* Arbitrary year in the future. Don't set this too high or
630  * mutt_date_make_time() returns something larger than will fit in a time_t
631  * on some systems */
632  struct tm max = { 0 };
633  max.tm_year = 130;
634  max.tm_mon = 11;
635  max.tm_mday = 31;
636  max.tm_hour = 23;
637  max.tm_min = 59;
638  max.tm_sec = 59;
639 
640  if (strchr("<>=", s[0]))
641  {
642  /* offset from current time
643  * <3d less than three days ago
644  * >3d more than three days ago
645  * =3d exactly three days ago */
646  struct tm *tm = NULL;
647  bool exact = false;
648 
649  if (s[0] == '<')
650  {
652  tm = &min;
653  }
654  else
655  {
657  tm = &max;
658 
659  if (s[0] == '=')
660  exact = true;
661  }
662 
663  /* Reset the HMS unless we are relative matching using one of those
664  * offsets. */
665  char *offset_type = NULL;
666  strtol(s + 1, &offset_type, 0);
667  if (!(*offset_type && strchr("HMS", *offset_type)))
668  {
669  tm->tm_hour = 23;
670  tm->tm_min = 59;
671  tm->tm_sec = 59;
672  }
673 
674  /* force negative offset */
675  get_offset(tm, s + 1, -1);
676 
677  if (exact)
678  {
679  /* start at the beginning of the day in question */
680  memcpy(&min, &max, sizeof(max));
681  min.tm_hour = 0;
682  min.tm_sec = 0;
683  min.tm_min = 0;
684  }
685  }
686  else
687  {
688  const char *pc = s;
689 
690  bool have_min = false;
691  bool until_now = false;
692  if (isdigit((unsigned char) *pc))
693  {
694  /* minimum date specified */
695  pc = get_date(pc, &min, err);
696  if (!pc)
697  {
698  return false;
699  }
700  have_min = true;
701  SKIPWS(pc);
702  if (*pc == '-')
703  {
704  const char *pt = pc + 1;
705  SKIPWS(pt);
706  until_now = (*pt == '\0');
707  }
708  }
709 
710  if (!until_now)
711  { /* max date or relative range/window */
712 
713  struct tm base_min;
714 
715  if (!have_min)
716  { /* save base minimum and set current date, e.g. for "-3d+1d" */
717  memcpy(&base_min, &min, sizeof(base_min));
719  min.tm_hour = 0;
720  min.tm_sec = 0;
721  min.tm_min = 0;
722  }
723 
724  /* preset max date for relative offsets,
725  * if nothing follows we search for messages on a specific day */
726  max.tm_year = min.tm_year;
727  max.tm_mon = min.tm_mon;
728  max.tm_mday = min.tm_mday;
729 
730  if (!parse_date_range(pc, &min, &max, have_min, &base_min, err))
731  { /* bail out on any parsing error */
732  return false;
733  }
734  }
735  }
736 
737  /* Since we allow two dates to be specified we'll have to adjust that. */
738  adjust_date_range(&min, &max);
739 
740  pat->min = mutt_date_make_time(&min, true);
741  pat->max = mutt_date_make_time(&max, true);
742 
743  return true;
744 }
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition: pattern.c:583
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:641
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:37
static const char * get_date(const char *s, struct tm *t, struct Buffer *err)
Parse a (partial) date in dd/mm/yyyy format.
Definition: pattern.c:411
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: pattern.c:357
#define SKIPWS(ch)
Definition: string2.h:46
int min
Minimum for range checks.
Definition: pattern.h:61
int max
Maximum for range checks.
Definition: pattern.h:62
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:228
static const char * parse_date_range(const char *pc, struct tm *min, struct tm *max, bool have_min, struct tm *base_min, struct Buffer *err)
Parse a date range.
Definition: pattern.c:497
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_range()

static bool eat_range ( struct Pattern pat,
int  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a number range - Implements Pattern::eat_arg()

Definition at line 749 of file pattern.c.

750 {
751  char *tmp = NULL;
752  bool do_exclusive = false;
753  bool skip_quote = false;
754 
755  /* If simple_search is set to "~m %s", the range will have double quotes
756  * around it... */
757  if (*s->dptr == '"')
758  {
759  s->dptr++;
760  skip_quote = true;
761  }
762  if (*s->dptr == '<')
763  do_exclusive = true;
764  if ((*s->dptr != '-') && (*s->dptr != '<'))
765  {
766  /* range minimum */
767  if (*s->dptr == '>')
768  {
769  pat->max = MUTT_MAXRANGE;
770  pat->min = strtol(s->dptr + 1, &tmp, 0) + 1; /* exclusive range */
771  }
772  else
773  pat->min = strtol(s->dptr, &tmp, 0);
774  if (toupper((unsigned char) *tmp) == 'K') /* is there a prefix? */
775  {
776  pat->min *= 1024;
777  tmp++;
778  }
779  else if (toupper((unsigned char) *tmp) == 'M')
780  {
781  pat->min *= 1048576;
782  tmp++;
783  }
784  if (*s->dptr == '>')
785  {
786  s->dptr = tmp;
787  return true;
788  }
789  if (*tmp != '-')
790  {
791  /* exact value */
792  pat->max = pat->min;
793  s->dptr = tmp;
794  return true;
795  }
796  tmp++;
797  }
798  else
799  {
800  s->dptr++;
801  tmp = s->dptr;
802  }
803 
804  if (isdigit((unsigned char) *tmp))
805  {
806  /* range maximum */
807  pat->max = strtol(tmp, &tmp, 0);
808  if (toupper((unsigned char) *tmp) == 'K')
809  {
810  pat->max *= 1024;
811  tmp++;
812  }
813  else if (toupper((unsigned char) *tmp) == 'M')
814  {
815  pat->max *= 1048576;
816  tmp++;
817  }
818  if (do_exclusive)
819  (pat->max)--;
820  }
821  else
822  pat->max = MUTT_MAXRANGE;
823 
824  if (skip_quote && (*tmp == '"'))
825  tmp++;
826 
827  SKIPWS(tmp);
828  s->dptr = tmp;
829  return true;
830 }
#define MUTT_MAXRANGE
Definition: pattern.c:99
#define SKIPWS(ch)
Definition: string2.h:46
int min
Minimum for range checks.
Definition: pattern.h:61
char * dptr
Current read/write position.
Definition: buffer.h:36
int max
Maximum for range checks.
Definition: pattern.h:62

◆ report_regerror()

static int report_regerror ( int  regerr,
regex_t *  preg,
struct Buffer err 
)
static

Create a regex error message.

Parameters
regerrRegex error code
pregRegex pattern buffer
errBuffer for error messages
Return values
RANGE_E_SYNTAXAlways

Definition at line 839 of file pattern.c.

840 {
841  size_t ds = err->dsize;
842 
843  if (regerror(regerr, preg, err->data, ds) > ds)
844  mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
845  /* The return value is fixed, exists only to shorten code at callsite */
846  return RANGE_E_SYNTAX;
847 }
Range contains syntax error.
Definition: pattern.c:125
size_t dsize
Length of data.
Definition: buffer.h:37
Log at debug level 2.
Definition: logging.h:41
char * data
Pointer to data.
Definition: buffer.h:35
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the caller graph for this function:

◆ is_context_available()

static bool is_context_available ( struct Buffer s,
regmatch_t  pmatch[],
int  kind,
struct Buffer err 
)
static

Do we need a Context for this Pattern?

Parameters
sString to check
pmatchRegex matches
kindRange type, e.g. RANGE_K_REL
errBuffer for error messages
Return values
falseIf context is required, but not available
trueOtherwise

Definition at line 858 of file pattern.c.

860 {
861  const char *context_req_chars[] = {
862  [RANGE_K_REL] = ".0123456789",
863  [RANGE_K_ABS] = ".",
864  [RANGE_K_LT] = "",
865  [RANGE_K_GT] = "",
866  [RANGE_K_BARE] = ".",
867  };
868 
869  /* First decide if we're going to need the context at all.
870  * Relative patterns need it if they contain a dot or a number.
871  * Absolute patterns only need it if they contain a dot. */
872  char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
873  if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
874  return true;
875 
876  /* We need a current message. Do we actually have one? */
877  if (Context && Context->menu)
878  return true;
879 
880  /* Nope. */
881  mutt_buffer_strcpy(err, _("No current message"));
882  return false;
883 }
The "current" mailbox.
Definition: context.h:37
Single symbol.
Definition: pattern.c:150
#define _(a)
Definition: message.h:28
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Greater-than range.
Definition: pattern.c:149
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Absolute range.
Definition: pattern.c:147
Less-than range.
Definition: pattern.c:148
Relative range.
Definition: pattern.c:146
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ scan_range_num()

static int scan_range_num ( struct Buffer s,
regmatch_t  pmatch[],
int  group,
int  kind 
)
static

Parse a number range.

Parameters
sString to parse
pmatchArray of regex matches
groupIndex of regex match to use
kindRange type, e.g. RANGE_K_REL
Return values
numParse number

Definition at line 893 of file pattern.c.

894 {
895  int num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
896  unsigned char c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
897  if (toupper(c) == 'K')
898  num *= KILO;
899  else if (toupper(c) == 'M')
900  num *= MEGA;
901  switch (kind)
902  {
903  case RANGE_K_REL:
904  {
906  return num + EMSG(e);
907  }
908  case RANGE_K_LT:
909  return num - 1;
910  case RANGE_K_GT:
911  return num + 1;
912  default:
913  return num;
914  }
915 }
The "current" mailbox.
Definition: context.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
#define MEGA
Definition: pattern.c:96
#define KILO
Definition: pattern.c:95
struct Mailbox * mailbox
Definition: context.h:50
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Greater-than range.
Definition: pattern.c:149
char * dptr
Current read/write position.
Definition: buffer.h:36
#define EMSG(e)
Definition: pattern.c:97
int current
Current entry.
Definition: mutt_menu.h:85
Less-than range.
Definition: pattern.c:148
Relative range.
Definition: pattern.c:146
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ scan_range_slot()

static int scan_range_slot ( struct Buffer s,
regmatch_t  pmatch[],
int  grp,
int  side,
int  kind 
)
static

Parse a range of message numbers.

Parameters
sString to parse
pmatchRegex matches
grpWhich regex match to use
sideWhich side of the range is this? RANGE_S_LEFT or RANGE_S_RIGHT
kindRange type, e.g. RANGE_K_REL
Return values
numIndex number for the message specified

Definition at line 926 of file pattern.c.

927 {
928  /* This means the left or right subpattern was empty, e.g. ",." */
929  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
930  {
931  if (side == RANGE_S_LEFT)
932  return 1;
933  if (side == RANGE_S_RIGHT)
934  return Context->mailbox->msg_count;
935  }
936  /* We have something, so determine what */
937  unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
938  switch (c)
939  {
940  case RANGE_CIRCUM:
941  return 1;
942  case RANGE_DOLLAR:
943  return Context->mailbox->msg_count;
944  case RANGE_DOT:
945  {
947  return EMSG(e);
948  }
949  case RANGE_LT:
950  case RANGE_GT:
951  return scan_range_num(s, pmatch, grp + 1, kind);
952  default:
953  /* Only other possibility: a number */
954  return scan_range_num(s, pmatch, grp, kind);
955  }
956 }
The "current" mailbox.
Definition: context.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
#define RANGE_LT
Definition: pattern.c:115
#define RANGE_DOLLAR
Definition: pattern.c:114
struct Mailbox * mailbox
Definition: context.h:50
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind)
Parse a number range.
Definition: pattern.c:893
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Left side of range.
Definition: pattern.c:160
char * dptr
Current read/write position.
Definition: buffer.h:36
#define RANGE_GT
Definition: pattern.c:116
#define RANGE_CIRCUM
Definition: pattern.c:113
#define EMSG(e)
Definition: pattern.c:97
int current
Current entry.
Definition: mutt_menu.h:85
#define RANGE_DOT
Definition: pattern.c:112
Right side of range.
Definition: pattern.c:161
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ order_range()

static void order_range ( struct Pattern pat)
static

Put a range in order.

Parameters
patPattern to check

Definition at line 962 of file pattern.c.

963 {
964  if (pat->min <= pat->max)
965  return;
966  int num = pat->min;
967  pat->min = pat->max;
968  pat->max = num;
969 }
int min
Minimum for range checks.
Definition: pattern.h:61
int max
Maximum for range checks.
Definition: pattern.h:62
+ Here is the caller graph for this function:

◆ eat_range_by_regex()

static int eat_range_by_regex ( struct Pattern pat,
struct Buffer s,
int  kind,
struct Buffer err 
)
static

Parse a range given as a regex.

Parameters
patPattern to store the range in
sString to parse
kindRange type, e.g. RANGE_K_REL
errBuffer for error messages
Return values
numEatRangeError code, e.g. RANGE_E_OK

Definition at line 979 of file pattern.c.

981 {
982  int regerr;
983  regmatch_t pmatch[RANGE_RX_GROUPS];
984  struct RangeRegex *pspec = &range_regexes[kind];
985 
986  /* First time through, compile the big regex */
987  if (!pspec->ready)
988  {
989  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
990  if (regerr != 0)
991  return report_regerror(regerr, &pspec->cooked, err);
992  pspec->ready = true;
993  }
994 
995  /* Match the pattern buffer against the compiled regex.
996  * No match means syntax error. */
997  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
998  if (regerr != 0)
999  return report_regerror(regerr, &pspec->cooked, err);
1000 
1001  if (!is_context_available(s, pmatch, kind, err))
1002  return RANGE_E_CTX;
1003 
1004  /* Snarf the contents of the two sides of the range. */
1005  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind);
1006  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind);
1007  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
1008 
1009  /* Special case for a bare 0. */
1010  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
1011  {
1012  if (!Context->menu)
1013  {
1014  mutt_buffer_strcpy(err, _("No current message"));
1015  return RANGE_E_CTX;
1016  }
1018  pat->max = EMSG(e);
1019  pat->min = pat->max;
1020  }
1021 
1022  /* Since we don't enforce order, we must swap bounds if they're backward */
1023  order_range(pat);
1024 
1025  /* Slide pointer past the entire match. */
1026  s->dptr += pmatch[0].rm_eo;
1027  return RANGE_E_OK;
1028 }
The "current" mailbox.
Definition: context.h:37
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
regex_t cooked
Compiled form.
Definition: pattern.c:138
Single symbol.
Definition: pattern.c:150
Range is valid.
Definition: pattern.c:124
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:126
struct Mailbox * mailbox
Definition: context.h:50
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
int min
Minimum for range checks.
Definition: pattern.h:61
Left side of range.
Definition: pattern.c:160
Regular expression representing a range.
Definition: pattern.c:132
#define RANGE_RX_GROUPS
Definition: pattern.c:93
static struct RangeRegex range_regexes[]
Set of Regexes for various range types.
Definition: pattern.c:190
char * dptr
Current read/write position.
Definition: buffer.h:36
const char * raw
Regex as string.
Definition: pattern.c:134
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Log at debug level 1.
Definition: logging.h:40
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: pattern.c:962
#define EMSG(e)
Definition: pattern.c:97
static int scan_range_slot(struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind)
Parse a range of message numbers.
Definition: pattern.c:926
int max
Maximum for range checks.
Definition: pattern.h:62
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: pattern.c:839
int lgrp
Paren group matching the left side.
Definition: pattern.c:135
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int current
Current entry.
Definition: mutt_menu.h:85
int rgrp
Paren group matching the right side.
Definition: pattern.c:136
bool ready
Compiled yet?
Definition: pattern.c:137
static bool is_context_available(struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err)
Do we need a Context for this Pattern?
Definition: pattern.c:858
Right side of range.
Definition: pattern.c:161
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ eat_message_range()

static bool eat_message_range ( struct Pattern pat,
int  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a range of message numbers - Implements Pattern::eat_arg()

Definition at line 1033 of file pattern.c.

1035 {
1036  bool skip_quote = false;
1037 
1038  /* We need a Context for pretty much anything. */
1039  if (!Context)
1040  {
1041  mutt_buffer_strcpy(err, _("No Context"));
1042  return false;
1043  }
1044 
1045  /* If simple_search is set to "~m %s", the range will have double quotes
1046  * around it... */
1047  if (*s->dptr == '"')
1048  {
1049  s->dptr++;
1050  skip_quote = true;
1051  }
1052 
1053  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
1054  {
1055  switch (eat_range_by_regex(pat, s, i_kind, err))
1056  {
1057  case RANGE_E_CTX:
1058  /* This means it matched syntactically but lacked context.
1059  * No point in continuing. */
1060  break;
1061  case RANGE_E_SYNTAX:
1062  /* Try another syntax, then */
1063  continue;
1064  case RANGE_E_OK:
1065  if (skip_quote && (*s->dptr == '"'))
1066  s->dptr++;
1067  SKIPWS(s->dptr);
1068  return true;
1069  }
1070  }
1071  return false;
1072 }
The "current" mailbox.
Definition: context.h:37
Range is valid.
Definition: pattern.c:124
Range contains syntax error.
Definition: pattern.c:125
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:126
#define SKIPWS(ch)
Definition: string2.h:46
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Range is invalid.
Definition: pattern.c:152
static int eat_range_by_regex(struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err)
Parse a range given as a regex.
Definition: pattern.c:979
+ Here is the call graph for this function:

◆ eat_date()

static bool eat_date ( struct Pattern pat,
int  flags,
struct Buffer s,
struct Buffer err 
)
static

Parse a date pattern - Implements Pattern::eat_arg()

Definition at line 1077 of file pattern.c.

1078 {
1079  struct Buffer *tmp = mutt_buffer_pool_get();
1080  bool rc = false;
1081 
1082  char *pexpr = s->dptr;
1084  {
1085  snprintf(err->data, err->dsize, _("Error in expression: %s"), pexpr);
1086  goto out;
1087  }
1088 
1089  if (mutt_buffer_is_empty(tmp))
1090  {
1091  snprintf(err->data, err->dsize, "%s", _("Empty expression"));
1092  goto out;
1093  }
1094 
1095  if (flags & MUTT_PC_PATTERN_DYNAMIC)
1096  {
1097  pat->dynamic = true;
1098  pat->p.str = mutt_str_dup(tmp->data);
1099  }
1100 
1101  rc = eval_date_minmax(pat, tmp->data, err);
1102 
1103 out:
1105 
1106  return rc;
1107 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:76
String manipulation buffer.
Definition: buffer.h:33
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#define _(a)
Definition: message.h:28
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: pattern.h:43
size_t dsize
Length of data.
Definition: buffer.h:37
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:58
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:422
static bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against &#39;now&#39;.
Definition: pattern.c:621
union Pattern::@1 p
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
char * str
String, if string_match is set.
Definition: pattern.h:67
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:75
+ Here is the call graph for this function:

◆ patmatch()

static bool patmatch ( const struct Pattern pat,
const char *  buf 
)
static

Compare a string to a Pattern.

Parameters
patPattern to use
bufString to compare
Return values
trueMatch
falseNo match

Definition at line 1116 of file pattern.c.

1117 {
1118  if (pat->is_multi)
1119  return (mutt_list_find(&pat->p.multi_cases, buf) != NULL);
1120  if (pat->string_match)
1121  return pat->ign_case ? strcasestr(buf, pat->p.str) : strstr(buf, pat->p.str);
1122  if (pat->group_match)
1123  return mutt_group_match(pat->p.group, buf);
1124  return (regexec(pat->p.regex, buf, 0, NULL, 0) == 0);
1125 }
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:65
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:60
bool mutt_group_match(struct Group *g, const char *s)
Does a string match an entry in a Group?
Definition: group.c:324
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:102
bool string_match
Check a string for a match.
Definition: pattern.h:54
bool ign_case
Ignore case for local string_match searches.
Definition: pattern.h:56
union Pattern::@1 p
char * str
String, if string_match is set.
Definition: pattern.h:67
struct Group * group
Address group if group_match is set.
Definition: pattern.h:66
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ msg_search()

static bool msg_search ( struct Mailbox m,
struct Pattern pat,
int  msgno 
)
static

Search an email.

Parameters
mMailbox
patPattern to find
msgnoMessage to search
Return values
truePattern found
falseError or pattern not found

Definition at line 1135 of file pattern.c.

1136 {
1137  bool match = false;
1138  struct Message *msg = mx_msg_open(m, msgno);
1139  if (!msg)
1140  {
1141  return match;
1142  }
1143 
1144  FILE *fp = NULL;
1145  long len = 0;
1146  struct Email *e = m->emails[msgno];
1147 #ifdef USE_FMEMOPEN
1148  char *temp = NULL;
1149  size_t tempsize = 0;
1150 #else
1151  struct stat st;
1152 #endif
1153 
1154  if (C_ThoroughSearch)
1155  {
1156  /* decode the header / body */
1157  struct State s = { 0 };
1158  s.fp_in = msg->fp;
1159  s.flags = MUTT_CHARCONV;
1160 #ifdef USE_FMEMOPEN
1161  s.fp_out = open_memstream(&temp, &tempsize);
1162  if (!s.fp_out)
1163  {
1164  mutt_perror(_("Error opening 'memory stream'"));
1165  return false;
1166  }
1167 #else
1168  s.fp_out = mutt_file_mkstemp();
1169  if (!s.fp_out)
1170  {
1171  mutt_perror(_("Can't create temporary file"));
1172  return false;
1173  }
1174 #endif
1175 
1176  if (pat->op != MUTT_PAT_BODY)
1177  mutt_copy_header(msg->fp, e, s.fp_out, CH_FROM | CH_DECODE, NULL, 0);
1178 
1179  if (pat->op != MUTT_PAT_HEADER)
1180  {
1182 
1183  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) &&
1185  {
1186  mx_msg_close(m, &msg);
1187  if (s.fp_out)
1188  {
1190 #ifdef USE_FMEMOPEN
1191  FREE(&temp);
1192 #endif
1193  }
1194  return false;
1195  }
1196 
1197  fseeko(msg->fp, e->offset, SEEK_SET);
1198  mutt_body_handler(e->content, &s);
1199  }
1200 
1201 #ifdef USE_FMEMOPEN
1203  len = tempsize;
1204 
1205  if (tempsize != 0)
1206  {
1207  fp = fmemopen(temp, tempsize, "r");
1208  if (!fp)
1209  {
1210  mutt_perror(_("Error re-opening 'memory stream'"));
1211  FREE(&temp);
1212  return false;
1213  }
1214  }
1215  else
1216  { /* fmemopen can't handle empty buffers */
1217  fp = mutt_file_fopen("/dev/null", "r");
1218  if (!fp)
1219  {
1220  mutt_perror(_("Error opening /dev/null"));
1221  return false;
1222  }
1223  }
1224 #else
1225  fp = s.fp_out;
1226  fflush(fp);
1227  fseek(fp, 0, SEEK_SET);
1228  fstat(fileno(fp), &st);
1229  len = (long) st.st_size;
1230 #endif
1231  }
1232  else
1233  {
1234  /* raw header / body */
1235  fp = msg->fp;
1236  if (pat->op != MUTT_PAT_BODY)
1237  {
1238  fseeko(fp, e->offset, SEEK_SET);
1239  len = e->content->offset - e->offset;
1240  }
1241  if (pat->op != MUTT_PAT_HEADER)
1242  {
1243  if (pat->op == MUTT_PAT_BODY)
1244  fseeko(fp, e->content->offset, SEEK_SET);
1245  len += e->content->length;
1246  }
1247  }
1248 
1249  size_t blen = 256;
1250  char *buf = mutt_mem_malloc(blen);
1251 
1252  /* search the file "fp" */
1253  while (len > 0)
1254  {
1255  if (pat->op == MUTT_PAT_HEADER)
1256  {
1257  buf = mutt_rfc822_read_line(fp, buf, &blen);
1258  if (*buf == '\0')
1259  break;
1260  }
1261  else if (!fgets(buf, blen - 1, fp))
1262  break; /* don't loop forever */
1263  if (patmatch(pat, buf))
1264  {
1265  match = true;
1266  break;
1267  }
1268  len -= mutt_str_len(buf);
1269  }
1270 
1271  FREE(&buf);
1272 
1273  mx_msg_close(m, &msg);
1274 
1275  if (C_ThoroughSearch)
1276  mutt_file_fclose(&fp);
1277 
1278 #ifdef USE_FMEMOPEN
1279  FREE(&temp);
1280 #endif
1281  return match;
1282 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
Pattern matches email&#39;s header.
Definition: pattern.h:125
#define WithCrypto
Definition: lib.h:118
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
struct Body * content
List of MIME parts.
Definition: email.h:90
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:48
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1180
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
A local copy of an email.
Definition: mx.h:83
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
bool C_ThoroughSearch
Config: Decode headers and messages before searching them.
Definition: pattern.c:75
#define mutt_file_mkstemp()
Definition: file.h:106
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:83
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
Pattern matches email&#39;s body.
Definition: pattern.h:124
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:399
FILE * fp
pointer to the message data
Definition: mx.h:85
#define FREE(x)
Definition: memory.h:40
Keep track when processing files.
Definition: state.h:44
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1585
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1132
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
int msgno
Number displayed to the user.
Definition: email.h:86
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:1031
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ lookup_tag()

static const struct PatternFlags* lookup_tag ( char  tag)
static

Lookup a pattern modifier.

Parameters
tagLetter, e.g. 'b' for pattern '~b'
Return values
ptrPattern data

Definition at line 1348 of file pattern.c.

1349 {
1350  for (int i = 0; Flags[i].tag; i++)
1351  if (Flags[i].tag == tag)
1352  return &Flags[i];
1353  return NULL;
1354 }
int tag
Character used to represent this operation, e.g. &#39;A&#39; for &#39;~A&#39;.
Definition: pattern.c:169
static const struct PatternFlags Flags[]
Lookup table for all patterns.
Definition: pattern.c:1288
+ Here is the caller graph for this function:

◆ find_matching_paren()

static char* find_matching_paren ( char *  s)
static

Find the matching parenthesis.

Parameters
sstring to search
Return values
ptr
  • Matching close parenthesis
  • End of string NUL, if not found

Definition at line 1363 of file pattern.c.

1364 {
1365  int level = 1;
1366 
1367  for (; *s; s++)
1368  {
1369  if (*s == '(')
1370  level++;
1371  else if (*s == ')')
1372  {
1373  level--;
1374  if (level == 0)
1375  break;
1376  }
1377  }
1378  return s;
1379 }
+ Here is the caller graph for this function:

◆ mutt_pattern_free()

void mutt_pattern_free ( struct PatternList **  pat)

Free a Pattern.

Parameters
[out]patPattern to free

Definition at line 1385 of file pattern.c.

1386 {
1387  if (!pat || !*pat)
1388  return;
1389 
1390  struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
1391 
1392  while (np)
1393  {
1394  next = SLIST_NEXT(np, entries);
1395 
1396  if (np->is_multi)
1398  else if (np->string_match || np->dynamic)
1399  FREE(&np->p.str);
1400  else if (np->group_match)
1401  np->p.group = NULL;
1402  else if (np->p.regex)
1403  {
1404  regfree(np->p.regex);
1405  FREE(&np->p.regex);
1406  }
1407 
1408  mutt_pattern_free(&np->child);
1409  FREE(&np);
1410 
1411  np = next;
1412  }
1413 
1414  FREE(pat);
1415 }
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:63
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:65
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:60
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
A simple (non-regex) pattern.
Definition: pattern.h:49
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:58
bool string_match
Check a string for a match.
Definition: pattern.h:54
#define SLIST_NEXT(elm, field)
Definition: queue.h:269
#define SLIST_FIRST(head)
Definition: queue.h:228
union Pattern::@1 p
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1385
char * str
String, if string_match is set.
Definition: pattern.h:67
struct Group * group
Address group if group_match is set.
Definition: pattern.h:66
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_node_new()

static struct PatternList* mutt_pattern_node_new ( void  )
static

Create a new list containing a Pattern.

Return values
ptrNewly created list containing a single node with a Pattern

Definition at line 1421 of file pattern.c.

1422 {
1423  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1424  SLIST_INIT(h);
1425  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1426  SLIST_INSERT_HEAD(h, p, entries);
1427  return h;
1428 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define SLIST_INIT(head)
Definition: queue.h:255
A simple (non-regex) pattern.
Definition: pattern.h:49
union Pattern::@1 p
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:264
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_comp()

struct PatternList* mutt_pattern_comp ( const char *  s,
PatternCompFlags  flags,
struct Buffer err 
)

Create a Pattern.

Parameters
sPattern string
flagsFlags, e.g. MUTT_PC_FULL_MSG
errBuffer for error messages
Return values
ptrNewly allocated Pattern

Definition at line 1437 of file pattern.c.

1438 {
1439  /* curlist when assigned will always point to a list containing at least one node
1440  * with a Pattern value. */
1441  struct PatternList *curlist = NULL;
1442  struct PatternList *tmp = NULL, *tmp2 = NULL;
1443  struct PatternList *last = NULL;
1444  bool pat_not = false;
1445  bool all_addr = false;
1446  bool pat_or = false;
1447  bool implicit = true; /* used to detect logical AND operator */
1448  bool is_alias = false;
1449  short thread_op;
1450  const struct PatternFlags *entry = NULL;
1451  char *p = NULL;
1452  char *buf = NULL;
1453  struct Buffer ps;
1454 
1455  mutt_buffer_init(&ps);
1456  ps.dptr = (char *) s;
1457  ps.dsize = mutt_str_len(s);
1458 
1459  while (*ps.dptr)
1460  {
1461  SKIPWS(ps.dptr);
1462  switch (*ps.dptr)
1463  {
1464  case '^':
1465  ps.dptr++;
1466  all_addr = !all_addr;
1467  break;
1468  case '!':
1469  ps.dptr++;
1470  pat_not = !pat_not;
1471  break;
1472  case '@':
1473  ps.dptr++;
1474  is_alias = !is_alias;
1475  break;
1476  case '|':
1477  if (!pat_or)
1478  {
1479  if (!curlist)
1480  {
1481  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1482  return NULL;
1483  }
1484 
1485  struct Pattern *pat = SLIST_FIRST(curlist);
1486 
1487  if (SLIST_NEXT(pat, entries))
1488  {
1489  /* A & B | C == (A & B) | C */
1490  tmp = mutt_pattern_node_new();
1491  pat = SLIST_FIRST(tmp);
1492  pat->op = MUTT_PAT_AND;
1493  pat->child = curlist;
1494 
1495  curlist = tmp;
1496  last = curlist;
1497  }
1498 
1499  pat_or = true;
1500  }
1501  ps.dptr++;
1502  implicit = false;
1503  pat_not = false;
1504  all_addr = false;
1505  is_alias = false;
1506  break;
1507  case '%':
1508  case '=':
1509  case '~':
1510  {
1511  struct Pattern *pat = NULL;
1512  if (ps.dptr[1] == '\0')
1513  {
1514  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1515  goto cleanup;
1516  }
1517  thread_op = 0;
1518  if (ps.dptr[1] == '(')
1519  thread_op = MUTT_PAT_THREAD;
1520  else if ((ps.dptr[1] == '<') && (ps.dptr[2] == '('))
1521  thread_op = MUTT_PAT_PARENT;
1522  else if ((ps.dptr[1] == '>') && (ps.dptr[2] == '('))
1523  thread_op = MUTT_PAT_CHILDREN;
1524  if (thread_op)
1525  {
1526  ps.dptr++; /* skip ~ */
1527  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1528  ps.dptr++;
1529  p = find_matching_paren(ps.dptr + 1);
1530  if (p[0] != ')')
1531  {
1532  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1533  goto cleanup;
1534  }
1535  tmp = mutt_pattern_node_new();
1536  pat = SLIST_FIRST(tmp);
1537  pat->op = thread_op;
1538  if (last)
1539  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1540  else
1541  curlist = tmp;
1542  last = tmp;
1543  pat->pat_not ^= pat_not;
1544  pat->all_addr |= all_addr;
1545  pat->is_alias |= is_alias;
1546  pat_not = false;
1547  all_addr = false;
1548  is_alias = false;
1549  /* compile the sub-expression */
1550  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1551  tmp2 = mutt_pattern_comp(buf, flags, err);
1552  if (!tmp2)
1553  {
1554  FREE(&buf);
1555  goto cleanup;
1556  }
1557  FREE(&buf);
1558  pat->child = tmp2;
1559  ps.dptr = p + 1; /* restore location */
1560  break;
1561  }
1562  if (implicit && pat_or)
1563  {
1564  /* A | B & C == (A | B) & C */
1565  tmp = mutt_pattern_node_new();
1566  pat = SLIST_FIRST(tmp);
1567  pat->op = MUTT_PAT_OR;
1568  pat->child = curlist;
1569  curlist = tmp;
1570  last = tmp;
1571  pat_or = false;
1572  }
1573 
1574  tmp = mutt_pattern_node_new();
1575  pat = SLIST_FIRST(tmp);
1576  pat->pat_not = pat_not;
1577  pat->all_addr = all_addr;
1578  pat->is_alias = is_alias;
1579  pat->string_match = (ps.dptr[0] == '=');
1580  pat->group_match = (ps.dptr[0] == '%');
1581  pat_not = false;
1582  all_addr = false;
1583  is_alias = false;
1584 
1585  if (last)
1586  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1587  else
1588  curlist = tmp;
1589  if (curlist != last)
1590  FREE(&last);
1591  last = tmp;
1592 
1593  ps.dptr++; /* move past the ~ */
1594  entry = lookup_tag(*ps.dptr);
1595  if (!entry)
1596  {
1597  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1598  goto cleanup;
1599  }
1600  if (entry->flags && ((flags & entry->flags) == 0))
1601  {
1602  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1603  goto cleanup;
1604  }
1605  if (flags & MUTT_PC_SEND_MODE_SEARCH)
1606  pat->sendmode = true;
1607 
1608  pat->op = entry->op;
1609 
1610  ps.dptr++; /* eat the operator and any optional whitespace */
1611  SKIPWS(ps.dptr);
1612 
1613  if (entry->eat_arg)
1614  {
1615  if (ps.dptr[0] == '\0')
1616  {
1617  mutt_buffer_printf(err, "%s", _("missing parameter"));
1618  goto cleanup;
1619  }
1620  if (!entry->eat_arg(pat, flags, &ps, err))
1621  {
1622  goto cleanup;
1623  }
1624  }
1625  implicit = true;
1626  break;
1627  }
1628 
1629  case '(':
1630  {
1631  p = find_matching_paren(ps.dptr + 1);
1632  if (p[0] != ')')
1633  {
1634  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1635  goto cleanup;
1636  }
1637  /* compile the sub-expression */
1638  buf = mutt_strn_dup(ps.dptr + 1, p - (ps.dptr + 1));
1639  tmp = mutt_pattern_comp(buf, flags, err);
1640  FREE(&buf);
1641  if (!tmp)
1642  goto cleanup;
1643  struct Pattern *pat = SLIST_FIRST(tmp);
1644  if (last)
1645  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1646  else
1647  curlist = tmp;
1648  last = tmp;
1649  pat = SLIST_FIRST(tmp);
1650  pat->pat_not ^= pat_not;
1651  pat->all_addr |= all_addr;
1652  pat->is_alias |= is_alias;
1653  pat_not = false;
1654  all_addr = false;
1655  is_alias = false;
1656  ps.dptr = p + 1; /* restore location */
1657  break;
1658  }
1659 
1660  default:
1661  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1662  goto cleanup;
1663  }
1664  }
1665  if (!curlist)
1666  {
1667  mutt_buffer_strcpy(err, _("empty pattern"));
1668  return NULL;
1669  }
1670  if (curlist != tmp)
1671  FREE(&tmp);
1672  if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1673  {
1674  tmp = mutt_pattern_node_new();
1675  struct Pattern *pat = SLIST_FIRST(tmp);
1676  pat->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1677  pat->child = curlist;
1678  curlist = tmp;
1679  }
1680 
1681  return curlist;
1682 
1683 cleanup:
1684  mutt_pattern_free(&curlist);
1685  return NULL;
1686 }
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:63
int flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: pattern.c:171
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: pattern.c:1363
Pattern matches a child email.
Definition: pattern.h:111
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
A simple (non-regex) pattern.
Definition: pattern.h:49
bool is_alias
Is there an alias for this Address?
Definition: pattern.h:57
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: pattern.c:170
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:553
static const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition: pattern.c:1348
#define SKIPWS(ch)
Definition: string2.h:46
bool string_match
Check a string for a match.
Definition: pattern.h:54
bool pat_not
Pattern should be inverted (not)
Definition: pattern.h:52
static struct PatternList * mutt_pattern_node_new(void)
Create a new list containing a Pattern.
Definition: pattern.c:1421
#define SLIST_NEXT(elm, field)
Definition: queue.h:269
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1437
#define SLIST_FIRST(head)
Definition: queue.h:228
Either pattern can match.
Definition: pattern.h:108
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1385
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
Pattern matches parent.
Definition: pattern.h:110
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
bool sendmode
Evaluate searches in send-mode.
Definition: pattern.h:59
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
Definition: pattern.h:44
Both patterns must match.
Definition: pattern.h:107
#define FREE(x)
Definition: memory.h:40
Pattern matches email thread.
Definition: pattern.h:109
Mapping between user character and internal constant.
Definition: pattern.c:167
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
bool(* eat_arg)(struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
Function to parse a pattern.
Definition: pattern.c:181
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ perform_and()

static bool perform_and ( struct PatternList *  pat,
PatternExecFlags  flags,
struct Mailbox m,
struct Email e,
struct PatternCache cache 
)
static

Perform a logical AND on a set of Patterns.

Parameters
patPatterns to test
flagsOptional flags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
eEmail
cacheCached Patterns
Return values
trueIf ALL of the Patterns evaluates to true

Definition at line 1697 of file pattern.c.

1699 {
1700  struct Pattern *p = NULL;
1701 
1702  SLIST_FOREACH(p, pat, entries)
1703  {
1704  if (mutt_pattern_exec(p, flags, m, e, cache) <= 0)
1705  return false;
1706  }
1707  return true;
1708 }
A simple (non-regex) pattern.
Definition: pattern.h:49
int 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: pattern.c:2129
union Pattern::@1 p
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:230
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ perform_or()

static int perform_or ( struct PatternList *  pat,
PatternExecFlags  flags,
struct Mailbox m,
struct Email e,
struct PatternCache cache 
)
static

Perform a logical OR on a set of Patterns.

Parameters
patPatterns to test
flagsOptional flags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
eEmail
cacheCached Patterns
Return values
trueIf ONE (or more) of the Patterns evaluates to true

Definition at line 1719 of file pattern.c.

1721 {
1722  struct Pattern *p = NULL;
1723 
1724  SLIST_FOREACH(p, pat, entries)
1725  {
1726  if (mutt_pattern_exec(p, flags, m, e, cache) > 0)
1727  return true;
1728  }
1729  return false;
1730 }
A simple (non-regex) pattern.
Definition: pattern.h:49
int 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: pattern.c:2129
union Pattern::@1 p
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:230
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_addrlist()

static int match_addrlist ( struct Pattern pat,
bool  match_personal,
int  n,
  ... 
)
static

Match a Pattern against and Address list.

Parameters
patPattern to find
match_personalIf true, also match the pattern against the real name
nNumber of Addresses supplied
...Variable number of Addresses
Return values
true
  • One Address matches (all_addr is false)
  • All the Addresses match (all_addr is true)

Definition at line 1742 of file pattern.c.

1743 {
1744  va_list ap;
1745 
1746  va_start(ap, n);
1747  for (; n; n--)
1748  {
1749  struct AddressList *al = va_arg(ap, struct AddressList *);
1750  struct Address *a = NULL;
1751  TAILQ_FOREACH(a, al, entries)
1752  {
1753  if (pat->all_addr ^ ((!pat->is_alias || alias_reverse_lookup(a)) &&
1754  ((a->mailbox && patmatch(pat, a->mailbox)) ||
1755  (match_personal && a->personal && patmatch(pat, a->personal)))))
1756  {
1757  va_end(ap);
1758  return !pat->all_addr; /* Found match, or non-match if all_addr */
1759  }
1760  }
1761  }
1762  va_end(ap);
1763  return pat->all_addr; /* No matches, or all matches if all_addr */
1764 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_alias
Is there an alias for this Address?
Definition: pattern.h:57
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
va_start(args, fmt)
struct Address * alias_reverse_lookup(const struct Address *addr)
Does the user have an alias for the given address.
Definition: reverse.c:87
char * personal
Real name of address.
Definition: address.h:36
int n
Definition: acutest.h:492
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
va_end(args)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_reference()

static bool match_reference ( struct Pattern pat,
struct ListHead *  refs 
)
static

Match references against a Pattern.

Parameters
patPattern to match
refsList of References
Return values
trueOne of the references matches

Definition at line 1772 of file pattern.c.

1773 {
1774  struct ListNode *np = NULL;
1775  STAILQ_FOREACH(np, refs, entries)
1776  {
1777  if (patmatch(pat, np->data))
1778  return true;
1779  }
1780  return false;
1781 }
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * data
String.
Definition: list.h:36
A List node for strings.
Definition: list.h:34
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_predicate_recipient()

static int mutt_is_predicate_recipient ( bool  all_addr,
struct Envelope e,
addr_predicate_t  p 
)
static

Test an Envelopes Addresses using a predicate function.

Parameters
all_addrIf true, ALL Addresses must match
eEnvelope
pPredicate function, e.g. mutt_is_subscribed_list()
Return values
true
  • One Address matches (all_addr is false)
  • All the Addresses match (all_addr is true)

Test the 'To' and 'Cc' fields of an Address using a test function (the predicate).

Definition at line 1794 of file pattern.c.

1795 {
1796  struct AddressList *als[] = { &e->to, &e->cc };
1797  for (size_t i = 0; i < mutt_array_size(als); ++i)
1798  {
1799  struct AddressList *al = als[i];
1800  struct Address *a = NULL;
1801  TAILQ_FOREACH(a, al, entries)
1802  {
1803  if (all_addr ^ p(a))
1804  return !all_addr;
1805  }
1806  }
1807  return all_addr;
1808 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
#define mutt_array_size(x)
Definition: memory.h:33
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
+ Here is the caller graph for this function:

◆ mutt_is_subscribed_list_recipient()

int mutt_is_subscribed_list_recipient ( bool  all_addr,
struct Envelope e 
)

Matches subscribed mailing lists.

Parameters
all_addrIf true, ALL Addresses must be on the subscribed list
eEnvelope
Return values
true
  • One Address is subscribed (all_addr is false)
  • All the Addresses are subscribed (all_addr is true)

Definition at line 1818 of file pattern.c.

1819 {
1821 }
bool mutt_is_subscribed_list(const struct Address *addr)
Is this the email address of a user-subscribed mailing list? - Implements addr_predicate_t.
Definition: maillist.c:57
static int mutt_is_predicate_recipient(bool all_addr, struct Envelope *e, addr_predicate_t p)
Test an Envelopes Addresses using a predicate function.
Definition: pattern.c:1794
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_list_recipient()

int mutt_is_list_recipient ( bool  all_addr,
struct Envelope e 
)

Matches known mailing lists.

Parameters
all_addrIf true, ALL Addresses must be mailing lists
eEnvelope
Return values
true
  • One Address is a mailing list (all_addr is false)
  • All the Addresses are mailing lists (all_addr is true)

Definition at line 1831 of file pattern.c.

1832 {
1833  return mutt_is_predicate_recipient(all_addr, e, &mutt_is_mail_list);
1834 }
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: maillist.c:45
static int mutt_is_predicate_recipient(bool all_addr, struct Envelope *e, addr_predicate_t p)
Test an Envelopes Addresses using a predicate function.
Definition: pattern.c:1794
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_user()

static int match_user ( int  all_addr,
struct AddressList *  al1,
struct AddressList *  al2 
)
static

Matches the user's email Address.

Parameters
all_addrIf true, ALL Addresses must refer to the user
al1First AddressList
al2Second AddressList
Return values
true
  • One Address refers to the user (all_addr is false)
  • All the Addresses refer to the user (all_addr is true)

Definition at line 1845 of file pattern.c.

1846 {
1847  struct Address *a = NULL;
1848  if (al1)
1849  {
1850  TAILQ_FOREACH(a, al1, entries)
1851  {
1852  if (all_addr ^ mutt_addr_is_user(a))
1853  return !all_addr;
1854  }
1855  }
1856 
1857  if (al2)
1858  {
1859  TAILQ_FOREACH(a, al2, entries)
1860  {
1861  if (all_addr ^ mutt_addr_is_user(a))
1862  return !all_addr;
1863  }
1864  }
1865  return all_addr;
1866 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:545
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_threadcomplete()

static int match_threadcomplete ( struct PatternList *  pat,
PatternExecFlags  flags,
struct Mailbox m,
struct MuttThread t,
int  left,
int  up,
int  right,
int  down 
)
static

Match a Pattern against an email thread.

Parameters
patPattern to match
flagsFlags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
tEmail thread
leftNavigate to the previous email
upNavigate to the email's parent
rightNavigate to the next email
downNavigate to the email's children
Return values
1Success, match found
0No match

Definition at line 1881 of file pattern.c.

1884 {
1885  if (!t)
1886  return 0;
1887 
1888  int a;
1889  struct Email *e = t->message;
1890  if (e)
1891  if (mutt_pattern_exec(SLIST_FIRST(pat), flags, m, e, NULL))
1892  return 1;
1893 
1894  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
1895  return a;
1896  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
1897  {
1898  return a;
1899  }
1900  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
1901  {
1902  return a;
1903  }
1904  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
1905  return a;
1906  return 0;
1907 }
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
The envelope/body of an email.
Definition: email.h:37
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
static int match_threadcomplete(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t, int left, int up, int right, int down)
Match a Pattern against an email thread.
Definition: pattern.c:1881
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
int 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: pattern.c:2129
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define SLIST_FIRST(head)
Definition: queue.h:228
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_threadparent()

static int match_threadparent ( struct PatternList *  pat,
PatternExecFlags  flags,
struct Mailbox m,
struct MuttThread t 
)
static

Match Pattern against an email's parent.

Parameters
patPattern to match
flagsFlags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
tThread of email
Return values
1Success, pattern matched
0Pattern did not match
-1Error

Definition at line 1919 of file pattern.c.

1921 {
1922  if (!t || !t->parent || !t->parent->message)
1923  return 0;
1924 
1925  return mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->parent->message, NULL);
1926 }
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
int 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: pattern.c:2129
#define SLIST_FIRST(head)
Definition: queue.h:228
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_threadchildren()

static int match_threadchildren ( struct PatternList *  pat,
PatternExecFlags  flags,
struct Mailbox m,
struct MuttThread t 
)
static

Match Pattern against an email's children.

Parameters
patPattern to match
flagsFlags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
tThread of email
Return values
1Success, pattern matched
0Pattern did not match
-1Error

Definition at line 1938 of file pattern.c.

1940 {
1941  if (!t || !t->child)
1942  return 0;
1943 
1944  for (t = t->child; t; t = t->next)
1945  if (t->message && mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->message, NULL))
1946  return 1;
1947 
1948  return 0;
1949 }
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
int 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: pattern.c:2129
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define SLIST_FIRST(head)
Definition: queue.h:228
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_content_type()

static bool match_content_type ( const struct Pattern pat,
struct Body b 
)
static

Match a Pattern against an Attachment's Content-Type.

Parameters
patPattern to match
bAttachment
Return values
trueSuccess, pattern matched
falsePattern did not match

Definition at line 1958 of file pattern.c.

1959 {
1960  if (!b)
1961  return false;
1962 
1963  char buf[256];
1964  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1965 
1966  if (patmatch(pat, buf))
1967  return true;
1968  if (match_content_type(pat, b->parts))
1969  return true;
1970  if (match_content_type(pat, b->next))
1971  return true;
1972  return false;
1973 }
struct Body * next
next attachment in the list
Definition: body.h:53
char * subtype
content-type subtype
Definition: body.h:37
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
#define TYPE(body)
Definition: mime.h:83
static bool match_content_type(const struct Pattern *pat, struct Body *b)
Match a Pattern against an Attachment&#39;s Content-Type.
Definition: pattern.c:1958
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_update_dynamic_date()

static bool match_update_dynamic_date ( struct Pattern pat)
static

Update a dynamic date pattern.

Parameters
patPattern to modify
Return values
truePattern valid and updated
falsePattern invalid

Definition at line 1981 of file pattern.c.

1982 {
1983  struct Buffer *err = mutt_buffer_pool_get();
1984 
1985  bool rc = eval_date_minmax(pat, pat->p.str, err);
1987 
1988  return rc;
1989 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
static bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against &#39;now&#39;.
Definition: pattern.c:621
union Pattern::@1 p
char * str
String, if string_match is set.
Definition: pattern.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_mime_content_type()

static bool match_mime_content_type ( const struct Pattern pat,
struct Mailbox m,
struct Email e 
)
static

Match a Pattern against an email's Content-Type.

Parameters
patPattern to match
mMailbox
eEmail
Return values
trueSuccess, pattern matched
falsePattern did not match

Definition at line 1999 of file pattern.c.

2001 {
2003  return match_content_type(pat, e->content);
2004 }
struct Body * content
List of MIME parts.
Definition: email.h:90
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:48
static bool match_content_type(const struct Pattern *pat, struct Body *b)
Match a Pattern against an Attachment&#39;s Content-Type.
Definition: pattern.c:1958
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_pattern_cache_value()

static void set_pattern_cache_value ( int *  cache_entry,
int  value 
)
static

Sets a value in the PatternCache cache entry.

Parameters
cache_entryCache entry to update
valueValue to set

Normalizes the "true" value to 2.

Definition at line 2013 of file pattern.c.

2014 {
2015  *cache_entry = (value != 0) ? 2 : 1;
2016 }
+ Here is the caller graph for this function:

◆ get_pattern_cache_value()

static int get_pattern_cache_value ( int  cache_entry)
static

Get pattern cache value.

Parameters
cache_entryCache entry to get
Return values
1if the cache value is set and has a true value
0otherwise (even if unset!)

Definition at line 2024 of file pattern.c.

2025 {
2026  return cache_entry == 2;
2027 }
+ Here is the caller graph for this function:

◆ is_pattern_cache_set()

static int is_pattern_cache_set ( int  cache_entry)
static

Is a given Pattern cached?

Parameters
cache_entryCache entry to check
Return values
trueIf it is cached

Definition at line 2034 of file pattern.c.

2035 {
2036  return cache_entry != 0;
2037 }
+ Here is the caller graph for this function:

◆ msg_search_sendmode()

static int msg_search_sendmode ( struct Email e,
struct Pattern pat 
)
static

Search in send-mode.

Parameters
eEmail to search
patPattern to find
Return values
1Success, pattern matched
0Pattern did not match
-1Error

Definition at line 2047 of file pattern.c.

2048 {
2049  bool match = false;
2050  char *buf = NULL;
2051  size_t blen = 0;
2052  FILE *fp = NULL;
2053 
2054  if ((pat->op == MUTT_PAT_HEADER) || (pat->op == MUTT_PAT_WHOLE_MSG))
2055  {
2056  struct Buffer *tempfile = mutt_buffer_pool_get();
2057  mutt_buffer_mktemp(tempfile);
2058  fp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
2059  if (!fp)
2060  {
2061  mutt_perror(mutt_b2s(tempfile));
2062  mutt_buffer_pool_release(&tempfile);
2063  return 0;
2064  }
2065 
2067  false, false, NeoMutt->sub);
2068  fflush(fp);
2069  fseek(fp, 0, 0);
2070 
2071  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
2072  {
2073  if (patmatch(pat, buf) == 0)
2074  {
2075  match = true;
2076  break;
2077  }
2078  }
2079 
2080  FREE(&buf);
2081  mutt_file_fclose(&fp);
2082  unlink(mutt_b2s(tempfile));
2083  mutt_buffer_pool_release(&tempfile);
2084 
2085  if (match)
2086  return match;
2087  }
2088 
2089  if ((pat->op == MUTT_PAT_BODY) || (pat->op == MUTT_PAT_WHOLE_MSG))
2090  {
2091  fp = mutt_file_fopen(e->content->filename, "r");
2092  if (!fp)
2093  {
2095  return 0;
2096  }
2097 
2098  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
2099  {
2100  if (patmatch(pat, buf) == 0)
2101  {
2102  match = true;
2103  break;
2104  }
2105  }
2106 
2107  FREE(&buf);
2108  mutt_file_fclose(&fp);
2109  }
2110 
2111  return match;
2112 }
Pattern matches email&#39;s header.
Definition: pattern.h:125
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
A postponed Email, just the envelope info.
Definition: header.h:42
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Body * content
List of MIME parts.
Definition: email.h:90
String manipulation buffer.
Definition: buffer.h:33
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:667
Container for Accounts, Notifications.
Definition: neomutt.h:36
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Envelope * env
Envelope information.
Definition: email.h:89
#define mutt_b2s(buf)
Definition: buffer.h:41
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
Pattern matches email&#39;s body.
Definition: pattern.h:124
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Pattern matches raw email text.
Definition: pattern.h:127
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:573
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_exec()

int mutt_pattern_exec ( struct Pattern pat,
PatternExecFlags  flags,
struct Mailbox m,
struct Email e,
struct PatternCache cache 
)

Match a pattern against an email header.

Parameters
patPattern to match
flagsFlags, e.g. MUTT_MATCH_FULL_ADDRESS
mMailbox
eEmail
cacheCache for common Patterns
Return values
1Success, pattern matched
0Pattern did not match
-1Error

flags: MUTT_MATCH_FULL_ADDRESS - match both personal and machine address cache: For repeated matches against the same Header, passing in non-NULL will store some of the cacheable pattern matches in this structure.

Definition at line 2129 of file pattern.c.

2131 {
2132  switch (pat->op)
2133  {
2134  case MUTT_PAT_AND:
2135  return pat->pat_not ^ (perform_and(pat->child, flags, m, e, cache) > 0);
2136  case MUTT_PAT_OR:
2137  return pat->pat_not ^ (perform_or(pat->child, flags, m, e, cache) > 0);
2138  case MUTT_PAT_THREAD:
2139  return pat->pat_not ^
2140  match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
2141  case MUTT_PAT_PARENT:
2142  return pat->pat_not ^ match_threadparent(pat->child, flags, m, e->thread);
2143  case MUTT_PAT_CHILDREN:
2144  return pat->pat_not ^ match_threadchildren(pat->child, flags, m, e->thread);
2145  case MUTT_ALL:
2146  return !pat->pat_not;
2147  case MUTT_EXPIRED:
2148  return pat->pat_not ^ e->expired;
2149  case MUTT_SUPERSEDED:
2150  return pat->pat_not ^ e->superseded;
2151  case MUTT_FLAG:
2152  return pat->pat_not ^ e->flagged;
2153  case MUTT_TAG:
2154  return pat->pat_not ^ e->tagged;
2155  case MUTT_NEW:
2156  return pat->pat_not ? e->old || e->read : !(e->old || e->read);
2157  case MUTT_UNREAD:
2158  return pat->pat_not ? e->read : !e->read;
2159  case MUTT_REPLIED:
2160  return pat->pat_not ^ e->replied;
2161  case MUTT_OLD:
2162  return pat->pat_not ? (!e->old || e->read) : (e->old && !e->read);
2163  case MUTT_READ:
2164  return pat->pat_not ^ e->read;
2165  case MUTT_DELETED:
2166  return pat->pat_not ^ e->deleted;
2167  case MUTT_PAT_MESSAGE:
2168  return pat->pat_not ^ ((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
2169  case MUTT_PAT_DATE:
2170  if (pat->dynamic)
2172  return pat->pat_not ^ (e->date_sent >= pat->min && e->date_sent <= pat->max);
2174  if (pat->dynamic)
2176  return pat->pat_not ^ (e->received >= pat->min && e->received <= pat->max);
2177  case MUTT_PAT_BODY:
2178  case MUTT_PAT_HEADER:
2179  case MUTT_PAT_WHOLE_MSG:
2180  if (pat->sendmode)
2181  {
2182  if (!e->content || !e->content->filename)
2183  return 0;
2184  return pat->pat_not ^ msg_search_sendmode(e, pat);
2185  }
2186  /* m can be NULL in certain cases, such as when replying to a message
2187  * from the attachment menu and the user has a reply-hook using "~e".
2188  * This is also the case when message scoring. */
2189  if (!m)
2190  return 0;
2191 #ifdef USE_IMAP
2192  /* IMAP search sets e->matched at search compile time */
2193  if ((m->type == MUTT_IMAP) && pat->string_match)
2194  return e->matched;
2195 #endif
2196  return pat->pat_not ^ msg_search(m, pat, e->msgno);
2197  case MUTT_PAT_SERVERSEARCH:
2198 #ifdef USE_IMAP
2199  if (!m)
2200  return 0;
2201  if (m->type == MUTT_IMAP)
2202  {
2203  if (pat->string_match)
2204  return e->matched;
2205  return 0;
2206  }
2207  mutt_error(_("error: server custom search only supported with IMAP"));
2208  return 0;
2209 #else
2210  mutt_error(_("error: server custom search only supported with IMAP"));
2211  return -1;
2212 #endif
2213  case MUTT_PAT_SENDER:
2214  if (!e->env)
2215  return 0;
2216  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2217  1, &e->env->sender);
2218  case MUTT_PAT_FROM:
2219  if (!e->env)
2220  return 0;
2221  return pat->pat_not ^
2222  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->from);
2223  case MUTT_PAT_TO:
2224  if (!e->env)
2225  return 0;
2226  return pat->pat_not ^
2227  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->to);
2228  case MUTT_PAT_CC:
2229  if (!e->env)
2230  return 0;
2231  return pat->pat_not ^
2232  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->cc);
2233  case MUTT_PAT_SUBJECT:
2234  if (!e->env)
2235  return 0;
2236  return pat->pat_not ^ (e->env->subject && patmatch(pat, e->env->subject));
2237  case MUTT_PAT_ID:
2238  case MUTT_PAT_ID_EXTERNAL:
2239  if (!e->env)
2240  return 0;
2241  return pat->pat_not ^ (e->env->message_id && patmatch(pat, e->env->message_id));
2242  case MUTT_PAT_SCORE:
2243  return pat->pat_not ^ (e->score >= pat->min &&
2244  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
2245  case MUTT_PAT_SIZE:
2246  return pat->pat_not ^
2247  (e->content->length >= pat->min &&
2248  (pat->max == MUTT_MAXRANGE || e->content->length <= pat->max));
2249  case MUTT_PAT_REFERENCE:
2250  if (!e->env)
2251  return 0;
2252  return pat->pat_not ^ (match_reference(pat, &e->env->references) ||
2253  match_reference(pat, &e->env->in_reply_to));
2254  case MUTT_PAT_ADDRESS:
2255  if (!e->env)
2256  return 0;
2257  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2258  4, &e->env->from, &e->env->sender,
2259  &e->env->to, &e->env->cc);
2260  case MUTT_PAT_RECIPIENT:
2261  if (!e->env)
2262  return 0;
2263  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2264  2, &e->env->to, &e->env->cc);
2265  case MUTT_PAT_LIST: /* known list, subscribed or not */
2266  {
2267  if (!e->env)
2268  return 0;
2269 
2270  int result;
2271  if (cache)
2272  {
2273  int *cache_entry = pat->all_addr ? &cache->list_all : &cache->list_one;
2274  if (!is_pattern_cache_set(*cache_entry))
2275  {
2276  set_pattern_cache_value(cache_entry,
2277  mutt_is_list_recipient(pat->all_addr, e->env));
2278  }
2279  result = get_pattern_cache_value(*cache_entry);
2280  }
2281  else
2282  result = mutt_is_list_recipient(pat->all_addr, e->env);
2283  return pat->pat_not ^ result;
2284  }
2286  {
2287  if (!e->env)
2288  return 0;
2289 
2290  int result;
2291  if (cache)
2292  {
2293  int *cache_entry = pat->all_addr ? &cache->sub_all : &cache->sub_one;
2294  if (!is_pattern_cache_set(*cache_entry))
2295  {
2297  cache_entry, mutt_is_subscribed_list_recipient(pat->all_addr, e->env));
2298  }
2299  result = get_pattern_cache_value(*cache_entry);
2300  }
2301  else
2302  result = mutt_is_subscribed_list_recipient(pat->all_addr, e->env);
2303  return pat->pat_not ^ result;
2304  }
2306  {
2307  if (!e->env)
2308  return 0;
2309 
2310  int result;
2311  if (cache)
2312  {
2313  int *cache_entry = pat->all_addr ? &cache->pers_recip_all : &cache->pers_recip_one;
2314  if (!is_pattern_cache_set(*cache_entry))
2315  {
2317  cache_entry, match_user(pat->all_addr, &e->env->to, &e->env->cc));
2318  }
2319  result = get_pattern_cache_value(*cache_entry);
2320  }
2321  else
2322  result = match_user(pat->all_addr, &e->env->to, &e->env->cc);
2323  return pat->pat_not ^ result;
2324  }
2326  {
2327  if (!e->env)
2328  return 0;
2329 
2330  int result;
2331  if (cache)
2332  {
2333  int *cache_entry = pat->all_addr ? &cache->pers_from_all : &cache->pers_from_one;
2334  if (!is_pattern_cache_set(*cache_entry))
2335  {
2336  set_pattern_cache_value(cache_entry,
2337  match_user(pat->all_addr, &e->env->from, NULL));
2338  }
2339  result = get_pattern_cache_value(*cache_entry);
2340  }
2341  else
2342  result = match_user(pat->all_addr, &e->env->from, NULL);
2343  return pat->pat_not ^ result;
2344  }
2345  case MUTT_PAT_COLLAPSED:
2346  return pat->pat_not ^ (e->collapsed && e->num_hidden > 1);
2347  case MUTT_PAT_CRYPT_SIGN:
2348  if (!WithCrypto)
2349  break;
2350  return pat->pat_not ^ ((e->security & SEC_SIGN) ? 1 : 0);
2352  if (!WithCrypto)
2353  break;
2354  return pat->pat_not ^ ((e->security & SEC_GOODSIGN) ? 1 : 0);
2356  if (!WithCrypto)
2357  break;
2358  return pat->pat_not ^ ((e->security & SEC_ENCRYPT) ? 1 : 0);
2359  case MUTT_PAT_PGP_KEY:
2360  if (!(WithCrypto & APPLICATION_PGP))
2361  break;
2362  return pat->pat_not ^ ((e->security & PGP_KEY) == PGP_KEY);
2363  case MUTT_PAT_XLABEL:
2364  if (!e->env)
2365  return 0;
2366  return pat->pat_not ^ (e->env->x_label && patmatch(pat, e->env->x_label));
2367  case MUTT_PAT_DRIVER_TAGS:
2368  {
2369  char *tags = driver_tags_get(&e->tags);
2370  bool rc = (pat->pat_not ^ (tags && patmatch(pat, tags)));
2371  FREE(&tags);
2372  return rc;
2373  }
2374  case MUTT_PAT_HORMEL:
2375  if (!e->env)
2376  return 0;
2377  return pat->pat_not ^ (e->env->spam.data && patmatch(pat, e->env->spam.data));
2378  case MUTT_PAT_DUPLICATED:
2379  return pat->pat_not ^ (e->thread && e->thread->duplicate_thread);
2380  case MUTT_PAT_MIMEATTACH:
2381  if (!m)
2382  return 0;
2383  {
2384  int count = mutt_count_body_parts(m, e);
2385  return pat->pat_not ^ (count >= pat->min &&
2386  (pat->max == MUTT_MAXRANGE || count <= pat->max));
2387  }
2388  case MUTT_PAT_MIMETYPE:
2389  if (!m)
2390  return 0;
2391  return pat->pat_not ^ match_mime_content_type(pat, m, e);
2392  case MUTT_PAT_UNREFERENCED:
2393  return pat->pat_not ^ (e->thread && !e->thread->child);
2394  case MUTT_PAT_BROKEN:
2395  return pat->pat_not ^ (e->thread && e->thread->fake_thread);
2396 #ifdef USE_NNTP
2397  case MUTT_PAT_NEWSGROUPS:
2398  if (!e->env)
2399  return 0;
2400  return pat->pat_not ^ (e->env->newsgroups && patmatch(pat, e->env->newsgroups));
2401 #endif
2402  }
2403  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
2404  return -1;
2405 }
Pattern matches date received.
Definition: pattern.h:118
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:63
Deleted messages.
Definition: mutt.h:101
Pattern matches email&#39;s header.
Definition: pattern.h:125
Pattern matches MIME type.
Definition: pattern.h:147
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Pattern matches &#39;Date:&#39; field.
Definition: pattern.h:117
#define WithCrypto
Definition: lib.h:118
static bool match_reference(struct Pattern *pat, struct ListHead *refs)
Match references against a Pattern.
Definition: pattern.c:1772
static bool perform_and(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical AND on a set of Patterns.
Definition: pattern.c:1697
Pattern matches newsgroup.
Definition: pattern.h:149
Pattern matches email&#39;s score.
Definition: pattern.h:130
int pers_recip_all
^~p
Definition: pattern.h:92
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
static int match_threadchildren(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s children.
Definition: pattern.c:1938
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against and Address list.
Definition: pattern.c:1742
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
Message is part of a broken thread.
Definition: pattern.h:121
Pattern matches email&#39;s size.
Definition: pattern.h:131
struct Body * content
List of MIME parts.
Definition: email.h:90
Flagged messages.
Definition: mutt.h:102
Pattern matches &#39;From:&#39; field.
Definition: pattern.h:116
#define MUTT_MAXRANGE
Definition: pattern.c:99
Email is from the user.
Definition: pattern.h:137
#define _(a)
Definition: message.h:28
Email is on mailing list.
Definition: pattern.h:134
Pattern matches a child email.
Definition: pattern.h:111
static int match_user(int all_addr, struct AddressList *al1, struct AddressList *al2)
Matches the user&#39;s email Address.
Definition: pattern.c:1845
bool expired
Already expired?
Definition: email.h:52
Pattern matches email&#39;s Message-Id.
Definition: pattern.h:122
Messages that have been replied to.
Definition: mutt.h:95
int sub_all
^~u
Definition: pattern.h:90
Pattern matches message number.
Definition: pattern.h:129
static int match_threadcomplete(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t, int left, int up, int right, int down)
Match a Pattern against an email thread.
Definition: pattern.c:1881
Email is on subscribed mailing list.
Definition: pattern.h:135
static int msg_search_sendmode(struct Email *e, struct Pattern *pat)
Search in send-mode.
Definition: pattern.c:2047
static int is_pattern_cache_set(int cache_entry)
Is a given Pattern cached?
Definition: pattern.c:2034
All messages.
Definition: mutt.h:91
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:58
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
bool old
Email is seen, but unread.
Definition: email.h:50
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
Duplicate message.
Definition: pattern.h:119
struct Envelope * env
Envelope information.
Definition: email.h:89
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
bool string_match
Check a string for a match.
Definition: pattern.h:54
bool pat_not
Pattern should be inverted (not)
Definition: pattern.h:52
bool superseded
Got superseded?
Definition: email.h:53
int min
Minimum for range checks.
Definition: pattern.h:61
struct TagList tags
For drivers that support server tagging.
Definition: email.h:102
int score
Message score.
Definition: email.h:88
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:81
Old messages.
Definition: mutt.h:94
int pers_from_one
~P
Definition: pattern.h:95
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
bool duplicate_thread
Duplicated Email in Thread.
Definition: thread.h:37
Server-side pattern matches.
Definition: pattern.h:144
Pattern matches &#39;Cc:&#39; field.
Definition: pattern.h:113
int pers_recip_one
~p
Definition: pattern.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
Message is unreferenced in the thread.
Definition: pattern.h:120
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
bool fake_thread
Emails grouped by Subject.
Definition: thread.h:36
Pattern matches keyword/label.
Definition: pattern.h:143
Either pattern can match.
Definition: pattern.h:108
char * driver_tags_get(struct TagList *list)
Get tags.
Definition: tags.c:142
size_t num_hidden
Number of hidden messages in this view.
Definition: email.h:75
Pattern matches email&#39;s spam score.
Definition: pattern.h:126
Superseded messages.
Definition: mutt.h:107
Tagged messages.
Definition: mutt.h:103
Message is encrypted.
Definition: pattern.h:141
char * data
Pointer to data.
Definition: buffer.h:35
Pattern matches &#39;Subject:&#39; field.
Definition: pattern.h:115
int list_all
^~l
Definition: pattern.h:88
New messages.
Definition: mutt.h:93
Messages that have been read.
Definition: mutt.h:96
static int get_pattern_cache_value(int cache_entry)
Get pattern cache value.
Definition: pattern.c:2024
Email is addressed to the user.
Definition: pattern.h:136
Message has PGP key.
Definition: pattern.h:142
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
Pattern matches parent.
Definition: pattern.h:110
static int perform_or(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical OR on a set of Patterns.
Definition: pattern.c:1719
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:76
Expired messages.
Definition: mutt.h:106
int pers_from_all
^~P
Definition: pattern.h:94
#define SEC_SIGN
Email is signed.
Definition: lib.h:81
Unread messages.
Definition: mutt.h:97
Pattern matches email&#39;s body.
Definition: pattern.h:124
static bool msg_search(struct Mailbox *m, struct Pattern *pat, int msgno)
Search an email.
Definition: pattern.c:1135
char * subject
Email&#39;s subject.
Definition: envelope.h:66
#define PGP_KEY
Definition: lib.h:101
bool flagged
Marked important?
Definition: email.h:43
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
#define EMSG(e)
Definition: pattern.c:97
Message is signed.
Definition: pattern.h:139
bool deleted
Email is deleted.
Definition: email.h:45
bool sendmode
Evaluate searches in send-mode.
Definition: pattern.h:59
#define mutt_error(...)
Definition: logging.h:84
bool replied
Email has been replied to.
Definition: email.h:54
static int match_threadparent(struct PatternList *pat, PatternExecFlags flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s parent.
Definition: pattern.c:1919
Thread is collapsed.
Definition: pattern.h:114
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: pattern.c:1818
Pattern matches sender.
Definition: pattern.h:128
Both patterns must match.
Definition: pattern.h:107
#define FREE(x)
Definition: memory.h:40
Message is crypographically verified.
Definition: pattern.h:140
int max
Maximum for range checks.
Definition: pattern.h:62
Pattern matches &#39;References:&#39; or &#39;In-Reply-To:&#39; field.
Definition: pattern.h:132
static bool match_update_dynamic_date(struct Pattern *pat)
Update a dynamic date pattern.
Definition: pattern.c:1981
Pattern matches message tags.
Definition: pattern.h:145
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
Pattern matches any address field.
Definition: pattern.h:138
User is a recipient of the email.
Definition: pattern.h:133
static bool match_mime_content_type(const struct Pattern *pat, struct Mailbox *m, struct Email *e)
Match a Pattern against an email&#39;s Content-Type.
Definition: pattern.c:1999
Pattern matches email thread.
Definition: pattern.h:109
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:205
Pattern matches &#39;To:&#39; field.
Definition: pattern.h:112
static void set_pattern_cache_value(int *cache_entry, int value)
Sets a value in the PatternCache cache entry.
Definition: pattern.c:2013
Pattern matches raw email text.
Definition: pattern.h:127
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
char * x_label
X-Label.
Definition: envelope.h:72
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: pattern.c:1831
Pattern matches number of attachments.
Definition: pattern.h:146
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:82
int list_one
~l
Definition: pattern.h:89
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
Message-Id is among results from an external query.
Definition: pattern.h:123
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1116
struct Buffer spam
Spam header.
Definition: envelope.h:80
bool matched
Search matches this Email.
Definition: email.h:68
int msgno
Number displayed to the user.
Definition: email.h:86
int sub_one
~u
Definition: pattern.h:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 2412 of file pattern.c.

2413 {
2414  mutt_buffer_reset(buf);
2415  mutt_buffer_addch(buf, '"');
2416  while (*str)
2417  {
2418  if ((*str == '\\') || (*str == '"'))
2419  mutt_buffer_addch(buf, '\\');
2420  mutt_buffer_addch(buf, *str++);
2421  }
2422  mutt_buffer_addch(buf, '"');
2423 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
+ 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 2430 of file pattern.c.

2431 {
2432  bool do_simple = true;
2433 
2434  for (const char *p = mutt_b2s(buf); p && (p[0] != '\0'); p++)
2435  {
2436  if ((p[0] == '\\') && (p[1] != '\0'))
2437  p++;
2438  else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
2439  {
2440  do_simple = false;
2441  break;
2442  }
2443  }
2444 
2445  /* XXX - is mutt_istr_cmp() right here, or should we use locale's
2446  * equivalences? */
2447 
2448  if (do_simple) /* yup, so spoof a real request */
2449  {
2450  /* convert old tokens into the new format */
2451  if (mutt_istr_equal("all", mutt_b2s(buf)) || mutt_str_equal("^", mutt_b2s(buf)) ||
2452  mutt_str_equal(".", mutt_b2s(buf))) /* ~A is more efficient */
2453  {
2454  mutt_buffer_strcpy(buf, "~A");
2455  }
2456  else if (mutt_istr_equal("del", mutt_b2s(buf)))
2457  mutt_buffer_strcpy(buf, "~D");
2458  else if (mutt_istr_equal("flag", mutt_b2s(buf)))
2459  mutt_buffer_strcpy(buf, "~F");
2460  else if (mutt_istr_equal("new", mutt_b2s(buf)))
2461  mutt_buffer_strcpy(buf, "~N");
2462  else if (mutt_istr_equal("old", mutt_b2s(buf)))
2463  mutt_buffer_strcpy(buf, "~O");
2464  else if (mutt_istr_equal("repl", mutt_b2s(buf)))
2465  mutt_buffer_strcpy(buf, "~Q");
2466  else if (mutt_istr_equal("read", mutt_b2s(buf)))
2467  mutt_buffer_strcpy(buf, "~R");
2468  else if (mutt_istr_equal("tag", mutt_b2s(buf)))
2469  mutt_buffer_strcpy(buf, "~T");
2470  else if (mutt_istr_equal("unread", mutt_b2s(buf)))
2471  mutt_buffer_strcpy(buf, "~U");
2472  else
2473  {
2474  struct Buffer *tmp = mutt_buffer_pool_get();
2475  quote_simple(mutt_b2s(buf), tmp);
2476  mutt_file_expand_fmt(buf, simple, mutt_b2s(tmp));
2478  }
2479  }
2480 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
static void quote_simple(const char *str, struct Buffer *buf)
Apply simple quoting to a string.
Definition: pattern.c:2412
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
#define mutt_b2s(buf)
Definition: buffer.h:41
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:1440
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ top_of_thread()

static struct MuttThread* top_of_thread ( struct Email e)
static

Find the first email in the current thread.

Parameters
eCurrent Email
Return values
ptrSuccess, email found
NULLError

Definition at line 2488 of file pattern.c.

2489 {
2490  if (!e)
2491  return NULL;
2492 
2493  struct MuttThread *t = e->thread;
2494 
2495  while (t && t->parent)
2496  t = t->parent;
2497 
2498  return t;
2499 }
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
An Email conversation.
Definition: thread.h:34
+ Here is the caller graph for this function:

◆ mutt_limit_current_thread()

bool mutt_limit_current_thread ( struct Email e)

Limit the email view to the current thread.

Parameters
eCurrent Email
Return values
trueSuccess
falseFailure

Definition at line 2507 of file pattern.c.

2508 {
2509  if (!e || !Context || !Context->mailbox)
2510  return false;
2511 
2512  struct MuttThread *me = top_of_thread(e);
2513  if (!me)
2514  return false;
2515 
2516  struct Mailbox *m = Context->mailbox;
2517 
2518  m->vcount = 0;
2519  Context->vsize = 0;
2520  Context->collapsed = false;
2521 
2522  for (int i = 0; i < m->msg_count; i++)
2523  {
2524  e = m->emails[i];
2525  if (!e)
2526  break;
2527 
2528  e->vnum = -1;
2529  e->limited = false;
2530  e->collapsed = false;
2531  e->num_hidden = 0;
2532 
2533  if (top_of_thread(e) == me)
2534  {
2535  struct Body *body = e->content;
2536 
2537  e->vnum = m->vcount;
2538  e->limited = true;
2539  m->v2r[m->vcount] = i;
2540  m->vcount++;
2541  Context->vsize += (body->length + body->offset - body->hdr_offset);
2542  }
2543  }
2544  return true;
2545 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The "current" mailbox.
Definition: context.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct Body * content
List of MIME parts.
Definition: email.h:90
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:39
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition: pattern.c:2488
size_t num_hidden
Number of hidden messages in this view.
Definition: email.h:75
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
int vnum
Virtual message number.
Definition: email.h:87
An Email conversation.
Definition: thread.h:34
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
bool collapsed
Are all threads collapsed?
Definition: context.h:48
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_func()

int mutt_pattern_func ( int  op,
char *  prompt 
)

Perform some Pattern matching.

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

Definition at line 2554 of file pattern.c.

2555 {
2556  if (!Context || !Context->mailbox)
2557  return -1;
2558 
2559  struct Buffer err;
2560  int rc = -1;
2561  struct Progress progress;
2562  struct Buffer *buf = mutt_buffer_pool_get();
2563  struct Mailbox *m = Context->mailbox;
2564 
2566  if (prompt || (op != MUTT_LIMIT))
2567  {
2568  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR) != 0) ||
2569  mutt_buffer_is_empty(buf))
2570  {
2572  return -1;
2573  }
2574  }
2575 
2576  mutt_message(_("Compiling search pattern..."));
2577 
2578  char *simple = mutt_buffer_strdup(buf);
2580 
2581  mutt_buffer_init(&err);
2582  err.dsize = 256;
2583  err.data = mutt_mem_malloc(err.dsize);
2584  struct PatternList *pat = mutt_pattern_comp(buf->data, MUTT_PC_FULL_MSG, &err);
2585  if (!pat)
2586  {
2587  mutt_error("%s", err.data);
2588  goto bail;
2589  }
2590 
2591 #ifdef USE_IMAP
2592  if ((m->type == MUTT_IMAP) && (!imap_search(m, pat)))
2593  goto bail;
2594 #endif
2595 
2596  mutt_progress_init(&progress, _("Executing command on matching messages..."),
2597  MUTT_PROGRESS_READ, (op == MUTT_LIMIT) ? m->msg_count : m->vcount);
2598 
2599  if (op == MUTT_LIMIT)
2600  {
2601  m->vcount = 0;
2602  Context->vsize = 0;
2603  Context->collapsed = false;
2604  int padding = mx_msg_padding_size(m);
2605 
2606  for (int i = 0; i < m->msg_count; i++)
2607  {
2608  struct Email *e = m->emails[i];
2609  if (!e)
2610  break;
2611 
2612  mutt_progress_update(&progress, i, -1);
2613  /* new limit pattern implicitly uncollapses all threads */
2614  e->vnum = -1;
2615  e->limited = false;
2616  e->collapsed = false;
2617  e->num_hidden = 0;
2618  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2619  {
2620  e->vnum = m->vcount;
2621  e->limited = true;
2622  m->v2r[m->vcount] = i;
2623  m->vcount++;
2624  struct Body *b = e->content;
2625  Context->vsize += b->length + b->offset - b->hdr_offset + padding;
2626  }
2627  }
2628  }
2629  else
2630  {
2631  for (int i = 0; i < m->vcount; i++)
2632  {
2633  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2634  if (!e)
2635  continue;
2636  mutt_progress_update(&progress, i, -1);
2637  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2638  {
2639  switch (op)
2640  {
2641  case MUTT_UNDELETE:
2642  mutt_set_flag(m, e, MUTT_PURGE, false);
2643  /* fallthrough */
2644  case MUTT_DELETE:
2645  mutt_set_flag(m, e, MUTT_DELETE, (op == MUTT_DELETE));
2646  break;
2647  case MUTT_TAG:
2648  case MUTT_UNTAG:
2649  mutt_set_flag(m, e, MUTT_TAG, (op == MUTT_TAG));
2650  break;
2651  }
2652  }
2653  }
2654  }
2655 
2656  mutt_clear_error();
2657 
2658  if (op == MUTT_LIMIT)
2659  {
2660  /* drop previous limit pattern */
2661  FREE(&Context->pattern);
2663 
2664  if (m->msg_count && !m->vcount)
2665  mutt_error(_("No messages matched criteria"));
2666 
2667  /* record new limit pattern, unless match all */
2668  const char *pbuf = buf->data;
2669  while (*pbuf == ' ')
2670  pbuf++;
2671  if (!mutt_str_equal(pbuf, "~A"))
2672  {
2673  Context->pattern = simple;
2674  simple = NULL; /* don't clobber it */
2676  }
2677  }
2678 
2679  rc = 0;
2680 
2681 bail:
2683  FREE(&simple);
2684  mutt_pattern_free(&pat);
2685  FREE(&err.data);
2686 
2687  return rc;
2688 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
bool imap_search(struct Mailbox *m, const struct PatternList *pat)
Find messages in mailbox matching a pattern.
Definition: search.c:226
The "current" mailbox.
Definition: context.h:37
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:68
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
#define mutt_message(...)
Definition: logging.h:83
void mutt_check_simple(struct Buffer *buf, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:2430
Messages in limited view.
Definition: mutt.h:105
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Body * content
List of MIME parts.
Definition: email.h:90
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
String manipulation buffer.
Definition: buffer.h:33
Messages to be un-deleted.
Definition: mutt.h:99
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
Messages to be purged (bypass trash)
Definition: mutt.h:100
A progress bar.
Definition: progress.h:50
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:64
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
struct Mailbox * mailbox
Definition: context.h:50
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:42
bool limited
Is this message in a limited view?
Definition: email.h:74
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
off_t vsize
Definition: context.h:39
int 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: pattern.c:2129
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1437
#define SLIST_FIRST(head)
Definition: queue.h:228
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Messages to be deleted.
Definition: mutt.h:98
A mailbox.
Definition: mailbox.h:81
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t num_hidden
Number of hidden messages in this view.
Definition: email.h:75
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
Tagged messages.
Definition: mutt.h:103
char * data
Pointer to data.
Definition: buffer.h:35
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1385
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
int vnum
Virtual message number.
Definition: email.h:87
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:76
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: mutt_globals.h:110
#define mutt_buffer_get_field(field, buf, complete)
Definition: curs_lib.h:85
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
bool collapsed
Are all threads collapsed?
Definition: context.h:48
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: pattern.h:42
Messages to be un-tagged.
Definition: mutt.h:104
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1543
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
char * pattern
Limit pattern string.
Definition: context.h:40
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_search_command()

int mutt_search_command ( int  cur,
int  op 
)

Perform a search.

Parameters
curIndex number of current email
opOperation to perform, e.g. OP_SEARCH_NEXT
Return values
>=0 Index of matching email
-1No match, or error

Definition at line 2697 of file pattern.c.

2698 {
2699  struct Progress progress;
2700 
2701  if ((*LastSearch == '\0') || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
2702  {
2703  char buf[256];
2704  mutt_str_copy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
2705  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2706  _("Search for: ") :
2707  _("Reverse search for: "),
2708  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0) ||
2709  (buf[0] == '\0'))
2710  {
2711  return -1;
2712  }
2713 
2714  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
2715  OptSearchReverse = false;
2716  else
2717  OptSearchReverse = true;
2718 
2719  /* compare the *expanded* version of the search pattern in case
2720  * $simple_search has changed while we were searching */
2721  struct Buffer *tmp = mutt_buffer_pool_get();
2722  mutt_buffer_strcpy(tmp, buf);
2724 
2726  {
2727  struct Buffer err;
2728  mutt_buffer_init(&err);
2729  OptSearchInvalid = true;
2730  mutt_str_copy(LastSearch, buf, sizeof(LastSearch));
2732  mutt_message(_("Compiling search pattern..."));
2734  err.dsize = 256;
2735  err.data = mutt_mem_malloc(err.dsize);
2737  if (!SearchPattern)
2738  {
2740  mutt_error("%s", err.data);
2741  FREE(&err.data);
2742  LastSearch[0] = '\0';
2743  LastSearchExpn[0] = '\0';
2744  return -1;
2745  }
2746  FREE(&err.data);
2747  mutt_clear_error();
2748  }
2749 
2751  }
2752 
2753  if (OptSearchInvalid)
2754  {
2755  for (int i = 0; i < Context->mailbox->msg_count; i++)
2756  Context->mailbox->emails[i]->searched = false;
2757 #ifdef USE_IMAP
2758  if ((Context->mailbox->type == MUTT_IMAP) &&
2760  return -1;
2761 #endif
2762  OptSearchInvalid = false;
2763  }
2764 
2765  int incr = OptSearchReverse ? -1 : 1;
2766  if (op == OP_SEARCH_OPPOSITE)
2767  incr = -incr;
2768 
2769  mutt_progress_init(&progress, _("Searching..."), MUTT_PROGRESS_READ,
2770  Context->mailbox->vcount);
2771 
2772  for (int i = cur + incr, j = 0; j != Context->mailbox->vcount; j++)
2773  {
2774  const char *msg = NULL;
2775  mutt_progress_update(&progress, j, -1);
2776  if (i > Context->mailbox->vcount - 1)
2777  {
2778  i = 0;
2779  if (C_WrapSearch)
2780  msg = _("Search wrapped to top");
2781  else
2782  {
2783  mutt_message(_("Search hit bottom without finding match"));
2784  return -1;
2785  }
2786  }
2787  else if (i < 0)
2788  {
2789  i = Context->mailbox->vcount - 1;
2790  if (C_WrapSearch)
2791  msg = _("Search wrapped to bottom");
2792  else
2793  {
2794  mutt_message(_("Search hit top without finding match"));
2795  return -1;
2796  }
2797  }
2798 
2799  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2800  if (e->searched)
2801  {
2802  /* if we've already evaluated this message, use the cached value */
2803  if (e->matched)
2804  {
2805  mutt_clear_error();
2806  if (msg && *msg)
2807  mutt_message(msg);
2808  return i;
2809  }
2810  }
2811  else
2812  {
2813  /* remember that we've already searched this message */
2814  e->searched = true;
2816  Context->mailbox, e, NULL);
2817  if (e->matched > 0)
2818  {
2819  mutt_clear_error();
2820  if (msg && *msg)
2821  mutt_message(msg);
2822  return i;
2823  }
2824  }
2825 
2826  if (SigInt)
2827  {
2828  mutt_error(_("Search interrupted"));
2829  SigInt = 0;
2830  return -1;
2831  }
2832 
2833  i += incr;
2834  }
2835 
2836  mutt_error(_("Not found"));
2837  return -1;
2838 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:876
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
bool imap_search(struct Mailbox *m, const struct PatternList *pat)
Find messages in mailbox matching a pattern.
Definition: search.c:226
The "current" mailbox.
Definition: context.h:37
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:91
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:406
if(!test_colorize_)
Definition: acutest.h:499
#define mutt_message(...)
Definition: logging.h:83
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: mutt_globals.h:75
void mutt_check_simple(struct Buffer *buf, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:2430
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
static char LastSearch[256]
last pattern searched for
Definition: pattern.c:200
bool searched
Email has been searched.
Definition: email.h:67
A progress bar.
Definition: progress.h:50
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:64
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
int vcount
The number of virtual messages.
Definition: mailbox.h:102
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
struct Mailbox * mailbox
Definition: context.h:50
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:42
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
#define mutt_b2s(buf)
Definition: buffer.h:41
int 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: pattern.c:2129
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1437
static char LastSearchExpn[1024]
expanded version of LastSearch
Definition: pattern.c:201
#define SLIST_FIRST(head)
Definition: queue.h:228
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * data
Pointer to data.
Definition: buffer.h:35
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1385
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:52
void mutt_progress_init(struct Progress *progress, const char *msg, enum ProgressType type, size_t size)
Set up a progress bar.
Definition: progress.c:153
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:76
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: mutt_globals.h:172
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: mutt_globals.h:110
static struct PatternList * SearchPattern
current search pattern
Definition: pattern.c:199
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:721
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: pattern.h:42
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
WHERE bool OptSearchReverse
(pseudo) used by ci_search_command
Definition: options.h:53
bool matched
Search matches this Email.
Definition: email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_ThoroughSearch

bool C_ThoroughSearch

Config: Decode headers and messages before searching them.

Definition at line 75 of file pattern.c.

◆ range_regexes

struct RangeRegex range_regexes[]
static
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 } },
}
Single symbol.
Definition: pattern.c:150
#define RANGE_REL_RX
Definition: pattern.c:81
#define RANGE_ABS_RX
Definition: pattern.c:85
Greater-than range.
Definition: pattern.c:149
#define RANGE_LT_RX
Definition: pattern.c:88
#define RANGE_BARE_RX
Definition: pattern.c:92
Absolute range.
Definition: pattern.c:147
#define RANGE_GT_RX
Definition: pattern.c:89
Less-than range.
Definition: pattern.c:148
Relative range.
Definition: pattern.c:146

Set of Regexes for various range types.

This array, will also contain the compiled regexes.

Definition at line 190 of file pattern.c.

◆ SearchPattern

struct PatternList* SearchPattern = NULL
static

current search pattern

Definition at line 199 of file pattern.c.

◆ LastSearch

char LastSearch[256] = { 0 }
static

last pattern searched for

Definition at line 200 of file pattern.c.

◆ LastSearchExpn

char LastSearchExpn[1024] = { 0 }
static

expanded version of LastSearch

Definition at line 201 of file pattern.c.

◆ Flags

const struct PatternFlags Flags[]
static

Lookup table for all patterns.

Definition at line 1288 of file pattern.c.