NeoMutt  2018-07-16 +1360-3df4a2
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 "config/lib.h"
#include "email/lib.h"
#include "conn/conn.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 "mailbox.h"
#include "mutt_logging.h"
#include "mutt_menu.h"
#include "mutt_parse.h"
#include "muttlib.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 PatternFlags
 Flags for parse_date_range(), e.g. MUTT_PDR_MINUS. 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, struct Buffer *s, struct Buffer *err)
 Parse a regex. 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, struct Buffer *s, struct Buffer *err)
 Parse a query for an external search program. 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 eat_date (struct Pattern *pat, struct Buffer *s, struct Buffer *err)
 Parse a date pattern. More...
 
static bool eat_range (struct Pattern *pat, struct Buffer *s, struct Buffer *err)
 Parse a number range. 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, struct Buffer *s, struct Buffer *err)
 Parse a range of message numbers. More...
 
static int 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 Pattern **pat)
 Free a Pattern. More...
 
struct Patternmutt_pattern_new (void)
 Create a new Pattern. More...
 
struct Patternmutt_pattern_comp (char *s, int flags, struct Buffer *err)
 Create a Pattern. More...
 
static bool perform_and (struct Pattern *pat, enum PatternExecFlag 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 Pattern *pat, enum PatternExecFlag 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...
 
int mutt_is_list_recipient (bool alladdr, struct Address *a1, struct Address *a2)
 Matches subscribed mailing lists. More...
 
int mutt_is_list_cc (int alladdr, struct Address *a1, struct Address *a2)
 Matches known mailing lists. More...
 
static int match_user (int alladdr, struct Address *a1, struct Address *a2)
 Matches the user's email Address. More...
 
static int match_threadcomplete (struct Pattern *pat, enum PatternExecFlag 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 Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct MuttThread *t)
 Match Pattern against an email's parent. More...
 
static int match_threadchildren (struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct MuttThread *t)
 Match Pattern against an email's children. More...
 
static int match_content_type (const struct Pattern *pat, struct Body *b)
 Match a Pattern against an Attachment's Content-Type. More...
 
static int 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, enum PatternExecFlag 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, char *buf, size_t buflen)
 Apply simple quoting to a string. More...
 
void mutt_check_simple (char *s, size_t len, 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 PatternSearchPattern = 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

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

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

Definition at line 75 of file pattern.c.

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

Definition at line 76 of file pattern.c.

#define RANGE_REL_RX   "^" RANGE_REL_SLOT_RX "," RANGE_REL_SLOT_RX

Definition at line 77 of file pattern.c.

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

Definition at line 80 of file pattern.c.

#define RANGE_ABS_RX   "^" RANGE_ABS_SLOT_RX "-" RANGE_ABS_SLOT_RX

Definition at line 81 of file pattern.c.

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

Definition at line 84 of file pattern.c.

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

Definition at line 85 of file pattern.c.

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

Definition at line 88 of file pattern.c.

#define RANGE_RX_GROUPS   5

Definition at line 89 of file pattern.c.

#define KILO   1024

Definition at line 91 of file pattern.c.

#define MEGA   1048576

Definition at line 92 of file pattern.c.

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

Definition at line 93 of file pattern.c.

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

Definition at line 94 of file pattern.c.

#define MUTT_MAXRANGE   -1

Definition at line 97 of file pattern.c.

#define MUTT_PDR_NO_FLAGS   0

No flags are set.

Definition at line 100 of file pattern.c.

#define MUTT_PDR_MINUS   (1 << 0)

Pattern contains a range.

Definition at line 101 of file pattern.c.

#define MUTT_PDR_PLUS   (1 << 1)

Extend the range using '+'.

Definition at line 102 of file pattern.c.

#define MUTT_PDR_WINDOW   (1 << 2)

Extend the range in both directions using '*'.

Definition at line 103 of file pattern.c.

#define MUTT_PDR_ABSOLUTE   (1 << 3)

Absolute pattern range.

Definition at line 104 of file pattern.c.

#define MUTT_PDR_DONE   (1 << 4)

Pattern parse successfully.

Definition at line 105 of file pattern.c.

#define MUTT_PDR_ERROR   (1 << 8)

Invalid pattern.

Definition at line 106 of file pattern.c.

#define MUTT_PDR_ERRORDONE   (MUTT_PDR_ERROR | MUTT_PDR_DONE)

Definition at line 108 of file pattern.c.

#define RANGE_DOT   '.'

Definition at line 110 of file pattern.c.

#define RANGE_CIRCUM   '^'

Definition at line 111 of file pattern.c.

#define RANGE_DOLLAR   '$'

Definition at line 112 of file pattern.c.

#define RANGE_LT   '<'

Definition at line 113 of file pattern.c.

#define RANGE_GT   '>'

Definition at line 114 of file pattern.c.

Typedef Documentation

typedef uint16_t PatternFlags

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

Definition at line 99 of file pattern.c.

Enumeration Type Documentation

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

121 {
122  RANGE_E_OK,
124  RANGE_E_CTX,
125 };
Range is valid.
Definition: pattern.c:122
Range contains syntax error.
Definition: pattern.c:123
Range requires Context, but none available.
Definition: pattern.c:124
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 142 of file pattern.c.

143 {
144  RANGE_K_REL,
145  RANGE_K_ABS,
146  RANGE_K_LT,
147  RANGE_K_GT,
148  RANGE_K_BARE,
149  /* add new ones HERE */
151 };
Single symbol.
Definition: pattern.c:148
Greater-than range.
Definition: pattern.c:147
Range is invalid.
Definition: pattern.c:150
Absolute range.
Definition: pattern.c:145
Less-than range.
Definition: pattern.c:146
Relative range.
Definition: pattern.c:144
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 156 of file pattern.c.

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

Function Documentation

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

Parse a regex.

Parameters
patPattern to match
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 199 of file pattern.c.

200 {
201  struct Buffer buf;
202  char errmsg[256];
203  int r;
204 
205  mutt_buffer_init(&buf);
206  char *pexpr = s->dptr;
207  if ((mutt_extract_token(&buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) || !buf.data)
208  {
209  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
210  FREE(&buf.data);
211  return false;
212  }
213  if (buf.data[0] == '\0')
214  {
215  mutt_buffer_printf(err, "%s", _("Empty expression"));
216  FREE(&buf.data);
217  return false;
218  }
219 
220  if (pat->stringmatch)
221  {
222  pat->p.str = mutt_str_strdup(buf.data);
223  pat->ign_case = mutt_mb_is_lower(buf.data);
224  FREE(&buf.data);
225  }
226  else if (pat->groupmatch)
227  {
228  pat->p.group = mutt_pattern_group(buf.data);
229  FREE(&buf.data);
230  }
231  else
232  {
233  pat->p.regex = mutt_mem_malloc(sizeof(regex_t));
234  int flags = mutt_mb_is_lower(buf.data) ? REG_ICASE : 0;
235  r = REGCOMP(pat->p.regex, buf.data, REG_NEWLINE | REG_NOSUB | flags);
236  if (r != 0)
237  {
238  regerror(r, pat->p.regex, errmsg, sizeof(errmsg));
239  mutt_buffer_add_printf(err, "'%s': %s", buf.data, errmsg);
240  FREE(&buf.data);
241  FREE(&pat->p.regex);
242  return false;
243  }
244  FREE(&buf.data);
245  }
246 
247  return true;
248 }
struct Group * mutt_pattern_group(const char *k)
Match a pattern to a Group.
Definition: group.c:64
regex_t * regex
Definition: pattern.h:60
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:80
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:200
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:239
bool ign_case
ignore case for local stringmatch searches
Definition: pattern.h:52
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2659
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
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:383
char * str
Definition: pattern.h:62
struct Group * group
Definition: pattern.h:61
#define FREE(x)
Definition: memory.h:40
bool groupmatch
Definition: pattern.h:51
bool stringmatch
Definition: pattern.h:50
#define REGCOMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:52
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition: mbyte.c:346
#define MUTT_TOKEN_PATTERN
!)|~ are terms (for patterns)
Definition: mutt.h:79

+ Here is the call graph for this function:

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

255 {
256  struct ListHead *msgid_list = (struct ListHead *) (user_data);
257  char *nows = mutt_str_skip_whitespace(line);
258  if (!*nows)
259  return true;
261  mutt_list_insert_tail(msgid_list, mutt_str_strdup(nows));
262  return true;
263 }
char * mutt_str_skip_whitespace(char *p)
Find the first non-whitespace character in a string.
Definition: string.c:716
const char * line
Definition: common.c:35
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:58
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
Definition: string.c:728
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:383

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Parse a query for an external search program.

Parameters
patPattern to match
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 272 of file pattern.c.

273 {
274  struct Buffer cmd_buf;
275  struct Buffer tok_buf;
276  FILE *fp = NULL;
277 
279  {
280  mutt_buffer_printf(err, "%s", _("No search command defined"));
281  return false;
282  }
283 
284  mutt_buffer_init(&tok_buf);
285  char *pexpr = s->dptr;
286  if ((mutt_extract_token(&tok_buf, s, MUTT_TOKEN_PATTERN | MUTT_TOKEN_COMMENT) != 0) ||
287  !tok_buf.data)
288  {
289  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
290  return false;
291  }
292  if (*tok_buf.data == '\0')
293  {
294  mutt_buffer_printf(err, "%s", _("Empty expression"));
295  FREE(&tok_buf.data);
296  return false;
297  }
298 
299  mutt_buffer_init(&cmd_buf);
301  mutt_buffer_addch(&cmd_buf, ' ');
302  if (!Context || !Context->mailbox)
303  {
304  mutt_buffer_addch(&cmd_buf, '/');
305  }
306  else
307  {
308  char *escaped_folder = mutt_path_escape(Context->mailbox->path);
309  mutt_debug(LL_DEBUG2, "escaped folder path: %s\n", escaped_folder);
310  mutt_buffer_addch(&cmd_buf, '\'');
311  mutt_buffer_addstr(&cmd_buf, escaped_folder);
312  mutt_buffer_addch(&cmd_buf, '\'');
313  }
314  mutt_buffer_addch(&cmd_buf, ' ');
315  mutt_buffer_addstr(&cmd_buf, tok_buf.data);
316  FREE(&tok_buf.data);
317 
318  mutt_message(_("Running search command: %s ..."), cmd_buf.data);
319  pat->ismulti = true;
321  pid_t pid = mutt_create_filter(cmd_buf.data, NULL, &fp, NULL);
322  if (pid < 0)
323  {
324  mutt_buffer_printf(err, "unable to fork command: %s\n", cmd_buf.data);
325  FREE(&cmd_buf.data);
326  return false;
327  }
328 
330  mutt_file_fclose(&fp);
331  mutt_wait_filter(pid);
332  FREE(&cmd_buf.data);
333  return true;
334 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
The "current" mailbox.
Definition: context.h:37
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_message(...)
Definition: logging.h:87
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:80
String manipulation buffer.
Definition: buffer.h:33
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:724
#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:200
struct Mailbox * mailbox
Definition: context.h:51
Log at debug level 2.
Definition: logging.h:57
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
Definition: path.c:535
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:258
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2659
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:273
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:254
char path[PATH_MAX]
Definition: mailbox.h:85
union Pattern::@2 p
#define FREE(x)
Definition: memory.h:40
struct ListHead multi_cases
Definition: pattern.h:63
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66
WHERE char * C_ExternalSearchCommand
Config: External search command.
Definition: globals.h:113
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
Definition: list.c:145
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
#define MUTT_TOKEN_PATTERN
!)|~ are terms (for patterns)
Definition: mutt.h:79
bool ismulti
multiple case (only for I pattern now)
Definition: pattern.h:54

+ Here is the call graph for this function:

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

349 {
350  char *ps = NULL;
351  int offset = strtol(s, &ps, 0);
352  if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
353  offset = -offset;
354 
355  switch (*ps)
356  {
357  case 'y':
358  tm->tm_year += offset;
359  break;
360  case 'm':
361  tm->tm_mon += offset;
362  break;
363  case 'w':
364  tm->tm_mday += 7 * offset;
365  break;
366  case 'd':
367  tm->tm_mday += offset;
368  break;
369  case 'H':
370  tm->tm_hour += offset;
371  break;
372  case 'M':
373  tm->tm_min += offset;
374  break;
375  case 'S':
376  tm->tm_sec += offset;
377  break;
378  default:
379  return s;
380  }
382  return ps + 1;
383 }
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
Definition: date.c:302

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

402 {
403  char *p = NULL;
404  time_t now = time(NULL);
405  struct tm *tm = localtime(&now);
406 
407  t->tm_mday = strtol(s, &p, 10);
408  if ((t->tm_mday < 1) || (t->tm_mday > 31))
409  {
410  mutt_buffer_printf(err, _("Invalid day of month: %s"), s);
411  return NULL;
412  }
413  if (*p != '/')
414  {
415  /* fill in today's month and year */
416  t->tm_mon = tm->tm_mon;
417  t->tm_year = tm->tm_year;
418  return p;
419  }
420  p++;
421  t->tm_mon = strtol(p, &p, 10) - 1;
422  if ((t->tm_mon < 0) || (t->tm_mon > 11))
423  {
424  mutt_buffer_printf(err, _("Invalid month: %s"), p);
425  return NULL;
426  }
427  if (*p != '/')
428  {
429  t->tm_year = tm->tm_year;
430  return p;
431  }
432  p++;
433  t->tm_year = strtol(p, &p, 10);
434  if (t->tm_year < 70) /* year 2000+ */
435  t->tm_year += 100;
436  else if (t->tm_year > 1900)
437  t->tm_year -= 1900;
438  return p;
439 }
#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:200

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

538 {
539  if ((min->tm_year > max->tm_year) ||
540  ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
541  ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
542  (min->tm_mday > max->tm_mday)))
543  {
544  int tmp;
545 
546  tmp = min->tm_year;
547  min->tm_year = max->tm_year;
548  max->tm_year = tmp;
549 
550  tmp = min->tm_mon;
551  min->tm_mon = max->tm_mon;
552  max->tm_mon = tmp;
553 
554  tmp = min->tm_mday;
555  min->tm_mday = max->tm_mday;
556  max->tm_mday = tmp;
557 
558  min->tm_hour = 0;
559  min->tm_min = 0;
560  min->tm_sec = 0;
561  max->tm_hour = 23;
562  max->tm_min = 59;
563  max->tm_sec = 59;
564  }
565 }

+ Here is the caller graph for this function:

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

Parse a date pattern.

Parameters
patPattern to store the date in
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 574 of file pattern.c.

575 {
576  struct Buffer buf;
577  struct tm min, max;
578  char *offset_type = NULL;
579 
580  mutt_buffer_init(&buf);
581  char *pexpr = s->dptr;
582  if ((mutt_extract_token(&buf, s, MUTT_TOKEN_COMMENT | MUTT_TOKEN_PATTERN) != 0) || !buf.data)
583  {
584  FREE(&buf.data);
585  mutt_buffer_printf(err, _("Error in expression: %s"), pexpr);
586  return false;
587  }
588  if (buf.data[0] == '\0')
589  {
590  FREE(&buf.data);
591  mutt_buffer_printf(err, "%s", _("Empty expression"));
592  return false;
593  }
594 
595  memset(&min, 0, sizeof(min));
596  /* the '0' time is Jan 1, 1970 UTC, so in order to prevent a negative time
597  * when doing timezone conversion, we use Jan 2, 1970 UTC as the base here */
598  min.tm_mday = 2;
599  min.tm_year = 70;
600 
601  memset(&max, 0, sizeof(max));
602 
603  /* Arbitrary year in the future. Don't set this too high or
604  * mutt_date_make_time() returns something larger than will fit in a time_t
605  * on some systems */
606  max.tm_year = 130;
607  max.tm_mon = 11;
608  max.tm_mday = 31;
609  max.tm_hour = 23;
610  max.tm_min = 59;
611  max.tm_sec = 59;
612 
613  if (strchr("<>=", buf.data[0]))
614  {
615  /* offset from current time
616  * <3d less than three days ago
617  * >3d more than three days ago
618  * =3d exactly three days ago */
619  time_t now = time(NULL);
620  struct tm *tm = localtime(&now);
621  bool exact = false;
622 
623  if (buf.data[0] == '<')
624  {
625  memcpy(&min, tm, sizeof(min));
626  tm = &min;
627  }
628  else
629  {
630  memcpy(&max, tm, sizeof(max));
631  tm = &max;
632 
633  if (buf.data[0] == '=')
634  exact = true;
635  }
636 
637  /* Reset the HMS unless we are relative matching using one of those
638  * offsets. */
639  strtol(buf.data + 1, &offset_type, 0);
640  if (!(*offset_type && strchr("HMS", *offset_type)))
641  {
642  tm->tm_hour = 23;
643  tm->tm_min = 59;
644  tm->tm_sec = 59;
645  }
646 
647  /* force negative offset */
648  get_offset(tm, buf.data + 1, -1);
649 
650  if (exact)
651  {
652  /* start at the beginning of the day in question */
653  memcpy(&min, &max, sizeof(max));
654  min.tm_hour = 0;
655  min.tm_sec = 0;
656  min.tm_min = 0;
657  }
658  }
659  else
660  {
661  const char *pc = buf.data;
662 
663  bool have_min = false;
664  int until_now = false;
665  if (isdigit((unsigned char) *pc))
666  {
667  /* minimum date specified */
668  pc = get_date(pc, &min, err);
669  if (!pc)
670  {
671  FREE(&buf.data);
672  return false;
673  }
674  have_min = true;
675  SKIPWS(pc);
676  if (*pc == '-')
677  {
678  const char *pt = pc + 1;
679  SKIPWS(pt);
680  until_now = (*pt == '\0');
681  }
682  }
683 
684  if (!until_now)
685  { /* max date or relative range/window */
686 
687  struct tm base_min;
688 
689  if (!have_min)
690  { /* save base minimum and set current date, e.g. for "-3d+1d" */
691  time_t now = time(NULL);
692  struct tm *tm = localtime(&now);
693  memcpy(&base_min, &min, sizeof(base_min));
694  memcpy(&min, tm, sizeof(min));
695  min.tm_hour = 0;
696  min.tm_sec = 0;
697  min.tm_min = 0;
698  }
699 
700  /* preset max date for relative offsets,
701  * if nothing follows we search for messages on a specific day */
702  max.tm_year = min.tm_year;
703  max.tm_mon = min.tm_mon;
704  max.tm_mday = min.tm_mday;
705 
706  if (!parse_date_range(pc, &min, &max, have_min, &base_min, err))
707  { /* bail out on any parsing error */
708  FREE(&buf.data);
709  return false;
710  }
711  }
712  }
713 
714  /* Since we allow two dates to be specified we'll have to adjust that. */
715  adjust_date_range(&min, &max);
716 
717  pat->min = mutt_date_make_time(&min, 1);
718  pat->max = mutt_date_make_time(&max, 1);
719 
720  FREE(&buf.data);
721 
722  return true;
723 }
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
Definition: pattern.c:537
#define MUTT_TOKEN_COMMENT
Don&#39;t reap comments.
Definition: mutt.h:80
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:200
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:401
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
Definition: pattern.c:348
#define SKIPWS(ch)
Definition: string2.h:46
int min
Definition: pattern.h:55
time_t mutt_date_make_time(struct tm *t, int local)
Convert struct tm to time_t
Definition: date.c:237
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:2659
char * dptr
current read/write position
Definition: buffer.h:36
#define FREE(x)
Definition: memory.h:40
int max
Definition: pattern.h:56
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66
#define MUTT_TOKEN_PATTERN
!)|~ are terms (for patterns)
Definition: mutt.h:79
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:451

+ Here is the call graph for this function:

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

Parse a number range.

Parameters
patPattern to store the range in
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 732 of file pattern.c.

733 {
734  char *tmp = NULL;
735  bool do_exclusive = false;
736  bool skip_quote = false;
737 
738  /* If simple_search is set to "~m %s", the range will have double quotes
739  * around it... */
740  if (*s->dptr == '"')
741  {
742  s->dptr++;
743  skip_quote = true;
744  }
745  if (*s->dptr == '<')
746  do_exclusive = true;
747  if ((*s->dptr != '-') && (*s->dptr != '<'))
748  {
749  /* range minimum */
750  if (*s->dptr == '>')
751  {
752  pat->max = MUTT_MAXRANGE;
753  pat->min = strtol(s->dptr + 1, &tmp, 0) + 1; /* exclusive range */
754  }
755  else
756  pat->min = strtol(s->dptr, &tmp, 0);
757  if (toupper((unsigned char) *tmp) == 'K') /* is there a prefix? */
758  {
759  pat->min *= 1024;
760  tmp++;
761  }
762  else if (toupper((unsigned char) *tmp) == 'M')
763  {
764  pat->min *= 1048576;
765  tmp++;
766  }
767  if (*s->dptr == '>')
768  {
769  s->dptr = tmp;
770  return true;
771  }
772  if (*tmp != '-')
773  {
774  /* exact value */
775  pat->max = pat->min;
776  s->dptr = tmp;
777  return true;
778  }
779  tmp++;
780  }
781  else
782  {
783  s->dptr++;
784  tmp = s->dptr;
785  }
786 
787  if (isdigit((unsigned char) *tmp))
788  {
789  /* range maximum */
790  pat->max = strtol(tmp, &tmp, 0);
791  if (toupper((unsigned char) *tmp) == 'K')
792  {
793  pat->max *= 1024;
794  tmp++;
795  }
796  else if (toupper((unsigned char) *tmp) == 'M')
797  {
798  pat->max *= 1048576;
799  tmp++;
800  }
801  if (do_exclusive)
802  (pat->max)--;
803  }
804  else
805  pat->max = MUTT_MAXRANGE;
806 
807  if (skip_quote && (*tmp == '"'))
808  tmp++;
809 
810  SKIPWS(tmp);
811  s->dptr = tmp;
812  return true;
813 }
#define MUTT_MAXRANGE
Definition: pattern.c:97
#define SKIPWS(ch)
Definition: string2.h:46
int min
Definition: pattern.h:55
char * dptr
current read/write position
Definition: buffer.h:36
int max
Definition: pattern.h:56
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 822 of file pattern.c.

823 {
824  size_t ds = err->dsize;
825 
826  if (regerror(regerr, preg, err->data, ds) > ds)
827  mutt_debug(LL_DEBUG2, "warning: buffer too small for regerror\n");
828  /* The return value is fixed, exists only to shorten code at callsite */
829  return RANGE_E_SYNTAX;
830 }
Range contains syntax error.
Definition: pattern.c:123
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:85

+ Here is the caller graph for this function:

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

843 {
844  const char *context_req_chars[] = {
845  [RANGE_K_REL] = ".0123456789",
846  [RANGE_K_ABS] = ".",
847  [RANGE_K_LT] = "",
848  [RANGE_K_GT] = "",
849  [RANGE_K_BARE] = ".",
850  };
851 
852  /* First decide if we're going to need the context at all.
853  * Relative patterns need it if they contain a dot or a number.
854  * Absolute patterns only need it if they contain a dot. */
855  char *context_loc = strpbrk(s->dptr + pmatch[0].rm_so, context_req_chars[kind]);
856  if (!context_loc || (context_loc >= &s->dptr[pmatch[0].rm_eo]))
857  return true;
858 
859  /* We need a current message. Do we actually have one? */
860  if (Context && Context->menu)
861  return true;
862 
863  /* Nope. */
864  mutt_buffer_strcpy(err, _("No current message"));
865  return false;
866 }
The "current" mailbox.
Definition: context.h:37
Single symbol.
Definition: pattern.c:148
#define _(a)
Definition: message.h:28
struct Menu * menu
needed for pattern compilation
Definition: context.h:47
Greater-than range.
Definition: pattern.c:147
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:316
char * dptr
current read/write position
Definition: buffer.h:36
Absolute range.
Definition: pattern.c:145
Less-than range.
Definition: pattern.c:146
Relative range.
Definition: pattern.c:144

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

877 {
878  int num;
879  unsigned char c;
880 
881  num = (int) strtol(&s->dptr[pmatch[group].rm_so], NULL, 0);
882  c = (unsigned char) (s->dptr[pmatch[group].rm_eo - 1]);
883  if (toupper(c) == 'K')
884  num *= KILO;
885  else if (toupper(c) == 'M')
886  num *= MEGA;
887  switch (kind)
888  {
889  case RANGE_K_REL:
890  return num + CTX_MSGNO(Context);
891  case RANGE_K_LT:
892  return num - 1;
893  case RANGE_K_GT:
894  return num + 1;
895  default:
896  return num;
897  }
898 }
The "current" mailbox.
Definition: context.h:37
#define MEGA
Definition: pattern.c:92
#define KILO
Definition: pattern.c:91
Greater-than range.
Definition: pattern.c:147
char * dptr
current read/write position
Definition: buffer.h:36
#define CTX_MSGNO(ctx)
Definition: pattern.c:94
Less-than range.
Definition: pattern.c:146
Relative range.
Definition: pattern.c:144

+ Here is the caller graph for this function:

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

910 {
911  unsigned char c;
912 
913  /* This means the left or right subpattern was empty, e.g. ",." */
914  if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
915  {
916  if (side == RANGE_S_LEFT)
917  return 1;
918  else if (side == RANGE_S_RIGHT)
919  return Context->mailbox->msg_count;
920  }
921  /* We have something, so determine what */
922  c = (unsigned char) (s->dptr[pmatch[grp].rm_so]);
923  switch (c)
924  {
925  case RANGE_CIRCUM:
926  return 1;
927  case RANGE_DOLLAR:
928  return Context->mailbox->msg_count;
929  case RANGE_DOT:
930  return CTX_MSGNO(Context);
931  case RANGE_LT:
932  case RANGE_GT:
933  return scan_range_num(s, pmatch, grp + 1, kind);
934  default:
935  /* Only other possibility: a number */
936  return scan_range_num(s, pmatch, grp, kind);
937  }
938 }
The "current" mailbox.
Definition: context.h:37
int msg_count
total number of messages
Definition: mailbox.h:93
#define RANGE_LT
Definition: pattern.c:113
#define RANGE_DOLLAR
Definition: pattern.c:112
struct Mailbox * mailbox
Definition: context.h:51
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind)
Parse a number range.
Definition: pattern.c:876
Left side of range.
Definition: pattern.c:158
char * dptr
current read/write position
Definition: buffer.h:36
#define RANGE_GT
Definition: pattern.c:114
#define RANGE_CIRCUM
Definition: pattern.c:111
#define CTX_MSGNO(ctx)
Definition: pattern.c:94
#define RANGE_DOT
Definition: pattern.c:110
Right side of range.
Definition: pattern.c:159

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void order_range ( struct Pattern pat)
static

Put a range in order.

Parameters
patPattern to check

Definition at line 944 of file pattern.c.

945 {
946  int num;
947 
948  if (pat->min <= pat->max)
949  return;
950  num = pat->min;
951  pat->min = pat->max;
952  pat->max = num;
953 }
int min
Definition: pattern.h:55
int max
Definition: pattern.h:56

+ Here is the caller graph for this function:

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

965 {
966  int regerr;
967  regmatch_t pmatch[RANGE_RX_GROUPS];
968  struct RangeRegex *pspec = &range_regexes[kind];
969 
970  /* First time through, compile the big regex */
971  if (!pspec->ready)
972  {
973  regerr = regcomp(&pspec->cooked, pspec->raw, REG_EXTENDED);
974  if (regerr)
975  return report_regerror(regerr, &pspec->cooked, err);
976  pspec->ready = 1;
977  }
978 
979  /* Match the pattern buffer against the compiled regex.
980  * No match means syntax error. */
981  regerr = regexec(&pspec->cooked, s->dptr, RANGE_RX_GROUPS, pmatch, 0);
982  if (regerr)
983  return report_regerror(regerr, &pspec->cooked, err);
984 
985  if (!is_context_available(s, pmatch, kind, err))
986  return RANGE_E_CTX;
987 
988  /* Snarf the contents of the two sides of the range. */
989  pat->min = scan_range_slot(s, pmatch, pspec->lgrp, RANGE_S_LEFT, kind);
990  pat->max = scan_range_slot(s, pmatch, pspec->rgrp, RANGE_S_RIGHT, kind);
991  mutt_debug(LL_DEBUG1, "pat->min=%d pat->max=%d\n", pat->min, pat->max);
992 
993  /* Special case for a bare 0. */
994  if ((kind == RANGE_K_BARE) && (pat->min == 0) && (pat->max == 0))
995  {
996  if (!Context->menu)
997  {
998  mutt_buffer_strcpy(err, _("No current message"));
999  return RANGE_E_CTX;
1000  }
1001  pat->max = CTX_MSGNO(Context);
1002  pat->min = pat->max;
1003  }
1004 
1005  /* Since we don't enforce order, we must swap bounds if they're backward */
1006  order_range(pat);
1007 
1008  /* Slide pointer past the entire match. */
1009  s->dptr += pmatch[0].rm_eo;
1010  return RANGE_E_OK;
1011 }
The "current" mailbox.
Definition: context.h:37
regex_t cooked
compiled form
Definition: pattern.c:136
Single symbol.
Definition: pattern.c:148
Range is valid.
Definition: pattern.c:122
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:124
struct Menu * menu
needed for pattern compilation
Definition: context.h:47
int ready
compiled yet?
Definition: pattern.c:135
int min
Definition: pattern.h:55
Left side of range.
Definition: pattern.c:158
Regular expression representing a range.
Definition: pattern.c:130
#define RANGE_RX_GROUPS
Definition: pattern.c:89
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:316
static struct RangeRegex range_regexes[]
Set of Regexes for various range types.
Definition: pattern.c:179
char * dptr
current read/write position
Definition: buffer.h:36
const char * raw
regex as string
Definition: pattern.c:132
Log at debug level 1.
Definition: logging.h:56
static void order_range(struct Pattern *pat)
Put a range in order.
Definition: pattern.c:944
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:909
int max
Definition: pattern.h:56
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
Definition: pattern.c:822
int lgrp
paren group matching the left side
Definition: pattern.c:133
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int rgrp
paren group matching the right side
Definition: pattern.c:134
#define CTX_MSGNO(ctx)
Definition: pattern.c:94
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:841
Right side of range.
Definition: pattern.c:159

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Parse a range of message numbers.

Parameters
patPattern to store the range in
sString to parse
errBuffer for error messages
Return values
trueIf the pattern was read successfully

Definition at line 1020 of file pattern.c.

1021 {
1022  bool skip_quote = false;
1023 
1024  /* We need a Context for pretty much anything. */
1025  if (!Context)
1026  {
1027  mutt_buffer_strcpy(err, _("No Context"));
1028  return false;
1029  }
1030 
1031  /* If simple_search is set to "~m %s", the range will have double quotes
1032  * around it... */
1033  if (*s->dptr == '"')
1034  {
1035  s->dptr++;
1036  skip_quote = true;
1037  }
1038 
1039  for (int i_kind = 0; i_kind != RANGE_K_INVALID; i_kind++)
1040  {
1041  switch (eat_range_by_regex(pat, s, i_kind, err))
1042  {
1043  case RANGE_E_CTX:
1044  /* This means it matched syntactically but lacked context.
1045  * No point in continuing. */
1046  break;
1047  case RANGE_E_SYNTAX:
1048  /* Try another syntax, then */
1049  continue;
1050  case RANGE_E_OK:
1051  if (skip_quote && (*s->dptr == '"'))
1052  s->dptr++;
1053  SKIPWS(s->dptr);
1054  return true;
1055  }
1056  }
1057  return false;
1058 }
The "current" mailbox.
Definition: context.h:37
Range is valid.
Definition: pattern.c:122
Range contains syntax error.
Definition: pattern.c:123
#define _(a)
Definition: message.h:28
Range requires Context, but none available.
Definition: pattern.c:124
#define SKIPWS(ch)
Definition: string2.h:46
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:316
char * dptr
current read/write position
Definition: buffer.h:36
Range is invalid.
Definition: pattern.c:150
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:963

+ Here is the call graph for this function:

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

Compare a string to a Pattern.

Parameters
patPattern to use
bufString to compare
Return values
0Match
1No match

Definition at line 1067 of file pattern.c.

1068 {
1069  if (pat->ismulti)
1070  return (mutt_list_find(&pat->p.multi_cases, buf) == NULL);
1071  else if (pat->stringmatch)
1072  return pat->ign_case ? !strcasestr(buf, pat->p.str) : !strstr(buf, pat->p.str);
1073  else if (pat->groupmatch)
1074  return !mutt_group_match(pat->p.group, buf);
1075  else
1076  return regexec(pat->p.regex, buf, 0, NULL, 0);
1077 }
regex_t * regex
Definition: pattern.h:60
bool mutt_group_match(struct Group *g, const char *s)
Does a string match an entry in a Group?
Definition: group.c:321
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:88
bool ign_case
ignore case for local stringmatch searches
Definition: pattern.h:52
union Pattern::@2 p
char * str
Definition: pattern.h:62
struct Group * group
Definition: pattern.h:61
bool groupmatch
Definition: pattern.h:51
bool stringmatch
Definition: pattern.h:50
struct ListHead multi_cases
Definition: pattern.h:63
bool ismulti
multiple case (only for I pattern now)
Definition: pattern.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1088 {
1089  bool match = false;
1090  struct Message *msg = mx_msg_open(m, msgno);
1091  if (!msg)
1092  {
1093  return match;
1094  }
1095 
1096  FILE *fp = NULL;
1097  long lng = 0;
1098  struct Email *e = m->emails[msgno];
1099 #ifdef USE_FMEMOPEN
1100  char *temp = NULL;
1101  size_t tempsize;
1102 #else
1103  struct stat st;
1104 #endif
1105 
1106  if (C_ThoroughSearch)
1107  {
1108  /* decode the header / body */
1109  struct State s = { 0 };
1110  s.fp_in = msg->fp;
1111  s.flags = MUTT_CHARCONV;
1112 #ifdef USE_FMEMOPEN
1113  s.fp_out = open_memstream(&temp, &tempsize);
1114  if (!s.fp_out)
1115  {
1116  mutt_perror(_("Error opening 'memory stream'"));
1117  return false;
1118  }
1119 #else
1120  s.fp_out = mutt_file_mkstemp();
1121  if (!s.fp_out)
1122  {
1123  mutt_perror(_("Can't create temporary file"));
1124  return false;
1125  }
1126 #endif
1127 
1128  if (pat->op != MUTT_PAT_BODY)
1129  mutt_copy_header(msg->fp, e, s.fp_out, CH_FROM | CH_DECODE, NULL);
1130 
1131  if (pat->op != MUTT_PAT_HEADER)
1132  {
1134 
1135  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) &&
1137  {
1138  mx_msg_close(m, &msg);
1139  if (s.fp_out)
1140  {
1142 #ifdef USE_FMEMOPEN
1143  FREE(&temp);
1144 #endif
1145  }
1146  return false;
1147  }
1148 
1149  fseeko(msg->fp, e->offset, SEEK_SET);
1150  mutt_body_handler(e->content, &s);
1151  }
1152 
1153 #ifdef USE_FMEMOPEN
1154  fclose(s.fp_out);
1155  lng = tempsize;
1156 
1157  if (tempsize)
1158  {
1159  fp = fmemopen(temp, tempsize, "r");
1160  if (!fp)
1161  {
1162  mutt_perror(_("Error re-opening 'memory stream'"));
1163  return false;
1164  }
1165  }
1166  else
1167  { /* fmemopen cannot handle empty buffers */
1168  fp = mutt_file_fopen("/dev/null", "r");
1169  if (!fp)
1170  {
1171  mutt_perror(_("Error opening /dev/null"));
1172  return false;
1173  }
1174  }
1175 #else
1176  fp = s.fp_out;
1177  fflush(fp);
1178  fseek(fp, 0, SEEK_SET);
1179  fstat(fileno(fp), &st);
1180  lng = (long) st.st_size;
1181 #endif
1182  }
1183  else
1184  {
1185  /* raw header / body */
1186  fp = msg->fp;
1187  if (pat->op != MUTT_PAT_BODY)
1188  {
1189  fseeko(fp, e->offset, SEEK_SET);
1190  lng = e->content->offset - e->offset;
1191  }
1192  if (pat->op != MUTT_PAT_HEADER)
1193  {
1194  if (pat->op == MUTT_PAT_BODY)
1195  fseeko(fp, e->content->offset, SEEK_SET);
1196  lng += e->content->length;
1197  }
1198  }
1199 
1200  size_t blen = 256;
1201  char *buf = mutt_mem_malloc(blen);
1202 
1203  /* search the file "fp" */
1204  while (lng > 0)
1205  {
1206  if (pat->op == MUTT_PAT_HEADER)
1207  {
1208  buf = mutt_rfc822_read_line(fp, buf, &blen);
1209  if (*buf == '\0')
1210  break;
1211  }
1212  else if (!fgets(buf, blen - 1, fp))
1213  break; /* don't loop forever */
1214  if (patmatch(pat, buf) == 0)
1215  {
1216  match = true;
1217  break;
1218  }
1219  lng -= mutt_str_strlen(buf);
1220  }
1221 
1222  FREE(&buf);
1223 
1224  mx_msg_close(m, &msg);
1225 
1226  if (C_ThoroughSearch)
1227  {
1228  mutt_file_fclose(&fp);
1229 #ifdef USE_FMEMOPEN
1230  if (tempsize)
1231  FREE(&temp);
1232 #endif
1233  }
1234 
1235  return match;
1236 }
struct Email ** emails
Definition: mailbox.h:100
Pattern matches email&#39;s header.
Definition: pattern.h:123
static int patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1067
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:89
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
struct Body * content
list of MIME parts
Definition: email.h:93
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:50
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
#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:662
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:120
FILE * fp_in
File to read from.
Definition: state.h:46
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix)
Copy Email header.
Definition: copy.c:386
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:1058
int crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:144
A local copy of an email.
Definition: mx.h:81
LOFF_T length
length (in bytes) of attachment
Definition: body.h:47
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
#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:71
#define mutt_file_mkstemp()
Definition: file.h:103
short op
Definition: pattern.h:47
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
LOFF_T offset
where in the stream does this message begin?
Definition: email.h:86
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:546
Pattern matches email&#39;s body.
Definition: pattern.h:122
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:1524
#define WithCrypto
Definition: ncrypt.h:155
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1010
int msgno
number displayed to the user
Definition: email.h:89
char * mutt_rfc822_read_line(FILE *fp, char *line, size_t *linelen)
Read a header line from a file.
Definition: parse.c:940

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1303 {
1304  for (int i = 0; Flags[i].tag; i++)
1305  if (Flags[i].tag == tag)
1306  return &Flags[i];
1307  return NULL;
1308 }
int tag
character used to represent this op
Definition: pattern.c:167
static const struct PatternFlags Flags[]
Lookup table for all patterns.
Definition: pattern.c:1242

