schleuder 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|