smess 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +87 -0
- data/LICENSE +20 -0
- data/README.md +114 -0
- data/lib/smess.rb +63 -0
- data/lib/smess/country_code_registry.rb +33 -0
- data/lib/smess/logging.rb +16 -0
- data/lib/smess/outputs/auto.rb +26 -0
- data/lib/smess/outputs/clickatell.rb +115 -0
- data/lib/smess/outputs/etisalatdemo.rb +61 -0
- data/lib/smess/outputs/global_mouth.rb +87 -0
- data/lib/smess/outputs/iconectiv.rb +48 -0
- data/lib/smess/outputs/ipx.rb +223 -0
- data/lib/smess/outputs/ipxus.rb +103 -0
- data/lib/smess/outputs/mblox.rb +155 -0
- data/lib/smess/outputs/mm7.rb +122 -0
- data/lib/smess/outputs/smsglobal.rb +70 -0
- data/lib/smess/outputs/test.rb +31 -0
- data/lib/smess/outputs/twilio.rb +69 -0
- data/lib/smess/sms.rb +25 -0
- data/lib/smess/utils.rb +91 -0
- data/lib/smess/version.rb +3 -0
- data/lib/string.rb +122 -0
- metadata +192 -0
data/lib/smess/sms.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Smess
|
2
|
+
class Sms
|
3
|
+
|
4
|
+
attr_accessor :to, :message, :originator, :output, :results
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
opts = args.first || {}
|
8
|
+
@to = opts.fetch(:to, nil)
|
9
|
+
@message = opts.fetch(:message, "")
|
10
|
+
@originator = opts.fetch(:originator, nil)
|
11
|
+
@output = opts.fetch(:output, "auto")
|
12
|
+
end
|
13
|
+
|
14
|
+
def deliver
|
15
|
+
out_class = output
|
16
|
+
out = ("Smess::#{out_class.to_s.camelize}").constantize.new
|
17
|
+
results = out.deliver_sms self
|
18
|
+
end
|
19
|
+
|
20
|
+
def delivered?
|
21
|
+
@results[:response_code] == "0" rescue false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/smess/utils.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Smess
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# cleans and forces the selected country prefix on the number given
|
8
|
+
# if international is set a lighter cleaning is done to preserve any existing country code
|
9
|
+
# this is not entirely problem-free for US area codes without leading 0.
|
10
|
+
def clean_phone(num)
|
11
|
+
num = num.to_s
|
12
|
+
|
13
|
+
return nil if /\{[a-z]+:.+\}/.match(num)
|
14
|
+
|
15
|
+
# make num all digits
|
16
|
+
num = num.gsub(/\D/,"")
|
17
|
+
|
18
|
+
if num.length > 0 && num[0..1] == "00"
|
19
|
+
num = num[2..-1]
|
20
|
+
elsif num.length > 0 && num[0] == "0"
|
21
|
+
# cut away leading zeros
|
22
|
+
num = num[1..-1] # while num[0] == "0"
|
23
|
+
# Add country code unless the start of the number is the correct country code
|
24
|
+
unless num[0..Smess.config.country_code.to_s.length-1] == Smess.config.country_code.to_s
|
25
|
+
num = Smess.config.country_code.to_s + num
|
26
|
+
end
|
27
|
+
elsif !Smess.config.international
|
28
|
+
# Add country code unless the start of the number is the correct country code
|
29
|
+
unless num[0..Smess.config.country_code.to_s.length-1] == Smess.config.country_code.to_s
|
30
|
+
num = Smess.config.country_code.to_s + num
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# number must be in a valid range
|
35
|
+
unless (10..15) === num.length
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
num
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
# returns an array of strings of gsm-compatible lengths
|
45
|
+
# performance issue: utf8_safe_split also loops over the split point
|
46
|
+
# this should be used when sending via concatenating providers
|
47
|
+
def split_sms(text)
|
48
|
+
return [text] unless text.sms_length > 160
|
49
|
+
|
50
|
+
result = []
|
51
|
+
while text.sms_length > 0
|
52
|
+
end_char = 151
|
53
|
+
part = ""
|
54
|
+
while part.sms_length < 152 && part != text
|
55
|
+
end_char = end_char + 1
|
56
|
+
part = text.utf8_safe_split(end_char)[0] || ""
|
57
|
+
end
|
58
|
+
result << part
|
59
|
+
text = text.utf8_safe_split(end_char)[1] || ""
|
60
|
+
end
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns an array of strings of <160 char lengths
|
65
|
+
# splits on whitespace and will mangle non-space whitespace
|
66
|
+
# this should be used when sending via non-concatenating providers
|
67
|
+
def separate_sms(text)
|
68
|
+
return [text] unless text.sms_length > 160
|
69
|
+
|
70
|
+
end_char = 160
|
71
|
+
result = []
|
72
|
+
while text.sms_length > end_char
|
73
|
+
part = ""
|
74
|
+
parts = text.utf8_safe_split(end_char)
|
75
|
+
text = parts[1]
|
76
|
+
splitpoint = end_char-parts[0].reverse.index(/[^\w-]+/)
|
77
|
+
split = parts[0].utf8_safe_split(splitpoint)
|
78
|
+
result << split[0].strip
|
79
|
+
text = (split[1]+text).strip rescue text
|
80
|
+
end
|
81
|
+
result << text
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def booleanize(value)
|
86
|
+
value.to_s.downcase == "true"
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
data/lib/string.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
class String
|
2
|
+
def to_underscore
|
3
|
+
self.gsub(/::/, '/').
|
4
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
5
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
6
|
+
tr("-", "_").
|
7
|
+
downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def valid_utf8?
|
12
|
+
!!unpack("U") rescue false
|
13
|
+
end
|
14
|
+
|
15
|
+
def utf8_safe_split(n)
|
16
|
+
if length <= n
|
17
|
+
[self, nil]
|
18
|
+
else
|
19
|
+
before = self[0, n]
|
20
|
+
after = self[n..-1]
|
21
|
+
until after.valid_utf8?
|
22
|
+
n = n - 1
|
23
|
+
before = self[0, n]
|
24
|
+
after = self[n..-1]
|
25
|
+
end
|
26
|
+
[before, after.empty? ? nil : after]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# like strlen but with SMS alphabet calculations
|
31
|
+
def sms_length
|
32
|
+
escaped = Regexp.escape('€|^{}[]~\\')
|
33
|
+
pattern = Regexp.new( "["+escaped+"]" )
|
34
|
+
|
35
|
+
self.length + self.scan(pattern).length
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def strip_nongsm_chars(replacement = "")
|
40
|
+
ret = self.dup
|
41
|
+
ret.strip_nongsm_chars!(replacement)
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
|
45
|
+
# Cleans a string to comply with the GSM alphabet
|
46
|
+
def strip_nongsm_chars!(replacement = "")
|
47
|
+
# Should this be a patch to String?
|
48
|
+
|
49
|
+
# keeping them here in canse I need them
|
50
|
+
#$basic_alpha = array(
|
51
|
+
# '@','£','$','¥','è','é','ù','ì','ò','Ç',"\n",'Ø','ø',"\r",'Å','å',
|
52
|
+
# 'Δ','_','Φ','Γ','Λ','Ω','Π','Ψ','Σ','Θ','Ξ','Æ','æ','ß','É',' ',
|
53
|
+
# '!','"','#','¤','%','&','\'','(',')','*','+',',','-','.','/','0',
|
54
|
+
# '1','2','3','4','5','6','7','8','9',':',';','<','=','>','?','¡',
|
55
|
+
# 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
56
|
+
# 'Q','R','S','T','U','V','W','X','Y','Z','Ä','Ö','Ñ','Ü','§','¿',
|
57
|
+
# 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
|
58
|
+
# 'q','r','s','t','u','v','w','x','y','z','ä','ö','ñ','ü','à'
|
59
|
+
#);
|
60
|
+
#$extended_alpha = array('|','^','€','{','}','[',']','~','\\');
|
61
|
+
#$all_alpha = array_merge($basic_alpha, $extended_alpha);
|
62
|
+
|
63
|
+
allowed = '@£$¥èéùìòÇ'+"\n"+'Øø'+"\r"+'ÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ'+' '+Regexp.escape('!"#¤%&\'()*+,-.')+'\/'+Regexp.escape('0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà|^€{}[]~\\')
|
64
|
+
|
65
|
+
map = {
|
66
|
+
/á|â|ã/ => "a",
|
67
|
+
/ê|ẽ|ë/ => "e",
|
68
|
+
/í|î|ï/ => "i",
|
69
|
+
/ó|ô|õ/ => "o",
|
70
|
+
/ú|ů|û/ => "u",
|
71
|
+
/ç/ => "Ç"
|
72
|
+
}
|
73
|
+
|
74
|
+
map.each do |key, value|
|
75
|
+
self.gsub!(key, value)
|
76
|
+
end
|
77
|
+
|
78
|
+
pattern = Regexp.new( "[^"+allowed+"]" )
|
79
|
+
self.gsub!(pattern,"")
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# cleans and adds the country prefix on the string given preserveing any existing country code
|
84
|
+
# this is not entirely problem-free for US area codes without leading 0.
|
85
|
+
# if force_country_code is set it forces the selected country prefix on the string given
|
86
|
+
# yes old, yes crappy, yes convoluted... legacy stuff, ok.
|
87
|
+
def msisdn(*args)
|
88
|
+
ret = self.dup
|
89
|
+
ret.msisdn!(*args)
|
90
|
+
ret.empty? ? nil : ret
|
91
|
+
end
|
92
|
+
def msisdn!(country_code = 1, force_country_code = false)
|
93
|
+
self.replace("") and return self if /\{[a-z]+:.+\}/.match(self) # custom crap
|
94
|
+
|
95
|
+
# make num all digits
|
96
|
+
self.gsub!(/\D/,"")
|
97
|
+
|
98
|
+
if length > 0 && self[0..1] == "00"
|
99
|
+
self.replace(self[2..-1])
|
100
|
+
elsif length > 0 && self[0] == "0"
|
101
|
+
# cut away leading zeros
|
102
|
+
self.replace(self[1..-1])
|
103
|
+
# Add country code unless the start of the number is the correct country code
|
104
|
+
unless self[0..country_code.to_s.length-1] == country_code.to_s
|
105
|
+
self.prepend(country_code.to_s)
|
106
|
+
end
|
107
|
+
elsif force_country_code
|
108
|
+
# Add country code unless the start of the number is the correct country code
|
109
|
+
unless self[0..country_code.to_s.length-1] == country_code.to_s
|
110
|
+
self.prepend(country_code.to_s)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# number must be in a valid range
|
115
|
+
unless (10..15) === self.length
|
116
|
+
self.replace("") and return self
|
117
|
+
end
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smess
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Westin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.4.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.4.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jahtml_formatter
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mail
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: savon
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: httpi
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: clickatell
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: twilio-ruby
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
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
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activesupport
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.0'
|
139
|
+
description: A mess of SMS messaging
|
140
|
+
email: martin@eimermusic.com
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- lib/smess/country_code_registry.rb
|
146
|
+
- lib/smess/logging.rb
|
147
|
+
- lib/smess/outputs/auto.rb
|
148
|
+
- lib/smess/outputs/clickatell.rb
|
149
|
+
- lib/smess/outputs/etisalatdemo.rb
|
150
|
+
- lib/smess/outputs/global_mouth.rb
|
151
|
+
- lib/smess/outputs/iconectiv.rb
|
152
|
+
- lib/smess/outputs/ipx.rb
|
153
|
+
- lib/smess/outputs/ipxus.rb
|
154
|
+
- lib/smess/outputs/mblox.rb
|
155
|
+
- lib/smess/outputs/mm7.rb
|
156
|
+
- lib/smess/outputs/smsglobal.rb
|
157
|
+
- lib/smess/outputs/test.rb
|
158
|
+
- lib/smess/outputs/twilio.rb
|
159
|
+
- lib/smess/sms.rb
|
160
|
+
- lib/smess/utils.rb
|
161
|
+
- lib/smess/version.rb
|
162
|
+
- lib/smess.rb
|
163
|
+
- lib/string.rb
|
164
|
+
- Gemfile
|
165
|
+
- Gemfile.lock
|
166
|
+
- LICENSE
|
167
|
+
- README.md
|
168
|
+
homepage: https://github.com/eimermusic/smess
|
169
|
+
licenses: []
|
170
|
+
metadata: {}
|
171
|
+
post_install_message:
|
172
|
+
rdoc_options: []
|
173
|
+
require_paths:
|
174
|
+
- lib
|
175
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: 1.9.2
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - '>='
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: 1.3.7
|
185
|
+
requirements: []
|
186
|
+
rubyforge_project:
|
187
|
+
rubygems_version: 2.0.2
|
188
|
+
signing_key:
|
189
|
+
specification_version: 4
|
190
|
+
summary: A messy SMS messenger supporting every aggregator I have gotten my hands
|
191
|
+
on
|
192
|
+
test_files: []
|