EXPORTED void mailbox_archive(struct mailbox *mailbox,
                              mailbox_decideproc_t *decideproc, void *deciderock, unsigned flags)

{
    int r;
    int dirtycache = 0;
    const message_t *msg;
    struct index_record copyrecord;
    const char *srcname;
    const char *destname;
    char *spoolcache = xstrdup(mailbox_meta_fname(mailbox, META_CACHE));
    char *archivecache = xstrdup(mailbox_meta_fname(mailbox, META_ARCHIVECACHE));
    int differentcache = strcmp(spoolcache, archivecache);
    int object_storage_enabled = 0;
#if defined ENABLE_OBJECTSTORE
    object_storage_enabled = config_getswitch(IMAPOPT_OBJECT_STORAGE_ENABLED) ;
#endif
    free(spoolcache);
    free(archivecache);

    assert(mailbox_index_islocked(mailbox, 1));
    if (!decideproc) decideproc = &mailbox_should_archive;

    struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, flags);

    while ((msg = mailbox_iter_step(iter))) {
        const struct index_record *record = msg_record(msg);
        const char *action = NULL;
        if (decideproc(mailbox, record, deciderock)) {
            if (record->internal_flags & FLAG_INTERNAL_ARCHIVED)
                continue;
            copyrecord = *record;
            srcname = mailbox_spool_fname(mailbox, copyrecord.uid);
            destname = mailbox_archive_fname(mailbox, copyrecord.uid);

            /* load cache before changing the flags */
            r = mailbox_cacherecord(mailbox, &copyrecord);
            if (r) {
                xsyslog(LOG_ERR, "IOERROR: failed to read cache",
                                 "mailbox=<%s> record=<%u> error=<%s>",
                                 mailbox_name(mailbox), copyrecord.uid, error_message(r));
                continue;
            }
#if defined ENABLE_OBJECTSTORE
            if (object_storage_enabled){
                /* upload on the blob store */
                r = objectstore_put(mailbox, &copyrecord, srcname);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: objectstorage put failed",
                                     "mailbox=<%s> record=<%u> "
                                        "srcname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     srcname, error_message(r));
                    // didn't manage to store it, so remove the ARCHIVED flag
                    continue;
                }
                r = unlink (srcname);
                if (r < 0)
                    syslog(LOG_ERR, "unlink(%s) failed: %m", srcname);
            }
#endif
            copyrecord.internal_flags |= FLAG_INTERNAL_ARCHIVED | FLAG_INTERNAL_NEEDS_CLEANUP;
            action = "archive";
        }
        else
        {
            if (!(record->internal_flags & FLAG_INTERNAL_ARCHIVED))
                continue;
            copyrecord = *record;
            destname = mailbox_spool_fname(mailbox, copyrecord.uid);
            srcname = mailbox_archive_fname(mailbox, copyrecord.uid);

            /* load cache before changing the flags */
            r = mailbox_cacherecord(mailbox, &copyrecord);
            if (r) {
                xsyslog(LOG_ERR, "IOERROR: failed to read cache",
                                 "mailbox=<%s> record=<%u> error=<%s>",
                                 mailbox_name(mailbox), copyrecord.uid, error_message(r));
                continue;
            }

#if defined ENABLE_OBJECTSTORE
            if (object_storage_enabled){
                /* recover from the blob store */
                r = objectstore_get(mailbox, &copyrecord, destname);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: objectstorage get failed",
                                     "mailbox=<%s> record=<%u> "
                                        "destname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     destname, error_message(r));
                    continue;
                }
                objectstore_delete(mailbox, &copyrecord); // this should only lower ref count.
            }
#endif

            copyrecord.internal_flags &= ~FLAG_INTERNAL_ARCHIVED;
            copyrecord.internal_flags |= FLAG_INTERNAL_NEEDS_CLEANUP;
            action = "unarchive";
        }

        if (!object_storage_enabled){
            /* got a file to copy! */
            if (strcmp(srcname, destname)) {
                r = cyrus_copyfile(srcname, destname, COPYFILE_MKDIR|COPYFILE_KEEPTIME);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: copyfile failed",
                                     "mailbox=<%s> record=<%u> "
                                        "srcname=<%s> destname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     srcname, destname, error_message(r));
                    continue;
                }
            }
        }

        /* got a new cache record to write */
        if (differentcache)
        {
            dirtycache = 1;
            copyrecord.cache_offset = 0;
            if (mailbox_append_cache(mailbox, &copyrecord))
                continue;
        }

        /* rewrite the index record */
        copyrecord.silentupdate = 1;
        copyrecord.ignorelimits = 1;
        if (mailbox_rewrite_index_record(mailbox, &copyrecord))
            continue;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_UNLINK;

        if (config_auditlog) {
            char flagstr[FLAGMAPSTR_MAXLEN];
            flags_to_str(&copyrecord, flagstr);
            syslog(LOG_NOTICE, "auditlog: %s sessionid=<%s> mailbox=<%s> "
                   "uniqueid=<%s> uid=<%u> guid=<%s> cid=<%s> sysflags=<%s>",
                   action, session_id(), mailbox_name(mailbox), mailbox_uniqueid(mailbox),
                   copyrecord.uid, message_guid_encode(&copyrecord.guid),
                   conversation_id_encode(copyrecord.cid), flagstr);
        }
    }
    mailbox_iter_done(&iter);

    /* if we have stale cache records, we'll need a repack */
    if (dirtycache) {
        mailbox_index_dirty(mailbox);
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
    }
}
EXPORTED void mailbox_archive(struct mailbox *mailbox,
                              mailbox_decideproc_t *decideproc, void *deciderock, unsigned flags)

