static int restore_expunged(struct mailbox *mailbox, int mode, unsigned long *uids, unsigned nuids, time_t time_since, unsigned *numrestored, const char *extname) { struct index_record newrecord; annotate_state_t *astate = NULL; unsigned uidnum = 0; char oldfname[MAX_MAILBOX_PATH]; const char *fname; char *userid = mboxname_to_userid(mailbox->name); int r = 0; *numrestored = 0; struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_UNLINKED); const message_t *msg; while ((msg = mailbox_iter_step(iter))) { const struct index_record *record = msg_record(msg); /* still active */ if (!(record->internal_flags & FLAG_INTERNAL_EXPUNGED)) continue; if (mode == MODE_UID) { while (uidnum < nuids && record->uid > uids[uidnum]) uidnum++; if (uidnum >= nuids) continue; if (record->uid != uids[uidnum]) continue; /* otherwise we want this one */ } else if (mode == MODE_TIME) { if (record->last_updated < time_since) continue; /* otherwise we want this one */ } /* work on a copy */ newrecord = *record; /* duplicate the old filename */ fname = mailbox_record_fname(mailbox, record); xstrncpy(oldfname, fname, MAX_MAILBOX_PATH); /* bump the UID, strip the flags */ newrecord.uid = mailbox->i.last_uid + 1; newrecord.internal_flags &= ~FLAG_INTERNAL_EXPUNGED; if (unsetdeleted) newrecord.system_flags &= ~FLAG_DELETED; /* copy the message file */ fname = mailbox_record_fname(mailbox, &newrecord); r = mailbox_copyfile(oldfname, fname, 0); if (r) break; /* add the flag if requested */ if (addflag) { int userflag = 0; r = mailbox_user_flag(mailbox, addflag, &userflag, 1); if (r) break; newrecord.user_flags[userflag/32] |= 1<<(userflag&31); } /* and append the new record */ r = mailbox_append_index_record(mailbox, &newrecord); if (r) break; /* ensure we have an astate connected to the destination * mailbox, so that the annotation txn will be committed * when we close the mailbox */ r = mailbox_get_annotate_state(mailbox, newrecord.uid, &astate); if (r) break; /* and copy over any annotations */ r = annotate_msg_copy(mailbox, record->uid, mailbox, newrecord.uid, userid); if (r) break; if (verbose) printf("Unexpunged %s: %u => %u\n", extname, record->uid, newrecord.uid); /* mark the old one unlinked so we don't see it again */ struct index_record oldrecord = *record; oldrecord.internal_flags |= FLAG_INTERNAL_UNLINKED | FLAG_INTERNAL_NEEDS_CLEANUP; r = mailbox_rewrite_index_record(mailbox, &oldrecord); if (r) break; (*numrestored)++; } /* better get that seen to */ if (*numrestored) mailbox->i.options |= OPT_MAILBOX_NEEDS_UNLINK; mailbox_iter_done(&iter); free(userid); return r; }
static int restore_expunged(struct mailbox *mailbox, int mode, unsigned long *uids, unsigned nuids, time_t time_since, unsigned *numrestored, const char *mboxname) { uint32_t recno; uint32_t olduid; struct index_record record; unsigned uidnum = 0; char oldfname[MAX_MAILBOX_PATH]; const char *fname; int r = 0; *numrestored = 0; for (recno = 1; recno <= mailbox->i.num_records; recno++) { r = mailbox_read_index_record(mailbox, recno, &record); if (r) return r; /* still active */ if (!(record.system_flags & FLAG_EXPUNGED)) continue; /* no file, unrescuable */ if (record.system_flags & FLAG_UNLINKED) continue; if (mode == MODE_UID) { while (uidnum < nuids && record.uid > uids[uidnum]) uidnum++; if (uidnum >= nuids) continue; if (record.uid != uids[uidnum]) continue; /* otherwise we want this one */ } else if (mode == MODE_TIME) { if (record.last_updated < time_since) continue; /* otherwise we want this one */ } /* mark the old one unlinked so we don't see it again */ olduid = record.uid; record.system_flags |= FLAG_UNLINKED; r = mailbox_rewrite_index_record(mailbox, &record); if (r) return r; /* duplicate the old filename */ fname = mailbox_message_fname(mailbox, olduid); xstrncpy(oldfname, fname, MAX_MAILBOX_PATH); /* bump the UID, strip the flags */ record.uid = mailbox->i.last_uid + 1; record.system_flags &= ~(FLAG_UNLINKED|FLAG_EXPUNGED); if (unsetdeleted) record.system_flags &= ~FLAG_DELETED; /* copy the message file */ fname = mailbox_message_fname(mailbox, record.uid); r = mailbox_copyfile(oldfname, fname, 0); if (r) return r; /* and append the new record */ mailbox_append_index_record(mailbox, &record); if (verbose) printf("Unexpunged %s: %u => %u\n", mboxname, olduid, record.uid); (*numrestored)++; } return 0; }