class EventMachine::EmailServer::POP3Server

Attributes

debug[RW]

Public Class Methods

new(hostname, userstore, emailstore) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 10
def initialize(hostname, userstore, emailstore)
  @hostname = hostname
  @userstore = userstore
  @emailstore = emailstore
  @state = 'auth' # 'trans' and 'data'
  @auth_attempts = 0
  @apop_challenge = "<#{rand(10**4 - 1)}.#{rand(10**9 - 1)}@#{@hostname}>"
  @debug = false
  @emails = Array.new
end

Public Instance Methods

apop(username, hash) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 282
def apop(username, hash)
        user(username)
        return false unless @user
        if Digest::MD5.new.update("#{@apop_challenge}#{@user.password}").hexdigest == hash
                return true
        end
        false
end
auth_state(line) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 60
def auth_state(line)
                  case line
                  when /^QUIT$/
                          send("+OK dewey POP3 server signing off", true)
  when /^CAPA$/
    send("+OK Capability list follows\r\n"+@@capabilities.join("\r\n")+"\r\n.")
                  when /^USER (.+)$/
                          user($1)
                          if @user
                                  send("+OK #{@user.username} is most welcome here")
                          else
                                  @failed += 1
                                  if @failed > 2
                                          send("-ERR you're out!", true)
      else
                                  send("-ERR sorry, no mailbox for #{$1} here")
                                  end
                          end
                  when /^PASS (.+)$/
                          if pass($1)
                                  @state = 'trans'
                                  emails
                                  msgs, bytes = stat
                                  send("+OK #{@user.username}'s maildrop has #{msgs} messages (#{bytes} octets)")
                          else
                                  @failed += 1
                                  if @failed > 2
                                          send("-ERR you're out!", true)
      else
        send("-ERR no dope.")
      end
                          end
                  when /^APOP ([^\s]+) (.+)$/
                          if apop($1,$2)
                                  @state = 'trans'
                                  emails
                                  send("+OK #{@user.username} is most welcome here")
                          else
                                  @failed += 1
                                  if @failed > 2
                                          send("-ERR you're out!", true)
      else
                                    send("-ERR sorry, no mailbox for #{$1} here")
      end
                          end
  else
    send("-ERR unknown command")
                  end
end
dele(msgid) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 264
def dele(msgid)
        msgid = msgid.to_i
        return false if msgid > @emails.length
        @emails[msgid-1].marked = true
end
emails() click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 230
def emails
@emails = @emailstore.emails_by_userid(@user.id)
end
list(msgid = nil) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 244
def list(msgid = nil)
        msgid = msgid.to_i if msgid
        if msgid
                return false if msgid > @emails.length or @emails[msgid-1].marked
                return [ [msgid, @emails[msgid].body.length] ]
        else
                msgs = []
                @emails.each_with_index do |e,i|
                        msgs << [ i + 1, e.body.length ]
                end
                msgs
        end
end
pass(password) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 224
def pass(password)
        return false unless @user
        return false unless @user.password == password
        true
end
post_init() click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 21
def post_init
  puts ">> +OK POP3 server ready #{@apop_challenge}" if @debug
  send_data("+OK POP3 server ready #{@apop_challenge}\r\n")
end
process_line(line) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 47
def process_line(line)
        case @state
        when 'auth'
  auth_state(line)
        when 'trans'
  trans_state(line)
        when 'update'
  update_state(line)
else
        send("-ERR unknown command")
        end
end
quit() click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 276
def quit
@emails.find_all {|e| e.marked}.each do |email|
  @emailstore.delete_email(email)
end
end
receive_data(data) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 26
                  def receive_data(data)
  puts ">> #{data}" if @debug
  data.split(/[\r\n]+/).each do |line|
    process_line(line)
  end
end
retr(msgid) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 258
def retr(msgid)
        msgid = msgid.to_i
        return false if msgid > @emails.length or @emails[msgid-1].marked == 'true'
        @emails[msgid-1].body
end
rset() click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 270
def rset
        @emails.each do |e|
                e.marked = false
        end
end
send(data, close=false) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 33
def send(data, close=false)
  puts "<< #{data}" if @debug
  send_data("#{data}\r\n")
  puts "++ closing connection" if @debug and close
  close_connection(true) if close
end
stat() click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 234
def stat
        msgs = bytes = 0
        @emails.each do |e|
                next if e.marked == 'true'
                msgs += 1
                bytes += e.body.length
        end
        [msgs, bytes]
end
trans_state(line) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 110
def trans_state(line)
                  case line
                  when /^NOOP$/
                          send("+OK")
                  when /^STAT$/
                          msgs, bytes = stat
                          send("+OK #{msgs} #{bytes}")
                  when /^LIST$/
                          msgs, bytes = stat
                          msg = "+OK #{msgs} messages (#{bytes} octets)\r\n"
                          list.each do |num, bytes|
                                  msg += "#{num} #{bytes}\r\n"
                          end
                          msg += "."
                          send(msg)
                  when /^LIST (\d+)$/
                          msgs, bytes = stat
                          num, bytes = list($1)
                          if num
                                  send("+OK #{num} #{bytes}")
                          else
                                  send("-ERR no such message, only #{msgs} messages in maildrop")
                          end
                  when /^RETR (\d+)$/
                          msg = retr($1)
                          if msg
                                  msg = "+OK #{msg.length} octets\r\n" + msg + "\r\n."
                          else
                                  msg = "-ERR no such message"
                          end
                          send(msg)
                  when /^DELE (\d+)$/
                          if dele($1)
                                  send("+OK message #{$1} marked")
                          else
                                  send("-ERR message #{$1} already marked")
                          end
                  when /^RSET$/
                          rset
                          msgs, bytes = stat
                          send("+OK maildrop has #{msgs} messages (#{bytes} octets)")
                  when /^QUIT$/
                          @state = 'update'
                          quit
                          msgs, bytes = stat
                          if msgs > 0
                                  send("+OK dewey POP3 server signing off (#{msgs} messages left)", true)
                          else
                                  send("+OK dewey POP3 server signing off (maildrop empty)", true)
                          end
                  when /^TOP (\d+) (\d+)$/
                          lines = $2
                          msg = retr($1)
                          unless msg
                                  send("-ERR no such message")
    else
                          cnt = nil
                          final = ""
                          msg.split(/\n/).each do |l|
                                  final += l+"\n"
                                  if cnt
                                          cnt += 1
                                          break if cnt > lines
                                  end
                                  if l !~ /\w/
                                          cnt = 0
                                  end
                          end
                          send("+OK\r\n"+final+"\r\n.")
    end
                  when /^UIDL$/
                          msgid = 0
                          msg = ''
                          @emails.each do |e|
                                  msgid += 1
                                  next if e.marked
                                  msg += "#{msgid} #{Digest::MD5.new.update(e.body).hexdigest}\r\n"
                          end
                          send("+OK\r\n#{msg}.")
  when /^UIDL (\d+)$/
    mid = $1
                          msgid = 0
    msg = ''
                          @emails.each do |e|
                                  msgid += 1
                                  next if e.marked
      if mid == msgid
        msg += "#{msgid} #{Digest::MD5.new.update(e.body).hexdigest}\r\n"
        last
      end
                          end
    if msg.length > 0
      send("+OK\r\n#{msg}.")
    else
      send("-ERR no such message, only #{msgid} messages in maildrop")
    end
  else
    send("-ERR unknown command")
                  end
end
unbind(reason=nil) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 40
def unbind(reason=nil)
  @emails.find_all {|e| e.marked}.each do |email|
    @emailstore.delete_email(email)
    puts "deleted #{email.id}" if @debug
  end
end
update_state(line) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 211
def update_state(line)
                  case line
                  when /^QUIT$/
                          send("+OK dewey POP3 server signing off", true)
  else
    send("-ERR unknown command")
                  end
end
user(username) click to toggle source
# File lib/eventmachine/email_server/pop3_server.rb, line 220
def user(username)
        @user = @userstore.user_by_username(username)
end