This commit is contained in:
Wojciech Todryk 2011-08-26 22:59:43 +02:00
parent 649dc660df
commit 52b4c63ddb
13 changed files with 287 additions and 107 deletions

View file

@ -39,8 +39,7 @@ class MessagesController < ApplicationController
(uids_remote-uids_local).each_slice($defaults["imap_fetch_slice"].to_i) do |slice|
messages = @mailbox.uid_fetch(slice, ImapMessageModule::IMAPMessage.fetch_attr)
messages.each do |m|
mess = ImapMessageModule::IMAPMessage.fromImap(m)
Message.createForUser(@current_user,@current_folder,mess)
Message.createForUser(@current_user,@current_folder,m)
end
end
@ -141,41 +140,50 @@ class MessagesController < ApplicationController
@attachments = []
@render_as_text = []
@message = @current_user.messages.find(params[:id])
@message = @current_user.messages.find_by_uid(params[:id])
@message.update_attributes(:unseen => false)
imap_message = @mailbox.fetch_body(@message.uid)
parts = imap_message.split(/\r\n\r\n/)
@message_header = parts[0]
mail = Mail.new(imap_message)
@title = mail.subject
if mail.multipart?
idx = 0
mail.parts.each do |part|
case part.content_type
when /^text\/plain/ then
@render_as_text << part.body.raw_source
@mail = Mail.new(imap_message)
if @mail.multipart?
# idx = 0
# @mail.parts.each do |part|
# a = Attachment.new( :message_id => @message.id,
# :description => part.content_description,
# :type => part.content_type,
# :content => part.body.raw_source,
# :encoding => part.content_transfer_encoding,
# :idx => idx,
# :multipart => part.multipart?
# )
# logger.custom('a',a.to_s)
# if a.isText?
# @render_as_text << a.content_normalized
# else
# @attachments << a
# end
#
# idx += 1
# end
Attachment.fromPart(@attachments,@message.id,@mail.parts,0)
@attachments.each do |a|
a.isText? ? @render_as_text << a.content_normalized : @render_as_text
end
else
a = Attachment.new( :message_id => @message.id,
:description => part.content_description,
:type => part.content_type,
:content => part.body.raw_source,
:idx => idx
)
@attachments << a
end
idx += 1
end
else
if mail.content_type.nil?
@render_as_text << mail.body.raw_source
else
a = Attachment.new( :message_id => @message.id,
:type => mail.content_type,
:encoding => mail.body.encoding,
:charset => mail.body.charset,
:content => mail.body.raw_source,
:description => @mail.content_description,
:type => @mail.content_type,
:encoding => @mail.body.encoding,
:charset => @mail.body.charset,
:content => @mail.body.raw_source,
:idx => 0
)
logger.custom('a',a.to_s)
if a.isText?
@render_as_text << a.content_normalized
else
@attachments << a
end
end
@ -203,6 +211,7 @@ class MessagesController < ApplicationController
:description => part.content_description,
:type => part.content_type,
:content => part.body.raw_source,
:encoding => part.content_transfer_encoding,
:idx => params[:idx]
)
else
@ -216,7 +225,7 @@ class MessagesController < ApplicationController
end
headers['Content-type'] = a.type
headers['Content-Disposition'] = %(attachment; filename="#{a.name}")
render :text => a.content_decoded
render :text => a.decode
end
end

View file

@ -13,10 +13,14 @@ class UserController < ApplicationController
end
def authenticate
if !$defaults["only_can_logins"].include?(params[:user][:email])
if not $defaults["only_can_logins"].nil?
if not $defaults["only_can_logins"].include?(params[:user][:email])
redirect_to :controller => 'internal', :action => 'onlycanlogins'
return false
end
end
user = User.find_by_email(params[:user][:email])
if user.nil?
redirect_to :action => 'unknown' ,:email=> params[:user][:email]

View file

@ -14,15 +14,24 @@ module MessagesHelper
date.nil? ? t(:no_data) : date.strftime("%Y-%m-%d %H:%M")
end
def address_formatter(addr)
ImapMessageModule::IMAPAddress.parse(addr).friendly
# def address_formatter(addr)
# ImapMessageModule::IMAPAddress.parse(addr).friendly
# end
def address_formatter(addr,mode)
s = ""
length = $defaults["msg_address_length"].to_i
fs = addr.split(/</)
if mode == :index
fs[0].size.zero? ? s = fs[1] : s = fs[0]
s.length >= length ? s = s[0,length]+"..." : s
else
fs[0].size.zero? ? s = "<" + fs[1] + ">" : s << fs[0] + " <" + fs[1] + ">"
end
def show_address_formatter(addr)
html = ""
fs = addr.split(/#/)
fs[0].size.zero? ? html << h("<")+fs[1]+h("@")+fs[2]+h(">") : html << fs[0]+h(" <")+fs[1]+h("@")+fs[2]+h(">")
html
return h(s)
end
def subject_formatter(message)
@ -32,7 +41,7 @@ module MessagesHelper
length = $defaults["msg_subject_length"].to_i
message.subject.length >= length ? s = message.subject[0,length]+"..." : s = message.subject
end
link_to s,{:controller => 'messages', :action => 'show', :id => message.id} , :title => message.subject
link_to s,{:controller => 'messages', :action => 'show', :id => message.uid} , :title => message.subject
end
def attachment_formatter(message)
@ -61,8 +70,9 @@ module MessagesHelper
end
def content_text_plain_for_render(text)
html = h(text)
html.gsub!(/\r\n/,"<br/>")
html = "<pre>"
html << h(text)
html << "</pre>"
html
end

View file

@ -3,20 +3,51 @@ class Attachment
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :type, :charset, :encoding, :name, :description, :content, :message_id, :idx
attr_accessor :type, :charset, :encoding, :name, :description, :content, :message_id, :idx, :boundary, :format, :multipart
attr_reader :link
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
if @type =~ /name=(\S+)/
@name = $1
@type =~ /^(\S+);/
@type = $1
if not @type.nil?
params = @type.split(/;\s*/)
@type = params[0]
params.each do |p|
if p =~ /=/
fields = p.split(/=/)
key = fields[0]
value = fields[1]
if Attachment.attribute_method?(key) == true
send("#{key}=", value)
end
end
end
end
end
def multipart?
multipart
end
def self.fromPart(attachments,id,parts,idx)
parts.each do |part|
a = Attachment.new( :message_id => id,
:description => part.content_description,
:type => part.content_type,
:content => part.body.raw_source,
:encoding => part.content_transfer_encoding,
:idx => idx,
:multipart => part.multipart?
)
if a.multipart?
fromPart(attachments,id,part.parts,idx)
else
@name = "no_name.dat"
attachments << a
end
idx += 1
end
end
@ -24,6 +55,25 @@ class Attachment
false
end
def name
if @name.nil?
case type
when /^text\/html/
"index#{idx}.html"
when /^multipart/
"multipart#{idx}.part"
when /^text\/plain/
"file#{idx}.txt"
else
"filaname.dat"
end
else
@name
end
end
def to_s
s = "Attachment:\n"
instance_variables.sort.each do |name|
@ -36,8 +86,12 @@ class Attachment
s
end
def isText?
@type.nil? or @type =~ /^text\/plain/
end
def title
@description.nil? ? @name : @description
@description.nil? ? name : @description
end
def type
@ -52,6 +106,51 @@ class Attachment
@encoding.nil? ? '' : @encoding
end
def format
@format.nil? ? '' : @format
end
def boundary
@boundary.nil? ? '' : @boundary
end
def decode
case @encoding
when /quoted-printable/
decoded = @content.gsub(/_/," ").unpack("M").first
when /base64/
decoded = @content.unpack("m").first
when /uuencode/
array = @content.split(/\n/)
if array[0] =~ /^begin/
size = array.size
array.delete_at(size-1)
array.delete_at(size-2)
array.delete_at(0)
end
string = array.join
decoded = string.unpack("u").first
else
decoded = @content
end
end
def content_normalized
decoded = decode
if not @charset == 'UTF-8'
@charset.nil? ? charset = $defaults["msg_unknown_encoding"] : charset = @charset
charseted = Iconv.iconv("UTF-8",charset,decoded)
else
charseted = decoded
end
charseted
end
end
# def to_html
# html = "<span class=\"attachment\">"
# html << "<span class=\"title\">"
@ -81,9 +180,4 @@ class Attachment
# html
# end
def content_decoded
# TODO attachments decoding
@content
end
end

View file

@ -1,8 +1,47 @@
require 'iconv'
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :folder
attr_accessor :body
set_primary_key :uid
attr_accessible :unseen, :to_addr, :size, :content_type, :folder_id, :subject, :date, :uid, :from_addr, :user_id, :msg_id
def self.decode(text,unknown_encoding = $defaults["msg_unknown_encoding"])
begin
if text.=~(/^=\?/).nil?
after = Iconv.conv('UTF-8',unknown_encoding,text)
else
f = text.split(/\?/)
case f[2].downcase
when 'q':
after = f[3].gsub(/_/," ").unpack("M").first
when 'b':
after = f[3].gsub(/_/," ").unpack("m").first
else
return text
end
if f[1].downcase != 'utf-8'
after = Iconv.conv('UTF-8',f[1],after)
end
end
return after
rescue
logger.error("Class Message: String decode error: #{text}")
return text
end
end
def self.addr_to_db(addr)
ret = ""
name = addr.name
name.nil? ? ret : ret << decode(name)
ret << "<" + addr.mailbox + "@" + addr.host
ret
end
def self.getPageForUser(user,folder,page,sort_field,sort_dir)
@ -17,23 +56,33 @@ class Message < ActiveRecord::Base
Message.paginate :page => page , :per_page => user.prefs.msgs_per_page.to_i, :conditions=> ['user_id = ? and folder_id = ?', user.id,folder.id],:order => order
end
def self.createForUser(user,folder,mess)
def self.createForUser(user,folder,imap_message)
envelope = imap_message.attr['ENVELOPE']
from = addr_to_db(envelope.from[0])
to = addr_to_db(envelope.to[0])
envelope.subject.nil? ? subject = "" : subject = decode(envelope.subject)
create(
:user_id => user.id,
:folder_id => folder.id,
:msg_id => mess.message_id,
:uid => mess.uid,
:from_addr => mess.from_to_db,
:to_addr => mess.to_to_db,
:subject => mess.subject,
:content_type => mess.content_type,
:date => mess.date,
:unseen => mess.unseen,
:size => mess.size)
:msg_id => envelope.message_id,
:uid => imap_message.attr['UID'].to_i,
:from_addr => from,
:to_addr => to,
:subject => subject,
:content_type => imap_message.attr['BODYSTRUCTURE'].media_type.downcase,
:date => envelope.date,
:unseen => !(imap_message.attr['FLAGS'].member? :Seen),
:size => imap_message.attr['RFC822.SIZE']
)
end
def change_folder(folder)
update_attributes(:folder_id => folder.id)
end
end

View file

@ -17,8 +17,12 @@ msgs_inbox_view_fields: [from_addr, subject, date, size]
msgs_sent_view_fields: [to_addr, subject, date, size]
msg_subject_length: 45
msg_address_length: 35
msg_search_fields: [subject, from, to]
# if encoding can not be get from data
msg_unknown_encoding: ISO-8859-2
imap_debug: false
imap_use_ssl: 'false'
imap_port: 143
@ -35,4 +39,5 @@ mailbox_trash: INBOX.Trash
mailbox_sent: INBOX.sent
mailbox_drafts: INBOX.drafts
# array of logins which only can login to application, comment it to allow everyone to login
only_can_logins: [wtodryk]

View file

@ -1,6 +1,6 @@
class CreateMessages < ActiveRecord::Migration
def self.up
create_table :messages do |t|
create_table :messages ,:id => false do |t|
t.integer :folder_id
t.integer :user_id
t.string :msg_id

View file

@ -37,7 +37,7 @@ ActiveRecord::Schema.define(:version => 20110816120258) do
t.string "alter_name"
end
create_table "messages", :force => true do |t|
create_table "messages", :id => false, :force => true do |t|
t.integer "folder_id"
t.integer "user_id"
t.string "msg_id"

View file

@ -46,40 +46,41 @@ end
class IMAPMessage
@@fetch_attr = ['ENVELOPE','BODYSTRUCTURE', 'FLAGS', 'UID', 'RFC822.SIZE']
#@@fetch_attr = ['RFC822','FLAGS', 'UID', 'RFC822.SIZE']
attr_accessor :envelope,:uid,:content_type,:size,:unseen,:from,:message_id,:to,:from,:subject,:date
def initialize
end
def self.fromImap(message)
m = IMAPMessage.new
envelope = message.attr['ENVELOPE']
m.envelope = envelope
m.message_id = envelope.message_id
m.date = envelope.date
m.subject = envelope.subject
m.uid = message.attr['UID']
#content_type = m.attr['BODYSTRUCTURE'].multipart? ? 'multipart' : 'text'
m.content_type = message.attr['BODYSTRUCTURE'].media_type.downcase
m.size = message.attr['RFC822.SIZE']
m.unseen = !(message.attr['FLAGS'].member? :Seen)
m.from = IMAPAddress.from_address(envelope.from[0])
m.to = IMAPAddress.from_address(envelope.to[0])
m
end
# attr_accessor :envelope,:uid,:content_type,:size,:unseen,:from,:message_id,:to,:from,:subject,:date
#
# def initialize
# end
#
# def self.fromImap(message)
# m = IMAPMessage.new
# envelope = message.attr['ENVELOPE']
# m.envelope = envelope
# m.message_id = envelope.message_id
# m.date = envelope.date
# m.subject = envelope.subject
# m.uid = message.attr['UID']
# #content_type = m.attr['BODYSTRUCTURE'].multipart? ? 'multipart' : 'text'
# m.content_type = message.attr['BODYSTRUCTURE'].media_type.downcase
# m.size = message.attr['RFC822.SIZE']
# m.unseen = !(message.attr['FLAGS'].member? :Seen)
# m.from = IMAPAddress.from_address(envelope.from[0])
# m.to = IMAPAddress.from_address(envelope.to[0])
# m
# end
#
def self.fetch_attr
@@fetch_attr
end
def from_to_db
from.to_db
end
def to_to_db
to.to_db
end
#
# def from_to_db
# from.to_db
# end
#
# def to_to_db
# to.to_db
# end
end

View file

@ -499,6 +499,11 @@ div.render_text pre {
padding: 5px;
border: 1px solid #5E634E;
margin: 10px 0 0 0;
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
span.attachment {
@ -512,4 +517,3 @@ span.attachment pre {
span.attachment span.title {
font-weight: bold;
}

View file

@ -1,6 +1,6 @@
<div class="msg_header">
<%= raw mail_param_view(@message,"from_addr",show_address_formatter(@message.from_addr)) %>
<%= raw mail_param_view(@message,"to_addr",show_address_formatter(@message.to_addr)) %>
<%= raw mail_param_view(@message,"from_addr",address_formatter(@message.from_addr,:message)) %>
<%= raw mail_param_view(@message,"to_addr",address_formatter(@message.to_addr,:message)) %>
<%= raw mail_param_view(@message,"subject",@message.subject) %>
<%= raw mail_param_view(@message,"date",date_formatter(@message.date)) %>
<%= hidden_field_tag 'uids[]', @message.uid %>

View file

@ -1,6 +1,12 @@
<td><%= check_box_tag "uids[]", row.uid %></td>
<td><%= attachment_formatter(row) %></td>
<td nowrap="nowrap"><%= address_formatter(row.from_addr) %></td>
<% if @current_folder.hasFullName?($defaults["mailbox_sent"]) %>
<td nowrap="nowrap"><%= address_formatter(row.to_addr,:index) %></td>
<% else %>
<td nowrap="nowrap"><%= address_formatter(row.from_addr,:index) %></td>
<% end %>
<td nowrap="nowrap"><%= subject_formatter(row) %></td>
<td nowrap="nowrap"><%= date_formatter(row.date) %></td>
</td><td nowrap="nowrap"><%= size_formatter(row.size) %></td><td><%= raw('&nbsp;') %>

View file

@ -30,9 +30,7 @@
</p>
<% else %>
<% @render_as_text.each do |r| %>
<pre>
<%= raw content_text_plain_for_render(r) %>
</pre>
<% end %>
<% end %>
</div>