#!/usr/bin/env ruby

# use it like so: Net::HTTP.multi_post_form(url, params)
require 'net/http'
class Net::HTTP
def self.multi_post_form(url, params)
req = Post.new(url.path)
req.multipart_params = params
req.basic_auth url.user, url.password if url.user
new(url.host, url.port).start {|http|
http.request(req)
}
end
end

module Net
class HTTP
class Post
def multipart_params=(param_hash={})
boundary_token = [Array.new(8) {rand(256)}].join
self.content_type = "multipart/form-data; boundary=#{boundary_token}"
boundary_marker = "--#{boundary_token}\r\n"

self.body = param_hash.map { |param_name, param_value|
boundary_marker + text_to_multipart(param_name, param_hash.delete(param_name).to_s) unless param_value.respond_to?(:read) || param_value.kind_of?(Hash)
}.join('')

self.body += param_hash.map { |param_name, param_value|
boundary_marker + file_to_multipart(param_name, param_value)
}.join('')

self.body += "--#{boundary_token}--\r\n"
end

protected

def file_to_multipart(key, file)
if (file.kind_of? Hash)
file_data = file[:data]
file_name = file[:name]
mime_type = file[:mime] || "application/octet-stream"
else
file_data = file.read
file_name = File.basename(file.path)
mime_type = "application/octet-stream"
end
part = %Q|Content-Disposition: form-data; name=\"#{key}\"; filename="#{file_name}"\r\n|
part += "Content-Transfer-Encoding: binary\r\n"
part += "Content-Type: #{mime_type}\r\n\r\n#{file_data}\r\n"
end

def text_to_multipart(key,value)
"Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
end
end
end
end

class User
require 'rubygems'
require 'sqlite3'

def self.db
SQLite3::Database.new(File.join(ENV["HOME"], "tumblr.db"))
end

def self.create_table
db.execute("CREATE TABLE users (email varchar, email_login varchar, password varchar)");
end

def self.find(email)
begin
email_login, password = db.get_first_row("SELECT email_login, password FROM users WHERE email = ?", email)
rescue SQLite3::SQLException
create_table
end
if (email_login && password)
return {:email => email_login, :password => password}
end
nil
end

def self.add(email, email_login, password)
begin
db.execute("DELETE FROM users WHERE email = ?", email) if (find(email))
rescue SQLite3::SQLException
create_table
end

db.execute("INSERT INTO users (email, email_login, password) VALUES (?, ?, ?)", email, email_login, password)
end
end

class Tumblr
require 'net/http'

def initialize(email, password)
@email, @password = email, password
end

def params
{ 'email' => @email, 'password' => @password }
end

def post_regular(subject, body)
p = params.merge({
'type' => 'regular',
'title' => subject,
'body' => body
})
res = Net::HTTP.post_form(URI.parse("http://www.tumblr.com/api/write"), p)
end

def post_image(caption, file_name, file_data, mime)
p = params.merge({
'type' => 'photo',
'caption' => caption,
'data' => {:name => file_name, :data => file_data, :mime => mime}
})
res = Net::HTTP.multi_post_form(URI.parse("http://www.tumblr.com/api/write"), p)
# res = Net::HTTP.multi_post_form(URI.parse("http://localhost:2000/"), p)
puts res.inspect
end
end

class Part
require 'base64'

attr_reader :content_type, :filename, :contents
def initialize(text)
@filename = ""
header, body = text.split("\n\n")
@content_type = header.match(/Content-Type:\s(.*);/i)[1]
@filename = header.match(/name="?(.*)"?/i)[1] if header.match(/name="?(.*)"?/i)
if (header.match(/Content-Transfer-Encoding: base64/))
@contents = Base64.decode64(body)
else
@contents = body
end
end
end

email = STDIN.read
email = open('email_iphone.txt').read if email.empty?
#File.open('email_iphone.txt', 'w') { |f| f.puts email }

from = email.match(/^From:.*[^a-zA-Z0-9\.\-_]([a-zA-Z0-9\.\-_]+@[\w\.-]+)/)[1]
subject = email.match(/^Subject: (.*)$/)[1]
boundary = email.match(/boundary="?(.*)"?/)[1] if email.match(/boundary=/)

File.open('log.txt', 'a') { |f| f.puts Time.now.to_s + " Subject: #{subject}"}

post_body = ""
file_name = ""
file_data = ""
file_mime = ""

if boundary # multi-part
email.sub!(/^.+?[^"]#{boundary}/m, '')
email.split(/-*#{boundary}/).each do |part|
next if part.empty? || part.match(/^\s*-+\s*$/)
next unless part.match(/Content-Type:/i)

p = Part.new(part)
case p.content_type
when 'text/plain'
post_body = p.contents
when /image/
file_data = p.contents
file_name = p.filename
file_mime = p.content_type
end
end
else
email.sub!(/^.+?\n\n/m, '')
post_body = email
end

if (post_body.match(/email:/i) && post_body.match(/password:/i))
User.add(from, post_body.match(/email:\s*(.*)$/i)[1], post_body.match(/password:\s*(.*)$/i)[1])
else
user = User.find(from)
t = Tumblr.new(user[:email], user[:password])
unless file_name.empty?
t.post_image(subject || post_body, file_name, file_data, file_mime)
else
t.post_regular(subject, post_body)
end
end