Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- STDOUT.sync = true
- module Enumerable
- def none?
- if block_given?
- not self.any? { |e| yield e }
- else
- not self.any?
- end
- end
- end
- module Og
- module EntityMixin
- class_extension do
- def find_or_create_with params
- unless obj = self.query_by_example(params).first
- obj = self.create_with(params)
- end
- return obj
- end
- end
- end
- end
- class Object
- def to_numeric
- Integer(self) rescue Float(self) rescue self
- end
- def numeric?
- to_numeric == self
- end
- end
- class Contact
- property :name, String
- property :address, String
- belongs_to ContactBook
- belongs_to User
- end
- class ContactBook
- include Og::EntityMixin
- property :name, String
- belongs_to User
- has_many Contact
- end
- class User
- property :name, String
- property :email, String
- property :login, String
- property :password, String
- has_many ContactBook
- has_many Contact
- def password
- @password
- end
- def password=(pwd)
- @password = self.class.encode_password pwd
- end
- def self.encode_password pwd
- Digest::SHA1.hexdigest(pwd)
- end
- end
- class Numeric
- def even?
- self % 2 == 0
- end
- def odd?
- !even?
- end
- end
- class Array
- def to_hash
- Hash[*(self.map{|k,v| [k,v]}.flatten)]
- end
- end
- module NIMAP
- class Envelope
- def initialize uid
- #TODO: make sure that the @@cache works over different sessions
- @@cache ||= {}
- envelope uid.to_i
- end
- def envelope uid = (@envelope.uid rescue nil)
- if uid
- unless @envelope || @envelope = @@cache[uid]
- @envelope = OpenStruct.new
- Server.fetch_envelope(uid).each_pair do |key, val|
- if val.respond_to? :to_ary
- node = OpenStruct.new
- val.first.each_pair do |nkey, nval|
- node.send("#{nkey}=", (nval ? Kconv.toutf8(nval.to_s) : nil))
- end
- @envelope.send("#{key}=", node)
- else
- @envelope.send("#{key}=", (val ? Kconv.toutf8(val.to_s) : nil))
- end
- end
- @envelope.from.address = "#{@envelope.from.mailbox}@#{@envelope.from.host}".downcase
- @envelope.date = Time.parse(@envelope.date)
- @envelope.uid = uid
- return false if @@cache.include?(@envelope)
- @@cache[uid] = @envelope
- Thread.new do
- fetch_parts
- end
- end
- return @envelope
- end
- end
- def uid; envelope.uid end
- def subject; envelope.subject end
- def date; envelope.date end
- def from; envelope.from end
- def to; envelope.to end
- def body
- Server.fetch(uid, "BODY")
- end
- def ==(other)
- return false unless other.is_a?(self.class)
- # note that little ! here
- result = [
- :subject, :date, :from, :to
- ].all?{ |e|
- other.send(e) == self.send(e)
- }
- result
- end
- def fetch_parts
- starter = ['TEXT', 0]
- content = true
- while content
- current = starter.shift
- content = body_part(current)
- p content
- starter << current.succ
- end
- end
- def body_part part = 'TEXT'
- body = (envelope.body ||= {})
- begin
- envelope.body[part] ||= Server.fetch(uid, "BODY[#{part}]")
- rescue Net::IMAP::NoResponseError
- return false
- end
- end
- def text
- text = body_part 1
- text = body_part if text.empty?
- text = body_part 2 if text.empty?
- #text = NKF.nkf("-s", Net::IMAP.decode_utf7(text.to_s))
- text = Kconv.toutf8(text)
- {
- "=20\r\n" => "\n"
- }.each do |pattern, replacement|
- text.gsub!(pattern, replacement)
- end
- ["\r\n", "\n\r", "\n", "<br /><br />"].each{|n| text.gsub!(n, "<br />")}
- uris = URI.extract(text)
- uris = uris.map{|u| URI.parse(u).to_s rescue nil}.compact.uniq
- uris.each{|u| text.gsub!(u, %{<a href="#{u}">#{u}</a>}) }
- return text
- end
- def multipart_extract struct
- extracted = []
- if struct.respond_to? :parts
- extracted << struct.parts.map{|part| multipart_extract(part)}
- else
- if struct
- extracted << "#{struct.media_type}/#{struct.subtype}"
- end
- end
- extracted
- end
- def self.[] uid
- self.new uid
- end
- def self.create_with mail
- pp mail
- end
- def self.cache_flush
- @@cache ||= {}
- print("Cache size before: #{@@cache.size}")
- @@cache.clear
- puts(", and after #{@@cache.size}")
- end
- end
- class Server
- class << self
- def method_missing meth, *args, &block
- server = Nitro::Session.current[:server]
- server.send(meth, *args, &block)
- end
- end
- def method_missing meth, *args, &block
- p [:method_missing, meth, args]
- connect unless @imap
- imap :send, meth, *args, &block
- end
- def initialize host = 'localhost', user = nil, pass = nil
- raise "provide username and password" unless [user,pass].all?
- connect @host = host, @user = user, @pass = pass
- end
- def imap
- connect unless @imap
- @imap
- end
- def connect host = 'localhost', user = @user, pass = @pass
- @imap = Net::IMAP.new(host)
- imap :authenticate, 'LOGIN', user, pass
- @imap
- end
- def disconnect
- return true if imap :disconnected?
- imap :disconnect
- end
- def reconnect
- disconnect
- connect
- end
- def check_mail
- p [:check_mail]
- examine @mailbox[:name], :force
- end
- # open mailbox read-only
- def examine mailbox, force = nil
- @mailbox ||= {}
- mailbox = mailbox.to_s.upcase
- if (@mailbox.values_at(:mode, :name) != [:read_only, mailbox]) || force
- imap :examine, mailbox
- Envelope.cache_flush
- @mailbox = {:mode => :read_only, :name => mailbox}
- end
- end
- # open mailbox read/write
- def select mailbox, force = nil
- @mailbox ||= {}
- mailbox = mailbox.to_s.upcase
- if @mailbox.values_at(:mode, :name) != [:read_write, mailbox] || force
- imap :select, mailbox
- Envelope.cache_flush
- @mailbox = {:mode => :read_write, :name => mailbox}
- end
- end
- def status mailbox = @mailbox[:name]
- imap(:status, mailbox, %w(MESSAGES RECENT UNSEEN)).map{|k,v| [k.downcase.to_sym, v]}.to_hash
- end
- def delete uid
- imap :select, @mailbox[:name]
- imap :store, uid, " FLAGS", [:Deleted]
- imap :expunge
- examine(@mailbox[:name], :force)
- imap :examine, @mailbox[:name]
- end
- def mailbox mailbox = 'inbox', query = 'all', start = 0, size = 30
- start, size = start.to_i, size.to_i
- mails = []
- examine mailbox rescue reconnect
- #debugger
- begin
- time = Time.now
- results = sort(query) rescue []
- mails = []
- results.reverse.each do |result|
- mail = Envelope.new(result)
- mails << mail unless mails.include?(mail)
- if mails.size >= size
- puts "finished fetching #{mails.size}/#{size} mails after #{Time.now - time} seconds"
- return mails.sort_by{|m| m.date}.reverse
- end
- end
- rescue
- return mails
- end
- end
- def fetch uid, opt
- s = imap :uid_fetch, uid, opt.to_s.upcase
- s.first.attr[opt.to_s]
- end
- def fetch_envelopes *uids
- threads = imap :uid_thread, 'REFERENCES', 'ALL', 'UTF-8'
- pp threads.map do |t|
- Evelope.new t.seqno
- end
- end
- def fetch_envelope uid
- fetch(uid, 'ENVELOPE')
- end
- # recent, all, new, not, or ...
- def search query = 'recent'
- imap :uid_search, param_transform(query)
- end
- def sort query = 'all', keys = 'date'
- keys, query = [keys, query].map{|e| param_transform(e)}
- imap :uid_sort, keys, query, 'UTF-8'
- end
- def param_transform *args
- # %w(foo bar) %w(FOO BAR) "foo bar" "FOO BAR" ["foo bar", "foobar"]
- [args].flatten.map{|s| s.split.map{|s| [s.upcase]}}.flatten
- end
- # just a proxy to @imap so nothing blows up
- # use that instead of @imap
- def imap meth, *args, &block
- p [:imap, meth, args, block]
- begin
- Timeout::timeout(10) do
- return @imap.send(meth, *args, &block)
- end
- rescue Object => ex
- if [IOError, ThreadError].include? ex.class and not failure
- reconnect
- failure = true
- retry
- else
- p :imap_error
- p ex.class
- puts ex
- pp ex.backtrace
- raise
- end
- end
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement