No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Jon Trowbridge <trow@ximian.com>
18 * Chris Toshok <toshok@ximian.com>
19 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include "eab-book-util.h"
31
32 /* Copied from camel_strstrcase */
33 static gchar *
34 eab_strstrcase (const gchar *haystack,
35 const gchar *needle)
36 {
37 /* find the needle in the haystack neglecting case */
38 const gchar *ptr;
39 guint len;
40
41 g_return_val_if_fail (haystack != NULL, NULL);
42 g_return_val_if_fail (needle != NULL, NULL);
43
44 len = strlen (needle);
45 if (len > strlen (haystack))
46 return NULL;
47
48 if (len == 0)
49 return (gchar *) haystack;
50
51 for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
52 if (!g_ascii_strncasecmp (ptr, needle, len))
53 return (gchar *) ptr;
54
55 return NULL;
56 }
57
58 GSList *
59 eab_contact_list_from_string (const gchar *str)
60 {
61 GSList *contacts = NULL;
62 GString *gstr = g_string_new (NULL);
63 gchar *str_stripped;
64 gchar *p = (gchar *) str;
65 gchar *q;
66
67 if (!p)
68 return NULL;
69
70 if (!strncmp (p, "Book: ", 6)) {
71 p = strchr (p, '\n');
72 if (!p) {
73 g_warning (G_STRLOC ": Got book but no newline!");
74 return NULL;
75 }
76 p++;
77 }
78
79 while (*p) {
80 if (*p != '\r') g_string_append_c (gstr, *p);
81
82 p++;
83 }
84
85 p = str_stripped = g_string_free (gstr, FALSE);
86
87 /* Note: The vCard standard says
88 *
89 * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
90 * items *CRLF "END" [ws] ":" [ws] "VCARD"
91 *
92 * which means we can have whitespace (e.g. "BEGIN : VCARD"). So we're not being
93 * fully compliant here, although I'm not sure it matters. The ideal solution
94 * would be to have a vcard parsing function that returned the end of the vcard
95 * parsed. Arguably, contact list parsing should all be in libebook's e-vcard.c,
96 * where we can do proper parsing and validation without code duplication. */
97
98 for (p = eab_strstrcase (p, "BEGIN:VCARD"); p; p = eab_strstrcase (q, "\nBEGIN:VCARD")) {
99 gchar *card_str;
100
101 if (*p == '\n')
102 p++;
103
104 for (q = eab_strstrcase (p, "END:VCARD"); q; q = eab_strstrcase (q, "END:VCARD")) {
105 gchar *temp;
106
107 q += 9;
108 temp = q;
109 if (*temp)
110 temp += strspn (temp, "\r\n\t ");
111
112 if (*temp == '\0' || !g_ascii_strncasecmp (temp, "BEGIN:VCARD", 11))
113 break; /* Found the outer END:VCARD */
114 }
115
116 if (!q)
117 break;
118
119 card_str = g_strndup (p, q - p);
120 contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (card_str));
121 g_free (card_str);
122 }
123
124 g_free (str_stripped);
125
126 return g_slist_reverse (contacts);
127 }
128
129 gchar *
130 eab_contact_list_to_string (const GSList *contacts)
131 {
132 GString *str = g_string_new ("");
133 const GSList *l;
134
135 for (l = contacts; l; l = l->next) {
136 EContact *contact = l->data;
137 gchar *vcard_str;
138
139 e_contact_inline_local_photos (contact, NULL);
140 vcard_str = e_vcard_to_string (
141 E_VCARD (contact), EVC_FORMAT_VCARD_30);
142
143 g_string_append (str, vcard_str);
144 if (l->next)
145 g_string_append (str, "\r\n\r\n");
146 }
147
148 return g_string_free (str, FALSE);
149 }
150
151 gboolean
152 eab_book_and_contact_list_from_string (ESourceRegistry *registry,
153 const gchar *str,
154 EBookClient **book_client,
155 GSList **contacts)
156 {
157 ESource *source;
158 const gchar *s0, *s1;
159 gchar *uid;
160
161 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
162 g_return_val_if_fail (str != NULL, FALSE);
163 g_return_val_if_fail (book_client != NULL, FALSE);
164 g_return_val_if_fail (contacts != NULL, FALSE);
165
166 *contacts = eab_contact_list_from_string (str);
167
168 if (!strncmp (str, "Book: ", 6)) {
169 s0 = str + 6;
170 s1 = strchr (str, '\r');
171
172 if (!s1)
173 s1 = strchr (str, '\n');
174 } else {
175 s0 = NULL;
176 s1 = NULL;
177 }
178
179 if (!s0 || !s1) {
180 *book_client = NULL;
181 return FALSE;
182 }
183
184 uid = g_strndup (s0, s1 - s0);
185 source = e_source_registry_ref_source (registry, uid);
186 if (source != NULL) {
187 *book_client = e_book_client_new (source, NULL);
188 g_object_unref (source);
189 } else {
190 *book_client = NULL;
191 }
192 g_free (uid);
193
194 return (*book_client != NULL);
195 }
196
197 gchar *
198 eab_book_and_contact_list_to_string (EBookClient *book_client,
199 const GSList *contacts)
200 {
201 gchar *s0, *s1;
202
203 s0 = eab_contact_list_to_string (contacts);
204 if (!s0)
205 s0 = g_strdup ("");
206
207 if (book_client != NULL) {
208 EClient *client;
209 ESource *source;
210 const gchar *uid;
211
212 client = E_CLIENT (book_client);
213 source = e_client_get_source (client);
214 uid = e_source_get_uid (source);
215 s1 = g_strconcat ("Book: ", uid, "\r\n", s0, NULL);
216 } else
217 s1 = g_strdup (s0);
218
219 g_free (s0);
220 return s1;
221 }
222
223 /* bad place for this i know. */
224 gint
225 e_utf8_casefold_collate_len (const gchar *str1,
226 const gchar *str2,
227 gint len)
228 {
229 gchar *s1 = g_utf8_casefold (str1, len);
230 gchar *s2 = g_utf8_casefold (str2, len);
231 gint rv;
232
233 rv = g_utf8_collate (s1, s2);
234
235 g_free (s1);
236 g_free (s2);
237
238 return rv;
239 }
240
241 gint
242 e_utf8_casefold_collate (const gchar *str1,
243 const gchar *str2)
244 {
245 return e_utf8_casefold_collate_len (str1, str2, -1);
246 }