1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2010-2014 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU General Public License Version 2
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "config.h"
23
24 #include <gio/gio.h>
25 #include <glib-object.h>
26 #include <lcms2.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #ifdef HAVE_PWD_H
30 #include <pwd.h>
31 #endif
32 #include <math.h>
33
34 #include "cd-common.h"
35 #include "cd-profile.h"
36 #include "cd-profile-db.h"
37 #include "cd-resources.h"
38
39 static void cd_profile_finalize (GObject *object);
40 static void cd_profile_set_filename (CdProfile *profile,
41 const gchar *filename);
42
43 #define GET_PRIVATE(o) (cd_profile_get_instance_private (o))
44
45 /**
46 * CdProfilePrivate:
47 *
48 * Private #CdProfile data
49 **/
50 typedef struct
51 {
52 CdObjectScope object_scope;
53 gchar *filename;
54 gchar *id;
55 gchar *object_path;
56 gchar *qualifier;
57 gchar *format;
58 gchar *checksum;
59 gchar *title;
60 GDBusConnection *connection;
61 guint registration_id;
62 guint watcher_id;
63 CdProfileKind kind;
64 CdColorspace colorspace;
65 GHashTable *metadata;
66 gboolean has_vcgt;
67 gboolean is_system_wide;
68 gint64 created;
69 guint owner;
70 gchar **warnings;
71 GMappedFile *mapped_file;
72 guint score;
73 CdProfileDb *db;
74 } CdProfilePrivate;
75
76 enum {
77 SIGNAL_INVALIDATE,
78 SIGNAL_LAST
79 };
80
81 enum {
82 PROP_0,
83 PROP_OBJECT_PATH,
84 PROP_ID,
85 PROP_QUALIFIER,
86 PROP_TITLE,
87 PROP_FILENAME,
88 PROP_LAST
89 };
90
91 static guint signals[SIGNAL_LAST] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE(CdProfile,cd_profile,G_TYPE_OBJECT)92 G_DEFINE_TYPE_WITH_PRIVATE (CdProfile, cd_profile, G_TYPE_OBJECT)
93
94 /**
95 * cd_profile_error_quark:
96 **/
97 GQuark
98 cd_profile_error_quark (void)
99 {
100 guint i;
101 static GQuark quark = 0;
102 if (!quark) {
103 quark = g_quark_from_static_string ("CdProfile");
104 for (i = 0; i < CD_PROFILE_ERROR_LAST; i++) {
105 g_dbus_error_register_error (quark,
106 i,
107 cd_profile_error_to_string (i));
108 }
109 }
110 return quark;
111 }
112
113 /**
114 * cd_profile_get_scope:
115 **/
116 CdObjectScope
cd_profile_get_scope(CdProfile * profile)117 cd_profile_get_scope (CdProfile *profile)
118 {
119 CdProfilePrivate *priv = GET_PRIVATE (profile);
120 g_return_val_if_fail (CD_IS_PROFILE (profile), 0);
121 return priv->object_scope;
122 }
123
124 /**
125 * cd_profile_set_scope:
126 **/
127 void
cd_profile_set_scope(CdProfile * profile,CdObjectScope object_scope)128 cd_profile_set_scope (CdProfile *profile, CdObjectScope object_scope)
129 {
130 CdProfilePrivate *priv = GET_PRIVATE (profile);
131 g_return_if_fail (CD_IS_PROFILE (profile));
132 priv->object_scope = object_scope;
133 }
134
135 /**
136 * cd_profile_get_owner:
137 **/
138 guint
cd_profile_get_owner(CdProfile * profile)139 cd_profile_get_owner (CdProfile *profile)
140 {
141 CdProfilePrivate *priv = GET_PRIVATE (profile);
142 g_return_val_if_fail (CD_IS_PROFILE (profile), G_MAXUINT);
143 return priv->owner;
144 }
145
146 /**
147 * cd_profile_set_owner:
148 **/
149 void
cd_profile_set_owner(CdProfile * profile,guint owner)150 cd_profile_set_owner (CdProfile *profile, guint owner)
151 {
152 CdProfilePrivate *priv = GET_PRIVATE (profile);
153 g_return_if_fail (CD_IS_PROFILE (profile));
154 priv->owner = owner;
155 }
156
157 /**
158 * cd_profile_set_is_system_wide:
159 **/
160 void
cd_profile_set_is_system_wide(CdProfile * profile,gboolean is_system_wide)161 cd_profile_set_is_system_wide (CdProfile *profile, gboolean is_system_wide)
162 {
163 CdProfilePrivate *priv = GET_PRIVATE (profile);
164 g_return_if_fail (CD_IS_PROFILE (profile));
165 priv->is_system_wide = is_system_wide;
166
167 /* by default, prefer systemwide profiles over user profiles */
168 priv->score += 1;
169 }
170
171 /**
172 * cd_profile_get_is_system_wide:
173 **/
174 gboolean
cd_profile_get_is_system_wide(CdProfile * profile)175 cd_profile_get_is_system_wide (CdProfile *profile)
176 {
177 CdProfilePrivate *priv = GET_PRIVATE (profile);
178 g_return_val_if_fail (CD_IS_PROFILE (profile), FALSE);
179 return priv->is_system_wide;
180 }
181
182 /**
183 * cd_profile_get_object_path:
184 **/
185 const gchar *
cd_profile_get_object_path(CdProfile * profile)186 cd_profile_get_object_path (CdProfile *profile)
187 {
188 CdProfilePrivate *priv = GET_PRIVATE (profile);
189 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
190 return priv->object_path;
191 }
192
193 /**
194 * cd_profile_get_id:
195 **/
196 const gchar *
cd_profile_get_id(CdProfile * profile)197 cd_profile_get_id (CdProfile *profile)
198 {
199 CdProfilePrivate *priv = GET_PRIVATE (profile);
200 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
201 return priv->id;
202 }
203
204 /**
205 * cd_profile_set_object_path:
206 **/
207 static void
cd_profile_set_object_path(CdProfile * profile)208 cd_profile_set_object_path (CdProfile *profile)
209 {
210 CdProfilePrivate *priv = GET_PRIVATE (profile);
211 #ifdef HAVE_PWD_H
212 struct passwd *pw;
213 #endif
214 g_autofree gchar *path_tmp = NULL;
215 g_autofree gchar *path_owner = NULL;
216
217 /* append the uid to the object path */
218 #ifdef HAVE_PWD_H
219 pw = getpwuid (priv->owner);
220 if (priv->owner == 0 ||
221 g_strcmp0 (pw->pw_name, DAEMON_USER) == 0) {
222 path_tmp = g_strdup (priv->id);
223 } else {
224 path_tmp = g_strdup_printf ("%s_%s_%u",
225 priv->id,
226 pw->pw_name,
227 priv->owner);
228 }
229 #else
230 if (priv->owner == 0) {
231 path_tmp = g_strdup (priv->id);
232 } else {
233 path_tmp = g_strdup_printf ("%s_%d",
234 priv->id,
235 priv->owner);
236 }
237 #endif
238 /* make sure object path is sane */
239 path_owner = cd_main_ensure_dbus_path (path_tmp);
240
241 priv->object_path = g_build_filename (COLORD_DBUS_PATH,
242 "profiles",
243 path_owner,
244 NULL);
245 }
246
247 /**
248 * cd_profile_set_metadata:
249 **/
250 static void
cd_profile_set_metadata(CdProfile * profile,const gchar * property,const gchar * value)251 cd_profile_set_metadata (CdProfile *profile,
252 const gchar *property,
253 const gchar *value)
254 {
255 CdProfilePrivate *priv = GET_PRIVATE (profile);
256 /* i1Profiler sets this */
257 if (g_strcmp0 (property, "CreatorApp") == 0)
258 property = CD_PROFILE_METADATA_CMF_PRODUCT;
259 g_hash_table_insert (priv->metadata,
260 g_strdup (property),
261 g_strdup (value));
262 }
263
264 /**
265 * cd_profile_set_id:
266 **/
267 void
cd_profile_set_id(CdProfile * profile,const gchar * id)268 cd_profile_set_id (CdProfile *profile, const gchar *id)
269 {
270 CdProfilePrivate *priv = GET_PRIVATE (profile);
271
272 CdStandardSpace standard_space = CD_STANDARD_SPACE_UNKNOWN;
273
274 g_return_if_fail (CD_IS_PROFILE (profile));
275
276 g_free (priv->id);
277 priv->id = g_strdup (id);
278
279 /* all profiles have a score initially */
280 priv->score = 1;
281
282 /* http://www.color.org/srgbprofiles.xalter */
283 if (g_strcmp0 (id, "icc-34562abf994ccd066d2c5721d0d68c5d") == 0) {
284 /* sRGB_v4_ICC_preference */
285 standard_space = CD_STANDARD_SPACE_SRGB;
286 priv->score = 10;
287 }
288 if (g_strcmp0 (id, "icc-fc66337837e2886bfd72e9838228f1b8") == 0) {
289 /* sRGB_v4_ICC_preference_displayclass */
290 standard_space = CD_STANDARD_SPACE_SRGB;
291 priv->score = 8;
292 }
293 if (g_strcmp0 (id, "icc-29f83ddeaff255ae7842fae4ca83390d") == 0) {
294 /* sRGB_IEC61966-2-1_black_scaled */
295 standard_space = CD_STANDARD_SPACE_SRGB;
296 priv->score = 6;
297 }
298 if (g_strcmp0 (id, "icc-c95bd637e95d8a3b0df38f99c1320389") == 0) {
299 /* sRGB_IEC61966-2-1_no_black_scaling */
300 standard_space = CD_STANDARD_SPACE_SRGB;
301 priv->score = 4;
302 }
303
304 /* from http://download.adobe.com/pub/adobe/iccprofiles/ */
305 if (g_strcmp0 (id, "icc-dea88382d899d5f6e573b432473ae138") == 0) {
306 /* AdobeRGB1998 */
307 standard_space = CD_STANDARD_SPACE_ADOBE_RGB;
308 priv->score = 10;
309 }
310 if (g_strcmp0 (id, "icc-91cf26c58e07eda724fdbf3eadce4505") == 0) {
311 /* ColorMatchRGB */
312 standard_space = CD_STANDARD_SPACE_LAST;
313 }
314 if (g_strcmp0 (id, "icc-2e54d10b392cac47226469ba2ea95bd8") == 0) {
315 /* AppleRGB */
316 standard_space = CD_STANDARD_SPACE_LAST;
317 }
318
319 /* add additional metadata to fix the GUIs */
320 if (standard_space != CD_STANDARD_SPACE_UNKNOWN) {
321 cd_profile_set_metadata (profile,
322 CD_PROFILE_METADATA_STANDARD_SPACE,
323 cd_standard_space_to_string (standard_space));
324 cd_profile_set_metadata (profile,
325 CD_PROFILE_METADATA_DATA_SOURCE,
326 CD_PROFILE_METADATA_DATA_SOURCE_STANDARD);
327 }
328
329 /* now calculate this again */
330 cd_profile_set_object_path (profile);
331 }
332
333 /**
334 * cd_profile_get_filename:
335 **/
336 const gchar *
cd_profile_get_filename(CdProfile * profile)337 cd_profile_get_filename (CdProfile *profile)
338 {
339 CdProfilePrivate *priv = GET_PRIVATE (profile);
340 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
341 return priv->filename;
342 }
343
344 /**
345 * cd_profile_dbus_emit_property_changed:
346 **/
347 static void
cd_profile_dbus_emit_property_changed(CdProfile * profile,const gchar * property_name,GVariant * property_value)348 cd_profile_dbus_emit_property_changed (CdProfile *profile,
349 const gchar *property_name,
350 GVariant *property_value)
351 {
352 CdProfilePrivate *priv = GET_PRIVATE (profile);
353 GVariantBuilder builder;
354 GVariantBuilder invalidated_builder;
355
356 /* not yet connected */
357 if (priv->connection == NULL)
358 return;
359
360 /* build the dict */
361 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
362 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
363 g_variant_builder_add (&builder,
364 "{sv}",
365 property_name,
366 property_value);
367 g_dbus_connection_emit_signal (priv->connection,
368 NULL,
369 priv->object_path,
370 "org.freedesktop.DBus.Properties",
371 "PropertiesChanged",
372 g_variant_new ("(sa{sv}as)",
373 COLORD_DBUS_INTERFACE_PROFILE,
374 &builder,
375 &invalidated_builder),
376 NULL);
377 g_variant_builder_clear (&builder);
378 g_variant_builder_clear (&invalidated_builder);
379 }
380
381 /**
382 * cd_profile_dbus_emit_profile_changed:
383 **/
384 static void
cd_profile_dbus_emit_profile_changed(CdProfile * profile)385 cd_profile_dbus_emit_profile_changed (CdProfile *profile)
386 {
387 CdProfilePrivate *priv = GET_PRIVATE (profile);
388
389 /* not yet connected */
390 if (priv->connection == NULL)
391 return;
392
393 /* emit signal */
394 g_debug ("CdProfile: emit Changed on %s",
395 cd_profile_get_object_path (profile));
396 g_dbus_connection_emit_signal (priv->connection,
397 NULL,
398 cd_profile_get_object_path (profile),
399 COLORD_DBUS_INTERFACE_PROFILE,
400 "Changed",
401 NULL,
402 NULL);
403
404 /* emit signal */
405 g_debug ("CdProfile: emit Changed");
406 g_dbus_connection_emit_signal (priv->connection,
407 NULL,
408 COLORD_DBUS_PATH,
409 COLORD_DBUS_INTERFACE,
410 "ProfileChanged",
411 g_variant_new ("(o)",
412 cd_profile_get_object_path (profile)),
413 NULL);
414 }
415
416 /**
417 * cd_profile_install_system_wide:
418 **/
419 static gboolean
cd_profile_install_system_wide(CdProfile * profile,GError ** error)420 cd_profile_install_system_wide (CdProfile *profile, GError **error)
421 {
422 CdProfilePrivate *priv = GET_PRIVATE (profile);
423 gboolean ret = TRUE;
424 g_autoptr(GError) error_local = NULL;
425 g_autofree gchar *basename = NULL;
426 g_autofree gchar *filename = NULL;
427 g_autoptr(GFile) file_dest = NULL;
428 g_autoptr(GFile) file = NULL;
429
430 /* is icc filename set? */
431 if (priv->filename == NULL) {
432 g_set_error (error,
433 CD_PROFILE_ERROR,
434 CD_PROFILE_ERROR_INTERNAL,
435 "icc filename not set");
436 return FALSE;
437 }
438
439 /* is profile already installed in /var/db/color */
440 if (g_str_has_prefix (priv->filename,
441 CD_SYSTEM_PROFILES_DIR)) {
442 g_set_error (error,
443 CD_PROFILE_ERROR,
444 CD_PROFILE_ERROR_ALREADY_INSTALLED,
445 "file %s already installed in /var",
446 priv->filename);
447 return FALSE;
448 }
449
450 /* is profile already installed in /usr/local/share/color */
451 if (g_str_has_prefix (priv->filename,
452 DATADIR "/color")) {
453 g_set_error (error,
454 CD_PROFILE_ERROR,
455 CD_PROFILE_ERROR_ALREADY_INSTALLED,
456 "file %s already installed in /usr",
457 priv->filename);
458 return FALSE;
459 }
460
461 /* copy */
462 basename = g_path_get_basename (priv->filename);
463 filename = g_build_filename (CD_SYSTEM_PROFILES_DIR,
464 basename, NULL);
465 file_dest = g_file_new_for_path (filename);
466
467 /* try to write a mapped file first, else copy the file */
468 if (priv->mapped_file != NULL) {
469 g_debug ("writing mapped file to %s", filename);
470 ret = g_file_replace_contents (file_dest,
471 g_mapped_file_get_contents (priv->mapped_file),
472 g_mapped_file_get_length (priv->mapped_file),
473 NULL,
474 FALSE,
475 G_FILE_CREATE_REPLACE_DESTINATION,
476 NULL,
477 NULL, /* cancellable */
478 &error_local);
479 if (!ret) {
480 g_set_error (error,
481 CD_PROFILE_ERROR,
482 CD_PROFILE_ERROR_FAILED_TO_WRITE,
483 "failed to write mapped file %s: %s",
484 priv->filename,
485 error_local->message);
486 return FALSE;
487 }
488 } else {
489 file = g_file_new_for_path (priv->filename);
490 ret = g_file_copy (file, file_dest, G_FILE_COPY_OVERWRITE,
491 NULL, NULL, NULL, &error_local);
492 if (!ret) {
493 g_set_error (error,
494 CD_PROFILE_ERROR,
495 CD_PROFILE_ERROR_FAILED_TO_WRITE,
496 "failed to copy %s: %s",
497 priv->filename,
498 error_local->message);
499 return FALSE;
500 }
501 }
502 return TRUE;
503 }
504
505 /**
506 * cd_profile_get_metadata_as_variant:
507 **/
508 static GVariant *
cd_profile_get_metadata_as_variant(CdProfile * profile)509 cd_profile_get_metadata_as_variant (CdProfile *profile)
510 {
511 CdProfilePrivate *priv = GET_PRIVATE (profile);
512 GList *l;
513 GVariantBuilder builder;
514 g_autoptr(GList) list = NULL;
515
516 /* do not try to build an empty array */
517 if (g_hash_table_size (priv->metadata) == 0)
518 return g_variant_new_array (G_VARIANT_TYPE ("{ss}"), NULL, 0);
519
520 /* add all the keys in the dictionary to the variant builder */
521 list = g_hash_table_get_keys (priv->metadata);
522 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
523 for (l = list; l != NULL; l = l->next) {
524 g_variant_builder_add (&builder,
525 "{ss}",
526 l->data,
527 g_hash_table_lookup (priv->metadata,
528 l->data));
529 }
530 return g_variant_builder_end (&builder);
531 }
532
533 /**
534 * cd_profile_get_nullable_for_string:
535 **/
536 static GVariant *
cd_profile_get_nullable_for_string(const gchar * value)537 cd_profile_get_nullable_for_string (const gchar *value)
538 {
539 if (value == NULL)
540 return g_variant_new_string ("");
541 return g_variant_new_string (value);
542 }
543
544 /**
545 * cd_profile_set_title:
546 **/
547 static gboolean
cd_profile_set_title(CdProfile * profile,const gchar * value,guint sender_uid,GError ** error)548 cd_profile_set_title (CdProfile *profile,
549 const gchar *value,
550 guint sender_uid,
551 GError **error)
552 {
553 CdProfilePrivate *priv = GET_PRIVATE (profile);
554
555 /* check title is suitable */
556 if (value == NULL || strlen (value) < 3 ||
557 !g_utf8_validate (value, -1, NULL)) {
558 g_set_error (error,
559 CD_CLIENT_ERROR,
560 CD_CLIENT_ERROR_INPUT_INVALID,
561 "'Title' value input invalid: %s", value);
562 return FALSE;
563 }
564
565 /* save in database */
566 return cd_profile_db_set_property (priv->db, priv->id,
567 CD_PROFILE_PROPERTY_TITLE, sender_uid,
568 value, error);
569 }
570
571 /**
572 * cd_profile_set_property_internal:
573 **/
574 gboolean
cd_profile_set_property_internal(CdProfile * profile,const gchar * property,const gchar * value,guint sender_uid,GError ** error)575 cd_profile_set_property_internal (CdProfile *profile,
576 const gchar *property,
577 const gchar *value,
578 guint sender_uid,
579 GError **error)
580 {
581 CdProfilePrivate *priv = GET_PRIVATE (profile);
582
583 /* sanity check the length of the key and value */
584 if (strlen (property) > CD_DBUS_METADATA_KEY_LEN_MAX) {
585 g_set_error_literal (error,
586 CD_CLIENT_ERROR,
587 CD_CLIENT_ERROR_INPUT_INVALID,
588 "metadata key length invalid");
589 return FALSE;
590 }
591 if (value != NULL && strlen (value) > CD_DBUS_METADATA_VALUE_LEN_MAX) {
592 g_set_error_literal (error,
593 CD_CLIENT_ERROR,
594 CD_CLIENT_ERROR_INPUT_INVALID,
595 "metadata value length invalid");
596 return FALSE;
597 }
598
599 if (g_strcmp0 (property, CD_PROFILE_PROPERTY_FILENAME) == 0) {
600 cd_profile_set_filename (profile, value);
601 cd_profile_dbus_emit_property_changed (profile,
602 property,
603 g_variant_new_string (value));
604 } else if (g_strcmp0 (property, CD_PROFILE_PROPERTY_QUALIFIER) == 0) {
605 cd_profile_set_qualifier (profile, value);
606 cd_profile_dbus_emit_property_changed (profile,
607 property,
608 g_variant_new_string (value));
609 } else if (g_strcmp0 (property, CD_PROFILE_PROPERTY_FORMAT) == 0) {
610 cd_profile_set_format (profile, value);
611 cd_profile_dbus_emit_property_changed (profile,
612 property,
613 g_variant_new_string (value));
614 } else if (g_strcmp0 (property, CD_PROFILE_PROPERTY_COLORSPACE) == 0) {
615 priv->colorspace = cd_colorspace_from_string (value);
616 cd_profile_dbus_emit_property_changed (profile,
617 property,
618 g_variant_new_string (value));
619 } else if (g_strcmp0 (property, CD_PROFILE_PROPERTY_TITLE) == 0) {
620 if (!cd_profile_set_title (profile, value, sender_uid, error))
621 return FALSE;
622 cd_profile_dbus_emit_property_changed (profile, property,
623 g_variant_new_string (value));
624 } else {
625 /* add to metadata */
626 cd_profile_set_metadata (profile, property, value);
627 cd_profile_dbus_emit_property_changed (profile,
628 CD_PROFILE_PROPERTY_METADATA,
629 cd_profile_get_metadata_as_variant (profile));
630 return TRUE;
631 }
632
633 /* emit global signal */
634 cd_profile_dbus_emit_profile_changed (profile);
635 return TRUE;
636 }
637
638 /**
639 * cd_profile_dbus_method_call:
640 **/
641 static void
cd_profile_dbus_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)642 cd_profile_dbus_method_call (GDBusConnection *connection, const gchar *sender,
643 const gchar *object_path, const gchar *interface_name,
644 const gchar *method_name, GVariant *parameters,
645 GDBusMethodInvocation *invocation, gpointer user_data)
646 {
647 CdProfile *profile = CD_PROFILE (user_data);
648 CdProfilePrivate *priv = GET_PRIVATE (profile);
649 gboolean ret;
650 guint uid;
651 const gchar *property_name = NULL;
652 const gchar *property_value = NULL;
653 g_autoptr(GError) error = NULL;
654
655 /* return '' */
656 if (g_strcmp0 (method_name, "SetProperty") == 0) {
657
658 /* require auth */
659 ret = cd_main_sender_authenticated (connection,
660 sender,
661 "org.freedesktop.color-manager.modify-profile",
662 &error);
663 if (!ret) {
664 g_dbus_method_invocation_return_error (invocation,
665 CD_PROFILE_ERROR,
666 CD_PROFILE_ERROR_FAILED_TO_AUTHENTICATE,
667 "%s", error->message);
668 return;
669 }
670
671 /* get UID */
672 uid = cd_main_get_sender_uid (connection, sender, &error);
673 if (uid == G_MAXUINT) {
674 g_dbus_method_invocation_return_error (invocation,
675 CD_PROFILE_ERROR,
676 CD_PROFILE_ERROR_FAILED_TO_GET_UID,
677 "%s", error->message);
678 return;
679 }
680
681 /* set, and parse */
682 g_variant_get (parameters, "(&s&s)",
683 &property_name,
684 &property_value);
685 g_debug ("CdProfile %s:SetProperty(%s,%s)",
686 sender, property_name, property_value);
687 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_FILENAME) == 0) {
688 g_dbus_method_invocation_return_error (invocation,
689 CD_PROFILE_ERROR,
690 CD_PROFILE_ERROR_PROPERTY_INVALID,
691 "Setting the %s property after "
692 "profile creation is no longer supported",
693 property_name);
694 return;
695 }
696 ret = cd_profile_set_property_internal (profile,
697 property_name,
698 property_value,
699 uid,
700 &error);
701 if (!ret) {
702 g_dbus_method_invocation_return_gerror (invocation, error);
703 return;
704 }
705 g_dbus_method_invocation_return_value (invocation, NULL);
706 return;
707 }
708
709 /* return '' */
710 if (g_strcmp0 (method_name, "InstallSystemWide") == 0) {
711
712 /* require auth */
713 g_debug ("CdProfile %s:InstallSystemWide() on %s",
714 sender, priv->object_path);
715 ret = cd_main_sender_authenticated (connection,
716 sender,
717 "org.freedesktop.color-manager.install-system-wide",
718 &error);
719 if (!ret) {
720 g_dbus_method_invocation_return_error (invocation,
721 CD_PROFILE_ERROR,
722 CD_PROFILE_ERROR_FAILED_TO_AUTHENTICATE,
723 "%s", error->message);
724 return;
725 }
726
727 /* copy systemwide */
728 ret = cd_profile_install_system_wide (profile, &error);
729 if (!ret) {
730 g_dbus_method_invocation_return_gerror (invocation, error);
731 return;
732 }
733
734 g_dbus_method_invocation_return_value (invocation, NULL);
735 return;
736 }
737
738
739 /* we suck */
740 g_critical ("failed to process method %s", method_name);
741 }
742
743 /**
744 * cd_profile_dbus_get_property:
745 **/
746 static GVariant *
cd_profile_dbus_get_property(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * property_name,GError ** error,gpointer user_data)747 cd_profile_dbus_get_property (GDBusConnection *connection, const gchar *sender,
748 const gchar *object_path, const gchar *interface_name,
749 const gchar *property_name, GError **error,
750 gpointer user_data)
751 {
752 CdProfile *profile = CD_PROFILE (user_data);
753 CdProfilePrivate *priv = GET_PRIVATE (profile);
754 gboolean ret;
755
756 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_TITLE) == 0) {
757 guint uid;
758 g_autofree gchar *title_db = NULL;
759
760 uid = cd_main_get_sender_uid (connection, sender, error);
761 if (uid == G_MAXUINT)
762 return NULL;
763 ret = cd_profile_db_get_property (priv->db, priv->id,
764 property_name, uid,
765 &title_db, error);
766 if (!ret)
767 return NULL;
768 if (title_db != NULL)
769 return cd_profile_get_nullable_for_string (title_db);
770 return cd_profile_get_nullable_for_string (priv->title);
771 }
772 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_ID) == 0)
773 return cd_profile_get_nullable_for_string (priv->id);
774 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_QUALIFIER) == 0)
775 return cd_profile_get_nullable_for_string (priv->qualifier);
776 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_FORMAT) == 0)
777 return cd_profile_get_nullable_for_string (priv->format);
778 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_FILENAME) == 0)
779 return cd_profile_get_nullable_for_string (priv->filename);
780 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_KIND) == 0)
781 return g_variant_new_string (cd_profile_kind_to_string (priv->kind));
782 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_COLORSPACE) == 0)
783 return g_variant_new_string (cd_colorspace_to_string (priv->colorspace));
784 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_HAS_VCGT) == 0)
785 return g_variant_new_boolean (priv->has_vcgt);
786 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_IS_SYSTEM_WIDE) == 0)
787 return g_variant_new_boolean (priv->is_system_wide);
788 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_METADATA) == 0)
789 return cd_profile_get_metadata_as_variant (profile);
790 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_CREATED) == 0)
791 return g_variant_new_int64 (priv->created);
792 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_SCOPE) == 0)
793 return g_variant_new_string (cd_object_scope_to_string (priv->object_scope));
794 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_OWNER) == 0)
795 return g_variant_new_uint32 (priv->owner);
796 if (g_strcmp0 (property_name, CD_PROFILE_PROPERTY_WARNINGS) == 0) {
797 if (priv->warnings == NULL) {
798 const gchar *tmp[] = { NULL };
799 return g_variant_new_strv (tmp, -1);
800 }
801 return g_variant_new_strv ((const gchar * const *) priv->warnings, -1);
802 }
803
804 /* return an error */
805 g_set_error (error,
806 CD_PROFILE_ERROR,
807 CD_PROFILE_ERROR_INTERNAL,
808 "failed to get profile property %s",
809 property_name);
810 return NULL;
811 }
812
813 /**
814 * cd_profile_register_object:
815 **/
816 gboolean
cd_profile_register_object(CdProfile * profile,GDBusConnection * connection,GDBusInterfaceInfo * info,GError ** error)817 cd_profile_register_object (CdProfile *profile,
818 GDBusConnection *connection,
819 GDBusInterfaceInfo *info,
820 GError **error)
821 {
822 CdProfilePrivate *priv = GET_PRIVATE (profile);
823 g_autoptr(GError) error_local = NULL;
824
825 static const GDBusInterfaceVTable interface_vtable = {
826 cd_profile_dbus_method_call,
827 cd_profile_dbus_get_property,
828 NULL
829 };
830
831 priv->connection = connection;
832 priv->registration_id = g_dbus_connection_register_object (
833 connection,
834 priv->object_path,
835 info,
836 &interface_vtable,
837 profile, /* user_data */
838 NULL, /* user_data_free_func */
839 &error_local); /* GError** */
840 if (priv->registration_id == 0) {
841 g_set_error (error,
842 CD_PROFILE_ERROR,
843 CD_PROFILE_ERROR_INTERNAL,
844 "failed to register object: %s",
845 error_local->message);
846 return FALSE;
847 }
848 return TRUE;
849 }
850
851 /**
852 * cd_profile_fixup_title:
853 **/
854 static gchar *
cd_profile_fixup_title(const gchar * text)855 cd_profile_fixup_title (const gchar *text)
856 {
857 gchar *title;
858 gchar *tmp;
859 guint len;
860
861 /* nothing set */
862 if (text == NULL)
863 return NULL;
864
865 /* remove the hardcoded confusing title */
866 if (g_str_has_prefix (text, "Default, "))
867 text += 9;
868 title = g_strdup (text);
869
870 /* hack to make old profiles look nice */
871 tmp = g_strstr_len (title, -1, " (201");
872 if (tmp != NULL)
873 *tmp = '\0';
874
875 /* make underscores into spaces */
876 g_strdelimit (title, "_", ' ');
877
878 /* remove any shitty suffix */
879 if (g_str_has_suffix (title, ".icc") ||
880 g_str_has_suffix (title, ".ICC") ||
881 g_str_has_suffix (title, ".icm") ||
882 g_str_has_suffix (title, ".ICM")) {
883 len = strlen (title);
884 if (len > 4)
885 title[len - 4] = '\0';
886 }
887 return title;
888 }
889
890 /**
891 * cd_profile_set_from_profile:
892 **/
893 static gboolean
cd_profile_set_from_profile(CdProfile * profile,CdIcc * icc,GError ** error)894 cd_profile_set_from_profile (CdProfile *profile, CdIcc *icc, GError **error)
895 {
896 CdProfilePrivate *priv = GET_PRIVATE (profile);
897 CdProfileWarning warning;
898 GList *l;
899 cmsHPROFILE lcms_profile;
900 const gchar *key;
901 const gchar *value;
902 gboolean ret = FALSE;
903 guint i;
904 struct tm created;
905 g_autoptr(GArray) flags = NULL;
906 g_autoptr(GHashTable) metadata = NULL;
907 g_autoptr(GList) keys = NULL;
908
909 /* get the description as the title */
910 value = cd_icc_get_description (icc, NULL, error);
911 if (value == NULL)
912 return FALSE;
913 priv->title = cd_profile_fixup_title (value);
914
915 /* get the profile kind */
916 priv->kind = cd_icc_get_kind (icc);
917 priv->colorspace = cd_icc_get_colorspace (icc);
918
919 /* get metadata */
920 metadata = cd_icc_get_metadata (icc);
921 keys = g_hash_table_get_keys (metadata);
922 for (l = keys; l != NULL; l = l->next) {
923 key = l->data;
924 value = g_hash_table_lookup (metadata, key);
925 g_debug ("Adding metadata %s=%s", key, value);
926 g_hash_table_insert (priv->metadata,
927 g_strdup (key),
928 g_strdup (value));
929 }
930
931 /* set the format from the metadata */
932 value = g_hash_table_lookup (priv->metadata,
933 CD_PROFILE_METADATA_MAPPING_FORMAT);
934 if (value != NULL)
935 cd_profile_set_format (profile, value);
936
937 /* set the qualifier from the metadata */
938 value = g_hash_table_lookup (priv->metadata,
939 CD_PROFILE_METADATA_MAPPING_QUALIFIER);
940 if (value != NULL)
941 cd_profile_set_qualifier (profile, value);
942
943 /* set a generic qualifier if there was nothing set before */
944 if (priv->colorspace == CD_COLORSPACE_RGB &&
945 priv->qualifier == NULL) {
946 cd_profile_set_format (profile, "ColorSpace..");
947 cd_profile_set_qualifier (profile, "RGB..");
948 }
949
950 /* get the profile created time and date */
951 lcms_profile = cd_icc_get_handle (icc);
952 ret = cmsGetHeaderCreationDateTime (lcms_profile, &created);
953 if (ret) {
954 created.tm_isdst = -1;
955 priv->created = mktime (&created);
956 } else {
957 g_warning ("failed to get created time");
958 priv->created = 0;
959 }
960
961 /* do we have vcgt */
962 priv->has_vcgt = cmsIsTag (lcms_profile, cmsSigVcgtTag);
963
964 /* get the checksum for the profile if we can */
965 priv->checksum = g_strdup (cd_icc_get_checksum (icc));
966
967 /* get any warnings for the profile */
968 flags = cd_icc_get_warnings (icc);
969 priv->warnings = g_new0 (gchar *, flags->len + 1);
970 if (flags->len > 0) {
971 for (i = 0; i < flags->len; i++) {
972 warning = g_array_index (flags, CdProfileWarning, i);
973 priv->warnings[i] = g_strdup (cd_profile_warning_to_string (warning));
974 }
975 }
976 return TRUE;
977 }
978
979 /**
980 * cd_profile_get_warnings:
981 **/
982 const gchar **
cd_profile_get_warnings(CdProfile * profile)983 cd_profile_get_warnings (CdProfile *profile)
984 {
985 CdProfilePrivate *priv = GET_PRIVATE (profile);
986 return (const gchar **) priv->warnings;
987 }
988
989 /**
990 * cd_profile_emit_parsed_property_changed:
991 **/
992 static void
cd_profile_emit_parsed_property_changed(CdProfile * profile)993 cd_profile_emit_parsed_property_changed (CdProfile *profile)
994 {
995 CdProfilePrivate *priv = GET_PRIVATE (profile);
996
997 cd_profile_dbus_emit_property_changed (profile,
998 CD_PROFILE_PROPERTY_FILENAME,
999 cd_profile_get_nullable_for_string (priv->filename));
1000 cd_profile_dbus_emit_property_changed (profile,
1001 CD_PROFILE_PROPERTY_TITLE,
1002 cd_profile_get_nullable_for_string (priv->title));
1003 cd_profile_dbus_emit_property_changed (profile,
1004 CD_PROFILE_PROPERTY_KIND,
1005 g_variant_new_string (cd_profile_kind_to_string (priv->kind)));
1006 cd_profile_dbus_emit_property_changed (profile,
1007 CD_PROFILE_PROPERTY_COLORSPACE,
1008 g_variant_new_string (cd_colorspace_to_string (priv->colorspace)));
1009 cd_profile_dbus_emit_property_changed (profile,
1010 CD_PROFILE_PROPERTY_HAS_VCGT,
1011 g_variant_new_boolean (priv->has_vcgt));
1012 cd_profile_dbus_emit_property_changed (profile,
1013 CD_PROFILE_PROPERTY_METADATA,
1014 cd_profile_get_metadata_as_variant (profile));
1015 cd_profile_dbus_emit_property_changed (profile,
1016 CD_PROFILE_PROPERTY_QUALIFIER,
1017 cd_profile_get_nullable_for_string (priv->qualifier));
1018 cd_profile_dbus_emit_property_changed (profile,
1019 CD_PROFILE_PROPERTY_FORMAT,
1020 cd_profile_get_nullable_for_string (priv->format));
1021 cd_profile_dbus_emit_property_changed (profile,
1022 CD_PROFILE_PROPERTY_CREATED,
1023 g_variant_new_int64 (priv->created));
1024 }
1025
1026 /**
1027 * cd_profile_load_from_icc:
1028 **/
1029 gboolean
cd_profile_load_from_icc(CdProfile * profile,CdIcc * icc,GError ** error)1030 cd_profile_load_from_icc (CdProfile *profile, CdIcc *icc, GError **error)
1031 {
1032 g_return_val_if_fail (CD_IS_PROFILE (profile), FALSE);
1033
1034 /* save filename */
1035 cd_profile_set_filename (profile, cd_icc_get_filename (icc));
1036
1037 /* set the virtual profile from the lcms profile */
1038 if (!cd_profile_set_from_profile (profile, icc, error))
1039 return FALSE;
1040
1041 /* emit all the things that could have changed */
1042 cd_profile_emit_parsed_property_changed (profile);
1043 return TRUE;
1044 }
1045
1046 /**
1047 * cd_profile_load_from_fd:
1048 **/
1049 gboolean
cd_profile_load_from_fd(CdProfile * profile,gint fd,GError ** error)1050 cd_profile_load_from_fd (CdProfile *profile,
1051 gint fd,
1052 GError **error)
1053 {
1054 CdProfilePrivate *priv = GET_PRIVATE (profile);
1055 gboolean ret;
1056 g_autoptr(GError) error_local = NULL;
1057 g_autoptr(CdIcc) icc = NULL;
1058
1059 g_return_val_if_fail (CD_IS_PROFILE (profile), FALSE);
1060
1061 /* check we're not already set */
1062 if (priv->kind != CD_PROFILE_KIND_UNKNOWN) {
1063 g_set_error (error,
1064 CD_PROFILE_ERROR,
1065 CD_PROFILE_ERROR_INTERNAL,
1066 "profile '%s' already set",
1067 priv->object_path);
1068 return FALSE;
1069 }
1070
1071 /* open fd and parse the file */
1072 icc = cd_icc_new ();
1073 ret = cd_icc_load_fd (icc, fd,
1074 CD_ICC_LOAD_FLAGS_METADATA,
1075 &error_local);
1076 if (!ret) {
1077 g_set_error_literal (error,
1078 CD_PROFILE_ERROR,
1079 CD_PROFILE_ERROR_FAILED_TO_READ,
1080 error_local->message);
1081 return FALSE;
1082 }
1083
1084 /* create a mapped file */
1085 priv->mapped_file = g_mapped_file_new_from_fd (fd, FALSE, error);
1086 if (priv->mapped_file == NULL) {
1087 g_set_error (error,
1088 CD_PROFILE_ERROR,
1089 CD_PROFILE_ERROR_FAILED_TO_READ,
1090 "failed to create mapped file from fd %i",
1091 fd);
1092 return FALSE;
1093 }
1094
1095 /* set the virtual profile from the lcms profile */
1096 if (!cd_profile_set_from_profile (profile, icc, error))
1097 return FALSE;
1098
1099 /* emit all the things that could have changed */
1100 cd_profile_emit_parsed_property_changed (profile);
1101 return TRUE;
1102 }
1103
1104 /**
1105 * cd_profile_load_from_filename:
1106 **/
1107 gboolean
cd_profile_load_from_filename(CdProfile * profile,const gchar * filename,GError ** error)1108 cd_profile_load_from_filename (CdProfile *profile, const gchar *filename, GError **error)
1109 {
1110 CdProfilePrivate *priv = GET_PRIVATE (profile);
1111 gboolean ret = FALSE;
1112 g_autoptr(GError) error_local = NULL;
1113 g_autoptr(CdIcc) icc = NULL;
1114 g_autoptr(GFile) file = NULL;
1115
1116 g_return_val_if_fail (CD_IS_PROFILE (profile), FALSE);
1117
1118 /* check we're not already set */
1119 if (priv->kind != CD_PROFILE_KIND_UNKNOWN) {
1120 g_set_error (error,
1121 CD_PROFILE_ERROR,
1122 CD_PROFILE_ERROR_INTERNAL,
1123 "profile '%s' already set",
1124 priv->object_path);
1125 return FALSE;
1126 }
1127
1128 /* open fd and parse the file */
1129 icc = cd_icc_new ();
1130 file = g_file_new_for_path (filename);
1131 ret = cd_icc_load_file (icc, file,
1132 CD_ICC_LOAD_FLAGS_METADATA,
1133 NULL,
1134 &error_local);
1135 if (!ret) {
1136 g_set_error_literal (error,
1137 CD_PROFILE_ERROR,
1138 CD_PROFILE_ERROR_FAILED_TO_READ,
1139 error_local->message);
1140 return FALSE;
1141 }
1142
1143 /* create a mapped file */
1144 priv->mapped_file = g_mapped_file_new (filename, FALSE, error);
1145 if (priv->mapped_file == NULL) {
1146 g_set_error (error,
1147 CD_PROFILE_ERROR,
1148 CD_PROFILE_ERROR_FAILED_TO_READ,
1149 "failed to create mapped file from filname %s",
1150 filename);
1151 return FALSE;
1152 }
1153
1154 /* set the virtual profile from the lcms profile */
1155 if (!cd_profile_set_from_profile (profile, icc, error))
1156 return FALSE;
1157
1158 /* emit all the things that could have changed */
1159 cd_profile_emit_parsed_property_changed (profile);
1160 return TRUE;
1161 }
1162
1163 /**
1164 * cd_profile_get_qualifier:
1165 **/
1166 const gchar *
cd_profile_get_qualifier(CdProfile * profile)1167 cd_profile_get_qualifier (CdProfile *profile)
1168 {
1169 CdProfilePrivate *priv = GET_PRIVATE (profile);
1170 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
1171 return priv->qualifier;
1172 }
1173
1174 /**
1175 * cd_profile_set_qualifier:
1176 **/
1177 void
cd_profile_set_qualifier(CdProfile * profile,const gchar * qualifier)1178 cd_profile_set_qualifier (CdProfile *profile, const gchar *qualifier)
1179 {
1180 CdProfilePrivate *priv = GET_PRIVATE (profile);
1181 g_return_if_fail (CD_IS_PROFILE (profile));
1182 g_free (priv->qualifier);
1183 priv->qualifier = g_strdup (qualifier);
1184 }
1185
1186 /**
1187 * cd_profile_set_format:
1188 **/
1189 void
cd_profile_set_format(CdProfile * profile,const gchar * format)1190 cd_profile_set_format (CdProfile *profile, const gchar *format)
1191 {
1192 CdProfilePrivate *priv = GET_PRIVATE (profile);
1193 g_return_if_fail (CD_IS_PROFILE (profile));
1194 g_free (priv->format);
1195 priv->format = g_strdup (format);
1196 }
1197
1198 /**
1199 * cd_profile_set_filename:
1200 **/
1201 static void
cd_profile_set_filename(CdProfile * profile,const gchar * filename)1202 cd_profile_set_filename (CdProfile *profile, const gchar *filename)
1203 {
1204 CdProfilePrivate *priv = GET_PRIVATE (profile);
1205 g_return_if_fail (CD_IS_PROFILE (profile));
1206 g_free (priv->filename);
1207 priv->filename = g_strdup (filename);
1208 }
1209
1210 /**
1211 * cd_profile_get_title:
1212 **/
1213 const gchar *
cd_profile_get_title(CdProfile * profile)1214 cd_profile_get_title (CdProfile *profile)
1215 {
1216 CdProfilePrivate *priv = GET_PRIVATE (profile);
1217 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
1218 return priv->title;
1219 }
1220
1221 /**
1222 * cd_profile_get_metadata:
1223 **/
1224 GHashTable *
cd_profile_get_metadata(CdProfile * profile)1225 cd_profile_get_metadata (CdProfile *profile)
1226 {
1227 CdProfilePrivate *priv = GET_PRIVATE (profile);
1228 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
1229 return priv->metadata;
1230 }
1231
1232 /**
1233 * cd_profile_get_metadata_item:
1234 **/
1235 const gchar *
cd_profile_get_metadata_item(CdProfile * profile,const gchar * key)1236 cd_profile_get_metadata_item (CdProfile *profile, const gchar *key)
1237 {
1238 CdProfilePrivate *priv = GET_PRIVATE (profile);
1239 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
1240 return g_hash_table_lookup (priv->metadata, key);
1241 }
1242
1243 /**
1244 * cd_profile_get_score:
1245 *
1246 * Profiles from official vendors such as http://www.color.org/ should be
1247 * more important than profiles generated from source data.
1248 *
1249 * Return value: A number which corresponds to the importance of the profile,
1250 * where larger numbers have more importance than lower numbers.
1251 **/
1252 guint
cd_profile_get_score(CdProfile * profile)1253 cd_profile_get_score (CdProfile *profile)
1254 {
1255 CdProfilePrivate *priv = GET_PRIVATE (profile);
1256 g_return_val_if_fail (CD_IS_PROFILE (profile), 0);
1257 return priv->score;
1258 }
1259
1260 /**
1261 * cd_profile_get_kind:
1262 **/
1263 CdProfileKind
cd_profile_get_kind(CdProfile * profile)1264 cd_profile_get_kind (CdProfile *profile)
1265 {
1266 CdProfilePrivate *priv = GET_PRIVATE (profile);
1267 g_return_val_if_fail (CD_IS_PROFILE (profile), 0);
1268 return priv->kind;
1269 }
1270
1271 /**
1272 * cd_profile_get_colorspace:
1273 **/
1274 CdColorspace
cd_profile_get_colorspace(CdProfile * profile)1275 cd_profile_get_colorspace (CdProfile *profile)
1276 {
1277 CdProfilePrivate *priv = GET_PRIVATE (profile);
1278 g_return_val_if_fail (CD_IS_PROFILE (profile), 0);
1279 return priv->colorspace;
1280 }
1281
1282 /**
1283 * cd_profile_get_has_vcgt:
1284 **/
1285 gboolean
cd_profile_get_has_vcgt(CdProfile * profile)1286 cd_profile_get_has_vcgt (CdProfile *profile)
1287 {
1288 CdProfilePrivate *priv = GET_PRIVATE (profile);
1289 g_return_val_if_fail (CD_IS_PROFILE (profile), FALSE);
1290 return priv->has_vcgt;
1291 }
1292
1293 /**
1294 * cd_profile_get_checksum:
1295 **/
1296 const gchar *
cd_profile_get_checksum(CdProfile * profile)1297 cd_profile_get_checksum (CdProfile *profile)
1298 {
1299 CdProfilePrivate *priv = GET_PRIVATE (profile);
1300 g_return_val_if_fail (CD_IS_PROFILE (profile), NULL);
1301 return priv->checksum;
1302 }
1303
1304 /**
1305 * cd_profile_name_vanished_cb:
1306 **/
1307 static void
cd_profile_name_vanished_cb(GDBusConnection * connection,const gchar * name,gpointer user_data)1308 cd_profile_name_vanished_cb (GDBusConnection *connection,
1309 const gchar *name,
1310 gpointer user_data)
1311 {
1312 CdProfile *profile = CD_PROFILE (user_data);
1313 g_debug ("CdProfile: emit 'invalidate' as %s vanished", name);
1314 g_signal_emit (profile, signals[SIGNAL_INVALIDATE], 0);
1315 }
1316
1317 /**
1318 * cd_profile_watch_sender:
1319 **/
1320 void
cd_profile_watch_sender(CdProfile * profile,const gchar * sender)1321 cd_profile_watch_sender (CdProfile *profile, const gchar *sender)
1322 {
1323 CdProfilePrivate *priv = GET_PRIVATE (profile);
1324 g_return_if_fail (CD_IS_PROFILE (profile));
1325 priv->watcher_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
1326 sender,
1327 G_BUS_NAME_WATCHER_FLAGS_NONE,
1328 NULL,
1329 cd_profile_name_vanished_cb,
1330 profile,
1331 NULL);
1332 }
1333
1334 /**
1335 * cd_profile_get_property:
1336 **/
1337 static void
cd_profile_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1338 cd_profile_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1339 {
1340 CdProfile *profile = CD_PROFILE (object);
1341 CdProfilePrivate *priv = GET_PRIVATE (profile);
1342
1343 switch (prop_id) {
1344 case PROP_OBJECT_PATH:
1345 g_value_set_string (value, priv->object_path);
1346 break;
1347 case PROP_ID:
1348 g_value_set_string (value, priv->id);
1349 break;
1350 default:
1351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1352 break;
1353 }
1354 }
1355
1356 /**
1357 * cd_profile_set_property:
1358 **/
1359 static void
cd_profile_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1360 cd_profile_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
1361 {
1362 CdProfile *profile = CD_PROFILE (object);
1363 CdProfilePrivate *priv = GET_PRIVATE (profile);
1364
1365 switch (prop_id) {
1366 case PROP_OBJECT_PATH:
1367 g_free (priv->object_path);
1368 priv->object_path = g_strdup (g_value_get_string (value));
1369 break;
1370 case PROP_ID:
1371 g_free (priv->id);
1372 priv->id = g_strdup (g_value_get_string (value));
1373 break;
1374 default:
1375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1376 break;
1377 }
1378 }
1379
1380 /**
1381 * cd_profile_class_init:
1382 **/
1383 static void
cd_profile_class_init(CdProfileClass * klass)1384 cd_profile_class_init (CdProfileClass *klass)
1385 {
1386 GParamSpec *pspec;
1387 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1388 object_class->finalize = cd_profile_finalize;
1389 object_class->get_property = cd_profile_get_property;
1390 object_class->set_property = cd_profile_set_property;
1391
1392 /**
1393 * CdProfile:object-path:
1394 */
1395 pspec = g_param_spec_string ("object-path", NULL, NULL,
1396 NULL,
1397 G_PARAM_READWRITE);
1398 g_object_class_install_property (object_class, PROP_OBJECT_PATH, pspec);
1399
1400 /**
1401 * CdProfile:id:
1402 */
1403 pspec = g_param_spec_string ("id", NULL, NULL,
1404 NULL,
1405 G_PARAM_READWRITE);
1406 g_object_class_install_property (object_class, PROP_ID, pspec);
1407
1408 /**
1409 * CdProfile::invalidate:
1410 **/
1411 signals[SIGNAL_INVALIDATE] =
1412 g_signal_new ("invalidate",
1413 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
1414 G_STRUCT_OFFSET (CdProfileClass, invalidate),
1415 NULL, NULL, g_cclosure_marshal_VOID__VOID,
1416 G_TYPE_NONE, 0);
1417 }
1418
1419 /**
1420 * cd_profile_init:
1421 **/
1422 static void
cd_profile_init(CdProfile * profile)1423 cd_profile_init (CdProfile *profile)
1424 {
1425 CdProfilePrivate *priv = GET_PRIVATE (profile);
1426 priv->db = cd_profile_db_new ();
1427 priv->metadata = g_hash_table_new_full (g_str_hash,
1428 g_str_equal,
1429 g_free,
1430 g_free);
1431 }
1432
1433 /**
1434 * cd_profile_finalize:
1435 **/
1436 static void
cd_profile_finalize(GObject * object)1437 cd_profile_finalize (GObject *object)
1438 {
1439 CdProfile *profile = CD_PROFILE (object);
1440 CdProfilePrivate *priv = GET_PRIVATE (profile);
1441
1442 if (priv->watcher_id > 0)
1443 g_bus_unwatch_name (priv->watcher_id);
1444 if (priv->registration_id > 0) {
1445 g_dbus_connection_unregister_object (priv->connection,
1446 priv->registration_id);
1447 }
1448 if (priv->mapped_file != NULL)
1449 g_mapped_file_unref (priv->mapped_file);
1450 g_free (priv->filename);
1451 g_free (priv->qualifier);
1452 g_free (priv->format);
1453 g_free (priv->title);
1454 g_free (priv->id);
1455 g_free (priv->checksum);
1456 g_free (priv->object_path);
1457 g_object_unref (priv->db);
1458 g_strfreev (priv->warnings);
1459 g_hash_table_unref (priv->metadata);
1460
1461 G_OBJECT_CLASS (cd_profile_parent_class)->finalize (object);
1462 }
1463
1464 /**
1465 * cd_profile_new:
1466 **/
1467 CdProfile *
cd_profile_new(void)1468 cd_profile_new (void)
1469 {
1470 CdProfile *profile;
1471 profile = g_object_new (CD_TYPE_PROFILE, NULL);
1472 return CD_PROFILE (profile);
1473 }
1474
1475