2010-10-27 15:12:26 -04:00
require 'mail'
require 'sqlite3'
require 'eventmachine'
module MailCatcher::Mail
2011-10-09 03:45:23 -04:00
module_function
def db
@@__db || = begin
SQLite3 :: Database . new ( ':memory:' , :type_translation = > true ) . tap do | db |
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 )
@@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 ] )
result = @@add_message_query . execute ( message [ :sender ] , message [ :recipients ] . to_json , mail . subject , message [ :source ] , mail . mime_type || 'text/plain' , message [ :source ] . length )
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
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 )
@@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 )
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def latest_created_at
@@latest_created_at_query || = db . prepare " SELECT created_at FROM message ORDER BY created_at DESC LIMIT 1 "
@@latest_created_at_query . execute . next
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def messages
@@messages_query || = db . prepare " SELECT id, sender, recipients, subject, size, created_at FROM message ORDER BY created_at ASC "
@@messages_query . execute . map do | row |
Hash [ row . fields . zip ( row ) ] . tap do | message |
2011-05-27 10:10:05 -04:00
message [ " recipients " ] && = ActiveSupport :: JSON . decode message [ " recipients " ]
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 )
@@message_query || = db . prepare " SELECT * FROM message WHERE id = ? LIMIT 1 "
row = @@message_query . execute ( id ) . next
row && Hash [ row . fields . zip ( row ) ] . tap do | message |
message [ " recipients " ] && = ActiveSupport :: JSON . decode 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 )
@@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 "
( ! ! @@message_has_html_query . execute ( id ) . next ) || [ 'text/html' , 'application/xhtml+xml' ] . include? ( message ( id ) [ " type " ] )
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_has_plain? ( id )
@@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 "
end
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
def message_parts ( id )
@@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 |
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 )
@@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 |
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 )
@@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
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 )
@@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
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 )
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 )
@@message_part_cid_query || = db . prepare 'SELECT * FROM message_part WHERE message_id = ?'
@@message_part_cid_query . execute ( message_id ) . map do | row |
part = Hash [ row . fields . zip ( row ) ]
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!
@@delete_messages_query || = db . prepare 'DELETE FROM message'
@@delete_message_parts_query || = db . prepare 'DELETE FROM message_part'
2011-06-09 23:21:39 -04:00
2011-10-09 03:45:23 -04:00
@@delete_messages_query . execute and
@@delete_message_parts_query . execute
2010-10-27 15:12:26 -04:00
end
2011-06-09 23:21:39 -04:00
end