smailr 0.6.2 → 0.7.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.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/bin/smailr +10 -236
- data/lib/smailr.rb +60 -34
- data/lib/smailr/alias.rb +28 -29
- data/lib/smailr/cli.rb +262 -0
- data/lib/smailr/dkim.rb +24 -28
- data/lib/smailr/domain.rb +13 -14
- data/lib/smailr/mailbox.rb +22 -23
- data/lib/smailr/model.rb +50 -50
- data/lib/smailr/setup.rb +6 -2
- data/migrations/005_mailboxes_add_digest_identifier_to_passwords.rb +15 -15
- data/migrations/006_mailboxes_password_schema_allow_null.rb +12 -0
- metadata +14 -14
- data/bin/commander +0 -16
- data/bin/sequel +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd1155588b6637a588d5284aefb168421f2a5325
|
4
|
+
data.tar.gz: d750025813678d2d6aadff17b3ebf3efc729fd7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d9da463d534d61cc9e1e7942d11a7d7756b18b74b150c85e31498cc2b3e1f12778c00be5fcbe9c444b9b0434cd22e2f32e070c0f9845d344602bff906ce034
|
7
|
+
data.tar.gz: 2297af6c3b3ce95dd82f9cc6279487f2de6cf37c8faaeb8141e768a0b6596890024c21c1f175ed8d969bb295b054350fada39601d2ba36f3c84cbc592919965d
|
data/README.md
CHANGED
@@ -157,9 +157,9 @@ automatically. Open mutt for the specified mailbox:
|
|
157
157
|
### Verify
|
158
158
|
|
159
159
|
Smailr generates a report via the Port25 SMTP Verifier. It generates a test,
|
160
|
-
sends it to
|
161
|
-
return generate a echo message with a report about
|
162
|
-
|
160
|
+
sends it to check-auth-user=eaxmple.comt@verifier.port25.com, which will in
|
161
|
+
return generate a echo message with a report about results of many SMTP
|
162
|
+
components: SPF, SenderID, DomainKeys, DKIM and Spamassassin.
|
163
163
|
|
164
164
|
To generate a message, sent from user@example.com and return the report to the
|
165
165
|
same address simply call the following command:
|
data/bin/smailr
CHANGED
@@ -1,241 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
require 'smailr'
|
5
|
-
|
2
|
+
#$: << File.expand_path('../../lib', __FILE__)
|
6
3
|
#
|
7
|
-
#
|
4
|
+
#require 'pathname'
|
5
|
+
#ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
6
|
+
# Pathname.new(__FILE__).realpath)
|
8
7
|
#
|
9
|
-
|
10
|
-
|
11
|
-
return :address if string =~ /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i
|
12
|
-
end
|
13
|
-
|
14
|
-
def ask_password
|
15
|
-
min_password_length = Smailr.config["password_policy"]["length"]
|
16
|
-
|
17
|
-
password = ask("Password: ") { |q| q.echo = "*" }
|
18
|
-
confirm = ask("Confirm: ") { |q| q.echo = "*" }
|
19
|
-
|
20
|
-
if password != confirm
|
21
|
-
say("Mismatch; try again.")
|
22
|
-
ask_password
|
23
|
-
end
|
24
|
-
|
25
|
-
if password.length < min_password_length.to_i
|
26
|
-
say("Too short; try again.")
|
27
|
-
ask_password
|
28
|
-
end
|
29
|
-
|
30
|
-
password
|
31
|
-
end
|
32
|
-
|
33
|
-
program :version, Smailr::VERSION
|
34
|
-
program :description, 'Simple MAIL manageR - Virtual mail hosting management from the CLI'
|
35
|
-
|
36
|
-
|
37
|
-
#
|
38
|
-
# Commands
|
39
|
-
#
|
40
|
-
command :add do |c|
|
41
|
-
c.syntax = 'smailr add domain | mailbox | alias [options]'
|
42
|
-
c.summary = 'Add a new domain, mailbox or alias to the mail system.'
|
43
|
-
c.example 'Add a domain', 'smailr add example.com'
|
44
|
-
c.example 'Add a mailbox', 'smailr add user@example.com'
|
45
|
-
c.example 'Add an alias', 'smailr add alias@localdom.com --alias user@example.com,user1@example.com'
|
46
|
-
c.example 'Setup DKIM for a domain', 'smailr add ono.at --dkim'
|
47
|
-
c.option '--alias DESTINATION', String, 'Specify the alias destination.'
|
48
|
-
c.option '--password PASSWORD', String, 'The password for a new mailbox. If you omit this option, it prompts for one.'
|
49
|
-
c.option '--dkim SELECTOR', String, 'Add a DKIM Key with the specified selector for domain.'
|
50
|
-
c.action do |args, options|
|
51
|
-
address = args[0]
|
52
|
-
type = determine_object(address)
|
53
|
-
|
54
|
-
case type
|
55
|
-
when :domain
|
56
|
-
if options.dkim
|
57
|
-
selector = options.dkim
|
58
|
-
key = Smailr::Dkim.add(address, selector)
|
59
|
-
|
60
|
-
puts "public-key " + key.to_a[1..-2].join.gsub(/\n/, '')
|
61
|
-
else
|
62
|
-
Smailr::Domain.add(address)
|
63
|
-
end
|
64
|
-
|
65
|
-
when :address
|
66
|
-
if options.alias
|
67
|
-
source = args[0]
|
68
|
-
destinations = options.alias.split(',')
|
69
|
-
Smailr::Alias.add(source, destinations)
|
70
|
-
else
|
71
|
-
options.password ||= ask_password
|
72
|
-
Smailr::Mailbox.add(address, options.password)
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
command :ls do |c|
|
80
|
-
c.syntax = 'smailr ls [domain]'
|
81
|
-
c.summary = 'List domains or mailboxes of a specific domain.'
|
82
|
-
c.action do |args, options|
|
83
|
-
case args[0]
|
84
|
-
when /^[^@][A-Z0-9.-]+\.[A-Z]{2,6}$/i then
|
85
|
-
domain = Smailr::Model::Domain[:fqdn => args[0]]
|
86
|
-
domain.mailboxes.each do |mbox|
|
87
|
-
puts "m: #{mbox.localpart}@#{args[0]}"
|
88
|
-
end
|
89
|
-
domain.aliases.each do |aliass|
|
90
|
-
puts "a: #{aliass.localpart}@#{args[0]} > #{aliass.dstlocalpart}@#{aliass.dstdomain}"
|
91
|
-
end
|
92
|
-
when nil
|
93
|
-
domains = Smailr::DB[:domains]
|
94
|
-
domains.all.each do |d|
|
95
|
-
domain = Smailr::Model::Domain[:fqdn => d[:fqdn]]
|
96
|
-
puts d[:fqdn]
|
97
|
-
end
|
98
|
-
else
|
99
|
-
error "You can either list a domains or a domains addresses."
|
100
|
-
exit 1
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
command :rm do |c|
|
106
|
-
c.syntax = 'smailr rm domain | mailbox [options]'
|
107
|
-
c.summary = 'Remove a domain, mailbox or alias known to the mail system.'
|
108
|
-
c.example 'Remove a domain', 'smailr rm example.com'
|
109
|
-
c.option '--force', 'Force the operation, do not ask for confirmation.'
|
110
|
-
c.option '--dkim SELECTOR', String, 'Remove a dkim key.'
|
111
|
-
c.option '--alias DESTINATION', String, 'Specify the destination you want to remove from the alias.'
|
112
|
-
c.action do |args, options|
|
113
|
-
address = args[0]
|
114
|
-
type = determine_object(address)
|
115
|
-
case type
|
116
|
-
when :domain
|
117
|
-
if options.dkim
|
118
|
-
selecotr = options.dkim
|
119
|
-
Smailr::Dkim.rm(address, selector)
|
120
|
-
else
|
121
|
-
Smailr::Domain.rm(address, options.force)
|
122
|
-
end
|
123
|
-
|
124
|
-
when :address
|
125
|
-
if options.alias
|
126
|
-
source = args[0]
|
127
|
-
destinations = options.alias.split(',')
|
8
|
+
#require 'rubygems'
|
9
|
+
#require 'bundler/setup'
|
128
10
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
command :passwd do |c|
|
138
|
-
c.syntax = 'smailr passwd mailbox'
|
139
|
-
c.summary = 'Update a users password.'
|
140
|
-
c.action do |args,options|
|
141
|
-
address = args[0]
|
142
|
-
password = ask_password
|
143
|
-
Smailr::Mailbox.update_password(address, password)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
command :setup do |c|
|
149
|
-
c.syntax = 'smailr setup'
|
150
|
-
c.summary = 'Install all required components on a mailserver'
|
151
|
-
c.action do |args,options|
|
152
|
-
Smailr::Setup.run
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
command :migrate do |c|
|
158
|
-
c.syntax = 'smailr migrate [options]'
|
159
|
-
c.summary = 'Create database and run migrations'
|
160
|
-
c.option '--to VERSION', String, 'Migrate the database to a specifict version.'
|
161
|
-
c.action do |args,options|
|
162
|
-
require 'sequel/extensions/migration'
|
163
|
-
raise "Database not configured" unless Smailr::DB
|
164
|
-
|
165
|
-
if options.version.nil?
|
166
|
-
Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory)
|
167
|
-
else
|
168
|
-
Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory, :target => options.version.to_i)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
command :mutt do |c|
|
175
|
-
base = Smailr.config["mail_spool_path"]
|
176
|
-
|
177
|
-
c.syntax = "smailr mutt address"
|
178
|
-
c.summary = "View the mailbox of the specified address in mutt."
|
179
|
-
c.description = "Open the mailbox of the specified address in mutt.\n\n " +
|
180
|
-
"Requires that mutt is installed and tries to find a suitable maildir in: " + base
|
181
|
-
c.example 'Open test@example.com', 'smailr mutt test@example.com'
|
182
|
-
c.action do |args,options|
|
183
|
-
localpart, fqdn = args[0].split('@')
|
184
|
-
|
185
|
-
mutt = `command -v mutt || { echo "Please install mutt first. Aborting." >&2; exit 1; }`
|
186
|
-
if $?
|
187
|
-
|
188
|
-
possibilities = [
|
189
|
-
"#{base}/#{fqdn}/#{localpart}/Maildir",
|
190
|
-
"#{base}/users/#{fqdn}/#{localpart}/Maildir",
|
191
|
-
"#{base}/users/#{fqdn}/#{localpart}/.maildir",
|
192
|
-
"#{base}/users/#{fqdn}/#{localpart}"
|
193
|
-
]
|
194
|
-
|
195
|
-
possibilities.each do |path|
|
196
|
-
if File.readable?(path)
|
197
|
-
puts "Opening maildir #{path} with mutt."
|
198
|
-
exec "MAIL=#{path} MAILDIR=#{path} #{mutt} -mMaildir"
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
command :verify do |c|
|
206
|
-
c.syntax = "smailr verify address"
|
207
|
-
c.summary = "Send out a test message to verify a domains configuration via verifier.port25.com"
|
208
|
-
c.description = "A reply email will be sent back to you with an analysis of the message’s authentication" +
|
209
|
-
"status. The report will perform the following checks: SPF, SenderID, DomainKeys, DKIM " +
|
210
|
-
"and Spamassassin.\n\n"
|
211
|
-
c.example 'Verify test@example.com (report will be sent to test@example.com)', 'smailr verify test@example.com'
|
212
|
-
c.example 'Verify test@example.com, send report to root@example.com', 'smailr verify test@example.com --report-to root@example.com'
|
213
|
-
|
214
|
-
c.option '-r DESTINATION', '--report-to DESTINATION', String, 'Send the report to the specified address instead.'
|
215
|
-
|
216
|
-
c.action do |args,options|
|
217
|
-
from = args[0]
|
218
|
-
options.default :report_to => from
|
219
|
-
|
220
|
-
dstlocalpart, dstfqdn = options.report_to.split('@')
|
221
|
-
|
222
|
-
require 'socket'
|
223
|
-
require 'date'
|
224
|
-
require 'net/smtp'
|
225
|
-
Net::SMTP.start('localhost', 25) do |smtp|
|
226
|
-
to = "check-auth-#{dstlocalpart}=#{dstfqdn}@verifier.port25.com"
|
227
|
-
|
228
|
-
message = [
|
229
|
-
"From: #{from}",
|
230
|
-
"To: #{to}",
|
231
|
-
"Subject: Port25 Mail Verification Test",
|
232
|
-
"Date: #{DateTime.now.strftime("%a, %d %b %Y %H:%M:%S %z")}",
|
233
|
-
"",
|
234
|
-
"This is a test message for the port25 mail verification test, it was",
|
235
|
-
"sent from the following server: #{Socket.gethostname}."
|
236
|
-
].join("\r\n")
|
11
|
+
require 'smailr'
|
12
|
+
require 'smailr/cli'
|
13
|
+
require 'smailr/setup'
|
237
14
|
|
238
|
-
|
239
|
-
end
|
240
|
-
end
|
241
|
-
end
|
15
|
+
Smailr::Cli.new.run
|
data/lib/smailr.rb
CHANGED
@@ -1,47 +1,73 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
|
3
|
-
require 'sqlite3'
|
4
|
-
require 'sequel'
|
5
|
-
require 'commander/import'
|
2
|
+
|
6
3
|
require 'fileutils'
|
4
|
+
require 'logger'
|
5
|
+
require 'sequel'
|
6
|
+
require 'sqlite3'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
# dkim
|
10
|
+
require 'date'
|
11
|
+
require 'openssl'
|
12
|
+
|
13
|
+
require 'smailr/alias'
|
14
|
+
require 'smailr/dkim'
|
15
|
+
require 'smailr/domain'
|
16
|
+
require 'smailr/mailbox'
|
7
17
|
|
8
18
|
module Smailr
|
9
|
-
VERSION = '0.6.2'
|
10
|
-
|
11
|
-
autoload :Model, 'smailr/model'
|
12
|
-
autoload :Domain, 'smailr/domain'
|
13
|
-
autoload :Mailbox, 'smailr/mailbox'
|
14
|
-
autoload :Alias, 'smailr/alias'
|
15
|
-
autoload :Dkim, 'smailr/dkim'
|
16
|
-
autoload :Setup, 'smailr/setup'
|
17
|
-
|
18
|
-
class << self;
|
19
|
-
attr_accessor :config
|
20
|
-
attr_accessor :config_files
|
21
|
-
attr_accessor :load_config
|
22
|
-
attr_accessor :contrib_directory
|
23
|
-
attr_accessor :migrations_directory
|
24
|
-
end
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
config.merge!(YAML.load_file(f))
|
31
|
-
end
|
32
|
-
end
|
33
|
-
self.config = config
|
34
|
-
end
|
20
|
+
# Exception Classes
|
21
|
+
class MissingDomain < StandardError ; end
|
22
|
+
|
23
|
+
VERSION = '0.7.0'
|
35
24
|
|
36
|
-
|
37
|
-
|
25
|
+
class << self;
|
26
|
+
attr_accessor :config
|
27
|
+
attr_accessor :config_files
|
28
|
+
attr_accessor :load_config
|
29
|
+
attr_accessor :contrib_directory
|
30
|
+
attr_accessor :migrations_directory
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.load_config
|
34
|
+
config = {}
|
35
|
+
config_files.each do |f|
|
36
|
+
if File.readable?(f)
|
37
|
+
config.merge!(YAML.load_file(f))
|
38
|
+
end
|
38
39
|
end
|
40
|
+
self.config = config
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.db_connect
|
44
|
+
Sequel.connect(self.config['database'])
|
45
|
+
end
|
39
46
|
|
47
|
+
def self.logger
|
48
|
+
unless @logger
|
49
|
+
@logger = Logger.new(STDOUT)
|
50
|
+
@logger.level = Logger::Severity::DEBUG
|
51
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
52
|
+
if severity == "ERROR"
|
53
|
+
"ERROR: #{msg}\n"
|
54
|
+
else
|
55
|
+
"#{msg}\n"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@logger
|
60
|
+
end
|
40
61
|
|
62
|
+
def self.logger=(logger)
|
63
|
+
@logger = logger
|
64
|
+
end
|
41
65
|
end
|
42
66
|
|
43
|
-
Smailr.contrib_directory ||=
|
44
|
-
Smailr.migrations_directory ||=
|
45
|
-
Smailr.config_files ||=
|
67
|
+
Smailr.contrib_directory ||= File.expand_path('../../contrib', __FILE__)
|
68
|
+
Smailr.migrations_directory ||= File.expand_path('../../migrations', __FILE__)
|
69
|
+
Smailr.config_files ||= [ File.expand_path('../../smailr.yml', __FILE__), '/etc/smailr.yml']
|
46
70
|
Smailr.load_config
|
47
71
|
Smailr::DB = Smailr::db_connect
|
72
|
+
require 'smailr/model'
|
73
|
+
Smailr::DB.sql_log_level = :debug
|
data/lib/smailr/alias.rb
CHANGED
@@ -1,40 +1,39 @@
|
|
1
1
|
module Smailr
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
class Alias
|
3
|
+
def self.add(source, destinations)
|
4
|
+
srclocalpart, srcdomain = source.split('@')
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
6
|
+
# We don't want aliases for non-local domains, since the
|
7
|
+
# exim router won't accept it.
|
8
|
+
if not Model::Domain[:fqdn => srcdomain].exists?
|
9
|
+
raise MissingDomain, "You are trying to add an alias for a non existing domain: #{source}"
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
12
|
+
destinations.each do |dst|
|
13
|
+
dstlocalpart, dstdomain = dst.split('@')
|
15
14
|
|
16
|
-
|
15
|
+
Smailr::logger.warn("Adding alias: #{source} -> #{dst}")
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
Model::Alias.find_or_create(:domain => Model::Domain[:fqdn => srcdomain],
|
18
|
+
:localpart => srclocalpart,
|
19
|
+
:dstdomain => dstdomain,
|
20
|
+
:dstlocalpart => dstlocalpart)
|
21
|
+
end
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
24
|
+
def self.rm(source, destinations)
|
25
|
+
srclocalpart, srcdomain = source.split('@')
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
destinations.each do |dst|
|
28
|
+
Smailr::logger.warn("Removing alias: #{source} -> #{dst}")
|
30
29
|
|
31
|
-
|
30
|
+
dstlocalpart, dstdomain = dst.split('@')
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
32
|
+
Model::Alias.filter(:domain => Model::Domain[:fqdn => srcdomain],
|
33
|
+
:localpart => srclocalpart,
|
34
|
+
:dstdomain => dstdomain,
|
35
|
+
:dstlocalpart => dstlocalpart).delete
|
36
|
+
end
|
39
37
|
end
|
38
|
+
end
|
40
39
|
end
|
data/lib/smailr/cli.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'commander'
|
2
|
+
|
3
|
+
module Smailr
|
4
|
+
class Cli
|
5
|
+
|
6
|
+
include Commander::Methods
|
7
|
+
|
8
|
+
## Our own CLI Helpers
|
9
|
+
|
10
|
+
# Determine whether we the passed string is a domain or a mail
|
11
|
+
# address.
|
12
|
+
#
|
13
|
+
# Returns either :domain or :address
|
14
|
+
def determine_object(string)
|
15
|
+
return :domain if string =~ /^[^@][A-Z0-9.-]+\.[A-Z]{2,6}$/i
|
16
|
+
return :address if string =~ /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i
|
17
|
+
end
|
18
|
+
|
19
|
+
# Run an interactive cli dialog to enter and confirm a password.
|
20
|
+
#
|
21
|
+
# Returns a string containing the entered password if password and
|
22
|
+
# confirmation match.
|
23
|
+
def ask_password
|
24
|
+
min_password_length = Smailr.config["password_policy"]["length"]
|
25
|
+
|
26
|
+
password = ask("Password: ") { |q| q.echo = "*" }
|
27
|
+
confirm = ask("Confirm: ") { |q| q.echo = "*" }
|
28
|
+
|
29
|
+
if password != confirm
|
30
|
+
say("Mismatch; try again.")
|
31
|
+
ask_password
|
32
|
+
end
|
33
|
+
|
34
|
+
if password.length < min_password_length.to_i
|
35
|
+
say("Too short; try again.")
|
36
|
+
ask_password
|
37
|
+
end
|
38
|
+
|
39
|
+
password
|
40
|
+
end
|
41
|
+
|
42
|
+
# Initialize the Cli
|
43
|
+
def run
|
44
|
+
program :description, 'smailr - Virtual Mail Hosting Management CLI'
|
45
|
+
program :version, Smailr::VERSION
|
46
|
+
|
47
|
+
### Commands
|
48
|
+
|
49
|
+
command :add do |c|
|
50
|
+
c.syntax = 'smailr add domain | mailbox | alias [options]'
|
51
|
+
c.summary = 'Add a new domain, mailbox or alias to the mail system.'
|
52
|
+
c.example 'Add a domain', 'smailr add example.com'
|
53
|
+
c.example 'Add a mailbox', 'smailr add user@example.com'
|
54
|
+
c.example 'Add an alias', 'smailr add alias@localdom.com --alias user@example.com,user1@example.com'
|
55
|
+
c.example 'Setup DKIM for a domain', 'smailr add ono.at --dkim'
|
56
|
+
c.option '--alias DESTINATION', String, 'Specify the alias destination.'
|
57
|
+
c.option '--password PASSWORD', String, 'The password for a new mailbox. If you omit this option, it prompts for one.'
|
58
|
+
c.option '--dkim SELECTOR', String, 'Add a DKIM Key with the specified selector for domain.'
|
59
|
+
c.action do |args, options|
|
60
|
+
address = args[0]
|
61
|
+
type = determine_object(address)
|
62
|
+
|
63
|
+
case type
|
64
|
+
when :domain
|
65
|
+
if options.dkim
|
66
|
+
selector = options.dkim
|
67
|
+
key = Smailr::Dkim.add(address, selector)
|
68
|
+
|
69
|
+
puts "public-key " + key.split("\n").slice(1..-2).join
|
70
|
+
else
|
71
|
+
Smailr::Domain.add(address)
|
72
|
+
end
|
73
|
+
|
74
|
+
when :address
|
75
|
+
if options.alias
|
76
|
+
source = args[0]
|
77
|
+
destinations = options.alias.split(',')
|
78
|
+
Smailr::Alias.add(source, destinations)
|
79
|
+
else
|
80
|
+
options.password ||= ask_password
|
81
|
+
Smailr::Mailbox.add(address, options.password)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
command :ls do |c|
|
89
|
+
c.syntax = 'smailr ls [domain]'
|
90
|
+
c.summary = 'List domains or mailboxes and aliases of a specific domain.'
|
91
|
+
c.action do |args, options|
|
92
|
+
case args[0]
|
93
|
+
when /^[^@][A-Z0-9.-]+\.[A-Z]{2,6}$/i then
|
94
|
+
domain = Smailr::Model::Domain[:fqdn => args[0]]
|
95
|
+
domain.mailboxes.each do |mbox|
|
96
|
+
puts "m: #{mbox.localpart}@#{args[0]}"
|
97
|
+
end
|
98
|
+
domain.aliases.each do |aliass|
|
99
|
+
puts "a: #{aliass.localpart}@#{args[0]} > #{aliass.dstlocalpart}@#{aliass.dstdomain}"
|
100
|
+
end
|
101
|
+
when nil
|
102
|
+
domains = Smailr::DB[:domains]
|
103
|
+
domains.all.each do |d|
|
104
|
+
domain = Smailr::Model::Domain[:fqdn => d[:fqdn]]
|
105
|
+
puts d[:fqdn]
|
106
|
+
end
|
107
|
+
else
|
108
|
+
error "You can either list a domains or a domains addresses."
|
109
|
+
exit 1
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
command :rm do |c|
|
115
|
+
c.syntax = 'smailr rm domain | mailbox [options]'
|
116
|
+
c.summary = 'Remove a domain, mailbox or alias known to the mail system.'
|
117
|
+
c.example 'Remove a domain', 'smailr rm example.com'
|
118
|
+
c.option '--force', 'Force the operation, do not ask for confirmation.'
|
119
|
+
c.option '--dkim SELECTOR', String, 'Remove a dkim key.'
|
120
|
+
c.option '--alias DESTINATION', String, 'Specify the destination you want to remove from the alias.'
|
121
|
+
c.action do |args, options|
|
122
|
+
address = args[0]
|
123
|
+
type = determine_object(address)
|
124
|
+
case type
|
125
|
+
when :domain
|
126
|
+
if options.dkim
|
127
|
+
selector = options.dkim
|
128
|
+
Smailr::Dkim.rm(address, selector)
|
129
|
+
else
|
130
|
+
Smailr::Domain.rm(address, options.force)
|
131
|
+
end
|
132
|
+
|
133
|
+
when :address
|
134
|
+
if options.alias
|
135
|
+
source = args[0]
|
136
|
+
destinations = options.alias.split(',')
|
137
|
+
|
138
|
+
Smailr::Alias.rm(source, destinations)
|
139
|
+
else
|
140
|
+
Smailr::Mailbox.rm(address, options)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
command :passwd do |c|
|
147
|
+
c.syntax = 'smailr passwd mailbox'
|
148
|
+
c.summary = 'Update a users password.'
|
149
|
+
c.action do |args,options|
|
150
|
+
address = args[0]
|
151
|
+
password = ask_password
|
152
|
+
Smailr::Mailbox.update_password(address, password)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
command :setup do |c|
|
158
|
+
c.syntax = 'smailr setup'
|
159
|
+
c.summary = 'Install all required components on a mailserver'
|
160
|
+
c.action do |args,options|
|
161
|
+
Smailr::Setup.new.run
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
command :migrate do |c|
|
167
|
+
c.syntax = 'smailr migrate [options]'
|
168
|
+
c.summary = 'Create database and run migrations'
|
169
|
+
c.option '--to VERSION', String, 'Migrate the database to a specifict version.'
|
170
|
+
c.action do |args,options|
|
171
|
+
require 'sequel/extensions/migration'
|
172
|
+
raise "Database not configured" unless Smailr::DB
|
173
|
+
|
174
|
+
if options.to.nil?
|
175
|
+
if Sequel::Migrator.is_current?(Smailr::DB, Smailr.migrations_directory)
|
176
|
+
puts "Database schema already up to date. Exiting"
|
177
|
+
exit 0
|
178
|
+
end
|
179
|
+
|
180
|
+
puts "Running database migrations to latest version."
|
181
|
+
Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory)
|
182
|
+
else
|
183
|
+
puts "Running database migrations to version: #{options.to}"
|
184
|
+
Sequel::Migrator.apply(Smailr::DB, Smailr.migrations_directory, options.to.to_i)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
command :mutt do |c|
|
191
|
+
base = Smailr.config["mail_spool_path"]
|
192
|
+
|
193
|
+
c.syntax = "smailr mutt address"
|
194
|
+
c.summary = "View the mailbox of the specified address in mutt."
|
195
|
+
c.description = "Open the mailbox of the specified address in mutt.\n\n " +
|
196
|
+
"Requires that mutt is installed and tries to find a suitable maildir in: " + base
|
197
|
+
c.example 'Open test@example.com', 'smailr mutt test@example.com'
|
198
|
+
c.action do |args,options|
|
199
|
+
localpart, fqdn = args[0].split('@')
|
200
|
+
|
201
|
+
mutt = `command -v mutt || { echo "Please install mutt first. Aborting." >&2; exit 1; }`
|
202
|
+
if $?
|
203
|
+
|
204
|
+
possibilities = [
|
205
|
+
"#{base}/#{fqdn}/#{localpart}/Maildir",
|
206
|
+
"#{base}/users/#{fqdn}/#{localpart}/Maildir",
|
207
|
+
"#{base}/users/#{fqdn}/#{localpart}/.maildir",
|
208
|
+
"#{base}/users/#{fqdn}/#{localpart}"
|
209
|
+
]
|
210
|
+
|
211
|
+
possibilities.each do |path|
|
212
|
+
if File.readable?(path)
|
213
|
+
puts "Opening maildir #{path} with mutt."
|
214
|
+
exec "MAIL=#{path} MAILDIR=#{path} #{mutt} -mMaildir"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
command :verify do |c|
|
222
|
+
c.syntax = "smailr verify address"
|
223
|
+
c.summary = "Send out a test message to verify a domains configuration via verifier.port25.com"
|
224
|
+
c.description = "A reply email will be sent back to you with an analysis of the message’s authentication" +
|
225
|
+
"status. The report will perform the following checks: SPF, SenderID, DomainKeys, DKIM " +
|
226
|
+
"and Spamassassin.\n\n"
|
227
|
+
c.example 'Verify test@example.com (report will be sent to test@example.com)', 'smailr verify test@example.com'
|
228
|
+
c.example 'Verify test@example.com, send report to root@example.com', 'smailr verify test@example.com --report-to root@example.com'
|
229
|
+
|
230
|
+
c.option '-r DESTINATION', '--report-to DESTINATION', String, 'Send the report to the specified address instead.'
|
231
|
+
|
232
|
+
c.action do |args,options|
|
233
|
+
from = args[0]
|
234
|
+
options.default :report_to => from
|
235
|
+
|
236
|
+
dstlocalpart, dstfqdn = options.report_to.split('@')
|
237
|
+
|
238
|
+
require 'socket'
|
239
|
+
require 'date'
|
240
|
+
require 'net/smtp'
|
241
|
+
Net::SMTP.start('localhost', 25) do |smtp|
|
242
|
+
to = "check-auth-#{dstlocalpart}=#{dstfqdn}@verifier.port25.com"
|
243
|
+
|
244
|
+
message = [
|
245
|
+
"From: #{from}",
|
246
|
+
"To: #{to}",
|
247
|
+
"Subject: Port25 Mail Verification Test",
|
248
|
+
"Date: #{DateTime.now.strftime("%a, %d %b %Y %H:%M:%S %z")}",
|
249
|
+
"",
|
250
|
+
"This is a test message for the port25 mail verification test, it was",
|
251
|
+
"sent from the following server: #{Socket.gethostname}."
|
252
|
+
].join("\r\n")
|
253
|
+
|
254
|
+
smtp.send_message(message, from, to)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
run!
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
data/lib/smailr/dkim.rb
CHANGED
@@ -1,37 +1,33 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'openssl'
|
3
|
-
|
4
1
|
module Smailr
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
2
|
+
class Dkim
|
3
|
+
def self.add(fqdn, selector)
|
4
|
+
unless Model::Domain[:fqdn => fqdn]
|
5
|
+
raise MissingDomain, "You trying to add a DKIM key for a non existing domain: #{fqdn}"
|
6
|
+
end
|
11
7
|
|
12
|
-
|
8
|
+
private_key, public_key = generate_rsa_key
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
dkim = Model::Dkim.for_domain!(fqdn, selector)
|
11
|
+
dkim.private_key = private_key
|
12
|
+
dkim.public_key = public_key
|
13
|
+
dkim.selector = selector
|
14
|
+
dkim.save
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
# Return the key so it can be used for automation
|
17
|
+
dkim.public_key
|
18
|
+
end
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
def self.rm(fqdn, selector)
|
21
|
+
dkim = Model::Dkim.for_domain(fqdn, selector)
|
22
|
+
dkim.destroy
|
23
|
+
end
|
28
24
|
|
29
|
-
|
25
|
+
private
|
30
26
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
27
|
+
def self.generate_rsa_key(length = 1024)
|
28
|
+
rsa_key = OpenSSL::PKey::RSA.new(length)
|
29
|
+
[ rsa_key.to_pem,
|
30
|
+
rsa_key.public_key.to_pem ]
|
36
31
|
end
|
32
|
+
end
|
37
33
|
end
|
data/lib/smailr/domain.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
module Smailr
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def self.rm(fqdn, force = false)
|
9
|
-
if force or
|
10
|
-
agree("Do you want to remove the domain #{fqdn} and all related items? (yes/no) ")
|
2
|
+
class Domain
|
3
|
+
def self.add(fqdn)
|
4
|
+
Smailr::logger.warn("Adding domain: #{fqdn}")
|
5
|
+
Model::Domain.create(:fqdn => fqdn)
|
6
|
+
end
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
def self.rm(fqdn, force = false)
|
9
|
+
# TODO - only require force, if related entries exist
|
10
|
+
if force
|
11
|
+
domain = Model::Domain[:fqdn => fqdn]
|
12
|
+
domain.rm_related
|
13
|
+
domain.destroy
|
14
|
+
end
|
17
15
|
end
|
16
|
+
end
|
18
17
|
end
|
data/lib/smailr/mailbox.rb
CHANGED
@@ -1,32 +1,31 @@
|
|
1
1
|
module Smailr
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
class Mailbox
|
3
|
+
def self.add(address, password)
|
4
|
+
Smailr::logger.warn("Adding mailbox: #{address}")
|
5
5
|
|
6
|
-
|
6
|
+
fqdn = address.split('@')[1]
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
8
|
+
if not Model::Domain[:fqdn => fqdn]
|
9
|
+
raise MissingDomain, "Trying to add a mailbox for a non existing domain: #{fqdn}"
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
mbox = Model::Mailbox.for_address!(address)
|
13
|
+
mbox.password = password
|
14
|
+
mbox.save
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def self.update_password(address, password)
|
18
|
+
mbox = Model::Mailbox.for_address(address)
|
19
|
+
mbox.password = password
|
20
|
+
mbox.save
|
21
|
+
end
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
def self.rm(address, options)
|
24
|
+
Smailr::logger.warn("Removing mailbox (from database): #{address}")
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
26
|
+
mbox = Model::Mailbox.for_address(address)
|
27
|
+
mbox.rm_related
|
28
|
+
mbox.destroy
|
31
29
|
end
|
30
|
+
end
|
32
31
|
end
|
data/lib/smailr/model.rb
CHANGED
@@ -1,68 +1,68 @@
|
|
1
1
|
require 'digest/sha1'
|
2
2
|
|
3
3
|
module Smailr
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module Model
|
5
|
+
class Domain < Sequel::Model
|
6
|
+
one_to_many :mailboxes
|
7
|
+
one_to_many :aliases
|
8
|
+
one_to_many :dkims
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
def rm_related
|
11
|
+
self.remove_all_mailboxes
|
12
|
+
self.remove_all_aliases
|
13
|
+
self.remove_all_dkims
|
14
|
+
end
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
class Dkim < Sequel::Model
|
18
|
+
many_to_one :domain
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def self.for_domain(fqdn, selector)
|
21
|
+
self[:domain => Domain[:fqdn => fqdn], :selector => selector]
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
def self.for_domain!(fqdn, selector)
|
25
|
+
find_or_create(:domain => Domain[:fqdn => fqdn], :selector => selector)
|
26
|
+
end
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
class Mailbox < Sequel::Model
|
30
|
+
many_to_one :domain
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def password=(clear)
|
33
|
+
self[:password_scheme] = '{SHA}'
|
34
|
+
self[:password] = Digest::SHA1.hexdigest(clear)
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def rm_related
|
38
|
+
self.aliases.destroy
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def aliases
|
42
|
+
Model::Alias.where(
|
43
|
+
:dstlocalpart => self.localpart,
|
44
|
+
:dstdomain => self.domain.fqdn
|
45
|
+
)
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
def self.domain(fqdn)
|
49
|
+
Domain[:fqdn => fqdn]
|
50
|
+
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
def self.for_address(address)
|
53
|
+
localpart, fqdn = address.split('@')
|
54
|
+
self[:localpart => localpart, :domain => domain(fqdn)]
|
55
|
+
end
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
def self.for_address!(address)
|
58
|
+
localpart, fqdn = address.split('@')
|
59
|
+
find_or_create(:localpart => localpart, :domain => domain(fqdn))
|
60
|
+
end
|
61
61
|
|
62
|
-
|
62
|
+
end
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
end
|
64
|
+
class Alias < Sequel::Model
|
65
|
+
many_to_one :domain
|
67
66
|
end
|
67
|
+
end
|
68
68
|
end
|
data/lib/smailr/setup.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
Sequel.migration do
|
2
|
-
|
3
|
-
|
2
|
+
up do
|
3
|
+
puts <<-MESSAGE
|
4
4
|
|
5
|
-
|
5
|
+
WARNING ---------------------------------------------------------------------------------
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
You need to adapt your mailserver configuration with this version of smailr, as
|
8
|
+
passwords are now stored including the hash scheme.
|
9
9
|
|
10
|
-
|
10
|
+
Select the hash from `mailboxes.password` and the scheme from `mailboxes.password_scheme`
|
11
11
|
|
12
|
-
|
12
|
+
--------------------------------------------------------------------------------- WARNING
|
13
13
|
|
14
|
-
|
14
|
+
MESSAGE
|
15
15
|
|
16
|
-
|
16
|
+
add_column :mailboxes, :password_scheme, String
|
17
17
|
|
18
|
-
|
18
|
+
from(:mailboxes).update(password_scheme: "{SHA}")
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
20
|
+
alter_table(:mailboxes) do
|
21
|
+
set_column_not_null(:password_scheme)
|
23
22
|
end
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
# Downgrade is not supported, as we would drop necessary information do do effective hashing
|
26
|
+
# in case this feature was already used to add various hashes to the database
|
27
27
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
up do
|
3
|
+
# Remove this until we figured out whats wrong with error handling
|
4
|
+
# and we can do it for all fields
|
5
|
+
alter_table(:mailboxes) do
|
6
|
+
set_column_allow_null(:password_scheme)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Downgrade is not supported, as we would drop necessary information do do effective hashing
|
11
|
+
# in case this feature was already used to add various hashes to the database
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smailr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Schlesinger
|
@@ -14,30 +14,30 @@ dependencies:
|
|
14
14
|
name: commander
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '4.3'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '4.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sequel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '4.26'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '4.26'
|
41
41
|
description: |-
|
42
42
|
Smailr is a CLI tool which lets you manage your virtual mailhosting setup
|
43
43
|
from the shell. It currently uses SQLite as a backend, samples for Dovecot/Exim provided.
|
@@ -48,14 +48,13 @@ extensions: []
|
|
48
48
|
extra_rdoc_files: []
|
49
49
|
files:
|
50
50
|
- README.md
|
51
|
-
- bin/commander
|
52
|
-
- bin/sequel
|
53
51
|
- bin/smailr
|
54
52
|
- contrib/dovecot-sql.conf
|
55
53
|
- contrib/dovecot.conf
|
56
54
|
- contrib/exim4.conf
|
57
55
|
- lib/smailr.rb
|
58
56
|
- lib/smailr/alias.rb
|
57
|
+
- lib/smailr/cli.rb
|
59
58
|
- lib/smailr/dkim.rb
|
60
59
|
- lib/smailr/domain.rb
|
61
60
|
- lib/smailr/mailbox.rb
|
@@ -66,9 +65,11 @@ files:
|
|
66
65
|
- migrations/003_aliases.rb
|
67
66
|
- migrations/004_dkims.rb
|
68
67
|
- migrations/005_mailboxes_add_digest_identifier_to_passwords.rb
|
68
|
+
- migrations/006_mailboxes_password_schema_allow_null.rb
|
69
69
|
- smailr.yml
|
70
70
|
homepage: http://github.com/sts/smailr
|
71
|
-
licenses:
|
71
|
+
licenses:
|
72
|
+
- Apache-2.0
|
72
73
|
metadata: {}
|
73
74
|
post_install_message: |2+
|
74
75
|
|
@@ -81,7 +82,7 @@ post_install_message: |2+
|
|
81
82
|
|
82
83
|
* Install Dovecot with SQlite support
|
83
84
|
|
84
|
-
* run
|
85
|
+
* run ln -s `gem contents smailr|grep bin/smailr` /usr/local/sbin
|
85
86
|
|
86
87
|
* run "smailr setup" to create exim, dovecot and smailr configuration (you
|
87
88
|
can edit the configuration in an editor window before everyting is
|
@@ -107,7 +108,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
108
|
requirements:
|
108
109
|
- Exim
|
109
110
|
- Dovecot
|
110
|
-
- Debian
|
111
111
|
rubyforge_project:
|
112
112
|
rubygems_version: 2.4.6
|
113
113
|
signing_key:
|
data/bin/commander
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This file was generated by Bundler.
|
4
|
-
#
|
5
|
-
# The application 'commander' is installed as part of a gem, and
|
6
|
-
# this file is here to facilitate running it.
|
7
|
-
#
|
8
|
-
|
9
|
-
require 'pathname'
|
10
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
-
Pathname.new(__FILE__).realpath)
|
12
|
-
|
13
|
-
require 'rubygems'
|
14
|
-
require 'bundler/setup'
|
15
|
-
|
16
|
-
load Gem.bin_path('commander', 'commander')
|
data/bin/sequel
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This file was generated by Bundler.
|
4
|
-
#
|
5
|
-
# The application 'sequel' is installed as part of a gem, and
|
6
|
-
# this file is here to facilitate running it.
|
7
|
-
#
|
8
|
-
|
9
|
-
require 'pathname'
|
10
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
-
Pathname.new(__FILE__).realpath)
|
12
|
-
|
13
|
-
require 'rubygems'
|
14
|
-
require 'bundler/setup'
|
15
|
-
|
16
|
-
load Gem.bin_path('sequel', 'sequel')
|