Skip to content

Instantly share code, notes, and snippets.

@bpot
Created August 29, 2009 05:54
Show Gist options
  • Save bpot/177404 to your computer and use it in GitHub Desktop.
Save bpot/177404 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'eventmachine'
require 'dataflow'
# Experimenting with dataflow + EM
def do_pop_stuff
pop_client = EventMachine::POP::POP3Client.new('pop.gmail.com', 995, true, 'username', 'password')
print "stat: #{pop_client.stat}\n"
pop_client.mails.each do |m|
print m.raw + "\n"
end
end
module EventMachine
module POP
class POPMail
attr_accessor :uidl
def initialize(number, client)
@number = number
@client = client
end
def header
@client.header(@number)
end
def raw
@client.retr(@number)
end
end
class POP3Connection < EM::Connection
include Protocols::LineText2
include Dataflow
attr_accessor :username, :password, :guard
def self.connect(host, port, ssl, username, password, guard)
p "connecting"
EM.connect(host, port, self) do |c|
c.username = username
c.password = password
c.guard = guard
end
end
def post_init
start_tls
@responder = :login
@mails = []
p "post init"
end
def login
p "logging in"
send_data "USER #{username}\r\n"
@responder = :receive_user
end
def receive_user
send_data "PASS #{password}\r\n"
@responder = :receive_auth_response
end
def receive_auth_response
if @line.match(/\+OK/)
unify @guard, ""
else
raise StandardError, "Could not authenticate"
end
end
def send_data(data)
p "send: #{data}"
super
end
def receive_line(line)
p "recv: #{line}"
@line = line
send @responder if @responder
end
def auth_guard
@guard.object_id # force wait on variable
end
def send_command(command, *args)
auth_guard
@responder = "receive_#{command.downcase}"
data = command
data += " " + args.join(" ") unless args.empty?
send_data "#{data}\r\n"
@result = Dataflow::Variable.new
end
def stat
p "sSTAT"
send_command("STAT")
end
def receive_stat
matches = @line.match(/\+OK (\d+) (\d+)/)
unify @result, matches[1].to_i
end
def retr(number)
@body = []
send_command("RETR", number)
end
def receive_retr
if @line =~ /^\+OK/
# ignore
elsif @line == "."
unify @result, @body.join("\n")
else
@body << @line
end
end
def header(number)
send_command("TOP", number, 0)
end
def receive_header
if @line =~ /^\+OK/
# ignore
elsif @line == "."
unify @result, @header.join("\n")
else
@header << @line
end
end
def mails
@mail ||= send_command("UIDL")
end
def receive_uidl
if @line == "."
unify @result, @mails
elsif @line == "+OK"
# ignore
else
matches = @line.match(/(\d+) (.*)/)
mail = POPMail.new(matches[1], self)
mail.uidl = matches[2]
@mails << mail
end
end
def queue_command(*args)
end
def do_next_command
end
def need_raw_mails
end
end
class POP3Client
include Dataflow
def initialize(*args)
@connection = nil
guard = Dataflow::Variable.new
EM.next_tick {
@connection = EventMachine::POP::POP3Connection.connect(*args.push(guard))
}
guard.object_id # wait until connection is complete
@connection
end
def method_missing(*args)
@connection.send(*args)
end
end
end
end
EM.run {
Thread.abort_on_exception = true
EM.defer {
do_pop_stuff
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment