Index: addressbook/tests/ebook/Makefile.am
===================================================================
--- addressbook/tests/ebook/Makefile.am	(revision 9748)
+++ addressbook/tests/ebook/Makefile.am	(working copy)
@@ -9,7 +9,7 @@
 	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
 	$(EVOLUTION_ADDRESSBOOK_LIBS)
 
-noinst_PROGRAMS= test-changes test-categories test-date test-ebook test-ebook-async test-ebook-view test-nonexistent-id test-photo test-query test-self test-string test-undefinedfield test-untyped-phones test-search test-stress-bookviews
+noinst_PROGRAMS= test-changes test-categories test-date test-ebook test-ebook-async test-ebook-view test-nonexistent-id test-ordered-phones test-photo test-query test-self test-string test-undefinedfield test-untyped-phones test-search test-stress-bookviews
 
 test_search_LDADD=$(TEST_LIBS)
 test_date_LDADD=$(TEST_LIBS)
@@ -19,6 +19,7 @@
 test_changes_LDADD=$(TEST_LIBS)
 test_categories_LDADD=$(TEST_LIBS)
 test_nonexistent_id_LDADD=$(TEST_LIBS)
+test_ordered_phones_LDADD=$(TEST_LIBS)
 test_photo_LDADD=$(TEST_LIBS)
 test_query_LDADD=$(TEST_LIBS)
 test_self_LDADD=$(TEST_LIBS)
Index: addressbook/libebook/e-contact.c
===================================================================
--- addressbook/libebook/e-contact.c	(revision 9748)
+++ addressbook/libebook/e-contact.c	(working copy)
@@ -808,7 +808,8 @@
 								e_vcard_attribute_param_new (EVC_TYPE),
 								"OTHER");
 					}
-					e_vcard_add_attribute (E_VCARD (contact), attr);
+					/* append, so that first attr is still first attr */
+					e_vcard_append_attribute (E_VCARD (contact), attr);
 				}
 
 				e_vcard_attribute_add_value (attr, sval);
@@ -829,7 +830,7 @@
 			gboolean found = FALSE;
 			int num_left = info->list_elem;
 			GList *attrs = e_vcard_get_attributes (E_VCARD (contact));
-			GList *l;
+			GList *l, *last_attr;
 
 			for (l = attrs; l && !found; l = l->next) {
 				const char *name;
@@ -880,10 +881,12 @@
 						}
 
 						if (found_needed1 && found_needed2) {
+							last_attr = l; /* remember last occurrence, even if it's not the one we want */
 							if (num_left-- == 0) {
 								found = TRUE;
-								break;
 							}
+							break; /* break here, otherwise we'd match again if there
+								  are any more params in this attribute */
 						}
 					}
 				}
@@ -896,7 +899,8 @@
 			else {
 				/* we didn't find it - add a new attribute */
 				attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
-				e_vcard_add_attribute (E_VCARD (contact), attr);
+				/* append attribute, to ensure we don't change HOME into HOME_1, for example */
+				e_vcard_append_attribute (E_VCARD (contact), attr);
 				if (info->attr_type1)
 					e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE),
 										info->attr_type1);
@@ -1372,18 +1376,25 @@
 }
 
 /**
- * e_contact_get:
+ * e_contact_get_field_and_attribute:
  * @contact: an #EContact
  * @field_id: an #EContactField
+ * @attrp: pointer to an #EVCardAttribute
  *
- * Gets the value of @contact's field specified by @field_id.
+ * Gets the value of @contact's field specified by @field_id, and
+ * returns a pointer to the corresponding #EVCardAttribute in @attrp,
+ * if the field is backed by a single attribute.  @attrp is set to NULL
+ * if the field is not backed by a single attribute, or the field is
+ * not found.
  *
  * Return value: Depends on the field's type, owned by the caller.
  **/
 gpointer
-e_contact_get (EContact *contact, EContactField field_id)
+e_contact_get_field_and_attribute (EContact *contact, EContactField field_id,
+    EVCardAttribute **attrp)
 {
 	const EContactFieldInfo *info = NULL;
+	*attrp = NULL;
 
 	g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL);
 	g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL);
@@ -1391,20 +1402,20 @@
 	info = &field_info[field_id];
 
 	if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		*attrp = e_contact_get_first_attr (contact, info->vcard_field_name);
 		gboolean rv = FALSE;
 
-		if (attr) {
-			GList *v = e_vcard_attribute_get_values (attr);
+		if (*attrp) {
+			GList *v = e_vcard_attribute_get_values (*attrp);
 			rv = v && v->data && !g_ascii_strcasecmp ((char*)v->data, "true");
 			return rv ? "1" : NULL;
 		}
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		*attrp = e_contact_get_first_attr (contact, info->vcard_field_name);
 
-		if (attr) {
-			GList *list = g_list_copy (e_vcard_attribute_get_values (attr));
+		if (*attrp) {
+			GList *list = g_list_copy (e_vcard_attribute_get_values (*attrp));
 			GList *l;
 			for (l = list; l; l = l->next)
 				l->data = g_strdup (l->data);
@@ -1413,12 +1424,12 @@
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
 		if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
-			EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+			*attrp = e_contact_get_first_attr (contact, info->vcard_field_name);
 
-			if (attr) {
+			if (*attrp) {
 				GList *v;
 
-				v = e_vcard_attribute_get_values (attr);
+				v = e_vcard_attribute_get_values (*attrp);
 				v = g_list_nth (v, info->list_elem);
 
 				return v ? g_strdup (v->data) : NULL;
@@ -1427,6 +1438,8 @@
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) {
 		if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
+			/* more than one attribute, so do not set *attrp until
+			 * we find the requested one */
 			GList *attrs, *l;
 			int num_left = info->list_elem;
 
@@ -1441,6 +1454,7 @@
 				if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
 					if (num_left-- == 0) {
 						GList *v = e_vcard_attribute_get_values (attr);
+						*attrp = attr;
 
 						return v ? g_strdup (v->data) : NULL;
 					}
@@ -1449,11 +1463,11 @@
 		}
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
-		EVCardAttribute *attr = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem);
+		*attrp = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem);
 
 		if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
-			if (attr) {
-				GList *p = e_vcard_attribute_get_values (attr);
+			if (*attrp) {
+				GList *p = e_vcard_attribute_get_values (*attrp);
 				return g_strdup (p->data);
 			}
 			else {
@@ -1461,21 +1475,21 @@
 			}
 		}
 		else { /* struct */
-			return info->struct_getter (contact, attr);
+			return info->struct_getter (contact, *attrp);
 		}
 
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
-		if (attr)
-			return info->struct_getter (contact, attr);
+		*attrp = e_contact_get_first_attr (contact, info->vcard_field_name);
+		if (*attrp)
+			return info->struct_getter (contact, *attrp);
 	}
 	else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
-		EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
+		*attrp = e_contact_get_first_attr (contact, info->vcard_field_name);
 		void *rv = NULL;
 
-		if (attr)
-			rv = info->struct_getter (contact, attr);
+		if (*attrp)
+			rv = info->struct_getter (contact, *attrp);
 
 		if (info->t & E_CONTACT_FIELD_TYPE_STRUCT)
 			return (gpointer)info->boxed_type_getter();
@@ -1504,12 +1518,12 @@
 			return g_strdup (str);
 		}
 		case E_CONTACT_CATEGORIES: {
-			EVCardAttribute *attr = e_contact_get_first_attr (contact, EVC_CATEGORIES);
+			*attrp = e_contact_get_first_attr (contact, EVC_CATEGORIES);
 			char *rv = NULL;
 
-			if (attr) {
+			if (*attrp) {
 				GString *str = g_string_new ("");
-				GList *v = e_vcard_attribute_get_values (attr);
+				GList *v = e_vcard_attribute_get_values (*attrp);
 				while (v) {
 					g_string_append (str, (char*)v->data);
 					v = v->next;
@@ -1528,6 +1542,7 @@
 		}
 	}
 	else {
+		/* no single attribute, so don't set *attrp */
 		GList *attrs, *l;
 		GList *rv = NULL; /* used for multi attribute lists */
 
@@ -1557,6 +1572,23 @@
 }
 
 /**
+ * e_contact_get:
+ * @contact: an #EContact
+ * @field_id: an #EContactField
+ *
+ * Gets the value of @contact's field specified by @field_id.
+ *
+ * Return value: Depends on the field's type, owned by the caller.
+ **/
+gpointer
+e_contact_get (EContact *contact, EContactField field_id)
+{
+	EVCardAttribute *attr;
+	return e_contact_get_field_and_attribute(contact, field_id, &attr);
+}
+
+
+/**
  * e_contact_get_const:
  * @contact: an #EContact
  * @field_id: an #EContactField
@@ -1603,8 +1635,39 @@
 
 	/* set the cached slot to NULL so we'll re-get the new string
 	   if e_contact_get_const is called again */
+	if (contact->priv->cached_strings[field_id])
+		g_free(contact->priv->cached_strings[field_id]);
 	contact->priv->cached_strings[field_id] = NULL;
 
+	/* if we're NULLing out a field, and it is a multi_elem or synthetic
+	 * type, then we need to NULL out cached strings for all elements higher
+	 * in the sequence, because they're about to move: that is, if we set
+	 * E_CONTACT_PHONE_HOME = NULL, then E_CONTACT_PHONE_HOME_2 becomes
+	 * E_CONTACT_PHONE_HOME, so we'd better not be caching
+	 * E_CONTACT_PHONE_HOME_2.
+	 */
+	/* XXX while necessary, this could be pretty costly, relative
+	 * to the benefit of caching these strings in the first place!
+	 */
+	if (value == NULL &&
+	    (field_info[field_id].t &
+		(E_CONTACT_FIELD_TYPE_MULTI_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC))) {
+		int i, nth = field_info[field_id].list_elem;
+		for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
+			if ((field_info[i].t &
+				(E_CONTACT_FIELD_TYPE_MULTI_ELEM |
+				    E_CONTACT_FIELD_TYPE_SYNTHETIC) &&
+			    (field_info[i].list_elem > nth) &&
+			    (!strcmp(field_info[i].vcard_field_name,
+				field_info[field_id].vcard_field_name)))) {
+				if (contact->priv->cached_strings[i])
+					g_free(contact->priv->cached_strings[i]);
+				contact->priv->cached_strings[i] = NULL;
+			}
+		}
+	}
+
+
 	g_object_set (contact,
 		      e_contact_field_name (field_id), value,
 		      NULL);
@@ -1640,11 +1703,12 @@
 		name = e_vcard_attribute_get_name (attr);
 
 		if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
-			l = g_list_prepend (l, e_vcard_attribute_copy (attr));
+			l = g_list_append (l, e_vcard_attribute_copy (attr));
 		}
 	}
 
-	return g_list_reverse(l);
+	return l;
+
 }
 
 /**
@@ -1669,7 +1733,11 @@
 	e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name);
 
 	for (l = attributes; l; l = l->next)
-		e_vcard_add_attribute (E_VCARD (contact),
+		/* append the attributes, to ensure synthetic
+		 * attributes such as EMAIL_1, EMAIL_2 are in the same
+		 * order as the vcard entries appear.
+		 */
+		e_vcard_append_attribute (E_VCARD (contact),
 				       e_vcard_attribute_copy ((EVCardAttribute*)l->data));
 }
 
Index: addressbook/libebook/e-vcard.c
===================================================================
--- addressbook/libebook/e-vcard.c	(revision 9748)
+++ addressbook/libebook/e-vcard.c	(working copy)
@@ -1149,6 +1149,22 @@
 }
 
 /**
+ * e_vcard_append_attribute:
+ * @evc: an #EVCard
+ * @attr: an #EVCardAttribute to add to end of list of attributes
+ *
+ * Adds @attr to @evc.
+ **/
+void
+e_vcard_append_attribute (EVCard *evc, EVCardAttribute *attr)
+{
+	g_return_if_fail (E_IS_VCARD (evc));
+	g_return_if_fail (attr != NULL);
+
+	evc->priv->attributes = g_list_append (evc->priv->attributes, attr);
+}
+
+/**
  * e_vcard_add_attribute_with_value:
  * @evcard: an #EVCard
  * @attr: an #EVCardAttribute to add
Index: addressbook/libebook/e-contact.h
===================================================================
--- addressbook/libebook/e-contact.h	(revision 9748)
+++ addressbook/libebook/e-contact.h	(working copy)
@@ -294,6 +294,7 @@
 EContact*               e_contact_duplicate        (EContact *contact);
 
 gpointer                e_contact_get              (EContact *contact, EContactField field_id);
+gpointer		e_contact_get_field_and_attribute (EContact *contact, EContactField field_id, EVCardAttribute **attrp);
 gconstpointer		e_contact_get_const        (EContact *contact, EContactField field_id);
 void                    e_contact_set              (EContact *contact, EContactField field_id, const gpointer value);
 
Index: addressbook/libebook/e-vcard.h
===================================================================
--- addressbook/libebook/e-vcard.h	(revision 9748)
+++ addressbook/libebook/e-vcard.h	(working copy)
@@ -146,6 +146,7 @@
 void             e_vcard_remove_attributes           (EVCard *evc, const char *attr_group, const char *attr_name);
 void             e_vcard_remove_attribute            (EVCard *evc, EVCardAttribute *attr);
 void             e_vcard_add_attribute               (EVCard *evc, EVCardAttribute *attr);
+void             e_vcard_append_attribute            (EVCard *evc, EVCardAttribute *attr);
 void             e_vcard_add_attribute_with_value    (EVCard *evcard, EVCardAttribute *attr, const char *value);
 void             e_vcard_add_attribute_with_values   (EVCard *evcard, EVCardAttribute *attr, ...);
 void             e_vcard_attribute_add_value         (EVCardAttribute *attr, const char *value);
