helpers (9217B)
1 #!/usr/bin/env zsh 2 # 3 # Jaro Mail, your humble and faithful electronic postman 4 # 5 # a tool to easily and privately handle your e-mail communication 6 # 7 # Copyleft (C) 2010-2015 Denis Roio <jaromil@dyne.org> 8 # 9 # This source code is free software; you can redistribute it and/or 10 # modify it under the terms of the GNU Public License as published by 11 # the Free Software Foundation; either version 3 of the License, or 12 # (at your option) any later version. 13 # 14 # This source code is distributed in the hope that it will be useful, 15 # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17 # Please refer to the GNU Public License for more details. 18 # 19 # You should have received a copy of the GNU Public License along with 20 # this source code; if not, write to: 21 # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 23 # start without options: auto 24 # read or compose depending if there is an argument that is an email 25 # or a folder to start with 26 27 # which mutt binary to use 28 mutt="mutt" 29 30 datestamp() { date '+%d%b%y' } 31 32 # remote leading and trailing spaces in a string taken from stdin 33 trim() { 34 sed -e 's/^[[:space:]]*//g ; s/[[:space:]]*\$//g' 35 } 36 37 # zmodload zsh/mapfile 38 printfile() { 39 print ${mapfile[$1]} 40 } 41 42 # extract all emails found in a text from stdin 43 # outputs them one per line 44 extract_emails() { 45 awk '{ for (i=1;i<=NF;i++) 46 if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) { 47 gsub(/<|>|,/ , "" , $i); print $i } }' 48 } 49 50 # zmodload zsh/regex 51 isemail() { 52 print "$1" | grep -q -E '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}' && return 0 53 return 1 54 } 55 56 ismailinglist() { 57 _head=`awk '{ print $0 } 58 /^$/ { exit }'` 59 [[ "$_head" =~ "List-Id" ]] \ 60 || [[ "$_head" =~ "X-BeenThere" ]] \ 61 || [[ "$_head" =~ "List-Post" ]] \ 62 || [[ "$_head" =~ "X-Mailman-Version" ]] \ 63 || [[ "$_head" =~ "Mailing-List" ]] \ 64 && return 0 65 return 1 66 } 67 68 # parses stdin and converts some characters to html 69 escape_html() { 70 sed -e ' 71 s/\&/\&/g 72 s/>/\>/g 73 s/</\</g 74 s/"/\"/g 75 ' 76 } 77 78 e_parse() { 79 _arg="" 80 # optional second argument limits parsing to header fields 81 [[ "$1" = "" ]] || [[ "$1" = "all" ]] || _arg="-x $1" 82 83 # use RFC822 parser in fetchaddr 84 e_parsed=`${WORKDIR}/bin/fetchaddr ${=_arg} -a` 85 86 for _p in ${(f)e_parsed}; do 87 _e="${(Q)_p[(ws:,:)1]:l}" 88 # check if an email address was found 89 isemail "$_e" || continue 90 # avoid duplicates 91 [[ "${(v)e_addr[$_e]}" = "" ]] || continue 92 93 # extract also the name using comma separator 94 _n="${(Q)_p[(ws:,:)2]}" 95 96 e_addr+=("$_e" "$_n") 97 func "parsed: $_n <$_e>" 98 done 99 100 # no emails found 101 [[ ${#e_addr} = 0 ]] && return 1 102 103 return 0 104 } 105 106 107 # short utility to print only mail headers 108 hdr() { 109 [[ -r "$1" ]] || { 110 error "hdr() called on non existing file: $1" 111 return 1 } 112 awk '{ print $0 } 113 /^$/ { exit }' "$1" 114 } 115 116 # short utility to print only mail body 117 body() { 118 { test -r "$1" } || { 119 error "body() called on non existing file: $1" 120 return 1 } 121 awk ' 122 BEGIN { head=1 } 123 /^$/ { head=0 } 124 { if(head==0) 125 print $0 126 else 127 next }' "$1" 128 } 129 130 save_replay() { 131 fn save_replay 132 _cmd="$1" 133 req=(_cmd) 134 ckreq || return 1 135 136 tee $MAILDIRS/cache/replay.$_cmd 137 [[ $? = 0 ]] && \ 138 ln -sf $MAILDIRS/cache/replay.$_cmd $MAILDIRS/cache/replay.last 139 return 0 140 } 141 142 replay() { 143 fn "replay $*" 144 145 arg=$1 146 147 if [[ "$arg" = "" ]]; then 148 149 if [[ -r $MAILDIRS/cache/replay.last ]]; then 150 notice "Replay last stdout from `stat -c %z $MAILDIRS/cache/replay.last`" 151 cat $MAILDIRS/cache/replay.last 152 return $? 153 else 154 # never run a command? 155 error "There is nothing to replay" 156 return 1 157 fi 158 159 elif [[ -r $MAILDIRS/cache/replay.$arg ]]; then 160 notice "Replay stdout of command '$arg' from `stat -c %z $MAILDIRS/cache/replay.last`" 161 cat $MAILDIRS/cache/replay.$arg 162 return $? 163 164 elif [[ "$arg" = "list" ]]; then 165 notice "Listing available replays:" 166 ls -l $MAILDIRS/cache/replay.* 167 return $? 168 else 169 error "Nothing to replay for command: $arg" 170 return 1 171 fi 172 return 1 173 } 174 175 ######### 176 ## Editor 177 # this part guesses what is the best editor already present on the system 178 # of course we have a preference for AutOrg, the editor from our suite 179 # however the default is nano if nothing else is choosen. 180 jarovim() { 181 fn jarovim 182 vim -c 'set fo=tcrq' -c 'set tw=72' \ 183 -c 'map <C-j> {gq}' -c 'imap <C-j> <esc>{gq}i' \ 184 "${@}" 185 return $? 186 } 187 188 edit_file() { 189 fn edit_file $* 190 _editor=${EDITOR:-vim} 191 _editor=${JARO_EDITOR:-$_editor} 192 req=(_editor) 193 ckreq || return 1 194 195 func "selected editor: $_editor" 196 case $_editor in 197 # refine settings for email 198 vi|vim) jarovim "$*"; return $? ;; 199 emacs) emacsclient "$*"; return $? ;; 200 *) ${=_editor} "$*"; return $? ;; 201 esac 202 203 # if we are here we need to guess 204 case $OS in 205 MAC) open -t $* ;; 206 GNU) 207 ps ax|grep '[e]macs' > /dev/null 208 if [ $? = 0 ]; then 209 emacsclient -a $* 210 elif command -v vim > /dev/null; then 211 jarovim $* 212 elif command -v nano > /dev/null; then 213 nano -m -S -Q ">" -I -E -D -T 4 -U -W -c -i -k -r 72 $* 214 else 215 error "No editor found, please configure the JARO_EDITOR environment variable." 216 fi 217 ;; 218 esac 219 return $? 220 } 221 222 ############## 223 ## Open a File 224 preview_file() { 225 case $OS in 226 GNU) 227 xdg-open $* 228 ;; 229 MAC) 230 open -g $* 231 ;; 232 esac 233 } 234 235 236 ######################### 237 ## check if we are online 238 is_online() { 239 func "Test if we are online" 240 { test "$FORCE" = "1" } && { 241 act "Internet check skipped (--force in use)" 242 return 0 243 } 244 _res=1 245 _host=${1:-8.8.8.8} 246 _port=${2:-NONE} 247 248 _mode=inet # or host 249 { test "$_port" = "NONE" } || { _mode=host } 250 251 case $_mode in 252 inet) 253 func "trying to ping ${_host}" 254 ping -c1 -n ${_host} 2>&1 > /dev/null 255 { test $? = 0 } || { 256 error "Internet seems unreachable" 257 act "Network connection is checked with a ping to 8.8.8.8" 258 act "if your network doesn't allows it to pass, use -f to force." 259 error "Operation aborted." 260 exit 1 261 } 262 act "Internet seems to be reachable" 263 ;; 264 host) 265 func "trying to connect ${_host} port ${_port}" 266 #busybox nc -w 16 -z ${_host} ${_port} > /dev/null 267 busybox nc -w 16 -z ${_host} ${_port} > /dev/null 268 { test $? = 0 } || { 269 error "Host unreachable: $_host" 270 act "Network connection is checked with 16s timeout" 271 act "if you want to bypass this check, use -f to force." 272 error "Operation aborted." 273 return 1 274 } 275 act "Host $_host responds on port $_port" 276 ;; 277 esac 278 return 0 279 } 280 281 282 human_size() { 283 [[ $1 -gt 0 ]] || { 284 error "human_size() called with invalid argument" 285 return 1 286 } 287 288 # we use the binary operation for speed 289 # shift right 10 is divide by 1024 290 291 # gigabytes 292 [[ $1 -gt 1073741824 ]] && { 293 print -n "$(( $1 >> 30 )) GB" 294 return 0 295 } 296 297 # megabytes 298 [[ $1 -gt 1048576 ]] && { 299 print -n "$(( $1 >> 20 )) MB" 300 return 0 301 } 302 # kilobytes 303 [[ $1 -gt 1024 ]] && { 304 print -n "$(( $1 >> 10 )) KB" 305 return 0 306 } 307 # bytes 308 print -n "$1 Bytes" 309 return 0 310 } 311 312 ###### 313 # CERT 314 # downloads and/or installs certificates 315 316 317 318 cert() { 319 320 act "Downloading all known certificates (needs Internet connectivity)" 321 322 # gmail) 323 cc=Equifax_Secure_Certificate_Authority 324 if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then 325 326 curl -o $MAILDIRS/certs/${cc}.pem \ 327 "https://www.geotrust.com/resources/root_certificates/certificates/${cc}.cer" 328 openssl x509 -in \ 329 $MAILDIRS/certs/${cc}.pem -fingerprint \ 330 -subject -issuer -serial -hash -noout 331 fi 332 notice "Google CA succesfully installed" 333 334 # dyne|autistici|freaknet) 335 cc=Autistici_Certificate_Authority 336 if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then 337 curl -o $MAILDIRS/certs/${cc}.pem \ 338 "http://ca.autistici.org/ca.pem" 339 openssl x509 -in \ 340 $MAILDIRS/certs/${cc}.pem \ 341 -fingerprint -subject -issuer -serial -hash -noout 342 fi 343 notice "Aut/Inv CA succesfully installed" 344 345 # riseup) 346 cc=RiseupCA 347 if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then 348 curl -o $MAILDIRS/certs/${cc}.pem "https://help.riseup.net/assets/43052/RiseupCA.pem" 349 openssl x509 -in \ 350 $MAILDIRS/certs/${cc}.pem \ 351 -fingerprint -subject -issuer -serial -hash -noout 352 fi 353 notice "Riseup CA succesfully installed" 354 355 act "refreshing certificates" 356 c_rehash $MAILDIRS/certs > /dev/null 357 if [ $? != 0 ]; then 358 error "Error refreshing certificates in $MAILDIRS/certs" 359 c_rehash $MAILDIRS/certs 360 fi 361 notice "Done importing most common certificates." 362 return 0 363 }