NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mbox_sync()

Save changes to the Mailbox. More...

+ Collaboration diagram for mbox_sync():

Functions

static enum MxStatus comp_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
enum MxStatus maildir_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus mbox_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus mh_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus nntp_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus nm_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 
static enum MxStatus pop_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -.
 

Detailed Description

Save changes to the Mailbox.

Parameters
mMailbox to sync
Return values
enumMxStatus
Precondition
m is not NULL

Function Documentation

◆ comp_mbox_sync()

static enum MxStatus comp_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Changes in NeoMutt only affect the tmp file. Calling comp_mbox_sync() will commit them to the compressed file.

Definition at line 619 of file compress.c.

620{
621 if (!m->compress_info)
622 return MX_STATUS_ERROR;
623
624 struct CompressInfo *ci = m->compress_info;
625
626 if (!ci->cmd_close)
627 {
628 mutt_error(_("Can't sync a compressed file without a close-hook"));
629 return MX_STATUS_ERROR;
630 }
631
632 const struct MxOps *ops = ci->child_ops;
633 if (!ops)
634 return MX_STATUS_ERROR;
635
636 if (!lock_realpath(m, true))
637 {
638 mutt_error(_("Unable to lock mailbox"));
639 return MX_STATUS_ERROR;
640 }
641
642 enum MxStatus check = comp_mbox_check(m);
643 if (check != MX_STATUS_OK)
644 goto sync_cleanup;
645
646 check = ops->mbox_sync(m);
647 if (check != MX_STATUS_OK)
648 goto sync_cleanup;
649
650 if (!execute_command(m, ci->cmd_close, _("Compressing %s")))
651 {
652 check = MX_STATUS_ERROR;
653 goto sync_cleanup;
654 }
655
656 check = MX_STATUS_OK;
657
658sync_cleanup:
659 store_size(m);
661 return check;
662}
static void store_size(const struct Mailbox *m)
Save the size of the compressed file.
Definition: compress.c:202
static bool lock_realpath(struct Mailbox *m, bool excl)
Try to lock the Mailbox.realpath.
Definition: compress.c:107
static void unlock_realpath(struct Mailbox *m)
Unlock the mailbox->realpath.
Definition: compress.c:148
static bool execute_command(struct Mailbox *m, const struct Expando *exp, const char *progress)
Run a system command.
Definition: compress.c:323
#define mutt_error(...)
Definition: logging2.h:92
static enum MxStatus comp_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: compress.c:583
#define _(a)
Definition: message.h:28
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition: mxapi.h:63
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:64
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:65
Private data for compress.
Definition: lib.h:58
const struct MxOps * child_ops
callbacks of de-compressed file
Definition: lib.h:63
struct Expando * cmd_close
close-hook command
Definition: lib.h:60
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:121
Definition: mxapi.h:91
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:187
+ Here is the call graph for this function:

◆ maildir_mbox_sync()

enum MxStatus maildir_mbox_sync ( struct Mailbox m)

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Return values
enumMxStatus
Note
The flag retvals come from a call to a backend sync function

Definition at line 839 of file mailbox.c.

840{
841 enum MxStatus check = maildir_check(m);
842 if (check == MX_STATUS_ERROR)
843 return check;
844
845 struct HeaderCache *hc = maildir_hcache_open(m);
846
847 struct Progress *progress = NULL;
848 if (m->verbose)
849 {
851 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
852 }
853
854 for (int i = 0; i < m->msg_count; i++)
855 {
856 progress_update(progress, i, -1);
857
858 struct Email *e = m->emails[i];
859 if (!maildir_sync_mailbox_message(m, e, hc))
860 {
861 progress_free(&progress);
862 goto err;
863 }
864 }
865 progress_free(&progress);
867
868 /* XXX race condition? */
869
871
872 /* adjust indices */
873
874 if (m->msg_deleted)
875 {
876 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
877 for (int i = 0, j = 0; i < m->msg_count; i++)
878 {
879 struct Email *e = m->emails[i];
880 if (!e)
881 break;
882
883 if (!e->deleted || c_maildir_trash)
884 e->index = j++;
885 }
886 }
887
888 return check;
889
890err:
892 return MX_STATUS_ERROR;
893}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition: hcache.c:96
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition: hcache.c:69
static enum MxStatus maildir_check(struct Mailbox *m)
Check for new mail.
Definition: mailbox.c:539
void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mailbox.c:717
bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: message.c:311
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:83
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:80
The envelope/body of an email.
Definition: email.h:39
bool deleted
Email is deleted.
Definition: email.h:78
int index
The absolute (unsorted) message number.
Definition: email.h:113
Header Cache.
Definition: lib.h:86
int msg_count
Total number of messages.
Definition: mailbox.h:88
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
bool verbose
Display status messages?
Definition: mailbox.h:117
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:

◆ mbox_mbox_sync()

static enum MxStatus mbox_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Definition at line 1062 of file mbox.c.

1063{
1065 if (!adata)
1066 return MX_STATUS_ERROR;
1067
1068 struct Buffer *tempfile = NULL;
1069 char buf[32] = { 0 };
1070 int j;
1071 bool unlink_tempfile = false;
1072 bool need_sort = false; /* flag to resort mailbox if new mail arrives */
1073 int first = -1; /* first message to be written */
1074 LOFF_T offset; /* location in mailbox to write changed messages */
1075 struct stat st = { 0 };
1076 struct MUpdate *new_offset = NULL;
1077 struct MUpdate *old_offset = NULL;
1078 FILE *fp = NULL;
1079 struct Progress *progress = NULL;
1080 enum MxStatus rc = MX_STATUS_ERROR;
1081
1082 /* sort message by their position in the mailbox on disk */
1083 const enum SortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
1084 if (c_sort != SORT_ORDER)
1085 {
1086 mutt_sort_order(m);
1087 need_sort = true;
1088 }
1089
1090 /* need to open the file for writing in such a way that it does not truncate
1091 * the file, so use read-write mode. */
1092 adata->fp = freopen(mailbox_path(m), "r+", adata->fp);
1093 if (!adata->fp)
1094 {
1095 mx_fastclose_mailbox(m, false);
1096 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1097 goto fatal;
1098 }
1099
1101
1102 if (mbox_lock_mailbox(m, true, true) == -1)
1103 {
1105 mutt_error(_("Unable to lock mailbox"));
1106 goto bail;
1107 }
1108
1109 /* Check to make sure that the file hasn't changed on disk */
1110 enum MxStatus check = mbox_mbox_check(m);
1111 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1112 {
1113 /* new mail arrived, or mailbox reopened */
1114 rc = check;
1115 goto bail;
1116 }
1117 else if (check < 0)
1118 {
1119 goto fatal;
1120 }
1121
1122 /* Create a temporary file to write the new version of the mailbox in. */
1123 tempfile = buf_pool_get();
1124 buf_mktemp(tempfile);
1125 int fd = open(buf_string(tempfile), O_WRONLY | O_EXCL | O_CREAT, 0600);
1126 if ((fd == -1) || !(fp = fdopen(fd, "w")))
1127 {
1128 if (fd != -1)
1129 {
1130 close(fd);
1131 unlink_tempfile = true;
1132 }
1133 mutt_error(_("Could not create temporary file"));
1134 goto bail;
1135 }
1136 unlink_tempfile = true;
1137
1138 /* find the first deleted/changed message. we save a lot of time by only
1139 * rewriting the mailbox from the point where it has actually changed. */
1140 int i = 0;
1141 for (; (i < m->msg_count) && !m->emails[i]->deleted &&
1142 !m->emails[i]->changed && !m->emails[i]->attach_del;
1143 i++)
1144 {
1145 }
1146 if (i == m->msg_count)
1147 {
1148 /* this means m->changed or m->msg_deleted was set, but no
1149 * messages were found to be changed or deleted. This should
1150 * never happen, is we presume it is a bug in neomutt. */
1151 mutt_error(_("sync: mbox modified, but no modified messages (report this bug)"));
1152 mutt_debug(LL_DEBUG1, "no modified messages\n");
1153 goto bail;
1154 }
1155
1156 /* save the index of the first changed/deleted message */
1157 first = i;
1158 /* where to start overwriting */
1159 offset = m->emails[i]->offset;
1160
1161 /* the offset stored in the header does not include the MMDF_SEP, so make
1162 * sure we seek to the correct location */
1163 if (m->type == MUTT_MMDF)
1164 offset -= (sizeof(MMDF_SEP) - 1);
1165
1166 /* allocate space for the new offsets */
1167 new_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));
1168 old_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));
1169
1170 if (m->verbose)
1171 {
1173 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
1174 }
1175
1176 for (i = first, j = 0; i < m->msg_count; i++)
1177 {
1178 progress_update(progress, i, i / (m->msg_count / 100 + 1));
1179 /* back up some information which is needed to restore offsets when
1180 * something fails. */
1181
1182 old_offset[i - first].valid = true;
1183 old_offset[i - first].hdr = m->emails[i]->offset;
1184 old_offset[i - first].body = m->emails[i]->body->offset;
1185 old_offset[i - first].lines = m->emails[i]->lines;
1186 old_offset[i - first].length = m->emails[i]->body->length;
1187
1188 if (!m->emails[i]->deleted)
1189 {
1190 j++;
1191
1192 if (m->type == MUTT_MMDF)
1193 {
1194 if (fputs(MMDF_SEP, fp) == EOF)
1195 {
1196 mutt_perror("%s", buf_string(tempfile));
1197 goto bail;
1198 }
1199 }
1200
1201 /* save the new offset for this message. we add 'offset' because the
1202 * temporary file only contains saved message which are located after
1203 * 'offset' in the real mailbox */
1204 new_offset[i - first].hdr = ftello(fp) + offset;
1205
1206 struct Message *msg = mx_msg_open(m, m->emails[i]);
1207 const int rc2 = mutt_copy_message(fp, m->emails[i], msg, MUTT_CM_UPDATE,
1209 mx_msg_close(m, &msg);
1210 if (rc2 != 0)
1211 {
1212 mutt_perror("%s", buf_string(tempfile));
1213 goto bail;
1214 }
1215
1216 /* Since messages could have been deleted, the offsets stored in memory
1217 * will be wrong, so update what we can, which is the offset of this
1218 * message, and the offset of the body. If this is a multipart message,
1219 * we just flush the in memory cache so that the message will be reparsed
1220 * if the user accesses it later. */
1221 new_offset[i - first].body = ftello(fp) - m->emails[i]->body->length + offset;
1222 mutt_body_free(&m->emails[i]->body->parts);
1223
1224 if (m->type == MUTT_MMDF)
1225 {
1226 if (fputs(MMDF_SEP, fp) == EOF)
1227 {
1228 mutt_perror("%s", buf_string(tempfile));
1229 goto bail;
1230 }
1231 }
1232 else
1233 {
1234 if (fputs("\n", fp) == EOF)
1235 {
1236 mutt_perror("%s", buf_string(tempfile));
1237 goto bail;
1238 }
1239 }
1240 }
1241 }
1242
1243 if (mutt_file_fclose(&fp) != 0)
1244 {
1245 mutt_debug(LL_DEBUG1, "mutt_file_fclose (&) returned non-zero\n");
1246 mutt_perror("%s", buf_string(tempfile));
1247 goto bail;
1248 }
1249
1250 /* Save the state of this folder. */
1251 if (stat(mailbox_path(m), &st) == -1)
1252 {
1253 mutt_perror("%s", mailbox_path(m));
1254 goto bail;
1255 }
1256
1257 unlink_tempfile = false;
1258
1259 fp = mutt_file_fopen(buf_string(tempfile), "r");
1260 if (!fp)
1261 {
1263 mx_fastclose_mailbox(m, false);
1264 mutt_debug(LL_DEBUG1, "unable to reopen temp copy of mailbox!\n");
1265 mutt_perror("%s", buf_string(tempfile));
1266 FREE(&new_offset);
1267 FREE(&old_offset);
1268 goto fatal;
1269 }
1270
1271 if (!mutt_file_seek(adata->fp, offset, SEEK_SET) || /* seek the append location */
1272 /* do a sanity check to make sure the mailbox looks ok */
1273 !fgets(buf, sizeof(buf), adata->fp) ||
1274 ((m->type == MUTT_MBOX) && !mutt_str_startswith(buf, "From ")) ||
1275 ((m->type == MUTT_MMDF) && !mutt_str_equal(MMDF_SEP, buf)))
1276 {
1277 mutt_debug(LL_DEBUG1, "message not in expected position\n");
1278 mutt_debug(LL_DEBUG1, " LINE: %s\n", buf);
1279 i = -1;
1280 }
1281 else
1282 {
1283 if (!mutt_file_seek(adata->fp, offset, SEEK_SET)) /* return to proper offset */
1284 {
1285 i = -1;
1286 }
1287 else
1288 {
1289 /* copy the temp mailbox back into place starting at the first
1290 * change/deleted message */
1291 if (m->verbose)
1292 mutt_message(_("Committing changes..."));
1293 i = mutt_file_copy_stream(fp, adata->fp);
1294
1295 if (ferror(adata->fp))
1296 i = -1;
1297 }
1298 if (i >= 0)
1299 {
1300 m->size = ftello(adata->fp); /* update the mailbox->size of the mailbox */
1301 if ((m->size < 0) || (ftruncate(fileno(adata->fp), m->size) != 0))
1302 {
1303 i = -1;
1304 mutt_debug(LL_DEBUG1, "ftruncate() failed\n");
1305 }
1306 }
1307 }
1308
1311
1312 if ((mutt_file_fclose(&adata->fp) != 0) || (i == -1))
1313 {
1314 /* error occurred while writing the mailbox back, so keep the temp copy around */
1315
1316 struct Buffer *savefile = buf_pool_get();
1317
1318 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
1319 buf_printf(savefile, "%s/neomutt.%s-%s-%u", NONULL(c_tmp_dir),
1320 NONULL(Username), NONULL(ShortHostname), (unsigned int) getpid());
1321 rename(buf_string(tempfile), buf_string(savefile));
1323 mx_fastclose_mailbox(m, false);
1324 buf_pretty_mailbox(savefile);
1325 mutt_error(_("Write failed! Saved partial mailbox to %s"), buf_string(savefile));
1326 buf_pool_release(&savefile);
1327 FREE(&new_offset);
1328 FREE(&old_offset);
1329 goto fatal;
1330 }
1331
1332 /* Restore the previous access/modification times */
1333 mbox_reset_atime(m, &st);
1334
1335 /* reopen the mailbox in read-only mode */
1336 adata->fp = mbox_open_readwrite(m);
1337 if (!adata->fp)
1338 {
1339 adata->fp = mbox_open_readonly(m);
1340 }
1341 if (!adata->fp)
1342 {
1343 unlink(buf_string(tempfile));
1345 mx_fastclose_mailbox(m, false);
1346 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1347 FREE(&new_offset);
1348 FREE(&old_offset);
1349 goto fatal;
1350 }
1351
1352 /* update the offsets of the rewritten messages */
1353 for (i = first, j = first; i < m->msg_count; i++)
1354 {
1355 if (!m->emails[i]->deleted)
1356 {
1357 m->emails[i]->offset = new_offset[i - first].hdr;
1358 m->emails[i]->body->hdr_offset = new_offset[i - first].hdr;
1359 m->emails[i]->body->offset = new_offset[i - first].body;
1360 m->emails[i]->index = j++;
1361 }
1362 }
1363 FREE(&new_offset);
1364 FREE(&old_offset);
1365 unlink(buf_string(tempfile)); /* remove partial copy of the mailbox */
1366 buf_pool_release(&tempfile);
1368
1369 const bool c_check_mbox_size = cs_subset_bool(NeoMutt->sub, "check_mbox_size");
1370 if (c_check_mbox_size)
1371 {
1372 struct Mailbox *m_tmp = mailbox_find(mailbox_path(m));
1373 if (m_tmp && !m_tmp->has_new)
1374 mailbox_update(m_tmp);
1375 }
1376
1377 progress_free(&progress);
1378 return 0; /* signal success */
1379
1380bail: /* Come here in case of disaster */
1381
1382 mutt_file_fclose(&fp);
1383
1384 if (tempfile && unlink_tempfile)
1385 unlink(buf_string(tempfile));
1386
1387 /* restore offsets, as far as they are valid */
1388 if ((first >= 0) && old_offset)
1389 {
1390 for (i = first; (i < m->msg_count) && old_offset[i - first].valid; i++)
1391 {
1392 m->emails[i]->offset = old_offset[i - first].hdr;
1393 m->emails[i]->body->hdr_offset = old_offset[i - first].hdr;
1394 m->emails[i]->body->offset = old_offset[i - first].body;
1395 m->emails[i]->lines = old_offset[i - first].lines;
1396 m->emails[i]->body->length = old_offset[i - first].length;
1397 }
1398 }
1399
1400 /* this is ok to call even if we haven't locked anything */
1402
1404 FREE(&new_offset);
1405 FREE(&old_offset);
1406
1407 adata->fp = freopen(mailbox_path(m), "r", adata->fp);
1408 if (!adata->fp)
1409 {
1410 mutt_error(_("Could not reopen mailbox"));
1411 mx_fastclose_mailbox(m, false);
1412 goto fatal;
1413 }
1414
1416 if (need_sort)
1417 {
1418 /* if the mailbox was reopened, the thread tree will be invalid so make
1419 * sure to start threading from scratch. */
1421 }
1422
1423fatal:
1424 buf_pool_release(&tempfile);
1425 progress_free(&progress);
1426 return rc;
1427}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:907
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:42
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:54
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:58
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
void mailbox_update(struct Mailbox *m)
Get the mailbox's current size.
Definition: mailbox.c:216
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:234
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:151
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:190
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:191
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:286
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:775
#define mutt_file_fclose(FP)
Definition: file.h:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
char * Username
User's login name.
Definition: globals.c:41
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
static enum MxStatus mbox_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mbox.c:928
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define MMDF_SEP
Definition: lib.h:62
static int mbox_lock_mailbox(struct Mailbox *m, bool excl, bool retry)
Lock a mailbox.
Definition: mbox.c:138
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition: mbox.c:123
static FILE * mbox_open_readwrite(struct Mailbox *m)
Open an mbox read-write.
Definition: mbox.c:801
static FILE * mbox_open_readonly(struct Mailbox *m)
Open an mbox read-only.
Definition: mbox.c:816
static void mbox_unlock_mailbox(struct Mailbox *m)
Unlock a mailbox.
Definition: mbox.c:162
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:746
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:45
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:654
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:554
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1178
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:412
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1132
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:68
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:66
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
void mutt_sig_block(void)
Block signals during critical operations.
Definition: signal.c:166
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition: signal.c:184
SortType
Methods for sorting.
Definition: sort2.h:34
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:40
void mutt_sort_order(struct Mailbox *m)
Sort emails by their disk order.
Definition: sort.c:444
#define NONULL(x)
Definition: string2.h:37
void * adata
Private data (for Mailbox backends)
Definition: account.h:42
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
String manipulation buffer.
Definition: buffer.h:36
int lines
How many lines in the body of this message?
Definition: email.h:62
struct Body * body
List of MIME parts.
Definition: email.h:69
bool changed
Email has been edited.
Definition: email.h:77
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:71
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:102
Store of new offsets, used by mutt_sync_mailbox()
Definition: mbox.c:67
long lines
Definition: mbox.c:71
LOFF_T hdr
Definition: mbox.c:69
LOFF_T length
Definition: mbox.c:72
LOFF_T body
Definition: mbox.c:70
bool valid
Definition: mbox.c:68
A mailbox.
Definition: mailbox.h:79
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
off_t size
Size of the Mailbox.
Definition: mailbox.h:84
Mbox-specific Account data -.
Definition: lib.h:49
FILE * fp
Mailbox file.
Definition: lib.h:50
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
#define buf_mktemp(buf)
Definition: tmp.h:33
+ Here is the call graph for this function:

