nofxx-activesms 0.9.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.
Files changed (56) hide show
  1. data/.autotest +17 -0
  2. data/CHANGELOG +5 -0
  3. data/History.txt +25 -0
  4. data/License.txt +22 -0
  5. data/MIT-LICENSE +22 -0
  6. data/Manifest.txt +56 -0
  7. data/README.txt +54 -0
  8. data/Rakefile +16 -0
  9. data/activesms.gemspec +36 -0
  10. data/config/hoe.rb +78 -0
  11. data/config/requirements.rb +15 -0
  12. the PDU format.webarchive +0 -0
  13. data/generators/sms/USAGE +20 -0
  14. data/generators/sms/sms_generator.rb +35 -0
  15. data/generators/sms/templates/fixture.rhtml +1 -0
  16. data/generators/sms/templates/model.rb +19 -0
  17. data/generators/sms/templates/sms.yml +103 -0
  18. data/generators/sms/templates/unit_test.rb +31 -0
  19. data/init.rb +4 -0
  20. data/lib/activesms.rb +79 -0
  21. data/lib/activesms/adv_attr_accessor.rb +32 -0
  22. data/lib/activesms/base.rb +249 -0
  23. data/lib/activesms/config.rb +20 -0
  24. data/lib/activesms/connection_adapters/abstract_adapter.rb +52 -0
  25. data/lib/activesms/connection_adapters/bulk_sms_adapter.rb +67 -0
  26. data/lib/activesms/connection_adapters/clickatell_adapter.rb +51 -0
  27. data/lib/activesms/connection_adapters/human_adapter.rb +174 -0
  28. data/lib/activesms/connection_adapters/simplewire_adapter.rb +73 -0
  29. data/lib/activesms/connections.rb +63 -0
  30. data/lib/activesms/email.rb +60 -0
  31. data/lib/activesms/exceptions.rb +35 -0
  32. data/lib/activesms/sms.rb +9 -0
  33. data/lib/activesms/sms2email.rb +21 -0
  34. data/lib/activesms/validations.rb +86 -0
  35. data/lib/activesms/version.rb +9 -0
  36. data/lib/activesms/views/active_sms/sms2_email/sms_message.html.erb +1 -0
  37. data/script/console +10 -0
  38. data/script/destroy +14 -0
  39. data/script/generate +14 -0
  40. data/script/txt2html +82 -0
  41. data/setup.rb +1585 -0
  42. data/spec/activesms/base_spec.rb +11 -0
  43. data/spec/activesms/connection_adapters/abstract_adapter_spec.rb +30 -0
  44. data/spec/activesms/connection_adapters/human_adapter_spec.rb +38 -0
  45. data/spec/activesms/connection_adapters/simplewire_spec.rb +75 -0
  46. data/spec/activesms/email_spec.rb +72 -0
  47. data/spec/activesms/sms2email_spec.rb +31 -0
  48. data/spec/activesms/sms_spec.rb +31 -0
  49. data/spec/activesms_spec.rb +15 -0
  50. data/spec/spec.opts +1 -0
  51. data/spec/spec_helper.rb +57 -0
  52. data/tasks/deployment.rake +34 -0
  53. data/tasks/environment.rake +7 -0
  54. data/tasks/rspec.rake +21 -0
  55. data/views/active_sms/base/sms2_email/sms_message.html.erb +1 -0
  56. metadata +130 -0
@@ -0,0 +1,67 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+
3
+ module ActiveSms
4
+ class Base
5
+ def self.bulk_sms_connection(config) #:nodoc:
6
+ return ConnectionAdapters::BulkSmsAdapter.new(logger, config)
7
+ end
8
+ end
9
+
10
+ module ConnectionAdapters
11
+ class BulkSmsAdapter < AbstractAdapter
12
+
13
+ SERVICE_HOSTS = {
14
+ :international => 'bulksms.vsms.net',
15
+ :safrica => 'bulksms.2way.co.za',
16
+ :spoin => 'bulksms.com.es',
17
+ :uk => 'www.bulksms.co.uk',
18
+ :usa => 'usa.bulksms.com'
19
+ }
20
+ SERVICE_PORT = 5567
21
+ SERVICE_PATH = '/eapi/submission/send_sms/2/2.0'
22
+
23
+ STATUS_MESSAGES = {
24
+ 0 => 'in progress',
25
+ 1 => 'scheduled',
26
+ 22 => 'internal fatal error',
27
+ 23 => 'authentication failure',
28
+ 24 => 'data validation failed',
29
+ 25 => 'insufficient credits',
30
+ 26 => 'upstream credits not available',
31
+ 27 => 'daily quota exceeded',
32
+ 28 => 'upstream quota exceeded',
33
+ 40 => 'temporarily unavailable'
34
+ }
35
+
36
+ # Create an adapter for the BulkSMS gateway.
37
+ #
38
+ # Options:
39
+ # * <tt>:region</tt>
40
+ # * <tt>:username</tt>
41
+ # * <tt>:password</tt>
42
+ def initialize(logger = nil, config = {})
43
+ super(logger)
44
+ @config = config.dup
45
+
46
+ host = SERVICE_HOSTS[config[:region]] || SERVICE_HOSTS[:uk]
47
+ @service_url = "http://#{host}:#{SERVICE_PORT}#{SERVICE_PATH}"
48
+ end
49
+
50
+ # Return the human readable name of the connection adapter name.
51
+ def adapter_name
52
+ return 'BulkSMS'
53
+ end
54
+
55
+ def deliver(sms)
56
+ params = {
57
+ :username => @config[:username],
58
+ :password => @config[:password],
59
+ :msisdn => sms.recipients,
60
+ :message => sms.body,
61
+ }
62
+ send_http_request(@service_url, params)
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,51 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+
3
+ module ActiveSms
4
+ class Base
5
+ def self.clickatell_connection(config) #:nodoc:
6
+ return ConnectionAdapters::ClickatellAdapter.new(logger, config)
7
+ end
8
+ end
9
+
10
+ module ConnectionAdapters
11
+ class ClickatellAdapter < AbstractAdapter
12
+
13
+ SERVICE_HOST = "api.clickatell.com"
14
+ SERVICE_PATH = "/http/sendmsg"
15
+
16
+ # Create an adapter for the Clickatell gateway.
17
+ #
18
+ # Options:
19
+ #
20
+ # * <tt>:user</tt>
21
+ # * <tt>:password</tt>
22
+ # * <tt>:api_id</tt>
23
+ # * <tt>use_ssl</tt>
24
+ def initialize(logger = nil, config = {})
25
+ super(logger)
26
+ @config = config.dup
27
+
28
+ scheme = config[:use_ssl] ? "https" : "http"
29
+ @service_url = "#{scheme}://#{SERVICE_HOST}#{SERVICE_PATH}"
30
+ end
31
+
32
+ # Return the human readable name of the gateway adapter name.
33
+ def adapter_name
34
+ return 'Clickatell'
35
+ end
36
+
37
+ def deliver(sms)
38
+ params = {
39
+ :user => @config[:user],
40
+ :password => @config[:password],
41
+ :api_id => @config[:api_id],
42
+ :to => sms.recipients,
43
+ :from => sms.from,
44
+ :text => sms.body
45
+ }
46
+ send_http_request(@service_url, params)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,174 @@
1
+ # #
2
+ # Human Gateway Adapter (www.human.com.br)
3
+ #
4
+ # Original code: Cassio Marques
5
+ # Merge with activesms: Marcos Piccinini
6
+ #
7
+ # 07/2008
8
+ #
9
+ # Configuracao para envio de mensagens SMS, de acordo com
10
+ # especificacoes no Manual de Integracao ao Human Gateway
11
+ require 'activesms/connection_adapters/abstract_adapter'
12
+
13
+ module ActiveSms
14
+ class Base
15
+ def self.human_connection(config) #:nodoc:
16
+ return ConnectionAdapters::HumanAdapter.new(logger, config)
17
+ end
18
+ end
19
+
20
+ module ConnectionAdapters
21
+ class HumanAdapter < AbstractAdapter
22
+ attr_reader :service_url
23
+
24
+ # As Human specification on 2008
25
+ SERVICE_HOST = "system.human.com.br"
26
+ SERVICE_PATH = "GatewayIntegration/msgSms.do"
27
+ SERVICE_PORT = "8080"
28
+ # Service options
29
+ SERVICE_TYPE = 'E'
30
+ SERVICE_DISPATCH = 'send'
31
+ # callbackOption: 1
32
+
33
+ # Create an adapter for the Human gateway.
34
+ #
35
+ # Options:
36
+ #
37
+ # * <tt>:account</tt>
38
+ # * <tt>:code</tt>
39
+ # * <tt>use_ssl (human does not support this as July/2008)</tt>
40
+ def initialize(logger = nil, config = {})
41
+ super(logger)
42
+ @config = config.dup
43
+
44
+ human_scheme = config[:use_ssl] ? 'https' : 'http'
45
+ @service_url = "#{human_scheme}://#{SERVICE_HOST}:#{SERVICE_PORT}/#{SERVICE_PATH}"
46
+ end
47
+
48
+ # Return the human readable name of the gateway adapter name.
49
+ def adapter_name
50
+ return 'Human'
51
+ end
52
+
53
+ # Formats the data object to what human gateway expects
54
+ def date_format_human(date)
55
+ date = Time.parse(date, Time.now.utc) unless date.respond_to?('strftime')
56
+ date.strftime("%d/%m/%Y %H:%M:%S")
57
+ end
58
+
59
+ # Deliver the message!
60
+ # :id => Reference to the message on human servers.j
61
+ # so we can check status later
62
+ # :schedule => expects a Date/Timestamp object
63
+ # if date is on the past message is immeditaly sent
64
+ def deliver(sms)
65
+ params = {
66
+ :dispatch => SERVICE_DISPATCH,
67
+ :type => SERVICE_TYPE,
68
+ :account => @config[:account],
69
+ :code => @config[:code],
70
+ :to => sms.recipients,
71
+ :from => sms.from || @config[:from],
72
+ :msg => sms.body,
73
+ :id => sms.id,
74
+ }
75
+ # Human supports scheduling
76
+ # if we got some date, share with em!
77
+ params[:schedule] = date_format_human(sms.schedule) if sms.schedule
78
+ # Send it!
79
+ send_http_request(@service_url, params)
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ # def initialize(logger = nil, config = {})
86
+ # super(logger)
87
+ # @config = config.dup
88
+ #
89
+ # human_scheme = config[:use_ssl] ? 'https' : 'http'
90
+ # @service_url = "#{human_scheme}://#{SERVICE_HOST}:#{SERVICE_PORT}/#{SERVICE_PATH}"
91
+ # #raise_not_configured_exception unless @@config && !@@config.empty?
92
+ # #@messages = []
93
+ # #@results = {}
94
+ # #@total_sent = 0
95
+ # end
96
+ #attr_reader :total_sent
97
+ # Define as configuracoes que serao utilizadas para realizar o envio
98
+ # das mensagens.
99
+ # #
100
+ # # Recebe um hash com os valores a configurar.
101
+ # def SmsSender.configure(config)
102
+ # @@config = config unless !@@config.nil?
103
+ # end
104
+ #
105
+ # # Exibe as configuracoes de envio atuais
106
+ # def self.show_configuration
107
+ # raise_not_configured_exception unless @@config
108
+ # puts @@config.inspect
109
+ # end
110
+ #
111
+ # # Adiciona um item na lista de mensagens a serem enviadas
112
+ # def add_message(message)
113
+ # unless message.kind_of? Sms
114
+ # raise ArgumentError,
115
+ # "Eu esperava receber um objeto da classe Sms, mas voce me enviou um #{message.class}",
116
+ # caller
117
+ # end
118
+ # @messages << message
119
+ # end
120
+ #
121
+ # # Realiza o envio de todas as mensagens.
122
+ # #
123
+ # # Salva no banco o status de cada SMS
124
+ # # apos a tentativa de envio.
125
+ # #
126
+ # # Retorna um hash com o id e o status de envio
127
+ # # de cada mensagem.
128
+ # def send_all
129
+ # @messages.each do |m|
130
+ # resp = run_request(m)
131
+ # m.status = SmsStatus.find(resp.slice(/\d{3}/))
132
+ # if block_given?
133
+ # yield m
134
+ # end
135
+ # m.save
136
+ # end
137
+ # end
138
+ #
139
+ # # Limpa a lista de mensagens a serem enviadas
140
+ # def clear_list
141
+ # @messages.clear
142
+ # end
143
+ #
144
+ # private
145
+ # # Lanca uma excecao indicando que esse sender nao foi devidamente
146
+ # # configurado antes de ser utilizado.
147
+ # def self.raise_not_configured_exception # :doc:
148
+ # raise RuntimeError, "Parametros para configuracao nao informados", caller
149
+ # end
150
+ #
151
+ # # Cria o header da requisicao (para envio de mensagens individuais)
152
+ # def create_request_header(message) # :doc:
153
+ # "dispatch=#{ERB::Util.url_encode(@@config['dispatch'])}"+
154
+ # "&account=#{ERB::Util.url_encode(@@config['account'])}"+
155
+ # "&code=#{ERB::Util.url_encode(@@config['password'])}"+
156
+ # "&msg=#{ERB::Util.url_encode(message.message_text)}"+
157
+ # "&from=#{ERB::Util.url_encode(@@config['from'])}"+
158
+ # "&to=#{ERB::Util.url_encode(message.doador.celular.full_number)}"+
159
+ # "&id=#{ERB::Util.url_encode(message.id)}"+
160
+ # "&schedule=#{ERB::Util.url_encode(message.agendado_para)}"
161
+ # end
162
+ #
163
+ # # Executa o request HTTP POST para envio da mensagem SMS
164
+ # def run_request(message) # :doc:
165
+ # http = Net::HTTP.new(@@config['base_url'], @@config['port'])
166
+ # headers = {
167
+ # 'Referer' => 'http://'+@@config['base_url']+@@config['path']
168
+ # }
169
+ # resp = http.post2(@@config['path'], create_request_header(message), headers)
170
+ # @total_sent += 1
171
+ # resp.body
172
+ # end
173
+ #
174
+ # end
@@ -0,0 +1,73 @@
1
+ require 'activesms/connection_adapters/abstract_adapter'
2
+ require 'ostruct'
3
+
4
+ begin
5
+ require 'java'
6
+ include_class 'com.simplewire.sms.SMS'
7
+ rescue LoadError
8
+ puts "JRuby is required for the simplewire adapter"
9
+ raise $!
10
+ end
11
+
12
+ module ActiveSms
13
+ class Base
14
+ def self.simplewire_connection(config) #:nodoc:
15
+ return ConnectionAdapters::SimplewireAdapter.new(logger, config)
16
+ end
17
+ end
18
+
19
+ module ConnectionAdapters
20
+ class SimplewireAdapter < AbstractAdapter
21
+
22
+ # Create a simplewire adapter. The config requires subscriber_id and subscriber_password.
23
+ def initialize(logger = nil, config = {})
24
+ super(logger)
25
+ @config = config.dup
26
+ @config.symbolize_keys!
27
+ @subscriber_id = @config[:subscriber_id]
28
+ @subscriber_password = @config[:subscriber_password]
29
+ @remote_host = @config[:remote_host]
30
+
31
+ if @subscriber_id.nil?
32
+ raise "subscriber_id is required for simplewire"
33
+ end
34
+ if @subscriber_password.nil?
35
+ raise "subscriber_password is required for simplewire"
36
+ end
37
+ end
38
+
39
+ # Return the human readable name of the gateway adapter name.
40
+ def adapter_name
41
+ return 'Simplewire'
42
+ end
43
+
44
+ # Send the sms message using the simplewire adapter
45
+ def deliver(sms)
46
+ create_sms(sms).submit()
47
+ end
48
+
49
+ def parse(xmldata)
50
+ sms = SMS.new
51
+ sms.parse(xmldata)
52
+ s = OpenStruct.new
53
+ s.body = sms.msg_text.to_s
54
+ s.from = sms.source_addr.address.to_s
55
+ s.to = sms.destination_addr.address.to_s
56
+ s
57
+ end
58
+
59
+ # Create the simplewire sms message to send
60
+ def create_sms(sms)
61
+ s = SMS.new
62
+ s.subscriber_id = @subscriber_id
63
+ s.subscriber_password = @subscriber_password
64
+ s.remote_host = @remote_host if @remote_host
65
+ s.msg_pin = sms.recipients
66
+ s.setSourceAddr(SMS::ADDR_TYPE_NETWORK, sms.from)
67
+ s.msg_text = sms.body
68
+ raise StandardError.new("SMS Body over 140 characters, body = \n#{sms.body}") if sms.body.size > 140
69
+ s
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,63 @@
1
+ module ActiveSms #:nodoc#
2
+
3
+ class Base
4
+ @@connection = nil
5
+
6
+ class << self
7
+ # Returns true if a connection that's accessible to this class has already
8
+ # been opened.
9
+ def connected?
10
+ return !@@connection.nil?
11
+ end
12
+
13
+ # Returns the connection currently associated with the class. This can
14
+ # also be used to "borrow" the connection to do work that is specific to
15
+ # a particular SMS gateway.
16
+ def connection
17
+ raise ConnectionNotEstablished unless @@connection
18
+ return @@connection
19
+ end
20
+
21
+ # Set the gateway connection for the class.
22
+ def connection=(spec) #:nodoc:
23
+ raise ConnectionNotEstablished unless spec
24
+ @@connection = spec
25
+ end
26
+
27
+ # Establishes the connection to the SMS gateway. Accepts a hash as input
28
+ # where the :adapter key must be specified with the name of a gateway
29
+ # adapter (in lower-case)
30
+ #
31
+ # ActiveSms::Base.establish_connection(
32
+ # :adapter => "clickatell",
33
+ # :username => "myusername",
34
+ # :password => "mypassword"
35
+ # :api_id => "myapiid"
36
+ # )
37
+ #
38
+ # Also accepts keys as strings (for parsing from YAML, for example).
39
+ #
40
+ # The exceptions AdapterNotSpecified, AdapterNotFound, and ArgumentError
41
+ # may be returned.
42
+ def establish_connection(config)
43
+ config = config.symbolize_keys
44
+ unless config.key?(:adapter)
45
+ raise AdapterNotSpecified, "#{config} adapter is not configured"
46
+ end
47
+ adapter_method = "#{config[:adapter]}_connection"
48
+ unless respond_to?(adapter_method)
49
+ raise AdapterNotFound,
50
+ "configuration specifies nonexistent #{config[:adapter]} adapter"
51
+ end
52
+ self.connection = self.send(adapter_method, config)
53
+ end
54
+ end
55
+
56
+ # Returns the connection currently associated with the class. This can
57
+ # also be used to "borrow" the connection to do work that is specific to
58
+ # a particular SMS gateway.
59
+ def connection
60
+ self.class.connection
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,60 @@
1
+ require 'yaml'
2
+ #require 'activesms/config'
3
+
4
+ module ActiveSms #:nodoc#
5
+ module Email
6
+ RAILS_CONFIG_ROOT = defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/config" : "#{File.dirname(__FILE__)}/../../generators/sms/templates" unless defined?(RAILS_CONFIG_ROOT)
7
+ # and load what we have!
8
+ conf_yml ||= YAML::load(File.open("#{RAILS_CONFIG_ROOT}/sms.yml"))
9
+ @@carriers ||= conf_yml['carriers']
10
+ @@from_address ||= conf_yml['config']['from_address']
11
+
12
+ def carriers
13
+ @@carriers.dup
14
+ end
15
+
16
+ def email_deliver(sms)#number,carrier,message,options={})
17
+
18
+ number = sms.recipients
19
+ carrier = sms.carrier
20
+ # number = format_number(number)
21
+
22
+ #options[:limit] ||= message.length
23
+ #options[:from] ||= @@from_address
24
+ #message = message[0..options[:limit]-1]
25
+ sms_email = determine_sms_email(number, carrier)#format_number(number),carrier)
26
+
27
+ Sms2Email.deliver_sms_message(sms_email, sms.body, @@from_address)
28
+ rescue CarrierException => e
29
+ raise e
30
+ end
31
+
32
+ def get_sms_address(number,carrier)
33
+ number = format_number(number)
34
+ determine_sms_email(number,carrier)
35
+ end
36
+
37
+ private
38
+
39
+ def format_number(number)
40
+ pre_formatted = number.gsub(/\D/,"").strip
41
+ formatted = (pre_formatted.length > 11) ? pre_formatted[2..pre_formatted.length] : pre_formatted
42
+
43
+ return is_valid?(formatted) ? formatted : (raise PhoneNumberError.new("Phone number (#{format_number(number)}) is not formatted correctly"))
44
+ end
45
+
46
+ def is_valid?(number)
47
+ return (number.length >= 10 && number[/^.\d+$/]) ? true : false
48
+ end
49
+
50
+ def determine_sms_email(phone_number, carrier)
51
+ carrier = carrier.to_s.downcase
52
+
53
+ if carriers.has_key?(carrier)
54
+ "#{phone_number}#{carriers[carrier]}"
55
+ else
56
+ raise CarrierException.new("Specified carrier, #{carrier} is not supported.")
57
+ end
58
+ end
59
+ end
60
+ end