NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
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() -. More...
 
static enum MxStatus maildir_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus mh_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus mbox_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus nntp_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus nm_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 
static enum MxStatus pop_mbox_sync (struct Mailbox *m)
 Save changes to the Mailbox - Implements MxOps::mbox_sync() -. More...
 

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 620 of file compress.c.

621{
622 if (!m->compress_info)
623 return MX_STATUS_ERROR;
624
625 struct CompressInfo *ci = m->compress_info;
626
627 if (!ci->cmd_close)
628 {
629 mutt_error(_("Can't sync a compressed file without a close-hook"));
630 return MX_STATUS_ERROR;
631 }
632
633 const struct MxOps *ops = ci->child_ops;
634 if (!ops)
635 return MX_STATUS_ERROR;
636
637 if (!lock_realpath(m, true))
638 {
639 mutt_error(_("Unable to lock mailbox"));
640 return MX_STATUS_ERROR;
641 }
642
643 enum MxStatus check = comp_mbox_check(m);
644 if (check != MX_STATUS_OK)
645 goto sync_cleanup;
646
647 check = ops->mbox_sync(m);
648 if (check != MX_STATUS_OK)
649 goto sync_cleanup;
650
651 int rc = execute_command(m, ci->cmd_close, _("Compressing %s"));
652 if (rc == 0)
653 {
654 check = MX_STATUS_ERROR;
655 goto sync_cleanup;
656 }
657
658 check = MX_STATUS_OK;
659
660sync_cleanup:
661 store_size(m);
663 return check;
664}
static int execute_command(struct Mailbox *m, const char *command, const char *progress)
Run a system command.
Definition: compress.c:324
static void store_size(const struct Mailbox *m)
Save the size of the compressed file.
Definition: compress.c:181
static bool lock_realpath(struct Mailbox *m, bool excl)
Try to lock the Mailbox.realpath.
Definition: compress.c:88
static void unlock_realpath(struct Mailbox *m)
Unlock the mailbox->realpath.
Definition: compress.c:127
#define mutt_error(...)
Definition: logging.h:87
static enum MxStatus comp_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: compress.c:584
#define _(a)
Definition: message.h:28
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
Private data for compress.
Definition: lib.h:47
const struct MxOps * child_ops
callbacks of de-compressed file
Definition: lib.h:52
const char * cmd_close
close-hook command
Definition: lib.h:49
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:120
Definition: mxapi.h:112
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition: mxapi.h:208
+ Here is the call graph for this function:

◆ maildir_mbox_sync()

static enum MxStatus maildir_mbox_sync ( struct Mailbox m)
static

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 1375 of file maildir.c.

1376{
1377 enum MxStatus check = maildir_mbox_check(m);
1378 if (check == MX_STATUS_ERROR)
1379 return check;
1380
1381 struct HeaderCache *hc = NULL;
1382#ifdef USE_HCACHE
1383 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1384 if (m->type == MUTT_MAILDIR)
1385 hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
1386#endif
1387
1388 struct Progress *progress = NULL;
1389 if (m->verbose)
1390 {
1391 char msg[PATH_MAX] = { 0 };
1392 snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
1393 progress = progress_new(msg, MUTT_PROGRESS_WRITE, m->msg_count);
1394 }
1395
1396 for (int i = 0; i < m->msg_count; i++)
1397 {
1398 if (m->verbose)
1399 progress_update(progress, i, -1);
1400
1401 if (!maildir_sync_mailbox_message(m, i, hc))
1402 {
1403 progress_free(&progress);
1404 goto err;
1405 }
1406 }
1407 progress_free(&progress);
1408
1409#ifdef USE_HCACHE
1410 if (m->type == MUTT_MAILDIR)
1412#endif
1413
1414 /* XXX race condition? */
1415
1417
1418 /* adjust indices */
1419
1420 if (m->msg_deleted)
1421 {
1422 for (int i = 0, j = 0; i < m->msg_count; i++)
1423 {
1424 struct Email *e = m->emails[i];
1425 if (!e)
1426 break;
1427
1428 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
1429 if (!e->deleted || c_maildir_trash)
1430 e->index = j++;
1431 }
1432 }
1433
1434 return check;
1435
1436err:
1437#ifdef USE_HCACHE
1438 if (m->type == MUTT_MAILDIR)
1440#endif
1441 return MX_STATUS_ERROR;
1442}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static enum MxStatus maildir_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: maildir.c:1169
void mutt_hcache_close(struct HeaderCache *hc)
Multiplexor for StoreOps::close.
Definition: hcache.c:483
struct HeaderCache * mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
Multiplexor for StoreOps::open.
Definition: hcache.c:373
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
static void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: maildir.c:477
bool maildir_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: maildir.c:949
#define PATH_MAX
Definition: mutt.h:41
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
The envelope/body of an email.
Definition: email.h:37
bool deleted
Email is deleted.
Definition: email.h:76
int index
The absolute (unsorted) message number.
Definition: email.h:109
Header cache structure.
Definition: lib.h:88
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
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:114
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 1038 of file mh.c.

1039{
1040 enum MxStatus check = mh_mbox_check(m);
1041 if (check == MX_STATUS_ERROR)
1042 return check;
1043
1044 struct HeaderCache *hc = NULL;
1045#ifdef USE_HCACHE
1046 const char *const c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
1047 if (m->type == MUTT_MH)
1048 hc = mutt_hcache_open(c_header_cache, mailbox_path(m), NULL);
1049#endif
1050
1051 struct Progress *progress = NULL;
1052 if (m->verbose)
1053 {
1054 char msg[PATH_MAX] = { 0 };
1055 snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
1056 progress = progress_new(msg, MUTT_PROGRESS_WRITE, m->msg_count);
1057 }
1058
1059 for (int i = 0; i < m->msg_count; i++)
1060 {
1061 if (m->verbose)
1062 progress_update(progress, i, -1);
1063
1064 if (mh_sync_mailbox_message(m, i, hc) == -1)
1065 {
1066 progress_free(&progress);
1067 goto err;
1068 }
1069 }
1070 progress_free(&progress);
1071
1072#ifdef USE_HCACHE
1073 if (m->type == MUTT_MH)
1075#endif
1076
1077 mh_seq_update(m);
1078
1079 /* XXX race condition? */
1080
1081 mh_update_mtime(m);
1082
1083 /* adjust indices */
1084
1085 if (m->msg_deleted)
1086 {
1087 for (int i = 0, j = 0; i < m->msg_count; i++)
1088 {
1089 struct Email *e = m->emails[i];
1090 if (!e)
1091 break;
1092
1093 if (!e->deleted)
1094 e->index = j++;
1095 }
1096 }
1097
1098 return check;
1099
1100err:
1101#ifdef USE_HCACHE
1102 if (m->type == MUTT_MH)
1104#endif
1105 return MX_STATUS_ERROR;
1106}
static enum MxStatus mh_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mh.c:893
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
static void mh_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition: mh.c:477
int mh_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: mh.c:757
void mh_seq_update(struct Mailbox *m)
Update sequence numbers.
Definition: sequence.c:231
+ 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 1156 of file mbox.c.

