最小的Ruby飞信客户端


最小的飞信的ruby客户端,功能很简单,目前只能给自己和飞信好友发短信。使用TCP连接,没有走HTTP通道。 

更新部分内容应对2010年7月25日飞信升级。有图形验证码了?没有时间管它,先hack一下绕过去。
 
#!/usr/bin/ruby  
# Using GPL v2  
# Author:: DongYuwei(mailto:newdongyuwei@gmail.com)  
# 更新部分内容应对2010年7月25日飞信升级   
  
require 'uri'  
require 'net/http'  
require 'net/https'  
require "socket"  
require 'rexml/document'  
require 'digest/md5'  
require 'digest/sha1'  
require "iconv"  
  
class Fetion  
    def initialize(phone_num , password)  
        @phone_num = phone_num;  
        @password = password;  
        @domain = "fetion.com.cn";  
        @login_xml = '<args><device type="PC" version="0" client-version="3.5.2540" /><caps value="simple-im;im-session;temp-group;personal-group" /><events value="contact;permission;system-message;personal-group" /><user-info attributes="all" /><presence><basic value="400" desc="" /></presence></args>';  
        self.init  
    end  
      
    def init  
        doc = REXML::Document.new(self.get_system_config())  
        sipc_proxy = ""  
        doc.elements.each("//sipc-proxy") do |element|  # using regexp should be faster  
            sipc_proxy = element.text  
        end  
        @SIPC = SIPC.new(sipc_proxy);  
          
        sipc_url = ""  
        #ssi-app-sign-in  
        doc.elements.each("//ssi-app-sign-in-v2") do |element|  
            sipc_url = element.text  
        end  
        @fetion_num = self.get_fetion_num(self.SSIAppSignIn(sipc_url))  
    end  
      
    def login()  
        request1 = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 1 R\r\nL: %s\r\n\r\n",@domain, @fetion_num, @login_xml.length)  
        request1 = request1 + @login_xml  
        server_response = @SIPC.request(request1)  
        @nonce = server_response.scan(/nonce="(.*)"/)[0][0]  
          
        request2 = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 2 R\r\nA: Digest response=\"%s\",cnonce=\"%s\"\r\nL: %s\r\n\r\n", @domain, @fetion_num, self.get_response(), @cnonce, @login_xml.length)  
        request2 = request2 + @login_xml  
        @SIPC.request(request2)  
    end  
      
    def send_sms(phone, sms_text)  
        sms_text = Iconv.iconv("UTF-8","UTF-8",sms_text)[0]  
        request = sprintf("M %s SIP-C/2.0\r\nF: %s\r\nI: 2\r\nQ: 1 M\r\nT: tel:%s\r\nN: SendSMS\r\nL: %s\r\n\r\n",@domain, @fetion_num, phone, sms_text.length)  
        request = request + sms_text  
        @SIPC.request(request)  
    end  
      
    def send_sms_to_self(sms_text)  
        sms_text = Iconv.iconv("UTF-8","UTF-8",sms_text)[0]  
        request = sprintf("M %s SIP-C/2.0\r\nF: %s\r\nI: 2\r\nQ: 1 M\r\nT: %s\r\nN: SendCatSMS\r\nL: %s\r\n\r\n",@domain, @fetion_num, @uri, sms_text.length)  
        request = request + sms_text  
        @SIPC.request(request)  
    end  
  
    def logout()  
        logout_request = sprintf("R %s SIP-C/2.0\r\nF: %s\r\nI: 1 \r\nQ: 3 R\r\nX: 0\r\n\r\n", @domain, @fetion_num)  
        @SIPC.request(logout_request)  
    end  
      
    def get_response()  
        @cnonce = Digest::MD5.hexdigest(rand.to_s)  
        key = Digest::MD5.digest(@fetion_num + ":" + @domain + ":" + @password)  
        h1 = Digest::MD5.hexdigest(key + ":" + @nonce + ":" + @cnonce).upcase  
        h2 = Digest::MD5.hexdigest("REGISTER:" + @fetion_num).upcase  
        return Digest::MD5.hexdigest(h1+":" + @nonce + ":" + h2).upcase  
    end  
      
    def get_system_config()  
        uri = URI.parse("http://nav.fetion.com.cn/nav/getsystemconfig.aspx")  
        http = Net::HTTP.new(uri.host, uri.port)  
        params = sprintf('<config><user mobile-no="%s" /><client type="PC" version="3.5.2540" platform="W5.1" /><servers version="0" /><service-no version="0" /><parameters version="0" /><hints version="0" /><http-applications version="0" /><client-config version="0" /></config>',@phone_num)  
        headers = {  
          'Content-Type' => 'application/x-www-form-urlencoded'  
        }  
        resp = http.post(uri.path, params, headers)  
        return resp.body  
    end  
      
    def SSIAppSignIn(url)  
        uri = URI.parse(url)  
        path = uri.path + "?mobileno=" + @phone_num + "&pwd=" + @password  
        http = Net::HTTP.new(uri.host,uri.port)  
        http.use_ssl = true  
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE # turn off SSL warning  
        resp, xml = http.get(path, nil)  
          
        ok = "200"  
        doc = REXML::Document.new(xml)  
        doc.elements.each("//results") do|element|  
           ok = element.attribute("status-code").value  
       end  
       if ok != "200"#421 verification picture?  
            return self.SSIAppSignIn(url)  
       end  
        return xml  
    end  
      
    def get_fetion_num(xml)  
        @uri = ""  
        doc = REXML::Document.new(xml)  
        doc.elements.each("//results/user") do |element|  
          @uri = element.attribute("uri").value  
        end   
        return @uri.scan(/sip:([0-9]+)@/)[0][0]  
    end  
end  
  
class SIPC  
    def initialize(sipc_addr)  
        uri = sipc_addr.split(":")  
        @socket = TCPSocket.new(uri[0], uri[1].to_i)  
    end  
  
    # send SIP request  
    def request(sip_request)  
        puts sip_request  
        @socket.write_nonblock(sip_request)  
        #select read_nonblock and rescue is the key  
        IO.select [@socket]  
        res = ""  
        begin  
            while chunk = @socket.read_nonblock(4096)  
                res = res + chunk  
            end  
        rescue  
                puts "Error: #{$!}"  
        end  
        puts res   
        return res   
    end  
end  
  
#for test  
if __FILE__ == $0  
    fetion = Fetion.new("13651368727","password")  
    fetion.login()  
    fetion.send_sms_to_self("test-ruby-fetion")  
    #fetion.send_sms("mobileID","any sms")  
end  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值