session-android/src/org/thoughtcrime/securesms/database/XmlBackup.java
Moxie Marlinspike aa25f94291 Enhanced import/export support.
1) Allow imports from the stock SMS database at any time.

2) Provide plaintext export support, in a format compatible with
   the "SMS Backup And Restore" app.

3) Fix the DB weirdness on encrypted restore that previously
   required killing the app.
2013-06-24 21:02:30 -07:00

185 lines
6.0 KiB
Java

package org.thoughtcrime.securesms.database;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
public class XmlBackup {
private static final String PROTOCOL = "protocol";
private static final String ADDRESS = "address";
private static final String DATE = "date";
private static final String TYPE = "type";
private static final String SUBJECT = "subject";
private static final String BODY = "body";
private static final String SERVICE_CENTER = "service_center";
private static final String READ = "read";
private static final String STATUS = "status";
private final XmlPullParser parser;
public XmlBackup(String path) throws XmlPullParserException, FileNotFoundException {
this.parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(new FileInputStream(path), null);
}
public XmlBackupItem getNext() throws IOException, XmlPullParserException {
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (!name.equals("sms")) {
continue;
}
int attributeCount = parser.getAttributeCount();
if (attributeCount <= 0) {
continue;
}
XmlBackupItem item = new XmlBackupItem();
for (int i=0;i<attributeCount;i++) {
String attributeName = parser.getAttributeName(i);
if (attributeName.equals(PROTOCOL )) item.protocol = Integer.parseInt(parser.getAttributeValue(i));
else if (attributeName.equals(ADDRESS )) item.address = parser.getAttributeValue(i);
else if (attributeName.equals(DATE )) item.date = Long.parseLong(parser.getAttributeValue(i));
else if (attributeName.equals(TYPE )) item.type = Integer.parseInt(parser.getAttributeValue(i));
else if (attributeName.equals(SUBJECT )) item.subject = parser.getAttributeValue(i);
else if (attributeName.equals(BODY )) item.body = parser.getAttributeValue(i);
else if (attributeName.equals(SERVICE_CENTER)) item.serviceCenter = parser.getAttributeValue(i);
else if (attributeName.equals(READ )) item.read = Integer.parseInt(parser.getAttributeValue(i));
else if (attributeName.equals(STATUS )) item.status = Integer.parseInt(parser.getAttributeValue(i));
}
return item;
}
return null;
}
public static class XmlBackupItem {
private int protocol;
private String address;
private long date;
private int type;
private String subject;
private String body;
private String serviceCenter;
private int read;
private int status;
public XmlBackupItem() {}
public XmlBackupItem(int protocol, String address, long date, int type, String subject,
String body, String serviceCenter, int read, int status)
{
this.protocol = protocol;
this.address = address;
this.date = date;
this.type = type;
this.subject = subject;
this.body = body;
this.serviceCenter = serviceCenter;
this.read = read;
this.status = status;
}
public int getProtocol() {
return protocol;
}
public String getAddress() {
return address;
}
public long getDate() {
return date;
}
public int getType() {
return type;
}
public String getSubject() {
return subject;
}
public String getBody() {
return body;
}
public String getServiceCenter() {
return serviceCenter;
}
public int getRead() {
return read;
}
public int getStatus() {
return status;
}
}
public static class Writer {
private BufferedWriter writer;
private XmlSerializer serializer;
public Writer(String path, int count) throws IOException {
this.writer = new BufferedWriter(new FileWriter(path));
this.serializer = Xml.newSerializer();
this.serializer.setOutput(writer);
this.serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
this.serializer.startDocument("UTF-8", true);
this.serializer.startTag("", "smses");
this.serializer.attribute("", "count", count+"");
}
public void writeItem(XmlBackupItem item) throws IOException {
this.serializer.startTag("", "sms");
this.serializer.attribute("", "protocol", item.getProtocol() + "");
this.serializer.attribute("", "address", item.getAddress());
this.serializer.attribute("", "date", item.getDate()+"");
this.serializer.attribute("", "type", item.getType()+"");
this.serializer.attribute("", "subject", item.getSubject()+"");
try {
this.serializer.attribute("", "body", item.getBody()+"");
} catch (IllegalArgumentException ise) {
// XXX - Fucking Android. Their serializer includes a bug that doesn't
// handle some unicode characters correctly.
Log.w("XmlBackup", ise);
}
this.serializer.attribute("", "toa", null+"");
this.serializer.attribute("", "sc_toa", null+"");
this.serializer.attribute("", "service_center", item.getServiceCenter()+"");
this.serializer.attribute("", "read", item.getRead()+"");
this.serializer.attribute("" , "status", item.getStatus()+"");
this.serializer.attribute("", "locked", "0");
this.serializer.endTag("", "sms");
}
public void close() throws IOException {
this.serializer.endTag("", "smses");
this.serializer.endDocument();
}
}
}