NeoMutt  2019-12-07-60-g0cfa53
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 "mutt/mutt.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 "filter.h"
#include "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "mutt_logging.h"
#include "mutt_menu.h"
#include "mutt_parse.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "progress.h"
#include "protos.h"
#include "state.h"
#include <sys/stat.h>
#include "imap/imap.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 pattern_eat_t(struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 typedef pattern_eat_t - Parse a pattern More...
 
typedef bool(* addr_predicate_t) (const struct Address *a)
 typedef addr_predicate_t - 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_t. 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_t. 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_t. 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_t. More...
 
static bool eat_date (struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)
 Parse a date pattern - Implements pattern_eat_t. 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...
 
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 76 of file pattern.c.

◆ RANGE_REL_SLOT_RX

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

Definition at line 77 of file pattern.c.

◆ RANGE_REL_RX

#define RANGE_REL_RX   "^" RANGE_REL_SLOT_RX "," RANGE_REL_SLOT_RX

Definition at line 78 of file pattern.c.

◆ RANGE_ABS_SLOT_RX

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

Definition at line 81 of file pattern.c.

◆ RANGE_ABS_RX

#define RANGE_ABS_RX   "^" RANGE_ABS_SLOT_RX "-" RANGE_ABS_SLOT_RX

Definition at line 82 of file pattern.c.

◆ RANGE_LT_RX

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

Definition at line 85 of file pattern.c.

◆ RANGE_GT_RX

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

Definition at line 86 of file pattern.c.

◆ RANGE_BARE_RX

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

Definition at line 89 of file pattern.c.

◆ RANGE_RX_GROUPS

#define RANGE_RX_GROUPS   5

Definition at line 90 of file pattern.c.

◆ KILO

#define KILO   1024

Definition at line 92 of file pattern.c.

◆ MEGA

#define MEGA   1048576

Definition at line 93 of file pattern.c.

◆ EMSG

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

Definition at line 94 of file pattern.c.

◆ MUTT_MAXRANGE

#define MUTT_MAXRANGE   -1

Definition at line 96 of file pattern.c.

◆ MUTT_PDR_NO_FLAGS

#define MUTT_PDR_NO_FLAGS   0

No flags are set.

Definition at line 99 of file pattern.c.

◆ MUTT_PDR_MINUS

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 100 of file pattern.c.

◆ MUTT_PDR_PLUS

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 101 of file pattern.c.

◆ MUTT_PDR_WINDOW

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 102 of file pattern.c.

◆ MUTT_PDR_ABSOLUTE

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 103 of file pattern.c.

◆ MUTT_PDR_DONE

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 104 of file pattern.c.

◆ MUTT_PDR_ERROR

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 105 of file pattern.c.

◆ MUTT_PDR_ERRORDONE

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 107 of file pattern.c.

◆ RANGE_DOT

#define RANGE_DOT   '.'

Definition at line 109 of file pattern.c.

◆ RANGE_CIRCUM

#define RANGE_CIRCUM   '^'

Definition at line 110 of file pattern.c.

◆ RANGE_DOLLAR

#define RANGE_DOLLAR   '$'

Definition at line 111 of file pattern.c.

◆ RANGE_LT

#define RANGE_LT   '<'

Definition at line 112 of file pattern.c.

◆ RANGE_GT

#define RANGE_GT   '>'

Definition at line 113 of file pattern.c.

Typedef Documentation

◆ ParseDateRangeFlags

typedef uint16_t ParseDateRangeFlags

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

Definition at line 98 of file pattern.c.

◆ pattern_eat_t

typedef bool pattern_eat_t(struct Pattern *pat, int flags, struct Buffer *s, struct Buffer *err)

typedef pattern_eat_t - Parse a pattern

Parameters
patPattern to store the results in
flagsFlags, e.g. MUTT_PC_PATTERN_DYNAMIC
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 169 of file pattern.c.

◆ addr_predicate_t

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

typedef addr_predicate_t - Test an Address for some condition

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

Definition at line 207 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 119 of file pattern.c.

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

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

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

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

156 {
157  RANGE_S_LEFT,
158  RANGE_S_RIGHT,
159 };
Left side of range.
Definition: pattern.c:157
Right side of range.
Definition: pattern.c:158

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_t.

Definition at line 212 of file pattern.c.

213 {
214  struct Buffer buf;
215 
216  mutt_buffer_init(&buf);
217  char *pexpr = s->dptr;
218  if ((mutt_extract_token(&buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) || !buf.data)
219  {
220  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
221  FREE(&buf.data);
222  return false;
223  }
224  if (buf.data[0] == '\0')
225  {
226  mutt_buffer_printf(err, "%s", _("Empty expression"));
227  FREE(&buf.data);
228  return false;
229  }
230 
231  if (pat->string_match)
232  {
233  pat->p.str = mutt_str_strdup(buf.data);
234  pat->ign_case = mutt_mb_is_lower(buf.data);
235  FREE(&buf.data);
236  }
237  else if (pat->group_match)
238  {
239  pat->p.group = mutt_pattern_group(buf.data);
240  FREE(&buf.data);
241  }
242  else
243  {
244  pat->p.regex = mutt_mem_malloc(sizeof(regex_t));
245  int case_flags = mutt_mb_is_lower(buf.data) ? REG_ICASE : 0;
246  int rc = REG_COMP(pat->p.regex, buf.data, REG_NEWLINE | REG_NOSUB | case_flags);
247  if (rc != 0)
248  {
249  char errmsg[256];
250  regerror(rc, pat->p.regex, errmsg, sizeof(errmsg));
251  mutt_buffer_add_printf(err, "'%s': %s", buf.data, errmsg);
252  FREE(&buf.data);
253  FREE(&pat->p.regex);
254  return false;
255  }
256  FREE(&buf.data);
257  }
258 
259  return true;
260 }
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:64
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:82
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:54
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
bool ign_case
Ignore case for local string_match searches.
Definition: pattern.h:56
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2674
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:66
struct Group * group
Address group if group_match is set.
Definition: pattern.h:65
#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:81
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 266 of file pattern.c.

267 {
268  struct ListHead *msgid_list = (struct ListHead *) (user_data);
269  char *nows = mutt_str_skip_whitespace(line);
270  if (!*nows)
271  return true;
273  mutt_list_insert_tail(msgid_list, mutt_str_strdup(nows));
274  return true;
275 }
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition: string.c:720
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:734
const char * line
Definition: common.c:36
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
+ 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_t.

Definition at line 280 of file pattern.c.

281 {
282  struct Buffer cmd_buf;
283  struct Buffer tok_buf;
284  FILE *fp = NULL;
285 
287  {
288  mutt_buffer_printf(err, "%s", _("No search command defined"));
289  return false;
290  }
291 
292  mutt_buffer_init(&tok_buf);
293  char *pexpr = s->dptr;
294  if ((mutt_extract_token(&tok_buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) ||
295  !tok_buf.data)
296  {
297  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
298  return false;
299  }
300  if (*tok_buf.data == '\0')
301  {
302  mutt_buffer_printf(err, "%s", _("Empty expression"));
303  FREE(&tok_buf.data);
304  return false;
305  }
306 
307  mutt_buffer_init(&cmd_buf);
309  mutt_buffer_addch(&cmd_buf, ' ');
310  if (!Context || !Context->mailbox)
311  {
312  mutt_buffer_addch(&cmd_buf, '/');
313  }
314  else
315  {
316  char *escaped_folder = mutt_path_escape(mailbox_path(Context->mailbox));
317  mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
318  mutt_buffer_addch(&cmd_buf, '\'');
319  mutt_buffer_addstr(&cmd_buf, escaped_folder);
320  mutt_buffer_addch(&cmd_buf, '\'');
321  }
322  mutt_buffer_addch(&cmd_buf, ' ');
323  mutt_buffer_addstr(&cmd_buf, tok_buf.data);
324  FREE(&tok_buf.data);
325 
326  mutt_message(_("Running search command: %s ..."), cmd_buf.data);
327  pat->is_multi = true;
329  pid_t pid = mutt_create_filter(cmd_buf.data, NULL, &fp, NULL);
330  if (pid < 0)
331  {
332  mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf.data);
333  FREE(&cmd_buf.data);
334  return false;
335  }
336 
338  mutt_file_fclose(&fp);
339  mutt_wait_filter(pid);
340  FREE(&cmd_buf.data);
341  return true;
342 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:209
The "current" mailbox.
Definition: context.h:36
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:191
#define mutt_message(...)
Definition: logging.h:83
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:82
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:59
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
struct Mailbox * mailbox
Definition: context.h:50
Log at debug level 2.
Definition: logging.h:41
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
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:764
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:2674
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:266
union Pattern::@2 p
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:67
#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:110
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:168
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
Definition: mutt.h:81
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:500
+ 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 356 of file pattern.c.

357 {
358  char *ps = NULL;
359  int offset = strtol(s, &ps, 0);
360  if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
361  offset = -offset;
362 
363  switch (*ps)
364  {
365  case 'y':
366  tm->tm_year += offset;
367  break;
368  case 'm':
369  tm->tm_mon += offset;
370  break;
371  case 'w':
372  tm->tm_mday += 7 * offset;
373  break;
374  case 'd':
375  tm->tm_mday += offset;
376  break;
377  case 'H':
378  tm->tm_hour += offset;
379  break;
380  case 'M':
381  tm->tm_min += offset;
382  break;
383  case 'S':
384  tm->tm_sec += offset;
385  break;
386  default:
387  return s;
388  }
390  return ps + 1;
391 }
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" = 23 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

Definition at line 409 of file pattern.c.

410 {
411  char *p = NULL;
412  struct tm tm = mutt_date_localtime(MUTT_DATE_NOW);
413 
414  t->tm_mday = strtol(s, &p, 10);
415  if ((t->tm_mday < 1) || (t->tm_mday > 31))
416  {
417  mutt_buffer_printf(err, _("Invalid day of month: %s"), s);
418  return NULL;
419  }
420  if (*p != '/')
421  {
422  /* fill in today's month and year */
423  t->tm_mon = tm.tm_mon;
424  t->tm_year = tm.tm_year;
425  return p;
426  }
427  p++;
428  t->tm_mon = strtol(p, &p, 10) - 1;
429  if ((t->tm_mon < 0) || (t->tm_mon > 11))
430  {
431  mutt_buffer_printf(err, _("Invalid month: %s"), p);
432  return NULL;
433  }
434  if (*p != '/')
435  {
436  t->tm_year = tm.tm_year;
437  return p;
438  }
439  p++;
440  t->tm_year = strtol(p, &p, 10);
441  if (t->tm_year < 70) /* year 2000+ */
442  t->tm_year += 100;
443  else if (t->tm_year > 1900)
444  t->tm_year -= 1900;
445  return p;
446 }
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
+ 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 458 of file pattern.c.

460 {
462  while (*pc && ((flags & MUTT_PDR_DONE) == 0))
463  {
464  const char *pt = NULL;
465  char ch = *pc++;
466  SKIPWS(pc);
467  switch (ch)
468  {
469  case '-':
470  {
471  /* try a range of absolute date minus offset of Ndwmy */
472  pt = get_offset(min, pc, -1);
473  if (pc == pt)
474  {
475  if (flags == MUTT_PDR_NO_FLAGS)
476  { /* nothing yet and no offset parsed => absolute date? */
477  if (!get_date(pc, max, err))
478  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_ERRORDONE); /* done bad */
479  else
480  {
481  /* reestablish initial base minimum if not specified */
482  if (!have_min)
483  memcpy(min, base_min, sizeof(struct tm));
484  flags |= (MUTT_PDR_ABSOLUTE | MUTT_PDR_DONE); /* done good */
485  }
486  }
487  else
488  flags |= MUTT_PDR_ERRORDONE;
489  }
490  else
491  {
492  pc = pt;
493  if ((flags == MUTT_PDR_NO_FLAGS) && !have_min)
494  { /* the very first "-3d" without a previous absolute date */
495  max->tm_year = min->tm_year;
496  max->tm_mon = min->tm_mon;
497  max->tm_mday = min->tm_mday;
498  }
499  flags |= MUTT_PDR_MINUS;
500  }
501  break;
502  }
503  case '+':
504  { /* enlarge plus range */
505  pt = get_offset(max, pc, 1);
506  if (pc == pt)
507  flags |= MUTT_PDR_ERRORDONE;
508  else
509  {
510  pc = pt;
511  flags |= MUTT_PDR_PLUS;
512  }
513  break;
514  }
515  case '*':
516  { /* enlarge window in both directions */
517  pt = get_offset(min, pc, -1);
518  if (pc == pt)
519  flags |= MUTT_PDR_ERRORDONE;
520  else
521  {
522  pc = get_offset(max, pc, 1);
523  flags |= MUTT_PDR_WINDOW;
524  }
525  break;
526  }
527  default:
528  flags |= MUTT_PDR_ERRORDONE;
529  }
530  SKIPWS(pc);
531  }
532  if ((flags & MUTT_PDR_ERROR) && !(flags & MUTT_PDR_ABSOLUTE))
533  { /* get_date has its own error message, don't overwrite it here */
534  mutt_buffer_printf(err, _("Invalid relative date: %s"), pc - 1);
535  }
536  return (flags & MUTT_PDR_ERROR) ? NULL : pc;
537 }
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
Definition: pattern.c:103
#define MUTT_PDR_WINDOW
Extend the range in both directions using &#39;*&#39;.
Definition: pattern.c:102
#define MUTT_PDR_NO_FLAGS
No flags are set.
Definition: pattern.c:99
#define MUTT_PDR_ERROR
Invalid pattern.
Definition: pattern.c:105
#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:409
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: pattern.c:356
#define MUTT_PDR_PLUS
Extend the range using &#39;+&#39;.
Definition: pattern.c:101
#define SKIPWS(ch)
Definition: string2.h:47
#define MUTT_PDR_MINUS
Pattern contains a range.
Definition: pattern.c:100
#define MUTT_PDR_ERRORDONE
Definition: pattern.c:107
#define MUTT_PDR_DONE
Pattern parse successfully.
Definition: pattern.c:104
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
Definition: pattern.c:98
+ 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 544 of file pattern.c.

545 {
546  if ((min->tm_year > max->tm_year) ||
547  ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
548  ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
549  (min->tm_mday > max->tm_mday)))
550  {
551  int tmp;
552 
553  tmp = min->tm_year;
554  min->tm_year = max->tm_year;
555  max->tm_year = tmp;
556 
557  tmp = min->tm_mon;
558  min->tm_mon = max->tm_mon;
559  max->tm_mon = tmp;
560 
561  tmp = min->tm_mday;
562  min->tm_mday = max->tm_mday;
563  max->tm_mday = tmp;
564 
565  min->tm_hour = 0;
566  min->tm_min = 0;
567  min->tm_sec = 0;
568  max->tm_hour = 23;
569  max->tm_min = 59;
570  max->tm_sec = 59;
571  }
572 }
+ 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 582 of file pattern.c.

