Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
83f6a439
...
83f6a4390dd7ae002ee4dfd7ed788f4169bee9ea
authored
2001-05-28 14:25:56 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
implemented
1 parent
e01b13b1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
872 additions
and
1 deletions
imap4d/search.c
imap4d/search.c
View file @
83f6a43
...
...
@@ -21,12 +21,883 @@
* This will be a royal pain in the arse to implement
* Alain: True, but the new lib mailbox should coming handy with
* some sort of query interface.
* Sergey: It was, indeed.
*/
/* Implementation details:
The searching criteria are parsed and compiled into the array of
instructions. Each item of the array is either an instruction (inst_t
type) or the argument to previous instruction. The code array is
terminated by NULL. The result of `executing' the code array is
0 or 1 depending on whether current message meets the search
conditions.
Note/FIXME: Implementing boolean shortcuts would speed up the long
search queries. */
struct
parsebuf
;
typedef
void
(
*
inst_t
)
__P
((
struct
parsebuf
*
pb
));
static
void
cond_and
__P
((
struct
parsebuf
*
pb
));
static
void
cond_or
__P
((
struct
parsebuf
*
pb
));
static
void
cond_not
__P
((
struct
parsebuf
*
pb
));
static
void
cond_all
__P
((
struct
parsebuf
*
pb
));
static
void
cond_bcc
__P
((
struct
parsebuf
*
pb
));
static
void
cond_before
__P
((
struct
parsebuf
*
pb
));
static
void
cond_body
__P
((
struct
parsebuf
*
pb
));
static
void
cond_cc
__P
((
struct
parsebuf
*
pb
));
static
void
cond_from
__P
((
struct
parsebuf
*
pb
));
static
void
cond_header
__P
((
struct
parsebuf
*
pb
));
static
void
cond_keyword
__P
((
struct
parsebuf
*
pb
));
static
void
cond_larger
__P
((
struct
parsebuf
*
pb
));
static
void
cond_on
__P
((
struct
parsebuf
*
pb
));
static
void
cond_sentbefore
__P
((
struct
parsebuf
*
pb
));
static
void
cond_senton
__P
((
struct
parsebuf
*
pb
));
static
void
cond_sentsince
__P
((
struct
parsebuf
*
pb
));
static
void
cond_since
__P
((
struct
parsebuf
*
pb
));
static
void
cond_smaller
__P
((
struct
parsebuf
*
pb
));
static
void
cond_subject
__P
((
struct
parsebuf
*
pb
));
static
void
cond_text
__P
((
struct
parsebuf
*
pb
));
static
void
cond_to
__P
((
struct
parsebuf
*
pb
));
static
void
cond_uid
__P
((
struct
parsebuf
*
pb
));
/* A basic condition structure */
struct
cond
{
char
*
name
;
/* Condition name */
char
*
argtypes
;
/* String of argument types or NULL if takes no args */
inst_t
inst
;
/* Corresponding instruction */
};
/* Types are: s -- string
n -- number
d -- date
m -- message set
*/
/* List of basic conditions */
struct
cond
condlist
[]
=
{
"ALL"
,
NULL
,
cond_all
,
"BCC"
,
"s"
,
cond_bcc
,
"BEFORE"
,
"d"
,
cond_before
,
"BODY"
,
"s"
,
cond_body
,
"CC"
,
"s"
,
cond_cc
,
"FROM"
,
"s"
,
cond_from
,
"HEADER"
,
"ss"
,
cond_header
,
"KEYWORD"
,
"s"
,
cond_keyword
,
"LARGER"
,
"n"
,
cond_larger
,
"ON"
,
"d"
,
cond_on
,
"SENTBEFORE"
,
"d"
,
cond_sentbefore
,
"SENTON"
,
"d"
,
cond_senton
,
"SENTSINCE"
,
"d"
,
cond_sentsince
,
"SINCE"
,
"d"
,
cond_since
,
"SMALLER"
,
"n"
,
cond_smaller
,
"SUBJECT"
,
"s"
,
cond_subject
,
"TEXT"
,
"s"
,
cond_text
,
"TO"
,
"s"
,
cond_to
,
"UID"
,
"m"
,
cond_uid
,
NULL
,
};
/* Other search keys described by rfc2060 are implemented on top of these
basic conditions. Condition equivalence structure defines the equivalent
condition in terms of basic ones. (Kind of macro substitution) */
struct
cond_equiv
{
char
*
name
;
/* RFC2060 search key name */
char
*
equiv
;
/* Equivalent query in terms of basic conds */
};
struct
cond_equiv
equiv_list
[]
=
{
"ANSWERED"
,
"KEYWORD
\\
Answered"
,
"DELETED"
,
"KEYWORD
\\
Deleted"
,
"DRAFT"
,
"KEYWORD
\\
Draft"
,
"FLAGGED"
,
"KEYWORD
\\
Flagged"
,
"NEW"
,
"(RECENT UNSEEN)"
,
"OLD"
,
"NOT RECENT"
,
"RECENT"
,
"KEYWORD
\\
Recent"
,
"SEEN"
,
"KEYWORD
\\
Seen"
,
"UNANSWERED"
,
"NOT KEYWORD
\\
Answered"
,
"UNDELETED"
,
"NOT KEYWORD
\\
Deleted"
,
"UNDRAFT"
,
"NOT KEYWORD
\\
Draft"
,
"UNFLAGGED"
,
"NOT KEYWORD
\\
Flagged"
,
"UNKEYWORD"
,
"NOT KEYWORD"
,
"UNSEEN"
,
"NOT KEYWORD
\\
Seen"
,
NULL
};
/* A memory allocation chain used to keep track of objects allocated during
the recursive-descent parsing. */
struct
mem_chain
{
struct
mem_chain
*
next
;
void
*
mem
;
};
/* Code and stack sizes for execution of compiled search statement */
#define CODESIZE 64
#define CODEINCR 16
#define STACKSIZE 64
#define STACKINCR 16
/* Maximum length of a token. Tokens longer than that are accepted, provided
that they are enclosed in doublequotes */
#define MAXTOKEN 64
/* Parse buffer structure */
struct
parsebuf
{
char
*
token
;
/* Current token. Either points to tokbuf
or is allocated within `alloc' chain */
char
tokbuf
[
MAXTOKEN
+
1
];
/* Token buffer for short tokens */
char
*
arg
;
/* Rest of command line to be parsed */
char
*
err_mesg
;
/* Error message if a parse error occured */
struct
mem_chain
*
alloc
;
/* Chain of objects allocated during parsing */
int
codesize
;
/* Current size of allocated code */
inst_t
*
code
;
/* Code buffer */
int
pc
;
/* Program counter. On parse time points
to the next free slot in `code' array.
On execution time, points to the next
instruction to be executed */
int
stacksize
;
/* Current size of allocated stack */
int
*
stack
;
/* Stack buffer. */
int
tos
;
/* Top of stack */
message_t
msg
;
/* Execution time only: current message */
};
static
void
put_code
__P
((
struct
parsebuf
*
pb
,
inst_t
inst
));
static
void
parse_free_mem
__P
((
struct
parsebuf
*
pb
));
static
void
*
parse_regmem
__P
((
struct
parsebuf
*
pb
,
void
*
mem
));
static
char
*
parse_strdup
__P
((
struct
parsebuf
*
pb
,
char
*
s
));
static
void
*
parse_alloc
__P
((
struct
parsebuf
*
pb
,
size_t
size
));
static
int
parse_search_key_list
__P
((
struct
parsebuf
*
pb
));
static
int
parse_search_key
__P
((
struct
parsebuf
*
pb
));
static
int
parse_gettoken
__P
((
struct
parsebuf
*
pb
,
int
req
));
static
int
search_run
__P
((
struct
parsebuf
*
pb
));
static
void
do_search
__P
((
struct
parsebuf
*
pb
));
int
imap4d_search
(
struct
imap4d_command
*
command
,
char
*
arg
)
{
char
*
sp
;
char
*
str
;
struct
parsebuf
parsebuf
;
if
(
!
(
command
->
states
&
state
))
return
util_finish
(
command
,
RESP_BAD
,
"Wrong state"
);
return
util_finish
(
command
,
RESP_NO
,
"Not supported"
);
memset
(
&
parsebuf
,
0
,
sizeof
(
parsebuf
));
parsebuf
.
arg
=
arg
;
parsebuf
.
err_mesg
=
NULL
;
parsebuf
.
alloc
=
NULL
;
if
(
!
parse_gettoken
(
&
parsebuf
,
0
))
return
util_finish
(
command
,
RESP_BAD
,
"Too few args"
);
if
(
strcasecmp
(
parsebuf
.
token
,
"CHARSET"
)
==
0
)
{
if
(
!
parse_gettoken
(
&
parsebuf
,
0
))
return
util_finish
(
command
,
RESP_BAD
,
"Too few args"
);
/* Currently only ASCII is supported */
if
(
strcmp
(
parsebuf
.
token
,
"US-ASCII"
))
return
util_finish
(
command
,
RESP_NO
,
"Charset not supported"
);
if
(
!
parse_gettoken
(
&
parsebuf
,
0
))
return
util_finish
(
command
,
RESP_BAD
,
"Too few args"
);
}
/* Compile the expression */
if
(
parse_search_key_list
(
&
parsebuf
))
{
parse_free_mem
(
&
parsebuf
);
return
util_finish
(
command
,
RESP_BAD
,
"%s (near %s)"
,
parsebuf
.
err_mesg
,
*
parsebuf
.
arg
?
parsebuf
.
arg
:
"end"
);
}
put_code
(
&
parsebuf
,
NULL
);
/* Execute compiled expression */
do_search
(
&
parsebuf
);
parse_free_mem
(
&
parsebuf
);
return
util_finish
(
command
,
RESP_OK
,
"Completed"
);
}
/* For each message from the mailbox execute the query from `pb' and
output the message number if the query returned 1 */
void
do_search
(
struct
parsebuf
*
pb
)
{
size_t
i
,
count
=
0
;
size_t
*
set
=
NULL
;
int
n
=
0
;
mailbox_messages_count
(
mbox
,
&
count
);
util_send
(
"* SEARCH"
);
for
(
i
=
1
;
i
<=
count
;
i
++
)
{
if
(
mailbox_get_message
(
mbox
,
i
,
&
pb
->
msg
)
==
0
&&
search_run
(
pb
))
util_send
(
" %d"
,
i
);
}
util_send
(
"
\r\n
"
);
}
/* Parse buffer functions */
int
parse_gettoken
(
struct
parsebuf
*
pb
,
int
req
)
{
int
rc
;
char
*
s
;
pb
->
token
=
pb
->
tokbuf
;
while
(
*
pb
->
arg
&&
*
pb
->
arg
==
' '
)
pb
->
arg
++
;
switch
(
*
pb
->
arg
)
{
case
'('
:
case
')'
:
pb
->
token
[
0
]
=
*
pb
->
arg
++
;
pb
->
token
[
1
]
=
0
;
rc
=
1
;
break
;
case
'"'
:
s
=
++
pb
->
arg
;
while
(
*
pb
->
arg
&&
*
pb
->
arg
!=
'"'
)
pb
->
arg
++
;
rc
=
pb
->
arg
-
s
;
if
(
*
pb
->
arg
)
pb
->
arg
++
;
if
(
rc
>=
sizeof
(
pb
->
tokbuf
))
pb
->
token
=
parse_alloc
(
pb
,
rc
+
1
);
memcpy
(
pb
->
token
,
s
,
rc
);
pb
->
token
[
rc
]
=
0
;
break
;
default:
rc
=
util_token
(
pb
->
token
,
sizeof
(
pb
->
tokbuf
),
&
pb
->
arg
);
break
;
}
if
(
req
&&
rc
==
0
)
pb
->
err_mesg
=
"Unexpected end of statement"
;
return
rc
;
}
/* Memory handling */
/* Free all memory allocated for parsebuf structure */
void
parse_free_mem
(
struct
parsebuf
*
pb
)
{
struct
mem_chain
*
alloc
,
*
next
;
alloc
=
pb
->
alloc
;
while
(
alloc
)
{
next
=
alloc
->
next
;
free
(
alloc
->
mem
);
free
(
alloc
);
alloc
=
next
;
}
if
(
pb
->
code
)
free
(
pb
->
code
);
if
(
pb
->
stack
)
free
(
pb
->
stack
);
}
/* Register a memory pointer mem with the parsebuf */
void
*
parse_regmem
(
struct
parsebuf
*
pb
,
void
*
mem
)
{
struct
mem_chain
*
mp
;
mp
=
malloc
(
sizeof
(
*
mp
));
if
(
!
mp
)
imap4d_bye
(
ERR_NO_MEM
);
mp
->
next
=
pb
->
alloc
;
pb
->
alloc
=
mp
;
mp
->
mem
=
mem
;
return
mem
;
}
/* Allocate `size' bytes of memory within parsebuf structure */
void
*
parse_alloc
(
struct
parsebuf
*
pb
,
size_t
size
)
{
void
*
p
=
malloc
(
size
);
if
(
!
p
)
imap4d_bye
(
ERR_NO_MEM
);
return
parse_regmem
(
pb
,
p
);
}
/* Create a copy of the string. */
char
*
parse_strdup
(
struct
parsebuf
*
pb
,
char
*
s
)
{
s
=
strdup
(
s
);
if
(
!
s
)
imap4d_bye
(
ERR_NO_MEM
);
return
parse_regmem
(
pb
,
s
);
}
/* A recursive-descent parser for the following grammar:
search_key_list : search_key
| search_key_list search_key
;
search_key : simple_key
| NOT simple_key
| OR simple_key simple_key
| '(' search_key_list ')'
;
*/
int
parse_search_key_list
(
struct
parsebuf
*
pb
)
{
int
count
=
0
;
while
(
pb
->
token
[
0
]
&&
pb
->
token
[
0
]
!=
')'
)
{
if
(
parse_search_key
(
pb
))
return
1
;
if
(
count
++
)
put_code
(
pb
,
cond_and
);
}
return
0
;
}
int
parse_search_key
(
struct
parsebuf
*
pb
)
{
if
(
strcmp
(
pb
->
token
,
"("
)
==
0
)
{
if
(
parse_gettoken
(
pb
,
1
)
==
0
||
parse_search_key_list
(
pb
))
return
1
;
if
(
strcmp
(
pb
->
token
,
")"
))
{
pb
->
err_mesg
=
"Unbalanced parenthesis"
;
return
1
;
}
parse_gettoken
(
pb
,
0
);
return
0
;
}
else
if
(
strcasecmp
(
pb
->
token
,
"NOT"
)
==
0
)
{
if
(
parse_gettoken
(
pb
,
1
)
==
0
||
parse_search_key
(
pb
))
return
1
;
put_code
(
pb
,
cond_not
);
return
0
;
}
else
if
(
strcasecmp
(
pb
->
token
,
"OR"
)
==
0
)
{
if
(
parse_gettoken
(
pb
,
1
)
==
0
||
parse_search_key
(
pb
)
||
parse_search_key
(
pb
))
return
1
;
put_code
(
pb
,
cond_or
);
return
0
;
}
else
return
parse_equiv_key
(
pb
);
}
int
parse_equiv_key
(
struct
parsebuf
*
pb
)
{
struct
cond_equiv
*
condp
;
char
*
arg
;
char
*
save_arg
;
for
(
condp
=
equiv_list
;
condp
->
name
&&
strcasecmp
(
condp
->
name
,
pb
->
token
);
condp
++
)
;
if
(
!
condp
->
name
)
return
parse_simple_key
(
pb
);
save_arg
=
pb
->
arg
;
arg
=
parse_strdup
(
pb
,
condp
->
equiv
);
pb
->
arg
=
arg
;
parse_gettoken
(
pb
,
0
);
if
(
parse_search_key_list
(
pb
))
{
/* shouldn't happen */
syslog
(
LOG_CRIT
,
"%s:%d: INTERNAL ERROR"
,
__FILE__
,
__LINE__
);
abort
();
}
pb
->
arg
=
save_arg
;
parse_gettoken
(
pb
,
0
);
return
0
;
}
int
parse_simple_key
(
struct
parsebuf
*
pb
)
{
struct
cond
*
condp
;
char
*
t
;
time_t
time
;
for
(
condp
=
condlist
;
condp
->
name
&&
strcasecmp
(
condp
->
name
,
pb
->
token
);
condp
++
)
;
if
(
!
condp
->
name
)
{
pb
->
err_mesg
=
"Unknown search criterion"
;
return
1
;
}
put_code
(
pb
,
condp
->
inst
);
parse_gettoken
(
pb
,
0
);
if
(
condp
->
argtypes
)
{
char
*
t
=
condp
->
argtypes
;
char
*
s
;
int
n
;
size_t
*
set
;
for
(;
*
t
;
t
++
,
parse_gettoken
(
pb
,
0
))
{
if
(
!
pb
->
token
[
0
])
{
pb
->
err_mesg
=
"Not enough arguments for criterion"
;
return
1
;
}
switch
(
*
t
)
{
case
's'
:
/* string */
put_code
(
pb
,
(
inst_t
)
parse_strdup
(
pb
,
pb
->
token
));
break
;
case
'n'
:
/* number */
n
=
strtoul
(
pb
->
token
,
&
s
,
10
);
if
(
*
s
)
{
pb
->
err_mesg
=
"Invalid number"
;
return
1
;
}
put_code
(
pb
,
(
inst_t
)
n
);
break
;
case
'd'
:
/* date */
if
(
util_parse_internal_date
(
pb
->
token
,
&
time
))
{
pb
->
err_mesg
=
"Bad date format"
;
return
1
;
}
put_code
(
pb
,
(
inst_t
)
time
);
break
;
case
'm'
:
/* message set */
if
(
util_msgset
(
pb
->
token
,
&
set
,
&
n
,
1
))
/*FIXME: isuid?*/
{
pb
->
err_mesg
=
"Bogus number set"
;
return
1
;
}
put_code
(
pb
,
(
inst_t
)
n
);
put_code
(
pb
,
(
inst_t
)
parse_regmem
(
pb
,
set
));
break
;
default:
syslog
(
LOG_CRIT
,
"%s:%d: INTERNAL ERROR"
,
__FILE__
,
__LINE__
);
abort
();
/* should never happen */
}
}
}
return
0
;
}
/* Code generator */
void
put_code
(
struct
parsebuf
*
pb
,
inst_t
inst
)
{
if
(
pb
->
codesize
==
0
)
{
pb
->
codesize
=
CODESIZE
;
pb
->
code
=
calloc
(
CODESIZE
,
sizeof
(
pb
->
code
[
0
]));
if
(
!
pb
->
code
)
imap4d_bye
(
ERR_NO_MEM
);
pb
->
pc
=
0
;
}
else
if
(
pb
->
pc
>=
pb
->
codesize
)
{
inst_t
*
new_code
;
pb
->
codesize
+=
CODEINCR
;
new_code
=
realloc
(
pb
->
code
,
pb
->
codesize
*
sizeof
(
pb
->
code
[
0
]));
if
(
!
new_code
)
imap4d_bye
(
ERR_NO_MEM
);
pb
->
code
=
new_code
;
}
pb
->
code
[
pb
->
pc
++
]
=
inst
;
}
/* The machine */
static
void
*
_search_arg
(
struct
parsebuf
*
pb
)
{
return
(
void
*
)
pb
->
code
[
pb
->
pc
++
];
}
static
int
_search_push
(
struct
parsebuf
*
pb
,
int
val
)
{
if
(
pb
->
tos
==
pb
->
stacksize
)
{
if
(
pb
->
stacksize
==
0
)
{
pb
->
stacksize
=
STACKSIZE
;
pb
->
stack
=
calloc
(
STACKSIZE
,
sizeof
(
pb
->
stack
[
0
]));
}
else
{
pb
->
stacksize
+=
STACKINCR
;
pb
->
stack
=
realloc
(
pb
->
stack
,
pb
->
stacksize
*
sizeof
(
pb
->
stack
[
0
]));
}
if
(
!
pb
->
stack
)
imap4d_bye
(
ERR_NO_MEM
);
}
pb
->
stack
[
pb
->
tos
++
]
=
val
;
}
static
int
_search_pop
(
struct
parsebuf
*
pb
)
{
if
(
pb
->
tos
==
0
)
{
syslog
(
LOG_CRIT
,
"%s:%d: INTERNAL ERROR"
,
__FILE__
,
__LINE__
);
abort
();
/* shouldn't happen */
}
return
pb
->
stack
[
--
pb
->
tos
];
}
/* Executes a query from parsebuf */
int
search_run
(
struct
parsebuf
*
pb
)
{
pb
->
pc
=
0
;
while
(
pb
->
code
[
pb
->
pc
]
!=
NULL
)
(
*
pb
->
code
[
pb
->
pc
++
])
(
pb
);
return
_search_pop
(
pb
);
}
/* Helper functions for evaluationg conditions */
/* Scan the header of a message for the occurence of field named `name'.
Return true if any of the occurences contained substring `value' */
static
int
_scan_header
(
struct
parsebuf
*
pb
,
char
*
name
,
char
*
value
)
{
char
buffer
[
512
];
header_t
header
=
NULL
;
message_get_header
(
pb
->
msg
,
&
header
);
if
(
!
header_get_value
(
header
,
name
,
buffer
,
sizeof
(
buffer
),
NULL
))
{
return
strstr
(
buffer
,
value
)
!=
NULL
;
}
return
0
;
}
/* Get the value of Date: field and convert it to timestamp */
static
int
_header_date
(
struct
parsebuf
*
pb
,
time_t
*
timep
)
{
char
buffer
[
512
];
header_t
header
=
NULL
;
message_get_header
(
pb
->
msg
,
&
header
);
if
(
!
header_get_value
(
header
,
"Date"
,
buffer
,
sizeof
(
buffer
),
NULL
)
&&
util_parse_header_date
(
buffer
,
timep
))
return
0
;
return
1
;
}
/* Scan all header fields for the occurence of a substring `text' */
static
int
_scan_header_all
(
struct
parsebuf
*
pb
,
char
*
text
)
{
char
buffer
[
512
];
header_t
header
=
NULL
;
size_t
fcount
=
0
;
int
i
,
rc
;
message_get_header
(
pb
->
msg
,
&
header
);
header_get_field_count
(
header
,
&
fcount
);
for
(
i
=
rc
=
0
;
i
<
fcount
;
i
++
)
{
if
(
header_get_field_value
(
header
,
i
,
buffer
,
sizeof
(
buffer
),
NULL
))
rc
=
strstr
(
buffer
,
text
)
!=
NULL
;
}
return
rc
;
}
/* Scan body of the message for the occurence of a substring */
static
int
_scan_body
(
struct
parsebuf
*
pb
,
char
*
text
)
{
body_t
body
=
NULL
;
stream_t
stream
=
NULL
;
size_t
size
=
0
,
lines
=
0
;
char
buffer
[
128
];
size_t
n
=
0
;
off_t
offset
=
0
;
int
rc
;
message_get_body
(
pb
->
msg
,
&
body
);
body_size
(
body
,
&
size
);
body_lines
(
body
,
&
lines
);
body_get_stream
(
body
,
&
stream
);
rc
=
0
;
while
(
rc
==
0
&&
stream_read
(
stream
,
buffer
,
sizeof
(
buffer
)
-
1
,
offset
,
&
n
)
==
0
&&
n
>
0
)
{
offset
+=
n
;
rc
=
strstr
(
buffer
,
text
)
!=
NULL
;
}
return
rc
;
}
/* Basic instructions */
void
cond_and
(
struct
parsebuf
*
pb
)
{
int
n1
,
n2
;
n1
=
_search_pop
(
pb
);
n2
=
_search_pop
(
pb
);
_search_push
(
pb
,
n1
&&
n2
);
}
void
cond_or
(
struct
parsebuf
*
pb
)
{
int
n1
,
n2
;
n1
=
_search_pop
(
pb
);
n2
=
_search_pop
(
pb
);
_search_push
(
pb
,
n1
||
n2
);
}
void
cond_not
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
!
_search_pop
(
pb
));
}
void
cond_all
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
1
);
}
void
cond_bcc
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
_scan_header
(
pb
,
"bcc"
,
_search_arg
(
pb
)));
}
void
cond_before
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
;
char
buffer
[
512
];
envelope_t
env
;
int
rc
=
0
;
message_get_envelope
(
pb
->
msg
,
&
env
);
envelope_date
(
env
,
buffer
,
sizeof
(
buffer
),
NULL
);
util_parse_rfc822_date
(
buffer
,
&
mesg_time
);
_search_push
(
pb
,
mesg_time
<
t
);
}
void
cond_body
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
_scan_body
(
pb
,
_search_arg
(
pb
)));
}
void
cond_cc
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
_scan_header
(
pb
,
"cc"
,
_search_arg
(
pb
)));
}
void
cond_from
(
struct
parsebuf
*
pb
)
{
char
*
s
=
_search_arg
(
pb
);
envelope_t
env
;
char
buffer
[
512
];
int
rc
=
0
;
message_get_envelope
(
pb
->
msg
,
&
env
);
if
(
envelope_sender
(
env
,
buffer
,
sizeof
(
buffer
),
NULL
)
==
0
)
rc
=
strstr
(
buffer
,
s
)
!=
NULL
;
_search_push
(
pb
,
_scan_header
(
pb
,
"from"
,
s
));
}
void
cond_header
(
struct
parsebuf
*
pb
)
{
char
*
name
=
_search_arg
(
pb
);
char
*
value
=
_search_arg
(
pb
);
_search_push
(
pb
,
_scan_header
(
pb
,
name
,
value
));
}
void
cond_keyword
(
struct
parsebuf
*
pb
)
{
char
*
s
=
_search_arg
(
pb
);
int
rc
;
attribute_t
attr
=
NULL
;
message_get_attribute
(
pb
->
msg
,
&
attr
);
if
(
!
strcmp
(
s
,
"
\\
Seen"
))
rc
=
attribute_is_seen
(
attr
);
else
if
(
!
strcmp
(
s
,
"
\\
Answered"
))
rc
=
attribute_is_answered
(
attr
);
else
if
(
!
strcmp
(
s
,
"
\\
Flagged"
))
rc
=
attribute_is_flagged
(
attr
);
else
if
(
!
strcmp
(
s
,
"
\\
Deleted"
))
rc
=
attribute_is_deleted
(
attr
);
else
if
(
!
strcmp
(
s
,
"
\\
Draft"
))
rc
=
attribute_is_draft
(
attr
);
else
if
(
!
strcmp
(
s
,
"
\\
Recent"
))
rc
=
attribute_is_recent
(
attr
);
else
rc
=
0
;
_search_push
(
pb
,
rc
);
}
void
cond_larger
(
struct
parsebuf
*
pb
)
{
int
n
=
(
int
)
_search_arg
(
pb
);
size_t
size
=
0
;
message_size
(
pb
->
msg
,
&
size
);
_search_push
(
pb
,
size
>
n
);
}
void
cond_on
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
;
char
buffer
[
512
];
envelope_t
env
;
int
rc
=
0
;
message_get_envelope
(
pb
->
msg
,
&
env
);
envelope_date
(
env
,
buffer
,
sizeof
(
buffer
),
NULL
);
util_parse_rfc822_date
(
buffer
,
&
mesg_time
);
_search_push
(
pb
,
t
<=
mesg_time
&&
mesg_time
<=
t
+
86400
);
}
void
cond_sentbefore
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
=
0
;
_header_date
(
pb
,
&
mesg_time
);
_search_push
(
pb
,
mesg_time
<
t
);
}
void
cond_senton
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
=
0
;
_header_date
(
pb
,
&
mesg_time
);
_search_push
(
pb
,
t
<=
mesg_time
&&
mesg_time
<=
t
+
86400
);
}
void
cond_sentsince
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
=
0
;
_header_date
(
pb
,
&
mesg_time
);
_search_push
(
pb
,
mesg_time
>=
t
);
}
void
cond_since
(
struct
parsebuf
*
pb
)
{
time_t
t
=
(
time_t
)
_search_arg
(
pb
);
time_t
mesg_time
;
char
buffer
[
512
];
envelope_t
env
;
int
rc
=
0
;
message_get_envelope
(
pb
->
msg
,
&
env
);
envelope_date
(
env
,
buffer
,
sizeof
(
buffer
),
NULL
);
util_parse_rfc822_date
(
buffer
,
&
mesg_time
);
_search_push
(
pb
,
mesg_time
>=
t
);
}
void
cond_smaller
(
struct
parsebuf
*
pb
)
{
int
n
=
(
int
)
_search_arg
(
pb
);
size_t
size
=
0
;
message_size
(
pb
->
msg
,
&
size
);
_search_push
(
pb
,
size
<
n
);
}
void
cond_subject
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
_scan_header
(
pb
,
"subject"
,
_search_arg
(
pb
)));
}
void
cond_text
(
struct
parsebuf
*
pb
)
{
char
*
s
=
_search_arg
(
pb
);
_search_push
(
pb
,
_scan_header_all
(
pb
,
s
)
||
_scan_body
(
pb
,
s
));
}
void
cond_to
(
struct
parsebuf
*
pb
)
{
_search_push
(
pb
,
_scan_header
(
pb
,
"to"
,
_search_arg
(
pb
)));
}
void
cond_uid
(
struct
parsebuf
*
pb
)
{
int
n
=
(
int
)
_search_arg
(
pb
);
size_t
*
set
=
(
size_t
*
)
_search_arg
(
pb
);
size_t
uid
=
0
;
int
i
,
rc
;
message_get_uid
(
pb
->
msg
,
&
uid
);
for
(
i
=
rc
=
0
;
rc
==
0
&&
i
<
n
;
i
++
)
rc
=
set
[
i
]
==
uid
;
_search_push
(
pb
,
rc
);
}
...
...
Please
register
or
sign in
to post a comment