53 #define MUTT_PDR_NO_FLAGS 0
54 #define MUTT_PDR_MINUS (1 << 0)
55 #define MUTT_PDR_PLUS (1 << 1)
56 #define MUTT_PDR_WINDOW (1 << 2)
57 #define MUTT_PDR_ABSOLUTE (1 << 3)
58 #define MUTT_PDR_DONE (1 << 4)
59 #define MUTT_PDR_ERROR (1 << 8)
62 #define MUTT_PDR_ERRORDONE (MUTT_PDR_ERROR | MUTT_PDR_DONE)
85 char *pexpr = s->
dptr;
91 if (buf->
data[0] ==
'\0')
109 #ifdef USE_DEBUG_GRAPHVIZ
117 regerror(rc2, pat->
p.
regex, errmsg,
sizeof(errmsg));
137 struct ListHead *msgid_list = (
struct ListHead *) (user_data);
165 if (!c_external_search_command)
171 char *pexpr = s->
dptr;
178 if (*tok_buf->
data ==
'\0')
236 static const char *
get_offset(
struct tm *tm,
const char *s,
int sign)
239 int offset = strtol(s, &ps, 0);
240 if (((sign < 0) && (offset > 0)) || ((sign > 0) && (offset < 0)))
246 tm->tm_year += offset;
249 tm->tm_mon += offset;
252 tm->tm_mday += 7 * offset;
255 tm->tm_mday += offset;
258 tm->tm_hour += offset;
261 tm->tm_min += offset;
264 tm->tm_sec += offset;
296 for (
int v = 0; v < 8; v++)
298 if (s[v] && (s[v] >=
'0') && (s[v] <=
'9'))
310 sscanf(s,
"%4d%2d%2d", &year, &month, &mday);
313 if (t->tm_year > 1900)
315 t->tm_mon = month - 1;
318 if ((t->tm_mday < 1) || (t->tm_mday > 31))
320 snprintf(err->
data, err->
dsize,
_(
"Invalid day of month: %s"), s);
323 if ((t->tm_mon < 0) || (t->tm_mon > 11))
325 snprintf(err->
data, err->
dsize,
_(
"Invalid month: %s"), s);
332 t->tm_mday = strtol(s, &p, 10);
333 if ((t->tm_mday < 1) || (t->tm_mday > 31))
341 t->tm_mon = tm.tm_mon;
342 t->tm_year = tm.tm_year;
346 t->tm_mon = strtol(p, &p, 10) - 1;
347 if ((t->tm_mon < 0) || (t->tm_mon > 11))
354 t->tm_year = tm.tm_year;
358 t->tm_year = strtol(p, &p, 10);
361 else if (t->tm_year > 1900)
377 bool have_min,
struct tm *base_min,
struct Buffer *err)
382 const char *pt = NULL;
401 memcpy(min, base_min,
sizeof(
struct tm));
413 max->tm_year = min->tm_year;
414 max->tm_mon = min->tm_mon;
415 max->tm_mday = min->tm_mday;
464 if ((min->tm_year > max->tm_year) ||
465 ((min->tm_year == max->tm_year) && (min->tm_mon > max->tm_mon)) ||
466 ((min->tm_year == max->tm_year) && (min->tm_mon == max->tm_mon) &&
467 (min->tm_mday > max->tm_mday)))
472 min->tm_year = max->tm_year;
476 min->tm_mon = max->tm_mon;
480 min->tm_mday = max->tm_mday;
504 struct tm min = { 0 };
511 struct tm max = { 0 };
519 if (strchr(
"<>=", s[0]))
525 struct tm *tm = NULL;
544 char *offset_type = NULL;
545 strtol(s + 1, &offset_type, 0);
546 if (!(*offset_type && strchr(
"HMS", *offset_type)))
559 memcpy(&min, &max,
sizeof(max));
569 bool have_min =
false;
570 bool until_now =
false;
571 if (isdigit((
unsigned char) *pc))
583 const char *pt = pc + 1;
585 until_now = (*pt ==
'\0');
596 memcpy(&base_min, &min,
sizeof(base_min));
605 max.tm_year = min.tm_year;
606 max.tm_mon = min.tm_mon;
607 max.tm_mday = min.tm_mday;
632 bool do_exclusive =
false;
633 bool skip_quote =
false;
644 if ((*s->
dptr !=
'-') && (*s->
dptr !=
'<'))
650 pat->
min = strtol(s->
dptr + 1, &tmp, 0) + 1;
653 pat->
min = strtol(s->
dptr, &tmp, 0);
654 if (toupper((
unsigned char) *tmp) ==
'K')
659 else if (toupper((
unsigned char) *tmp) ==
'M')
684 if (isdigit((
unsigned char) *tmp))
687 pat->
max = strtol(tmp, &tmp, 0);
688 if (toupper((
unsigned char) *tmp) ==
'K')
693 else if (toupper((
unsigned char) *tmp) ==
'M')
704 if (skip_quote && (*tmp ==
'"'))
721 size_t ds = err->
dsize;
723 if (regerror(regerr, preg, err->
data, ds) > ds)
742 const char *context_req_chars[] = {
753 char *context_loc = strpbrk(s->
dptr + pmatch[0].rm_so, context_req_chars[kind]);
754 if (!context_loc || (context_loc >= &s->
dptr[pmatch[0].rm_eo]))
779 int num = (int) strtol(&s->
dptr[pmatch[group].rm_so], NULL, 0);
780 unsigned char c = (
unsigned char) (s->
dptr[pmatch[group].rm_eo - 1]);
781 if (toupper(c) ==
'K')
783 else if (toupper(c) ==
'M')
790 return num +
EMSG(e);
813 int side,
int kind,
struct Mailbox *m,
struct Menu *menu)
816 if ((pmatch[grp].rm_so == -1) || (pmatch[grp].rm_so == pmatch[grp].rm_eo))
824 unsigned char c = (
unsigned char) (s->
dptr[pmatch[grp].rm_so]);
878 regerr = regcomp(&pspec->
cooked, pspec->
raw, REG_EXTENDED);
918 s->
dptr += pmatch[0].rm_eo;
943 bool skip_quote =
false;
965 if (skip_quote && (*s->
dptr ==
'"'))
983 char *pexpr = s->
dptr;
986 snprintf(err->
data, err->
dsize,
_(
"Error in expression: %s"), pexpr);
992 snprintf(err->
data, err->
dsize,
"%s",
_(
"Empty expression"));
1061 #ifdef USE_DEBUG_GRAPHVIZ
1062 FREE(&np->raw_pattern);
1088 struct PatternList *h =
mutt_mem_calloc(1,
sizeof(
struct PatternList));
1127 leaf->
child = *curlist;
1165 struct PatternList *curlist = NULL;
1166 bool pat_not =
false;
1167 bool all_addr =
false;
1168 bool pat_or =
false;
1169 bool implicit =
true;
1170 bool is_alias =
false;
1176 if (!s || (s[0] ==
'\0'))
1183 ps.
dptr = (
char *) s;
1193 all_addr = !all_addr;
1201 is_alias = !is_alias;
1232 if (ps.
dptr[1] ==
'\0')
1237 short thread_op = 0;
1238 if (ps.
dptr[1] ==
'(')
1240 else if ((ps.
dptr[1] ==
'<') && (ps.
dptr[2] ==
'('))
1242 else if ((ps.
dptr[1] ==
'>') && (ps.
dptr[2] ==
'('))
1256 leaf->
op = thread_op;
1276 if (implicit && pat_or)
1290 if (entry->
flags && ((flags & entry->
flags) == 0))
1303 leaf->
op = entry->
op;
1313 if (ps.
dptr[0] ==
'\0')
1325 if (!
eat_date(leaf, flags, &ps, err))
1337 if (!
eat_query(leaf, flags, &ps, err, m))
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
#define MUTT_PDR_PLUS
Extend the range using '+'.
#define MUTT_PDR_NO_FLAGS
No flags are set.
bool eval_date_minmax(struct Pattern *pat, const char *s, struct Buffer *err)
Evaluate a date-range pattern against 'now'.
static int scan_range_slot(struct Buffer *s, regmatch_t pmatch[], int grp, int side, int kind, struct Mailbox *m, struct Menu *menu)
Parse a range of message numbers.
uint16_t ParseDateRangeFlags
Flags for parse_date_range(), e.g. MUTT_PDR_MINUS.
#define MUTT_PDR_ERROR
Invalid pattern.
static char * find_matching_paren(char *s)
Find the matching parenthesis.
static int scan_range_num(struct Buffer *s, regmatch_t pmatch[], int group, int kind, struct Mailbox *m, struct Menu *menu)
Parse a number range.
struct PatternList * mutt_pattern_comp(struct Mailbox *m, struct Menu *menu, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
#define MUTT_PDR_ABSOLUTE
Absolute pattern range.
static int eat_range_by_regex(struct Pattern *pat, struct Buffer *s, int kind, struct Buffer *err, struct Mailbox *m, struct Menu *menu)
Parse a range given as a regex.
static struct Pattern * attach_leaf(struct PatternList *list, struct Pattern *leaf)
Attach a Pattern to a Pattern List.
static void adjust_date_range(struct tm *min, struct tm *max)
Put a date range in the correct order.
static const char * get_date(const char *s, struct tm *t, struct Buffer *err)
Parse a (partial) date in dd/mm/yyyy format.
EatRangeError
Error codes for eat_range_by_regex()
@ RANGE_E_MVIEW
Range requires MailboxView, but none available.
@ RANGE_E_OK
Range is valid.
@ RANGE_E_SYNTAX
Range contains syntax error.
#define MUTT_PDR_DONE
Pattern parse successfully.
static struct Pattern * attach_new_leaf(struct PatternList **curlist)
Attach a new Pattern to a List.
static struct PatternList * mutt_pattern_list_new(void)
Create a new list containing a Pattern.
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.
static const char * get_offset(struct tm *tm, const char *s, int sign)
Calculate a symbolic offset.
static struct Pattern * attach_new_root(struct PatternList **curlist)
Create a new Pattern as a parent for a List.
static void order_range(struct Pattern *pat)
Put a range in order.
static struct Pattern * mutt_pattern_new(void)
Create a new Pattern.
#define MUTT_PDR_ERRORDONE
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
static bool is_menu_available(struct Buffer *s, regmatch_t pmatch[], int kind, struct Buffer *err, struct Menu *menu)
Do we need a MailboxView for this Pattern?
#define MUTT_PDR_MINUS
Pattern contains a range.
static int report_regerror(int regerr, regex_t *preg, struct Buffer *err)
Create a regex error message.
#define MUTT_PDR_WINDOW
Extend the range in both directions using '*'.
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
time_t mutt_date_make_time(struct tm *t, bool local)
Convert struct tm to time_t
void mutt_date_normalize_time(struct tm *tm)
Fix the contents of a struct tm.
#define MUTT_DATE_NOW
Constant representing the 'current time', see: mutt_date_gmtime(), mutt_date_localtime()
Structs that make up an email.
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
bool mutt_file_map_lines(mutt_file_map_t func, void *user_data, FILE *fp, ReadLineFlags flags)
Process lines of text read from a file pointer.
#define MUTT_RL_NO_FLAGS
No flags are set.
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
struct Group * mutt_pattern_group(const char *pat)
Match a pattern to a Group.
static bool eat_query(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Mailbox *m)
Parse a query for an external search program - Implements eat_arg_t -.
static bool eat_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a number range - Implements eat_arg_t -.
static bool eat_date(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a date pattern - Implements eat_arg_t -.
static bool eat_message_range(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err, struct Mailbox *m, struct Menu *menu)
Parse a range of message numbers - Implements eat_arg_t -.
static bool eat_regex(struct Pattern *pat, PatternCompFlags flags, struct Buffer *s, struct Buffer *err)
Parse a regex - Implements eat_arg_t -.
#define mutt_message(...)
#define mutt_debug(LEVEL,...)
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 -.
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
void mutt_list_clear(struct ListHead *h)
Free a list, but NOT its strings.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
@ LL_DEBUG2
Log at debug level 2.
@ LL_DEBUG1
Log at debug level 1.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Convenience wrapper for the library headers.
char * mutt_path_escape(const char *src)
Escapes single quotes in a path for a command string.
void mutt_str_remove_trailing_ws(char *s)
Trim trailing whitespace from a string.
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
char * mutt_str_dup(const char *str)
Copy a string, safely.
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Many unsorted constants and some structs.
#define MUTT_TOKEN_COMMENT
Don't reap comments.
#define MUTT_TOKEN_PATTERN
~%=!| are terms (for patterns)
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
The "currently-open" mailbox.
const struct PatternFlags * lookup_tag(char tag)
Lookup a pattern modifier.
#define MUTT_PC_SEND_MODE_SEARCH
Allow send-mode body searching.
uint8_t PatternCompFlags
Flags for mutt_pattern_comp(), e.g. MUTT_PC_FULL_MSG.
@ MUTT_PAT_OR
Either pattern can match.
@ MUTT_PAT_CHILDREN
Pattern matches a child email.
@ MUTT_PAT_PARENT
Pattern matches parent.
@ MUTT_PAT_AND
Both patterns must match.
@ MUTT_PAT_THREAD
Pattern matches email thread.
#define MUTT_PC_PATTERN_DYNAMIC
Enable runtime date range evaluation.
@ RANGE_S_LEFT
Left side of range.
@ RANGE_S_RIGHT
Right side of range.
@ EAT_RANGE
Process a number (range)
@ EAT_MESSAGE_RANGE
Process a message number (range)
@ EAT_DATE
Process a date (range)
@ EAT_QUERY
Process a query string.
@ EAT_REGEX
Process a regex.
@ RANGE_K_REL
Relative range.
@ RANGE_K_ABS
Absolute range.
@ RANGE_K_LT
Less-than range.
@ RANGE_K_INVALID
Range is invalid.
@ RANGE_K_BARE
Single symbol.
@ RANGE_K_GT
Greater-than range.
struct RangeRegex RangeRegexes[]
Set of Regexes for various range types.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
#define SLIST_FOREACH(var, head, field)
#define SLIST_INSERT_HEAD(head, elm, field)
#define SLIST_NEXT(elm, field)
#define SLIST_FIRST(head)
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
String manipulation buffer.
char * dptr
Current read/write position.
size_t dsize
Length of data.
char * data
Pointer to data.
The envelope/body of an email.
int msg_count
Total number of messages.
Container for Accounts, Notifications.
struct ConfigSubset * sub
Inherited config items.
Mapping between user character and internal constant.
enum PatternEat eat_arg
Type of function needed to parse flag, e.g. EAT_DATE.
PatternCompFlags flags
Pattern flags, e.g. MUTT_PC_FULL_MSG.
int op
Operation to perform, e.g. MUTT_PAT_SCORE.
A simple (non-regex) pattern.
bool group_match
Check a group of Addresses.
int max
Maximum for range checks.
bool all_addr
All Addresses in the list must match.
struct Group * group
Address group if group_match is set.
struct PatternList * child
Arguments to logical operation.
bool string_match
Check a string for a match.
regex_t * regex
Compiled regex, for non-pattern matching.
struct ListHead multi_cases
Multiple strings for ~I pattern.
char * str
String, if string_match is set.
bool is_alias
Is there an alias for this Address?
bool ign_case
Ignore case for local string_match searches.
bool dynamic
Evaluate date ranges at run time.
short op
Operation, e.g. MUTT_PAT_SCORE.
bool sendmode
Evaluate searches in send-mode.
bool is_multi
Multiple case (only for ~I pattern now)
int min
Minimum for range checks.
bool pat_not
Pattern should be inverted (not)
Regular expression representing a range.
int lgrp
Paren group matching the left side.
int rgrp
Paren group matching the right side.
regex_t cooked
Compiled form.
const char * raw
Regex as string.