583 {
584  /* the '0' time is Jan 1, 1970 UTC, so in order to prevent a negative time
585  * when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */
586  struct tm min = { 0 };
587  min.tm_mday = 2;
588  min.tm_year = 70;
589 
590  /* Arbitrary year in the future. Don't set this too high or
591  * mutt_date_make_time() returns something larger than will fit in a time_t
592  * on some systems */
593  struct tm max = { 0 };
594  max.tm_year = 130;
595  max.tm_mon = 11;
596  max.tm_mday = 31;
597  max.tm_hour = 23;
598  max.tm_min = 59;
599  max.tm_sec = 59;
600 
601  if (strchr("<>=", s[0]))
602  {
603  /* offset from current time
604  * <3d less than three days ago
605  * >3d more than three days ago
606  * =3d exactly three days ago */
607  struct tm *tm = NULL;
608  bool exact = false;
609 
610  if (s[0] == '<')
611  {
613  tm = &min;
614  }
615  else
616  {
618  tm = &max;
619 
620  if (s[0] == '=')
621  exact = true;
622  }
623 
624  /* Reset the HMS unless we are relative matching using one of those
625  * offsets. */
626  char *offset_type = NULL;
627  strtol(s + 1, &offset_type, 0);
628  if (!(*offset_type && strchr("HMS", *offset_type)))
629  {
630  tm->tm_hour = 23;
631  tm->tm_min = 59;
632  tm->tm_sec = 59;
633  }
634 
635  /* force negative offset */
636  get_offset(tm, s + 1, -1);
637 
638  if (exact)
639  {
640  /* start at the beginning of the day in question */
641  memcpy(&min, &max, sizeof(max));
642  min.tm_hour = 0;
643  min.tm_sec = 0;
644  min.tm_min = 0;
645  }
646  }
647  else
648  {
649  const char *pc = s;
650 
651  bool have_min = false;
652  bool until_now = false;
653  if (isdigit((unsigned char) *pc))
654  {
655  /* minimum date specified */
656  pc = get_date(pc, &min, err);
657  if (!pc)
658  {
659  return false;
660  }
661  have_min = true;
662  SKIPWS(pc);
663  if (*pc == '-')
664  {
665  const char *pt = pc + 1;
666  SKIPWS(pt);
667  until_now = (*pt == '\0');
668  }
669  }
670 
671  if (!until_now)
672  { /* max date or relative range/window */
673 
674  struct tm base_min;
675 
676  if (!have_min)
677  { /* save base minimum and set current date, e.g. for "-3d+1d" */
678  memcpy(&base_min, &min, sizeof(base_min));
680  min.tm_hour = 0;
681  min.tm_sec = 0;
682  min.tm_min = 0;
683  }
684 
685  /* preset max date for relative offsets,
686  * if nothing follows we search for messages on a specific day */
687  max.tm_year = min.tm_year;
688  max.tm_mon = min.tm_mon;
689  max.tm_mday = min.tm_mday;
690 
691  if (!parse_date_range(pc, &min, &max, have_min, &base_min, err))
692  { /* bail out on any parsing error */
693  return false;
694  }
695  }
696  }
697 
698  /* Since we allow two dates to be specified we'll have to adjust that. */
699  adjust_date_range(&min, &max);
700 
701  pat->min = mutt_date_make_time(&min, true);
702  pat->max = mutt_date_make_time(&max, true);
703 
704  return true;
705 }
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition: pattern.c:544
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:409
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: pattern.c:356
#define SKIPWS(ch)
Definition: string2.h:47
int min
Minimum for range checks.
Definition: pattern.h:60
int max
Maximum for range checks.
Definition: pattern.h:61
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:458
+ 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_t.

Definition at line 710 of file pattern.c.

711 {
712  char *tmp = NULL;
713  bool do_exclusive = false;
714  bool skip_quote = false;
715 
716  /* If simple_search is set to "~m %s", the range will have double quotes
717  * around it... */
718  if (*s->dptr == '"')
719  {
720  s->dptr++;
721  skip_quote = true;
722  }
723  if (*s->dptr == '<')
724  do_exclusive = true;
725  if ((*s->dptr != '-') && (*s->dptr != '<'))
726  {
727  /* range minimum */
728  if (*s->dptr == '>')
729  {
730  pat->max = MUTT_MAXRANGE;
731  pat->min = strtol(s->dptr + 1, &tmp, 0) + 1; /* exclusive range */
732  }
733  else
734  pat->min = strtol(s->dptr, &tmp, 0);
735  if (toupper((unsigned char) *tmp) == 'K') /* is there a prefix? */
736  {
737  pat->min *= 1024;
738  tmp++;
739  }
740  else if (toupper((unsigned char) *tmp) == 'M')
741  {
742  pat->min *= 1048576;
743  tmp++;
744  }
745  if (*s->dptr == '>')
746  {
747  s->dptr = tmp;
748  return true;
749  }
750  if (*tmp != '-')
751  {
752  /* exact value */
753  pat->max = pat->min;
754  s->dptr = tmp;
755  return true;
756  }
757  tmp++;
758  }
759  else
760  {
761  s->dptr++;
762  tmp = s->dptr;
763  }
764 
765  if (isdigit((unsigned char) *tmp))
766  {
767  /* range maximum */
768  pat->max = strtol(tmp, &tmp, 0);
769  if (toupper((unsigned char) *tmp) == 'K')
770  {
771  pat->max *= 1024;
772  tmp++;
773  }
774  else if (toupper((unsigned char) *tmp) == 'M')
775  {
776  pat->max *= 1048576;
777  tmp++;
778  }
779  if (do_exclusive)
780  (pat->max)--;
781  }
782  else
783  pat->max = MUTT_MAXRANGE;
784 
785  if (skip_quote && (*tmp == '"'))
786  tmp++;
787 
788  SKIPWS(tmp);
789  s->dptr = tmp;
790  return true;
791 }
#define MUTT_MAXRANGE
Definition: pattern.c:96
#define SKIPWS(ch)
Definition: string2.h:47
int min
Minimum for range checks.
Definition: pattern.h:60
char * dptr
Current read/write position.
Definition: buffer.h:36
int max
Maximum for range checks.
Definition: pattern.h:61

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

801 {
802  size_t ds = err->dsize;
803 
804  if (regerror(regerr, preg, err->data, ds) > ds)
805  mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
806  /* The return value is fixed, exists only to shorten code at callsite */
807  return RANGE_E_SYNTAX;
808 }
Range contains syntax error.
Definition: pattern.c:122
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 819 of file pattern.c.

821 {
822  const char *context_req_chars[] = {
823  [RANGE_K_REL] = ".0123456789",
824  [RANGE_K_ABS] = ".",
825  [RANGE_K_LT] = "",
826  [RANGE_K_GT] = "",
827  [RANGE_K_BARE] = ".",
828  };
829 
830  /* First decide if we're going to need the context at all.
831  * Relative patterns need it if they contain a dot or a number.
832  * Absolute patterns only need it if they contain a dot. */
833  char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
834  if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
835  return true;
836 
837  /* We need a current message. Do we actually have one? */
838  if (Context && Context->menu)
839  return true;
840 
841  /* Nope. */
842  mutt_buffer_strcpy(err, _("No current message"));
843  return false;
844 }
The "current" mailbox.
Definition: context.h:36
Single symbol.
Definition: pattern.c:147
#define _(a)
Definition: message.h:28
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Greater-than range.
Definition: pattern.c:146
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:144
Less-than range.
Definition: pattern.c:145
Relative range.
Definition: pattern.c:143
+ 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 854 of file pattern.c.

855 {
856  int num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
857  unsigned char c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
858  if (toupper(c) == 'K')
859  num *= KILO;
860  else if (toupper(c) == 'M')
861  num *= MEGA;
862  switch (kind)
863  {
864  case RANGE_K_REL:
865  {
867  return num + EMSG(e);
868  }
869  case RANGE_K_LT:
870  return num - 1;
871  case RANGE_K_GT:
872  return num + 1;
873  default:
874  return num;
875  }
876 }
The "current" mailbox.
Definition: context.h:36
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:414
#define MEGA
Definition: pattern.c:93
#define KILO
Definition: pattern.c:92
struct Mailbox * mailbox
Definition: context.h:50
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Greater-than range.
Definition: pattern.c:146
char * dptr
Current read/write position.
Definition: buffer.h:36
#define EMSG(e)
Definition: pattern.c:94
int current
Current entry.
Definition: mutt_menu.h:87
Less-than range.
Definition: pattern.c:145
Relative range.
Definition: pattern.c:143
+ 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 887 of file pattern.c.

888 {
889  /* This means the left or right subpattern was empty, e.g. ",." */
890  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
891  {
892  if (side == RANGE_S_LEFT)
893  return 1;
894  if (side == RANGE_S_RIGHT)
895  return Context->mailbox->msg_count;
896  }
897  /* We have something, so determine what */
898  unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
899  switch (c)
900  {
901  case RANGE_CIRCUM:
902  return 1;
903  case RANGE_DOLLAR:
904  return Context->mailbox->msg_count;
905  case RANGE_DOT:
906  {
908  return EMSG(e);
909  }
910  case RANGE_LT:
911  case RANGE_GT:
912  return scan_range_num(s, pmatch, grp + 1, kind);
913  default:
914  /* Only other possibility: a number */
915  return scan_range_num(s, pmatch, grp, kind);
916  }
917 }
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:90
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:414
#define RANGE_LT
Definition: pattern.c:112
#define RANGE_DOLLAR
Definition: pattern.c:111
struct Mailbox * mailbox
Definition: context.h:50
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind)
Parse a number range.
Definition: pattern.c:854
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
Left side of range.
Definition: pattern.c:157
char * dptr
Current read/write position.
Definition: buffer.h:36
#define RANGE_GT
Definition: pattern.c:113
#define RANGE_CIRCUM
Definition: pattern.c:110
#define EMSG(e)
Definition: pattern.c:94
int current
Current entry.
Definition: mutt_menu.h:87
#define RANGE_DOT
Definition: pattern.c:109
Right side of range.
Definition: pattern.c:158
+ 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 923 of file pattern.c.

924 {
925  if (pat->min <= pat->max)
926  return;
927  int num = pat->min;
928  pat->min = pat->max;
929  pat->max = num;
930 }
int min
Minimum for range checks.
Definition: pattern.h:60
int max
Maximum for range checks.
Definition: pattern.h:61
+ 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 940 of file pattern.c.

942 {
943  int regerr;
944  regmatch_t pmatch[RANGE_RX_GROUPS];
945  struct RangeRegex *pspec = &range_regexes[kind];
946 
947  /* First time through, compile the big regex */
948  if (!pspec->ready)
949  {
950  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
951  if (regerr != 0)
952  return report_regerror(regerr, &pspec->cooked, err);
953  pspec->ready = true;
954  }
955 
956  /* Match the pattern buffer against the compiled regex.
957  * No match means syntax error. */
958  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
959  if (regerr != 0)
960  return report_regerror(regerr, &pspec->cooked, err);
961 
962  if (!is_context_available(s, pmatch, kind, err))
963  return RANGE_E_CTX;
964 
965  /* Snarf the contents of the two sides of the range. */
966  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind);
967  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind);
968  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
969 
970  /* Special case for a bare 0. */
971  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
972  {
973  if (!Context->menu)
974  {
975  mutt_buffer_strcpy(err, _("No current message"));
976  return RANGE_E_CTX;
977  }
979  pat->max = EMSG(e);
980  pat->min = pat->max;
981  }
982 
983  /* Since we don't enforce order, we must swap bounds if they're backward */
984  order_range(pat);
985 
986  /* Slide pointer past the entire match. */
987  s->dptr += pmatch[0].rm_eo;
988  return RANGE_E_OK;
989 }
The "current" mailbox.
Definition: context.h:36
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:414
regex_t cooked
Compiled form.
Definition: pattern.c:135
Single symbol.
Definition: pattern.c:147
Range is valid.
Definition: pattern.c:121
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:123
struct Mailbox * mailbox
Definition: context.h:50
struct Menu * menu
Needed for pattern compilation.
Definition: context.h:46
int min
Minimum for range checks.
Definition: pattern.h:60
Left side of range.
Definition: pattern.c:157
Regular expression representing a range.
Definition: pattern.c:129
#define RANGE_RX_GROUPS
Definition: pattern.c:90
static struct RangeRegex range_regexes[]
Set of Regexes for various range types.
Definition: pattern.c:189
char * dptr
Current read/write position.
Definition: buffer.h:36
const char * raw
Regex as string.
Definition: pattern.c:131
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:923
#define EMSG(e)
Definition: pattern.c:94
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:887
int max
Maximum for range checks.
Definition: pattern.h:61
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: pattern.c:800
int lgrp
Paren group matching the left side.
Definition: pattern.c:132
#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:133
bool ready
Compiled yet?
Definition: pattern.c:134
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:819
Right side of range.
Definition: pattern.c:158
+ 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_t.

Definition at line 994 of file pattern.c.

996 {
997  bool skip_quote = false;
998 
999  /* We need a Context for pretty much anything. */
1000  if (!Context)
1001  {
1002  mutt_buffer_strcpy(err, _("No Context"));
1003  return false;
1004  }
1005 
1006  /* If simple_search is set to "~m %s", the range will have double quotes
1007  * around it... */
1008  if (*s->dptr == '"')
1009  {
1010  s->dptr++;
1011  skip_quote = true;
1012  }
1013 
1014  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
1015  {
1016  switch (eat_range_by_regex(pat, s, i_kind, err))
1017  {
1018  case RANGE_E_CTX:
1019  /* This means it matched syntactically but lacked context.
1020  * No point in continuing. */
1021  break;
1022  case RANGE_E_SYNTAX:
1023  /* Try another syntax, then */
1024  continue;
1025  case RANGE_E_OK:
1026  if (skip_quote && (*s->dptr == '"'))
1027  s->dptr++;
1028  SKIPWS(s->dptr);
1029  return true;
1030  }
1031  }
1032  return false;
1033 }
The "current" mailbox.
Definition: context.h:36
Range is valid.
Definition: pattern.c:121
Range contains syntax error.
Definition: pattern.c:122
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:123
#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:149
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:940
+ 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_t.

Definition at line 1038 of file pattern.c.

1039 {
1040  struct Buffer *tmp = mutt_buffer_pool_get();
1041  bool rc = false;
1042 
1043  char *pexpr = s->dptr;
1045  {
1046  snprintf(err->data, err->dsize, _("Error in expression: %s"), pexpr);
1047  goto out;
1048  }
1049 
1050  if (mutt_buffer_is_empty(tmp))
1051  {
1052  snprintf(err->data, err->dsize, "%s", _("Empty expression"));
1053  goto out;
1054  }
1055 
1056  if (flags & MUTT_PC_PATTERN_DYNAMIC)
1057  {
1058  pat->dynamic = true;
1059  pat->p.str = mutt_str_strdup(tmp->data);
1060  }
1061 
1062  rc = eval_date_minmax(pat, tmp->data, err);
1063 
1064 out:
1066 
1067  return rc;
1068 }
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:82
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:58
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2674
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:582
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:66
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:81
+ 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 1077 of file pattern.c.

1078 {
1079  if (pat->is_multi)
1080  return (mutt_list_find(&pat->p.multi_cases, buf) != NULL);
1081  if (pat->string_match)
1082  return pat->ign_case ? strcasestr(buf, pat->p.str) : strstr(buf, pat->p.str);
1083  if (pat->group_match)
1084  return mutt_group_match(pat->p.group, buf);
1085  return (regexec(pat->p.regex, buf, 0, NULL, 0) == 0);
1086 }
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:64
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:59
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:54
bool ign_case
Ignore case for local string_match searches.
Definition: pattern.h:56
union Pattern::@2 p
char * str
String, if string_match is set.
Definition: pattern.h:66
struct Group * group
Address group if group_match is set.
Definition: pattern.h:65
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:67
+ 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 1096 of file pattern.c.