◆ mh_mbox_sync()

static enum MxStatus mh_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Return values
MX_STATUS_REOPENEDmailbox has been externally modified
MX_STATUS_NEW_MAILnew mail has arrived
0Success
-1Error
Note
The flag retvals come from a call to a backend sync function

Definition at line 1065 of file mh.c.

1066{
1067 enum MxStatus check = mh_check(m);
1068 if (check == MX_STATUS_ERROR)
1069 return check;
1070
1071 struct HeaderCache *hc = NULL;
1072#ifdef USE_HCACHE
1073 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1074 hc = hcache_open(c_header_cache, mailbox_path(m), NULL);
1075#endif
1076
1077 struct Progress *progress = NULL;
1078 if (m->verbose)
1079 {
1081 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
1082 }
1083
1084 for (int i = 0; i < m->msg_count; i++)
1085 {
1086 progress_update(progress, i, -1);
1087
1088 struct Email *e = m->emails[i];
1089 if (mh_sync_mailbox_message(m, e, hc) == -1)
1090 {
1091 progress_free(&progress);
1092 goto err;
1093 }
1094 }
1095 progress_free(&progress);
1096
1097#ifdef USE_HCACHE
1098 hcache_close(&hc);
1099#endif
1100
1101 mh_seq_update(m);
1102
1103 /* XXX race condition? */
1104
1105 mh_update_mtime(m);
1106
1107 /* adjust indices */
1108
1109 if (m->msg_deleted)
1110 {
1111 for (int i = 0, j = 0; i < m->msg_count; i++)
1112 {
1113 struct Email *e = m->emails[i];
1114 if (!e)
1115 break;
1116
1117 if (!e->deleted)
1118 e->index = j++;
1119 }
1120 }
1121
1122 return check;
1123
1124err:
1125#ifdef USE_HCACHE
1126 hcache_close(&hc);
1127#endif
1128 return MX_STATUS_ERROR;
1129}
struct HeaderCache * hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:471
void hcache_close(struct HeaderCache **ptr)
Multiplexor for StoreOps::close.
Definition: hcache.c:540
static void mh_update_mtime(struct Mailbox *m)
Update our record of the mailbox modification time.
Definition: mh.c:419
static enum MxStatus mh_check(struct Mailbox *m)
Check for new mail.
Definition: mh.c:909
int mh_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: mh.c:728
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition: sequence.c:234
+ Here is the call graph for this function:

