1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
10 * for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 */
16
17 #include <stdlib.h>
18 #include <libebook/libebook.h>
19
20 #include "client-test-utils.h"
21 #include "e-test-server-utils.h"
22
23 static ETestServerClosure book_closure = { E_TEST_SERVER_ADDRESS_BOOK, NULL, 0 };
24
25 static const gchar *photo_data =
26 "/9j / 4AAQSkZJRgABAQEARwBHAAD//gAXQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q / 9sAQwAIBgYHB\
27 gUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04Mjw\
28 uMzQy / 9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM\
29 jIyMjIyMjIyMjIyMjIyMjIy / 8AAEQgAMgAyAwEiAAIRAQMRAf / EABsAAQACAwEBAAAAAAAAAAA\
30 AAAAHCAQFBgID / 8QAMBAAAgEDAQYEBQQDAAAAAAAAAQIDAAQRBQYSEyExQQdhcYEiI0JRkRQVM\
31 qFiguH / xAAaAQADAQEBAQAAAAAAAAAAAAAABAUCBgED / 8QAIxEAAgICAQQCAwAAAAAAAAAAAAE\
32 CAwQRQRITITEUYQUiUf / aAAwDAQACEQMRAD8An + sHUtWtNKjVrmQ7754cajLvjrgfbzPIdzWdV\
33 fds9pJb3XdQkMrcFZGj + HqY0bdVV9Tz / wBia + N9vbjvkaxMb5E9N6SJB1HxLEEjJaWsUjD6QzS\
34 MPXdGB7E1zV74t63HINy1s4F7CWCTn77wrA0TY86jY3N1qsUk6wxBxBDvYjLHkoUH4j3JP / a0V\
35 3s1CvF / QM9tKpw0THeU + TLkj8VLnmzT8y0n9FujBx5bioba / rZLWx3iPZ7RzLp95GtnqRGVTez\
36 HNjruH7 / 4n + 67iqpq7Qi3uYWMMsNynfnE6sM8 / Lr6VamFi0KMepUE1Sx7XZHbI + fjxos1H0z3S\
37 lKYEjzISI2I64OKqsyu8sck2QYrmPjBvpIYg598Vauoh8VtlY7JW2isoBwpPl6hGByZTyD + o6E\
38 +h7UtlVOcPHA/+PyI1Wal6Zp7vaC / 06wnTTLtEeUDiKwzu4H8vI9AM9Tiuctkng1Nnk1G5cOoY\
39 ifB4nI / jB7VjWuoT21qPmwXUCHKlphHKvqG5N6g0 / cLi / Rg88FhbkbxlaUSu3kqpnn6kDzqGqb\
40 NdPB0XyK4 / svZr9RVntL50GePdcKEDqzhVBx7sKtPpayppNosxzKIlDHzxUFeG2zo2n2kivWhK\
41 6PpHwwoTnfk65J7kZyT9z5VYADAwKuYtfRA5zPv7tnjgUpSmREV8bq1hvbWW1uY1khlUo6MMhg\
42 eor7UoAje18FtmLe9eeQT3EXPcglkJRPbv71EWu7Dajp2o3MGmlRCkjKQ30jPUe1WlrlNW0Rpt\
43 TleNB84DnjkD0P9VlxT4Nqck9pmn8JuFp2zo0cgCWFi2e7555 / NSHXLadso2m3sU0NxlV65HM+\
44 VdTW3rgwvsUpSvAFKUoAUxSlAClKUAKUpQB//2Q==";
45
46 static GMainLoop *loop = NULL;
47 static gchar *micheal_jackson_uid = NULL;
48 static gchar *james_brown_uid = NULL;
49
50 /* Decide what to do with every "view-completed" signal */
51 enum {
52 ITERATION_SWAP_FACE = 0,
53 ITERATION_DELETE_JAMES,
54 ITERATION_UPDATE_MICHEAL,
55 ITERATION_DELETE_MICHEAL,
56 ITERATION_FINISH
57 };
58 static gint iteration = ITERATION_SWAP_FACE;
59
60 static void
print_contact(EContact * contact)61 print_contact (EContact *contact)
62 {
63 EContactPhoto *photo = e_contact_get (contact, E_CONTACT_PHOTO);
64
65 g_assert (photo != NULL);
66 g_assert (photo->type == E_CONTACT_PHOTO_TYPE_URI);
67 g_print ("Test passed with photo uri: %s\n", photo->data.uri);
68
69 e_contact_photo_free (photo);
70 }
71
72 static void
objects_added(EBookView * book_view,const GSList * contacts)73 objects_added (EBookView *book_view,
74 const GSList *contacts)
75 {
76 const GSList *l;
77
78 for (l = (GSList *) contacts; l; l = l->next) {
79 print_contact (l->data);
80 }
81 }
82
83 static void
objects_modified(EBookView * book_view,const GSList * contacts)84 objects_modified (EBookView *book_view,
85 const GSList *contacts)
86 {
87 GSList *l;
88
89 for (l = (GSList *) contacts; l; l = l->next) {
90 print_contact (l->data);
91 }
92 }
93
94 static void
objects_removed(EBookClientView * book_view,const GSList * ids)95 objects_removed (EBookClientView *book_view,
96 const GSList *ids)
97 {
98 GSList *l;
99
100 for (l = (GSList *) ids; l; l = l->next) {
101 g_print ("Removed contact: %s\n", (gchar *) l->data);
102 }
103 }
104
105 /* This provokes the backend to handle a cross-referenced photo
106 * between contacts, how the backend handles this is its choice,
107 * we should test that when deleting one of the contacts, the other
108 * contact does not lose its photo on disk as a result.
109 */
110 static void
give_james_brown_micheal_jacksons_face(EBookClient * book)111 give_james_brown_micheal_jacksons_face (EBookClient *book)
112 {
113 EContact *micheal = NULL, *james = NULL;
114 EContactPhoto *micheal_face;
115 EContactPhoto *james_face;
116 GError *error = NULL;
117
118 if (!e_book_client_get_contact_sync (book, micheal_jackson_uid, &micheal, NULL, &error))
119 g_error ("Unable to get micheal jackson's contact information: %s", error->message);
120
121 if (!e_book_client_get_contact_sync (book, james_brown_uid, &james, NULL, &error))
122 g_error ("Unable to get james brown's contact information: %s", error->message);
123
124 g_assert (micheal);
125 g_assert (james);
126
127 micheal_face = e_contact_get (micheal, E_CONTACT_PHOTO);
128 g_assert_nonnull (micheal_face);
129 g_assert (micheal_face->type == E_CONTACT_PHOTO_TYPE_URI);
130
131 james_face = e_contact_photo_new ();
132 james_face->type = E_CONTACT_PHOTO_TYPE_URI;
133 james_face->data.uri = g_strdup (micheal_face->data.uri);
134
135 e_contact_set (james, E_CONTACT_PHOTO, james_face);
136
137 g_print ("Giving james brown micheal jacksons face: %s\n", micheal_face->data.uri);
138
139 e_contact_photo_free (micheal_face);
140 e_contact_photo_free (james_face);
141
142 if (!e_book_client_modify_contact_sync (book, james, E_BOOK_OPERATION_FLAG_NONE, NULL, &error))
143 g_error ("Failed to modify contact with cross referenced photo: %s", error->message);
144
145 g_object_unref (micheal);
146 g_object_unref (james);
147 }
148
149 static void
update_contact_inline(EBookClient * book,const gchar * uid)150 update_contact_inline (EBookClient *book,
151 const gchar *uid)
152 {
153 EContact *contact = NULL;
154 EContactPhoto *photo;
155 guchar *data;
156 gsize length = 0;
157 GError *error = NULL;
158
159 if (!e_book_client_get_contact_sync (book, uid, &contact, NULL, &error))
160 g_error ("Unable to get contact: %s", error->message);
161
162 g_assert (contact);
163
164 data = g_base64_decode (photo_data, &length);
165
166 photo = e_contact_photo_new ();
167 photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
168 photo->data.inlined.mime_type = g_strdup ("image/png");
169 photo->data.inlined.data = data;
170 photo->data.inlined.length = length;
171
172 /* set the photo */
173 e_contact_set (contact, E_CONTACT_PHOTO, photo);
174
175 e_contact_photo_free (photo);
176
177 if (!e_book_client_modify_contact_sync (book, contact, E_BOOK_OPERATION_FLAG_NONE, NULL, &error))
178 g_error ("Failed to modify contact with inline photo data: %s", error->message);
179
180 g_object_unref (contact);
181 }
182
183 /* This assertion is made a couple of times in the view-complete
184 * handler, we run it to ensure that binary blobs and cross-referenced
185 * photo uris exist on disk while they should */
186 static void
assert_uri_exists(EBookClient * book,const gchar * uid)187 assert_uri_exists (EBookClient *book,
188 const gchar *uid)
189 {
190 EContact *contact;
191 EContactPhoto *photo;
192 gchar *filename;
193 gboolean success;
194 GError *error = NULL;
195
196 if (!e_book_client_get_contact_sync (book, uid, &contact, NULL, &error))
197 g_error ("Unable to get contact: %s", error->message);
198
199 g_assert (contact);
200
201 photo = e_contact_get (contact, E_CONTACT_PHOTO);
202 g_assert (photo);
203 g_assert (photo->type == E_CONTACT_PHOTO_TYPE_URI);
204
205 filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
206 g_assert (filename);
207
208 /* The file should absolutely exist at this point */
209 g_assert (g_file_test (filename, G_FILE_TEST_EXISTS));
210
211 e_contact_photo_free (photo);
212
213 success = e_contact_inline_local_photos (contact, &error);
214 g_assert_no_error (error);
215 g_assert (success);
216
217 photo = e_contact_get (contact, E_CONTACT_PHOTO);
218 g_assert (photo);
219 g_assert (photo->type == E_CONTACT_PHOTO_TYPE_INLINED);
220 g_assert_cmpstr (e_contact_photo_get_mime_type (photo), ==, "image/png");
221
222 e_contact_photo_free (photo);
223 g_object_unref (contact);
224 g_free (filename);
225 }
226
227 static void
complete(EBookClientView * view,const GError * error)228 complete (EBookClientView *view,
229 const GError *error)
230 {
231 EBookClient *book = e_book_client_view_ref_client (view);
232 GError *local_error = NULL;
233
234 g_print ("View complete, iteration %d\n", iteration);
235
236 /* We get another "complete" notification after removing or modifying a contact */
237 switch (iteration++) {
238 case ITERATION_SWAP_FACE:
239 give_james_brown_micheal_jacksons_face (book);
240 break;
241 case ITERATION_DELETE_JAMES:
242 assert_uri_exists (book, james_brown_uid);
243
244 if (!e_book_client_remove_contact_by_uid_sync (book, james_brown_uid, E_BOOK_OPERATION_FLAG_NONE, NULL, &local_error))
245 g_error ("Error removing contact: %s", local_error->message);
246
247 g_free (james_brown_uid);
248 james_brown_uid = NULL;
249 break;
250 case ITERATION_UPDATE_MICHEAL:
251 assert_uri_exists (book, micheal_jackson_uid);
252
253 update_contact_inline (book, micheal_jackson_uid);
254 break;
255 case ITERATION_DELETE_MICHEAL:
256 assert_uri_exists (book, micheal_jackson_uid);
257
258 if (!e_book_client_remove_contact_by_uid_sync (book, micheal_jackson_uid, E_BOOK_OPERATION_FLAG_NONE, NULL, &local_error))
259 g_error ("Error removing contact: %s", local_error->message);
260
261 g_free (micheal_jackson_uid);
262 micheal_jackson_uid = NULL;
263 break;
264 case ITERATION_FINISH:
265 e_book_client_view_stop (view, NULL);
266 g_object_unref (view);
267 g_main_loop_quit (loop);
268 break;
269 default:
270 g_assert_not_reached ();
271 break;
272 }
273
274 g_object_unref (book);
275 }
276
277 static void
setup_and_start_view(EBookClientView * view)278 setup_and_start_view (EBookClientView *view)
279 {
280 GError *error = NULL;
281
282 g_signal_connect (view, "objects-added", G_CALLBACK (objects_added), NULL);
283 g_signal_connect (view, "objects-removed", G_CALLBACK (objects_removed), NULL);
284 g_signal_connect (view, "objects-modified", G_CALLBACK (objects_modified), NULL);
285 g_signal_connect (view, "complete", G_CALLBACK (complete), NULL);
286
287 e_book_client_view_set_fields_of_interest (view, NULL, &error);
288 if (error)
289 g_error ("set fields of interest: %s", error->message);
290
291 e_book_client_view_start (view, &error);
292 if (error)
293 g_error ("start view: %s", error->message);
294 }
295
296 static void
add_contact_inline(EBookClient * book)297 add_contact_inline (EBookClient *book)
298 {
299 EContact *contact;
300 EContactPhoto *photo;
301 guchar *data;
302 gsize length = 0;
303
304 contact = e_contact_new ();
305
306 data = g_base64_decode (photo_data, &length);
307
308 photo = e_contact_photo_new ();
309 photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
310 photo->data.inlined.mime_type = g_strdup ("image/png");
311 photo->data.inlined.data = data;
312 photo->data.inlined.length = length;
313
314 /* set the photo */
315 e_contact_set (contact, E_CONTACT_PHOTO, photo);
316 e_contact_set (contact, E_CONTACT_FULL_NAME, "Micheal Jackson");
317
318 e_contact_photo_free (photo);
319
320 if (!add_contact_verify (book, contact))
321 g_error ("Failed to add contact");
322
323 micheal_jackson_uid = e_contact_get (contact, E_CONTACT_UID);
324
325 g_object_unref (contact);
326 }
327
328 static void
add_contact_uri(EBookClient * book)329 add_contact_uri (EBookClient *book)
330 {
331 EContact *contact;
332 EContactPhoto *photo;
333
334 contact = e_contact_new ();
335
336 photo = e_contact_photo_new ();
337 photo->type = E_CONTACT_PHOTO_TYPE_URI;
338 photo->data.uri = g_strdup ("http://en.wikipedia.org/wiki/File:Jamesbrown4.jpg");
339
340 /* set the photo */
341 e_contact_set (contact, E_CONTACT_PHOTO, photo);
342 e_contact_set (contact, E_CONTACT_FULL_NAME, "James Brown");
343
344 e_contact_photo_free (photo);
345
346 if (!add_contact_verify (book, contact))
347 g_error ("Failed to add contact");
348
349 james_brown_uid = e_contact_get (contact, E_CONTACT_UID);
350
351 g_object_unref (contact);
352 }
353
354 static void
test_photo_is_uri(ETestServerFixture * fixture,gconstpointer user_data)355 test_photo_is_uri (ETestServerFixture *fixture,
356 gconstpointer user_data)
357 {
358 EBookClient *book_client;
359 EBookClientView *view;
360 EBookQuery *query;
361 GError *error = NULL;
362 gchar *sexp;
363
364 book_client = E_TEST_SERVER_UTILS_SERVICE (fixture, EBookClient);
365
366 add_contact_inline (book_client);
367 add_contact_uri (book_client);
368
369 query = e_book_query_any_field_contains ("");
370 sexp = e_book_query_to_string (query);
371 e_book_query_unref (query);
372 if (!e_book_client_get_view_sync (book_client, sexp, &view, NULL, &error))
373 g_error ("get book view sync: %s", error->message);
374
375 g_free (sexp);
376
377 setup_and_start_view (view);
378
379 loop = fixture->loop;
380 g_main_loop_run (loop);
381 }
382
383 gint
main(gint argc,gchar ** argv)384 main (gint argc,
385 gchar **argv)
386 {
387 g_test_init (&argc, &argv, NULL);
388 g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution-data-server/");
389
390 client_test_utils_read_args (argc, argv);
391
392 g_test_add (
393 "/EBookClient/PhotoIsUri",
394 ETestServerFixture,
395 &book_closure,
396 e_test_server_utils_setup,
397 test_photo_is_uri,
398 e_test_server_utils_teardown);
399
400 return e_test_server_utils_run (argc, argv);
401 }
402