/** * e_vcard_attribute_param_copy: * @param: an #EVCardAttributeParam * * Makes a copy of @param. * * Return value: a new #EVCardAttributeParam identical to @param. **/ EVCardAttributeParam* e_vcard_attribute_param_copy (EVCardAttributeParam *param) { EVCardAttributeParam *p; GList *l; g_return_val_if_fail (param != NULL, NULL); p = e_vcard_attribute_param_new (e_vcard_attribute_param_get_name (param)); for (l = param->values; l; l = l->next) { e_vcard_attribute_param_add_value (p, l->data); } return p; }
/* * Convenience function to set the type parmeter of a vcard attribute * * attr: the attribute to modify * type: semicolan seperated list of values * */ void hito_vcard_attribute_set_type (EVCardAttribute *attr, const gchar *type) { GList *params; EVCardAttributeParam *p = NULL; gchar **values; gint i; /* look for the TYPE parameter */ for (params = e_vcard_attribute_get_params (attr); params; params = g_list_next (params)) { if (!strcmp (e_vcard_attribute_param_get_name (params->data), "TYPE")) { p = params->data; break; } } /* we didn't find the TYPE parameter, so create it now */ if (!p) { /* if there isn't an existing TYPE and we are not setting a value, we can * return straight away */ if (!type) return; p = e_vcard_attribute_param_new ("TYPE"); e_vcard_attribute_add_param (attr, p); } /* remove the current values */ e_vcard_attribute_param_remove_values (p); /* if type is null, we don't want to add any type parameters */ if (!type) return; values = g_strsplit (type, ";", -1); for (i = 0; (values[i]); i++) { e_vcard_attribute_param_add_value (p, values[i]); } g_strfreev (values); }
static GtkWidget * contacts_type_edit_widget_new (EVCardAttribute *attr, gboolean multi_line, gboolean *changed) { const TypeTuple *types; types = contacts_get_field_types (e_vcard_attribute_get_name (attr)); if (types) { guint i; GtkWidget *combo = gtk_combo_box_entry_new_text (); GtkWidget *align; gchar *first_type = ""; EVCardAttributeParam *param; EContactTypeChangeData *data; /* Retrieve all types, but we only look at the first one * TODO: A sane way of selecting multiple types, to conform * with spec? (Almost no other vCard-using apps do this, * so not high priority) */ GList *contact_types = contacts_get_types ( e_vcard_attribute_get_params (attr)); if (contact_types) { param = (EVCardAttributeParam *)contact_types->data; GList *values = e_vcard_attribute_param_get_values (param); first_type = values ? (gchar *)values->data : ""; g_list_free (contact_types); } else { param = e_vcard_attribute_param_new ("TYPE"); e_vcard_attribute_add_param_with_value ( attr, param, ""); } data = g_new (EContactTypeChangeData, 1); data->param = param; data->attr_name = e_vcard_attribute_get_name (attr); data->changed = changed; for (i = 0; types[i].index; i++) { gtk_combo_box_append_text ( GTK_COMBO_BOX (combo), _(types[i].value)); /* Note: We use a case-insensitive search here, as * specified in the spec (as the types are predefined, * we can use non-locale-friendly strcasecmp) */ if (first_type) { if (g_ascii_strcasecmp (types[i].index, first_type) == 0) { first_type = NULL; gtk_combo_box_set_active ( GTK_COMBO_BOX (combo), i); } } } /* Support custom types, as per spec */ if ((first_type) && (g_ascii_strncasecmp (first_type, "X-", 2) == 0)) { gtk_entry_set_text ( GTK_ENTRY (GTK_BIN (combo)->child), (const gchar *)(first_type+2)); first_type = NULL; } if (first_type) gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i-1); gtk_widget_show (combo); if (/*(e_vcard_attribute_is_single_valued (attr)) &&*/ (multi_line == FALSE)) align = gtk_alignment_new (0, 0.5, 0, 0); else align = gtk_alignment_new (0, 0, 0, 0); /* TODO: Find something better than this? */ gtk_widget_set_size_request (combo, 80, -1); gtk_container_add (GTK_CONTAINER (align), combo); /* Connect signal for changes */ g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (contacts_type_entry_changed), data); /* Free change data structure on destruction */ g_signal_connect_swapped (G_OBJECT (align), "destroy", G_CALLBACK (g_free), data); return align; } return NULL; }
static void vcard_import_contact (VCardImporter *gci, EContact *contact) { EContactPhoto *photo; GList *attrs, *attr; gchar *uid = NULL; /* Apple's addressbook.app exports PHOTO's without a TYPE * param, so let's figure out the format here if there's a * PHOTO attribute missing a TYPE param. * * this is sort of a hack, as EContact sets the type for us if * we use the setter. so let's e_contact_get + e_contact_set * on E_CONTACT_PHOTO. */ photo = e_contact_get (contact, E_CONTACT_PHOTO); if (photo) { e_contact_set (contact, E_CONTACT_PHOTO, photo); e_contact_photo_free (photo); } /* Deal with our XML EDestination stuff in EMAIL attributes, if there is any. */ attrs = e_contact_get_attributes (contact, E_CONTACT_EMAIL); for (attr = attrs; attr; attr = attr->next) { EVCardAttribute *a = attr->data; GList *v = e_vcard_attribute_get_values (a); if (v && v->data) { if (!strncmp ((gchar *)v->data, "<?xml", 5)) { EDestination *dest = e_destination_import ((gchar *) v->data); e_destination_export_to_vcard_attribute (dest, a); g_object_unref (dest); } } } e_contact_set_attributes (contact, E_CONTACT_EMAIL, attrs); /* Deal with TEL attributes that don't conform to what we need. * * 1. if there's no location (HOME/WORK/OTHER), default to OTHER. * 2. if there's *only* a location specified, default to VOICE. */ attrs = e_vcard_get_attributes (E_VCARD (contact)); for (attr = attrs; attr; attr = attr->next) { EVCardAttribute *a = attr->data; gboolean location_only = TRUE; gboolean no_location = TRUE; gboolean is_work_home = FALSE; GList *params, *param; if (g_ascii_strcasecmp (e_vcard_attribute_get_name (a), EVC_TEL)) continue; params = e_vcard_attribute_get_params (a); for (param = params; param; param = param->next) { EVCardAttributeParam *p = param->data; GList *vs, *v; if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (p), EVC_TYPE)) continue; vs = e_vcard_attribute_param_get_values (p); for (v = vs; v; v = v->next) { is_work_home = is_work_home || !g_ascii_strcasecmp ((gchar *)v->data, "WORK") || !g_ascii_strcasecmp ((gchar *)v->data, "HOME"); if (!g_ascii_strcasecmp ((gchar *)v->data, "WORK") || !g_ascii_strcasecmp ((gchar *)v->data, "HOME") || !g_ascii_strcasecmp ((gchar *)v->data, "OTHER")) no_location = FALSE; else location_only = FALSE; } } if (is_work_home) { /* only WORK and HOME phone numbers require locations, * the rest should be kept as is */ if (location_only) { /* add VOICE */ e_vcard_attribute_add_param_with_value (a, e_vcard_attribute_param_new (EVC_TYPE), "VOICE"); } if (no_location) { /* add OTHER */ e_vcard_attribute_add_param_with_value (a, e_vcard_attribute_param_new (EVC_TYPE), "OTHER"); } } } /* Deal with ADR and EMAIL attributes that don't conform to what * we need. If HOME or WORK isn't specified, add TYPE=OTHER. */ attrs = e_vcard_get_attributes (E_VCARD (contact)); for (attr = attrs; attr; attr = attr->next) { EVCardAttribute *a = attr->data; gboolean no_location = TRUE; GList *params, *param; if (g_ascii_strcasecmp (e_vcard_attribute_get_name (a), EVC_ADR) && g_ascii_strcasecmp (e_vcard_attribute_get_name (a), EVC_EMAIL)) continue; params = e_vcard_attribute_get_params (a); for (param = params; param; param = param->next) { EVCardAttributeParam *p = param->data; GList *vs, *v; if (g_ascii_strcasecmp (e_vcard_attribute_param_get_name (p), EVC_TYPE)) continue; vs = e_vcard_attribute_param_get_values (p); for (v = vs; v; v = v->next) { if (!g_ascii_strcasecmp ((gchar *)v->data, "WORK") || !g_ascii_strcasecmp ((gchar *)v->data, "HOME")) no_location = FALSE; } } if (no_location) { /* add OTHER */ e_vcard_attribute_add_param_with_value (a, e_vcard_attribute_param_new (EVC_TYPE), "OTHER"); } } /* Work around the fact that these fields no longer show up in the UI */ add_to_notes (contact, E_CONTACT_OFFICE); add_to_notes (contact, E_CONTACT_SPOUSE); add_to_notes (contact, E_CONTACT_BLOG_URL); /* FIXME Error checking */ if (e_book_client_add_contact_sync (gci->book_client, contact, &uid, NULL, NULL) && uid) { e_contact_set (contact, E_CONTACT_UID, uid); g_free (uid); } }
static void read_attribute_params (EVCardAttribute *attr, char **p, gboolean *quoted_printable) { char *lp; GString *str; EVCardAttributeParam *param = NULL; gboolean in_quote = FALSE; str = g_string_new (""); for( lp = skip_newline( *p, *quoted_printable ); *lp != '\n' && *lp != '\r' && *lp != '\0'; lp = skip_newline( lp, *quoted_printable ) ) { if (*lp == '"') { in_quote = !in_quote; lp = g_utf8_next_char (lp); } else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') { g_string_append_unichar (str, g_utf8_get_char (lp)); lp = g_utf8_next_char (lp); } /* accumulate until we hit the '=' or ';'. If we hit * a '=' the string contains the parameter name. if * we hit a ';' the string contains the parameter * value and the name is either ENCODING (if value == * QUOTED-PRINTABLE) or TYPE (in any other case.) */ else if (*lp == '=') { if (str->len > 0) { param = e_vcard_attribute_param_new (str->str); g_string_assign (str, ""); lp = g_utf8_next_char (lp); } else { skip_until (&lp, ":;"); if (*lp == ';') { lp = g_utf8_next_char (lp); } else if (*lp == ':') { /* do nothing */ } else { skip_to_next_line( &lp ); break; } } } else if (*lp == ';' || *lp == ':' || *lp == ',') { gboolean colon = (*lp == ':'); gboolean comma = (*lp == ','); if (param) { if (str->len > 0) { e_vcard_attribute_param_add_value (param, str->str); g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got a parameter of the form: * PARAM=(.*,)?[:;] * so what we do depends on if there are already values * for the parameter. If there are, we just finish * this parameter and skip past the offending character * (unless it's the ':'). If there aren't values, we free * the parameter then skip past the character. */ if (!param->values) { e_vcard_attribute_param_free (param); param = NULL; if (!colon) lp = g_utf8_next_char (lp); } } if (param && !g_ascii_strcasecmp (param->name, "encoding") && !g_ascii_strcasecmp (param->values->data, "quoted-printable")) { *quoted_printable = TRUE; e_vcard_attribute_param_free (param); param = NULL; } } else { if (str->len > 0) { char *param_name; if (!g_ascii_strcasecmp (str->str, "quoted-printable")) { param_name = "ENCODING"; *quoted_printable = TRUE; } /* apple's broken addressbook app outputs naked BASE64 parameters, which aren't even vcard 3.0 compliant. */ else if (!g_ascii_strcasecmp (str->str, "base64")) { param_name = "ENCODING"; g_string_assign (str, "b"); } else { param_name = "TYPE"; } if (param_name) { param = e_vcard_attribute_param_new (param_name); e_vcard_attribute_param_add_value (param, str->str); } g_string_assign (str, ""); if (!colon) lp = g_utf8_next_char (lp); } else { /* we've got an attribute with a truly empty attribute parameter. So it's of the form: ATTR;[PARAM=value;]*;[PARAM=value;]*: (note the extra ';') the only thing to do here is, well.. nothing. we skip over the character if it's not a colon, and the rest is handled for us: We'll either continue through the loop again if we hit a ';', or we'll break out correct below if it was a ':' */ if (!colon) lp = g_utf8_next_char (lp); } } if (param && !comma) { e_vcard_attribute_add_param (attr, param); param = NULL; } if (colon) break; } else { g_warning ("invalid character found in parameter spec"); g_string_assign (str, ""); /* skip_until (&lp, ":;"); */ skip_to_next_line( &lp ); } } if (str) g_string_free (str, TRUE); *p = lp; }