summaryrefslogtreecommitdiff
path: root/contrib/smsweb/smswsc.rb
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/smsweb/smswsc.rb')
-rwxr-xr-xcontrib/smsweb/smswsc.rb341
1 files changed, 341 insertions, 0 deletions
diff --git a/contrib/smsweb/smswsc.rb b/contrib/smsweb/smswsc.rb
new file mode 100755
index 0000000..1800e13
--- /dev/null
+++ b/contrib/smsweb/smswsc.rb
@@ -0,0 +1,341 @@
+#!/usr/bin/env ruby1.8
+#
+# vim: set sw=2 ts=2 expandtab:
+#
+# SMS Web Service client example library
+#
+# Copyright (C) 2010 by James Maki
+#
+# Author: James Maki <jamescmaki@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+require 'rubygems'
+require 'net/http'
+require 'cgi'
+require 'inform'
+require 'smswsc/utils'
+require 'smswsc/phonebook_entry'
+require 'smswsc/sms_message'
+
+module SMSWSC
+ module Error
+ class General < RuntimeError; end
+ class HTTP < General; end
+ class XML < General; end
+ class BadRequest < General; end
+ class Unauthorized < General; end
+ class Forbidden < General; end
+ class NotFound < General; end
+ class ServiceUnavailable < General; end
+ end
+
+ SMSWS_PATH = "/smsws/v1"
+ PHONEBOOK_PATH = Utils.ref(SMSWS_PATH, "phonebook")
+ MESSAGES_PATH = Utils.ref(SMSWS_PATH, "messages")
+ SEND_PATH = Utils.ref(SMSWS_PATH, "send")
+
+ class Client
+ include Utils
+
+ DEFAULT_PORT = 5857
+ VERSION = '0.1'
+
+ attr_accessor :use_ssl
+ attr_accessor :http_debug
+ attr_accessor :http_read_timeout
+
+ def initialize(username, passwd, host, port = DEFAULT_PORT)
+ @host = host
+ @port = port
+ @username = username
+ @passwd = passwd
+ @error = ""
+ @headers = {
+ 'Content-Type' => 'application/xml',
+ 'User-Agent' => "smswsc/#{VERSION}",
+ }
+ @use_ssl = false
+ @http_debug = false
+ @http_read_timeout = 300
+ end
+
+ def user_agent(ua)
+ @headers['User-Agent'] = ua
+ end
+
+ def phonebook_query(path = PHONEBOOK_PATH)
+ case path
+ when PhonebookEntry
+ path = path.uri.to_s
+ when String
+ when URI
+ path = path.to_s
+ else
+ raise ArgumentError, "Invalid param type: #{path.class}"
+ end
+
+ phonebook = []
+
+ response = get_resource(path)
+
+ root = process_response(response, Net::HTTPOK)
+
+ root.elements.each("phonebook-entry") do |entry|
+ phonebook << PhonebookEntry.load_xml(entry)
+ end
+
+ return phonebook
+ end
+
+ def sms_messages_query(path = MESSAGES_PATH)
+ case path
+ when SMSMessage
+ path = path.uri.to_s
+ when String
+ when URI
+ path = path.to_s
+ else
+ raise ArgumentError, "Invalid param type: #{path.class}"
+ end
+
+ msgs = []
+
+ response = get_resource(path)
+
+ root = process_response(response, Net::HTTPOK)
+
+ root.elements.each("sms-message") do |entry|
+ msgs << SMSMessage.load_xml(entry)
+ end
+
+ return msgs
+ end
+
+ def sms_messages_delete(path = MESSAGES_PATH)
+ case path
+ when SMSMessage
+ path = path.uri.to_s
+ when String
+ when URI
+ path = path.to_s
+ else
+ raise ArgumentError, "Invalid param type: #{path.class}"
+ end
+
+ response = delete_resource(path)
+
+ root = process_response(response, Net::HTTPOK)
+
+ return true
+ end
+
+ def sms_send(msg)
+ response = post_resource(SEND_PATH, msg.to_xml)
+
+ root = process_response(response, Net::HTTPCreated)
+
+ return true
+ end
+
+ private
+
+ def process_response(response, klass)
+ root = response_xml(response)
+ if root
+ message = root.elements['status-message'].text
+ else
+ message = "response message not given"
+ end
+
+ unless response.instance_of?(klass)
+ if response.instance_of?(Net::HTTPBadRequest)
+ raise Error::BadRequest, "Bad Request: " + message
+ elsif response.instance_of?(Net::HTTPUnauthorized)
+ raise Error::Unauthorized, "Unauthorized: " + message
+ elsif response.instance_of?(Net::HTTPForbidden)
+ raise Error::Forbidden, "Forbidden: " + message
+ elsif response.instance_of?(Net::HTTPNotFound)
+ raise Error::NotFound, "Not Found: " + message
+ elsif response.instance_of?(Net::HTTPServiceUnavailable)
+ raise Error::ServiceUnavailable, "Service Unavailable: " + message
+ else
+ raise Error::General, "Failed to fulfill request: " + message
+ end
+ end
+
+ return root
+ end
+
+ def response_xml(response)
+ return nil unless response.content_type.to_s.downcase == 'application/xml'
+
+ begin
+ document = REXML::Document.new(response.body)
+ root = document.root
+ rescue REXML::ParseException => e
+ Inform.err(e.to_s)
+ raise Error::XML, "failed to parse response XML"
+ end
+
+ return root
+ end
+
+ def authorize(request)
+ if @username && @passwd
+ request.basic_auth(@username, @passwd)
+ end
+ end
+
+ def parse_qpath(url)
+ url = URI.parse(url)
+ qpath = url.path
+ if url.query
+ qpath += "?" + url.query
+ end
+
+ return qpath
+ end
+
+ def net_http
+ http = Net::HTTP.new(@host, @port)
+
+ http.read_timeout = @http_read_timeout
+ http.set_debug_output($stderr) if @http_debug
+
+ if @use_ssl
+ http.use_ssl = @use_ssl
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+
+ return http
+ end
+
+ def post_resource(ref, body, headers = {})
+ headers = @headers.merge(headers)
+ qpath = parse_qpath(ref)
+
+ begin
+ request = Net::HTTP::Post.new(qpath, headers)
+ authorize(request)
+
+ response = net_http.start do |http|
+ http.request(request, body)
+ end
+ rescue => e
+ Inform.err("POST #{ref} failed: #{e.class}: #{e}")
+ raise Error::HTTP, "POST #{ref} failed: #{e}"
+ end
+
+ return response
+ end
+
+ def delete_resource(ref, headers = {})
+ headers = @headers.merge(headers)
+ qpath = parse_qpath(ref)
+
+ begin
+ request = Net::HTTP::Delete.new(qpath, headers)
+ authorize(request)
+
+ response = net_http.start do |http|
+ http.request(request)
+ end
+ rescue => e
+ Inform.err("DELETE #{ref} failed: #{e.class}: #{e}")
+ raise Error::HTTP, "DELETE #{ref} failed: #{e}"
+ end
+
+ return response
+ end
+
+ def get_resource(ref, headers = {})
+ headers = @headers.merge(headers)
+ qpath = parse_qpath(ref)
+
+ begin
+ request = Net::HTTP::Get.new(qpath, headers)
+ authorize(request)
+
+ response = net_http.start do |http|
+ http.request(request)
+ end
+ rescue => e
+ Inform.err("GET #{ref} failed: #{e.class}: #{e}")
+ raise Error::HTTP, "GET #{ref} failed: #{e}"
+ end
+
+ return response
+ end
+
+ def put_resource(ref, body, headers = {})
+ headers = @headers.merge(headers)
+ qpath = parse_qpath(ref)
+
+ begin
+ request = Net::HTTP::Put.new(qpath, headers)
+ authorize(request)
+
+ response = net_http.start do |http|
+ http.request(request, body)
+ end
+ rescue => e
+ Inform.err("PUT #{ref} failed: #{e.class}: #{e}")
+ raise Error::HTTP, "PUT #{ref} failed: #{e}"
+ end
+
+ return response
+ end
+ end
+end
+
+if $0 == __FILE__ then
+ SMSWS_ROOT = File.expand_path(File.dirname(__FILE__))
+
+ Dir.chdir(SMSWS_ROOT)
+
+ SMSWS_CONFIG = "#{SMSWS_ROOT}/sms.config"
+ $config = YAML::load_file(SMSWS_CONFIG)
+
+ ENV['SMS_CONFIG'] = "#{SMSWS_CONFIG}"
+
+ Inform.syslog = false
+ if Inform.syslog
+ Syslog.open("smswsc", Syslog::LOG_NDELAY, Syslog::LOG_LOCAL7)
+ else
+ Inform.level = Inform::LOG_ERR
+ #Inform.level = Inform::LOG_DEBUG
+ Inform.file = $stdout
+ end
+
+ client = SMSWSC::Client.new(
+ $config["smsws"]["user"],
+ $config["smsws"]["passwd"],
+ "192.168.2.1",
+ $config["smsws"]["port"]
+ )
+
+ msgs = client.sms_messages_query
+ p msgs
+
+ pb = client.phonebook_query
+ p pb
+
+ msg = SMSWSC::SMSMessage.new
+ msg.addr = "jcm"
+ msg.user_data = "test me web by name"
+ client.sms_send(msg)
+end