NeoMutt  2019-11-11
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 <sys/stat.h>
#include <time.h>
#include "mutt/mutt.h"
#include "address/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "pattern.h"
#include "alias.h"
#include "context.h"
#include "copy.h"
#include "curs_lib.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 "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 CTX_MSGNO(ctx)   (EMSG((ctx)->mailbox->emails[(ctx)->mailbox->v2r[(ctx)->menu->current]]))
 
#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 74 of file pattern.c.

◆ RANGE_REL_SLOT_RX

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

Definition at line 75 of file pattern.c.

◆ RANGE_REL_RX

#define RANGE_REL_RX   "^" RANGE_REL_SLOT_RX "," RANGE_REL_SLOT_RX

Definition at line 76 of file pattern.c.

◆ RANGE_ABS_SLOT_RX

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

Definition at line 79 of file pattern.c.

◆ RANGE_ABS_RX

#define RANGE_ABS_RX   "^" RANGE_ABS_SLOT_RX "-" RANGE_ABS_SLOT_RX

Definition at line 80 of file pattern.c.

◆ RANGE_LT_RX

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

Definition at line 83 of file pattern.c.

◆ RANGE_GT_RX

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

Definition at line 84 of file pattern.c.

◆ RANGE_BARE_RX

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

Definition at line 87 of file pattern.c.

◆ RANGE_RX_GROUPS

#define RANGE_RX_GROUPS   5

Definition at line 88 of file pattern.c.

◆ KILO

#define KILO   1024

Definition at line 90 of file pattern.c.

◆ MEGA

#define MEGA   1048576

Definition at line 91 of file pattern.c.

◆ EMSG

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

Definition at line 92 of file pattern.c.

◆ CTX_MSGNO

#define CTX_MSGNO (   ctx)    (EMSG((ctx)->mailbox->emails[(ctx)->mailbox->v2r[(ctx)->menu->current]]))

Definition at line 93 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:2655
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:210
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:194
#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:57
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:2655
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:112
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:221
#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:290
+ 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:736
#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:36
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:736
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:36
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:224
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:57
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  return num + CTX_MSGNO(Context);
866  case RANGE_K_LT:
867  return num - 1;
868  case RANGE_K_GT:
869  return num + 1;
870  default:
871  return num;
872  }
873 }
The "current" mailbox.
Definition: context.h:36
#define MEGA
Definition: pattern.c:91
#define KILO
Definition: pattern.c:90
Greater-than range.
Definition: pattern.c:146
char * dptr
Current read/write position.
Definition: buffer.h:36
#define CTX_MSGNO(ctx)
Definition: pattern.c:93
Less-than range.
Definition: pattern.c:145
Relative range.
Definition: pattern.c:143
+ 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 884 of file pattern.c.

885 {
886  /* This means the left or right subpattern was empty, e.g. ",." */
887  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
888  {
889  if (side == RANGE_S_LEFT)
890  return 1;
891  if (side == RANGE_S_RIGHT)
892  return Context->mailbox->msg_count;
893  }
894  /* We have something, so determine what */
895  unsigned char c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
896  switch (c)
897  {
898  case RANGE_CIRCUM:
899  return 1;
900  case RANGE_DOLLAR:
901  return Context->mailbox->msg_count;
902  case RANGE_DOT:
903  return CTX_MSGNO(Context);
904  case RANGE_LT:
905  case RANGE_GT:
906  return scan_range_num(s, pmatch, grp + 1, kind);
907  default:
908  /* Only other possibility: a number */
909  return scan_range_num(s, pmatch, grp, kind);
910  }
911 }
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:102
#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
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 CTX_MSGNO(ctx)
Definition: pattern.c:93
#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 917 of file pattern.c.

918 {
919  if (pat->min <= pat->max)
920  return;
921  int num = pat->min;
922  pat->min = pat->max;
923  pat->max = num;
924 }
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 934 of file pattern.c.

936 {
937  int regerr;
938  regmatch_t pmatch[RANGE_RX_GROUPS];
939  struct RangeRegex *pspec = &range_regexes[kind];
940 
941  /* First time through, compile the big regex */
942  if (!pspec->ready)
943  {
944  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
945  if (regerr != 0)
946  return report_regerror(regerr, &pspec->cooked, err);
947  pspec->ready = true;
948  }
949 
950  /* Match the pattern buffer against the compiled regex.
951  * No match means syntax error. */
952  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
953  if (regerr != 0)
954  return report_regerror(regerr, &pspec->cooked, err);
955 
956  if (!is_context_available(s, pmatch, kind, err))
957  return RANGE_E_CTX;
958 
959  /* Snarf the contents of the two sides of the range. */
960  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind);
961  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind);
962  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
963 
964  /* Special case for a bare 0. */
965  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
966  {
967  if (!Context->menu)
968  {
969  mutt_buffer_strcpy(err, _("No current message"));
970  return RANGE_E_CTX;
971  }
972  pat->max = CTX_MSGNO(Context);
973  pat->min = pat->max;
974  }
975 
976  /* Since we don't enforce order, we must swap bounds if they're backward */
977  order_range(pat);
978 
979  /* Slide pointer past the entire match. */
980  s->dptr += pmatch[0].rm_eo;
981  return RANGE_E_OK;
982 }
The "current" mailbox.
Definition: context.h:36
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 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:88
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:56
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: pattern.c:917
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:884
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 rgrp
Paren group matching the right side.
Definition: pattern.c:133
#define CTX_MSGNO(ctx)
Definition: pattern.c:93
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 987 of file pattern.c.

989 {
990  bool skip_quote = false;
991 
992  /* We need a Context for pretty much anything. */
993  if (!Context)
994  {
995  mutt_buffer_strcpy(err, _("No Context"));
996  return false;
997  }
998 
999  /* If simple_search is set to "~m %s", the range will have double quotes
1000  * around it... */
1001  if (*s->dptr == '"')
1002  {
1003  s->dptr++;
1004  skip_quote = true;
1005  }
1006 
1007  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
1008  {
1009  switch (eat_range_by_regex(pat, s, i_kind, err))
1010  {
1011  case RANGE_E_CTX:
1012  /* This means it matched syntactically but lacked context.
1013  * No point in continuing. */
1014  break;
1015  case RANGE_E_SYNTAX:
1016  /* Try another syntax, then */
1017  continue;
1018  case RANGE_E_OK:
1019  if (skip_quote && (*s->dptr == '"'))
1020  s->dptr++;
1021  SKIPWS(s->dptr);
1022  return true;
1023  }
1024  }
1025  return false;
1026 }
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:934
+ 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 1031 of file pattern.c.