{
    int r;
    int dirtycache = 0;
    const message_t *msg;
    struct index_record copyrecord;
    const char *srcname;
    const char *destname;
    char *spoolcache = xstrdup(mailbox_meta_fname(mailbox, META_CACHE));
    char *archivecache = xstrdup(mailbox_meta_fname(mailbox, META_ARCHIVECACHE));
    int differentcache = strcmp(spoolcache, archivecache);
    int object_storage_enabled = 0;
#if defined ENABLE_OBJECTSTORE
    object_storage_enabled = config_getswitch(IMAPOPT_OBJECT_STORAGE_ENABLED) ;
#endif
    free(spoolcache);
    free(archivecache);

    assert(mailbox_index_islocked(mailbox, 1));
    if (!decideproc) decideproc = &mailbox_should_archive;

    struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, flags);

    while ((msg = mailbox_iter_step(iter))) {
        const struct index_record *record = msg_record(msg);
        const char *action = NULL;
        if (decideproc(mailbox, record, deciderock)) {
            if (record->internal_flags & FLAG_INTERNAL_ARCHIVED)
                continue;
            copyrecord = *record;
            srcname = mailbox_spool_fname(mailbox, copyrecord.uid);
            destname = mailbox_archive_fname(mailbox, copyrecord.uid);

             
            r = mailbox_cacherecord(mailbox, &copyrecord);
            if (r) {
                xsyslog(LOG_ERR, "IOERROR: failed to read cache",
                                 "mailbox=<%s> record=<%u> error=<%s>",
                                 mailbox_name(mailbox), copyrecord.uid, error_message(r));
                continue;
            }
#if defined ENABLE_OBJECTSTORE
            if (object_storage_enabled){
                 
                r = objectstore_put(mailbox, &copyrecord, srcname);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: objectstorage put failed",
                                     "mailbox=<%s> record=<%u> "
                                        "srcname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     srcname, error_message(r));
                     
                    continue;
                }
                r = unlink (srcname);
                if (r < 0)
                    syslog(LOG_ERR, "unlink(%s) failed: %m", srcname);
            }
#endif
            copyrecord.internal_flags |= FLAG_INTERNAL_ARCHIVED | FLAG_INTERNAL_NEEDS_CLEANUP;
            action = "archive";
        }
        else
        {
            if (!(record->internal_flags & FLAG_INTERNAL_ARCHIVED))
                continue;
            copyrecord = *record;
            destname = mailbox_spool_fname(mailbox, copyrecord.uid);
            srcname = mailbox_archive_fname(mailbox, copyrecord.uid);

             
            r = mailbox_cacherecord(mailbox, &copyrecord);
            if (r) {
                xsyslog(LOG_ERR, "IOERROR: failed to read cache",
                                 "mailbox=<%s> record=<%u> error=<%s>",
                                 mailbox_name(mailbox), copyrecord.uid, error_message(r));
                continue;
            }

#if defined ENABLE_OBJECTSTORE
            if (object_storage_enabled){
                 
                r = objectstore_get(mailbox, &copyrecord, destname);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: objectstorage get failed",
                                     "mailbox=<%s> record=<%u> "
                                        "destname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     destname, error_message(r));
                    continue;
                }
                objectstore_delete(mailbox, &copyrecord);  
            }
#endif

            copyrecord.internal_flags &= ~FLAG_INTERNAL_ARCHIVED;
            copyrecord.internal_flags |= FLAG_INTERNAL_NEEDS_CLEANUP;
            action = "unarchive";
        }

        if (!object_storage_enabled){
             
            if (strcmp(srcname, destname)) {
                r = cyrus_copyfile(srcname, destname, COPYFILE_MKDIR|COPYFILE_KEEPTIME);
                if (r) {
                    xsyslog(LOG_ERR, "IOERROR: copyfile failed",
                                     "mailbox=<%s> record=<%u> "
                                        "srcname=<%s> destname=<%s> error=<%s>",
                                     mailbox_name(mailbox), copyrecord.uid,
                                     srcname, destname, error_message(r));
                    continue;
                }
            }
        }

         
        if (differentcache)
        {
            dirtycache = 1;
            copyrecord.cache_offset = 0;
            if (mailbox_append_cache(mailbox, &copyrecord))
                continue;
        }

         
        copyrecord.silentupdate = 1;
        copyrecord.ignorelimits = 1;
        if (mailbox_rewrite_index_record(mailbox, &copyrecord))
            continue;
        mailbox->i.options |= OPT_MAILBOX_NEEDS_UNLINK;

        if (config_auditlog) {
            char flagstr[FLAGMAPSTR_MAXLEN];
            flags_to_str(&copyrecord, flagstr);
            syslog(LOG_NOTICE, "auditlog: %s sessionid=<%s> mailbox=<%s> "
                   "uniqueid=<%s> uid=<%u> guid=<%s> cid=<%s> sysflags=<%s>",
                   action, session_id(), mailbox_name(mailbox), mailbox_uniqueid(mailbox),
                   copyrecord.uid, message_guid_encode(&copyrecord.guid),
                   conversation_id_encode(copyrecord.cid), flagstr);
        }
    }
    mailbox_iter_done(&iter);

     
    if (dirtycache) {
        mailbox_index_dirty(mailbox);
        mailbox->i.options |= OPT_MAILBOX_NEEDS_REPACK;
    }
}