schleuder 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/LICENSE +339 -0
- data/README +32 -0
- data/bin/schleuder +96 -0
- data/bin/schleuder-fix-gem-dependencies +30 -0
- data/bin/schleuder-init-setup +37 -0
- data/bin/schleuder-migrate-v2.1-to-v2.2 +205 -0
- data/bin/schleuder-newlist +384 -0
- data/contrib/check-expired-keys.rb +59 -0
- data/contrib/mutt-schleuder-colors.rc +10 -0
- data/contrib/mutt-schleuder-resend.vim +24 -0
- data/contrib/smtpserver.rb +76 -0
- data/ext/default-list.conf +146 -0
- data/ext/default-members.conf +7 -0
- data/ext/list.conf.example +14 -0
- data/ext/schleuder.conf +62 -0
- data/lib/schleuder.rb +49 -0
- data/lib/schleuder/archiver.rb +46 -0
- data/lib/schleuder/crypt.rb +188 -0
- data/lib/schleuder/errors.rb +5 -0
- data/lib/schleuder/list.rb +177 -0
- data/lib/schleuder/list_config.rb +146 -0
- data/lib/schleuder/log/listlogger.rb +56 -0
- data/lib/schleuder/log/outputter/emailoutputter.rb +118 -0
- data/lib/schleuder/log/outputter/metaemailoutputter.rb +50 -0
- data/lib/schleuder/log/schleuderlogger.rb +23 -0
- data/lib/schleuder/mail.rb +861 -0
- data/lib/schleuder/mailer.rb +26 -0
- data/lib/schleuder/member.rb +69 -0
- data/lib/schleuder/plugin.rb +54 -0
- data/lib/schleuder/processor.rb +363 -0
- data/lib/schleuder/schleuder_config.rb +72 -0
- data/lib/schleuder/storage.rb +84 -0
- data/lib/schleuder/utils.rb +80 -0
- data/lib/schleuder/version.rb +3 -0
- data/man/schleuder-newlist.8 +191 -0
- data/man/schleuder.8 +400 -0
- data/plugins/README +20 -0
- data/plugins/manage_keys_plugin.rb +113 -0
- data/plugins/manage_members_plugin.rb +152 -0
- data/plugins/manage_self_plugin.rb +26 -0
- data/plugins/resend_plugin.rb +35 -0
- data/plugins/version_plugin.rb +12 -0
- metadata +178 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Schleuder
|
2
|
+
class Mailer
|
3
|
+
def self.send(msg, to=nil, sender=Schleuder.list.bounce_addr, nolog=false)
|
4
|
+
to = msg.to if to.nil?
|
5
|
+
|
6
|
+
# TODO: TLS
|
7
|
+
host = Schleuder.config.smtp_host
|
8
|
+
port = Schleuder.config.smtp_port
|
9
|
+
unless nolog
|
10
|
+
Schleuder.log.info { "Delivering mail to #{host}:#{port}" }
|
11
|
+
Schleuder.log.debug { "Mail has Sender: #{sender} - To: #{to.inspect}" }
|
12
|
+
end
|
13
|
+
Net::SMTP.start(host, port) do |smtpcon|
|
14
|
+
smtpcon.send_message msg.to_s, sender, to
|
15
|
+
end
|
16
|
+
true
|
17
|
+
rescue => e
|
18
|
+
if e.message.frozen?
|
19
|
+
Schleuder.log.warn "Something went wrong, while sending a message. I'll better preserve the message that should have been sent:\n#{msg.to_s}"
|
20
|
+
else
|
21
|
+
e.message << "\nOriginal message:\n#{msg.to_s}"
|
22
|
+
end
|
23
|
+
raise
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Schleuder
|
2
|
+
class Member < Storage
|
3
|
+
schleuder_attr :email, nil
|
4
|
+
schleuder_attr :mime, 'MIME'
|
5
|
+
# only send encrypted mail to this member
|
6
|
+
schleuder_attr :encrypted_only, false
|
7
|
+
schleuder_attr :key_fingerprint, nil
|
8
|
+
|
9
|
+
def initialize(config_file, fromfile=true)
|
10
|
+
super(config_file, fromfile)
|
11
|
+
|
12
|
+
# compress fingerprint
|
13
|
+
self.key_fingerprint = self.key_fingerprint
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_hash
|
17
|
+
Hash[*self.class.default_schleuder_attributes.keys.collect { |key|
|
18
|
+
unless (val = send(key)).to_s.empty?
|
19
|
+
[ key, val ]
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
}.flatten.compact]
|
24
|
+
end
|
25
|
+
|
26
|
+
def key_fingerprint=(fpr)
|
27
|
+
schleuder_attributes['key_fingerprint'] = Schleuder::Utils.compress_fingerprint(fpr)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
email
|
32
|
+
end
|
33
|
+
|
34
|
+
def key(only_valid_keys=true)
|
35
|
+
if @key.nil? || !only_valid_keys # by default we want only valid keys. If
|
36
|
+
# we ask also for invalid keys we want
|
37
|
+
# to redo the keylookup
|
38
|
+
lookup_str = self.key_fingerprint.nil? ? self.email : self.key_fingerprint
|
39
|
+
key_result = crypt.get_key(lookup_str,only_valid_keys)
|
40
|
+
if k = key_result.first
|
41
|
+
@key = k
|
42
|
+
self.key_fingerprint = @key.subkeys.first.fingerprint
|
43
|
+
else
|
44
|
+
@key = nil
|
45
|
+
self.key_fingerprint = nil
|
46
|
+
return key_result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@key
|
50
|
+
end
|
51
|
+
|
52
|
+
def uses_key?(other_key)
|
53
|
+
key # initialize @key
|
54
|
+
!@key.nil? && @key.subkeys.first.fingerprint == other_key.subkeys.first.fingerprint
|
55
|
+
end
|
56
|
+
|
57
|
+
def key_descr
|
58
|
+
k, msg = key
|
59
|
+
k ? crypt.key_descr(k) : "*Warning:* #{msg}"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def crypt
|
64
|
+
# No simple way to get hands on mail.crypt, so we create another here.
|
65
|
+
# But on class side as it does not need to be per member
|
66
|
+
@@crypt ||= Crypt.new(nil)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Schleuder
|
2
|
+
# Parent-class for plugins. Sets up stub and helper methods.
|
3
|
+
class Plugin
|
4
|
+
# Define whether this plugin should be used for emails sent to the
|
5
|
+
# list-address or the request-address.
|
6
|
+
attr_reader :plugin_type
|
7
|
+
|
8
|
+
def Plugin.signing_key(mail)
|
9
|
+
@@key ||= mail.crypt.get_key(mail.in_signed.fpr).first
|
10
|
+
end
|
11
|
+
|
12
|
+
# Helper: creates a reply to the sender of the incoming message. The
|
13
|
+
# destination address is detemined by finding the list-member connected to
|
14
|
+
# the key that signed the incoming message. +msg+ is used as body for the
|
15
|
+
# outgoing mail.
|
16
|
+
def Plugin.reply(mail, msg, keywords)
|
17
|
+
Schleuder.log.info "Building reply mail"
|
18
|
+
out = Mail.new
|
19
|
+
|
20
|
+
out.subject = "Re: #{mail.subject}"
|
21
|
+
key = Plugin.signing_key(mail)
|
22
|
+
Schleuder.log.debug "Looking up member by key: #{key.inspect}"
|
23
|
+
member = Schleuder.list.find_member_by_key(key) || Schleuder.list.find_admin_by_key(key)
|
24
|
+
Schleuder.log.debug { "Result: #{member.inspect}" }
|
25
|
+
if member
|
26
|
+
Schleuder.log.info { "Found member for key: %s" % member.inspect }
|
27
|
+
else
|
28
|
+
Schleuder.log.error "No member or admin found for signing key, aborting reply."
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
imail = out.individualize(member)
|
33
|
+
imail.in_reply_to = mail.message_id
|
34
|
+
imail.body = msg
|
35
|
+
|
36
|
+
unless imail.encrypt!(member)
|
37
|
+
Schleuder.log.debug 'encrypting failed, replacing body with please-fix-message'
|
38
|
+
imail.body = "Encrypting to #{imail.to} failed. Please fix."
|
39
|
+
end
|
40
|
+
|
41
|
+
Schleuder.log.info "Sending to #{imail.to}"
|
42
|
+
Mailer.send(imail)
|
43
|
+
|
44
|
+
unless (Schleuder.list.config.keywords_admin_notify & keywords).empty?
|
45
|
+
Schleuder.log.info "Sending notification to admins"
|
46
|
+
msg = "Hello list-admin,\n\nmember #{member.email} sent the keyword(s) '#{keywords.join("','")}' and received the following reply-message:\n\n\n".fmt << msg
|
47
|
+
Schleuder.log.notify_admin 'Notice', msg
|
48
|
+
end
|
49
|
+
|
50
|
+
Schleuder.log.info "Exiting"
|
51
|
+
exit 0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,363 @@
|
|
1
|
+
module Schleuder
|
2
|
+
def log
|
3
|
+
SchleuderLogger.new unless Log4r::Logger['log4r']
|
4
|
+
# If there's a ListLogger we use that, else the global SchleuderLogger.
|
5
|
+
# The ListLogger is being set up in List::initialize().
|
6
|
+
Log4r::Logger['list'] || Log4r::Logger['log4r']
|
7
|
+
end
|
8
|
+
module_function :log
|
9
|
+
|
10
|
+
def config(config_file=nil)
|
11
|
+
# read the base config (class overloads itself with conf/schleuder.conf)
|
12
|
+
@config ||= SchleuderConfig.new(config_file)
|
13
|
+
end
|
14
|
+
module_function :config
|
15
|
+
|
16
|
+
def list
|
17
|
+
@list || nil
|
18
|
+
end
|
19
|
+
module_function :list
|
20
|
+
|
21
|
+
def list=(list)
|
22
|
+
@list = list
|
23
|
+
end
|
24
|
+
module_function :list=
|
25
|
+
|
26
|
+
def origmsg=(msg)
|
27
|
+
@origmsg = msg
|
28
|
+
end
|
29
|
+
module_function :origmsg=
|
30
|
+
|
31
|
+
def origmsg
|
32
|
+
@origmsg || nil
|
33
|
+
end
|
34
|
+
module_function :origmsg
|
35
|
+
|
36
|
+
def self.listname(listname=nil)
|
37
|
+
@listname ||= listname
|
38
|
+
end
|
39
|
+
|
40
|
+
class Processor
|
41
|
+
def self.run(listname, message)
|
42
|
+
Schleuder.listname listname
|
43
|
+
Schleuder.origmsg = message
|
44
|
+
Schleuder.log.debug "Testing if list-dir exists"
|
45
|
+
unless File.directory?(List.listdir(listname))
|
46
|
+
msg = "No such list: #{listname}"
|
47
|
+
$stderr.puts msg
|
48
|
+
Schleuder.log.warn msg
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
Schleuder.log.debug "Creating list"
|
53
|
+
Schleuder.list = List.new(listname)
|
54
|
+
|
55
|
+
Schleuder.log.debug "Parsing incoming message"
|
56
|
+
mail = Mail.parse(message)
|
57
|
+
Schleuder.log.info "New mail incoming from #{mail.from}"
|
58
|
+
|
59
|
+
msize = message.size / 1024
|
60
|
+
lsize = Schleuder.list.config.max_message_size
|
61
|
+
if msize > lsize
|
62
|
+
self.bounce_or_drop "too big (#{msize}kB > #{lsize}kB)", "This address accepts only messages up to #{Schleuder.list.config.max_message_size} kilobyte.", mail
|
63
|
+
end
|
64
|
+
|
65
|
+
# if mail is a bounce we forward it directly to the admins, as
|
66
|
+
# dealing with those probably fails (encrypted attachments etc.)
|
67
|
+
if mail.bounce?
|
68
|
+
Schleuder.log.info "This is a bounce, forwarding to admins and exiting"
|
69
|
+
Schleuder.log.notify_admin "Problem", [ "Hello,\n\nI caught a bounce. Please take care of it.", message ]
|
70
|
+
Schleuder.log.info "Exiting cleanly"
|
71
|
+
exit(0)
|
72
|
+
end
|
73
|
+
|
74
|
+
if Schleuder.list.config.dump_incoming_mail
|
75
|
+
dump_dir = File.join(Schleuder.list.listdir,'dumps')
|
76
|
+
Dir.mkdir dump_dir unless File.directory? dump_dir
|
77
|
+
require 'digest/sha1'
|
78
|
+
msg_file = File.join(dump_dir,"#{Digest::SHA1.hexdigest(message[0..10000])}.msg")
|
79
|
+
Schleuder.log.info "Dumping message to #{msg_file}"
|
80
|
+
File.open(msg_file,"w") { |f| f << message }
|
81
|
+
Schleuder.log.notify_admin "Dump notification", "Hello,\n\nI dumped the current incoming message to #{msg_file} \n\nYou should erase that file after inspection!"
|
82
|
+
end
|
83
|
+
|
84
|
+
# if mail is a send-key-request we answer directly
|
85
|
+
if mail.to.to_a.include?(Schleuder.list.sendkey_addr) || (mail.subject.strip.downcase == 'send key!' && mail.body.strip.empty?)
|
86
|
+
Schleuder.log.info "Found send-key-request"
|
87
|
+
# TODO: refactor with Plugin::reply
|
88
|
+
out = Mail.new
|
89
|
+
out.subject = "Re: #{mail.subject}"
|
90
|
+
Schleuder.log.info "Building reply"
|
91
|
+
iout = out.individualize(Member.new({'email' => mail.from.first}))
|
92
|
+
iout.in_reply_to = mail.message_id
|
93
|
+
Schleuder.log.debug "Filling body with key-id and key"
|
94
|
+
iout.body = "#{Schleuder.list.key.to_s}\n#{mail.crypt.export(Schleuder.list.key_fingerprint).to_s}"
|
95
|
+
Schleuder.log.debug "Signing outgoing email"
|
96
|
+
rawmail = iout.sign
|
97
|
+
Schleuder.log.info "Handing over to Mailer"
|
98
|
+
Mailer.send(rawmail, iout.to)
|
99
|
+
Schleuder.log.info "Exiting"
|
100
|
+
exit 0
|
101
|
+
end
|
102
|
+
|
103
|
+
# Analyse data (hopefully an incoming mail).
|
104
|
+
# Is it multi-part? encrypted? pgp/mime? signed?
|
105
|
+
Schleuder.log.debug "Analysing incoming mail"
|
106
|
+
begin
|
107
|
+
mail.decrypt!
|
108
|
+
rescue GPGME::Error::DecryptFailed => e
|
109
|
+
Schleuder.log.error "#{e}\n\nOriginal message:\n#{message}"
|
110
|
+
$stdout.puts "Schleuder speaking. Cannot decrypt. Please check your setup.\nMessages to this list need to be encrypted with this key:\n#{Schleuder.list.key}"
|
111
|
+
exit 100
|
112
|
+
end
|
113
|
+
|
114
|
+
if !mail.to.nil? && mail.to.include?(Schleuder.list.owner_addr)
|
115
|
+
Schleuder.log.info "This is a message to the owner(s), forwarding to admins and exiting"
|
116
|
+
Schleuder.log.notify_admin "Message", [ "Hello,\n\nthe attached message is directed to you as list-owner(s). Please take care of it!\n\n", mail ]
|
117
|
+
Schleuder.log.info "Exiting cleanly"
|
118
|
+
exit(0)
|
119
|
+
end
|
120
|
+
|
121
|
+
if Schleuder.list.config.receive_signed_only && !mail.in_signed
|
122
|
+
self.bounce_or_drop "not validly signed", "This address accepts only messages validly signed in an OpenPGP-compatible way", mail
|
123
|
+
end
|
124
|
+
|
125
|
+
if Schleuder.list.config.receive_encrypted_only && !mail.in_encrypted
|
126
|
+
self.bounce_or_drop 'not encrypted', "This address accepts only messages encrypted with this key:\n#{Schleuder.list.key}", mail, message
|
127
|
+
end
|
128
|
+
|
129
|
+
if Schleuder.list.config.receive_authenticated_only && !(mail.from_member || mail.from_admin)
|
130
|
+
self.bounce_or_drop "not authenticated", "This address accepts only messages validly signed by a list-member's key.", mail
|
131
|
+
end
|
132
|
+
|
133
|
+
if Schleuder.list.config.receive_from_member_emailaddresses_only && !(mail.from_member_address?||mail.from_admin_address?)
|
134
|
+
self.bounce_or_drop "not from a member e-mail address", "This address accepts only messages from member addresses.", mail
|
135
|
+
end
|
136
|
+
|
137
|
+
if Schleuder.list.config.receive_admin_only && !mail.from_admin
|
138
|
+
self.bounce_or_drop "not authenticated as admin", "This address accepts only messages validly signed by a list-admin's key.", mail
|
139
|
+
end
|
140
|
+
|
141
|
+
if mail.to.to_a.include?(Schleuder.list.request_addr)
|
142
|
+
if (mail.from_member || mail.from_admin) && mail.in_encrypted
|
143
|
+
process_plugins(mail)
|
144
|
+
# If we reach this point no plugin took over
|
145
|
+
self.bounce_or_drop "not a valid request", "No valid command found in message. This address (-request) accepts only messages containing valid schleuder-keyword-commands.".fmt, mail
|
146
|
+
end
|
147
|
+
self.bounce_or_drop "not authenticated", "This address (-request) accepts only encrypted messages by list-members.".fmt, mail
|
148
|
+
end
|
149
|
+
|
150
|
+
unless mail.from_member || mail.from_admin
|
151
|
+
Schleuder.log.debug "Mail is not from a list-member, adding prefix_in"
|
152
|
+
mail.add_prefix_in!
|
153
|
+
end
|
154
|
+
|
155
|
+
# Checking for keywords in mail-body (e.g. X-RESEND)
|
156
|
+
if mail.from_member || mail.from_admin
|
157
|
+
if mail.in_encrypted
|
158
|
+
Schleuder.log.info "Incoming mail is encrypted and authorized, processing plugins"
|
159
|
+
process_plugins(mail)
|
160
|
+
else
|
161
|
+
Schleuder.log.info "Incoming mail is not encrypted or authorized, skipping plugins"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# first encrypt and send message to external recipients and collect
|
166
|
+
# information about the process
|
167
|
+
mail.resend_to.each do |receiver|
|
168
|
+
if receiver.email.to_s.empty?
|
169
|
+
errmsg = "Invalid value for receiver.email: %s. Skipping."
|
170
|
+
Schleuder.log.warn { errmsg % receiver.email.inspect }
|
171
|
+
next
|
172
|
+
end
|
173
|
+
|
174
|
+
imail = mail.individualize(receiver)
|
175
|
+
imail.add_public_footer!
|
176
|
+
|
177
|
+
if Schleuder.list.config.send_encrypted_only
|
178
|
+
enc_only = true
|
179
|
+
else
|
180
|
+
enc_only = receiver.encrypted_only
|
181
|
+
end
|
182
|
+
|
183
|
+
begin
|
184
|
+
ret = self.send(imail, receiver, enc_only)
|
185
|
+
if ret.first
|
186
|
+
# store meta-data about the sent message
|
187
|
+
crypt = " (#{ret[1]})"
|
188
|
+
mail.metadata[:resent_to] << receiver.email + crypt
|
189
|
+
else
|
190
|
+
mail.metadata[:error] << "Not resent to #{receiver.email}: #{ret[1]}"
|
191
|
+
end
|
192
|
+
rescue => e
|
193
|
+
Schleuder.log.error e
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
mail.add_prefix_out! unless mail.metadata[:resent_to].empty?
|
198
|
+
mail.add_prefix!
|
199
|
+
mail.add_metadata!
|
200
|
+
|
201
|
+
# archive message if necessary
|
202
|
+
Schleuder.list.archive(mail) if Schleuder.list.config.archive
|
203
|
+
|
204
|
+
# encrypt message and send mail for each list-member
|
205
|
+
Schleuder.log.info { 'Looping over all list-members to send out' }
|
206
|
+
Schleuder.list.members.each do |receiver|
|
207
|
+
Schleuder.log.debug { "Looping for #{receiver.inspect}" }
|
208
|
+
|
209
|
+
if receiver.email.to_s.empty?
|
210
|
+
errmsg = "Invalid value for receiver.email: %s. Skipping."
|
211
|
+
Schleuder.log.warn { errmsg % receiver.email.inspect }
|
212
|
+
next
|
213
|
+
end
|
214
|
+
|
215
|
+
imail = mail.individualize_member(receiver)
|
216
|
+
|
217
|
+
if Schleuder.list.config.send_encrypted_only
|
218
|
+
enc_only = true
|
219
|
+
else
|
220
|
+
enc_only = receiver.encrypted_only
|
221
|
+
end
|
222
|
+
|
223
|
+
# encrypt for each receiver
|
224
|
+
begin
|
225
|
+
sent = self.send(imail, receiver, enc_only)
|
226
|
+
unless sent.first
|
227
|
+
Schleuder.log.error sent[1]
|
228
|
+
end
|
229
|
+
rescue => e
|
230
|
+
Schleuder.log.error e
|
231
|
+
end
|
232
|
+
end
|
233
|
+
Schleuder.log.info { 'Processing done, this is the end.' }
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.send(mail, receiver, encrypted_only=true, sender=Schleuder.list.bounce_addr)
|
237
|
+
begin
|
238
|
+
encrypted, errmsg = mail.encrypt!(receiver)
|
239
|
+
rescue GPGME::Error::UnusablePublicKey => e
|
240
|
+
# This exception is thrown, if the public key of a certain list
|
241
|
+
# member is not usable (because it is revoked, expired, disabled or
|
242
|
+
# invalid).
|
243
|
+
k = e.keys.first
|
244
|
+
key = mail.crypt.get_key(k.fpr).first
|
245
|
+
errmsg = "#{e.message}: (#{k.class})\n#{key.to_s}"
|
246
|
+
Schleuder.log.error "Encryption failed (#{errmsg})"
|
247
|
+
encrypted = false
|
248
|
+
rescue GPGME::Error::General => e
|
249
|
+
errmsg = e.message
|
250
|
+
Schleuder.log.error "Encryption failed (#{errmsg})"
|
251
|
+
encrypted = false
|
252
|
+
end
|
253
|
+
if encrypted
|
254
|
+
Mailer.send(mail, nil, sender)
|
255
|
+
return [true, 'encrypted']
|
256
|
+
else
|
257
|
+
if encrypted_only
|
258
|
+
Schleuder.log.debug "Sending plaintext not allowed, message not sent to #{receiver.inspect}!"
|
259
|
+
return [false, "Encrypting to #{receiver.email.inspect} failed: #{errmsg} (sending plaintext disallowed)"]
|
260
|
+
else
|
261
|
+
Schleuder.log.info "Sending plaintext allowed, doing so"
|
262
|
+
# sign msg
|
263
|
+
if rawmail = mail.sign
|
264
|
+
Mailer.send(rawmail, mail.to, sender)
|
265
|
+
return [true, "unencrypted (#{errmsg})"]
|
266
|
+
else
|
267
|
+
return [false, "signing failed"]
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def self.test(listname=nil)
|
274
|
+
# Doing things that trigger exceptions if they fail, which we rescue and
|
275
|
+
# put to stderr
|
276
|
+
# TODO: test #{smtp_host}:25
|
277
|
+
begin
|
278
|
+
# test listdir
|
279
|
+
Dir.entries Schleuder.config.lists_dir
|
280
|
+
|
281
|
+
# test superadminaddr
|
282
|
+
Utils::verify_addr('superadminaddr', Schleuder.config.superadminaddr)
|
283
|
+
|
284
|
+
if listname
|
285
|
+
# testwise create a list-object (reads list-config etc.)
|
286
|
+
list = List.new listname
|
287
|
+
# test for listdir
|
288
|
+
Dir.entries list.listdir
|
289
|
+
# test admins
|
290
|
+
list.config.admins.each do |a|
|
291
|
+
Utils::verify_addr('adminaddr', a.email)
|
292
|
+
key, msg = a.key
|
293
|
+
if !key
|
294
|
+
raise "Admin: #{a}'s key lookup fails! Problem: #{msg}"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
crypt = Crypt.new(list.config.gpg_password)
|
299
|
+
|
300
|
+
list.members.each do |m|
|
301
|
+
Utils::verify_addr('member address', m.email)
|
302
|
+
key, msg = m.key
|
303
|
+
if !key
|
304
|
+
raise "#{m}'s key lookup fails! Problem: #{msg}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
rescue => e
|
309
|
+
$stderr.puts e.message
|
310
|
+
$stderr.puts e.backtrace
|
311
|
+
exit 1
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def self.newlist(listname, interactive='true', args=nil)
|
316
|
+
created_list = Schleuder::ListCreator.create(listname,interactive,args)
|
317
|
+
end
|
318
|
+
|
319
|
+
def self.bounce_or_drop(status, bounce_msg, mail)
|
320
|
+
Schleuder.log.warn "Mail is #{status}, not passing it along"
|
321
|
+
|
322
|
+
if Schleuder.list.config.bounces_drop_all
|
323
|
+
Schleuder.log.warn "Found bounces_drop_all being true: dropping!"
|
324
|
+
self.bounce_notify_admin status, "bounces_drop_all is true"
|
325
|
+
exit 0
|
326
|
+
end
|
327
|
+
|
328
|
+
Schleuder.log.debug "Testing bounces_drop_on_headers"
|
329
|
+
Schleuder.list.config.bounces_drop_on_headers.each do |header,value|
|
330
|
+
Schleuder.log.debug "Testing #{header} => #{value}"
|
331
|
+
if mail.header[header].to_s.downcase == value.to_s.downcase
|
332
|
+
Schleuder.log.warn "Found matching drop-header: #{header} => #{value} -- dropping!"
|
333
|
+
self.bounce_notify_admin status, "Forbidden header found: '#{header.capitalize}: #{value.capitalize}'"
|
334
|
+
exit 0
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# if we're still alive: bounce message
|
339
|
+
Schleuder.log.info "bouncing mail to sender"
|
340
|
+
self.bounce_notify_admin status
|
341
|
+
$stdout.puts bounce_msg
|
342
|
+
exit 100
|
343
|
+
end
|
344
|
+
|
345
|
+
def self.bounce_notify_admin(reason, drop_reason='')
|
346
|
+
msg = "The attached incoming email has not been passed to the list.\nReason: #{reason}.\n"
|
347
|
+
if drop_reason.empty?
|
348
|
+
msg += "\nIt has been bounced to the sender.\n"
|
349
|
+
else
|
350
|
+
msg += "\nIt has *not* been bounced but dropped.\nReason: #{drop_reason}.\n"
|
351
|
+
end
|
352
|
+
|
353
|
+
Schleuder.log.notify_admin("Notice", [ msg, Mail.parse(Schleuder.origmsg) ]) if Schleuder.list.config.bounces_notify_admin
|
354
|
+
end
|
355
|
+
|
356
|
+
def self.process_plugins(mail)
|
357
|
+
Schleuder.log.info 'Email is encrypted and authorized, processing plugins'
|
358
|
+
# process plugins
|
359
|
+
Schleuder.log.debug 'Processing plugins'
|
360
|
+
mail.process_plugins!
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|