mailcatcher 0.5.8 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mail_catcher.rb CHANGED
@@ -1,22 +1,13 @@
1
- require 'open3'
2
-
3
- require 'active_support/all'
1
+ require 'active_support/core_ext'
4
2
  require 'eventmachine'
3
+ require 'open3'
5
4
  require 'optparse'
6
5
  require 'rbconfig'
7
6
  require 'thin'
8
7
 
9
- module MailCatcher
10
- extend ActiveSupport::Autoload
11
-
12
- autoload :Events
13
- autoload :Growl
14
- autoload :Mail
15
- autoload :Smtp
16
- autoload :Web
17
-
18
- module_function
8
+ require 'mail_catcher/version'
19
9
 
10
+ module MailCatcher extend self
20
11
  def which command
21
12
  Open3.popen3 'which', 'command' do |stdin, stdout, stderr|
22
13
  return stdout.read.chomp.presence
@@ -55,7 +46,7 @@ module_function
55
46
  end
56
47
  end
57
48
 
58
- @@defaults = {
49
+ @defaults = {
59
50
  :smtp_ip => '127.0.0.1',
60
51
  :smtp_port => '1025',
61
52
  :http_ip => '127.0.0.1',
@@ -66,11 +57,11 @@ module_function
66
57
  :browse => false,
67
58
  }
68
59
 
69
- def parse! arguments=ARGV, defaults=@@defaults
70
- @@defaults.dup.tap do |options|
60
+ def parse! arguments=ARGV, defaults=@defaults
61
+ @defaults.dup.tap do |options|
71
62
  OptionParser.new do |parser|
72
63
  parser.banner = "Usage: mailcatcher [options]"
73
- parser.version = File.read(File.expand_path("../../VERSION", __FILE__))
64
+ parser.version = VERSION
74
65
 
75
66
  parser.on("--ip IP", "Set the ip address of both servers") do |ip|
76
67
  options[:smtp_ip] = options[:http_ip] = ip
@@ -131,7 +122,7 @@ module_function
131
122
 
132
123
  def run! options=nil
133
124
  # If we are passed options, fill in the blanks
134
- options &&= @@defaults.merge options
125
+ options &&= @defaults.merge options
135
126
  # Otherwise, parse them from ARGV
136
127
  options ||= parse!
137
128
 
@@ -182,7 +173,6 @@ module_function
182
173
  end
183
174
 
184
175
  protected
185
- module_function
186
176
 
187
177
  def rescue_port port
188
178
  begin
@@ -192,10 +182,16 @@ module_function
192
182
  rescue RuntimeError
193
183
  if $!.to_s =~ /\bno acceptor\b/
194
184
  puts "~~> ERROR: Something's using port #{port}. Are you already running MailCatcher?"
195
- exit -1
185
+ exit(-1)
196
186
  else
197
187
  raise
198
188
  end
199
189
  end
200
190
  end
201
191
  end
192
+
193
+ require 'mail_catcher/events'
194
+ require 'mail_catcher/growl'
195
+ require 'mail_catcher/mail'
196
+ require 'mail_catcher/smtp'
197
+ require 'mail_catcher/web'
@@ -2,4 +2,4 @@ require 'eventmachine'
2
2
 
3
3
  module MailCatcher::Events
4
4
  MessageAdded = EventMachine::Channel.new
5
- end
5
+ end
@@ -1,6 +1,5 @@
1
1
  module MailCatcher
2
- module Growl
3
- module_function
2
+ module Growl extend self
4
3
  def start
5
4
  MailCatcher::Events::MessageAdded.subscribe MailCatcher::Growl.method :notify
6
5
  end
@@ -1,12 +1,11 @@
1
+ require 'active_support/json'
1
2
  require 'mail'
2
3
  require 'sqlite3'
3
4
  require 'eventmachine'
4
5
 
5
- module MailCatcher::Mail
6
- module_function
7
-
6
+ module MailCatcher::Mail extend self
8
7
  def db
9
- @@__db ||= begin
8
+ @__db ||= begin
10
9
  SQLite3::Database.new(':memory:', :type_translation => true).tap do |db|
11
10
  db.execute(<<-SQL)
12
11
  CREATE TABLE message (
@@ -39,10 +38,10 @@ module_function
39
38
  end
40
39
 
41
40
  def add_message(message)
42
- @@add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
41
+ @add_message_query ||= db.prepare("INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now'))")
43
42
 
44
43
  mail = Mail.new(message[:source])
45
- result = @@add_message_query.execute(message[:sender], message[:recipients].to_json, mail.subject, message[:source], mail.mime_type || 'text/plain', message[:source].length)
44
+ @add_message_query.execute(message[:sender], message[:recipients].to_json, mail.subject, message[:source], mail.mime_type || 'text/plain', message[:source].length)
46
45
  message_id = db.last_insert_row_id
47
46
  parts = mail.all_parts
48
47
  parts = [mail] if parts.empty?
@@ -60,18 +59,18 @@ module_function
60
59
  end
61
60
 
62
61
  def add_message_part(*args)
63
- @@add_message_part_query ||= db.prepare "INSERT INTO message_part (message_id, cid, type, is_attachment, filename, charset, body, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))"
64
- @@add_message_part_query.execute(*args)
62
+ @add_message_part_query ||= db.prepare "INSERT INTO message_part (message_id, cid, type, is_attachment, filename, charset, body, size, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))"
63
+ @add_message_part_query.execute(*args)
65
64
  end
66
65
 
67
66
  def latest_created_at
68
- @@latest_created_at_query ||= db.prepare "SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1"
69
- @@latest_created_at_query.execute.next
67
+ @latest_created_at_query ||= db.prepare "SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1"
68
+ @latest_created_at_query.execute.next
70
69
  end
71
70
 
72
71
  def messages
73
- @@messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at ASC"
74
- @@messages_query.execute.map do |row|
72
+ @messages_query ||= db.prepare "SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at ASC"
73
+ @messages_query.execute.map do |row|
75
74
  Hash[row.fields.zip(row)].tap do |message|
76
75
  message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
77
76
  end
@@ -79,46 +78,46 @@ module_function
79
78
  end
80
79
 
81
80
  def message(id)
82
- @@message_query ||= db.prepare "SELECT * FROM message WHERE id = ? LIMIT 1"
83
- row = @@message_query.execute(id).next
81
+ @message_query ||= db.prepare "SELECT * FROM message WHERE id = ? LIMIT 1"
82
+ row = @message_query.execute(id).next
84
83
  row && Hash[row.fields.zip(row)].tap do |message|
85
84
  message["recipients"] &&= ActiveSupport::JSON.decode message["recipients"]
86
85
  end
87
86
  end
88
87
 
89
88
  def message_has_html?(id)
90
- @@message_has_html_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type IN ('application/xhtml+xml', 'text/html') LIMIT 1"
91
- (!!@@message_has_html_query.execute(id).next) || ['text/html', 'application/xhtml+xml'].include?(message(id)["type"])
89
+ @message_has_html_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type IN ('application/xhtml+xml', 'text/html') LIMIT 1"
90
+ (!!@message_has_html_query.execute(id).next) || ['text/html', 'application/xhtml+xml'].include?(message(id)["type"])
92
91
  end
93
92
 
94
93
  def message_has_plain?(id)
95
- @@message_has_plain_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1"
96
- (!!@@message_has_plain_query.execute(id).next) || message(id)["type"] == "text/plain"
94
+ @message_has_plain_query ||= db.prepare "SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1"
95
+ (!!@message_has_plain_query.execute(id).next) || message(id)["type"] == "text/plain"
97
96
  end
98
97
 
99
98
  def message_parts(id)
100
- @@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC"
101
- @@message_parts_query.execute(id).map do |row|
99
+ @message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC"
100
+ @message_parts_query.execute(id).map do |row|
102
101
  Hash[row.fields.zip(row)]
103
102
  end
104
103
  end
105
104
 
106
105
  def message_attachments(id)
107
- @@message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC"
108
- @@message_parts_query.execute(id).map do |row|
106
+ @message_parts_query ||= db.prepare "SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC"
107
+ @message_parts_query.execute(id).map do |row|
109
108
  Hash[row.fields.zip(row)]
110
109
  end
111
110
  end
112
111
 
113
112
  def message_part(message_id, part_id)
114
- @@message_part_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1"
115
- row = @@message_part_query.execute(message_id, part_id).next
113
+ @message_part_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1"
114
+ row = @message_part_query.execute(message_id, part_id).next
116
115
  row && Hash[row.fields.zip(row)]
117
116
  end
118
117
 
119
118
  def message_part_type(message_id, part_type)
120
- @@message_part_type_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1"
121
- row = @@message_part_type_query.execute(message_id, part_type).next
119
+ @message_part_type_query ||= db.prepare "SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1"
120
+ row = @message_part_type_query.execute(message_id, part_type).next
122
121
  row && Hash[row.fields.zip(row)]
123
122
  end
124
123
 
@@ -136,19 +135,19 @@ module_function
136
135
  end
137
136
 
138
137
  def message_part_cid(message_id, cid)
139
- @@message_part_cid_query ||= db.prepare 'SELECT * FROM message_part WHERE message_id = ?'
140
- @@message_part_cid_query.execute(message_id).map do |row|
141
- part = Hash[row.fields.zip(row)]
138
+ @message_part_cid_query ||= db.prepare 'SELECT * FROM message_part WHERE message_id = ?'
139
+ @message_part_cid_query.execute(message_id).map do |row|
140
+ Hash[row.fields.zip(row)]
142
141
  end.find do |part|
143
142
  part["cid"] == cid
144
143
  end
145
144
  end
146
145
 
147
146
  def delete!
148
- @@delete_messages_query ||= db.prepare 'DELETE FROM message'
149
- @@delete_message_parts_query ||= db.prepare 'DELETE FROM message_part'
147
+ @delete_messages_query ||= db.prepare 'DELETE FROM message'
148
+ @delete_message_parts_query ||= db.prepare 'DELETE FROM message_part'
150
149
 
151
- @@delete_messages_query.execute and
152
- @@delete_message_parts_query.execute
150
+ @delete_messages_query.execute and
151
+ @delete_message_parts_query.execute
153
152
  end
154
153
  end
@@ -34,7 +34,10 @@ class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
34
34
 
35
35
  def receive_data_chunk(lines)
36
36
  current_message[:source] ||= ""
37
- current_message[:source] += lines.join("\n")
37
+ lines.each do |line|
38
+ # RFC821 4.5.2 says leading periods should be stripped from the body data.
39
+ current_message[:source] << line.sub(/\A\./, "") << "\n"
40
+ end
38
41
  true
39
42
  end
40
43
 
@@ -0,0 +1,3 @@
1
+ module MailCatcher
2
+ VERSION = "0.5.9"
3
+ end
Binary file
@@ -16,77 +16,93 @@ time, mark, audio, video {
16
16
  border: 0;
17
17
  font-size: 100%;
18
18
  font: inherit;
19
- vertical-align: baseline; }
19
+ vertical-align: baseline;
20
+ }
20
21
 
21
22
  body {
22
- line-height: 1; }
23
+ line-height: 1;
24
+ }
23
25
 