+ Here is the caller graph for this function:

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

1317 {
1318  int level = 1;
1319 
1320  for (; *s; s++)
1321  {
1322  if (*s == '(')
1323  level++;
1324  else if (*s == ')')
1325  {
1326  level--;
1327  if (!level)
1328  break;
1329  }
1330  }
1331  return s;
1332 }

+ Here is the caller graph for this function:

void mutt_pattern_free ( struct Pattern **  pat)

Free a Pattern.

Parameters
[out]patPattern to free

Definition at line 1338 of file pattern.c.

1339 {
1340  if (!pat || !*pat)
1341  return;
1342 
1343  struct Pattern *tmp = NULL;
1344 
1345  while (*pat)
1346  {
1347  tmp = *pat;
1348  *pat = (*pat)->next;
1349 
1350  if (tmp->ismulti)
1351  mutt_list_free(&tmp->p.multi_cases);
1352  else if (tmp->stringmatch)
1353  FREE(&tmp->p.str);
1354  else if (tmp->groupmatch)
1355  tmp->p.group = NULL;
1356  else if (tmp->p.regex)
1357  {
1358  regfree(tmp->p.regex);
1359  FREE(&tmp->p.regex);
1360  }
1361 
1362  mutt_pattern_free(&tmp->child);
1363  FREE(&tmp);
1364  }
1365 }
regex_t * regex
Definition: pattern.h:60
void mutt_pattern_free(struct Pattern **pat)
Free a Pattern.
Definition: pattern.c:1338
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:105
A simple (non-regex) pattern.
Definition: pattern.h:45
struct Pattern * next
Definition: pattern.h:57
struct Pattern * child
arguments to logical op
Definition: pattern.h:58
union Pattern::@2 p
char * str
Definition: pattern.h:62
struct Group * group
Definition: pattern.h:61
#define FREE(x)
Definition: memory.h:40
bool groupmatch
Definition: pattern.h:51
bool stringmatch
Definition: pattern.h:50
struct ListHead multi_cases
Definition: pattern.h:63
bool ismulti
multiple case (only for I pattern now)
Definition: pattern.h:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

struct Pattern* mutt_pattern_new ( void  )

Create a new Pattern.

Return values
ptrNew Pattern

Definition at line 1371 of file pattern.c.

