5
0
mirror of https://github.com/cwinfo/envayasms.git synced 2024-09-16 12:39:35 +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:
Jesse Young 2011-09-21 21:12:39 -07:00
parent dbf35364ca
commit 73bc3c9fc6
9 changed files with 122 additions and 57 deletions

View File

@ -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" />

View File

@ -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));

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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: