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
2016-08-10 15:38:34 -04:00
SQLite3 :: Database . new ( MailCatcher . options [ :sqlite_db ] , :type_translation = > true ) . tap do | db |
2011-10-09 03:45:23 -04:00
db . execute ( <<-SQL)
2016-08-10 15:38:34 -04:00
CREATE TABLE IF NOT EXISTS message (
2011-10-09 03:45:23 -04:00
id INTEGER PRIMARY KEY ASC ,
sender TEXT ,
recipients TEXT ,
subject TEXT ,
2016-08-11 08:23:33 -04:00
from_server TEXT ,
2011-10-09 03:45:23 -04:00
source BLOB ,
size TEXT ,
type TEXT ,
created_at DATETIME DEFAULT CURRENT_DATETIME
)
SQL
db . execute ( <<-SQL)
2016-08-10 15:38:34 -04:00
CREATE TABLE IF NOT EXISTS message_part (
2011-10-09 03:45:23 -04:00
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 )
2016-08-11 08:23:33 -04:00
@add_message_query || = db . prepare ( " INSERT INTO message (sender, recipients, subject, from_server, 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-08-11 08:23:33 -04:00
from_server = mail . received ? mail . received . value . sub ( / ^from \ s+ / , '' ) . sub ( / \ s+.*$ / , '' ) : nil
2016-08-10 14:45:58 -04:00
sender = ( mail . from && ! mail . from . empty? ) ? mail . from : message [ :sender ]
recipients = ( mail . to && ! mail . to . empty? ) ? mail . to : message [ :recipients ]
2016-08-11 08:23:33 -04:00
@add_message_query . execute ( sender , JSON . generate ( recipients ) , mail . subject , from_server , 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
2016-08-10 16:15:56 -04:00
if MailCatcher . options [ :delete_older_than ]
MailCatcher :: Mail . delete_messages_older_than! ( MailCatcher . options [ :delete_older_than ] )
end
2016-08-10 16:35:05 -04:00
if MailCatcher . options [ :keep_num_emails ]
MailCatcher :: Mail . delete_messages_keep! ( MailCatcher . options [ :keep_num_emails ] )
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 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
2016-08-11 08:23:33 -04:00
@messages_query || = db . prepare MailCatcher . show_from_server? ?
" SELECT id, sender, recipients, subject, from_server, size, created_at FROM message ORDER BY created_at, id ASC " :
" 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-08-11 08:23:33 -04:00
unless MailCatcher . show_from_server?
message . delete ( 'from_server' )
end
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 )
2016-04-23 03:49:55 -04:00
message if message 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
2016-08-10 16:15:56 -04:00
def delete_messages_older_than! ( modifier )
@delete_messages_older_than_query || = db . prepare " DELETE FROM message WHERE created_at < datetime('now', ?) "
@delete_message_parts_older_than_query || = db . prepare " DELETE FROM message_part WHERE created_at < datetime('now', ?) "
@delete_messages_older_than_query . execute ( modifier ) and
@delete_message_parts_older_than_query . execute ( modifier )
end
2016-08-10 16:35:05 -04:00
def delete_messages_keep! ( keep_num_emails )
@delete_messages_query || = db . prepare " DELETE FROM message WHERE id IN (SELECT id FROM message ORDER BY id DESC LIMIT -1 OFFSET ?); "
@delete_message_parts_query || = db . prepare " DELETE FROM message_part WHERE id NOT IN (SELECT id FROM message) "
@delete_messages_query . execute ( keep_num_emails ) and
@delete_message_parts_query . execute ( )
end
2011-06-09 23:21:39 -04:00
end