1157{
1159 if (!adata)
1160 return MX_STATUS_ERROR;
1161
1162 struct Buffer *tempfile = NULL;
1163 char buf[32] = { 0 };
1164 int j;
1165 bool unlink_tempfile = false;
1166 bool need_sort = false; /* flag to resort mailbox if new mail arrives */
1167 int first = -1; /* first message to be written */
1168 LOFF_T offset; /* location in mailbox to write changed messages */
1169 struct stat st = { 0 };
1170 struct MUpdate *new_offset = NULL;
1171 struct MUpdate *old_offset = NULL;
1172 FILE *fp = NULL;
1173 struct Progress *progress = NULL;
1174 enum MxStatus rc = MX_STATUS_ERROR;
1175
1176 /* sort message by their position in the mailbox on disk */
1177 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
1178 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
1179 if (c_sort != SORT_ORDER)
1180 {
1182 cs_subset_str_native_set(NeoMutt->sub, "use_threads", UT_FLAT, NULL);
1184 cs_subset_str_native_set(NeoMutt->sub, "sort", c_sort, NULL);
1185 cs_subset_str_native_set(NeoMutt->sub, "use_threads", c_use_threads, NULL);
1186 need_sort = true;
1187 }
1188
1189 /* need to open the file for writing in such a way that it does not truncate
1190 * the file, so use read-write mode. */
1191 adata->fp = freopen(mailbox_path(m), "r+", adata->fp);
1192 if (!adata->fp)
1193 {
1194 mx_fastclose_mailbox(m, false);
1195 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1196 goto fatal;
1197 }
1198
1200
1201 if (mbox_lock_mailbox(m, true, true) == -1)
1202 {
1204 mutt_error(_("Unable to lock mailbox"));
1205 goto bail;
1206 }
1207
1208 /* Check to make sure that the file hasn't changed on disk */
1209 enum MxStatus check = mbox_mbox_check(m);
1210 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1211 {
1212 /* new mail arrived, or mailbox reopened */
1213 rc = check;
1214 goto bail;
1215 }
1216 else if (check < 0)
1217 {
1218 goto fatal;
1219 }
1220
1221 /* Create a temporary file to write the new version of the mailbox in. */
1222 tempfile = mutt_buffer_pool_get();
1223 mutt_buffer_mktemp(tempfile);
1224 int fd = open(mutt_buffer_string(tempfile), O_WRONLY | O_EXCL | O_CREAT, 0600);
1225 if ((fd == -1) || !(fp = fdopen(fd, "w")))
1226 {
1227 if (fd != -1)
1228 {
1229 close(fd);
1230 unlink_tempfile = true;
1231 }
1232 mutt_error(_("Could not create temporary file"));
1233 goto bail;
1234 }
1235 unlink_tempfile = true;
1236
1237 /* find the first deleted/changed message. we save a lot of time by only
1238 * rewriting the mailbox from the point where it has actually changed. */
1239 int i = 0;
1240 for (; (i < m->msg_count) && !m->emails[i]->deleted &&
1241 !m->emails[i]->changed && !m->emails[i]->attach_del;
1242 i++)
1243 {
1244 }
1245 if (i == m->msg_count)
1246 {
1247 /* this means m->changed or m->msg_deleted was set, but no
1248 * messages were found to be changed or deleted. This should
1249 * never happen, is we presume it is a bug in neomutt. */
1250 mutt_error(_("sync: mbox modified, but no modified messages (report this bug)"));
1251 mutt_debug(LL_DEBUG1, "no modified messages\n");
1252 goto bail;
1253 }
1254
1255 /* save the index of the first changed/deleted message */
1256 first = i;
1257 /* where to start overwriting */
1258 offset = m->emails[i]->offset;
1259
1260 /* the offset stored in the header does not include the MMDF_SEP, so make
1261 * sure we seek to the correct location */
1262 if (m->type == MUTT_MMDF)
1263 offset -= (sizeof(MMDF_SEP) - 1);
1264
1265 /* allocate space for the new offsets */
1266 new_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));
1267 old_offset = mutt_mem_calloc(m->msg_count - first, sizeof(struct MUpdate));
1268
1269 if (m->verbose)
1270 {
1271 char msg[PATH_MAX] = { 0 };
1272 snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
1273 progress = progress_new(msg, MUTT_PROGRESS_WRITE, m->msg_count);
1274 }
1275
1276 for (i = first, j = 0; i < m->msg_count; i++)
1277 {
1278 if (m->verbose)
1279 progress_update(progress, i, i / (m->msg_count / 100 + 1));
1280 /* back up some information which is needed to restore offsets when
1281 * something fails. */
1282
1283 old_offset[i - first].valid = true;
1284 old_offset[i - first].hdr = m->emails[i]->offset;
1285 old_offset[i - first].body = m->emails[i]->body->offset;
1286 old_offset[i - first].lines = m->emails[i]->lines;
1287 old_offset[i - first].length = m->emails[i]->body->length;
1288
1289 if (!m->emails[i]->deleted)
1290 {
1291 j++;
1292
1293 if (m->type == MUTT_MMDF)
1294 {
1295 if (fputs(MMDF_SEP, fp) == EOF)
1296 {
1298 goto bail;
1299 }
1300 }
1301
1302 /* save the new offset for this message. we add 'offset' because the
1303 * temporary file only contains saved message which are located after
1304 * 'offset' in the real mailbox */
1305 new_offset[i - first].hdr = ftello(fp) + offset;
1306
1307 struct Message *msg = mx_msg_open(m, m->emails[i]->msgno);
1308 const int rc2 = mutt_copy_message(fp, m->emails[i], msg, MUTT_CM_UPDATE,
1310 mx_msg_close(m, &msg);
1311 if (rc2 != 0)
1312 {
1314 goto bail;
1315 }
1316
1317 /* Since messages could have been deleted, the offsets stored in memory
1318 * will be wrong, so update what we can, which is the offset of this
1319 * message, and the offset of the body. If this is a multipart message,
1320 * we just flush the in memory cache so that the message will be reparsed
1321 * if the user accesses it later. */
1322 new_offset[i - first].body = ftello(fp) - m->emails[i]->body->length + offset;
1323 mutt_body_free(&m->emails[i]->body->parts);
1324
1325 switch (m->type)
1326 {
1327 case MUTT_MMDF:
1328 if (fputs(MMDF_SEP, fp) == EOF)
1329 {
1331 goto bail;
1332 }
1333 break;
1334 default:
1335 if (fputs("\n", fp) == EOF)
1336 {
1338 goto bail;
1339 }
1340 }
1341 }
1342 }
1343
1344 if (mutt_file_fclose(&fp) != 0)
1345 {
1346 mutt_debug(LL_DEBUG1, "mutt_file_fclose (&) returned non-zero\n");
1348 goto bail;
1349 }
1350
1351 /* Save the state of this folder. */
1352 if (stat(mailbox_path(m), &st) == -1)
1353 {
1355 goto bail;
1356 }
1357
1358 unlink_tempfile = false;
1359
1360 fp = fopen(mutt_buffer_string(tempfile), "r");
1361 if (!fp)
1362 {
1364 mx_fastclose_mailbox(m, false);
1365 mutt_debug(LL_DEBUG1, "unable to reopen temp copy of mailbox!\n");
1367 FREE(&new_offset);
1368 FREE(&old_offset);
1369 goto fatal;
1370 }
1371
1372 if (!mutt_file_seek(adata->fp, offset, SEEK_SET) || /* seek the append location */
1373 /* do a sanity check to make sure the mailbox looks ok */
1374 !fgets(buf, sizeof(buf), adata->fp) ||
1375 ((m->type == MUTT_MBOX) && !mutt_str_startswith(buf, "From ")) ||
1376 ((m->type == MUTT_MMDF) && !mutt_str_equal(MMDF_SEP, buf)))
1377 {
1378 mutt_debug(LL_DEBUG1, "message not in expected position\n");
1379 mutt_debug(LL_DEBUG1, " LINE: %s\n", buf);
1380 i = -1;
1381 }
1382 else
1383 {
1384 if (!mutt_file_seek(adata->fp, offset, SEEK_SET)) /* return to proper offset */
1385 {
1386 i = -1;
1387 }
1388 else
1389 {
1390 /* copy the temp mailbox back into place starting at the first
1391 * change/deleted message */
1392 if (m->verbose)
1393 mutt_message(_("Committing changes..."));
1394 i = mutt_file_copy_stream(fp, adata->fp);
1395
1396 if (ferror(adata->fp))
1397 i = -1;
1398 }
1399 if (i >= 0)
1400 {
1401 m->size = ftello(adata->fp); /* update the mailbox->size of the mailbox */
1402 if ((m->size < 0) || (ftruncate(fileno(adata->fp), m->size) != 0))
1403 {
1404 i = -1;
1405 mutt_debug(LL_DEBUG1, "ftruncate() failed\n");
1406 }
1407 }
1408 }
1409
1411 fp = NULL;
1413
1414 if ((mutt_file_fclose(&adata->fp) != 0) || (i == -1))
1415 {
1416 /* error occurred while writing the mailbox back, so keep the temp copy around */
1417
1418 struct Buffer *savefile = mutt_buffer_pool_get();
1419
1420 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
1421 mutt_buffer_printf(savefile, "%s/neomutt.%s-%s-%u", NONULL(c_tmp_dir),
1422 NONULL(Username), NONULL(ShortHostname), (unsigned int) getpid());
1423 rename(mutt_buffer_string(tempfile), mutt_buffer_string(savefile));
1425 mx_fastclose_mailbox(m, false);
1427 mutt_error(_("Write failed! Saved partial mailbox to %s"), mutt_buffer_string(savefile));
1428 mutt_buffer_pool_release(&savefile);
1429 FREE(&new_offset);
1430 FREE(&old_offset);
1431 goto fatal;
1432 }
1433
1434 /* Restore the previous access/modification times */
1435 mbox_reset_atime(m, &st);
1436
1437 /* reopen the mailbox in read-only mode */
1438 adata->fp = mbox_open_readwrite(m);
1439 if (!adata->fp)
1440 {
1441 adata->fp = mbox_open_readonly(m);
1442 }
1443 if (!adata->fp)
1444 {
1445 unlink(mutt_buffer_string(tempfile));
1447 mx_fastclose_mailbox(m, false);
1448 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1449 FREE(&new_offset);
1450 FREE(&old_offset);
1451 goto fatal;
1452 }
1453
1454 /* update the offsets of the rewritten messages */
1455 for (i = first, j = first; i < m->msg_count; i++)
1456 {
1457 if (!m->emails[i]->deleted)
1458 {
1459 m->emails[i]->offset = new_offset[i - first].hdr;
1460 m->emails[i]->body->hdr_offset = new_offset[i - first].hdr;
1461 m->emails[i]->body->offset = new_offset[i - first].body;
1462 m->emails[i]->index = j++;
1463 }
1464 }
1465 FREE(&new_offset);
1466 FREE(&old_offset);
1467 unlink(mutt_buffer_string(tempfile)); /* remove partial copy of the mailbox */
1468 mutt_buffer_pool_release(&tempfile);
1470
1471 const bool c_check_mbox_size = cs_subset_bool(NeoMutt->sub, "check_mbox_size");
1472 if (c_check_mbox_size)
1473 {
1474 struct Mailbox *m_tmp = mailbox_find(mailbox_path(m));
1475 if (m_tmp && !m_tmp->has_new)
1476 mailbox_update(m_tmp);
1477 }
1478
1479 progress_free(&progress);
1480 return 0; /* signal success */
1481
1482bail: /* Come here in case of disaster */
1483
1484 mutt_file_fclose(&fp);
1485
1486 if (tempfile && unlink_tempfile)
1487 unlink(mutt_buffer_string(tempfile));
1488
1489 /* restore offsets, as far as they are valid */
1490 if ((first >= 0) && old_offset)
1491 {
1492 for (i = first; (i < m->msg_count) && old_offset[i - first].valid; i++)
1493 {
1494 m->emails[i]->offset = old_offset[i - first].hdr;
1495 m->emails[i]->body->hdr_offset = old_offset[i - first].hdr;
1496 m->emails[i]->body->offset = old_offset[i - first].body;
1497 m->emails[i]->lines = old_offset[i - first].lines;
1498 m->emails[i]->body->length = old_offset[i - first].length;
1499 }
1500 }
1501
1502 /* this is ok to call even if we haven't locked anything */
1504
1506 FREE(&new_offset);
1507 FREE(&old_offset);
1508
1509 adata->fp = freopen(mailbox_path(m), "r", adata->fp);
1510 if (!adata->fp)
1511 {
1512 mutt_error(_("Could not reopen mailbox"));
1513 mx_fastclose_mailbox(m, false);
1514 goto fatal;
1515 }
1516
1518 if (need_sort)
1519 {
1520 /* if the mailbox was reopened, the thread tree will be invalid so make
1521 * sure to start threading from scratch. */
1523 }
1524
1525fatal:
1526 mutt_buffer_pool_release(&tempfile);
1527 progress_free(&progress);
1528 return rc;
1529}
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
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:868
#define MUTT_CM_UPDATE
Update structs on sync.
Definition: copy.h:40
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:52
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:706
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: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
static enum MxStatus mbox_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition: mbox.c:1026
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_update(struct Mailbox *m)
Get the mailbox's current size.
Definition: mailbox.c:204
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition: mailbox.c:222
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:139
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition: mailbox.h:176
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition: mailbox.h:177
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
#define MMDF_SEP
Definition: lib.h:61
static int mbox_lock_mailbox(struct Mailbox *m, bool excl, bool retry)
Lock a mailbox.
Definition: mbox.c:134
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition: mbox.c:119
static FILE * mbox_open_readwrite(struct Mailbox *m)
Open an mbox read-write.
Definition: mbox.c:899
static FILE * mbox_open_readonly(struct Mailbox *m)
Open an mbox read-only.
Definition: mbox.c:914
static void mbox_unlock_mailbox(struct Mailbox *m)
Unlock a mailbox.
Definition: mbox.c:156
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition: mbox.c:843
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:43
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:85
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:600
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1192
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:429
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1146
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition: mxapi.h:89
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition: mxapi.h:87
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_sig_block(void)
Block signals during critical operations.
Definition: signal.c:150
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition: signal.c:168
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:44
#define NONULL(x)
Definition: string2.h:37
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
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:34
int lines
How many lines in the body of this message?
Definition: email.h:60
struct Body * body
List of MIME parts.
Definition: email.h:67
bool changed
Email has been edited.
Definition: email.h:75
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:98
int msgno
Number displayed to the user.
Definition: email.h:110
Store of new offsets, used by mutt_sync_mailbox()
Definition: mbox.c:66
long lines
Definition: mbox.c:70
LOFF_T hdr
Definition: mbox.c:68
LOFF_T length
Definition: mbox.c:71
LOFF_T body
Definition: mbox.c:69
bool valid
Definition: mbox.c:67
A mailbox.
Definition: mailbox.h:79
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
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: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ 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 2478 of file nntp.c.

