blob: 3d2ce29110629043127fd380f999be68dc0157eb (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
#autoload
# options:
#
# -n plugin - can complete nicknames from specified plugin
# -s sep - complete a list of addresses separated by specified character
# -c - e-mail address must be of form user@host (no comments or aliases)
#
# Plugins are written as separate functions with names starting `_email-'.
# They should either do their own completion or return the addresses in the
# reply array in the form 'alias:address' and return 300. The -c option is
# passed on to plugins (and -n could be if needed ever). New plugins will be
# picked up and run automatically.
# plugins
(( $+functions[_email-mail] )) ||
_email-mail() {
reply=( ${${${(M)${(f)"$(<$files[$plugin])"}:#alias*}##alias[[:blank:]]##}/[[:blank:]]##/:} )
return 300
}
(( $+functions[_email-mutt] )) || _email-mutt() { _email-mail }
(( $+functions[_email-mush] )) || _email-mush() { _email-mail }
(( $+functions[_email-MH] )) ||
_email-MH() {
reply=( ${${(f)"$(_call_program aliases ali)"}/: /:} )
return 300
}
(( $+functions[_email-pine] )) ||
_email-pine() {
reply=( ${${${${${(f)"$(<~/.addressbook)"}:#*DELETED*}:#\ *}/ [^ ]# /:}%% *} )
return 300
}
(( $+functions[_email-ldap] )) ||
_email-ldap() {
local -a expl ali res filter
local -A opts
local dn cn mail
zparseopts -D -E -A opts c
zstyle -a ":completion:${curcontext}:$curtag" filter filter
(( $#filter )) || return
filter=( "("${filter}"=${PREFIX}*${SUFFIX})" )
(( $#filter > 1 )) && filter="(|"${(j..)filter}")"
res=( ${(f)"$(_call_program $curtag ldapsearch -LLL \$filter cn mail 2>/dev/null)"} )
(( $#res > 1 )) || return
for dn cn mail in "${res[@]}"; do
if (( $+opts[-c] )); then
ali+=( "${mail#*: }" )
else
cn="${cn#*: }"
[[ $cn = *$~__specials* ]] && cn="\"$cn\""
ali+=( "$cn <${mail#*: }>" )
fi
done
compstate[insert]=menu
_wanted email-ldap expl 'matching names' \
compadd -U -i "$IPREFIX" -I "$ISUFFIX" "$@" -a - ali
}
(( $+functions[_email-local] )) ||
_email-local() {
local suf opts
zparseopts -D -E -A opts c S:=suf
if compset -P '*@'; then
_hosts "$@" "$suf[@]"
else
suf=()
compset -S '@*' || suf=( -qS @ )
_users "$suf[@]" "$@"
fi
}
_email_addresses() {
local -a plugins reply list args
local -A opts files
local plugin rcfile expl ret fret
local __specialx='][()<>@,;:\\".'
local __spacex=" " # Space, tab
local __specials="[$__specialx]"
local __atom="[^$__specialx$__spacex]##"
local __space="[$__spacex]#" # Really, space or comment
local __qtext='[^"\\]'
local __qpair='\\?'
local __beginq='"'
local __endq='(|[^\\])"'
local __dot="$__space.$__space"
local __domainref="$__atom"
local __domainlit='\[([^]]|'"$__qpair"')#(|[^\\])\]'
local __quotedstring="$__beginq($__qtext|$__qpair)#$__endq"
local __word="($__atom|$__quotedstring)"
local __phrase="($__space$__word$__space)#" # Strictly, should use `##'
local __localpart="$__word($__dot$__word)#"
local __subdomain="($__domainref|$__domainlit)"
local __domain="$__subdomain($__dot$__subdomain)#"
local __addrspec="$__localpart$__space@$__space$__domain"
local __addresses="($__qtext|$__quotedstring)##"
zparseopts -D -E -A opts n: s: c
set -- "$@" -M 'r:|[.@]=* r:|=* m:{a-zA-Z}={A-Za-z}'
if [[ -n $opts[-s] ]]; then
# remove up to the last unquoted separator
if [[ ${(Q)PREFIX} = (#b)($~__addresses$opts[-s])* ]]; then
IFS="$opts[-s]" eval 'compset -P $(( ${#${=${:-x${match[1]}x}}} - 1 )) "*${opts[-s]}"'
fi
# for the suffix, I'm too lazy to work out how to preserve quoted separators
compset -S "$opts[-s]*" || set -- -q -S "$opts[-s]" "$@"
fi
# get list of all plugins except any with missing config files
files=( mutt ~/.muttrc mush ~/.mushrc mail ${MAILRC:-~/.mailrc} pine ~/.addressbook )
plugins=(
${${(k)functions[(I)_email-*]#*-}:#(${(kj.|.)~files})}
$files(Ne:'REPLY=( ${(k)files[(r)$REPLY]} ):')
)
ret=1
_tags email-$plugins
while _tags; do
for plugin in $plugins; do
if _requested email-$plugin; then
while _next_label email-$plugin expl 'email address'; do
args=()
if (( $+opts[-c] )) || zstyle -t \
":completion:${curcontext}:$curtag" strip-comments
then
args=( '-c' )
fi
if ! _call_function fret _email-$plugin "$@" $args; then
_message "$plugin: plugin not found"
continue
fi
ret=$(( ret && fret ))
if (( fret == 300 )); then
if (( ! $+opts[-c] )) && [[ $opts[-n] = $plugin ]]; then
zformat -a list ' -- ' "${reply[@]}"
_wanted mail-aliases expl 'alias' compadd "$@" \
-d list - ${reply%%:*} && ret=0
else
if (( $#args )); then
reply=( ${(SM)${reply#*:}##$~__addrspec} )
else
# remove lines not containing `@' as they probably aren't addresses
reply=( "${(@)${(M@)reply:#*@*}#*:}" )
fi
compadd -a "$@" "$expl[@]" reply && ret=0
fi
fi
done
fi
done
(( ret )) || return 0
done
return 1
}
_email_addresses "$@"
|