NeoMutt  2025-12-11-911-gd8d604
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 589 of file compress.c.

590{
591 if (!m->compress_info)
592 return MX_STATUS_ERROR;
593
594 struct CompressInfo *ci = m->compress_info;
595
596 if (!ci->cmd_close)
597 {
598 mutt_error(_("Can't sync a compressed file without a close-hook"));
599 return MX_STATUS_ERROR;
600 }
601
602 const struct MxOps *ops = ci->child_ops;
603 if (!ops)
604 return MX_STATUS_ERROR;
605
606 if (!lock_realpath(m, true))
607 {
608 mutt_error(_("Unable to lock mailbox"));
609 return MX_STATUS_ERROR;
610 }
611
612 enum MxStatus check = comp_mbox_check(m);
613 if (check != MX_STATUS_OK)
614 goto sync_cleanup;
615
616 check = ops->mbox_sync(m);
617 if (check != MX_STATUS_OK)
618 goto sync_cleanup;
619
620 if (!execute_command(m, ci->cmd_close, _("Compressing %s")))
621 {
622 check = MX_STATUS_ERROR;
623 goto sync_cleanup;
624 }
625
626 check = MX_STATUS_OK;
627
628sync_cleanup:
629 store_size(m);
631 return check;
632}
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:108
static void unlock_realpath(struct Mailbox *m)
Unlock the mailbox->realpath.
Definition compress.c:153
static bool execute_command(struct Mailbox *m, const struct Expando *exp, const char *progress)
Run a system command.
Definition compress.c:295
#define mutt_error(...)
Definition logging2.h:94
static enum MxStatus comp_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition compress.c:553
#define _(a)
Definition message.h:28
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_sync(), and mbox_close()
Definition mxapi.h:70
@ MX_STATUS_ERROR
An error occurred.
Definition mxapi.h:71
@ MX_STATUS_OK
No changes.
Definition mxapi.h:72
Private data for compress.
Definition lib.h:61
const struct MxOps * child_ops
callbacks of de-compressed file
Definition lib.h:66
struct Expando * cmd_close
close-hook command
Definition lib.h:63
void * compress_info
Compressed mbox module private data.
Definition mailbox.h:123
Definition mxapi.h:98
enum MxStatus(* mbox_sync)(struct Mailbox *m)
Definition mxapi.h:194
+ 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 849 of file mailbox.c.

850{
851 enum MxStatus check = maildir_check(m);
852 if (check == MX_STATUS_ERROR)
853 return check;
854
855 struct HeaderCache *hc = maildir_hcache_open(m);
856
857 struct Progress *progress = NULL;
858 if (m->verbose)
859 {
861 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
862 }
863
864 for (int i = 0; i < m->msg_count; i++)
865 {
866 progress_update(progress, i, -1);
867
868 struct Email *e = m->emails[i];
869 if (!maildir_sync_mailbox_message(m, e, hc))
870 {
871 progress_free(&progress);
872 goto err;
873 }
874 }
875 progress_free(&progress);
877
878 /* XXX race condition? */
879
881
882 /* adjust indices */
883
884 if (m->msg_deleted)
885 {
886 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
887 for (int i = 0, j = 0; i < m->msg_count; i++)
888 {
889 struct Email *e = m->emails[i];
890 if (!e)
891 break;
892
893 if (!e->deleted || c_maildir_trash)
894 e->index = j++;
895 }
896 }
897
898 return check;
899
900err:
902 return MX_STATUS_ERROR;
903}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:216
struct HeaderCache * maildir_hcache_open(struct Mailbox *m)
Open the Header Cache.
Definition hcache.c:104
void maildir_hcache_close(struct HeaderCache **ptr)
Close the Header Cache.
Definition hcache.c:77
static enum MxStatus maildir_check(struct Mailbox *m)
Check for new mail.
Definition mailbox.c:546
void maildir_update_mtime(struct Mailbox *m)
Update our record of the Maildir modification time.
Definition mailbox.c:725
bool maildir_sync_mailbox_message(struct Mailbox *m, struct Email *e, struct HeaderCache *hc)
Save changes to the mailbox.
Definition message.c:315
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition lib.h:85
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:110
Header Cache.
Definition lib.h:87
int msg_count
Total number of messages.
Definition mailbox.h:90
struct Email ** emails
Array of Emails.
Definition mailbox.h:98
int msg_deleted
Number of deleted messages.
Definition mailbox.h:95
bool verbose
Display status messages?
Definition mailbox.h:119
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 1090 of file mbox.c.

1091{
1093 if (!adata)
1094 return MX_STATUS_ERROR;
1095
1096 struct Buffer *tempfile = NULL;
1097 char buf[32] = { 0 };
1098 int j;
1099 bool unlink_tempfile = false;
1100 bool need_sort = false; /* flag to resort mailbox if new mail arrives */
1101 int first = -1; /* first message to be written */
1102 LOFF_T offset; /* location in mailbox to write changed messages */
1103 struct stat st = { 0 };
1104 struct MUpdate *new_offset = NULL;
1105 struct MUpdate *old_offset = NULL;
1106 FILE *fp = NULL;
1107 struct Progress *progress = NULL;
1108 enum MxStatus rc = MX_STATUS_ERROR;
1109
1110 /* sort message by their position in the mailbox on disk */
1111 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
1112 if (c_sort != EMAIL_SORT_UNSORTED)
1113 {
1115 need_sort = true;
1116 }
1117
1118 /* need to open the file for writing in such a way that it does not truncate
1119 * the file, so use read-write mode. */
1120 adata->fp = freopen(mailbox_path(m), "r+", adata->fp);
1121 if (!adata->fp)
1122 {
1123 mx_fastclose_mailbox(m, false);
1124 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1125 goto fatal;
1126 }
1127
1129
1130 if (mbox_lock_mailbox(m, true, true) == -1)
1131 {
1133 mutt_error(_("Unable to lock mailbox"));
1134 goto bail;
1135 }
1136
1137 /* Check to make sure that the file hasn't changed on disk */
1138 enum MxStatus check = mbox_mbox_check(m);
1139 if ((check == MX_STATUS_NEW_MAIL) || (check == MX_STATUS_REOPENED))
1140 {
1141 /* new mail arrived, or mailbox reopened */
1142 rc = check;
1143 goto bail;
1144 }
1145 else if (check < 0)
1146 {
1147 goto fatal;
1148 }
1149
1150 /* Create a temporary file to write the new version of the mailbox in. */
1151 tempfile = buf_pool_get();
1152 buf_mktemp(tempfile);
1153 int fd = open(buf_string(tempfile), O_WRONLY | O_EXCL | O_CREAT, 0600);
1154 if ((fd == -1) || !(fp = fdopen(fd, "w")))
1155 {
1156 if (fd != -1)
1157 {
1158 close(fd);
1159 unlink_tempfile = true;
1160 }
1161 mutt_error(_("Could not create temporary file"));
1162 goto bail;
1163 }
1164 unlink_tempfile = true;
1165
1166 /* find the first deleted/changed message. we save a lot of time by only
1167 * rewriting the mailbox from the point where it has actually changed. */
1168 int i = 0;
1169 for (; (i < m->msg_count) && !m->emails[i]->deleted &&
1170 !m->emails[i]->changed && !m->emails[i]->attach_del;
1171 i++)
1172 {
1173 }
1174 if (i == m->msg_count)
1175 {
1176 /* this means m->changed or m->msg_deleted was set, but no
1177 * messages were found to be changed or deleted. This should
1178 * never happen, is we presume it is a bug in neomutt. */
1179 mutt_error(_("sync: mbox modified, but no modified messages (report this bug)"));
1180 mutt_debug(LL_DEBUG1, "no modified messages\n");
1181 goto bail;
1182 }
1183
1184 /* save the index of the first changed/deleted message */
1185 first = i;
1186 /* where to start overwriting */
1187 offset = m->emails[i]->offset;
1188
1189 /* the offset stored in the header does not include the MMDF_SEP, so make
1190 * sure we seek to the correct location */
1191 if (m->type == MUTT_MMDF)
1192 offset -= (sizeof(MMDF_SEP) - 1);
1193
1194 /* allocate space for the new offsets */
1195 new_offset = MUTT_MEM_CALLOC(m->msg_count - first, struct MUpdate);
1196 old_offset = MUTT_MEM_CALLOC(m->msg_count - first, struct MUpdate);
1197
1198 if (m->verbose)
1199 {
1201 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
1202 }
1203
1204 for (i = first, j = 0; i < m->msg_count; i++)
1205 {
1206 progress_update(progress, i, i / (m->msg_count / 100 + 1));
1207 /* back up some information which is needed to restore offsets when
1208 * something fails. */
1209
1210 old_offset[i - first].valid = true;
1211 old_offset[i - first].hdr = m->emails[i]->offset;
1212 old_offset[i - first].body = m->emails[i]->body->offset;
1213 old_offset[i - first].lines = m->emails[i]->lines;
1214 old_offset[i - first].length = m->emails[i]->body->length;
1215
1216 if (!m->emails[i]->deleted)
1217 {
1218 j++;
1219
1220 if (m->type == MUTT_MMDF)
1221 {
1222 if (fputs(MMDF_SEP, fp) == EOF)
1223 {
1224 mutt_perror("%s", buf_string(tempfile));
1225 goto bail;
1226 }
1227 }
1228
1229 /* save the new offset for this message. we add 'offset' because the
1230 * temporary file only contains saved message which are located after
1231 * 'offset' in the real mailbox */
1232 new_offset[i - first].hdr = ftello(fp) + offset;
1233
1234 struct Message *msg = mx_msg_open(m, m->emails[i]);
1235 const int rc2 = mutt_copy_message(fp, m->emails[i], msg, MUTT_CM_UPDATE,
1237 mx_msg_close(m, &msg);
1238 if (rc2 != 0)
1239 {
1240 mutt_perror("%s", buf_string(tempfile));
1241 goto bail;
1242 }
1243
1244 /* Since messages could have been deleted, the offsets stored in memory
1245 * will be wrong, so update what we can, which is the offset of this
1246 * message, and the offset of the body. If this is a multipart message,
1247 * we just flush the in memory cache so that the message will be reparsed
1248 * if the user accesses it later. */
1249 new_offset[i - first].body = ftello(fp) - m->emails[i]->body->length + offset;
1250 mutt_body_free(&m->emails[i]->body->parts);
1251
1252 if (m->type == MUTT_MMDF)
1253 {
1254 if (fputs(MMDF_SEP, fp) == EOF)
1255 {
1256 mutt_perror("%s", buf_string(tempfile));
1257 goto bail;
1258 }
1259 }
1260 else
1261 {
1262 if (fputs(MBOX_SEP, fp) == EOF)
1263 {
1264 mutt_perror("%s", buf_string(tempfile));
1265 goto bail;
1266 }
1267 }
1268 }
1269 }
1270
1271 if (mutt_file_fclose(&fp) != 0)
1272 {
1273 mutt_debug(LL_DEBUG1, "mutt_file_fclose (&) returned non-zero\n");
1274 mutt_perror("%s", buf_string(tempfile));
1275 goto bail;
1276 }
1277
1278 /* Save the state of this folder. */
1279 if (stat(mailbox_path(m), &st) == -1)
1280 {
1281 mutt_perror("%s", mailbox_path(m));
1282 goto bail;
1283 }
1284
1285 unlink_tempfile = false;
1286
1287 fp = mutt_file_fopen(buf_string(tempfile), "r");
1288 if (!fp)
1289 {
1291 mx_fastclose_mailbox(m, false);
1292 mutt_debug(LL_DEBUG1, "unable to reopen temp copy of mailbox!\n");
1293 mutt_perror("%s", buf_string(tempfile));
1294 FREE(&new_offset);
1295 FREE(&old_offset);
1296 goto fatal;
1297 }
1298
1299 if (!mutt_file_seek(adata->fp, offset, SEEK_SET) || /* seek the append location */
1300 /* do a sanity check to make sure the mailbox looks ok */
1301 !fgets(buf, sizeof(buf), adata->fp) ||
1302 ((m->type == MUTT_MBOX) && !mutt_str_startswith(buf, "From ")) ||
1303 ((m->type == MUTT_MMDF) && !mutt_str_equal(MMDF_SEP, buf)))
1304 {
1305 mutt_debug(LL_DEBUG1, "message not in expected position\n");
1306 mutt_debug(LL_DEBUG1, " LINE: %s\n", buf);
1307 i = -1;
1308 }
1309 else
1310 {
1311 if (!mutt_file_seek(adata->fp, offset, SEEK_SET)) /* return to proper offset */
1312 {
1313 i = -1;
1314 }
1315 else
1316 {
1317 /* copy the temp mailbox back into place starting at the first
1318 * change/deleted message */
1319 if (m->verbose)
1320 mutt_message(_("Committing changes..."));
1321 i = mutt_file_copy_stream(fp, adata->fp);
1322
1323 if (ferror(adata->fp))
1324 i = -1;
1325 }
1326 if (i >= 0)
1327 {
1328 m->size = ftello(adata->fp); /* update the mailbox->size of the mailbox */
1329 if ((m->size < 0) || (ftruncate(fileno(adata->fp), m->size) != 0))
1330 {
1331 i = -1;
1332 mutt_debug(LL_DEBUG1, "ftruncate() failed\n");
1333 }
1334 }
1335 }
1336
1339
1340 if ((mutt_file_fclose(&adata->fp) != 0) || (i == -1))
1341 {
1342 /* error occurred while writing the mailbox back, so keep the temp copy around */
1343
1344 struct Buffer *savefile = buf_pool_get();
1345
1346 const char *const c_tmp_dir = cs_subset_path(NeoMutt->sub, "tmp_dir");
1347 buf_printf(savefile, "%s/neomutt.%s-%s-%u", NONULL(c_tmp_dir),
1348 NONULL(NeoMutt->username), NONULL(ShortHostname), (unsigned int) getpid());
1349 rename(buf_string(tempfile), buf_string(savefile));
1351 mx_fastclose_mailbox(m, false);
1352 pretty_mailbox(savefile);
1353 mutt_error(_("Write failed! Saved partial mailbox to %s"), buf_string(savefile));
1354 buf_pool_release(&savefile);
1355 FREE(&new_offset);
1356 FREE(&old_offset);
1357 goto fatal;
1358 }
1359
1360 /* Restore the previous access/modification times */
1361 mbox_reset_atime(m, &st);
1362
1363 /* reopen the mailbox in read-only mode */
1364 adata->fp = mbox_open_readwrite(m);
1365 if (!adata->fp)
1366 {
1367 adata->fp = mbox_open_readonly(m);
1368 }
1369 if (!adata->fp)
1370 {
1371 unlink(buf_string(tempfile));
1373 mx_fastclose_mailbox(m, false);
1374 mutt_error(_("Fatal error! Could not reopen mailbox!"));
1375 FREE(&new_offset);
1376 FREE(&old_offset);
1377 goto fatal;
1378 }
1379
1380 /* update the offsets of the rewritten messages */
1381 for (i = first, j = first; i < m->msg_count; i++)
1382 {
1383 if (!m->emails[i]->deleted)
1384 {
1385 m->emails[i]->offset = new_offset[i - first].hdr;
1386 m->emails[i]->body->hdr_offset = new_offset[i - first].hdr;
1387 m->emails[i]->body->offset = new_offset[i - first].body;
1388 m->emails[i]->index = j++;
1389 }
1390 }
1391 FREE(&new_offset);
1392 FREE(&old_offset);
1393 unlink(buf_string(tempfile)); /* remove partial copy of the mailbox */
1394 buf_pool_release(&tempfile);
1396
1397 const bool c_check_mbox_size = cs_subset_bool(NeoMutt->sub, "check_mbox_size");
1398 if (c_check_mbox_size)
1399 {
1400 struct Mailbox *m_tmp = mailbox_find(mailbox_path(m));
1401 if (m_tmp && !m_tmp->has_new)
1402 mailbox_update(m_tmp);
1403 }
1404
1405 progress_free(&progress);
1406 return 0; /* signal success */
1407
1408bail: /* Come here in case of disaster */
1409
1410 mutt_file_fclose(&fp);
1411
1412 if (tempfile && unlink_tempfile)
1413 unlink(buf_string(tempfile));
1414
1415 /* restore offsets, as far as they are valid */
1416 if ((first >= 0) && old_offset)
1417 {
1418 for (i = first; (i < m->msg_count) && old_offset[i - first].valid; i++)
1419 {
1420 m->emails[i]->offset = old_offset[i - first].hdr;
1421 m->emails[i]->body->hdr_offset = old_offset[i - first].hdr;
1422 m->emails[i]->body->offset = old_offset[i - first].body;
1423 m->emails[i]->lines = old_offset[i - first].lines;
1424 m->emails[i]->body->length = old_offset[i - first].length;
1425 }
1426 }
1427
1428 /* this is ok to call even if we haven't locked anything */
1430
1432 FREE(&new_offset);
1433 FREE(&old_offset);
1434
1435 adata->fp = freopen(mailbox_path(m), "r", adata->fp);
1436 if (!adata->fp)
1437 {
1438 mutt_error(_("Could not reopen mailbox"));
1439 mx_fastclose_mailbox(m, false);
1440 goto fatal;
1441 }
1442
1444 if (need_sort)
1445 {
1446 /* if the mailbox was reopened, the thread tree will be invalid so make
1447 * sure to start threading from scratch. */
1449 }
1450
1451fatal:
1452 buf_pool_release(&tempfile);
1453 progress_free(&progress);
1454 return rc;
1455}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
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:168
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
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_email.c:920
@ MUTT_CM_UPDATE
Update structs on sync.
Definition copy_email.h:46
@ CH_UPDATE
Update the status and x-status fields?
Definition copy_email.h:66
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ CH_FROM
Retain the "From " message separator?
Definition copy_email.h:70
void mailbox_update(struct Mailbox *m)
Get the mailbox's current size.
Definition mailbox.c:214
void mailbox_changed(struct Mailbox *m, enum NotifyMailbox action)
Notify observers of a change to a Mailbox.
Definition mailbox.c:232
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:183
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:184
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
void mutt_sort_unsorted(struct Mailbox *m)
Sort emails by their disk order.
Definition sort.c:448
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_UNSORTED
Sort by the order the messages appear in the mailbox.
Definition sort.h:64
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
char * ShortHostname
Short version of the hostname.
Definition globals.c:36
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
static enum MxStatus mbox_mbox_check(struct Mailbox *m)
Check for new mail - Implements MxOps::mbox_check() -.
Definition mbox.c:956
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define MMDF_SEP
Definition lib.h:63
static int mbox_lock_mailbox(struct Mailbox *m, bool excl, bool retry)
Lock a mailbox.
Definition mbox.c:136
static struct MboxAccountData * mbox_adata_get(struct Mailbox *m)
Get the private data associated with a Mailbox.
Definition mbox.c:121
static FILE * mbox_open_readwrite(struct Mailbox *m)
Open an mbox read-write.
Definition mbox.c:829
static FILE * mbox_open_readonly(struct Mailbox *m)
Open an mbox read-only.
Definition mbox.c:844
static void mbox_unlock_mailbox(struct Mailbox *m)
Unlock a mailbox.
Definition mbox.c:160
void mbox_reset_atime(struct Mailbox *m, struct stat *st)
Reset the access time on the mailbox file.
Definition mbox.c:774
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
#define MBOX_SEP
Definition mx.h:69
@ MX_STATUS_REOPENED
Mailbox was reopened.
Definition mxapi.h:75
@ MX_STATUS_NEW_MAIL
New mail received in Mailbox.
Definition mxapi.h:73
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
void mutt_sig_block(void)
Block signals during critical operations.
Definition signal.c:227
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition signal.c:245
#define NONULL(x)
Definition string2.h:44
void * adata
Private data (for Mailbox backends)
Definition account.h:42
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
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:81
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:99
Store of new offsets, used by mutt_sync_mailbox()
Definition mbox.c:65
long lines
Number of lines.
Definition mbox.c:69
LOFF_T hdr
Header offset.
Definition mbox.c:67
LOFF_T length
Total length.
Definition mbox.c:70
LOFF_T body
Body offset.
Definition mbox.c:68
bool valid
Is this entry valid?
Definition mbox.c:66
A mailbox.
Definition mailbox.h:81
bool has_new
Mailbox has new mail.
Definition mailbox.h:87
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
off_t size
Size of the Mailbox.
Definition mailbox.h:86
Mbox-specific Account data -.
Definition lib.h:50
FILE * fp
Mailbox file.
Definition lib.h:51
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
char * username
User's login name.
Definition neomutt.h:56
#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 1067 of file mh.c.

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

2566{
2567 struct NntpMboxData *mdata = m->mdata;
2568
2569 /* check for new articles */
2570 mdata->adata->check_time = 0;
2571 enum MxStatus check = check_mailbox(m);
2572 if (check != MX_STATUS_OK)
2573 return check;
2574
2575#ifdef USE_HCACHE
2576 mdata->last_cached = 0;
2577 struct HeaderCache *hc = nntp_hcache_open(mdata);
2578#endif
2579
2580 for (int i = 0; i < m->msg_count; i++)
2581 {
2582 struct Email *e = m->emails[i];
2583 if (!e)
2584 break;
2585
2586 char buf[16] = { 0 };
2587
2588 snprintf(buf, sizeof(buf), ANUM_FMT, nntp_edata_get(e)->article_num);
2589 if (mdata->bcache && e->deleted)
2590 {
2591 mutt_debug(LL_DEBUG2, "mutt_bcache_del %s\n", buf);
2592 mutt_bcache_del(mdata->bcache, buf);
2593 }
2594
2595#ifdef USE_HCACHE
2596 if (hc && (e->changed || e->deleted))
2597 {
2598 if (e->deleted && !e->read)
2599 mdata->unread--;
2600 mutt_debug(LL_DEBUG2, "hcache_store_email %s\n", buf);
2601 hcache_store_email(hc, buf, strlen(buf), e, 0);
2602 }
2603#endif
2604 }
2605
2606#ifdef USE_HCACHE
2607 if (hc)
2608 {
2609 hcache_close(&hc);
2610 mdata->last_cached = mdata->last_loaded;
2611 }
2612#endif
2613
2614 /* save .newsrc entries */
2616 nntp_newsrc_update(mdata->adata);
2617 nntp_newsrc_close(mdata->adata);
2618 return MX_STATUS_OK;
2619}
int mutt_bcache_del(struct BodyCache *bcache, const char *id)
Delete a file from the Body Cache.
Definition bcache.c:274
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:683
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
struct HeaderCache * nntp_hcache_open(struct NntpMboxData *mdata)
Open newsgroup hcache.
Definition newsrc.c:709
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:64
static enum MxStatus check_mailbox(struct Mailbox *m)
Check current newsgroup for new articles.
Definition nntp.c:1490
bool read
Email is read.
Definition email.h:50
void * mdata
Driver specific data.
Definition mailbox.h:134
NNTP-specific Mailbox data -.
Definition mdata.h:34
anum_t last_cached
Last cached article.
Definition mdata.h:40
struct BodyCache * bcache
Body cache.
Definition mdata.h:50
struct NntpAccountData * adata
Account data.
Definition mdata.h:48
anum_t unread
Unread articles.
Definition mdata.h:41
anum_t last_loaded
Last loaded article.
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 2293 of file notmuch.c.

2294{
2295 struct NmMboxData *mdata = nm_mdata_get(m);
2296 if (!mdata)
2297 return MX_STATUS_ERROR;
2298
2299 enum MxStatus rc = MX_STATUS_OK;
2300 struct Progress *progress = NULL;
2301 char *url = mutt_str_dup(mailbox_path(m));
2302 bool changed = false;
2303
2304 mutt_debug(LL_DEBUG1, "nm: sync start\n");
2305
2306 if (m->verbose)
2307 {
2308 /* all is in this function so we don't use data->progress here */
2310 progress_set_message(progress, _("Writing %s..."), mailbox_path(m));
2311 }
2312
2313 struct HeaderCache *hc = nm_hcache_open(m);
2314
2315 /* Iterate through all messages, syncing flag changes to the underlying
2316 * maildir/mh files and updating the notmuch database for renames/deletes */
2317 int mh_sync_errors = 0;
2318 for (int i = 0; i < m->msg_count; i++)
2319 {
2320 char old_file[PATH_MAX], new_file[PATH_MAX];
2321 struct Email *e = m->emails[i];
2322 if (!e)
2323 break;
2324
2325 struct NmEmailData *edata = nm_edata_get(e);
2326 if (!edata)
2327 continue;
2328
2329 progress_update(progress, i, -1);
2330
2331 *old_file = '\0';
2332 *new_file = '\0';
2333
2334 if (edata->oldpath)
2335 {
2336 mutt_str_copy(old_file, edata->oldpath, sizeof(old_file));
2337 mutt_debug(LL_DEBUG2, "nm: fixing obsolete path '%s'\n", old_file);
2338 }
2339 else
2340 {
2341 email_get_fullpath(e, old_file, sizeof(old_file));
2342 }
2343
2344 /* Temporarily set mailbox path and type to the message's backing
2345 * maildir folder so maildir_sync_mailbox_message() can operate */
2346 buf_strcpy(&m->pathbuf, edata->folder);
2347 m->type = edata->type;
2348
2349 bool ok = maildir_sync_mailbox_message(m, e, hc);
2350 if (!ok)
2351 {
2352 /* Syncing file failed, query notmuch for an updated filepath
2353 * (another process may have moved the message on disk) */
2354 m->type = MUTT_NOTMUCH;
2355 notmuch_database_t *db = nm_db_get(m, true);
2356 if (db)
2357 {
2358 notmuch_message_t *msg = get_nm_message(db, e);
2359
2361
2362 buf_strcpy(&m->pathbuf, edata->folder);
2363 m->type = edata->type;
2364 ok = maildir_sync_mailbox_message(m, e, hc);
2365 m->type = MUTT_NOTMUCH;
2366 }
2367 nm_db_release(m);
2368 m->type = edata->type;
2369 }
2370
2371 /* Restore the virtual notmuch mailbox path */
2372 buf_strcpy(&m->pathbuf, url);
2373 m->type = MUTT_NOTMUCH;
2374
2375 if (!ok)
2376 {
2377 mh_sync_errors += 1;
2378 continue;
2379 }
2380
2381 /* If the message was deleted or its file was renamed (e.g. flag change),
2382 * update the notmuch database to reflect the new state */
2383 if (!e->deleted)
2384 email_get_fullpath(e, new_file, sizeof(new_file));
2385
2386 if (e->deleted || !mutt_str_equal(old_file, new_file))
2387 {
2388 if (e->deleted && (remove_filename(m, old_file) == 0))
2389 changed = true;
2390 else if (*new_file && *old_file && (rename_filename(m, old_file, new_file, e) == 0))
2391 changed = true;
2392 }
2393
2394 FREE(&edata->oldpath);
2395 }
2396
2397 if (mh_sync_errors > 0)
2398 {
2399 mutt_error(ngettext("Unable to sync %d message due to external mailbox modification",
2400 "Unable to sync %d messages due to external mailbox modification",
2401 mh_sync_errors),
2402 mh_sync_errors);
2403 rc = MX_STATUS_ERROR;
2404 }
2405
2406 buf_strcpy(&m->pathbuf, url);
2407 m->type = MUTT_NOTMUCH;
2408
2409 nm_db_release(m);
2410
2411 if (changed)
2412 {
2413 mdata->mtime.tv_sec = mutt_date_now();
2414 mdata->mtime.tv_nsec = 0;
2415 }
2416
2417 nm_hcache_close(&hc);
2418
2419 progress_free(&progress);
2420 FREE(&url);
2421 mutt_debug(LL_DEBUG1, "nm: .... sync done [rc=%d]\n", rc);
2422 return rc;
2423}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
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:586
#define PATH_MAX
Definition mutt.h:49
notmuch_database_t * nm_db_get(struct Mailbox *m, bool writable)
Get the Notmuch database.
Definition db.c:210
int nm_db_release(struct Mailbox *m)
Close the Notmuch database.
Definition db.c:245
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:230
static void sync_email_path_with_nm(struct Email *e, notmuch_message_t *msg)
Synchronize NeoMutt's Email path with notmuch.
Definition notmuch.c:1122
static notmuch_message_t * get_nm_message(notmuch_database_t *db, struct Email *e)
Find a Notmuch message.
Definition notmuch.c:1081
static int rename_filename(struct Mailbox *m, const char *old_file, const char *new_file, struct Email *e)
Rename the file.
Definition notmuch.c:1367
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:1303
static void nm_hcache_close(struct HeaderCache **ptr)
Close the header cache.
Definition notmuch.c:125
void * edata
Driver-specific data.
Definition email.h:74
struct Buffer pathbuf
Path of the Mailbox.
Definition mailbox.h:82
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
+ 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 873 of file pop.c.

874{
875 int i, j, rc = 0;
876 char buf[1024] = { 0 };
878#ifdef USE_HCACHE
879 struct HeaderCache *hc = NULL;
880#endif
881
882 adata->check_time = 0;
883
884 int num_deleted = 0;
885 for (i = 0; i < m->msg_count; i++)
886 {
887 if (m->emails[i]->deleted)
888 num_deleted++;
889 }
890
891 while (true)
892 {
893 if (pop_reconnect(m) < 0)
894 return MX_STATUS_ERROR;
895
896#ifdef USE_HCACHE
897 hc = pop_hcache_open(adata, mailbox_path(m));
898#endif
899
900 struct Progress *progress = NULL;
901 if (m->verbose)
902 {
903 progress = progress_new(MUTT_PROGRESS_WRITE, num_deleted);
904 progress_set_message(progress, _("Marking messages deleted..."));
905 }
906
907 for (i = 0, j = 0, rc = 0; (rc == 0) && (i < m->msg_count); i++)
908 {
909 struct PopEmailData *edata = pop_edata_get(m->emails[i]);
910 if (m->emails[i]->deleted && (edata->refno != -1))
911 {
912 j++;
913 progress_update(progress, j, -1);
914 snprintf(buf, sizeof(buf), "DELE %d\r\n", edata->refno);
915 rc = pop_query(adata, buf, sizeof(buf));
916 if (rc == 0)
917 {
918 mutt_bcache_del(adata->bcache, cache_id(edata->uid));
919#ifdef USE_HCACHE
920 hcache_delete_email(hc, edata->uid, strlen(edata->uid));
921#endif
922 }
923 }
924
925#ifdef USE_HCACHE
926 if (m->emails[i]->changed)
927 {
928 hcache_store_email(hc, edata->uid, strlen(edata->uid), m->emails[i], 0);
929 }
930#endif
931 }
932 progress_free(&progress);
933
934#ifdef USE_HCACHE
935 hcache_close(&hc);
936#endif
937
938 if (rc == 0)
939 {
940 mutt_str_copy(buf, "QUIT\r\n", sizeof(buf));
941 rc = pop_query(adata, buf, sizeof(buf));
942 }
943
944 if (rc == 0)
945 {
946 adata->clear_cache = true;
947 pop_clear_cache(adata);
948 adata->status = POP_DISCONNECTED;
949 return MX_STATUS_OK;
950 }
951
952 if (rc == -2)
953 {
954 mutt_error("%s", adata->err_msg);
955 return MX_STATUS_ERROR;
956 }
957 }
958}
int hcache_delete_email(struct HeaderCache *hc, const char *key, size_t keylen)
Multiplexor for StoreOps::delete_record.
Definition hcache.c:752
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:109
@ POP_DISCONNECTED
Disconnected from server.
Definition private.h:49
static void pop_clear_cache(struct PopAccountData *adata)
Delete all cached messages.
Definition pop.c:509
static const char * cache_id(const char *id)
Make a message-cache-compatible id.
Definition pop.c:85
static struct HeaderCache * pop_hcache_open(struct PopAccountData *adata, const char *path)
Open the header cache.
Definition pop.c:316
POP-specific Account data -.
Definition adata.h:37
bool clear_cache
Clear the cache.
Definition adata.h:49
time_t check_time
Last check time.
Definition adata.h:51
char err_msg[POP_CMD_RESPONSE]
Last error message.
Definition adata.h:57
unsigned int status
Connection status.
Definition adata.h:39
struct BodyCache * bcache
body cache
Definition adata.h:56
POP-specific Email data -.
Definition edata.h:32
+ Here is the call graph for this function: