db.c (mairix-0.23) | : | db.c (mairix-0.24) | ||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
*/ | */ | |||
/* Handle complete database */ | /* Handle complete database */ | |||
#include "mairix.h" | #include "mairix.h" | |||
#include "reader.h" | #include "reader.h" | |||
#include <ctype.h> | #include <ctype.h> | |||
#include <assert.h> | #include <assert.h> | |||
#include <sys/time.h> | #include <sys/time.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include "imapinterface.h" | ||||
struct sortable_token {/*{{{*/ | struct sortable_token {/*{{{*/ | |||
char *text; | char *text; | |||
int index; | int index; | |||
}; | }; | |||
/*}}}*/ | /*}}}*/ | |||
static int compare_sortable_tokens(const void *a, const void *b)/*{{{*/ | static int compare_sortable_tokens(const void *a, const void *b)/*{{{*/ | |||
{ | { | |||
const struct sortable_token *aa = (const struct sortable_token *) a; | const struct sortable_token *aa = (const struct sortable_token *) a; | |||
const struct sortable_token *bb = (const struct sortable_token *) b; | const struct sortable_token *bb = (const struct sortable_token *) b; | |||
skipping to change at line 137 | skipping to change at line 138 | |||
const char **aa = (const char **) a; | const char **aa = (const char **) a; | |||
const char **bb = (const char **) b; | const char **bb = (const char **) b; | |||
return strcmp(*aa, *bb); | return strcmp(*aa, *bb); | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
static void check_message_path_integrity(struct database *db)/*{{{*/ | static void check_message_path_integrity(struct database *db)/*{{{*/ | |||
{ | { | |||
/* TODO : for now only checks integrity of non-mbox paths. */ | /* TODO : for now only checks integrity of non-mbox paths. */ | |||
/* Check there are no duplicates */ | /* Check there are no duplicates */ | |||
int i; | int i; | |||
int n; | int n, imap_n; | |||
int has_duplicate = 0; | int has_duplicate = 0; | |||
char **paths; | char **paths, **imaps; | |||
paths = new_array(char *, db->n_msgs); | paths = new_array(char *, db->n_msgs); | |||
for (i=0, n=0; i<db->n_msgs; i++) { | imaps = new_array(char *, db->n_msgs); | |||
for (i=0, n=0, imap_n=0; i<db->n_msgs; i++) { | ||||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_DEAD: | case MTY_DEAD: | |||
case MTY_MBOX: | case MTY_MBOX: | |||
break; | break; | |||
case MTY_FILE: | case MTY_FILE: | |||
paths[n++] = db->msgs[i].src.mpf.path; | paths[n++] = db->msgs[i].src.mpf.path; | |||
break; | break; | |||
case MTY_IMAP: | ||||
imaps[imap_n++] = db->msgs[i].src.mpf.path; | ||||
break; | ||||
} | } | |||
} | } | |||
qsort(paths, n, sizeof(char *), compare_strings); | qsort(paths, n, sizeof(char *), compare_strings); | |||
qsort(imaps, imap_n, sizeof(char *), compare_strings); | ||||
for (i=1; i<n; i++) { | for (i=1; i<n; i++) { | |||
if (!strcmp(paths[i-1], paths[i])) { | if (!strcmp(paths[i-1], paths[i])) { | |||
fprintf(stderr, "Path <%s> repeated\n", paths[i]); | fprintf(stderr, "Path <%s> repeated\n", paths[i]); | |||
has_duplicate = 1; | has_duplicate = 1; | |||
} | } | |||
} | } | |||
for (i=1; i<imap_n; i++) { | ||||
if (!strcmp(imaps[i-1], imaps[i])) { | ||||
fprintf(stderr, "IMAP message <%s> repeated\n", imaps[i]); | ||||
has_duplicate = 1; | ||||
} | ||||
} | ||||
fflush(stderr); | fflush(stderr); | |||
assert(!has_duplicate); | assert(!has_duplicate); | |||
free(paths); | free(paths); | |||
free(imaps); | ||||
return; | return; | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
void check_database_integrity(struct database *db)/*{{{*/ | void check_database_integrity(struct database *db)/*{{{*/ | |||
{ | { | |||
if (verbose) fprintf(stderr, "Checking message path integrity\n"); | if (verbose) fprintf(stderr, "Checking message path integrity\n"); | |||
check_message_path_integrity(db); | check_message_path_integrity(db); | |||
/* Just check encoding chains for now */ | /* Just check encoding chains for now */ | |||
if (verbose) fprintf(stderr, "Checking to\n"); | if (verbose) fprintf(stderr, "Checking to\n"); | |||
skipping to change at line 244 | skipping to change at line 257 | |||
free_toktable2(db->msg_ids); | free_toktable2(db->msg_ids); | |||
if (db->msgs) { | if (db->msgs) { | |||
for (i=0; i<db->n_msgs; i++) { | for (i=0; i<db->n_msgs; i++) { | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_DEAD: | case MTY_DEAD: | |||
break; | break; | |||
case MTY_MBOX: | case MTY_MBOX: | |||
break; | break; | |||
case MTY_FILE: | case MTY_FILE: | |||
case MTY_IMAP: | ||||
assert(db->msgs[i].src.mpf.path); | assert(db->msgs[i].src.mpf.path); | |||
free(db->msgs[i].src.mpf.path); | free(db->msgs[i].src.mpf.path); | |||
break; | break; | |||
} | } | |||
} | } | |||
free(db->msgs); | free(db->msgs); | |||
free(db->type); | free(db->type); | |||
} | } | |||
free(db); | free(db); | |||
skipping to change at line 472 | skipping to change at line 486 | |||
switch (rd_msg_type(input, i)) { | switch (rd_msg_type(input, i)) { | |||
case DB_MSG_DEAD: | case DB_MSG_DEAD: | |||
result->type[i] = MTY_DEAD; | result->type[i] = MTY_DEAD; | |||
break; | break; | |||
case DB_MSG_FILE: | case DB_MSG_FILE: | |||
result->type[i] = MTY_FILE; | result->type[i] = MTY_FILE; | |||
result->msgs[i].src.mpf.path = new_string(input->data + input->path_offs ets[i]); | result->msgs[i].src.mpf.path = new_string(input->data + input->path_offs ets[i]); | |||
result->msgs[i].src.mpf.mtime = input->mtime_table[i]; | result->msgs[i].src.mpf.mtime = input->mtime_table[i]; | |||
result->msgs[i].src.mpf.size = input->size_table[i]; | result->msgs[i].src.mpf.size = input->size_table[i]; | |||
break; | break; | |||
case DB_MSG_IMAP: | ||||
result->type[i] = MTY_IMAP; | ||||
result->msgs[i].src.mpf.path = new_string(input->data + input->path_offs | ||||
ets[i]); | ||||
result->msgs[i].src.mpf.mtime = 0; | ||||
result->msgs[i].src.mpf.size = 0; | ||||
break; | ||||
case DB_MSG_MBOX: | case DB_MSG_MBOX: | |||
{ | { | |||
unsigned int mbi, msgi; | unsigned int mbi, msgi; | |||
int n; | int n; | |||
struct mbox *mb; | struct mbox *mb; | |||
result->type[i] = MTY_MBOX; | result->type[i] = MTY_MBOX; | |||
decode_mbox_indices(input->path_offsets[i], &mbi, &msgi); | decode_mbox_indices(input->path_offsets[i], &mbi, &msgi); | |||
result->msgs[i].src.mbox.file_index = mbi; | result->msgs[i].src.mbox.file_index = mbi; | |||
mb = &result->mboxen[mbi]; | mb = &result->mboxen[mbi]; | |||
assert(mb->n_so_far == msgi); | assert(mb->n_so_far == msgi); | |||
skipping to change at line 716 | skipping to change at line 736 | |||
case 'R': m->replied = 1; break; | case 'R': m->replied = 1; break; | |||
case 'S': m->seen = 1; break; | case 'S': m->seen = 1; break; | |||
default: break; | default: break; | |||
} | } | |||
p++; | p++; | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
static void scan_new_messages(struct database *db, int start_at)/*{{{*/ | static void scan_new_messages(struct database *db, int start_at, struct imap_ll *imapc)/*{{{*/ | |||
{ | { | |||
int i; | int i; | |||
for (i=start_at; i<db->n_msgs; i++) { | for (i=start_at; i<db->n_msgs; i++) { | |||
struct rfc822 *msg = NULL; | struct rfc822 *msg = NULL; | |||
int len = strlen(db->msgs[i].src.mpf.path); | int len = strlen(db->msgs[i].src.mpf.path); | |||
if (len > 10 && !strcmp(db->msgs[i].src.mpf.path + len - 11, "/.gitignore")) | if (len > 10 && !strcmp(db->msgs[i].src.mpf.path + len - 11, "/.gitignore")) | |||
continue; | continue; | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_DEAD: | case MTY_DEAD: | |||
assert(0); | assert(0); | |||
break; | break; | |||
case MTY_MBOX: | case MTY_MBOX: | |||
assert(0); /* Should never get here - mbox messages are scanned elsewher e. */ | assert(0); /* Should never get here - mbox messages are scanned elsewher e. */ | |||
break; | break; | |||
case MTY_FILE: | case MTY_FILE: | |||
if (verbose) fprintf(stderr, "Scanning <%s>\n", db->msgs[i].src.mpf.path ); | if (verbose) fprintf(stderr, "Scanning <%s>\n", db->msgs[i].src.mpf.path ); | |||
msg = make_rfc822(db->msgs[i].src.mpf.path); | msg = make_rfc822(db->msgs[i].src.mpf.path); | |||
break; | break; | |||
case MTY_IMAP: | ||||
if (verbose) fprintf(stderr, "Scanning IMAP <%s>\n", db->msgs[i].src.mpf | ||||
.path); | ||||
msg = make_rfc822_from_imap(db->msgs[i].src.mpf.path, imapc); | ||||
break; | ||||
} | } | |||
if(msg) | if(msg) | |||
{ | { | |||
db->msgs[i].date = msg->hdrs.date; | db->msgs[i].date = msg->hdrs.date; | |||
scan_maildir_flags(&db->msgs[i]); | scan_maildir_flags(&db->msgs[i]); | |||
tokenise_message(i, db, msg); | tokenise_message(i, db, msg); | |||
free_rfc822(msg); | free_rfc822(msg); | |||
} | } | |||
else | else | |||
fprintf(stderr, "Skipping %s (could not parse message)\n", db->msgs[i].src .mpf.path); | fprintf(stderr, "Skipping %s (could not parse message)\n", db->msgs[i].src .mpf.path); | |||
skipping to change at line 787 | skipping to change at line 811 | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
static void find_threading(struct database *db)/*{{{*/ | static void find_threading(struct database *db)/*{{{*/ | |||
{ | { | |||
/* ix is a table mapping path array index to the lowest path array index that | /* ix is a table mapping path array index to the lowest path array index that | |||
* is known to share at least one message ID in its hdrs somewhere (i.e. they | * is known to share at least one message ID in its hdrs somewhere (i.e. they | |||
* must be in the same thread) */ | * must be in the same thread) */ | |||
int *ix; | int *ix; | |||
int i, m, np, nm, sm; | int i, m, np, sm; | |||
int next_tid; | int next_tid; | |||
np = db->n_msgs; | np = db->n_msgs; | |||
nm = db->msg_ids->n; | ||||
sm = db->msg_ids->size; | sm = db->msg_ids->size; | |||
ix = new_array(int, np); | ix = new_array(int, np); | |||
for (i=0; i<np; i++) { | for (i=0; i<np; i++) { | |||
ix[i] = i; /* default - every message in a thread of its own */ | ix[i] = i; /* default - every message in a thread of its own */ | |||
} | } | |||
for (m=0; m<sm; m++) { | for (m=0; m<sm; m++) { | |||
struct token2 *tok = db->msg_ids->tokens[m]; | struct token2 *tok = db->msg_ids->tokens[m]; | |||
if (tok) { | if (tok) { | |||
skipping to change at line 848 | skipping to change at line 871 | |||
db->msgs[i].tid = next_tid++; | db->msgs[i].tid = next_tid++; | |||
} else { | } else { | |||
db->msgs[i].tid = db->msgs[ix[i]].tid; | db->msgs[i].tid = db->msgs[ix[i]].tid; | |||
} | } | |||
} | } | |||
free(ix); | free(ix); | |||
return; | return; | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
static int lookup_msgpath(struct msgpath *sorted_paths, int n_msgs, char *key)/* {{{*/ | static int lookup_msgpath(struct msgpath *sorted_paths, int n_msgs, char *key, e num message_type type)/*{{{*/ | |||
{ | { | |||
/* Implement bisection search */ | /* Implement bisection search */ | |||
int l, h, m, r; | int l, h, m, r; | |||
l = 0, h = n_msgs; | l = 0, h = n_msgs; | |||
m = -1; | m = -1; | |||
while (h > l) { | while (h > l) { | |||
m = (h + l) >> 1; | m = (h + l) >> 1; | |||
/* Should only get called on 'file' type messages - TBC */ | /* Should only get called on 'file' type messages - TBC */ | |||
r = strcmp(sorted_paths[m].src.mpf.path, key); | if (sorted_paths[m].type < type) { | |||
r = -1; | ||||
} else if (sorted_paths[m].type > type) { | ||||
r = 1; | ||||
} else { | ||||
r = strcmp(sorted_paths[m].src.mpf.path, key); | ||||
} | ||||
if (r == 0) break; | if (r == 0) break; | |||
if (l == m) return -1; | if (l == m) return -1; | |||
if (r > 0) h = m; | if (r > 0) h = m; | |||
else l = m; | else l = m; | |||
} | } | |||
return m; | return m; | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
void maybe_grow_message_arrays(struct database *db)/*{{{*/ | void maybe_grow_message_arrays(struct database *db)/*{{{*/ | |||
{ | { | |||
skipping to change at line 879 | skipping to change at line 908 | |||
if (db->max_msgs <= 128) { | if (db->max_msgs <= 128) { | |||
db->max_msgs = 256; | db->max_msgs = 256; | |||
} else { | } else { | |||
db->max_msgs += (db->max_msgs >> 1); | db->max_msgs += (db->max_msgs >> 1); | |||
} | } | |||
db->msgs = grow_array(struct msgpath, db->max_msgs, db->msgs); | db->msgs = grow_array(struct msgpath, db->max_msgs, db->msgs); | |||
db->type = grow_array(enum message_type, db->max_msgs, db->type); | db->type = grow_array(enum message_type, db->max_msgs, db->type); | |||
} | } | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
static void add_msg_path(struct database *db, char *path, time_t mtime, size_t m essage_size)/*{{{*/ | static void add_msg_path(struct database *db, char *path, time_t mtime, size_t m essage_size, enum message_type type)/*{{{*/ | |||
{ | { | |||
maybe_grow_message_arrays(db); | maybe_grow_message_arrays(db); | |||
db->type[db->n_msgs] = MTY_FILE; | db->type[db->n_msgs] = type; | |||
db->msgs[db->n_msgs].src.mpf.path = new_string(path); | db->msgs[db->n_msgs].src.mpf.path = new_string(path); | |||
db->msgs[db->n_msgs].src.mpf.mtime = mtime; | db->msgs[db->n_msgs].src.mpf.mtime = mtime; | |||
db->msgs[db->n_msgs].src.mpf.size = message_size; | db->msgs[db->n_msgs].src.mpf.size = message_size; | |||
++db->n_msgs; | ++db->n_msgs; | |||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
enum stat_result {/*{{{*/ | ||||
STAT_RESULT_BAD, | ||||
STAT_RESULT_FILE, | ||||
STAT_RESULT_DIR, | ||||
}; | ||||
/*}}}*/ | ||||
static int do_stat(struct msgpath *mp)/*{{{*/ | static int do_stat(struct msgpath *mp)/*{{{*/ | |||
{ | { | |||
struct stat sb; | struct stat sb; | |||
int status; | int status; | |||
if (mp->type == MTY_IMAP) { | ||||
mp->src.mpf.mtime = 0; | ||||
mp->src.mpf.size = 0; | ||||
return STAT_RESULT_FILE; | ||||
} | ||||
status = stat(mp->src.mpf.path, &sb); | status = stat(mp->src.mpf.path, &sb); | |||
if ((status < 0) || | if (status < 0) { | |||
!S_ISREG(sb.st_mode)) { | return STAT_RESULT_BAD; | |||
return 0; | } | |||
} else { | if (S_ISREG(sb.st_mode)) { | |||
mp->src.mpf.mtime = sb.st_mtime; | mp->src.mpf.mtime = sb.st_mtime; | |||
mp->src.mpf.size = sb.st_size; | mp->src.mpf.size = sb.st_size; | |||
return 1; | return STAT_RESULT_FILE; | |||
} else if (S_ISDIR(sb.st_mode)) { | ||||
return STAT_RESULT_DIR; | ||||
} | } | |||
return STAT_RESULT_BAD; | ||||
} | } | |||
/*}}}*/ | /*}}}*/ | |||
int update_database(struct database *db, struct msgpath *sorted_paths, int n_msg s, int do_fast_index)/*{{{*/ | int update_database(struct database *db, struct msgpath *sorted_paths, int n_msg s, int do_fast_index, struct imap_ll *imapc)/*{{{*/ | |||
{ | { | |||
/* The incoming list must be sorted into order, to make binary searching | /* The incoming list must be sorted into order, to make binary searching | |||
* possible. We search for each existing path in the incoming sorted array. | * possible. We search for each existing path in the incoming sorted array. | |||
* If the date differs, or the file no longer exist, the existing database | * If the date differs, or the file no longer exist, the existing database | |||
* entry for that file is nulled. (These are only recovered if the database | * entry for that file is nulled. (These are only recovered if the database | |||
* is actively compressed.) If the date differed, a new entry for the file | * is actively compressed.) If the date differed, a new entry for the file | |||
* is put at the end of the list. Similarly, any new file goes at the end. | * is put at the end of the list. Similarly, any new file goes at the end. | |||
* These new entries are all rescanned to find tokens and add them to the | * These new entries are all rescanned to find tokens and add them to the | |||
* database. */ | * database. */ | |||
char *file_in_db, *file_in_new_list; | char *file_in_db, *file_in_new_list; | |||
int matched_index; | int matched_index; | |||
int i, new_entries_start_at; | int i, new_entries_start_at; | |||
int any_new, n_newly_pruned, n_already_dead; | int any_new, n_newly_pruned, n_already_dead; | |||
int status; | ||||
file_in_db = new_array(char, n_msgs); | file_in_db = new_array(char, n_msgs); | |||
file_in_new_list = new_array(char, db->n_msgs); | file_in_new_list = new_array(char, db->n_msgs); | |||
bzero(file_in_db, n_msgs); | bzero(file_in_db, n_msgs); | |||
bzero(file_in_new_list, db->n_msgs); | bzero(file_in_new_list, db->n_msgs); | |||
n_already_dead = 0; | n_already_dead = 0; | |||
n_newly_pruned = 0; | n_newly_pruned = 0; | |||
for (i=0; i<db->n_msgs; i++) { | for (i=0; i<db->n_msgs; i++) { | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_FILE: | case MTY_FILE: | |||
matched_index = lookup_msgpath(sorted_paths, n_msgs, db->msgs[i].src.mpf .path); | matched_index = lookup_msgpath(sorted_paths, n_msgs, db->msgs[i].src.mpf .path, MTY_FILE); | |||
if (matched_index >= 0) { | if (matched_index >= 0) { | |||
if (do_fast_index) { | if (do_fast_index) { | |||
/* Assume the presence of a matching path is good enough without | /* Assume the presence of a matching path is good enough without | |||
* even bothering to stat the file that's there now. */ | * even bothering to stat the file that's there now. */ | |||
file_in_db[matched_index] = 1; | file_in_db[matched_index] = 1; | |||
file_in_new_list[i] = 1; | file_in_new_list[i] = 1; | |||
} else { | } else { | |||
status = do_stat(sorted_paths + matched_index); | switch (do_stat(sorted_paths + matched_index)) { | |||
if (status) { | case STAT_RESULT_FILE: | |||
if (sorted_paths[matched_index].src.mpf.mtime == db->msgs[i].src.m | if (sorted_paths[matched_index].src.mpf.mtime == db->msgs[i].src | |||
pf.mtime) { | .mpf.mtime) { | |||
/* Treat stale files as though the path has changed. */ | /* Treat stale files as though the path has changed. */ | |||
file_in_db[matched_index] = 1; | file_in_db[matched_index] = 1; | |||
file_in_new_list[i] = 1; | file_in_new_list[i] = 1; | |||
} | } | |||
} else { | break; | |||
/* This path will get treated as dead, and be re-stated below. | default: | |||
* When that stat fails, the path won't get added to the db. */ | /* This path will get treated as dead, and be re-stated below. | |||
* When that stat fails, the path won't get added to the db. */ | ||||
break; | ||||
} | } | |||
} | } | |||
} | } | |||
break; | break; | |||
case MTY_IMAP: | ||||
matched_index = lookup_msgpath(sorted_paths, n_msgs, db->msgs[i].src.mpf | ||||
.path, MTY_IMAP); | ||||
if (matched_index >= 0) { | ||||
file_in_db[matched_index] = 1; | ||||
file_in_new_list[i] = 1; | ||||
} | ||||
break; | ||||
case MTY_MBOX: | case MTY_MBOX: | |||
/* Nothing to do on this pass. */ | /* Nothing to do on this pass. */ | |||
break; | break; | |||
case MTY_DEAD: | case MTY_DEAD: | |||
break; | break; | |||
} | } | |||
} | } | |||
/* Add new entries to database */ | /* Add new entries to database */ | |||
new_entries_start_at = db->n_msgs; | new_entries_start_at = db->n_msgs; | |||
for (i=0; i<db->n_msgs; i++) { | for (i=0; i<db->n_msgs; i++) { | |||
/* Weed dead entries */ | /* Weed dead entries */ | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_FILE: | case MTY_FILE: | |||
case MTY_IMAP: | ||||
if (!file_in_new_list[i]) { | if (!file_in_new_list[i]) { | |||
free(db->msgs[i].src.mpf.path); | free(db->msgs[i].src.mpf.path); | |||
db->msgs[i].src.mpf.path = NULL; | db->msgs[i].src.mpf.path = NULL; | |||
db->type[i] = MTY_DEAD; | db->type[i] = MTY_DEAD; | |||
++n_newly_pruned; | ++n_newly_pruned; | |||
} | } | |||
break; | break; | |||
case MTY_MBOX: | case MTY_MBOX: | |||
{ | { | |||
int msg_index, file_index, number_valid; | int msg_index, file_index, number_valid; | |||
skipping to change at line 1006 | skipping to change at line 1059 | |||
} | } | |||
} | } | |||
if (verbose) { | if (verbose) { | |||
fprintf(stderr, "%d newly dead messages, %d messages now dead in total\n", n _newly_pruned, n_newly_pruned+n_already_dead); | fprintf(stderr, "%d newly dead messages, %d messages now dead in total\n", n _newly_pruned, n_newly_pruned+n_already_dead); | |||
} | } | |||
any_new = 0; | any_new = 0; | |||
for (i=0; i<n_msgs; i++) { | for (i=0; i<n_msgs; i++) { | |||
if (!file_in_db[i]) { | if (!file_in_db[i]) { | |||
int status; | ||||
any_new = 1; | any_new = 1; | |||
/* The 'sorted_paths' array is only used for file-per-message folders. */ | /* The 'sorted_paths' array is only used for file-per-message folders. */ | |||
status = do_stat(sorted_paths + i); | switch(do_stat(sorted_paths + i)) { | |||
if (status) { | case STAT_RESULT_FILE: | |||
/* We only add files that could be successfully stat()'d as regular | /* We only add files that could be successfully stat()'d as regular | |||
* files. */ | * files. */ | |||
add_msg_path(db, sorted_paths[i].src.mpf.path, sorted_paths[i].src.mpf.m | add_msg_path(db, sorted_paths[i].src.mpf.path, sorted_paths[i].src.mpf | |||
time, sorted_paths[i].src.mpf.size); | .mtime, sorted_paths[i].src.mpf.size, sorted_paths[i].type); | |||
} else { | break; | |||
fprintf(stderr, "Cannot add '%s' to database; stat() failed\n", sorted_p | case STAT_RESULT_DIR: | |||
aths[i].src.mpf.path); | if (sorted_paths[i].source_ft == FT_MH) { | |||
/* With MH, something that looks like a message but is a | ||||
directory is actually a subfolder with a numeric name. | ||||
Don't warn about it */ | ||||
break; | ||||
} | ||||
/* In all other cases, treat any non-regular-file the same | ||||
and warn about it. */ | ||||
/* fallthrough */ | ||||
default: | ||||
fprintf(stderr, "Cannot add '%s' to database; stat() failed\n", sorted | ||||
_paths[i].src.mpf.path); | ||||
break; | ||||
} | } | |||
} | } | |||
} | } | |||
if (any_new) { | if (any_new) { | |||
scan_new_messages(db, new_entries_start_at); | scan_new_messages(db, new_entries_start_at, imapc); | |||
} | } | |||
/* Add newly found mbox messages. */ | /* Add newly found mbox messages. */ | |||
any_new |= add_mbox_messages(db); | any_new |= add_mbox_messages(db); | |||
if (any_new) { | if (any_new) { | |||
find_threading(db); | find_threading(db); | |||
} else { | } else { | |||
if (verbose) fprintf(stderr, "No new messages found\n"); | if (verbose) fprintf(stderr, "No new messages found\n"); | |||
} | } | |||
skipping to change at line 1255 | skipping to change at line 1319 | |||
fprintf(stderr, "Culling dead messages\n"); | fprintf(stderr, "Culling dead messages\n"); | |||
} | } | |||
n_old = db->n_msgs; | n_old = db->n_msgs; | |||
new_idx = new_array(int, n_old); | new_idx = new_array(int, n_old); | |||
for (i=0, j=0; i<n_old; i++) { | for (i=0, j=0; i<n_old; i++) { | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_FILE: | case MTY_FILE: | |||
case MTY_MBOX: | case MTY_MBOX: | |||
case MTY_IMAP: | ||||
new_idx[i] = j++; | new_idx[i] = j++; | |||
break; | break; | |||
case MTY_DEAD: | case MTY_DEAD: | |||
new_idx[i] = -1; | new_idx[i] = -1; | |||
any_culled = 1; | any_culled = 1; | |||
break; | break; | |||
} | } | |||
} | } | |||
recode_toktable(db->to, new_idx); | recode_toktable(db->to, new_idx); | |||
skipping to change at line 1279 | skipping to change at line 1344 | |||
recode_toktable(db->attachment_name, new_idx); | recode_toktable(db->attachment_name, new_idx); | |||
recode_toktable2(db->msg_ids, new_idx); | recode_toktable2(db->msg_ids, new_idx); | |||
/* And crunch down the filename table */ | /* And crunch down the filename table */ | |||
for (i=0, j=0; i<n_old; i++) { | for (i=0, j=0; i<n_old; i++) { | |||
switch (db->type[i]) { | switch (db->type[i]) { | |||
case MTY_DEAD: | case MTY_DEAD: | |||
break; | break; | |||
case MTY_FILE: | case MTY_FILE: | |||
case MTY_MBOX: | case MTY_MBOX: | |||
case MTY_IMAP: | ||||
if (i > j) { | if (i > j) { | |||
db->msgs[j] = db->msgs[i]; | db->msgs[j] = db->msgs[i]; | |||
db->type[j] = db->type[i]; | db->type[j] = db->type[i]; | |||
} | } | |||
j++; | j++; | |||
break; | break; | |||
} | } | |||
} | } | |||
db->n_msgs = j; | db->n_msgs = j; | |||
End of changes. 34 change blocks. | ||||
40 lines changed or deleted | 109 lines changed or added |