◆ nntp_mbox_sync()

static enum MxStatus nntp_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Note
May also return values from check_mailbox()

Definition at line 2536 of file nntp.c.

2537{
2538 struct NntpMboxData *mdata = m->mdata;
2539
2540 /* check for new articles */
2541 mdata->adata->check_time = 0;
2542 enum MxStatus check = check_mailbox(m);
2543 if (check != MX_STATUS_OK)
2544 return check;
2545
2546#ifdef USE_HCACHE
2547 mdata->last_cached = 0;
2548 struct HeaderCache *hc = nntp_hcache_open(mdata);
2549#endif
2550
2551 for (int i = 0; i < m->msg_count; i++)
2552 {
2553 struct Email *e = m->emails[i];
2554 if (!e)
2555 break;
2556
2557 char buf[16] = { 0 };
2558
2559 snprintf(buf, sizeof(buf), ANUM_FMT, nntp_edata_get(e)->article_num);
2560 if (mdata->bcache && e->deleted)
2561 {
2562 mutt_debug(LL_DEBUG2, "mutt_bcache_del %s\n", buf);
2563 mutt_bcache_del(mdata->bcache, buf);
2564 }
2565
2566#ifdef USE_HCACHE
2567 if (hc && (e->changed || e->deleted))
2568 {
2569 if (e->deleted && !e->read)
2570 mdata->unread--;
2571 mutt_debug(LL_DEBUG2, "hcache_store_email %s\n", buf);
2572 hcache_store_email(hc, buf, strlen(buf), e, 0);
2573 }
2574#endif
2575 }
2576
2577#ifdef USE_HCACHE
2578 if (hc)
2579 {
2580 hcache_close(&hc);
2581 mdata->last_cached = mdata->last_loaded;
2582 }
2583#endif
2584
2585 /* save .newsrc entries */
2587 nntp_newsrc_update(mdata->adata);
2588 nntp_newsrc_close(mdata->adata);
2589 return MX_STATUS_OK;
2590}
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:266
int hcache_store_email(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:668
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:710
void nntp_newsrc_gen_entries(struct Mailbox *m)
Generate array of .newsrc entries.
Definition: newsrc.c:302
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:60
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:121
int nntp_newsrc_update(struct NntpAccountData *adata)
Update .newsrc file.
Definition: newsrc.c:444
#define ANUM_FMT
Definition: lib.h:61
static enum MxStatus check_mailbox(struct Mailbox *m)
Check current newsgroup for new articles.
Definition: nntp.c:1479
bool read
Email is read.
Definition: email.h:50
void * mdata
Driver specific data.
Definition: mailbox.h:132
NNTP-specific Mailbox data -.
Definition: mdata.h:34
anum_t last_cached
Definition: mdata.h:40
struct BodyCache * bcache
Definition: mdata.h:50
struct NntpAccountData * adata
Definition: mdata.h:48
anum_t unread
Definition: mdata.h:41
anum_t last_loaded
Definition: mdata.h:39
+ Here is the call graph for this function:

◆ nm_mbox_sync()

static enum MxStatus nm_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Definition at line 2231 of file notmuch.c.

2232{
2233 struct NmMboxData *mdata = nm_mdata_get(m);
2234 if (!mdata)
2235 return MX_STATUS_ERROR;
2236
2237 enum MxStatus rc = MX_STATUS_OK;
2238 struct Progress *progress = NULL;
2239 char *url = mutt_str_dup(mailbox_path(m));
2240 bool changed = false;
2241
2242 mutt_debug(LL_DEBUG1, "nm: sync start\n");
2243
2244 if (m->verbose)
2245 {
2246 /* all is in this function so we don't use data->progress here */
2248 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
2249 }
2250
2251 struct HeaderCache *hc = nm_hcache_open(m);
2252
2253 int mh_sync_errors = 0;
2254 for (int i = 0; i < m->msg_count; i++)
2255 {
2256 char old_file[PATH_MAX], new_file[PATH_MAX];
2257 struct Email *e = m->emails[i];
2258 if (!e)
2259 break;
2260
2261 struct NmEmailData *edata = nm_edata_get(e);
2262
2263 progress_update(progress, i, -1);
2264
2265 *old_file = '\0';
2266 *new_file = '\0';
2267
2268 if (edata->oldpath)
2269 {
2270 mutt_str_copy(old_file, edata->oldpath, sizeof(old_file));
2271 old_file[sizeof(old_file) - 1] = '\0';
2272 mutt_debug(LL_DEBUG2, "nm: fixing obsolete path '%s'\n", old_file);
2273 }
2274 else
2275 {
2276 email_get_fullpath(e, old_file, sizeof(old_file));
2277 }
2278
2279 buf_strcpy(&m->pathbuf, edata->folder);
2280 m->type = edata->type;
2281
2282 bool ok = maildir_sync_mailbox_message(m, e, hc);
2283 if (!ok)
2284 {
2285 // Syncing file failed, query notmuch for new filepath.
2286 m->type = MUTT_NOTMUCH;
2287 notmuch_database_t *db = nm_db_get(m, true);
2288 if (db)
2289 {
2290 notmuch_message_t *msg = get_nm_message(db, e);
2291
2293
2294 buf_strcpy(&m->pathbuf, edata->folder);
2295 m->type = edata->type;
2296 ok = maildir_sync_mailbox_message(m, e, hc);
2297 m->type = MUTT_NOTMUCH;
2298 }
2299 nm_db_release(m);
2300 m->type = edata->type;
2301 }
2302
2303 buf_strcpy(&m->pathbuf, url);
2304 m->type = MUTT_NOTMUCH;
2305
2306 if (!ok)
2307 {
2308 mh_sync_errors += 1;
2309 continue;
2310 }
2311
2312 if (!e->deleted)
2313 email_get_fullpath(e, new_file, sizeof(new_file));
2314
2315 if (e->deleted || !mutt_str_equal(old_file, new_file))
2316 {
2317 if (e->deleted && (remove_filename(m, old_file) == 0))
2318 changed = true;
2319 else if (*new_file && *old_file && (rename_filename(m, old_file, new_file, e) == 0))
2320 changed = true;
2321 }
2322
2323 FREE(&edata->oldpath);
2324 }
2325
2326 if (mh_sync_errors > 0)
2327 {
2328 mutt_error(ngettext("Unable to sync %d message due to external mailbox modification",
2329 "Unable to sync %d messages due to external mailbox modification",
2330 mh_sync_errors),
2331 mh_sync_errors);
2332 }
2333
2334 buf_strcpy(&m->pathbuf, url);
2335 m->type = MUTT_NOTMUCH;
2336
2337 nm_db_release(m);
2338
2339 if (changed)
2340 {
2341 mdata->mtime.tv_sec = mutt_date_now();
2342 mdata->mtime.tv_nsec = 0;
2343 }
2344
2345 nm_hcache_close(&hc);
2346
2347 progress_free(&progress);
2348 FREE(&url);
2349 mutt_debug(LL_DEBUG1, "nm: .... sync done [rc=%d]\n", rc);
2350 return rc;
2351}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:575
#define PATH_MAX
Definition: mutt.h:42
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:208
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:232
struct NmEmailData * nm_edata_get(struct Email *e)
Get the Notmuch Email data.
Definition: edata.c:72
struct NmMboxData * nm_mdata_get(struct Mailbox *m)
Get the Notmuch Mailbox data.
Definition: mdata.c:96
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:237
static void sync_email_path_with_nm(struct Email *e, notmuch_message_t *msg)
Synchronize Neomutt's Email path with notmuch.
Definition: notmuch.c:1088
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition: notmuch.c:1047
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1331
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:118
static int remove_filename(struct Mailbox *m, const char *path)
Delete a file.
Definition: notmuch.c:1267
static void nm_hcache_close(struct HeaderCache **ptr)
Close the header cache.
Definition: notmuch.c:132
void * edata
Driver-specific data.
Definition: email.h:74
struct Buffer pathbuf
Path of the Mailbox.
Definition: mailbox.h:80
Notmuch-specific Email data -.
Definition: edata.h:34
Notmuch-specific Mailbox data -.
Definition: mdata.h:35
struct timespec mtime
Time Mailbox was last changed.
Definition: mdata.h:44
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:53
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:52
+ Here is the call graph for this function:

◆ pop_mbox_sync()

static enum MxStatus pop_mbox_sync ( struct Mailbox m)
static

Save changes to the Mailbox - Implements MxOps::mbox_sync() -.

Update POP mailbox, delete messages from server

Definition at line 860 of file pop.c.

861{
862 int i, j, rc = 0;
863 char buf[1024] = { 0 };
865#ifdef USE_HCACHE
866 struct HeaderCache *hc = NULL;
867#endif
868
869 adata->check_time = 0;
870
871 int num_deleted = 0;
872 for (i = 0; i < m->msg_count; i++)
873 {
874 if (m->emails[i]->deleted)
875 num_deleted++;
876 }
877
878 while (true)
879 {
880 if (pop_reconnect(m) < 0)
881 return MX_STATUS_ERROR;
882
883#ifdef USE_HCACHE
884 hc = pop_hcache_open(adata, mailbox_path(m));
885#endif
886
887 struct Progress *progress = NULL;
888 if (m->verbose)
889 {
890 progress = progress_new(MUTT_PROGRESS_WRITE, num_deleted);
891 progress_set_message(progress, _("Marking messages deleted..."));
892 }
893
894 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
895 {
896 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
897 if (m->emails[i]->deleted && (edata->refno != -1))
898 {
899 j++;
900 progress_update(progress, j, -1);
901 snprintf(buf, sizeof(buf), "DELE %d\r\n", edata->refno);
902 rc = pop_query(adata, buf, sizeof(buf));
903 if (rc == 0)
904 {
905 mutt_bcache_del(adata->bcache, cache_id(edata->uid));
906#ifdef USE_HCACHE
907 hcache_delete_email(hc, edata->uid, strlen(edata->uid));
908#endif
909 }
910 }
911
912#ifdef USE_HCACHE
913 if (m->emails[i]->changed)
914 {
915 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
916 }
917#endif
918 }
919 progress_free(&progress);
920
921#ifdef USE_HCACHE
922 hcache_close(&hc);
923#endif
924
925 if (rc == 0)
926 {
927 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
928 rc = pop_query(adata, buf, sizeof(buf));
929 }
930
931 if (rc == 0)
932 {
933 adata->clear_cache = true;
934 pop_clear_cache(adata);
935 adata->status = POP_DISCONNECTED;
936 return MX_STATUS_OK;
937 }
938
939 if (rc == -2)
940 {
941 mutt_error("%s", adata->err_msg);
942 return MX_STATUS_ERROR;
943 }
944 }
945}
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:737
struct PopAccountData * pop_adata_get(struct Mailbox *m)
Get the Account data for this mailbox.
Definition: adata.c:73
struct PopEmailData * pop_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:68
int pop_reconnect(struct Mailbox *m)
Reconnect and verify indexes if connection was lost.
Definition: lib.c:609
#define pop_query(adata, buf, buflen)
Definition: private.h:111
@ POP_DISCONNECTED
Disconnected from server.
Definition: private.h:51
static void pop_clear_cache(struct PopAccountData *adata)
Delete all cached messages.
Definition: pop.c:493
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition: pop.c:82
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition: pop.c:300
POP-specific Account data -.
Definition: adata.h:37
bool clear_cache
Definition: adata.h:49
time_t check_time
Definition: adata.h:51
char err_msg[POP_CMD_RESPONSE]
Definition: adata.h:56
unsigned int status
Definition: adata.h:39
struct BodyCache * bcache
body cache
Definition: adata.h:55
POP-specific Email data -.
Definition: edata.h:32
+ Here is the call graph for this function: