NeoMutt  2021-10-29-43-g6b8931
Teaching an old dog new tricks
DOXYGEN
search.c File Reference

IMAP search routines. More...

#include "config.h"
#include <stdbool.h>
#include <string.h>
#include "private.h"
#include "mutt/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "lib.h"
#include "pattern/lib.h"
#include "adata.h"
#include "mdata.h"
+ Include dependency graph for search.c:

Go to the source code of this file.

Functions

static int check_pattern_list (const struct PatternList *patterns)
 Check how many patterns in a list can be searched server-side. More...
 
static bool compile_search (const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
 Convert NeoMutt pattern to IMAP search. More...
 
static bool check_pattern (const struct Pattern *pat)
 Check whether a pattern can be searched server-side. More...
 
static bool compile_search_children (const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
 Compile a search command for a pattern's children. More...
 
static bool compile_search_self (const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
 Compile a search command for a pattern. More...
 
bool imap_search (struct Mailbox *m, const struct PatternList *pat)
 Find messages in mailbox matching a pattern. More...
 
void cmd_parse_search (struct ImapAccountData *adata, const char *s)
 Store SEARCH response for later use. More...
 

Detailed Description

IMAP search routines.

Authors
  • Michael R. Elkins
  • Brandon Long
  • Brendan Cully
  • Richard Russon

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 search.c.

Function Documentation

◆ check_pattern_list()

static int check_pattern_list ( const struct PatternList *  patterns)
static

Check how many patterns in a list can be searched server-side.

Parameters
patternsList of patterns to match
Return values
numNumber of patterns search that can be searched server-side

Definition at line 83 of file search.c.

84 {
85  int positives = 0;
86 
87  const struct Pattern *pat = NULL;
88  SLIST_FOREACH(pat, patterns, entries)
89  {
90  positives += check_pattern(pat);
91  }
92 
93  return positives;
94 }
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:231
static bool check_pattern(const struct Pattern *pat)
Check whether a pattern can be searched server-side.
Definition: search.c:57
A simple (non-regex) pattern.
Definition: lib.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compile_search()

static bool compile_search ( const struct ImapAccountData adata,
const struct Pattern pat,
struct Buffer buf 
)
static

Convert NeoMutt pattern to IMAP search.

Parameters
adataImap Account data
patPattern to convert
bufBuffer for result
Return values
trueSuccess
falseFailure

Convert neomutt Pattern to IMAP SEARCH command containing only elements that require full-text search (neomutt already has what it needs for most match types, and does a better job (eg server doesn't support regexes).

Definition at line 209 of file search.c.

211 {
212  if (!check_pattern(pat))
213  return true;
214 
215  if (pat->pat_not)
216  mutt_buffer_addstr(buf, "NOT ");
217 
218  return pat->child ? compile_search_children(adata, pat, buf) :
219  compile_search_self(adata, pat, buf);
220 }
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
static bool compile_search_children(const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
Compile a search command for a pattern's children.
Definition: search.c:104
static bool compile_search_self(const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
Compile a search command for a pattern.
Definition: search.c:143
struct PatternList * child
Arguments to logical operation.
Definition: lib.h:82
bool pat_not
Pattern should be inverted (not)
Definition: lib.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_pattern()

static bool check_pattern ( const struct Pattern pat)
static

Check whether a pattern can be searched server-side.

Parameters
patPattern to check
Return values
truePattern can be searched server-side
falsePattern cannot be searched server-side

Definition at line 57 of file search.c.

58 {
59  switch (pat->op)
60  {
61  case MUTT_PAT_BODY:
62  case MUTT_PAT_HEADER:
63  case MUTT_PAT_WHOLE_MSG:
64  if (pat->string_match)
65  return true;
66  break;
68  return true;
69  break;
70  default:
71  if (pat->child && check_pattern_list(pat->child))
72  return true;
73  break;
74  }
75  return false;
76 }
@ MUTT_PAT_HEADER
Pattern matches email's header.
Definition: lib.h:144
@ MUTT_PAT_WHOLE_MSG
Pattern matches raw email text.
Definition: lib.h:146
@ MUTT_PAT_SERVERSEARCH
Server-side pattern matches.
Definition: lib.h:163
@ MUTT_PAT_BODY
Pattern matches email's body.
Definition: lib.h:143
static int check_pattern_list(const struct PatternList *patterns)
Check how many patterns in a list can be searched server-side.
Definition: search.c:83
bool string_match
Check a string for a match.
Definition: lib.h:73
short op
Operation, e.g. MUTT_PAT_SCORE.
Definition: lib.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compile_search_children()

static bool compile_search_children ( const struct ImapAccountData adata,
const struct Pattern pat,
struct Buffer buf 
)
static

Compile a search command for a pattern's children.

Parameters
adataImap Account data
patParent pattern
bufBuffer for the resulting command
Return values
trueSuccess
falseFailure

Definition at line 104 of file search.c.

106 {
107  int clauses = check_pattern_list(pat->child);
108  if (clauses == 0)
109  return true;
110 
111  mutt_buffer_addch(buf, '(');
112 
113  struct Pattern *c;
114  SLIST_FOREACH(c, pat->child, entries)
115  {
116  if (!check_pattern(c))
117  continue;
118 
119  if ((pat->op == MUTT_PAT_OR) && (clauses > 1))
120  mutt_buffer_addstr(buf, "OR ");
121 
122  if (!compile_search(adata, c, buf))
123  return false;
124 
125  if (clauses > 1)
126  mutt_buffer_addch(buf, ' ');
127 
128  clauses--;
129  }
130 
131  mutt_buffer_addch(buf, ')');
132  return true;
133 }
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
@ MUTT_PAT_OR
Either pattern can match.
Definition: lib.h:127
static bool compile_search(const struct ImapAccountData *adata, const struct Pattern *pat, struct Buffer *buf)
Convert NeoMutt pattern to IMAP search.
Definition: search.c:209
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compile_search_self()

static bool compile_search_self ( const struct ImapAccountData adata,
const struct Pattern pat,
struct Buffer buf 
)
static

Compile a search command for a pattern.

Parameters
adataImap Account data
patPattern
bufBuffer for the resulting command
Return values
trueSuccess
falseFailure

Definition at line 143 of file search.c.

145 {
146  char term[256];
147  char *delim = NULL;
148 
149  switch (pat->op)
150  {
151  case MUTT_PAT_HEADER:
152  mutt_buffer_addstr(buf, "HEADER ");
153 
154  /* extract header name */
155  delim = strchr(pat->p.str, ':');
156  if (!delim)
157  {
158  mutt_error(_("Header search without header name: %s"), pat->p.str);
159  return false;
160  }
161  *delim = '\0';
162  imap_quote_string(term, sizeof(term), pat->p.str, false);
163  mutt_buffer_addstr(buf, term);
164  mutt_buffer_addch(buf, ' ');
165 
166  /* and field */
167  *delim = ':';
168  delim++;
169  SKIPWS(delim);
170  imap_quote_string(term, sizeof(term), delim, false);
171  mutt_buffer_addstr(buf, term);
172  break;
173  case MUTT_PAT_BODY:
174  mutt_buffer_addstr(buf, "BODY ");
175  imap_quote_string(term, sizeof(term), pat->p.str, false);
176  mutt_buffer_addstr(buf, term);
177  break;
178  case MUTT_PAT_WHOLE_MSG:
179  mutt_buffer_addstr(buf, "TEXT ");
180  imap_quote_string(term, sizeof(term), pat->p.str, false);
181  mutt_buffer_addstr(buf, term);
182  break;
184  if (!(adata->capabilities & IMAP_CAP_X_GM_EXT_1))
185  {
186  mutt_error(_("Server-side custom search not supported: %s"), pat->p.str);
187  return false;
188  }
189  mutt_buffer_addstr(buf, "X-GM-RAW ");
190  imap_quote_string(term, sizeof(term), pat->p.str, false);
191  mutt_buffer_addstr(buf, term);
192  break;
193  }
194  return true;
195 }
#define mutt_error(...)
Definition: logging.h:87
#define IMAP_CAP_X_GM_EXT_1
https://developers.google.com/gmail/imap/imap-extensions
Definition: private.h:142
void imap_quote_string(char *dest, size_t dlen, const char *src, bool quote_backtick)
Quote string according to IMAP rules.
Definition: util.c:840
#define _(a)
Definition: message.h:28
#define SKIPWS(ch)
Definition: string2.h:46
ImapCapFlags capabilities
Capability flags.
Definition: adata.h:55
union Pattern::@1 p
char * str
String, if string_match is set.
Definition: lib.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ imap_search()

bool imap_search ( struct Mailbox m,
const struct PatternList *  pat 
)

Find messages in mailbox matching a pattern.

Parameters
mMailbox
patPattern to match
Return values
trueSuccess
falseFailure

Definition at line 229 of file search.c.

230 {
231  for (int i = 0; i < m->msg_count; i++)
232  {
233  struct Email *e = m->emails[i];
234  if (!e)
235  break;
236  e->matched = false;
237  }
238 
239  if (check_pattern_list(pat) == 0)
240  return true;
241 
242  struct Buffer buf;
243  mutt_buffer_init(&buf);
244  mutt_buffer_addstr(&buf, "UID SEARCH ");
245 
246  struct ImapAccountData *adata = imap_adata_get(m);
247  const bool ok = compile_search(adata, SLIST_FIRST(pat), &buf) &&
249 
250  FREE(&buf.data);
251  return ok;
252 }
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
struct ImapAccountData * imap_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:90
int imap_exec(struct ImapAccountData *adata, const char *cmdstr, ImapCmdFlags flags)
Execute a command and wait for the response from the server.
Definition: command.c:1255
#define IMAP_CMD_NO_FLAGS
No flags are set.
Definition: private.h:73
@ IMAP_EXEC_SUCCESS
Imap command executed or queued successfully.
Definition: private.h:84
#define FREE(x)
Definition: memory.h:40
#define SLIST_FIRST(head)
Definition: queue.h:229
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
String manipulation buffer.
Definition: buffer.h:34
The envelope/body of an email.
Definition: email.h:37
bool matched
Search matches this Email.
Definition: email.h:102
IMAP-specific Account data -.
Definition: adata.h:40
char * buf
Definition: adata.h:59
int msg_count
Total number of messages.
Definition: mailbox.h:91
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ cmd_parse_search()

void cmd_parse_search ( struct ImapAccountData adata,
const char *  s 
)

Store SEARCH response for later use.

Parameters
adataImap Account data
sCommand string with search results

Definition at line 259 of file search.c.

260 {
261  unsigned int uid;
262  struct Email *e = NULL;
263  struct ImapMboxData *mdata = adata->mailbox->mdata;
264 
265  mutt_debug(LL_DEBUG2, "Handling SEARCH\n");
266 
267  while ((s = imap_next_word((char *) s)) && (*s != '\0'))
268  {
269  if (!mutt_str_atoui(s, &uid))
270  continue;
271  e = mutt_hash_int_find(mdata->uid_hash, uid);
272  if (e)
273  e->matched = true;
274  }
275 }
const char * mutt_str_atoui(const char *str, unsigned int *dst)
Convert ASCII string to an unsigned integer.
Definition: atoi.c:202
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
void * mutt_hash_int_find(const struct HashTable *table, unsigned int intkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:392
char * imap_next_word(char *s)
Find where the next IMAP word begins.
Definition: util.c:792
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
struct Mailbox * mailbox
Current selected mailbox.
Definition: adata.h:76
IMAP-specific Mailbox data -.
Definition: mdata.h:39
void * mdata
Driver specific data.
Definition: mailbox.h:136
+ Here is the call graph for this function:
+ Here is the caller graph for this function: