rfetion 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/rfetion/command.rb +1 -1
- data/lib/rfetion/fetion.rb +83 -68
- data/lib/rfetion/sipc_message.rb +14 -6
- data/rfetion.gemspec +2 -2
- data/spec/rfetion/fetion_spec.rb +1 -0
- data/spec/rfetion/sipc_message_spec.rb +4 -4
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.1
|
data/lib/rfetion/command.rb
CHANGED
@@ -86,7 +86,7 @@ begin
|
|
86
86
|
|
87
87
|
raise FetionException.new('You must input your mobile number or fetion sid, password and content') unless (options[:mobile_no] or options[:sid]) and options[:password] and options[:content]
|
88
88
|
if options[:time]
|
89
|
-
Fetion.
|
89
|
+
Fetion.set_schedule_sms(options)
|
90
90
|
else
|
91
91
|
Fetion.send_sms(options)
|
92
92
|
end
|
data/lib/rfetion/fetion.rb
CHANGED
@@ -20,9 +20,7 @@ class Fetion
|
|
20
20
|
DOMAIN = "fetion.com.cn"
|
21
21
|
|
22
22
|
def initialize
|
23
|
-
@call = 0
|
24
|
-
@alive = 0
|
25
|
-
@seq = 0
|
23
|
+
@call = @alive = @seq = 0
|
26
24
|
@buddies = []
|
27
25
|
@contacts = []
|
28
26
|
@logger = Logger.new(STDOUT)
|
@@ -146,6 +144,8 @@ class Fetion
|
|
146
144
|
end
|
147
145
|
|
148
146
|
def login
|
147
|
+
@logger.info "fetion login"
|
148
|
+
|
149
149
|
if @mobile_no
|
150
150
|
url = FETION_LOGIN_URL.sub('%mobileno%', @mobile_no).sub('sid=%sid%', '')
|
151
151
|
else
|
@@ -157,74 +157,82 @@ class Fetion
|
|
157
157
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
158
158
|
headers = {'User-Agent' => USER_AGENT}
|
159
159
|
response = http.request_get(uri.request_uri, headers)
|
160
|
+
parse_ssic(response)
|
160
161
|
|
161
|
-
|
162
|
-
|
163
|
-
parse_login_response(response)
|
162
|
+
@logger.info "fetion login success"
|
164
163
|
end
|
165
164
|
|
166
165
|
def register
|
166
|
+
@logger.info "fetion register"
|
167
|
+
|
167
168
|
call = next_call
|
168
169
|
register_first
|
169
170
|
register_second
|
170
171
|
call = next_call
|
172
|
+
|
173
|
+
@logger.info "fetion register success"
|
171
174
|
end
|
172
175
|
|
173
176
|
def register_first
|
177
|
+
@logger.debug "fetion register first"
|
178
|
+
|
174
179
|
curl_exec(SIPP, next_url('i'))
|
175
180
|
curl_exec(SipcMessage.register_first(self))
|
176
181
|
response = pulse
|
177
|
-
|
178
|
-
|
179
|
-
@nonce = $1
|
180
|
-
@key = $2
|
181
|
-
@signature = $3
|
182
|
-
@response = calc_response
|
182
|
+
parse_nonce(response)
|
183
183
|
|
184
|
-
@logger.debug "
|
185
|
-
@logger.debug "key: #{@key}"
|
186
|
-
@logger.debug "signature: #{@signature}"
|
187
|
-
@logger.debug "response: #{@response}"
|
184
|
+
@logger.debug "fetion register first success"
|
188
185
|
end
|
189
186
|
|
190
187
|
def register_second
|
188
|
+
@logger.debug "fetion register second"
|
189
|
+
|
191
190
|
body = %Q|<args><device machine-code="B04B5DA2F5F1B8D01A76C0EBC841414C" /><caps value="ff" /><events value="7f" /><user-info mobile-no="#{@mobile_no}" user-id="#{@user_id}"><personal version="0" attributes="v4default" /><custom-config version="0" /><contact-list version="0" buddy-attributes="v4default" /></user-info><credentials domains="fetion.com.cn;m161.com.cn;www.ikuwa.cn;games.fetion.com.cn" /><presence><basic value="400" desc="" /></presence></args>|
|
192
191
|
curl_exec(SipcMessage.register_second(self))
|
193
192
|
response = pulse
|
193
|
+
parse_info(response)
|
194
194
|
|
195
|
-
|
196
|
-
|
197
|
-
parse_info(response.body)
|
198
|
-
parse_buddies(response.body)
|
195
|
+
@logger.debug "fetion register second success"
|
199
196
|
end
|
200
197
|
|
201
198
|
def get_contacts
|
199
|
+
@logger.info "fetion get contacts"
|
200
|
+
|
202
201
|
curl_exec(SipcMessage.get_group_list(self))
|
203
202
|
|
204
203
|
response = curl_exec(SipcMessage.presence(self))
|
205
204
|
response = curl_exec(SipcMessage.get_group_topic(self))
|
206
|
-
|
207
|
-
parse_contacts(response.body)
|
205
|
+
parse_contacts(response)
|
208
206
|
|
209
207
|
curl_exec(SipcMessage.get_address_list(self))
|
210
208
|
pulse
|
209
|
+
|
210
|
+
@logger.info "fetion get contacts success"
|
211
211
|
end
|
212
212
|
|
213
213
|
def send_msg(receiver, content)
|
214
|
-
@logger.info "fetion send msg to #{receiver}"
|
215
|
-
|
214
|
+
@logger.info "fetion send cat msg to #{receiver}"
|
215
|
+
|
216
|
+
curl_exec(SipcMessage.send_cat_msg(self, receiver, content))
|
216
217
|
response = pulse
|
217
218
|
|
218
|
-
raise
|
219
|
-
|
219
|
+
raise FetionException.new("Fetion Error: Send cat msg error") unless Net::HTTPSuccess === response
|
220
|
+
sipc_message = SipcMessage.sipc_response(response.body)
|
221
|
+
raise Fetion::SendMsgException.new("Fetion Error: Send cat msg error with #{sipc_message}") unless SipcMessage::OK === sipc_message
|
222
|
+
|
223
|
+
@logger.info "fetion send cat msg to #{receiver} success"
|
220
224
|
end
|
221
225
|
|
222
226
|
def send_sms(receiver, content)
|
223
227
|
@logger.info "fetion send cat sms to #{receiver}"
|
228
|
+
|
224
229
|
curl_exec(SipcMessage.send_cat_sms(self, receiver, content))
|
225
230
|
response = pulse
|
226
231
|
|
227
|
-
raise
|
232
|
+
raise FetionException.new("Fetion Error: Send cat sms error") unless Net::HTTPSuccess === response
|
233
|
+
sipc_message = SipcMessage.sipc_response(response.body)
|
234
|
+
raise Fetion::SendSmsException.new("Fetion Error: Send cat sms error with #{sipc_message}") unless SipcMessage::Send === sipc_message
|
235
|
+
|
228
236
|
@logger.info "fetion send cat sms to #{receiver} success"
|
229
237
|
end
|
230
238
|
|
@@ -240,7 +248,10 @@ class Fetion
|
|
240
248
|
curl_exec(SipcMessage.set_schedule_sms(self, receivers, content, time.strftime('%Y-%m-%d %H:%M:%S')))
|
241
249
|
response = pulse
|
242
250
|
|
243
|
-
raise
|
251
|
+
raise FetionException.new("Fetion Error: Set schedule sms error") unless Net::HTTPSuccess === response
|
252
|
+
sipc_message = SipcMessage.sipc_response(response.body)
|
253
|
+
raise Fetion::SetScheduleSmsException.new("Fetion Error: Set schedule sms error with #{sipc_message}") unless SipcMessage::OK === sipc_message
|
254
|
+
|
244
255
|
@logger.info "fetion schedule send sms to #{receivers.join(', ')} success"
|
245
256
|
end
|
246
257
|
|
@@ -253,7 +264,9 @@ class Fetion
|
|
253
264
|
@logger.info "fetion send request to add #{uri} as friend"
|
254
265
|
curl_exec(SipcMessage.add_buddy(self, options))
|
255
266
|
response = pulse
|
256
|
-
raise
|
267
|
+
raise FetionException.new("Fetion Error: Add buddy error") unless Net::HTTPSuccess === response
|
268
|
+
sipc_message = SipcMessage.sipc_response(response.body)
|
269
|
+
raise Fetion::AddBuddyException.new("Fetion Error: Add buddy error with #{sipc_message}") unless SipcMessage::OK === sipc_message
|
257
270
|
|
258
271
|
@logger.info "fetion send request to add #{uri} as friend success"
|
259
272
|
end
|
@@ -265,23 +278,28 @@ class Fetion
|
|
265
278
|
uri = options[:mobile_no] ? "tel:#{options[:mobile_no]}" : "sip:#{options[:sip]}"
|
266
279
|
|
267
280
|
@logger.info "fetion get contact info of #{uri}"
|
268
|
-
curl_exec(SipcMessage.get_contact_info(self,
|
281
|
+
curl_exec(SipcMessage.get_contact_info(self, uri))
|
269
282
|
response = pulse
|
270
283
|
|
284
|
+
raise FetionException.new("Fetion Error: get contact info error") unless Net::HTTPSuccess === response
|
271
285
|
sipc_response = SipcMessage.sipc_response(response.body)
|
272
|
-
raise Fetion::NoUserException.new("Fetion Error: get contact info #{uri} with #{sipc_response
|
286
|
+
raise Fetion::NoUserException.new("Fetion Error: get contact info #{uri} with #{sipc_response}") unless SipcMessage::OK === sipc_response
|
273
287
|
|
274
288
|
@logger.info "fetion get contact info of #{uri} success"
|
275
289
|
end
|
276
290
|
|
277
291
|
def logout
|
292
|
+
@logger.info "fetion logout"
|
293
|
+
|
278
294
|
curl_exec(SipcMessage.logout(self))
|
279
295
|
response = pulse
|
280
296
|
|
281
297
|
# raise FetionException.new("Fetion Error: Logout error") unless response.is_a? Net::HTTPSuccess
|
298
|
+
@logger.info "fetion logout success"
|
282
299
|
end
|
283
300
|
|
284
|
-
def
|
301
|
+
def parse_ssic(response)
|
302
|
+
raise Fetion::LoginException.new('Fetion Error: Login failed.') unless Net::HTTPSuccess === response
|
285
303
|
raise Fetion::LoginException.new('Fetion Error: No ssic found in cookie.') unless response['set-cookie'] =~ /ssic=(.*);/
|
286
304
|
|
287
305
|
@ssic = $1
|
@@ -306,34 +324,54 @@ class Fetion
|
|
306
324
|
@logger.debug "user_id: " + @user_id
|
307
325
|
@logger.debug "sid: " + @sid
|
308
326
|
end
|
327
|
+
|
328
|
+
def parse_nonce(response)
|
329
|
+
raise FetionException.new("Fetion Error: Register first error.") unless Net::HTTPSuccess === response
|
330
|
+
sipc_response = SipcMessage.sipc_response(response.body)
|
331
|
+
raise Fetion::RegisterException.new("Fetion Error: Register first should get unauthorized response with #{sipc_response}.") unless SipcMessage::Unauthoried === sipc_response
|
332
|
+
raise Fetion::NoNonceException.new("Fetion Error: No nonce found") unless response.body =~ /nonce="(.*?)",key="(.*?)",signature="(.*?)"/
|
333
|
+
|
334
|
+
@nonce = $1
|
335
|
+
@key = $2
|
336
|
+
@signature = $3
|
337
|
+
@response = calc_response
|
338
|
+
|
339
|
+
@logger.debug "nonce: #{@nonce}"
|
340
|
+
@logger.debug "key: #{@key}"
|
341
|
+
@logger.debug "signature: #{@signature}"
|
342
|
+
@logger.debug "response: #{@response}"
|
343
|
+
end
|
309
344
|
|
310
|
-
def parse_info(
|
311
|
-
|
345
|
+
def parse_info(response)
|
346
|
+
raise Fetion::FetionException.new("Fetion Error: Register second error.") unless Net::HTTPSuccess === response
|
347
|
+
sipc_response = SipcMessage.sipc_response(response.body)
|
348
|
+
raise Fetion::RegisterException.new("Fetion Error: Register second error with #{sipc_response}.") unless SipcMessage::OK === sipc_response
|
349
|
+
|
350
|
+
response.body.scan(%r{<results>.*?</results>}).each do |results|
|
312
351
|
doc = Nokogiri::XML(results)
|
313
352
|
personal = doc.root.xpath("/results/user-info/personal").first
|
314
353
|
@nickname = personal['nickname']
|
315
|
-
end
|
316
|
-
|
317
|
-
@logger.debug "nickname: #@nickname"
|
318
|
-
end
|
319
|
-
|
320
|
-
def parse_buddies(response_body)
|
321
|
-
response_body.scan(%r{<results>.*?</results>}).each do |results|
|
322
|
-
doc = Nokogiri::XML(results)
|
323
354
|
doc.root.xpath("/results//buddies/b").each do |buddy|
|
324
355
|
@buddies << {:uri => buddy["u"]}
|
325
356
|
end
|
326
357
|
end
|
358
|
+
|
359
|
+
@logger.debug "nickname: #@nickname"
|
327
360
|
@logger.debug "buddies: #{@buddies.inspect}"
|
328
361
|
end
|
329
362
|
|
330
|
-
def parse_contacts(
|
331
|
-
|
363
|
+
def parse_contacts(response)
|
364
|
+
raise FetionException.new('Fetion Error: get contacts error.') unless Net::HTTPSuccess === response
|
365
|
+
sipc_response = SipcMessage.sipc_response(response.body)
|
366
|
+
raise Fetion::GetContactsException.new("Fetion Error: get contacts failed with #{sipc_response}.") unless Net::HTTPSuccess === response and SipcMessage::OK === sipc_response
|
367
|
+
|
368
|
+
response.body.scan(%r{<events>.*?</events>}).each do |results|
|
332
369
|
doc = Nokogiri::XML(results)
|
333
370
|
doc.root.xpath("/events//c/p").each do |person|
|
334
371
|
@contacts << Contact.new(person) if person['sid']
|
335
372
|
end
|
336
373
|
end
|
374
|
+
|
337
375
|
@logger.debug "contacts: #{@contacts.inspect}"
|
338
376
|
end
|
339
377
|
|
@@ -388,30 +426,6 @@ class Fetion
|
|
388
426
|
def self?(mobile_or_sid)
|
389
427
|
mobile_or_sid == @mobile_no or mobile_or_sid == @sid
|
390
428
|
end
|
391
|
-
|
392
|
-
[:login, :register, :get_contacts, :logout].each do |method|
|
393
|
-
class_eval <<-EOF
|
394
|
-
alias_method :origin_#{method}, :#{method}
|
395
|
-
|
396
|
-
def #{method}
|
397
|
-
@logger.info "fetion #{method.to_s.gsub(/_/, ' ')}"
|
398
|
-
origin_#{method}
|
399
|
-
@logger.info "fetion #{method.to_s.gsub(/_/, ' ')} success"
|
400
|
-
end
|
401
|
-
EOF
|
402
|
-
end
|
403
|
-
|
404
|
-
[:register_first, :register_second].each do |method|
|
405
|
-
class_eval <<-EOF
|
406
|
-
alias_method :origin_#{method}, :#{method}
|
407
|
-
|
408
|
-
def #{method}
|
409
|
-
@logger.debug "fetion #{method.to_s.gsub(/_/, ' ')}"
|
410
|
-
origin_#{method}
|
411
|
-
@logger.debug "fetion #{method.to_s.gsub(/_/, ' ')} success"
|
412
|
-
end
|
413
|
-
EOF
|
414
|
-
end
|
415
429
|
end
|
416
430
|
|
417
431
|
class FetionException < Exception; end
|
@@ -422,4 +436,5 @@ class Fetion::SendSmsException < FetionException; end
|
|
422
436
|
class Fetion::SendMsgException < FetionException; end
|
423
437
|
class Fetion::SetScheduleSmsException < FetionException; end
|
424
438
|
class Fetion::AddBuddyException < FetionException; end
|
439
|
+
class Fetion::GetContactsException < FetionException; end
|
425
440
|
class Fetion::NoUserException < FetionException; end
|
data/lib/rfetion/sipc_message.rb
CHANGED
@@ -34,8 +34,8 @@ class SipcMessage
|
|
34
34
|
sipc_create(:command => 'M', :F => fetion.sid, :I => fetion.next_call, :Q => '1 M', :T => receiver, :N => 'SendCatSMS', :body => content)
|
35
35
|
end
|
36
36
|
|
37
|
-
def self.
|
38
|
-
sipc_create(:command => 'M', :F => fetion.sid, :I => fetion.next_call, :Q => '
|
37
|
+
def self.send_cat_msg(fetion, receiver, content)
|
38
|
+
sipc_create(:command => 'M', :F => fetion.sid, :I => fetion.next_call, :Q => '2 M', :T => receiver, :K => 'SaveHistory', :N => 'CatMsg', :body => content)
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.set_schedule_sms(fetion, receivers, content, time)
|
@@ -49,8 +49,8 @@ class SipcMessage
|
|
49
49
|
sipc_create(:command => 'S', :F => fetion.sid, :I => fetion.next_call, :Q => '1 S', :N => 'AddBuddyV4', :body => body)
|
50
50
|
end
|
51
51
|
|
52
|
-
def self.get_contact_info(fetion,
|
53
|
-
body = %Q|<args><contact uri="
|
52
|
+
def self.get_contact_info(fetion, uri)
|
53
|
+
body = %Q|<args><contact uri="#{uri}" /></args>|
|
54
54
|
sipc_create(:command => 'S', :F => fetion.sid, :I => fetion.next_call, :Q => '1 S', :N => 'GetContactInfoV4', :body => body)
|
55
55
|
end
|
56
56
|
|
@@ -66,7 +66,7 @@ class SipcMessage
|
|
66
66
|
body = options.delete(:body)
|
67
67
|
with_l = options.delete(:with_l)
|
68
68
|
|
69
|
-
sorted_key = [:F, :I, :Q, :CN, :CL, :A, :AK, :X, :T, :
|
69
|
+
sorted_key = [:F, :I, :Q, :CN, :CL, :A, :AK, :X, :T, :K, :N, :SV]
|
70
70
|
sipc = "#{options.delete(:command)} fetion.com.cn SIP-C/4.0\r\n"
|
71
71
|
sorted_key.each {|k| sipc += "#{k}: #{options[k]}\r\n" if options[k]}
|
72
72
|
sipc += "L: #{body == '' ? 4 : body.size}\r\n" if with_l
|
@@ -75,8 +75,10 @@ class SipcMessage
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def self.sipc_response(http_response_body)
|
78
|
-
sipc, code, message = http_response_body.
|
78
|
+
sipc, code, message = http_response_body.split(/(\r)?\n/).first.split(' ')
|
79
79
|
RESPONSES[code.to_i].new(code, message)
|
80
|
+
rescue NoMethodError
|
81
|
+
raise FetionException.new("Fetion error: No response to #{code} #{message}")
|
80
82
|
end
|
81
83
|
|
82
84
|
class Response
|
@@ -93,11 +95,17 @@ class SipcMessage
|
|
93
95
|
end
|
94
96
|
|
95
97
|
class OK < Response; end
|
98
|
+
class Send < Response; end
|
99
|
+
class Bad < Response; end
|
100
|
+
class Unauthoried < Response; end
|
96
101
|
class NotFound < Response; end
|
97
102
|
class ExtentionRequired < Response; end
|
98
103
|
|
99
104
|
RESPONSES = {
|
100
105
|
200 => SipcMessage::OK,
|
106
|
+
280 => SipcMessage::Send,
|
107
|
+
400 => SipcMessage::Bad,
|
108
|
+
401 => SipcMessage::Unauthoried,
|
101
109
|
404 => SipcMessage::NotFound,
|
102
110
|
421 => SipcMessage::ExtentionRequired
|
103
111
|
}
|
data/rfetion.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rfetion}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Richard Huang"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-10}
|
13
13
|
s.description = %q{rfetion is a ruby gem for China Mobile fetion service that you can send SMS free.}
|
14
14
|
s.email = %q{flyerhzm@gmail.com}
|
15
15
|
s.executables = ["rfetion", "rfetion"]
|
data/spec/rfetion/fetion_spec.rb
CHANGED
@@ -57,10 +57,10 @@ describe SipcMessage do
|
|
57
57
|
SipcMessage.send_cat_sms(@fetion, 'sip:730020377@fetion.com.cn;p=6907', 'test').should == sipc_message
|
58
58
|
end
|
59
59
|
|
60
|
-
it "should send msg" do
|
60
|
+
it "should send cat msg" do
|
61
61
|
@fetion.call = 8
|
62
|
-
sipc_message = %Q|M fetion.com.cn SIP-C/4.0\r\nF: 730020377\r\nI: 9\r\nQ:
|
63
|
-
SipcMessage.
|
62
|
+
sipc_message = %Q|M fetion.com.cn SIP-C/4.0\r\nF: 730020377\r\nI: 9\r\nQ: 2 M\r\nT: sip:638993408@fetion.com.cn;p=2242\r\nK: SaveHistory\r\nN: CatMsg\r\nL: 4\r\n\r\ntestSIPP|
|
63
|
+
SipcMessage.send_cat_msg(@fetion, 'sip:638993408@fetion.com.cn;p=2242', 'test').should == sipc_message
|
64
64
|
end
|
65
65
|
|
66
66
|
it "should set schedule sms" do
|
@@ -72,7 +72,7 @@ describe SipcMessage do
|
|
72
72
|
it "should get contact info" do
|
73
73
|
@fetion.call = 10
|
74
74
|
sipc_message = %Q|S fetion.com.cn SIP-C/4.0\r\nF: 730020377\r\nI: 11\r\nQ: 1 S\r\nN: GetContactInfoV4\r\nL: 46\r\n\r\n<args><contact uri="tel:15800681507" /></args>SIPP|
|
75
|
-
SipcMessage.get_contact_info(@fetion, 15800681507).should == sipc_message
|
75
|
+
SipcMessage.get_contact_info(@fetion, "tel:15800681507").should == sipc_message
|
76
76
|
end
|
77
77
|
|
78
78
|
it "should add buddy" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rfetion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-05-
|
12
|
+
date: 2010-05-10 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|