2479{
2480 struct NntpMboxData *mdata = m->mdata;
2481
2482 /* check for new articles */
2483 mdata->adata->check_time = 0;
2484 enum MxStatus check = check_mailbox(m);
2485 if (check != MX_STATUS_OK)
2486 return check;
2487
2488#ifdef USE_HCACHE
2489 mdata->last_cached = 0;
2490 struct HeaderCache *hc = nntp_hcache_open(mdata);
2491#endif
2492
2493 for (int i = 0; i < m->msg_count; i++)
2494 {
2495 struct Email *e = m->emails[i];
2496 if (!e)
2497 break;
2498
2499 char buf[16] = { 0 };
2500
2501 snprintf(buf, sizeof(buf), ANUM, nntp_edata_get(e)->article_num);
2502 if (mdata->bcache && e->deleted)
2503 {
2504 mutt_debug(LL_DEBUG2, "mutt_bcache_del %s\n", buf);
2505 mutt_bcache_del(mdata->bcache, buf);
2506 }
2507
2508#ifdef USE_HCACHE
2509 if (hc && (e->changed || e->deleted))
2510 {
2511 if (e->deleted && !e->read)
2512 mdata->unread--;
2513 mutt_debug(LL_DEBUG2, "mutt_hcache_store %s\n", buf);
2514 mutt_hcache_store(hc, buf, strlen(buf), e, 0);
2515 }
2516#endif
2517 }
2518
2519#ifdef USE_HCACHE
2520 if (hc)
2521 {
2523 mdata->last_cached = mdata->last_loaded;
2524 }
2525#endif
2526
2527 /* save .newsrc entries */
2529 nntp_newsrc_update(mdata->adata);
2530 nntp_newsrc_close(mdata->adata);
2531 return MX_STATUS_OK;
2532}
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition: bcache.c:265
int mutt_hcache_store(struct HeaderCache *hc, const char *key, size_t keylen, struct Email *e, uint32_t uidvalidity)
Multiplexor for StoreOps::store.
Definition: hcache.c:610
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition: newsrc.c:711
void nntp_newsrc_gen_entries(struct Mailbox *m)
Generate array of .newsrc entries.
Definition: newsrc.c:299
struct NntpEmailData * nntp_edata_get(struct Email *e)
Get the private data for this Email.
Definition: edata.c:58
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:118
int nntp_newsrc_update(struct NntpAccountData *adata)
Update .newsrc file.
Definition: newsrc.c:442
#define ANUM
Definition: lib.h:61
static enum MxStatus check_mailbox(struct Mailbox *m)
Check current newsgroup for new articles.
Definition: nntp.c:1433
bool read
Email is read.
Definition: email.h:48
void * mdata
Driver specific data.
Definition: mailbox.h:132
NNTP-specific Mailbox data -.
Definition: mdata.h:33
anum_t last_cached
Definition: mdata.h:39
struct BodyCache * bcache
Definition: mdata.h:49
struct NntpAccountData * adata
Definition: mdata.h:47
anum_t unread
Definition: mdata.h:40
anum_t last_loaded
Definition: mdata.h:38
+ 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 2205 of file notmuch.c.

2206{
2207 struct NmMboxData *mdata = nm_mdata_get(m);
2208 if (!mdata)
2209 return MX_STATUS_ERROR;
2210
2211 enum MxStatus rc = MX_STATUS_OK;
2212 struct Progress *progress = NULL;
2213 char *url = mutt_str_dup(mailbox_path(m));
2214 bool changed = false;
2215
2216 mutt_debug(LL_DEBUG1, "nm: sync start\n");
2217
2218 if (m->verbose)
2219 {
2220 /* all is in this function so we don't use data->progress here */
2221 char msg[PATH_MAX] = { 0 };
2222 snprintf(msg, sizeof(msg), _("Writing %s..."), mailbox_path(m));
2223 progress = progress_new(msg, MUTT_PROGRESS_WRITE, m->msg_count);
2224 }
2225
2226 struct HeaderCache *h = nm_hcache_open(m);
2227
2228 int mh_sync_errors = 0;
2229 for (int i = 0; i < m->msg_count; i++)
2230 {
2231 char old_file[PATH_MAX], new_file[PATH_MAX];
2232 struct Email *e = m->emails[i];
2233 if (!e)
2234 break;
2235
2236 struct NmEmailData *edata = nm_edata_get(e);
2237
2238 if (m->verbose)
2239 progress_update(progress, i, -1);
2240
2241 *old_file = '\0';
2242 *new_file = '\0';
2243
2244 if (edata->oldpath)
2245 {
2246 mutt_str_copy(old_file, edata->oldpath, sizeof(old_file));
2247 old_file[sizeof(old_file) - 1] = '\0';
2248 mutt_debug(LL_DEBUG2, "nm: fixing obsolete path '%s'\n", old_file);
2249 }
2250 else
2251 email_get_fullpath(e, old_file, sizeof(old_file));
2252
2253 mutt_buffer_strcpy(&m->pathbuf, edata->folder);
2254 m->type = edata->type;
2255
2256 bool ok = maildir_sync_mailbox_message(m, i, h);
2257 if (!ok)
2258 {
2259 // Syncing file failed, query notmuch for new filepath.
2260 m->type = MUTT_NOTMUCH;
2261 notmuch_database_t *db = nm_db_get(m, true);
2262 if (db)
2263 {
2264 notmuch_message_t *msg = get_nm_message(db, e);
2265
2267
2268 mutt_buffer_strcpy(&m->pathbuf, edata->folder);
2269 m->type = edata->type;
2270 ok = maildir_sync_mailbox_message(m, i, h);
2271 m->type = MUTT_NOTMUCH;
2272 }
2273 nm_db_release(m);
2274 m->type = edata->type;
2275 }
2276
2277 mutt_buffer_strcpy(&m->pathbuf, url);
2278 m->type = MUTT_NOTMUCH;
2279
2280 if (!ok)
2281 {
2282 mh_sync_errors += 1;
2283 continue;
2284 }
2285
2286 if (!e->deleted)
2287 email_get_fullpath(e, new_file, sizeof(new_file));
2288
2289 if (e->deleted || (strcmp(old_file, new_file) != 0))
2290 {
2291 if (e->deleted && (remove_filename(m, old_file) == 0))
2292 changed = true;
2293 else if (*new_file && *old_file && (rename_filename(m, old_file, new_file, e) == 0))
2294 changed = true;
2295 }
2296
2297 FREE(&edata->oldpath);
2298 }
2299
2300 if (mh_sync_errors > 0)
2301 {
2302 mutt_error(ngettext("Unable to sync %d message due to external mailbox modification",
2303 "Unable to sync %d messages due to external mailbox modification",
2304 mh_sync_errors),
2305 mh_sync_errors);
2306 }
2307
2308 mutt_buffer_strcpy(&m->pathbuf, url);
2309 m->type = MUTT_NOTMUCH;
2310
2311 nm_db_release(m);
2312
2313 if (changed)
2314 {
2315 m->mtime.tv_sec = mutt_date_now();
2316 m->mtime.tv_nsec = 0;
2317 }
2318
2319 nm_hcache_close(h);
2320
2321 progress_free(&progress);
2322 FREE(&url);
2323 mutt_debug(LL_DEBUG1, "nm: .... sync done [rc=%d]\n", rc);
2324 return rc;
2325}
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
bool maildir_sync_mailbox_message(struct Mailbox *m, int msgno, struct HeaderCache *hc)
Save changes to the mailbox.
Definition: maildir.c:949
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
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:652
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition: db.c:198
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition: db.c:222
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:97
static char * email_get_fullpath(struct Email *e, char *buf, size_t buflen)
Get the full path of an email.
Definition: notmuch.c:226
static void sync_email_path_with_nm(struct Email *e, notmuch_message_t *msg)
Synchronize Neomutt's Email path with notmuch.
Definition: notmuch.c:1075
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition: notmuch.c:1034
static void nm_hcache_close(struct HeaderCache *h)
Close the header cache.
Definition: notmuch.c:125
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition: notmuch.c:1315
static struct HeaderCache * nm_hcache_open(struct Mailbox *m)
Open a header cache.
Definition: notmuch.c:111
static int remove_filename(struct Mailbox *m, const char *path)
Delete a file.
Definition: notmuch.c:1251
void * edata
Driver-specific data.
Definition: email.h:72
struct timespec mtime
Time Mailbox was last changed.
Definition: mailbox.h:104
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:34
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:52
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:51
+ 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 859 of file pop.c.

860{
861 int i, j, rc = 0;
862 char buf[1024] = { 0 };
864#ifdef USE_HCACHE
865 struct HeaderCache *hc = NULL;
866#endif
867
868 adata->check_time = 0;
869
870 int num_deleted = 0;
871 for (i = 0; i < m->msg_count; i++)
872 {
873 if (m->emails[i]->deleted)
874 num_deleted++;
875 }
876
877 while (true)
878 {
879 if (pop_reconnect(m) < 0)
880 return MX_STATUS_ERROR;
881
882#ifdef USE_HCACHE
883 hc = pop_hcache_open(adata, mailbox_path(m));
884#endif
885
886 struct Progress *progress = NULL;
887 if (m->verbose)
888 {
889 progress = progress_new(_("Marking messages deleted..."),
890 MUTT_PROGRESS_WRITE, num_deleted);
891 }
892
893 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
894 {
895 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
896 if (m->emails[i]->deleted && (edata->refno != -1))
897 {
898 j++;
899 if (m->verbose)
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 mutt_hcache_delete_record(hc, edata->uid, strlen(edata->uid));
908#endif
909 }
910 }
911
912#ifdef USE_HCACHE
913 if (m->emails[i]->changed)
914 {
915 mutt_hcache_store(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
916 }
917#endif
918 }
919 progress_free(&progress);
920
921#ifdef USE_HCACHE
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 mutt_hcache_delete_record(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition: hcache.c:689
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:65
int pop_reconnect(struct Mailbox *m)
Reconnect and verify indexes if connection was lost.
Definition: lib.c:599
#define pop_query(adata, buf, buflen)
Definition: private.h:109
@ POP_DISCONNECTED
Disconnected from server.
Definition: private.h:51
static void pop_clear_cache(struct PopAccountData *adata)
Delete all cached messages.
Definition: pop.c:491
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition: pop.c:83
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition: pop.c:297
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: