NeoMutt  2020-03-20-65-g141838
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 <regex.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 "gui/lib.h"
#include "mutt.h"
#include "pattern.h"
#include "alias.h"
#include "context.h"
#include "copy.h"
#include "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "init.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 "sendlib.h"
#include "state.h"
#include "ncrypt/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_strdup(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:66
bool group_match
Check a group of Addresses.
Definition: pattern.h:56
#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
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:52
bool string_match
Check a string for a match.
Definition: pattern.h:55
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:57
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:416
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
union Pattern::@2 p
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
char * str
String, if string_match is set.
Definition: pattern.h:68
struct Group * group
Address group if group_match is set.
Definition: pattern.h:67
#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:66
+ 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)
272  return true;
274  mutt_list_insert_tail(msgid_list, mutt_str_strdup(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:743
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:757
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int const char int line
Definition: acutest.h:602
+ 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:192
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:61
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:51
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:416
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
union Pattern::@2 p
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:69
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
WHERE char * C_ExternalSearchCommand
Config: External search command.
Definition: globals.h:112
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:168
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:291
+ 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:737
#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:47
#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:737
#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:47
int min
Minimum for range checks.
Definition: pattern.h:62
int max
Maximum for range checks.
Definition: pattern.h:63
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
Definition: date.c:225
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:47
int min
Minimum for range checks.
Definition: pattern.h:62
char * dptr
Current read/write position.
Definition: buffer.h:36
int max
Maximum for range checks.
Definition: pattern.h:63

◆ 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:47
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:413
#define MEGA
Definition: pattern.c:96
#define KILO
Definition: pattern.c:95
struct Mailbox * mailbox
Definition: context.h:51
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:47
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:87
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:413
#define RANGE_LT
Definition: pattern.c:115
#define RANGE_DOLLAR
Definition: pattern.c:114
struct Mailbox * mailbox
Definition: context.h:51
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:47
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:87
#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:62
int max
Maximum for range checks.
Definition: pattern.h:63
+ 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:413
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:51
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:47
int min
Minimum for range checks.
Definition: pattern.h:62
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:63
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:87
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:47
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_strdup(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
#define _(a)
Definition: message.h:28
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
Definition: pattern.h:44
size_t dsize
Length of data.
Definition: buffer.h:37
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:59
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:416
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
char * dptr
Current read/write position.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:35
union Pattern::@2 p
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
char * str
String, if string_match is set.
Definition: pattern.h:68
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:66
bool group_match
Check a group of Addresses.
Definition: pattern.h:56
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:61
bool mutt_group_match(struct Group *g, const char *s)
Does a string match an entry in a Group?
Definition: group.c:325
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:103
bool string_match
Check a string for a match.
Definition: pattern.h:55
bool ign_case
Ignore case for local string_match searches.
Definition: pattern.h:57
union Pattern::@2 p
char * str
String, if string_match is set.
Definition: pattern.h:68
struct Group * group
Address group if group_match is set.
Definition: pattern.h:67
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:69
+ 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_strlen(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:126
#define WithCrypto
Definition: lib.h:163
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:125
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:49
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
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
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:1171
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:146
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:105
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:52
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
Pattern matches email&#39;s body.
Definition: pattern.h:125
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:392
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:1550
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:1123
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:1062
+ 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
ptrMatching close parenthesis
ptrEnd of string NUL, if not found

Definition at line 1362 of file pattern.c.

1363 {
1364  int level = 1;
1365 
1366  for (; *s; s++)
1367  {
1368  if (*s == '(')
1369  level++;
1370  else if (*s == ')')
1371  {
1372  level--;
1373  if (level == 0)
1374  break;
1375  }
1376  }
1377  return s;
1378 }
+ 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 1384 of file pattern.c.

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

1421 {
1422  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1423  SLIST_INIT(h);
1424  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1425  SLIST_INSERT_HEAD(h, p, entries);
1426  return h;
1427 }
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:50
union Pattern::@2 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 1436 of file pattern.c.

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

1698 {
1699  struct Pattern *p = NULL;
1700 
1701  SLIST_FOREACH(p, pat, entries)
1702  {
1703  if (mutt_pattern_exec(p, flags, m, e, cache) <= 0)
1704  return false;
1705  }
1706  return true;
1707 }
A simple (non-regex) pattern.
Definition: pattern.h:50
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:2122
union Pattern::@2 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 1718 of file pattern.c.

1720 {
1721  struct Pattern *p = NULL;
1722 
1723  SLIST_FOREACH(p, pat, entries)
1724  {
1725  if (mutt_pattern_exec(p, flags, m, e, cache) > 0)
1726  return true;
1727  }
1728  return false;
1729 }
A simple (non-regex) pattern.
Definition: pattern.h:50
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:2122
union Pattern::@2 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
trueOne Address matches (all_addr is false)
trueAll the Addresses match (all_addr is true)

Definition at line 1740 of file pattern.c.

1741 {
1742  va_list ap;
1743 
1744  va_start(ap, n);
1745  for (; n; n--)
1746  {
1747  struct AddressList *al = va_arg(ap, struct AddressList *);
1748  struct Address *a = NULL;
1749  TAILQ_FOREACH(a, al, entries)
1750  {
1751  if (pat->all_addr ^ ((!pat->is_alias || mutt_alias_reverse_lookup(a)) &&
1752  ((a->mailbox && patmatch(pat, a->mailbox)) ||
1753  (match_personal && a->personal && patmatch(pat, a->personal)))))
1754  {
1755  va_end(ap);
1756  return !pat->all_addr; /* Found match, or non-match if all_addr */
1757  }
1758  }
1759  }
1760  va_end(ap);
1761  return pat->all_addr; /* No matches, or all matches if all_addr */
1762 }
#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:58
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:54
va_start(args, fmt)
struct Address * mutt_alias_reverse_lookup(const struct Address *a)
Does the user have an alias for the given address.
Definition: alias.c:545
char * personal
Real name of address.
Definition: address.h:36
int n
Definition: acutest.h:477
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 1770 of file pattern.c.

1771 {
1772  struct ListNode *np = NULL;
1773  STAILQ_FOREACH(np, refs, entries)
1774  {
1775  if (patmatch(pat, np->data))
1776  return true;
1777  }
1778  return false;
1779 }
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * data
String.
Definition: list.h:35
A List node for strings.
Definition: list.h:33
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
trueOne Address matches (all_addr is false)
trueAll 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 1791 of file pattern.c.

1792 {
1793  struct AddressList *als[] = { &e->to, &e->cc };
1794  for (size_t i = 0; i < mutt_array_size(als); ++i)
1795  {
1796  struct AddressList *al = als[i];
1797  struct Address *a = NULL;
1798  TAILQ_FOREACH(a, al, entries)
1799  {
1800  if (all_addr ^ p(a))
1801  return !all_addr;
1802  }
1803  }
1804  return all_addr;
1805 }
#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
trueOne Address is subscribed (all_addr is false)
trueAll the Addresses are subscribed (all_addr is true)

Definition at line 1814 of file pattern.c.

1815 {
1817 }
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:1791
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: hdrline.c:126
+ 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
trueOne Address is a mailing list (all_addr is false)
trueAll the Addresses are mailing lists (all_addr is true)

Definition at line 1826 of file pattern.c.

1827 {
1828  return mutt_is_predicate_recipient(all_addr, e, &mutt_is_mail_list);
1829 }
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:114
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:1791
+ 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
trueOne Address refers to the user (all_addr is false)
trueAll the Addresses refer to the user (all_addr is true)

Definition at line 1839 of file pattern.c.

1840 {
1841  struct Address *a = NULL;
1842  if (al1)
1843  {
1844  TAILQ_FOREACH(a, al1, entries)
1845  {
1846  if (all_addr ^ mutt_addr_is_user(a))
1847  return !all_addr;
1848  }
1849  }
1850 
1851  if (al2)
1852  {
1853  TAILQ_FOREACH(a, al2, entries)
1854  {
1855  if (all_addr ^ mutt_addr_is_user(a))
1856  return !all_addr;
1857  }
1858  }
1859  return all_addr;
1860 }
#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:686
+ 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 1875 of file pattern.c.

1878 {
1879  if (!t)
1880  return 0;
1881 
1882  int a;
1883  struct Email *e = t->message;
1884  if (e)
1885  if (mutt_pattern_exec(SLIST_FIRST(pat), flags, m, e, NULL))
1886  return 1;
1887 
1888  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
1889  return a;
1890  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
1891  {
1892  return a;
1893  }
1894  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
1895  {
1896  return a;
1897  }
1898  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
1899  return a;
1900  return 0;
1901 }
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:1875
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:2122
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 1913 of file pattern.c.

1915 {
1916  if (!t || !t->parent || !t->parent->message)
1917  return 0;
1918 
1919  return mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->parent->message, NULL);
1920 }
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:2122
#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 1932 of file pattern.c.

1934 {
1935  if (!t || !t->child)
1936  return 0;
1937 
1938  for (t = t->child; t; t = t->next)
1939  if (t->message && mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->message, NULL))
1940  return 1;
1941 
1942  return 0;
1943 }
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:2122
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 1952 of file pattern.c.

1953 {
1954  if (!b)
1955  return false;
1956 
1957  char buf[256];
1958  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1959 
1960  if (patmatch(pat, buf))
1961  return true;
1962  if (match_content_type(pat, b->parts))
1963  return true;
1964  if (match_content_type(pat, b->next))
1965  return true;
1966  return false;
1967 }
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:1952
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 1975 of file pattern.c.

1976 {
1977  struct Buffer *err = mutt_buffer_pool_get();
1978 
1979  bool rc = eval_date_minmax(pat, pat->p.str, err);
1981 
1982  return rc;
1983 }
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::@2 p
char * str
String, if string_match is set.
Definition: pattern.h:68
+ 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 1993 of file pattern.c.

1995 {
1997  return match_content_type(pat, e->content);
1998 }
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:49
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:1952
+ 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 2007 of file pattern.c.

2008 {
2009  *cache_entry = (value != 0) ? 2 : 1;
2010 }
+ 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 2018 of file pattern.c.

2019 {
2020  return cache_entry == 2;
2021 }
+ 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 2028 of file pattern.c.

2029 {
2030  return cache_entry != 0;
2031 }
+ 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 2041 of file pattern.c.

2042 {
2043  bool match = false;
2044  char *buf = NULL;
2045  size_t blen = 0;
2046  FILE *fp = NULL;
2047 
2048  if ((pat->op == MUTT_PAT_HEADER) || (pat->op == MUTT_PAT_WHOLE_MSG))
2049  {
2050  struct Buffer *tempfile = mutt_buffer_pool_get();
2051  mutt_buffer_mktemp(tempfile);
2052  fp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
2053  if (!fp)
2054  {
2055  mutt_perror(mutt_b2s(tempfile));
2056  mutt_buffer_pool_release(&tempfile);
2057  return 0;
2058  }
2059 
2061  fflush(fp);
2062  fseek(fp, 0, 0);
2063 
2064  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
2065  {
2066  if (patmatch(pat, buf) == 0)
2067  {
2068  match = true;
2069  break;
2070  }
2071  }
2072 
2073  FREE(&buf);
2074  mutt_file_fclose(&fp);
2075  unlink(mutt_b2s(tempfile));
2076  mutt_buffer_pool_release(&tempfile);
2077 
2078  if (match)
2079  return match;
2080  }
2081 
2082  if ((pat->op == MUTT_PAT_BODY) || (pat->op == MUTT_PAT_WHOLE_MSG))
2083  {
2084  fp = mutt_file_fopen(e->content->filename, "r");
2085  if (!fp)
2086  {
2088  return 0;
2089  }
2090 
2091  while ((buf = mutt_file_read_line(buf, &blen, fp, NULL, 0)) != NULL)
2092  {
2093  if (patmatch(pat, buf) == 0)
2094  {
2095  match = true;
2096  break;
2097  }
2098  }
2099 
2100  FREE(&buf);
2101  mutt_file_fclose(&fp);
2102  }
2103 
2104  return match;
2105 }
Pattern matches email&#39;s header.
Definition: pattern.h:126
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
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
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
A postponed Email, just the envelope info.
Definition: sendlib.h:62
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
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2320
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:52
Pattern matches email&#39;s body.
Definition: pattern.h:125
#define FREE(x)
Definition: memory.h:40
Pattern matches raw email text.
Definition: pattern.h:128
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
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 2122 of file pattern.c.

2124 {
2125  switch (pat->op)
2126  {
2127  case MUTT_PAT_AND:
2128  return pat->pat_not ^ (perform_and(pat->child, flags, m, e, cache) > 0);
2129  case MUTT_PAT_OR:
2130  return pat->pat_not ^ (perform_or(pat->child, flags, m, e, cache) > 0);
2131  case MUTT_PAT_THREAD:
2132  return pat->pat_not ^
2133  match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
2134  case MUTT_PAT_PARENT:
2135  return pat->pat_not ^ match_threadparent(pat->child, flags, m, e->thread);
2136  case MUTT_PAT_CHILDREN:
2137  return pat->pat_not ^ match_threadchildren(pat->child, flags, m, e->thread);
2138  case MUTT_ALL:
2139  return !pat->pat_not;
2140  case MUTT_EXPIRED:
2141  return pat->pat_not ^ e->expired;
2142  case MUTT_SUPERSEDED:
2143  return pat->pat_not ^ e->superseded;
2144  case MUTT_FLAG:
2145  return pat->pat_not ^ e->flagged;
2146  case MUTT_TAG:
2147  return pat->pat_not ^ e->tagged;
2148  case MUTT_NEW:
2149  return pat->pat_not ? e->old || e->read : !(e->old || e->read);
2150  case MUTT_UNREAD:
2151  return pat->pat_not ? e->read : !e->read;
2152  case MUTT_REPLIED:
2153  return pat->pat_not ^ e->replied;
2154  case MUTT_OLD:
2155  return pat->pat_not ? (!e->old || e->read) : (e->old && !e->read);
2156  case MUTT_READ:
2157  return pat->pat_not ^ e->read;
2158  case MUTT_DELETED:
2159  return pat->pat_not ^ e->deleted;
2160  case MUTT_PAT_MESSAGE:
2161  return pat->pat_not ^ ((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
2162  case MUTT_PAT_DATE:
2163  if (pat->dynamic)
2165  return pat->pat_not ^ (e->date_sent >= pat->min && e->date_sent <= pat->max);
2167  if (pat->dynamic)
2169  return pat->pat_not ^ (e->received >= pat->min && e->received <= pat->max);
2170  case MUTT_PAT_BODY:
2171  case MUTT_PAT_HEADER:
2172  case MUTT_PAT_WHOLE_MSG:
2173  if (pat->sendmode)
2174  {
2175  if (!e->content || !e->content->filename)
2176  return 0;
2177  return pat->pat_not ^ msg_search_sendmode(e, pat);
2178  }
2179  /* m can be NULL in certain cases, such as when replying to a message
2180  * from the attachment menu and the user has a reply-hook using "~e".
2181  * This is also the case when message scoring. */
2182  if (!m)
2183  return 0;
2184 #ifdef USE_IMAP
2185  /* IMAP search sets e->matched at search compile time */
2186  if ((m->type == MUTT_IMAP) && pat->string_match)
2187  return e->matched;
2188 #endif
2189  return pat->pat_not ^ msg_search(m, pat, e->msgno);
2190  case MUTT_PAT_SERVERSEARCH:
2191 #ifdef USE_IMAP
2192  if (!m)
2193  return 0;
2194  if (m->type == MUTT_IMAP)
2195  {
2196  if (pat->string_match)
2197  return e->matched;
2198  return 0;
2199  }
2200  mutt_error(_("error: server custom search only supported with IMAP"));
2201  return 0;
2202 #else
2203  mutt_error(_("error: server custom search only supported with IMAP"));
2204  return -1;
2205 #endif
2206  case MUTT_PAT_SENDER:
2207  if (!e->env)
2208  return 0;
2209  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2210  1, &e->env->sender);
2211  case MUTT_PAT_FROM:
2212  if (!e->env)
2213  return 0;
2214  return pat->pat_not ^
2215  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->from);
2216  case MUTT_PAT_TO:
2217  if (!e->env)
2218  return 0;
2219  return pat->pat_not ^
2220  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->to);
2221  case MUTT_PAT_CC:
2222  if (!e->env)
2223  return 0;
2224  return pat->pat_not ^
2225  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->cc);
2226  case MUTT_PAT_SUBJECT:
2227  if (!e->env)
2228  return 0;
2229  return pat->pat_not ^ (e->env->subject && patmatch(pat, e->env->subject));
2230  case MUTT_PAT_ID:
2231  case MUTT_PAT_ID_EXTERNAL:
2232  if (!e->env)
2233  return 0;
2234  return pat->pat_not ^ (e->env->message_id && patmatch(pat, e->env->message_id));
2235  case MUTT_PAT_SCORE:
2236  return pat->pat_not ^ (e->score >= pat->min &&
2237  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
2238  case MUTT_PAT_SIZE:
2239  return pat->pat_not ^
2240  (e->content->length >= pat->min &&
2241  (pat->max == MUTT_MAXRANGE || e->content->length <= pat->max));
2242  case MUTT_PAT_REFERENCE:
2243  if (!e->env)
2244  return 0;
2245  return pat->pat_not ^ (match_reference(pat, &e->env->references) ||
2246  match_reference(pat, &e->env->in_reply_to));
2247  case MUTT_PAT_ADDRESS:
2248  if (!e->env)
2249  return 0;
2250  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2251  4, &e->env->from, &e->env->sender,
2252  &e->env->to, &e->env->cc);
2253  case MUTT_PAT_RECIPIENT:
2254  if (!e->env)
2255  return 0;
2256  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2257  2, &e->env->to, &e->env->cc);
2258  case MUTT_PAT_LIST: /* known list, subscribed or not */
2259  {
2260  if (!e->env)
2261  return 0;
2262 
2263  int result;
2264  if (cache)
2265  {
2266  int *cache_entry = pat->all_addr ? &cache->list_all : &cache->list_one;
2267  if (!is_pattern_cache_set(*cache_entry))
2268  {
2269  set_pattern_cache_value(cache_entry,
2270  mutt_is_list_recipient(pat->all_addr, e->env));
2271  }
2272  result = get_pattern_cache_value(*cache_entry);
2273  }
2274  else
2275  result = mutt_is_list_recipient(pat->all_addr, e->env);
2276  return pat->pat_not ^ result;
2277  }
2279  {
2280  if (!e->env)
2281  return 0;
2282 
2283  int result;
2284  if (cache)
2285  {
2286  int *cache_entry = pat->all_addr ? &cache->sub_all : &cache->sub_one;
2287  if (!is_pattern_cache_set(*cache_entry))
2288  {
2290  cache_entry, mutt_is_subscribed_list_recipient(pat->all_addr, e->env));
2291  }
2292  result = get_pattern_cache_value(*cache_entry);
2293  }
2294  else
2295  result = mutt_is_subscribed_list_recipient(pat->all_addr, e->env);
2296  return pat->pat_not ^ result;
2297  }
2299  {
2300  if (!e->env)
2301  return 0;
2302 
2303  int result;
2304  if (cache)
2305  {
2306  int *cache_entry = pat->all_addr ? &cache->pers_recip_all : &cache->pers_recip_one;
2307  if (!is_pattern_cache_set(*cache_entry))
2308  {
2310  cache_entry, match_user(pat->all_addr, &e->env->to, &e->env->cc));
2311  }
2312  result = get_pattern_cache_value(*cache_entry);
2313  }
2314  else
2315  result = match_user(pat->all_addr, &e->env->to, &e->env->cc);
2316  return pat->pat_not ^ result;
2317  }
2319  {
2320  if (!e->env)
2321  return 0;
2322 
2323  int result;
2324  if (cache)
2325  {
2326  int *cache_entry = pat->all_addr ? &cache->pers_from_all : &cache->pers_from_one;
2327  if (!is_pattern_cache_set(*cache_entry))
2328  {
2329  set_pattern_cache_value(cache_entry,
2330  match_user(pat->all_addr, &e->env->from, NULL));
2331  }
2332  result = get_pattern_cache_value(*cache_entry);
2333  }
2334  else
2335  result = match_user(pat->all_addr, &e->env->from, NULL);
2336  return pat->pat_not ^ result;
2337  }
2338  case MUTT_PAT_COLLAPSED:
2339  return pat->pat_not ^ (e->collapsed && e->num_hidden > 1);
2340  case MUTT_PAT_CRYPT_SIGN:
2341  if (!WithCrypto)
2342  break;
2343  return pat->pat_not ^ ((e->security & SEC_SIGN) ? 1 : 0);
2345  if (!WithCrypto)
2346  break;
2347  return pat->pat_not ^ ((e->security & SEC_GOODSIGN) ? 1 : 0);
2349  if (!WithCrypto)
2350  break;
2351  return pat->pat_not ^ ((e->security & SEC_ENCRYPT) ? 1 : 0);
2352  case MUTT_PAT_PGP_KEY:
2353  if (!(WithCrypto & APPLICATION_PGP))
2354  break;
2355  return pat->pat_not ^ ((e->security & PGP_KEY) == PGP_KEY);
2356  case MUTT_PAT_XLABEL:
2357  if (!e->env)
2358  return 0;
2359  return pat->pat_not ^ (e->env->x_label && patmatch(pat, e->env->x_label));
2360  case MUTT_PAT_DRIVER_TAGS:
2361  {
2362  char *tags = driver_tags_get(&e->tags);
2363  bool rc = (pat->pat_not ^ (tags && patmatch(pat, tags)));
2364  FREE(&tags);
2365  return rc;
2366  }
2367  case MUTT_PAT_HORMEL:
2368  if (!e->env)
2369  return 0;
2370  return pat->pat_not ^ (e->env->spam.data && patmatch(pat, e->env->spam.data));
2371  case MUTT_PAT_DUPLICATED:
2372  return pat->pat_not ^ (e->thread && e->thread->duplicate_thread);
2373  case MUTT_PAT_MIMEATTACH:
2374  if (!m)
2375  return 0;
2376  {
2377  int count = mutt_count_body_parts(m, e);
2378  return pat->pat_not ^ (count >= pat->min &&
2379  (pat->max == MUTT_MAXRANGE || count <= pat->max));
2380  }
2381  case MUTT_PAT_MIMETYPE:
2382  if (!m)
2383  return 0;
2384  return pat->pat_not ^ match_mime_content_type(pat, m, e);
2385  case MUTT_PAT_UNREFERENCED:
2386  return pat->pat_not ^ (e->thread && !e->thread->child);
2387  case MUTT_PAT_BROKEN:
2388  return pat->pat_not ^ (e->thread && e->thread->fake_thread);
2389 #ifdef USE_NNTP
2390  case MUTT_PAT_NEWSGROUPS:
2391  if (!e->env)
2392  return 0;
2393  return pat->pat_not ^ (e->env->newsgroups && patmatch(pat, e->env->newsgroups));
2394 #endif
2395  }
2396  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
2397  return -1;
2398 }
Pattern matches date received.
Definition: pattern.h:119
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:64
Deleted messages.
Definition: mutt.h:99
Pattern matches email&#39;s header.
Definition: pattern.h:126
Pattern matches MIME type.
Definition: pattern.h:148
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:118
#define WithCrypto
Definition: lib.h:163
static bool match_reference(struct Pattern *pat, struct ListHead *refs)
Match references against a Pattern.
Definition: pattern.c:1770
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:1696
Pattern matches newsgroup.
Definition: pattern.h:150
Pattern matches email&#39;s score.
Definition: pattern.h:131
int pers_recip_all
^~p
Definition: pattern.h:93
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:1932
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against and Address list.
Definition: pattern.c:1740
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
Message is part of a broken thread.
Definition: pattern.h:122
Pattern matches email&#39;s size.
Definition: pattern.h:132
struct Body * content
List of MIME parts.
Definition: email.h:90
Flagged messages.
Definition: mutt.h:100
Pattern matches &#39;From:&#39; field.
Definition: pattern.h:117
#define MUTT_MAXRANGE
Definition: pattern.c:99
Email is from the user.
Definition: pattern.h:138
#define _(a)
Definition: message.h:28
Email is on mailing list.
Definition: pattern.h:135
Pattern matches a child email.
Definition: pattern.h:112
static int match_user(int all_addr, struct AddressList *al1, struct AddressList *al2)
Matches the user&#39;s email Address.
Definition: pattern.c:1839
bool expired
Already expired?
Definition: email.h:52
Pattern matches email&#39;s Message-Id.
Definition: pattern.h:123
Messages that have been replied to.
Definition: mutt.h:93
int sub_all
^~u
Definition: pattern.h:91
Pattern matches message number.
Definition: pattern.h:130
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:1875
Email is on subscribed mailing list.
Definition: pattern.h:136
static int msg_search_sendmode(struct Email *e, struct Pattern *pat)
Search in send-mode.
Definition: pattern.c:2041
static int is_pattern_cache_set(int cache_entry)
Is a given Pattern cached?
Definition: pattern.c:2028
All messages.
Definition: mutt.h:89
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:59
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:54
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:120
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:55
bool pat_not
Pattern should be inverted (not)
Definition: pattern.h:53
bool superseded
Got superseded?
Definition: email.h:53
int min
Minimum for range checks.
Definition: pattern.h:62
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:92
int pers_from_one
~P
Definition: pattern.h:96
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:145
Pattern matches &#39;Cc:&#39; field.
Definition: pattern.h:114
int pers_recip_one
~p
Definition: pattern.h:94
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
Message is unreferenced in the thread.
Definition: pattern.h:121
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:144
Either pattern can match.
Definition: pattern.h:109
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:127
Superseded messages.
Definition: mutt.h:105
Tagged messages.
Definition: mutt.h:101
Message is encrypted.
Definition: pattern.h:142
char * data
Pointer to data.
Definition: buffer.h:35
Pattern matches &#39;Subject:&#39; field.
Definition: pattern.h:116
int list_all
^~l
Definition: pattern.h:89
New messages.
Definition: mutt.h:91
Messages that have been read.
Definition: mutt.h:94
static int get_pattern_cache_value(int cache_entry)
Get pattern cache value.
Definition: pattern.c:2018
Email is addressed to the user.
Definition: pattern.h:137
Message has PGP key.
Definition: pattern.h:143
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:52
Pattern matches parent.
Definition: pattern.h:111
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:1718
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:77
Expired messages.
Definition: mutt.h:104
int pers_from_all
^~P
Definition: pattern.h:95
#define SEC_SIGN
Email is signed.
Definition: lib.h:126
Unread messages.
Definition: mutt.h:95
Pattern matches email&#39;s body.
Definition: pattern.h:125
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:146
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:140
bool deleted
Email is deleted.
Definition: email.h:45
bool sendmode
Evaluate searches in send-mode.
Definition: pattern.h:60
#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:1913
Thread is collapsed.
Definition: pattern.h:115
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: pattern.c:1814
Pattern matches sender.
Definition: pattern.h:129
Both patterns must match.
Definition: pattern.h:108
#define FREE(x)
Definition: memory.h:40
Message is crypographically verified.
Definition: pattern.h:141
int max
Maximum for range checks.
Definition: pattern.h:63
Pattern matches &#39;References:&#39; or &#39;In-Reply-To:&#39; field.
Definition: pattern.h:133
static bool match_update_dynamic_date(struct Pattern *pat)
Update a dynamic date pattern.
Definition: pattern.c:1975
Pattern matches message tags.
Definition: pattern.h:146
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:139
User is a recipient of the email.
Definition: pattern.h:134
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:1993
Pattern matches email thread.
Definition: pattern.h:110
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:206
Pattern matches &#39;To:&#39; field.
Definition: pattern.h:113
static void set_pattern_cache_value(int *cache_entry, int value)
Sets a value in the PatternCache cache entry.
Definition: pattern.c:2007
Pattern matches raw email text.
Definition: pattern.h:128
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:1826
Pattern matches number of attachments.
Definition: pattern.h:147
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:127
int list_one
~l
Definition: pattern.h:90
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:124
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:92
+ 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 2405 of file pattern.c.

2406 {
2407  mutt_buffer_reset(buf);
2408  mutt_buffer_addch(buf, '"');
2409  while (*str)
2410  {
2411  if ((*str == '\\') || (*str == '"'))
2412  mutt_buffer_addch(buf, '\\');
2413  mutt_buffer_addch(buf, *str++);
2414  }
2415  mutt_buffer_addch(buf, '"');
2416 }
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 2423 of file pattern.c.

2424 {
2425  bool do_simple = true;
2426 
2427  for (const char *p = mutt_b2s(buf); p && (p[0] != '\0'); p++)
2428  {
2429  if ((p[0] == '\\') && (p[1] != '\0'))
2430  p++;
2431  else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
2432  {
2433  do_simple = false;
2434  break;
2435  }
2436  }
2437 
2438  /* XXX - is mutt_str_strcasecmp() right here, or should we use locale's
2439  * equivalences? */
2440 
2441  if (do_simple) /* yup, so spoof a real request */
2442  {
2443  /* convert old tokens into the new format */
2444  if ((mutt_str_strcasecmp("all", mutt_b2s(buf)) == 0) ||
2445  (mutt_str_strcmp("^", mutt_b2s(buf)) == 0) ||
2446  (mutt_str_strcmp(".", mutt_b2s(buf)) == 0)) /* ~A is more efficient */
2447  {
2448  mutt_buffer_strcpy(buf, "~A");
2449  }
2450  else if (mutt_str_strcasecmp("del", mutt_b2s(buf)) == 0)
2451  mutt_buffer_strcpy(buf, "~D");
2452  else if (mutt_str_strcasecmp("flag", mutt_b2s(buf)) == 0)
2453  mutt_buffer_strcpy(buf, "~F");
2454  else if (mutt_str_strcasecmp("new", mutt_b2s(buf)) == 0)
2455  mutt_buffer_strcpy(buf, "~N");
2456  else if (mutt_str_strcasecmp("old", mutt_b2s(buf)) == 0)
2457  mutt_buffer_strcpy(buf, "~O");
2458  else if (mutt_str_strcasecmp("repl", mutt_b2s(buf)) == 0)
2459  mutt_buffer_strcpy(buf, "~Q");
2460  else if (mutt_str_strcasecmp("read", mutt_b2s(buf)) == 0)
2461  mutt_buffer_strcpy(buf, "~R");
2462  else if (mutt_str_strcasecmp("tag", mutt_b2s(buf)) == 0)
2463  mutt_buffer_strcpy(buf, "~T");
2464  else if (mutt_str_strcasecmp("unread", mutt_b2s(buf)) == 0)
2465  mutt_buffer_strcpy(buf, "~U");
2466  else
2467  {
2468  struct Buffer *tmp = mutt_buffer_pool_get();
2469  quote_simple(mutt_b2s(buf), tmp);
2470  mutt_file_expand_fmt(buf, simple, mutt_b2s(tmp));
2472  }
2473  }
2474 }
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:2405
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 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:1441
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
+ 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 2482 of file pattern.c.

2483 {
2484  if (!e)
2485  return NULL;
2486 
2487  struct MuttThread *t = e->thread;
2488 
2489  while (t && t->parent)
2490  t = t->parent;
2491 
2492  return t;
2493 }
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 2501 of file pattern.c.

2502 {
2503  if (!e || !Context || !Context->mailbox)
2504  return false;
2505 
2506  struct MuttThread *me = top_of_thread(e);
2507  if (!me)
2508  return false;
2509 
2510  struct Mailbox *m = Context->mailbox;
2511 
2512  m->vcount = 0;
2513  Context->vsize = 0;
2514  Context->collapsed = false;
2515 
2516  for (int i = 0; i < m->msg_count; i++)
2517  {
2518  e = m->emails[i];
2519  if (!e)
2520  break;
2521 
2522  e->vnum = -1;
2523  e->limited = false;
2524  e->collapsed = false;
2525  e->num_hidden = 0;
2526 
2527  if (top_of_thread(e) == me)
2528  {
2529  struct Body *body = e->content;
2530 
2531  e->vnum = m->vcount;
2532  e->limited = true;
2533  m->v2r[m->vcount] = i;
2534  m->vcount++;
2535  Context->vsize += (body->length + body->offset - body->hdr_offset);
2536  }
2537  }
2538  return true;
2539 }
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:51
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:2482
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:49
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 2548 of file pattern.c.

2549 {
2550  if (!Context || !Context->mailbox)
2551  return -1;
2552 
2553  struct Buffer err;
2554  int rc = -1;
2555  struct Progress progress;
2556  struct Buffer *buf = mutt_buffer_pool_get();
2557  struct Mailbox *m = Context->mailbox;
2558 
2560  if (prompt || (op != MUTT_LIMIT))
2561  {
2562  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR) != 0) ||
2563  mutt_buffer_is_empty(buf))
2564  {
2566  return -1;
2567  }
2568  }
2569 
2570  mutt_message(_("Compiling search pattern..."));
2571 
2572  char *simple = mutt_buffer_strdup(buf);
2574 
2575  mutt_buffer_init(&err);
2576  err.dsize = 256;
2577  err.data = mutt_mem_malloc(err.dsize);
2578  struct PatternList *pat = mutt_pattern_comp(buf->data, MUTT_PC_FULL_MSG, &err);
2579  if (!pat)
2580  {
2581  mutt_error("%s", err.data);
2582  goto bail;
2583  }
2584 
2585 #ifdef USE_IMAP
2586  if ((m->type == MUTT_IMAP) && (imap_search(m, pat) < 0))
2587  goto bail;
2588 #endif
2589 
2590  mutt_progress_init(&progress, _("Executing command on matching messages..."),
2591  MUTT_PROGRESS_READ, (op == MUTT_LIMIT) ? m->msg_count : m->vcount);
2592 
2593  if (op == MUTT_LIMIT)
2594  {
2595  m->vcount = 0;
2596  Context->vsize = 0;
2597  Context->collapsed = false;
2598  int padding = mx_msg_padding_size(m);
2599 
2600  for (int i = 0; i < m->msg_count; i++)
2601  {
2602  struct Email *e = m->emails[i];
2603  if (!e)
2604  break;
2605 
2606  mutt_progress_update(&progress, i, -1);
2607  /* new limit pattern implicitly uncollapses all threads */
2608  e->vnum = -1;
2609  e->limited = false;
2610  e->collapsed = false;
2611  e->num_hidden = 0;
2612  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2613  {
2614  e->vnum = m->vcount;
2615  e->limited = true;
2616  m->v2r[m->vcount] = i;
2617  m->vcount++;
2618  struct Body *b = e->content;
2619  Context->vsize += b->length + b->offset - b->hdr_offset + padding;
2620  }
2621  }
2622  }
2623  else
2624  {
2625  for (int i = 0; i < m->vcount; i++)
2626  {
2627  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2628  if (!e)
2629  continue;
2630  mutt_progress_update(&progress, i, -1);
2631  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2632  {
2633  switch (op)
2634  {
2635  case MUTT_UNDELETE:
2636  mutt_set_flag(m, e, MUTT_PURGE, false);
2637  /* fallthrough */
2638  case MUTT_DELETE:
2639  mutt_set_flag(m, e, MUTT_DELETE, (op == MUTT_DELETE));
2640  break;
2641  case MUTT_TAG:
2642  case MUTT_UNTAG:
2643  mutt_set_flag(m, e, MUTT_TAG, (op == MUTT_TAG));
2644  break;
2645  }
2646  }
2647  }
2648  }
2649 
2650  mutt_clear_error();
2651 
2652  if (op == MUTT_LIMIT)
2653  {
2654  /* drop previous limit pattern */
2655  FREE(&Context->pattern);
2657 
2658  if (m->msg_count && !m->vcount)
2659  mutt_error(_("No messages matched criteria"));
2660 
2661  /* record new limit pattern, unless match all */
2662  const char *pbuf = buf->data;
2663  while (*pbuf == ' ')
2664  pbuf++;
2665  if (mutt_str_strcmp(pbuf, "~A") != 0)
2666  {
2667  Context->pattern = simple;
2668  simple = NULL; /* don't clobber it */
2670  }
2671  }
2672 
2673  rc = 0;
2674 
2675 bail:
2677  FREE(&simple);
2678  mutt_pattern_free(&pat);
2679  FREE(&err.data);
2680 
2681  return rc;
2682 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
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:70
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:413
#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:2423
Messages in limited view.
Definition: mutt.h:103
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
int imap_search(struct Mailbox *m, const struct PatternList *pat)
Find a matching mailbox.
Definition: imap.c:1361
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:97
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:98
A progress bar.
Definition: progress.h:49
#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:51
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:41
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:2122
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1436
#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:96
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:101
char * data
Pointer to data.
Definition: buffer.h:35
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1384
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:77
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
#define mutt_buffer_get_field(field, buf, complete)
Definition: curs_lib.h:84
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: globals.h:141
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
bool collapsed
Are all threads collapsed?
Definition: context.h:49
#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:43
Messages to be un-tagged.
Definition: mutt.h:102
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1528
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
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
+ 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 2691 of file pattern.c.

