/ home / bin / aerc-claude-correct
aerc-claude-correct
 1  #!/usr/bin/env bash
 2  # Correct email content using Claude while preserving email encoding
 3  # Use --draft flag to save as draft instead of outputting to stdout
 4  
 5  set -euo pipefail
 6  
 7  SAVE_AS_DRAFT=false
 8  if [[ "${1:-}" == "--draft" ]]; then
 9      SAVE_AS_DRAFT=true
10  fi
11  
12  if ! command -v claude &> /dev/null; then
13      echo "Error: claude command not found" >&2
14      exit 1
15  fi
16  
17  TMPDIR=$(mktemp -d)
18  trap 'rm -rf "$TMPDIR"' EXIT
19  
20  cat > "$TMPDIR/email.raw"
21  
22  if ! command -v mshow &> /dev/null; then
23      echo "Error: mshow (from mblaze) not found" >&2
24      cat "$TMPDIR/email.raw"
25      exit 1
26  fi
27  
28  # Extract headers (everything before first empty line)
29  sed '/^$/q' "$TMPDIR/email.raw" > "$TMPDIR/headers"
30  
31  content_type=$(grep -i "^Content-Type:" "$TMPDIR/headers" | head -1 || echo "")
32  
33  if echo "$content_type" | grep -qi "multipart"; then
34      echo "Error: Multipart emails not yet supported" >&2
35      cat "$TMPDIR/email.raw"
36      exit 1
37  fi
38  
39  # Extract body (everything after first empty line)
40  sed '1,/^$/d' "$TMPDIR/email.raw" > "$TMPDIR/body.raw"
41  
42  encoding=$(grep -i "^Content-Transfer-Encoding:" "$TMPDIR/headers" | head -1 | cut -d: -f2 | tr -d ' \r' || echo "")
43  
44  # Decode body based on encoding
45  case "$encoding" in
46      "quoted-printable")
47          perl -pe 's/=([0-9A-Fa-f]{2})/chr(hex($1))/eg; s/=\r?\n//g' < "$TMPDIR/body.raw" > "$TMPDIR/body.decoded"
48          ;;
49      "base64")
50          base64 -d < "$TMPDIR/body.raw" > "$TMPDIR/body.decoded" 2>/dev/null || cp "$TMPDIR/body.raw" "$TMPDIR/body.decoded"
51          ;;
52      *)
53          cp "$TMPDIR/body.raw" "$TMPDIR/body.decoded"
54          ;;
55  esac
56  
57  prompt="Correct grammar and spelling errors. Output ONLY the corrected text - no explanations, no preamble, just the raw corrected content."
58  
59  if ! claude "$prompt" < "$TMPDIR/body.decoded" > "$TMPDIR/body.corrected" 2>&1; then
60      echo "Error: Claude correction failed" >&2
61      cat "$TMPDIR/email.raw"
62      exit 1
63  fi
64  
65  {
66      cat "$TMPDIR/headers"
67      echo ""
68      case "$encoding" in
69          "quoted-printable")
70              perl -pe 's/([^\x20-\x7E])/sprintf("=%02X", ord($1))/eg' < "$TMPDIR/body.corrected"
71              ;;
72          "base64")
73              base64 < "$TMPDIR/body.corrected"
74              ;;
75          *)
76              cat "$TMPDIR/body.corrected"
77              ;;
78      esac
79  } > "$TMPDIR/final.eml"
80  
81  if [[ "$SAVE_AS_DRAFT" == "true" ]]; then
82      if command -v aerc-save-draft &> /dev/null; then
83          cat "$TMPDIR/final.eml" | aerc-save-draft >&2
84          echo "Corrected email saved as draft" >&2
85          cat "$TMPDIR/final.eml"
86      else
87          echo "Error: aerc-save-draft not found" >&2
88          cat "$TMPDIR/final.eml"
89          exit 1
90      fi
91  else
92      cat "$TMPDIR/final.eml"
93  fi