+ if (compressed)
+ {
+ int status;
+ if (wait(&status) < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
+ b->total = b->new = b->flagged = -1;
+ }
+}
+
+static time_t
+mdir_mtime(struct mbox *b)
+{
+ time_t mtime = 0;
+ char path[strlen(b->path) + 5];
+
+ for (int new=0; new<2; new++)
+ {
+ sprintf(path, "%s/%s", b->path, (new ? "new" : "cur"));
+ struct stat st;
+ if (stat(path, &st) < 0)
+ debug("[cannot stat %s] ", path);
+ else if (st.st_mtime > mtime)
+ mtime = st.st_mtime;
+ }
+ return mtime;
+}
+
+static void
+mdir_get_snippet(struct mbox *b)
+{
+ char buf[HDR_BUF_SIZE], sender[HDR_BUF_SIZE], subject[HDR_BUF_SIZE];
+ sender[0] = 0;
+ subject[0] = 0;
+
+ char path[strlen(b->path) + MDIR_MAX_NAME_LEN];
+ sprintf(path, "%s/%s", b->path, b->mdir_best);
+ mb_fd = open(path, O_RDONLY);
+ if (mb_fd < 0)
+ {
+ debug("[open failed: %m] ");
+ prepare_snippets(b, sender, subject);
+ return;
+ }
+ mb_seekable = 1;
+ mb_reset(0);
+
+ while (read_hdr_field(buf) > 0)
+ {
+ if (!strncasecmp(buf, "From:", 5))
+ strcpy(sender, buf+5);
+ else if (!strncasecmp(buf, "Subject:", 8))
+ strcpy(subject, buf+8);
+ }
+
+ close(mb_fd);
+ prepare_snippets(b, sender, subject);
+}
+
+static void
+scan_mdir(struct mbox *b)
+{
+ int dir_len = strlen(b->path);
+ char path[dir_len + MDIR_MAX_NAME_LEN];
+ strcpy(path, b->path);
+
+ b->total = b->new = b->flagged = 0;
+ b->best_time = 0;
+ b->best_is_new = 0;
+
+ for (int new=0; new<2; new++)
+ {
+ strcpy(path + dir_len, (new ? "/new" : "/cur"));
+ DIR *d = opendir(path);
+ if (!d)
+ {
+ debug("[cannot open %s: %m] ");
+ continue;
+ }
+ struct dirent *de;
+ while (de = readdir(d))
+ {
+ char *name = de->d_name;
+ if (name[0] == '.' || strlen(name) + 10 > MDIR_MAX_NAME_LEN)
+ continue;
+ path[dir_len + 4] = '/';
+ strcpy(path + dir_len + 5, name);
+
+ char *colon = strchr(name, ':');
+ int seen = 0;
+ int flagged = 0;
+ if (colon && colon[1] == '2' && colon[2] == ',')
+ {
+ // Another comma can separate extended flags (Dovecot extension)
+ for (int i=3; colon[i] && colon[i] != ','; i++)
+ switch (colon[i])
+ {
+ case 'S':
+ seen = 1;
+ break;
+ case 'F':
+ flagged = 1;
+ break;
+ }
+ }
+
+ int is_new = new;
+ if (b->o.unread_is_new && !seen)
+ is_new = 1;
+
+ b->total++;
+ if (is_new)
+ b->new++;
+ if (flagged)
+ b->flagged++;
+ if (debug_mode > 1)
+ debug("%s: new=%d flagged=%d seen=%d\n", path, is_new, flagged, seen);
+
+ if (is_new || flagged)
+ {
+ // Need to pick the best message to display
+ struct stat st;
+ if (stat(path, &st) < 0)
+ debug("[cannot stat %s: %m] ", path);
+ else if (is_new > b->best_is_new || is_new == b->best_is_new && st.st_mtime > b->best_time)
+ {
+ b->best_is_new = is_new;
+ b->best_time = st.st_mtime;
+ strcpy(b->mdir_best, path + dir_len + 1);
+ }
+ }
+ }
+ closedir(d);
+ }
+
+ if (b->best_time && b->o.snippets)
+ {
+ debug("best <%s> ", b->mdir_best);
+ mdir_get_snippet(b);
+ }