jaro (22894B)
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 # Copyright (C) 2010-2015 Dyne.org Foundation 8 # 9 # JaroMail is designed, written and maintained by Denis Roio <jaromil@dyne.org> 10 # 11 # This source code is free software; you can redistribute it and/or 12 # modify it under the terms of the GNU Public License as published by 13 # the Free Software Foundation; either version 3 of the License, or 14 # (at your option) any later version. 15 # 16 # This source code is distributed in the hope that it will be useful, 17 # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 19 # Please refer to the GNU Public License for more details. 20 # 21 # You should have received a copy of the GNU Public License along with 22 # this source code; if not, write to: 23 # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 25 PROGRAM=jaro-mail 26 VERSION=4.3-dev 27 DATE=Mar/2017 28 JAROMAILEXEC=$0 29 30 # default permission on files 31 umask 066 32 33 # honor quiet and debug flags as early as possible 34 if [[ ${@} == *-q* ]]; then QUIET=1; fi 35 if [[ ${@} == *-D* ]]; then DEBUG=1; fi 36 37 38 # check if we are inside the directory 39 if [ -r jaro/bin/jaro ]; then 40 MAILDIRS=`pwd` 41 # check if we are on OSX 42 elif [ -r /Applications/JaroMail.app ]; then 43 MAILDIRS="$HOME/Library/Application Support/JaroMail" 44 # else use GNU/Linux default 45 else 46 MAILDIRS=$HOME/Mail 47 fi 48 49 # end override 50 MAILDIRS=${JAROMAILDIR:-$MAILDIRS} 51 52 53 # check if we are testing from source 54 if [[ -r ../src/jaro ]]; then 55 WORKDIR="../src" 56 # check if we are on OSX 57 elif [[ -r /Applications/JaroMail.app/Contents/Resources/jaro ]]; then 58 WORKDIR="/Applications/JaroMail.app/Contents/Resources/jaro" 59 elif [[ -r /usr/share/jaromail/bin/jaro ]]; then 60 # use GNU/Linux default in usr 61 WORKDIR="/usr/share/jaromail" 62 else 63 # use GNU/Linux default in local 64 WORKDIR="/usr/local/share/jaromail" 65 fi 66 67 # env override 68 WORKDIR=${JAROWORKDIR:-$WORKDIR} 69 70 # load our zuper extension 71 # different load paths from inside source or installed 72 if [ "$WORKDIR" = "../src" ]; then 73 source $WORKDIR/zuper/zuper 74 else 75 source $WORKDIR/zlibs/zuper 76 fi 77 78 79 # what operating system are we in? use os_detect() 80 # simplifying modes of operation: GNU or MAC 81 case $(uname -o) in 82 GNU/Linux) OS=GNU 83 notice "Jaro Mail v${VERSION} running on GNU/Linux" ;; 84 85 Darwin) OS=MAC 86 notice "Jaro Mail v${VERSION} running on Mac/OSX" ;; 87 88 Cygwin) OS=WIN 89 notice "Jaro Mail v${VERSION} runing on MS/Win" ;; 90 91 *) OS=GNU # default 92 error "Running on an unknown operating system, assuming GNU" ;; 93 esac 94 95 96 97 # global variables 98 vars+=(DEBUG QUIET DRYRUN CALLMUTT MAILDIRS WORKDIR) 99 QUIET=${QUIET:-0} 100 DEBUG=${DEBUG:-0} 101 DRYRUN=${DRYRUN:-0} 102 CALLMUTT=${CALLMUTT:-1} 103 104 # use gnome-keyring for passwords on GNU systems 105 vars+=(PASS GNOMEKEY SECRET_TOOL PASSWORD_STORE_DIR) 106 PASS=${PASS:-0} 107 GNOMEKEY=${GNOMEKEY:-0} 108 SECRET_TOOL=${SECRET_TOOL:-0} 109 PASSWORD_STORE_DIR=${JARO_PASSWORD_STORE_DIR:-$MAILDIRS/.password-store} 110 111 # global variables for binaries called 112 vars+=(rm mkdir mutt SQL OS) 113 114 # load zsh modules 115 zmodload zsh/regex 116 zmodload zsh/mapfile 117 zmodload zsh/system 118 zmodload -F zsh/stat b:zstat 119 zmodload zsh/sched 120 121 ########################## 122 123 # SQL command 124 SQL=sqlite3 125 126 vars+=(PROGRAM global_quit) 127 global_quit=0 128 129 # global variable for account selection 130 vars+=(account account_type) 131 account=default 132 vars+=(list) 133 list=whitelist 134 135 # global variables for accounts 136 vars+=(name login imap imap_port smtp smtp_port protocol password auth accountopt) 137 arrs+=(folders exclude) 138 vars+=(host port type) 139 vars+=(my_hdr) 140 141 # global for server fingerprints 142 vars+=(fingerprint) 143 144 # global variables for addressbook 145 vars+=(hostname addressbook addressbook_tmp) 146 147 # global variables for email parsers 148 typeset -A e_addr 149 vars+=(e_parsed) 150 151 # global array for maildirs (filled by list_maildirs) 152 arrs+=(maildirs) 153 vars+=(last_deliver) 154 155 # stdin when read becomes globally accessible 156 vars+=(stdin bytesread) 157 stdin="" 158 bytesread=0 159 160 # global arrays for search results and mailpaths 161 # are all arrays of absolute paths 162 arrs+=(search_results mailpaths) 163 search_results=() 164 165 # global variable for mutt binary 166 vars+=(mutt pgpewrap dotlock) 167 168 # global variable for exit code 169 vars+=(exitcode) 170 # exitcode=0 171 172 # global variable for infos on imap folder 173 # format: name;num_of_messages;size_in_bytes 174 # last entry is grand_total_in_bytes ${imap_info[${#imap_info}]} 175 typeset -alU imap_info 176 177 # global variable for mutt options 178 vars+=(muttflags) 179 180 autoload colors; colors 181 182 # default addressbook 183 ADDRESSBOOK="$MAILDIRS/whitelist.abook" 184 185 # which command to use when creating dirs 186 mkdir="`command -v mkdir` -m 700 -p" 187 188 189 act "System in $WORKDIR" 190 191 PATH="$WORKDIR/bin:$PATH" 192 193 # load our ZLibs 194 if [ -d $WORKDIR/zlibs ]; then 195 # if testing from source load uncompiled libs 196 if [ "$WORKDIR" = "../src" ]; then 197 for z in `find $WORKDIR/zlibs -type f`; do 198 [[ "$z" =~ "zuper" ]] && continue 199 func "Loading zlib: ${z}" 200 source ${z} 201 done 202 else 203 fpath+=($WORKDIR/zlibs) 204 for z in `ls $WORKDIR/zlibs`; do 205 [[ "$z" =~ "zuper" ]] && continue 206 [[ "$z" =~ ".zwc" ]] && continue 207 func "Loading zlib: ${z}" 208 source $WORKDIR/zlibs/${z} 209 done 210 fi 211 212 func "full set of auxiliary functions loaded" 213 elif [[ $1 = source ]]; then 214 215 act "limited set of auxiliary functions sourced" 216 217 else 218 error "No ZLibs found in $WORKDIR/zlibs" 219 error "This installation of Jaro Mail is broken." 220 exit 1 221 fi 222 223 224 225 ########## 226 # complete 227 if [ "$WORKDIR" = "../src" ]; then 228 source $WORKDIR/zuper/zuper.init 229 else 230 source $WORKDIR/zlibs/zuper.init 231 fi 232 233 234 ACCOUNTS="$MAILDIRS/Accounts" 235 KEYRING="$MAILDIRS/Keyring" 236 237 case $OS in 238 GNU) 239 # backward compatibility tests for old paths in JaroMail <1.3 240 { test -d $WORKDIR/Accounts } && { test ! -d $ACCOUNTS } && { 241 act "Updating accounts location: $ACCOUNTS" 242 cp -ra $WORKDIR/Accounts $ACCOUNTS 243 } 244 245 { test -r "$WORKDIR/keyring" } && { test ! -r "$KEYRING" } && { 246 act "Updating keyring location: $KEYRING" 247 cp $WORKDIR/keyring "$KEYRING" 248 } 249 ;; 250 MAC) 251 ;; 252 esac 253 254 hostname=$(hostname) # gather the current hostname 255 256 [[ "$1" = "source" ]] || { # skip checks if just sourcing 257 258 # make sure we have a directory for account configurations 259 { test -d "$ACCOUNTS" } || { ${=mkdir} "$ACCOUNTS" } 260 261 # make sure we have a local keyring in case system-wide not found 262 # { test -r "$KEYRING" } || { create_keyring "$KEYRING" } 263 264 # make sure we have an addressbook 265 [[ -r "$ADDRESSBOOK" ]] || { create_addressbook "$ADDRESSBOOK" } 266 267 ${=mkdir} "$MAILDIRS" 268 269 # make sure the permissions are private 270 chmod 700 "$MAILDIRS" 271 272 ${=mkdir} "$MAILDIRS/logs" 273 # ${=mkdir} "$MAILDIRS/certs" 274 275 MUTTDIR="$MAILDIRS/.mutt" 276 { test -d "$MUTTDIR" } || { ${=mkdir} "$MUTTDIR" } 277 278 # make sure we have Filters.txt Applications.txt Mutt.txt 279 { test -r "$MAILDIRS/Filters.txt" } || { 280 cp "$WORKDIR/Filters.txt" "$MAILDIRS/Filters.txt" 281 notice "Default filters created" } 282 283 { test -r "$MAILDIRS/Applications.txt" } || { 284 cp "$WORKDIR/Applications.txt" "$MAILDIRS/Applications.txt" 285 notice "Default helper applications settings created" } 286 287 { test -r "$MAILDIRS/Mutt.txt" } || { 288 cp "$WORKDIR/Mutt.txt" "$MAILDIRS/Mutt.txt" 289 notice "Default Mutt configuration template created" } 290 291 } # if not sourcing 292 293 # binary programs recognition 294 check_bin() { 295 296 # required programs 297 for req in pinentry fetchmail gpg mutt msmtp; do 298 isfound $req 299 { test $? != 0 } && { 300 error "Cannot find $req. Please install it." 301 exit 1 302 } 303 done 304 305 # make sure a gnupg dir exists 306 { test -r $HOME/.gnupg/pubring.gpg } || { 307 ${=mkdir} $HOME/.gnupg 308 touch $HOME/.gnupg/pubring.gpg 309 touch $HOME/.gnupg/secring.gpg 310 } 311 312 # which find command to use 313 case $OS in 314 GNU) find="find -O3" ;; 315 MAC) find="gfind -O3" ;; 316 *) find="find" 317 esac 318 319 # which wipe command to use 320 if isfound wipe; then 321 rm="wipe -f -s -q -R /dev/urandom" 322 elif isfound srm; then 323 rm="srm -m" 324 else 325 rm="rm -f" 326 fi 327 func "Rm binary: $rm" 328 329 # which mutt binary to use 330 if isfound mutt; then 331 # system-wide 332 # TODO: check if this is also the location on Fedora 333 pgpewrap="${WORKDIR}/bin/gpgewrap" 334 dotlock="${WORKDIR}/bin/dotlock" 335 elif isfound mutt-jaro; then 336 # in-house compiled 337 mutt=mutt-jaro 338 pgpewrap=pgpewrap 339 dotlock=dotlock 340 else 341 error "Cannot find Mutt. Please install it." 342 exit 1 343 fi 344 func "Mutt binary: `command -v mutt`" 345 func "Notmuch binary: `command -v notmuch`" 346 func "Keyring set: $JARO_KEYRING" 347 if [[ "$JARO_KEYRING" == "" ]]; then 348 # check for pass, else fallback 349 if isfound pass; then 350 act "keyring in use: pass (auto-detected)" 351 [[ -d $PASSWORD_STORE_DIR ]] || 352 warning "the 'pass' keyring is found but not initialised" 353 354 PASS=1 355 356 # check if secret-tool is present else fallback to gnome-keyring 357 elif isfound secret-tool; then 358 act "keyring in use: secret-tool (auto-detected)" 359 SECRET_TOOL=1 360 else 361 ps ax | grep '[g]nome-keyring-daemon' > /dev/null 362 [[ $? = 0 ]] && { 363 act "keyring in use: gnome-keyring (auto-detected)" 364 GNOMEKEY=1 365 } 366 fi 367 368 else # JARO_KEYRING defined 369 370 case $JARO_KEYRING in 371 pass) 372 act "keyring in use: pass (set in JARO_KEYRING)" 373 export PASSWORD_STORE_DIR=${PASSWORD_STORE_DIR:-$HOME/.password-store} 374 [[ -d $PASSWORD_STORE_DIR ]] || { 375 error "the 'pass' keyring is found but not initialised" 376 error "run 'pass init your-gpg-id'" 377 } 378 PASS=1 ;; 379 secret-tool) 380 act "keyring in use: secret-tool (set in JARO_KEYRING)" 381 SECRET_TOOL=1 ;; 382 gnome-keyring) 383 act "keyring in use: gnome-keyring (set in JARO_KEYRING)" 384 GNOMEKEY=1 ;; 385 esac 386 387 fi 388 389 390 return 0 391 } 392 393 394 usage() { 395 cat <<EOF | more 396 Jaro Mail $VERSION - your humble and faithful electronic postman 397 398 Synopsis: jaro [options] [command] [command-options] 399 400 Main commands: 401 402 fetch download unread emails from [account] 403 send send all mails queued in the outbox 404 peek look into the [account] mailbox without downloading 405 index build or update the search index for all maildirs 406 search search maildirs or addressbook for expressions 407 408 Options: 409 410 -a use a particular [account] instead of default 411 -l set [abook] in use, 'whitelist' is default 412 -n dry run, show operations without executing them 413 -q run quietly without printing information 414 -D print debugging information at runtime 415 -v version information for this tool 416 -h print this help 417 418 == Addressbook commands (use -l to indicate which addressbook) 419 a pipe | in front indicate they take an email body from stdin 420 421 abook edit the [abook] using the console editor 422 423 extract list addresses of all recipients or senders found in: 424 maildir, search expr, vcard, gnupg keyring or pubkey 425 426 |import read address list from stdin into addressbook or group 427 (the output of extract commands can be piped to import) 428 429 430 == Operational commands (use -a to indicate [account]) 431 432 fetch downloads emails locally from [account] 433 434 send send all outbox/ queue via the [account]'s smtp 435 436 peek interactive connection to an [account]'s imap folder 437 (takes folder names as argument, default is INBOX) 438 439 passwd set [account]'s passwords in the OS native keyring 440 441 |queue read a mail from stdin and queue it in outbox/ for sending 442 443 |smtp read a mail from stdin and send it via [accounts]'s smtp 444 445 446 == Storage commands 447 448 open open a maildir folder (can use -R for read-only) 449 450 backup move search results from a maildir to another one 451 (string or date range matches, can use -n for dry-run) 452 453 merge merge a source maildir into destination, then delete source 454 455 update updates all filter engine according to Filters.txt 456 (also generates Sieve format rules ready for server use) 457 458 filter process a maildir distributing emails according to Filters.txt 459 (if none specified, processes incoming/ - called by fetch) 460 461 For a complete introductory documentation, see the User Manual (PDF) 462 Website on <http://dyne.org/software/jaro-mail> 463 Report bugs to <https://github.com/dyne/JaroMail/issues> 464 EOF 465 } 466 467 typeset -A subcommands_opts 468 469 main() { 470 # zuper option parser 471 472 option_main=(a: -account=a l: -list=l q -quiet=q D -debug=D h -help=h v -version=v n -dry-run=n f -force=f) 473 474 option_subcommands[__empty]="R -readonly=R" 475 option_subcommands[compose]="" 476 option_subcommands[queue]="" 477 option_subcommands[fetch]="" 478 option_subcommands[send]="" 479 option_subcommands[peek]="R -readonly=R" 480 option_subcommands[open]="R -readonly=R" 481 482 option_subcommands[help]="" 483 484 option_subcommands[update]="" 485 486 option_subcommands[stat]="" 487 488 option_subcommands[index]="" 489 option_subcommands[search]="" 490 option_subcommands[alot]="" 491 option_subcommands[notmuch]="" 492 493 option_subcommands[addr]="" 494 option_subcommands[learn]="" 495 option_subcommands[forget]="" 496 497 option_subcommands[complete]="" 498 option_subcommands[isknown]="" 499 500 option_subcommands[list]="" 501 option_subcommands[extract]="" 502 option_subcommands[parse]="" 503 option_subcommands[header]="" 504 option_subcommands[headers]="" 505 506 option_subcommands[import]="" 507 option_subcommands[export]="" 508 option_subcommands[vcard]="" 509 option_subcommands[abook]="" 510 option_subcommands[new]="" 511 512 option_subcommands[vim]="" 513 option_subcommands[edit]="" 514 option_subcommands[preview]="" 515 516 option_subcommands[replay]="" 517 518 option_subcommands[remember]="" 519 520 option_subcommands[backup]="" 521 option_subcommands[rmdupes]="" 522 option_subcommands[merge]="" 523 option_subcommands[filter]="" 524 option_subcommands[deliver]="" 525 526 option_subcommands[passwd]="" 527 option_subcommands[askpass]="" 528 529 option_subcommands[source]="" 530 531 option_subcommands[isonline]="" 532 533 option_subcommands[init]="" 534 535 option_subcommands[imap]="" 536 537 option_subcommands[smtp]="" 538 539 option_subcommands[crypt]="" 540 option_subcommands[cryptsign]="" 541 542 option_subcommands[isml]="" 543 option_subcommands[ismd]="" 544 545 option.parse $* || return 1 546 func "subcommand: $subcommand" 547 548 # print out version 549 if option.is_set -v; then 550 cat $JAROMAILEXEC | awk '/^#/ {print $0 } !/^#/ {exit}' 551 echo 552 fi 553 554 { option.is_set -a } && { account=`option.value -a` } 555 { option.is_set -l } && { 556 if [[ "`option.value -l`" =~ "black" ]]; then 557 list=blacklist 558 elif [[ "`option.value -l`" =~ "white" ]]; then 559 list=whitelist 560 else 561 list=`option.value -l` 562 fi 563 ADDRESSBOOK="$MAILDIRS"/$list.abook 564 } 565 { option.is_set -h } && { usage; return 0 } 566 { option.is_set -v } && { 567 cat $JAROMAILEXEC | awk 'BEGIN { v=1 } !/^#/ { exit }' 568 return 0 569 } 570 { option.is_set -q } && { QUIET=1 } 571 { option.is_set -D } && { DEBUG=1; QUIET=0 572 func "All debug messages ON" } 573 { option.is_set -n } && { DRYRUN=1 574 act "Dry run, show operations without executing them." } 575 { option.is_set -R } && { muttflags+=" -R " } 576 { option.is_set -f } && { FORCE=1 } 577 578 # clean up options from param 579 # PARAM=(${PARAM// -? /}) 580 581 case "$subcommand" in 582 583 compose) stdin_compose ${option_params} 584 exitcode=$? 585 ;; 586 587 queue) stdin_queue ${option_params} 588 exitcode=$? 589 ;; 590 591 fetch) fetch ${option_params} && \ 592 update_filters && \ 593 filter_maildir incoming && \ 594 update_notmuch 595 ;; 596 597 send) send ${option_params} 598 exitcode=$? 599 ;; 600 601 peek) peek ${option_params} 602 exitcode=$? 603 ;; 604 605 remember) 606 deliver remember 607 exitcode=$? 608 ;; 609 610 replay) 611 replay ${option_params} 612 exitcode=$? 613 ;; 614 615 update|init) 616 [[ "$option_params" = "" ]] || { 617 for p in $option_params; do 618 [[ "$p" = "." ]] && p=$PWD 619 [[ -d $p ]] && MAILDIRS=$p 620 done 621 } 622 init_inbox 623 update_filters 624 update_sieve 625 update_notmuch 626 notice "Initialization completed in $MAILDIRS" 627 act "configure accounts in $MAILDIRS/Accounts" 628 ;; 629 630 help) usage ;; 631 632 index) nm_index 633 exitcode=$? 634 ;; 635 636 # notmuch search with file output 637 search) search ${option_params} 638 [[ $DRYRUN = 1 ]] || { 639 for i in ${search_results=}; do 640 print - "$i" 641 done 642 } | save_replay $subcommand 643 ;; 644 645 alot) alot_search ${option_params} ;; 646 647 notmuch) 648 notice "Command: notmuch ${option_params}" 649 nm ${option_params} | save_replay $subcommand 650 exitcode=$? 651 ;; 652 653 addr|list) search_addressbook ${option_params} 654 ;; 655 656 complete) complete ${option_params} 657 exitcode=$? 658 ;; 659 660 isknown) sender_isknown ${option_params} 661 exitcode=$? 662 ;; 663 664 learn) learn ${option_params} 665 exitcode=$? 666 ;; 667 668 import) import ${option_params} 669 exitcode=$? 670 ;; 671 672 "export") 673 export_vcard ${option_params} 674 ;; 675 676 abook) edit_abook ${option_params} 677 exitcode=$? 678 ;; 679 680 new) 681 new_account ${option_params} 682 exitcode=$? 683 ;; 684 685 stat*) stats ${option_params} | sort -n 686 exitcode=$? 687 ;; 688 689 edit|vim) edit_file ${option_params} ;; 690 open) x_mutt -f ${option_params} ;; 691 preview) preview_file ${option_params} ;; 692 693 mkdir) 694 DEBUG=1 maildirmake ${option_params} 695 exitcode=$? 696 ;; 697 698 copy) 699 maildir_shift ${option_params} cp 700 exitcode=$? 701 ;; 702 703 move) 704 maildir_shift ${option_params} mv 705 exitcode=$? 706 ;; 707 708 link) 709 maildir_shift ${option_params} ln 710 exitcode=$? 711 ;; 712 713 rmdupes) rmdupes ${option_params} ;; 714 merge) merge ${option_params} ;; 715 716 filter) 717 update_filters ${option_params} 718 [[ $? = 0 ]] || { 719 error "error updating filters, operation aborted." 720 break 721 } 722 filter_maildir ${option_params} | save_replay $subcommand 723 exitcode=$? 724 ;; 725 726 deliver) 727 deliver ${option_params} 728 exitcode=$? 729 ;; 730 731 passwd) read_account $account 732 host=${option_params:-$imap} 733 new_password ;; 734 735 # cert) cert ${option_params} ;; # was checking is_online 736 737 isonline) is_online ${option_params}; exitcode=$? ;; 738 739 740 'source') return 0 ;; 741 742 askpass) 743 read_account $account 744 ask_password 745 # shell escape special chars 746 print - "$password" | sed ' 747 s/\&/\\&/g 748 s/\$/\\$/g 749 s/ /\\ /g 750 s/;/\\;/g 751 s/\?/\\?/g 752 s/\*/\\*/g 753 ' 754 # TODO: verify if this works with all passwords 755 exitcode=$? 756 ;; 757 758 imap) 759 imapcmd="${option_params[(w)1]}" 760 case $imapcmd in 761 console) 762 read_account $account 763 host=${imap:-$host} 764 ask_password 765 func "$login $password" 766 cat <<EOF | run_imap_query 767 B00000 CAPABILITY 768 B00001 LOGIN "${login}" "${password}" 769 EOF 770 ;; 771 getsize) 772 read_account $account 773 host=${imap:-$host} 774 ask_password 775 bytes_total=`imap_get_size "$2"` 776 exitcode=$? 777 notice "Size of account $login on $imap" 778 act "$bytes_total bytes" 779 mib_total=$(( $bytes_total / 1048576 )) 780 act "$mib_total MB (MiB)" 781 ;; 782 listfolders) 783 read_account $account 784 host=${imap:-$host} 785 ask_password 786 folders=(`imap_list_folders`) 787 exitcode=$? 788 notice "List of folders for $login on $imap" 789 for f in $folders; do print - "$f"; done \ 790 | save_replay $subcommand | column 791 792 ;; 793 # interactive) 794 # read_account 795 # ask_password 796 # imap_interactive_shell 797 # exitcode=$? 798 # ;; 799 *) 800 error "imap needs a subcommand: getsize or listfolders" 801 ;; 802 esac 803 ;; 804 805 # list) 806 # list_abook ${option_params} 807 # exitcode=$? 808 # ;; 809 810 extract|parse) 811 extract_addresses ${option_params} \ 812 | save_replay $subcommand 813 exitcode=$? 814 ;; 815 816 header|headers) 817 extract_headers ${option_params} 818 exitcode=$? 819 ;; 820 821 smtp) 822 smtp_send ${option_params} 823 exitcode=$? 824 ;; 825 826 isml) 827 ismailinglist 828 [[ $? = 0 ]] && \ 829 notice "Email read from stdin is a mailinglist" 830 exitcode=$? 831 ;; 832 833 ismd) 834 maildircheck ${option_params} 835 [[ $? = 0 ]] && \ 836 notice "Directory is a maildir: ${option_params}" 837 exitcode=$? 838 ;; 839 840 __empty) # unknown command, pass it to autostart 841 func "no command, autostart" 842 func "subcommand: $subcommand" 843 read_account "$account" 844 if [[ "$subcommand" = "__empty" ]]; then 845 # open folder 846 if [[ "$option_params" = "" ]]; then 847 x_mutt -Z 848 else 849 x_mutt -f "$option_params" 850 fi 851 fi 852 exitcode=$? 853 ;; 854 855 __unknown:*) 856 # argument passed: determine if an email 857 subcommand=${subcommand[(ws@:@)2]} 858 func "subcommand: $subcommand" 859 read_account "$account" 860 if isemail "$subcommand"; then 861 notice "Composing message to: $*" 862 # its an email, TODO see if we have it in our addressbook 863 x_mutt $* 864 exitcode=0 865 # or a directory of file 866 elif maildircheck "$subcommand"; then 867 # is it a maildir? then open 868 x_mutt -f "$subcommand" 869 exitcode=$? 870 elif maildircheck "$MAILDIRS/$subcommand"; then 871 x_mutt -f "$MAILDIRS/$subcommand" 872 exitcode=$? 873 elif [[ -f "$subcommand" ]]; then 874 # is it a regular file? then ;attach it 875 x_mutt -a $* 876 exitcode=0 877 else 878 # just open; mutt on first unread folder 879 x_mutt 880 exitcode=$? 881 882 fi 883 ;; 884 esac 885 886 return $exitcode 887 } 888 889 890 check_bin 891 main $@ 892 # endgame NOERRORS 893 # return $exitcode