-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ary Borenszweig
committed
Nov 1, 2012
0 parents
commit 1d4cc86
Showing
12 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.bundle | ||
*.gem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source :rubygems | ||
|
||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
PATH | ||
remote: . | ||
specs: | ||
em-msn (0.1) | ||
eventmachine | ||
rest-client | ||
|
||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
eventmachine (1.0.0) | ||
mime-types (1.19) | ||
rest-client (1.6.7) | ||
mime-types (>= 1.16) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
em-msn! |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# -*- encoding: utf-8 -*- | ||
$:.push File.expand_path("../lib", __FILE__) | ||
require "msn/version" | ||
|
||
Gem::Specification.new do |s| | ||
s.name = "em-msn" | ||
s.version = Msn::VERSION | ||
s.platform = Gem::Platform::RUBY | ||
s.authors = ["Ary Borenszweig"] | ||
s.email = %q{aborenszweig@manas.com.ar} | ||
s.homepage = "http://github.com/manastech/em-msn" | ||
s.summary = %q{MSN client (EventMachine + Ruby)} | ||
s.description = %q{An MSN client for Ruby written on top of EventMachine} | ||
|
||
s.files = [ | ||
"lib/em-msn.rb", | ||
"lib/msn/message.rb", | ||
"lib/msn/messenger.rb", | ||
"lib/msn/notification_server.rb", | ||
"lib/msn/protocol.rb", | ||
"lib/msn/switchboard.rb", | ||
"lib/msn/version.rb", | ||
] | ||
|
||
s.require_path = "lib" | ||
s.has_rdoc = false | ||
s.extra_rdoc_files = ["README.md"] | ||
|
||
s.add_dependency "eventmachine" | ||
s.add_dependency "rest-client" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module Msn | ||
end | ||
|
||
require 'eventmachine' | ||
require 'rest-client' | ||
require 'fiber' | ||
require 'cgi' | ||
require 'digest/md5' | ||
|
||
require_relative 'msn/protocol' | ||
require_relative 'msn/message' | ||
require_relative 'msn/notification_server' | ||
require_relative 'msn/switchboard' | ||
require_relative 'msn/messenger' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
class Msn::Message | ||
attr_accessor :email | ||
attr_accessor :display_name | ||
attr_accessor :text | ||
|
||
def initialize(email, display_name, text) | ||
@email = email | ||
@display_name = display_name | ||
@text = text | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
class Msn::Messenger | ||
attr_reader :username | ||
attr_reader :password | ||
|
||
def initialize(username, password) | ||
@username = username | ||
@password = password | ||
end | ||
|
||
def connect | ||
@notification_server = EM.connect 'messenger.hotmail.com', 1863, Msn::NotificationServer, self | ||
end | ||
|
||
def set_online_status(status) | ||
case status | ||
when :available, :online | ||
@notification_server.chg "NLN", 0 | ||
when :busy | ||
@notification_server.chg "BSY", 0 | ||
when :idle | ||
@notification_server.chg "IDL", 0 | ||
when :brb, :be_right_back | ||
@notification_server.chg "BRB", 0 | ||
when :away | ||
@notification_server.chg "AWY", 0 | ||
when :phone, :on_the_phone | ||
@notification_server.chg "PHN", 0 | ||
when :lunch, :out_to_lunch | ||
@notification_server.chg "LUN", 0 | ||
else | ||
raise "Wrong online status: #{status}" | ||
end | ||
end | ||
|
||
def on_ready(&handler) | ||
@on_ready_handler = handler | ||
end | ||
|
||
def on_message(&handler) | ||
@on_message_handler = handler | ||
end | ||
|
||
def accept_message(message) | ||
@on_message_handler.call(message) if @on_message_handler | ||
end | ||
|
||
def ready | ||
@on_ready_handler.call if @on_ready_handler | ||
end | ||
|
||
def self.debug | ||
@debug | ||
end | ||
|
||
def self.debug=(debug) | ||
@debug = debug | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
class Msn::NotificationServer < EventMachine::Connection | ||
include Msn::Protocol | ||
|
||
attr_reader :messenger | ||
attr_reader :display_name | ||
|
||
def initialize(messenger) | ||
@messenger = messenger | ||
end | ||
|
||
def username | ||
messenger.username | ||
end | ||
|
||
def password | ||
messenger.password | ||
end | ||
|
||
def post_init | ||
super | ||
|
||
login | ||
end | ||
|
||
def login | ||
Fiber.new do | ||
response = ver "MSNP8" | ||
if response[2] != "MSNP8" | ||
raise "Expected response to be 'VER 0 MSNP8' but it was '#{response}'" | ||
end | ||
|
||
response = cvr "0x0409", "winnt", "5.1", "i386", "MSNMSGR", "6.0.0602", "MSMSGS", username | ||
if response[2] == "1.0.0000" | ||
raise "The client version we are sending is not compatible anymore :-(" | ||
end | ||
|
||
response = usr "TWN", "I", username | ||
if response[0] == "XFR" && response[2] == "NS" | ||
host, port = response[3].split ':' | ||
@reconnect_host, @reconnect_port = response[3].split ':' | ||
close_connection | ||
else | ||
login_with_challenge(response[4]) | ||
end | ||
end.resume | ||
end | ||
|
||
def login_with_challenge(challenge) | ||
nexus_response = RestClient.get "https://nexus.passport.com/rdr/pprdr.asp" | ||
passport_urls = nexus_response.headers[:passporturls] | ||
passport_urls = Hash[passport_urls.split(',').map { |key_value| key_value.split('=', 2) }] | ||
passport_url = "https://#{passport_urls['DALogin']}" | ||
|
||
authorization = "Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in=#{CGI.escape username},pwd=#{CGI.escape password},#{challenge}" | ||
da_login_response = RestClient.get passport_url, 'Authorization' => authorization | ||
if da_login_response.net_http_res.code != "200" | ||
raise "Login failed (1)" | ||
end | ||
|
||
authentication_info = da_login_response.headers[:authentication_info] | ||
authentication_info = authentication_info["Passport1.4 ".length .. -1] | ||
authentication_info = Hash[authentication_info.split(',').map { |key_value| key_value.split('=', 2) }] | ||
if authentication_info['da-status'] != "success" | ||
raise "Login failed (2)" | ||
end | ||
|
||
from_pp = authentication_info['from-PP'] | ||
token = from_pp[1 .. -2] # remove single quotes | ||
|
||
first_msg = true | ||
on_event('MSG') do | ||
if first_msg | ||
first_msg = false | ||
messenger.ready | ||
end | ||
end | ||
|
||
on_event('RNG') do |header| | ||
host, port = header[2].split(':') | ||
rng_conn = EM.connect host, port, Msn::Switchboard, messenger | ||
rng_conn.ans username, header[4], header[1] | ||
end | ||
|
||
response = usr "TWN", "S", token | ||
if response[2] != "OK" | ||
raise "Login failed (3)" | ||
end | ||
|
||
@display_name = CGI.unescape response[4] | ||
end | ||
|
||
def unbind | ||
if @reconnect_host | ||
reconnect @reconnect_host, @reconnect_port.to_i | ||
@reconnect_host = @reconnect_port = nil | ||
login | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
module Msn::Protocol | ||
include EventMachine::Protocols::LineText2 | ||
|
||
def post_init | ||
@trid = 0 | ||
@command_fibers = {} | ||
end | ||
|
||
def receive_line(line) | ||
puts "<< #{line}" if Msn::Messenger.debug | ||
pieces = line.split(' ') | ||
|
||
case pieces[0] | ||
when 'CHL' | ||
answer_challenge pieces[2] | ||
when 'RNG' | ||
handle_event pieces | ||
when 'MSG' | ||
@header = pieces | ||
|
||
size = pieces.last.to_i | ||
set_binary_mode size | ||
when 'CHG', 'QRY' | ||
# ignore | ||
else | ||
if fiber = @command_fibers.delete(pieces[1].to_i) | ||
fiber.resume pieces | ||
else | ||
handle_event pieces | ||
end | ||
end | ||
end | ||
|
||
def receive_binary_data(data) | ||
puts "<<* #{data}" if Msn::Messenger.debug | ||
|
||
handle_event @header, data | ||
end | ||
|
||
def handle_event(header, data = nil) | ||
return unless @event_handlers | ||
|
||
handler = @event_handlers[header[0]] | ||
if handler | ||
Fiber.new do | ||
handler.call header, data | ||
end.resume | ||
end | ||
end | ||
|
||
def answer_challenge(challenge_string) | ||
payload = Digest::MD5.hexdigest "#{challenge_string}Q1P7W2E4J9R8U3S5" | ||
|
||
data = "QRY #{@trid} msmsgs@msnmsgr.com 32\r\n#{payload}" | ||
puts ">>* #{data}" if Msn::Messenger.debug | ||
|
||
send_data data | ||
|
||
@trid += 1 | ||
end | ||
|
||
def send_command(command, *args) | ||
@command_fibers[@trid] = Fiber.current | ||
|
||
text = "#{command} #{@trid} #{args.join ' '}\r\n" | ||
puts ">> #{text}" if Msn::Messenger.debug | ||
send_data text | ||
@trid += 1 | ||
|
||
Fiber.yield | ||
end | ||
|
||
def on_event(kind, &block) | ||
@event_handlers ||= {} | ||
@event_handlers[kind] = block | ||
end | ||
|
||
def method_missing(name, *args) | ||
send_command name.upcase, *args | ||
end | ||
|
||
def unbind | ||
puts "Chau :-(" | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class Msn::Switchboard < EventMachine::Connection | ||
include Msn::Protocol | ||
|
||
def initialize(messenger) | ||
@messenger = messenger | ||
|
||
on_event 'MSG' do |header, data| | ||
email = header[1] | ||
display_name = header[2] | ||
head, body = data.split "\r\n\r\n", 2 | ||
headers = Hash[head.split("\r\n").map { |line| line.split ':', 2 }] | ||
|
||
if headers['Content-Type'] =~ %r(text/plain) | ||
@messenger.accept_message Msn::Message.new(email, display_name, body) | ||
end | ||
end | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module Msn | ||
VERSION = "0.1" | ||
end |