2692 {
2693  struct Progress progress;
2694 
2695  if (!*LastSearch || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
2696  {
2697  char buf[256];
2698  mutt_str_strfcpy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
2699  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2700  _("Search for: ") :
2701  _("Reverse search for: "),
2702  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0) ||
2703  !buf[0])
2704  {
2705  return -1;
2706  }
2707 
2708  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
2709  OptSearchReverse = false;
2710  else
2711  OptSearchReverse = true;
2712 
2713  /* compare the *expanded* version of the search pattern in case
2714  * $simple_search has changed while we were searching */
2715  struct Buffer *tmp = mutt_buffer_pool_get();
2716  mutt_buffer_strcpy(tmp, buf);
2718 
2719  if (!SearchPattern || (mutt_str_strcmp(mutt_b2s(tmp), LastSearchExpn) != 0))
2720  {
2721  struct Buffer err;
2722  mutt_buffer_init(&err);
2723  OptSearchInvalid = true;
2724  mutt_str_strfcpy(LastSearch, buf, sizeof(LastSearch));
2726  mutt_message(_("Compiling search pattern..."));
2728  err.dsize = 256;
2729  err.data = mutt_mem_malloc(err.dsize);
2731  if (!SearchPattern)
2732  {
2734  mutt_error("%s", err.data);
2735  FREE(&err.data);
2736  LastSearch[0] = '\0';
2737  LastSearchExpn[0] = '\0';
2738  return -1;
2739  }
2740  FREE(&err.data);
2741  mutt_clear_error();
2742  }
2743 
2745  }
2746 
2747  if (OptSearchInvalid)
2748  {
2749  for (int i = 0; i < Context->mailbox->msg_count; i++)
2750  Context->mailbox->emails[i]->searched = false;
2751 #ifdef USE_IMAP
2752  if ((Context->mailbox->type == MUTT_IMAP) &&
2754  return -1;
2755 #endif
2756  OptSearchInvalid = false;
2757  }
2758 
2759  int incr = OptSearchReverse ? -1 : 1;
2760  if (op == OP_SEARCH_OPPOSITE)
2761  incr = -incr;
2762 
2763  mutt_progress_init(&progress, _("Searching..."), MUTT_PROGRESS_READ,
2764  Context->mailbox->vcount);
2765 
2766  for (int i = cur + incr, j = 0; j != Context->mailbox->vcount; j++)
2767  {
2768  const char *msg = NULL;
2769  mutt_progress_update(&progress, j, -1);
2770  if (i > Context->mailbox->vcount - 1)
2771  {
2772  i = 0;
2773  if (C_WrapSearch)
2774  msg = _("Search wrapped to top");
2775  else
2776  {
2777  mutt_message(_("Search hit bottom without finding match"));
2778  return -1;
2779  }
2780  }
2781  else if (i < 0)
2782  {
2783  i = Context->mailbox->vcount - 1;
2784  if (C_WrapSearch)
2785  msg = _("Search wrapped to bottom");
2786  else
2787  {
2788  mutt_message(_("Search hit top without finding match"));
2789  return -1;
2790  }
2791  }
2792 
2793  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2794  if (e->searched)
2795  {
2796  /* if we've already evaluated this message, use the cached value */
2797  if (e->matched)
2798  {
2799  mutt_clear_error();
2800  if (msg && *msg)
2801  mutt_message(msg);
2802  return i;
2803  }
2804  }
2805  else
2806  {
2807  /* remember that we've already searched this message */
2808  e->searched = true;
2810  Context->mailbox, e, NULL);
2811  if (e->matched > 0)
2812  {
2813  mutt_clear_error();
2814  if (msg && *msg)
2815  mutt_message(msg);
2816  return i;
2817  }
2818  }
2819 
2820  if (SigInt)
2821  {
2822  mutt_error(_("Search interrupted"));
2823  SigInt = 0;
2824  return -1;
2825  }
2826 
2827  i += incr;
2828  }
2829 
2830  mutt_error(_("Not found"));
2831  return -1;
2832 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
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:413
if(!test_colorize_)
Definition: acutest.h:484
#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:2423
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:79
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
int imap_search(struct Mailbox *m, const struct PatternList *pat)
Find a matching mailbox.
Definition: imap.c:1361
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
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: globals.h:258
bool searched
Email has been searched.
Definition: email.h:67
A progress bar.
Definition: progress.h:49
#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:90
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:51
Progress tracks elements, according to C_ReadInc.
Definition: progress.h:41
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:2122
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1436
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
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1384
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:53
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:77
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: globals.h:141
static struct PatternList * SearchPattern
current search pattern
Definition: pattern.c:199
#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:43
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
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
WHERE bool OptSearchReverse
(pseudo) used by ci_search_command
Definition: options.h:54
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.