mailcatcher 0.5.6 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -0
- data/VERSION +1 -1
- data/lib/mail_catcher.rb +35 -10
- data/lib/mail_catcher/smtp.rb +11 -0
- data/public/javascripts/application.js +118 -66
- data/public/javascripts/keymaster.min.js +4 -0
- data/views/index.haml +1 -0
- metadata +95 -30
data/README.md
CHANGED
@@ -20,6 +20,7 @@ MailCatcher runs a super simple SMTP server which catches any message sent to it
|
|
20
20
|
* Runs as a daemon run in the background.
|
21
21
|
* Sendmail-analogue command, `catchmail`, makes [using mailcatcher from PHP][withphp] a lot easier.
|
22
22
|
* Written super-simply in EventMachine, easy to dig in and change.
|
23
|
+
* Keyboard navigation between messages
|
23
24
|
|
24
25
|
## How
|
25
26
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.7
|
data/lib/mail_catcher.rb
CHANGED
@@ -15,6 +15,10 @@ module MailCatcher
|
|
15
15
|
|
16
16
|
module_function
|
17
17
|
|
18
|
+
def which command
|
19
|
+
IO.popen(["which", command], "r", :err => :close).read.chomp.presence
|
20
|
+
end
|
21
|
+
|
18
22
|
def mac?
|
19
23
|
RbConfig::CONFIG['host_os'] =~ /darwin/
|
20
24
|
end
|
@@ -28,17 +32,23 @@ module_function
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def growlnotify?
|
31
|
-
|
35
|
+
which "growlnotify"
|
32
36
|
end
|
33
37
|
|
34
|
-
def
|
35
|
-
|
36
|
-
# TODO: Look for growl framework accessible
|
37
|
-
false
|
38
|
+
def growl?
|
39
|
+
growlnotify?
|
38
40
|
end
|
39
41
|
|
40
|
-
def
|
41
|
-
|
42
|
+
def browse?
|
43
|
+
windows? or which "open"
|
44
|
+
end
|
45
|
+
|
46
|
+
def browse url
|
47
|
+
if windows?
|
48
|
+
system "start", "/b", url
|
49
|
+
elsif which "open"
|
50
|
+
system "open", url
|
51
|
+
end
|
42
52
|
end
|
43
53
|
|
44
54
|
@@defaults = {
|
@@ -49,6 +59,7 @@ module_function
|
|
49
59
|
:verbose => false,
|
50
60
|
:daemon => !windows?,
|
51
61
|
:growl => growlnotify?,
|
62
|
+
:browse => false,
|
52
63
|
}
|
53
64
|
|
54
65
|
def parse! arguments=ARGV, defaults=@@defaults
|
@@ -96,6 +107,12 @@ module_function
|
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
110
|
+
if browse?
|
111
|
+
parser.on('-b', '--browse', 'Open web browser') do
|
112
|
+
options[:browse] = true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
99
116
|
parser.on('-v', '--verbose', 'Be more verbose') do
|
100
117
|
options[:verbose] = true
|
101
118
|
end
|
@@ -123,19 +140,27 @@ module_function
|
|
123
140
|
# Get our lion on if asked
|
124
141
|
MailCatcher::Growl.start if options[:growl]
|
125
142
|
|
126
|
-
|
143
|
+
smtp_url = "smtp://#{options[:smtp_ip]}:#{options[:smtp_port]}"
|
144
|
+
http_url = "http://#{options[:http_ip]}:#{options[:http_port]}"
|
127
145
|
|
128
146
|
# Set up an SMTP server to run within EventMachine
|
129
147
|
rescue_port options[:smtp_port] do
|
130
148
|
EventMachine.start_server options[:smtp_ip], options[:smtp_port], Smtp
|
131
|
-
puts "==>
|
149
|
+
puts "==> #{smtp_url}"
|
132
150
|
end
|
133
151
|
|
134
152
|
# Let Thin set itself up inside our EventMachine loop
|
135
153
|
# (Skinny/WebSockets just works on the inside)
|
136
154
|
rescue_port options[:http_port] do
|
137
155
|
Thin::Server.start options[:http_ip], options[:http_port], Web
|
138
|
-
puts "==>
|
156
|
+
puts "==> #{http_url}"
|
157
|
+
end
|
158
|
+
|
159
|
+
# Open the web browser before detatching console
|
160
|
+
if options[:browse]
|
161
|
+
EventMachine.next_tick do
|
162
|
+
browse http_url
|
163
|
+
end
|
139
164
|
end
|
140
165
|
|
141
166
|
# Daemonize, if we should, but only after the servers have started.
|
data/lib/mail_catcher/smtp.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
3
|
class MailCatcher::Smtp < EventMachine::Protocols::SmtpServer
|
4
|
+
# We override EM's mail from processing to allow multiple mail-from commands
|
5
|
+
# per [RFC 2821](http://tools.ietf.org/html/rfc2821#section-4.1.1.2)
|
6
|
+
def process_mail_from sender
|
7
|
+
if @state.include? :mail_from
|
8
|
+
@state -= [:mail_from, :rcpt, :data]
|
9
|
+
receive_reset
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
4
15
|
def current_message
|
5
16
|
@current_message ||= {}
|
6
17
|
end
|
@@ -1,36 +1,37 @@
|
|
1
1
|
(function() {
|
2
2
|
var MailCatcher;
|
3
|
-
|
3
|
+
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
4
4
|
jQuery.expr[':'].icontains = function(a, i, m) {
|
5
5
|
var _ref, _ref2;
|
6
6
|
return ((_ref = (_ref2 = a.textContent) != null ? _ref2 : a.innerText) != null ? _ref : "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
|
7
7
|
};
|
8
|
-
|
9
8
|
MailCatcher = (function() {
|
10
|
-
|
11
9
|
function MailCatcher() {
|
12
|
-
|
13
|
-
|
10
|
+
this.nextTab = __bind(this.nextTab, this);;
|
11
|
+
this.previousTab = __bind(this.previousTab, this);;
|
12
|
+
this.openTab = __bind(this.openTab, this);;
|
13
|
+
this.selectedTab = __bind(this.selectedTab, this);;
|
14
|
+
this.getTab = __bind(this.getTab, this);; $('#messages tr').live('click', __bind(function(e) {
|
14
15
|
e.preventDefault();
|
15
|
-
return
|
16
|
-
});
|
17
|
-
$('input[name=search]').keyup(function(e) {
|
16
|
+
return this.loadMessage($(e.currentTarget).attr('data-message-id'));
|
17
|
+
}, this));
|
18
|
+
$('input[name=search]').keyup(__bind(function(e) {
|
18
19
|
var query;
|
19
20
|
query = $.trim($(e.currentTarget).val());
|
20
21
|
if (query) {
|
21
|
-
return
|
22
|
+
return this.searchMessages(query);
|
22
23
|
} else {
|
23
|
-
return
|
24
|
+
return this.clearSearch();
|
24
25
|
}
|
25
|
-
});
|
26
|
-
$('#message .views .format.tab a').live('click', function(e) {
|
26
|
+
}, this));
|
27
|
+
$('#message .views .format.tab a').live('click', __bind(function(e) {
|
27
28
|
e.preventDefault();
|
28
|
-
return
|
29
|
-
});
|
30
|
-
$('#message .views .analysis.tab a').live('click', function(e) {
|
29
|
+
return this.loadMessageBody(this.selectedMessage(), $($(e.currentTarget).parent('li')).data('message-format'));
|
30
|
+
}, this));
|
31
|
+
$('#message .views .analysis.tab a').live('click', __bind(function(e) {
|
31
32
|
e.preventDefault();
|
32
|
-
return
|
33
|
-
});
|
33
|
+
return this.loadMessageAnalysis(this.selectedMessage());
|
34
|
+
}, this));
|
34
35
|
$('#resizer').live({
|
35
36
|
mousedown: function(e) {
|
36
37
|
var events;
|
@@ -49,7 +50,7 @@
|
|
49
50
|
});
|
50
51
|
}
|
51
52
|
});
|
52
|
-
$('nav.app .clear a').live('click', function(e) {
|
53
|
+
$('nav.app .clear a').live('click', __bind(function(e) {
|
53
54
|
e.preventDefault();
|
54
55
|
if (confirm("You will lose all your received messages.\n\nAre you sure you want to clear all messages?")) {
|
55
56
|
return $.ajax({
|
@@ -65,8 +66,8 @@
|
|
65
66
|
}
|
66
67
|
});
|
67
68
|
}
|
68
|
-
});
|
69
|
-
$('nav.app .quit a').live('click', function(e) {
|
69
|
+
}, this));
|
70
|
+
$('nav.app .quit a').live('click', __bind(function(e) {
|
70
71
|
e.preventDefault();
|
71
72
|
if (confirm("You will lose all your received messages.\n\nAre you sure you want to quit?")) {
|
72
73
|
return $.ajax({
|
@@ -79,42 +80,106 @@
|
|
79
80
|
}
|
80
81
|
});
|
81
82
|
}
|
82
|
-
});
|
83
|
+
}, this));
|
84
|
+
key('up', __bind(function() {
|
85
|
+
var id;
|
86
|
+
id = this.selectedMessage() || 1;
|
87
|
+
if (id > 1) {
|
88
|
+
id -= 1;
|
89
|
+
}
|
90
|
+
return this.loadMessage(id);
|
91
|
+
}, this));
|
92
|
+
key('down', __bind(function() {
|
93
|
+
var id;
|
94
|
+
id = this.selectedMessage() || this.messagesCount();
|
95
|
+
if (id < this.messagesCount()) {
|
96
|
+
id += 1;
|
97
|
+
}
|
98
|
+
return this.loadMessage(id);
|
99
|
+
}, this));
|
100
|
+
key('⌘+up, ctrl+up', __bind(function() {
|
101
|
+
return this.loadMessage(1);
|
102
|
+
}, this));
|
103
|
+
key('⌘+down, ctrl+down', __bind(function() {
|
104
|
+
return this.loadMessage(this.messagesCount());
|
105
|
+
}, this));
|
106
|
+
key('left', __bind(function() {
|
107
|
+
return this.openTab(this.previousTab());
|
108
|
+
}, this));
|
109
|
+
key('right', __bind(function() {
|
110
|
+
return this.openTab(this.nextTab());
|
111
|
+
}, this));
|
83
112
|
this.refresh();
|
84
113
|
this.subscribe();
|
85
114
|
}
|
86
|
-
|
87
115
|
MailCatcher.prototype.parseDateRegexp = /^(\d{4})[-\/\\](\d{2})[-\/\\](\d{2})(?:\s+|T)(\d{2})[:-](\d{2})[:-](\d{2})(?:([ +-]\d{2}:\d{2}|\s*\S+|Z?))?$/;
|
88
|
-
|
89
116
|
MailCatcher.prototype.parseDate = function(date) {
|
90
117
|
var match;
|
91
118
|
if (match = this.parseDateRegexp.exec(date)) {
|
92
119
|
return new Date(match[1], match[2] - 1, match[3], match[4], match[5], match[6], 0);
|
93
120
|
}
|
94
121
|
};
|
95
|
-
|
96
122
|
MailCatcher.prototype.offsetTimeZone = function(date) {
|
97
123
|
var offset;
|
98
124
|
offset = Date.now().getTimezoneOffset() * 60000;
|
99
125
|
date.setTime(date.getTime() - offset);
|
100
126
|
return date;
|
101
127
|
};
|
102
|
-
|
103
128
|
MailCatcher.prototype.formatDate = function(date) {
|
104
|
-
if (typeof date === "string")
|
129
|
+
if (typeof date === "string") {
|
130
|
+
date && (date = this.parseDate(date));
|
131
|
+
}
|
105
132
|
date && (date = this.offsetTimeZone(date));
|
106
133
|
return date && (date = date.toString("dddd, d MMM yyyy h:mm:ss tt"));
|
107
134
|
};
|
108
|
-
|
135
|
+
MailCatcher.prototype.messagesCount = function() {
|
136
|
+
return $('#messages tr').length - 1;
|
137
|
+
};
|
138
|
+
MailCatcher.prototype.tabs = function() {
|
139
|
+
return $('#message ul').children('.tab');
|
140
|
+
};
|
141
|
+
MailCatcher.prototype.getTab = function(i) {
|
142
|
+
return $(this.tabs()[i]);
|
143
|
+
};
|
144
|
+
MailCatcher.prototype.selectedTab = function() {
|
145
|
+
return this.tabs().index($('#message li.tab.selected'));
|
146
|
+
};
|
147
|
+
MailCatcher.prototype.openTab = function(i) {
|
148
|
+
return this.getTab(i).children('a').click();
|
149
|
+
};
|
150
|
+
MailCatcher.prototype.previousTab = function(tab) {
|
151
|
+
var i;
|
152
|
+
i = tab || tab === 0 ? tab : this.selectedTab() - 1;
|
153
|
+
if (i < 0) {
|
154
|
+
i = this.tabs().length - 1;
|
155
|
+
}
|
156
|
+
if (this.getTab(i).is(":visible")) {
|
157
|
+
return i;
|
158
|
+
} else {
|
159
|
+
return this.previousTab(i - 1);
|
160
|
+
}
|
161
|
+
};
|
162
|
+
MailCatcher.prototype.nextTab = function(tab) {
|
163
|
+
var i;
|
164
|
+
i = tab ? tab : this.selectedTab() + 1;
|
165
|
+
if (i > this.tabs().length - 1) {
|
166
|
+
i = 0;
|
167
|
+
}
|
168
|
+
if (this.getTab(i).is(":visible")) {
|
169
|
+
return i;
|
170
|
+
} else {
|
171
|
+
return this.nextTab(i + 1);
|
172
|
+
}
|
173
|
+
};
|
109
174
|
MailCatcher.prototype.haveMessage = function(message) {
|
110
|
-
if (message.id != null)
|
175
|
+
if (message.id != null) {
|
176
|
+
message = message.id;
|
177
|
+
}
|
111
178
|
return $("#messages tbody tr[data-message-id=\"" + message + "\"]").length > 0;
|
112
179
|
};
|
113
|
-
|
114
180
|
MailCatcher.prototype.selectedMessage = function() {
|
115
181
|
return $('#messages tr.selected').data('message-id');
|
116
182
|
};
|
117
|
-
|
118
183
|
MailCatcher.prototype.searchMessages = function(query) {
|
119
184
|
var $rows, selector, token;
|
120
185
|
selector = ((function() {
|
@@ -131,25 +196,23 @@
|
|
131
196
|
$rows.not(selector).hide();
|
132
197
|
return $rows.filter(selector).show();
|
133
198
|
};
|
134
|
-
|
135
199
|
MailCatcher.prototype.clearSearch = function() {
|
136
200
|
return $('#messages tbody tr').show();
|
137
201
|
};
|
138
|
-
|
139
202
|
MailCatcher.prototype.addMessage = function(message) {
|
140
203
|
return $('#messages tbody').append($('<tr />').attr('data-message-id', message.id.toString()).append($('<td/>').text(message.sender || "No sender").toggleClass("blank", !message.sender)).append($('<td/>').text((message.recipients || []).join(', ') || "No receipients").toggleClass("blank", !message.recipients.length)).append($('<td/>').text(message.subject || "No subject").toggleClass("blank", !message.subject)).append($('<td/>').text(this.formatDate(message.created_at))));
|
141
204
|
};
|
142
|
-
|
143
205
|
MailCatcher.prototype.loadMessage = function(id) {
|
144
|
-
|
145
|
-
|
206
|
+
if ((id != null ? id.id : void 0) != null) {
|
207
|
+
id = id.id;
|
208
|
+
}
|
146
209
|
id || (id = $('#messages tr.selected').attr('data-message-id'));
|
147
210
|
if (id != null) {
|
148
211
|
$('#messages tbody tr:not([data-message-id="' + id + '"])').removeClass('selected');
|
149
212
|
$('#messages tbody tr[data-message-id="' + id + '"]').addClass('selected');
|
150
|
-
return $.getJSON('/messages/' + id + '.json', function(message) {
|
213
|
+
return $.getJSON('/messages/' + id + '.json', __bind(function(message) {
|
151
214
|
var $ul;
|
152
|
-
$('#message .metadata dd.created_at').text(
|
215
|
+
$('#message .metadata dd.created_at').text(this.formatDate(message.created_at));
|
153
216
|
$('#message .metadata dd.from').text(message.sender);
|
154
217
|
$('#message .metadata dd.to').text((message.recipients || []).join(', '));
|
155
218
|
$('#message .metadata dd.subject').text(message.subject);
|
@@ -179,14 +242,13 @@
|
|
179
242
|
}
|
180
243
|
$('#message .views .download a').attr('href', "/messages/" + id + ".eml");
|
181
244
|
if ($('#message .views .tab.analysis.selected').length) {
|
182
|
-
return
|
245
|
+
return this.loadMessageAnalysis();
|
183
246
|
} else {
|
184
|
-
return
|
247
|
+
return this.loadMessageBody();
|
185
248
|
}
|
186
|
-
});
|
249
|
+
}, this));
|
187
250
|
}
|
188
251
|
};
|
189
|
-
|
190
252
|
MailCatcher.prototype.loadMessageBody = function(id, format) {
|
191
253
|
id || (id = this.selectedMessage());
|
192
254
|
format || (format = $('#message .views .tab.format.selected').attr('data-message-format'));
|
@@ -197,7 +259,6 @@
|
|
197
259
|
return $('#message iframe').attr("src", "/messages/" + id + "." + format);
|
198
260
|
}
|
199
261
|
};
|
200
|
-
|
201
262
|
MailCatcher.prototype.loadMessageAnalysis = function(id) {
|
202
263
|
var $form, $iframe;
|
203
264
|
id || (id = this.selectedMessage());
|
@@ -212,49 +273,40 @@
|
|
212
273
|
});
|
213
274
|
}
|
214
275
|
};
|
215
|
-
|
216
276
|
MailCatcher.prototype.refresh = function() {
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
277
|
+
return $.getJSON('/messages', __bind(function(messages) {
|
278
|
+
return $.each(messages, __bind(function(i, message) {
|
279
|
+
if (!this.haveMessage(message)) {
|
280
|
+
return this.addMessage(message);
|
281
|
+
}
|
282
|
+
}, this));
|
283
|
+
}, this));
|
223
284
|
};
|
224
|
-
|
225
285
|
MailCatcher.prototype.subscribe = function() {
|
226
|
-
if (typeof WebSocket
|
286
|
+
if (typeof WebSocket != "undefined" && WebSocket !== null) {
|
227
287
|
return this.subscribeWebSocket();
|
228
288
|
} else {
|
229
289
|
return this.subscribePoll();
|
230
290
|
}
|
231
291
|
};
|
232
|
-
|
233
292
|
MailCatcher.prototype.subscribeWebSocket = function() {
|
234
|
-
var secure
|
235
|
-
_this = this;
|
293
|
+
var secure;
|
236
294
|
secure = window.location.scheme === 'https';
|
237
295
|
this.websocket = new WebSocket("" + (secure ? 'wss' : 'ws') + "://" + window.location.host + "/messages");
|
238
|
-
return this.websocket.onmessage = function(event) {
|
239
|
-
return
|
240
|
-
};
|
296
|
+
return this.websocket.onmessage = __bind(function(event) {
|
297
|
+
return this.addMessage($.parseJSON(event.data));
|
298
|
+
}, this);
|
241
299
|
};
|
242
|
-
|
243
300
|
MailCatcher.prototype.subscribePoll = function() {
|
244
|
-
var _this = this;
|
245
301
|
if (this.refreshInterval == null) {
|
246
|
-
return this.refreshInterval = setInterval((function() {
|
247
|
-
return
|
248
|
-
}), 1000);
|
302
|
+
return this.refreshInterval = setInterval((__bind(function() {
|
303
|
+
return this.refresh();
|
304
|
+
}, this)), 1000);
|
249
305
|
}
|
250
306
|
};
|
251
|
-
|
252
307
|
return MailCatcher;
|
253
|
-
|
254
308
|
})();
|
255
|
-
|
256
309
|
$(function() {
|
257
310
|
return window.MailCatcher = new MailCatcher;
|
258
311
|
});
|
259
|
-
|
260
312
|
}).call(this);
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// keymaster.js
|
2
|
+
// (c) 2011 Thomas Fuchs
|
3
|
+
// keymaster.js may be freely distributed under the MIT license.
|
4
|
+
(function(a){function h(a,b){var c=a.length;while(c--)if(a[c]===b)return c;return-1}function i(a){var b,g,i,j,k;b=a.keyCode;if(b==93||b==224)b=91;if(b in d){d[b]=!0;for(i in f)f[i]==b&&(l[i]=!0);return}if(!l.filter.call(this,a))return;if(!(b in c))return;for(j=0;j<c[b].length;j++){g=c[b][j];if(g.scope==e||g.scope=="all"){k=g.mods.length>0;for(i in d)if(!d[i]&&h(g.mods,+i)>-1||d[i]&&h(g.mods,+i)==-1)k=!1;(g.mods.length==0&&!d[16]&&!d[18]&&!d[17]&&!d[91]||k)&&g.method(a,g)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}}function j(a){var b=a.keyCode,c;if(b==93||b==224)b=91;if(b in d){d[b]=!1;for(c in f)f[c]==b&&(l[c]=!1)}}function k(){for(b in d)d[b]=!1;for(b in f)l[b]=!1}function l(a,b,d){var e,h,i,j;d===undefined&&(d=b,b="all"),a=a.replace(/\s/g,""),e=a.split(","),e[e.length-1]==""&&(e[e.length-2]+=",");for(i=0;i<e.length;i++){h=[],a=e[i].split("+");if(a.length>1){h=a.slice(0,a.length-1);for(j=0;j<h.length;j++)h[j]=f[h[j]];a=[a[a.length-1]]}a=a[0],a=g[a]||a.toUpperCase().charCodeAt(0),a in c||(c[a]=[]),c[a].push({shortcut:e[i],scope:b,method:d,key:e[i],mods:h})}}function m(a){var b=(a.target||a.srcElement).tagName;return b!="INPUT"&&b!="SELECT"&&b!="TEXTAREA"}function n(a){e=a||"all"}function o(){return e||"all"}function p(a){var b,d,e;for(b in c){d=c[b];for(e=0;e<d.length;)d[e].scope===a?d.splice(e,1):e++}}function q(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220};for(b=1;b<20;b++)f["f"+b]=111+b;for(b in f)l[b]=!1;q(document,"keydown",i),q(document,"keyup",j),q(window,"focus",k),a.key=l,a.key.setScope=n,a.key.getScope=o,a.key.deleteScope=p,a.key.filter=m,typeof module!="undefined"&&(module.exports=key)})(this);
|
data/views/index.haml
CHANGED
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.
|
4
|
+
version: 0.5.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '3.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: eventmachine
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ~>
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0.12'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0.12'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: haml
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '3.1'
|
44
54
|
type: :runtime
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.1'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: mail
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ~>
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '2.3'
|
55
70
|
type: :runtime
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2.3'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: sinatra
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ~>
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: '1.2'
|
66
86
|
type: :runtime
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.2'
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: skinny
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ~>
|
@@ -76,10 +101,15 @@ dependencies:
|
|
76
101
|
version: '0.2'
|
77
102
|
type: :runtime
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.2'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: sqlite3
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ~>
|
@@ -87,10 +117,15 @@ dependencies:
|
|
87
117
|
version: '1.3'
|
88
118
|
type: :runtime
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.3'
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: thin
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ~>
|
@@ -98,10 +133,15 @@ dependencies:
|
|
98
133
|
version: '1.2'
|
99
134
|
type: :runtime
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '1.2'
|
102
142
|
- !ruby/object:Gem::Dependency
|
103
143
|
name: coffee-script
|
104
|
-
requirement:
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
105
145
|
none: false
|
106
146
|
requirements:
|
107
147
|
- - ~>
|
@@ -109,10 +149,15 @@ dependencies:
|
|
109
149
|
version: '2.2'
|
110
150
|
type: :development
|
111
151
|
prerelease: false
|
112
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '2.2'
|
113
158
|
- !ruby/object:Gem::Dependency
|
114
159
|
name: compass
|
115
|
-
requirement:
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
116
161
|
none: false
|
117
162
|
requirements:
|
118
163
|
- - ~>
|
@@ -120,10 +165,15 @@ dependencies:
|
|
120
165
|
version: 0.11.1
|
121
166
|
type: :development
|
122
167
|
prerelease: false
|
123
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.11.1
|
124
174
|
- !ruby/object:Gem::Dependency
|
125
175
|
name: rake
|
126
|
-
requirement:
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
127
177
|
none: false
|
128
178
|
requirements:
|
129
179
|
- - ! '>='
|
@@ -131,10 +181,15 @@ dependencies:
|
|
131
181
|
version: '0'
|
132
182
|
type: :development
|
133
183
|
prerelease: false
|
134
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
135
190
|
- !ruby/object:Gem::Dependency
|
136
191
|
name: rdoc
|
137
|
-
requirement:
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
138
193
|
none: false
|
139
194
|
requirements:
|
140
195
|
- - ! '>='
|
@@ -142,10 +197,15 @@ dependencies:
|
|
142
197
|
version: '0'
|
143
198
|
type: :development
|
144
199
|
prerelease: false
|
145
|
-
version_requirements:
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
146
206
|
- !ruby/object:Gem::Dependency
|
147
207
|
name: sass
|
148
|
-
requirement:
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
149
209
|
none: false
|
150
210
|
requirements:
|
151
211
|
- - ~>
|
@@ -153,7 +213,12 @@ dependencies:
|
|
153
213
|
version: '3.1'
|
154
214
|
type: :development
|
155
215
|
prerelease: false
|
156
|
-
version_requirements:
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ~>
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '3.1'
|
157
222
|
description: ! " MailCatcher runs a super simple SMTP server which catches any\n
|
158
223
|
\ message sent to it to display in a web interface. Run\n mailcatcher, set
|
159
224
|
your favourite app to deliver to\n smtp://127.0.0.1:1025 instead of your default
|
@@ -184,6 +249,7 @@ files:
|
|
184
249
|
- public/javascripts/date.js
|
185
250
|
- public/javascripts/flexie.min.js
|
186
251
|
- public/javascripts/jquery.js
|
252
|
+
- public/javascripts/keymaster.min.js
|
187
253
|
- public/javascripts/modernizr.js
|
188
254
|
- public/javascripts/xslt-3.2.js
|
189
255
|
- public/stylesheets/application.css
|
@@ -209,9 +275,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
275
|
version: '0'
|
210
276
|
requirements: []
|
211
277
|
rubyforge_project:
|
212
|
-
rubygems_version: 1.8.
|
278
|
+
rubygems_version: 1.8.23
|
213
279
|
signing_key:
|
214
280
|
specification_version: 3
|
215
281
|
summary: Runs an SMTP server, catches and displays email in a web interface.
|
216
282
|
test_files: []
|
217
|
-
has_rdoc:
|