mirror of
https://github.com/cwinfo/envayasms.git
synced 2024-12-04 12:35:32 +00:00
MMS fixes: prevent httpclient from using transfer-encoding: chunked since nginx doesn't supportit; allow forwarding mms when content-location not set
This commit is contained in:
parent
dbf35364ca
commit
73bc3c9fc6
@ -2,7 +2,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.envaya.kalsms"
|
||||
android:versionCode="3"
|
||||
android:versionName="2.0-beta 2">
|
||||
android:versionName="2.0-beta 3">
|
||||
|
||||
<uses-sdk android:minSdkVersion="4" />
|
||||
|
||||
|
@ -657,6 +657,15 @@ public final class App extends Application {
|
||||
|
||||
private HttpClient httpClient;
|
||||
|
||||
public HttpParams getDefaultHttpParams()
|
||||
{
|
||||
HttpParams httpParams = new BasicHttpParams();
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, 8000);
|
||||
HttpConnectionParams.setSoTimeout(httpParams, 8000);
|
||||
HttpProtocolParams.setContentCharset(httpParams, "UTF-8");
|
||||
return httpParams;
|
||||
}
|
||||
|
||||
public synchronized HttpClient getHttpClient()
|
||||
{
|
||||
if (httpClient == null)
|
||||
@ -664,10 +673,7 @@ public final class App extends Application {
|
||||
// via http://thinkandroid.wordpress.com/2009/12/31/creating-an-http-client-example/
|
||||
// also http://hc.apache.org/httpclient-3.x/threading.html
|
||||
|
||||
HttpParams httpParams = new BasicHttpParams();
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, 8000);
|
||||
HttpConnectionParams.setSoTimeout(httpParams, 8000);
|
||||
HttpProtocolParams.setContentCharset(httpParams, "utf-8");
|
||||
HttpParams httpParams = getDefaultHttpParams();
|
||||
|
||||
SchemeRegistry registry = new SchemeRegistry();
|
||||
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||
|
@ -34,9 +34,10 @@ public class CheckMmsInboxService extends IntentService
|
||||
{
|
||||
List<IncomingMms> messages = mmsUtils.getMessagesInInbox();
|
||||
for (IncomingMms mms : messages)
|
||||
{
|
||||
{
|
||||
if (mmsUtils.isNewMms(mms))
|
||||
{
|
||||
app.log("New MMS id=" + mms.getId() + " in inbox");
|
||||
// prevent forwarding MMS messages that existed in inbox
|
||||
// before KalSMS started, or re-forwarding MMS multiple
|
||||
// times if we don't delete them.
|
||||
|
@ -11,7 +11,6 @@ import java.util.List;
|
||||
import org.apache.http.entity.mime.FormBodyPart;
|
||||
import org.apache.http.entity.mime.content.ByteArrayBody;
|
||||
import org.apache.http.entity.mime.content.ContentBody;
|
||||
import org.apache.http.entity.mime.content.InputStreamBody;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.envaya.kalsms.task.ForwarderTask;
|
||||
|
||||
@ -106,21 +105,24 @@ public class IncomingMms extends IncomingMessage {
|
||||
{
|
||||
if (contentType != null)
|
||||
{
|
||||
contentType += "; charset=utf-8";
|
||||
contentType += "; charset=UTF-8";
|
||||
}
|
||||
|
||||
body = new ByteArrayBody(text.getBytes(), contentType, partName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// avoid using InputStreamBody because it forces the HTTP request
|
||||
// to be sent using Transfer-Encoding: chunked, which is not
|
||||
// supported by some web servers (including nginx)
|
||||
|
||||
try
|
||||
{
|
||||
body = new InputStreamBody(part.openInputStream(),
|
||||
contentType, partName);
|
||||
body = new ByteArrayBody(part.getData(), contentType, partName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
app.logError("Error opening data for " + part.toString(), ex);
|
||||
app.logError("Error reading data for " + part.toString(), ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ final class MmsObserver extends ContentObserver {
|
||||
@Override
|
||||
public void onChange(final boolean selfChange) {
|
||||
super.onChange(selfChange);
|
||||
|
||||
if (!selfChange)
|
||||
{
|
||||
// check MMS inbox in an IntentService since it may be slow
|
||||
|
@ -1,7 +1,9 @@
|
||||
package org.envaya.kalsms;
|
||||
|
||||
import android.net.Uri;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MmsPart {
|
||||
@ -11,6 +13,7 @@ public class MmsPart {
|
||||
private String name;
|
||||
private String text;
|
||||
private String cid;
|
||||
private String dataFile;
|
||||
|
||||
public MmsPart(App app, long partId)
|
||||
{
|
||||
@ -88,6 +91,60 @@ public class MmsPart {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setDataFile(String dataFile)
|
||||
{
|
||||
this.dataFile = dataFile;
|
||||
}
|
||||
|
||||
public String getDataFile()
|
||||
{
|
||||
return dataFile;
|
||||
}
|
||||
|
||||
public long getDataLength()
|
||||
{
|
||||
if (dataFile != null)
|
||||
{
|
||||
return new File(dataFile).length();
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getData() throws IOException
|
||||
{
|
||||
int length = (int)getDataLength();
|
||||
byte[] bytes = new byte[length];
|
||||
|
||||
int offset = 0;
|
||||
int bytesRead = 0;
|
||||
|
||||
InputStream in = openInputStream();
|
||||
|
||||
while (offset < bytes.length)
|
||||
{
|
||||
bytesRead = in.read(bytes, offset, bytes.length - offset);
|
||||
|
||||
if (bytesRead < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
offset += bytesRead;
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
||||
if (offset < bytes.length)
|
||||
{
|
||||
throw new IOException("Failed to read complete data of MMS part");
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* For multimedia parts, the _data column of the MMS Parts table contains the
|
||||
* path on the Android filesystem containing that file, and openInputStream
|
||||
|
@ -4,6 +4,7 @@ package org.envaya.kalsms;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -29,7 +30,7 @@ public class MmsUtils
|
||||
private static final int MESSAGE_TYPE_RETRIEVE_CONF = 0x84;
|
||||
|
||||
// todo -- prevent unbounded growth?
|
||||
private final Set<String> seenMmsContentLocations = new HashSet<String>();
|
||||
private final Set<Long> seenMmsIds = new HashSet<Long>();
|
||||
|
||||
private App app;
|
||||
private ContentResolver contentResolver;
|
||||
@ -43,7 +44,7 @@ public class MmsUtils
|
||||
private List<MmsPart> getMmsParts(long id)
|
||||
{
|
||||
Cursor cur = contentResolver.query(PART_URI, new String[] {
|
||||
"_id", "ct", "name", "text", "cid"
|
||||
"_id", "ct", "name", "text", "cid", "_data"
|
||||
}, "mid = ?", new String[] { "" + id }, null);
|
||||
|
||||
// assume that if there is at least one part saved in database
|
||||
@ -58,7 +59,9 @@ public class MmsUtils
|
||||
MmsPart part = new MmsPart(app, partId);
|
||||
part.setContentType(cur.getString(1));
|
||||
part.setName(cur.getString(2));
|
||||
|
||||
|
||||
part.setDataFile(cur.getString(5));
|
||||
|
||||
// todo interpret charset like com.google.android.mms.pdu.EncodedStringValue
|
||||
part.setText(cur.getString(3));
|
||||
|
||||
@ -105,18 +108,18 @@ public class MmsUtils
|
||||
|
||||
Cursor c = contentResolver.query(INBOX_URI,
|
||||
new String[] {"_id", "ct_l"},
|
||||
"m_type = ? AND ct_l is not NULL", new String[] { m_type }, null);
|
||||
|
||||
"m_type = ? ", new String[] { m_type }, null);
|
||||
|
||||
List<IncomingMms> messages = new ArrayList<IncomingMms>();
|
||||
|
||||
while (c.moveToNext())
|
||||
{
|
||||
long id = c.getLong(0);
|
||||
|
||||
|
||||
IncomingMms mms = new IncomingMms(app, getSenderNumber(id), id);
|
||||
|
||||
mms.setContentLocation(c.getString(1));
|
||||
|
||||
|
||||
for (MmsPart part : getMmsParts(id))
|
||||
{
|
||||
mms.addPart(part);
|
||||
@ -129,48 +132,39 @@ public class MmsUtils
|
||||
return messages;
|
||||
}
|
||||
|
||||
public boolean deleteFromInbox(IncomingMms mms)
|
||||
public synchronized boolean deleteFromInbox(IncomingMms mms)
|
||||
{
|
||||
String contentLocation = mms.getContentLocation();
|
||||
|
||||
int res;
|
||||
if (contentLocation != null)
|
||||
{
|
||||
Uri uri = Uri.parse("content://mms/inbox");
|
||||
|
||||
/*
|
||||
* Delete by content location (ct_l) rather than _id so that
|
||||
* M-Notification.ind and M-Retrieve.conf messages are both deleted
|
||||
* (otherwise it would remain in Messaging inbox with a Download button)
|
||||
*/
|
||||
|
||||
res = contentResolver.delete(uri,
|
||||
"ct_l = ?",
|
||||
new String[] { contentLocation });
|
||||
long id = mms.getId();
|
||||
|
||||
Uri uri = Uri.parse("content://mms/inbox/" + id);
|
||||
int res = contentResolver.delete(uri, null, null);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
app.log("MMS id="+id+" deleted from inbox");
|
||||
|
||||
// remove id from set because Messaging app reuses ids
|
||||
// of deleted messages.
|
||||
// TODO: handle reuse of IDs deleted directly through Messaging
|
||||
// app while KalSMS is running
|
||||
seenMmsIds.remove(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.log("mms has no content-location");
|
||||
Uri uri = Uri.parse("content://mms/inbox/" + mms.getId());
|
||||
res = contentResolver.delete(uri, null, null);
|
||||
app.log("MMS id="+id+" could not be deleted from inbox");
|
||||
}
|
||||
|
||||
app.log(res + " rows deleted");
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
public synchronized void markOldMms(IncomingMms mms)
|
||||
{
|
||||
String contentLocation = mms.getContentLocation();
|
||||
if (contentLocation != null)
|
||||
{
|
||||
seenMmsContentLocations.add(contentLocation);
|
||||
}
|
||||
long id = mms.getId();
|
||||
seenMmsIds.add(id);
|
||||
}
|
||||
|
||||
public synchronized boolean isNewMms(IncomingMms mms)
|
||||
{
|
||||
String contentLocation = mms.getContentLocation();
|
||||
return contentLocation != null && !seenMmsContentLocations.contains(contentLocation);
|
||||
}
|
||||
long id = mms.getId();
|
||||
return !seenMmsIds.contains(id);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import android.os.AsyncTask;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
@ -19,13 +20,17 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.mime.FormBodyPart;
|
||||
import org.apache.http.entity.mime.MultipartEntity;
|
||||
import org.apache.http.entity.mime.content.StringBody;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.HttpProtocolParams;
|
||||
import org.envaya.kalsms.App;
|
||||
import org.envaya.kalsms.Base64Coder;
|
||||
import org.envaya.kalsms.OutgoingMessage;
|
||||
@ -109,27 +114,30 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
||||
{
|
||||
MultipartEntity entity = new MultipartEntity();//HttpMultipartMode.BROWSER_COMPATIBLE);
|
||||
|
||||
Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
for (BasicNameValuePair param : params)
|
||||
{
|
||||
entity.addPart(param.getName(), new StringBody(param.getValue()));
|
||||
entity.addPart(param.getName(), new StringBody(param.getValue(), charset));
|
||||
}
|
||||
|
||||
for (FormBodyPart formPart : formParts)
|
||||
{
|
||||
entity.addPart(formPart);
|
||||
}
|
||||
post.setEntity(entity);
|
||||
post.setEntity(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
post.setEntity(new UrlEncodedFormEntity(params));
|
||||
}
|
||||
|
||||
HttpClient client = app.getHttpClient();
|
||||
|
||||
String signature = getSignature();
|
||||
|
||||
post.setHeader("X-Kalsms-Signature", signature);
|
||||
|
||||
HttpClient client = app.getHttpClient();
|
||||
HttpResponse response = client.execute(post);
|
||||
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
|
@ -3,14 +3,11 @@ package org.envaya.kalsms.ui;
|
||||
import org.envaya.kalsms.task.HttpTask;
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Html;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -18,6 +15,7 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import java.util.List;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.envaya.kalsms.App;
|
||||
@ -92,13 +90,13 @@ public class Main extends Activity {
|
||||
case R.id.check_now:
|
||||
app.checkOutgoingMessages();
|
||||
return true;
|
||||
case R.id.retry_now:
|
||||
case R.id.retry_now:
|
||||
app.retryStuckMessages();
|
||||
return true;
|
||||
case R.id.forward_inbox:
|
||||
startActivity(new Intent(this, ForwardInbox.class));
|
||||
return true;
|
||||
case R.id.help:
|
||||
case R.id.help:
|
||||
startActivity(new Intent(this, Help.class));
|
||||
return true;
|
||||
case R.id.test:
|
||||
|
Loading…
Reference in New Issue
Block a user