1097 {
1098  bool match = false;
1099  struct Message *msg = mx_msg_open(m, msgno);
1100  if (!msg)
1101  {
1102  return match;
1103  }
1104 
1105  FILE *fp = NULL;
1106  long lng = 0;
1107  struct Email *e = m->emails[msgno];
1108 #ifdef USE_FMEMOPEN
1109  char *temp = NULL;
1110  size_t tempsize;
1111 #else
1112  struct stat st;
1113 #endif
1114 
1115  if (C_ThoroughSearch)
1116  {
1117  /* decode the header / body */
1118  struct State s = { 0 };
1119  s.fp_in = msg->fp;
1120  s.flags = MUTT_CHARCONV;
1121 #ifdef USE_FMEMOPEN
1122  s.fp_out = open_memstream(&temp, &tempsize);
1123  if (!s.fp_out)
1124  {
1125  mutt_perror(_("Error opening 'memory stream'"));
1126  return false;
1127  }
1128 #else
1129  s.fp_out = mutt_file_mkstemp();
1130  if (!s.fp_out)
1131  {
1132  mutt_perror(_("Can't create temporary file"));
1133  return false;
1134  }
1135 #endif
1136 
1137  if (pat->op != MUTT_PAT_BODY)
1138  mutt_copy_header(msg->fp, e, s.fp_out, CH_FROM | CH_DECODE, NULL, 0);
1139 
1140  if (pat->op != MUTT_PAT_HEADER)
1141  {
1143 
1144  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) &&
1146  {
1147  mx_msg_close(m, &msg);
1148  if (s.fp_out)
1149  {
1151 #ifdef USE_FMEMOPEN
1152  FREE(&temp);
1153 #endif
1154  }
1155  return false;
1156  }
1157 
1158  fseeko(msg->fp, e->offset, SEEK_SET);
1159  mutt_body_handler(e->content, &s);
1160  }
1161 
1162 #ifdef USE_FMEMOPEN
1164  lng = tempsize;
1165 
1166  if (tempsize)
1167  {
1168  fp = fmemopen(temp, tempsize, "r");
1169  if (!fp)
1170  {
1171  mutt_perror(_("Error re-opening 'memory stream'"));
1172  return false;
1173  }
1174  }
1175  else
1176  { /* fmemopen can't handle empty buffers */
1177  fp = mutt_file_fopen("/dev/null", "r");
1178  if (!fp)
1179  {
1180  mutt_perror(_("Error opening /dev/null"));
1181  return false;
1182  }
1183  }
1184 #else
1185  fp = s.fp_out;
1186  fflush(fp);
1187  fseek(fp, 0, SEEK_SET);
1188  fstat(fileno(fp), &st);
1189  lng = (long) st.st_size;
1190 #endif
1191  }
1192  else
1193  {
1194  /* raw header / body */
1195  fp = msg->fp;
1196  if (pat->op != MUTT_PAT_BODY)
1197  {
1198  fseeko(fp, e->offset, SEEK_SET);
1199  lng = e->content->offset - e->offset;
1200  }
1201  if (pat->op != MUTT_PAT_HEADER)
1202  {
1203  if (pat->op == MUTT_PAT_BODY)
1204  fseeko(fp, e->content->offset, SEEK_SET);
1205  lng += e->content->length;
1206  }
1207  }
1208 
1209  size_t blen = 256;
1210  char *buf = mutt_mem_malloc(blen);
1211 
1212  /* search the file "fp" */
1213  while (lng > 0)
1214  {
1215  if (pat->op == MUTT_PAT_HEADER)
1216  {
1217  buf = mutt_rfc822_read_line(fp, buf, &blen);
1218  if (*buf == '\0')
1219  break;
1220  }
1221  else if (!fgets(buf, blen - 1, fp))
1222  break; /* don't loop forever */
1223  if (patmatch(pat, buf))
1224  {
1225  match = true;
1226  break;
1227  }
1228  lng -= mutt_str_strlen(buf);
1229  }
1230 
1231  FREE(&buf);
1232 
1233  mx_msg_close(m, &msg);
1234 
1235  if (C_ThoroughSearch)
1236  {
1237  mutt_file_fclose(&fp);
1238 #ifdef USE_FMEMOPEN
1239  if (tempsize)
1240  FREE(&temp);
1241 #endif
1242  }
1243 
1244  return match;
1245 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
Pattern matches email&#39;s header.
Definition: pattern.h:124
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
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:666
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
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:1140
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:145
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
A local copy of an email.
Definition: mx.h:81
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:72
#define mutt_file_mkstemp()
Definition: file.h:105
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
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:123
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:83
#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:1551
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
#define WithCrypto
Definition: ncrypt.h:160
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1092
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1077
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 1311 of file pattern.c.

1312 {
1313  for (int i = 0; Flags[i].tag; i++)
1314  if (Flags[i].tag == tag)
1315  return &Flags[i];
1316  return NULL;
1317 }
int tag
Character used to represent this operation, e.g. &#39;A&#39; for &#39;~A&#39;.
Definition: pattern.c:177
static const struct PatternFlags Flags[]
Lookup table for all patterns.
Definition: pattern.c:1251
+ 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 1325 of file pattern.c.

1326 {
1327  int level = 1;
1328 
1329  for (; *s; s++)
1330  {
1331  if (*s == '(')
1332  level++;
1333  else if (*s == ')')
1334  {
1335  level--;
1336  if (level == 0)
1337  break;
1338  }
1339  }
1340  return s;
1341 }
+ 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 1347 of file pattern.c.

1348 {
1349  if (!pat || !*pat)
1350  return;
1351 
1352  struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
1353 
1354  while (np)
1355  {
1356  next = SLIST_NEXT(np, entries);
1357 
1358  if (np->is_multi)
1360  else if (np->string_match || np->dynamic)
1361  FREE(&np->p.str);
1362  else if (np->group_match)
1363  np->p.group = NULL;
1364  else if (np->p.regex)
1365  {
1366  regfree(np->p.regex);
1367  FREE(&np->p.regex);
1368  }
1369 
1370  mutt_pattern_free(&np->child);
1371  FREE(&np);
1372 
1373  np = next;
1374  }
1375 
1376  FREE(pat);
1377 }
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:62
regex_t * regex
Compiled regex, for non-pattern matching.
Definition: pattern.h:64
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
bool is_multi
Multiple case (only for ~I pattern now)
Definition: pattern.h:59
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:49
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:58
bool string_match
Check a string for a match.
Definition: pattern.h:54
#define SLIST_NEXT(elm, field)
Definition: queue.h:269
#define SLIST_FIRST(head)
Definition: queue.h:228
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1347
union Pattern::@2 p
char * str
String, if string_match is set.
Definition: pattern.h:66
struct Group * group
Address group if group_match is set.
Definition: pattern.h:65
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Multiple strings for ~I pattern.
Definition: pattern.h:67
+ 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 1383 of file pattern.c.