1372 {
1373  return mutt_mem_calloc(1, sizeof(struct Pattern));
1374 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
A simple (non-regex) pattern.
Definition: pattern.h:45

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

struct Pattern* mutt_pattern_comp ( char *  s,
int  flags,
struct Buffer err 
)

Create a Pattern.

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

Definition at line 1383 of file pattern.c.

1384 {
1385  struct Pattern *curlist = NULL;
1386  struct Pattern *tmp = NULL, *tmp2 = NULL;
1387  struct Pattern *last = NULL;
1388  bool not = false;
1389  bool alladdr = false;
1390  bool or = false;
1391  bool implicit = true; /* used to detect logical AND operator */
1392  bool isalias = false;
1393  short thread_op;
1394  const struct PatternFlags *entry = NULL;
1395  char *p = NULL;
1396  char *buf = NULL;
1397  struct Buffer ps;
1398 
1399  mutt_buffer_init(&ps);
1400  ps.dptr = s;
1401  ps.dsize = mutt_str_strlen(s);
1402 
1403  while (*ps.dptr)
1404  {
1405  SKIPWS(ps.dptr);
1406  switch (*ps.dptr)
1407  {
1408  case '^':
1409  ps.dptr++;
1410  alladdr = !alladdr;
1411  break;
1412  case '!':
1413  ps.dptr++;
1414  not = !not;
1415  break;
1416  case '@':
1417  ps.dptr++;
1418  isalias = !isalias;
1419  break;
1420  case '|':
1421  if (! or)
1422  {
1423  if (!curlist)
1424  {
1425  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1426  return NULL;
1427  }
1428  if (curlist->next)
1429  {
1430  /* A & B | C == (A & B) | C */
1431  tmp = mutt_pattern_new();
1432  tmp->op = MUTT_PAT_AND;
1433  tmp->child = curlist;
1434 
1435  curlist = tmp;
1436  last = curlist;
1437  }
1438 
1439  or = true;
1440  }
1441  ps.dptr++;
1442  implicit = false;
1443  not = false;
1444  alladdr = false;
1445  isalias = false;
1446  break;
1447  case '%':
1448  case '=':
1449  case '~':
1450  if (!*(ps.dptr + 1))
1451  {
1452  mutt_buffer_printf(err, _("missing pattern: %s"), ps.dptr);
1453  mutt_pattern_free(&curlist);
1454  return NULL;
1455  }
1456  thread_op = 0;
1457  if (*(ps.dptr + 1) == '(')
1458  thread_op = MUTT_PAT_THREAD;
1459  else if ((*(ps.dptr + 1) == '<') && (*(ps.dptr + 2) == '('))
1460  thread_op = MUTT_PAT_PARENT;
1461  else if ((*(ps.dptr + 1) == '>') && (*(ps.dptr + 2) == '('))
1462  thread_op = MUTT_PAT_CHILDREN;
1463  if (thread_op)
1464  {
1465  ps.dptr++; /* skip ~ */
1466  if ((thread_op == MUTT_PAT_PARENT) || (thread_op == MUTT_PAT_CHILDREN))
1467  ps.dptr++;
1468  p = find_matching_paren(ps.dptr + 1);
1469  if (*p != ')')
1470  {
1471  mutt_buffer_printf(err, _("mismatched brackets: %s"), ps.dptr);
1472  mutt_pattern_free(&curlist);
1473  return NULL;
1474  }
1475  tmp = mutt_pattern_new();
1476  tmp->op = thread_op;
1477  if (last)
1478  last->next = tmp;
1479  else
1480  curlist = tmp;
1481  last = tmp;
1482  tmp->not ^= not;
1483  tmp->alladdr |= alladdr;
1484  tmp->isalias |= isalias;
1485  not = false;
1486  alladdr = false;
1487  isalias = false;
1488  /* compile the sub-expression */
1489  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1490  tmp2 = mutt_pattern_comp(buf, flags, err);
1491  if (!tmp2)
1492  {
1493  FREE(&buf);
1494  mutt_pattern_free(&curlist);
1495  return NULL;
1496  }
1497  FREE(&buf);
1498  tmp->child = tmp2;
1499  ps.dptr = p + 1; /* restore location */
1500  break;
1501  }
1502  if (implicit && or)
1503  {
1504  /* A | B & C == (A | B) & C */
1505  tmp = mutt_pattern_new();
1506  tmp->op = MUTT_PAT_OR;
1507  tmp->child = curlist;
1508  curlist = tmp;
1509  last = tmp;
1510  or = false;
1511  }
1512 
1513  tmp = mutt_pattern_new();
1514  tmp->not = not;
1515  tmp->alladdr = alladdr;
1516  tmp->isalias = isalias;
1517  tmp->stringmatch = (*ps.dptr == '=');
1518  tmp->groupmatch = (*ps.dptr == '%');
1519  not = false;
1520  alladdr = false;
1521  isalias = false;
1522 
1523  if (last)
1524  last->next = tmp;
1525  else
1526  curlist = tmp;
1527  last = tmp;
1528 
1529  ps.dptr++; /* move past the ~ */
1530  entry = lookup_tag(*ps.dptr);
1531  if (!entry)
1532  {
1533  mutt_buffer_printf(err, _("%c: invalid pattern modifier"), *ps.dptr);
1534  mutt_pattern_free(&curlist);
1535  return NULL;
1536  }
1537  if (entry->class && ((flags & entry->class) == 0))
1538  {
1539  mutt_buffer_printf(err, _("%c: not supported in this mode"), *ps.dptr);
1540  mutt_pattern_free(&curlist);
1541  return NULL;
1542  }
1543  tmp->op = entry->op;
1544 
1545  ps.dptr++; /* eat the operator and any optional whitespace */
1546  SKIPWS(ps.dptr);
1547 
1548  if (entry->eat_arg)
1549  {
1550  if (!*ps.dptr)
1551  {
1552  mutt_buffer_printf(err, "%s", _("missing parameter"));
1553  mutt_pattern_free(&curlist);
1554  return NULL;
1555  }
1556  if (!entry->eat_arg(tmp, &ps, err))
1557  {
1558  mutt_pattern_free(&curlist);
1559  return NULL;
1560  }
1561  }
1562  implicit = true;
1563  break;
1564  case '(':
1565  p = find_matching_paren(ps.dptr + 1);
1566  if (*p != ')')
1567  {
1568  mutt_buffer_printf(err, _("mismatched parenthesis: %s"), ps.dptr);
1569  mutt_pattern_free(&curlist);
1570  return NULL;
1571  }
1572  /* compile the sub-expression */
1573  buf = mutt_str_substr_dup(ps.dptr + 1, p);
1574  tmp = mutt_pattern_comp(buf, flags, err);
1575  if (!tmp)
1576  {
1577  FREE(&buf);
1578  mutt_pattern_free(&curlist);
1579  return NULL;
1580  }
1581  FREE(&buf);
1582  if (last)
1583  last->next = tmp;
1584  else
1585  curlist = tmp;
1586  last = tmp;
1587  tmp->not ^= not;
1588  tmp->alladdr |= alladdr;
1589  tmp->isalias |= isalias;
1590  not = false;
1591  alladdr = false;
1592  isalias = false;
1593  ps.dptr = p + 1; /* restore location */
1594  break;
1595  default:
1596  mutt_buffer_printf(err, _("error in pattern at: %s"), ps.dptr);
1597  mutt_pattern_free(&curlist);
1598  return NULL;
1599  }
1600  }
1601  if (!curlist)
1602  {
1603  mutt_buffer_strcpy(err, _("empty pattern"));
1604  return NULL;
1605  }
1606  if (curlist->next)
1607  {
1608  tmp = mutt_pattern_new();
1609  tmp->op = or ? MUTT_PAT_OR : MUTT_PAT_AND;
1610  tmp->child = curlist;
1611  curlist = tmp;
1612  }
1613  return curlist;
1614 }
bool not
Definition: pattern.h:48
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
void mutt_pattern_free(struct Pattern **pat)
Free a Pattern.
Definition: pattern.c:1338
static char * find_matching_paren(char *s)
Find the matching parenthesis.
Definition: pattern.c:1316
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:662
Pattern matches a child email.
Definition: pattern.h:109
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:200
A simple (non-regex) pattern.
Definition: pattern.h:45
int op
operation to perform
Definition: pattern.c:168
struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
Definition: pattern.c:1371
struct Pattern * next
Definition: pattern.h:57
static const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
Definition: pattern.c:1302
#define SKIPWS(ch)
Definition: string2.h:46
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:316
Either pattern can match.
Definition: pattern.h:106
struct Pattern * child
arguments to logical op
Definition: pattern.h:58
int class
Pattern class, e.g.
Definition: pattern.c:169
short op
Definition: pattern.h:47
Pattern matches parent.
Definition: pattern.h:108
struct Pattern * mutt_pattern_comp(char *s, int flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1383
bool isalias
Definition: pattern.h:53
bool(* eat_arg)(struct Pattern *, struct Buffer *, struct Buffer *)
Callback function to parse the argument.
Definition: pattern.c:170
Both patterns must match.
Definition: pattern.h:105
#define FREE(x)
Definition: memory.h:40
bool groupmatch
Definition: pattern.h:51
bool stringmatch
Definition: pattern.h:50
bool alladdr
Definition: pattern.h:49
Pattern matches email thread.
Definition: pattern.h:107
Mapping between user character and internal constant.
Definition: pattern.c:165
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:575

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool perform_and ( struct Pattern pat,
enum PatternExecFlag  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 1625 of file pattern.c.

1627 {
1628  for (; pat; pat = pat->next)
1629  if (mutt_pattern_exec(pat, flags, m, e, cache) <= 0)
1630  return false;
1631  return true;
1632 }
struct Pattern * next
Definition: pattern.h:57
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int perform_or ( struct Pattern pat,
enum PatternExecFlag  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 1643 of file pattern.c.

1645 {
1646  for (; pat; pat = pat->next)
1647  if (mutt_pattern_exec(pat, flags, m, e, cache) > 0)
1648  return true;
1649  return false;
1650 }
struct Pattern * next
Definition: pattern.h:57
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 (alladdr is false)
trueAll the Addresses match (alladdr is true)

Definition at line 1661 of file pattern.c.

1662 {
1663  va_list ap;
1664 
1665  va_start(ap, n);
1666  for (; n; n--)
1667  {
1668  for (struct Address *a = va_arg(ap, struct Address *); a; a = a->next)
1669  {
1670  if (pat->alladdr ^ ((!pat->isalias || mutt_alias_reverse_lookup(a)) &&
1671  ((a->mailbox && !patmatch(pat, a->mailbox)) ||
1672  (match_personal && a->personal && !patmatch(pat, a->personal)))))
1673  {
1674  va_end(ap);
1675  return !pat->alladdr; /* Found match, or non-match if alladdr */
1676  }
1677  }
1678  }
1679  va_end(ap);
1680  return pat->alladdr; /* No matches, or all matches if alladdr */
1681 }
static int patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1067
struct Address * mutt_alias_reverse_lookup(struct Address *a)
Does the user have an alias for the given address.
Definition: alias.c:537
An email address.
Definition: address.h:32
bool isalias
Definition: pattern.h:53
bool alladdr
Definition: pattern.h:49
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1690 {
1691  struct ListNode *np = NULL;
1692  STAILQ_FOREACH(np, refs, entries)
1693  {
1694  if (patmatch(pat, np->data) == 0)
1695  return true;
1696  }
1697  return false;
1698 }
static int patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1067
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
char * data
Definition: list.h:35
A List node for strings.
Definition: list.h:33

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_is_list_recipient ( bool  alladdr,
struct Address a1,
struct Address a2 
)

Matches subscribed mailing lists.

Parameters
alladdrIf true, ALL Addresses must be on the subscribed list
a1First Address list
a2Second Address list
Return values
trueOne Address is subscribed (alladdr is false)
trueAll the Addresses are subscribed (alladdr is true)

Definition at line 1708 of file pattern.c.

1709 {
1710  for (; a1; a1 = a1->next)
1711  if (alladdr ^ mutt_is_subscribed_list(a1))
1712  return !alladdr;
1713  for (; a2; a2 = a2->next)
1714  if (alladdr ^ mutt_is_subscribed_list(a2))
1715  return !alladdr;
1716  return alladdr;
1717 }
bool mutt_is_subscribed_list(struct Address *addr)
Is this the email address of a user-subscribed mailing list?
Definition: hdrline.c:111
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_is_list_cc ( int  alladdr,
struct Address a1,
struct Address a2 
)

Matches known mailing lists.

Parameters
alladdrIf true, ALL Addresses must be mailing lists
a1First Address list
a2Second Address list
Return values
trueOne Address is a mailing list (alladdr is false)
trueAll the Addresses are mailing lists (alladdr is true)

The function name may seem a little bit misleading: It checks all recipients in To and Cc for known mailing lists, subscribed or not.

Definition at line 1730 of file pattern.c.

1731 {
1732  for (; a1; a1 = a1->next)
1733  if (alladdr ^ mutt_is_mail_list(a1))
1734  return !alladdr;
1735  for (; a2; a2 = a2->next)
1736  if (alladdr ^ mutt_is_mail_list(a2))
1737  return !alladdr;
1738  return alladdr;
1739 }
bool mutt_is_mail_list(struct Address *addr)
Is this the email address of a mailing list?
Definition: hdrline.c:99
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int match_user ( int  alladdr,
struct Address a1,
struct Address a2 
)
static

Matches the user's email Address.

Parameters
alladdrIf true, ALL Addresses must refer to the user
a1First Address list
a2Second Address list
Return values
trueOne Address refers to the user (alladdr is false)
trueAll the Addresses refer to the user (alladdr is true)

Definition at line 1749 of file pattern.c.

1750 {
1751  for (; a1; a1 = a1->next)
1752  if (alladdr ^ mutt_addr_is_user(a1))
1753  return !alladdr;
1754  for (; a2; a2 = a2->next)
1755  if (alladdr ^ mutt_addr_is_user(a2))
1756  return !alladdr;
1757  return alladdr;
1758 }
bool mutt_addr_is_user(struct Address *addr)
Does the address belong to the user.
Definition: alias.c:678
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int match_threadcomplete ( struct Pattern pat,
enum PatternExecFlag  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 1773 of file pattern.c.

1776 {
1777  int a;
1778  struct Email *e = NULL;
1779 
1780  if (!t)
1781  return 0;
1782  e = t->message;
1783  if (e)
1784  if (mutt_pattern_exec(pat, flags, m, e, NULL))
1785  return 1;
1786 
1787  if (up && (a = match_threadcomplete(pat, flags, m, t->parent, 1, 1, 1, 0)))
1788  return a;
1789  if (right && t->parent && (a = match_threadcomplete(pat, flags, m, t->next, 0, 0, 1, 1)))
1790  {
1791  return a;
1792  }
1793  if (left && t->parent && (a = match_threadcomplete(pat, flags, m, t->prev, 1, 0, 0, 1)))
1794  {
1795  return a;
1796  }
1797  if (down && (a = match_threadcomplete(pat, flags, m, t->child, 1, 0, 1, 1)))
1798  return a;
1799  return 0;
1800 }
struct MuttThread * next
Definition: thread.h:46
The envelope/body of an email.
Definition: email.h:37
struct MuttThread * parent
Definition: thread.h:44
struct MuttThread * prev
Definition: thread.h:47
struct MuttThread * child
Definition: thread.h:45
static int match_threadcomplete(struct Pattern *pat, enum PatternExecFlag 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:1773
struct Email * message
Definition: thread.h:48
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int match_threadparent ( struct Pattern pat,
enum PatternExecFlag  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 1812 of file pattern.c.

1814 {
1815  if (!t || !t->parent || !t->parent->message)
1816  return 0;
1817 
1818  return mutt_pattern_exec(pat, flags, m, t->parent->message, NULL);
1819 }
struct MuttThread * parent
Definition: thread.h:44
struct Email * message
Definition: thread.h:48
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int match_threadchildren ( struct Pattern pat,
enum PatternExecFlag  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 1831 of file pattern.c.

1833 {
1834  if (!t || !t->child)
1835  return 0;
1836 
1837  for (t = t->child; t; t = t->next)
1838  if (t->message && mutt_pattern_exec(pat, flags, m, t->message, NULL))
1839  return 1;
1840 
1841  return 0;
1842 }
struct MuttThread * next
Definition: thread.h:46
struct MuttThread * child
Definition: thread.h:45
struct Email * message
Definition: thread.h:48
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int 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
1Success, pattern matched
0Pattern did not match

Definition at line 1851 of file pattern.c.

1852 {
1853  char buf[256];
1854  if (!b)
1855  return 0;
1856 
1857  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1858 
1859  if (patmatch(pat, buf) == 0)
1860  return 1;
1861  if (match_content_type(pat, b->parts))
1862  return 1;
1863  if (match_content_type(pat, b->next))
1864  return 1;
1865  return 0;
1866 }
static int patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1067
struct Body * next
next attachment in the list
Definition: body.h:58
char * subtype
content-type subtype
Definition: body.h:37
static int match_content_type(const struct Pattern *pat, struct Body *b)
Match a Pattern against an Attachment&#39;s Content-Type.
Definition: pattern.c:1851
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:59
#define TYPE(body)
Definition: mime.h:83

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int 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
1Success, pattern matched
0Pattern did not match

Definition at line 1876 of file pattern.c.

1878 {
1880  return match_content_type(pat, e->content);
1881 }
struct Body * content
list of MIME parts
Definition: email.h:93
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:50
static int match_content_type(const struct Pattern *pat, struct Body *b)
Match a Pattern against an Attachment&#39;s Content-Type.
Definition: pattern.c:1851

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

1891 {
1892  *cache_entry = value ? 2 : 1;
1893 }

+ Here is the caller graph for this function:

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

1902 {
1903  return cache_entry == 2;
1904 }

+ Here is the caller graph for this function:

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

1912 {
1913  return cache_entry != 0;
1914 }

+ Here is the caller graph for this function:

int mutt_pattern_exec ( struct Pattern pat,
enum PatternExecFlag  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 1931 of file pattern.c.

1933 {
1934  int result;
1935  int *cache_entry = NULL;
1936 
1937  switch (pat->op)
1938  {
1939  case MUTT_PAT_AND:
1940  return pat->not^(perform_and(pat->child, flags, m, e, cache) > 0);
1941  case MUTT_PAT_OR:
1942  return pat->not^(perform_or(pat->child, flags, m, e, cache) > 0);
1943  case MUTT_PAT_THREAD:
1944  return pat->not^match_threadcomplete(pat->child, flags, m, e->thread, 1, 1, 1, 1);
1945  case MUTT_PAT_PARENT:
1946  return pat->not^match_threadparent(pat->child, flags, m, e->thread);
1947  case MUTT_PAT_CHILDREN:
1948  return pat->not^match_threadchildren(pat->child, flags, m, e->thread);
1949  case MUTT_ALL:
1950  return !pat->not;
1951  case MUTT_EXPIRED:
1952  return pat->not^e->expired;
1953  case MUTT_SUPERSEDED:
1954  return pat->not^e->superseded;
1955  case MUTT_FLAG:
1956  return pat->not^e->flagged;
1957  case MUTT_TAG:
1958  return pat->not^e->tagged;
1959  case MUTT_NEW:
1960  return pat->not? e->old || e->read : !(e->old || e->read);
1961  case MUTT_UNREAD:
1962  return pat->not? e->read : !e->read;
1963  case MUTT_REPLIED:
1964  return pat->not^e->replied;
1965  case MUTT_OLD:
1966  return pat->not? (!e->old || e->read) : (e->old && !e->read);
1967  case MUTT_READ:
1968  return pat->not^e->read;
1969  case MUTT_DELETED:
1970  return pat->not^e->deleted;
1971  case MUTT_PAT_MESSAGE:
1972  return pat->not^((EMSG(e) >= pat->min) && (EMSG(e) <= pat->max));
1973  case MUTT_PAT_DATE:
1974  return pat->not^(e->date_sent >= pat->min && e->date_sent <= pat->max);
1976  return pat->not^(e->received >= pat->min && e->received <= pat->max);
1977  case MUTT_PAT_BODY:
1978  case MUTT_PAT_HEADER:
1979  case MUTT_PAT_WHOLE_MSG:
1980  /* m can be NULL in certain cases, such as when replying to a message
1981  * from the attachment menu and the user has a reply-hook using "~e" (bug
1982  * #2190).
1983  * This is also the case when message scoring. */
1984  if (!m)
1985  return 0;
1986 #ifdef USE_IMAP
1987  /* IMAP search sets e->matched at search compile time */
1988  if ((m->magic == MUTT_IMAP) && pat->stringmatch)
1989  return e->matched;
1990 #endif
1991  return pat->not^msg_search(m, pat, e->msgno);
1992  case MUTT_PAT_SERVERSEARCH:
1993 #ifdef USE_IMAP
1994  if (!m)
1995  return 0;
1996  if (m->magic == MUTT_IMAP)
1997  {
1998  if (pat->stringmatch)
1999  return e->matched;
2000  return 0;
2001  }
2002  mutt_error(_("error: server custom search only supported with IMAP"));
2003  return 0;
2004 #else
2005  mutt_error(_("error: server custom search only supported with IMAP"));
2006  return -1;
2007 #endif
2008  case MUTT_PAT_SENDER:
2009  if (!e->env)
2010  return 0;
2011  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1,
2012  e->env->sender);
2013  case MUTT_PAT_FROM:
2014  if (!e->env)
2015  return 0;
2016  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1,
2017  e->env->from);
2018  case MUTT_PAT_TO:
2019  if (!e->env)
2020  return 0;
2021  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1,
2022  e->env->to);
2023  case MUTT_PAT_CC:
2024  if (!e->env)
2025  return 0;
2026  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 1,
2027  e->env->cc);
2028  case MUTT_PAT_SUBJECT:
2029  if (!e->env)
2030  return 0;
2031  return pat->not^(e->env->subject &&patmatch(pat, e->env->subject) == 0);
2032  case MUTT_PAT_ID:
2033  case MUTT_PAT_ID_EXTERNAL:
2034  if (!e->env)
2035  return 0;
2036  return pat->not^(e->env->message_id &&patmatch(pat, e->env->message_id) == 0);
2037  case MUTT_PAT_SCORE:
2038  return pat->not^(e->score >= pat->min &&
2039  (pat->max == MUTT_MAXRANGE || e->score <= pat->max));
2040  case MUTT_PAT_SIZE:
2041  return pat->not^(e->content->length >= pat->min &&
2042  (pat->max == MUTT_MAXRANGE || e->content->length <= pat->max));
2043  case MUTT_PAT_REFERENCE:
2044  if (!e->env)
2045  return 0;
2046  return pat->not^(match_reference(pat, &e->env->references) ||
2047  match_reference(pat, &e->env->in_reply_to));
2048  case MUTT_PAT_ADDRESS:
2049  if (!e->env)
2050  return 0;
2051  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 4,
2052  e->env->from, e->env->sender, e->env->to,
2053  e->env->cc);
2054  case MUTT_PAT_RECIPIENT:
2055  if (!e->env)
2056  return 0;
2057  return pat->not^match_addrlist(pat, (flags & MUTT_MATCH_FULL_ADDRESS), 2,
2058  e->env->to, e->env->cc);
2059  case MUTT_PAT_LIST: /* known list, subscribed or not */
2060  if (!e->env)
2061  return 0;
2062  if (cache)
2063  {
2064  cache_entry = pat->alladdr ? &cache->list_all : &cache->list_one;
2065  if (!is_pattern_cache_set(*cache_entry))
2066  {
2068  cache_entry, mutt_is_list_cc(pat->alladdr, e->env->to, e->env->cc));
2069  }
2070  result = get_pattern_cache_value(*cache_entry);
2071  }
2072  else
2073  result = mutt_is_list_cc(pat->alladdr, e->env->to, e->env->cc);
2074  return pat->not^result;
2076  if (!e->env)
2077  return 0;
2078  if (cache)
2079  {
2080  cache_entry = pat->alladdr ? &cache->sub_all : &cache->sub_one;
2081  if (!is_pattern_cache_set(*cache_entry))
2082  {
2084  cache_entry,
2085  mutt_is_list_recipient(pat->alladdr, e->env->to, e->env->cc));
2086  }
2087  result = get_pattern_cache_value(*cache_entry);
2088  }
2089  else
2090  result = mutt_is_list_recipient(pat->alladdr, e->env->to, e->env->cc);
2091  return pat->not^result;
2093  if (!e->env)
2094  return 0;
2095  if (cache)
2096  {
2097  cache_entry = pat->alladdr ? &cache->pers_recip_all : &cache->pers_recip_one;
2098  if (!is_pattern_cache_set(*cache_entry))
2099  {
2100  set_pattern_cache_value(cache_entry,
2101  match_user(pat->alladdr, e->env->to, e->env->cc));
2102  }
2103  result = get_pattern_cache_value(*cache_entry);
2104  }
2105  else
2106  result = match_user(pat->alladdr, e->env->to, e->env->cc);
2107  return pat->not^result;
2109  if (!e->env)
2110  return 0;
2111  if (cache)
2112  {
2113  cache_entry = pat->alladdr ? &cache->pers_from_all : &cache->pers_from_one;
2114  if (!is_pattern_cache_set(*cache_entry))
2115  set_pattern_cache_value(cache_entry, match_user(pat->alladdr, e->env->from, NULL));
2116  result = get_pattern_cache_value(*cache_entry);
2117  }
2118  else
2119  result = match_user(pat->alladdr, e->env->from, NULL);
2120  return pat->not^result;
2121  case MUTT_PAT_COLLAPSED:
2122  return pat->not^(e->collapsed && e->num_hidden > 1);
2123  case MUTT_PAT_CRYPT_SIGN:
2124  if (!WithCrypto)
2125  break;
2126  return pat->not^((e->security & SEC_SIGN) ? 1 : 0);
2128  if (!WithCrypto)
2129  break;
2130  return pat->not^((e->security & SEC_GOODSIGN) ? 1 : 0);
2132  if (!WithCrypto)
2133  break;
2134  return pat->not^((e->security & SEC_ENCRYPT) ? 1 : 0);
2135  case MUTT_PAT_PGP_KEY:
2136  if (!(WithCrypto & APPLICATION_PGP))
2137  break;
2138  return pat->not^((e->security & PGP_KEY) == PGP_KEY);
2139  case MUTT_PAT_XLABEL:
2140  if (!e->env)
2141  return 0;
2142  return pat->not^(e->env->x_label &&patmatch(pat, e->env->x_label) == 0);
2143  case MUTT_PAT_DRIVER_TAGS:
2144  {
2145  char *tags = driver_tags_get(&e->tags);
2146  bool rc = (pat->not^(tags &&patmatch(pat, tags) == 0));
2147  FREE(&tags);
2148  return rc;
2149  }
2150  case MUTT_PAT_HORMEL:
2151  if (!e->env)
2152  return 0;
2153  return pat->not^(e->env->spam && e->env->spam->data &&
2154  patmatch(pat, e->env->spam->data) == 0);
2155  case MUTT_PAT_DUPLICATED:
2156  return pat->not^(e->thread && e->thread->duplicate_thread);
2157  case MUTT_PAT_MIMEATTACH:
2158  if (!m)
2159  return 0;
2160  {
2161  int count = mutt_count_body_parts(m, e);
2162  return pat->not^(count >= pat->min &&
2163  (pat->max == MUTT_MAXRANGE || count <= pat->max));
2164  }
2165  case MUTT_PAT_MIMETYPE:
2166  if (!m)
2167  return 0;
2168  return pat->not^match_mime_content_type(pat, m, e);
2169  case MUTT_PAT_UNREFERENCED:
2170  return pat->not^(e->thread && !e->thread->child);
2171  case MUTT_PAT_BROKEN:
2172  return pat->not^(e->thread && e->thread->fake_thread);
2173 #ifdef USE_NNTP
2174  case MUTT_PAT_NEWSGROUPS:
2175  if (!e->env)
2176  return 0;
2177  return pat->not^(e->env->newsgroups &&patmatch(pat, e->env->newsgroups) == 0);
2178 #endif
2179  }
2180  mutt_error(_("error: unknown op %d (report this error)"), pat->op);
2181  return -1;
2182 }
Pattern matches date received.
Definition: pattern.h:116
Deleted messages.
Definition: mutt.h:103
Pattern matches email&#39;s header.
Definition: pattern.h:123
Pattern matches MIME type.
Definition: pattern.h:145
Pattern matches &#39;Date:&#39; field.
Definition: pattern.h:115
static int patmatch(const struct Pattern *pat, const char *buf)
Compare a string to a Pattern.
Definition: pattern.c:1067
static bool match_reference(struct Pattern *pat, struct ListHead *refs)
Match references against a Pattern.
Definition: pattern.c:1689
bool not
Definition: pattern.h:48
Pattern matches newsgroup.
Definition: pattern.h:147
Pattern matches email&#39;s score.
Definition: pattern.h:128
int pers_recip_all
^~p
Definition: pattern.h:89
struct Address * to
Definition: envelope.h:42
struct MuttThread * thread
Definition: email.h:97
static int match_addrlist(struct Pattern *pat, bool match_personal, int n,...)
Match a Pattern against and Address list.
Definition: pattern.c:1661
Message is part of a broken thread.
Definition: pattern.h:119
int mutt_is_list_recipient(bool alladdr, struct Address *a1, struct Address *a2)
Matches subscribed mailing lists.
Definition: pattern.c:1708
Pattern matches email&#39;s size.
Definition: pattern.h:129
struct Body * content
list of MIME parts
Definition: email.h:93
Flagged messages.
Definition: mutt.h:104
Pattern matches &#39;From:&#39; field.
Definition: pattern.h:114
#define MUTT_MAXRANGE
Definition: pattern.c:97
Email is from the user.
Definition: pattern.h:135
Match the full address.
Definition: pattern.h:72
#define _(a)
Definition: message.h:28
Email is on mailing list.
Definition: pattern.h:132
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
struct TagHead tags
for drivers that support server tagging
Definition: email.h:110
Pattern matches a child email.
Definition: pattern.h:109
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:120
bool expired
already expired?
Definition: email.h:52
Pattern matches email&#39;s Message-Id.
Definition: pattern.h:120
struct Address * sender
Definition: envelope.h:45
static int 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:1876
Messages that have been replied to.
Definition: mutt.h:97
int sub_all
^~u
Definition: pattern.h:87
Pattern matches message number.
Definition: pattern.h:127
Email is on subscribed mailing list.
Definition: pattern.h:133
static int is_pattern_cache_set(int cache_entry)
Is a given Pattern cached?
Definition: pattern.c:1911
All messages.
Definition: mutt.h:93
bool tagged
Definition: email.h:44
char * driver_tags_get(struct TagHead *head)
Get tags.
Definition: tags.c:150
bool read
Definition: email.h:51
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:66
char * message_id
Definition: envelope.h:53
static int perform_or(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical OR on a set of Patterns.
Definition: pattern.c:1643
bool old
Definition: email.h:50
#define SEC_GOODSIGN
Email has a valid signature.
Definition: ncrypt.h:122
enum MailboxType magic
mailbox type
Definition: mailbox.h:106
Duplicate message.
Definition: pattern.h:117
struct Envelope * env
envelope information
Definition: email.h:92
static int match_threadparent(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s parent.
Definition: pattern.c:1812
bool superseded
got superseded?
Definition: email.h:53
struct Address * from
Definition: envelope.h:41
int min
Definition: pattern.h:55
int score
Definition: email.h:91
time_t date_sent
time when the message was sent (UTC)
Definition: email.h:84
Old messages.
Definition: mutt.h:96
int pers_from_one
~P
Definition: pattern.h:92
struct MuttThread * child
Definition: thread.h:45
bool duplicate_thread
Definition: thread.h:37
Server-side pattern matches.
Definition: pattern.h:142
Pattern matches &#39;Cc:&#39; field.
Definition: pattern.h:111
#define SEC_SIGN
Email is signed.
Definition: ncrypt.h:121
int pers_recip_one
~p
Definition: pattern.h:90
Message is unreferenced in the thread.
Definition: pattern.h:118
LOFF_T length
length (in bytes) of attachment
Definition: body.h:47
bool fake_thread
Definition: thread.h:36
Pattern matches keyword/label.
Definition: pattern.h:141
static int match_threadchildren(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct MuttThread *t)
Match Pattern against an email&#39;s children.
Definition: pattern.c:1831
Either pattern can match.
Definition: pattern.h:106
size_t num_hidden
number of hidden messages in this view
Definition: email.h:78
#define PGP_KEY
Definition: ncrypt.h:138
Pattern matches email&#39;s spam score.
Definition: pattern.h:124
Superseded messages.
Definition: mutt.h:109
Tagged messages.
Definition: mutt.h:105
Message is encrypted.
Definition: pattern.h:139
char * data
pointer to data
Definition: buffer.h:35
int mutt_is_list_cc(int alladdr, struct Address *a1, struct Address *a2)
Matches known mailing lists.
Definition: pattern.c:1730
Pattern matches &#39;Subject:&#39; field.
Definition: pattern.h:113
struct Pattern * child
arguments to logical op
Definition: pattern.h:58
int list_all
^~l
Definition: pattern.h:85
New messages.
Definition: mutt.h:95
Messages that have been read.
Definition: mutt.h:98
static int get_pattern_cache_value(int cache_entry)
Get pattern cache value.
Definition: pattern.c:1901
Email is addressed to the user.
Definition: pattern.h:134
Message has PGP key.
Definition: pattern.h:140
bool collapsed
is this message part of a collapsed thread?
Definition: email.h:76
static bool perform_and(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Perform a logical AND on a set of Patterns.
Definition: pattern.c:1625
short op
Definition: pattern.h:47
Pattern matches parent.
Definition: pattern.h:108
static int match_threadcomplete(struct Pattern *pat, enum PatternExecFlag 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:1773
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
Expired messages.
Definition: mutt.h:108
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:129
int pers_from_all
^~P
Definition: pattern.h:91
Unread messages.
Definition: mutt.h:99
struct Buffer * spam
Definition: envelope.h:64
Pattern matches email&#39;s body.
Definition: pattern.h:122
static bool msg_search(struct Mailbox *m, struct Pattern *pat, int msgno)
Search an email.
Definition: pattern.c:1087
char * subject
Definition: envelope.h:50
bool flagged
marked important?
Definition: email.h:43
char * newsgroups
Definition: envelope.h:59
#define EMSG(e)
Definition: pattern.c:93
Message is signed.
Definition: pattern.h:137
bool deleted
Definition: email.h:45
#define mutt_error(...)
Definition: logging.h:88
bool replied
Definition: email.h:54
Thread is collapsed.
Definition: pattern.h:112
static int match_user(int alladdr, struct Address *a1, struct Address *a2)
Matches the user&#39;s email Address.
Definition: pattern.c:1749
Pattern matches sender.
Definition: pattern.h:126
Both patterns must match.
Definition: pattern.h:105
#define FREE(x)
Definition: memory.h:40
Message is crypographically verified.
Definition: pattern.h:138
int max
Definition: pattern.h:56
Pattern matches &#39;References:&#39; or &#39;In-Reply-To:&#39; field.
Definition: pattern.h:130
bool stringmatch
Definition: pattern.h:50
Pattern matches message tags.
Definition: pattern.h:143
Pattern matches any address field.
Definition: pattern.h:136
User is a recipient of the email.
Definition: pattern.h:131
bool alladdr
Definition: pattern.h:49
Pattern matches email thread.
Definition: pattern.h:107
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:216
Pattern matches &#39;To:&#39; field.
Definition: pattern.h:110
static void set_pattern_cache_value(int *cache_entry, int value)
Sets a value in the PatternCache cache entry.
Definition: pattern.c:1890
Pattern matches raw email text.
Definition: pattern.h:125
struct ListHead references
message references (in reverse order)
Definition: envelope.h:65
char * x_label
Definition: envelope.h:56
#define WithCrypto
Definition: ncrypt.h:155
Pattern matches number of attachments.
Definition: pattern.h:144
int list_one
~l
Definition: pattern.h:86
time_t received
time when the message was placed in the mailbox
Definition: email.h:85
Message-Id is among results from an external query.
Definition: pattern.h:121
struct Address * cc
Definition: envelope.h:43
bool matched
Definition: email.h:70
int msgno
number displayed to the user
Definition: email.h:89
int sub_one
~u
Definition: pattern.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void quote_simple ( const char *  str,
char *  buf,
size_t  buflen 
)
static

Apply simple quoting to a string.

Parameters
strString to quote
bufBuffer for the result
buflenLength of buffer

Definition at line 2190 of file pattern.c.

2191 {
2192  int i = 0;
2193 
2194  buf[i++] = '"';
2195  while (*str && i < buflen - 3)
2196  {
2197  if ((*str == '\\') || (*str == '"'))
2198  buf[i++] = '\\';
2199  buf[i++] = *str++;
2200  }
2201  buf[i++] = '"';
2202  buf[i] = '\0';
2203 }

+ Here is the caller graph for this function:

void mutt_check_simple ( char *  s,
size_t  len,
const char *  simple 
)

Convert a simple search into a real request.

Parameters
sBuffer for the result
lenLength of buffer
simpleSearch string to convert

Definition at line 2211 of file pattern.c.

2212 {
2213  bool do_simple = true;
2214 
2215  for (char *p = s; p && *p; p++)
2216  {
2217  if ((*p == '\\') && *(p + 1))
2218  p++;
2219  else if ((*p == '~') || (*p == '=') || (*p == '%'))
2220  {
2221  do_simple = false;
2222  break;
2223  }
2224  }
2225 
2226  /* XXX - is mutt_str_strcasecmp() right here, or should we use locale's
2227  * equivalences? */
2228 
2229  if (do_simple) /* yup, so spoof a real request */
2230  {
2231  /* convert old tokens into the new format */
2232  if ((mutt_str_strcasecmp("all", s) == 0) || (mutt_str_strcmp("^", s) == 0) ||
2233  (mutt_str_strcmp(".", s) == 0)) /* ~A is more efficient */
2234  {
2235  mutt_str_strfcpy(s, "~A", len);
2236  }
2237  else if (mutt_str_strcasecmp("del", s) == 0)
2238  mutt_str_strfcpy(s, "~D", len);
2239  else if (mutt_str_strcasecmp("flag", s) == 0)
2240  mutt_str_strfcpy(s, "~F", len);
2241  else if (mutt_str_strcasecmp("new", s) == 0)
2242  mutt_str_strfcpy(s, "~N", len);
2243  else if (mutt_str_strcasecmp("old", s) == 0)
2244  mutt_str_strfcpy(s, "~O", len);
2245  else if (mutt_str_strcasecmp("repl", s) == 0)
2246  mutt_str_strfcpy(s, "~Q", len);
2247  else if (mutt_str_strcasecmp("read", s) == 0)
2248  mutt_str_strfcpy(s, "~R", len);
2249  else if (mutt_str_strcasecmp("tag", s) == 0)
2250  mutt_str_strfcpy(s, "~T", len);
2251  else if (mutt_str_strcasecmp("unread", s) == 0)
2252  mutt_str_strfcpy(s, "~U", len);
2253  else
2254  {
2255  char tmp[1024];
2256  quote_simple(s, tmp, sizeof(tmp));
2257  mutt_file_expand_fmt(s, len, simple, tmp);
2258  }
2259  }
2260 }
static void quote_simple(const char *str, char *buf, size_t buflen)
Apply simple quoting to a string.
Definition: pattern.c:2190
void mutt_file_expand_fmt(char *dest, size_t destlen, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1335
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:741
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:624
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:611

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

2269 {
2270  struct MuttThread *t = NULL;
2271 
2272  if (!e)
2273  return NULL;
2274 
2275  t = e->thread;
2276 
2277  while (t && t->parent)
2278  t = t->parent;
2279 
2280  return t;
2281 }
struct MuttThread * thread
Definition: email.h:97
struct MuttThread * parent
Definition: thread.h:44
An email conversation.
Definition: thread.h:34

+ Here is the caller graph for this function:

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

2290 {
2291  struct MuttThread *me = NULL;
2292 
2293  if (!e)
2294  return false;
2295 
2296  me = top_of_thread(e);
2297  if (!me)
2298  return false;
2299 
2300  Context->mailbox->vcount = 0;
2301  Context->vsize = 0;
2302  Context->collapsed = false;
2303 
2304  for (int i = 0; i < Context->mailbox->msg_count; i++)
2305  {
2306  Context->mailbox->emails[i]->virtual = -1;
2307  Context->mailbox->emails[i]->limited = false;
2308  Context->mailbox->emails[i]->collapsed = false;
2309  Context->mailbox->emails[i]->num_hidden = 0;
2310 
2311  if (top_of_thread(Context->mailbox->emails[i]) == me)
2312  {
2313  struct Body *body = Context->mailbox->emails[i]->content;
2314 
2316  Context->mailbox->emails[i]->limited = true;
2318  Context->mailbox->vcount++;
2319  Context->vsize += (body->length + body->offset - body->hdr_offset);
2320  }
2321  }
2322  return true;
2323 }
struct Email ** emails
Definition: mailbox.h:100
The "current" mailbox.
Definition: context.h:37
int msg_count
total number of messages
Definition: mailbox.h:93
int virtual
virtual message number
Definition: email.h:90
struct Body * content
list of MIME parts
Definition: email.h:93
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
int vcount
the number of virtual messages
Definition: mailbox.h:103
The body of an email.
Definition: body.h:34
struct Mailbox * mailbox
Definition: context.h:51
bool limited
is this message in a limited view?
Definition: email.h:77
off_t vsize
Definition: context.h:39
LOFF_T length
length (in bytes) of attachment
Definition: body.h:47
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition: pattern.c:2268
size_t num_hidden
number of hidden messages in this view
Definition: email.h:78
bool collapsed
is this message part of a collapsed thread?
Definition: email.h:76
An email conversation.
Definition: thread.h:34
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:102
bool collapsed
are all threads collapsed?
Definition: context.h:49
long hdr_offset
offset in stream where the headers begin.
Definition: body.h:42

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

2333 {
2334  struct Pattern *pat = NULL;
2335  char buf[1024] = "", *simple = NULL;
2336  struct Buffer err;
2337  int rc = -1, padding;
2338  struct Progress progress;
2339 
2340  mutt_str_strfcpy(buf, Context->pattern, sizeof(buf));
2341  if (prompt || (op != MUTT_LIMIT))
2342  if ((mutt_get_field(prompt, buf, sizeof(buf), MUTT_PATTERN | MUTT_CLEAR) != 0) ||
2343  !buf[0])
2344  return -1;
2345 
2346  mutt_message(_("Compiling search pattern..."));
2347 
2348  simple = mutt_str_strdup(buf);
2349  mutt_check_simple(buf, sizeof(buf), NONULL(C_SimpleSearch));
2350 
2351  mutt_buffer_init(&err);
2352  err.dsize = 256;
2353  err.data = mutt_mem_malloc(err.dsize);
2354  pat = mutt_pattern_comp(buf, MUTT_FULL_MSG, &err);
2355  if (!pat)
2356  {
2357  mutt_error("%s", err.data);
2358  goto bail;
2359  }
2360 
2361 #ifdef USE_IMAP
2362  if ((Context->mailbox->magic == MUTT_IMAP) && (imap_search(Context->mailbox, pat) < 0))
2363  goto bail;
2364 #endif
2365 
2366  mutt_progress_init(&progress, _("Executing command on matching messages..."),
2368  (op == MUTT_LIMIT) ? Context->mailbox->msg_count :
2369  Context->mailbox->vcount);
2370 
2371  if (op == MUTT_LIMIT)
2372  {
2373  Context->mailbox->vcount = 0;
2374  Context->vsize = 0;
2375  Context->collapsed = false;
2376  padding = mx_msg_padding_size(Context->mailbox);
2377 
2378  for (int i = 0; i < Context->mailbox->msg_count; i++)
2379  {
2380  mutt_progress_update(&progress, i, -1);
2381  /* new limit pattern implicitly uncollapses all threads */
2382  Context->mailbox->emails[i]->virtual = -1;
2383  Context->mailbox->emails[i]->limited = false;
2384  Context->mailbox->emails[i]->collapsed = false;
2385  Context->mailbox->emails[i]->num_hidden = 0;
2387  Context->mailbox->emails[i], NULL))
2388  {
2390  Context->mailbox->emails[i]->limited = true;
2392  Context->mailbox->vcount++;
2393  struct Body *b = Context->mailbox->emails[i]->content;
2394  Context->vsize += b->length + b->offset - b->hdr_offset + padding;
2395  }
2396  }
2397  }
2398  else
2399  {
2400  for (int i = 0; i < Context->mailbox->vcount; i++)
2401  {
2402  mutt_progress_update(&progress, i, -1);
2404  Context->mailbox->emails[Context->mailbox->v2r[i]], NULL))
2405  {
2406  switch (op)
2407  {
2408  case MUTT_UNDELETE:
2411  MUTT_PURGE, false);
2412  /* fallthrough */
2413  case MUTT_DELETE:
2416  MUTT_DELETE, (op == MUTT_DELETE));
2417  break;
2418  case MUTT_TAG:
2419  case MUTT_UNTAG:
2422  MUTT_TAG, (op == MUTT_TAG));
2423  break;
2424  }
2425  }
2426  }
2427  }
2428 
2429  mutt_clear_error();
2430 
2431  if (op == MUTT_LIMIT)
2432  {
2433  /* drop previous limit pattern */
2434  FREE(&Context->pattern);
2436 
2438  mutt_error(_("No messages matched criteria"));
2439 
2440  /* record new limit pattern, unless match all */
2441  char *pbuf = buf;
2442  while (*pbuf == ' ')
2443  pbuf++;
2444  if (mutt_str_strcmp(pbuf, "~A") != 0)
2445  {
2446  Context->pattern = simple;
2447  simple = NULL; /* don't clobber it */
2449  }
2450  }
2451 
2452  rc = 0;
2453 
2454 bail:
2455  FREE(&simple);
2456  mutt_pattern_free(&pat);
2457  FREE(&err.data);
2458 
2459  return rc;
2460 }
struct Email ** emails
Definition: mailbox.h:100
The "current" mailbox.
Definition: context.h:37
#define MUTT_PROGRESS_MSG
message-based progress
Definition: progress.h:33
#define NONULL(x)
Definition: string2.h:36
int msg_count
total number of messages
Definition: mailbox.h:93
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:68
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:66
int imap_search(struct Mailbox *m, const struct Pattern *pat)
Find a matching mailbox.
Definition: imap.c:1358
#define mutt_message(...)
Definition: logging.h:87
int virtual
virtual message number
Definition: email.h:90
Messages in limited view.
Definition: mutt.h:107
struct Body * content
list of MIME parts
Definition: email.h:93
#define MUTT_FULL_MSG
Definition: pattern.h:40
void mutt_progress_update(struct Progress *progress, long pos, int percent)
Update the state of the progress bar.
Definition: progress.c:170
void mutt_progress_init(struct Progress *progress, const char *msg, unsigned short flags, unsigned short inc, size_t size)
Set up a progress bar.
Definition: progress.c:113
String manipulation buffer.
Definition: buffer.h:33
Messages to be un-deleted.
Definition: mutt.h:101
LOFF_T offset
offset where the actual data begins
Definition: body.h:46
Match the full address.
Definition: pattern.h:72
#define _(a)
Definition: message.h:28
void mutt_pattern_free(struct Pattern **pat)
Free a Pattern.
Definition: pattern.c:1338
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
Messages to be purged (bypass trash)
Definition: mutt.h:102
A progress bar.
Definition: progress.h:38
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:68
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:77
int vcount
the number of virtual messages
Definition: mailbox.h:103
The body of an email.
Definition: body.h:34
A simple (non-regex) pattern.
Definition: pattern.h:45
struct Mailbox * mailbox
Definition: context.h:51
enum MailboxType magic
mailbox type
Definition: mailbox.h:106
bool limited
is this message in a limited view?
Definition: email.h:77
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
off_t vsize
Definition: context.h:39
LOFF_T length
length (in bytes) of attachment
Definition: body.h:47
Messages to be deleted.
Definition: mutt.h:100
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
size_t num_hidden
number of hidden messages in this view
Definition: email.h:78
Tagged messages.
Definition: mutt.h:105
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:741
bool collapsed
is this message part of a collapsed thread?
Definition: email.h:76
struct Pattern * limit_pattern
compiled limit pattern
Definition: context.h:41
struct Pattern * mutt_pattern_comp(char *s, int flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1383
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: globals.h:146
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:102
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:383
bool collapsed
are all threads collapsed?
Definition: context.h:49
#define mutt_error(...)
Definition: logging.h:88
void mutt_check_simple(char *s, size_t len, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:2211
#define FREE(x)
Definition: memory.h:40
Messages to be un-tagged.
Definition: mutt.h:106
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size.
Definition: mx.c:1429
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:66
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931
char * pattern
limit pattern string
Definition: context.h:40
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:611
WHERE short C_ReadInc
Config: Update the progress bar after this many records read (0 to disable)
Definition: globals.h:156

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

2470 {
2471  struct Progress progress;
2472 
2473  if (!*LastSearch || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
2474  {
2475  char buf[256];
2476  mutt_str_strfcpy(buf, *LastSearch ? LastSearch : "", sizeof(buf));
2477  if ((mutt_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
2478  _("Search for: ") :
2479  _("Reverse search for: "),
2480  buf, sizeof(buf), MUTT_CLEAR | MUTT_PATTERN) != 0) ||
2481  !buf[0])
2482  {
2483  return -1;
2484  }
2485 
2486  if ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT))
2487  OptSearchReverse = false;
2488  else
2489  OptSearchReverse = true;
2490 
2491  /* compare the *expanded* version of the search pattern in case
2492  * $simple_search has changed while we were searching */
2493  char temp[1024];
2494  mutt_str_strfcpy(temp, buf, sizeof(temp));
2495  mutt_check_simple(temp, sizeof(temp), NONULL(C_SimpleSearch));
2496 
2497  if (!SearchPattern || (mutt_str_strcmp(temp, LastSearchExpn) != 0))
2498  {
2499  struct Buffer err;
2500  mutt_buffer_init(&err);
2501  OptSearchInvalid = true;
2502  mutt_str_strfcpy(LastSearch, buf, sizeof(LastSearch));
2503  mutt_message(_("Compiling search pattern..."));
2505  err.dsize = 256;
2506  err.data = mutt_mem_malloc(err.dsize);
2508  if (!SearchPattern)
2509  {
2510  mutt_error("%s", err.data);
2511  FREE(&err.data);
2512  LastSearch[0] = '\0';
2513  return -1;
2514  }
2515  FREE(&err.data);
2516  mutt_clear_error();
2517  }
2518  }
2519 
2520  if (OptSearchInvalid)
2521  {
2522  for (int i = 0; i < Context->mailbox->msg_count; i++)
2523  Context->mailbox->emails[i]->searched = false;
2524 #ifdef USE_IMAP
2525  if ((Context->mailbox->magic == MUTT_IMAP) &&
2527  return -1;
2528 #endif
2529  OptSearchInvalid = false;
2530  }
2531 
2532  int incr = (OptSearchReverse) ? -1 : 1;
2533  if (op == OP_SEARCH_OPPOSITE)
2534  incr = -incr;
2535 
2536  mutt_progress_init(&progress, _("Searching..."), MUTT_PROGRESS_MSG, C_ReadInc,
2537  Context->mailbox->vcount);
2538 
2539  for (int i = cur + incr, j = 0; j != Context->mailbox->vcount; j++)
2540  {
2541  const char *msg = NULL;
2542  mutt_progress_update(&progress, j, -1);
2543  if (i > Context->mailbox->vcount - 1)
2544  {
2545  i = 0;
2546  if (C_WrapSearch)
2547  msg = _("Search wrapped to top");
2548  else
2549  {
2550  mutt_message(_("Search hit bottom without finding match"));
2551  return -1;
2552  }
2553  }
2554  else if (i < 0)
2555  {
2556  i = Context->mailbox->vcount - 1;
2557  if (C_WrapSearch)
2558  msg = _("Search wrapped to bottom");
2559  else
2560  {
2561  mutt_message(_("Search hit top without finding match"));
2562  return -1;
2563  }
2564  }
2565 
2566  struct Email *e = Context->mailbox->emails[Context->mailbox->v2r[i]];
2567  if (e->searched)
2568  {
2569  /* if we've already evaluated this message, use the cached value */
2570  if (e->matched)
2571  {
2572  mutt_clear_error();
2573  if (msg && *msg)
2574  mutt_message(msg);
2575  return i;
2576  }
2577  }
2578  else
2579  {
2580  /* remember that we've already searched this message */
2581  e->searched = true;
2583  Context->mailbox, e, NULL);
2584  if (e->matched > 0)
2585  {
2586  mutt_clear_error();
2587  if (msg && *msg)
2588  mutt_message(msg);
2589  return i;
2590  }
2591  }
2592 
2593  if (SigInt)
2594  {
2595  mutt_error(_("Search interrupted"));
2596  SigInt = 0;
2597  return -1;
2598  }
2599 
2600  i += incr;
2601  }
2602 
2603  mutt_error(_("Not found"));
2604  return -1;
2605 }
struct Email ** emails
Definition: mailbox.h:100
The "current" mailbox.
Definition: context.h:37
#define MUTT_PROGRESS_MSG
message-based progress
Definition: progress.h:33
#define NONULL(x)
Definition: string2.h:36
int msg_count
total number of messages
Definition: mailbox.h:93
The envelope/body of an email.
Definition: email.h:37
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:66
int imap_search(struct Mailbox *m, const struct Pattern *pat)
Find a matching mailbox.
Definition: imap.c:1358
#define mutt_message(...)
Definition: logging.h:87
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:91
#define MUTT_FULL_MSG
Definition: pattern.h:40
void mutt_progress_update(struct Progress *progress, long pos, int percent)
Update the state of the progress bar.
Definition: progress.c:170
void mutt_progress_init(struct Progress *progress, const char *msg, unsigned short flags, unsigned short inc, size_t size)
Set up a progress bar.
Definition: progress.c:113
String manipulation buffer.
Definition: buffer.h:33
Match the full address.
Definition: pattern.h:72
#define _(a)
Definition: message.h:28
static char LastSearch[256]
last pattern searched for
Definition: pattern.c:189
WHERE bool C_WrapSearch
Config: Wrap around when the search hits the end.
Definition: globals.h:267
void mutt_pattern_free(struct Pattern **pat)
Free a Pattern.
Definition: pattern.c:1338
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
bool searched
Definition: email.h:69
A progress bar.
Definition: progress.h:38
#define MUTT_PATTERN
Pattern mode - only used for history classes.
Definition: mutt.h:68
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:77
int vcount
the number of virtual messages
Definition: mailbox.h:103
struct Mailbox * mailbox
Definition: context.h:51
enum MailboxType magic
mailbox type
Definition: mailbox.h:106
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
static char LastSearchExpn[1024]
expanded version of LastSearch
Definition: pattern.c:190
static struct Pattern * SearchPattern
current search pattern
Definition: pattern.c:188
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
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:741
WHERE bool OptSearchInvalid
(pseudo) used to invalidate the search pat
Definition: options.h:49
struct Pattern * mutt_pattern_comp(char *s, int flags, struct Buffer *err)
Create a Pattern.
Definition: pattern.c:1383
WHERE char * C_SimpleSearch
Config: Pattern to search for when search doesn&#39;t contain ~&#39;s.
Definition: globals.h:146
int * v2r
mapping from virtual to real msgno
Definition: mailbox.h:102
#define mutt_error(...)
Definition: logging.h:88
void mutt_check_simple(char *s, size_t len, const char *simple)
Convert a simple search into a real request.
Definition: pattern.c:2211
#define FREE(x)
Definition: memory.h:40
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66
int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition: pattern.c:1931
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:611
WHERE bool OptSearchReverse
(pseudo) used by ci_search_command
Definition: options.h:50
WHERE short C_ReadInc
Config: Update the progress bar after this many records read (0 to disable)
Definition: globals.h:156
bool matched
Definition: email.h:70

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

