diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5826402
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/vendor
+composer.phar
+composer.lock
+.DS_Store
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..87a0ca5
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+nexmo
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..e206d70
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1162f43
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..5774d69
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.idea/nexmo.iml b/.idea/nexmo.iml
new file mode 100644
index 0000000..6b8184f
--- /dev/null
+++ b/.idea/nexmo.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/.idea/php.xml b/.idea/php.xml
new file mode 100644
index 0000000..84c5e58
--- /dev/null
+++ b/.idea/php.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
new file mode 100644
index 0000000..922003b
--- /dev/null
+++ b/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..def6a6a
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..f3445bc
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,391 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1400702043442
+ 1400702043442
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..aa14ee5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,14 @@
+language: php
+
+php:
+ - 5.3
+ - 5.4
+ - 5.5
+ - 5.6
+ - hhvm
+
+before_script:
+ - composer self-update
+ - composer install --prefer-source --no-interaction --dev
+
+script: phpunit
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..225f2d6
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "artistan/nexmo",
+ "description": "",
+ "authors": [
+ {
+ "name": "Charles Peterson",
+ "email": "artistan@gmail.com"
+ }
+ ],
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "git://github.com/orchestral/phpseclib.git"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "illuminate/support": "4.1.*"
+ },
+ "require-dev":{
+ "phpunit/phpunit": "3.7.*",
+ "orchestra/testbench": "2.1.*",
+ "mockery/mockery": "dev-master@dev"
+ },
+ "autoload": {
+ "psr-0": {
+ "Artistan\\Nexmo": "src/"
+ }
+ },
+ "minimum-stability": "stable"
+}
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..3347b75
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ ./tests/
+
+
+
diff --git a/src/Artistan/Nexmo/Facades/Account.php b/src/Artistan/Nexmo/Facades/Account.php
new file mode 100644
index 0000000..e96539a
--- /dev/null
+++ b/src/Artistan/Nexmo/Facades/Account.php
@@ -0,0 +1,14 @@
+package('artistan/nexmo');
+ }
+
+ /**
+ * Register the service provider.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ // Receipt
+ $this->app['nexmoreceipt'] = $this->app->share(function($app)
+ {
+ return new Account();
+ });
+
+ $this->app->booting(function()
+ {
+ $loader = \Illuminate\Foundation\AliasLoader::getInstance();
+ $loader->alias('NexmoReceipt', 'Artistan\Nexmo\Facades\Receipt');
+ });
+
+ // Account
+ $this->app['nexmoaccount'] = $this->app->share(function($app)
+ {
+ return new Account();
+ });
+
+ $this->app->booting(function()
+ {
+ $loader = \Illuminate\Foundation\AliasLoader::getInstance();
+ $loader->alias('NexmoAccount', 'Artistan\Nexmo\Facades\Account');
+ });
+
+ // SMS Message
+ $this->app['nexmosmsmessage'] = $this->app->share(function($app)
+ {
+ return new MessageSms();
+ });
+
+ $this->app->booting(function()
+ {
+ $loader = \Illuminate\Foundation\AliasLoader::getInstance();
+ $loader->alias('NexmoSmsMessage', 'Artistan\Nexmo\Facades\Message\Sms');
+ });
+ }
+
+ /**
+ * Get the services provided by the provider.
+ *
+ * @return array
+ */
+ public function provides()
+ {
+ return array('nexmosmsmessage','nexmoreceipt','nexmoaccount');
+ }
+
+}
diff --git a/src/Artistan/Nexmo/Service/Account.php b/src/Artistan/Nexmo/Service/Account.php
new file mode 100644
index 0000000..ea6a4b2
--- /dev/null
+++ b/src/Artistan/Nexmo/Service/Account.php
@@ -0,0 +1,246 @@
+ array('method' => 'GET', 'url' => '/account/get-balance/{k}/{s}'),
+ 'get_pricing' => array('method' => 'GET', 'url' => '/account/get-pricing/outbound/{k}/{s}/{country_code}'),
+ 'get_own_numbers' => array('method' => 'GET', 'url' => '/account/numbers/{k}/{s}'),
+ 'search_numbers' => array('method' => 'GET', 'url' => '/number/search/{k}/{s}/{country_code}?pattern={pattern}'),
+ 'buy_number' => array('method' => 'POST', 'url' => '/number/buy/{k}/{s}/{country_code}/{msisdn}'),
+ 'cancel_number' => array('method' => 'POST', 'url' => '/number/cancel/{k}/{s}/{country_code}/{msisdn}')
+ );
+
+
+ private $cache = array();
+
+ /**
+ * @param $nx_key Your Nexmo account key
+ * @param $nx_secret Your Nexmo secret
+ */
+ public function __construct ($api_key='', $api_secret='') {
+ if(!empty($api_key) && !empty($api_secret)){
+ $this->nx_key = $api_key;
+ $this->nx_secret = $api_secret;
+ } else {
+ $this->nx_key = \Config::get('nexmo::auth.api_key');
+ $this->nx_secret = \Config::get('nexmo::auth.api_secret');
+ }
+
+ if(empty($this->nx_key) || empty($this->nx_secret)){
+ throw new \Exception("Account Credentials Exception",5001);
+ }
+ }
+
+
+ /**
+ * Return your account balance in Euros
+ * @return float|bool
+ */
+ public function balance () {
+ if (!isset($this->cache['balance'])) {
+ $tmp = $this->apiCall('get_balance');
+ if (!$tmp['data']) return false;
+
+ $this->cache['balance'] = $tmp['data']['value'];
+ }
+
+ return (float)$this->cache['balance'];
+ }
+
+
+ /**
+ * Find out the price to send a message to a country
+ * @param $country_code Country code to return the SMS price for
+ * @return float|bool
+ */
+ public function smsPricing ($country_code) {
+ $country_code = strtoupper($country_code);
+
+ if (!isset($this->cache['country_codes']))
+ $this->cache['country_codes'] = array();
+
+ if (!isset($this->cache['country_codes'][$country_code])) {
+ $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code));
+ if (!$tmp['data']) return false;
+
+ $this->cache['country_codes'][$country_code] = $tmp['data'];
+ }
+
+ return (float)$this->cache['country_codes'][$country_code]['mt'];
+ }
+
+
+ /**
+ * Return a countries international dialing code
+ * @param $country_code Country code to return the dialing code for
+ * @return string|bool
+ */
+ public function getCountryDialingCode ($country_code) {
+ $country_code = strtoupper($country_code);
+
+ if (!isset($this->cache['country_codes']))
+ $this->cache['country_codes'] = array();
+
+ if (!isset($this->cache['country_codes'][$country_code])) {
+ $tmp = $this->apiCall('get_pricing', array('country_code'=>$country_code));
+ if (!$tmp['data']) return false;
+
+ $this->cache['country_codes'][$country_code] = $tmp['data'];
+ }
+
+ return (string)$this->cache['country_codes'][$country_code]['prefix'];
+ }
+
+
+ /**
+ * Get an array of all purchased numbers for your account
+ * @return array|bool
+ */
+ public function numbersList () {
+ if (!isset($this->cache['own_numbers'])) {
+ $tmp = $this->apiCall('get_own_numbers');
+ if (!$tmp['data']) return false;
+
+ $this->cache['own_numbers'] = $tmp['data'];
+ }
+
+ if (!$this->cache['own_numbers']['numbers']) {
+ return array();
+ }
+
+ return $this->cache['own_numbers']['numbers'];
+ }
+
+
+ /**
+ * Search available numbers to purchase for your account
+ * @param $country_code Country code to search available numbers in
+ * @param $pattern Number pattern to search for
+ * @return bool
+ */
+ public function numbersSearch ($country_code, $pattern) {
+ $country_code = strtoupper($country_code);
+
+ $tmp = $this->apiCall('search_numbers', array('country_code'=>$country_code, 'pattern'=>$pattern));
+ if (!$tmp['data'] || !isset($tmp['data']['numbers'])) return false;
+ return $tmp['data']['numbers'];
+ }
+
+
+ /**
+ * Purchase an available number to your account
+ * @param $country_code Country code for your desired number
+ * @param $msisdn Full number which you wish to purchase
+ * @return bool
+ */
+ public function numbersBuy ($country_code, $msisdn) {
+ $country_code = strtoupper($country_code);
+
+ $tmp = $this->apiCall('buy_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn));
+ return ($tmp['http_code'] === 200);
+ }
+
+
+ /**
+ * Cancel an existing number on your account
+ * @param $country_code Country code for which the number is for
+ * @param $msisdn The number to cancel
+ * @return bool
+ */
+ public function numbersCancel ($country_code, $msisdn) {
+ $country_code = strtoupper($country_code);
+
+ $tmp = $this->apiCall('cancel_number', array('country_code'=>$country_code, 'msisdn'=>$msisdn));
+ return ($tmp['http_code'] === 200);
+ }
+
+
+ /**
+ * Run a REST command on Nexmo SMS services
+ * @param $command
+ * @param array $data
+ * @return array|bool
+ */
+ private function apiCall($command, $data=array()) {
+ if (!isset($this->rest_commands[$command])) {
+ return false;
+ }
+
+ $cmd = $this->rest_commands[$command];
+
+ $url = $cmd['url'];
+ $url = str_replace(array('{k}', '{s}') ,array($this->nx_key, $this->nx_secret), $url);
+
+ $parsed_data = array();
+ foreach ($data as $k => $v) $parsed_data['{'.$k.'}'] = $v;
+ $url = str_replace(array_keys($parsed_data) ,array_values($parsed_data), $url);
+
+ $url = trim($this->rest_base_url, '/') . $url;
+ $post_data = '';
+
+ // If available, use CURL
+ if (function_exists('curl_version')) {
+
+ $to_nexmo = curl_init( $url );
+ curl_setopt( $to_nexmo, CURLOPT_RETURNTRANSFER, true );
+ curl_setopt( $to_nexmo, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($to_nexmo, CURLOPT_HTTPHEADER, array('Accept: application/json'));
+
+ if ($cmd['method'] == 'POST') {
+ curl_setopt( $to_nexmo, CURLOPT_POST, true );
+ curl_setopt( $to_nexmo, CURLOPT_POSTFIELDS, $post_data );
+ }
+
+ $from_nexmo = curl_exec( $to_nexmo );
+ $curl_info = curl_getinfo($to_nexmo);
+ $http_response_code = $curl_info['http_code'];
+ curl_close ( $to_nexmo );
+
+ } elseif (ini_get('allow_url_fopen')) {
+ // No CURL available so try the awesome file_get_contents
+
+ $opts = array('http' =>
+ array(
+ 'method' => 'GET',
+ 'header' => 'Accept: application/json'
+ )
+ );
+
+ if ($cmd['method'] == 'POST') {
+ $opts['http']['method'] = 'POST';
+ $opts['http']['header'] .= "\r\nContent-type: application/x-www-form-urlencoded";
+ $opts['http']['content'] = $post_data;
+ }
+
+ $context = stream_context_create($opts);
+ $from_nexmo = file_get_contents($url, false, $context);
+
+ // et the response code
+ preg_match('/HTTP\/[^ ]+ ([0-9]+)/i', $http_response_header[0], $m);
+ $http_response_code = $m[1];
+
+ } else {
+ // No way of sending a HTTP post :(
+ return false;
+ }
+
+ $data = json_decode($from_nexmo, true);
+ return array(
+ 'data' => $data,
+ 'http_code' => (int)$http_response_code
+ );
+
+ }
+}
\ No newline at end of file
diff --git a/src/Artistan/Nexmo/Service/Message/Sms.php b/src/Artistan/Nexmo/Service/Message/Sms.php
new file mode 100644
index 0000000..e5ffc40
--- /dev/null
+++ b/src/Artistan/Nexmo/Service/Message/Sms.php
@@ -0,0 +1,438 @@
+nx_key = $api_key;
+ $this->nx_secret = $api_secret;
+ } else {
+ $this->nx_key = \Config::get('nexmo::auth.api_key');
+ $this->nx_secret = \Config::get('nexmo::auth.api_secret');
+ }
+
+ if(empty($this->nx_key) || empty($this->nx_secret)){
+ throw new \Exception("Account Credentials Exception",5001);
+ }
+ }
+
+
+
+ /**
+ * Prepare new text message.
+ *
+ * If $unicode is not provided we will try to detect the
+ * message type. Otherwise set to TRUE if you require
+ * unicode characters.
+ */
+ function sendText ( $to, $from, $message, $unicode=null ) {
+
+ // Making sure strings are UTF-8 encoded
+ if ( !is_numeric($from) && !mb_check_encoding($from, 'UTF-8') ) {
+ trigger_error('$from needs to be a valid UTF-8 encoded string');
+ return false;
+ }
+
+ if ( !mb_check_encoding($message, 'UTF-8') ) {
+ trigger_error('$message needs to be a valid UTF-8 encoded string');
+ return false;
+ }
+
+ if ($unicode === null) {
+ $containsUnicode = max(array_map('ord', str_split($message))) > 127;
+ } else {
+ $containsUnicode = (bool)$unicode;
+ }
+
+ // Make sure $from is valid
+ $from = $this->validateOriginator($from);
+
+ // URL Encode
+ $from = urlencode( $from );
+ $message = urlencode( $message );
+
+ // Send away!
+ $post = array(
+ 'from' => $from,
+ 'to' => $to,
+ 'text' => $message,
+ 'type' => $containsUnicode ? 'unicode' : 'text'
+ );
+ return $this->sendRequest ( $post );
+
+ }
+
+
+ /**
+ * Prepare new WAP message.
+ */
+ function sendBinary ( $to, $from, $body, $udh ) {
+
+ //Binary messages must be hex encoded
+ $body = bin2hex ( $body );
+ $udh = bin2hex ( $udh );
+
+ // Make sure $from is valid
+ $from = $this->validateOriginator($from);
+
+ // Send away!
+ $post = array(
+ 'from' => $from,
+ 'to' => $to,
+ 'type' => 'binary',
+ 'body' => $body,
+ 'udh' => $udh
+ );
+ return $this->sendRequest ( $post );
+
+ }
+
+
+ /**
+ * Prepare new binary message.
+ */
+ function pushWap ( $to, $from, $title, $url, $validity = 172800000 ) {
+
+ // Making sure $title and $url are UTF-8 encoded
+ if ( !mb_check_encoding($title, 'UTF-8') || !mb_check_encoding($url, 'UTF-8') ) {
+ trigger_error('$title and $udh need to be valid UTF-8 encoded strings');
+ return false;
+ }
+
+ // Make sure $from is valid
+ $from = $this->validateOriginator($from);
+
+ // Send away!
+ $post = array(
+ 'from' => $from,
+ 'to' => $to,
+ 'type' => 'wappush',
+ 'url' => $url,
+ 'title' => $title,
+ 'validity' => $validity
+ );
+ return $this->sendRequest ( $post );
+
+ }
+
+
+ /**
+ * Prepare and send a new message.
+ */
+ private function sendRequest ( $data ) {
+ // Build the post data
+ $data = array_merge($data, array('username' => $this->nx_key, 'password' => $this->nx_secret));
+ $post = '';
+ foreach($data as $k => $v){
+ $post .= "&$k=$v";
+ }
+
+ // If available, use CURL
+ if (function_exists('curl_version')) {
+
+ $to_nexmo = curl_init( $this->nx_uri );
+ curl_setopt( $to_nexmo, CURLOPT_POST, true );
+ curl_setopt( $to_nexmo, CURLOPT_RETURNTRANSFER, true );
+ curl_setopt( $to_nexmo, CURLOPT_POSTFIELDS, $post );
+
+ if (!$this->ssl_verify) {
+ curl_setopt( $to_nexmo, CURLOPT_SSL_VERIFYPEER, false);
+ }
+
+ $from_nexmo = curl_exec( $to_nexmo );
+ curl_close ( $to_nexmo );
+
+ } elseif (ini_get('allow_url_fopen')) {
+ // No CURL available so try the awesome file_get_contents
+
+ $opts = array('http' =>
+ array(
+ 'method' => 'POST',
+ 'header' => 'Content-type: application/x-www-form-urlencoded',
+ 'content' => $post
+ )
+ );
+ $context = stream_context_create($opts);
+ $from_nexmo = file_get_contents($this->nx_uri, false, $context);
+ var_dump($from_nexmo);exit;
+
+ } else {
+ // No way of sending a HTTP post :(
+ return false;
+ }
+
+
+ return $this->nexmoParse( $from_nexmo );
+
+ }
+
+
+ /**
+ * Recursively normalise any key names in an object, removing unwanted characters
+ */
+ private function normaliseKeys ($obj) {
+ // Determine is working with a class or araay
+ if ($obj instanceof stdClass) {
+ $new_obj = new stdClass();
+ $is_obj = true;
+ } else {
+ $new_obj = array();
+ $is_obj = false;
+ }
+
+
+ foreach($obj as $key => $val){
+ // If we come across another class/array, normalise it
+ if ($val instanceof stdClass || is_array($val)) {
+ $val = $this->normaliseKeys($val);
+ }
+
+ // Replace any unwanted characters in they key name
+ if ($is_obj) {
+ $new_obj->{str_replace('-', '', $key)} = $val;
+ } else {
+ $new_obj[str_replace('-', '', $key)] = $val;
+ }
+ }
+
+ return $new_obj;
+ }
+
+
+ /**
+ * Parse server response.
+ */
+ private function nexmoParse ( $from_nexmo ) {
+ $response = json_decode($from_nexmo);
+
+ // Copy the response data into an object, removing any '-' characters from the key
+ $response_obj = $this->normaliseKeys($response);
+
+ if ($response_obj) {
+ $this->nexmo_response = $response_obj;
+
+ // Find the total cost of this message
+ $response_obj->cost = $total_cost = 0;
+ if (is_array($response_obj->messages)) {
+ foreach ($response_obj->messages as $msg) {
+ if (property_exists($msg, "messageprice")) {
+ $total_cost = $total_cost + (float)$msg->messageprice;
+ }
+ }
+
+ $response_obj->cost = $total_cost;
+ }
+
+ return $response_obj;
+
+ } else {
+ // A malformed response
+ $this->nexmo_response = array();
+ return false;
+ }
+
+ }
+
+
+ /**
+ * Validate an originator string
+ *
+ * If the originator ('from' field) is invalid, some networks may reject the network
+ * whilst stinging you with the financial cost! While this cannot correct them, it
+ * will try its best to correctly format them.
+ */
+ private function validateOriginator($inp){
+ // Remove any invalid characters
+ $ret = preg_replace('/[^a-zA-Z0-9]/', '', (string)$inp);
+
+ if(preg_match('/[a-zA-Z]/', $inp)){
+
+ // Alphanumeric format so make sure it's < 11 chars
+ $ret = substr($ret, 0, 11);
+
+ } else {
+
+ // Numerical, remove any prepending '00'
+ if(substr($ret, 0, 2) == '00'){
+ $ret = substr($ret, 2);
+ $ret = substr($ret, 0, 15);
+ }
+ }
+
+ return (string)$ret;
+ }
+
+
+
+ /**
+ * Display a brief overview of a sent message.
+ * Useful for debugging and quick-start purposes.
+ */
+ public function displayOverview( $nexmo_response=null ){
+ $info = (!$nexmo_response) ? $this->nexmo_response : $nexmo_response;
+
+ if (!$nexmo_response ) return 'Cannot display an overview of this response';
+
+ // How many messages were sent?
+ if ( $info->messagecount > 1 ) {
+
+ $status = 'Your message was sent in ' . $info->messagecount . ' parts';
+
+ } elseif ( $info->messagecount == 1) {
+
+ $status = 'Your message was sent';
+
+ } else {
+
+ return 'There was an error sending your message';
+ }
+
+ // Build an array of each message status and ID
+ if (!is_array($info->messages)) $info->messages = array();
+ $message_status = array();
+ foreach ( $info->messages as $message ) {
+ $tmp = array('id'=>'', 'status'=>0);
+
+ if ( $message->status != 0) {
+ $tmp['status'] = $message->errortext;
+ } else {
+ $tmp['status'] = 'OK';
+ $tmp['id'] = $message->messageid;
+ }
+
+ $message_status[] = $tmp;
+ }
+
+
+ // Build the output
+ if (isset($_SERVER['HTTP_HOST'])) {
+ // HTML output
+ $ret = '
'.$status.' |
';
+ $ret .= 'Status | Message ID |
';
+ foreach ($message_status as $mstat) {
+ $ret .= ''.$mstat['status'].' | '.$mstat['id'].' |
';
+ }
+ $ret .= '
';
+
+ } else {
+
+ // CLI output
+ $ret = "$status:\n";
+
+ // Get the sizes for the table
+ $out_sizes = array('id'=>strlen('Message ID'), 'status'=>strlen('Status'));
+ foreach ($message_status as $mstat) {
+ if ($out_sizes['id'] < strlen($mstat['id'])) {
+ $out_sizes['id'] = strlen($mstat['id']);
+ }
+ if ($out_sizes['status'] < strlen($mstat['status'])) {
+ $out_sizes['status'] = strlen($mstat['status']);
+ }
+ }
+
+ $ret .= ' '.str_pad('Status', $out_sizes['status'], ' ').' ';
+ $ret .= str_pad('Message ID', $out_sizes['id'], ' ')."\n";
+ foreach ($message_status as $mstat) {
+ $ret .= ' '.str_pad($mstat['status'], $out_sizes['status'], ' ').' ';
+ $ret .= str_pad($mstat['id'], $out_sizes['id'], ' ')."\n";
+ }
+ }
+
+ return $ret;
+ }
+
+
+
+
+
+
+
+ /**
+ * Inbound text methods
+ */
+
+
+ /**
+ * Check for any inbound messages, using $_GET by default.
+ *
+ * This will set the current message to the inbound
+ * message allowing for a future reply() call.
+ */
+ public function inboundText( $data=null ){
+ if(!$data) $data = $_GET;
+
+ if(!isset($data['text'], $data['msisdn'], $data['to'])) return false;
+
+ // Get the relevant data
+ $this->to = $data['to'];
+ $this->from = $data['msisdn'];
+ $this->text = $data['text'];
+ $this->network = (isset($data['network-code'])) ? $data['network-code'] : '';
+ $this->message_id = $data['messageId'];
+
+ // Flag that we have an inbound message
+ $this->inbound_message = true;
+
+ return true;
+ }
+
+
+ /**
+ * Reply the current message if one is set.
+ */
+ public function reply ($message) {
+ // Make sure we actually have a text to reply to
+ if (!$this->inbound_message) {
+ return false;
+ }
+
+ return $this->sendText($this->from, $this->to, $message);
+ }
+
+}
\ No newline at end of file
diff --git a/src/Artistan/Nexmo/Service/Receipt.php b/src/Artistan/Nexmo/Service/Receipt.php
new file mode 100644
index 0000000..0204614
--- /dev/null
+++ b/src/Artistan/Nexmo/Service/Receipt.php
@@ -0,0 +1,64 @@
+found = true;
+
+ // Get the relevant data
+ $this->to = $data['msisdn'];
+ $this->from = $data['to'];
+ $this->network = $data['network-code'];
+ $this->message_id = $data['messageId'];
+ $this->status = strtoupper($data['status']);
+
+ // Format the date into timestamp
+ $dp = date_parse_from_format('ymdGi', $data['scts']);
+ $this->received_time = mktime($dp['hour'], $dp['minute'], $dp['second'], $dp['month'], $dp['day'], $dp['year']);
+
+ // TODO add event with this object attached.
+ }
+
+
+ /**
+ * Returns true if a valid receipt is found
+ */
+ public function exists () {
+ return $this->found;
+ }
+}
\ No newline at end of file
diff --git a/src/Artistan/Nexmo/original/Nexmo-PHP-lib b/src/Artistan/Nexmo/original/Nexmo-PHP-lib
new file mode 160000
index 0000000..fceadaf
--- /dev/null
+++ b/src/Artistan/Nexmo/original/Nexmo-PHP-lib
@@ -0,0 +1 @@
+Subproject commit fceadafe642636a224f442401db012f395832aa4
diff --git a/src/config/auth.php b/src/config/auth.php
new file mode 100644
index 0000000..43a4e29
--- /dev/null
+++ b/src/config/auth.php
@@ -0,0 +1,8 @@
+ 'api_key',
+ 'api_secret' => 'api_secret'
+);
\ No newline at end of file
diff --git a/tests/.gitkeep b/tests/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/AccountTest.php b/tests/AccountTest.php
new file mode 100644
index 0000000..8888523
--- /dev/null
+++ b/tests/AccountTest.php
@@ -0,0 +1,22 @@
+assertTrue(true);
+ }
+}
+
\ No newline at end of file
diff --git a/tests/MessageSmsTest.php b/tests/MessageSmsTest.php
new file mode 100644
index 0000000..b0e32b0
--- /dev/null
+++ b/tests/MessageSmsTest.php
@@ -0,0 +1,22 @@
+assertTrue(true);
+ }
+}
+
\ No newline at end of file
diff --git a/tests/ReceiptTest.php b/tests/ReceiptTest.php
new file mode 100644
index 0000000..3d9e357
--- /dev/null
+++ b/tests/ReceiptTest.php
@@ -0,0 +1,22 @@
+assertTrue(true);
+ }
+}
+
\ No newline at end of file