smshelper 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -5
- data/README.md +122 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/smshelper/api.rb +13 -8
- data/lib/smshelper/api/base.rb +40 -19
- data/lib/smshelper/api/bulksms.rb +1 -1
- data/lib/smshelper/api/mycoolsms.rb +4 -0
- data/lib/smshelper/api/nexmo.rb +1 -0
- data/lib/smshelper/api/response_codes.rb +63 -0
- data/lib/smshelper/api/routomessaging.rb +58 -21
- data/lib/smshelper/api/smswarehouse.rb +41 -10
- data/lib/smshelper/api/textmagic.rb +1 -3
- data/lib/smshelper/api/traitel.rb +10 -1
- data/lib/smshelper/api/vianett.rb +32 -10
- data/smshelper.gemspec +9 -6
- metadata +23 -11
- data/README.rdoc +0 -71
data/Gemfile
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
5
2
|
|
6
|
-
# Add dependencies to develop your gem here.
|
7
|
-
# Include everything needed to run rake, tests, features, etc.
|
8
3
|
gem 'api_smith'
|
9
4
|
gem 'savon'
|
10
5
|
gem 'nokogiri'
|
6
|
+
|
11
7
|
gem 'textmagic'
|
12
8
|
|
13
9
|
gem 'uuid'
|
14
10
|
gem 'digest-crc'
|
11
|
+
gem 'virtus'
|
15
12
|
|
16
13
|
group :development do
|
17
14
|
gem "pry"
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
Smshelper
|
2
|
+
---------
|
3
|
+
|
4
|
+
__THE lib for SMS-MT / HLR-Lookups.__
|
5
|
+
|
6
|
+
One day i was asked to connect a crm to correspond in SMS with call
|
7
|
+
center customers. Chose at random one of the operators, wrote a few
|
8
|
+
lines of code and there it was - SMS inbound/outbound.
|
9
|
+
|
10
|
+
> "Some of our messages aren't being delivered on time, some are being
|
11
|
+
> lost altogether, some arrive multiple times, some arrive after more
|
12
|
+
> then 24 hours from being sent"
|
13
|
+
|
14
|
+
> _--Your faithful customer_
|
15
|
+
|
16
|
+
I kept adding operators and here are the results...
|
17
|
+
|
18
|
+
__Currently supported:__
|
19
|
+
|
20
|
+
* __Unicode:__ across all operators
|
21
|
+
<table>
|
22
|
+
<tr>
|
23
|
+
<th>Operator</th><th>#send_message</th><th>#get_balance</th><th>#get_status</th><th>#get_callback_response</th><th>#hlr_lookup</th>
|
24
|
+
</tr>
|
25
|
+
<tr>
|
26
|
+
<td>Aql</td><td>X</td><td>X</td><td>_</td><td>X</td><td>_</td>
|
27
|
+
</tr>
|
28
|
+
<tr>
|
29
|
+
<td>Bulksms</td><td>X</td><td>X</td><td>X</td><td>X</td><td>_</td>
|
30
|
+
</tr>
|
31
|
+
<tr>
|
32
|
+
<td>Clickatell</td><td>X</td><td>X</td><td>X</td><td>_</td><td>_</td>
|
33
|
+
</tr>
|
34
|
+
<tr>
|
35
|
+
<td>Esendex</td><td>X</td><td>X</td><td>X</td><td>X</td><td>_</td>
|
36
|
+
</tr>
|
37
|
+
<tr>
|
38
|
+
<td>Mediaburst</td><td>X</td><td>X</td><td>_</td><td>X</td><td>_</td>
|
39
|
+
</tr>
|
40
|
+
<tr>
|
41
|
+
<td>Mycoolsms</td><td>X</td><td>X</td><td>_</td><td>X</td><td>X</td>
|
42
|
+
</tr>
|
43
|
+
<tr>
|
44
|
+
<td>Nexmo</td><td>X</td><td>X</td><td>_</td><td>X</td><td>_</td>
|
45
|
+
</tr>
|
46
|
+
<tr>
|
47
|
+
<td>Routomessaging</td><td>X</td><td>X</td><td>_</td><td>X</td><td>X**</td>
|
48
|
+
</tr>
|
49
|
+
<tr>
|
50
|
+
<td>Smstrade</td><td>X</td><td>X</td><td>_</td><td>X</td><td>_</td>
|
51
|
+
</tr>
|
52
|
+
<tr>
|
53
|
+
<td>Textmagic</td><td>X</td><td>X</td><td>_</td><td>X</td><td>_</td>
|
54
|
+
</tr>
|
55
|
+
<tr>
|
56
|
+
<td>Traitel</td><td>X</td><td>X</td><td>_</td><td>_</td><td>_</td>
|
57
|
+
</tr>
|
58
|
+
<tr>
|
59
|
+
<td>Vianett</td><td>X</td><td>X</td><td>_</td><td>X</td><td>X</td>
|
60
|
+
</tr>
|
61
|
+
<tr>
|
62
|
+
<td>Webtext</td><td>X</td><td>X</td><td>_</td><td>_</td><td>_</td>
|
63
|
+
</tr>
|
64
|
+
</table>
|
65
|
+
|
66
|
+
<!-- <iframe width='561' height='300' frameborder='0' src='https://docs.google.com/spreadsheet/pub?key=0AvGdwcIrVUI9dDNOUkE5Mlo0VnJEcmJaYlRJRkg1aEE&single=true&gid=0&output=html&widget=true'></iframe> -->
|
67
|
+
** _Does_ __NOT__ _provide handset network status, so you can't check if a
|
68
|
+
subscriber is in reception zone with a switched-on handset._
|
69
|
+
|
70
|
+
__Installation__
|
71
|
+
|
72
|
+
gem install smshelper
|
73
|
+
|
74
|
+
__Usage__
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
require 'smshelper'
|
78
|
+
config = Smshelper::Config.new(
|
79
|
+
:webtext => {:uname => '', :passwd => ''},
|
80
|
+
:bulksms => {:uname => '', :passwd => ''},
|
81
|
+
:clickatell => {:api_key => '',:uname => '', :passwd => ''},
|
82
|
+
:textmagic => {:uname => '', :passwd => ''},
|
83
|
+
:smstrade => {:api_key => ''},
|
84
|
+
:esendex => {:uname => '', :passwd => '', :acc => ''},
|
85
|
+
:mediaburst => {:uname => '', :passwd => ''},
|
86
|
+
:nexmo => {:uname => '', :passwd => ''}
|
87
|
+
)
|
88
|
+
|
89
|
+
service0 = Smshelper::Api::Bulksms.new config
|
90
|
+
service1 = Smshelper::Api::Webtext.new config
|
91
|
+
service2 = Smshelper::Api::Clickatell.new config
|
92
|
+
service3 = Smshelper::Api::Textmagic.new config
|
93
|
+
service4 = Smshelper::Api::Smstrade.new config, :route => 'gold'
|
94
|
+
service5 = Smshelper::Api::Esendex.new config, 'com:validityperiod' => '1'
|
95
|
+
service6 = Smshelper::Api::MediaBurst.new config
|
96
|
+
service7 = Smshelper::Api::Nexmo.new config, :ttl => '60000'
|
97
|
+
|
98
|
+
message = Smshelper::Message.new(
|
99
|
+
:recipient => '14128765432',
|
100
|
+
:text => "The balance on
|
101
|
+
#{serviceX.class.name} is
|
102
|
+
#{serviceX.get_balance}",
|
103
|
+
:sender => '33765432132')
|
104
|
+
|
105
|
+
serviceX.send_message message
|
106
|
+
|
107
|
+
```
|
108
|
+
|
109
|
+
### Is It "Production Ready™"?
|
110
|
+
|
111
|
+
Most likely not, there are no tests yet and the API is going
|
112
|
+
to change a bit until v1.0.0 release
|
113
|
+
|
114
|
+
__TODO:__
|
115
|
+
|
116
|
+
* TESTs
|
117
|
+
* introduce plugin infrastructure
|
118
|
+
* handle sms of any size (_currently smshelper tries to use concat
|
119
|
+
setts, operator permitting_)
|
120
|
+
* add support for www.totext.net, www.world-text.com, www.mpulse.eu, www.clicksms.co.uk, www.tellustalk.com, www.tm4b.com, www.txtnation.com, www.smsextrapro.com, www.truesenses.com
|
121
|
+
|
122
|
+
### I welcome pull requests!
|
data/Rakefile
CHANGED
@@ -17,8 +17,8 @@ Jeweler::Tasks.new do |gem|
|
|
17
17
|
gem.name = "smshelper"
|
18
18
|
gem.homepage = "http://github.com/voipscout/smshelper"
|
19
19
|
gem.license = "MIT"
|
20
|
-
gem.summary = %Q{send sms with
|
21
|
-
gem.description = %Q{
|
20
|
+
gem.summary = %Q{send sms with 10+ gateways}
|
21
|
+
gem.description = %Q{send sms with multiple gateways, like esendex, bulksms, clickatell etc..}
|
22
22
|
gem.email = "voipscout@gmail.com"
|
23
23
|
gem.authors = ["Voip Scout"]
|
24
24
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.6
|
data/lib/smshelper/api.rb
CHANGED
@@ -1,26 +1,31 @@
|
|
1
|
-
require '
|
1
|
+
require 'virtus'
|
2
2
|
|
3
3
|
module Smshelper
|
4
4
|
module Api
|
5
5
|
path = (File.dirname File.expand_path(__FILE__))
|
6
|
-
VERSION = '0.0.
|
6
|
+
VERSION = '0.0.2'#File.read('blahblah')
|
7
7
|
|
8
8
|
autoload :Base, "#{path}/api/base"
|
9
9
|
autoload :ResponseCodes, "#{path}/api/response_codes"
|
10
|
-
|
10
|
+
|
11
11
|
autoload :Bulksms, "#{path}/api/bulksms"
|
12
|
-
autoload :Clickatell, "#{path}/api/clickatell"
|
13
12
|
autoload :Textmagic, "#{path}/api/textmagic"
|
14
13
|
autoload :Smstrade, "#{path}/api/smstrade"
|
15
14
|
autoload :Esendex, "#{path}/api/esendex"
|
16
15
|
autoload :Mediaburst, "#{path}/api/mediaburst"
|
17
16
|
autoload :Nexmo, "#{path}/api/nexmo"
|
18
|
-
autoload :Traitel, "#{path}/api/traitel"
|
19
|
-
|
20
17
|
autoload :Aql, "#{path}/api/aql"
|
21
18
|
autoload :Vianett, "#{path}/api/vianett"
|
22
|
-
autoload :Txtnation, "#{path}/api/txtnation"
|
23
|
-
autoload :Totext, "#{path}/api/totext"
|
24
19
|
autoload :Mycoolsms, "#{path}/api/mycoolsms"
|
20
|
+
autoload :Routomessaging, "#{path}/api/routomessaging"
|
21
|
+
# Still no support for get_callback_response
|
22
|
+
|
23
|
+
autoload :Traitel, "#{path}/api/traitel"
|
24
|
+
autoload :Clickatell, "#{path}/api/clickatell"
|
25
|
+
autoload :Webtext, "#{path}/api/webtext"
|
26
|
+
#TODO:
|
27
|
+
#autoload :Txtnation, "#{path}/api/txtnation"
|
28
|
+
#autoload :Totext, "#{path}/api/totext"
|
29
|
+
#autoload :Smswarehouse, "#{path}/api/smswarehouse"
|
25
30
|
end
|
26
31
|
end
|
data/lib/smshelper/api/base.rb
CHANGED
@@ -9,9 +9,9 @@ module Smshelper
|
|
9
9
|
def initialize(*args)
|
10
10
|
@sent_message_ids, @sent_message_statuses = Array.new, Hash.new
|
11
11
|
@response_code = ResponseCodes.new
|
12
|
-
@extra_options = args.shift
|
12
|
+
@extra_options = (args.empty? ? {} : args.shift)
|
13
13
|
@uuid = UUID.new
|
14
|
-
class_factory 'DeliveryReport', 'InboundMessage', 'UnknownReply'
|
14
|
+
class_factory 'DeliveryReport', 'InboundMessage', 'UnknownReply', 'HlrReport'
|
15
15
|
end
|
16
16
|
|
17
17
|
protected
|
@@ -19,31 +19,52 @@ module Smshelper
|
|
19
19
|
names.each do |name|
|
20
20
|
klass = self.class.const_set(name, Class.new)
|
21
21
|
klass.class_eval do
|
22
|
-
|
22
|
+
include Virtus
|
23
23
|
|
24
24
|
define_method(:initialize) do |args = {}|
|
25
25
|
args.each do |k,v|
|
26
|
+
# Sinatra params has splat, captures
|
26
27
|
unless k.to_s =~ (/splat/ || /captures/)
|
27
|
-
self.class.
|
28
|
-
instance_variable_set("@"+k.to_s, v)
|
28
|
+
self.class.attribute(k, v.class, :default => v)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
#TODO: Find out why is this needed!
|
36
|
-
define_method("_dump".to_sym) do |level|
|
37
|
-
self.to_yaml
|
38
|
-
end
|
39
|
-
|
40
|
-
def self._load(str)
|
41
|
-
YAML.load str
|
31
|
+
self.class.attribute(:uuid, String, :default => UUID.generate)
|
32
|
+
self.class.attribute(:service, String, :default => self.class.name.split('::')[2])
|
42
33
|
end
|
43
34
|
|
44
35
|
end
|
45
36
|
end
|
46
37
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
38
|
+
|
39
|
+
# def class_factory(*names)
|
40
|
+
# names.each do |name|
|
41
|
+
# klass = self.class.const_set(name, Class.new)
|
42
|
+
# klass.class_eval do
|
43
|
+
# attr_reader :uuid, :service
|
44
|
+
|
45
|
+
# define_method(:initialize) do |args = {}|
|
46
|
+
# args.each do |k,v|
|
47
|
+
# unless k.to_s =~ (/splat/ || /captures/)
|
48
|
+
# self.class.send(:define_method, k.to_sym) {v}
|
49
|
+
# instance_variable_set("@"+k.to_s, v)
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
# instance_variable_set("@uuid", UUID.generate)
|
53
|
+
# instance_variable_set("@service", self.class.name.split('::')[2])
|
54
|
+
# end
|
55
|
+
|
56
|
+
# define_method("_dump".to_sym) do |level|
|
57
|
+
# self.to_yaml
|
58
|
+
# end
|
59
|
+
|
60
|
+
# def self._load(str)
|
61
|
+
# YAML.load str
|
62
|
+
# end
|
63
|
+
|
64
|
+
# end
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
|
68
|
+
end # class Base
|
69
|
+
end # module Api
|
70
|
+
end # module Smshelper
|
@@ -21,7 +21,7 @@ module Smshelper
|
|
21
21
|
:msisdn => message.recipient,
|
22
22
|
:message => message.text,
|
23
23
|
:sender => message.sender}
|
24
|
-
options
|
24
|
+
options.merge!(@extra_options) unless @extra_options.nil?
|
25
25
|
resp = (post 'eapi/submission/send_sms/2/2.0', :extra_query => options.merge(q)).split('|')
|
26
26
|
process_response_code(resp.first) ? (@sent_message_ids << resp.last.strip; resp.last.strip) : (raise ErrorDuringSend, @response_code.bulksms(resp.first))
|
27
27
|
end
|
@@ -24,6 +24,10 @@ module Smshelper
|
|
24
24
|
{'EUR' => JSON.parse(post 'api-socket.php', :extra_query => {:function => 'getBalance'})['balance']}
|
25
25
|
end
|
26
26
|
|
27
|
+
def get_status
|
28
|
+
raise NotImplementedError, "Sms status checks unsupported by #{self.class.name}"
|
29
|
+
end
|
30
|
+
|
27
31
|
def hlr_lookup(number)
|
28
32
|
JSON.parse(post 'api-socket.php', :extra_query => {:function => 'doHlrLookup', :number => number})
|
29
33
|
end
|
data/lib/smshelper/api/nexmo.rb
CHANGED
@@ -174,6 +174,69 @@ module Smshelper
|
|
174
174
|
|
175
175
|
AQL = {}
|
176
176
|
|
177
|
+
ROUTO = {
|
178
|
+
'0' => 'Delivered',
|
179
|
+
'1' => 'Rejected: Message length is invalid',
|
180
|
+
'2' => 'Subscriber absent',
|
181
|
+
'3' => 'Device memory capacity exceeded',
|
182
|
+
'4' => 'Equipment protocol error',
|
183
|
+
'5' => 'Equipment not supported',
|
184
|
+
'6' => 'Equipment not SM equipped',
|
185
|
+
'7' => 'Unknown service centre',
|
186
|
+
'8' => 'Service centre congestion',
|
187
|
+
'9' => 'Undeliverable',
|
188
|
+
'10' => 'Rejected: Invalid source address',
|
189
|
+
'11' => 'Invalid destination address',
|
190
|
+
'12' => 'Illegal subscriber',
|
191
|
+
'13' => 'Teleservice not provisioned',
|
192
|
+
'14' => 'Illegal equipment',
|
193
|
+
'15' => 'Call barred',
|
194
|
+
'16' => 'Facility not supported',
|
195
|
+
'17' => 'Subscriber busy for SM',
|
196
|
+
'18' => 'System failure',
|
197
|
+
'19' => 'Message waiting, list full',
|
198
|
+
'20' => 'Data missing',
|
199
|
+
'21' => 'Unexpected data value',
|
200
|
+
'22' => 'Resource limitation',
|
201
|
+
'23' => 'Initiating release',
|
202
|
+
'24' => 'Unknown alphabet',
|
203
|
+
'25' => 'USSD busy',
|
204
|
+
'26' => 'Duplicated invoke ID',
|
205
|
+
'27' => 'No supported service',
|
206
|
+
'28' => 'Mistyped parameter',
|
207
|
+
'29' => 'Unexpected response from peer',
|
208
|
+
'30' => 'Service completion failure',
|
209
|
+
'31' => 'No response from peer',
|
210
|
+
'32' => 'Invalid response received',
|
211
|
+
'34' => 'Invalid destination',
|
212
|
+
'49' => 'Message type not supported',
|
213
|
+
'50' => 'Destination blocked for sending',
|
214
|
+
'51' => 'Not enough money',
|
215
|
+
'52' => 'No price',
|
216
|
+
'67' => 'Invalid esm_class field data',
|
217
|
+
'69' => 'Rejected by SMSC',
|
218
|
+
'72' => 'Rejected: Invalid source address TON',
|
219
|
+
'73' => 'Rejected: Invalid source address NPI',
|
220
|
+
'80' => 'Rejected: Invalid destination address TON',
|
221
|
+
'81' => 'Rejected: Invalid destination address NPI',
|
222
|
+
'88' => 'Throttling error',
|
223
|
+
'97' => 'Rejected: Invalid scheduled delivery time',
|
224
|
+
'100' => 'Error sending message',
|
225
|
+
'247' => 'Sent',
|
226
|
+
'248' => 'Sent',
|
227
|
+
'249' => 'Rejected',
|
228
|
+
'250' => 'Accepted',
|
229
|
+
'251' => 'Undeliverable',
|
230
|
+
'252' => 'Deleted',
|
231
|
+
'253' => 'Expired',
|
232
|
+
'254' => 'Roaming level not supported',
|
233
|
+
'255' => 'Unknown error'
|
234
|
+
}
|
235
|
+
def routomessaging(code)
|
236
|
+
# Those are delivery callback status codes
|
237
|
+
ROUTO[code]
|
238
|
+
end
|
239
|
+
|
177
240
|
def webtext(code)
|
178
241
|
WEBTEXT[code]
|
179
242
|
end
|
@@ -1,30 +1,67 @@
|
|
1
1
|
#TODO: different base_uri's for get_balance and send_message
|
2
|
-
module
|
3
|
-
|
4
|
-
|
2
|
+
module Smshelper
|
3
|
+
module Api
|
4
|
+
class Routomessaging < Base
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(*args)
|
7
|
+
config = args.shift
|
8
|
+
@uname, @passwd = config.routomessaging[:uname], config.routomessaging[:passwd]
|
9
|
+
add_request_options! :skip_endpoint => true
|
10
|
+
super
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
#send_message TO, MESSAGE, FROM
|
14
|
+
def send_message(message)
|
15
|
+
uuid = (Digest::CRC32.hexdigest @uuid.generate).unpack('U*').collect {|x| sprintf '%02X', x}.join
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
if message.utf_8
|
18
|
+
message.to_hex_be
|
19
|
+
q = {:type => 'longunicode'}
|
20
|
+
else
|
21
|
+
q = {:type => 'LongSMS'}
|
22
|
+
end
|
23
|
+
|
24
|
+
options = {
|
25
|
+
:number => message.recipient,
|
26
|
+
:message => message.text,
|
27
|
+
:ownnum => message.sender
|
28
|
+
}
|
29
|
+
options.merge!(@extra_options) unless @extra_options.nil?
|
30
|
+
options.merge!(:mess_id => uuid) if options[:delivery]
|
31
|
+
options.merge!(:user => @uname, :pass => @passwd)
|
32
|
+
|
33
|
+
resp = (post 'http://smsc5.routotelecom.com/NewSMSsend', :extra_query => options.merge(q))
|
34
|
+
process_response_code(resp) ? (@sent_message_ids << uuid; uuid) : (raise ErrorDuringSend, 'error response processing not implemented yet')
|
35
|
+
end
|
19
36
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
37
|
+
def get_balance
|
38
|
+
opts = {:username => @uname, :password => @passwd}
|
39
|
+
{'EUR' => (post 'http://smsc6.routotelecom.com/balance.php', :extra_query => opts).gsub("\n", '').to_f.round(4)}
|
40
|
+
end
|
24
41
|
|
25
|
-
(
|
42
|
+
def hlr_lookup(number)
|
43
|
+
opts = {:number => number, :user => @uname, :pass => @passwd}
|
44
|
+
(get 'http://hlr.routotelecom.com', :extra_query => opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_callback_response(args = {})
|
48
|
+
DeliveryReport.new(
|
49
|
+
:message_id => args['mess_id'],
|
50
|
+
:timestamp => Time.now,
|
51
|
+
:delivered => ((args['status'] == '0') ? true : false),
|
52
|
+
:status => @response_code.routomessaging(args['status']),
|
53
|
+
:original_params => args
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_status
|
58
|
+
raise NotImplementedError, "Sms status checks unsupported by #{self.class.name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def process_response_code(code)
|
63
|
+
(code.gsub!("\n", '') == 'success') ? true : false
|
64
|
+
end
|
26
65
|
end
|
27
66
|
end
|
28
67
|
end
|
29
|
-
|
30
|
-
#
|
@@ -1,22 +1,25 @@
|
|
1
1
|
module Smshelper
|
2
2
|
module Api
|
3
3
|
class Smswarehouse < Base
|
4
|
-
base_uri "http://websms.smswarehouse.com:7800"
|
5
|
-
endpoint "websms"
|
4
|
+
# base_uri "http://websms.smswarehouse.com:7800"
|
5
|
+
# endpoint "websms"
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(*args)
|
8
|
+
config = args.shift
|
8
9
|
@uname, @passwd = config.smswarehouse[:uname], config.smswarehouse[:passwd]
|
10
|
+
add_request_options! :skip_endpoint => true
|
9
11
|
super
|
10
12
|
end
|
11
13
|
|
12
14
|
def send_message(message)
|
13
15
|
|
14
16
|
if message.utf_8
|
15
|
-
message.
|
16
|
-
|
17
|
+
message.to_hex_be
|
18
|
+
q = {:type => '0', :esm => '64', :dcs => '8'}
|
17
19
|
# raise NotImplementedError, "UTF-8 unsupported by #{self.class.name}"
|
18
20
|
else
|
19
|
-
|
21
|
+
#q = {:type => '5', :esm => '64', :dcs => '0'}
|
22
|
+
q = {:type => '1', :esm => '0', :dcs => '0'}
|
20
23
|
end
|
21
24
|
|
22
25
|
options = {
|
@@ -26,19 +29,25 @@ module Smshelper
|
|
26
29
|
:text => message.text,
|
27
30
|
:sid => message.sender}
|
28
31
|
|
29
|
-
|
32
|
+
options.merge!(@extra_options) unless @extra_options.nil?
|
33
|
+
|
34
|
+
url = 'http://websms.smswarehouse.com:7800/websms/webmsg'
|
35
|
+
resp = (post url, :extra_query => q.merge(options)) #.split('::').last.strip
|
30
36
|
@sent_message_ids << resp
|
37
|
+
pp resp
|
31
38
|
resp
|
32
39
|
end
|
33
40
|
|
34
41
|
def get_balance
|
35
|
-
|
36
|
-
|
42
|
+
opts = {:userid => @uname, :password => @passwd}
|
43
|
+
url = 'http://websms.smswarehouse.com:7800/websms/balanceReport'
|
44
|
+
{'EUR' => (post url, :extra_query => opts).split(/\n/).last.split('::').last.strip}
|
37
45
|
end
|
38
46
|
|
39
47
|
def get_status(message_id)
|
48
|
+
url = 'http://websms.smswarehouse.com:7800/websms/websmsstatus'
|
40
49
|
options = {:userid => @uname, :password => @passwd}
|
41
|
-
resp = (post
|
50
|
+
resp = (post url, :extra_query => {:respid => message_id.to_s}.merge(options)).split('-')[1].strip
|
42
51
|
@sent_message_statuses[message_id] = []
|
43
52
|
[resp].each_with_index do |status, index|
|
44
53
|
@sent_message_statuses[message_id] << {"part #{index}" => resp}
|
@@ -46,6 +55,28 @@ module Smshelper
|
|
46
55
|
{message_id => @sent_message_statuses[message_id]}
|
47
56
|
end
|
48
57
|
|
58
|
+
def get_callback_response(args = {})
|
59
|
+
if args['notificationType'] == 'MessageReceived'
|
60
|
+
InboundMessage.new(
|
61
|
+
:message_id => args['id'],
|
62
|
+
:sender => args['originator'],
|
63
|
+
:recipient => args['recipient'],
|
64
|
+
:text => args['body'],
|
65
|
+
:timestamp => Time.now,
|
66
|
+
:original_params => args
|
67
|
+
)
|
68
|
+
elsif args['notificationType'] == 'MessageEvent'
|
69
|
+
DeliveryReport.new(
|
70
|
+
:message_id => args['id'],
|
71
|
+
:timestamp => Time.now,
|
72
|
+
:delivered => ((args['eventType'] == 'Delivered') ? true : false),
|
73
|
+
:original_params => args
|
74
|
+
)
|
75
|
+
else
|
76
|
+
UnknownReply.new(args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
49
80
|
private
|
50
81
|
def process_response_code(code)
|
51
82
|
(code == 'DELIVRD') ? true : false
|
@@ -21,9 +21,7 @@ module Smshelper
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def get_status(message_id)
|
24
|
-
|
25
|
-
@sent_message_statuses[message_id] << {"Part 01" => @api.message_status(message_id)}
|
26
|
-
{message_id => @sent_message_statuses[message_id]}
|
24
|
+
raise NotImplementedError, "Sms status checks unsupported by #{self.class.name}"
|
27
25
|
end
|
28
26
|
|
29
27
|
def get_callback_response(args = {})
|
@@ -23,7 +23,7 @@ module Smshelper
|
|
23
23
|
:output => :verbose,
|
24
24
|
:concatenate => true
|
25
25
|
}
|
26
|
-
options
|
26
|
+
options.merge!(@extra_options) unless @extra_options.nil?
|
27
27
|
resp = (get 'smsgateway.pl', :extra_query => options.merge(q))
|
28
28
|
process_response_code(resp) ? (@sent_message_ids << resp.split(',')[2]; resp.split(',')[2]) : (raise ErrorDuringSend "Could not deliver")
|
29
29
|
end
|
@@ -36,6 +36,15 @@ module Smshelper
|
|
36
36
|
raise NotImplementedError, "Sms status checks unsupported by #{self.class.name}"
|
37
37
|
end
|
38
38
|
|
39
|
+
def get_callback_response(args = {})
|
40
|
+
DeliveryReport.new(
|
41
|
+
:message_id => args['tt_id'],
|
42
|
+
:timestamp => Time.now,
|
43
|
+
:delivered => ((args['code'] == '0') ? true : false),
|
44
|
+
:original_params => args
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
39
48
|
private
|
40
49
|
def process_response_code(code)
|
41
50
|
code =~ /accepted/ ? true : false
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Smshelper
|
2
2
|
module Api
|
3
3
|
class Vianett < Base
|
4
|
-
base_uri 'http://smsc.vianett.no/V3/CPA/MT'
|
5
4
|
|
6
5
|
def initialize(*args)
|
7
6
|
config = args.shift
|
8
7
|
add_query_options! :username => config.vianett[:uname], :password => config.vianett[:passwd]
|
8
|
+
add_request_options! :skip_endpoint => true
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
@@ -13,28 +13,50 @@ module Smshelper
|
|
13
13
|
uuid = (Digest::CRC32.hexdigest @uuid.generate).unpack('U*').collect {|x| sprintf '%02X', x}.join
|
14
14
|
|
15
15
|
options = {
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
16
|
+
:tel => message.recipient,
|
17
|
+
:msg => message.text,
|
18
|
+
:senderaddress => message.sender,
|
19
|
+
:senderaddresstype => '1',
|
20
|
+
:nrq => '1',
|
19
21
|
# :refno => '1',
|
20
22
|
:msgid => uuid}
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
binding.pry
|
24
|
+
options.merge!(@extra_options) unless @extra_options.nil?
|
25
|
+
resp = (post 'http://smsc.vianett.no/V3/CPA/MT/MT.ashx', :extra_query => options)
|
26
|
+
process_response_code(resp) ? (@sent_message_ids << uuid; uuid) : (raise ErrorDuringSend, "#{self.class.name} does not implement detailed error reporting - #{resp}")
|
24
27
|
end
|
25
28
|
|
26
29
|
def get_balance
|
27
|
-
{
|
30
|
+
{'EUR' => (post 'http://oldsms.vianett.com/files/balancelimit_check.asp').split('|').last}
|
28
31
|
end
|
29
32
|
|
33
|
+
# Vianett provides async lookup as well with callbacks
|
34
|
+
def hlr_lookup_synchronous(number)
|
35
|
+
opts = {:phonenumber => number}
|
36
|
+
(get 'http://smsc.vianett.no/v3/cpa/cpawebservice.asmx/SubmitHLR2', :extra_query => opts )['SubmitHLRResponse']
|
37
|
+
end
|
38
|
+
alias_method :hlr_lookup, :hlr_lookup_synchronous
|
39
|
+
|
30
40
|
def get_status(message_id)
|
31
41
|
raise NotImplementedError, "Sms status checks unsupported by #{self.class.name}"
|
32
42
|
end
|
33
43
|
|
34
|
-
|
44
|
+
def get_callback_response(args = {})
|
45
|
+
if args['requesttype'] == 'notificationstatus'
|
46
|
+
DeliveryReport.new(
|
47
|
+
:message_id => args['refno'],
|
48
|
+
:timestamp => Time.parse(args['now']),
|
49
|
+
:delivered => ((args['Status'] == 'DELIVRD') ? true : false),
|
50
|
+
:original_params => args
|
51
|
+
)
|
52
|
+
else
|
53
|
+
UnknownReply.new(args)
|
54
|
+
end
|
55
|
+
end
|
35
56
|
|
57
|
+
private
|
36
58
|
def process_response_code(code)
|
37
|
-
(code == 'OK') ? true : false
|
59
|
+
(code['ack']['__content__'] == 'OK') ? true : false
|
38
60
|
end
|
39
61
|
|
40
62
|
end
|
data/smshelper.gemspec
CHANGED
@@ -5,23 +5,23 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "smshelper"
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Voip Scout"]
|
12
|
-
s.date = "2012-05-
|
13
|
-
s.description = "
|
12
|
+
s.date = "2012-05-31"
|
13
|
+
s.description = "send sms with multiple gateways, like esendex, bulksms, clickatell etc.."
|
14
14
|
s.email = "voipscout@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
17
|
-
"README.
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
21
|
".rspec",
|
22
22
|
"Gemfile",
|
23
23
|
"LICENSE.txt",
|
24
|
-
"README.
|
24
|
+
"README.md",
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
27
|
"lib/smshelper.rb",
|
@@ -55,7 +55,7 @@ Gem::Specification.new do |s|
|
|
55
55
|
s.licenses = ["MIT"]
|
56
56
|
s.require_paths = ["lib"]
|
57
57
|
s.rubygems_version = "1.8.24"
|
58
|
-
s.summary = "send sms with
|
58
|
+
s.summary = "send sms with 10+ gateways"
|
59
59
|
|
60
60
|
if s.respond_to? :specification_version then
|
61
61
|
s.specification_version = 3
|
@@ -67,6 +67,7 @@ Gem::Specification.new do |s|
|
|
67
67
|
s.add_runtime_dependency(%q<textmagic>, [">= 0"])
|
68
68
|
s.add_runtime_dependency(%q<uuid>, [">= 0"])
|
69
69
|
s.add_runtime_dependency(%q<digest-crc>, [">= 0"])
|
70
|
+
s.add_runtime_dependency(%q<virtus>, [">= 0"])
|
70
71
|
s.add_development_dependency(%q<pry>, [">= 0"])
|
71
72
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
72
73
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
@@ -80,6 +81,7 @@ Gem::Specification.new do |s|
|
|
80
81
|
s.add_dependency(%q<textmagic>, [">= 0"])
|
81
82
|
s.add_dependency(%q<uuid>, [">= 0"])
|
82
83
|
s.add_dependency(%q<digest-crc>, [">= 0"])
|
84
|
+
s.add_dependency(%q<virtus>, [">= 0"])
|
83
85
|
s.add_dependency(%q<pry>, [">= 0"])
|
84
86
|
s.add_dependency(%q<rspec>, [">= 0"])
|
85
87
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
@@ -94,6 +96,7 @@ Gem::Specification.new do |s|
|
|
94
96
|
s.add_dependency(%q<textmagic>, [">= 0"])
|
95
97
|
s.add_dependency(%q<uuid>, [">= 0"])
|
96
98
|
s.add_dependency(%q<digest-crc>, [">= 0"])
|
99
|
+
s.add_dependency(%q<virtus>, [">= 0"])
|
97
100
|
s.add_dependency(%q<pry>, [">= 0"])
|
98
101
|
s.add_dependency(%q<rspec>, [">= 0"])
|
99
102
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smshelper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: api_smith
|
@@ -107,6 +107,22 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: virtus
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
110
126
|
- !ruby/object:Gem::Dependency
|
111
127
|
name: pry
|
112
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,21 +219,19 @@ dependencies:
|
|
203
219
|
- - ! '>='
|
204
220
|
- !ruby/object:Gem::Version
|
205
221
|
version: '0'
|
206
|
-
description:
|
207
|
-
www.smstrade.eu, www.esendex.com, www.mediaburst.co.uk, www.nexmo.com, www.vianett.com,
|
208
|
-
www.traitel.com.au, www.my-cool-sms.com, www.aql.com
|
222
|
+
description: send sms with multiple gateways, like esendex, bulksms, clickatell etc..
|
209
223
|
email: voipscout@gmail.com
|
210
224
|
executables: []
|
211
225
|
extensions: []
|
212
226
|
extra_rdoc_files:
|
213
227
|
- LICENSE.txt
|
214
|
-
- README.
|
228
|
+
- README.md
|
215
229
|
files:
|
216
230
|
- .document
|
217
231
|
- .rspec
|
218
232
|
- Gemfile
|
219
233
|
- LICENSE.txt
|
220
|
-
- README.
|
234
|
+
- README.md
|
221
235
|
- Rakefile
|
222
236
|
- VERSION
|
223
237
|
- lib/smshelper.rb
|
@@ -261,7 +275,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
261
275
|
version: '0'
|
262
276
|
segments:
|
263
277
|
- 0
|
264
|
-
hash:
|
278
|
+
hash: 2305576144060548028
|
265
279
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
266
280
|
none: false
|
267
281
|
requirements:
|
@@ -273,7 +287,5 @@ rubyforge_project:
|
|
273
287
|
rubygems_version: 1.8.24
|
274
288
|
signing_key:
|
275
289
|
specification_version: 3
|
276
|
-
summary:
|
277
|
-
www.smstrade.eu, www.esendex.com, www.mediaburst.co.uk, www.nexmo.com, www.vianett.com,
|
278
|
-
www.traitel.com.au, www.my-cool-sms.com, www.aql.com'
|
290
|
+
summary: send sms with 10+ gateways
|
279
291
|
test_files: []
|
data/README.rdoc
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
= smshelper
|
2
|
-
A utility library to do SMS-MT
|
3
|
-
|
4
|
-
== Currently supported providers:
|
5
|
-
|
6
|
-
* www.bulksms.com
|
7
|
-
* www.webtext.com
|
8
|
-
* www.clickatell.com
|
9
|
-
* www.textmagic.com
|
10
|
-
* www.smstrade.eu
|
11
|
-
* www.esendex.com
|
12
|
-
* www.mediaburst.co.uk
|
13
|
-
* www.nexmo.com
|
14
|
-
* www.vianett.com
|
15
|
-
* www.traitel.com.au
|
16
|
-
* www.my-cool-sms.com
|
17
|
-
* www.aql.com
|
18
|
-
== Features
|
19
|
-
|
20
|
-
* NEW HLR lookup support via my-cool-sms
|
21
|
-
* unicode support - all operators
|
22
|
-
* send message
|
23
|
-
* check balance, all except vianett
|
24
|
-
* check sent message status - select operators only
|
25
|
-
== Installation
|
26
|
-
|
27
|
-
gem install smshelper
|
28
|
-
== Usage
|
29
|
-
|
30
|
-
require 'smshelper'
|
31
|
-
config = Smshelper::Config.new(
|
32
|
-
:webtext => {:uname => '', :passwd => ''},
|
33
|
-
:bulksms => {:uname => '', :passwd => ''},
|
34
|
-
:clickatell => {:api_key => '',:uname => '', :passwd => ''},
|
35
|
-
:textmagic => {:uname => '', :passwd => ''},
|
36
|
-
:smstrade => {:api_key => ''},
|
37
|
-
:esendex => {:uname => '', :passwd => '', :acc => ''},
|
38
|
-
:mediaburst => {:uname => '', :passwd => ''},
|
39
|
-
:nexmo => {:uname => '', :passwd => ''}
|
40
|
-
)
|
41
|
-
|
42
|
-
service0 = Smshelper::Api::Bulksms.new config
|
43
|
-
service1 = Smshelper::Api::Webtext.new config
|
44
|
-
service2 = Smshelper::Api::Clickatell.new config
|
45
|
-
service3 = Smshelper::Api::Textmagic.new config
|
46
|
-
service4 = Smshelper::Api::Smstrade.new config, :route => 'gold'
|
47
|
-
service5 = Smshelper::Api::Esendex.new config, 'com:validityperiod' => '1'
|
48
|
-
service6 = Smshelper::Api::MediaBurst.new config
|
49
|
-
service7 = Smshelper::Api::Nexmo.new config, :ttl => '60000'
|
50
|
-
|
51
|
-
message = Smshelper::Message.new(:recipient => '14128765432', :text => "The balance on #{serviceX.class.to_s} is #{serviceX.get_balance}", :sender => '33765432132')
|
52
|
-
serviceX.send_message message
|
53
|
-
== TODO:
|
54
|
-
|
55
|
-
* create tests
|
56
|
-
* refactor / rewrite class factories as modules
|
57
|
-
* handle sms of any size - operator specific settings
|
58
|
-
* add support for www.totext.net, www.world-text.com, www.mpulse.eu, www.clicksms.co.uk, www.tellustalk.com, www.tm4b.com, www.txtnation.com, www.smsextrapro.com, www.truesenses.com, www.routomessaging.net
|
59
|
-
== Contributing to smshelper
|
60
|
-
|
61
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
62
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
63
|
-
* Fork the project.
|
64
|
-
* Start a feature/bugfix branch.
|
65
|
-
* Commit and push until you are happy with your contribution.
|
66
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
67
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
68
|
-
|
69
|
-
== Copyright
|
70
|
-
|
71
|
-
Copyright (c) 2012 Voip Scout.
|