diff options
author | Ben Sima <ben@bensima.com> | 2025-04-18 12:52:41 -0400 |
---|---|---|
committer | Ben Sima <ben@bensima.com> | 2025-04-18 12:52:41 -0400 |
commit | a6d62663e20fb5d1359845017787c85c4b10746f (patch) | |
tree | 3d949ed83abacb80c2ac0c50a6f52ef5087febb8 /fix-mail-duplicates.sh | |
parent | 7cf00fd9819f663cd411f1079cbbd22127ec7941 (diff) |
mail duplicates one-off script
Diffstat (limited to 'fix-mail-duplicates.sh')
-rwxr-xr-x | fix-mail-duplicates.sh | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/fix-mail-duplicates.sh b/fix-mail-duplicates.sh new file mode 100755 index 0000000..7803649 --- /dev/null +++ b/fix-mail-duplicates.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# fix-mail-duplicates.sh +# Usage: fix-mail-duplicates.sh /path/to/maildir 682 + +set -e + +# Check if arguments were provided +if [ $# -ne 2 ]; then + echo "Usage: $0 /path/to/maildir UID_NUMBER" + echo "Example: $0 ~/Mail/ben@bensima.com/Archive 682" + exit 1 +fi + +MAILDIR="$1" +UID_NUM="$2" + +# Validate the arguments +if [ ! -d "$MAILDIR" ]; then + echo "Error: Maildir '$MAILDIR' does not exist or is not a directory" + exit 1 +fi + +if ! [[ "$UID_NUM" =~ ^[0-9]+$ ]]; then + echo "Error: UID must be a number, got '$UID_NUM'" + exit 1 +fi + +echo "Looking for duplicate UID $UID_NUM in $MAILDIR..." + +# Find all files with the EXACT UID (using word boundaries) +DUPLICATE_FILES=$(find "$MAILDIR" -type f -name "*,U=$UID_NUM[,:]*") +FILE_COUNT=$(echo "$DUPLICATE_FILES" | wc -l) + +if [ "$FILE_COUNT" -le 1 ]; then + echo "No duplicates found. Nothing to fix." + exit 0 +fi + +echo "Found $FILE_COUNT files with the same UID $UID_NUM" + +# Get timestamps for each file to determine which is newer +declare -A FILE_TIMES +for f in $DUPLICATE_FILES; do + # Get the message Date: header if possible, otherwise use file time + if command -v formail >/dev/null 2>&1; then + DATE_HDR=$(formail -xDate: < "$f" 2>/dev/null) + if [ -n "$DATE_HDR" ]; then + # Convert to epoch seconds if possible + MSG_TIME=$(date -d "$DATE_HDR" +%s 2>/dev/null) + if [ $? -eq 0 ]; then + FILE_TIMES["$f"]="$MSG_TIME" + continue + fi + fi + fi + + # Fallback to file modification time + FILE_TIMES["$f"]=$(stat -c %Y "$f") +done + +# Find the oldest file (we'll keep its UID) +OLDEST_FILE="" +OLDEST_TIME=9999999999 +for f in "${!FILE_TIMES[@]}"; do + if [ "${FILE_TIMES[$f]}" -lt "$OLDEST_TIME" ]; then + OLDEST_TIME="${FILE_TIMES[$f]}" + OLDEST_FILE="$f" + fi +done + +echo "Keeping original UID on oldest file: $OLDEST_FILE" + +# Rename all newer files by removing the UID part +for f in $DUPLICATE_FILES; do + if [ "$f" != "$OLDEST_FILE" ]; then + # More precise sed pattern to avoid partial UID matches + NEW_NAME=$(echo "$f" | sed "s/,U=$UID_NUM\([,:]\)/, \1/" | sed "s/:2,/,/") + echo "Renaming newer duplicate:" + echo " From: $f" + echo " To: $NEW_NAME" + mv "$f" "$NEW_NAME" + fi +done + +echo "Fixed UID collision for UID $UID_NUM. Please run mbsync again." |