1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU Lesser General Public
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
20 * Author: Chris Toshok (toshok@ximian.com)
31 #include <glib/gi18n-lib.h>
32 #include "e-contact.h"
34 #include "e-name-western.h"
37 #include "libedataserver/e-data-server-util.h"
39 #define LOCALEDIR e_util_get_localedir ()
44 #define E_CONTACT_GET_PRIVATE(obj) \
45 (G_TYPE_INSTANCE_GET_PRIVATE \
46 ((obj), E_TYPE_CONTACT, EContactPrivate))
48 G_DEFINE_TYPE (EContact, e_contact, E_TYPE_VCARD)
50 struct _EContactPrivate {
51 gchar *cached_strings[E_CONTACT_FIELD_LAST];
54 #define E_CONTACT_FIELD_TYPE_STRING 0x00000001 /* used for simple single valued attributes */
55 /*E_CONTACT_FIELD_TYPE_FLOAT*/
56 #define E_CONTACT_FIELD_TYPE_LIST 0x00000002 /* used for multivalued single attributes - the elements are of type gchar * */
57 #define E_CONTACT_FIELD_TYPE_MULTI 0x00000004 /* used for multivalued attributes - the elements are of type EVCardAttribute */
58 #define E_CONTACT_FIELD_TYPE_GETSET 0x00000008 /* used for attributes that need custom handling for getting/setting */
59 #define E_CONTACT_FIELD_TYPE_STRUCT 0x00000010 /* used for structured types (N and ADR properties, in particular) */
60 #define E_CONTACT_FIELD_TYPE_BOOLEAN 0x00000020 /* used for boolean types (WANTS_HTML) */
62 #define E_CONTACT_FIELD_TYPE_SYNTHETIC 0x10000000 /* used when there isn't a corresponding vcard field (such as email_1) */
63 #define E_CONTACT_FIELD_TYPE_LIST_ELEM 0x20000000 /* used when a synthetic attribute is a numbered list element */
64 #define E_CONTACT_FIELD_TYPE_MULTI_ELEM 0x40000000 /* used when we're looking for the nth attribute where more than 1 can be present in the vcard */
65 #define E_CONTACT_FIELD_TYPE_ATTR_TYPE 0x80000000 /* used when a synthetic attribute is flagged with a TYPE= that we'll be looking for */
70 EContactField field_id;
71 const gchar *vcard_field_name;
72 const gchar *field_name; /* non translated */
73 const gchar *pretty_name; /* translated */
78 const gchar *attr_type1;
79 const gchar *attr_type2;
81 gpointer (*struct_getter)(EContact *contact, EVCardAttribute *attribute);
82 void (*struct_setter)(EContact *contact, EVCardAttribute *attribute, gpointer data);
84 GType (*boxed_type_getter) (void);
87 static gpointer photo_getter (EContact *contact, EVCardAttribute *attr);
88 static void photo_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
89 static gpointer geo_getter (EContact *contact, EVCardAttribute *attr);
90 static void geo_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
91 static gpointer fn_getter (EContact *contact, EVCardAttribute *attr);
92 static void fn_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
93 static gpointer n_getter (EContact *contact, EVCardAttribute *attr);
94 static void n_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
95 static gpointer fileas_getter (EContact *contact, EVCardAttribute *attr);
96 static void fileas_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
97 static gpointer adr_getter (EContact *contact, EVCardAttribute *attr);
98 static void adr_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
99 static gpointer date_getter (EContact *contact, EVCardAttribute *attr);
100 static void date_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
101 static gpointer cert_getter (EContact *contact, EVCardAttribute *attr);
102 static void cert_setter (EContact *contact, EVCardAttribute *attr, gpointer data);
104 #define STRING_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro) }
105 #define BOOLEAN_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_BOOLEAN, (id), (vc), (n), (pn), (ro) }
106 #define LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_LIST, (id), (vc), (n), (pn), (ro) }
107 #define MULTI_LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_MULTI, (id), (vc), (n), (pn), (ro) }
108 #define GETSET_FIELD(id,vc,n,pn,ro,get,set) { E_CONTACT_FIELD_TYPE_STRING | E_CONTACT_FIELD_TYPE_GETSET, (id), (vc), (n), (pn), (ro), -1, NULL, NULL, (get), (set) }
109 #define STRUCT_FIELD(id,vc,n,pn,ro,get,set,ty) { E_CONTACT_FIELD_TYPE_STRUCT | E_CONTACT_FIELD_TYPE_GETSET, (id), (vc), (n), (pn), (ro), -1, NULL, NULL, (get), (set), (ty) }
110 #define SYNTH_STR_FIELD(id,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING | E_CONTACT_FIELD_TYPE_SYNTHETIC, (id), NULL, (n), (pn), (ro) }
111 #define LIST_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_LIST_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) }
112 #define MULTI_ELEM_STR_FIELD(id,vc,n,pn,ro,nm) { E_CONTACT_FIELD_TYPE_MULTI_ELEM | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nm) }
113 #define ATTR_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), NULL }
114 #define ATTR_TYPE_GETSET_FIELD(id,vc,n,pn,ro,at1,nth,get,set) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_GETSET, (id), (vc), (n), (pn), (ro), (nth), (at1), NULL, (get), (set) }
115 #define ATTR2_TYPE_STR_FIELD(id,vc,n,pn,ro,at1,at2,nth) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro), (nth), (at1), (at2) }
116 #define ATTR_TYPE_STRUCT_FIELD(id,vc,n,pn,ro,at,get,set,ty) { E_CONTACT_FIELD_TYPE_ATTR_TYPE | E_CONTACT_FIELD_TYPE_SYNTHETIC | E_CONTACT_FIELD_TYPE_GETSET | E_CONTACT_FIELD_TYPE_STRUCT, (id), (vc), (n), (pn), (ro), 0, (at), NULL, (get), (set), (ty) }
118 /* This *must* be kept in the same order as the EContactField enum */
119 static const EContactFieldInfo field_info[] = {
120 {0,}, /* Dummy row as EContactField starts from 1 */
121 STRING_FIELD (E_CONTACT_UID, EVC_UID, "id", N_("Unique ID"), FALSE),
122 /* FILE_AS is not really a structured field - we use a getter/setter
123 * so we can generate its value if necessary in the getter */
124 /* Translators: This is an EContact field description, in this case it's a
125 * preferred user's description (or display name) of the contact. Note 'File' is a verb here. */
126 GETSET_FIELD (E_CONTACT_FILE_AS, EVC_X_FILE_AS, "file_as", N_("File Under"), FALSE, fileas_getter, fileas_setter),
127 /* URI of the book to which the contact belongs to */
128 STRING_FIELD (E_CONTACT_BOOK_URI, EVC_X_BOOK_URI, "book_uri", N_("Book URI"), FALSE),
131 /* FN isn't really a structured field - we use a getter/setter
132 * so we can set the N property (since evo 1.4 works fine with
133 * vcards that don't even have a N attribute. *sigh*) */
134 GETSET_FIELD (E_CONTACT_FULL_NAME, EVC_FN, "full_name", N_("Full Name"), FALSE, fn_getter, fn_setter),
135 LIST_ELEM_STR_FIELD (E_CONTACT_GIVEN_NAME, EVC_N, "given_name", N_("Given Name"), FALSE, 1),
136 LIST_ELEM_STR_FIELD (E_CONTACT_FAMILY_NAME, EVC_N, "family_name", N_("Family Name"), FALSE, 0),
137 STRING_FIELD (E_CONTACT_NICKNAME, EVC_NICKNAME, "nickname", N_("Nickname"), FALSE),
140 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_1, EVC_EMAIL, "email_1", N_("Email 1"), FALSE, 0),
141 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_2, EVC_EMAIL, "email_2", N_("Email 2"), FALSE, 1),
142 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_3, EVC_EMAIL, "email_3", N_("Email 3"), FALSE, 2),
143 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_4, EVC_EMAIL, "email_4", N_("Email 4"), FALSE, 3),
145 STRING_FIELD (E_CONTACT_MAILER, EVC_MAILER, "mailer", N_("Mailer"), FALSE),
148 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_HOME, EVC_LABEL, "address_label_home", N_("Home Address Label"), FALSE, "HOME", 0),
149 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK, EVC_LABEL, "address_label_work", N_("Work Address Label"), FALSE, "WORK", 0),
150 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_OTHER, EVC_LABEL, "address_label_other", N_("Other Address Label"), FALSE, "OTHER", 0),
153 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ASSISTANT, EVC_TEL, "assistant_phone", N_("Assistant Phone"), FALSE, EVC_X_ASSISTANT, 0),
154 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS, EVC_TEL, "business_phone", N_("Business Phone"), FALSE, "WORK", "VOICE", 0),
155 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_2, EVC_TEL, "business_phone_2", N_("Business Phone 2"), FALSE, "WORK", "VOICE", 1),
156 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_FAX, EVC_TEL, "business_fax", N_("Business Fax"), FALSE, "WORK", "FAX", 0),
157 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CALLBACK, EVC_TEL, "callback_phone", N_("Callback Phone"), FALSE, EVC_X_CALLBACK, 0),
158 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CAR, EVC_TEL, "car_phone", N_("Car Phone"), FALSE, "CAR", 0),
159 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_COMPANY, EVC_TEL, "company_phone", N_("Company Phone"), FALSE, EVC_X_COMPANY, 0),
160 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME, EVC_TEL, "home_phone", N_("Home Phone"), FALSE, "HOME", "VOICE", 0),
161 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_2, EVC_TEL, "home_phone_2", N_("Home Phone 2"), FALSE, "HOME", "VOICE", 1),
162 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_FAX, EVC_TEL, "home_fax", N_("Home Fax"), FALSE, "HOME", "FAX", 0),
163 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ISDN, EVC_TEL, "isdn_phone", N_("ISDN"), FALSE, "ISDN", 0),
164 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_MOBILE, EVC_TEL, "mobile_phone", N_("Mobile Phone"), FALSE, "CELL", 0),
165 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER, EVC_TEL, "other_phone", N_("Other Phone"), FALSE, "VOICE", 0),
166 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER_FAX, EVC_TEL, "other_fax", N_("Other Fax"), FALSE, "FAX", 0),
167 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PAGER, EVC_TEL, "pager", N_("Pager"), FALSE, "PAGER", 0),
168 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PRIMARY, EVC_TEL, "primary_phone", N_("Primary Phone"), FALSE, "PREF", 0),
169 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_RADIO, EVC_TEL, "radio", N_("Radio"), FALSE, EVC_X_RADIO, 0),
170 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TELEX, EVC_TEL, "telex", N_("Telex"), FALSE, EVC_X_TELEX, 0),
171 /* To translators: TTY is Teletypewriter */
172 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TTYTDD, EVC_TEL, "tty", N_("TTY"), FALSE, EVC_X_TTYTDD, 0),
174 /* Organizational fields */
175 LIST_ELEM_STR_FIELD (E_CONTACT_ORG, EVC_ORG, "org", N_("Organization"), FALSE, 0),
176 LIST_ELEM_STR_FIELD (E_CONTACT_ORG_UNIT, EVC_ORG, "org_unit", N_("Organizational Unit"), FALSE, 1),
177 LIST_ELEM_STR_FIELD (E_CONTACT_OFFICE, EVC_ORG, "office", N_("Office"), FALSE, 2),
178 STRING_FIELD (E_CONTACT_TITLE, EVC_TITLE, "title", N_("Title"), FALSE),
179 STRING_FIELD (E_CONTACT_ROLE, EVC_ROLE, "role", N_("Role"), FALSE),
180 STRING_FIELD (E_CONTACT_MANAGER, EVC_X_MANAGER, "manager", N_("Manager"), FALSE),
181 STRING_FIELD (E_CONTACT_ASSISTANT, EVC_X_ASSISTANT, "assistant", N_("Assistant"), FALSE),
184 STRING_FIELD (E_CONTACT_HOMEPAGE_URL, EVC_URL, "homepage_url", N_("Homepage URL"), FALSE),
185 STRING_FIELD (E_CONTACT_BLOG_URL, EVC_X_BLOG_URL, "blog_url", N_("Weblog URL"), FALSE),
187 /* Contact categories */
188 SYNTH_STR_FIELD (E_CONTACT_CATEGORIES, "categories", N_("Categories"), FALSE),
190 /* Collaboration fields */
191 STRING_FIELD (E_CONTACT_CALENDAR_URI, EVC_CALURI, "caluri", N_("Calendar URI"), FALSE),
192 STRING_FIELD (E_CONTACT_FREEBUSY_URL, EVC_FBURL, "fburl", N_("Free/Busy URL"), FALSE),
193 STRING_FIELD (E_CONTACT_ICS_CALENDAR, EVC_ICSCALENDAR, "icscalendar", N_("ICS Calendar"), FALSE),
194 STRING_FIELD (E_CONTACT_VIDEO_URL, EVC_X_VIDEO_URL, "video_url", N_("Video Conferencing URL"), FALSE),
197 STRING_FIELD (E_CONTACT_SPOUSE, EVC_X_SPOUSE, "spouse", N_("Spouse's Name"), FALSE),
198 STRING_FIELD (E_CONTACT_NOTE, EVC_NOTE, "note", N_("Note"), FALSE),
200 /* Instant messaging fields */
201 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_HOME_1, EVC_X_AIM, "im_aim_home_1", N_("AIM Home Screen Name 1"), FALSE, "HOME", 0),
202 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_HOME_2, EVC_X_AIM, "im_aim_home_2", N_("AIM Home Screen Name 2"), FALSE, "HOME", 1),
203 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_HOME_3, EVC_X_AIM, "im_aim_home_3", N_("AIM Home Screen Name 3"), FALSE, "HOME", 2),
204 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_WORK_1, EVC_X_AIM, "im_aim_work_1", N_("AIM Work Screen Name 1"), FALSE, "WORK", 0),
205 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_WORK_2, EVC_X_AIM, "im_aim_work_2", N_("AIM Work Screen Name 2"), FALSE, "WORK", 1),
206 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_AIM_WORK_3, EVC_X_AIM, "im_aim_work_3", N_("AIM Work Screen Name 3"), FALSE, "WORK", 2),
207 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_HOME_1, EVC_X_GROUPWISE, "im_groupwise_home_1", N_("GroupWise Home Screen Name 1"), FALSE, "HOME", 0),
208 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_HOME_2, EVC_X_GROUPWISE, "im_groupwise_home_2", N_("GroupWise Home Screen Name 2"), FALSE, "HOME", 1),
209 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_HOME_3, EVC_X_GROUPWISE, "im_groupwise_home_3", N_("GroupWise Home Screen Name 3"), FALSE, "HOME", 2),
210 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_WORK_1, EVC_X_GROUPWISE, "im_groupwise_work_1", N_("GroupWise Work Screen Name 1"), FALSE, "WORK", 0),
211 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_WORK_2, EVC_X_GROUPWISE, "im_groupwise_work_2", N_("GroupWise Work Screen Name 2"), FALSE, "WORK", 1),
212 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GROUPWISE_WORK_3, EVC_X_GROUPWISE, "im_groupwise_work_3", N_("GroupWise Work Screen Name 3"), FALSE, "WORK", 2),
213 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_HOME_1, EVC_X_JABBER, "im_jabber_home_1", N_("Jabber Home ID 1"), FALSE, "HOME", 0),
214 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_HOME_2, EVC_X_JABBER, "im_jabber_home_2", N_("Jabber Home ID 2"), FALSE, "HOME", 1),
215 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_HOME_3, EVC_X_JABBER, "im_jabber_home_3", N_("Jabber Home ID 3"), FALSE, "HOME", 2),
216 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_WORK_1, EVC_X_JABBER, "im_jabber_work_1", N_("Jabber Work ID 1"), FALSE, "WORK", 0),
217 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_WORK_2, EVC_X_JABBER, "im_jabber_work_3", N_("Jabber Work ID 2"), FALSE, "WORK", 1),
218 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_JABBER_WORK_3, EVC_X_JABBER, "im_jabber_work_2", N_("Jabber Work ID 3"), FALSE, "WORK", 2),
219 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_HOME_1, EVC_X_YAHOO, "im_yahoo_home_1", N_("Yahoo! Home Screen Name 1"), FALSE, "HOME", 0),
220 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_HOME_2, EVC_X_YAHOO, "im_yahoo_home_2", N_("Yahoo! Home Screen Name 2"), FALSE, "HOME", 1),
221 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_HOME_3, EVC_X_YAHOO, "im_yahoo_home_3", N_("Yahoo! Home Screen Name 3"), FALSE, "HOME", 2),
222 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_WORK_1, EVC_X_YAHOO, "im_yahoo_work_1", N_("Yahoo! Work Screen Name 1"), FALSE, "WORK", 0),
223 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_WORK_2, EVC_X_YAHOO, "im_yahoo_work_2", N_("Yahoo! Work Screen Name 2"), FALSE, "WORK", 1),
224 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_YAHOO_WORK_3, EVC_X_YAHOO, "im_yahoo_work_3", N_("Yahoo! Work Screen Name 3"), FALSE, "WORK", 2),
225 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_HOME_1, EVC_X_MSN, "im_msn_home_1", N_("MSN Home Screen Name 1"), FALSE, "HOME", 0),
226 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_HOME_2, EVC_X_MSN, "im_msn_home_2", N_("MSN Home Screen Name 2"), FALSE, "HOME", 1),
227 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_HOME_3, EVC_X_MSN, "im_msn_home_3", N_("MSN Home Screen Name 3"), FALSE, "HOME", 2),
228 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_WORK_1, EVC_X_MSN, "im_msn_work_1", N_("MSN Work Screen Name 1"), FALSE, "WORK", 0),
229 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_WORK_2, EVC_X_MSN, "im_msn_work_2", N_("MSN Work Screen Name 2"), FALSE, "WORK", 1),
230 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_MSN_WORK_3, EVC_X_MSN, "im_msn_work_3", N_("MSN Work Screen Name 3"), FALSE, "WORK", 2),
231 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_HOME_1, EVC_X_ICQ, "im_icq_home_1", N_("ICQ Home ID 1"), FALSE, "HOME", 0),
232 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_HOME_2, EVC_X_ICQ, "im_icq_home_2", N_("ICQ Home ID 2"), FALSE, "HOME", 1),
233 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_HOME_3, EVC_X_ICQ, "im_icq_home_3", N_("ICQ Home ID 3"), FALSE, "HOME", 2),
234 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_WORK_1, EVC_X_ICQ, "im_icq_work_1", N_("ICQ Work ID 1"), FALSE, "WORK", 0),
235 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_WORK_2, EVC_X_ICQ, "im_icq_work_2", N_("ICQ Work ID 2"), FALSE, "WORK", 1),
236 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_ICQ_WORK_3, EVC_X_ICQ, "im_icq_work_3", N_("ICQ Work ID 3"), FALSE, "WORK", 2),
238 /* Last modified time */
239 STRING_FIELD (E_CONTACT_REV, EVC_REV, "Rev", N_("Last Revision"), FALSE),
240 /* Translators: This is an EContact field description, in this case it's a
241 * virtual field, which returns either name of the contact or the organization
242 * name, recognized by multiple other fields, where the first filled is used. */
243 SYNTH_STR_FIELD (E_CONTACT_NAME_OR_ORG, "name_or_org", N_("Name or Org"), TRUE),
246 MULTI_LIST_FIELD (E_CONTACT_ADDRESS, EVC_ADR, "address", N_("Address List"), FALSE),
247 ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_HOME, EVC_ADR, "address_home", N_("Home Address"), FALSE, "HOME", adr_getter, adr_setter, e_contact_address_get_type),
248 ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_WORK, EVC_ADR, "address_work", N_("Work Address"), FALSE, "WORK", adr_getter, adr_setter, e_contact_address_get_type),
249 ATTR_TYPE_STRUCT_FIELD (E_CONTACT_ADDRESS_OTHER, EVC_ADR, "address_other", N_("Other Address"), FALSE, "OTHER", adr_getter, adr_setter, e_contact_address_get_type),
251 /* Contact categories */
252 LIST_FIELD (E_CONTACT_CATEGORY_LIST, EVC_CATEGORIES, "category_list", N_("Category List"), FALSE),
255 STRUCT_FIELD (E_CONTACT_PHOTO, EVC_PHOTO, "photo", N_("Photo"), FALSE, photo_getter, photo_setter, e_contact_photo_get_type),
256 STRUCT_FIELD (E_CONTACT_LOGO, EVC_LOGO, "logo", N_("Logo"), FALSE, photo_getter, photo_setter, e_contact_photo_get_type),
258 /* Translators: This is an EContact field description, in this case it's a name
259 * of the contact, as specified in http://tools.ietf.org/html/rfc6350#section-6.2.2 */
260 STRUCT_FIELD (E_CONTACT_NAME, EVC_N, "name", N_("Name"), FALSE, n_getter, n_setter, e_contact_name_get_type),
261 MULTI_LIST_FIELD (E_CONTACT_EMAIL, EVC_EMAIL, "email", N_("Email List"), FALSE),
263 /* Instant messaging fields */
264 MULTI_LIST_FIELD (E_CONTACT_IM_AIM, EVC_X_AIM, "im_aim", N_("AIM Screen Name List"), FALSE),
265 MULTI_LIST_FIELD (E_CONTACT_IM_GROUPWISE, EVC_X_GROUPWISE, "im_groupwise", N_("GroupWise ID List"), FALSE),
266 MULTI_LIST_FIELD (E_CONTACT_IM_JABBER, EVC_X_JABBER, "im_jabber", N_("Jabber ID List"), FALSE),
267 MULTI_LIST_FIELD (E_CONTACT_IM_YAHOO, EVC_X_YAHOO, "im_yahoo", N_("Yahoo! Screen Name List"), FALSE),
268 MULTI_LIST_FIELD (E_CONTACT_IM_MSN, EVC_X_MSN, "im_msn", N_("MSN Screen Name List"), FALSE),
269 MULTI_LIST_FIELD (E_CONTACT_IM_ICQ, EVC_X_ICQ, "im_icq", N_("ICQ ID List"), FALSE),
271 BOOLEAN_FIELD (E_CONTACT_WANTS_HTML, EVC_X_WANTS_HTML, "wants_html", N_("Wants HTML Mail"), FALSE),
273 /* Translators: This is an EContact field description, in this case it's a
274 * field describing whether it's a Contact list (list of email addresses) or a
275 * regular contact for one person/organization/... */
276 BOOLEAN_FIELD (E_CONTACT_IS_LIST, EVC_X_LIST, "list", N_("List"), FALSE),
277 /* Translators: This is an EContact field description, in this case it's a flag
278 * used to determine whether when sending to Contact lists the addresses should be
279 * shown or not to other recipients - basically whether to use BCC field or CC
280 * message header when sending messages to this Contact list. */
281 BOOLEAN_FIELD (E_CONTACT_LIST_SHOW_ADDRESSES, EVC_X_LIST_SHOW_ADDRESSES, "list_show_addresses", N_("List Shows Addresses"), FALSE),
283 STRUCT_FIELD (E_CONTACT_BIRTH_DATE, EVC_BDAY, "birth_date", N_("Birth Date"), FALSE, date_getter, date_setter, e_contact_date_get_type),
284 STRUCT_FIELD (E_CONTACT_ANNIVERSARY, EVC_X_ANNIVERSARY, "anniversary", N_("Anniversary"), FALSE, date_getter, date_setter, e_contact_date_get_type),
286 /* Security fields */
287 ATTR_TYPE_STRUCT_FIELD (E_CONTACT_X509_CERT, EVC_KEY, "x509Cert", N_("X.509 Certificate"), FALSE, "X509", cert_getter, cert_setter, e_contact_cert_get_type),
289 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_HOME_1, EVC_X_GADUGADU, "im_gadugadu_home_1", N_("Gadu-Gadu Home ID 1"), FALSE, "HOME", 0),
290 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_HOME_2, EVC_X_GADUGADU, "im_gadugadu_home_2", N_("Gadu-Gadu Home ID 2"), FALSE, "HOME", 1),
291 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_HOME_3, EVC_X_GADUGADU, "im_gadugadu_home_3", N_("Gadu-Gadu Home ID 3"), FALSE, "HOME", 2),
292 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_WORK_1, EVC_X_GADUGADU, "im_gadugadu_work_1", N_("Gadu-Gadu Work ID 1"), FALSE, "WORK", 0),
293 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_WORK_2, EVC_X_GADUGADU, "im_gadugadu_work_2", N_("Gadu-Gadu Work ID 2"), FALSE, "WORK", 1),
294 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GADUGADU_WORK_3, EVC_X_GADUGADU, "im_gadugadu_work_3", N_("Gadu-Gadu Work ID 3"), FALSE, "WORK", 2),
295 MULTI_LIST_FIELD (E_CONTACT_IM_GADUGADU, EVC_X_GADUGADU, "im_gadugadu", N_("Gadu-Gadu ID List"), FALSE),
297 /* Geo information */
298 STRUCT_FIELD (E_CONTACT_GEO, EVC_GEO, "geo", N_("Geographic Information"), FALSE, geo_getter, geo_setter, e_contact_geo_get_type),
300 MULTI_LIST_FIELD (E_CONTACT_TEL, EVC_TEL, "phone", N_("Telephone"), FALSE),
302 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_HOME_1, EVC_X_SKYPE, "im_skype_home_1", N_("Skype Home Name 1"), FALSE, "HOME", 0),
303 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_HOME_2, EVC_X_SKYPE, "im_skype_home_2", N_("Skype Home Name 2"), FALSE, "HOME", 1),
304 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_HOME_3, EVC_X_SKYPE, "im_skype_home_3", N_("Skype Home Name 3"), FALSE, "HOME", 2),
305 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_WORK_1, EVC_X_SKYPE, "im_skype_work_1", N_("Skype Work Name 1"), FALSE, "WORK", 0),
306 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_WORK_2, EVC_X_SKYPE, "im_skype_work_2", N_("Skype Work Name 2"), FALSE, "WORK", 1),
307 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_SKYPE_WORK_3, EVC_X_SKYPE, "im_skype_work_3", N_("Skype Work Name 3"), FALSE, "WORK", 2),
308 MULTI_LIST_FIELD (E_CONTACT_IM_SKYPE, EVC_X_SKYPE, "im_skype", N_("Skype Name List"), FALSE),
310 MULTI_LIST_FIELD (E_CONTACT_SIP, EVC_X_SIP, "sip", N_("SIP address"), FALSE),
312 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_HOME_1, EVC_X_GOOGLE_TALK, "im_google_talk_home_1", N_("Google Talk Home Name 1"), FALSE, "HOME", 0),
313 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_HOME_2, EVC_X_GOOGLE_TALK, "im_google_talk_home_2", N_("Google Talk Home Name 2"), FALSE, "HOME", 1),
314 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_HOME_3, EVC_X_GOOGLE_TALK, "im_google_talk_home_3", N_("Google Talk Home Name 3"), FALSE, "HOME", 2),
315 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_WORK_1, EVC_X_GOOGLE_TALK, "im_google_talk_work_1", N_("Google Talk Work Name 1"), FALSE, "WORK", 0),
316 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_WORK_2, EVC_X_GOOGLE_TALK, "im_google_talk_work_2", N_("Google Talk Work Name 2"), FALSE, "WORK", 1),
317 ATTR_TYPE_STR_FIELD (E_CONTACT_IM_GOOGLE_TALK_WORK_3, EVC_X_GOOGLE_TALK, "im_google_talk_work_3", N_("Google Talk Work Name 3"), FALSE, "WORK", 2),
318 MULTI_LIST_FIELD (E_CONTACT_IM_GOOGLE_TALK, EVC_X_GOOGLE_TALK, "im_google_talk", N_("Google Talk Name List"), FALSE),
320 MULTI_LIST_FIELD (E_CONTACT_IM_TWITTER, EVC_X_TWITTER, "im_twitter", N_("Twitter Name List"), FALSE)
323 #undef LIST_ELEM_STR_FIELD
325 #undef SYNTH_STR_FIELD
329 static void e_contact_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
330 static void e_contact_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
333 e_contact_finalize (GObject *object)
335 EContactPrivate *priv;
338 priv = E_CONTACT_GET_PRIVATE (object);
340 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++)
341 g_free (priv->cached_strings[i]);
343 /* Chain up to parent's finalize() method. */
344 G_OBJECT_CLASS (e_contact_parent_class)->finalize (object);
348 e_contact_class_init (EContactClass *class)
350 GObjectClass *object_class;
353 g_type_class_add_private (class, sizeof (EContactPrivate));
355 object_class = G_OBJECT_CLASS (class);
356 object_class->set_property = e_contact_set_property;
357 object_class->get_property = e_contact_get_property;
358 object_class->finalize = e_contact_finalize;
360 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
361 GParamSpec *pspec = NULL;
363 /* Verify the table is correctly ordered */
364 g_assert (i == field_info[i].field_id);
366 if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRING)
367 pspec = g_param_spec_string (field_info[i].field_name,
368 _(field_info[i].pretty_name),
369 field_info[i].pretty_name,
371 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
372 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
373 else if (field_info[i].t & E_CONTACT_FIELD_TYPE_BOOLEAN)
374 pspec = g_param_spec_boolean (field_info[i].field_name,
375 _(field_info[i].pretty_name),
376 field_info[i].pretty_name,
378 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
379 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
380 else if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRUCT)
381 pspec = g_param_spec_boxed (field_info[i].field_name,
382 _(field_info[i].pretty_name),
383 field_info[i].pretty_name,
384 field_info[i].boxed_type_getter (),
385 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
386 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
388 pspec = g_param_spec_pointer (field_info[i].field_name,
389 _(field_info[i].pretty_name),
390 field_info[i].pretty_name,
391 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
392 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
394 g_object_class_install_property (object_class, field_info[i].field_id,
400 e_contact_init (EContact *ec)
402 ec->priv = E_CONTACT_GET_PRIVATE (ec);
406 geo_getter (EContact *contact,
407 EVCardAttribute *attr)
410 GList *p = e_vcard_attribute_get_values (attr);
411 EContactGeo *geo = g_new0 (EContactGeo, 1);
413 geo->latitude = (p && p->data ? g_ascii_strtod (p->data, NULL) : 0); if (p) p = p->next;
414 geo->longitude = (p && p->data ? g_ascii_strtod (p->data, NULL) : 0);
423 geo_setter (EContact *contact,
424 EVCardAttribute *attr,
427 EContactGeo *geo = data;
428 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
430 e_vcard_attribute_add_value
431 (attr, g_ascii_dtostr (buf, sizeof (buf), geo->latitude));
433 e_vcard_attribute_add_value
434 (attr, g_ascii_dtostr (buf, sizeof (buf), geo->longitude));
438 photo_getter (EContact *contact,
439 EVCardAttribute *attr)
446 values = e_vcard_attribute_get_param (attr, EVC_ENCODING);
447 if (values && (g_ascii_strcasecmp (values->data, "b") == 0 ||
448 /* second for photo vCard 2.1 support */
449 g_ascii_strcasecmp (values->data, "base64") == 0)) {
450 values = e_vcard_attribute_get_values_decoded (attr);
451 if (values && values->data) {
452 GString *s = values->data;
453 EContactPhoto *photo;
458 photo = g_new0 (EContactPhoto, 1);
459 photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
460 photo->data.inlined.length = s->len;
461 photo->data.inlined.data = g_malloc (photo->data.inlined.length);
462 memcpy (photo->data.inlined.data, s->str, photo->data.inlined.length);
464 values = e_vcard_attribute_get_param (attr, EVC_TYPE);
465 if (values && values->data)
466 photo->data.inlined.mime_type = g_strdup_printf("image/%s", (gchar *)values->data);
471 values = e_vcard_attribute_get_param (attr, EVC_VALUE);
472 if (values && g_ascii_strcasecmp (values->data, "uri") == 0) {
473 EContactPhoto *photo;
474 photo = g_new0 (EContactPhoto, 1);
475 photo->type = E_CONTACT_PHOTO_TYPE_URI;
476 photo->data.uri = e_vcard_attribute_get_value (attr);
483 photo_setter (EContact *contact,
484 EVCardAttribute *attr,
487 EContactPhoto *photo = data;
488 const gchar *image_type, *p;
490 switch (photo->type) {
491 case E_CONTACT_PHOTO_TYPE_INLINED:
492 g_return_if_fail (photo->data.inlined.length > 0);
494 e_vcard_attribute_add_param_with_value (attr,
495 e_vcard_attribute_param_new (EVC_ENCODING),
497 if (photo->data.inlined.mime_type && (p = strchr (photo->data.inlined.mime_type, '/'))) {
500 image_type = "X-EVOLUTION-UNKNOWN";
502 e_vcard_attribute_add_param_with_value (attr,
503 e_vcard_attribute_param_new (EVC_TYPE),
506 e_vcard_attribute_add_value_decoded (attr, (gchar *) photo->data.inlined.data, photo->data.inlined.length);
508 case E_CONTACT_PHOTO_TYPE_URI:
509 e_vcard_attribute_add_param_with_value (attr,
510 e_vcard_attribute_param_new (EVC_VALUE),
512 e_vcard_attribute_add_value (attr, photo->data.uri);
515 g_warning ("Unknown EContactPhotoType %d", photo->type);
522 fn_getter (EContact *contact,
523 EVCardAttribute *attr)
525 /* this fills FN, if not there yet */
529 name = e_contact_get (contact, E_CONTACT_NAME);
531 e_contact_name_free (name);
533 attr = e_vcard_get_attribute (E_VCARD (contact), EVC_FN);
537 GList *p = e_vcard_attribute_get_values (attr);
539 return p && p->data ? p->data : (gpointer) "";
545 fn_setter (EContact *contact,
546 EVCardAttribute *attr,
549 gchar *name_str = data;
551 e_vcard_attribute_add_value (attr, name_str);
553 attr = e_vcard_get_attribute (E_VCARD (contact), EVC_N);
555 EContactName *name = e_contact_name_from_string ((gchar *) data);
557 attr = e_vcard_attribute_new (NULL, EVC_N);
558 e_vcard_append_attribute (E_VCARD (contact), attr);
560 /* call the setter directly */
561 n_setter (contact, attr, name);
563 e_contact_name_free (name);
568 fileas_getter (EContact *contact,
569 EVCardAttribute *attr)
574 p = e_vcard_attribute_get_values (attr);
575 if (!p || !p->data || !*((const gchar *) p->data))
580 /* Generate a FILE_AS field */
582 gchar *new_file_as = NULL;
584 name = e_contact_get (contact, E_CONTACT_NAME);
586 /* Use name if available */
588 gchar *strings[3], **stringptr;
591 if (name->family && *name->family)
592 *(stringptr++) = name->family;
593 if (name->given && *name->given)
594 *(stringptr++) = name->given;
595 if (stringptr != strings) {
597 new_file_as = g_strjoinv (", ", strings);
600 e_contact_name_free (name);
603 /* Use org as fallback */
605 const gchar *org = e_contact_get_const (contact, E_CONTACT_ORG);
608 new_file_as = g_strdup (org);
612 /* Add the FILE_AS attribute to the vcard */
614 attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS);
615 e_vcard_add_attribute_with_value (E_VCARD (contact), attr, new_file_as);
617 g_free (new_file_as);
622 p = e_vcard_attribute_get_values (attr);
624 return p && p->data ? p->data : (gpointer) "";
631 fileas_setter (EContact *contact,
632 EVCardAttribute *attr,
635 /* Default implementation */
636 const gchar *file_as = data;
637 e_vcard_attribute_add_value (attr, file_as ? : "");
643 n_getter (EContact *contact,
644 EVCardAttribute *attr)
646 EContactName *name = g_new0 (EContactName, 1);
647 EVCardAttribute *new_attr;
651 GList *p = e_vcard_attribute_get_values (attr);
653 name->family = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
654 name->given = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
655 name->additional = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
656 name->prefixes = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
657 name->suffixes = g_strdup (p && p->data ? p->data : "");
660 new_attr = e_vcard_get_attribute (E_VCARD (contact), EVC_FN);
662 new_attr = e_vcard_attribute_new (NULL, EVC_FN);
663 e_vcard_append_attribute (E_VCARD (contact), new_attr);
664 name_str = e_contact_name_to_string (name);
665 e_vcard_attribute_add_value (new_attr, name_str);
673 n_setter (EContact *contact,
674 EVCardAttribute *attr,
677 EContactName *name = data;
679 e_vcard_attribute_add_value (attr, name->family ? name->family : "");
680 e_vcard_attribute_add_value (attr, name->given ? name->given : "");
681 e_vcard_attribute_add_value (attr, name->additional ? name->additional : "");
682 e_vcard_attribute_add_value (attr, name->prefixes ? name->prefixes : "");
683 e_vcard_attribute_add_value (attr, name->suffixes ? name->suffixes : "");
685 /* now find the attribute for FileAs. if it's not present, fill it in */
686 attr = e_vcard_get_attribute (E_VCARD (contact), EVC_X_FILE_AS);
688 gchar *strings[3], **stringptr;
690 attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS);
691 e_vcard_append_attribute (E_VCARD (contact), attr);
694 if (name->family && *name->family)
695 *(stringptr++) = name->family;
696 if (name->given && *name->given)
697 *(stringptr++) = name->given;
699 string = g_strjoinv(", ", strings);
701 e_vcard_attribute_add_value (attr, string);
710 adr_getter (EContact *contact,
711 EVCardAttribute *attr)
714 GList *p = e_vcard_attribute_get_values (attr);
715 EContactAddress *addr = g_new0 (EContactAddress, 1);
717 addr->address_format = g_strdup ("");
718 addr->po = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
719 addr->ext = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
720 addr->street = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
721 addr->locality = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
722 addr->region = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
723 addr->code = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
724 addr->country = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
733 adr_setter (EContact *contact,
734 EVCardAttribute *attr,
737 EContactAddress *addr = data;
739 e_vcard_attribute_add_value (attr, addr->po);
740 e_vcard_attribute_add_value (attr, addr->ext);
741 e_vcard_attribute_add_value (attr, addr->street);
742 e_vcard_attribute_add_value (attr, addr->locality);
743 e_vcard_attribute_add_value (attr, addr->region);
744 e_vcard_attribute_add_value (attr, addr->code);
745 e_vcard_attribute_add_value (attr, addr->country);
751 date_getter (EContact *contact,
752 EVCardAttribute *attr)
755 GList *p = e_vcard_attribute_get_values (attr);
758 if (p && p->data && ((gchar *) p->data)[0])
759 date = e_contact_date_from_string ((gchar *) p->data);
770 date_setter (EContact *contact,
771 EVCardAttribute *attr,
774 EContactDate *date = data;
777 str = e_contact_date_to_string (date);
779 e_vcard_attribute_add_value (attr, str);
786 cert_getter (EContact *contact,
787 EVCardAttribute *attr)
790 /* the certificate is stored in this vcard. just
792 GList *values = e_vcard_attribute_get_values_decoded (attr);
794 if (values && values->data) {
795 GString *s = values->data;
796 EContactCert *cert = g_new0 (EContactCert, 1);
798 cert->length = s->len;
799 cert->data = g_malloc (cert->length);
800 memcpy (cert->data, s->str, cert->length);
806 /* XXX if we stored a fingerprint in the cert we could look it
807 * up via NSS, but that would require the additional NSS dep
808 * here, and we'd have more than one process opening the
809 * certdb, which is bad. *sigh * */
815 cert_setter (EContact *contact,
816 EVCardAttribute *attr,
819 EContactCert *cert = data;
821 e_vcard_attribute_add_param_with_value (attr,
822 e_vcard_attribute_param_new (EVC_ENCODING),
825 e_vcard_attribute_add_value_decoded (attr, cert->data, cert->length);
830 /* Set_arg handler for the contact */
832 e_contact_set_property (GObject *object,
837 EContact *contact = E_CONTACT (object);
838 const EContactFieldInfo *info = NULL;
840 if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) {
841 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
845 info = &field_info[prop_id];
847 if (info->t & E_CONTACT_FIELD_TYPE_MULTI) {
848 GList *new_values = g_value_get_pointer (value);
851 /* first we remove all attributes of the type we're
852 * adding, then add new ones based on the values that
854 e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name);
856 for (l = new_values; l; l = l->next)
857 e_vcard_append_attribute_with_value (E_VCARD (contact),
858 e_vcard_attribute_new (NULL, info->vcard_field_name),
861 else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) {
862 if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) {
863 /* XXX this is kinda broken - we don't insert
864 * insert padding elements if, e.g. the user
865 * sets email 3 when email 1 and 2 don't
866 * exist. But, if we *did* pad the lists we'd
867 * end up with empty items in the vcard. I
868 * dunno which is worse. */
869 EVCardAttribute *attr = NULL;
870 gboolean found = FALSE;
871 gint num_left = info->list_elem;
872 GList *attrs = e_vcard_get_attributes (E_VCARD (contact));
876 for (l = attrs; l; l = l->next) {
880 name = e_vcard_attribute_get_name (attr);
882 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
883 if (num_left-- == 0) {
890 sval = g_value_get_string (value);
893 /* we found it, overwrite it */
894 e_vcard_attribute_remove_values (attr);
897 /* we didn't find it - add a new attribute */
898 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
899 if (!g_ascii_strcasecmp (info->vcard_field_name, "EMAIL") &&
902 /* Add default type */
903 e_vcard_attribute_add_param_with_value ( attr,
904 e_vcard_attribute_param_new (EVC_TYPE),
907 e_vcard_append_attribute (E_VCARD (contact), attr);
910 e_vcard_attribute_add_value (attr, sval);
914 e_vcard_remove_attribute (E_VCARD (contact), attr);
917 else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
918 /* XXX this is kinda broken - we don't insert
919 * insert padding elements if, e.g. the user
920 * sets email 3 when email 1 and 2 don't
921 * exist. But, if we *did* pad the lists we'd
922 * end up with empty items in the vcard. I
923 * dunno which is worse. */
924 EVCardAttribute *attr = NULL;
925 gboolean found = FALSE;
926 gint num_left = info->list_elem;
927 GList *attrs = e_vcard_get_attributes (E_VCARD (contact));
930 for (l = attrs; l && !found; l = l->next) {
932 gboolean found_needed1, found_needed2;
934 found_needed1 = (info->attr_type1 == NULL);
935 found_needed2 = (info->attr_type2 == NULL);
938 name = e_vcard_attribute_get_name (attr);
940 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
943 for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
944 EVCardAttributeParam *param = params->data;
945 const gchar *param_name = e_vcard_attribute_param_get_name (param);
947 if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
948 gboolean matches = FALSE;
949 GList *values = e_vcard_attribute_param_get_values (param);
951 while (values && values->data) {
952 if (!found_needed1 && !g_ascii_strcasecmp ((gchar *) values->data, info->attr_type1)) {
953 found_needed1 = TRUE;
956 else if (!found_needed2 && !g_ascii_strcasecmp ((gchar *) values->data, info->attr_type2)) {
957 found_needed2 = TRUE;
959 } else if (found_needed1) {
960 if (!matches || !found_needed2)
965 values = values->next;
969 /* this is to enforce that we find an attribute
970 * with *only* the TYPE='s we need. This may seem like
971 * an odd restriction but it's the only way at present to
972 * implement the Other Fax and Other Phone attributes. */
973 found_needed1 = FALSE;
978 if (found_needed1 && found_needed2) {
979 if (num_left-- == 0) {
989 /* we found it, overwrite it */
990 e_vcard_attribute_remove_values (attr);
993 /* we didn't find it - add a new attribute */
994 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
995 e_vcard_append_attribute (E_VCARD (contact), attr);
996 if (info->attr_type1)
997 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE),
999 if (info->attr_type2)
1000 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE),
1004 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT || info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1005 gpointer data = info->t & E_CONTACT_FIELD_TYPE_STRUCT ? g_value_get_boxed (value) : (gchar *) g_value_get_string (value);
1007 if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
1008 || (data && *(gchar *) data))
1009 info->struct_setter (contact, attr, data);
1011 e_vcard_remove_attribute (E_VCARD (contact), attr);
1014 const gchar *sval = g_value_get_string (value);
1017 e_vcard_attribute_add_value (attr, sval);
1019 e_vcard_remove_attribute (E_VCARD (contact), attr);
1022 else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
1023 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1026 const gchar *sval = g_value_get_string (value);
1029 if (!sval || !*sval)
1032 d(printf ("adding new %s\n", info->vcard_field_name));
1034 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
1035 e_vcard_append_attribute (E_VCARD (contact), attr);
1038 values = e_vcard_attribute_get_values (attr);
1039 p = g_list_nth (values, info->list_elem);
1043 p->data = g_strdup (g_value_get_string (value));
1046 /* there weren't enough elements in the list, pad it */
1047 gint count = info->list_elem - g_list_length (values);
1050 e_vcard_attribute_add_value (attr, "");
1052 e_vcard_attribute_add_value (attr, g_value_get_string (value));
1056 switch (info->field_id) {
1057 case E_CONTACT_CATEGORIES: {
1058 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), EVC_CATEGORIES);
1063 e_vcard_attribute_remove_values (attr);
1065 /* we didn't find it - add a new attribute */
1066 attr = e_vcard_attribute_new (NULL, EVC_CATEGORIES);
1067 e_vcard_append_attribute (E_VCARD (contact), attr);
1070 str = g_value_get_string (value);
1072 split = g_strsplit (str, ",", 0);
1074 for (s = split; *s; s++) {
1075 e_vcard_attribute_add_value (attr, g_strstrip (*s));
1079 e_vcard_attribute_add_value (attr, str);
1082 d(printf ("removing %s\n", info->vcard_field_name));
1084 e_vcard_remove_attribute (E_VCARD (contact), attr);
1089 g_warning ("unhandled synthetic field 0x%02x", info->field_id);
1094 else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT || info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1095 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1096 gpointer data = info->t & E_CONTACT_FIELD_TYPE_STRUCT ? g_value_get_boxed (value) : (gchar *) g_value_get_string (value);
1099 if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
1100 || (data && *(gchar *) data)) {
1101 d(printf ("overwriting existing %s\n", info->vcard_field_name));
1102 /* remove all existing values and parameters.
1103 * the setter will add the correct ones */
1104 e_vcard_attribute_remove_values (attr);
1105 e_vcard_attribute_remove_params (attr);
1107 info->struct_setter (contact, attr, data);
1110 d(printf ("removing %s\n", info->vcard_field_name));
1112 e_vcard_remove_attribute (E_VCARD (contact), attr);
1115 else if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
1116 || (data && *(gchar *) data)) {
1117 d(printf ("adding new %s\n", info->vcard_field_name));
1118 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
1120 e_vcard_append_attribute (E_VCARD (contact), attr);
1122 info->struct_setter (contact, attr, data);
1125 else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1126 EVCardAttribute *attr;
1128 /* first we search for an attribute we can overwrite */
1129 attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1131 d(printf ("setting %s to `%s'\n", info->vcard_field_name, g_value_get_string (value)));
1132 e_vcard_attribute_remove_values (attr);
1133 e_vcard_attribute_add_value (attr, g_value_get_boolean (value) ? "TRUE" : "FALSE");
1136 /* and if we don't find one we create a new attribute */
1137 e_vcard_append_attribute_with_value (E_VCARD (contact),
1138 e_vcard_attribute_new (NULL, info->vcard_field_name),
1139 g_value_get_boolean (value) ? "TRUE" : "FALSE");
1142 else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1143 EVCardAttribute *attr;
1144 const gchar *sval = g_value_get_string (value);
1146 /* first we search for an attribute we can overwrite */
1147 if (sval == NULL || g_ascii_strcasecmp (info->vcard_field_name, EVC_UID) != 0) {
1148 attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1150 /* Avoid useless vcard parsing when trying to set a new non-empty UID.
1151 * Parsing the vcard is pointless in this particular case because even
1152 * if there is a UID in the unparsed vcard, it is going to be ignored
1153 * upon parsing if we already have a UID for the vcard */
1154 attr = e_vcard_get_attribute_if_parsed (E_VCARD (contact), EVC_UID);
1158 d(printf ("setting %s to `%s'\n", info->vcard_field_name, sval));
1159 e_vcard_attribute_remove_values (attr);
1161 e_vcard_attribute_add_value (attr, sval);
1164 d(printf ("removing %s\n", info->vcard_field_name));
1166 e_vcard_remove_attribute (E_VCARD (contact), attr);
1171 /* and if we don't find one we create a new attribute */
1172 e_vcard_append_attribute_with_value (E_VCARD (contact),
1173 e_vcard_attribute_new (NULL, info->vcard_field_name),
1177 else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1178 EVCardAttribute *attr;
1181 values = g_value_get_pointer (value);
1183 attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1186 e_vcard_attribute_remove_values (attr);
1189 e_vcard_remove_attribute (E_VCARD (contact), attr);
1192 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
1193 e_vcard_append_attribute (E_VCARD (contact), attr);
1196 for (l = values; l != NULL; l = l->next)
1197 e_vcard_attribute_add_value (attr, l->data);
1200 g_warning ("unhandled attribute `%s'", info->vcard_field_name);
1204 static EVCardAttribute *
1205 e_contact_find_attribute_with_types (EContact *contact,
1206 const gchar *attr_name,
1207 const gchar *type_needed1,
1208 const gchar *type_needed2,
1212 gboolean found_needed1, found_needed2;
1214 attrs = e_vcard_get_attributes (E_VCARD (contact));
1216 for (l = attrs; l; l = l->next) {
1217 EVCardAttribute *attr = l->data;
1220 found_needed1 = (type_needed1 == NULL);
1221 found_needed2 = (type_needed2 == NULL);
1223 name = e_vcard_attribute_get_name (attr);
1225 if (!g_ascii_strcasecmp (name, attr_name)) {
1228 for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
1229 EVCardAttributeParam *param = params->data;
1230 const gchar *param_name = e_vcard_attribute_param_get_name (param);
1232 if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
1233 gboolean matches = FALSE;
1234 GList *values = e_vcard_attribute_param_get_values (param);
1236 while (values && values->data) {
1237 if (!found_needed1 && !g_ascii_strcasecmp ((gchar *) values->data, type_needed1)) {
1238 found_needed1 = TRUE;
1241 else if (!found_needed2 && !g_ascii_strcasecmp ((gchar *) values->data, type_needed2)) {
1242 found_needed2 = TRUE;
1244 } else if (found_needed1) {
1245 if (!matches || !found_needed2)
1249 values = values->next;
1253 /* this is to enforce that we find an attribute
1254 * with *only* the TYPE='s we need. This may seem like
1255 * an odd restriction but it's the only way at present to
1256 * implement the Other Fax and Other Phone attributes. */
1257 found_needed1 = FALSE;
1262 if (found_needed1 && found_needed2) {
1276 e_contact_get_property (GObject *object,
1281 const EContactFieldInfo *info = NULL;
1284 if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) {
1285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1286 g_value_reset (value);
1290 info = &field_info[prop_id];
1291 data = e_contact_get (E_CONTACT (object), prop_id);
1293 if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1294 g_value_set_boolean (value, data != NULL);
1295 } else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1296 g_value_set_pointer (value, data);
1297 } else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1298 g_value_take_boxed (value, data);
1299 } else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1300 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1301 g_value_set_boxed (value, data);
1303 g_value_set_string (value, data);
1305 } else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1306 g_value_set_string (value, data);
1308 g_value_set_pointer (value, data);
1317 * Creates a new, blank #EContact.
1319 * Returns: A new #EContact.
1322 e_contact_new (void)
1324 return e_contact_new_from_vcard ("");
1328 * e_contact_new_from_vcard:
1329 * @vcard: a string representing a vcard
1331 * Creates a new #EContact based on a vcard.
1333 * Returns: A new #EContact.
1336 e_contact_new_from_vcard (const gchar *vcard)
1339 g_return_val_if_fail (vcard != NULL, NULL);
1341 contact = g_object_new (E_TYPE_CONTACT, NULL);
1342 e_vcard_construct (E_VCARD (contact), vcard);
1348 * e_contact_new_from_vcard_with_uid:
1349 * @vcard: a string representing a vcard
1350 * @uid: a contact UID
1352 * Creates a new #EContact based on a vcard and a predefined UID.
1354 * Returns: A new #EContact.
1359 e_contact_new_from_vcard_with_uid (const gchar *vcard,
1363 g_return_val_if_fail (vcard != NULL, NULL);
1365 contact = g_object_new (E_TYPE_CONTACT, NULL);
1366 e_vcard_construct_with_uid (E_VCARD (contact), vcard, uid);
1372 * e_contact_duplicate:
1373 * @contact: an #EContact
1375 * Creates a copy of @contact.
1377 * Returns: (transfer full): A new #EContact identical to @contact.
1380 e_contact_duplicate (EContact *contact)
1385 g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
1387 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1388 c = e_contact_new_from_vcard (vcard);
1395 * e_contact_field_name:
1396 * @field_id: an #EContactField
1398 * Gets the string representation of @field_id.
1400 * Returns: The string representation of @field_id, or %NULL if it doesn't exist.
1403 e_contact_field_name (EContactField field_id)
1405 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, "");
1407 return field_info[field_id].field_name;
1411 * e_contact_pretty_name:
1412 * @field_id: an #EContactField
1414 * Gets a human-readable, translated string representation
1417 * Returns: The human-readable representation of @field_id, or %NULL if it doesn't exist.
1420 e_contact_pretty_name (EContactField field_id)
1422 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, "");
1425 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1426 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1429 return _(field_info[field_id].pretty_name);
1433 * e_contact_vcard_attribute:
1434 * @field_id: an #EContactField
1436 * Gets the vcard attribute corresponding to @field_id, as a string.
1438 * Returns: The vcard attribute corresponding to @field_id, or %NULL if it doesn't exist.
1441 e_contact_vcard_attribute (EContactField field_id)
1443 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, "");
1445 return field_info[field_id].vcard_field_name;
1449 * e_contact_field_id:
1450 * @field_name: a string representing a contact field
1452 * Gets the #EContactField corresponding to the @field_name.
1454 * Returns: An #EContactField corresponding to @field_name, or %0 if it doesn't exist.
1457 e_contact_field_id (const gchar *field_name)
1460 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
1461 if (!g_ascii_strcasecmp (field_info[i].field_name, field_name))
1462 return field_info[i].field_id;
1469 * e_contact_field_id_from_vcard:
1470 * @vcard_field: a string representing a vCard field
1472 * Gets the #EContactField corresponding to the @vcard_field.
1474 * Returns: An #EContactField corresponding to @vcard_field, or %0 if it doesn't exist.
1479 e_contact_field_id_from_vcard (const gchar *vcard_field)
1483 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
1484 if (field_info[i].vcard_field_name == NULL)
1486 if (field_info[i].t & E_CONTACT_FIELD_TYPE_SYNTHETIC)
1488 if (!strcmp (field_info[i].vcard_field_name, vcard_field))
1489 return field_info[i].field_id;
1492 g_warning ("unknown vCard field `%s'", vcard_field);
1498 * @contact: an #EContact
1499 * @field_id: an #EContactField
1501 * Gets the value of @contact's field specified by @field_id.
1503 * Returns: (transfer full) (allow-none): Depends on the field's type, owned by the caller. This may be %NULL if the field isn't set.
1506 e_contact_get (EContact *contact,
1507 EContactField field_id)
1509 const EContactFieldInfo *info = NULL;
1511 g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL);
1512 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, NULL);
1514 info = &field_info[field_id];
1516 if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1517 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1518 gboolean rv = FALSE;
1521 GList *v = e_vcard_attribute_get_values (attr);
1522 rv = v && v->data && !g_ascii_strcasecmp ((gchar *)v->data, "true");
1523 return rv ? (gpointer) "1" : NULL;
1526 else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1527 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1530 GList *list = g_list_copy (e_vcard_attribute_get_values (attr));
1532 for (l = list; l; l = l->next)
1533 l->data = l->data ? g_strstrip (g_strdup (l->data)) : NULL;
1537 else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
1538 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1539 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1544 v = e_vcard_attribute_get_values (attr);
1545 v = g_list_nth (v, info->list_elem);
1547 return (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL;
1551 else if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) {
1552 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1554 gint num_left = info->list_elem;
1556 attrs = e_vcard_get_attributes (E_VCARD (contact));
1558 for (l = attrs; l; l = l->next) {
1559 EVCardAttribute *attr = l->data;
1562 name = e_vcard_attribute_get_name (attr);
1564 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
1565 if (num_left-- == 0) {
1566 GList *v = e_vcard_attribute_get_values (attr);
1568 return (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL;
1574 else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
1575 EVCardAttribute *attr = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem);
1577 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1579 GList *p = e_vcard_attribute_get_values (attr);
1580 return (p && p->data) ? g_strstrip (g_strdup (p->data)) : NULL;
1587 return info->struct_getter (contact, attr);
1591 else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1592 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1594 return info->struct_getter (contact, attr);
1596 else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1597 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1600 rv = info->struct_getter (contact, attr);
1602 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT)
1603 return (gpointer) info->boxed_type_getter ();
1607 return g_strstrip (g_strdup (rv));
1609 else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) {
1610 switch (info->field_id) {
1611 case E_CONTACT_NAME_OR_ORG: {
1614 str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
1616 str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
1618 str = e_contact_get_const (contact, E_CONTACT_ORG);
1620 gboolean is_list = GPOINTER_TO_INT (e_contact_get (contact, E_CONTACT_IS_LIST));
1623 str = _("Unnamed List");
1625 str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
1628 return str ? g_strstrip (g_strdup (str)) : NULL;
1630 case E_CONTACT_CATEGORIES: {
1631 EVCardAttribute *attr = e_vcard_get_attribute (E_VCARD (contact), EVC_CATEGORIES);
1635 GString *str = g_string_new ("");
1636 GList *v = e_vcard_attribute_get_values (attr);
1638 g_string_append (str, (gchar *) v->data);
1641 g_string_append_c (str, ',');
1644 rv = g_string_free (str, FALSE);
1649 g_warning ("unhandled synthetic field 0x%02x", info->field_id);
1653 else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1654 EVCardAttribute *attr;
1655 const gchar *cv = NULL;
1658 /* Do our best to avoid vcard parsing by not calling
1659 * e_vcard_get_attributes */
1661 cv = contact->priv->cached_strings[field_id];
1663 return g_strdup (cv);
1665 attr = e_vcard_get_attribute (E_VCARD (contact), info->vcard_field_name);
1668 v = e_vcard_attribute_get_values (attr);
1670 return ((v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL);
1674 GList *rv = NULL; /* used for multi attribute lists */
1676 attrs = e_vcard_get_attributes (E_VCARD (contact));
1678 for (l = attrs; l; l = l->next) {
1679 EVCardAttribute *attr = l->data;
1682 name = e_vcard_attribute_get_name (attr);
1684 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
1686 v = e_vcard_attribute_get_values (attr);
1688 rv = g_list_append (rv, (v && v->data) ? g_strstrip (g_strdup (v->data)) : NULL);
1697 * e_contact_get_const:
1698 * @contact: an #EContact
1699 * @field_id: an #EContactField
1701 * Gets the value of @contact's field specified by @field_id, caching
1702 * the result so it can be freed later.
1704 * Returns: (transfer none): Depends on the field's type, owned by the
1708 e_contact_get_const (EContact *contact,
1709 EContactField field_id)
1711 gpointer value = NULL;
1713 g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
1714 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, NULL);
1715 g_return_val_if_fail (field_info[field_id].t & E_CONTACT_FIELD_TYPE_STRING, NULL);
1717 value = contact->priv->cached_strings[field_id];
1720 value = e_contact_get (contact, field_id);
1722 contact->priv->cached_strings[field_id] = value;
1730 * @contact: an #EContact
1731 * @field_id: an #EContactField
1732 * @value: a value whose type depends on the @field_id
1734 * Sets the value of @contact's field specified by @field_id to @value.
1737 e_contact_set (EContact *contact,
1738 EContactField field_id,
1739 gconstpointer value)
1741 d(printf ("e_contact_set (%p, %d, %p)\n", contact, field_id, value));
1743 g_return_if_fail (contact && E_IS_CONTACT (contact));
1744 g_return_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST);
1746 /* set the cached slot to NULL so we'll re-get the new string
1747 * if e_contact_get_const is called again */
1748 g_free (contact->priv->cached_strings[field_id]);
1749 contact->priv->cached_strings[field_id] = NULL;
1751 g_object_set (contact,
1752 e_contact_field_name (field_id), value,
1757 * e_contact_get_attributes:
1758 * @contact: an #EContact
1759 * @field_id: an #EContactField
1761 * Gets a list of the vcard attributes for @contact's @field_id.
1763 * Returns: (transfer full) (element-type EVCardAttribute): A #GList of pointers
1764 * to #EVCardAttribute, owned by the caller.
1767 e_contact_get_attributes (EContact *contact,
1768 EContactField field_id)
1772 const EContactFieldInfo *info = NULL;
1774 g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL);
1775 g_return_val_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST, NULL);
1777 info = &field_info[field_id];
1779 attrs = e_vcard_get_attributes (E_VCARD (contact));
1781 for (a = attrs; a; a = a->next) {
1782 EVCardAttribute *attr = a->data;
1785 name = e_vcard_attribute_get_name (attr);
1787 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
1788 l = g_list_prepend (l, e_vcard_attribute_copy (attr));
1792 return g_list_reverse (l);
1796 * e_contact_set_attributes:
1797 * @contact: an #EContact
1798 * @field_id: an #EContactField
1799 * @attributes: (element-type EVCardAttribute): a #GList of pointers to #EVCardAttribute
1801 * Sets the vcard attributes for @contact's @field_id.
1802 * Attributes are added to the contact in the same order as they are in @attributes.
1805 e_contact_set_attributes (EContact *contact,
1806 EContactField field_id,
1809 const EContactFieldInfo *info = NULL;
1812 g_return_if_fail (contact && E_IS_CONTACT (contact));
1813 g_return_if_fail (field_id >= 1 && field_id < E_CONTACT_FIELD_LAST);
1815 info = &field_info[field_id];
1817 e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name);
1819 for (l = attributes; l; l = l->next)
1820 e_vcard_append_attribute (E_VCARD (contact),
1821 e_vcard_attribute_copy ((EVCardAttribute *) l->data));
1825 * e_contact_name_new:
1827 * Creates a new #EContactName struct.
1829 * Returns: A new #EContactName struct.
1832 e_contact_name_new (void)
1834 return g_new0 (EContactName, 1);
1838 * e_contact_name_to_string:
1839 * @name: an #EContactName
1841 * Generates a string representation of @name.
1843 * Returns: The string representation of @name.
1846 e_contact_name_to_string (const EContactName *name)
1848 gchar *strings[6], **stringptr = strings;
1850 g_return_val_if_fail (name != NULL, NULL);
1852 if (name->prefixes && *name->prefixes)
1853 *(stringptr++) = name->prefixes;
1854 if (name->given && *name->given)
1855 *(stringptr++) = name->given;
1856 if (name->additional && *name->additional)
1857 *(stringptr++) = name->additional;
1858 if (name->family && *name->family)
1859 *(stringptr++) = name->family;
1860 if (name->suffixes && *name->suffixes)
1861 *(stringptr++) = name->suffixes;
1863 return g_strjoinv(" ", strings);
1867 * e_contact_name_from_string:
1868 * @name_str: a string representing a contact's full name
1870 * Creates a new #EContactName based on the parsed @name_str.
1872 * Returns: A new #EContactName struct.
1875 e_contact_name_from_string (const gchar *name_str)
1878 ENameWestern *western;
1880 g_return_val_if_fail (name_str != NULL, NULL);
1882 name = e_contact_name_new ();
1883 western = e_name_western_parse (name_str);
1885 name->prefixes = g_strdup (western->prefix);
1886 name->given = g_strdup (western->first );
1887 name->additional = g_strdup (western->middle);
1888 name->family = g_strdup (western->last );
1889 name->suffixes = g_strdup (western->suffix);
1891 e_name_western_free (western);
1897 * e_contact_name_copy:
1898 * @n: an #EContactName
1900 * Creates a copy of @n.
1902 * Returns: A new #EContactName identical to @n.
1905 e_contact_name_copy (EContactName *n)
1909 g_return_val_if_fail (n != NULL, NULL);
1911 name = e_contact_name_new ();
1913 name->prefixes = g_strdup (n->prefixes);
1914 name->given = g_strdup (n->given);
1915 name->additional = g_strdup (n->additional);
1916 name->family = g_strdup (n->family);
1917 name->suffixes = g_strdup (n->suffixes);
1923 * e_contact_name_free:
1924 * @name: an #EContactName
1926 * Frees @name and its contents.
1929 e_contact_name_free (EContactName *name)
1934 g_free (name->family);
1935 g_free (name->given);
1936 g_free (name->additional);
1937 g_free (name->prefixes);
1938 g_free (name->suffixes);
1943 #define E_CONTACT_DEFINE_BOXED_TYPE(_tp,_nm) \
1945 _tp ## _get_type (void) \
1947 static volatile gsize type_id__volatile = 0; \
1949 if (g_once_init_enter (&type_id__volatile)) { \
1952 type_id = g_boxed_type_register_static (_nm, \
1953 (GBoxedCopyFunc) _tp ## _copy, \
1954 (GBoxedFreeFunc) _tp ## _free); \
1956 g_once_init_leave (&type_id__volatile, type_id);\
1959 return type_id__volatile; \
1962 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_name, "EContactName")
1965 * e_contact_date_from_string:
1966 * @str: a date string in the format YYYY-MM-DD or YYYYMMDD
1968 * Creates a new #EContactDate based on @str.
1970 * Returns: A new #EContactDate struct.
1973 e_contact_date_from_string (const gchar *str)
1975 EContactDate * date;
1979 g_return_val_if_fail (str != NULL, NULL);
1981 date = e_contact_date_new ();
1982 /* ignore time part */
1983 if ((t = strchr (str, 'T')) != NULL)
1986 length = strlen (str);
1988 if (length == 10 ) {
1989 date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111;
1990 date->month = str[5] * 10 + str[6] - '0' * 11;
1991 date->day = str[8] * 10 + str[9] - '0' * 11;
1992 } else if (length == 8) {
1993 date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111;
1994 date->month = str[4] * 10 + str[5] - '0' * 11;
1995 date->day = str[6] * 10 + str[7] - '0' * 11;
2002 * e_contact_date_to_string:
2003 * @dt: an #EContactDate
2005 * Generates a date string in the format YYYY-MM-DD based
2006 * on the values of @dt.
2008 * Returns: A date string, owned by the caller.
2011 e_contact_date_to_string (EContactDate *dt)
2014 return g_strdup_printf ("%04d-%02d-%02d",
2015 CLAMP (dt->year, 1000, 9999),
2016 CLAMP (dt->month, 1, 12),
2017 CLAMP (dt->day, 1, 31));
2023 * e_contact_date_equal:
2024 * @dt1: an #EContactDate
2025 * @dt2: an #EContactDate
2027 * Checks if @dt1 and @dt2 are the same date.
2029 * Returns: %TRUE if @dt1 and @dt2 are equal, %FALSE otherwise.
2032 e_contact_date_equal (EContactDate *dt1,
2036 return (dt1->year == dt2->year &&
2037 dt1->month == dt2->month &&
2038 dt1->day == dt2->day);
2040 return (!!dt1 == !!dt2);
2044 * e_contact_date_copy:
2045 * @dt: an #EContactDate
2047 * Creates a copy of @dt.
2049 * Returns: A new #EContactDate struct identical to @dt.
2051 static EContactDate *
2052 e_contact_date_copy (EContactDate *dt)
2054 EContactDate *dt2 = e_contact_date_new ();
2055 dt2->year = dt->year;
2056 dt2->month = dt->month;
2063 * e_contact_date_free:
2064 * @date: an #EContactDate
2066 * Frees the @date struct and its contents.
2069 e_contact_date_free (EContactDate *date)
2074 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_date, "EContactDate")
2077 * e_contact_date_new:
2079 * Creates a new #EContactDate struct.
2081 * Returns: A new #EContactDate struct.
2084 e_contact_date_new (void)
2086 return g_new0 (EContactDate, 1);
2090 * e_contact_photo_new:
2092 * Creates a new #EContactPhoto struct.
2094 * Returns: (transfer full): A new #EContactPhoto struct.
2099 e_contact_photo_new (void)
2101 return g_new0 (EContactPhoto, 1);
2105 * e_contact_photo_free:
2106 * @photo: an #EContactPhoto struct
2108 * Frees the @photo struct and its contents.
2111 e_contact_photo_free (EContactPhoto *photo)
2116 switch (photo->type) {
2117 case E_CONTACT_PHOTO_TYPE_INLINED:
2118 g_free (photo->data.inlined.mime_type);
2119 g_free (photo->data.inlined.data);
2121 case E_CONTACT_PHOTO_TYPE_URI:
2122 g_free (photo->data.uri);
2125 g_warning ("Unknown EContactPhotoType %d", photo->type);
2133 * e_contact_photo_copy:
2134 * @photo: an #EContactPhoto
2136 * Creates a copy of @photo.
2138 * Returns: A new #EContactPhoto struct identical to @photo.
2140 static EContactPhoto *
2141 e_contact_photo_copy (EContactPhoto *photo)
2143 EContactPhoto *photo2 = g_new0 (EContactPhoto, 1);
2144 switch (photo->type) {
2145 case E_CONTACT_PHOTO_TYPE_INLINED:
2146 photo2->type = E_CONTACT_PHOTO_TYPE_INLINED;
2147 photo2->data.inlined.mime_type = g_strdup (photo->data.inlined.mime_type);
2148 photo2->data.inlined.length = photo->data.inlined.length;
2149 photo2->data.inlined.data = g_malloc (photo2->data.inlined.length);
2150 memcpy (photo2->data.inlined.data, photo->data.inlined.data, photo->data.inlined.length);
2152 case E_CONTACT_PHOTO_TYPE_URI:
2153 photo2->type = E_CONTACT_PHOTO_TYPE_URI;
2154 photo2->data.uri = g_strdup (photo->data.uri);
2157 g_warning ("Unknown EContactPhotoType %d", photo->type);
2164 * e_contact_photo_get_inlined:
2165 * @photo: an #EContactPhoto
2166 * @len: (out caller-allocates) (transfer none): the length of the inlined data
2168 * Gets the @photo's data.
2170 * Returns: (transfer none) (array length=len) (allow-none): the inlined image in the
2171 * #EContactPhoto, or %NULL if it has not been set.
2176 e_contact_photo_get_inlined (EContactPhoto *photo,
2179 g_return_val_if_fail (photo != NULL, NULL);
2180 g_return_val_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_INLINED, NULL);
2182 *len = photo->data.inlined.length;
2183 return photo->data.inlined.data;
2187 * e_contact_photo_set_inlined:
2188 * @photo: an #EContactPhoto
2189 * @data: (transfer none) (array length=len): the inlined image data
2190 * @len: the length of @data
2192 * Sets the @photo's inlined data.
2197 e_contact_photo_set_inlined (EContactPhoto *photo,
2201 g_return_if_fail (photo != NULL);
2202 g_return_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_INLINED);
2204 photo->data.inlined.data = g_malloc (len);
2205 memcpy (photo->data.inlined.data, data, len);
2206 photo->data.inlined.length = len;
2210 * e_contact_photo_get_mime_type:
2211 * @photo: an #EContactPhoto
2213 * Gets the @photo's mime type.
2215 * Returns: (transfer none) (allow-none): the MIME type of the image, or %NULL if it has not been set.
2220 e_contact_photo_get_mime_type (EContactPhoto *photo)
2222 g_return_val_if_fail (photo != NULL, NULL);
2223 g_return_val_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_INLINED, NULL);
2225 return photo->data.inlined.mime_type;
2229 * e_contact_photo_set_mime_type:
2230 * @photo: an #EContactPhoto
2231 * @mime_type: the mime type
2233 * Sets the @photo's mime type.
2238 e_contact_photo_set_mime_type (EContactPhoto *photo,
2239 const gchar *mime_type)
2241 g_return_if_fail (photo != NULL);
2242 g_return_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_INLINED);
2244 g_free (photo->data.inlined.mime_type);
2245 photo->data.inlined.mime_type = g_strdup (mime_type);
2249 * e_contact_photo_get_uri:
2250 * @photo: an #EContactPhoto
2252 * Gets the @photo's URI.
2254 * Returns: (transfer none) (allow-none): the URI of the image, or %NULL if it has not been set
2259 e_contact_photo_get_uri (EContactPhoto *photo)
2261 g_return_val_if_fail (photo != NULL, NULL);
2262 g_return_val_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_URI, NULL);
2264 return photo->data.uri;
2268 * e_contact_photo_set_uri:
2269 * @photo: an #EContactPhoto
2270 * @uri: the @photo's URI
2272 * Sets the @photo's URI.
2277 e_contact_photo_set_uri (EContactPhoto *photo,
2280 g_return_if_fail (photo != NULL);
2281 g_return_if_fail (photo->type == E_CONTACT_PHOTO_TYPE_URI);
2283 g_free (photo->data.uri);
2284 photo->data.uri = g_strdup (uri);
2287 /* Try to unescape a mime type which was encoded into
2288 * the filename, return the mime type if g_content_type_from_mime_type()
2289 * returns something for the decoded filename extension.
2292 mime_type_from_filename (const gchar *filename)
2296 gchar *content_type;
2298 extension = strrchr (filename, '.');
2305 mime_type = g_uri_unescape_string (extension, NULL);
2306 content_type = g_content_type_from_mime_type (mime_type);
2308 if (!content_type) {
2313 g_free (content_type);
2319 e_contact_photo_make_inline (EContactPhoto *photo,
2323 gchar *contents = NULL;
2325 gboolean success = FALSE;
2327 /* Just a sanity check, this wont happen but return TRUE anyway */
2328 if (photo->type != E_CONTACT_PHOTO_TYPE_URI)
2331 filename = g_filename_from_uri (photo->data.uri, NULL, error);
2335 if (g_file_get_contents (filename, &contents, &length, error)) {
2338 mime_type = mime_type_from_filename (filename);
2340 gchar *content_type =
2341 g_content_type_guess (NULL, (const guchar *) contents, length, NULL);
2344 mime_type = g_content_type_get_mime_type (content_type);
2346 g_free (content_type);
2349 g_free (photo->data.uri);
2351 photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
2352 photo->data.inlined.data = (guchar *) contents;
2353 photo->data.inlined.length = length;
2354 photo->data.inlined.mime_type = mime_type;
2364 e_contact_inline_photo_field (EContact *contact,
2365 EContactField field,
2368 EContactPhoto *photo;
2369 gboolean success = TRUE;
2371 photo = e_contact_get (contact, field);
2374 if (photo->type == E_CONTACT_PHOTO_TYPE_URI &&
2375 g_str_has_prefix (photo->data.uri, "file://")) {
2376 success = e_contact_photo_make_inline (photo, error);
2379 e_contact_set (contact, field, photo);
2381 e_contact_photo_free (photo);
2388 * e_contact_inline_local_photos:
2389 * @contact: an #EContact
2390 * @error: the location to store any #GError which might occur
2392 * Tries to modify any #EContactPhoto fields which are
2393 * stored on the local file system as type %E_CONTACT_PHOTO_TYPE_URI
2394 * to be inlined and stored as %E_CONTACT_PHOTO_TYPE_INLINED instead.
2396 * Returns: %TRUE if there were no errors, upon error %FALSE is returned
2397 * and @error is set.
2402 e_contact_inline_local_photos (EContact *contact,
2405 gboolean success = TRUE;
2407 g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
2409 success = e_contact_inline_photo_field (contact, E_CONTACT_PHOTO, error);
2411 success = e_contact_inline_photo_field (contact, E_CONTACT_LOGO, error);
2416 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_photo, "EContactPhoto")
2419 * e_contact_geo_free:
2420 * @geo: an #EContactGeo
2422 * Frees the @geo struct and its contents.
2427 e_contact_geo_free (EContactGeo *geo)
2432 static EContactGeo *
2433 e_contact_geo_copy (EContactGeo *geo)
2435 EContactGeo *geo2 = g_new0 (EContactGeo, 1);
2436 geo2->latitude = geo->latitude;
2437 geo2->longitude = geo->longitude;
2442 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_geo, "EContactGeo")
2445 * e_contact_address_new:
2447 * Creates a new #EContactAddress struct.
2449 * Returns: (transfer full): A new #EContactAddress struct.
2454 e_contact_address_new (void)
2456 return g_new0 (EContactAddress, 1);
2460 * e_contact_address_free:
2461 * @address: an #EContactAddress
2463 * Frees the @address struct and its contents.
2466 e_contact_address_free (EContactAddress *address)
2471 g_free (address->address_format);
2472 g_free (address->po);
2473 g_free (address->ext);
2474 g_free (address->street);
2475 g_free (address->locality);
2476 g_free (address->region);
2477 g_free (address->code);
2478 g_free (address->country);
2483 static EContactAddress *
2484 e_contact_address_copy (EContactAddress *address)
2486 EContactAddress *address2 = g_new0 (EContactAddress, 1);
2488 address2->address_format = g_strdup (address->address_format);
2489 address2->po = g_strdup (address->po);
2490 address2->ext = g_strdup (address->ext);
2491 address2->street = g_strdup (address->street);
2492 address2->locality = g_strdup (address->locality);
2493 address2->region = g_strdup (address->region);
2494 address2->code = g_strdup (address->code);
2495 address2->country = g_strdup (address->country);
2500 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_address, "EContactAddress")
2503 * e_contact_cert_free:
2504 * @cert: an #EContactCert
2506 * Frees the @cert struct and its contents.
2509 e_contact_cert_free (EContactCert *cert)
2514 g_free (cert->data);
2518 static EContactCert *
2519 e_contact_cert_copy (EContactCert *cert)
2521 EContactCert *cert2 = g_new0 (EContactCert, 1);
2522 cert2->length = cert->length;
2523 cert2->data = g_malloc (cert2->length);
2524 memcpy (cert2->data, cert->data, cert->length);
2529 E_CONTACT_DEFINE_BOXED_TYPE (e_contact_cert, "EContactCert")