2014-03-17 01:31:05 -04:00
require " eventmachine "
2016-04-23 03:45:49 -04:00
require " json "
2014-03-17 01:31:05 -04:00
require " mail "
require " sqlite3 "
2010-10-27 15:12:26 -04:00
2012-07-25 00:00:31 -04:00
module MailCatcher::Mail extend self
2011-10-09 03:45:23 -04:00
def db
2012-07-25 00:00:31 -04:00
@__db || = begin
2014-03-17 01:31:05 -04:00
SQLite3 :: Database . new ( " :memory: " , :type_translation = > true ) . tap do | db |
2011-10-09 03:45:23 -04:00
db . execute ( <<-SQL)
CREATE TABLE message (
id INTEGER PRIMARY KEY ASC ,
sender TEXT ,
recipients TEXT ,
subject TEXT ,
source BLOB ,
size TEXT ,
type TEXT ,
created_at DATETIME DEFAULT CURRENT_DATETIME
)
SQL
db . execute ( <<-SQL)
CREATE TABLE message_part (
id INTEGER PRIMARY KEY ASC ,
message_id INTEGER NOT NULL ,
cid TEXT ,
type TEXT ,
is_attachment INTEGER ,
filename TEXT ,
charset TEXT ,
body BLOB ,
size INTEGER ,
created_at DATETIME DEFAULT CURRENT_DATETIME
)
SQL
2010-10-27 15:12:26 -04:00
end
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def add_message ( message )
2012-07-25 00:00:31 -04:00
@add_message_query || = db . prepare ( " INSERT INTO message (sender, recipients, subject, source, type, size, created_at) VALUES (?, ?, ?, ?, ?, ?, datetime('now')) " )
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
mail = Mail . new ( message [ :source ] )
2016-04-23 03:45:49 -04:00
@add_message_query . execute ( message [ :sender ] , JSON . generate ( message [ :recipients ] ) , mail . subject , message [ :source ] , mail . mime_type || " text/plain " , message [ :source ] . length )
2011-10-09 03:45:23 -04:00
message_id = db . last_insert_row_id
parts = mail . all_parts
parts = [ mail ] if parts . empty?
parts . each do | part |
body = part . body . to_s
# Only parts have CIDs, not mail
cid = part . cid if part . respond_to? :cid
2014-03-17 01:31:05 -04:00
add_message_part ( message_id , cid , part . mime_type || " text/plain " , part . attachment? ? 1 : 0 , part . filename , part . charset , body , body . length )
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
EventMachine . next_tick do
message = MailCatcher :: Mail . message message_id
MailCatcher :: Events :: MessageAdded . push message
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def add_message_part ( * args )
2012-07-25 00:00:31 -04:00
@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')) "
@add_message_part_query . execute ( * args )
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def latest_created_at
2012-07-25 00:00:31 -04:00
@latest_created_at_query || = db . prepare " SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1 "
@latest_created_at_query . execute . next
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def messages
2014-12-31 11:34:58 -05:00
@messages_query || = db . prepare " SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at, id ASC "
2012-07-25 00:00:31 -04:00
@messages_query . execute . map do | row |
2011-10-09 03:45:23 -04:00
Hash [ row . fields . zip ( row ) ] . tap do | message |
2016-04-23 03:45:49 -04:00
message [ " recipients " ] && = JSON . parse ( message [ " recipients " ] )
2011-05-27 10:10:05 -04:00
end
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message ( id )
2012-07-25 00:00:31 -04:00
@message_query || = db . prepare " SELECT * FROM message WHERE id = ? LIMIT 1 "
row = @message_query . execute ( id ) . next
2011-10-09 03:45:23 -04:00
row && Hash [ row . fields . zip ( row ) ] . tap do | message |
2016-04-23 03:45:49 -04:00
message [ " recipients " ] && = JSON . parse ( message [ " recipients " ] )
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_has_html? ( id )
2012-07-25 00:00:31 -04:00
@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 "
2014-03-17 01:31:05 -04:00
( ! ! @message_has_html_query . execute ( id ) . next ) || [ " text/html " , " application/xhtml+xml " ] . include? ( message ( id ) [ " type " ] )
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_has_plain? ( id )
2012-07-25 00:00:31 -04:00
@message_has_plain_query || = db . prepare " SELECT 1 FROM message_part WHERE message_id = ? AND is_attachment = 0 AND type = 'text/plain' LIMIT 1 "
( ! ! @message_has_plain_query . execute ( id ) . next ) || message ( id ) [ " type " ] == " text/plain "
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_parts ( id )
2012-07-25 00:00:31 -04:00
@message_parts_query || = db . prepare " SELECT cid, type, filename, size FROM message_part WHERE message_id = ? ORDER BY filename ASC "
@message_parts_query . execute ( id ) . map do | row |
2011-10-09 03:45:23 -04:00
Hash [ row . fields . zip ( row ) ]
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_attachments ( id )
2012-07-25 00:00:31 -04:00
@message_parts_query || = db . prepare " SELECT cid, type, filename, size FROM message_part WHERE message_id = ? AND is_attachment = 1 ORDER BY filename ASC "
@message_parts_query . execute ( id ) . map do | row |
2011-10-09 03:45:23 -04:00
Hash [ row . fields . zip ( row ) ]
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part ( message_id , part_id )
2012-07-25 00:00:31 -04:00
@message_part_query || = db . prepare " SELECT * FROM message_part WHERE message_id = ? AND id = ? LIMIT 1 "
row = @message_part_query . execute ( message_id , part_id ) . next
2011-10-09 03:45:23 -04:00
row && Hash [ row . fields . zip ( row ) ]
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_type ( message_id , part_type )
2012-07-25 00:00:31 -04:00
@message_part_type_query || = db . prepare " SELECT * FROM message_part WHERE message_id = ? AND type = ? AND is_attachment = 0 LIMIT 1 "
row = @message_part_type_query . execute ( message_id , part_type ) . next
2011-10-09 03:45:23 -04:00
row && Hash [ row . fields . zip ( row ) ]
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_html ( message_id )
part = message_part_type ( message_id , " text/html " )
part || = message_part_type ( message_id , " application/xhtml+xml " )
part || = begin
message = message ( message_id )
2014-03-17 01:31:05 -04:00
message if message . present? and [ " text/html " , " application/xhtml+xml " ] . include? message [ " type " ]
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_part_plain ( message_id )
message_part_type message_id , " text/plain "
end
def message_part_cid ( message_id , cid )
2014-03-17 01:31:05 -04:00
@message_part_cid_query || = db . prepare " SELECT * FROM message_part WHERE message_id = ? "
2012-07-25 00:00:31 -04:00
@message_part_cid_query . execute ( message_id ) . map do | row |
2012-07-24 23:47:12 -04:00
Hash [ row . fields . zip ( row ) ]
2011-10-09 03:45:23 -04:00
end . find do | part |
part [ " cid " ] == cid
2010-10-27 15:12:26 -04:00
end
2011-10-09 03:45:23 -04:00
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def delete!
2016-01-11 12:23:41 -05:00
@delete_all_messages_query || = db . prepare " DELETE FROM message "
@delete_all_message_parts_query || = db . prepare " DELETE FROM message_part "
2011-06-09 23:21:39 -04:00
2016-01-11 12:23:41 -05:00
@delete_all_messages_query . execute and
@delete_all_message_parts_query . execute
2010-10-27 15:12:26 -04:00
end
2012-10-24 18:45:26 -04:00
def delete_message! ( message_id )
2014-03-17 01:31:05 -04:00
@delete_messages_query || = db . prepare " DELETE FROM message WHERE id = ? "
@delete_message_parts_query || = db . prepare " DELETE FROM message_part WHERE message_id = ? "
2012-10-24 18:45:26 -04:00
@delete_messages_query . execute ( message_id ) and
@delete_message_parts_query . execute ( message_id )
end
2011-06-09 23:21:39 -04:00
end