24
26
  ol, ul {
25
- list-style: none; }
27
+ list-style: none;
28
+ }
26
29
 
27
30
  table {
28
31
  border-collapse: collapse;
29
- border-spacing: 0; }
32
+ border-spacing: 0;
33
+ }
30
34
 
31
35
  caption, th, td {
32
36
  text-align: left;
33
37
  font-weight: normal;
34
- vertical-align: middle; }
38
+ vertical-align: middle;
39
+ }
35
40
 
36
41
  q, blockquote {
37
- quotes: none; }
38
- q:before, q:after, blockquote:before, blockquote:after {
39
- content: "";
40
- content: none; }
42
+ quotes: none;
43
+ }
44
+ q:before, q:after, blockquote:before, blockquote:after {
45
+ content: "";
46
+ content: none;
47
+ }
41
48
 
42
49
  a img {
43
- border: none; }
50
+ border: none;
51
+ }
44
52
 
45
53
  article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary {
46
- display: block; }
54
+ display: block;
55
+ }
47
56
 
48
57
  html, body {
49
58
  width: 100%;
50
- height: 100%; }
59
+ height: 100%;
60
+ }
51
61
 
52
62
  body {
53
- display: -moz-box;
54
63
  display: -webkit-box;
64
+ display: -moz-box;
55
65
  display: -ms-box;
56
66
  display: box;
57
- -moz-box-orient: vertical;
58
67
  -webkit-box-orient: vertical;
68
+ -moz-box-orient: vertical;
59
69
  -ms-box-orient: vertical;
60
70
  box-orient: vertical;
61
71
  background: #eeeeee;
62
72
  color: black;
63
73
  font-size: 12px;
64
- font-family: Helvetica, sans-serif; }
65
- body body {
66
- font-size: 75%;
67
- line-height: 2em; }
68
- body html > body {
69
- font-size: 12px; }
70
- body.iframe {
71
- background: white; }
72
- body.iframe h1 {
73
- font-size: 1.3em;
74
- margin: 12px; }
75
- body.iframe p, body.iframe form {
76
- margin: 0 12px 12px 12px;
77
- line-height: 1.25; }
78
- body.iframe .loading {
79
- color: #666666;
80
- margin-left: 0.5em; }
74
+ font-family: Helvetica, sans-serif;
75
+ }
76
+ body body {
77
+ font-size: 75%;
78
+ line-height: 2em;
79
+ }
80
+ body html > body {
81
+ font-size: 12px;
82
+ }
83
+ body.iframe {
84
+ background: white;
85
+ }
86
+ body.iframe h1 {
87
+ font-size: 1.3em;
88
+ margin: 12px;
89
+ }
90
+ body.iframe p, body.iframe form {
91
+ margin: 0 12px 12px 12px;
92
+ line-height: 1.25;
93
+ }
94
+ body.iframe .loading {
95
+ color: #666666;
96
+ margin-left: 0.5em;
97
+ }
81
98
 
