Skip to content

Commit 9e3725a

Browse files
committed
mod_mail, nets: Ignore swap files during maildir traversals.
If swap files are encountered during maildir traversals, ignore them if IGNORE_SWAPFILES_IN_MAILDIRS is defined in mod_mail.h. This way, even if they are present for some reason, they do not cause issues.
1 parent 2690700 commit 9e3725a

File tree

9 files changed

+41
-20
lines changed

9 files changed

+41
-20
lines changed

include/mod_mail.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ struct bbs_url;
2020
struct bbs_tcp_client;
2121
struct dirent;
2222

23+
/* This will incur a slight performance penalty, but if you as the postmaster are at all prone to opening maildir
24+
* files in an editor directly to inspect them (which should be avoided!), this will ensure correctness.
25+
* You can disable this if you promise NEVER, NEVER, NEVER to manually inspect maildirs without copying
26+
* them elsewhere to do so. */
27+
#define IGNORE_SWAPFILES_IN_MAILDIRS
28+
2329
/* RFC 3696 Section 3 (updated by erratum to 256, but doesn't hurt to use the original, longer length) */
2430
#define MAX_EMAIL_ADDRESS_LENGTH 320
2531

@@ -498,6 +504,15 @@ void maildir_extract_from_filename(char *restrict filename);
498504
*/
499505
int uidsort(const struct dirent **da, const struct dirent **db);
500506

507+
/*! \brief Whether this is a valid maildir file. Skip if not. */
508+
#ifdef IGNORE_SWAPFILES_IN_MAILDIRS
509+
#define IS_MAILDIR_FILE(entry) (entry->d_type == DT_REG && strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..") && !bbs_str_ends_with(entry->d_name, ".swp"))
510+
#else
511+
#define IS_MAILDIR_FILE(entry) (entry->d_type == DT_REG && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
512+
#endif
513+
514+
#define IS_MAILDIR_DIR(entry) (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
515+
501516
/*!
502517
* \brief Perform an ordered traversal (by UID) of a maildir cur directory
503518
* \note This function MUST ONLY be used in the cur dir, NOT the new dir (use maildir_sequence_traverse for that)

modules/mod_mail.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,7 +2120,15 @@ int uidsort(const struct dirent **da, const struct dirent **db)
21202120
bbs_error("Failed to parse UID for %s / %s\n", a, b);
21212121
return 0;
21222122
} else if (unlikely(auid == buid)) {
2123-
bbs_error("Message UIDs are equal? (%u = %u)\n", auid, buid);
2123+
#ifdef IGNORE_SWAPFILES_IN_MAILDIRS
2124+
if (bbs_str_ends_with(a, ".swp") || bbs_str_ends_with(b, ".swp")) {
2125+
/* Whatever function is calling scandir will exclude swap files using
2126+
* IS_MAILDIR_FILE(), so even though this is a problematic comparison here,
2127+
* it can safely be ignored since the caller will end up ignoring it. */
2128+
return 0;
2129+
}
2130+
#endif
2131+
bbs_error("Message UIDs are equal? (%u = %u) for %s and %s\n", auid, buid, a, b);
21242132
return 0;
21252133
}
21262134

