You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

176 lines
6.6 KiB

  1. #!/bin/sh
  2. # - Syncs mail for all accounts, or a single account given as an argument.
  3. # - Displays a notification showing the number of new mails.
  4. # - Displays a notification for each new mail with its subject displayed.
  5. # - Runs notmuch to index new mail.
  6. # - This script can be set up as a cron job for automated mail syncing.
  7. # There are many arbitrary and ugly features in this script because it is
  8. # inherently difficult to pass environmental variables to cronjobs and other
  9. # issues. It also should at least be compatible with Linux (and maybe BSD) with
  10. # Xorg and MacOS as well.
  11. USAGE="Usage:\n\
  12. $(basename "$0") [-p] [-s <email-sybol>] [-S <mailbox-sybol>] <account> [<account>]\n\
  13. Arguments:
  14. account: name of account to sync, can be any number of accounts, including zero (which will lead to\n\
  15. all accounts being synced).\n\
  16. Options:
  17. -p: Force private mode (by default emails will be displayed with sender and title if fewer than 5).\n\
  18. This option will display only the mailbox and the number of emails, regardless of how many\n\
  19. there are.\n\
  20. -s: Symbol to use for emails (default \`📧\`).\n\
  21. Change to what you want to see or pass empty string for less eye-candy.\n\
  22. -S: Symbol to use for mailboxes (default \`📬\`).\n\
  23. Change to what you want to see or pass empty string for less eye-candy.\n\
  24. -h: displays help message."
  25. # Read Options:
  26. while getopts ":s:S:ph" flag
  27. do
  28. case "$flag" in
  29. s)
  30. mailsymbol="$OPTARG"
  31. ;;
  32. S)
  33. boxsymbol="$OPTARG"
  34. ;;
  35. p)
  36. private_mode="$OPTARG"
  37. ;;
  38. h)
  39. echo -e "$USAGE"
  40. exit 0
  41. ;;
  42. \?)
  43. echo "Invalid option: -$OPTARG" >&2
  44. exit 1
  45. ;;
  46. :)
  47. echo "Option -$OPTARG requires an argument." >&2
  48. exit 1
  49. ;;
  50. esac
  51. done
  52. # Shift pointer to read accounts:
  53. shift $((OPTIND - 1))
  54. # Set default symobols:
  55. if [[ -z ${mailsymbol+.} ]]; then
  56. mailsymbol="📧"
  57. fi
  58. if [[ -z ${boxsymbol+.} ]]; then
  59. boxsymbol="📬"
  60. fi
  61. # Run only if not already running in other instance
  62. pgrep mbsync >/dev/null && { echo "mbsync is already running."; exit ;}
  63. # First, we have to get the right variables for the mbsync file, the pass
  64. # archive, notmuch and the GPG home. This is done by searching common profile
  65. # files for variable assignments. This is ugly, but there are few options that
  66. # will work on the maximum number of machines.
  67. eval "$(grep -h -- \
  68. "^\s*\(export \)\?\(MBSYNCRC\|MPOPRC\|PASSWORD_STORE_DIR\|PASSWORD_STORE_GPG_OPTS\|NOTMUCH_CONFIG\|GNUPGHOME\|MAILSYNC_MUTE\|XDG_CONFIG_HOME\|XDG_DATA_HOME\)=" \
  69. "$HOME/.profile" "$HOME/.bash_profile" "$HOME/.zprofile" "$HOME/.config/zsh/.zprofile" "$HOME/.zshenv" \
  70. "$HOME/.config/zsh/.zshenv" "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.config/zsh/.zshrc" \
  71. "$HOME/.pam_environment" 2>/dev/null)"
  72. export GPG_TTY="$(tty)"
  73. [ -n "$MBSYNCRC" ] && alias mbsync="mbsync -c $MBSYNCRC" || MBSYNCRC="$HOME/.mbsyncrc"
  74. [ -n "$MPOPRC" ] || MPOPRC="$HOME/.config/mpop/config"
  75. lastrun="${XDG_CONFIG_HOME:-$HOME/.config}/mutt/.mailsynclastrun"
  76. # Settings are different for MacOS (Darwin) systems.
  77. case "$(uname)" in
  78. Darwin)
  79. notify() { osascript -e "display notification \"$2 in $1\" with title \"Account: $account\" subtitle \"$2 new mail(s)\"" && sleep 2 ;}
  80. messageinfo() { osascript -e "display notification with title \"$mailsymbol$from [$account]\" subtitle \"$subject\"" ;}
  81. ;;
  82. *)
  83. case "$(readlink -f /sbin/init)" in
  84. *systemd*|*openrc*) export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus ;;
  85. esac
  86. # remember if a display server is running since `ps` doesn't always contain a display
  87. pgrepoutput="$(pgrep -ax X\(\|org\|wayland\))"
  88. [ -z $displays ] && [ -d /tmp/.X11-unix ] && displays=$(cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done)
  89. notify() { [ -n "$pgrepoutput" ] && for x in ${displays:-0:}; do
  90. export DISPLAY=$x
  91. notify-send --app-name="mutt-wizard" "Account: $1" "$boxsymbol $2 new mail(s)."
  92. done ;}
  93. messageinfo() { [ -n "$pgrepoutput" ] && for x in ${displays:-0:}; do
  94. export DISPLAY=$x
  95. notify-send --app-name="mutt-wizard" "$mailsymbol$from [$account]" "$subject"
  96. done ;}
  97. ;;
  98. esac
  99. # Check account for new mail. Notify if there is new content.
  100. syncandnotify() {
  101. acc="$(echo "$account" | sed "s/.*\///")"
  102. if [ "$1" = "pop" ]; then
  103. # Handle POP
  104. mpop "$acc"
  105. else
  106. # Handle IMAP
  107. if [ -z "$opts" ]; then mbsync "$acc"; else mbsync "$opts" "$acc"; fi
  108. fi
  109. new=$(find\
  110. "$HOME/.local/share/mail/$acc/"[Ii][Nn][Bb][Oo][Xx]/new/ \
  111. "$HOME/.local/share/mail/$acc/"[Ii][Nn][Bb][Oo][Xx]/cur/ \
  112. -type f -newer "$lastrun" 2> /dev/null)
  113. newcount=$(echo "$new" | sed '/^\s*$/d' | wc -l)
  114. [ -z "$MAILSYNC_MUTE" ] && case 1 in
  115. $((newcount > 5)) ) notify "$acc" "$newcount" ;;
  116. $((newcount > 0)) ) for file in $new; do
  117. # Extract subject and sender from mail.
  118. from=$(awk '/^From: / && ++n ==1,/^\<.*\>:/' "$file" | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | awk '{ $1=""; if (NF>=3)$NF=""; print $0 }' | sed 's/^[[:blank:]]*[\"'\''\<]*//;s/[\"'\''\>]*[[:blank:]]*$//')
  119. subject=$(awk '/^Subject: / && ++n == 1,/^\<.*\>: / && ++i == 2' "$file" | head -n 1 | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | sed 's/^Subject: //' | sed 's/^{[[:blank:]]*[\"'\''\<]*//;s/[\"'\''\>]*[[:blank:]]*$//' | tr -d '\n')
  120. messageinfo &
  121. done ;;
  122. esac
  123. }
  124. # Sync accounts passed as argument or all.
  125. if [ "$#" -gt "0" ]; then
  126. for arg in "$@"; do
  127. [ "${arg%${arg#?}}" = '-' ] && opts="${opts:+${opts} }${arg}" && shift 1
  128. done
  129. accounts=$*
  130. fi
  131. [ -z "$imap_accounts" ] && [ -r "$MBSYNCRC" ] && imap_accounts="$(awk '/^Channel/ {print $2}' "$MBSYNCRC" 2>/dev/null)"
  132. [ -z "$pop_accounts" ] && [ -r "$MPOPRC" ] && pop_accounts="$(awk '/^account/ {print $2}' "$MPOPRC" 2>/dev/null)"
  133. # Parallelize multiple accounts
  134. for account in $imap_accounts; do
  135. if [ -n "$accounts" ]; then
  136. for tmp_ac in $accounts; do
  137. [ "$tmp_ac" = "$account" ] && syncandnotify "imap" &
  138. done
  139. continue
  140. fi
  141. syncandnotify "imap" &
  142. done
  143. for account in $pop_accounts; do
  144. if [ -n "$accounts" ]; then
  145. for tmp_ac in $accounts; do
  146. [ "$tmp_ac" = "$account" ] && syncandnotify "pop" &
  147. done
  148. continue
  149. fi
  150. syncandnotify "pop" &
  151. done
  152. wait
  153. notmuch new --quiet
  154. #Create a touch file that indicates the time of the last run of mailsync
  155. touch "$lastrun"