82
99
  .button {
83
100
  padding: 0.5em 1em;
84
101
  border: 1px solid #cccccc;
85
- -moz-border-radius: 2px;
86
102
  -webkit-border-radius: 2px;
87
- -o-border-radius: 2px;
103
+ -moz-border-radius: 2px;
88
104
  -ms-border-radius: 2px;
89
- -khtml-border-radius: 2px;
105
+ -o-border-radius: 2px;
90
106
  border-radius: 2px;
91
107
  background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)), #ececec;
92
108
  background: -webkit-linear-gradient(#f4f4f4, #ececec), #ececec;
@@ -96,99 +112,115 @@ body {
96
112
  background: linear-gradient(#f4f4f4, #ececec), #ececec;
97
113
  color: #666666;
98
114
  text-shadow: 1px 1px 0 white;
99
- text-decoration: none; }
100
- .button:hover, .button:focus {
101
- border-color: #999999;
102
- border-bottom-color: #666666;
103
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
104
- background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
105
- background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
106
- background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
107
- background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
108
- background: linear-gradient(#eeeeee, #dddddd), #dddddd;
109
- color: #333333;
110
- text-decoration: none; }
111
- .button:active, .button.active {
112
- border-color: #666666;
113
- border-bottom-color: #999999;
114
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
115
- background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
116
- background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
117
- background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
118
- background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
119
- background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
120
- color: #333333;
121
- text-decoration: none;
122
- text-shadow: -1px -1px 0 #eeeeee; }
115
+ text-decoration: none;
116
+ }
117
+ .button:hover, .button:focus {
118
+ border-color: #999999;
119
+ border-bottom-color: #666666;
120
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
121
+ background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
122
+ background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
123
+ background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
124
+ background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
125
+ background: linear-gradient(#eeeeee, #dddddd), #dddddd;
126
+ color: #333333;
127
+ text-decoration: none;
128
+ }
129
+ .button:active, .button.active {
130
+ border-color: #666666;
131
+ border-bottom-color: #999999;
132
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
133
+ background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
134
+ background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
135
+ background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
136
+ background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
137
+ background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
138
+ color: #333333;
139
+ text-decoration: none;
140
+ text-shadow: -1px -1px 0 #eeeeee;
141
+ }
123
142
 
124
143
  body > header {
125
144
  overflow: hidden;
126
145
  *zoom: 1;
127
- border-bottom: 1px solid #cccccc; }
128
- body > header h1 {
129
- float: left;
130
- margin-left: 6px;
131
- padding: 6px;
132
- padding-left: 30px;
133
- background: url(/images/logo.png) left no-repeat;
134
- font-size: 18px;
135
- font-weight: bold; }
136
- body > header h1 a {
137
- color: black;
138
- text-decoration: none;
139
- text-shadow: 0 1px 0 white;
140
- -moz-transition: 0.1s ease;
141
- -webkit-transition: 0.1s ease;
142
- -o-transition: 0.1s ease;
143
- transition: 0.1s ease; }
144
- body > header h1 a:hover {
145
- color: #4183c4; }
146
- body > header nav {
147
- border-left: 1px solid #cccccc; }
148
- body > header nav.project {
149
- float: left; }
150
- body > header nav.app {
151
- float: right; }
152
- body > header nav li {
153
- display: block;
154
- float: left;
155
- border-left: 1px solid white;
156
- border-right: 1px solid #cccccc; }
157
- body > header nav li input {
158
- margin: 6px; }
159
- body > header nav li a {
160
- display: block;
161
- padding: 10px;
162
- text-decoration: none;
163
- text-shadow: 0 1px 0 white;
164
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)), #ececec;
165
- background: -webkit-linear-gradient(#f4f4f4, #ececec), #ececec;
166
- background: -moz-linear-gradient(#f4f4f4, #ececec), #ececec;
167
- background: -o-linear-gradient(#f4f4f4, #ececec), #ececec;
168
- background: -ms-linear-gradient(#f4f4f4, #ececec), #ececec;
169
- background: linear-gradient(#f4f4f4, #ececec), #ececec;
170
- color: #666666;
171
- text-shadow: 1px 1px 0 white;
172
- text-decoration: none; }
173
- body > header nav li a:hover, body > header nav li a:focus {
174
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
175
- background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
176
- background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
177
- background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
178
- background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
179
- background: linear-gradient(#eeeeee, #dddddd), #dddddd;
180
- color: #333333;
181
- text-decoration: none; }
182
- body > header nav li a:active, body > header nav li a.active {
183
- background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
184
- background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
185
- background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
186
- background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
187
- background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
188
- background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
189
- color: #333333;
190
- text-decoration: none;
191
- text-shadow: -1px -1px 0 #eeeeee; }
146
+ border-bottom: 1px solid #cccccc;
147
+ }
148
+ body > header h1 {
149
+ float: left;
150
+ margin-left: 6px;
151
+ padding: 6px;
152
+ padding-left: 30px;
153
+ background: url(/images/logo.png) left no-repeat;
154
+ font-size: 18px;
155
+ font-weight: bold;
156
+ }
157
+ body > header h1 a {
158
+ color: black;
159
+ text-decoration: none;
160
+ text-shadow: 0 1px 0 white;
161
+ -webkit-transition: 0.1s ease;
162
+ -moz-transition: 0.1s ease;
163
+ -ms-transition: 0.1s ease;
164
+ -o-transition: 0.1s ease;
165
+ transition: 0.1s ease;
166
+ }
167
+ body > header h1 a:hover {
168
+ color: #4183c4;
169
+ }
170
+ body > header nav {
171
+ border-left: 1px solid #cccccc;
172
+ }
173
+ body > header nav.project {
174
+ float: left;
175
+ }
176
+ body > header nav.app {
177
+ float: right;
178
+ }
179
+ body > header nav li {
180
+ display: block;
181
+ float: left;
182
+ border-left: 1px solid white;
183
+ border-right: 1px solid #cccccc;
184
+ }
185
+ body > header nav li input {
186
+ margin: 6px;
187
+ }
188
+ body > header nav li a {
189
+ display: block;
190
+ padding: 10px;
191
+ text-decoration: none;
192
+ text-shadow: 0 1px 0 white;
193
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f4f4), color-stop(100%, #ececec)), #ececec;
194
+ background: -webkit-linear-gradient(#f4f4f4, #ececec), #ececec;
195
+ background: -moz-linear-gradient(#f4f4f4, #ececec), #ececec;
196
+ background: -o-linear-gradient(#f4f4f4, #ececec), #ececec;
197
+ background: -ms-linear-gradient(#f4f4f4, #ececec), #ececec;
198
+ background: linear-gradient(#f4f4f4, #ececec), #ececec;
199
+ color: #666666;
200
+ text-shadow: 1px 1px 0 white;
201
+ text-decoration: none;
202
+ }
203
+ body > header nav li a:hover, body > header nav li a:focus {
204
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #eeeeee), color-stop(100%, #dddddd)), #dddddd;
205
+ background: -webkit-linear-gradient(#eeeeee, #dddddd), #dddddd;
206
+ background: -moz-linear-gradient(#eeeeee, #dddddd), #dddddd;
207
+ background: -o-linear-gradient(#eeeeee, #dddddd), #dddddd;
208
+ background: -ms-linear-gradient(#eeeeee, #dddddd), #dddddd;
209
+ background: linear-gradient(#eeeeee, #dddddd), #dddddd;
210
+ color: #333333;
211
+ text-decoration: none;
212
+ }
213
+ body > header nav li a:active, body > header nav li a.active {
214
+ background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #dddddd), color-stop(100%, #eeeeee)), #eeeeee;
215
+ background: -webkit-linear-gradient(#dddddd, #eeeeee), #eeeeee;
216
+ background: -moz-linear-gradient(#dddddd, #eeeeee), #eeeeee;
217
+ background: -o-linear-gradient(#dddddd, #eeeeee), #eeeeee;
218
+ background: -ms-linear-gradient(#dddddd, #eeeeee), #eeeeee;
219
+ background: linear-gradient(#dddddd, #eeeeee), #eeeeee;
220
+ color: #333333;
221
+ text-decoration: none;
222
+ text-shadow: -1px -1px 0 #eeeeee;
223
+ }
192
224
 
193
225
  #messages {
194
226
  width: 100%;
@@ -196,182 +228,226 @@ body > header {
196
228
  min-height: 3em;
197
229
  overflow: auto;
198
230
  background: white;
199
- border-top: 1px solid white; }
200
- #messages table {
201
- overflow: hidden;
202
- *zoom: 1;
203
- width: 100%; }
204
- #messages table thead tr {
205
- background: #eeeeee;
206
- color: #333333; }
207
- #messages table thead tr th {
208
- padding: 0.25em;
209
- font-weight: bold;
210
- color: #666666;
211
- text-shadow: 0 1px 0 white; }
212
- #messages table tbody tr {
213
- cursor: pointer;
214
- -moz-transition: 0.1s ease;
215
- -webkit-transition: 0.1s ease;
216
- -o-transition: 0.1s ease;
217
- transition: 0.1s ease;
218
- color: #333333; }
219
- #messages table tbody tr:hover {
220
- color: black; }
221
- #messages table tbody tr:nth-child(even) {
222
- background: #f0f0f0; }
223
- #messages table tbody tr.selected {
224
- background: Highlight;
225
- color: HighlightText; }
226
- #messages table tbody tr td {
227
- padding: 0.25em; }
228
- #messages table tbody tr td.blank {
229
- color: #666666;
230
- font-style: italic; }
231
+ border-top: 1px solid white;
232
+ }
233
+ #messages table {
234
+ overflow: hidden;
235
+ *zoom: 1;
236
+ width: 100%;
237
+ }
238
+ #messages table thead tr {
239
+ background: #eeeeee;
240
+ color: #333333;
241
+ }
242
+ #messages table thead tr th {
243
+ padding: 0.25em;
244
+ font-weight: bold;
245
+ color: #666666;
246
+ text-shadow: 0 1px 0 white;
247
+ }
248
+ #messages table tbody tr {
249
+ cursor: pointer;
250
+ -webkit-transition: 0.1s ease;
251
+ -moz-transition: 0.1s ease;
252
+ -ms-transition: 0.1s ease;
253
+ -o-transition: 0.1s ease;
254
+ transition: 0.1s ease;
255
+ color: #333333;
256
+ }
257
+ #messages table tbody tr:hover {
258
+ color: black;
259
+ }
260
+ #messages table tbody tr:nth-child(even) {
261
+ background: #f0f0f0;
262
+ }
263
+ #messages table tbody tr.selected {
264
+ background: Highlight;
265
+ color: HighlightText;
266
+ }
267
+ #messages table tbody tr td {
268
+ padding: 0.25em;
269
+ }
270
+ #messages table tbody tr td.blank {
271
+ color: #666666;
272
+ font-style: italic;
273
+ }
231
274
 
232
275
  #resizer {
233
276
  padding-bottom: 5px;
234
- cursor: ns-resize; }
235
- #resizer .ruler {
236
- border-top: 1px solid #cccccc;
237
- border-bottom: 1px solid white; }
277
+ cursor: ns-resize;
278
+ }
279
+ #resizer .ruler {
280
+ border-top: 1px solid #cccccc;
281
+ border-bottom: 1px solid white;
282
+ }
238
283
 
239
284
  #message {
240
- display: -moz-box;
241
285
  display: -webkit-box;
286
+ display: -moz-box;
242
287
  display: -ms-box;
243
288
  display: box;
244
- -moz-box-orient: vertical;
245
289
  -webkit-box-orient: vertical;
290
+ -moz-box-orient: vertical;
246
291
  -ms-box-orient: vertical;
247
292
  box-orient: vertical;
248
- -moz-box-flex: 1;
249
293
  -webkit-box-flex: 1;
294
+ -moz-box-flex: 1;
250
295
  -ms-box-flex: 1;
251
- box-flex: 1; }
252
- #message > header {
253
- overflow: hidden;
254
- *zoom: 1; }
255
- #message > header .metadata {
256
- overflow: hidden;
257
- *zoom: 1;
258
- padding: 0.5em;
259
- padding-top: 0; }
260
- #message > header .metadata dt, #message > header .metadata dd {
261
- padding: 0.25em; }
262
- #message > header .metadata dt {
263
- float: left;
264
- clear: left;
265
- width: 8em;
266
- margin-right: 0.5em;
267
- text-align: right;
268
- font-weight: bold;
269
- color: #666666;
270
- text-shadow: 0 1px 0 white; }
271
- #message > header .metadata dd.subject {
272
- font-weight: bold; }
273
- #message > header .metadata .attachments {
274
- display: none; }
275
- #message > header .metadata .attachments ul {
276
- display: inline; }
277
- #message > header .metadata .attachments ul li {
278
- display: -moz-inline-box;
279
- -moz-box-orient: vertical;
280
- display: inline-block;
281
- vertical-align: middle;
282
- *vertical-align: auto;
283
- margin-right: 0.5em; }
284
- #message > header .metadata .attachments ul li {
285
- *display: inline; }
286
- #message > header .views ul {
287
- padding: 0 0.5em;
288
- border-bottom: 1px solid #cccccc; }
289
- #message > header .views .tab {
290
- display: -moz-inline-box;
291
- -moz-box-orient: vertical;
292
- display: inline-block;
293
- vertical-align: middle;
294
- *vertical-align: auto; }
295
- #message > header .views .tab {
296
- *display: inline; }
297
- #message > header .views .tab a {
298
- display: -moz-inline-box;
299
- -moz-box-orient: vertical;
300
- display: inline-block;
301
- vertical-align: middle;
302
- *vertical-align: auto;
303
- padding: 0.5em;
304
- border: 1px solid #cccccc;
305
- background: #dddddd;
306
- color: #333333;
307
- border-width: 1px 1px 0 1px;
308
- cursor: pointer;
309
- text-shadow: 0 1px 0 #eeeeee;
310
- text-decoration: none; }
311
- #message > header .views .tab a {
312
- *display: inline; }
313
- #message > header .views .tab:not(.selected):hover a {
314
- background-color: #eeeeee; }
315
- #message > header .views .tab.selected a {
316
- background: white;
317
- color: black;
318
- height: 13px;
319
- -moz-box-shadow: 1px 1px 0 #cccccc;
320
- -webkit-box-shadow: 1px 1px 0 #cccccc;
321
- -o-box-shadow: 1px 1px 0 #cccccc;
322
- box-shadow: 1px 1px 0 #cccccc;
323
- margin-bottom: -2px;
324
- cursor: default; }
325
- #message > header .views .action {
326
- display: -moz-inline-box;
327
- -moz-box-orient: vertical;
328
- display: inline-block;
329
- vertical-align: middle;
330
- *vertical-align: auto;
331
- float: right;
332
- margin: 0 0.25em; }
333
- #message > header .views .action {
334
- *display: inline; }
296
+ box-flex: 1;
297
+ }
298
+ #message > header {
299
+ overflow: hidden;
300
+ *zoom: 1;
301
+ }
302
+ #message > header .metadata {
303
+ overflow: hidden;
304
+ *zoom: 1;
305
+ padding: 0.5em;
306
+ padding-top: 0;
307
+ }
308
+ #message > header .metadata dt, #message > header .metadata dd {
309
+ padding: 0.25em;
310
+ }
311
+ #message > header .metadata dt {
312
+ float: left;
313
+ clear: left;
314
+ width: 8em;
315
+ margin-right: 0.5em;
316
+ text-align: right;
317
+ font-weight: bold;
318
+ color: #666666;
319
+ text-shadow: 0 1px 0 white;
320
+ }
321
+ #message > header .metadata dd.subject {
322
+ font-weight: bold;
323
+ }
324
+ #message > header .metadata .attachments {
325
+ display: none;
326
+ }
327
+ #message > header .metadata .attachments ul {
328
+ display: inline;
329
+ }
330
+ #message > header .metadata .attachments ul li {
331
+ display: -moz-inline-box;
332
+ -moz-box-orient: vertical;
333
+ display: inline-block;
334
+ vertical-align: middle;
335
+ *vertical-align: auto;
336
+ margin-right: 0.5em;
337
+ }
338
+ #message > header .metadata .attachments ul li {
339
+ *display: inline;
340
+ }
341
+ #message > header .views ul {
342
+ padding: 0 0.5em;
343
+ border-bottom: 1px solid #cccccc;
344
+ }
345
+ #message > header .views .tab {
346
+ display: -moz-inline-box;
347
+ -moz-box-orient: vertical;
348
+ display: inline-block;
349
+ vertical-align: middle;
350
+ *vertical-align: auto;
351
+ }
352
+ #message > header .views .tab {
353
+ *display: inline;
354
+ }
355
+ #message > header .views .tab a {
356
+ display: -moz-inline-box;
357
+ -moz-box-orient: vertical;
358
+ display: inline-block;
359
+ vertical-align: middle;
360
+ *vertical-align: auto;
361
+ padding: 0.5em;
362
+ border: 1px solid #cccccc;
363
+ background: #dddddd;
364
+ color: #333333;
365
+ border-width: 1px 1px 0 1px;
366
+ cursor: pointer;
367
+ text-shadow: 0 1px 0 #eeeeee;
368
+ text-decoration: none;
369
+ }
370
+ #message > header .views .tab a {
371
+ *display: inline;
372
+ }
373
+ #message > header .views .tab:not(.selected):hover a {
374
+ background-color: #eeeeee;
375
+ }
376
+ #message > header .views .tab.selected a {
377
+ background: white;
378
+ color: black;
379
+ height: 13px;
380
+ -webkit-box-shadow: 1px 1px 0 #cccccc;
381
+ -moz-box-shadow: 1px 1px 0 #cccccc;
382
+ box-shadow: 1px 1px 0 #cccccc;
383
+ margin-bottom: -2px;
384
+ cursor: default;
385
+ }
386
+ #message > header .views .action {
387
+ display: -moz-inline-box;
388
+ -moz-box-orient: vertical;
389
+ display: inline-block;
390
+ vertical-align: middle;
391
+ *vertical-align: auto;
392
+ float: right;
393
+ margin: 0 0.25em;
394
+ }
395
+ #message > header .views .action {
396
+ *display: inline;
397
+ }
335
398
 