1032 {
1033  struct Buffer *tmp = mutt_buffer_pool_get();
1034  bool rc = false;
1035 
1036  char *pexpr = s->dptr;
1038  {
1039  snprintf(err->data, err->dsize, _("Error in expression: %s"), pexpr);
1040  goto out;
1041  }
1042 
1043  if (mutt_buffer_is_empty(tmp))
1044  {
1045  snprintf(err->data, err->dsize, "%s", _("Empty expression"));
1046  goto out;
1047  }
1048 
1049  if (flags & MUTT_PC_PATTERN_DYNAMIC)
1050  {
1051  pat->dynamic = true;
1052  pat->p.str = mutt_str_strdup(tmp->data);
1053  }
1054 
1055  rc = eval_date_minmax(pat, tmp->data, err);
1056 
1057 out:
1059 
1060  return rc;
1061 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
#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:2655
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 1070 of file pattern.c.

1071 {
1072  if (pat->is_multi)
1073  return (mutt_list_find(&pat->p.multi_cases, buf) != NULL);
1074  if (pat->string_match)
1075  return pat->ign_case ? strcasestr(buf, pat->p.str) : strstr(buf, pat->p.str);
1076  if (pat->group_match)
1077  return mutt_group_match(pat->p.group, buf);
1078  return (regexec(pat->p.regex, buf, 0, NULL, 0) == 0);
1079 }
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 1089 of file pattern.c.

1090 {
1091  bool match = false;
1092  struct Message *msg = mx_msg_open(m, msgno);
1093  if (!msg)
1094  {
1095  return match;
1096  }
1097 
1098  FILE *fp = NULL;
1099  long lng = 0;
1100  struct Email *e = m->emails[msgno];
1101 #ifdef USE_FMEMOPEN
1102  char *temp = NULL;
1103  size_t tempsize;
1104 #else
1105  struct stat st;
1106 #endif
1107 
1108  if (C_ThoroughSearch)
1109  {
1110  /* decode the header / body */
1111  struct State s = { 0 };
1112  s.fp_in = msg->fp;
1113  s.flags = MUTT_CHARCONV;
1114 #ifdef USE_FMEMOPEN
1115  s.fp_out = open_memstream(&temp, &tempsize);
1116  if (!s.fp_out)
1117  {
1118  mutt_perror(_("Error opening 'memory stream'"));
1119  return false;
1120  }
1121 #else
1122  s.fp_out = mutt_file_mkstemp();
1123  if (!s.fp_out)
1124  {
1125  mutt_perror(_("Can't create temporary file"));
1126  return false;
1127  }
1128 #endif
1129 
1130  if (pat->op != MUTT_PAT_BODY)
1131  mutt_copy_header(msg->fp, e, s.fp_out, CH_FROM | CH_DECODE, NULL, 0);
1132 
1133  if (pat->op != MUTT_PAT_HEADER)
1134  {
1136 
1137  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) &&
1139  {
1140  mx_msg_close(m, &msg);
1141  if (s.fp_out)
1142  {
1144 #ifdef USE_FMEMOPEN
1145  FREE(&temp);
1146 #endif
1147  }
1148  return false;
1149  }
1150 
1151  fseeko(msg->fp, e->offset, SEEK_SET);
1152  mutt_body_handler(e->content, &s);
1153  }
1154 
1155 #ifdef USE_FMEMOPEN
1156  fclose(s.fp_out);
1157  lng = tempsize;
1158 
1159  if (tempsize)
1160  {
1161  fp = fmemopen(temp, tempsize, "r");
1162  if (!fp)
1163  {
1164  mutt_perror(_("Error re-opening 'memory stream'"));
1165  return false;
1166  }
1167  }
1168  else
1169  { /* fmemopen can't handle empty buffers */
1170  fp = mutt_file_fopen("/dev/null", "r");
1171  if (!fp)
1172  {
1173  mutt_perror(_("Error opening /dev/null"));
1174  return false;
1175  }
1176  }
1177 #else
1178  fp = s.fp_out;
1179  fflush(fp);
1180  fseek(fp, 0, SEEK_SET);
1181  fstat(fileno(fp), &st);
1182  lng = (long) st.st_size;
1183 #endif
1184  }
1185  else
1186  {
1187  /* raw header / body */
1188  fp = msg->fp;
1189  if (pat->op != MUTT_PAT_BODY)
1190  {
1191  fseeko(fp, e->offset, SEEK_SET);
1192  lng = e->content->offset - e->offset;
1193  }
1194  if (pat->op != MUTT_PAT_HEADER)
1195  {
1196  if (pat->op == MUTT_PAT_BODY)
1197  fseeko(fp, e->content->offset, SEEK_SET);
1198  lng += e->content->length;
1199  }
1200  }
1201 
1202  size_t blen = 256;
1203  char *buf = mutt_mem_malloc(blen);
1204 
1205  /* search the file "fp" */
1206  while (lng > 0)
1207  {
1208  if (pat->op == MUTT_PAT_HEADER)
1209  {
1210  buf = mutt_rfc822_read_line(fp, buf, &blen);
1211  if (*buf == '\0')
1212  break;
1213  }
1214  else if (!fgets(buf, blen - 1, fp))
1215  break; /* don't loop forever */
1216  if (patmatch(pat, buf))
1217  {
1218  match = true;
1219  break;
1220  }
1221  lng -= mutt_str_strlen(buf);
1222  }
1223 
1224  FREE(&buf);
1225 
1226  mx_msg_close(m, &msg);
1227 
1228  if (C_ThoroughSearch)
1229  {
1230  mutt_file_fclose(&fp);
1231 #ifdef USE_FMEMOPEN
1232  if (tempsize)
1233  FREE(&temp);
1234 #endif
1235  }
1236 
1237  return match;
1238 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
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:1101
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:147
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:70
#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:1053
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1070
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:1060
+ 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 1304 of file pattern.c.

1305 {
1306  for (int i = 0; Flags[i].tag; i++)
1307  if (Flags[i].tag == tag)
1308  return &Flags[i];
1309  return NULL;
1310 }
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:1244
+ 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 1318 of file pattern.c.

1319 {
1320  int level = 1;
1321 
1322  for (; *s; s++)
1323  {
1324  if (*s == '(')
1325  level++;
1326  else if (*s == ')')
1327  {
1328  level--;
1329  if (level == 0)
1330  break;
1331  }
1332  }
1333  return s;
1334 }
+ 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 1340 of file pattern.c.

1341 {
1342  if (!pat || !*pat)
1343  return;
1344 
1345  struct Pattern *np = SLIST_FIRST(*pat), *next = NULL;
1346 
1347  while (np)
1348  {
1349  next = SLIST_NEXT(np, entries);
1350 
1351  if (np->is_multi)
1353  else if (np->string_match || np->dynamic)
1354  FREE(&np->p.str);
1355  else if (np->group_match)
1356  np->p.group = NULL;
1357  else if (np->p.regex)
1358  {
1359  regfree(np->p.regex);
1360  FREE(&np->p.regex);
1361  }
1362 
1363  mutt_pattern_free(&np->child);
1364  FREE(&np);
1365 
1366  np = next;
1367  }
1368 
1369  FREE(pat);
1370 }
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:270
#define SLIST_FIRST(head)
Definition: queue.h:229
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1340
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 1376 of file pattern.c.

1377 {
1378  struct PatternList *h = mutt_mem_calloc(1, sizeof(struct PatternList));
1379  SLIST_INIT(h);
1380  struct Pattern *p = mutt_mem_calloc(1, sizeof(struct Pattern));
1381  SLIST_INSERT_HEAD(h, p, entries);
1382  return h;
1383 }
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:256
A simple (non-regex) pattern.
Definition: pattern.h:49
union Pattern::@2 p
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:265
+ 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 1392 of file pattern.c.

1393 {
1394  /* curlist when assigned will always point to a list containing at least one node
1395  * with a Pattern value. */
1396  struct PatternList *curlist = NULL;
1397  struct PatternList *tmp = NULL, *tmp2 = NULL;
1398  struct PatternList *last = NULL;
1399  bool pat_not = false;
1400  bool all_addr = false;
1401  bool pat_or = false;
1402  bool implicit = true; /* used to detect logical AND operator */
1403  bool is_alias = false;
1404  short thread_op;
1405  const struct PatternFlags *entry = NULL;
1406  char *p = NULL;
1407  char *buf = NULL;
1408  struct Buffer ps;
1409 
1410  mutt_buffer_init(&ps);
1411  ps.dptr = (char *) s;
1412  ps.dsize = mutt_str_strlen(s);
1413 
1414  while (*ps.dptr)
1415  {
1416  SKIPWS(ps.dptr);
1417  switch (*ps.dptr)
1418  {
1419  case '^':
1420  ps.dptr++;
1421  all_addr = !all_addr;
1422  break;
1423  case '!':
1424  ps.dptr++;
1425  pat_not = !pat_not;
1426  break;
1427  case '@':
1428  ps.dptr++;
1429  is_alias = !is_alias;
1430  break;
1431  case '|':
1432  if (!pat_or)
1433  {
1434  if (!curlist)
1435  {
1436  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1437  return NULL;
1438  }
1439 
1440  struct Pattern *pat = SLIST_FIRST(curlist);
1441 
1442  if (SLIST_NEXT(pat, entries))
1443  {
1444  /* A & B | C == (A & B) | C */
1445  tmp = mutt_pattern_node_new();
1446  pat = SLIST_FIRST(tmp);
1447  pat->op = MUTT_PAT_AND;
1448  pat->child = curlist;
1449 
1450  curlist = tmp;
1451  last = curlist;
1452  }
1453 
1454  pat_or = true;
1455  }
1456  ps.dptr++;
1457  implicit = false;
1458  pat_not = false;
1459  all_addr = false;
1460  is_alias = false;
1461  break;
1462  case '%':
1463  case '=':
1464  case '~':
1465  {
1466  struct Pattern *pat = NULL;
1467  if (ps.dptr[1] == '\0')
1468  {
1469  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1470  goto cleanup;
1471  }
1472  thread_op = 0;
1473  if (ps.dptr[1] == '(')
1474  thread_op = MUTT_PAT_THREAD;
1475  else if ((ps.dptr[1] == '<') && (ps.dptr[2] == '('))
1476  thread_op = MUTT_PAT_PARENT;
1477  else if ((ps.dptr[1] == '>') && (ps.dptr[2] == '('))
1478  thread_op = MUTT_PAT_CHILDREN;
1479  if (thread_op)
1480  {
1481  ps.dptr++; /* skip ~ */
1482  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1483  ps.dptr++;
1484  p = find_matching_paren(ps.dptr + 1);
1485  if (p[0] != ')')
1486  {
1487  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1488  goto cleanup;
1489  }
1490  tmp = mutt_pattern_node_new();
1491  pat = SLIST_FIRST(tmp);
1492  pat->op = thread_op;
1493  if (last)
1494  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1495  else
1496  curlist = tmp;
1497  last = tmp;
1498  pat->pat_not ^= pat_not;
1499  pat->all_addr |= all_addr;
1500  pat->is_alias |= is_alias;
1501  pat_not = false;
1502  all_addr = false;
1503  is_alias = false;
1504  /* compile the sub-expression */
1505  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1506  tmp2 = mutt_pattern_comp(buf, flags, err);
1507  if (!tmp2)
1508  {
1509  FREE(&buf);
1510  goto cleanup;
1511  }
1512  FREE(&buf);
1513  pat->child = tmp2;
1514  ps.dptr = p + 1; /* restore location */
1515  break;
1516  }
1517  if (implicit && pat_or)
1518  {
1519  /* A | B & C == (A | B) & C */
1520  tmp = mutt_pattern_node_new();
1521  pat = SLIST_FIRST(tmp);
1522  pat->op = MUTT_PAT_OR;
1523  pat->child = curlist;
1524  curlist = tmp;
1525  last = tmp;
1526  pat_or = false;
1527  }
1528 
1529  tmp = mutt_pattern_node_new();
1530  pat = SLIST_FIRST(tmp);
1531  pat->pat_not = pat_not;
1532  pat->all_addr = all_addr;
1533  pat->is_alias = is_alias;
1534  pat->string_match = (ps.dptr[0] == '=');
1535  pat->group_match = (ps.dptr[0] == '%');
1536  pat_not = false;
1537  all_addr = false;
1538  is_alias = false;
1539 
1540  if (last)
1541  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1542  else
1543  curlist = tmp;
1544  if (curlist != last)
1545  FREE(&last);
1546  last = tmp;
1547 
1548  ps.dptr++; /* move past the ~ */
1549  entry = lookup_tag(*ps.dptr);
1550  if (!entry)
1551  {
1552  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1553  goto cleanup;
1554  }
1555  if (entry->flags && ((flags & entry->flags) == 0))
1556  {
1557  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1558  goto cleanup;
1559  }
1560  pat->op = entry->op;
1561 
1562  ps.dptr++; /* eat the operator and any optional whitespace */
1563  SKIPWS(ps.dptr);
1564 
1565  if (entry->eat_arg)
1566  {
1567  if (ps.dptr[0] == '\0')
1568  {
1569  mutt_buffer_printf(err, "%s", _("missing parameter"));
1570  goto cleanup;
1571  }
1572  if (!entry->eat_arg(pat, flags, &ps, err))
1573  {
1574  goto cleanup;
1575  }
1576  }
1577  implicit = true;
1578  break;
1579  }
1580 
1581  case '(':
1582  {
1583  p = find_matching_paren(ps.dptr + 1);
1584  if (p[0] != ')')
1585  {
1586  mutt_buffer_printf(err, _("mismatched parentheses: %s"), ps.dptr);
1587  goto cleanup;
1588  }
1589  /* compile the sub-expression */
1590  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1591  tmp = mutt_pattern_comp(buf, flags, err);
1592  FREE(&buf);
1593  if (!tmp)
1594  goto cleanup;
1595  struct Pattern *pat = SLIST_FIRST(tmp);
1596  if (last)
1597  SLIST_NEXT(SLIST_FIRST(last), entries) = pat;
1598  else
1599  curlist = tmp;
1600  last = tmp;
1601  pat = SLIST_FIRST(tmp);
1602  pat->pat_not ^= pat_not;
1603  pat->all_addr |= all_addr;
1604  pat->is_alias |= is_alias;
1605  pat_not = false;
1606  all_addr = false;
1607  is_alias = false;
1608  ps.dptr = p + 1; /* restore location */
1609  break;
1610  }
1611 
1612  default:
1613  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1614  goto cleanup;
1615  }
1616  }
1617  if (!curlist)
1618  {
1619  mutt_buffer_strcpy(err, _("empty pattern"));
1620  return NULL;
1621  }
1622  if (curlist != tmp)
1623  FREE(&tmp);
1624  if (SLIST_NEXT(SLIST_FIRST(curlist), entries))
1625  {
1626  tmp = mutt_pattern_node_new();
1627  struct Pattern *pat = SLIST_FIRST(tmp);
1628  pat->op = pat_or ? MUTT_PAT_OR : MUTT_PAT_AND;
1629  pat->child = curlist;
1630  curlist = tmp;
1631  }
1632 
1633  return curlist;
1634 
1635 cleanup:
1636  mutt_pattern_free(&curlist);
1637  return NULL;
1638 }
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:1318
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:1304
#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:1376
#define SLIST_NEXT(elm, field)
Definition: queue.h:270
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1392
#define SLIST_FIRST(head)
Definition: queue.h:229
Either pattern can match.
Definition: pattern.h:107
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1340
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 1649 of file pattern.c.

1651 {
1652  struct Pattern *p = NULL;
1653 
1654  SLIST_FOREACH(p, pat, entries)
1655  {
1656  if (mutt_pattern_exec(p, flags, m, e, cache) <= 0)
1657  return false;
1658  }
1659  return true;
1660 }
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:2001
union Pattern::@2 p
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:231
+ 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 1671 of file pattern.c.

1673 {
1674  struct Pattern *p = NULL;
1675 
1676  SLIST_FOREACH(p, pat, entries)
1677  {
1678  if (mutt_pattern_exec(p, flags, m, e, cache) > 0)
1679  return true;
1680  }
1681  return false;
1682 }
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:2001
union Pattern::@2 p
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:231
+ 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 1693 of file pattern.c.

1694 {
1695  va_list ap;
1696 
1697  va_start(ap, n);
1698  for (; n; n--)
1699  {
1700  struct AddressList *al = va_arg(ap, struct AddressList *);
1701  struct Address *a = NULL;
1702  TAILQ_FOREACH(a, al, entries)
1703  {
1704  if (pat->all_addr ^ ((!pat->is_alias || mutt_alias_reverse_lookup(a)) &&
1705  ((a->mailbox && patmatch(pat, a->mailbox)) ||
1706  (match_personal && a->personal && patmatch(pat, a->personal)))))
1707  {
1708  va_end(ap);
1709  return !pat->all_addr; /* Found match, or non-match if all_addr */
1710  }
1711  }
1712  }
1713  va_end(ap);
1714  return pat->all_addr; /* No matches, or all matches if all_addr */
1715 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:1070
+ 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 1723 of file pattern.c.

1724 {
1725  struct ListNode *np = NULL;
1726  STAILQ_FOREACH(np, refs, entries)
1727  {
1728  if (patmatch(pat, np->data))
1729  return true;
1730  }
1731  return false;
1732 }
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
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:1070
+ 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 1744 of file pattern.c.

1745 {
1746  struct AddressList *als[] = { &e->to, &e->cc };
1747  for (size_t i = 0; i < mutt_array_size(als); ++i)
1748  {
1749  struct AddressList *al = als[i];
1750  struct Address *a = NULL;
1751  TAILQ_FOREACH(a, al, entries)
1752  {
1753  if (all_addr ^ p(a))
1754  return !all_addr;
1755  }
1756  }
1757  return all_addr;
1758 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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 1767 of file pattern.c.

1768 {
1770 }
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:1744
bool mutt_is_subscribed_list(const struct Address *addr)
Is this the email address of a user-subscribed mailing list?
Definition: hdrline.c:128
+ 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 1779 of file pattern.c.

1780 {
1781  return mutt_is_predicate_recipient(all_addr, e, &mutt_is_mail_list);
1782 }
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
Definition: hdrline.c:116
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:1744
+ 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 1792 of file pattern.c.

1793 {
1794  struct Address *a = NULL;
1795  if (al1)
1796  {
1797  TAILQ_FOREACH(a, al1, entries)
1798  {
1799  if (all_addr ^ mutt_addr_is_user(a))
1800  return !all_addr;
1801  }
1802  }
1803 
1804  if (al2)
1805  {
1806  TAILQ_FOREACH(a, al2, entries)
1807  {
1808  if (all_addr ^ mutt_addr_is_user(a))
1809  return !all_addr;
1810  }
1811  }
1812  return all_addr;
1813 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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 1828 of file pattern.c.

1831 {
1832  if (!t)
1833  return 0;
1834 
1835  int a;
1836  struct Email *e = t->message;
1837  if (e)
1838  if (mutt_pattern_exec(SLIST_FIRST(pat), flags, m, e, NULL))
1839  return 1;
1840 
1841  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
1842  return a;
1843  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
1844  {
1845  return a;
1846  }
1847  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
1848  {
1849  return a;
1850  }
1851  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
1852  return a;
1853  return 0;
1854 }
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:1828
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:2001
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define SLIST_FIRST(head)
Definition: queue.h:229
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 1866 of file pattern.c.

1868 {
1869  if (!t || !t->parent || !t->parent->message)
1870  return 0;
1871 
1872  return mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->parent->message, NULL);
1873 }
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:2001
#define SLIST_FIRST(head)
Definition: queue.h:229
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 1885 of file pattern.c.

1887 {
1888  if (!t || !t->child)
1889  return 0;
1890 
1891  for (t = t->child; t; t = t->next)
1892  if (t->message && mutt_pattern_exec(SLIST_FIRST(pat), flags, m, t->message, NULL))
1893  return 1;
1894 
1895  return 0;
1896 }
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:2001
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
#define SLIST_FIRST(head)
Definition: queue.h:229
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 1905 of file pattern.c.

1906 {
1907  if (!b)
1908  return false;
1909 
1910  char buf[256];
1911  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1912 
1913  if (patmatch(pat, buf))
1914  return true;
1915  if (match_content_type(pat, b->parts))
1916  return true;
1917  if (match_content_type(pat, b->next))
1918  return true;
1919  return false;
1920 }
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:1905
static bool patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1070
+ 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 1928 of file pattern.c.

1929 {
1930  struct Buffer *err = mutt_buffer_pool_get();
1931 
1932  bool rc = eval_date_minmax(pat, pat->p.str, err);
1934 
1935  return rc;
1936 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
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 1946 of file pattern.c.

1948 {
1950  return match_content_type(pat, e->content);
1951 }
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:1905
+ 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 1960 of file pattern.c.

1961 {
1962  *cache_entry = (value != 0) ? 2 : 1;
1963 }
+ 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 1971 of file pattern.c.

1972 {
1973  return cache_entry == 2;
1974 }
+ 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 1981 of file pattern.c.

1982 {
1983  return cache_entry != 0;
1984 }
+ 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 2001 of file pattern.c.

2003 {
2004  switch (pat->op)
2005  {
2006  case MUTT_PAT_AND:
2007  return pat->pat_not ^ (perform_and(pat->child, flags, m, e, cache) > 0);
2008  case MUTT_PAT_OR:
2009  return pat->pat_not ^ (perform_or(pat->child, flags, m, e, cache) > 0);
2010  case MUTT_PAT_THREAD:
2011  return pat->pat_not ^
2012  match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
2013  case MUTT_PAT_PARENT:
2014  return pat->pat_not ^ match_threadparent(pat->child, flags, m, e->thread);
2015  case MUTT_PAT_CHILDREN:
2016  return pat->pat_not ^ match_threadchildren(pat->child, flags, m, e->thread);
2017  case MUTT_ALL:
2018  return !pat->pat_not;
2019  case MUTT_EXPIRED:
2020  return pat->pat_not ^ e->expired;
2021  case MUTT_SUPERSEDED:
2022  return pat->pat_not ^ e->superseded;
2023  case MUTT_FLAG:
2024  return pat->pat_not ^ e->flagged;
2025  case MUTT_TAG:
2026  return pat->pat_not ^ e->tagged;
2027  case MUTT_NEW:
2028  return pat->pat_not ? e->old || e->read : !(e->old || e->read);
2029  case MUTT_UNREAD:
2030  return pat->pat_not ? e->read : !e->read;
2031  case MUTT_REPLIED:
2032  return pat->pat_not ^ e->replied;
2033  case MUTT_OLD:
2034  return pat->pat_not ? (!e->old || e->read) : (e->old && !e->read);
2035  case MUTT_READ:
2036  return pat->pat_not ^ e->read;
2037  case MUTT_DELETED:
2038  return pat->pat_not ^ e->deleted;
2039  case MUTT_PAT_MESSAGE:
2040  return pat->pat_not ^ ((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
2041  case MUTT_PAT_DATE:
2042  if (pat->dynamic)
2044  return pat->pat_not ^ (e->date_sent >= pat->min && e->date_sent <= pat->max);
2046  if (pat->dynamic)
2048  return pat->pat_not ^ (e->received >= pat->min && e->received <= pat->max);
2049  case MUTT_PAT_BODY:
2050  case MUTT_PAT_HEADER:
2051  case MUTT_PAT_WHOLE_MSG:
2052  /* m can be NULL in certain cases, such as when replying to a message
2053  * from the attachment menu and the user has a reply-hook using "~e".
2054  * This is also the case when message scoring. */
2055  if (!m)
2056  return 0;
2057 #ifdef USE_IMAP
2058  /* IMAP search sets e->matched at search compile time */
2059  if ((m->magic == MUTT_IMAP) && pat->string_match)
2060  return e->matched;
2061 #endif
2062  return pat->pat_not ^ msg_search(m, pat, e->msgno);
2063  case MUTT_PAT_SERVERSEARCH:
2064 #ifdef USE_IMAP
2065  if (!m)
2066  return 0;
2067  if (m->magic == MUTT_IMAP)
2068  {
2069  if (pat->string_match)
2070  return e->matched;
2071  return 0;
2072  }
2073  mutt_error(_("error: server custom search only supported with IMAP"));
2074  return 0;
2075 #else
2076  mutt_error(_("error: server custom search only supported with IMAP"));
2077  return -1;
2078 #endif
2079  case MUTT_PAT_SENDER:
2080  if (!e->env)
2081  return 0;
2082  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2083  1, &e->env->sender);
2084  case MUTT_PAT_FROM:
2085  if (!e->env)
2086  return 0;
2087  return pat->pat_not ^
2088  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->from);
2089  case MUTT_PAT_TO:
2090  if (!e->env)
2091  return 0;
2092  return pat->pat_not ^
2093  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->to);
2094  case MUTT_PAT_CC:
2095  if (!e->env)
2096  return 0;
2097  return pat->pat_not ^
2098  match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1, &e->env->cc);
2099  case MUTT_PAT_SUBJECT:
2100  if (!e->env)
2101  return 0;
2102  return pat->pat_not ^ (e->env->subject && patmatch(pat, e->env->subject));
2103  case MUTT_PAT_ID:
2104  case MUTT_PAT_ID_EXTERNAL:
2105  if (!e->env)
2106  return 0;
2107  return pat->pat_not ^ (e->env->message_id && patmatch(pat, e->env->message_id));
2108  case MUTT_PAT_SCORE:
2109  return pat->pat_not ^ (e->score >= pat->min &&
2110  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
2111  case MUTT_PAT_SIZE:
2112  return pat->pat_not ^
2113  (e->content->length >= pat->min &&
2114  (pat->max == MUTT_MAXRANGE || e->content->length <= pat->max));
2115  case MUTT_PAT_REFERENCE:
2116  if (!e->env)
2117  return 0;
2118  return pat->pat_not ^ (match_reference(pat, &e->env->references) ||
2119  match_reference(pat, &e->env->in_reply_to));
2120  case MUTT_PAT_ADDRESS:
2121  if (!e->env)
2122  return 0;
2123  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2124  4, &e->env->from, &e->env->sender,
2125  &e->env->to, &e->env->cc);
2126  case MUTT_PAT_RECIPIENT:
2127  if (!e->env)
2128  return 0;
2129  return pat->pat_not ^ match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS),
2130  2, &e->env->to, &e->env->cc);
2131  case MUTT_PAT_LIST: /* known list, subscribed or not */
2132  {
2133  if (!e->env)
2134  return 0;
2135 
2136  int result;
2137  if (cache)
2138  {
2139  int *cache_entry = pat->all_addr ? &cache->list_all : &cache->list_one;
2140  if (!is_pattern_cache_set(*cache_entry))
2141  {
2142  set_pattern_cache_value(cache_entry,
2143  mutt_is_list_recipient(pat->all_addr, e->env));
2144  }
2145  result = get_pattern_cache_value(*cache_entry);
2146  }
2147  else
2148  result = mutt_is_list_recipient(pat->all_addr, e->env);
2149  return pat->pat_not ^ result;
2150  }
2152  {
2153  if (!e->env)
2154  return 0;
2155 
2156  int result;
2157  if (cache)
2158  {
2159  int *cache_entry = pat->all_addr ? &cache->sub_all : &cache->sub_one;
2160  if (!is_pattern_cache_set(*cache_entry))
2161  {
2163  cache_entry, mutt_is_subscribed_list_recipient(pat->all_addr, e->env));
2164  }
2165  result = get_pattern_cache_value(*cache_entry);
2166  }
2167  else
2168  result = mutt_is_subscribed_list_recipient(pat->all_addr, e->env);
2169  return pat->pat_not ^ result;
2170  }
2172  {
2173  if (!e->env)
2174  return 0;
2175 
2176  int result;
2177  if (cache)
2178  {
2179  int *cache_entry = pat->all_addr ? &cache->pers_recip_all : &cache->pers_recip_one;
2180  if (!is_pattern_cache_set(*cache_entry))
2181  {
2183  cache_entry, match_user(pat->all_addr, &e->env->to, &e->env->cc));
2184  }
2185  result = get_pattern_cache_value(*cache_entry);
2186  }
2187  else
2188  result = match_user(pat->all_addr, &e->env->to, &e->env->cc);
2189  return pat->pat_not ^ result;
2190  }
2192  {
2193  if (!e->env)
2194  return 0;
2195 
2196  int result;
2197  if (cache)
2198  {
2199  int *cache_entry = pat->all_addr ? &cache->pers_from_all : &cache->pers_from_one;
2200  if (!is_pattern_cache_set(*cache_entry))
2201  set_pattern_cache_value(cache_entry,
2202  match_user(pat->all_addr, &e->env->from, NULL));
2203  result = get_pattern_cache_value(*cache_entry);
2204  }
2205  else
2206  result = match_user(pat->all_addr, &e->env->from, NULL);
2207  return pat->pat_not ^ result;
2208  }
2209  case MUTT_PAT_COLLAPSED:
2210  return pat->pat_not ^ (e->collapsed && e->num_hidden > 1);
2211  case MUTT_PAT_CRYPT_SIGN:
2212  if (!WithCrypto)
2213  break;
2214  return pat->pat_not ^ ((e->security & SEC_SIGN) ? 1 : 0);
2216  if (!WithCrypto)
2217  break;
2218  return pat->pat_not ^ ((e->security & SEC_GOODSIGN) ? 1 : 0);
2220  if (!WithCrypto)
2221  break;
2222  return pat->pat_not ^ ((e->security & SEC_ENCRYPT) ? 1 : 0);
2223  case MUTT_PAT_PGP_KEY:
2224  if (!(WithCrypto & APPLICATION_PGP))
2225  break;
2226  return pat->pat_not ^ ((e->security & PGP_KEY) == PGP_KEY);
2227  case MUTT_PAT_XLABEL:
2228  if (!e->env)
2229  return 0;
2230  return pat->pat_not ^ (e->env->x_label && patmatch(pat, e->env->x_label));
2231  case MUTT_PAT_DRIVER_TAGS:
2232  {
2233  char *tags = driver_tags_get(&e->tags);
2234  bool rc = (pat->pat_not ^ (tags && patmatch(pat, tags)));
2235  FREE(&tags);
2236  return rc;
2237  }
2238  case MUTT_PAT_HORMEL:
2239  if (!e->env)
2240  return 0;
2241  return pat->pat_not ^ (e->env->spam.data && patmatch(pat, e->env->spam.data));
2242  case MUTT_PAT_DUPLICATED:
2243  return pat->pat_not ^ (e->thread && e->thread->duplicate_thread);
2244  case MUTT_PAT_MIMEATTACH:
2245  if (!m)
2246  return 0;
2247  {
2248  int count = mutt_count_body_parts(m, e);
2249  return pat->pat_not ^ (count >= pat->min &&
2250  (pat->max == MUTT_MAXRANGE || count <= pat->max));
2251  }
2252  case MUTT_PAT_MIMETYPE:
2253  if (!m)
2254  return 0;
2255  return pat->pat_not ^ match_mime_content_type(pat, m, e);
2256  case MUTT_PAT_UNREFERENCED:
2257  return pat->pat_not ^ (e->thread && !e->thread->child);
2258  case MUTT_PAT_BROKEN:
2259  return pat->pat_not ^ (e->thread && e->thread->fake_thread);
2260 #ifdef USE_NNTP
2261  case MUTT_PAT_NEWSGROUPS:
2262  if (!e->env)
2263  return 0;
2264  return pat->pat_not ^ (e->env->newsgroups && patmatch(pat, e->env->newsgroups));
2265 #endif
2266  }
2267  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
2268  return -1;
2269 }
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:1723
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:1649
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:1885
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against and Address list.
Definition: pattern.c:1693
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:1792
#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:1828
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:1981
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:116
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:1971
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:1671
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:1089
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:92
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:1866
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:1767
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:1928
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:1946
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:1960
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:1779
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:1070
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 2276 of file pattern.c.

2277 {
2278  mutt_buffer_reset(buf);
2279  mutt_buffer_addch(buf, '"');
2280  while (*str)
2281  {
2282  if ((*str == '\\') || (*str == '"'))
2283  mutt_buffer_addch(buf, '\\');
2284  mutt_buffer_addch(buf, *str++);
2285  }
2286  mutt_buffer_addch(buf, '"');
2287 }
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 2294 of file pattern.c.

2295 {
2296  bool do_simple = true;
2297 
2298  for (const char *p = mutt_b2s(buf); p && (p[0] != '\0'); p++)
2299  {
2300  if ((p[0] == '\\') && (p[1] != '\0'))
2301  p++;
2302  else if ((p[0] == '~') || (p[0] == '=') || (p[0] == '%'))
2303  {
2304  do_simple = false;
2305  break;
2306  }
2307  }
2308 
2309  /* XXX - is mutt_str_strcasecmp() right here, or should we use locale's
2310  * equivalences? */
2311 
2312  if (do_simple) /* yup, so spoof a real request */
2313  {
2314  /* convert old tokens into the new format */
2315  if ((mutt_str_strcasecmp("all", mutt_b2s(buf)) == 0) ||
2316  (mutt_str_strcmp("^", mutt_b2s(buf)) == 0) ||
2317  (mutt_str_strcmp(".", mutt_b2s(buf)) == 0)) /* ~A is more efficient */
2318  {
2319  mutt_buffer_strcpy(buf, "~A");
2320  }
2321  else if (mutt_str_strcasecmp("del", mutt_b2s(buf)) == 0)
2322  mutt_buffer_strcpy(buf, "~D");
2323  else if (mutt_str_strcasecmp("flag", mutt_b2s(buf)) == 0)
2324  mutt_buffer_strcpy(buf, "~F");
2325  else if (mutt_str_strcasecmp("new", mutt_b2s(buf)) == 0)
2326  mutt_buffer_strcpy(buf, "~N");
2327  else if (mutt_str_strcasecmp("old", mutt_b2s(buf)) == 0)
2328  mutt_buffer_strcpy(buf, "~O");
2329  else if (mutt_str_strcasecmp("repl", mutt_b2s(buf)) == 0)
2330  mutt_buffer_strcpy(buf, "~Q");
2331  else if (mutt_str_strcasecmp("read", mutt_b2s(buf)) == 0)
2332  mutt_buffer_strcpy(buf, "~R");
2333  else if (mutt_str_strcasecmp("tag", mutt_b2s(buf)) == 0)
2334  mutt_buffer_strcpy(buf, "~T");
2335  else if (mutt_str_strcasecmp("unread", mutt_b2s(buf)) == 0)
2336  mutt_buffer_strcpy(buf, "~U");
2337  else
2338  {
2339  struct Buffer *tmp = mutt_buffer_pool_get();
2340  quote_simple(mutt_b2s(buf), tmp);
2341  mutt_file_expand_fmt(buf, simple, mutt_b2s(tmp));
2343  }
2344  }
2345 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:100
static void quote_simple(const char *str, struct Buffer *buf)
Apply simple quoting to a string.
Definition: pattern.c:2276
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
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:1434
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 2353 of file pattern.c.

2354 {
2355  if (!e)
2356  return NULL;
2357 
2358  struct MuttThread *t = e->thread;
2359 
2360  while (t && t->parent)
2361  t = t->parent;
2362 
2363  return t;
2364 }
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 2372 of file pattern.c.

2373 {
2374  if (!e)
2375  return false;
2376 
2377  struct MuttThread *me = top_of_thread(e);
2378  if (!me)
2379  return false;
2380 
2381  Context->mailbox->vcount = 0;
2382  Context->vsize = 0;
2383  Context->collapsed = false;
2384 
2385  for (int i = 0; i < Context->mailbox->msg_count; i++)
2386  {
2387  Context->mailbox->emails[i]->vnum = -1;
2388  Context->mailbox->emails[i]->limited = false;
2389  Context->mailbox->emails[i]->collapsed = false;
2390  Context->mailbox->emails[i]->num_hidden = 0;
2391 
2392  if (top_of_thread(Context->mailbox->emails[i]) == me)
2393  {
2394  struct Body *body = Context->mailbox->emails[i]->content;
2395 
2397  Context->mailbox->emails[i]->limited = true;
2399  Context->mailbox->vcount++;
2400  Context->vsize += (body->length + body->offset - body->hdr_offset);
2401  }
2402  }
2403  return true;
2404 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
int msg_count
Total number of messages.
Definition: mailbox.h:102
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:113
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
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition: pattern.c:2353
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:112
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 2413 of file pattern.c.

2414 {
2415  struct Buffer err;
2416  int rc = -1;
2417  struct Progress progress;
2418  struct Buffer *buf = mutt_buffer_pool_get();
2419 
2421  if (prompt || (op != MUTT_LIMIT))
2422  {
2423  if ((mutt_buffer_get_field(prompt, buf, MUTT_PATTERN | MUTT_CLEAR) != 0) ||
2424  mutt_buffer_is_empty(buf))
2425  {
2427  return -1;
2428  }
2429  }
2430 
2431  mutt_message(_("Compiling search pattern..."));
2432 
2433  char *simple = mutt_buffer_strdup(buf);
2435 
2436  mutt_buffer_init(&err);
2437  err.dsize = 256;
2438  err.data = mutt_mem_malloc(err.dsize);
2439  struct PatternList *pat = mutt_pattern_comp(buf->data, MUTT_PC_FULL_MSG, &err);
2440  if (!pat)
2441  {
2442  mutt_error("%s", err.data);
2443  goto bail;
2444  }
2445 
2446 #ifdef USE_IMAP
2447  if ((Context->mailbox->magic == MUTT_IMAP) && (imap_search(Context->mailbox, pat) < 0))
2448  goto bail;
2449 #endif
2450 
2452  &progress, _("Executing command on matching messages..."), MUTT_PROGRESS_READ,
2454 
2455  if (op == MUTT_LIMIT)
2456  {
2457  Context->mailbox->vcount = 0;
2458  Context->vsize = 0;
2459  Context->collapsed = false;
2460  int padding = mx_msg_padding_size(Context->mailbox);
2461 
2462  for (int i = 0; i < Context->mailbox->msg_count; i++)
2463  {
2464  mutt_progress_update(&progress, i, -1);
2465  /* new limit pattern implicitly uncollapses all threads */
2466  Context->mailbox->emails[i]->vnum = -1;
2467  Context->mailbox->emails[i]->limited = false;
2468  Context->mailbox->emails[i]->collapsed = false;
2469  Context->mailbox->emails[i]->num_hidden = 0;
2471  Context->mailbox, Context->mailbox->emails[i], NULL))
2472  {
2474  Context->mailbox->emails[i]->limited = true;
2476  Context->mailbox->vcount++;
2477  struct Body *b = Context->mailbox->emails[i]->content;
2478  Context->vsize += b->length + b->offset - b->hdr_offset + padding;
2479  }
2480  }
2481  }
2482  else
2483  {
2484  for (int i = 0; i < Context->mailbox->vcount; i++)
2485  {
2486  mutt_progress_update(&progress, i, -1);
2488  Context->mailbox->emails[Context->mailbox->v2r[i]], NULL))
2489  {
2490  switch (op)
2491  {
2492  case MUTT_UNDELETE:
2495  MUTT_PURGE, false);
2496  /* fallthrough */
2497  case MUTT_DELETE:
2500  MUTT_DELETE, (op == MUTT_DELETE));
2501  break;
2502  case MUTT_TAG:
2503  case MUTT_UNTAG:
2506  MUTT_TAG, (op == MUTT_TAG));
2507  break;
2508  }
2509  }
2510  }
2511  }
2512 
2513  mutt_clear_error();
2514 
2515  if (op == MUTT_LIMIT)
2516  {
2517  /* drop previous limit pattern */
2518  FREE(&Context->pattern);
2520 
2522  mutt_error(_("No messages matched criteria"));
2523 
2524  /* record new limit pattern, unless match all */
2525  const char *pbuf = buf->data;
2526  while (*pbuf == ' ')
2527  pbuf++;
2528  if (mutt_str_strcmp(pbuf, "~A") != 0)
2529  {
2530  Context->pattern = simple;
2531  simple = NULL; /* don't clobber it */
2533  }
2534  }
2535 
2536  rc = 0;
2537 
2538 bail:
2540  FREE(&simple);
2541  mutt_pattern_free(&pat);
2542  FREE(&err.data);
2543 
2544  return rc;
2545 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:102
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:69
#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:100
#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:2294
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:111
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:1348
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:113
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:215
struct Mailbox * mailbox
Definition: context.h:50
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
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:115
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:2001
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1392
#define SLIST_FIRST(head)
Definition: queue.h:229
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
Messages to be deleted.
Definition: mutt.h:102
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:1340
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:156
#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:84
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: globals.h:142
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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:1475
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:37
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 2554 of file pattern.c.

2555 {
2556  struct Progress progress;
2557 
2558  if (!*LastSearch || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
2559  {
2560  char buf[256];
2561  mutt_str_strfcpy(buf, (LastSearch[0] != '\0') ? LastSearch : "", sizeof(buf));
2562  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2563  _("Search for: ") :
2564  _("Reverse search for: "),
2565  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0) ||
2566  !buf[0])
2567  {
2568  return -1;
2569  }
2570 
2571  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
2572  OptSearchReverse = false;
2573  else
2574  OptSearchReverse = true;
2575 
2576  /* compare the *expanded* version of the search pattern in case
2577  * $simple_search has changed while we were searching */
2578  struct Buffer *tmp = mutt_buffer_pool_get();
2579  mutt_buffer_strcpy(tmp, buf);
2581 
2582  if (!SearchPattern || (mutt_str_strcmp(mutt_b2s(tmp), LastSearchExpn) != 0))
2583  {
2584  struct Buffer err;
2585  mutt_buffer_init(&err);
2586  OptSearchInvalid = true;
2587  mutt_str_strfcpy(LastSearch, buf, sizeof(LastSearch));
2589  mutt_message(_("Compiling search pattern..."));
2591  err.dsize = 256;
2592  err.data = mutt_mem_malloc(err.dsize);
2594  if (!SearchPattern)
2595  {
2597  mutt_error("%s", err.data);
2598  FREE(&err.data);
2599  LastSearch[0] = '\0';
2600  LastSearchExpn[0] = '\0';
2601  return -1;
2602  }
2603  FREE(&err.data);
2604  mutt_clear_error();
2605  }
2606 
2608  }
2609 
2610  if (OptSearchInvalid)
2611  {
2612  for (int i = 0; i < Context->mailbox->msg_count; i++)
2613  Context->mailbox->emails[i]->searched = false;
2614 #ifdef USE_IMAP
2615  if ((Context->mailbox->magic == MUTT_IMAP) &&
2617  return -1;
2618 #endif
2619  OptSearchInvalid = false;
2620  }
2621 
2622  int incr = OptSearchReverse ? -1 : 1;
2623  if (op == OP_SEARCH_OPPOSITE)
2624  incr = -incr;
2625 
2626  mutt_progress_init(&progress, _("Searching..."), MUTT_PROGRESS_READ,
2627  Context->mailbox->vcount);
2628 
2629  for (int i = cur + incr, j = 0; j != Context->mailbox->vcount; j++)
2630  {
2631  const char *msg = NULL;
2632  mutt_progress_update(&progress, j, -1);
2633  if (i > Context->mailbox->vcount - 1)
2634  {
2635  i = 0;
2636  if (C_WrapSearch)
2637  msg = _("Search wrapped to top");
2638  else
2639  {
2640  mutt_message(_("Search hit bottom without finding match"));
2641  return -1;
2642  }
2643  }
2644  else if (i < 0)
2645  {
2646  i = Context->mailbox->vcount - 1;
2647  if (C_WrapSearch)
2648  msg = _("Search wrapped to bottom");
2649  else
2650  {
2651  mutt_message(_("Search hit top without finding match"));
2652  return -1;
2653  }
2654  }
2655 
2656  struct Email *e = Context->mailbox->emails[Context->mailbox->v2r[i]];
2657  if (e->searched)
2658  {
2659  /* if we've already evaluated this message, use the cached value */
2660  if (e->matched)
2661  {
2662  mutt_clear_error();
2663  if (msg && *msg)
2664  mutt_message(msg);
2665  return i;
2666  }
2667  }
2668  else
2669  {
2670  /* remember that we've already searched this message */
2671  e->searched = true;
2673  Context->mailbox, e, NULL);
2674  if (e->matched > 0)
2675  {
2676  mutt_clear_error();
2677  if (msg && *msg)
2678  mutt_message(msg);
2679  return i;
2680  }
2681  }
2682 
2683  if (SigInt)
2684  {
2685  mutt_error(_("Search interrupted"));
2686  SigInt = 0;
2687  return -1;
2688  }
2689 
2690  i += incr;
2691  }
2692 
2693  mutt_error(_("Not found"));
2694  return -1;
2695 }
struct Email ** emails
Array of Emails.
Definition: mailbox.h:110
The "current" mailbox.
Definition: context.h:36
#define NONULL(x)
Definition: string2.h:37
int msg_count
Total number of messages.
Definition: mailbox.h:102
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:100
#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:2294
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:81
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:111
int imap_search(struct Mailbox *m, const struct PatternList *pat)
Find a matching mailbox.
Definition: imap.c:1348
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:270
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:91
int vcount
The number of virtual messages.
Definition: mailbox.h:113
void mutt_progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:215
struct Mailbox * mailbox
Definition: context.h:50
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:116
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:115
#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:2001
struct PatternList * mutt_pattern_comp(const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1392
static char LastSearchExpn[1024]
expanded version of LastSearch
Definition: pattern.c:200
#define SLIST_FIRST(head)
Definition: queue.h:229
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:1340
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
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:156
#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:142
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:112
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 70 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:76
#define RANGE_ABS_RX
Definition: pattern.c:80
Greater-than range.
Definition: pattern.c:146
#define RANGE_LT_RX
Definition: pattern.c:83
#define RANGE_BARE_RX
Definition: pattern.c:87
Absolute range.
Definition: pattern.c:144
#define RANGE_GT_RX
Definition: pattern.c:84
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 1244 of file pattern.c.