(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/res/layout/main.xml b/res/layout/main.xml
old mode 100644
new mode 100755
index 22272f0..634ae00
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -3,11 +3,11 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:background="#333333">
-
-
-
+ android:layout_height="fill_parent"
+ android:id="@+id/info"
+ android:textColor="#FFFFFF"
+ android:layout_margin="5px">
diff --git a/res/values/strings.xml b/res/values/strings.xml
old mode 100644
new mode 100755
index a734339..b48bf11
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,5 +1,4 @@
- SMS Gateway Running.\n
- KalSMS
+ KalSMS Envaya
diff --git a/res/xml/prefs.xml b/res/xml/prefs.xml
old mode 100644
new mode 100755
index b39b361..e3d2c3c
--- a/res/xml/prefs.xml
+++ b/res/xml/prefs.xml
@@ -1,26 +1,27 @@
+
-
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/src/kalsms/niryariv/itp/Main.java b/src/kalsms/niryariv/itp/Main.java
deleted file mode 100644
index 9188aac..0000000
--- a/src/kalsms/niryariv/itp/Main.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package kalsms.niryariv.itp;
-
-import kalsms.niryariv.itp.R;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Html;
-import android.util.Log;
-import android.view.Menu;
-import android.widget.TextView;
-
-public class Main extends Activity {
-
-// public static final String PREFS_NAME = "KalPrefsFile";
-
- public String identifier = "";
- public String targetUrl = "";
- public Boolean polling = false;
-
- public void onResume() {
- Log.d("KALSMS", "RESUME");
- super.onResume();
-
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
-
- this.identifier = settings.getString("pref_identifier", "");
- this.targetUrl = settings.getString("pref_target_url", "");
- this.polling = settings.getBoolean("pref_poll_switch", false);
-
- Log.d("KALSMS", "onResume ident:" + this.identifier +"\ntarget:" + this.targetUrl);
-
- String infoText = new String();
-
- // Home Screen text
- infoText = "All SMS messages";
-
- if (this.identifier.trim() != "") {
- infoText += " starting with " + this.identifier + "";
- }
-
- infoText += " are now sent to " + this.targetUrl +" in the following format:";
- infoText += "GET " + this.targetUrl + "?sender=<phone#>&msg=<message>
";
- infoText += "If the response body contains text, it will SMS back to the originating phone.";
-
- if (this.polling) {
- infoText += "The target URL will be polled every 15 minutes (note that polling increases power consumption)
";
- }
-
- infoText += "
Press Menu to set SMS identifier or target URL.";
-
- infoText += "Questions/feedback: niryariv@gmail.com
";
- // END Home Screen text
-
- TextView info = (TextView) this.findViewById(R.id.info);
- info.setText(Html.fromHtml(infoText));
-
- }
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
-
- Log.d("KALSMS", "STARTED");
- }
-
-
- // first time the Menu key is pressed
- public boolean onCreateOptionsMenu(Menu menu) {
- startActivity(new Intent(this, Prefs.class));
- return(true);
- }
-
- // any other time the Menu key is pressed
- public boolean onPrepareOptionsMenu(Menu menu) {
- startActivity(new Intent(this, Prefs.class));
- return(true);
- }
-
-
- @Override
- protected void onStop(){
- // dont do much with this, atm..
- super.onStop();
- }
-
-}
diff --git a/src/kalsms/niryariv/itp/Prefs.java b/src/kalsms/niryariv/itp/Prefs.java
deleted file mode 100755
index 16fa71b..0000000
--- a/src/kalsms/niryariv/itp/Prefs.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package kalsms.niryariv.itp;
-
-import kalsms.niryariv.itp.R;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.util.Log;
-import android.view.Menu;
-
-
-public class Prefs extends PreferenceActivity implements OnSharedPreferenceChangeListener {
-
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.prefs);
- }
-
- protected void onResume() {
- super.onResume();
- // Set up a listener whenever a key changes
- getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- // Unregister the listener whenever a key changes
- getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
- }
-
-
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- Preference pref = findPreference(key);
- if (pref instanceof EditTextPreference) {
- EditTextPreference textPref = (EditTextPreference) pref;
- pref.setSummary(textPref.getSummary());
- Log.d("KALSMS", "textPref.getSummary(): " + textPref.getSummary());
- }
- if(pref instanceof CheckBoxPreference) {
- CheckBoxPreference checkbox = (CheckBoxPreference) pref;
- AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- Intent pintent = new Intent(this, SMSSender.class);
- PendingIntent pIntent = PendingIntent.getBroadcast(this,0,pintent, 0);
- if(checkbox.isChecked()) {
- alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
- Log.d("KALSMS", "alarm manager turned on");
- } else {
- alarm.cancel(pIntent);
- Log.d("SMS_GATEWAY", "alarm manager turned off");
- }
- }
- }
-
- // first time the Menu key is pressed
- public boolean onCreateOptionsMenu(Menu menu) {
- startActivity(new Intent(this, Prefs.class));
- return(true);
- }
-
- // any other time the Menu key is pressed
- public boolean onPrepareOptionsMenu(Menu menu) {
- startActivity(new Intent(this, Prefs.class));
- return(true);
- }
-}
-
diff --git a/src/kalsms/niryariv/itp/SMSReceiver.java b/src/kalsms/niryariv/itp/SMSReceiver.java
deleted file mode 100644
index 9791d50..0000000
--- a/src/kalsms/niryariv/itp/SMSReceiver.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package kalsms.niryariv.itp;
-
-import java.util.ArrayList;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.telephony.SmsMessage;
-import android.util.Log;
-
-public class SMSReceiver extends BroadcastReceiver {
-
- @Override
- // source: http://www.devx.com/wireless/Article/39495/1954
- public void onReceive(Context context, Intent intent) {
- if (!intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
- return;
- }
-
- // get settings
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
- TargetUrlRequest url = new TargetUrlRequest();
-
- String identifier = settings.getString("pref_identifier", "");
- String targetUrl = settings.getString("pref_target_url", "");
-
- SmsMessage msgs[] = getMessagesFromIntent(intent);
-
- for (int i = 0; i < msgs.length; i++) {
- SmsMessage mesg = msgs[i];
- String message = mesg.getDisplayMessageBody();
- String sender = mesg.getDisplayOriginatingAddress();
-
- if (message != null && message.length() > 0
- && (message.toLowerCase().startsWith(identifier) || identifier.trim() == "")) {
- Log.d("KALSMS", "MSG RCVD:\"" + message + "\" from: " + sender);
-
- // send the message to the URL
- String resp = url.openURL(sender, message, targetUrl, false).toString();
- Log.d("KALSMS", "RESP:\"" + resp);
-
- // SMS back the response
- if (resp.trim().length() > 0) {
- ArrayList> items = url.parseXML(resp);
- url.sendMessages(items);
- }
- // delete SMS from inbox, to prevent it from filling up
- DeleteSMSFromInbox(context, mesg);
- }
- }
- }
-
- private void DeleteSMSFromInbox(Context context, SmsMessage mesg) {
- Log.d("KALSMS", "try to delete SMS");
- try {
- Uri uriSms = Uri.parse("content://sms/inbox");
- StringBuilder sb = new StringBuilder();
- sb.append("address='" + mesg.getOriginatingAddress() + "' AND ");
- sb.append("body='" + mesg.getMessageBody() + "'");
- Cursor c = context.getContentResolver().query(uriSms, null, sb.toString(), null, null);
- c.moveToFirst();
- int thread_id = c.getInt(1);
- context.getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id), null, null);
- c.close();
- } catch (Exception ex) {
- // deletions don't work most of the time since the timing of the
- // receipt and saving to the inbox
- // makes it difficult to match up perfectly. the SMS might not be in
- // the inbox yet when this receiver triggers!
- Log.d("SmsReceiver", "Error deleting sms from inbox: " + ex.getMessage());
- }
- }
-
-
- // from http://github.com/dimagi/rapidandroid
- // source: http://www.devx.com/wireless/Article/39495/1954
- private SmsMessage[] getMessagesFromIntent(Intent intent) {
- SmsMessage retMsgs[] = null;
- Bundle bdl = intent.getExtras();
- try {
- Object pdus[] = (Object[]) bdl.get("pdus");
- retMsgs = new SmsMessage[pdus.length];
- for (int n = 0; n < pdus.length; n++) {
- byte[] byteData = (byte[]) pdus[n];
- retMsgs[n] = SmsMessage.createFromPdu(byteData);
- }
- } catch (Exception e) {
- Log.e("KALSMS", "GetMessages ERROR\n" + e);
- }
- return retMsgs;
- }
-}
\ No newline at end of file
diff --git a/src/kalsms/niryariv/itp/SMSSender.java b/src/kalsms/niryariv/itp/SMSSender.java
deleted file mode 100755
index 774084c..0000000
--- a/src/kalsms/niryariv/itp/SMSSender.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package kalsms.niryariv.itp;
-
-import java.util.ArrayList;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.PowerManager;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-public class SMSSender extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
-
- // acquiring the wake clock to prevent device from sleeping while request is processed
- final PowerManager pm = (PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock wake = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "http_request");
- wake.acquire();
-
- // get settings
- SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
- String targetUrl = settings.getString("pref_target_url", "");
- Log.d("KALSMS", "url:\"" + targetUrl);
- TargetUrlRequest url = new TargetUrlRequest();
- // send the message to the URL
- String resp = url.openURL("","",targetUrl, true).toString();
-
- Log.d("KALSMS", "RESP:\"" + resp);
-
- // SMS back the response
- if (resp.trim().length() > 0) {
- ArrayList> items = url.parseXML(resp);
- url.sendMessages(items);
- }
- wake.release();
- }
-}
diff --git a/src/kalsms/niryariv/itp/TargetUrlRequest.java b/src/kalsms/niryariv/itp/TargetUrlRequest.java
deleted file mode 100644
index f891d0e..0000000
--- a/src/kalsms/niryariv/itp/TargetUrlRequest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package kalsms.niryariv.itp;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.util.EntityUtils;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import android.telephony.SmsManager;
-import android.util.Log;
-
-public class TargetUrlRequest {
-
- private String sender = "";
-
- public String openURL(String sender, String message, String targetUrl, Boolean isPollRequest) {
-
- this.sender = sender;
-
- List qparams = new ArrayList();
-
- if(sender.trim().length() > 0 && message.trim().length() > 0) {
- qparams.add(new BasicNameValuePair("sender", sender));
- qparams.add(new BasicNameValuePair("msg", message));
- } else if (isPollRequest) {
- qparams.add(new BasicNameValuePair("poll", "true"));
- }
-
- String url = targetUrl + "?" + URLEncodedUtils.format(qparams, "UTF-8");
-
- try {
- HttpClient client = new DefaultHttpClient();
- HttpGet get = new HttpGet(url);
-
- HttpResponse responseGet = client.execute(get);
- HttpEntity resEntityGet = responseGet.getEntity();
- if (resEntityGet != null) {
- String resp = EntityUtils.toString(resEntityGet);
- Log.e("KALSMS", "HTTP RESP" + resp);
- return resp;
- }
- } catch (Exception e) {
- Log.e("KALSMS", "HTTP REQ FAILED:" + url);
- e.printStackTrace();
- }
- return "";
- }
-
- public ArrayList> parseXML(String xml) {
- ArrayList> output = new ArrayList>();
-
- try {
- DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
-
- Document doc = dBuilder.parse(new InputSource(new StringReader(xml)));
-
- NodeList rnodes = doc.getElementsByTagName("reply");
-
- NodeList nodes = rnodes.item(0).getChildNodes();
-
- for (int i=0; i < nodes.getLength(); i++) {
- try {
- List item = new ArrayList();
-
- Node node = nodes.item(i);
- if (node.getNodeType() != Node.ELEMENT_NODE) continue;
-
- Element e = (Element) node;
- String nodeName = e.getNodeName();
-
- if (nodeName.equalsIgnoreCase("sms")) {
- if (!e.getAttribute("phone").equals("")) {
- item.add(e.getAttribute("phone"));
- item.add(e.getFirstChild().getNodeValue());
- output.add((ArrayList) item);
- }
- } else if (nodeName.equalsIgnoreCase("sms-to-sender")) {
- item.add("sender");
- item.add(e.getFirstChild().getNodeValue());
- output.add((ArrayList) item);
- } else {
- continue;
- }
- } catch (Exception e){
- Log.e("KALSMS", "FAILED PARSING XML NODE# " + i );
- }
- }
- Log.e("KALSMS", "PARSING XML RETURNS " + output );
- return (output);
-
- } catch (Exception e) {
- Log.e("KALSMS", "PARSING XML FAILED: " + xml );
- e.printStackTrace();
- return (output);
- }
- }
-
- public void sendMessages(ArrayList> items) {
- SmsManager smgr = SmsManager.getDefault();
- for (int j = 0; j < items.size(); j++) {
- String sendTo = items.get(j).get(0);
- if (sendTo.toLowerCase() == "sender") sendTo = this.sender;
- String sendMsg = items.get(j).get(1);
- try {
- Log.d("KALSMS", "SEND MSG:\"" + sendMsg + "\" TO: " + sendTo);
- smgr.sendTextMessage(sendTo, null, sendMsg, null, null);
- } catch (Exception ex) {
- Log.d("KALSMS", "SMS FAILED");
- }
- }
- }
-
-}
-
diff --git a/src/org/envaya/kalsms/App.java b/src/org/envaya/kalsms/App.java
new file mode 100755
index 0000000..97866ed
--- /dev/null
+++ b/src/org/envaya/kalsms/App.java
@@ -0,0 +1,158 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.envaya.kalsms;
+
+import android.app.PendingIntent;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.preference.PreferenceManager;
+import android.telephony.SmsManager;
+import android.util.Log;
+
+/**
+ *
+ * @author Jesse
+ */
+public class App {
+
+ public static final int OUTGOING_POLL_SECONDS = 30;
+
+ public static final String LOG_NAME = "KALSMS";
+ public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
+ public static final String SEND_STATUS_INTENT = "org.envaya.kalsms.SEND_STATUS";
+
+ public Context context;
+ public SharedPreferences settings;
+
+ public App(Context context)
+ {
+ this.context = context;
+ this.settings = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+
+ static void debug(String msg)
+ {
+ Log.d(LOG_NAME, msg);
+ }
+
+ public void log(String msg)
+ {
+ Log.d(LOG_NAME, msg);
+
+ Intent broadcast = new Intent(App.LOG_INTENT);
+ broadcast.putExtra("message", msg);
+ context.sendBroadcast(broadcast);
+ }
+
+ public void logError(Throwable ex)
+ {
+ logError("ERROR", ex);
+ }
+
+ public void logError(String msg, Throwable ex)
+ {
+ logError(msg, ex, false);
+ }
+
+ public void logError(String msg, Throwable ex, boolean detail)
+ {
+ log(msg + ": " + ex.getClass().getName() + ": " + ex.getMessage());
+
+ if (detail)
+ {
+ for (StackTraceElement elem : ex.getStackTrace())
+ {
+ log(elem.getClassName() + ":" + elem.getMethodName() + ":" + elem.getLineNumber());
+ }
+ Throwable innerEx = ex.getCause();
+ if (innerEx != null)
+ {
+ logError("Inner exception:", innerEx, true);
+ }
+ }
+ }
+
+ public String getIncomingUrl()
+ {
+ return getServerUrl() + "/pg/receive_sms";
+ }
+
+ public String getOutgoingUrl()
+ {
+ return getServerUrl() + "/pg/dequeue_sms";
+ }
+
+ public String getSendStatusUrl()
+ {
+ return getServerUrl() + "/pg/sms_sent";
+ }
+
+ public String getServerUrl()
+ {
+ return settings.getString("server_url", "");
+ }
+
+ public String getPhoneNumber()
+ {
+ return settings.getString("phone_number", "");
+ }
+
+ public String getPassword()
+ {
+ return settings.getString("password", "");
+ }
+
+ private SQLiteDatabase db;
+ public SQLiteDatabase getWritableDatabase()
+ {
+ if (db == null)
+ {
+ db = new DBHelper(context).getWritableDatabase();
+ }
+ return db;
+ }
+
+ public void sendSMS(OutgoingSmsMessage sms)
+ {
+ String serverId = sms.getServerId();
+
+ if (serverId != null)
+ {
+ SQLiteDatabase db = this.getWritableDatabase();
+ Cursor cursor =
+ db.rawQuery("select 1 from sent_sms where server_id=?", new String[] { serverId });
+
+ boolean exists = (cursor.getCount() > 0);
+ cursor.close();
+ if (exists)
+ {
+ log(sms.getLogName() + " already sent, skipping");
+ return;
+ }
+
+ ContentValues values = new ContentValues();
+ values.put("server_id", serverId);
+ db.insert("sent_sms", null, values);
+ }
+
+ SmsManager smgr = SmsManager.getDefault();
+
+ Intent intent = new Intent(App.SEND_STATUS_INTENT);
+ intent.putExtra("serverId", serverId);
+
+ PendingIntent sentIntent = PendingIntent.getBroadcast(
+ this.context,
+ 0,
+ intent,
+ PendingIntent.FLAG_ONE_SHOT);
+
+ log("Sending " +sms.getLogName() + " to " + sms.getTo());
+ smgr.sendTextMessage(sms.getTo(), null, sms.getMessage(), sentIntent, null);
+ }
+}
diff --git a/src/org/envaya/kalsms/DBHelper.java b/src/org/envaya/kalsms/DBHelper.java
new file mode 100755
index 0000000..0710128
--- /dev/null
+++ b/src/org/envaya/kalsms/DBHelper.java
@@ -0,0 +1,37 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.envaya.kalsms;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ *
+ * @author Jesse
+ */
+public class DBHelper extends SQLiteOpenHelper {
+
+ private static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "org.envaya.kalsms.db";
+
+ private static final String SENT_SMS_TABLE_CREATE =
+ "CREATE TABLE sent_sms (server_id text);"
+ + "CREATE INDEX server_id_index ON sent_sms (server_id);";
+
+ public DBHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(SENT_SMS_TABLE_CREATE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+ }
+}
diff --git a/src/org/envaya/kalsms/IncomingMessageForwarder.java b/src/org/envaya/kalsms/IncomingMessageForwarder.java
new file mode 100755
index 0000000..3eb2727
--- /dev/null
+++ b/src/org/envaya/kalsms/IncomingMessageForwarder.java
@@ -0,0 +1,161 @@
+package org.envaya.kalsms;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import java.util.ArrayList;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.http.HttpResponse;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+
+public class IncomingMessageForwarder extends BroadcastReceiver {
+
+ private App app;
+
+ public List sendMessageToServer(SmsMessage sms) {
+
+ String message = sms.getDisplayMessageBody();
+ String sender = sms.getDisplayOriginatingAddress();
+ String recipient = app.getPhoneNumber();
+
+ app.log("Received SMS from " + sender);
+
+ if (message == null || message.length() == 0) {
+ return new ArrayList();
+ }
+
+ List replies = new ArrayList();
+
+ try {
+
+ List params = new ArrayList();
+ params.add(new BasicNameValuePair("from", sender));
+ params.add(new BasicNameValuePair("to", recipient));
+ params.add(new BasicNameValuePair("message", message));
+ params.add(new BasicNameValuePair("secret", app.getPassword()));
+
+ HttpClient client = new DefaultHttpClient();
+ HttpPost post = new HttpPost(app.getIncomingUrl());
+ post.setEntity(new UrlEncodedFormEntity(params));
+
+ app.log("Forwarding incoming SMS to server");
+
+ HttpResponse response = client.execute(post);
+
+ InputStream responseStream = response.getEntity().getContent();
+ DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document xml = xmlBuilder.parse(responseStream);
+
+ NodeList smsNodes = xml.getElementsByTagName("Sms");
+ for (int i = 0; i < smsNodes.getLength(); i++) {
+ Element smsElement = (Element) smsNodes.item(i);
+
+ OutgoingSmsMessage reply = new OutgoingSmsMessage();
+
+ reply.setFrom(recipient);
+ reply.setTo(sender);
+ reply.setMessage(smsElement.getFirstChild().getNodeValue());
+
+ replies.add(reply);
+ }
+ } catch (SAXException ex) {
+ app.logError("Error parsing response from server while forwarding incoming message", ex);
+ } catch (IOException ex) {
+ app.logError("Error forwarding incoming message to server", ex);
+ } catch (ParserConfigurationException ex) {
+ app.logError("Error configuring XML parser", ex);
+ }
+
+ return replies;
+ }
+
+ public void smsReceived(Intent intent) {
+
+ for (SmsMessage sms : getMessagesFromIntent(intent)) {
+ List replies = sendMessageToServer(sms);
+
+ for (OutgoingSmsMessage reply : replies)
+ {
+ app.sendSMS(reply);
+ }
+
+ //DeleteSMSFromInbox(context, mesg);
+ }
+
+ }
+
+
+ @Override
+ // source: http://www.devx.com/wireless/Article/39495/1954
+ public void onReceive(Context context, Intent intent) {
+ try {
+ this.app = new App(context);
+
+ String action = intent.getAction();
+
+ if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {
+ smsReceived(intent);
+ }
+ } catch (Throwable ex) {
+ app.logError("Unexpected error in IncomingMessageForwarder", ex, true);
+ }
+ }
+
+ /*
+ private void DeleteSMSFromInbox(Context context, SmsMessage mesg) {
+ Log.d("KALSMS", "try to delete SMS");
+ try {
+ Uri uriSms = Uri.parse("content://sms/inbox");
+ StringBuilder sb = new StringBuilder();
+ sb.append("address='" + mesg.getOriginatingAddress() + "' AND ");
+ sb.append("body='" + mesg.getMessageBody() + "'");
+ Cursor c = context.getContentResolver().query(uriSms, null, sb.toString(), null, null);
+ c.moveToFirst();
+ int thread_id = c.getInt(1);
+ context.getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id), null, null);
+ c.close();
+ } catch (Exception ex) {
+ // deletions don't work most of the time since the timing of the
+ // receipt and saving to the inbox
+ // makes it difficult to match up perfectly. the SMS might not be in
+ // the inbox yet when this receiver triggers!
+ Log.d("SmsReceiver", "Error deleting sms from inbox: " + ex.getMessage());
+ }
+ }
+ */
+
+ // from http://github.com/dimagi/rapidandroid
+ // source: http://www.devx.com/wireless/Article/39495/1954
+
+ private SmsMessage[] getMessagesFromIntent(Intent intent) {
+ SmsMessage retMsgs[] = null;
+ Bundle bdl = intent.getExtras();
+ Object pdus[] = (Object[]) bdl.get("pdus");
+ retMsgs = new SmsMessage[pdus.length];
+ for (int n = 0; n < pdus.length; n++) {
+ byte[] byteData = (byte[]) pdus[n];
+ retMsgs[n] = SmsMessage.createFromPdu(byteData);
+ }
+ return retMsgs;
+ }
+}
\ No newline at end of file
diff --git a/src/org/envaya/kalsms/Main.java b/src/org/envaya/kalsms/Main.java
new file mode 100755
index 0000000..a4e4e8f
--- /dev/null
+++ b/src/org/envaya/kalsms/Main.java
@@ -0,0 +1,102 @@
+package org.envaya.kalsms;
+
+import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.preference.PreferenceManager;
+import android.text.Html;
+import android.text.method.ScrollingMovementMethod;
+import android.view.Menu;
+import android.widget.TextView;
+
+public class Main extends Activity {
+
+ private BroadcastReceiver logReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ showLogMessage(intent.getExtras().getString("message"));
+ }
+ };
+
+ public void showLogMessage(String message)
+ {
+ TextView info = (TextView) Main.this.findViewById(R.id.info);
+ if (message != null)
+ {
+ info.append(message + "\n");
+ }
+ }
+
+ public void onResume() {
+ App.debug("RESUME");
+ super.onResume();
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ App.debug("STARTED");
+
+ setContentView(R.layout.main);
+ PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
+
+ AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(this,
+ 0,
+ new Intent(this, OutgoingMessagePoller.class),
+ 0);
+
+ alarm.setRepeating(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime(),
+ App.OUTGOING_POLL_SECONDS * 1000,
+ pendingIntent);
+
+ App app = new App(this.getApplication());
+
+ TextView info = (TextView) this.findViewById(R.id.info);
+
+ info.setText(Html.fromHtml("SMS Gateway running.
"));
+
+ showLogMessage("Server URL is: " + app.getServerUrl());
+ showLogMessage("Your phone number is: " + app.getPhoneNumber());
+ showLogMessage("Checking for outgoing messages every " + App.OUTGOING_POLL_SECONDS + " sec");
+
+ info.append(Html.fromHtml("Press Menu to edit settings.
"));
+
+ info.setMovementMethod(new ScrollingMovementMethod());
+
+ IntentFilter logReceiverFilter = new IntentFilter();
+
+ logReceiverFilter.addAction(App.LOG_INTENT);
+ registerReceiver(logReceiver, logReceiverFilter);
+ }
+
+ // first time the Menu key is pressed
+ public boolean onCreateOptionsMenu(Menu menu) {
+ startActivity(new Intent(this, Prefs.class));
+ return(true);
+ }
+
+ // any other time the Menu key is pressed
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ startActivity(new Intent(this, Prefs.class));
+ return(true);
+ }
+
+ @Override
+ protected void onStop(){
+ // dont do much with this, atm..
+ super.onStop();
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/envaya/kalsms/MessageStatusNotifier.java b/src/org/envaya/kalsms/MessageStatusNotifier.java
new file mode 100755
index 0000000..a2bad10
--- /dev/null
+++ b/src/org/envaya/kalsms/MessageStatusNotifier.java
@@ -0,0 +1,82 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.envaya.kalsms;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telephony.SmsManager;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+
+public class MessageStatusNotifier extends BroadcastReceiver {
+
+ private App app;
+
+ public void notifySuccess(String serverId)
+ {
+ if (serverId != null)
+ {
+ try {
+ app.log("Notifying server of sent SMS id=" + serverId);
+ List params = new ArrayList();
+ params.add(new BasicNameValuePair("from", app.getPhoneNumber()));
+ params.add(new BasicNameValuePair("secret", app.getPassword()));
+ params.add(new BasicNameValuePair("id", serverId));
+
+ HttpClient client = new DefaultHttpClient();
+ HttpPost post = new HttpPost(app.getSendStatusUrl());
+ post.setEntity(new UrlEncodedFormEntity(params));
+
+ client.execute(post);
+ }
+ catch (IOException ex)
+ {
+ app.logError("Error while notifying server of outgoing message", ex);
+ }
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ app = new App(context);
+
+ String serverId = intent.getExtras().getString("serverId");
+
+ String desc = serverId == null ? "SMS reply" : ("SMS id=" + serverId);
+
+ switch (getResultCode()) {
+ case Activity.RESULT_OK:
+ app.log(desc + " sent successfully");
+ this.notifySuccess(serverId);
+ break;
+ case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+ app.log(desc + " could not be sent (generic failure)");
+ break;
+ case SmsManager.RESULT_ERROR_RADIO_OFF:
+ app.log(desc + " could not be sent (radio off)");
+ break;
+ case SmsManager.RESULT_ERROR_NO_SERVICE:
+ app.log(desc + " could not be sent (no service)");
+ break;
+ case SmsManager.RESULT_ERROR_NULL_PDU:
+ app.log(desc + " could not be sent (null PDU");
+ break;
+ default:
+ app.log("SMS could not be sent (unknown error)");
+ break;
+ }
+ }
+}
diff --git a/src/org/envaya/kalsms/OutgoingMessagePoller.java b/src/org/envaya/kalsms/OutgoingMessagePoller.java
new file mode 100755
index 0000000..f204cac
--- /dev/null
+++ b/src/org/envaya/kalsms/OutgoingMessagePoller.java
@@ -0,0 +1,89 @@
+package org.envaya.kalsms;
+
+import java.util.ArrayList;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+public class OutgoingMessagePoller extends BroadcastReceiver {
+
+ private App app;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try
+ {
+ app = new App(context);
+
+ app.log("Checking for outgoing messages");
+
+ for (OutgoingSmsMessage sms : getOutgoingMessages())
+ {
+ app.sendSMS(sms);
+ }
+ }
+ catch (Throwable ex)
+ {
+ app.logError("Unexpected error in OutgoingMessagePoller", ex, true);
+ }
+ }
+
+ public List getOutgoingMessages() {
+ List messages = new ArrayList();
+
+ try {
+ List params = new ArrayList();
+ params.add(new BasicNameValuePair("from", app.getPhoneNumber()));
+ params.add(new BasicNameValuePair("secret", app.getPassword()));
+
+ HttpClient client = new DefaultHttpClient();
+ HttpPost post = new HttpPost(app.getOutgoingUrl());
+ post.setEntity(new UrlEncodedFormEntity(params));
+
+ HttpResponse response = client.execute(post);
+
+ InputStream responseStream = response.getEntity().getContent();
+ DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document xml = xmlBuilder.parse(responseStream);
+
+ NodeList smsNodes = xml.getElementsByTagName("Sms");
+ for (int i = 0; i < smsNodes.getLength(); i++) {
+ Element smsElement = (Element) smsNodes.item(i);
+ OutgoingSmsMessage sms = new OutgoingSmsMessage();
+
+ sms.setFrom(app.getPhoneNumber());
+ sms.setTo(smsElement.getAttribute("to"));
+ sms.setMessage(smsElement.getFirstChild().getNodeValue());
+ sms.setServerId(smsElement.getAttribute("id"));
+
+ messages.add(sms);
+ }
+ } catch (SAXException ex) {
+ app.logError("Error parsing response from server while retreiving outgoing messages", ex);
+ } catch (IOException ex) {
+ app.logError("Error retreiving outgoing messages from server", ex);
+ } catch (ParserConfigurationException ex) {
+ app.logError("Error configuring XML parser", ex);
+ }
+
+ return messages;
+ }
+
+}
diff --git a/src/org/envaya/kalsms/OutgoingSmsMessage.java b/src/org/envaya/kalsms/OutgoingSmsMessage.java
new file mode 100755
index 0000000..bed824a
--- /dev/null
+++ b/src/org/envaya/kalsms/OutgoingSmsMessage.java
@@ -0,0 +1,60 @@
+
+package org.envaya.kalsms;
+
+public class OutgoingSmsMessage {
+
+ private String serverId;
+ private String message;
+ private String from;
+ private String to;
+
+ public OutgoingSmsMessage()
+ {
+ }
+
+ public String getLogName()
+ {
+ return (serverId == null) ? "SMS reply" : ("SMS id=" + serverId);
+ }
+
+ public String getServerId()
+ {
+ return serverId;
+ }
+
+ public void setServerId(String id)
+ {
+ this.serverId = id;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage(String message)
+ {
+ this.message = message;
+ }
+
+ public String getFrom()
+ {
+ return from;
+ }
+
+ public void setFrom(String from)
+ {
+ this.from = from;
+ }
+
+ public String getTo()
+ {
+ return to;
+ }
+
+ public void setTo(String to)
+ {
+ this.to = to;
+ }
+
+}
diff --git a/src/org/envaya/kalsms/Prefs.java b/src/org/envaya/kalsms/Prefs.java
new file mode 100755
index 0000000..4d00416
--- /dev/null
+++ b/src/org/envaya/kalsms/Prefs.java
@@ -0,0 +1,71 @@
+package org.envaya.kalsms;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.view.Menu;
+
+public class Prefs extends PreferenceActivity implements OnSharedPreferenceChangeListener {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.prefs);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // Set up a listener whenever a key changes
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ // Unregister the listener whenever a key changes
+ getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ /*
+ Preference pref = findPreference(key);
+ if (pref instanceof EditTextPreference) {
+ EditTextPreference textPref = (EditTextPreference) pref;
+ pref.setSummary(textPref.getSummary());
+ Log.d("KALSMS", "textPref.getSummary(): " + textPref.getSummary());
+ }
+ if(pref instanceof CheckBoxPreference) {
+ CheckBoxPreference checkbox = (CheckBoxPreference) pref;
+ AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+ Intent pintent = new Intent(this, SMSSender.class);
+ PendingIntent pIntent = PendingIntent.getBroadcast(this,0,pintent, 0);
+ if(checkbox.isChecked()) {
+ alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime(),
+ AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
+ Log.d("KALSMS", "alarm manager turned on");
+ } else {
+ alarm.cancel(pIntent);
+ Log.d("SMS_GATEWAY", "alarm manager turned off");
+ }
+ }
+ */
+ }
+
+ // first time the Menu key is pressed
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ startActivity(new Intent(this, Prefs.class));
+ return (true);
+ }
+
+ // any other time the Menu key is pressed
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ startActivity(new Intent(this, Prefs.class));
+ return (true);
+ }
+}