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

View file

@ -13,10 +13,14 @@ class UserController < ApplicationController
end end
def authenticate def authenticate
if !$defaults["only_can_logins"].include?(params[:user][:email])
redirect_to :controller => 'internal', :action => 'onlycanlogins' if not $defaults["only_can_logins"].nil?
return false if not $defaults["only_can_logins"].include?(params[:user][:email])
redirect_to :controller => 'internal', :action => 'onlycanlogins'
return false
end
end end
user = User.find_by_email(params[:user][:email]) user = User.find_by_email(params[:user][:email])
if user.nil? if user.nil?
redirect_to :action => 'unknown' ,:email=> params[:user][:email] 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") date.nil? ? t(:no_data) : date.strftime("%Y-%m-%d %H:%M")
end end
def address_formatter(addr) # def address_formatter(addr)
ImapMessageModule::IMAPAddress.parse(addr).friendly # ImapMessageModule::IMAPAddress.parse(addr).friendly
end # 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
return h(s)
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
end end
def subject_formatter(message) def subject_formatter(message)
@ -32,7 +41,7 @@ module MessagesHelper
length = $defaults["msg_subject_length"].to_i length = $defaults["msg_subject_length"].to_i
message.subject.length >= length ? s = message.subject[0,length]+"..." : s = message.subject message.subject.length >= length ? s = message.subject[0,length]+"..." : s = message.subject
end 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 end
def attachment_formatter(message) def attachment_formatter(message)
@ -61,8 +70,9 @@ module MessagesHelper
end end
def content_text_plain_for_render(text) def content_text_plain_for_render(text)
html = h(text) html = "<pre>"
html.gsub!(/\r\n/,"<br/>") html << h(text)
html << "</pre>"
html html
end end

View file

@ -3,20 +3,51 @@ class Attachment
include ActiveModel::Conversion include ActiveModel::Conversion
extend ActiveModel::Naming 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 attr_reader :link
def initialize(attributes = {}) def initialize(attributes = {})
attributes.each do |name, value| attributes.each do |name, value|
send("#{name}=", value) send("#{name}=", value)
end end
if @type =~ /name=(\S+)/ if not @type.nil?
@name = $1 params = @type.split(/;\s*/)
@type =~ /^(\S+);/ @type = params[0]
@type = $1 params.each do |p|
else if p =~ /=/
@name = "no_name.dat" 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
attachments << a
end
idx += 1
end end
end end
@ -24,6 +55,25 @@ class Attachment
false false
end 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 def to_s
s = "Attachment:\n" s = "Attachment:\n"
instance_variables.sort.each do |name| instance_variables.sort.each do |name|
@ -36,8 +86,12 @@ class Attachment
s s
end end
def isText?
@type.nil? or @type =~ /^text\/plain/
end
def title def title
@description.nil? ? @name : @description @description.nil? ? name : @description
end end
def type def type
@ -52,6 +106,51 @@ class Attachment
@encoding.nil? ? '' : @encoding @encoding.nil? ? '' : @encoding
end 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 # def to_html
# html = "<span class=\"attachment\">" # html = "<span class=\"attachment\">"
# html << "<span class=\"title\">" # html << "<span class=\"title\">"
@ -81,9 +180,4 @@ class Attachment
# html # html
# end # end
def content_decoded
# TODO attachments decoding
@content
end
end

View file

@ -1,8 +1,47 @@
require 'iconv'
class Message < ActiveRecord::Base class Message < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :folder 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) 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 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 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( create(
:user_id => user.id, :user_id => user.id,
:folder_id => folder.id, :folder_id => folder.id,
:msg_id => mess.message_id, :msg_id => envelope.message_id,
:uid => mess.uid, :uid => imap_message.attr['UID'].to_i,
:from_addr => mess.from_to_db, :from_addr => from,
:to_addr => mess.to_to_db, :to_addr => to,
:subject => mess.subject, :subject => subject,
:content_type => mess.content_type, :content_type => imap_message.attr['BODYSTRUCTURE'].media_type.downcase,
:date => mess.date, :date => envelope.date,
:unseen => mess.unseen, :unseen => !(imap_message.attr['FLAGS'].member? :Seen),
:size => mess.size) :size => imap_message.attr['RFC822.SIZE']
end )
end
def change_folder(folder) def change_folder(folder)
update_attributes(:folder_id => folder.id) update_attributes(:folder_id => folder.id)
end end
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] msgs_sent_view_fields: [to_addr, subject, date, size]
msg_subject_length: 45 msg_subject_length: 45
msg_address_length: 35
msg_search_fields: [subject, from, to] msg_search_fields: [subject, from, to]
# if encoding can not be get from data
msg_unknown_encoding: ISO-8859-2
imap_debug: false imap_debug: false
imap_use_ssl: 'false' imap_use_ssl: 'false'
imap_port: 143 imap_port: 143
@ -35,4 +39,5 @@ mailbox_trash: INBOX.Trash
mailbox_sent: INBOX.sent mailbox_sent: INBOX.sent
mailbox_drafts: INBOX.drafts mailbox_drafts: INBOX.drafts
# array of logins which only can login to application, comment it to allow everyone to login
only_can_logins: [wtodryk] only_can_logins: [wtodryk]

View file

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

View file

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

View file

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

View file

@ -499,6 +499,11 @@ div.render_text pre {
padding: 5px; padding: 5px;
border: 1px solid #5E634E; border: 1px solid #5E634E;
margin: 10px 0 0 0; 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 { span.attachment {
@ -512,4 +517,3 @@ span.attachment pre {
span.attachment span.title { span.attachment span.title {
font-weight: bold; font-weight: bold;
} }

View file

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

View file

@ -1,6 +1,12 @@
<td><%= check_box_tag "uids[]", row.uid %></td> <td><%= check_box_tag "uids[]", row.uid %></td>
<td><%= attachment_formatter(row) %></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"><%= subject_formatter(row) %></td>
<td nowrap="nowrap"><%= date_formatter(row.date) %></td> <td nowrap="nowrap"><%= date_formatter(row.date) %></td>
</td><td nowrap="nowrap"><%= size_formatter(row.size) %></td><td><%= raw('&nbsp;') %> </td><td nowrap="nowrap"><%= size_formatter(row.size) %></td><td><%= raw('&nbsp;') %>

View file

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