336
399
  .fractal-analysis {
337
- margin: 12px 0; }
338
- .fractal-analysis .report-intro {
339
- font-weight: bold; }
340
- .fractal-analysis .report-intro.valid {
341
- color: #009900; }
342
- .fractal-analysis .report-intro.invalid {
343
- color: #cc3333; }
344
- .fractal-analysis code {
345
- font-family: Monaco, "Courier New", Courier, monospace;
346
- background-color: #f8f8ff;
347
- color: #444444;
348
- padding: 0 0.2em;
349
- border: 1px solid #dedede; }
350
- .fractal-analysis ul {
351
- margin: 1em 0 1em 1em;
352
- list-style-type: square; }
353
- .fractal-analysis ol {
354
- margin: 1em 0 1em 2em;
355
- list-style-type: decimal; }
356
- .fractal-analysis ul li, .fractal-analysis ol li {
357
- display: list-item;
358
- margin: 0.5em 0 0.5em 1em; }
359
- .fractal-analysis .error-intro strong {
360
- font-weight: bold; }
361
- .fractal-analysis .unsupported-clients dt {
362
- padding-left: 1em; }
363
- .fractal-analysis .unsupported-clients dd {
364
- padding-left: 2em; }
365
- .fractal-analysis .unsupported-clients dd ul li {
366
- display: list-item; }
400
+ margin: 12px 0;
401
+ }
402
+ .fractal-analysis .report-intro {
403
+ font-weight: bold;
404
+ }
405
+ .fractal-analysis .report-intro.valid {
406
+ color: #009900;
407
+ }
408
+ .fractal-analysis .report-intro.invalid {
409
+ color: #cc3333;
410
+ }
411
+ .fractal-analysis code {
412
+ font-family: Monaco, "Courier New", Courier, monospace;
413
+ background-color: #f8f8ff;
414
+ color: #444444;
415
+ padding: 0 0.2em;
416
+ border: 1px solid #dedede;
417
+ }
418
+ .fractal-analysis ul {
419
+ margin: 1em 0 1em 1em;
420
+ list-style-type: square;
421
+ }
422
+ .fractal-analysis ol {
423
+ margin: 1em 0 1em 2em;
424
+ list-style-type: decimal;
425
+ }
426
+ .fractal-analysis ul li, .fractal-analysis ol li {
427
+ display: list-item;
428
+ margin: 0.5em 0 0.5em 1em;
429
+ }
430
+ .fractal-analysis .error-intro strong {
431
+ font-weight: bold;
432
+ }
433
+ .fractal-analysis .unsupported-clients dt {
434
+ padding-left: 1em;
435
+ }
436
+ .fractal-analysis .unsupported-clients dd {
437
+ padding-left: 2em;
438
+ }
439
+ .fractal-analysis .unsupported-clients dd ul li {
440
+ display: list-item;
441
+ }
367
442
 
368
443
  iframe {
369
- display: -moz-box;
370
444
  display: -webkit-box;
445
+ display: -moz-box;
371
446
  display: -ms-box;
372
447
  display: box;
373
- -moz-box-flex: 1;
374
448
  -webkit-box-flex: 1;
449
+ -moz-box-flex: 1;
375
450
  -ms-box-flex: 1;
376
451
  box-flex: 1;
377
- background: white; }
452
+ background: white;
453
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailcatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8
4
+ version: 0.5.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-17 00:00:00.000000000 Z
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '0.12'
37
+ version: '1.0'
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: '0.12'
45
+ version: '1.0'
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: haml
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -92,16 +92,13 @@ dependencies:
92
92
  - !ruby/object:Gem::Version
93
93
  version: '1.2'
94
94
  - !ruby/object:Gem::Dependency
95
- name: skinny
95
+ name: sqlite3
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: '0.2'
102
- - - ! '>='
103
- - !ruby/object:Gem::Version
104
- version: 0.2.1
101
+ version: '1.3'
105
102
  type: :runtime
106
103
  prerelease: false
107
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -109,74 +106,71 @@ dependencies:
109
106
  requirements:
110
107
  - - ~>
111
108
  - !ruby/object:Gem::Version
112
- version: '0.2'
113
- - - ! '>='
114
- - !ruby/object:Gem::Version
115
- version: 0.2.1
109
+ version: '1.3'
116
110
  - !ruby/object:Gem::Dependency
117
- name: sqlite3
111
+ name: thin
118
112
  requirement: !ruby/object:Gem::Requirement
119
113
  none: false
120
114
  requirements:
121
- - - ~>
115
+ - - ! '>='
122
116
  - !ruby/object:Gem::Version
123
- version: '1.3'
117
+ version: '0'
124
118
  type: :runtime
125
119
  prerelease: false
126
120
  version_requirements: !ruby/object:Gem::Requirement
127
121
  none: false
128
122
  requirements:
129
- - - ~>
123
+ - - ! '>='
130
124
  - !ruby/object:Gem::Version
131
- version: '1.3'
125
+ version: '0'
132
126
  - !ruby/object:Gem::Dependency
133
- name: thin
127
+ name: skinny
134
128
  requirement: !ruby/object:Gem::Requirement
135
129
  none: false
136
130
  requirements:
137
- - - ~>
131
+ - - ! '>='
138
132
  - !ruby/object:Gem::Version
139
- version: '1.2'
133
+ version: '0'
140
134
  type: :runtime
141
135
  prerelease: false
142
136
  version_requirements: !ruby/object:Gem::Requirement
143
137
  none: false
144
138
  requirements:
145
- - - ~>
139
+ - - ! '>='
146
140
  - !ruby/object:Gem::Version
147
- version: '1.2'
141
+ version: '0'
148
142
  - !ruby/object:Gem::Dependency
149
143
  name: coffee-script
150
144
  requirement: !ruby/object:Gem::Requirement
151
145
  none: false
152
146
  requirements:
153
- - - ~>
147
+ - - ! '>='
154
148
  - !ruby/object:Gem::Version
155
- version: '2.2'
149
+ version: '0'
156
150
  type: :development
157
151
  prerelease: false
158
152
  version_requirements: !ruby/object:Gem::Requirement
159
153
  none: false
160
154
  requirements:
161
- - - ~>
155
+ - - ! '>='
162
156
  - !ruby/object:Gem::Version
163
- version: '2.2'
157
+ version: '0'
164
158
  - !ruby/object:Gem::Dependency
165
159
  name: compass
166
160
  requirement: !ruby/object:Gem::Requirement
167
161
  none: false
168
162
  requirements:
169
- - - ~>
163
+ - - ! '>='
170
164
  - !ruby/object:Gem::Version
171
- version: 0.11.1
165
+ version: '0'
172
166
  type: :development
173
167
  prerelease: false
174
168
  version_requirements: !ruby/object:Gem::Requirement
175
169
  none: false
176
170
  requirements:
177
- - - ~>
171
+ - - ! '>='
178
172
  - !ruby/object:Gem::Version
179
- version: 0.11.1
173
+ version: '0'
180
174
  - !ruby/object:Gem::Dependency
181
175
  name: rake
182
176
  requirement: !ruby/object:Gem::Requirement
@@ -214,17 +208,17 @@ dependencies:
214
208
  requirement: !ruby/object:Gem::Requirement
215
209
  none: false
216
210
  requirements:
217
- - - ~>
211
+ - - ! '>='
218
212
  - !ruby/object:Gem::Version
219
- version: '3.1'
213
+ version: '0'
220
214
  type: :development
221
215
  prerelease: false
222
216
  version_requirements: !ruby/object:Gem::Requirement
223
217
  none: false
224
218
  requirements:
225
- - - ~>
219
+ - - ! '>='
226
220
  - !ruby/object:Gem::Version
227
- version: '3.1'
221
+ version: '0'
228
222
  description: ! " MailCatcher runs a super simple SMTP server which catches any\n
229
223
  \ message sent to it to display in a web interface. Run\n mailcatcher, set
230
224
  your favourite app to deliver to\n smtp://127.0.0.1:1025 instead of your default
@@ -240,15 +234,16 @@ extra_rdoc_files:
240
234
  files:
241
235
  - README.md
242
236
  - LICENSE
243
- - VERSION
244
237
  - bin/catchmail
245
238
  - bin/mailcatcher
246
239
  - lib/mail_catcher/events.rb
247
240
  - lib/mail_catcher/growl.rb
248
241
  - lib/mail_catcher/mail.rb
249
242
  - lib/mail_catcher/smtp.rb
243
+ - lib/mail_catcher/version.rb
250
244
  - lib/mail_catcher/web.rb
251
245
  - lib/mail_catcher.rb
246
+ - public/favicon.ico
252
247
  - public/images/logo.png
253
248
  - public/images/logo_large.png
254
249
  - public/javascripts/application.js
@@ -286,3 +281,4 @@ signing_key:
286
281
  specification_version: 3
287
282
  summary: Runs an SMTP server, catches and displays email in a web interface.
288
283
  test_files: []
284
+ has_rdoc:
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.5.8