@@ -2143,7 +2151,7 @@ static int maildir_traverse(const char *path, int (*on_file)(const char *dir_nam
21432151
return -1;
21442152
}
21452153
while (fno < files && (entry = entries[fno++])) {
2146-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
2154+
if (!IS_MAILDIR_FILE(entry)) {
21472155
continue;
21482156
}
21492157
seqno++;

nets/net_imap.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,7 @@ static int imap_expunge(struct imap_session *imap, int silent)
10421042
return -1;
10431043
}
10441044
while (fno < files && (entry = entries[fno++])) {
1045-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
1045+
if (!IS_MAILDIR_FILE(entry)) {
10461046
goto next;
10471047
}
10481048

@@ -1186,7 +1186,7 @@ static void do_qresync(struct imap_session *imap, unsigned long lastmodseq, cons
11861186
*/
11871187
int i = 0;
11881188
while (fno < files && (entry = entries[fno++])) {
1189-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
1189+
if (!IS_MAILDIR_FILE(entry)) {
11901190
continue;
11911191
}
11921192
seqno++;
@@ -1222,7 +1222,7 @@ static void do_qresync(struct imap_session *imap, unsigned long lastmodseq, cons
12221222
free_if(expunged);
12231223

12241224
while (fno < files && (entry = entries[fno++])) {
1225-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
1225+
if (!IS_MAILDIR_FILE(entry)) {
12261226
goto next;
12271227
}
12281228
seqno++;
@@ -2098,7 +2098,7 @@ static int handle_copy(struct imap_session *imap, const char *sequences, const c
20982098
unsigned int msguid;
20992099
struct stat st;
21002100

2101-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
2101+
if (!IS_MAILDIR_FILE(entry)) {
21022102
continue;
21032103
}
21042104
msguid = imap_msg_in_range(imap, ++seqno, entry->d_name, sequences, usinguid, &error);
@@ -2194,7 +2194,7 @@ static int handle_move(struct imap_session *imap, const char *sequences, const c
21942194
unsigned int msguid;
21952195
unsigned long modseq;
21962196

2197-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
2197+
if (!IS_MAILDIR_FILE(entry)) {
21982198
goto cleanup;
21992199
}
22002200
++seqno;
@@ -3306,7 +3306,7 @@ static int process_flags(struct imap_session *imap, char *s, int usinguid, const
33063306
unsigned int msguid;
33073307
unsigned long modseq;
33083308

3309-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
3309+
if (!IS_MAILDIR_FILE(entry)) {
33103310
continue;
33113311
}
33123312
msguid = imap_msg_in_range(imap, ++seqno, entry->d_name, sequences, usinguid, &error);
@@ -3346,7 +3346,7 @@ static int process_flags(struct imap_session *imap, char *s, int usinguid, const
33463346
int i;
33473347
int newflags, changes = 0;
33483348

3349-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
3349+
if (!IS_MAILDIR_FILE(entry)) {
33503350
continue;
33513351
}
33523352
msguid = imap_msg_in_range(imap, ++seqno, entry->d_name, sequences, usinguid, &error);
@@ -3759,7 +3759,7 @@ static int sub_rename(const char *path, const char *prefix, const char *newprefi
37593759
return -1;
37603760
}
37613761
while (fno < files && (entry = entries[fno++])) {
3762-
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
3762+
if (!IS_MAILDIR_DIR(entry)) {
37633763
continue;
37643764
} else if (entry->d_type == DT_DIR) { /* We only care about directories, not files. */
37653765
if (!strncmp(entry->d_name, prefix, prefixlen)) {

nets/net_imap/imap_server_fetch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ static int process_fetch(struct imap_session *imap, int usinguid, struct fetch_r
952952
char fullname[516];
953953
int markseen, recent;
954954

955-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
955+
if (!IS_MAILDIR_FILE(entry)) {
956956
goto next;
957957
}
958958
msguid = imap_msg_in_range(imap, ++seqno, entry->d_name, sequences, usinguid, &error);

nets/net_imap/imap_server_list.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ int list_iterate(struct imap_session *imap, struct list_command *lcmd, int level
377377
const char *mailboxname = entry->d_name;
378378

379379
/* Only care about directories, not files. */
380-
if (entry->d_type != DT_DIR || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
380+
if (!IS_MAILDIR_DIR(entry)) {
381381
goto cleanup;
382382
}
383383

@@ -465,7 +465,7 @@ int list_scandir(struct imap_session *imap, struct list_command *lcmd, int level
465465
const char *mailboxname = entry->d_name;
466466

467467
/* Only care about directories, not files. */
468-
if (entry->d_type != DT_DIR || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
468+
if (!IS_MAILDIR_DIR(entry)) {
469469
goto cleanup;
470470
}
471471

nets/net_imap/imap_server_maildir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ int imap_msg_to_filename(const char *directory, int seqno, unsigned int uid, cha
355355
return -1;
356356
}
357357
while (fno < files && (entry = entries[fno++])) {
358-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
358+
if (!IS_MAILDIR_FILE(entry)) {
359359
continue;
360360
}
361361
myseqno++;

nets/net_imap/imap_server_search.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,9 +990,7 @@ static int search_dir(struct imap_session *imap, const char *dirname, int newdir
990990
return -1;
991991
}
992992
while (fno < files && (entry = entries[fno++])) {
993-
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
994-
goto next;
995-
} else if (entry->d_type != DT_REG) { /* We only care about directories, not files. */
993+
if (!IS_MAILDIR_FILE(entry)) {
996994
goto next;
997995
}
998996
seqno++;

nets/net_nntp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ static int nntp_traverse(const char *path, int (*on_file)(const char *dir_name,
251251
return -1;
252252
}
253253
while (fno < files && (entry = entries[fno++])) {
254-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
254+
if (!IS_MAILDIR_FILE(entry)) {
255255
free(entry);
256256
continue;
257257
}
@@ -281,7 +281,7 @@ static int nntp_traverse2(const char *path, int (*on_file)(const char *dir_name,
281281
}
282282
while (fno < files && (entry = entries[fno++])) {
283283
int msgno;
284-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
284+
if (!IS_MAILDIR_FILE(entry)) {
285285
goto cleanup;
286286
}
287287
/* Filename format is ARTICLEID_MESSAGEID */

nets/net_pop3.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ static int pop3_traverse(const char *path, int (*on_file)(const char *dir_name,
237237
return -1;
238238
}
239239
while (fno < files && (entry = entries[fno++])) {
240-
if (entry->d_type != DT_REG || !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
240+
if (!IS_MAILDIR_FILE(entry)) {
241241
free(entry);
242242
continue;
243243
}

0 commit comments

Comments
 (0)