1384 {
1385  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1386  SLIST_INIT(h);
1387  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1388  SLIST_INSERT_HEAD(h, p, entries);
1389  return h;
1390 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define SLIST_INIT(head)
Definition: queue.h:255
A simple (non-regex) pattern.
Definition: pattern.h:49
union Pattern::@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 1399 of file pattern.c.

1400 {
1401  /* curlist when assigned will always point to a list containing at least one node
1402  * with a Pattern value. */
1403  struct PatternList *curlist = NULL;
1404  struct PatternList *tmp = NULL, *tmp2 = NULL;
1405  struct PatternList *last = NULL;
1406  bool pat_not = false;
1407  bool all_addr = false;
1408  bool pat_or = false;
1409  bool implicit = true; /* used to detect logical AND operator */
1410  bool is_alias = false;
1411  short thread_op;
1412  const struct PatternFlags *entry = NULL;
1413  char *p = NULL;
1414  char *buf = NULL;
1415  struct Buffer ps;
1416 
1417  mutt_buffer_init(&ps);
1418  ps.dptr = (char *) s;
1419  ps.dsize = mutt_str_strlen(s);
1420 
1421  while (*ps.dptr)
1422  {
1423  SKIPWS(ps.dptr);
1424  switch (*ps.dptr)
1425  {
1426  case '^':
1427  ps.dptr++;
1428  all_addr = !all_addr;
1429  break;
1430  case '!':
1431  ps.dptr++;
1432  pat_not = !pat_not;
1433  break;
1434  case '@':
1435  ps.dptr++;
1436  is_alias = !is_alias;
1437  break;
1438  case '|':
1439  if (!pat_or)
1440  {
1441  if (!curlist)
1442  {
1443  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1444  return NULL;
1445  }
1446 
1447  struct Pattern *pat = SLIST_FIRST(curlist);
1448 
1449  if (SLIST_NEXT(pat, entries))
1450  {
1451  /* A & B | C == (A & B) | C */
1452  tmp = mutt_pattern_node_new();
1453  pat = SLIST_FIRST(tmp);
1454  pat->op = MUTT_PAT_AND;
1455  pat->child = curlist;
1456 
1457  curlist = tmp;
1458  last = curlist;
1459  }
1460 
1461  pat_or = true;
1462  }
1463  ps.dptr++;
1464  implicit = false;
1465  pat_not = false;
1466  all_addr = false;
1467  is_alias = false;
1468  break;
1469  case '%':
1470  case '=':
1471  case '~':
1472  {
1473  struct Pattern *pat = NULL;
1474  if (ps.dptr[1] == '\0')
1475  {
1476  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1477  goto cleanup;
1478  }
1479  thread_op = 0;
1480  if (ps.dptr[1] == '(')
1481  thread_op = MUTT_PAT_THREAD;
1482  else if ((ps.dptr[1] == '<') && (ps.dptr[2] == '('))
1483  thread_op = MUTT_PAT_PARENT;
1484  else if ((ps.dptr[1] == '>') && (ps.dptr[2] == '('))
1485  thread_op = MUTT_PAT_CHILDREN;
1486  if (thread_op)
1487  {
1488  ps.dptr++; /* skip ~ */
1489  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1490  ps.dptr++;
1491  p = find_matching_paren(ps.dptr + 1);
1492  if (p[0] != ')')
1493  {
1494  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1495  goto cleanup;
1496  }
1497  tmp = mutt_pattern_node_new();
1498  pat = SLIST_FIRST(tmp);
1499  pat->op = thread_op;
1500  if (last)
1501  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1502  else
1503  curlist = tmp;
1504  last = tmp;
1505  pat->pat_not ^= pat_not;
1506  pat->all_addr |= all_addr;
1507  pat->is_alias |= is_alias;
1508  pat_not = false;
1509  all_addr = false;
1510  is_alias = false;
1511  /* compile the sub-expression */
1512  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1513  tmp2 = mutt_pattern_comp(buf, flags, err);
1514  if (!tmp2)
1515  {
1516  FREE(&buf);
1517  goto cleanup;
1518  }
1519  FREE(&buf);
1520  pat->child = tmp2;
1521  ps.dptr = p + 1; /* restore location */
1522  break;
1523  }
1524  if (implicit && pat_or)
1525  {
1526  /* A | B & C == (A | B) & C */
1527  tmp = mutt_pattern_node_new();
1528  pat = SLIST_FIRST(tmp);
1529  pat->op = MUTT_PAT_OR;
1530  pat->child = curlist;
1531  curlist = tmp;
1532  last = tmp;
1533  pat_or = false;
1534  }
1535 
1536  tmp = mutt_pattern_node_new();
1537  pat = SLIST_FIRST(tmp);
1538  pat->pat_not = pat_not;
1539  pat->all_addr = all_addr;
1540  pat->is_alias = is_alias;
1541  pat->string_match = (ps.dptr[0] == '=');
1542  pat->group_match = (ps.dptr[0] == '%');
1543  pat_not = false;
1544  all_addr = false;
1545  is_alias = false;
1546 
1547  if (last)
1548  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1549  else
1550  curlist = tmp;
1551  if (curlist != last)
1552  FREE(&last);
1553  last = tmp;
1554 
1555  ps.dptr++; /* move past the ~ */
1556  entry = lookup_tag(*ps.dptr);
1557  if (!entry)
1558  {
1559  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1560  goto cleanup;
1561  }
1562  if (entry->flags && ((flags & entry->flags) == 0))
1563  {
1564  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1565  goto cleanup;
1566  }
1567  pat->op = entry->op;
1568 
1569  ps.dptr++; /* eat the operator and any optional whitespace */
1570  SKIPWS(ps.dptr);
1571 
1572  if (entry->eat_arg)
1573  {
1574  if (ps.dptr[0] == '\0')
1575  {
1576  mutt_buffer_printf(err, "%s", _("missing parameter"));
1577  goto cleanup;
1578  }
1579  if (!entry->eat_arg(pat, flags, &ps, err))
1580  {
1581  goto cleanup;
1582  }
1583  }
1584  implicit = true;
1585  break;
1586  }
1587 
1588  case '(':
1589  {
1590  p = find_matching_paren(ps.dptr + 1);
1591  if (p[0] != ')')
1592  {
1593  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1594  goto cleanup;
1595  }
1596  /* compile the sub-expression */
1597  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1598  tmp = mutt_pattern_comp(buf, flags, err);
1599  FREE(&buf);
1600  if (!tmp)
1601  goto cleanup;
1602  struct Pattern *pat = SLIST_FIRST(tmp);
1603  if (last)
1604  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1605  else
1606  curlist = tmp;
1607  last = tmp;
1608  pat = SLIST_FIRST(tmp);
1609  pat->pat_not ^= pat_not;
1610  pat->all_addr |= all_addr;
1611  pat->is_alias |= is_alias;
1612  pat_not = false;
1613  all_addr = false;
1614  is_alias = false;
1615  ps.dptr = p + 1; /* restore location */
1616  break;
1617  }
1618 
1619  default:
1620  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1621  goto cleanup;
1622  }
1623  }
1624  if (!curlist)
1625  {
1626  mutt_buffer_strcpy(err, _("empty pattern"));
1627  return NULL;
1628  }
1629  if (curlist != tmp)
1630  FREE(&tmp);
1631  if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1632  {
1633  tmp = mutt_pattern_node_new();
1634  struct Pattern *pat = SLIST_FIRST(tmp);
1635  pat->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1636  pat->child = curlist;
1637  curlist = tmp;
1638  }
1639 
1640  return curlist;
1641 
1642 cleanup:
1643  mutt_pattern_free(&curlist);
1644  return NULL;
1645 }
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:62
pattern_eat_t * eat_arg
Callback function to parse the argument.
Definition: pattern.c:180
int flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
Definition: pattern.c:179
bool group_match
Check a group of Addresses.
Definition: pattern.h:55
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: pattern.c:1325
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
Pattern matches a child email.
Definition: pattern.h:110
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
A simple (non-regex) pattern.
Definition: pattern.h:49
bool is_alias
Is there an alias for this Address?
Definition: pattern.h:57
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
Definition: pattern.c:178
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
static const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition: pattern.c:1311
#define SKIPWS(ch)
Definition: string2.h:47
bool string_match
Check a string for a match.
Definition: pattern.h:54
bool pat_not
Pattern should be inverted (not)
Definition: pattern.h:52
static struct PatternList * mutt_pattern_node_new(void)
Create a new list containing a Pattern.
Definition: pattern.c:1383
#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:1399
#define SLIST_FIRST(head)
Definition: queue.h:228
Either pattern can match.
Definition: pattern.h:107
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1347
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
Pattern matches parent.
Definition: pattern.h:109
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Both patterns must match.
Definition: pattern.h:106
#define FREE(x)
Definition: memory.h:40
Pattern matches email thread.
Definition: pattern.h:108
Mapping between user character and internal constant.
Definition: pattern.c:175
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:579
+ 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 1656 of file pattern.c.

1658 {
1659  struct Pattern *p = NULL;
1660 
1661  SLIST_FOREACH(p, pat, entries)
1662  {
1663  if (mutt_pattern_exec(p, flags, m, e, cache) <= 0)
1664  return false;
1665  }
1666  return true;
1667 }
A simple (non-regex) pattern.
Definition: pattern.h:49
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:2008
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 1678 of file pattern.c.

1680 {
1681  struct Pattern *p = NULL;
1682 
1683  SLIST_FOREACH(p, pat, entries)
1684  {
1685  if (mutt_pattern_exec(p, flags, m, e, cache) > 0)
1686  return true;
1687  }
1688  return false;
1689 }
A simple (non-regex) pattern.
Definition: pattern.h:49
int mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:2008
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 1700 of file pattern.c.

1701 {
1702  va_list ap;
1703 
1704  va_start(ap, n);
1705  for (; n; n--)
1706  {
1707  struct AddressList *al = va_arg(ap, struct AddressList *);
1708  struct Address *a = NULL;
1709  TAILQ_FOREACH(a, al, entries)
1710  {
1711  if (pat->all_addr ^ ((!pat->is_alias || mutt_alias_reverse_lookup(a)) &&
1712  ((a->mailbox && patmatch(pat, a->mailbox)) ||
1713  (match_personal && a->personal && patmatch(pat, a->personal)))))
1714  {
1715  va_end(ap);
1716  return !pat->all_addr; /* Found match, or non-match if all_addr */
1717  }
1718  }
1719  }
1720  va_end(ap);
1721  return pat->all_addr; /* No matches, or all matches if all_addr */
1722 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
bool is_alias
Is there an alias for this Address?
Definition: pattern.h:57
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
struct Address * mutt_alias_reverse_lookup(const struct Address *a)
Does the user have an alias for the given address.
Definition: alias.c:541
char * personal
Real name of address.
Definition: address.h:36
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1077
+ 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 1730 of file pattern.c.

1731 {
1732  struct ListNode *np = NULL;
1733  STAILQ_FOREACH(np, refs, entries)
1734  {
1735  if (patmatch(pat, np->data))
1736  return true;
1737  }
1738  return false;
1739 }
#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:1077
+ 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 1751 of file pattern.c.

1752 {
1753  struct AddressList *als[] = { &e->to, &e->cc };
1754  for (size_t i = 0; i < mutt_array_size(als); ++i)
1755  {
1756  struct AddressList *al = als[i];
1757  struct Address *a = NULL;
1758  TAILQ_FOREACH(a, al, entries)
1759  {
1760  if (all_addr ^ p(a))
1761  return !all_addr;
1762  }
1763  }
1764  return all_addr;
1765 }
#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 1774 of file pattern.c.

1775 {
1777 }
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:1751
bool mutt_is_subscribed_list(const struct Address *addr)
Is this the email address of a user-subscribed mailing list?
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 1786 of file pattern.c.

1787 {
1788  return mutt_is_predicate_recipient(all_addr, e, &mutt_is_mail_list);
1789 }
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
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:1751
+ 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 1799 of file pattern.c.

1800 {
1801  struct Address *a = NULL;
1802  if (al1)
1803  {
1804  TAILQ_FOREACH(a, al1, entries)
1805  {
1806  if (all_addr ^ mutt_addr_is_user(a))
1807  return !all_addr;
1808  }
1809  }
1810 
1811  if (al2)
1812  {
1813  TAILQ_FOREACH(a, al2, entries)
1814  {
1815  if (all_addr ^ mutt_addr_is_user(a))
1816  return !all_addr;
1817  }
1818  }
1819  return all_addr;
1820 }
#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:682
+ 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 1835 of file pattern.c.

1838 {
1839  if (!t)
1840  return 0;
1841 
1842  int a;
1843  struct Email *e = t->message;
1844  if (e)
1845  if (mutt_pattern_exec(SLIST_FIRST(pat), flags, m, e, NULL))
1846  return 1;
1847 
1848  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
1849  return a;
1850  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
1851  {
1852  return a;
1853  }
1854  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
1855  {
1856  return a;
1857  }
1858  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
1859  return a;
1860  return 0;
1861 }
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:1835
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:2008
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 1873 of file pattern.c.

1875 {
1876  if (!t || !t->parent || !t->parent->message)
1877  return 0;
1878 
1879  return mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->parent->message, NULL);
1880 }
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:2008
#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 1892 of file pattern.c.

1894 {
1895  if (!t || !t->child)
1896  return 0;
1897 
1898  for (t = t->child; t; t = t->next)
1899  if (t->message && mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->message, NULL))
1900  return 1;
1901 
1902  return 0;
1903 }
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:2008
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 1912 of file pattern.c.

1913 {
1914  if (!b)
1915  return false;
1916 
1917  char buf[256];
1918  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1919 
1920  if (patmatch(pat, buf))
1921  return true;
1922  if (match_content_type(pat, b->parts))
1923  return true;
1924  if (match_content_type(pat, b->next))
1925  return true;
1926  return false;
1927 }
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:1912
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1077
+ 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 1935 of file pattern.c.

1936 {
1937  struct Buffer *err = mutt_buffer_pool_get();
1938 
1939  bool rc = eval_date_minmax(pat, pat->p.str, err);
1941 
1942  return rc;
1943 }
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:582
union Pattern::@2 p
char * str
String, if string_match is set.
Definition: pattern.h:66
+ 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 1953 of file pattern.c.

1955 {
1957  return match_content_type(pat, e->content);
1958 }
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:1912
+ 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 1967 of file pattern.c.

1968 {
1969  *cache_entry = (value != 0) ? 2 : 1;
1970 }
+ 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 1978 of file pattern.c.

1979 {
1980  return cache_entry == 2;
1981 }
+ 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 1988 of file pattern.c.

1989 {
1990  return cache_entry != 0;
1991 }
+ 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 2008 of file pattern.c.

