Commit ab5a7ed2 authored by Sean Whitton's avatar Sean Whitton

Merge tag '0.24'

Version 0.24
parents a3fff057 9e3a8366
These people have contributed useful patches, ideas and suggestions:
Anand Kumria
Andr Costa
André Costa
Andreas Amann
Andre Costa
Aredridel
Balzs Szab
Balázs Szabó
Bardur Arantsson
Benj. Mako Hill
Chris Mason
......@@ -26,7 +26,7 @@ James Leifer
Jerry Jorgenson
Joerg Desch
Johannes Schindelin
Johannes Weil
Johannes Weißl
John Arthur Kane
John Keener
Jonathan Kamens
......@@ -43,10 +43,12 @@ Paramjit Oberoi
Paul Fox
Peter Chines
Peter Jeremy
Raphaël Hertzog
Robert Hofer
Roberto Boati
Samuel Tardieu
Sanjoy Mahajan
Sean Whitton
Satyaki Das
Steven Lumos
Tim Harder
......
......@@ -50,7 +50,7 @@ docdir=$(DESTDIR)@docdir@
OBJ = mairix.o db.o rfc822.o tok.o hash.o dirscan.o writer.o \
reader.o search.o stats.o dates.o datescan.o mbox.o md5.o \
fromcheck.o glob.o dumper.o expandstr.o dotlock.o \
nvp.o nvpscan.o
nvp.o nvpscan.o imap.o imapinterface.o
all : mairix
......@@ -73,6 +73,13 @@ dates.o : datescan.h
mbox.o : fromcheck.h
nvp.o : nvpscan.h
mairix.o : imapinterface.h
db.o : imapinterface.h
search.o : imapinterface.h
imap.o : imap.c imap.h
imapinterface.o : imapinterface.c imapinterface.h imap.h
version.h:
./mkversion
......
NEW IN VERSION 0.24
===================
* Support fancy Content-Disposition
* RFC5987-compliant headers
* Support for remote IMAP folders
* Fix string overrun bugs in nvp.c
* Option to follow symlinks to mboxes in rc file
* Minor parsing improvements, documentation fixes, and small bug repairs.
NEW IN VERSION 0.23
===================
* Allow '=' in message-id search for RFC2822 conformance
......
......@@ -18,13 +18,15 @@ The program is a very useful complement to mail programs like mutt
(http://www.mutt.org/, which supports Maildir, MH and mbox folders) and
Sylpheed (which supports MH folders).
The original author of mairix is Richard P. Curnow <rc@rc0.org.uk>.
It is maintained since 2017 by Kim Vandry <vandry@TZoNE.ORG>.
[(*) where the input or output folder is an mbox, a copy of the message is made
instead of symlinking.]
See also the mairix.txt file.
*********************************************************************
Copyright (C) Richard P. Curnow 2002-2004
Copyright (C) Richard P. Curnow & Kim Vandry & contributors 2017-
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
......@@ -41,8 +43,9 @@ See also the mairix.txt file.
*********************************************************************
Suggestions, bug reports, experiences, praise, complaints etc to the author
please, at <rc@rc0.org.uk>
Suggestions, bug reports, experiences, praise, complaints are welcom on
the mailing list or as issues or pull requests at
https://github.com/vandry/mairix
Since July 2006, there is a mairix-users mailing list. To subscribe or to view
the archives, visit
......
......@@ -181,6 +181,30 @@ test_for_flex () {
}
#}}}
#{{{ test_for_openssl
test_for_openssl () {
cat > docheck.c <<EOF;
#include <openssl/ssl.h>
int main () {
SSL_load_error_strings();
SSL_library_init();
return 0;
}
EOF
echo "Test program is" 1>&5
cat docheck.c 1>&5
${MYCC} ${MYCPPFLAGS} ${MYCFLAGS} ${MYLDFLAGS} -o docheck docheck.c -lssl -lcrypto 1>&5 2>&1
if [ $? -eq 0 ]
then
result=0
else
result=1
fi
rm -f docheck.c docheck
echo $result
}
#}}}
#{{{ usage
usage () {
cat <<EOF;
......@@ -343,6 +367,15 @@ else
exit 1;
fi
printf "Checking for OpenSSL : "
if [ `test_for_openssl` -eq 0 ]; then
printf "Yes\n";
DEFS="${DEFS} -DUSE_OPENSSL"
LIBS="${LIBS} -lssl -lcrypto"
else
printf "No (disabled IMAP STARTTLS support)\n";
fi
#{{{ Determine version number of the program.
if [ -f version.txt ]; then
revision=`cat version.txt`
......
......@@ -336,9 +336,11 @@ int scan_date_string(char *in, time_t *start, int *has_start, time_t *end, int *
start_tm.tm_hour = 0;
start_tm.tm_min = 0;
start_tm.tm_sec = 0;
start_tm.tm_isdst = -1;
end_tm.tm_hour = 23;
end_tm.tm_min = 59;
end_tm.tm_sec = 59;
end_tm.tm_isdst = -1;
hyphen = strchr(in, '-');
if (!hyphen) {
......
This diff is collapsed.
......@@ -35,7 +35,6 @@ struct msgpath_array *new_msgpath_array(void)/*{{{*/
struct msgpath_array *result;
result = new(struct msgpath_array);
result->paths = NULL;
result->type = NULL;
result->n = 0;
result->max = 0;
return result;
......@@ -46,8 +45,9 @@ void free_msgpath_array(struct msgpath_array *x)/*{{{*/
int i;
if (x->paths) {
for (i=0; i<x->n; i++) {
switch (x->type[i]) {
switch (x->paths[i].type) {
case MTY_FILE:
case MTY_IMAP:
free(x->paths[i].src.mpf.path);
break;
case MTY_MBOX:
......@@ -56,21 +56,20 @@ void free_msgpath_array(struct msgpath_array *x)/*{{{*/
break;
}
}
free(x->type);
free(x->paths);
}
free(x);
}
/*}}}*/
static void add_file_to_list(char *x, struct msgpath_array *arr) {/*{{{*/
static void add_file_to_list(char *x, struct msgpath_array *arr, enum folder_type ft) {/*{{{*/
char *y = new_string(x);
if (arr->n == arr->max) {
arr->max += 1024;
arr->paths = grow_array(struct msgpath, arr->max, arr->paths);
arr->type = grow_array(enum message_type, arr->max, arr->type);
}
arr->type[arr->n] = MTY_FILE;
arr->paths[arr->n].type = MTY_FILE;
arr->paths[arr->n].src.mpf.path = y;
arr->paths[arr->n].source_ft = ft;
++arr->n;
return;
}
......@@ -104,7 +103,7 @@ static void get_maildir_message_paths(char *folder, struct msgpath_array *arr)/*
strcpy(fname, subdir);
strcat(fname, "/");
strcat(fname, de->d_name);
add_file_to_list(fname, arr);
add_file_to_list(fname, arr, FT_MAILDIR);
}
closedir(d);
}
......@@ -151,7 +150,7 @@ static void get_mh_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/
strcat(fname, "/");
strcat(fname, de->d_name);
if (valid_mh_filename_p(de->d_name)) {
add_file_to_list(fname, arr);
add_file_to_list(fname, arr, FT_MH);
}
}
closedir(d);
......@@ -351,20 +350,6 @@ static void scan_directory(char *folder_base, char *this_folder, enum folder_typ
}
/*}}}*/
#endif
static int message_compare(const void *a, const void *b)/*{{{*/
{
/* FIXME : Is this a sensible way to do this with mbox messages in the picture? */
struct msgpath *aa = (struct msgpath *) a;
struct msgpath *bb = (struct msgpath *) b;
/* This should only get called on 'file' type messages - TBC! */
return strcmp(aa->src.mpf.path, bb->src.mpf.path);
}
/*}}}*/
static void sort_message_list(struct msgpath_array *arr)/*{{{*/
{
qsort(arr->paths, arr->n, sizeof(struct msgpath), message_compare);
}
/*}}}*/
/*{{{ void build_message_list */
void build_message_list(char *folder_base, char *folders, enum folder_type ft,
struct msgpath_array *msgs,
......@@ -394,7 +379,6 @@ void build_message_list(char *folder_base, char *folders, enum folder_type ft,
if (paths) free(paths);
sort_message_list(msgs);
return;
}
/*}}}*/
......
......@@ -99,6 +99,10 @@ void dump_database(char *filename)
printf("FILE %s, size=%d, tid=%d",
db->data + db->path_offsets[i], db->size_table[i], db->tid_table[i]);
break;
case DB_MSG_IMAP:
printf("IMAP %s, tid=%d",
db->data + db->path_offsets[i], db->tid_table[i]);
break;
case DB_MSG_MBOX:
{
unsigned int mbix, msgix;
......
This diff is collapsed.
#ifndef __IMAPLL_H__
#define __IMAPLL_H__
#ifdef USE_OPENSSL
#include <openssl/ssl.h>
#endif
#include <poll.h>
enum imap_ll_tltype {
TLTYPE_UNTAGGED = 1,
TLTYPE_TAGGED = 2,
TLTYPE_LIST = 3,
TLTYPE_SQLIST = 4,
TLTYPE_ATOM = 5,
TLTYPE_STRING = 6,
TLTYPE_CONTINUATION = 7,
/* the following only for imap_ll_build */
TLTYPE_END = 100,
TLTYPE_POP = 101,
TLTYPE_SUB = 102
};
struct imap_ll_tokenlist {
enum imap_ll_tltype type;
char *leaf;
size_t leaflen;
struct imap_ll_tokenlist *parent;
struct imap_ll_tokenlist *next;
/* children */
struct imap_ll_tokenlist *first;
struct imap_ll_tokenlist *last;
};
struct imap_ll *imap_ll_connect(const char *host, const char *port);
struct imap_ll *imap_ll_pipe_connect(const char *command);
void imap_ll_timeout(struct imap_ll *, int seconds);
struct imap_ll_tokenlist *imap_ll_waitline(struct imap_ll *);
void imap_ll_freeline(struct imap_ll_tokenlist *);
struct imap_ll_tokenlist *imap_ll_build(enum imap_ll_tltype maintype, ...);
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 {
IMAP_LL_STARTTLS_FAILED_PROCEED, /* STARTTLS failed but session still OK */
IMAP_LL_STARTTLS_FAILED, /* session must be closed */
IMAP_LL_STARTTLS_FAILED_CERT, /* certificate problem (session must be closed) */
IMAP_LL_STARTTLS_SUCCESS /* certificate problem (session must be closed) */
};
enum imap_ll_starttls_result imap_ll_starttls(struct imap_ll *, SSL_CTX *, const char *servername);
#endif
void imap_ll_logout(struct imap_ll *);
enum imap_login_result {
imap_login_ok = 0,
imap_login_denied = 1,
imap_login_error = 2
};
enum imap_login_result
imap_login(
struct imap_ll *,
const char *username, size_t username_len,
const char *password, size_t password_len
#ifdef USE_OPENSSL
, SSL_CTX *, const char *servername
#endif
);
/* returns the uidvalidity of the opened folder if successful */
const char *imap_select(
struct imap_ll *,
const char *foldername, size_t foldername_len,
int need_write,
long *exists_p /* optional, return number of messages which exist */
);
#endif
This diff is collapsed.
#ifndef __IMAPMSG_H__
#define __IMAPMSG_H__
#include "mairix.h"
struct imap_ll;
/* set pipe OR server, not both */
struct imap_ll *
imap_start(const char *pipe, const char *server, const char *username, const char *password);
void
build_imap_message_list(const char *folders, struct msgpath_array *msgs, struct globber_array *omit_globs, struct imap_ll *);
/* returns 1 on success, 0 otherwise */
int imap_fetch_message_raw(
const char *pseudopath, struct imap_ll *imapc,
/* on success, calls this callback */
void (*callback)(const char *, size_t, void *), void *arg
/* after the callback returns, the pointer to the message
data is no longer valid. */
);
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
......@@ -102,12 +102,18 @@ maildir
MH (compatible with the MH folder formats used by xmh, sylpheed, claws-mail, nnml (Gnus) and evolution)
.IP *
mbox (including mboxes that have been compressed with gzip or bzip2)
.IP *
IMAP: remote folders on an IMAP server
.PP
If maildir or MH source folders are used, and a search outputs its matches to
an mfolder in maildir or MH format, symbolic links are used to reference the
original messages inside the mfolder. However, if mbox folders are involved,
copies of messages are made instead.
copies of messages are made instead. If IMAP folders are used for both source
results, IMAP server-side copies of messages are made. With IMAP source folders
and any other type of results folder, messages are downloaded from the IMAP
server to be written to the results folder. With an IMAP results folder and
any other type of source folders, messages are uploaded to the IMAP server
to be appended to the results folder.
.SH OPTIONS
.B mairix
......@@ -233,7 +239,8 @@ paths on stdout.
.br
Instead of creating an mfolder containing the matched messages, display an
excerpt from their headers on stdout. The excerpt shows To, Cc, From, Subject
and Date.
and Date. With IMAP source folders, this requires downloading each matched
message from the IMAP server.
.TP
.B -H, --force-hardlinks
......@@ -467,12 +474,12 @@ parts the expression applies to. If there is no colon, the expression applies
to all the headers listed earlier and the body.
.IP "3."
After the colon, commas delineate separate disjuncts, which are
After the colon, slashes delineate separate disjuncts, which are
OR-ed together.
.IP "4."
Each disjunct may contain separate conjuncts, which are separated
by plus signs. These conditions are AND-ed together.
by commas. These conditions are AND-ed together.
.IP "5."
Each conjunct may start with a tilde to negate it, and may be
......@@ -597,9 +604,9 @@ for mutt, you could do
mkdir -p /home/richard/Mail/mfolder
touch /home/richard/Mail/mfolder/.mh_sequences
.Ex
which seems to work. Alternatively, within mutt, you could set MBOX_TYPE to
'mh' and save a message to '+mfolder' to have mutt set up the structure for you
in advance.
which seems to work. Alternatively, within mutt, you could set
MBOX_TYPE to 'mh' and save a message to '+mfolder' to have mutt set up
the structure for you in advance.
If you use Sylpheed, the best way seems to be to create the new folder from
within Sylpheed before letting mairix write into it.
......
......@@ -34,6 +34,7 @@
#include <ctype.h>
#include <locale.h>
#include <signal.h>
#include "imapinterface.h"
#ifdef TEST_OOM
int total_bytes=0;
......@@ -46,11 +47,17 @@ static char *folder_base = NULL;
static char *maildir_folders = NULL;
static char *mh_folders = NULL;
static char *mboxen = NULL;
static char *imap_folders = NULL;
static char *imap_pipe = NULL;
static char *imap_server = NULL;
static char *imap_username = NULL;
static char *imap_password = NULL;
static char *mfolder = NULL;
static char *omit = NULL;
static char *database_path = NULL;
static enum folder_type output_folder_type = FT_MAILDIR;
static int skip_integrity_checks = 0;
static int follow_mbox_symlinks = 0;
enum filetype {
M_NONE, M_FILE, M_DIR, M_OTHER
......@@ -100,6 +107,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++) {
......@@ -168,6 +176,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);
......@@ -249,6 +259,12 @@ static void parse_rc_file(char *name)/*{{{*/
}
else if (!strncasecmp(p, "mh=", 3)) add_folders(&mh_folders, copy_value(p));
else if (!strncasecmp(p, "mbox=", 5)) add_folders(&mboxen, copy_value(p));
else if (!strncasecmp(p, "imap=", 5)) add_folders(&imap_folders, copy_value(p));
else if (!strncasecmp(p, "imap_pipe=", 10)) imap_pipe = copy_value(p);
else if (!strncasecmp(p, "imap_server=", 12)) imap_server = copy_value(p);
else if (!strncasecmp(p, "imap_username=", 14)) imap_username = copy_value(p);
else if (!strncasecmp(p, "imap_password=", 14)) imap_password = copy_value(p);
else if (!strncasecmp(p, "follow_mbox_symlinks", 20)) follow_mbox_symlinks = 1;
else if (!strncasecmp(p, "omit=", 5)) add_folders(&omit, copy_value(p));
else if (!strncasecmp(p, "mformat=", 8)) {
......@@ -269,6 +285,23 @@ static void parse_rc_file(char *name)/*{{{*/
if (used_default_name) free(name);
}
/*}}}*/
static int message_compare(const void *a, const void *b)/*{{{*/
{
/* FIXME : Is this a sensible way to do this with mbox messages in the picture? */
struct msgpath *aa = (struct msgpath *) a;
struct msgpath *bb = (struct msgpath *) b;
if (aa->type < bb->type) return -1;
if (aa->type > bb->type) return 1;
return strcmp(aa->src.mpf.path, bb->src.mpf.path);
}
/*}}}*/
static void sort_message_list(struct msgpath_array *arr)/*{{{*/
{
qsort(arr->paths, arr->n, sizeof(struct msgpath), message_compare);
}
/*}}}*/
static int compare_strings(const void *a, const void *b)/*{{{*/
{
const char **aa = (const char **) a;
......@@ -279,14 +312,15 @@ static int compare_strings(const void *a, const void *b)/*{{{*/
static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/
{
/* Caveat : only examines the file-per-message case */
char **sorted_paths;
int i, n, nn;
char **sorted_paths, **sorted_imap;
int i, n, nn, imap_nn;
int result;
n = msgs->n;
sorted_paths = new_array(char *, n);
for (i=0, nn=0; i<n; i++) {
switch (msgs->type[i]) {
sorted_imap = new_array(char *, n);
for (i=0, nn=0, imap_nn=0; i<n; i++) {
switch (msgs->paths[i].type) {
case MTY_MBOX:
break;
case MTY_DEAD:
......@@ -295,9 +329,13 @@ static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/
case MTY_FILE:
sorted_paths[nn++] = msgs->paths[i].src.mpf.path;
break;
case MTY_IMAP:
sorted_imap[imap_nn++] = msgs->paths[i].src.mpf.path;
break;
}
}
qsort(sorted_paths, nn, sizeof(char *), compare_strings);
qsort(sorted_imap, imap_nn, sizeof(char *), compare_strings);
result = 0;
for (i=1; i<nn; i++) {
......@@ -306,8 +344,15 @@ static int check_message_list_for_duplicates(struct msgpath_array *msgs)/*{{{*/
break;
}
}
for (i=1; i<imap_nn; i++) {
if (!strcmp(sorted_imap[i-1], sorted_imap[i])) {
result = 1;
break;
}
}
free(sorted_paths);
free(sorted_imap);
return result;
}
/*}}}*/
......@@ -490,6 +535,8 @@ int main (int argc, char **argv)/*{{{*/
int do_integrity_checks = 1;
int do_forced_unlock = 0;
int do_fast_index = 0;
int do_mbox_symlinks = 0;
struct imap_ll *imapc = NULL;
unsigned int forced_hash_key = CREATE_RANDOM_DATABASE_HASH;
......@@ -558,11 +605,14 @@ int main (int argc, char **argv)/*{{{*/
} else if (!strcmp(*argv, "-h") ||
!strcmp(*argv, "--help")) {
do_help = 1;
} else if ((*argv)[0] == '-') {
fprintf(stderr, "Unrecognized option %s\n", *argv);
} else if (!strcmp(*argv, "--")) {
/* End of args */
argc--;
argv++;
break;
} else if ((*argv)[0] == '-') {
fprintf(stderr, "Unrecognized option %s\n", *argv);
exit(3);
} else {
/* standard args start */
break;
......@@ -617,6 +667,10 @@ int main (int argc, char **argv)/*{{{*/
do_integrity_checks = 0;
}
if (follow_mbox_symlinks) {
do_mbox_symlinks = 1;
}
if (!folder_base) {
fprintf(stderr, "No folder_base/MAIRIX_FOLDER_BASE set\n");
exit(2);
......@@ -671,23 +725,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) ||
......@@ -707,24 +768,40 @@ int main (int argc, char **argv)/*{{{*/
database_path);
unlock_and_exit(3);
}
result = search_top(do_threads, do_augment, database_path, complete_mfolder, argv, output_folder_type, verbose);
result = search_top(do_threads, do_augment, database_path, complete_mfolder, argv, output_folder_type, verbose, imap_pipe, imap_server, imap_username, imap_password);
} else {
enum filetype ftype;
if (!maildir_folders && !mh_folders && !mboxen) {
fprintf(stderr, "No [mh_]folders/mboxen/MAIRIX_[MH_]FOLDERS set\n");
if (imap_pipe && imap_server) {
fprintf(stderr, "specify one of imap_pipe or imap_server, not both\n");
unlock_and_exit(2);
}
if (imap_folders && (!(imap_pipe || imap_server))) {
fprintf(stderr, "If imap is given, imap_pipe OR imap_server is required\n");
imap_folders = NULL;
}
if (!maildir_folders && !mh_folders && !mboxen && !imap_folders) {
fprintf(stderr, "No [mh_]folders/mboxen/imap/MAIRIX_[MH_]FOLDERS set\n");
unlock_and_exit(2);
}
if (verbose) printf("Finding all currently existing messages...\n");
msgs = new_msgpath_array();
if (imap_folders) {
imapc = imap_start(imap_pipe, imap_server, imap_username, imap_password);
if (!imapc) unlock_and_exit(2);
build_imap_message_list(imap_folders, msgs, omit_globs, imapc);
}
if (maildir_folders) {
build_message_list(folder_base, maildir_folders, FT_MAILDIR, msgs, omit_globs);
}
if (mh_folders) {
build_message_list(folder_base, mh_folders, FT_MH, msgs, omit_globs);
}
sort_message_list(msgs);
/* The next call sorts the msgs array as part of looking for duplicates. */
if (check_message_list_for_duplicates(msgs)) {
......@@ -746,9 +823,9 @@ int main (int argc, char **argv)/*{{{*/
unlock_and_exit(2);
}
build_mbox_lists(db, folder_base, mboxen, omit_globs);
build_mbox_lists(db, folder_base, mboxen, omit_globs, do_mbox_symlinks);
any_updates = update_database(db, msgs->paths, msgs->n, do_fast_index);
any_updates = update_database(db, msgs->paths, msgs->n, do_fast_index, imapc);
if (do_purge) {
any_purges = cull_dead_messages(db, do_integrity_checks);
}
......
......@@ -33,9 +33,27 @@
#include "memmac.h"
enum message_type {/*{{{*/
MTY_DEAD, /* msg no longer exists, i.e. don't report in searches,
prune it on a '-p' run. */
MTY_FILE, /* msg <-> file in 1-1 correspondence e.g. maildir, MH */
MTY_MBOX, /* multiple msgs per file : MBOX format file */
MTY_IMAP /* Message on IMAP server; syntax: uidvalidity:uid:folder */
};
/*}}}*/
enum folder_type {/*{{{*/
FT_MAILDIR,
FT_MH,
FT_MBOX,
FT_RAW,
FT_EXCERPT,
FT_IMAP
};
/*}}}*/
struct msgpath {/*{{{*/
/* The 'selector' for this union is the corresponding entry of type 'enum
* message_type' */
enum message_type type; /* selector for union 'src' */
union {
struct {
char *path;
......@@ -52,6 +70,10 @@ struct msgpath {/*{{{*/
time_t date; /* representation of Date: header in message */
int tid; /* thread-id */
/* Track the folder type this came from, so we know the difference
between MH and Maildir, both of which have type MTY_FILE. */
enum folder_type source_ft;
/* Message flags. */
unsigned int seen:1;
unsigned int replied:1;
......@@ -61,15 +83,7 @@ struct msgpath {/*{{{*/
};
/*}}}*/
enum message_type {/*{{{*/
MTY_DEAD, /* msg no longer exists, i.e. don't report in searches,
prune it on a '-p' run. */
MTY_FILE, /* msg <-> file in 1-1 correspondence e.g. maildir, MH */
MTY_MBOX /* multiple msgs per file : MBOX format file */
};
/*}}}*/
struct msgpath_array {/*{{{*/
enum message_type *type;
struct msgpath *paths;
int n;
int max;
......@@ -243,15 +257,6 @@ struct database {/*{{{*/