diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..589e214
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "server/php/example/httpserver"]
+ path = server/php/example/httpserver
+ url = git://github.com/youngj/httpserver.git
diff --git a/res/menu/mainmenu.xml b/res/menu/mainmenu.xml
index 4c3ea24..cc7148d 100755
--- a/res/menu/mainmenu.xml
+++ b/res/menu/mainmenu.xml
@@ -6,4 +6,7 @@
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b3b6094..8dc1820 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3,4 +3,5 @@
KalSMS 2
Settings
Test
+ Check Now
diff --git a/server/php/KalSMS.php b/server/php/KalSMS.php
new file mode 100755
index 0000000..3c9a39d
--- /dev/null
+++ b/server/php/KalSMS.php
@@ -0,0 +1,177 @@
+compute_signature($full_url, $_POST, $correct_password);
+
+ //error_log("Correct signature: '$correct_signature'");
+
+ return $signature === $correct_signature;
+ }
+
+ function compute_signature($url, $data, $password)
+ {
+ ksort($data);
+
+ $input = $url;
+ foreach($data as $key => $value)
+ $input .= ",$key=$value";
+
+ $input .= ",$password";
+
+ //error_log("Signed data: '$input'");
+
+ return base64_encode(sha1($input, true));
+ }
+}
+
+class KalSMS_OutgoingMessage
+{
+ public $id = '';
+ public $to;
+ public $message;
+}
+
+class KalSMS_Action
+{
+ public $type;
+ public $kalsms;
+
+ function __construct($kalsms)
+ {
+ $this->kalsms = $kalsms;
+ }
+}
+
+class KalSMS_Action_Test extends KalSMS_Action
+{
+ function __construct($kalsms)
+ {
+ parent::__construct($kalsms);
+ $this->type = KalSMS::ACTION_TEST;
+ }
+}
+
+class KalSMS_Action_Incoming extends KalSMS_Action
+{
+ public $from;
+ public $message;
+
+ function __construct($kalsms)
+ {
+ parent::__construct($kalsms);
+ $this->type = KalSMS::ACTION_INCOMING;
+ $this->from = $_POST['from'];
+ $this->message = $_POST['message'];
+ }
+
+ function get_response_xml($messages)
+ {
+ ob_start();
+ echo "\n";
+ echo "";
+ foreach ($messages as $message)
+ {
+ echo "".KalSMS::escape($message->message)."";
+ }
+ echo "";
+ return ob_get_clean();
+ }
+}
+
+class KalSMS_Action_Outgoing extends KalSMS_Action
+{
+ function __construct($kalsms)
+ {
+ parent::__construct($kalsms);
+ $this->type = KalSMS::ACTION_OUTGOING;
+ }
+
+ function get_response_xml($messages)
+ {
+ ob_start();
+ echo "\n";
+ echo "";
+ foreach ($messages as $message)
+ {
+ echo "".
+ KalSMS::escape($message->message)."";
+ }
+ echo "";
+ return ob_get_clean();
+ }
+}
+
+class KalSMS_Action_SendStatus extends KalSMS_Action
+{
+ public $status;
+ public $id;
+
+ function __construct($type)
+ {
+ $this->type = KalSMS::ACTION_SEND_STATUS;
+ $this->status = (int)$_POST['status'];
+ $this->id = $_POST['id'];
+ }
+}
\ No newline at end of file
diff --git a/server/php/README.txt b/server/php/README.txt
new file mode 100755
index 0000000..cabf434
--- /dev/null
+++ b/server/php/README.txt
@@ -0,0 +1,25 @@
+
+PHP server library for KalSMS, with example implementation
+
+The KalSMS.php library is intended to be used as part of a PHP application
+running on an HTTP server that receives incoming SMS messages from, and sends
+outgoing SMS messages to an Android phone running KalSMS.
+
+To run the example implementation, the example/www/ directory should be made available
+via a web server running PHP (e.g. Apache). You can also use the included standalone
+PHP web server, by running the following commands:
+ git submodule init
+ php server.php
+
+example/config.php contains the list of phone numbers and passwords for phones running KalSMS.
+
+On a phone running KalSMS, go to Menu -> Settings and enter:
+ * Server URL: The URL to example/www/index.php.
+ If you're using server.php, this will be http://:8002/
+ * Your phone number: One of the phone numbers listed in example/config.php
+ * Password: The corresponding password in example/config.php
+
+To send an outgoing SMS, use
+ php example/send_sms.php
+
+See KalSMS.php and example/www/index.php
\ No newline at end of file
diff --git a/server/php/example/config.php b/server/php/example/config.php
new file mode 100755
index 0000000..6a6cadf
--- /dev/null
+++ b/server/php/example/config.php
@@ -0,0 +1,9 @@
+ 'rosebud',
+ '16505551213' => 's3krit',
+);
+$PHONE_NUMBERS = array_keys($PASSWORDS);
+
+$OUTGOING_DIR_NAME = __DIR__."/outgoing_sms";
\ No newline at end of file
diff --git a/server/php/example/httpserver b/server/php/example/httpserver
new file mode 160000
index 0000000..95a38ab
--- /dev/null
+++ b/server/php/example/httpserver
@@ -0,0 +1 @@
+Subproject commit 95a38ab08f14ac54dc64b6f6c008d7f69af8a8f4
diff --git a/server/php/example/send_sms.php b/server/php/example/send_sms.php
new file mode 100755
index 0000000..821f638
--- /dev/null
+++ b/server/php/example/send_sms.php
@@ -0,0 +1,41 @@
+] \"\"");
+ error_log("Examples: ");
+ error_log(" php send_sms.php 16505551212 16504449876 \"hello world\"");
+ error_log(" php send_sms.php 16504449876 \"hello world\"");
+ die;
+}
+
+$id = uniqid("");
+
+$filename = "$OUTGOING_DIR_NAME/$id.json";
+
+file_put_contents($filename, json_encode(array(
+ 'from' => $from,
+ 'to' => $to,
+ 'message' => $message,
+ 'id' => $id
+)));
+
+echo "Message $id added to outgoing queue\n";
\ No newline at end of file
diff --git a/server/php/example/server.php b/server/php/example/server.php
new file mode 100755
index 0000000..1eab65f
--- /dev/null
+++ b/server/php/example/server.php
@@ -0,0 +1,46 @@
+ 8002,
+ ));
+ }
+
+ function route_request($request)
+ {
+ $uri = $request->uri;
+
+ $doc_root = __DIR__ . '/www';
+
+ if (preg_match('#/$#', $uri))
+ {
+ $uri .= "index.php";
+ }
+
+ if (preg_match('#\.php$#', $uri))
+ {
+ return $this->get_php_response($request, "$doc_root$uri");
+ }
+ else
+ {
+ return $this->get_static_response($request, "$doc_root$uri");
+ }
+ }
+}
+
+$server = new ExampleServer();
+$server->run_forever();
\ No newline at end of file
diff --git a/server/php/example/test_sms.php b/server/php/example/test_sms.php
new file mode 100755
index 0000000..d56d634
--- /dev/null
+++ b/server/php/example/test_sms.php
@@ -0,0 +1,6 @@
+get_request_phone_number();
+
+$password = @$PASSWORDS[$phone_number];
+
+if (!isset($password) || !$kalsms->is_validated_request($password))
+{
+ header("HTTP/1.1 403 Forbidden");
+ error_log("Invalid request signature");
+ echo "Invalid request signature";
+ return;
+}
+
+$action = $kalsms->get_request_action();
+
+switch ($action->type)
+{
+ case KalSMS::ACTION_INCOMING:
+ error_log("Received SMS from {$action->from}");
+
+ $reply = new KalSMS_OutgoingMessage();
+ $reply->message = "You said: {$action->message}";
+
+ error_log("Sending reply: {$reply->message}");
+
+ header("Content-Type: text/xml");
+ echo $action->get_response_xml(array($reply));
+ return;
+
+ case KalSMS::ACTION_OUTGOING:
+ $messages = array();
+
+ $dir = opendir($OUTGOING_DIR_NAME);
+ while ($file = readdir($dir))
+ {
+ if (preg_match('#\.json$#', $file))
+ {
+ $data = json_decode(file_get_contents("$OUTGOING_DIR_NAME/$file"), true);
+ if ($data && @$data['from'] == $phone_number)
+ {
+ $sms = new KalSMS_OutgoingMessage();
+ $sms->id = $data['id'];
+ $sms->to = $data['to'];
+ $sms->from = $data['from'];
+ $sms->message = $data['message'];
+ $messages[] = $sms;
+ }
+ }
+ }
+ closedir($dir);
+
+ header("Content-Type: text/xml");
+ echo $action->get_response_xml($messages);
+ return;
+
+ case KalSMS::ACTION_SEND_STATUS:
+
+ $id = $action->id;
+
+ // delete file with matching id
+ if (preg_match('#^\w+$#', $id) && unlink("$OUTGOING_DIR_NAME/$id.json"))
+ {
+ echo "OK";
+ }
+ else
+ {
+ header("HTTP/1.1 404 Not Found");
+ echo "invalid id";
+ }
+ return;
+
+ case KalSMS::ACTION_TEST:
+ echo "OK";
+ return;
+
+ default:
+ header("HTTP/1.1 404 Not Found");
+ echo "Invalid action";
+ return;
+}
\ No newline at end of file
diff --git a/src/org/envaya/kalsms/App.java b/src/org/envaya/kalsms/App.java
index 3d32f0f..7300214 100755
--- a/src/org/envaya/kalsms/App.java
+++ b/src/org/envaya/kalsms/App.java
@@ -16,8 +16,10 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.telephony.SmsManager;
import android.util.Log;
+import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
@@ -71,6 +73,22 @@ public class App {
context.sendBroadcast(broadcast);
}
+ public void checkOutgoingMessages()
+ {
+ String serverUrl = getServerUrl();
+ if (serverUrl.length() > 0)
+ {
+ log("Checking for outgoing messages");
+ new PollerTask().execute(
+ new BasicNameValuePair("action", App.ACTION_OUTGOING)
+ );
+ }
+ else
+ {
+ log("Can't check outgoing messages; server URL not set");
+ }
+ }
+
public void setOutgoingMessageAlarm()
{
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -212,4 +230,20 @@ public class App {
log("Sending " +sms.getLogName() + " to " + sms.getTo());
smgr.sendTextMessage(sms.getTo(), null, sms.getMessage(), sentIntent, null);
}
+
+ private class PollerTask extends HttpTask {
+
+ public PollerTask()
+ {
+ super(app);
+ }
+
+ @Override
+ protected void handleResponse(HttpResponse response) throws Exception {
+ for (OutgoingSmsMessage reply : parseResponseXML(response)) {
+ app.sendSMS(reply);
+ }
+ }
+ }
+
}
diff --git a/src/org/envaya/kalsms/HttpTask.java b/src/org/envaya/kalsms/HttpTask.java
index c9737dd..74fd4db 100755
--- a/src/org/envaya/kalsms/HttpTask.java
+++ b/src/org/envaya/kalsms/HttpTask.java
@@ -84,6 +84,7 @@ public class HttpTask extends AsyncTask
String signature = this.getSignature(url, params);
+ post.setHeader("X-Kalsms-Version", "2");
post.setHeader("X-Kalsms-PhoneNumber", app.getPhoneNumber());
post.setHeader("X-Kalsms-Signature", signature);
diff --git a/src/org/envaya/kalsms/IncomingMessageForwarder.java b/src/org/envaya/kalsms/IncomingMessageForwarder.java
index bb336fb..27e9120 100755
--- a/src/org/envaya/kalsms/IncomingMessageForwarder.java
+++ b/src/org/envaya/kalsms/IncomingMessageForwarder.java
@@ -53,7 +53,6 @@ public class IncomingMessageForwarder extends BroadcastReceiver {
String serverUrl = app.getServerUrl();
String message = sms.getMessageBody();
String sender = sms.getOriginatingAddress();
- String recipient = app.getPhoneNumber();
app.log("Received SMS from " + sender);
@@ -64,7 +63,6 @@ public class IncomingMessageForwarder extends BroadcastReceiver {
new ForwarderTask(sms).execute(
new BasicNameValuePair("from", sender),
- new BasicNameValuePair("to", recipient),
new BasicNameValuePair("message", message),
new BasicNameValuePair("action", App.ACTION_INCOMING)
);
diff --git a/src/org/envaya/kalsms/Main.java b/src/org/envaya/kalsms/Main.java
index b312299..686a7e5 100755
--- a/src/org/envaya/kalsms/Main.java
+++ b/src/org/envaya/kalsms/Main.java
@@ -133,6 +133,9 @@ public class Main extends Activity {
case R.id.settings:
startActivity(new Intent(this, Prefs.class));
return true;
+ case R.id.check_now:
+ app.checkOutgoingMessages();
+ return true;
case R.id.test:
app.log("Testing server connection...");
new TestTask().execute(
diff --git a/src/org/envaya/kalsms/OutgoingMessagePoller.java b/src/org/envaya/kalsms/OutgoingMessagePoller.java
index 5a4c085..a8c9018 100755
--- a/src/org/envaya/kalsms/OutgoingMessagePoller.java
+++ b/src/org/envaya/kalsms/OutgoingMessagePoller.java
@@ -3,40 +3,14 @@ package org.envaya.kalsms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import org.apache.http.HttpResponse;
-import org.apache.http.message.BasicNameValuePair;
public class OutgoingMessagePoller extends BroadcastReceiver {
private App app;
- private class PollerTask extends HttpTask {
-
- public PollerTask()
- {
- super(app);
- }
-
- @Override
- protected void handleResponse(HttpResponse response) throws Exception {
- for (OutgoingSmsMessage reply : parseResponseXML(response)) {
- app.sendSMS(reply);
- }
- }
- }
-
@Override
public void onReceive(Context context, Intent intent) {
app = App.getInstance(context);
-
- String serverUrl = app.getServerUrl();
- if (serverUrl.length() > 0)
- {
- app.log("Checking for outgoing messages");
- new PollerTask().execute(
- new BasicNameValuePair("from", app.getPhoneNumber()),
- new BasicNameValuePair("action", App.ACTION_OUTGOING)
- );
- }
+ app.checkOutgoingMessages();
}
}