roundomo (6133B)
1 #!/usr/bin/env zsh 2 # 3 # Copyright (C) 2014-2015 Denis Roio <jaromil@dyne.org> 4 # 5 # This source code is free software; you can redistribute it and/or 6 # modify it under the terms of the GNU Public License as published by 7 # the Free Software Foundation; either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # This source code is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 # Please refer to the GNU Public License for more details. 14 # 15 # You should have received a copy of the GNU Public License along with 16 # this source code; if not, write to: 17 # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 19 REVISION="Feb/2015" 20 21 QUIET=0 22 DEBUG=0 23 24 SCRIPT=$0 25 26 TEST=0 27 28 # export ROUNDOMO to env with path to the installation 29 # else start it from inside the dir with ./dowse 30 DIR=${ROUNDOMO:-`pwd`} 31 32 # For gettext 33 TEXTDOMAIN=roundomo 34 35 36 source $DIR/zlibs/messaging.sh 37 38 39 # system configuration 40 [[ -r $DIR/roundomo.conf ]] || { 41 error "configuration not found: roundomo.conf"; return 1 } 42 43 source $DIR/roundomo.conf 44 45 myquery() { 46 mysql -B -N -L -u $roundcube_db_user -p$roundcube_db_pass $roundcube_db } 47 48 # quick command to login into the database to debug schemas 49 [[ "$1" == "login" ]] && { 50 mysql -u $roundcube_db_user -p$roundcube_db_pass $roundcube_db; return 0 } 51 52 53 whitelist() { 54 # check args 55 [[ "$1" == "" ]] && { error "no user specified to whitelist()"; return 1 } 56 user="$1" 57 58 # retrieve userid in db 59 check_user="select user_id from users where username='$user';" 60 user_id=`print $check_user | myquery` 61 62 [[ "$user_id" == "" ]] && { error "user not found: $user"; return 1 } 63 64 notice "Roundomo taking care of: $user (id: $user_id)" 65 66 # retrieve contacts in db 67 list_contacts="select email from contacts where user_id='$user_id';" 68 contacts=(`print $list_contacts | myquery`) 69 contacts_count=${#contacts} 70 act "contacts found in addressbook: ${contacts_count}" 71 [[ $contacts_count == 0 ]] && return 1 72 73 # hash contacts to avoid duplicate computation 74 contacts_hash="`print ${=contacts}|sha1sum|awk '{print $1}'`" 75 76 # if --force is used then force refresh of whitelist even is hash 77 # is the same (meaning there are no new contacts) 78 option_is_set -f || { 79 [[ -r ".$user" ]] && { 80 contacts_hash_prev=`cat ".$user"` 81 [[ "$contacts_hash_prev" == "$contacts_hash" ]] && { 82 act "no new contacts detected."; return 0 } 83 } 84 } 85 86 act "refreshing whitelist with new contacts" 87 88 cat <<EOF > ".$user.sieve" 89 require ["fileinto","mailbox","variables"]; 90 EOF 91 92 # whitelist only if contacts are present: 93 # makes sure priv is activated even with empty addressbook 94 [[ $contacts_count = 0 ]] || { 95 cat <<EOF >> ".$user.sieve" 96 if header :contains "From" [ 97 EOF 98 for i in $contacts; do 99 contacts_count=$(( $contacts_count - 1 )) 100 # a single entry may contain more comma separated addresses 101 ii=(${(s:,:)i}) 102 for c in $ii; do 103 print -n "\"$c\"" >> ".$user.sieve" 104 [[ $contacts_count -gt 0 ]] && { 105 print -n "," >> ".$user.sieve" } 106 done 107 print >> ".$user.sieve" 108 done 109 cat <<EOF >> ".$user.sieve" 110 ] 111 { fileinto "INBOX"; stop; } 112 EOF 113 } 114 115 # static rules: spam, priv, lists and social networks 116 cat <<EOF >> ".$user.sieve" 117 if header :is "X-Spam-Flag" "YES" { 118 fileinto :create "zz.spam"; stop; 119 } 120 121 if header :contains [ "To","Cc" ] "$user" { 122 fileinto :create "priv"; stop; 123 } 124 125 # lists auto filters 126 if header :matches "List-Id" "*<*>" { 127 fileinto :create "lists.\${2}"; stop; } 128 elsif header :matches "X-BeenThere" "*@*" { 129 fileinto :create "lists.\${1}.\${2}"; stop; } 130 elsif header :matches "List-Post" "<mailto:*@*" { 131 fileinto :create "lists.\${1}.\${2}"; stop; } 132 133 if anyof (header :contains "X-Mailman-Version" ".", 134 header :contains "Mailing-List" ".") { 135 fileinto :create "lists.unsorted"; stop; } 136 137 # social networks 138 if header :contains "From" "basecamp" { fileinto :create "zz.social"; stop; } 139 if header :contains "From" "linkedin.com" { fileinto :create "zz.social"; stop; } 140 if header :contains "From" "github.com" { fileinto :create "zz.social"; stop; } 141 if header :contains "From" "facebook" { fileinto :create "zz.social"; stop; } 142 if header :contains "From" "FriendFeed" { fileinto :create "zz.social"; stop; } 143 if header :contains "From" "twitter.com" { fileinto :create "zz.social"; stop; } 144 if header :contains "From" "identi.ca" { fileinto :create "zz.social"; stop; } 145 if header :contains "From" "wmt-noreply@google" { fileinto :create "zz.social"; stop; } 146 if header :contains "From" "plus.google.com" { fileinto :create "zz.social"; stop; } 147 if header :contains "From" "launchpad" { fileinto :create "zz.social"; stop; } 148 if header :contains "From" "statusnet" { fileinto :create "zz.social"; stop; } 149 if header :contains "From" "googlealerts" { fileinto :create "zz.social"; stop; } 150 if header :contains "From" "youtube.com" { fileinto :create "zz.social"; stop; } 151 152 fileinto :create "unsorted"; 153 EOF 154 155 act "sieve filter generated" 156 sievec .$user.sieve 157 [[ $? = 0 ]] || { 158 error "error: filters don't compile."; return 1 } 159 160 # save the latest hash to avoid duplicate effort 161 print "$contacts_hash" > ".$user" 162 163 func "cp .$user.sieve $sieve_path/$user" 164 [[ $TEST = 1 ]] || { 165 cp ".$user.sieve" $sieve_path/$user 166 } 167 } 168 169 # main() 170 171 typeset -A opts 172 typeset -A subcommands_opts 173 174 main_opts=(q -quiet=q D -debug=D h -help=h v -version=v f -force=f -no-color) 175 subcommands_opts[__default]="" 176 subcommands_opts[test]="" 177 178 init_commandline ${=argv} 179 180 [[ -r $DIR/roundomo.users ]] || { 181 error "roundomo.users is not configured with a list of users."; return 1 } 182 183 case "$subcommand" in 184 test) TEST=1 ; DEBUG=1 ;; 185 esac 186 187 roundomo_users=`awk '/^#/ {next} {print $0}' $DIR/roundomo.users` 188 for u in ${(f)roundomo_users}; do 189 whitelist "$u" 190 done 191 192