summaryrefslogtreecommitdiff
path: root/fix-mail-duplicates.sh
blob: 7803649aa0efa2de0b495d09815e0b095ce1c58b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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."