ruby_ucp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,6 +1,12 @@
1
1
  ============ RELEASED ==============
2
2
 
3
- = 0.1.0
3
+ = 0.2.0 (2011-02-06)
4
+ * miscelaneous cleanup
5
+ * basic documentation of methods in Ucp::Util::UCP
6
+ * fixed issues #1, #2, #3, #4, #6, #7
7
+ * added authentication handler/callback in Ucp::Util::UcpServer
8
+
9
+ = 0.1.0 (2011-01-16)
4
10
  * first public version of "ruby_ucp" gem
5
11
  * multiple PDUs support (operations 30,31,51,52,53,54,55,56,57,58,60,61)
6
12
  * added a class to implement an UCP server (e.g. for simulating a SMSC)
@@ -36,7 +42,3 @@
36
42
 
37
43
  = 0.3.0
38
44
  * methods documentation
39
-
40
- = 0.2.0
41
- * miscelaneous cleanup
42
-
data/README CHANGED
@@ -2,9 +2,64 @@
2
2
 
3
3
  A pure Ruby implementation of the EMI/UCP protocol v4.6 that is used when communicating
4
4
  with a SMSC.
5
- It allows sending SMS, text and binary.
6
- It supports also 7bit and 16bit encoded SMS.
5
+ Please consult up-to-date information in ruby_ucp's wiki: https://github.com/bitcoder/ruby_ucp/wiki.
6
+ Official releases can be obtained directly from RubyGems: https://rubygems.org/gems/ruby_ucp.
7
+ The following information may not be up-to-date; it is here just for quick access. See the wiki site.
7
8
 
8
- Have fun, this was just the first import, I will detail all in the upcoming versions.
9
+ Sergio Freire <sergio.freire at gmail.com>
10
+
11
+
12
+ Introduction
13
+ ============
14
+
15
+ About “ruby_ucp”
16
+
17
+ “ruby_ucp” is a pure Ruby library implementation of the EMI/UCP v.4.6 specification/protocol used by Large Accounts (e.g. applications) to communicate with SMSC’s, in order to send and receive short messages (“SMS”).
18
+ It is licensed under LGPL v2.1, so feel free to use it and contribute with your code or feedback in order to improve it.
19
+ The main focus of this library is the correct encoding/decoding of UCP PDUs. By combining low-level with helper methods, the user has full control of the built PDUs, all with ease.
20
+ Besides this, two classes are given: one for an UCP client and another for an UCP server. These classes are not perfect (e.g. they dont implement states) but may be used in most scenarios, specially the client, and serve as inspiration to build other ones.
21
+
22
+ The gem is available for download directly from the RubyGems repository, and is named ruby_ucp.
23
+ The UCP specification itself: EMI/UCP v4.6.
24
+ Some local info about UCP PDUs: https://github.com/bitcoder/ruby_ucp/wiki/UCP-PDUs.
25
+ Some local info on SMS alphabets/encodings: https://github.com/bitcoder/ruby_ucp/wiki/SMS-Alphabets.
26
+
27
+ Features
28
+ ========
29
+
30
+ Currently, it supports:
31
+
32
+ - encoding/decoding most UCP pdu’s: 01,30,31,51,52,53,54,55,56,57,58,60 and 61
33
+ - direct access to UCP pdu fields
34
+ - automatic checksum/length calculation
35
+ - instantiate an UCP pdu object from a given string
36
+ - helper methods within pdu’s, to easily build “submit messages” (AO)
37
+ - support alphanumeric originators
38
+ - en/decoding of 7bit GSM default alphabet text messages for basic text encoding
39
+ - en/decoding of 16bit (UCS2) messages for full character support
40
+ - simple UCP client (MULA), with authentication support
41
+ - simple UCP server (e.g. for simulating a SMSC or a LA application working in UCP SILA mode)
42
+ - automatic create multiple concatenated messages, for a given message text
43
+ - extern, smarter and more correct UCP clients/servers may be implemented using just the UCP pdu encoding/decoding features
44
+
45
+ Soon:
46
+
47
+ - automatic text encoding selection (7bit vs 16bit), for optimum concatenated message creation (reduce the number of SM parts; use only UCS-2 if necessary). (now 7bit is forced in make_multi_ucps() method)
48
+
49
+
50
+ Not so good features :)
51
+ ========================
52
+
53
+ - the library is thought for correctness, not performance (you should not find a problem though)
54
+ - the provided UCP client is synchronous; it does not have a state machine in order to handle UCP windowing features
55
+ - the provided UCP server is also synchronous; it does not support UCP windowing
56
+ - no Ruby v1.9.x support (it would require rewriting sensible parts due to encoding issues and string handling)
57
+ - unitary tests unspecified, yet
58
+ - documentation lacking, yet
59
+
60
+ Requirements
61
+ ============
62
+
63
+ Ruby v1.8.6 or v.1.8.7. No v1.9.x support!
64
+ (tested with Ubuntu 9.10, Redhat AS 5.x)
9
65
 
