summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Vandry <vandry@TZoNE.ORG>2014-09-05 10:30:45 -0400
committerKim Vandry <vandry@TZoNE.ORG>2014-09-05 15:07:39 -0400
commit23375a7b5edb87aa0b8781125321e0196a8d4246 (patch)
tree2d38cfc8bbb7beb020185946a85728ec3d4028b5
parent0d6473dc7f161d70a7f2baedaa40f13e3fe05a1e (diff)
Added support for search results in an IMAP folder
-rw-r--r--imap.c13
-rw-r--r--imap.h1
-rw-r--r--imapinterface.c148
-rw-r--r--imapinterface.h4
-rw-r--r--mairix.c28
-rw-r--r--mairix.h3
-rw-r--r--search.c58
7 files changed, 243 insertions, 12 deletions
diff --git a/imap.c b/imap.c
index b0dacf7..32ea428 100644
--- a/imap.c
+++ b/imap.c
@@ -838,6 +838,19 @@ imap_ll_status(struct imap_ll_tokenlist *t)
return t->leaf;
}
+int
+imap_ll_is_trycreate(struct imap_ll_tokenlist *t)
+{
+ return (
+ (0 == strcmp(imap_ll_status(t), "NO")) &&
+ (t->last->first->next) &&
+ ((t->last->first->next->type) == TLTYPE_SQLIST) &&
+ (t->last->first->next->first) &&
+ ((t->last->first->next->first->type) == TLTYPE_ATOM) &&
+ (0 == strcmp(t->last->first->next->first->leaf, "TRYCREATE"))
+ );
+}
+
#ifdef USE_OPENSSL
enum imap_ll_starttls_result
imap_ll_starttls(struct imap_ll *ll, SSL_CTX *sslctx, const char *servername)
diff --git a/imap.h b/imap.h
index 0e4d12b..38d571b 100644
--- a/imap.h
+++ b/imap.h
@@ -41,6 +41,7 @@ void imap_ll_append(struct imap_ll_tokenlist *, struct imap_ll_tokenlist *);
void imap_ll_pprint(struct imap_ll_tokenlist *, int indent, FILE *);
struct imap_ll_tokenlist *imap_ll_command(struct imap_ll *, struct imap_ll_tokenlist *, int timeout);
const char *imap_ll_status(struct imap_ll_tokenlist *);
+int imap_ll_is_trycreate(struct imap_ll_tokenlist *);
#ifdef USE_OPENSSL
enum imap_ll_starttls_result {
diff --git a/imapinterface.c b/imapinterface.c
index 4f9063c..7d09517 100644
--- a/imapinterface.c
+++ b/imapinterface.c
@@ -270,3 +270,151 @@ struct make_rfc822_from_imap_s s;
imap_fetch_message_raw(pseudopath, imapc, callback822, &s);
return s.r;
}
+
+void
+imap_clear_folder(struct imap_ll *imapc, const char *folder)
+{
+struct imap_ll_tokenlist *cmd, *result;
+
+ if (!imap_select(imapc, folder, -1, 1, NULL)) return;
+ cmd = imap_ll_build(
+ TLTYPE_TAGGED,
+ TLTYPE_ATOM, "STORE", (size_t)-1,
+ TLTYPE_ATOM, "1:*", (size_t)-1,
+ TLTYPE_ATOM, "+FLAGS", (size_t)-1,
+ TLTYPE_ATOM, "\\Deleted", (size_t)-1,
+ TLTYPE_END
+ );
+ result = imap_ll_command(imapc, cmd, 10);
+ imap_ll_freeline(cmd);
+ imap_ll_freeline(result);
+ cmd = imap_ll_build(
+ TLTYPE_TAGGED,
+ TLTYPE_ATOM, "EXPUNGE", (size_t)-1,
+ TLTYPE_END
+ );
+ result = imap_ll_command(imapc, cmd, 10);
+ imap_ll_freeline(cmd);
+ imap_ll_freeline(result);
+}
+
+void
+create_folder(struct imap_ll *imapc, const char *folder)
+{
+struct imap_ll_tokenlist *cmd, *result;
+
+ cmd = imap_ll_build(
+ TLTYPE_TAGGED,
+ TLTYPE_ATOM, "CREATE", (size_t)-1,
+ TLTYPE_STRING, folder, (size_t)-1,
+ TLTYPE_END
+ );
+ result = imap_ll_command(imapc, cmd, 10);
+ imap_ll_freeline(cmd);
+ imap_ll_freeline(result);
+}
+
+void
+imap_copy_message(struct imap_ll *imapc, const char *pseudopath, const char *to_folder)
+{
+struct imap_ll_tokenlist *cmd, *result;
+const char *uidvalidity, *uid, *folder, *p;
+size_t uidvalidity_len, uid_len;
+const char *actual_uidvalidity;
+
+ /* first part is the uidvalidity */
+ uidvalidity = pseudopath;
+ p = strchr(pseudopath, ':');
+ if (!p) return;
+ uidvalidity_len = p-pseudopath;
+ uid = p+1;
+
+ /* second part is the uid */
+ p = strchr(uid, ':');
+ if (!p) return;
+ uid_len = p-uid;
+ folder = p+1;
+
+ actual_uidvalidity = imap_select(imapc, folder, -1, 0, NULL);
+ if (!actual_uidvalidity) return;
+
+ if (
+ (strlen(actual_uidvalidity) != uidvalidity_len) ||
+ (0 != memcmp(uidvalidity, actual_uidvalidity, uidvalidity_len))
+ ) {
+ return;
+ }
+
+ cmd = imap_ll_build(
+ TLTYPE_TAGGED,
+ TLTYPE_ATOM, "UID", (size_t)-1,
+ TLTYPE_ATOM, "COPY", (size_t)-1,
+ TLTYPE_ATOM, uid, uid_len,
+ TLTYPE_STRING, to_folder, (size_t)-1,
+ TLTYPE_END
+ );
+ result = imap_ll_command(imapc, cmd, 10);
+
+ if (imap_ll_is_trycreate(result)) {
+ imap_ll_freeline(result);
+ create_folder(imapc, to_folder);
+ result = imap_ll_command(imapc, cmd, 10);
+ }
+ imap_ll_freeline(cmd);
+
+ if (0 != strcmp(imap_ll_status(result), "OK")) {
+ fprintf(stderr, "unable to COPY message to folder \"%s\":\n", to_folder);
+ imap_ll_pprint(result, 0, stderr);
+ }
+ imap_ll_freeline(result);
+}
+
+void
+imap_append_new_message(
+ struct imap_ll *imapc, const char *folder,
+ const unsigned char *data, size_t len,
+ int seen, int answered, int flagged
+)
+{
+struct imap_ll_tokenlist *flags, *cmd, *result;
+
+ if (!imap_select(imapc, folder, -1, 1, NULL)) return;
+ flags = imap_ll_build(TLTYPE_LIST, TLTYPE_END);
+ if (seen) {
+ imap_ll_append(flags, imap_ll_build(
+ TLTYPE_ATOM, "\\Seen", (size_t)-1, TLTYPE_END
+ ));
+ }
+ if (answered) {
+ imap_ll_append(flags, imap_ll_build(
+ TLTYPE_ATOM, "\\Answered", (size_t)-1, TLTYPE_END
+ ));
+ }
+ if (flagged) {
+ imap_ll_append(flags, imap_ll_build(
+ TLTYPE_ATOM, "\\Flagged", (size_t)-1, TLTYPE_END
+ ));
+ }
+ cmd = imap_ll_build(
+ TLTYPE_TAGGED,
+ TLTYPE_ATOM, "APPEND", (size_t)-1,
+ TLTYPE_STRING, folder, (size_t)-1,
+ TLTYPE_SUB, flags,
+ TLTYPE_STRING, data, len,
+ TLTYPE_END
+ );
+ result = imap_ll_command(imapc, cmd, 10);
+
+ if (imap_ll_is_trycreate(result)) {
+ imap_ll_freeline(result);
+ create_folder(imapc, folder);
+ result = imap_ll_command(imapc, cmd, 10);
+ }
+ imap_ll_freeline(cmd);
+
+ if (0 != strcmp(imap_ll_status(result), "OK")) {
+ fprintf(stderr, "unable to APPEND message to folder \"%s\":\n", folder);
+ imap_ll_pprint(result, 0, stderr);
+ }
+ imap_ll_freeline(result);
+}
diff --git a/imapinterface.h b/imapinterface.h
index 4c673e0..71f7a4f 100644
--- a/imapinterface.h
+++ b/imapinterface.h
@@ -24,4 +24,8 @@ int imap_fetch_message_raw(
struct rfc822 *
make_rfc822_from_imap(const char *pseudopath, struct imap_ll *);
+void imap_clear_folder(struct imap_ll *, const char *);
+void imap_append_new_message(struct imap_ll *, const char *folder, const unsigned char *data, size_t len, int seen, int answered, int flagged);
+void imap_copy_message(struct imap_ll *, const char *pseudopath, const char *to_folder);
+
#endif
diff --git a/mairix.c b/mairix.c
index b4d59a7..7112e6c 100644
--- a/mairix.c
+++ b/mairix.c
@@ -106,6 +106,7 @@ int member_of (const char *complete_mfolder,
break;
case FT_RAW: /* cannot happen but to keep compiler happy */
case FT_EXCERPT:
+ case FT_IMAP:
break;
}
for (i=0; i<n_paths; i++) {
@@ -174,6 +175,8 @@ static void parse_output_folder(char *p)/*{{{*/
output_folder_type = FT_EXCERPT;
} else if (!strncasecmp(temp, "mbox", 4)) {
output_folder_type = FT_MBOX;
+ } else if (!strncasecmp(temp, "imap", 4)) {
+ output_folder_type = FT_IMAP;
}
else {
fprintf(stderr, "Unrecognized mformat <%s>\n", temp);
@@ -712,23 +715,30 @@ int main (int argc, char **argv)/*{{{*/
mfolder = new_string("");
}
- /* complete_mfolder is needed by search_top() and member_of() so
- compute it once here rather than in search_top() as well */
- if ((mfolder[0] == '/') ||
- ((mfolder[0] == '.') && (mfolder[1] == '/'))) {
+ if (output_folder_type == FT_IMAP) {
complete_mfolder = new_string(mfolder);
} else {
- len = strlen(folder_base) + strlen(mfolder) + 2;
- complete_mfolder = new_array(char, len);
- strcpy(complete_mfolder, folder_base);
- strcat(complete_mfolder, "/");
- strcat(complete_mfolder, mfolder);
+ /* complete_mfolder is needed by search_top() and member_of() so
+ compute it once here rather than in search_top() as well */
+ if ((mfolder[0] == '/') ||
+ ((mfolder[0] == '.') && (mfolder[1] == '/'))) {
+ complete_mfolder = new_string(mfolder);
+ } else {
+ len = strlen(folder_base) + strlen(mfolder) + 2;
+ complete_mfolder = new_array(char, len);
+ strcpy(complete_mfolder, folder_base);
+ strcat(complete_mfolder, "/");
+ strcat(complete_mfolder, mfolder);
+ }
}
/* check whether mfolder output would destroy a mail folder or mbox */
switch (output_folder_type) {
case FT_RAW:
case FT_EXCERPT:
break;
+ case FT_IMAP:
+ /* the same check as below could be implemented in the future */
+ break;
default:
if ((member_of(complete_mfolder,folder_base, maildir_folders, FT_MAILDIR, omit_globs)||
member_of (complete_mfolder, folder_base, mh_folders, FT_MH, omit_globs) ||
diff --git a/mairix.h b/mairix.h
index f6943ac..4d9a316 100644
--- a/mairix.h
+++ b/mairix.h
@@ -248,7 +248,8 @@ enum folder_type {/*{{{*/
FT_MH,
FT_MBOX,
FT_RAW,
- FT_EXCERPT
+ FT_EXCERPT,
+ FT_IMAP
};
/*}}}*/
diff --git a/search.c b/search.c
index dbdfae9..d8eec42 100644
--- a/search.c
+++ b/search.c
@@ -829,7 +829,7 @@ static void string_tolower(char *str)
}
}
-static int do_search(struct read_db *db, char **args, char *output_path, int show_threads, enum folder_type ft, int verbose, const char *imap_pipe, const char *imap_server, const char *imap_username, const char *imap_password)/*{{{*/
+static int do_search(struct read_db *db, char **args, char *output_path, int show_threads, enum folder_type ft, int verbose, const char *imap_pipe, const char *imap_server, const char *imap_username, const char *imap_password, int please_clear)/*{{{*/
{
char *colon, *start_words;
int do_body, do_subject, do_from, do_to, do_cc, do_date, do_size;
@@ -1330,6 +1330,54 @@ static int do_search(struct read_db *db, char **args, char *output_path, int sho
}
break;
/*}}}*/
+ case FT_IMAP:/*{{{*/
+ GET_IMAP;
+ if (!imapc) break;
+ if (please_clear) {
+ imap_clear_folder(imapc, output_path);
+ }
+ for (i=0; i<db->n_msgs; i++) {
+ if (hit3[i]) {
+ int is_seen, is_replied, is_flagged;
+ get_flags_from_file(db, i, &is_seen, &is_replied, &is_flagged);
+ switch (rd_msg_type(db, i)) {
+ case DB_MSG_FILE:
+ {
+ int len;
+ unsigned char *data;
+ create_ro_mapping(db->data + db->path_offsets[i], &data, &len);
+ if (data) {
+ imap_append_new_message(imapc, output_path, data, len, is_seen, is_replied, is_flagged);
+ free_ro_mapping(data, len);
+ }
+ ++n_hits;
+ }
+ break;
+ case DB_MSG_IMAP:
+ {
+ imap_copy_message(imapc, db->data + db->path_offsets[i], output_path);
+ ++n_hits;
+ }
+ break;
+ case DB_MSG_MBOX:
+ {
+ unsigned char *start, *data;
+ int mbox_len, msg_len, mbi;
+ get_validated_mbox_msg(db, i, &mbi, &data, &mbox_len, &start, &msg_len);
+ imap_append_new_message(imapc, output_path, start, msg_len, is_seen, is_replied, is_flagged);
+ if (data) {
+ free_ro_mapping(data, mbox_len);
+ }
+ ++n_hits;
+ }
+ break;
+ case DB_MSG_DEAD:
+ break;
+ }
+ }
+ }
+ break;
+/*}}}*/
default:
assert(0);
break;
@@ -1500,6 +1548,7 @@ int search_top(int do_threads, int do_augment, char *database_path, char *comple
{
struct read_db *db;
int result;
+ int please_clear = 0;
db = open_db(database_path);
@@ -1517,6 +1566,7 @@ int search_top(int do_threads, int do_augment, char *database_path, char *comple
break;
case FT_RAW:
case FT_EXCERPT:
+ case FT_IMAP: /* Do it later, we do not yet have an IMAP connection */
break;
default:
assert(0);
@@ -1537,12 +1587,16 @@ int search_top(int do_threads, int do_augment, char *database_path, char *comple
case FT_RAW:
case FT_EXCERPT:
break;
+ case FT_IMAP:
+ /* Do it later: we do not yet have an IMAP connection */
+ please_clear = 1;
+ break;
default:
assert(0);
}
}
- result = do_search(db, argv, complete_mfolder, do_threads, ft, verbose, imap_pipe, imap_server, imap_username, imap_password);
+ result = do_search(db, argv, complete_mfolder, do_threads, ft, verbose, imap_pipe, imap_server, imap_username, imap_password, please_clear);
free(complete_mfolder);
close_db(db);
return result;