cimd 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +42 -0
- data/Guardfile +35 -0
- data/README.md +49 -0
- data/Rakefile +2 -0
- data/bin/cimd_cli.rb +70 -0
- data/cimd.gemspec +29 -0
- data/lib/cimd.rb +4 -0
- data/lib/cimd/version.rb +5 -0
- data/lib/cimd_constants.rb +91 -0
- data/lib/cimd_loop.rb +173 -0
- data/lib/cimd_messages.rb +56 -0
- data/lib/cimd_structures.rb +237 -0
- data/spec/lib/cimd_spec.rb +158 -0
- metadata +174 -0
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cimd (0.0.1)
|
5
|
+
eventmachine (>= 0.12)
|
6
|
+
thor
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
eventmachine (0.12.10)
|
13
|
+
ffi (1.0.11)
|
14
|
+
guard (1.3.2)
|
15
|
+
listen (>= 0.4.2)
|
16
|
+
thor (>= 0.14.6)
|
17
|
+
guard-rspec (1.2.1)
|
18
|
+
guard (>= 1.1)
|
19
|
+
listen (0.5.0)
|
20
|
+
rake (0.9.2.2)
|
21
|
+
rb-inotify (0.8.8)
|
22
|
+
ffi (>= 0.5.0)
|
23
|
+
rspec (2.6.0)
|
24
|
+
rspec-core (~> 2.6.0)
|
25
|
+
rspec-expectations (~> 2.6.0)
|
26
|
+
rspec-mocks (~> 2.6.0)
|
27
|
+
rspec-core (2.6.4)
|
28
|
+
rspec-expectations (2.6.0)
|
29
|
+
diff-lcs (~> 1.1.2)
|
30
|
+
rspec-mocks (2.6.0)
|
31
|
+
thor (0.16.0)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
cimd!
|
38
|
+
guard (>= 1.3)
|
39
|
+
guard-rspec (>= 1.2)
|
40
|
+
rake
|
41
|
+
rb-inotify (>= 0.8.8)
|
42
|
+
rspec
|
data/Guardfile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
#guard 'coffeescript', :input => 'app/assets/javascripts'
|
5
|
+
|
6
|
+
#guard 'livereload' do
|
7
|
+
#watch(%r{app/views/.+\.(erb|haml|slim)})
|
8
|
+
#watch(%r{app/helpers/.+\.rb})
|
9
|
+
#watch(%r{public/.+\.(css|js|html)})
|
10
|
+
#watch(%r{config/locales/.+\.yml})
|
11
|
+
## Rails Assets Pipeline
|
12
|
+
#watch(%r{(app|vendor)/assets/\w+/(.+\.(css|js|html)).*}) { |m| "/assets/#{m[2]}" }
|
13
|
+
#end
|
14
|
+
|
15
|
+
guard 'rspec', :version => 2 do
|
16
|
+
watch(%r{^spec/lib/.+_spec\.rb$})
|
17
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/cimd_spec.rb" }
|
18
|
+
#watch('spec/spec_helper.rb') { "spec" }
|
19
|
+
|
20
|
+
## Rails example
|
21
|
+
#watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
22
|
+
#watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
23
|
+
#watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
24
|
+
#watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
25
|
+
#watch('config/routes.rb') { "spec/routing" }
|
26
|
+
#watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
27
|
+
|
28
|
+
## Capybara request specs
|
29
|
+
#watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
30
|
+
|
31
|
+
## Turnip features and steps
|
32
|
+
#watch(%r{^spec/acceptance/(.+)\.feature$})
|
33
|
+
#watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
34
|
+
end
|
35
|
+
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
[![Dependency Status](https://gemnasium.com/musashimm/cimd.png)](https://gemnasium.com/musashimm/cimd)
|
2
|
+
[![Build Status](https://secure.travis-ci.org/musashimm/cimd.png)](http://travis-ci.org/musashimm/cimd)
|
3
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/musashimm/cimd)
|
4
|
+
|
5
|
+
CIMD
|
6
|
+
======
|
7
|
+
|
8
|
+
Overview
|
9
|
+
--------
|
10
|
+
|
11
|
+
Classes and binaries to handle SMS Cimd protocol.
|
12
|
+
|
13
|
+
Usage
|
14
|
+
-----
|
15
|
+
|
16
|
+
### cimd_cli.rb receivesms ###
|
17
|
+
`cimd_cli.rb receivesms` receives smses endlessly. If You want to stop reciving just press ^C.
|
18
|
+
|
19
|
+
cimd_cli.rb receivesms --msisdn=MSISDN --password=PASSWORD --server=SERVER --user-identity=USER_IDENTITY
|
20
|
+
|
21
|
+
Options:
|
22
|
+
--server=SERVER # Address of SMSC server (can be DNS name)
|
23
|
+
[--port=PORT] # Port number for CIMD protocol
|
24
|
+
# Default: 9971
|
25
|
+
--user-identity=USER_IDENTITY # Username of CIMD account
|
26
|
+
--password=PASSWORD # Password for CIMD account USERNAME
|
27
|
+
[--message=MESSAGE] # Message to be send
|
28
|
+
# Default: SMS test message
|
29
|
+
--msisdn=MSISDN # MSISDN number to be send
|
30
|
+
[--alpha-orig-address=ALPHA_ORIG_ADDRESS] # Identity of sender
|
31
|
+
# Default: Sms Service
|
32
|
+
### cimd_cli.rb sendsms ###
|
33
|
+
`cimd_cli.rb sendsms` sends text SMS to MSISDN number
|
34
|
+
|
35
|
+
cimd_cli.rb sendsms --msisdn=MSISDN --password=PASSWORD --server=SERVER --user-identity=USER_IDENTITY
|
36
|
+
|
37
|
+
Options:
|
38
|
+
--server=SERVER # Address of SMSC server (can be DNS name)
|
39
|
+
[--port=PORT] # Port number for CIMD protocol
|
40
|
+
# Default: 9971
|
41
|
+
--user-identity=USER_IDENTITY # Username of CIMD account
|
42
|
+
--password=PASSWORD # Password for CIMD account USERNAME
|
43
|
+
[--message=MESSAGE] # Message to be send
|
44
|
+
# Default: SMS test message
|
45
|
+
--msisdn=MSISDN # MSISDN number to be send
|
46
|
+
[--alpha-orig-address=ALPHA_ORIG_ADDRESS] # Identity of sender
|
47
|
+
# Default: Sms Service
|
48
|
+
|
49
|
+
|
data/Rakefile
ADDED
data/bin/cimd_cli.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'cimd'
|
6
|
+
require 'thor'
|
7
|
+
|
8
|
+
module CIMD
|
9
|
+
|
10
|
+
def self.start_eventmachine(conn,messages,options)
|
11
|
+
EventMachine.run do
|
12
|
+
Signal.trap("INT") { CIMD::Loop.logout_request }
|
13
|
+
Signal.trap("TERM") { CIMD::Loop.logout_request }
|
14
|
+
EventMachine.connect conn.server, conn.port, CIMD::Loop do |c|
|
15
|
+
c.messages = messages
|
16
|
+
c.conn = conn
|
17
|
+
c.options = options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class MyCLI < Thor
|
23
|
+
|
24
|
+
desc "sendsms", "Sends text SMS to MSISDN number"
|
25
|
+
option :server, :required => true,:desc => "Address of SMSC server (can be DNS name)"
|
26
|
+
option :port, :desc => "Port number for CIMD protocol",:default => 9971
|
27
|
+
option :user_identity, :required => true,:desc => "Username of CIMD account"
|
28
|
+
option :password, :required => true,:desc => "Password for CIMD account USERNAME"
|
29
|
+
option :message, :desc => "Message to be send",:default=>"SMS test message"
|
30
|
+
option :msisdn, :required => true,:desc => "MSISDN number to be send"
|
31
|
+
option :alpha_orig_address, :desc => "Identity of sender",:default => "Sms Service"
|
32
|
+
def sendsms()
|
33
|
+
puts "Sending sms message: #{options[:message]} to #{options[:msisdn]}"
|
34
|
+
conn = CIMD::Connection.new(options[:server],options[:port],options[:user_identity],options[:password],options[:alpha_orig_address],1,60)
|
35
|
+
messages = EM::Queue.new
|
36
|
+
messages.push(CIMD::login_message(conn))
|
37
|
+
messages.push(CIMD::submit_text_message(conn,options[:msisdn],options[:message]))
|
38
|
+
messages.push(CIMD::logout_message)
|
39
|
+
CIMD::start_eventmachine(conn,messages,{})
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "receivesms", "Receives smses and sends echo"
|
43
|
+
long_desc <<-LONGDESC
|
44
|
+
`cimd_cli.rb receivesms` receives smses endlessly. If You want to stop
|
45
|
+
reciving just press ^C.
|
46
|
+
LONGDESC
|
47
|
+
option :server, :required => true,:desc => "Address of SMSC server (can be DNS name)"
|
48
|
+
option :port, :desc => "Port number for CIMD protocol",:default => 9971
|
49
|
+
option :user_identity, :required => true,:desc => "Username of CIMD account"
|
50
|
+
option :password, :required => true,:desc => "Password for CIMD account USERNAME"
|
51
|
+
option :message, :desc => "Message to be send",:default=>"SMS test message"
|
52
|
+
option :msisdn, :required => true,:desc => "MSISDN number to be send"
|
53
|
+
option :alpha_orig_address, :desc => "Identity of sender",:default => "Sms Service"
|
54
|
+
def receivesms()
|
55
|
+
puts "Start receiving"
|
56
|
+
conn = CIMD::Connection.new(options[:server],options[:port],options[:user_identity],options[:password],options[:alpha_orig_address],1,60)
|
57
|
+
messages = EM::Queue.new
|
58
|
+
messages.push(CIMD::login_message(conn))
|
59
|
+
CIMD::start_eventmachine(conn,messages,{})
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
CIMD::MyCLI.start(ARGV)
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
data/cimd.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cimd/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cimd"
|
7
|
+
s.version = CIMD::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Wojciech Todryk"]
|
10
|
+
s.email = ["wojciech@todryk.pl"]
|
11
|
+
s.homepage = "http://todryk.pl/cimd"
|
12
|
+
s.summary = %q{Utils for CIMD protocol}
|
13
|
+
s.description = %q{Utils for CIMD protocol}
|
14
|
+
|
15
|
+
s.rubyforge_project = "cimd"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_dependency "eventmachine", [">= 0.12"]
|
22
|
+
s.add_dependency "thor", [">= 0"]
|
23
|
+
s.add_development_dependency "rspec", [">= 0"]
|
24
|
+
s.add_development_dependency "rake", [">= 0"]
|
25
|
+
s.add_development_dependency "guard", [">= 1.3"]
|
26
|
+
s.add_development_dependency "guard-rspec", [">= 1.2"]
|
27
|
+
s.add_development_dependency "rb-inotify", [">= 0.8.8"]
|
28
|
+
|
29
|
+
end
|
data/lib/cimd.rb
ADDED
data/lib/cimd/version.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module CIMD
|
2
|
+
|
3
|
+
STX = 0x02
|
4
|
+
ETX = 0x03
|
5
|
+
TAB = "\t"
|
6
|
+
CC = 0xFF
|
7
|
+
PARAM_SEP = ":"
|
8
|
+
|
9
|
+
# OP - OPERATION CODES
|
10
|
+
OP_LOGIN = 1
|
11
|
+
OP_LOGOUT = 2
|
12
|
+
OP_SUBMIT= 3
|
13
|
+
OP_ENQUIRE_MESSAGE_STATUS = 4
|
14
|
+
OP_DELIVERY_REQUEST = 5
|
15
|
+
OP_CANCEL_MESSAGE = 6
|
16
|
+
OP_SET = 8
|
17
|
+
OP_GET = 9
|
18
|
+
OP_DELIVERY_MESSAGE = 20
|
19
|
+
OP_DELIVERY_STATUS_REPORT = 23
|
20
|
+
OP_ALIVE = 40
|
21
|
+
OP_LOGIN_RESPONSE = 51
|
22
|
+
OP_LOGOUT_RESPONSE = 52
|
23
|
+
OP_SUBMIT_RESPONSE = 53
|
24
|
+
OP_ENQUIRE_MESSAGE_STATUS_RESPONSE = 54
|
25
|
+
OP_DELIVERY_REQUEST_RESPONSE = 55
|
26
|
+
OP_CANCEL_MESSAGE_RESPONSE = 56
|
27
|
+
OP_SET_RESPONSE = 58
|
28
|
+
OP_GET_RESPONSE = 59
|
29
|
+
OP_DELIVERY_MESSAGE_RESPONSE = 70
|
30
|
+
OP_DELIVERY_STATUS_REPORT_RESPONSE = 73
|
31
|
+
OP_ALIVE_RESPONSE = 90
|
32
|
+
OP_GENERAL_ERROR_RESPONSE = 98
|
33
|
+
OP_NACK = 99
|
34
|
+
|
35
|
+
def self.opcode_description(op_code)
|
36
|
+
descs = {
|
37
|
+
OP_LOGIN => "OP_LOGIN",
|
38
|
+
OP_LOGOUT => "OP_LOGOUT",
|
39
|
+
OP_SUBMIT=> "OP_SUBMIT",
|
40
|
+
OP_ENQUIRE_MESSAGE_STATUS => "OP_ENQUIRE_MESSAGE_STATUS",
|
41
|
+
OP_DELIVERY_REQUEST => "OP_DELIVERY_REQUEST",
|
42
|
+
OP_CANCEL_MESSAGE => "OP_CANCEL_MESSAGE",
|
43
|
+
OP_SET => "OP_SET",
|
44
|
+
OP_GET => "OP_GET",
|
45
|
+
OP_DELIVERY_MESSAGE => "OP_DELIVERY_MESSAGE",
|
46
|
+
OP_DELIVERY_STATUS_REPORT => "OP_DELIVERY_STATUS_REPORT",
|
47
|
+
OP_ALIVE => "OP_ALIVE",
|
48
|
+
OP_LOGIN_RESPONSE => "OP_LOGIN_RESPONSE",
|
49
|
+
OP_LOGOUT_RESPONSE => "OP_LOGOUT_RESPONSE",
|
50
|
+
OP_SUBMIT_RESPONSE => "OP_SUBMIT_RESPONSE",
|
51
|
+
OP_ENQUIRE_MESSAGE_STATUS_RESPONSE => "OP_ENQUIRE_MESSAGE_STATUS_RESPONSE",
|
52
|
+
OP_DELIVERY_REQUEST_RESPONSE => "OP_DELIVERY_REQUEST_RESPONSE",
|
53
|
+
OP_CANCEL_MESSAGE_RESPONSE => "OP_CANCEL_MESSAGE_RESPONSE",
|
54
|
+
OP_SET_RESPONSE => "OP_SET_RESPONSE",
|
55
|
+
OP_GET_RESPONSE => "OP_GET_RESPONSE",
|
56
|
+
OP_DELIVERY_MESSAGE_RESPONSE => "OP_DELIVERY_MESSAGE_RESPONSE",
|
57
|
+
OP_DELIVERY_STATUS_REPORT_RESPONSE => "OP_DELIVERY_STATUS_REPORT_RESPONSE",
|
58
|
+
OP_ALIVE_RESPONSE => "OP_ALIVE_RESPONSE",
|
59
|
+
OP_GENERAL_ERROR_RESPONSE => "OP_GENERAL_ERROR_RESPONSE",
|
60
|
+
OP_NACK => "",
|
61
|
+
}
|
62
|
+
return descs.has_key?(op_code) ? "(#{descs[op_code]})" : "(UNKNOWN)"
|
63
|
+
end
|
64
|
+
|
65
|
+
# P - PARAMETER
|
66
|
+
P_USER_IDENTITY = 10
|
67
|
+
P_PASSWORD = 11
|
68
|
+
P_SUBADDR = 12
|
69
|
+
P_WINDOW_SIZE = 19
|
70
|
+
P_DESTINATION_ADDRESS = 21
|
71
|
+
P_ORIGINATOR_ADDRESS = 23
|
72
|
+
P_ALPHA_ORIG_ADDRESS = 27
|
73
|
+
P_DATA_CODING_SCHEME = 30
|
74
|
+
P_USER_DATA_HEADER = 32
|
75
|
+
P_USER_DATA = 33
|
76
|
+
P_USER_DATA_BINARY = 34
|
77
|
+
P_PROTOCOL_IDENTIFIER = 52
|
78
|
+
P_SERVICE_CENTRE_TIME_STAMP = 60
|
79
|
+
P_ERROR_CODE = 900
|
80
|
+
P_ERROR_TEXT = 901
|
81
|
+
|
82
|
+
DEFAULT_WINDOW_SIZE = 1
|
83
|
+
DEFAULT_KEEP_ALIVE = 60
|
84
|
+
|
85
|
+
ALPHABET_DEFAULT = 0
|
86
|
+
ALPHABET_8BIT = 1
|
87
|
+
ALPHABET_UCS2 = 2
|
88
|
+
ALPHABET_RESERVED = 3
|
89
|
+
|
90
|
+
ALPHABET_BINARY = 8
|
91
|
+
end
|
data/lib/cimd_loop.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'cimd'
|
5
|
+
|
6
|
+
module CIMD
|
7
|
+
|
8
|
+
class Loop < EventMachine::Connection
|
9
|
+
|
10
|
+
@@logout_request = false
|
11
|
+
|
12
|
+
STATE=[:not_connected,:connected,:banner_received,:ready_to_send,:suspend]
|
13
|
+
MAX_NO_ACTIVITY_TIME = 180
|
14
|
+
attr_accessor :state
|
15
|
+
attr_accessor :messages
|
16
|
+
attr_accessor :conn
|
17
|
+
attr_accessor :keep_alive_counter
|
18
|
+
attr_accessor :no_activity_counter
|
19
|
+
attr_accessor :options
|
20
|
+
attr_accessor :logfile
|
21
|
+
attr_accessor :debug
|
22
|
+
|
23
|
+
def to_log(message)
|
24
|
+
#puts @debug
|
25
|
+
#puts @logfile
|
26
|
+
puts "#{Time.now.strftime("%Y-%m-%d/%H:%M:%S")} #{message}"
|
27
|
+
#puts message if @debug
|
28
|
+
#@logfile.puts message if @logfile
|
29
|
+
$stdout.flush
|
30
|
+
end
|
31
|
+
|
32
|
+
def change_state(new_state)
|
33
|
+
if @state != new_state
|
34
|
+
to_log("#### Transition: #{@state.to_s} ==> #{new_state.to_s} (no_act:#{ Time.now.tv_sec - @no_activity_counter}, keep:#{Time.now.tv_sec - @keep_alive_counter}, queue:#{@messages.size})")
|
35
|
+
@state = new_state
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.logout_request
|
40
|
+
@@logout_request = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
@state = :not_connected
|
45
|
+
@debug = false
|
46
|
+
@log = nil
|
47
|
+
@keep_alive_counter = Time.now.tv_sec
|
48
|
+
@no_activity_counter = Time.now.tv_sec
|
49
|
+
#@debug = true if @options[:debug]
|
50
|
+
#begin
|
51
|
+
# @log = File.new("ss", "w") if options[:logfile]
|
52
|
+
#rescue Exception => e
|
53
|
+
# puts e.to_s
|
54
|
+
# exit
|
55
|
+
#end
|
56
|
+
end
|
57
|
+
|
58
|
+
def post_init
|
59
|
+
|
60
|
+
@timer = EM.add_periodic_timer(1) do
|
61
|
+
|
62
|
+
if @@logout_request == true
|
63
|
+
change_state(:logout_request)
|
64
|
+
@@logout_request = false
|
65
|
+
end
|
66
|
+
|
67
|
+
change_state(:alive) if Time.now.tv_sec - @keep_alive_counter > @conn.keep_alive
|
68
|
+
change_state(:no_activity) if Time.now.tv_sec - @no_activity_counter > MAX_NO_ACTIVITY_TIME
|
69
|
+
|
70
|
+
#puts "No act:#{ Time.now.tv_sec - @no_activity_counter} Keep:#{Time.now.tv_sec - @keep_alive_counter} Queue: #{@messages.size}"
|
71
|
+
case @state
|
72
|
+
when :banner_received
|
73
|
+
change_state(:login_request)
|
74
|
+
@messages.pop{ |message| sending_message(message)}
|
75
|
+
when :login_sucessfull
|
76
|
+
change_state(:ready_to_send)
|
77
|
+
when :ready_to_send
|
78
|
+
change_state(:suspend)
|
79
|
+
@messages.pop{ |message| sending_message(message)}
|
80
|
+
when :no_activity,:logout_done
|
81
|
+
close_connection
|
82
|
+
when :alive
|
83
|
+
change_state(:suspend)
|
84
|
+
to_log("<<<< #{CIMD::alive_message}")
|
85
|
+
sending_message(CIMD::alive_message)
|
86
|
+
when :logout_request
|
87
|
+
@messages = EM::Queue.new
|
88
|
+
to_log("<<<< #{CIMD::logout_message}")
|
89
|
+
messages.push(CIMD::logout_message);
|
90
|
+
change_state(:ready_to_send)
|
91
|
+
when :suspend
|
92
|
+
#puts "Suspend"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end # post_init
|
97
|
+
|
98
|
+
def sending_message(message)
|
99
|
+
message.packet_number = @conn.packet_number!
|
100
|
+
to_log("<<<< #{message.to_s}")
|
101
|
+
send_data message.to_binary
|
102
|
+
@keep_alive_counter = Time.now.tv_sec
|
103
|
+
end
|
104
|
+
|
105
|
+
def sending_response_message(message)
|
106
|
+
m = CIMD::only_response_message(message)
|
107
|
+
to_log("<<<< #{m.to_s}")
|
108
|
+
send_data m.to_binary
|
109
|
+
end
|
110
|
+
|
111
|
+
def connection_completed
|
112
|
+
change_state(:connected)
|
113
|
+
end
|
114
|
+
|
115
|
+
def receive_data(data)
|
116
|
+
#puts "Received plain data: #{data}"
|
117
|
+
|
118
|
+
case data
|
119
|
+
when /CIMD2-A/
|
120
|
+
change_state(:banner_received)
|
121
|
+
else
|
122
|
+
|
123
|
+
(@buffer ||= BufferedTokenizer.new("\003")).extract(data).each do |line|
|
124
|
+
message = Message.parse(line)
|
125
|
+
|
126
|
+
to_log(">>>> #{message.to_s}")
|
127
|
+
# sprawdzic checsum
|
128
|
+
if message.is_binary?
|
129
|
+
message.parse_binary_data
|
130
|
+
to_log("**** Decoded binary: #{message.to_s}")
|
131
|
+
end
|
132
|
+
@no_activity_counter = Time.now.tv_sec
|
133
|
+
|
134
|
+
case message.operation_code
|
135
|
+
when CIMD::OP_LOGIN_RESPONSE
|
136
|
+
if message.has_error?
|
137
|
+
to_log("!!!! Error: #{message.error}")
|
138
|
+
close_connection
|
139
|
+
else
|
140
|
+
change_state(:login_sucessfull)
|
141
|
+
end
|
142
|
+
when CIMD::OP_SUBMIT_RESPONSE
|
143
|
+
if message.has_error?
|
144
|
+
to_log("!!!! Error: #{message.error}")
|
145
|
+
end
|
146
|
+
change_state(:ready_to_send)
|
147
|
+
when CIMD::OP_DELIVERY_STATUS_REPORT
|
148
|
+
sending_response_message(message)
|
149
|
+
when CIMD::OP_DELIVERY_MESSAGE
|
150
|
+
sending_response_message(message)
|
151
|
+
messages.push(CIMD::submit_text_message(@conn,message.parameter_value(CIMD::P_ORIGINATOR_ADDRESS),message.parameter_value(CIMD::P_USER_DATA)))
|
152
|
+
when CIMD::OP_LOGOUT_RESPONSE
|
153
|
+
change_state(:logout_done)
|
154
|
+
when CIMD::OP_ALIVE_RESPONSE
|
155
|
+
when CIMD::OP_GENERAL_ERROR_RESPONSE
|
156
|
+
to_log("!!!! Error: #{message.error}")
|
157
|
+
close_connection
|
158
|
+
else
|
159
|
+
to_log("???? Unknown message type: #{data}")
|
160
|
+
end # case message.operation_code
|
161
|
+
end
|
162
|
+
end # case data
|
163
|
+
end # receive_data
|
164
|
+
|
165
|
+
def unbind
|
166
|
+
@logfile.close unless @logfile.nil?
|
167
|
+
change_state(:not_connected)
|
168
|
+
EventMachine.stop_event_loop
|
169
|
+
end
|
170
|
+
|
171
|
+
end # class Loop
|
172
|
+
|
173
|
+
end # module CIMD
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module CIMD
|
2
|
+
|
3
|
+
def self.login_message(connection)
|
4
|
+
m = Message.new(OP_LOGIN)
|
5
|
+
p_login = Parameter.new(P_USER_IDENTITY,connection.user_identity)
|
6
|
+
p_password = Parameter.new(P_PASSWORD,connection.password)
|
7
|
+
m.add(p_login)
|
8
|
+
m.add(p_password)
|
9
|
+
return m
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.logout_message
|
13
|
+
m = Message.new(OP_LOGOUT)
|
14
|
+
return m
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.submit_text_message(connection,msisdn,text)
|
18
|
+
m = Message.new(OP_SUBMIT)
|
19
|
+
p_msisdn = Parameter.new(P_DESTINATION_ADDRESS,msisdn)
|
20
|
+
p_text = Parameter.new(P_USER_DATA,text)
|
21
|
+
m.add(p_msisdn)
|
22
|
+
m.add(p_text)
|
23
|
+
unless connection.alpha_orig_address.nil?
|
24
|
+
p_orig = Parameter.new(P_ALPHA_ORIG_ADDRESS,connection.alpha_orig_address)
|
25
|
+
m.add(p_orig)
|
26
|
+
end
|
27
|
+
return m
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.submit_binary_message(connection,msisdn,binary_text)
|
31
|
+
m = Message.new(OP_SUBMIT)
|
32
|
+
p_msisdn = Parameter.new(P_DESTINATION_ADDRESS,msisdn)
|
33
|
+
p_text = Parameter.new(P_USER_DATA_BINARY,binary_text)
|
34
|
+
p_dcs = Parameter.new(P_DATA_CODING_SCHEME,ALPHABET_BINARY)
|
35
|
+
m.add(p_msisdn)
|
36
|
+
m.add(p_text)
|
37
|
+
m.add(p_dcs)
|
38
|
+
unless connection.alpha_orig_address.nil?
|
39
|
+
p_orig = Parameter.new(P_ALPHA_ORIG_ADDRESS,connection.alpha_orig_address)
|
40
|
+
m.add(p_orig)
|
41
|
+
end
|
42
|
+
return m
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.only_response_message(message)
|
46
|
+
m = Message.new(message.operation_code + 50)
|
47
|
+
m.packet_number = message.packet_number
|
48
|
+
return m
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.alive_message
|
52
|
+
m = Message.new(OP_ALIVE)
|
53
|
+
return m
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module CIMD
|
2
|
+
|
3
|
+
class Connection
|
4
|
+
|
5
|
+
attr_accessor :server
|
6
|
+
attr_accessor :port
|
7
|
+
attr_accessor :user_identity
|
8
|
+
attr_accessor :password
|
9
|
+
attr_accessor :keep_alive
|
10
|
+
attr_accessor :packet_number
|
11
|
+
attr_accessor :window_size
|
12
|
+
attr_accessor :alpha_orig_address
|
13
|
+
|
14
|
+
def initialize(server,port,user_identity,password,alpha_orig_address,window_size,keep_alive)
|
15
|
+
@server = server
|
16
|
+
@port = port
|
17
|
+
@user_identity = user_identity
|
18
|
+
@password = password
|
19
|
+
@keep_alive = keep_alive
|
20
|
+
@packet_number = 1
|
21
|
+
@alpha_orig_address = alpha_orig_address
|
22
|
+
@window_size = window_size
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
return sprintf "\n\n*** Connection object:\nServer: %s\n,Port: %s\n,User identity: %s\nPassword: %s\nKeep Alive: %3d\nAlpha Orig Address: %s\n Packet number: %d\n\n",@server,@port,@user_identity,@password,@keep_alive,@alpha_orig_address,@packet_number
|
27
|
+
end
|
28
|
+
|
29
|
+
def packet_number?
|
30
|
+
return @packet_number
|
31
|
+
end
|
32
|
+
|
33
|
+
def packet_number!
|
34
|
+
f = @packet_number
|
35
|
+
(@packet_number += 2) > 255 ? @packet_number = 1 : @packet_number
|
36
|
+
return f
|
37
|
+
end
|
38
|
+
|
39
|
+
end #connection
|
40
|
+
|
41
|
+
class Parameter
|
42
|
+
|
43
|
+
attr_accessor :code
|
44
|
+
attr_accessor :value
|
45
|
+
|
46
|
+
def initialize(code,value)
|
47
|
+
@code = code
|
48
|
+
@value = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
return sprintf "%03d:%s",@code,@value
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.parse(data)
|
56
|
+
fields = data.split(":")
|
57
|
+
p = Parameter.new((fields[0]).to_i,fields[1])
|
58
|
+
return p
|
59
|
+
end
|
60
|
+
|
61
|
+
end #parameter
|
62
|
+
|
63
|
+
class Dcs
|
64
|
+
|
65
|
+
attr_accessor :value
|
66
|
+
|
67
|
+
def initialize(value)
|
68
|
+
@value = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_value(value)
|
72
|
+
@value = value.to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
def coding_group
|
76
|
+
return @value & 0xF0
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_coding_group_zero?
|
80
|
+
(@value & 0b11000000).zero?
|
81
|
+
end
|
82
|
+
|
83
|
+
def has_default_alphabet?
|
84
|
+
value.zero?
|
85
|
+
end
|
86
|
+
|
87
|
+
def alphabet
|
88
|
+
if has_coding_group_zero?
|
89
|
+
return (@value & 0b00001100) >> 2
|
90
|
+
else
|
91
|
+
return 0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def alphabet_set_UCS2
|
96
|
+
value = 8
|
97
|
+
end
|
98
|
+
|
99
|
+
end #dcs
|
100
|
+
|
101
|
+
class Message
|
102
|
+
|
103
|
+
attr_accessor :operation_code
|
104
|
+
attr_accessor :parameters
|
105
|
+
attr_accessor :packet_number
|
106
|
+
attr_accessor :checksum
|
107
|
+
attr_accessor :dcs
|
108
|
+
|
109
|
+
def initialize(operation_code)
|
110
|
+
@operation_code = operation_code
|
111
|
+
@packet_number = 1
|
112
|
+
@parameters = Array.new
|
113
|
+
@checksum = 0
|
114
|
+
@dcs = Dcs.new(0)
|
115
|
+
end
|
116
|
+
|
117
|
+
def alphabet
|
118
|
+
@dcs.alphabet
|
119
|
+
end
|
120
|
+
|
121
|
+
def has_alphabet_ucs2?
|
122
|
+
@dcs.alphabet == ALPHABET_UCS2
|
123
|
+
end
|
124
|
+
|
125
|
+
def has_error?
|
126
|
+
return has_parameter?(P_ERROR_CODE) ? true : false
|
127
|
+
end
|
128
|
+
|
129
|
+
def error
|
130
|
+
return has_error? ? "(#{parameter_value(CIMD::P_ERROR_CODE)}) #{parameter_value(CIMD::P_ERROR_TEXT)}" : nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def calc_checksum
|
134
|
+
checksum = 0
|
135
|
+
s = String.new
|
136
|
+
s << STX
|
137
|
+
s << (sprintf "%02d:%03d",@operation_code,@packet_number)
|
138
|
+
s << TAB
|
139
|
+
@parameters.each do |p|
|
140
|
+
s << p.to_s
|
141
|
+
s << TAB
|
142
|
+
end
|
143
|
+
|
144
|
+
s.each_byte do |b|
|
145
|
+
checksum += b
|
146
|
+
checksum &= 0xFF
|
147
|
+
end
|
148
|
+
return checksum
|
149
|
+
end
|
150
|
+
|
151
|
+
def add(parameter)
|
152
|
+
@parameters.push(parameter)
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_s
|
156
|
+
s = sprintf "<STX>%02d:%03d<TAB>",@operation_code,@packet_number
|
157
|
+
#add(Parameter.new(P_DATA_CODING_SCHEME,@dcs.value)) @operation_code == OP_SUBMIT
|
158
|
+
@parameters.each do |p|
|
159
|
+
s << p.to_s
|
160
|
+
s << "<TAB>"
|
161
|
+
end
|
162
|
+
s << (sprintf "%02x",@checksum).upcase
|
163
|
+
s << "<ETX> "
|
164
|
+
s << CIMD::opcode_description(@operation_code)
|
165
|
+
return s
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_binary
|
169
|
+
s = String.new
|
170
|
+
s << STX
|
171
|
+
s << (sprintf "%02d:%03d",@operation_code,@packet_number)
|
172
|
+
s << TAB
|
173
|
+
#add(Parameter.new(P_DATA_CODING_SCHEME,@dcs.value)) if @operation_code == OP_SUBMIT
|
174
|
+
@parameters.each do |p|
|
175
|
+
s << p.to_s
|
176
|
+
s << TAB
|
177
|
+
end
|
178
|
+
s << (sprintf "%02x",calc_checksum)
|
179
|
+
s << ETX
|
180
|
+
return s
|
181
|
+
end
|
182
|
+
|
183
|
+
def is_binary?
|
184
|
+
has_parameter?(P_USER_DATA_BINARY)
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.parse(data)
|
188
|
+
data.slice!(0)
|
189
|
+
fields = data.split(TAB)
|
190
|
+
header = fields[0].split(PARAM_SEP)
|
191
|
+
operation_code = header[0].to_i
|
192
|
+
m = Message.new(operation_code)
|
193
|
+
m.packet_number = header[1].to_i
|
194
|
+
fields.delete_at(0)
|
195
|
+
m.checksum = (fields.delete_at(fields.size - 1)).hex.to_i
|
196
|
+
fields.each do |p|
|
197
|
+
m.parameters << Parameter.parse(p)
|
198
|
+
end
|
199
|
+
m.dcs.set_value(m.parameter_value(P_DATA_CODING_SCHEME)) if m.has_parameter?(P_DATA_CODING_SCHEME)
|
200
|
+
return m
|
201
|
+
end
|
202
|
+
|
203
|
+
def parse_binary_data
|
204
|
+
if has_alphabet_ucs2? and @operation_code == OP_DELIVERY_MESSAGE
|
205
|
+
data = parameter_value(P_USER_DATA_BINARY)
|
206
|
+
i = 0
|
207
|
+
s = ""
|
208
|
+
while i < data.length do
|
209
|
+
s << data[i,2].hex
|
210
|
+
i += 2
|
211
|
+
end
|
212
|
+
p = Parameter.new(P_USER_DATA,Iconv.iconv("UTF-8", "UCS-2BE",s).first)
|
213
|
+
add(p)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def has_parameter?(code)
|
218
|
+
@parameters.each do |p|
|
219
|
+
return true if p.code == code
|
220
|
+
end
|
221
|
+
return false
|
222
|
+
end
|
223
|
+
|
224
|
+
def parameter_value(code)
|
225
|
+
@parameters.each do |p|
|
226
|
+
return p.value if p.code == code
|
227
|
+
end
|
228
|
+
return nil
|
229
|
+
end
|
230
|
+
|
231
|
+
end # message
|
232
|
+
|
233
|
+
end # CIMD
|
234
|
+
|
235
|
+
|
236
|
+
|
237
|
+
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'cimd'
|
2
|
+
require 'iconv'
|
3
|
+
|
4
|
+
describe CIMD do
|
5
|
+
|
6
|
+
it "has constants" do
|
7
|
+
CIMD::OP_LOGIN.should == 1
|
8
|
+
CIMD::OP_LOGOUT.should == 2
|
9
|
+
CIMD::OP_SUBMIT.should == 3
|
10
|
+
CIMD::ALPHABET_BINARY.should == 8
|
11
|
+
end
|
12
|
+
|
13
|
+
context CIMD::Connection do
|
14
|
+
|
15
|
+
let(:cn) { CIMD::Connection.new('server',1234,'user1','password1',nil,1,120) }
|
16
|
+
let(:c) { CIMD::Connection.new('server',1234,'user1','password1','alpha',1,120) }
|
17
|
+
|
18
|
+
it "returns connection object with nil alpha orig number" do
|
19
|
+
cn.user_identity.should eq('user1')
|
20
|
+
cn.password.should eq('password1')
|
21
|
+
cn.server.should eq('server')
|
22
|
+
cn.port.should eq(1234)
|
23
|
+
cn.alpha_orig_address.should be_nil
|
24
|
+
cn.window_size.should eq(1)
|
25
|
+
cn.keep_alive.should eq(120)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns connection object with not nil alpha orig number" do
|
29
|
+
c.user_identity.should eq('user1')
|
30
|
+
c.password.should eq('password1')
|
31
|
+
c.alpha_orig_address.should eq('alpha')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns first packet number" do
|
35
|
+
c.packet_number?.should eq(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns 10th packet number" do
|
39
|
+
10.times { c.packet_number! }
|
40
|
+
c.packet_number?.should eq(21)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns 130th packet number" do
|
44
|
+
130.times { c.packet_number! }
|
45
|
+
c.packet_number?.should eq(5)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "opcode description" do
|
49
|
+
CIMD::opcode_description("as").should eq("(UNKNOWN)")
|
50
|
+
CIMD::opcode_description(CIMD::OP_LOGIN).should eq("(OP_LOGIN)")
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end # context CIMD::Connection
|
55
|
+
|
56
|
+
context CIMD::Message do
|
57
|
+
|
58
|
+
let(:cn) { CIMD::Connection.new('server',1234,'user1','password1',nil,1,120) }
|
59
|
+
let(:c) { CIMD::Connection.new('server',1234,'user1','password1','alpha',1,120) }
|
60
|
+
let(:lm) { CIMD::login_message(cn) }
|
61
|
+
let(:lo) { CIMD::logout_message }
|
62
|
+
let(:submitn) { CIMD::submit_text_message(cn,'1234567789','textn') }
|
63
|
+
let(:submit) {CIMD::submit_text_message(c,'1234567789','text') }
|
64
|
+
|
65
|
+
it "returns login message" do
|
66
|
+
lm.has_parameter?(CIMD::P_USER_IDENTITY).should be_true
|
67
|
+
lm.has_parameter?(CIMD::P_PASSWORD).should be_true
|
68
|
+
lm.parameter_value(CIMD::P_USER_IDENTITY).should eq('user1')
|
69
|
+
lm.parameter_value(CIMD::P_PASSWORD).should eq('password1')
|
70
|
+
lm.has_parameter?(CIMD::P_DESTINATION_ADDRESS).should be_false
|
71
|
+
lm.parameter_value(CIMD::P_DESTINATION_ADDRESS).should be_nil
|
72
|
+
end
|
73
|
+
|
74
|
+
it "returns logout message" do
|
75
|
+
lo.parameters.size.should eq(0)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "to_s" do
|
79
|
+
submit.to_s.should eq("<STX>03:001<TAB>021:1234567789<TAB>033:text<TAB>027:alpha<TAB>00<ETX> (OP_SUBMIT)")
|
80
|
+
submitn.to_s.should eq("<STX>03:001<TAB>021:1234567789<TAB>033:textn<TAB>00<ETX> (OP_SUBMIT)")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "submit message with no alpha" do
|
84
|
+
#puts submitn
|
85
|
+
submitn.parameters.size.should eq(2)
|
86
|
+
submitn.has_parameter?(CIMD::P_ALPHA_ORIG_ADDRESS).should be_false
|
87
|
+
end
|
88
|
+
|
89
|
+
it "submit message with alpha" do
|
90
|
+
#puts submit
|
91
|
+
submit.parameters.size.should eq(3)
|
92
|
+
submit.has_parameter?(CIMD::P_ALPHA_ORIG_ADDRESS).should be_true
|
93
|
+
submit.parameter_value(CIMD::P_ALPHA_ORIG_ADDRESS).should eq('alpha')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "return confirmation frame" do
|
97
|
+
submit.packet_number = 5
|
98
|
+
m = CIMD::only_response_message(submit)
|
99
|
+
m.packet_number.should eq(submit.packet_number)
|
100
|
+
m.operation_code.should eq(submit.operation_code+50)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "inserts packet number to message" do
|
104
|
+
10.times { c.packet_number! }
|
105
|
+
submit.packet_number = c.packet_number!
|
106
|
+
submit.packet_number.should eq(21)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "calculates checksum test" do
|
110
|
+
m = CIMD::Message.new(CIMD::OP_GENERAL_ERROR_RESPONSE)
|
111
|
+
m.packet_number = 1
|
112
|
+
m.add(CIMD::Parameter.new(CIMD::P_ERROR_CODE,'2'))
|
113
|
+
m.add(CIMD::Parameter.new(CIMD::P_ERROR_TEXT,'Syntax error'))
|
114
|
+
sprintf("%02x",m.calc_checksum).upcase.should eq('03')
|
115
|
+
end
|
116
|
+
|
117
|
+
it "parses message" do
|
118
|
+
s = ""
|
119
|
+
s << CIMD::STX
|
120
|
+
s << (sprintf("%02d:%03d\t",1,23))
|
121
|
+
s << (sprintf("%03d:%s\t",11,'admin1'))
|
122
|
+
s << (sprintf("%03d:%s\t",10,'jan'))
|
123
|
+
s << "57"
|
124
|
+
s << CIMD::ETX
|
125
|
+
m = CIMD::Message.parse(s)
|
126
|
+
m.operation_code.should eq(1)
|
127
|
+
m.packet_number.should eq(23)
|
128
|
+
m.parameter_value(CIMD::P_USER_IDENTITY).should eq('jan')
|
129
|
+
m.parameter_value(CIMD::P_PASSWORD).should eq('admin1')
|
130
|
+
sprintf("%02x",m.calc_checksum).upcase.should eq('57')
|
131
|
+
end
|
132
|
+
|
133
|
+
it "parses binary message" do
|
134
|
+
s ="\00220:000\t021:48661001723\t023:48601130651\t060:120210100902\t034:0044006600760067006700720067006200760142006400660076007600660105\t052:0\t030:8\t1A\003"
|
135
|
+
m = CIMD::Message.parse(s)
|
136
|
+
sprintf("%02x",m.calc_checksum).upcase.should eq('1A')
|
137
|
+
m.is_binary?.should be_true
|
138
|
+
m.dcs.coding_group.should be_zero
|
139
|
+
m.dcs.has_coding_group_zero?.should be_true
|
140
|
+
m.alphabet.should eq(2)
|
141
|
+
m.has_alphabet_ucs2?.should be_true
|
142
|
+
m.parse_binary_data
|
143
|
+
m.parameter_value(CIMD::P_USER_DATA).should match(/^D/)
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
#context CIMD::Loop do
|
149
|
+
#let(:loop) { CIMD::Loop.new({}) }
|
150
|
+
|
151
|
+
#it ("create new loop instance") do
|
152
|
+
#puts loop
|
153
|
+
#end
|
154
|
+
|
155
|
+
#end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
metadata
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cimd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Wojciech Todryk
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.12'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.12'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: thor
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.3'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.3'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: guard-rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '1.2'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.2'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rb-inotify
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.8.8
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.8.8
|
126
|
+
description: Utils for CIMD protocol
|
127
|
+
email:
|
128
|
+
- wojciech@todryk.pl
|
129
|
+
executables:
|
130
|
+
- cimd_cli.rb
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- .travis.yml
|
135
|
+
- Gemfile
|
136
|
+
- Gemfile.lock
|
137
|
+
- Guardfile
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/cimd_cli.rb
|
141
|
+
- cimd.gemspec
|
142
|
+
- lib/cimd.rb
|
143
|
+
- lib/cimd/version.rb
|
144
|
+
- lib/cimd_constants.rb
|
145
|
+
- lib/cimd_loop.rb
|
146
|
+
- lib/cimd_messages.rb
|
147
|
+
- lib/cimd_structures.rb
|
148
|
+
- spec/lib/cimd_spec.rb
|
149
|
+
homepage: http://todryk.pl/cimd
|
150
|
+
licenses: []
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ! '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubyforge_project: cimd
|
169
|
+
rubygems_version: 1.8.24
|
170
|
+
signing_key:
|
171
|
+
specification_version: 3
|
172
|
+
summary: Utils for CIMD protocol
|
173
|
+
test_files:
|
174
|
+
- spec/lib/cimd_spec.rb
|