10
- Sergio Freire
data/Rakefile CHANGED
@@ -67,7 +67,7 @@ end
67
67
 
68
68
  spec = Gem::Specification.new do |s|
69
69
  s.name = 'ruby_ucp'
70
- s.version = '0.1.0'
70
+ s.version = '0.2.0'
71
71
  s.has_rdoc = true
72
72
  s.extra_rdoc_files = ['README', 'LICENSE']
73
73
  s.summary = 'EMI/UCP protocol library'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/lib/ruby_ucp.rb CHANGED
@@ -21,22 +21,48 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
21
  $:.unshift(File.dirname(__FILE__))
22
22
 
23
23
  require "ucp/base.rb"
24
+ require "ucp/pdu/base.rb"
24
25
  require "ucp/pdu/ucpmessage.rb"
26
+ require "ucp/pdu/ucp_operation.rb"
27
+ require "ucp/pdu/ucp_result.rb"
25
28
  require "ucp/pdu/ucp01.rb"
29
+ require "ucp/pdu/ucp01_operation.rb"
30
+ require "ucp/pdu/ucp01_result.rb"
26
31
  require "ucp/pdu/ucp30.rb"
32
+ require "ucp/pdu/ucp30_operation.rb"
33
+ require "ucp/pdu/ucp30_result.rb"
27
34
  require "ucp/pdu/ucp31.rb"
35
+ require "ucp/pdu/ucp31_operation.rb"
36
+ require "ucp/pdu/ucp31_result.rb"
28
37
  require "ucp/pdu/ucp5x.rb"
38
+ require "ucp/pdu/ucp51_result.rb"
39
+ require "ucp/pdu/ucp51_operation.rb"
40
+ require "ucp/pdu/ucp52_operation.rb"
41
+ require "ucp/pdu/ucp52_result.rb"
42
+ require "ucp/pdu/ucp53_operation.rb"
43
+ require "ucp/pdu/ucp53_result.rb"
44
+ require "ucp/pdu/ucp54_operation.rb"
45
+ require "ucp/pdu/ucp54_result.rb"
46
+ require "ucp/pdu/ucp55_operation.rb"
47
+ require "ucp/pdu/ucp55_result.rb"
48
+ require "ucp/pdu/ucp56_operation.rb"
49
+ require "ucp/pdu/ucp56_result.rb"
50
+ require "ucp/pdu/ucp57_operation.rb"
51
+ require "ucp/pdu/ucp57_result.rb"
52
+ require "ucp/pdu/ucp58_operation.rb"
53
+ require "ucp/pdu/ucp58_result.rb"
29
54
  require "ucp/pdu/ucp60.rb"
55
+ require "ucp/pdu/ucp60_operation.rb"
56
+ require "ucp/pdu/ucp60_result.rb"
30
57
  require "ucp/pdu/ucp61.rb"
58
+ require "ucp/pdu/ucp61_result.rb"
59
+ require "ucp/pdu/ucp61_operation.rb"
31
60
  require "ucp/util/base.rb"
61
+ require "ucp/util/packed_msg.rb"
62
+ require "ucp/util/gsm_packed_msg.rb"
63
+ require "ucp/util/ucp_client.rb"
64
+ require "ucp/util/sms_request.rb"
65
+ require "ucp/util/ucp.rb"
66
+ require "ucp/util/ucp_server.rb"
67
+ require "ucp/util/ucs2_packed_msg.rb"
32
68
 
33
-
34
- # Load all YCP PDUs
35
- Dir.glob(File.join(File.dirname(__FILE__), 'ucp', 'pdu', '*.rb')) do |f|
36
- require f unless f.match('ucpmessage.rb$')
37
- end
38
-
39
- # Load all auxiliary classes
40
- Dir.glob(File.join(File.dirname(__FILE__), 'ucp', 'util', '*.rb')) do |f|
41
- require f unless f.match('base.rb$')
42
- end
data/lib/samples/main.rb CHANGED
@@ -35,6 +35,12 @@ def handle_me(smsreq)
35
35
  puts "handle_me [#{smsreq.source_ip}:#{smsreq.source_port}] (#{smsreq.originator},#{smsreq.recipient}) (#{smsreq.part_nr}/#{smsreq.total_parts}): #{smsreq.text}\n"
36
36
  end
37
37
 
38
+ def auth_handler(authreq)
39
+ puts "auth_handler [#{authreq.source_ip}:#{authreq.source_port}] (#{authreq.account},#{authreq.password})\n"
40
+ return true
41
+ end
42
+
43
+
38
44
  #ucp=UCP.parse_str("*00/00113/O/51/961234567/1234/////////////////4/120/B49AED86CBC162B219AD66BBE17230//////////0106050003450202///90#")
39
45
  #puts "UCP: #{ucp.to_s}"
40
46
  #exit
@@ -89,7 +95,7 @@ puts ucp.to_s
89
95
 
90
96
  port=12009
91
97
  server=UcpServer.new(method(:handle_me),port)
92
-
98
+ server.set_authentication_handler(method(:auth_handler))
93
99
 
94
100
  cliente=UcpClient.new("localhost",port,{:login=>8006,:password=>"timor"})
95
101
  #sent=cliente.send_message(1234,961234567,"1234567890"*17+"ola custa 1€ sabias?")
@@ -116,14 +122,8 @@ puts ucp.to_s
116
122
 
117
123
 
118
124
  puts UCP.pack7bits("€")
119
- #puts UCP.packucs2("ola")
120
125
  puts UCP.decode7bitgsm(UCP.pack7bits("1234567890"*17))
121
- gsmparts= UCP.pack7bits2("1234567890"*17,134)
122
- puts "septets: #{gsmparts.required_septets} ; unenc: #{gsmparts.unencoded}"
123
- gsmparts= UCP.multi_pack7bits2("1234567890"*17,134)
124
- gsmparts.each { |gsmpart|
125
- puts "part: #{gsmpart.unencoded}"
126
- }
126
+
127
127
 
128
128
  UCP.make_multi_ucps(1235,961234568,"1234567890"*17)
129
129
 
@@ -45,7 +45,7 @@ class Ucp::Pdu::Ucp51Result < Ucp::Pdu::UCP5x
45
45
 
46
46
 
47
47
  def ack(mvp="",sm="")
48
- @fields=[:ack,:sm]
48
+ @fields=[:ack,:mvp,:sm]
49
49
  @h[:ack]="A"
50
50
  @h[:mvp]=mvp
51
51
  @h[:sm]=sm
data/lib/ucp/pdu/ucp60.rb CHANGED
@@ -18,11 +18,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
  =end
19
19
 
20
20
 
21
- class Ucp::Pdu::UCP61 < Ucp::Pdu::UCPMessage
21
+ class Ucp::Pdu::UCP60 < Ucp::Pdu::UCPMessage
22
22
 
23
23
  def initialize()
24
24
  super()
25
- @operation="61"
25
+ @operation="60"
26
26
  end
27
27
 
28
28
 
@@ -51,7 +51,7 @@ class Ucp::Pdu::Ucp60Operation < Ucp::Pdu::UCP60
51
51
  #super()
52
52
  #@operation_type="O"
53
53
 
54
- @h={:oadc=>originator, :pwd=>UCP.ascii2ira(password), :vers=>"0100", :styp=>"1", :oton=>"6",:onpi=>"5"}
54
+ @h={:oadc=>originator, :pwd=>UCP.ascii2ira(password).encoded, :vers=>"0100", :styp=>"1", :oton=>"6",:onpi=>"5"}
55
55
  @h=@h.merge ucpfields
56
56
  end
57
57
 
data/lib/ucp/pdu/ucp61.rb CHANGED
@@ -19,11 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
 