2010 {
2011  switch (pat->op)
2012  {
2013  case MUTT_PAT_AND:
2014  return pat->pat_not ^ (perform_and(pat->child, flags, m, e, cache) > 0);
2015  case MUTT_PAT_OR:
2016  return pat->pat_not ^ (perform_or(pat->child, flags, m, e, cache) > 0);
2017  case MUTT_PAT_THREAD:
2018  return pat->pat_not ^
2019  match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
2020  case MUTT_PAT_PARENT:
2021  return pat->pat_not ^ match_threadparent(pat->child, flags, m, e->thread);
2022  case MUTT_PAT_CHILDREN:
2023  return pat->pat_not ^ match_threadchildren(pat->child, flags, m, e->thread);
2024  case MUTT_ALL:
2025  return !pat->pat_not;
2026  case MUTT_EXPIRED:
2027  return pat->pat_not ^ e->expired;
2028  case MUTT_SUPERSEDED:
2029  return pat->pat_not ^ e->superseded;
2030  case MUTT_FLAG:
2031  return pat->pat_not ^ e->flagged;
2032  case MUTT_TAG:
2033  return pat->pat_not ^ e->tagged;
2034  case MUTT_NEW:
2035  return pat->pat_not ? e->old || e->read : !(e->old || e->read);
2036  case MUTT_UNREAD:
2037  return pat->pat_not ? e->read : !e->read;
2038  case MUTT_REPLIED:
2039  return pat->pat_not ^ e->replied;
2040  case MUTT_OLD:
2041  return pat->pat_not ? (!e->old || e->read) : (e->old && !e->read);
2042  case MUTT_READ:
2043  return pat->pat_not ^ e->read;
2044  case MUTT_DELETED:
2045  return pat->pat_not ^ e->deleted;
2046  case MUTT_PAT_MESSAGE:
2047  return pat->pat_not ^ ((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
2048  case MUTT_PAT_DATE:
2049  if (pat->dynamic)
2051  return pat->pat_not ^ (e->date_sent >= pat->min && e->date_sent <= pat->max);
2053  if (pat->dynamic)
2055  return pat->pat_not ^ (e->received >= pat->min && e->received <= pat->max);
2056  case MUTT_PAT_BODY:
2057  case MUTT_PAT_HEADER:
2058  case MUTT_PAT_WHOLE_MSG:
2059  /* m can be NULL in certain cases, such as when replying to a message
2060  * from the attachment menu and the user has a reply-hook using "~e".
2061  * This is also the case when message scoring. */
2062  if (!m)
2063  return 0;
2064 #ifdef USE_IMAP
2065  /* IMAP search sets e->matched at search compile time */
2066  if ((m->magic == MUTT_IMAP) && pat->string_match)
2067  return e->matched;
2068 #endif
2069  return pat->pat_not ^ msg_search(m, pat, e->msgno);
2070  case MUTT_PAT_SERVERSEARCH:
2071 #ifdef USE_IMAP
2072  if (!m)
2073  return 0;
2074  if (m->magic == MUTT_IMAP)
2075  {
2076  if (pat->string_match)
2077  return e->matched;
2078  return 0;
2079  }
2080  mutt_error(_("error: server custom search only supported with IMAP"));
2081  return 0;
2082 #else
2083  mutt_error(_("error: server custom search only supported with IMAP"));
2084  return -1;
2085 #endif
2086  case MUTT_PAT_SENDER:
2087  if (!e->env)
2088  return 0;
2089  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2090  1, &e->env->sender);
2091  case MUTT_PAT_FROM:
2092  if (!e->env)
2093  return 0;
2094  return pat->pat_not ^
2095  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->from);
2096  case MUTT_PAT_TO:
2097  if (!e->env)
2098  return 0;
2099  return pat->pat_not ^
2100  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->to);
2101  case MUTT_PAT_CC:
2102  if (!e->env)
2103  return 0;
2104  return pat->pat_not ^
2105  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->cc);
2106  case MUTT_PAT_SUBJECT:
2107  if (!e->env)
2108  return 0;
2109  return pat->pat_not ^ (e->env->subject && patmatch(pat, e->env->subject));
2110  case MUTT_PAT_ID:
2111  case MUTT_PAT_ID_EXTERNAL:
2112  if (!e->env)
2113  return 0;
2114  return pat->pat_not ^ (e->env->message_id && patmatch(pat, e->env->message_id));
2115  case MUTT_PAT_SCORE:
2116  return pat->pat_not ^ (e->score >= pat->min &&
2117  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
2118  case MUTT_PAT_SIZE:
2119  return pat->pat_not ^
2120  (e->content->length >= pat->min &&
2121  (pat->max == MUTT_MAXRANGE || e->content->length <= pat->max));
2122  case MUTT_PAT_REFERENCE:
2123  if (!e->env)
2124  return 0;
2125  return pat->pat_not ^ (match_reference(pat, &e->env->references) ||
2126  match_reference(pat, &e->env->in_reply_to));
2127  case MUTT_PAT_ADDRESS:
2128  if (!e->env)
2129  return 0;
2130  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2131  4, &e->env->from, &e->env->sender,
2132  &e->env->to, &e->env->cc);
2133  case MUTT_PAT_RECIPIENT:
2134  if (!e->env)
2135  return 0;
2136  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2137  2, &e->env->to, &e->env->cc);
2138  case MUTT_PAT_LIST: /* known list, subscribed or not */
2139  {
2140  if (!e->env)
2141  return 0;
2142 
2143  int result;
2144  if (cache)
2145  {
2146  int *cache_entry = pat->all_addr ? &cache->list_all : &cache->list_one;
2147  if (!is_pattern_cache_set(*cache_entry))
2148  {
2149  set_pattern_cache_value(cache_entry,
2150  mutt_is_list_recipient(pat->all_addr, e->env));
2151  }
2152  result = get_pattern_cache_value(*cache_entry);
2153  }
2154  else
2155  result = mutt_is_list_recipient(pat->all_addr, e->env);
2156  return pat->pat_not ^ result;
2157  }
2159  {
2160  if (!e->env)
2161  return 0;
2162 
2163  int result;
2164  if (cache)
2165  {
2166  int *cache_entry = pat->all_addr ? &cache->sub_all : &cache->sub_one;
2167  if (!is_pattern_cache_set(*cache_entry))
2168  {
2170  cache_entry, mutt_is_subscribed_list_recipient(pat->all_addr, e->env));
2171  }
2172  result = get_pattern_cache_value(*cache_entry);
2173  }
2174  else
2175  result = mutt_is_subscribed_list_recipient(pat->all_addr, e->env);
2176  return pat->pat_not ^ result;
2177  }
2179  {
2180  if (!e->env)
2181  return 0;
2182 
2183  int result;
2184  if (cache)
2185  {
2186  int *cache_entry = pat->all_addr ? &cache->pers_recip_all : &cache->pers_recip_one;
2187  if (!is_pattern_cache_set(*cache_entry))
2188  {
2190  cache_entry, match_user(pat->all_addr, &e->env->to, &e->env->cc));
2191  }
2192  result = get_pattern_cache_value(*cache_entry);
2193  }
2194  else
2195  result = match_user(pat->all_addr, &e->env->to, &e->env->cc);
2196  return pat->pat_not ^ result;
2197  }
2199  {
2200  if (!e->env)
2201  return 0;
2202 
2203  int result;
2204  if (cache)
2205  {
2206  int *cache_entry = pat->all_addr ? &cache->pers_from_all : &cache->pers_from_one;
2207  if (!is_pattern_cache_set(*cache_entry))
2208  set_pattern_cache_value(cache_entry,
2209  match_user(pat->all_addr, &e->env->from, NULL));
2210  result = get_pattern_cache_value(*cache_entry);
2211  }
2212  else
2213  result = match_user(pat->all_addr, &e->env->from, NULL);
2214  return pat->pat_not ^ result;
2215  }
2216  case MUTT_PAT_COLLAPSED:
2217  return pat->pat_not ^ (e->collapsed && e->num_hidden > 1);
2218  case MUTT_PAT_CRYPT_SIGN:
2219  if (!WithCrypto)
2220  break;
2221  return pat->pat_not ^ ((e->security & SEC_SIGN) ? 1 : 0);
2223  if (!WithCrypto)
2224  break;
2225  return pat->pat_not ^ ((e->security & SEC_GOODSIGN) ? 1 : 0);
2227  if (!WithCrypto)
2228  break;
2229  return pat->pat_not ^ ((e->security & SEC_ENCRYPT) ? 1 : 0);
2230  case MUTT_PAT_PGP_KEY:
2231  if (!(WithCrypto & APPLICATION_PGP))
2232  break;
2233  return pat->pat_not ^ ((e->security & PGP_KEY) == PGP_KEY);
2234  case MUTT_PAT_XLABEL:
2235  if (!e->env)
2236  return 0;
2237  return pat->pat_not ^ (e->env->x_label && patmatch(pat, e->env->x_label));
2238  case MUTT_PAT_DRIVER_TAGS:
2239  {
2240  char *tags = driver_tags_get(&e->tags);
2241  bool rc = (pat->pat_not ^ (tags && patmatch(pat, tags)));
2242  FREE(&tags);
2243  return rc;
2244  }
2245  case MUTT_PAT_HORMEL:
2246  if (!e->env)
2247  return 0;
2248  return pat->pat_not ^ (e->env->spam.data && patmatch(pat, e->env->spam.data));
2249  case MUTT_PAT_DUPLICATED:
2250  return pat->pat_not ^ (e->thread && e->thread->duplicate_thread);
2251  case MUTT_PAT_MIMEATTACH:
2252  if (!m)
2253  return 0;
2254  {
2255  int count = mutt_count_body_parts(m, e);
2256  return pat->pat_not ^ (count >= pat->min &&
2257  (pat->max == MUTT_MAXRANGE || count <= pat->max));
2258  }
2259  case MUTT_PAT_MIMETYPE:
2260  if (!m)
2261  return 0;
2262  return pat->pat_not ^ match_mime_content_type(pat, m, e);
2263  case MUTT_PAT_UNREFERENCED:
2264  return pat->pat_not ^ (e->thread && !e->thread->child);
2265  case MUTT_PAT_BROKEN:
2266  return pat->pat_not ^ (e->thread && e->thread->fake_thread);
2267 #ifdef USE_NNTP
2268  case MUTT_PAT_NEWSGROUPS:
2269  if (!e->env)
2270  return 0;
2271  return pat->pat_not ^ (e->env->newsgroups && patmatch(pat, e->env->newsgroups));
2272 #endif
2273  }
2274  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
2275  return -1;
2276 }
Pattern matches date received.
Definition: pattern.h:117
struct PatternList * child
Arguments to logical operation.
Definition: pattern.h:62
Deleted messages.
Definition: mutt.h:105
Pattern matches email&#39;s header.
Definition: pattern.h:124
Pattern matches MIME type.
Definition: pattern.h:146
Pattern matches &#39;Date:&#39; field.
Definition: pattern.h:116
static bool match_reference(struct Pattern *pat, struct ListHead *refs)
Match references against a Pattern.
Definition: pattern.c:1730
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:1656
Pattern matches newsgroup.
Definition: pattern.h:148
Pattern matches email&#39;s score.
Definition: pattern.h:129
int pers_recip_all
^~p
Definition: pattern.h:91
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:1892
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against and Address list.
Definition: pattern.c:1700
Message is part of a broken thread.
Definition: pattern.h:120
Pattern matches email&#39;s size.
Definition: pattern.h:130
struct Body * content
List of MIME parts.
Definition: email.h:90
Flagged messages.
Definition: mutt.h:106
Pattern matches &#39;From:&#39; field.
Definition: pattern.h:115
#define MUTT_MAXRANGE
Definition: pattern.c:96
Email is from the user.
Definition: pattern.h:136
#define _(a)
Definition: message.h:28
Email is on mailing list.
Definition: pattern.h:133
Pattern matches a child email.
Definition: pattern.h:110
static int match_user(int all_addr, struct AddressList *al1, struct AddressList *al2)
Matches the user&#39;s email Address.
Definition: pattern.c:1799
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
bool expired
Already expired?
Definition: email.h:52
Pattern matches email&#39;s Message-Id.
Definition: pattern.h:121
Messages that have been replied to.
Definition: mutt.h:99
int sub_all
^~u
Definition: pattern.h:89
Pattern matches message number.
Definition: pattern.h:128
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:1835
Email is on subscribed mailing list.
Definition: pattern.h:134
static int is_pattern_cache_set(int cache_entry)
Is a given Pattern cached?
Definition: pattern.c:1988
All messages.
Definition: mutt.h:95
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
bool dynamic
Evaluate date ranges at run time.
Definition: pattern.h:58
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
bool all_addr
All Addresses in the list must match.
Definition: pattern.h:53
bool old
Email is seen, but unread.
Definition: email.h:50
#define SEC_GOODSIGN
Email has a valid signature.
Definition: ncrypt.h:124
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
Duplicate message.
Definition: pattern.h:118
struct Envelope * env
Envelope information.
Definition: email.h:89
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
bool string_match
Check a string for a match.
Definition: pattern.h:54
bool pat_not
Pattern should be inverted (not)
Definition: pattern.h:52
bool superseded
Got superseded?
Definition: email.h:53
int min
Minimum for range checks.
Definition: pattern.h:60
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:98
int pers_from_one
~P
Definition: pattern.h:94
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:143
Pattern matches &#39;Cc:&#39; field.
Definition: pattern.h:112
#define SEC_SIGN
Email is signed.
Definition: ncrypt.h:123
int pers_recip_one
~p
Definition: pattern.h:92
Message is unreferenced in the thread.
Definition: pattern.h:119
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:142
Either pattern can match.
Definition: pattern.h:107
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
#define PGP_KEY
Definition: ncrypt.h:143
Pattern matches email&#39;s spam score.
Definition: pattern.h:125
Superseded messages.
Definition: mutt.h:111
Tagged messages.
Definition: mutt.h:107
Message is encrypted.
Definition: pattern.h:140
char * data
Pointer to data.
Definition: buffer.h:35
Pattern matches &#39;Subject:&#39; field.
Definition: pattern.h:114
int list_all
^~l
Definition: pattern.h:87
New messages.
Definition: mutt.h:97
Messages that have been read.
Definition: mutt.h:100
static int get_pattern_cache_value(int cache_entry)
Get pattern cache value.
Definition: pattern.c:1978
Email is addressed to the user.
Definition: pattern.h:135
Message has PGP key.
Definition: pattern.h:141
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: pattern.h:51
Pattern matches parent.
Definition: pattern.h:109
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:1678
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:39
#define MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition: pattern.h:75
Expired messages.
Definition: mutt.h:110
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
int pers_from_all
^~P
Definition: pattern.h:93
Unread messages.
Definition: mutt.h:101
Pattern matches email&#39;s body.
Definition: pattern.h:123
static bool msg_search(struct Mailbox *m, struct Pattern *pat, int msgno)
Search an email.
Definition: pattern.c:1096
char * subject
Email&#39;s subject.
Definition: envelope.h:66
bool flagged
Marked important?
Definition: email.h:43
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
#define EMSG(e)
Definition: pattern.c:94
Message is signed.
Definition: pattern.h:138
bool deleted
Email is deleted.
Definition: email.h:45
#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:1873
Thread is collapsed.
Definition: pattern.h:113
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: pattern.c:1774
Pattern matches sender.
Definition: pattern.h:127
Both patterns must match.
Definition: pattern.h:106
#define FREE(x)
Definition: memory.h:40
Message is crypographically verified.
Definition: pattern.h:139
int max
Maximum for range checks.
Definition: pattern.h:61
Pattern matches &#39;References:&#39; or &#39;In-Reply-To:&#39; field.
Definition: pattern.h:131
static bool match_update_dynamic_date(struct Pattern *pat)
Update a dynamic date pattern.
Definition: pattern.c:1935
Pattern matches message tags.
Definition: pattern.h:144
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:137
User is a recipient of the email.
Definition: pattern.h:132
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:1953
Pattern matches email thread.
Definition: pattern.h:108
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:111
static void set_pattern_cache_value(int *cache_entry, int value)
Sets a value in the PatternCache cache entry.
Definition: pattern.c:1967
Pattern matches raw email text.
Definition: pattern.h:126
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:52
char * x_label
X-Label.
Definition: envelope.h:72
#define WithCrypto
Definition: ncrypt.h:160
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: pattern.c:1786
Pattern matches number of attachments.
Definition: pattern.h:145
int list_one
~l
Definition: pattern.h:88
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:122
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1077
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:90
+ 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 2283 of file pattern.c.

2284 {
2285  mutt_buffer_reset(buf);
2286  mutt_buffer_addch(buf, '"');
2287  while (*str)
2288  {
2289  if ((*str == '\\') || (*str == '"'))
2290  mutt_buffer_addch(buf, '\\');
2291  mutt_buffer_addch(buf, *str++);
2292  }
2293  mutt_buffer_addch(buf, '"');
2294 }
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 2301 of file pattern.c.

2302 {
2303  bool do_simple = true;
2304 
2305  for (const char *p = mutt_b2s(buf); p && (p[0] != '\0'); p++)
2306  {
2307  if ((p[0] == '\\') && (p[1] != '\0'))
2308  p++;
2309  else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
2310  {
2311  do_simple = false;
2312  break;
2313  }
2314  }
2315 
2316  /* XXX - is mutt_str_strcasecmp() right here, or should we use locale's
2317  * equivalences? */
2318 
2319  if (do_simple) /* yup, so spoof a real request */
2320  {
2321  /* convert old tokens into the new format */
2322  if ((mutt_str_strcasecmp("all", mutt_b2s(buf)) == 0) ||
2323  (mutt_str_strcmp("^", mutt_b2s(buf)) == 0) ||
2324  (mutt_str_strcmp(".", mutt_b2s(buf)) == 0)) /* ~A is more efficient */
2325  {
2326  mutt_buffer_strcpy(buf, "~A");
2327  }
2328  else if (mutt_str_strcasecmp("del", mutt_b2s(buf)) == 0)
2329  mutt_buffer_strcpy(buf, "~D");
2330  else if (mutt_str_strcasecmp("flag", mutt_b2s(buf)) == 0)
2331  mutt_buffer_strcpy(buf, "~F");
2332  else if (mutt_str_strcasecmp("new", mutt_b2s(buf)) == 0)
2333  mutt_buffer_strcpy(buf, "~N");
2334  else if (mutt_str_strcasecmp("old", mutt_b2s(buf)) == 0)
2335  mutt_buffer_strcpy(buf, "~O");
2336  else if (mutt_str_strcasecmp("repl", mutt_b2s(buf)) == 0)
2337  mutt_buffer_strcpy(buf, "~Q");
2338  else if (mutt_str_strcasecmp("read", mutt_b2s(buf)) == 0)
2339  mutt_buffer_strcpy(buf, "~R");
2340  else if (mutt_str_strcasecmp("tag", mutt_b2s(buf)) == 0)
2341  mutt_buffer_strcpy(buf, "~T");
2342  else if (mutt_str_strcasecmp("unread", mutt_b2s(buf)) == 0)
2343  mutt_buffer_strcpy(buf, "~U");
2344  else
2345  {
2346  struct Buffer *tmp = mutt_buffer_pool_get();
2347  quote_simple(mutt_b2s(buf), tmp);
2348  mutt_file_expand_fmt(buf, simple, mutt_b2s(tmp));
2350  }
2351  }
2352 }
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:2283
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:1438
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:628
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
+ 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 2360 of file pattern.c.

2361 {
2362  if (!e)
2363  return NULL;
2364 
2365  struct MuttThread *t = e->thread;
2366 
2367  while (t && t->parent)
2368  t = t->parent;
2369 
2370  return t;
2371 }
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 2379 of file pattern.c.

