#!/usr/bin/env zsh

set -e

dummyrun=

zparseopts -D -A opts n
(( ${+opts[-n]} )) && dummyrun=echo

top="${HOME}/Maildir/mail/archive"

makemaildir() {
    dir="$1"
    umask 077
    $dummyrun mkdir -p "${dir}/cur" "${dir}/new" "${dir}/tmp"
    $dummyrun chmod 0700 "${dir}/cur" "${dir}/new" "${dir}/tmp"
}

refile_file() {
    id="$1"
    src="$2"
    dst="$3"

    # If a refile or delete previously happened but the notmuch
    # database didn't notice it yet, the filename may be incorrect.
    if [ ! -f "${src}" ]; then
	echo "Source file not found: ${id} (${src})."
	return
    fi

    # Make the destination maildir if it doesn't exist.
    md="${top}/${dst}"
    if [ ! -d "${md}" ]; then
	makemaildir "${md}"
    fi

    f=$(basename "$src")
    new="${md}/new/${f}"

    # If the source and the destination are the same, there's no need
    # to move.
    if [ "${src}" = "${new}" ]; then
	echo "${id} already there!"
    else
	echo "${src} -> ${new}"
	$dummyrun mv "${src}" "${new}"
    fi
}

refile_id() {
    id="$1"
    dst="$2"

    notmuch search --exclude=false --output=files "${id}" | while read file; do
	# A file that is already in the archive shouldn't move.
	# nb: need quotes around these to STOP regular expression
	# matching.
	if [[ "${file#${top}}" != "${file}" ]]; then
	    echo "Already archived: ${file}."
	else
	    refile_file "${id}" "${file}" "${dst}"
	fi
    done
}

archive() {
    comment="$1"
    search="$2"
    target="$3"
    tags="$4"

    echo "${comment}:"

    # Messages that are tagged as inbox, deleted, refile or flagged are ignored.
    # Messages that are less than 7 days old are ignored.
    notmuch search --exclude=false --output=messages \
	"${search} AND NOT tag:inbox AND NOT tag:inbox2 AND NOT tag:inbox3 AND NOT tag:inbox4 AND NOT tag:inbox5 AND NOT tag:deleted AND NOT tag:refile AND NOT tag:flagged AND NOT date:7d..now" | while read id
    do
	refile_id "${id}" "${target}"
	if [ "${tags}" != "" ]; then
	    $dummyrun notmuch tag ${tags} "${id}"
	fi
    done
}

# An example of how to perform bulk archiving:
# for y in 2007 2008 2009 2010 2011 2012 2013; do
#     for m in 01 02 03 04 05 06 07 08 09 10 11 12; do
# 	archive "All Mail ${y}-${m}" "(folder:\".d.[Gmail].All Mail\" and date:${y}-${m}..${y}-${m})" "dme.org/archive/${y}-${m}"
#     done
# done

# archive "2011" "folder:.o.Archives.2011" "oracle.com/archive/2011-05"
# archive "2012" "folder:.o.Archives.2012" "oracle.com/archive/2012-03"
# archive "2013" "folder:.o.Archives.2013" "oracle.com/archive/2013-05"

# exit

dm=$(date +%Y-%m)

# Now that I use bcc: to save outgoing mail, move it around here.
archive "Sent mail (dme.org)" "(folder:.d.INBOX AND tag:sent)" "dme.org/outbox"
archive "Sent mail (oracle.com)" "(folder:.o.INBOX AND tag:sent)" "oracle.com/outbox"

# BugDB messages can be moved to the trash.
archive "BugDB" "(folder:.o.INBOX AND from:bugap_a@)" "oracle.com/trash/${dm}" "+trash"

# RSS messages can be moved to the trash.
archive "RSS" "folder:.d.rss" "dme.org/rss/${dm}" "+trash"
archive "RSS" "folder:.l.rss" "dme.org/rss/${dm}" "+trash"

# Simple archiving for everything inboxes.
archive "Inbox (dme.org)" "folder:.d.INBOX" "dme.org/archive/${dm}"
archive "Inbox (oracle.com)" "folder:.o.INBOX" "oracle.com/archive/${dm}"

# macOS and iOS clients sometimes move things to an archive.
archive "Archive (oracle.com)" "folder:.o.Archive" "oracle.com/archive/${dm}"

# Google uses the "all mail" approach.
#
# XXX dme: This doesn't work very well, because all of the messages
# here are also somewhere else.
#archive "All Mail (dme.org)" "folder:\".d.[Gmail].All Mail\"" "dme.org/archive/${dm}"

# Mailing lists:
for i in \
    arm-netbook fork gnus i3 notmuch orgmode \
		edk2.devel emacs.devel virtio.devel \
		debian.{arm,boot,devel,devel-announce,laptop} \
		freebsd.virtualization \
	 ; do
    # Convert maildir name to a folder:
    folder=${i//.//}
    archive "List: ${i}" "folder:.d.list.${i}" "dme.org/list/${folder}/${dm}"
done

# Update the database.
notmuch-new

# Commit any changes.
mail-commit archive "archive: Updated."
