/**
 * 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;
}
Example #2
0
/*
 * 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);
}
Example #3
0
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;
}