2380 {
2381  if (!e || !Context || !Context->mailbox)
2382  return false;
2383 
2384  struct MuttThread *me = top_of_thread(e);
2385  if (!me)
2386  return false;
2387 
2388  struct Mailbox *m = Context->mailbox;
2389 
2390  m->vcount = 0;
2391  Context->vsize = 0;
2392  Context->collapsed = false;
2393 
2394  for (int i = 0; i < m->msg_count; i++)
2395  {
2396  e = m->emails[i];
2397  if (!e)
2398  break;
2399 
2400  e->vnum = -1;
2401  e->limited = false;
2402  e->collapsed = false;
2403  e->num_hidden = 0;
2404 
2405  if (top_of_thread(e) == me)
2406  {
2407  struct Body *body = e->content;
2408 
2409  e->vnum = m->vcount;
2410  e->limited = true;
2411  m->v2r[m->vcount] = i;
2412  m->vcount++;
2413  Context->vsize += (body->length + body->offset - body->hdr_offset);
2414  }
2415  }
2416  return true;
2417 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:90
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:101
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:50
bool limited
Is this message in a limited view?
Definition: email.h:74
off_t vsize
Definition: context.h:38
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:80
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition: pattern.c:2360
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:100
bool collapsed
Are all threads collapsed?
Definition: context.h:48
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pattern_func()

int mutt_pattern_func ( int  op,
char *  prompt 
)

Perform some Pattern matching.

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

Definition at line 2426 of file pattern.c.

2427 {
2428  if (!Context || !Context->mailbox)
2429  return -1;
2430 
2431  struct Buffer err;
2432  int rc = -1;
2433  struct Progress progress;
2434  struct Buffer *buf = mutt_buffer_pool_get();
2435  struct Mailbox *m = Context->mailbox;
2436 
2438  if (prompt || (op != MUTT_LIMIT))
2439  {
2440  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR) != 0) ||
2441  mutt_buffer_is_empty(buf))
2442  {
2444  return -1;
2445  }
2446  }
2447 
2448  mutt_message(_("Compiling search pattern..."));
2449 
2450  char *simple = mutt_buffer_strdup(buf);
2452 
2453  mutt_buffer_init(&err);
2454  err.dsize = 256;
2455  err.data = mutt_mem_malloc(err.dsize);
2456  struct PatternList *pat = mutt_pattern_comp(buf->data, MUTT_PC_FULL_MSG, &err);
2457  if (!pat)
2458  {
2459  mutt_error("%s", err.data);
2460  goto bail;
2461  }
2462 
2463 #ifdef USE_IMAP
2464  if ((m->magic == MUTT_IMAP) && (imap_search(m, pat) < 0))
2465  goto bail;
2466 #endif
2467 
2468  mutt_progress_init(&progress, _("Executing command on matching messages..."),
2469  MUTT_PROGRESS_READ, (op == MUTT_LIMIT) ? m->msg_count : m->vcount);
2470 
2471  if (op == MUTT_LIMIT)
2472  {
2473  m->vcount = 0;
2474  Context->vsize = 0;
2475  Context->collapsed = false;
2476  int padding = mx_msg_padding_size(m);
2477 
2478  for (int i = 0; i < m->msg_count; i++)
2479  {
2480  struct Email *e = m->emails[i];
2481  if (!e)
2482  break;
2483 
2484  mutt_progress_update(&progress, i, -1);
2485  /* new limit pattern implicitly uncollapses all threads */
2486  e->vnum = -1;
2487  e->limited = false;
2488  e->collapsed = false;
2489  e->num_hidden = 0;
2490  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2491  {
2492  e->vnum = m->vcount;
2493  e->limited = true;
2494  m->v2r[m->vcount] = i;
2495  m->vcount++;
2496  struct Body *b = e->content;
2497  Context->vsize += b->length + b->offset - b->hdr_offset + padding;
2498  }
2499  }
2500  }
2501  else
2502  {
2503  for (int i = 0; i < m->vcount; i++)
2504  {
2505  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2506  if (!e)
2507  continue;
2508  mutt_progress_update(&progress, i, -1);
2509  if (mutt_pattern_exec(SLIST_FIRST(pat), MUTT_MATCH_FULL_ADDRESS, m, e, NULL))
2510  {
2511  switch (op)
2512  {
2513  case MUTT_UNDELETE:
2514  mutt_set_flag(m, e, MUTT_PURGE, false);
2515  /* fallthrough */
2516  case MUTT_DELETE:
2517  mutt_set_flag(m, e, MUTT_DELETE, (op == MUTT_DELETE));
2518  break;
2519  case MUTT_TAG:
2520  case MUTT_UNTAG:
2521  mutt_set_flag(m, e, MUTT_TAG, (op == MUTT_TAG));
2522  break;
2523  }
2524  }
2525  }
2526  }
2527 
2528  mutt_clear_error();
2529 
2530  if (op == MUTT_LIMIT)
2531  {
2532  /* drop previous limit pattern */
2533  FREE(&Context->pattern);
2535 
2536  if (m->msg_count && !m->vcount)
2537  mutt_error(_("No messages matched criteria"));
2538 
2539  /* record new limit pattern, unless match all */
2540  const char *pbuf = buf->data;
2541  while (*pbuf == ' ')
2542  pbuf++;
2543  if (mutt_str_strcmp(pbuf, "~A") != 0)
2544  {
2545  Context->pattern = simple;
2546  simple = NULL; /* don't clobber it */
2548  }
2549  }
2550 
2551  rc = 0;
2552 
2553 bail:
2555  FREE(&simple);
2556  mutt_pattern_free(&pat);
2557  FREE(&err.data);
2558 
2559  return rc;
2560 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:90
#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:68
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:414
#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:2301
Messages in limited view.
Definition: mutt.h:109
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:1352
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:103
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:104
A progress bar.
Definition: progress.h:49
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:70
int vcount
The number of virtual messages.
Definition: mailbox.h:101
The body of an email.
Definition: body.h:34
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
struct Mailbox * mailbox
Definition: context.h:50
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
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:38
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:2008
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1399
#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:102
A mailbox.
Definition: mailbox.h:80
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:40
Tagged messages.
Definition: mutt.h:107
char * data
Pointer to data.
Definition: buffer.h:35
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1347
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:75
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:85
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: globals.h:140
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:100
bool collapsed
Are all threads collapsed?
Definition: context.h:48
#define mutt_error(...)
Definition: logging.h:84
#define FREE(x)
Definition: memory.h:40
#define MUTT_PC_FULL_MSG
Enable body and header matching.
Definition: pattern.h:43
Messages to be un-tagged.
Definition: mutt.h:108
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1517
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:52
char * pattern
Limit pattern string.
Definition: context.h:39
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:615
+ 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 2569 of file pattern.c.

2570 {
2571  struct Progress progress;
2572 
2573  if (!*LastSearch || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
2574  {
2575  char buf[256];
2576  mutt_str_strfcpy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
2577  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2578  _("Search for: ") :
2579  _("Reverse search for: "),
2580  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0) ||
2581  !buf[0])
2582  {
2583  return -1;
2584  }
2585 
2586  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
2587  OptSearchReverse = false;
2588  else
2589  OptSearchReverse = true;
2590 
2591  /* compare the *expanded* version of the search pattern in case
2592  * $simple_search has changed while we were searching */
2593  struct Buffer *tmp = mutt_buffer_pool_get();
2594  mutt_buffer_strcpy(tmp, buf);
2596 
2597  if (!SearchPattern || (mutt_str_strcmp(mutt_b2s(tmp), LastSearchExpn) != 0))
2598  {
2599  struct Buffer err;
2600  mutt_buffer_init(&err);
2601  OptSearchInvalid = true;
2602  mutt_str_strfcpy(LastSearch, buf, sizeof(LastSearch));
2604  mutt_message(_("Compiling search pattern..."));
2606  err.dsize = 256;
2607  err.data = mutt_mem_malloc(err.dsize);
2609  if (!SearchPattern)
2610  {
2612  mutt_error("%s", err.data);
2613  FREE(&err.data);
2614  LastSearch[0] = '\0';
2615  LastSearchExpn[0] = '\0';
2616  return -1;
2617  }
2618  FREE(&err.data);
2619  mutt_clear_error();
2620  }
2621 
2623  }
2624 
2625  if (OptSearchInvalid)
2626  {
2627  for (int i = 0; i < Context->mailbox->msg_count; i++)
2628  Context->mailbox->emails[i]->searched = false;
2629 #ifdef USE_IMAP
2630  if ((Context->mailbox->magic == MUTT_IMAP) &&
2632  return -1;
2633 #endif
2634  OptSearchInvalid = false;
2635  }
2636 
2637  int incr = OptSearchReverse ? -1 : 1;
2638  if (op == OP_SEARCH_OPPOSITE)
2639  incr = -incr;
2640 
2641  mutt_progress_init(&progress, _("Searching..."), MUTT_PROGRESS_READ,
2642  Context->mailbox->vcount);
2643 
2644  for (int i = cur + incr, j = 0; j != Context->mailbox->vcount; j++)
2645  {
2646  const char *msg = NULL;
2647  mutt_progress_update(&progress, j, -1);
2648  if (i > Context->mailbox->vcount - 1)
2649  {
2650  i = 0;
2651  if (C_WrapSearch)
2652  msg = _("Search wrapped to top");
2653  else
2654  {
2655  mutt_message(_("Search hit bottom without finding match"));
2656  return -1;
2657  }
2658  }
2659  else if (i < 0)
2660  {
2661  i = Context->mailbox->vcount - 1;
2662  if (C_WrapSearch)
2663  msg = _("Search wrapped to bottom");
2664  else
2665  {
2666  mutt_message(_("Search hit top without finding match"));
2667  return -1;
2668  }
2669  }
2670 
2671  struct Email *e = mutt_get_virt_email(Context->mailbox, i);
2672  if (e->searched)
2673  {
2674  /* if we've already evaluated this message, use the cached value */
2675  if (e->matched)
2676  {
2677  mutt_clear_error();
2678  if (msg && *msg)
2679  mutt_message(msg);
2680  return i;
2681  }
2682  }
2683  else
2684  {
2685  /* remember that we've already searched this message */
2686  e->searched = true;
2688  Context->mailbox, e, NULL);
2689  if (e->matched > 0)
2690  {
2691  mutt_clear_error();
2692  if (msg && *msg)
2693  mutt_message(msg);
2694  return i;
2695  }
2696  }
2697 
2698  if (SigInt)
2699  {
2700  mutt_error(_("Search interrupted"));
2701  SigInt = 0;
2702  return -1;
2703  }
2704 
2705  i += incr;
2706  }
2707 
2708  mutt_error(_("Not found"));
2709  return -1;
2710 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:98
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:90
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:68
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:414
#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:2301
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:1352
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
static char LastSearch[256]
last pattern searched for
Definition: pattern.c:199
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: globals.h:261
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:70
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:92
int vcount
The number of virtual messages.
Definition: mailbox.h:101
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:212
struct Mailbox * mailbox
Definition: context.h:50
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
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:2008
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1399
static char LastSearchExpn[1024]
expanded version of LastSearch
Definition: pattern.c:200
#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:750
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1347
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pattern
Definition: options.h:50
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:75
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:140
static struct PatternList * SearchPattern
current search pattern
Definition: pattern.c:198
#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:52
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
WHERE bool OptSearchReverse
(pseudo) used by ci_search_command
Definition: options.h:51
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 72 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:147
#define RANGE_REL_RX
Definition: pattern.c:78
#define RANGE_ABS_RX
Definition: pattern.c:82
Greater-than range.
Definition: pattern.c:146
#define RANGE_LT_RX
Definition: pattern.c:85
#define RANGE_BARE_RX
Definition: pattern.c:89
Absolute range.
Definition: pattern.c:144
#define RANGE_GT_RX
Definition: pattern.c:86
Less-than range.
Definition: pattern.c:145
Relative range.
Definition: pattern.c:143

Set of Regexes for various range types.

This array, will also contain the compiled regexes.

Definition at line 189 of file pattern.c.

◆ SearchPattern

struct PatternList* SearchPattern = NULL
static

current search pattern

Definition at line 198 of file pattern.c.

◆ LastSearch

char LastSearch[256] = { 0 }
static

last pattern searched for

Definition at line 199 of file pattern.c.

◆ LastSearchExpn

char LastSearchExpn[1024] = { 0 }
static

expanded version of LastSearch

Definition at line 200 of file pattern.c.

◆ Flags

const struct PatternFlags Flags[]
static

Lookup table for all patterns.

Definition at line 1251 of file pattern.c.