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.
Files changed (45) hide show
  1. data.tar.gz.sig +0 -0
  2. data/LICENSE +339 -0
  3. data/README +32 -0
  4. data/bin/schleuder +96 -0
  5. data/bin/schleuder-fix-gem-dependencies +30 -0
  6. data/bin/schleuder-init-setup +37 -0
  7. data/bin/schleuder-migrate-v2.1-to-v2.2 +205 -0
  8. data/bin/schleuder-newlist +384 -0
  9. data/contrib/check-expired-keys.rb +59 -0
  10. data/contrib/mutt-schleuder-colors.rc +10 -0
  11. data/contrib/mutt-schleuder-resend.vim +24 -0
  12. data/contrib/smtpserver.rb +76 -0
  13. data/ext/default-list.conf +146 -0
  14. data/ext/default-members.conf +7 -0
  15. data/ext/list.conf.example +14 -0
  16. data/ext/schleuder.conf +62 -0
  17. data/lib/schleuder.rb +49 -0
  18. data/lib/schleuder/archiver.rb +46 -0
  19. data/lib/schleuder/crypt.rb +188 -0
  20. data/lib/schleuder/errors.rb +5 -0
  21. data/lib/schleuder/list.rb +177 -0
  22. data/lib/schleuder/list_config.rb +146 -0
  23. data/lib/schleuder/log/listlogger.rb +56 -0
  24. data/lib/schleuder/log/outputter/emailoutputter.rb +118 -0
  25. data/lib/schleuder/log/outputter/metaemailoutputter.rb +50 -0
  26. data/lib/schleuder/log/schleuderlogger.rb +23 -0
  27. data/lib/schleuder/mail.rb +861 -0
  28. data/lib/schleuder/mailer.rb +26 -0
  29. data/lib/schleuder/member.rb +69 -0
  30. data/lib/schleuder/plugin.rb +54 -0
  31. data/lib/schleuder/processor.rb +363 -0
  32. data/lib/schleuder/schleuder_config.rb +72 -0
  33. data/lib/schleuder/storage.rb +84 -0
  34. data/lib/schleuder/utils.rb +80 -0
  35. data/lib/schleuder/version.rb +3 -0
  36. data/man/schleuder-newlist.8 +191 -0
  37. data/man/schleuder.8 +400 -0
  38. data/plugins/README +20 -0
  39. data/plugins/manage_keys_plugin.rb +113 -0
  40. data/plugins/manage_members_plugin.rb +152 -0
  41. data/plugins/manage_self_plugin.rb +26 -0
  42. data/plugins/resend_plugin.rb +35 -0
  43. data/plugins/version_plugin.rb +12 -0
  44. metadata +178 -0
  45. metadata.gz.sig +2 -0
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # We need to install one more gem depending on the used ruby-version.
4
+ # Unfortunately this isn't possible inside of rubygems, therefore we do it
5
+ # here.
6
+
7
+ require 'rubygems'
8
+ require 'rubygems/dependency_installer.rb'
9
+
10
+ inst = Gem::DependencyInstaller.new
11
+ spec = Gem::Specification.find_by_name 'schleuder'
12
+
13
+ begin
14
+ if RUBY_VERSION < "1.9"
15
+ name = 'tmail'
16
+ ver = '=1.2.3.1'
17
+ else
18
+ name = 'actionmailer'
19
+ ver = '=2.3.14'
20
+ end
21
+ inst.install name, ver
22
+ spec.add_dependency name, ver
23
+ # Write spec back to file, from rubygems/installer.rb
24
+ File.open(spec.spec_file.untaint, "w") do |f|
25
+ f << spec.to_ruby_for_cache
26
+ end
27
+ rescue Gem::FilePermissionError => e
28
+ $stderr.puts "Error: #{e.message}"
29
+ end
30
+
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $VERBOSE = nil
4
+
5
+ require 'fileutils'
6
+ require 'schleuder/utils'
7
+ require 'highline/system_extensions'
8
+
9
+ def usage
10
+ puts "Usage: #{File.basename(__FILE__)} --gem | /path/to/schleuder"
11
+ puts "Creates neccessary directories and copies default configurations to /etc/schleuder.\n".fmt
12
+ end
13
+
14
+ def copy(basedir)
15
+ %w(/etc/schleuder /var/log/schleuder).each do |dir|
16
+ FileUtils.mkdir(dir) unless File.directory?(dir)
17
+ end
18
+ files = Dir.glob(File.join(basedir, 'ext', '*')).reject { |f| ['Rakefile'].include?(f) }
19
+ FileUtils.cp(files, '/etc/schleuder/')
20
+ rescue Errno::EACCES => e
21
+ puts "#{e.message}"
22
+ puts "Please retry with appropriate privileges!"
23
+ exit 1
24
+ end
25
+
26
+ case ARGV.first
27
+ when nil,/-h|--help/
28
+ usage
29
+ exit 1
30
+ when /--gem/
31
+ require 'rubygems'
32
+ spec = Gem::Specification.find_by_name('schleuder')
33
+ copy(spec.gem_dir)
34
+ else
35
+ copy(ARGV.first)
36
+ end
37
+
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + '/../lib'
4
+ require 'schleuder'
5
+ require 'fileutils'
6
+ require 'yaml'
7
+ require 'open3'
8
+ require 'highline/system_extensions'
9
+
10
+ def usage
11
+ puts "Usage: #{File.basename(__FILE__)} [-c /path/to/base/schleuder.conf] /path/to/a/list.config"
12
+ exit 1
13
+ end
14
+
15
+ usage if ![1,3].include?(ARGV.length)
16
+
17
+ if (list_config = ARGV.shift) == '-c'
18
+ baseconfig = File.expand_path(ARGV.shift)
19
+ usage unless File.exist?(baseconfig)
20
+ Schleuder.config(baseconfig)
21
+ list_config = ARGV.shift
22
+ end
23
+
24
+ usage unless File.exist?(list_config = File.expand_path(list_config))
25
+
26
+ def notice(msg)
27
+ puts msg.fmt
28
+ end
29
+
30
+ def move_listdir(old_dir,old_config)
31
+ list_dir = old_config['myaddr'].split('@').reverse
32
+ if old_dir =~ /#{list_dir.join('\/')}/
33
+ notice("The current directory of the list seems already to match the new style. Did you already migrate that list? As I can't be sure what might be right or wrong, I exit here.")
34
+ exit 1
35
+ end
36
+
37
+ hostdir = File.expand_path(File.join(Schleuder.config.lists_dir, list_dir.first))
38
+ FileUtils.mkdir_p(hostdir) unless File.directory?(hostdir)
39
+
40
+ FileUtils.mv(old_dir, hostdir)
41
+ notice("Moved list-dir to #{File.join(hostdir, Schleuder.list.listname)}.")
42
+ File.expand_path(File.join(Schleuder.config.lists_dir, list_dir.join('/')))
43
+ end
44
+
45
+ def member_key(member)
46
+ key,msg = member.key
47
+ unless key
48
+ notice("Can't find unique key for #{member}. Reason: #{msg}")
49
+ end
50
+ member
51
+ end
52
+
53
+ def fix_list_conf(old_config,new_dir)
54
+ if old_config.delete('logging').to_s == 'true' && !old_config['lists_logfile'].nil?
55
+ old_config['log_file'] = old_config.delete('lists_logfile')
56
+ end
57
+
58
+ unless old_config['loglevel'].nil?
59
+ old_config['log_level'] = old_config.delete('loglevel')
60
+ end
61
+
62
+ if old_config.delete('log_rotate_keep')
63
+ notice("Schleuder doesn't care about log-rotation anymore, please set up logrotate.conf or similar instead.")
64
+ end
65
+
66
+ old_config['admins'] = old_config.delete('adminaddr').collect do |admin|
67
+ m = member_key(Schleuder::Member.new(:email => admin))
68
+ m.to_hash
69
+ end
70
+ old_config['key_fingerprint'] = Schleuder.list.key_fingerprint
71
+
72
+ File.open(File.join(new_dir, Schleuder.config.lists_configfile),'w') { |f| f << YAML::dump(old_config.to_hash) }
73
+ # reload list config
74
+ Schleuder.list = Schleuder::List.new(old_config['myaddr'])
75
+ end
76
+
77
+ def harden_members
78
+ Schleuder.list.members = Schleuder.list.members.collect { |member| member_key(member) }
79
+ end
80
+
81
+ def change_pubkey(old_config)
82
+ _name = old_config['myname']
83
+ _email = old_config['myaddr']
84
+ _pass = old_config['gpg_password']
85
+
86
+ # Fix for gpgme-ruby >= 1.0.8
87
+ GPGME::check_version('0.0.0') if GPGME.respond_to?('check_version')
88
+
89
+ # Add listname-request@ and listname-ownerhostname as UID.
90
+ gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email} adduid"
91
+ Open3.popen3(gpg_adduid) do |stdin, stdout, stderr|
92
+ owner_done = false
93
+ request_done = false
94
+ while line = stdout.readline rescue nil;
95
+ case line.chomp
96
+ when '[GNUPG:] GET_LINE keygen.name' then
97
+ reply = _name
98
+ when '[GNUPG:] GET_LINE keygen.email' then
99
+ if !request_done
100
+ email = _email.sub(/@/, '-request@')
101
+ request_done = true
102
+ else
103
+ email = _email.sub(/@/, '-owner@')
104
+ end
105
+ reply = email
106
+ when '[GNUPG:] GET_LINE keygen.comment' then
107
+ reply = 'schleuder list'
108
+ when '[GNUPG:] GET_HIDDEN passphrase.enter' then
109
+ reply = _pass
110
+ when '[GNUPG:] GET_LINE keyedit.prompt' then
111
+ if !owner_done
112
+ reply = "adduid"
113
+ owner_done = true
114
+ else
115
+ reply = "save"
116
+ end
117
+ else
118
+ reply = nil
119
+ end
120
+ #$stderr.puts line
121
+ if reply
122
+ #$stderr.puts reply
123
+ stdin.puts reply
124
+ end
125
+ end
126
+ end
127
+
128
+ # Make list@host the primary UID to avoid confusion.
129
+ # For some f***** up reason these two time calling gpg do not work in one run.
130
+ gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email}"
131
+ Open3.popen3(gpg_adduid) do |stdin, stdout,stderr|
132
+ uid_done = false
133
+ primary_done = false
134
+ while line = stdout.readline rescue nil;
135
+ case line.chomp
136
+ when '[GNUPG:] GET_LINE keyedit.prompt' then
137
+ if ! uid_done
138
+ reply = "uid 2"
139
+ uid_done = true
140
+ elsif ! primary_done
141
+ reply = "primary"
142
+ primary_done = true
143
+ else
144
+ reply = "save"
145
+ end
146
+ when '[GNUPG:] GET_HIDDEN passphrase.enter' then
147
+ reply = _pass
148
+ else
149
+ reply = nil
150
+ end
151
+ #$stderr.puts line
152
+ if reply
153
+ #$stderr.puts reply
154
+ stdin.puts reply
155
+ end
156
+ end
157
+ end
158
+ $stderr.puts
159
+ notice("Added address-extensions as UIDs to public key of list.")
160
+ end
161
+
162
+ ## run
163
+
164
+
165
+ old_config = YAML.load_file(list_config)
166
+ old_config['myname']||=File.basename(File.dirname(list_config))
167
+ Schleuder.list = Schleuder::List.new(File.basename(File.dirname(list_config)))
168
+ old_dir = File.dirname(list_config)
169
+
170
+ files = Dir["#{old_dir}/*"].inject({}) do |files, file|
171
+ files[File.basename(file)] = [:uid, :gid, :mode].inject({}) do |hash, sym|
172
+ hash[sym] = File.stat(file).send(sym)
173
+ hash
174
+ end
175
+ files
176
+ end
177
+
178
+ ENV['GNUPGHOME'] = new_dir = move_listdir(old_dir,old_config)
179
+ ENV.delete('GPG_AGENT_INFO') # might interfer with changing uids
180
+
181
+ change_pubkey(old_config)
182
+ fix_list_conf(old_config, new_dir)
183
+ harden_members
184
+
185
+ # Fix owner/modes if changed
186
+ files.each do |file, stat|
187
+ file = File.join(new_dir,file)
188
+ [file, "#{file}~"].each do |f|
189
+ if File.exist?(f)
190
+ File.chown(stat[:uid], stat[:gid], f) if File.stat(f).uid != stat[:uid] || File.stat(f).gid != stat[:gid]
191
+ File.chmod(stat[:mode], f) if File.stat(f).mode != stat[:mode]
192
+ end
193
+ end
194
+ end
195
+
196
+ puts "There're some manual steps required to finalize the migration:
197
+ - add two aliases for the list to your MTA:
198
+ #{Schleuder.list.request_addr}
199
+ and
200
+ #{Schleuder.list.owner_addr}
201
+
202
+ Running now the Schleuder test routine, which might give additional hints if something might be wrong"
203
+
204
+ Schleuder::Processor.test(old_config['myaddr'])
205
+
@@ -0,0 +1,384 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + '/../lib'
4
+ require 'schleuder'
5
+ require 'etc'
6
+ require 'open3'
7
+
8
+ class ListCreator
9
+ def self.usage
10
+ puts "Usage:
11
+ Required options:
12
+ listname@hostname.tld
13
+ Not required options (user will be promted unless -nointeractive is set or not run in a terminal),
14
+ -realname \"Foo List\"
15
+ -adminaddress listadmin@foobar.com
16
+ -initmember member1@foobar.com -initmemberkey /path/to/initmember_publickey
17
+ Optional options (flags on the same line have to be used together):
18
+ -mailuser mail (The user, which will invoke schleuder from your MTA, if non is supplied, the current user is taken)
19
+ -privatekeyfile /path/to/privatekey -publickeyfile /path/to/publickey -passphrase key_passphrase
20
+ -nointeractive
21
+
22
+ #{File.basename($0)} listname@hostname.tld (-realname \"Foo List\") (-adminaddress listadmin@foobar.com) (-initmember member1@foobar.com -initmemberkey /path/to/initmember_publickey) [-privatekeyfile /path/to/privatekey -publickeyfile /path/to/publickey -passphrase key_passphrase] [-nointeractive]"
23
+ exit 1
24
+ end
25
+
26
+
27
+ def self.process(arg)
28
+ # set safe umask
29
+ File.umask(0077)
30
+
31
+ listname = ARGV.shift.to_s
32
+ usage unless listname.split('@').size == 2
33
+ args = Hash.new
34
+ interactive = STDIN.tty?
35
+ while nextarg = ARGV.shift
36
+ if nextarg == '-realname'
37
+ args[:list_realname] = ARGV.shift
38
+ elsif nextarg == '-c'
39
+ Schleuder.config(ARGV.shift)
40
+ elsif nextarg == '-adminaddress'
41
+ args[:list_adminaddress] = ARGV.shift
42
+ elsif nextarg == '-initmember'
43
+ args[:list_initmember] = ARGV.shift
44
+ elsif nextarg == '-initmemberkey'
45
+ args[:list_initmemberkey] = ARGV.shift
46
+ elsif nextarg == '-privatekeyfile'
47
+ args[:list_privatekeyfile] = ARGV.shift
48
+ elsif nextarg == '-publickeyfile'
49
+ args[:list_publickeyfile] = ARGV.shift
50
+ elsif nextarg == '-passphrase'
51
+ args[:list_passphrase] = ARGV.shift
52
+ elsif nextarg == '-mailuser'
53
+ args[:mailuser] = ARGV.shift
54
+ elsif nextarg == '-nointeractive'
55
+ interactive = false
56
+ else
57
+ usage
58
+ end
59
+ end
60
+ Schleuder.log.debug "Calling Processor.newlist(#{listname})"
61
+ begin
62
+ ListCreator::create(listname,interactive,args)
63
+ rescue NewListError => e
64
+ puts "Error while creating new list: " + e.message
65
+ exit 1
66
+ end
67
+ end
68
+
69
+ # Creates a new list
70
+ # listname: name of the list
71
+ # interactive: Wether we can ask for missing informations. This requires ruby-highline! (Default: true)
72
+ # args: additional parameters as hash
73
+ def self.create(listname,interactive=true,args=nil)
74
+
75
+ # verfiy all arguments quite in a huge block
76
+ Schleuder.log.debug "Verifying arguments..."
77
+ args = Hash.new if args.nil?
78
+ begin
79
+ require 'highline/import' if interactive
80
+ rescue LoadError => ex
81
+ puts "Unable to load 'highline'.\n\n"
82
+ puts "Please install the highline gem before trying to use"
83
+ puts "#{$0} in interactive mode."
84
+ exit 1
85
+ end
86
+
87
+ # verify basic information
88
+ Schleuder.log.debug "Verifying basic information..."
89
+ listname = ListCreator::verify_strvar(listname,interactive,"The listname")
90
+ listdir = File.join([Schleuder.config.lists_dir, listname.split('@').reverse].flatten)
91
+ raise NewListError, "List or parts of a list named: #{listname} already exists!" if File.directory?(listdir)
92
+ list_email = ListCreator::verify_emailvar(listname,interactive,"The lists's email address")
93
+ list_realname = ListCreator::verify_strvar(args[:list_realname],interactive,"'Realname' (for GPG-key and email-headers)")
94
+ list_adminaddress = ListCreator::verify_emailvar(args[:list_adminaddress],interactive,"Admin email address")
95
+
96
+ raise NewListError,"Lists' email address and the admin address can't be the same" if list_email == list_adminaddress
97
+
98
+ # verify keyfiles
99
+ Schleuder.log.debug "Verifying keyfiles..."
100
+ list_privatekeyfile = args[:list_privatekeyfile] || 'none'
101
+ list_publickeyfile = args[:list_publickeyfile] || 'none'
102
+ list_passphrase = args[:list_passphrase] || 'none'
103
+ unless args[:mailuser].nil?
104
+ mailuser = Etc.getpwnam(args[:mailuser]).uid
105
+ else
106
+ mailuser = Process::Sys.getuid
107
+ end
108
+ unless (list_privatekeyfile == 'none') and
109
+ (list_publickeyfile == 'none') and
110
+ (list_passphrase == 'none') then
111
+ list_privatekeyfile = ListCreator::verify_filevar(
112
+ args[:list_privatekeyfile] || '',
113
+ interactive,
114
+ "the lists' private key file"
115
+ )
116
+ list_publickeyfile = ListCreator::verify_filevar(
117
+ args[:list_publickeyfile] || '',
118
+ interactive,
119
+ "the lists' public key file"
120
+ )
121
+ list_passphrase = ListCreator::verify_strvar(
122
+ args[:list_passphrase] || '',
123
+ interactive,
124
+ "the lists' key passphrase",
125
+ false
126
+ )
127
+ end
128
+
129
+ # Verify init member
130
+ Schleuder.log.debug "Verifying init member..."
131
+ list_initmember = ListCreator::verify_emailvar(
132
+ args[:list_initmember] || '',
133
+ interactive,
134
+ "Email address of the lists' initial member"
135
+ )
136
+ list_initmemberkey = ListCreator::verify_filevar(
137
+ args[:list_initmemberkey] || '',
138
+ interactive,
139
+ "the public key of the lists' initial member"
140
+ )
141
+ Schleuder.log.debug "Arguments verified..."
142
+
143
+ Schleuder.log.debug "Initialize list..."
144
+ list = ListCreator::init_list(listname,listdir)
145
+
146
+ Schleuder.log.debug "Set list options..."
147
+ list.config.myaddr = list_email.to_s
148
+ list.config.myname = list_realname.to_s
149
+
150
+ if list_passphrase == 'none' then
151
+ list.config.gpg_password = Schleuder::Utils::random_password.to_s
152
+ else
153
+ list.config.gpg_password = list_passphrase.to_s
154
+ end
155
+
156
+ if (list_privatekeyfile == 'none' and list_publickeyfile == 'none') then
157
+ Schleuder.log.debug "Generate list's keypair..."
158
+ puts "Creating list key, this can take some time..." if interactive
159
+ ListCreator::generate_fresh_keypair(listdir,list.config,interactive)
160
+ else
161
+ Schleuder.log.debug "Import list's keypair..."
162
+ ListCreator::import_keypair(list,list_privatekeyfile,list_publickeyfile)
163
+ end
164
+ if (list_initmember != 'none' and list_initmemberkey != 'none') then
165
+ Schleuder.log.debug "Add initmember to list..."
166
+ ListCreator::add_init_member(list,list_initmember,list_initmemberkey)
167
+ end
168
+
169
+ # set the lists key_fingerprint
170
+ list.config.key_fingerprint = list.key_fingerprint
171
+
172
+ # add the admin here, as we should have already imported the key at this point
173
+ new_admin = Schleuder::Member.new(:email => list_adminaddress.to_s)
174
+ key, msg = new_admin.key
175
+ if key
176
+ new_admin.key_fingerprint = key.subkeys.first.fingerprint
177
+ list.config.admins = new_admin
178
+ else
179
+ raise NewListError,"Could not find a suitable key for the list admin. Reason: #{msg}"
180
+ end
181
+
182
+ # store the config
183
+ Schleuder.log.debug "Store list config..."
184
+ list.config = list.config
185
+ Schleuder.log.debug "Changing ownership..."
186
+ ListCreator::filepermissions(listdir,mailuser)
187
+ Schleuder.log.debug "List successfully created..."
188
+ ListCreator::print_list_infos(list) if interactive
189
+ end
190
+
191
+ private
192
+
193
+ def self.init_list(listname,listdir)
194
+ require 'fileutils'
195
+ FileUtils.mkdir_p(listdir)
196
+ list = Schleuder::List.new(listname,true)
197
+ ENV['GNUPGHOME'] = listdir
198
+ list
199
+ end
200
+
201
+ def self.add_init_member(list,list_initmember,list_initmemberkey)
202
+ if key = Schleuder::Crypt.new(list.config.gpg_password).add_key_from_file(list_initmemberkey).imports.first
203
+ list.members = Array.new(1,Schleuder::Member.new({ :email => list_initmember, :key_fingerprint => key.fingerprint }))
204
+ else
205
+ raise NewListError,"Importing the init member key failed for some reason. Please verify the passed keyfile!"
206
+ end
207
+ end
208
+
209
+ def self.verify_strvar(var,interactive,question, echo=true)
210
+ if (var.nil? or var.empty?) and interactive then
211
+ str = question+": "
212
+ if echo
213
+ var = ask(str)
214
+ else
215
+ var = ask(str) { |question| question.echo = '*' }
216
+ end
217
+ end
218
+ raise NewListError,"Missing mandatory variable: "+question if (var.nil? or var.empty?)
219
+ var
220
+ end
221
+
222
+ def self.verify_emailvar(var,interactive,question)
223
+ var = ListCreator::verify_strvar(var,interactive,question)
224
+ begin
225
+ Schleuder::Utils::verify_addr(question,var)
226
+ rescue Exception => e
227
+ raise NewListError,"Mandatory emailaddress (#{question}) is not valid: " + e.message
228
+ end
229
+ var
230
+ end
231
+
232
+ def self.verify_filevar(var,interactive,question)
233
+ if (not var.nil? and not File.exist?(var)) and interactive then
234
+ var = ask("Filepath for "+question+": ")
235
+ end
236
+ raise NewListError,"Missing mandatory file: "+question if (not var.nil? and not File.exist?(var))
237
+ var
238
+ end
239
+
240
+ def self.progfunc(hook, what, type, current, total)
241
+ $stderr.write("#{what}: #{current}/#{total}\r")
242
+ $stderr.flush
243
+ end
244
+
245
+
246
+ def self.generate_fresh_keypair(listdir,listconfig,interactive)
247
+ _name = listconfig.myname
248
+ _email = listconfig.myaddr
249
+ _pass = listconfig.gpg_password
250
+ _type = Schleuder.config.gpg_key_type
251
+ _length = Schleuder.config.gpg_key_length
252
+ _sub_type = Schleuder.config.gpg_subkey_type
253
+ _sub_length = Schleuder.config.gpg_subkey_length
254
+ if GPGME.respond_to? 'check_version'
255
+ GPGME::check_version('0.0.0')
256
+ end
257
+ GPGME::Ctx.new.genkey(
258
+ ListCreator::create_gnupg_params_template(_name,_email,_pass,_type,_length,_sub_type,_sub_length),
259
+ nil,nil
260
+ )
261
+
262
+ # Add listname-request@hostname as UID.
263
+ gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email} adduid"
264
+ Open3.popen3(gpg_adduid) do |stdin, stdout|
265
+ owner_done = false
266
+ request_done = false
267
+ while line = stdout.readline rescue nil;
268
+ case line.chomp
269
+ when '[GNUPG:] GET_LINE keygen.name' then
270
+ reply = _name
271
+ when '[GNUPG:] GET_LINE keygen.email' then
272
+ if ! request_done
273
+ email = _email.sub(/@/, '-request@')
274
+ request_done = true
275
+ else
276
+ email = _email.sub(/@/, '-owner@')
277
+ end
278
+ reply = email
279
+ when '[GNUPG:] GET_LINE keygen.comment' then
280
+ reply = 'schleuder list'
281
+ when '[GNUPG:] GET_HIDDEN passphrase.enter' then
282
+ reply = _pass
283
+ when '[GNUPG:] GET_LINE keyedit.prompt' then
284
+ if ! owner_done
285
+ reply = "adduid"
286
+ owner_done = true
287
+ else
288
+ reply = "save"
289
+ end
290
+ else
291
+ reply = nil
292
+ end
293
+ #$stderr.puts line
294
+ if reply
295
+ #$stderr.puts reply
296
+ stdin.puts reply
297
+ end
298
+ end
299
+ end
300
+
301
+ # Make list@host the primary UID to avoid confusion.
302
+ # For some f***** up reason these two time calling gpg do not work in one run.
303
+ gpg_adduid = "gpg --no-tty --command-fd 0 --status-fd 1 --yes --edit-key #{_email}"
304
+ Open3.popen3(gpg_adduid) do |stdin, stdout|
305
+ uid_done = false
306
+ primary_done = false
307
+ while line = stdout.readline rescue nil;
308
+ case line.chomp
309
+ when '[GNUPG:] GET_LINE keyedit.prompt' then
310
+ if ! uid_done
311
+ reply = "uid 2"
312
+ uid_done = true
313
+ elsif ! primary_done
314
+ reply = "primary"
315
+ primary_done = true
316
+ else
317
+ reply = "save"
318
+ end
319
+ when '[GNUPG:] GET_HIDDEN passphrase.enter' then
320
+ reply = _pass
321
+ else
322
+ reply = nil
323
+ end
324
+ #$stderr.puts line
325
+ if reply
326
+ #$stderr.puts reply
327
+ stdin.puts reply
328
+ end
329
+ end
330
+ end
331
+ $stderr.puts
332
+ end
333
+
334
+ def self.import_keypair(list,list_privatekeyfile,list_publickeyfile)
335
+ crypt = Schleuder::Crypt.new(list.config.gpg_password)
336
+ Schleuder.log.debug "Importing private key from #{list_privatekeyfile}"
337
+ crypt.add_key_from_file(list_privatekeyfile)
338
+ Schleuder.log.debug "Importing public key from #{list_publickeyfile}"
339
+ crypt.add_key_from_file(list_publickeyfile)
340
+ end
341
+
342
+ def self.create_gnupg_params_template(name,email,pass,type,length,sub_type,sub_length)
343
+ "<GnupgKeyParms format=\"internal\">
344
+ Key-Type: #{type}
345
+ Key-Length: #{length}
346
+ Subkey-Type: #{sub_type}
347
+ Subkey-Length: #{sub_length}
348
+ Name-Real: #{name}
349
+ Name-Comment: schleuder list
350
+ Name-Email: #{email}
351
+ Expire-Date: 0
352
+ Passphrase: #{pass}
353
+ </GnupgKeyParms>"
354
+ end
355
+
356
+ def self.filepermissions(listdir, mailuser)
357
+ File.chown(mailuser,nil,listdir)
358
+ File.chmod(0700,listdir)
359
+ Dir.new(listdir).each{ |f|
360
+ unless f =~ /^\./
361
+ File.chown(mailuser,nil,listdir+"/"+f)
362
+ File.chmod(0600)
363
+ end
364
+ }
365
+ end
366
+
367
+ def self.print_list_infos(list)
368
+ puts "A new schleuder list called '#{list.config.myname}' has been created.".fmt
369
+ puts
370
+ puts "To get a working list you have to tell your MTA to handle this list. For various examples have a look at <http://schleuder.nadir.org/documentation/creating_lists.html>".fmt
371
+ puts
372
+ puts "Lists' key fingerprint:".fmt
373
+ crypt = Schleuder::Crypt.new(list.config.gpg_password)
374
+ key = crypt.get_key(list.config.myaddr).first
375
+ puts Schleuder::Utils::get_pretty_fingerprint(key)
376
+ end
377
+ end
378
+
379
+ begin
380
+ ListCreator.process(ARGV)
381
+ rescue NewListError => e
382
+ puts "Error while creating new list: " + e.message
383
+ exit 1
384
+ end