Class: Fetion

Inherits:
Object
  • Object
show all
Defined in:
lib/rfetion/fetion.rb

Constant Summary collapse

FETION_URL =
'http://221.130.44.194/ht/sd.aspx'
FETION_LOGIN_URL =
'https://nav.fetion.com.cn/ssiportal/SSIAppSignIn.aspx'
FETION_CONFIG_URL =
'http://nav.fetion.com.cn/nav/getsystemconfig.aspx'
FETION_SIPP =
'SIPP'
GUID =
Guid.new.to_s

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFetion

Returns a new instance of Fetion.



15
16
17
18
19
20
21
22
# File 'lib/rfetion/fetion.rb', line 15

def initialize
  @next_call = 0
  @seq = 0
  @buddies = []
  @contacts = []
  @logger = Logger.new(STDOUT)
  @logger.level = Logger::INFO
end

Instance Attribute Details

#contactsObject (readonly)

Returns the value of attribute contacts.



6
7
8
# File 'lib/rfetion/fetion.rb', line 6

def contacts
  @contacts
end

#mobile_noObject

Returns the value of attribute mobile_no.



5
6
7
# File 'lib/rfetion/fetion.rb', line 5

def mobile_no
  @mobile_no
end

#passwordObject

Returns the value of attribute password.



5
6
7
# File 'lib/rfetion/fetion.rb', line 5

def password
  @password
end

#uriObject (readonly)

Returns the value of attribute uri.



6
7
8
# File 'lib/rfetion/fetion.rb', line 6

def uri
  @uri
end

Class Method Details

.add_buddy(mobile_no, password, friend_mobile, level = Logger::INFO) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/rfetion/fetion.rb', line 60

def Fetion.add_buddy(mobile_no, password, friend_mobile, level = Logger::INFO)
  fetion = Fetion.new
  fetion.logger_level = level
  fetion.mobile_no = mobile_no
  fetion.password = password
  fetion.
  fetion.register
  fetion.add_buddy(friend_mobile)
  fetion.logout
end

.send_sms_to_friends(mobile_no, password, friends, content, level = Logger::INFO) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rfetion/fetion.rb', line 39

def Fetion.send_sms_to_friends(mobile_no, password, friends, content, level = Logger::INFO)
  friends = Array(friends)
  friends.collect! {|friend| friend.to_s}
  fetion = Fetion.new
  fetion.logger_level = level
  fetion.mobile_no = mobile_no
  fetion.password = password
  fetion.
  fetion.register
  fetion.get_buddy_list
  fetion.get_contacts_info
  fetion.contacts.each do |contact|
    if friends.include? contact.mobile_no.to_s
      fetion.send_sms(contact.uri, content)
    elsif friends.any? { |friend| contact.uri.index(friend) }
      fetion.send_sms
    end
  end
  fetion.logout
end

.send_sms_to_self(mobile_no, password, content, level = Logger::INFO) ⇒ Object



28
29
30
31
32
33
34
35
36
37
# File 'lib/rfetion/fetion.rb', line 28

def Fetion.send_sms_to_self(mobile_no, password, content, level = Logger::INFO)
  fetion = Fetion.new
  fetion.logger_level = level
  fetion.mobile_no = mobile_no
  fetion.password = password
  fetion.
  fetion.register
  fetion.send_sms(fetion.uri, content)
  fetion.logout
end

Instance Method Details

#add_buddy(mobile, nickname = nil) ⇒ Object

Raises:



187
188
189
190
191
192
193
194
195
196
# File 'lib/rfetion/fetion.rb', line 187