bool C_ThoroughSearch

Config: Decode headers and messages before searching them.

Definition at line 71 of file pattern.c.

struct RangeRegex range_regexes[]
static
Initial value:
= {
[RANGE_K_REL] = { RANGE_REL_RX, 1, 3, 0 },
[RANGE_K_ABS] = { RANGE_ABS_RX, 1, 3, 0 },
[RANGE_K_LT] = { RANGE_LT_RX, 1, 2, 0 },
[RANGE_K_GT] = { RANGE_GT_RX, 2, 1, 0 },
[RANGE_K_BARE] = { RANGE_BARE_RX, 1, 1, 0 },
}
Single symbol.
Definition: pattern.c:148
#define RANGE_REL_RX
Definition: pattern.c:77
#define RANGE_ABS_RX
Definition: pattern.c:81
Greater-than range.
Definition: pattern.c:147
#define RANGE_LT_RX
Definition: pattern.c:84
#define RANGE_BARE_RX
Definition: pattern.c:88
Absolute range.
Definition: pattern.c:145
#define RANGE_GT_RX
Definition: pattern.c:85
Less-than range.
Definition: pattern.c:146
Relative range.
Definition: pattern.c:144

Set of Regexes for various range types.

This array, will also contain the compiled regexes.

Definition at line 179 of file pattern.c.

struct Pattern* SearchPattern = NULL
static

current search pattern

Definition at line 188 of file pattern.c.

char LastSearch[256] = { 0 }
static

last pattern searched for

Definition at line 189 of file pattern.c.

char LastSearchExpn[1024] = { 0 }
static

expanded version of LastSearch

Definition at line 190 of file pattern.c.

const struct PatternFlags Flags[]
static

Lookup table for all patterns.

Definition at line 1242 of file pattern.c.