diff --git a/res/xml/contacts.xml b/res/xml/contacts.xml
index 7ea6e561..57aea051 100644
--- a/res/xml/contacts.xml
+++ b/res/xml/contacts.xml
@@ -37,6 +37,13 @@
+
+
+
+
+
+
+
diff --git a/src/at/bitfire/davdroid/resource/Contact.java b/src/at/bitfire/davdroid/resource/Contact.java
index dc45b71e..c55b686a 100644
--- a/src/at/bitfire/davdroid/resource/Contact.java
+++ b/src/at/bitfire/davdroid/resource/Contact.java
@@ -23,7 +23,6 @@ import lombok.ToString;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.ValidationException;
-import net.fortuna.ical4j.util.CompatibilityHints;
import net.fortuna.ical4j.vcard.GroupRegistry;
import net.fortuna.ical4j.vcard.ParameterFactoryRegistry;
import net.fortuna.ical4j.vcard.Property;
@@ -33,6 +32,7 @@ import net.fortuna.ical4j.vcard.VCard;
import net.fortuna.ical4j.vcard.VCardBuilder;
import net.fortuna.ical4j.vcard.VCardOutputter;
import net.fortuna.ical4j.vcard.parameter.Type;
+import net.fortuna.ical4j.vcard.property.Address;
import net.fortuna.ical4j.vcard.property.BDay;
import net.fortuna.ical4j.vcard.property.Email;
import net.fortuna.ical4j.vcard.property.Fn;
@@ -45,7 +45,6 @@ import net.fortuna.ical4j.vcard.property.Uid;
import net.fortuna.ical4j.vcard.property.Url;
import net.fortuna.ical4j.vcard.property.Version;
-import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import android.util.Log;
@@ -64,7 +63,7 @@ public class Contact extends Resource {
@Getter @Setter private String prefix, givenName, middleName, familyName, suffix;
@Getter @Setter private String phoneticGivenName, phoneticMiddleName, phoneticFamilyName;
@Getter @Setter private String[] nickNames;
-
+
@Getter @Setter private byte[] photo;
@Getter @Setter private Date birthDay;
@@ -92,6 +91,11 @@ public class Contact extends Resource {
phoneNumbers.add(number);
}
+ @Getter private List
addresses = new LinkedList();
+ public void addAddress(Address address) {
+ addresses.add(address);
+ }
+
@Getter private List URLs = new LinkedList();
public void addURL(URI url) {
URLs.add(url);
@@ -118,8 +122,6 @@ public class Contact extends Resource {
propertyFactoryRegistry.register("X-" + PhoneticMiddleName.PROPERTY_NAME, new PhoneticMiddleName.Factory());
propertyFactoryRegistry.register("X-" + PhoneticLastName.PROPERTY_NAME, new PhoneticLastName.Factory());
- //Log.d(TAG, IOUtils.toString(is));
-
VCardBuilder builder = new VCardBuilder(
new InputStreamReader(is),
new GroupRegistry(),
@@ -155,7 +157,6 @@ public class Contact extends Resource {
if (nickname != null)
nickNames = nickname.getNames();
- // structured name
N n = (N)vcard.getProperty(Id.N);
if (n != null) {
prefix = StringUtils.join(n.getPrefixes(), " ");
@@ -165,7 +166,6 @@ public class Contact extends Resource {
suffix = StringUtils.join(n.getSuffixes(), " ");
}
- // phonetic name
PhoneticFirstName phoneticFirstName = (PhoneticFirstName)vcard.getExtendedProperty(PhoneticFirstName.PROPERTY_NAME);
if (phoneticFirstName != null)
phoneticGivenName = phoneticFirstName.getValue();
@@ -182,6 +182,9 @@ public class Contact extends Resource {
for (Property p : vcard.getProperties(Id.TEL))
phoneNumbers.add((Telephone)p);
+ for (Property p : vcard.getProperties(Id.ADR))
+ addresses.add((Address)p);
+
Photo photo = (Photo)vcard.getProperty(Id.PHOTO);
if (photo != null)
this.photo = photo.getBinary();
@@ -236,12 +239,15 @@ public class Contact extends Resource {
properties.add(new PhoneticMiddleName(phoneticMiddleName));
if (phoneticFamilyName != null)
properties.add(new PhoneticLastName(phoneticFamilyName));
+
+ if (!emails.isEmpty())
+ properties.addAll(emails);
+
+ if (!addresses.isEmpty())
+ properties.addAll(addresses);
- for (Email email : emails)
- properties.add(email);
-
- for (Telephone number : phoneNumbers)
- properties.add(number);
+ if (!phoneNumbers.isEmpty())
+ properties.addAll(phoneNumbers);
for (URI uri : URLs)
properties.add(new Url(uri));
diff --git a/src/at/bitfire/davdroid/resource/LocalAddressBook.java b/src/at/bitfire/davdroid/resource/LocalAddressBook.java
index b734603f..1dfdd6da 100644
--- a/src/at/bitfire/davdroid/resource/LocalAddressBook.java
+++ b/src/at/bitfire/davdroid/resource/LocalAddressBook.java
@@ -16,6 +16,7 @@ import java.util.List;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.vcard.Parameter.Id;
import net.fortuna.ical4j.vcard.parameter.Type;
+import net.fortuna.ical4j.vcard.property.Address;
import net.fortuna.ical4j.vcard.property.Telephone;
import org.apache.commons.lang.StringUtils;
@@ -37,6 +38,7 @@ import android.provider.ContactsContract.CommonDataKinds.Note;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
@@ -223,6 +225,32 @@ public class LocalAddressBook extends LocalCollection {
c.addPhoneNumber(number);
}
+ // postal addresses
+ cursor = providerClient.query(dataURI(), new String[] {
+ /* 0 */ StructuredPostal.FORMATTED_ADDRESS, StructuredPostal.TYPE,
+ /* 2 */ StructuredPostal.STREET, StructuredPostal.POBOX, StructuredPostal.NEIGHBORHOOD,
+ /* 5 */ StructuredPostal.CITY, StructuredPostal.REGION, StructuredPostal.POSTCODE,
+ /* 8 */ StructuredPostal.COUNTRY
+ }, StructuredPostal.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
+ new String[] { String.valueOf(c.getLocalID()), StructuredPostal.CONTENT_ITEM_TYPE }, null);
+ while (cursor != null && cursor.moveToNext()) {
+ Type[] types = new Type[] {};
+ switch (cursor.getInt(1)) {
+ case StructuredPostal.TYPE_HOME:
+ types = new Type[] { Type.HOME };
+ break;
+ case StructuredPostal.TYPE_WORK:
+ types = new Type[] { Type.WORK };
+ break;
+ }
+ Address address = new Address(
+ cursor.getString(3), cursor.getString(4), cursor.getString(2),
+ cursor.getString(5), cursor.getString(6), cursor.getString(7),
+ cursor.getString(8), types
+ );
+ c.addAddress(address);
+ }
+
// photo
cursor = providerClient.query(dataURI(), new String[] { Photo.PHOTO },
Photo.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
@@ -329,6 +357,9 @@ public class LocalAddressBook extends LocalCollection {
for (Telephone number : contact.getPhoneNumbers())
pendingOperations.add(buildPhoneNumber(newDataInsertBuilder(localID, backrefIdx), number).build());
+
+ for (Address address : contact.getAddresses())
+ pendingOperations.add(buildAddress(newDataInsertBuilder(localID, backrefIdx), address).build());
if (contact.getPhoto() != null)
pendingOperations.add(buildPhoto(newDataInsertBuilder(localID, backrefIdx), contact.getPhoto()).build());
@@ -444,6 +475,43 @@ public class LocalAddressBook extends LocalCollection {
.withValue(Phone.TYPE, type);
}
+ protected Builder buildAddress(Builder builder, Address address) {
+ /* street po.box (extended)
+ * region
+ * postal code city
+ * country
+ */
+ String lineStreet = StringUtils.join(new String[] { address.getStreet(), address.getPoBox(), address.getExtended() }, " "),
+ lineLocality = StringUtils.join(new String[] { address.getPostcode(), address.getLocality() }, " ");
+
+ List lines = new LinkedList();
+ if (lineStreet != null)
+ lines.add(lineStreet);
+ if (address.getRegion() != null && !address.getRegion().isEmpty())
+ lines.add(address.getRegion());
+ if (lineLocality != null)
+ lines.add(lineLocality);
+
+ int typeCode = StructuredPostal.TYPE_OTHER;
+ Type type = (Type)address.getParameter(Id.TYPE);
+ if (type == Type.HOME)
+ typeCode = StructuredPostal.TYPE_HOME;
+ else if (type == Type.WORK)
+ typeCode = StructuredPostal.TYPE_WORK;
+
+ return builder
+ .withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE)
+ .withValue(StructuredPostal.FORMATTED_ADDRESS, StringUtils.join(lines, "\n"))
+ .withValue(StructuredPostal.TYPE, typeCode)
+ .withValue(StructuredPostal.STREET, address.getStreet())
+ .withValue(StructuredPostal.POBOX, address.getPoBox())
+ .withValue(StructuredPostal.NEIGHBORHOOD, address.getExtended())
+ .withValue(StructuredPostal.CITY, address.getLocality())
+ .withValue(StructuredPostal.REGION, address.getRegion())
+ .withValue(StructuredPostal.POSTCODE, address.getPostcode())
+ .withValue(StructuredPostal.COUNTRY, address.getCountry());
+ }
+
protected Builder buildPhoto(Builder builder, byte[] photo) {
return builder
.withValue(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE)
diff --git a/src/at/bitfire/davdroid/resource/RemoteCollection.java b/src/at/bitfire/davdroid/resource/RemoteCollection.java
index 5e5557ea..97243c79 100644
--- a/src/at/bitfire/davdroid/resource/RemoteCollection.java
+++ b/src/at/bitfire/davdroid/resource/RemoteCollection.java
@@ -8,6 +8,7 @@
package at.bitfire.davdroid.resource;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;
@@ -80,8 +81,12 @@ public abstract class RemoteCollection {
for (WebDavResource member : collection.getMembers()) {
ResourceType resource = newResourceSkeleton(member.getName(), member.getETag());
try {
- resource.parseEntity(member.getContent());
- foundResources.add(resource);
+ InputStream is = member.getContent();
+ if (is != null) {
+ resource.parseEntity(is);
+ foundResources.add(resource);
+ } else
+ Log.e(TAG, "Ignoring entity without content");
} catch (ParserException ex) {
Log.e(TAG, "Ignoring unparseable entity in multi-response", ex);
}
diff --git a/src/at/bitfire/davdroid/webdav/WebDavResource.java b/src/at/bitfire/davdroid/webdav/WebDavResource.java
index 062bb7ac..8b405ac0 100644
--- a/src/at/bitfire/davdroid/webdav/WebDavResource.java
+++ b/src/at/bitfire/davdroid/webdav/WebDavResource.java
@@ -140,12 +140,14 @@ public class WebDavResource {
checkResponse(response);
Header[] allowHeaders = response.getHeaders("Allow");
- for (Header allowHeader : allowHeaders)
- methods.addAll(Arrays.asList(allowHeader.getValue().split(", ?")));
+ if (allowHeaders != null)
+ for (Header allowHeader : allowHeaders)
+ methods.addAll(Arrays.asList(allowHeader.getValue().split(", ?")));
Header[] capHeaders = response.getHeaders("DAV");
- for (Header capHeader : capHeaders)
- capabilities.addAll(Arrays.asList(capHeader.getValue().split(", ?")));
+ if (capHeaders != null)
+ for (Header capHeader : capHeaders)
+ capabilities.addAll(Arrays.asList(capHeader.getValue().split(", ?")));
}
public boolean supportsDAV(String capability) {