def add_buddy(mobile, nickname = nil)
  @logger.info "fetion send request to add #{mobile} as friend"
  arg = %Q{<args><contacts><buddies><buddy uri="tel:#{mobile}" local-name="#{nickname}" buddy-lists="1" expose-mobile-no="1" expose-name="1" /></buddies></contacts></args>}
  msg = sip_create('S fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => next_call, 'Q' => '1 S', 'N' => 'AddBuddy'}, arg) + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)

  raise FetionException.new("Fetion Error: Add buddy error") unless response.is_a? Net::HTTPSuccess
  @logger.info "fetion send request to add #{mobile} as friend success"
end

#calc_cnonceObject



242
243
244
# File 'lib/rfetion/fetion.rb', line 242

def calc_cnonce
  Digest::MD5.hexdigest(GUID).upcase
end

#calc_responseObject



232
233
234
235
236
237
238
239
240
# File 'lib/rfetion/fetion.rb', line 232

def calc_response
  str = [hash_password[8..-1]].pack("H*")
  key = Digest::SHA1.digest("#{@sid}:#{@domain}:#{str}")

  h1 = Digest::MD5.hexdigest("#{key}:#{@nonce}:#{@cnonce}").upcase
  h2 = Digest::MD5.hexdigest("REGISTER:#{@sid}").upcase
  
  Digest::MD5.hexdigest("#{h1}:#{@nonce}:#{h2}").upcase
end

#curl_exec(url, ssic, body) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/rfetion/fetion.rb', line 208

def curl_exec(url, ssic, body)
  @logger.debug "fetion curl exec"
  @logger.debug "url: #{url}"
  @logger.debug "ssic: #{ssic}"
  @logger.debug "body: #{body}"
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  headers = {'Content-Type' => 'application/oct-stream', 'Pragma' => "xz4BBcV#{GUID}", 'User-Agent' => 'IIC2.0/PC 3.2.0540', 'Cookie' => "ssic=#{@ssic}"}
  response = http.request_post(uri.request_uri, body, headers)

  @logger.debug "response: #{response.inspect}"
  @logger.debug "response body: #{response.body}"
  @logger.debug "fetion curl exec complete"
  response
end

#get_buddy_listObject

Raises:



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/rfetion/fetion.rb', line 139

def get_buddy_list
  @logger.info "fetion get buddy list"
  arg = '<args><contacts><buddy-lists /><buddies attributes="all" /><mobile-buddies attributes="all" /><chat-friends /><blacklist /></contacts></args>'
  msg = sip_create('S fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => next_call, 'Q' => '1 S', 'N' => 'GetContactList'}, arg) + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)
  raise FetionException.new("Fetion Error: Get buddy list error") unless response.is_a? Net::HTTPSuccess

  response.body.scan(/uri="([^"]+)"/).each do |buddy|
    @buddies << {:uri => buddy[0]}
  end
  @logger.debug "buddies: #{@buddies.inspect}"
  @logger.info "fetion get buddy list success"
end

#get_contacts_infoObject

Raises:



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rfetion/fetion.rb', line 154

def get_contacts_info
  @logger.info "fetion get contacts info"
  arg = '<args><contacts attributes="all">'
  @buddies.each do |buddy|
    arg += "<contact uri=\"#{buddy[:uri]}\" />"
  end
  arg += '</contacts></args>'

  msg = sip_create('S fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => next_call, 'Q' => '1 S', 'N' => 'GetContactsInfo'}, arg) + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)
  raise FetionException.new("Fetion Error: Get contacts info error") unless response.is_a? Net::HTTPSuccess

  response.body.scan(%r{<events>.*?</events>}).each do |events|
    doc = REXML::Document.new(events)
    doc.elements.each("events/event/results/contacts/contact") do |contact|
      @contacts << Contact.new(contact.attributes["uri"], contact.elements.first.attributes)
    end
  end
  @logger.debug @contacts.inspect
  @logger.info "fetion get contacts info success"
end

#hash_passwordObject



246
247
248
249
250
# File 'lib/rfetion/fetion.rb', line 246

def hash_password
  salt = "#{0x77.chr}#{0x7A.chr}#{0x6D.chr}#{0x03.chr}"
  src = salt + Digest::SHA1.digest(@password)
  '777A6D03' + Digest::SHA1.hexdigest(src).upcase
end

#logger_level=(level) ⇒ Object



24
25
26
# File 'lib/rfetion/fetion.rb', line 24

def logger_level=(level)
  @logger.level = level
end

#loginObject

Raises:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rfetion/fetion.rb', line 71

def 
  @logger.info "fetion login"
  uri = URI.parse(FETION_LOGIN_URL + "?mobileno=#{@mobile_no}&pwd=#{@password}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  headers = {'Content-Type' => 'application/oct-stream', 'Pragma' => "xz4BBcV#{GUID}", 'User-Agent' => 'IIC2.0/PC 3.2.0540'}
  response = http.request_get(uri.request_uri, headers)

  raise FetionException.new('Fetion Error: Login failed.') unless response.is_a? Net::HTTPSuccess
  raise FetionException.new('Fetion Error: No ssic found in cookie.') unless response['set-cookie'] =~ /ssic=(.*);/

  @ssic = $1
  @logger.debug response.body
  doc = REXML::Document.new(response.body)
  results = doc.root
  @status_code = results.attributes["status-code"]
  user = results.children.first
  @user_status = user.attributes['user-status']
  @uri = user.attributes['uri']
  @mobile_no = user.attributes['mobile-no']
  @user_id = user.attributes['user-id']
  if @uri =~ /sip:(\d+)@(.+);/
    @sid = $1
    @domain = $2
  end
  @logger.debug "ssic: " + @ssic
  @logger.debug "status_code: " + @status_code
  @logger.debug "user_status: " + @user_status
  @logger.debug "uri: " + @uri
  @logger.debug "mobile_no: " + @mobile_no
  @logger.debug "user_id: " + @user_id
  @logger.debug "sid: " + @sid
  @logger.debug "domain: " + @domain
  @logger.info "fetion login success"
end

#logoutObject

Raises:



198
199
200
201
202
203
204
205
206
# File 'lib/rfetion/fetion.rb', line 198

def logout
  @logger.info "fetion logout"
  msg = sip_create('R fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => next_call, 'Q' => '2 R', 'X' => 0}, '') + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)

  raise FetionException.new("Fetion Error: Logout error") unless response.is_a? Net::HTTPSuccess
  @logger.info "fetion logout success"
end

#next_callObject



257
258
259
# File 'lib/rfetion/fetion.rb', line 257

def next_call
  @next_call += 1
end

#next_url(t = 's') ⇒ Object



252
253
254
255
# File 'lib/rfetion/fetion.rb', line 252

def next_url(t = 's')
  @seq += 1
  FETION_URL + "?t=#{t}&i=#{@seq}"
end

#registerObject

Raises:



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rfetion/fetion.rb', line 108

def register
  @logger.info "fetion http register"
  arg = '<args><device type="PC" version="44" client-version="3.2.0540" /><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>'

  call = next_call
  curl_exec(next_url, @ssic, FETION_SIPP)

  msg = sip_create("R fetion.com.cn SIP-C/2.0", {'F' => @sid, 'I' => call, 'Q' => '1 R'}, arg) + FETION_SIPP
  curl_exec(next_url('i'), @ssic, msg)

  response = curl_exec(next_url, @ssic, FETION_SIPP)
  raise FetionException.new("Fetion Error: no nonce found") unless response.body =~ /nonce="(\w+)"/
    
  @nonce = $1
  @salt =  "777A6D03"
  @cnonce = calc_cnonce
  @response = calc_response

  @logger.debug "nonce: #{@nonce}"
  @logger.debug "salt: #{@salt}"
  @logger.debug "cnonce: #{@cnonce}"
  @logger.debug "response: #{@response}"

  msg = sip_create('R fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => call, 'Q' => '2 R', 'A' => "Digest algorithm=\"SHA1-sess\",response=\"#{@response}\",cnonce=\"#{@cnonce}\",salt=\"#{@salt}\""}, arg) + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)

  raise FetionException.new('Fetion Error: Register failed.') unless response.is_a? Net::HTTPSuccess
  @logger.info "fetion http register success"
end

#send_sms(to, content) ⇒ Object

Raises:



177
178
179
180
181
182
183
184
185
# File 'lib/rfetion/fetion.rb', line 177

def send_sms(to, content)
  @logger.info "fetion send sms to #{to}"
  msg = sip_create('M fetion.com.cn SIP-C/2.0', {'F' => @sid, 'I' => next_call, 'Q' => '1 M', 'T' => to, 'N' => 'SendSMS'}, content) + FETION_SIPP
  curl_exec(next_url, @ssic, msg)
  response = curl_exec(next_url, @ssic, FETION_SIPP)

  raise FetionException.new("Fetion Error: Send sms error") unless response.is_a? Net::HTTPSuccess
  @logger.info "fetion send sms to #{to} success"
end

#sip_create(invite, fields, arg) ⇒ Object



224
225
226
227
228
229
230
# File 'lib/rfetion/fetion.rb', line 224

def sip_create(invite, fields, arg)
  sip = invite + "\r\n"
  fields.each {|k, v| sip += "#{k}: #{v}\r\n"}
  sip += "L: #{arg.size}\r\n\r\n#{arg}"
  @logger.debug "sip message: #{sip}"
  sip
end