1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
4 * Copyright (C) 2003 Ximian, Inc.
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 <libgnomevfs/gnome-vfs-mime-utils.h>
33 #include "e-contact.h"
35 #include "e-name-western.h"
38 #include "libedataserver/e-data-server-util.h"
39 #undef EVOLUTION_LOCALEDIR
40 #define EVOLUTION_LOCALEDIR e_util_get_localedir ()
45 struct _EContactPrivate {
46 char *cached_strings [E_CONTACT_FIELD_LAST];
49 #define E_CONTACT_FIELD_TYPE_STRING 0x00000001 /* used for simple single valued attributes */
50 /*E_CONTACT_FIELD_TYPE_FLOAT*/
51 #define E_CONTACT_FIELD_TYPE_LIST 0x00000002 /* used for multivalued single attributes - the elements are of type char* */
52 #define E_CONTACT_FIELD_TYPE_MULTI 0x00000004 /* used for multivalued attributes - the elements are of type EVCardAttribute */
53 #define E_CONTACT_FIELD_TYPE_GETSET 0x00000008 /* used for attributes that need custom handling for getting/setting */
54 #define E_CONTACT_FIELD_TYPE_STRUCT 0x00000010 /* used for structured types (N and ADR properties, in particular) */
55 #define E_CONTACT_FIELD_TYPE_BOOLEAN 0x00000020 /* used for boolean types (WANTS_HTML) */
57 #define E_CONTACT_FIELD_TYPE_SYNTHETIC 0x10000000 /* used when there isn't a corresponding vcard field (such as email_1) */
58 #define E_CONTACT_FIELD_TYPE_LIST_ELEM 0x20000000 /* used when a synthetic attribute is a numbered list element */
59 #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 */
60 #define E_CONTACT_FIELD_TYPE_ATTR_TYPE 0x80000000 /* used when a synthetic attribute is flagged with a TYPE= that we'll be looking for */
65 EContactField field_id;
66 const char *vcard_field_name;
67 const char *field_name; /* non translated */
68 const char *pretty_name; /* translated */
73 const char *attr_type1;
74 const char *attr_type2;
76 void* (*struct_getter)(EContact *contact, EVCardAttribute *attribute);
77 void (*struct_setter)(EContact *contact, EVCardAttribute *attribute, void *data);
79 GType (*boxed_type_getter) (void);
82 static void* photo_getter (EContact *contact, EVCardAttribute *attr);
83 static void photo_setter (EContact *contact, EVCardAttribute *attr, void *data);
84 static void* geo_getter (EContact *contact, EVCardAttribute *attr);
85 static void geo_setter (EContact *contact, EVCardAttribute *attr, void *data);
86 static void* fn_getter (EContact *contact, EVCardAttribute *attr);
87 static void fn_setter (EContact *contact, EVCardAttribute *attr, void *data);
88 static void* n_getter (EContact *contact, EVCardAttribute *attr);
89 static void n_setter (EContact *contact, EVCardAttribute *attr, void *data);
90 static void* adr_getter (EContact *contact, EVCardAttribute *attr);
91 static void adr_setter (EContact *contact, EVCardAttribute *attr, void *data);
92 static void* date_getter (EContact *contact, EVCardAttribute *attr);
93 static void date_setter (EContact *contact, EVCardAttribute *attr, void *data);
94 static void* cert_getter (EContact *contact, EVCardAttribute *attr);
95 static void cert_setter (EContact *contact, EVCardAttribute *attr, void *data);
97 #define STRING_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING, (id), (vc), (n), (pn), (ro) }
98 #define BOOLEAN_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_BOOLEAN, (id), (vc), (n), (pn), (ro) }
99 #define LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_LIST, (id), (vc), (n), (pn), (ro) }
100 #define MULTI_LIST_FIELD(id,vc,n,pn,ro) { E_CONTACT_FIELD_TYPE_MULTI, (id), (vc), (n), (pn), (ro) }
101 #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) }
102 #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) }
103 #define SYNTH_STR_FIELD(id,n,pn,ro) { E_CONTACT_FIELD_TYPE_STRING | E_CONTACT_FIELD_TYPE_SYNTHETIC, (id), NULL, (n), (pn), (ro) }
104 #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) }
105 #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) }
106 #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 }
107 #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) }
108 #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) }
109 #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) }
111 /* This *must* be kept in the same order as the EContactField enum */
112 static const EContactFieldInfo field_info[] = {
113 {0,}, /* Dummy row as EContactField starts from 1 */
114 STRING_FIELD (E_CONTACT_UID, EVC_UID, "id", N_("Unique ID"), FALSE),
115 STRING_FIELD (E_CONTACT_FILE_AS, EVC_X_FILE_AS, "file_as", N_("File Under"), FALSE),
116 /* URI of the book to which the contact belongs to */
117 STRING_FIELD (E_CONTACT_BOOK_URI, EVC_X_BOOK_URI, "book_uri", N_("Book URI"), FALSE),
120 /* FN isn't really a structured field - we use a getter/setter
121 so we can set the N property (since evo 1.4 works fine with
122 vcards that don't even have a N attribute. *sigh*) */
123 GETSET_FIELD (E_CONTACT_FULL_NAME, EVC_FN, "full_name", N_("Full Name"), FALSE, fn_getter, fn_setter),
124 LIST_ELEM_STR_FIELD (E_CONTACT_GIVEN_NAME, EVC_N, "given_name", N_("Given Name"), FALSE, 1),
125 LIST_ELEM_STR_FIELD (E_CONTACT_FAMILY_NAME, EVC_N, "family_name", N_("Family Name"), FALSE, 0),
126 STRING_FIELD (E_CONTACT_NICKNAME, EVC_NICKNAME, "nickname", N_("Nickname"), FALSE),
129 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_1, EVC_EMAIL, "email_1", N_("Email 1"), FALSE, 0),
130 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_2, EVC_EMAIL, "email_2", N_("Email 2"), FALSE, 1),
131 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_3, EVC_EMAIL, "email_3", N_("Email 3"), FALSE, 2),
132 MULTI_ELEM_STR_FIELD (E_CONTACT_EMAIL_4, EVC_EMAIL, "email_4", N_("Email 4"), FALSE, 3),
134 STRING_FIELD (E_CONTACT_MAILER, EVC_MAILER, "mailer", N_("Mailer"), FALSE),
137 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_HOME, EVC_LABEL, "address_label_home", N_("Home Address Label"), FALSE, "HOME", 0),
138 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_WORK, EVC_LABEL, "address_label_work", N_("Work Address Label"), FALSE, "WORK", 0),
139 ATTR_TYPE_STR_FIELD (E_CONTACT_ADDRESS_LABEL_OTHER, EVC_LABEL, "address_label_other", N_("Other Address Label"), FALSE, "OTHER", 0),
142 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ASSISTANT, EVC_TEL, "assistant_phone", N_("Assistant Phone"), FALSE, EVC_X_ASSISTANT, 0),
143 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS, EVC_TEL, "business_phone", N_("Business Phone"), FALSE, "WORK", "VOICE", 0),
144 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_2, EVC_TEL, "business_phone_2", N_("Business Phone 2"), FALSE, "WORK", "VOICE", 1),
145 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_BUSINESS_FAX, EVC_TEL, "business_fax", N_("Business Fax"), FALSE, "WORK", "FAX", 0),
146 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CALLBACK, EVC_TEL, "callback_phone", N_("Callback Phone"), FALSE, EVC_X_CALLBACK, 0),
147 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_CAR, EVC_TEL, "car_phone", N_("Car Phone"), FALSE, "CAR", 0),
148 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_COMPANY, EVC_TEL, "company_phone", N_("Company Phone"), FALSE, EVC_X_COMPANY, 0),
149 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME, EVC_TEL, "home_phone", N_("Home Phone"), FALSE, "HOME", "VOICE", 0),
150 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_2, EVC_TEL, "home_phone_2", N_("Home Phone 2"), FALSE, "HOME", "VOICE", 1),
151 ATTR2_TYPE_STR_FIELD (E_CONTACT_PHONE_HOME_FAX, EVC_TEL, "home_fax", N_("Home Fax"), FALSE, "HOME", "FAX", 0),
152 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_ISDN, EVC_TEL, "isdn_phone", N_("ISDN"), FALSE, "ISDN", 0),
153 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_MOBILE, EVC_TEL, "mobile_phone", N_("Mobile Phone"), FALSE, "CELL", 0),
154 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER, EVC_TEL, "other_phone", N_("Other Phone"), FALSE, "VOICE", 0),
155 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_OTHER_FAX, EVC_TEL, "other_fax", N_("Other Fax"), FALSE, "FAX", 0),
156 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PAGER, EVC_TEL, "pager", N_("Pager"), FALSE, "PAGER", 0),
157 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_PRIMARY, EVC_TEL, "primary_phone", N_("Primary Phone"), FALSE, "PREF", 0),
158 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_RADIO, EVC_TEL, "radio", N_("Radio"), FALSE, EVC_X_RADIO, 0),
159 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TELEX, EVC_TEL, "telex", N_("Telex"), FALSE, EVC_X_TELEX, 0),
160 /* To translators: TTY is Teletypewriter */
161 ATTR_TYPE_STR_FIELD (E_CONTACT_PHONE_TTYTDD, EVC_TEL, "tty", N_("TTY"), FALSE, EVC_X_TTYTDD, 0),
163 /* Organizational fields */
164 LIST_ELEM_STR_FIELD (E_CONTACT_ORG, EVC_ORG, "org", N_("Organization"), FALSE, 0),
165 LIST_ELEM_STR_FIELD (E_CONTACT_ORG_UNIT, EVC_ORG, "org_unit", N_("Organizational Unit"), FALSE, 1),
166 LIST_ELEM_STR_FIELD (E_CONTACT_OFFICE, EVC_ORG, "office", N_("Office"), FALSE, 2),
167 STRING_FIELD (E_CONTACT_TITLE, EVC_TITLE, "title", N_("Title"), FALSE),
168 STRING_FIELD (E_CONTACT_ROLE, EVC_ROLE, "role", N_("Role"), FALSE),
169 STRING_FIELD (E_CONTACT_MANAGER, EVC_X_MANAGER, "manager", N_("Manager"), FALSE),
170 STRING_FIELD (E_CONTACT_ASSISTANT, EVC_X_ASSISTANT, "assistant", N_("Assistant"), FALSE),
173 STRING_FIELD (E_CONTACT_HOMEPAGE_URL, EVC_URL, "homepage_url", N_("Homepage URL"), FALSE),
174 STRING_FIELD (E_CONTACT_BLOG_URL, EVC_X_BLOG_URL, "blog_url", N_("Weblog URL"), FALSE),
176 /* Contact categories */
177 SYNTH_STR_FIELD (E_CONTACT_CATEGORIES, "categories", N_("Categories"), FALSE),
179 /* Collaboration fields */
180 STRING_FIELD (E_CONTACT_CALENDAR_URI, EVC_CALURI, "caluri", N_("Calendar URI"), FALSE),
181 STRING_FIELD (E_CONTACT_FREEBUSY_URL, EVC_FBURL, "fburl", N_("Free/Busy URL"), FALSE),
182 STRING_FIELD (E_CONTACT_ICS_CALENDAR, EVC_ICSCALENDAR, "icscalendar", N_("ICS Calendar"), FALSE),
183 STRING_FIELD (E_CONTACT_VIDEO_URL, EVC_X_VIDEO_URL, "video_url", N_("Video Conferencing URL"), FALSE),
186 STRING_FIELD (E_CONTACT_SPOUSE, EVC_X_SPOUSE, "spouse", N_("Spouse's Name"), FALSE),
187 STRING_FIELD (E_CONTACT_NOTE, EVC_NOTE, "note", N_("Note"), FALSE),
189 /* Instant messaging fields */
190 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),
191 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),
192 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),
193 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),
194 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),
195 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),
196 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),
197 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),
198 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),
199 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),
200 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),
201 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),
202 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),
203 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),
204 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),
205 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),
206 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),
207 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),
208 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),
209 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),
210 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),
211 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),
212 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),
213 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),
214 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),
215 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),
216 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),
217 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),
218 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),
219 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),
220 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),
221 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),
222 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),
223 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),
224 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),
225 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),
227 /* Last modified time */
228 STRING_FIELD (E_CONTACT_REV, EVC_REV, "Rev", N_("Last Revision"), FALSE),
229 SYNTH_STR_FIELD (E_CONTACT_NAME_OR_ORG, "name_or_org", N_("Name or Org"), TRUE),
232 MULTI_LIST_FIELD (E_CONTACT_ADDRESS, EVC_ADR, "address", N_("Address List"), FALSE),
233 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),
234 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),
235 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),
237 /* Contact categories */
238 LIST_FIELD (E_CONTACT_CATEGORY_LIST, EVC_CATEGORIES, "category_list", N_("Category List"), FALSE),
241 STRUCT_FIELD (E_CONTACT_PHOTO, EVC_PHOTO, "photo", N_("Photo"), FALSE, photo_getter, photo_setter, e_contact_photo_get_type),
242 STRUCT_FIELD (E_CONTACT_LOGO, EVC_LOGO, "logo", N_("Logo"), FALSE, photo_getter, photo_setter, e_contact_photo_get_type),
244 STRUCT_FIELD (E_CONTACT_NAME, EVC_N, "name", N_("Name"), FALSE, n_getter, n_setter, e_contact_name_get_type),
245 MULTI_LIST_FIELD (E_CONTACT_EMAIL, EVC_EMAIL, "email", N_("Email List"), FALSE),
247 /* Instant messaging fields */
248 MULTI_LIST_FIELD (E_CONTACT_IM_AIM, EVC_X_AIM, "im_aim", N_("AIM Screen Name List"), FALSE),
249 MULTI_LIST_FIELD (E_CONTACT_IM_GROUPWISE, EVC_X_GROUPWISE, "im_groupwise", N_("GroupWise Id List"), FALSE),
250 MULTI_LIST_FIELD (E_CONTACT_IM_JABBER, EVC_X_JABBER, "im_jabber", N_("Jabber Id List"), FALSE),
251 MULTI_LIST_FIELD (E_CONTACT_IM_YAHOO, EVC_X_YAHOO, "im_yahoo", N_("Yahoo! Screen Name List"), FALSE),
252 MULTI_LIST_FIELD (E_CONTACT_IM_MSN, EVC_X_MSN, "im_msn", N_("MSN Screen Name List"), FALSE),
253 MULTI_LIST_FIELD (E_CONTACT_IM_ICQ, EVC_X_ICQ, "im_icq", N_("ICQ Id List"), FALSE),
255 BOOLEAN_FIELD (E_CONTACT_WANTS_HTML, EVC_X_WANTS_HTML, "wants_html", N_("Wants HTML Mail"), FALSE),
257 BOOLEAN_FIELD (E_CONTACT_IS_LIST, EVC_X_LIST, "list", N_("List"), FALSE),
258 BOOLEAN_FIELD (E_CONTACT_LIST_SHOW_ADDRESSES, EVC_X_LIST_SHOW_ADDRESSES, "list_show_addresses", N_("List Show Addresses"), FALSE),
260 STRUCT_FIELD (E_CONTACT_BIRTH_DATE, EVC_BDAY, "birth_date", N_("Birth Date"), FALSE, date_getter, date_setter, e_contact_date_get_type),
261 STRUCT_FIELD (E_CONTACT_ANNIVERSARY, EVC_X_ANNIVERSARY, "anniversary", N_("Anniversary"), FALSE, date_getter, date_setter, e_contact_date_get_type),
263 /* Security fields */
264 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),
266 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),
267 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),
268 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),
269 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),
270 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),
271 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),
272 MULTI_LIST_FIELD (E_CONTACT_IM_GADUGADU, EVC_X_GADUGADU, "im_gadugadu", N_("Gadu-Gadu Id List"), FALSE),
274 /* Geo information */
275 STRUCT_FIELD (E_CONTACT_GEO, EVC_GEO, "geo", N_("Geographic Information"), FALSE, geo_getter, geo_setter, e_contact_geo_get_type)
278 #undef LIST_ELEM_STR_FIELD
280 #undef SYNTH_STR_FIELD
284 static GObjectClass *parent_class;
286 static void e_contact_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
287 static void e_contact_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
290 e_contact_finalize (GObject *object)
292 EContact *ec = E_CONTACT (object);
295 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
296 g_free (ec->priv->cached_strings[i]);
304 G_OBJECT_CLASS (parent_class)->finalize (object);
308 e_contact_class_init (EContactClass *klass)
310 GObjectClass *object_class;
313 object_class = G_OBJECT_CLASS(klass);
315 parent_class = g_type_class_ref (E_TYPE_VCARD);
317 object_class->finalize = e_contact_finalize;
318 object_class->set_property = e_contact_set_property;
319 object_class->get_property = e_contact_get_property;
321 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i++) {
322 GParamSpec *pspec = NULL;
324 /* Verify the table is correctly ordered */
325 g_assert (i == field_info[i].field_id);
327 if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRING)
328 pspec = g_param_spec_string (field_info[i].field_name,
329 _(field_info[i].pretty_name),
330 field_info[i].pretty_name,
332 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
333 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
334 else if (field_info[i].t & E_CONTACT_FIELD_TYPE_BOOLEAN)
335 pspec = g_param_spec_boolean (field_info[i].field_name,
336 _(field_info[i].pretty_name),
337 field_info[i].pretty_name,
339 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
340 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
341 else if (field_info[i].t & E_CONTACT_FIELD_TYPE_STRUCT)
342 pspec = g_param_spec_boxed (field_info[i].field_name,
343 _(field_info[i].pretty_name),
344 field_info[i].pretty_name,
345 field_info[i].boxed_type_getter(),
346 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
347 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
349 pspec = g_param_spec_pointer (field_info[i].field_name,
350 _(field_info[i].pretty_name),
351 field_info[i].pretty_name,
352 (field_info[i].read_only ? G_PARAM_READABLE : G_PARAM_READWRITE)
353 | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
355 g_object_class_install_property (object_class, field_info[i].field_id,
361 e_contact_init (EContact *ec)
363 ec->priv = g_new0 (EContactPrivate, 1);
367 e_contact_get_type (void)
369 static GType contact_type = 0;
372 static const GTypeInfo contact_info = {
373 sizeof (EContactClass),
374 NULL, /* base_init */
375 NULL, /* base_finalize */
376 (GClassInitFunc) e_contact_class_init,
377 NULL, /* class_finalize */
378 NULL, /* class_data */
381 (GInstanceInitFunc) e_contact_init,
384 contact_type = g_type_register_static (E_TYPE_VCARD, "EContact", &contact_info, 0);
390 static EVCardAttribute*
391 e_contact_get_first_attr (EContact *contact, const char *attr_name)
395 attrs = e_vcard_get_attributes (E_VCARD (contact));
397 for (l = attrs; l; l = l->next) {
398 EVCardAttribute *attr = l->data;
401 name = e_vcard_attribute_get_name (attr);
403 if (!g_ascii_strcasecmp (name, attr_name))
413 geo_getter (EContact *contact, EVCardAttribute *attr)
416 GList *p = e_vcard_attribute_get_values (attr);
417 EContactGeo *geo = g_new0 (EContactGeo, 1);
419 geo->latitude = (p && p->data ? g_ascii_strtod (p->data, NULL) : 0); if (p) p = p->next;
420 geo->longitude = (p && p->data ? g_ascii_strtod (p->data, NULL) : 0);
429 geo_setter (EContact *contact, EVCardAttribute *attr, void *data)
431 EContactGeo *geo = data;
432 char buf[G_ASCII_DTOSTR_BUF_SIZE];
434 e_vcard_attribute_add_value
435 (attr, g_ascii_dtostr (buf, sizeof (buf), geo->latitude));
437 e_vcard_attribute_add_value
438 (attr, g_ascii_dtostr (buf, sizeof (buf), geo->longitude));
442 photo_getter (EContact *contact, EVCardAttribute *attr)
449 values = e_vcard_attribute_get_param (attr, EVC_ENCODING);
450 if (values && (g_ascii_strcasecmp (values->data, "b") == 0 ||
451 /* second for photo vCard 2.1 support */
452 g_ascii_strcasecmp (values->data, "base64") == 0)) {
453 values = e_vcard_attribute_get_values_decoded (attr);
454 if (values && values->data) {
455 GString *s = values->data;
456 EContactPhoto *photo;
461 photo = g_new0 (EContactPhoto, 1);
462 photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
463 photo->data.inlined.length = s->len;
464 photo->data.inlined.data = g_malloc (photo->data.inlined.length);
465 memcpy (photo->data.inlined.data, s->str, photo->data.inlined.length);
467 values = e_vcard_attribute_get_param (attr, EVC_TYPE);
468 if (values && values->data)
469 photo->data.inlined.mime_type = g_strdup_printf("image/%s", (char*)values->data);
474 values = e_vcard_attribute_get_param (attr, EVC_VALUE);
475 if (values && g_ascii_strcasecmp (values->data, "uri") == 0) {
476 EContactPhoto *photo;
477 photo = g_new0 (EContactPhoto, 1);
478 photo->type = E_CONTACT_PHOTO_TYPE_URI;
479 photo->data.uri = e_vcard_attribute_get_value (attr);
486 photo_setter (EContact *contact, EVCardAttribute *attr, void *data)
488 EContactPhoto *photo = data;
489 char *image_type, *p;
491 switch (photo->type) {
492 case E_CONTACT_PHOTO_TYPE_INLINED:
493 g_return_if_fail (photo->data.inlined.length > 0);
495 e_vcard_attribute_add_param_with_value (attr,
496 e_vcard_attribute_param_new (EVC_ENCODING),
498 if (photo->data.inlined.mime_type && (p = strchr (photo->data.inlined.mime_type, '/'))) {
501 image_type = "X-EVOLUTION-UNKNOWN";
503 e_vcard_attribute_add_param_with_value (attr,
504 e_vcard_attribute_param_new (EVC_TYPE),
507 e_vcard_attribute_add_value_decoded (attr, (char*)photo->data.inlined.data, photo->data.inlined.length);
509 case E_CONTACT_PHOTO_TYPE_URI:
510 e_vcard_attribute_add_param_with_value (attr,
511 e_vcard_attribute_param_new (EVC_VALUE),
513 e_vcard_attribute_add_value (attr, photo->data.uri);
516 g_warning ("Unknown EContactPhotoType %d", photo->type);
523 fn_getter (EContact *contact, EVCardAttribute *attr)
526 GList *p = e_vcard_attribute_get_values (attr);
528 return p && p->data ? p->data : "";
535 fn_setter (EContact *contact, EVCardAttribute *attr, void *data)
537 gchar *name_str = data;
539 e_vcard_attribute_add_value (attr, name_str);
541 attr = e_contact_get_first_attr (contact, EVC_N);
543 EContactName *name = e_contact_name_from_string ((char*)data);
545 attr = e_vcard_attribute_new (NULL, EVC_N);
546 e_vcard_add_attribute (E_VCARD (contact), attr);
548 /* call the setter directly */
549 n_setter (contact, attr, name);
551 e_contact_name_free (name);
558 n_getter (EContact *contact, EVCardAttribute *attr)
560 EContactName *name = g_new0 (EContactName, 1);
561 EVCardAttribute *new_attr;
565 GList *p = e_vcard_attribute_get_values (attr);
567 name->family = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
568 name->given = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
569 name->additional = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
570 name->prefixes = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
571 name->suffixes = g_strdup (p && p->data ? p->data : "");
574 new_attr = e_contact_get_first_attr (contact, EVC_FN);
576 new_attr = e_vcard_attribute_new (NULL, EVC_FN);
577 e_vcard_add_attribute (E_VCARD (contact), new_attr);
578 name_str = e_contact_name_to_string (name);
579 e_vcard_attribute_add_value (new_attr, name_str);
587 n_setter (EContact *contact, EVCardAttribute *attr, void *data)
589 EContactName *name = data;
591 e_vcard_attribute_add_value (attr, name->family);
592 e_vcard_attribute_add_value (attr, name->given);
593 e_vcard_attribute_add_value (attr, name->additional);
594 e_vcard_attribute_add_value (attr, name->prefixes);
595 e_vcard_attribute_add_value (attr, name->suffixes);
597 /* now find the attribute for FileAs. if it's not present, fill it in */
598 attr = e_contact_get_first_attr (contact, EVC_X_FILE_AS);
600 char *strings[3], **stringptr;
602 attr = e_vcard_attribute_new (NULL, EVC_X_FILE_AS);
603 e_vcard_add_attribute (E_VCARD (contact), attr);
606 if (name->family && *name->family)
607 *(stringptr++) = name->family;
608 if (name->given && *name->given)
609 *(stringptr++) = name->given;
611 string = g_strjoinv(", ", strings);
613 e_vcard_attribute_add_value (attr, string);
622 adr_getter (EContact *contact, EVCardAttribute *attr)
625 GList *p = e_vcard_attribute_get_values (attr);
626 EContactAddress *addr = g_new0 (EContactAddress, 1);
628 addr->address_format = g_strdup ("");
629 addr->po = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
630 addr->ext = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
631 addr->street = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
632 addr->locality = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
633 addr->region = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
634 addr->code = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
635 addr->country = g_strdup (p && p->data ? p->data : ""); if (p) p = p->next;
644 adr_setter (EContact *contact, EVCardAttribute *attr, void *data)
646 EContactAddress *addr = data;
648 e_vcard_attribute_add_value (attr, addr->po);
649 e_vcard_attribute_add_value (attr, addr->ext);
650 e_vcard_attribute_add_value (attr, addr->street);
651 e_vcard_attribute_add_value (attr, addr->locality);
652 e_vcard_attribute_add_value (attr, addr->region);
653 e_vcard_attribute_add_value (attr, addr->code);
654 e_vcard_attribute_add_value (attr, addr->country);
660 date_getter (EContact *contact, EVCardAttribute *attr)
663 GList *p = e_vcard_attribute_get_values (attr);
666 if (p && p->data && ((gchar *) p->data) [0])
667 date = e_contact_date_from_string ((char *) p->data);
678 date_setter (EContact *contact, EVCardAttribute *attr, void *data)
680 EContactDate *date = data;
683 str = e_contact_date_to_string (date);
685 e_vcard_attribute_add_value (attr, str);
692 cert_getter (EContact *contact, EVCardAttribute *attr)
695 /* the certificate is stored in this vcard. just
697 GList *values = e_vcard_attribute_get_values_decoded (attr);
699 if (values && values->data) {
700 GString *s = values->data;
701 EContactCert *cert = g_new0 (EContactCert, 1);
703 cert->length = s->len;
704 cert->data = g_malloc (cert->length);
705 memcpy (cert->data, s->str, cert->length);
711 /* XXX if we stored a fingerprint in the cert we could look it
712 up via NSS, but that would require the additional NSS dep
713 here, and we'd have more than one process opening the
714 certdb, which is bad. *sigh* */
720 cert_setter (EContact *contact, EVCardAttribute *attr, void *data)
722 EContactCert *cert = data;
724 e_vcard_attribute_add_param_with_value (attr,
725 e_vcard_attribute_param_new (EVC_ENCODING),
728 e_vcard_attribute_add_value_decoded (attr, cert->data, cert->length);
733 /* Set_arg handler for the contact */
735 e_contact_set_property (GObject *object,
740 EContact *contact = E_CONTACT (object);
741 const EContactFieldInfo *info = NULL;
743 if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) {
744 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
748 info = &field_info[prop_id];
750 if (info->t & E_CONTACT_FIELD_TYPE_MULTI) {
751 GList *new_values = g_value_get_pointer (value);
754 /* first we remove all attributes of the type we're
755 adding, then add new ones based on the values that
757 e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name);
759 for (l = new_values; l; l = l->next)
760 e_vcard_add_attribute_with_value (E_VCARD (contact),
761 e_vcard_attribute_new (NULL, info->vcard_field_name),
764 else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) {
765 if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) {
766 /* XXX this is kinda broken - we don't insert
767 insert padding elements if, e.g. the user
768 sets email 3 when email 1 and 2 don't
769 exist. But, if we *did* pad the lists we'd
770 end up with empty items in the vcard. I
771 dunno which is worse. */
772 EVCardAttribute *attr = NULL;
773 gboolean found = FALSE;
774 int num_left = info->list_elem;
775 GList *attrs = e_vcard_get_attributes (E_VCARD (contact));
779 for (l = attrs; l; l = l->next) {
783 name = e_vcard_attribute_get_name (attr);
785 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
786 if (num_left-- == 0) {
793 sval = g_value_get_string (value);
796 /* we found it, overwrite it */
797 e_vcard_attribute_remove_values (attr);
800 /* we didn't find it - add a new attribute */
801 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
802 if (!strcmp(info->vcard_field_name, "EMAIL") &&
805 /* Add default type */
806 e_vcard_attribute_add_param_with_value ( attr,
807 e_vcard_attribute_param_new (EVC_TYPE),
810 e_vcard_add_attribute (E_VCARD (contact), attr);
813 e_vcard_attribute_add_value (attr, sval);
817 e_vcard_remove_attribute (E_VCARD (contact), attr);
820 else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
821 /* XXX this is kinda broken - we don't insert
822 insert padding elements if, e.g. the user
823 sets email 3 when email 1 and 2 don't
824 exist. But, if we *did* pad the lists we'd
825 end up with empty items in the vcard. I
826 dunno which is worse. */
827 EVCardAttribute *attr = NULL;
828 gboolean found = FALSE;
829 int num_left = info->list_elem;
830 GList *attrs = e_vcard_get_attributes (E_VCARD (contact));
833 for (l = attrs; l && !found; l = l->next) {
835 gboolean found_needed1, found_needed2;
837 found_needed1 = (info->attr_type1 == NULL);
838 found_needed2 = (info->attr_type2 == NULL);
841 name = e_vcard_attribute_get_name (attr);
843 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
846 for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
847 EVCardAttributeParam *param = params->data;
848 const char *param_name = e_vcard_attribute_param_get_name (param);
850 if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
851 gboolean matches = FALSE;
852 GList *values = e_vcard_attribute_param_get_values (param);
854 while (values && values->data) {
855 if (!found_needed1 && !g_ascii_strcasecmp ((char*)values->data, info->attr_type1)) {
856 found_needed1 = TRUE;
859 else if (!found_needed2 && !g_ascii_strcasecmp ((char*)values->data, info->attr_type2)) {
860 found_needed2 = TRUE;
864 values = values->next;
868 /* this is to enforce that we find an attribute
869 with *only* the TYPE='s we need. This may seem like
870 an odd restriction but it's the only way at present to
871 implement the Other Fax and Other Phone attributes. */
873 found_needed2 = FALSE;
878 if (found_needed1 && found_needed2) {
879 if (num_left-- == 0) {
889 /* we found it, overwrite it */
890 e_vcard_attribute_remove_values (attr);
893 /* we didn't find it - add a new attribute */
894 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
895 e_vcard_add_attribute (E_VCARD (contact), attr);
896 if (info->attr_type1)
897 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE),
899 if (info->attr_type2)
900 e_vcard_attribute_add_param_with_value (attr, e_vcard_attribute_param_new (EVC_TYPE),
904 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT || info->t & E_CONTACT_FIELD_TYPE_GETSET) {
905 void *data = info->t & E_CONTACT_FIELD_TYPE_STRUCT ? g_value_get_boxed (value) : (char*)g_value_get_string (value);
907 if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
908 || (data && *(char*)data))
909 info->struct_setter (contact, attr, data);
911 e_vcard_remove_attribute (E_VCARD (contact), attr);
914 const char *sval = g_value_get_string (value);
917 e_vcard_attribute_add_value (attr, sval);
919 e_vcard_remove_attribute (E_VCARD (contact), attr);
922 else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
923 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
926 const char *sval = g_value_get_string (value);
932 d(printf ("adding new %s\n", info->vcard_field_name));
934 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
935 e_vcard_add_attribute (E_VCARD (contact), attr);
938 values = e_vcard_attribute_get_values (attr);
939 p = g_list_nth (values, info->list_elem);
943 p->data = g_strdup (g_value_get_string (value));
946 /* there weren't enough elements in the list, pad it */
947 int count = info->list_elem - g_list_length (values);
950 e_vcard_attribute_add_value (attr, "");
952 e_vcard_attribute_add_value (attr, g_value_get_string (value));
956 switch (info->field_id) {
957 case E_CONTACT_CATEGORIES: {
958 EVCardAttribute *attr = e_contact_get_first_attr (contact, EVC_CATEGORIES);
963 e_vcard_attribute_remove_values (attr);
965 /* we didn't find it - add a new attribute */
966 attr = e_vcard_attribute_new (NULL, EVC_CATEGORIES);
967 e_vcard_add_attribute (E_VCARD (contact), attr);
970 str = g_value_get_string (value);
972 split = g_strsplit (str, ",", 0);
974 for (s = split; *s; s++) {
975 e_vcard_attribute_add_value (attr, g_strstrip (*s));
979 e_vcard_attribute_add_value (attr, str);
982 d(printf ("removing %s\n", info->vcard_field_name));
984 e_vcard_remove_attribute (E_VCARD (contact), attr);
989 g_warning ("unhandled synthetic field 0x%02x", info->field_id);
994 else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT || info->t & E_CONTACT_FIELD_TYPE_GETSET) {
995 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
996 void *data = info->t & E_CONTACT_FIELD_TYPE_STRUCT ? g_value_get_boxed (value) : (char*)g_value_get_string (value);
999 if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
1000 || (data && *(char*)data)) {
1001 d(printf ("overwriting existing %s\n", info->vcard_field_name));
1002 /* remove all existing values and parameters.
1003 the setter will add the correct ones */
1004 e_vcard_attribute_remove_values (attr);
1005 e_vcard_attribute_remove_params (attr);
1007 info->struct_setter (contact, attr, data);
1010 d(printf ("removing %s\n", info->vcard_field_name));
1012 e_vcard_remove_attribute (E_VCARD (contact), attr);
1015 else if ((info->t & E_CONTACT_FIELD_TYPE_STRUCT && data)
1016 || (data && *(char*)data)) {
1017 d(printf ("adding new %s\n", info->vcard_field_name));
1018 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
1020 e_vcard_add_attribute (E_VCARD (contact), attr);
1022 info->struct_setter (contact, attr, data);
1025 else if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1026 EVCardAttribute *attr;
1028 /* first we search for an attribute we can overwrite */
1029 attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1031 d(printf ("setting %s to `%s'\n", info->vcard_field_name, g_value_get_string (value)));
1032 e_vcard_attribute_remove_values (attr);
1033 e_vcard_attribute_add_value (attr, g_value_get_boolean (value) ? "TRUE" : "FALSE");
1036 /* and if we don't find one we create a new attribute */
1037 e_vcard_add_attribute_with_value (E_VCARD (contact),
1038 e_vcard_attribute_new (NULL, info->vcard_field_name),
1039 g_value_get_boolean (value) ? "TRUE" : "FALSE");
1042 else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1043 EVCardAttribute *attr;
1044 const char *sval = g_value_get_string (value);
1046 /* first we search for an attribute we can overwrite */
1047 attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1049 d(printf ("setting %s to `%s'\n", info->vcard_field_name, sval));
1050 e_vcard_attribute_remove_values (attr);
1052 e_vcard_attribute_add_value (attr, sval);
1055 d(printf ("removing %s\n", info->vcard_field_name));
1057 e_vcard_remove_attribute (E_VCARD (contact), attr);
1062 /* and if we don't find one we create a new attribute */
1063 e_vcard_add_attribute_with_value (E_VCARD (contact),
1064 e_vcard_attribute_new (NULL, info->vcard_field_name),
1065 g_value_get_string (value));
1068 else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1069 EVCardAttribute *attr;
1072 values = g_value_get_pointer (value);
1074 attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1077 e_vcard_attribute_remove_values (attr);
1080 e_vcard_remove_attribute (E_VCARD (contact), attr);
1083 attr = e_vcard_attribute_new (NULL, info->vcard_field_name);
1084 e_vcard_add_attribute (E_VCARD (contact), attr);
1087 for (l = values; l != NULL; l = l->next)
1088 e_vcard_attribute_add_value (attr, l->data);
1091 g_warning ("unhandled attribute `%s'", info->vcard_field_name);
1095 static EVCardAttribute *
1096 e_contact_find_attribute_with_types (EContact *contact, const char *attr_name, const char *type_needed1, const char *type_needed2, int nth)
1099 gboolean found_needed1, found_needed2;
1101 attrs = e_vcard_get_attributes (E_VCARD (contact));
1103 for (l = attrs; l; l = l->next) {
1104 EVCardAttribute *attr = l->data;
1107 found_needed1 = (type_needed1 == NULL);
1108 found_needed2 = (type_needed2 == NULL);
1110 name = e_vcard_attribute_get_name (attr);
1112 if (!g_ascii_strcasecmp (name, attr_name)) {
1115 for (params = e_vcard_attribute_get_params (attr); params; params = params->next) {
1116 EVCardAttributeParam *param = params->data;
1117 const char *param_name = e_vcard_attribute_param_get_name (param);
1119 if (!g_ascii_strcasecmp (param_name, EVC_TYPE)) {
1120 gboolean matches = FALSE;
1121 GList *values = e_vcard_attribute_param_get_values (param);
1123 while (values && values->data) {
1124 if (!found_needed1 && !g_ascii_strcasecmp ((char*)values->data, type_needed1)) {
1125 found_needed1 = TRUE;
1128 else if (!found_needed2 && !g_ascii_strcasecmp ((char*)values->data, type_needed2)) {
1129 found_needed2 = TRUE;
1132 values = values->next;
1136 /* this is to enforce that we find an attribute
1137 with *only* the TYPE='s we need. This may seem like
1138 an odd restriction but it's the only way at present to
1139 implement the Other Fax and Other Phone attributes. */
1141 found_needed2 = FALSE;
1146 if (found_needed1 && found_needed2) {
1160 e_contact_get_property (GObject *object,
1165 const EContactFieldInfo *info = NULL;
1168 if (prop_id < 1 || prop_id >= E_CONTACT_FIELD_LAST) {
1169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1170 g_value_reset (value);
1174 info = &field_info[prop_id];
1175 data = e_contact_get (E_CONTACT (object), prop_id);
1177 if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1178 g_value_set_boolean (value, (gboolean)data);
1179 } else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1180 g_value_set_pointer (value, data);
1181 } else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1182 g_value_take_boxed (value, data);
1183 } else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1184 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1185 g_value_set_boxed (value, data);
1187 g_value_set_string (value, data);
1189 } else if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1190 g_value_set_string (value, data);
1192 g_value_set_pointer (value, data);
1201 * Creates a new, blank #EContact.
1203 * Return value: A new #EContact.
1206 e_contact_new (void)
1208 return e_contact_new_from_vcard ("");
1212 * e_contact_new_from_vcard:
1213 * @vcard: a string representing a vcard
1215 * Creates a new #EContact based on a vcard.
1217 * Return value: A new #EContact.
1220 e_contact_new_from_vcard (const char *vcard)
1223 const gchar *file_as;
1225 g_return_val_if_fail (vcard != NULL, NULL);
1227 contact = g_object_new (E_TYPE_CONTACT, NULL);
1228 e_vcard_construct (E_VCARD (contact), vcard);
1230 /* Generate a FILE_AS field if needed */
1232 file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
1233 if (!file_as || !*file_as) {
1236 gchar *file_as_new = NULL;
1238 gchar **strings_p = strings;
1240 name = e_contact_get (contact, E_CONTACT_NAME);
1241 org = e_contact_get_const (contact, E_CONTACT_ORG);
1244 if (name->family && *name->family)
1245 *(strings_p++) = name->family;
1246 if (name->given && *name->given)
1247 *(strings_p++) = name->given;
1249 if (strings_p != strings) {
1251 file_as_new = g_strjoinv (", ", strings);
1254 e_contact_name_free (name);
1257 if (!file_as_new && org && *org)
1258 file_as_new = g_strdup (org);
1261 e_contact_set (contact, E_CONTACT_FILE_AS, file_as_new);
1262 g_free (file_as_new);
1270 * e_contact_duplicate:
1271 * @contact: an #EContact
1273 * Creates a copy of @contact.
1275 * Return value: A new #EContact identical to @contact.
1278 e_contact_duplicate (EContact *contact)
1283 g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
1285 vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1286 c = e_contact_new_from_vcard (vcard);
1293 * e_contact_field_name:
1294 * @field_id: an #EContactField
1296 * Gets the string representation of @field_id.
1298 * Return value: The string representation of @field_id, or %NULL if it doesn't exist.
1301 e_contact_field_name (EContactField field_id)
1303 g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, "");
1305 return field_info[field_id].field_name;
1309 * e_contact_pretty_name:
1310 * @field_id: an #EContactField
1312 * Gets a human-readable, translated string representation
1315 * Return value: The human-readable representation of @field_id, or %NULL if it doesn't exist.
1318 e_contact_pretty_name (EContactField field_id)
1320 g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, "");
1323 bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
1324 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1327 return _(field_info[field_id].pretty_name);
1331 * e_contact_vcard_attribute:
1332 * @field_id: an #EContactField
1334 * Gets the vcard attribute corresponding to @field_id, as a string.
1336 * Return value: The vcard attribute corresponding to @field_id, or %NULL if it doesn't exist.
1339 e_contact_vcard_attribute (EContactField field_id)
1341 g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, "");
1343 return field_info[field_id].vcard_field_name;
1347 * e_contact_field_id:
1348 * @field_name: a string representing a contact field
1350 * Gets the #EContactField corresponding to the @field_name.
1352 * Return value: An #EContactField corresponding to @field_name, or %0 if it doesn't exist.
1355 e_contact_field_id (const char *field_name)
1358 for (i = E_CONTACT_FIELD_FIRST; i < E_CONTACT_FIELD_LAST; i ++) {
1359 if (!strcmp (field_info[i].field_name, field_name))
1360 return field_info[i].field_id;
1363 g_warning ("unknown field name `%s'", field_name);
1369 * @contact: an #EContact
1370 * @field_id: an #EContactField
1372 * Gets the value of @contact's field specified by @field_id.
1374 * Return value: Depends on the field's type, owned by the caller.
1377 e_contact_get (EContact *contact, EContactField field_id)
1379 const EContactFieldInfo *info = NULL;
1381 g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL);
1382 g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL);
1384 info = &field_info[field_id];
1386 if (info->t & E_CONTACT_FIELD_TYPE_BOOLEAN) {
1387 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1388 gboolean rv = FALSE;
1391 GList *v = e_vcard_attribute_get_values (attr);
1392 rv = v && v->data && !g_ascii_strcasecmp ((char*)v->data, "true");
1393 return (gpointer)rv;
1396 else if (info->t & E_CONTACT_FIELD_TYPE_LIST) {
1397 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1400 GList *list = g_list_copy (e_vcard_attribute_get_values (attr));
1402 for (l = list; l; l = l->next)
1403 l->data = g_strdup (l->data);
1407 else if (info->t & E_CONTACT_FIELD_TYPE_LIST_ELEM) {
1408 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1409 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1414 v = e_vcard_attribute_get_values (attr);
1415 v = g_list_nth (v, info->list_elem);
1417 return v ? g_strdup (v->data) : NULL;
1421 else if (info->t & E_CONTACT_FIELD_TYPE_MULTI_ELEM) {
1422 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1424 int num_left = info->list_elem;
1426 attrs = e_vcard_get_attributes (E_VCARD (contact));
1428 for (l = attrs; l; l = l->next) {
1429 EVCardAttribute *attr = l->data;
1432 name = e_vcard_attribute_get_name (attr);
1434 if (!strcmp (name, info->vcard_field_name)) {
1435 if (num_left-- == 0) {
1436 GList *v = e_vcard_attribute_get_values (attr);
1438 return v ? g_strdup (v->data) : NULL;
1444 else if (info->t & E_CONTACT_FIELD_TYPE_ATTR_TYPE) {
1445 EVCardAttribute *attr = e_contact_find_attribute_with_types (contact, info->vcard_field_name, info->attr_type1, info->attr_type2, info->list_elem);
1447 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1449 GList *p = e_vcard_attribute_get_values (attr);
1450 return g_strdup (p->data);
1457 return info->struct_getter (contact, attr);
1461 else if (info->t & E_CONTACT_FIELD_TYPE_STRUCT) {
1462 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1464 return info->struct_getter (contact, attr);
1466 else if (info->t & E_CONTACT_FIELD_TYPE_GETSET) {
1467 EVCardAttribute *attr = e_contact_get_first_attr (contact, info->vcard_field_name);
1471 rv = info->struct_getter (contact, attr);
1473 if (info->t & E_CONTACT_FIELD_TYPE_STRUCT)
1474 return (gpointer)info->boxed_type_getter();
1476 return g_strdup (rv);
1478 else if (info->t & E_CONTACT_FIELD_TYPE_SYNTHETIC) {
1479 switch (info->field_id) {
1480 case E_CONTACT_NAME_OR_ORG: {
1483 str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
1485 str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
1487 str = e_contact_get_const (contact, E_CONTACT_ORG);
1489 gboolean is_list = GPOINTER_TO_INT (e_contact_get (contact, E_CONTACT_IS_LIST));
1492 str = _("Unnamed List");
1494 str = e_contact_get_const (contact, E_CONTACT_EMAIL_1);
1497 return g_strdup (str);
1499 case E_CONTACT_CATEGORIES: {
1500 EVCardAttribute *attr = e_contact_get_first_attr (contact, EVC_CATEGORIES);
1504 GString *str = g_string_new ("");
1505 GList *v = e_vcard_attribute_get_values (attr);
1507 g_string_append (str, (char*)v->data);
1510 g_string_append_c (str, ',');
1513 rv = g_string_free (str, FALSE);
1519 g_warning ("unhandled synthetic field 0x%02x", info->field_id);
1525 GList *rv = NULL; /* used for multi attribute lists */
1527 attrs = e_vcard_get_attributes (E_VCARD (contact));
1529 for (l = attrs; l; l = l->next) {
1530 EVCardAttribute *attr = l->data;
1533 name = e_vcard_attribute_get_name (attr);
1535 if (!strcmp (name, info->vcard_field_name)) {
1537 v = e_vcard_attribute_get_values (attr);
1539 if (info->t & E_CONTACT_FIELD_TYPE_STRING) {
1540 return v ? g_strdup (v->data) : NULL;
1543 rv = g_list_append (rv, v ? g_strdup (v->data) : NULL);
1553 * e_contact_get_const:
1554 * @contact: an #EContact
1555 * @field_id: an #EContactField
1557 * Gets the value of @contact's field specified by @field_id, caching
1558 * the result so it can be freed later.
1560 * Return value: Depends on the field's type, owned by the #EContact.
1563 e_contact_get_const (EContact *contact, EContactField field_id)
1565 gpointer value = NULL;
1567 g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
1568 g_return_val_if_fail (field_info [field_id].t & E_CONTACT_FIELD_TYPE_STRING, NULL);
1570 value = contact->priv->cached_strings[field_id];
1573 value = e_contact_get (contact, field_id);
1575 contact->priv->cached_strings[field_id] = value;
1583 * @contact: an #EContact
1584 * @field_id: an #EContactField
1585 * @value: a value whose type depends on the @field_id
1587 * Sets the value of @contact's field specified by @field_id to @value.
1590 e_contact_set (EContact *contact, EContactField field_id, const gpointer value)
1592 d(printf ("e_contact_set (%p, %d, %p)\n", contact, field_id, value));
1594 g_return_if_fail (contact && E_IS_CONTACT (contact));
1595 g_return_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST);
1597 /* set the cached slot to NULL so we'll re-get the new string
1598 if e_contact_get_const is called again */
1599 contact->priv->cached_strings[field_id] = NULL;
1601 g_object_set (contact,
1602 e_contact_field_name (field_id), value,
1607 * e_contact_get_attributes:
1608 * @contact: an #EContact
1609 * @field_id: an #EContactField
1611 * Gets a list of the vcard attributes for @contact's @field_id.
1613 * Return value: A #GList of pointers to #EVCardAttribute, owned by the caller.
1616 e_contact_get_attributes (EContact *contact, EContactField field_id)
1620 const EContactFieldInfo *info = NULL;
1622 g_return_val_if_fail (contact && E_IS_CONTACT (contact), NULL);
1623 g_return_val_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST, NULL);
1625 info = &field_info[field_id];
1627 attrs = e_vcard_get_attributes (E_VCARD (contact));
1629 for (a = attrs; a; a = a->next) {
1630 EVCardAttribute *attr = a->data;
1633 name = e_vcard_attribute_get_name (attr);
1635 if (!g_ascii_strcasecmp (name, info->vcard_field_name)) {
1636 l = g_list_prepend (l, e_vcard_attribute_copy (attr));
1640 return g_list_reverse(l);
1644 * e_contact_set_attributes:
1645 * @contact: an #EContact
1646 * @field_id: an #EContactField
1647 * @attributes: a #GList of pointers to #EVCardAttribute
1649 * Sets the vcard attributes for @contact's @field_id.
1652 e_contact_set_attributes (EContact *contact, EContactField field_id, GList *attributes)
1654 const EContactFieldInfo *info = NULL;
1657 g_return_if_fail (contact && E_IS_CONTACT (contact));
1658 g_return_if_fail (field_id >= 1 && field_id <= E_CONTACT_FIELD_LAST);
1660 info = &field_info[field_id];
1662 e_vcard_remove_attributes (E_VCARD (contact), NULL, info->vcard_field_name);
1664 for (l = attributes; l; l = l->next)
1665 e_vcard_add_attribute (E_VCARD (contact),
1666 e_vcard_attribute_copy ((EVCardAttribute*)l->data));
1670 * e_contact_name_new:
1672 * Creates a new #EContactName struct.
1674 * Return value: A new #EContactName struct.
1677 e_contact_name_new (void)
1679 return g_new0 (EContactName, 1);
1683 * e_contact_name_to_string:
1684 * @name: an #EContactName
1686 * Generates a string representation of @name.
1688 * Return value: The string representation of @name.
1691 e_contact_name_to_string(const EContactName *name)
1693 char *strings[6], **stringptr = strings;
1695 g_return_val_if_fail (name != NULL, NULL);
1697 if (name->prefixes && *name->prefixes)
1698 *(stringptr++) = name->prefixes;
1699 if (name->given && *name->given)
1700 *(stringptr++) = name->given;
1701 if (name->additional && *name->additional)
1702 *(stringptr++) = name->additional;
1703 if (name->family && *name->family)
1704 *(stringptr++) = name->family;
1705 if (name->suffixes && *name->suffixes)
1706 *(stringptr++) = name->suffixes;
1708 return g_strjoinv(" ", strings);
1712 * e_contact_name_from_string:
1713 * @name_str: a string representing a contact's full name
1715 * Creates a new #EContactName based on the parsed @name_str.
1717 * Return value: A new #EContactName struct.
1720 e_contact_name_from_string (const char *name_str)
1722 EContactName *name = e_contact_name_new();
1723 ENameWestern *western;
1725 g_return_val_if_fail (name_str != NULL, NULL);
1727 western = e_name_western_parse (name_str ? name_str : "");
1729 name->prefixes = g_strdup (western->prefix);
1730 name->given = g_strdup (western->first );
1731 name->additional = g_strdup (western->middle);
1732 name->family = g_strdup (western->last );
1733 name->suffixes = g_strdup (western->suffix);
1735 e_name_western_free(western);
1741 * e_contact_name_copy:
1742 * @n: an #EContactName
1744 * Creates a copy of @n.
1746 * Return value: A new #EContactName identical to @n.
1749 e_contact_name_copy (EContactName *n)
1753 g_return_val_if_fail (n != NULL, NULL);
1755 name = e_contact_name_new();
1757 name->prefixes = g_strdup (n->prefixes);
1758 name->given = g_strdup (n->given);
1759 name->additional = g_strdup (n->additional);
1760 name->family = g_strdup (n->family);
1761 name->suffixes = g_strdup (n->suffixes);
1767 * e_contact_name_free:
1768 * @name: an #EContactName
1770 * Frees @name and its contents.
1773 e_contact_name_free (EContactName *name)
1778 g_free (name->family);
1779 g_free (name->given);
1780 g_free (name->additional);
1781 g_free (name->prefixes);
1782 g_free (name->suffixes);
1788 e_contact_name_get_type (void)
1790 static GType type_id = 0;
1793 type_id = g_boxed_type_register_static ("EContactName",
1794 (GBoxedCopyFunc) e_contact_name_copy,
1795 (GBoxedFreeFunc) e_contact_name_free);
1800 * e_contact_date_from_string:
1801 * @str: a date string in the format YYYY-MM-DD or YYYYMMDD
1803 * Creates a new #EContactDate based on @str.
1805 * Return value: A new #EContactDate struct.
1808 e_contact_date_from_string (const char *str)
1814 g_return_val_if_fail (str != NULL, NULL);
1816 date = e_contact_date_new();
1817 /* ignore time part */
1818 if ((t = strchr (str, 'T')) != NULL)
1821 length = strlen(str);
1823 if (length == 10 ) {
1824 date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111;
1825 date->month = str[5] * 10 + str[6] - '0' * 11;
1826 date->day = str[8] * 10 + str[9] - '0' * 11;
1827 } else if ( length == 8 ) {
1828 date->year = str[0] * 1000 + str[1] * 100 + str[2] * 10 + str[3] - '0' * 1111;
1829 date->month = str[4] * 10 + str[5] - '0' * 11;
1830 date->day = str[6] * 10 + str[7] - '0' * 11;
1837 * e_contact_date_to_string:
1838 * @dt: an #EContactDate
1840 * Generates a date string in the format YYYY-MM-DD based
1841 * on the values of @dt.
1843 * Return value: A date string, owned by the caller.
1846 e_contact_date_to_string (EContactDate *dt)
1849 return g_strdup_printf ("%04d-%02d-%02d",
1850 CLAMP(dt->year, 1000, 9999),
1851 CLAMP(dt->month, 1, 12),
1852 CLAMP(dt->day, 1, 31));
1858 * e_contact_date_equal:
1859 * @dt1: an #EContactDate
1860 * @dt2: an #EContactDate
1862 * Checks if @dt1 and @dt2 are the same date.
1864 * Return value: %TRUE if @dt1 and @dt2 are equal, %FALSE otherwise.
1867 e_contact_date_equal (EContactDate *dt1, EContactDate *dt2)
1870 return (dt1->year == dt2->year &&
1871 dt1->month == dt2->month &&
1872 dt1->day == dt2->day);
1874 return (!!dt1 == !!dt2);
1878 * e_contact_date_copy:
1879 * @dt: an #EContactDate
1881 * Creates a copy of @dt.
1883 * Return value: A new #EContactDate struct identical to @dt.
1885 static EContactDate *
1886 e_contact_date_copy (EContactDate *dt)
1888 EContactDate *dt2 = e_contact_date_new ();
1889 dt2->year = dt->year;
1890 dt2->month = dt->month;
1897 * e_contact_date_free:
1898 * @date: an #EContactDate
1900 * Frees the @date struct and its contents.
1903 e_contact_date_free (EContactDate *date)
1909 e_contact_date_get_type (void)
1911 static GType type_id = 0;
1914 type_id = g_boxed_type_register_static ("EContactDate",
1915 (GBoxedCopyFunc) e_contact_date_copy,
1916 (GBoxedFreeFunc) e_contact_date_free);
1921 * e_contact_date_new:
1923 * Creates a new #EContactDate struct.
1925 * Return value: A new #EContactDate struct.
1928 e_contact_date_new (void)
1930 return g_new0 (EContactDate, 1);
1934 * e_contact_photo_free:
1935 * @photo: an #EContactPhoto struct
1937 * Frees the @photo struct and its contents.
1940 e_contact_photo_free (EContactPhoto *photo)
1945 switch (photo->type) {
1946 case E_CONTACT_PHOTO_TYPE_INLINED:
1947 g_free (photo->data.inlined.mime_type);
1948 g_free (photo->data.inlined.data);
1950 case E_CONTACT_PHOTO_TYPE_URI:
1951 g_free (photo->data.uri);
1954 g_warning ("Unknown EContactPhotoType %d", photo->type);
1962 * e_contact_photo_copy:
1963 * @photo: an #EContactPhoto
1965 * Creates a copy of @photo.
1967 * Return value: A new #EContactPhoto struct identical to @photo.
1969 static EContactPhoto *
1970 e_contact_photo_copy (EContactPhoto *photo)
1972 EContactPhoto *photo2 = g_new0 (EContactPhoto, 1);
1973 switch (photo->type) {
1974 case E_CONTACT_PHOTO_TYPE_INLINED:
1975 photo2->type = E_CONTACT_PHOTO_TYPE_INLINED;
1976 photo2->data.inlined.mime_type = g_strdup (photo->data.inlined.mime_type);
1977 photo2->data.inlined.length = photo->data.inlined.length;
1978 photo2->data.inlined.data = g_malloc (photo2->data.inlined.length);
1979 memcpy (photo2->data.inlined.data, photo->data.inlined.data, photo->data.inlined.length);
1981 case E_CONTACT_PHOTO_TYPE_URI:
1982 photo2->type = E_CONTACT_PHOTO_TYPE_URI;
1983 photo2->data.uri = g_strdup (photo->data.uri);
1986 g_warning ("Unknown EContactPhotoType %d", photo->type);
1993 e_contact_photo_get_type (void)
1995 static GType type_id = 0;
1998 type_id = g_boxed_type_register_static ("EContactPhoto",
1999 (GBoxedCopyFunc) e_contact_photo_copy,
2000 (GBoxedFreeFunc) e_contact_photo_free);
2005 * e_contact_geo_free:
2006 * @geo: an #EContactGeo
2008 * Frees the @geo struct and its contents.
2011 e_contact_geo_free (EContactGeo *geo)
2016 static EContactGeo *
2017 e_contact_geo_copy (EContactGeo *geo)
2019 EContactGeo *geo2 = g_new0 (EContactGeo, 1);
2020 geo2->latitude = geo->latitude;
2021 geo2->longitude = geo->longitude;
2027 e_contact_geo_get_type (void)
2029 static GType type_id = 0;
2032 type_id = g_boxed_type_register_static ("EContactGeo",
2033 (GBoxedCopyFunc) e_contact_geo_copy,
2034 (GBoxedFreeFunc) e_contact_geo_free);
2040 * e_contact_address_free:
2041 * @address: an #EContactAddress
2043 * Frees the @address struct and its contents.
2046 e_contact_address_free (EContactAddress *address)
2051 g_free (address->address_format);
2052 g_free (address->po);
2053 g_free (address->ext);
2054 g_free (address->street);
2055 g_free (address->locality);
2056 g_free (address->region);
2057 g_free (address->code);
2058 g_free (address->country);
2063 static EContactAddress *
2064 e_contact_address_copy (EContactAddress *address)
2066 EContactAddress *address2 = g_new0 (EContactAddress, 1);
2068 address2->address_format = g_strdup (address->address_format);
2069 address2->po = g_strdup (address->po);
2070 address2->ext = g_strdup (address->ext);
2071 address2->street = g_strdup (address->street);
2072 address2->locality = g_strdup (address->locality);
2073 address2->region = g_strdup (address->region);
2074 address2->code = g_strdup (address->code);
2075 address2->country = g_strdup (address->country);
2081 e_contact_address_get_type (void)
2083 static GType type_id = 0;
2086 type_id = g_boxed_type_register_static ("EContactAddress",
2087 (GBoxedCopyFunc) e_contact_address_copy,
2088 (GBoxedFreeFunc) e_contact_address_free);
2093 * e_contact_cert_free:
2094 * @cert: an #EContactCert
2096 * Frees the @cert struct and its contents.
2099 e_contact_cert_free (EContactCert *cert)
2104 g_free (cert->data);
2108 static EContactCert *
2109 e_contact_cert_copy (EContactCert *cert)
2111 EContactCert *cert2 = g_new0 (EContactCert, 1);
2112 cert2->length = cert->length;
2113 cert2->data = g_malloc (cert2->length);
2114 memcpy (cert2->data, cert->data, cert->length);
2120 e_contact_cert_get_type (void)
2122 static GType type_id = 0;
2125 type_id = g_boxed_type_register_static ("EContactCert",
2126 (GBoxedCopyFunc) e_contact_cert_copy,
2127 (GBoxedFreeFunc) e_contact_cert_free);