diff --git a/Gemfile b/Gemfile index 88cbc74..ee025a2 100755 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,10 @@ gem 'rails', '3.0.7' #gem 'sqlite3-ruby',:require => 'sqlite3' gem 'arel' gem 'mysql2' , '0.2.7' -gem 'will_paginate' +gem 'will_paginate', '~> 3.0.beta' gem 'themes_for_rails' gem "ezcrypto", "~> 0.7.2" +gem "mail" #gem 'tmail' # Use unicorn as the web server diff --git a/Gemfile.lock b/Gemfile.lock index 5277b9e..a2a269d 100755 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,7 +66,7 @@ GEM treetop (1.4.9) polyglot (>= 0.3.1) tzinfo (0.3.29) - will_paginate (2.3.15) + will_paginate (3.0.pre4) PLATFORMS ruby @@ -74,7 +74,8 @@ PLATFORMS DEPENDENCIES arel ezcrypto (~> 0.7.2) + mail mysql2 (= 0.2.7) rails (= 3.0.7) themes_for_rails - will_paginate + will_paginate (~> 3.0.beta) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4b2899b..d3f7679 100755 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,9 +2,16 @@ require 'yaml' class ApplicationController < ActionController::Base + #unless config.consider_all_requests_local + # #rescue_from ActionController::RoutingError, :with => :route_not_found + # rescue_from ActiveRecord::RecordNotFound, :with => :route_not_found + #end + protect_from_forgery before_filter :load_defaults,:set_locale,:current_user + ################################# protected section ########################################### + protected def load_defaults @@ -48,4 +55,12 @@ class ApplicationController < ActionController::Base @current_folder = @current_user.folders.current(@selected_folder) end + ##################################### private section ########################################## + + #private + + #def route_not_found + # render :text => 'What the fuck are you looking for ?', :status => :not_found + #end + end diff --git a/app/controllers/folders_controller.rb b/app/controllers/folders_controller.rb index a78fb94..20a18d1 100755 --- a/app/controllers/folders_controller.rb +++ b/app/controllers/folders_controller.rb @@ -81,9 +81,10 @@ class FoldersController < ApplicationController def refresh Folder.refresh(@mailbox,@current_user) - if params[:flash] - flash[params[:type]] = params[:flash] - end + flash.keep + #if params[:flash] + # flash[params[:type]] = params[:flash] + #end redirect_to :action => 'index' end diff --git a/app/controllers/internal_controller.rb b/app/controllers/internal_controller.rb index 25d4bdd..bb3c559 100755 --- a/app/controllers/internal_controller.rb +++ b/app/controllers/internal_controller.rb @@ -4,9 +4,7 @@ class InternalController < ApplicationController layout "simple" def error - @title = params[:title] || t(:general_error) - @error = params[:error] || t(:unspecified_error) - logger.error "!!! InternalControllerError: " + @error + end def imaperror @@ -16,6 +14,13 @@ class InternalController < ApplicationController render 'error' end + def page_not_found + @title = t(:page_not_found) + @error = t(:page_not_found) + logger.error "!!! InternalControllerError: " + @error + render 'error' + end + def loginfailure reset_session flash[:error] = t(:login_failure) diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 5035202..9703948 100755 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -1,22 +1,85 @@ require 'imap_session' require 'imap_mailbox' +require 'imap_message' class MessagesController < ApplicationController include ImapMailboxModule include ImapSessionModule + include ImapMessageModule + include MessagesHelper before_filter :check_current_user ,:selected_folder - before_filter :get_current_folders, :only => [:index,:compose] + before_filter :get_current_folders, :only => [:index,:compose,:show] before_filter :open_imap_session, :only => :refresh after_filter :close_imap_session, :only => :refresh theme :theme_resolver + @@fetch_attr = ['ENVELOPE','BODYSTRUCTURE', 'FLAGS', 'UID', 'RFC822.SIZE'] + def index - flash[:notice] = 'Not implemented yet' + + open_imap_session + #################### + @messages = [] + + folder_status = @mailbox.status(@current_folder.full_name) + @current_folder.update_attributes(:messages => folder_status['MESSAGES'], :unseen => folder_status['UNSEEN']) + + if folder_status['MESSAGES'].zero? + return + end + + messages = @mailbox.fetch(@current_folder.full_name,1..-1, "UID") + logger.custom('mess',messages) + uids_to_be_fetched = [] + + messages.each do |m| + uids_to_be_fetched << m.attr['UID'] + end + + messages = [] + @current_user.messages.destroy_all + uids_to_be_fetched.each_slice($defaults["imap_fetch_slice"].to_i) do |slice| + logger.custom('slice',slice.join(",")) + messages = @mailbox.uid_fetch(@current_folder.full_name,slice, @@fetch_attr) + + + + messages.each do |m| + + envelope = m.attr['ENVELOPE'] + uid = m.attr['UID'] + #content_type = m.attr['BODYSTRUCTURE'].multipart? ? 'multipart' : 'text' + content_type = m.attr['BODYSTRUCTURE'].media_type.downcase + size = m.attr['RFC822.SIZE'] + unread = !(m.attr['FLAGS'].member? :Seen) + from = ImapMessageModule::IMAPAddress.from_address(envelope.from[0]) + logger.custom('from',from.to_db) + logger.custom('enevelope_from',envelope) + logger.custom('body',m.attr['BODYSTRUCTURE']) + message = @current_user.messages.create(:folder_id => @current_folder.id, + :msg_id => envelope.message_id, + :uid => uid, + :from => from.to_db, + :to => envelope.to, + :subject => envelope.subject, + :content_type => content_type, + :date => envelope.date, + :unread => unread, + :size => size) + + end + + end + + @messages = Message.getPageForUser(@current_user,params['page']) + + ############### + close_imap_session end def folder @@ -29,7 +92,20 @@ class MessagesController < ApplicationController end def refresh - redirect_to :action => 'index' + redirect_to :action => 'index' end + def ops + redirect_to :action => 'index' + end + + def show + @message = Message.find(params[:id]) + flash[:notice] = 'Not impelented yet' + open_imap_session + @body = @mailbox.fetch_body(@current_folder.full_name,@message.uid) + logger.custom('body',@body.inspect) + close_imap_session + end + end diff --git a/app/controllers/prefs_controller.rb b/app/controllers/prefs_controller.rb index 66af42d..813be02 100755 --- a/app/controllers/prefs_controller.rb +++ b/app/controllers/prefs_controller.rb @@ -8,6 +8,8 @@ class PrefsController < ApplicationController def index flash[:notice] = 'Not implemented yet' + + @prefs = @current_user.prefs end end diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb index 5db34d2..f878a99 100755 --- a/app/helpers/messages_helper.rb +++ b/app/helpers/messages_helper.rb @@ -1,4 +1,33 @@ module MessagesHelper + def size_formatter(size) + if size <= 2**10 + "#{size} #{t(:bytes)}" + elsif size <= 2**20 + sprintf("%.1f #{t(:kbytes)}",size.to_f/2**10) + else + sprintf("%.1f #{t(:mbytes)}",size.to_f/2**20) + end + end + + def date_formatter(date) + date.strftime("%Y-%m-%d %H:%M") + end + + def address_formatter(addr) + ImapMessageModule::IMAPAddress.parse(addr).friendly + end + + def subject_formatter(message) + length = $defaults["msg_subject_length"].to_i + logger.custom('l',length) + message.subject.length >= length ? s = message.subject[0,length]+"..." : s = message.subject + link_to s,:controller => 'messages', :action => 'show', :id => message.id + end + + def attachment_formatter(message) + message.content_type == 'text' ? "" : "A" + end + end diff --git a/app/models/message.rb b/app/models/message.rb index 590e3e3..eb79905 100755 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -1,2 +1,13 @@ class Message < ActiveRecord::Base + belongs_to :user + + #cattr_reader :per_page + #@@per_page = $defaults["msgs_per_page"] + + def self.getPageForUser(user,page,order = "date desc") + #Message.paginate :page => page , :per_page => user.prefs.msgs_per_page.to_i, :conditions=> ['user_id = ?', user.id],:order => order + + Message.paginate :page => page , :per_page => 50, :conditions=> ['user_id = ?', user.id],:order => order + end + end diff --git a/app/models/user.rb b/app/models/user.rb index 220cddb..cd63207 100755 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,6 +7,7 @@ class User < ActiveRecord::Base has_many :servers, :dependent => :destroy has_one :prefs, :dependent => :destroy has_many :folders, :dependent => :destroy + has_many :messages, :dependent => :destroy def set_cached_password(session,password) if $defaults['session_encryption'] diff --git a/config/application.rb b/config/application.rb index 2f9048c..4b75793 100755 --- a/config/application.rb +++ b/config/application.rb @@ -40,3 +40,12 @@ module Mailr config.filter_parameters += [:password] end end + +class ActiveSupport::BufferedLogger + def custom(desc,t) + info "\n**** #{desc} *****" + info t + info "**********************\n\n" + end +end + diff --git a/config/defaults.yml b/config/defaults.yml index 84bc8d4..d3da44e 100755 --- a/config/defaults.yml +++ b/config/defaults.yml @@ -3,13 +3,17 @@ locale: en msgs_per_page: 20 msgs_refresh_time: 300 -msg_send_type: html +msgs_send_type: html +msgs_update_time: 300 + +msg_subject_length: 45 imap_debug: true imap_use_ssl: 'false' imap_port: 143 imap_ssl_port: 993 imap_bye_timeout_retry_seconds: 2 +imap_fetch_slice: 20 session_encryption: true session_password: asDD3s2@sAdc983# diff --git a/config/environment.rb b/config/environment.rb index 0d0a345..9fde94f 100755 --- a/config/environment.rb +++ b/config/environment.rb @@ -3,3 +3,4 @@ require File.expand_path('../application', __FILE__) # Initialize the rails application Mailr::Application.initialize! + diff --git a/config/environments/development.rb b/config/environments/development.rb index d598c9d..5e43cf8 100755 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -10,7 +10,7 @@ Mailr::Application.configure do config.whiny_nils = true # Show full error reports and disable caching - config.consider_all_requests_local = true + config.consider_all_requests_local = false config.action_view.debug_rjs = true config.action_controller.perform_caching = false diff --git a/config/locales/en.yml b/config/locales/en.yml index a67f647..de8b24d 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -94,3 +94,9 @@ en: system_folder: System folder refresh_folders: Refresh folders show_hide: Show/Hide + page_not_found: Page not found + bytes: Bytes + kbytes: Kb + mbytes: MB + previous_page: Previous page + next_page: Next page diff --git a/config/routes.rb b/config/routes.rb index bf93097..1965c0e 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,7 +21,8 @@ Mailr::Application.routes.draw do match 'messages/folder/:id' => 'messages#folder' post "messages/ops" get "messages/compose" - get"messages/refresh" + get "messages/refresh" + match "messages/show/:id" => 'messages#show' get "user/logout" post "user/authenticate" @@ -33,6 +34,8 @@ Mailr::Application.routes.draw do themes_for_rails + match '*a', :to => 'internal#page_not_found' + # The priority is based upon order of creation: # first created -> highest priority. diff --git a/db/migrate/20110731185416_add_shown_to_folders.rb b/db/migrate/20110731185416_add_shown_to_folders.rb old mode 100644 new mode 100755 diff --git a/lib/imap_mailbox.rb b/lib/imap_mailbox.rb index ce7840c..dc23106 100755 --- a/lib/imap_mailbox.rb +++ b/lib/imap_mailbox.rb @@ -30,7 +30,7 @@ class IMAPMailbox @imap = Net::IMAP.new(server_name, server_port, server_use_ssl) rescue Net::IMAP::ByeResponseError => bye begin - System.sleep($defaults['imap_bye_timeout_retry_seconds']) + System.sleep($defaults["imap_bye_timeout_retry_seconds"]) @imap = Net::IMAP.new(server_name, server_port, server_use_ssl) rescue Exception => ex raise IMAPError, ex.inspect @@ -87,6 +87,40 @@ class IMAPMailbox raise e end end + + def fetch(folder_name,range,attribs) + begin + set_folder(folder_name) + @imap.fetch(range,attribs) + rescue Exception => e + raise e + end + end + + def uid_fetch(folder_name,range,attribs) + begin + set_folder(folder_name) + @imap.uid_fetch(range,attribs) + rescue Exception => e + raise e + end + end + + def set_folder(folder_name) + if folder_name.downcase != @selected_folder.downcase + @imap.select(folder_name) + @selected_folder = folder_name + end + end + + def status(folder_name) + @imap.status(folder_name, ["MESSAGES", "RECENT", "UNSEEN"]) + end + + def fetch_body(folder_name,uid) + uid_fetch(folder_name,uid,"BODY[]").first.attr["BODY[]"] + end + end end diff --git a/lib/imap_message.rb b/lib/imap_message.rb index 69cb45b..f62e137 100755 --- a/lib/imap_message.rb +++ b/lib/imap_message.rb @@ -1,5 +1,47 @@ require 'net/imap' module ImapMessageModule + +class IMAPAddress + + attr_accessor :name,:mailbox,:host + + def initialize() + name = "" + mailbox = "" + host = "" + end + + def self.from_address(addr) + a = IMAPAddress.new() + a.name = addr.name || "" + a.mailbox = addr.mailbox || "" + a.host = addr.host || "" + a + end + + def to_db + name + "#" + mailbox + "#" + host + end + + def self.parse(addr) + a = IMAPAddress.new() + f = addr.split("#") + a.name = f[0] + a.mailbox = f[1] + a.host = f[2] + a + end + + def friendly + if name.empty? + mailbox + host + else + name + end + end + +end + end diff --git a/lib/tasks/clear_db.rake b/lib/tasks/clear_db.rake old mode 100644 new mode 100755 index a77ada2..35407fc --- a/lib/tasks/clear_db.rake +++ b/lib/tasks/clear_db.rake @@ -1,5 +1,5 @@ namespace :db do - desc "Clears all date in db" + desc "Clears all data in db" task :clear_data => :environment do users = User.all puts "Number of users in db: #{users.size}" diff --git a/themes/olive/stylesheets/base.css b/themes/olive/stylesheets/base.css index 46a9482..d0a0439 100755 --- a/themes/olive/stylesheets/base.css +++ b/themes/olive/stylesheets/base.css @@ -218,7 +218,8 @@ body { } .table td { - padding: 5px; + padding: 2px 10px; + color: #5E634E; } .table td.last { diff --git a/themes/olive/stylesheets/style.css b/themes/olive/stylesheets/style.css index 184543c..6d8229d 100755 --- a/themes/olive/stylesheets/style.css +++ b/themes/olive/stylesheets/style.css @@ -365,3 +365,6 @@ input,select { color: grey; } +tr.unread td { + font-weight:bold; +} diff --git a/themes/olive/views/messages/_list.html.erb b/themes/olive/views/messages/_list.html.erb new file mode 100755 index 0000000..4c09fab --- /dev/null +++ b/themes/olive/views/messages/_list.html.erb @@ -0,0 +1,38 @@ +
+ +<% WillPaginate::ViewHelpers.pagination_options[:previous_label] = t(:previous_page) %> +<% WillPaginate::ViewHelpers.pagination_options[:next_label] = t(:next_page) %> + +
+ <%= will_paginate @messages %> +
+ +
+ + + + + + + + + + + + <% trclass = :even %> + <% @messages.each do |m| %> + <% m.unread == true ? unread = "unread" : unread = "" %> + + <%= render :partial => 'messages/row', :object => m %> + + <% trclass == :even ? trclass = :odd : trclass = :even %> + <% end %> + +
<%= raw(' ') %><%= t(:from) %><%= t(:subject) %><%= t(:date) %><%= t(:size) %>
+
+ +
+ <%= will_paginate @messages %> +
+ +
diff --git a/themes/olive/views/messages/_ops.html.erb b/themes/olive/views/messages/_ops.html.erb new file mode 100755 index 0000000..3293480 --- /dev/null +++ b/themes/olive/views/messages/_ops.html.erb @@ -0,0 +1,15 @@ +
+

+ <%= submit_tag(t(:copy), :name=> 'op')%> + <%= submit_tag(t(:move), :name=>'op')%> + <%= t :marked_messages %> + <%= t :to_folder %> + <%= raw select_for_folders("","parent_folder",@folders_shown,t(:parent_folder),true) %> +

+

+ <%= t :marked_messages %> + <%= submit_tag(t(:delete), :name=>'op')%> + <%= submit_tag(t(:mark_read), :name=>'op')%> + <%= submit_tag(t(:mark_unread), :name=>'op')%> +

+
diff --git a/themes/olive/views/messages/_row.html.erb b/themes/olive/views/messages/_row.html.erb new file mode 100755 index 0000000..8861d12 --- /dev/null +++ b/themes/olive/views/messages/_row.html.erb @@ -0,0 +1,6 @@ +<%= check_box_tag "uids[]", row.uid %> +<%= attachment_formatter(row) %> +<%= address_formatter(row.from) %> +<%= subject_formatter(row) %> +<%= date_formatter(row.date) %> +<%= size_formatter(row.size) %><%= raw(' ') %> diff --git a/themes/olive/views/messages/_search.html.erb b/themes/olive/views/messages/_search.html.erb new file mode 100755 index 0000000..bcbd6f4 --- /dev/null +++ b/themes/olive/views/messages/_search.html.erb @@ -0,0 +1,7 @@ +

+ <%= t :message_field %> + <%= submit_tag(t(:search), :name=>'op')%> <%= submit_tag(t(:show_all), :name=>'op')%> +

diff --git a/themes/olive/views/messages/index.html.erb b/themes/olive/views/messages/index.html.erb index d9087b6..f5a296a 100755 --- a/themes/olive/views/messages/index.html.erb +++ b/themes/olive/views/messages/index.html.erb @@ -13,21 +13,24 @@
<%= form_tag({:controller=>'messages', :action=>'ops'})%> + <% #render :partial => 'search' %> + <%= render :partial => 'ops' %> + + <%= raw form_button(t(:ops),'tick.png') %> + + <% if @current_folder.nil? %> +

<%= t(:no_folder_selected) %>

+ <% else %> +

<%= t(:current) %>: <%= pretty_folder_name(@current_folder) %>

+ <% end %> + + <% if @messages.size.zero? %> + <%= t(:no_messages) %> + <% else %> + <%= render :partial => 'list' %> + <% end %> + - - -<% if @current_folder.nil? %> -<%= t(:no_folder_selected) %> -<% else %> - -

Current: <%= pretty_folder_name(@current_folder) %>

- -<%= @current_folder.inspect %> -<%= Time.now - @current_folder.msgs_updated_at %> - -<% end %> - -
diff --git a/themes/olive/views/messages/show.html.erb b/themes/olive/views/messages/show.html.erb new file mode 100755 index 0000000..6d16d0d --- /dev/null +++ b/themes/olive/views/messages/show.html.erb @@ -0,0 +1,19 @@ +<% content_for :sidebar do %> +<%= render :partial => 'folders/list' %> +<% end %> + +<% content_for :title do %> +- <%= @message.subject %> +<% end %> + +
+
+ <%= raw main_navigation(:show) %> +
+
+

<%= @message.inspect %>

+

<%= @body.inspect %>

+
+
+ + diff --git a/themes/olive/views/prefs/index.html.erb b/themes/olive/views/prefs/index.html.erb index de2d8dc..ce76fec 100755 --- a/themes/olive/views/prefs/index.html.erb +++ b/themes/olive/views/prefs/index.html.erb @@ -13,6 +13,8 @@
<%= form_tag({:controller=>'messages', :action=>'ops'})%> - + + <%= @prefs.inspect %> +