20
20
 
21
21
 
22
- class Ucp::Pdu::UCP60 < Ucp::Pdu::UCPMessage
22
+ class Ucp::Pdu::UCP61 < Ucp::Pdu::UCPMessage
23
23
 
24
24
  def initialize()
25
25
  super()
26
- @operation="60"
26
+ @operation="61"
27
27
  end
28
28
 
29
29
 
@@ -0,0 +1,32 @@
1
+ =begin
2
+ Ruby library implementation of EMI/UCP protocol v4.6 for SMS
3
+ Copyright (C) 2011, Sergio Freire <sergio.freire@gmail.com>
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ =end
19
+
20
+
21
+ class Ucp::Util::AuthRequest
22
+
23
+ attr_reader :source_ip, :source_port, :account, :password
24
+
25
+ def initialize(account,password,source_ip=nil,source_port=nil)
26
+ @source_ip=source_ip
27
+ @source_port=source_port
28
+ @account=account
29
+ @password=password
30
+ end
31
+
32
+ end
data/lib/ucp/util/ucp.rb CHANGED
@@ -32,18 +32,21 @@ class Ucp::Util::UCP
32
32
  @extensiontable={}
33
33
  @extensiontable_rev={}
34
34
 
35
+ # add a character mapping to the 7bit GSM default alphabet
35
36
  :private
36
37
  def self.add_char(value,char)
37
38
  @gsmtable[char]=value
38
39
  @asciitable[value]=char
39
40
  end
40
41
 
42
+ # add an extesion character to the 7bit GSM default alphabet
41
43
  :private
42
44
  def self.add_extchar(value,char)
43
45
  @extensiontable[char]=value
44
46
  @extensiontable_rev[value]=char
45
47
  end
46
48
 
49
+ # build/initialize the GSM default alphabet mapping tables
47
50
  def self.initialize_ascii2ira
48
51
 
49
52
  ('A'..'Z').each { |c|
@@ -104,10 +107,6 @@ class Ucp::Util::UCP
104
107
  add_char(0x3E,">")
105
108
  add_char(0x3F,"?")
106
109
 
107
-
108
-
109
- #@extensiontable["€"]=0x65
110
- #@extensiontable_rev[0x65]="€"
111
110
  add_extchar(0x65,"€")
112
111
  add_extchar(0x14,"^")
113
112
  add_extchar(0x28,"{")
@@ -117,13 +116,11 @@ class Ucp::Util::UCP
117
116
  add_extchar(0x3D,"~")
118
117
  add_extchar(0x3E,"]")
119
118
  add_extchar(0x40,"|")
120
-
121
-
122
-
123
119
  end
124
120
 
121
+ # pack a given text string in 7bit GSM default alphabet
122
+ # return it as an hexadecimal string
125
123
  def self.pack7bits(str)
126
- #UCP.initialize_ascii2ira
127
124
 
128
125
  s=""
129
126
  str.each_char { |c|
@@ -178,105 +175,9 @@ class Ucp::Util::UCP
178
175
  i-=8
179
176
  end
180
177
 
181
-
182
-
183
178
  return hexstr
184
179
  end
185
180
 
186
-
187
- def self.pack7bits2(str,max_bytes)
188
-
189
- tainted=false
190
- s=""
191
- idx=0
192
- str.each_char { |c|
193
-
194
- ext=""
195
- gsmchar=@gsmtable[c]
196
-
197
- if gsmchar.nil?
198
- if @extensiontable.has_key?(c)
199
- ext="0011011" # 1B
200
- gsmchar=@extensiontable[c]
201
- else
202
- gsmchar=@gsmtable[" "]
203
- tainted=true
204
- end
205
- end
206
-
207
- #gsmchar=c[0]
208
- #puts "#{c} : #{gsmchar} xxx"
209
- #gsmchar=@gsmtable[" "] if gsmchar.nil?
210
-
211
- tmp= gsmchar.to_s(2)
212
-
213
- remainder=tmp.length%7
214
- if remainder!=0
215
- nfillbits=7-remainder
216
- tmp="0"*nfillbits+tmp
217
- end
218
-
219
- # if adding this character exceeds the max allowed nr of bytes, break
220
- if ((tmp+ext+s).length*1.0/8).ceil>max_bytes
221
- break
222
- end
223
-
224
- s=tmp+ext+s
225
-
226
- # if reached the max allowed nr of bytes, break
227
- if (s.length*1.0/8).ceil==max_bytes
228
- idx+=1
229
- break
230
- end
231
-
232
- idx+=1
233
- }
234
-
235
-
236
- required_septets=s.length/7
237
- remainder=s.length%8
238
- if remainder!=0
239
- nfillbits=8-remainder
240
- s="0"*nfillbits+s
241
- end
242
-
243
- #puts "S: #{s}"
244
-
245
- i=s.length-8
246
- hexstr=""
247
- while i>=0
248
- c=s[i,8]
249
-
250
- tmp=c.to_i(2).to_s(16).upcase
251
- if tmp.length==1
252
- tmp="0"+tmp
253
- end
254
- # puts tmp
255
- hexstr+=tmp
256
- i-=8
257
- end
258
-
259
-
260
- return GsmPackedMsg.new(hexstr,str[0,idx],idx,required_septets,tainted)
261
- end
262
-
263
- # @deprecated remove because unecessary
264
- def self.multi_pack7bits(str,max_bytes)
265
- msgparts=[]
266
- idx=0
267
- while true
268
- packedmsg=UCP.pack7bits2(str[idx..-1],max_bytes)
269
- msgparts<<packedmsg
270
- if idx+packedmsg.chars<str.length
271
- idx+=packedmsg.chars
272
- else
273
- break
274
- end
275
- end
276
- return msgparts
277
- end
278
-
279
-
280
181
  # convert standard string to IRA encoded hexstring
281
182
  def self.ascii2ira(str,max_bytes=nil)
282
183
 
@@ -323,7 +224,8 @@ class Ucp::Util::UCP
323
224
  return GsmPackedMsg.new(s,UCP.utf8_substr(str,0,idx-1),idx,required_septets,tainted)
324
225
  end
325
226
 
326
-
227
+ # a dirty UTF-8 substring implementation
228
+ # returns a substring of an UTF-8 encoded string, given the string, start end end characters
327
229
  def self.utf8_substr(str,idxs,idxe=nil)
328
230
  s=""
329
231
  i=0
@@ -335,6 +237,8 @@ class Ucp::Util::UCP
335
237
  return s
336
238
  end
337
239
 
240
+ # given a text, automatically split it if necessary and encode each part text in (IRA5) GSM default alphabet
241
+ # returns an array of IRA5 hexadecimal strings, one per part
338
242
  def self.multi_ascii2ira(str,max_bytes)
339
243
  msgparts=[]
340
244
  idx=0
@@ -368,7 +272,8 @@ class Ucp::Util::UCP
368
272
  return msgparts
369
273
  end
370
274
 
371
-
275
+ # convert a given UTF-8 string to "UCS-2"
276
+ # returns an object representing the UCS-2 packed message
372
277
  def self.str2ucs2(str,max_bytes=nil)
373
278
  hexstr=""
374
279
  str=Iconv.iconv("utf-16be", "utf-8", str).first
@@ -384,6 +289,8 @@ class Ucp::Util::UCP
384
289
  return Ucs2PackedMsg.new(hexstr,UCP.utf8_substr(str,0,i-1),i/2,i)
385
290
  end
386
291
 
292
+ # given a text, automatically split it if necessary and encode each part text in UCS-2
293
+ # returns an array of UCS-2 hexadecimal strings, one per part
387
294
  def self.multi_ucs2(str,max_bytes)
388
295
  msgparts=[]
389
296
  idx=0
@@ -415,8 +322,9 @@ class Ucp::Util::UCP
415
322
  return msgparts
416
323
  end
417
324
 
418
-
419
-
325
+ # automatically build the necessary UCP pdu's in order to encode a given submit message
326
+ # returns an array of UCP51 pdu's
327
+ # (for now, it does NOT select automatically the SM encoding; it forces/assumes 7bit GSM)
420
328
  def self.make_multi_ucps(originator,recipient,message,mr=0)
421
329
  ucps=[]
422
330
 
@@ -459,25 +367,8 @@ class Ucp::Util::UCP
459
367
  return ucps
460
368
  end
461
369
 
462
-
463
-
464
- def self.packucs2(str)
465
- hexstr=""
466
- s= Iconv.iconv("ucs-2be", "utf-8", str).first
467
- s.each_char{ |c|
468
-
469
- tmp=c[0].to_s(16).upcase
470
- if tmp.length==1
471
- tmp="0"+tmp
472
- end
473
-
474
- hexstr+=tmp
475
-
476
- }
477
- #puts s
478
- return hexstr
479
- end
480
-
370
+ # return an encoded originator alphanumeric address
371
+ # to be used in the "oadc" field, if alphanumeric
481
372
  def self.packoadc(oa)
482
373
  packedoa=UCP.pack7bits(oa)
483
374
 
@@ -493,6 +384,7 @@ class Ucp::Util::UCP
493
384
  return tmp+packedoa
494
385
  end
495
386
 
387
+ # convert an hexadecimal string to a binary string
496
388
  def self.hextobin(hstr)
497
389
  bstr=""
498
390
  i=0
@@ -528,12 +420,8 @@ class Ucp::Util::UCP
528
420
  return bstr
529
421
  end
530
422
 
531
-
532
- def self.decode7bitgsm(str)
533
-
534
- # retirar isto!!
535
- #initialize_ascii2ira
536
-
423
+ # decode a 7bit packed GSM default alphabet hexstring
424
+ def self.decode7bitgsm(str)
537
425
  unencoded=""
538
426
  #puts "#{str}"
539
427
  bstr=UCP.hextobin_reversed(str)
@@ -582,7 +470,7 @@ class Ucp::Util::UCP
582
470
  end
583
471
 
584
472
 
585
-
473
+ # decode an IRA5 hexadecimal represented string to string
586
474
  def self.decode_ira(str)
587
475
  unencoded=""
588
476
 
@@ -611,6 +499,7 @@ class Ucp::Util::UCP
611
499
 
612
500
 
613
501
 
502
+ # convert an integer to an hex string, two (or given) nibbles wide
614
503
  def self.int2hex(i,max_nibbles=2)
615
504
  tmp=i.to_s(16).upcase
616
505
  if tmp.length%2!=0
@@ -627,7 +516,7 @@ class Ucp::Util::UCP
627
516
 
628
517
 
629
518
 
630
- # usado para construir um UCP duma string
519
+ # given a UCP pdu string, return a UCP pdu object
631
520
  def self.parse_str(ustr)
632
521
  #puts "parse_str(#{ustr})"
633
522
 
@@ -759,21 +648,17 @@ class Ucp::Util::UCP
759
648
 
760
649
 
761
650
 
762
- # usado para construir uma resposta UCP a partir dum UCP
651
+ # given an UCP pdu object, build a corresponding result pdu
763
652
  def self.make_ucp_result(ucp)
764
- puts "make_ucp_result(#{ucp.to_s})"
653
+ #puts "make_ucp_result(#{ucp.to_s})"
765
654
 
766
655
  if ucp.nil?
767
656
  return nil
768
657
  end
769
658
 
770
659
  trn=ucp.trn
771
- #puts "#{trn}"
772
- # length
773
660
  operation_type=ucp.operation_type
774
- #puts "#{operation_type}"
775
661
  operation=ucp.operation
776
- #puts "#{operation}"
777
662
 
778
663
  ucpmsg=nil
779
664
 
@@ -811,12 +696,14 @@ class Ucp::Util::UCP
811
696
  return ucpmsg
812
697
  end
813
698
 
699
+ # convert hexadecimal represent string to string, assuming a byte per character
814
700
  def self.hex2str(hexstr)
815
701
  str=""
816
702
  hexstr.scan(/../).each { | tuple | str+=tuple.hex.chr }
817
703
  return str
818
704
  end
819
705
 
706
+ # given an UCP pdu object, decode message field
820
707
  def self.decode_ucp_msg(ucp)
821
708
  text=nil
822
709
  dcs=ucp.dcs.to_i(16)
@@ -828,7 +715,7 @@ class Ucp::Util::UCP
828
715
  else
829
716
 
830
717
  if ucp.operation.eql?("51") || ucp.operation.eql?("52") || ucp.operation.eql?("53")
831
- mt=ucp.get_field(:msg)
718
+ mt=ucp.get_field(:mt)
832
719
  if mt.eql?("2")
833
720
  # numeric message.. return it as it is
834
721
  text=ucp.get_field(:msg)
@@ -857,6 +744,7 @@ class Ucp::Util::UCP
857
744
  return text
858
745
  end
859
746
 
747
+ # given an UCP pdu object, decode the originator address
860
748
  def self.decode_ucp_oadc(ucp)
861
749
  otoa=nil
862
750
  oadc=ucp.get_field(:oadc)
@@ -19,16 +19,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
 
20
20
  require 'socket'
21
21
 
22
- class ClientQuitError < RuntimeError; end
23
-
24
- #class UcpServer
25
-
26
22
  include Ucp::Pdu
27
23
  include Ucp::Util
28
24
 
29
25
  class Ucp::Util::UcpServer
30
26
 
31
27
  @server=nil
28
+ @auth_handler=nil
32
29
 
33
30
  def initialize(handler,port,host=nil)
34
31
 
@@ -69,7 +66,6 @@ class Ucp::Util::UcpServer
69
66
 
70
67
  begin
71
68
  while line = s.gets(3.chr) # read a line at a time
72
- raise ClientQuitError if line =~ /^die\r?$/
73
69
 
74
70
  #puts "#{addr} [#{Time.now}]: #{line}"
75
71
 
@@ -83,23 +79,37 @@ class Ucp::Util::UcpServer
83
79
  smsreq=SmsRequest.new(UCP.decode_ucp_oadc(ucp),ucp.get_field(:adc),text,account,addr,port)
84
80
  smsreq.set_parts_info(ucp.message_ref, ucp.part_nr, ucp.total_parts)
85
81
  handler.call(smsreq)
82
+ elsif ucp.operation.eql?("60")
83
+ if !@auth_handler.nil?
84
+ authreq=AuthRequest.new(ucp.get_field(:oadc),UCP.decode_ira(ucp.get_field(:pwd)),addr,port)
85
+ auth_result=@auth_handler.call(authreq)
86
+ if !auth_result
87
+ reply_ucp=UCP.make_ucp_result(ucp)
88
+ reply_ucp.nack("01","authentication failed")
89
+ #puts "reply #{reply_ucp.to_s}"
90
+ s.print reply_ucp.to_s
91
+ puts "Ssent: #{reply_ucp.to_s}\n"
92
+ puts "*** #{name}:#{port} forced disconnected"
93
+ s.close # close socket
94
+ break
95
+ else
96
+ account=authreq.account
97
+ end
98
+ end
86
99
  end
87
100
 
88
101
  reply_ucp=UCP.make_ucp_result(ucp)
89
- #puts "bbbbbbbbbbbbb1"
90
102
  reply_ucp.ack("ok")
91
- #puts "bbbbbbbbbbbbb2"
103
+
92
104
  #puts "reply #{reply_ucp.to_s}"
93
105
  s.print reply_ucp.to_s
94
106
  puts "Ssent: #{reply_ucp.to_s}\n"
95
107
  end
96
- rescue ClientQuitError
97
- puts "*** #{name}:#{port} disconnected"
98
108
  ensure
109
+ puts "*** #{name}:#{port} disconnected/closed"
99
110
  s.close # close socket on error
100
111
  end
101
112
 
102
- puts "*** done with #{name}:#{port}"
103
113
  # end Thread
104
114
  end
105
115
 
@@ -117,6 +127,8 @@ class Ucp::Util::UcpServer
117
127
  @server.close
118
128
  end
119
129
 
120
-
130
+ def set_authentication_handler(handler)
131
+ @auth_handler=handler
132
+ end
121
133
 
122
134
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_ucp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sergio Freire
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-16 00:00:00 +00:00
18
+ date: 2011-02-06 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -74,6 +74,7 @@ files:
74
74
  - lib/ucp/pdu/ucp_operation.rb
75
75
  - lib/ucp/pdu/ucp_result.rb
76
76
  - lib/ucp/pdu/ucpmessage.rb
77
+ - lib/ucp/util/auth_request.rb
77
78
  - lib/ucp/util/base.rb
78
79
  - lib/ucp/util/gsm_packed_msg.rb
79
80
  - lib/ucp/util/packed_msg.rb