1 /*
2  * frogr-photoset.c -- An set in frogr (a photoset from flickr)
3  *
4  * Copyright (C) 2010-2020 Mario Sanchez Prada
5  * Authors: Mario Sanchez Prada <msanchez@gnome.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 3 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>
18  *
19  * Parts of this file based on code from GConf, licensed as GPL
20  * version 2 or later (Copyright (C) 1999, 2000 Red Hat Inc)
21  */
22 
23 #include "frogr-photoset.h"
24 
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 struct _FrogrPhotoSet
29 {
30   GObject parent;
31 
32   gchar *title;
33   gchar *description;
34   gchar *id;
35   gchar *local_id; /* For locally created sets only */
36   gchar *primary_photo_id;
37   gint n_photos;
38 };
39 
40 G_DEFINE_TYPE (FrogrPhotoSet, frogr_photoset, G_TYPE_OBJECT)
41 
42 
43 /* Properties */
44 enum  {
45   PROP_0,
46   PROP_TITLE,
47   PROP_DESCRIPTION,
48   PROP_ID,
49   PROP_LOCAL_ID,
50   PROP_PRIMARY_PHOTO_ID,
51   PROP_N_PHOTOS
52 };
53 
54 /* Prototypes */
55 
56 static gchar *_create_temporary_id_for_photoset (void);
57 
58 
59 /* Private API */
60 
61 /* The following function is based in gconf_unique_key(), licensed as
62    GPL version 2 or later (Copyright (C) 1999, 2000 Red Hat Inc) */
63 static gchar *
_create_temporary_id_for_photoset(void)64 _create_temporary_id_for_photoset (void)
65 {
66   /* This function is hardly cryptographically random but should be
67      "good enough" */
68   static guint serial = 0;
69   gchar* key;
70   gint64 tv, t, ut;
71   pid_t p;
72   uid_t u;
73   guint32 r;
74 
75   tv = g_get_real_time ();
76 
77   t = tv / G_USEC_PER_SEC;
78   ut = tv;
79 
80   p = getpid();
81   u = getuid();
82 
83   /* don't bother to seed; if it's based on the time or any other
84      changing info we can get, we may as well just use that changing
85      info. since we don't seed we'll at least get a different number
86      on every call to this function in the same executable. */
87   r = g_random_int();
88 
89   /* The letters may increase uniqueness by preventing "melds"
90      i.e. 01t01k01 and 0101t0k1 are not the same */
91   key = g_strdup_printf("%" G_GUINT32_FORMAT "t"
92                         "%" G_GINT64_FORMAT "ut"
93                         "%" G_GINT64_FORMAT "u"
94                         "%" G_GUINT32_FORMAT "p"
95                         "%" G_GINT32_FORMAT "r"
96                         "%" G_GUINT32_FORMAT "k"
97                         "%" G_GUINT32_FORMAT,
98                         /* Duplicate keys must be generated
99                            by two different program instances */
100                         serial,
101                         /* Duplicate keys must be generated
102                            in the same microsecond */
103                         t,
104                         ut,
105                         /* Duplicate keys must be generated by
106                            the same user */
107                         u,
108                         /* Duplicate keys must be generated by
109                            two programs that got the same PID */
110                         p,
111                         /* Duplicate keys must be generated with the
112                            same random seed and the same index into
113                            the series of pseudorandom values */
114                         r,
115                         /* Duplicate keys must result from running
116                            this function at the same stack location */
117                         GPOINTER_TO_UINT(&key));
118   ++serial;
119 
120   return key;
121 }
122 
123 static void
_frogr_photoset_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)124 _frogr_photoset_set_property (GObject *object,
125                               guint prop_id,
126                               const GValue *value,
127                               GParamSpec *pspec)
128 {
129   FrogrPhotoSet *self = FROGR_PHOTOSET (object);
130 
131   switch (prop_id)
132     {
133     case PROP_TITLE:
134       frogr_photoset_set_title (self, g_value_get_string (value));
135       break;
136     case PROP_DESCRIPTION:
137       frogr_photoset_set_description (self, g_value_get_string (value));
138       break;
139     case PROP_ID:
140       frogr_photoset_set_id (self, g_value_get_string (value));
141       break;
142     case PROP_LOCAL_ID:
143       frogr_photoset_set_local_id (self, g_value_get_string (value));
144       break;
145     case PROP_PRIMARY_PHOTO_ID:
146       frogr_photoset_set_primary_photo_id (self, g_value_get_string (value));
147       break;
148     case PROP_N_PHOTOS:
149       frogr_photoset_set_n_photos (self, g_value_get_int (value));
150       break;
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153       break;
154     }
155 }
156 
157 static void
_frogr_photoset_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)158 _frogr_photoset_get_property (GObject *object,
159                               guint prop_id,
160                               GValue *value,
161                               GParamSpec *pspec)
162 {
163   FrogrPhotoSet *self = FROGR_PHOTOSET (object);
164 
165   switch (prop_id)
166     {
167     case PROP_TITLE:
168       g_value_set_string (value, frogr_photoset_get_title (self));
169       break;
170     case PROP_DESCRIPTION:
171       g_value_set_string (value, frogr_photoset_get_description (self));
172       break;
173     case PROP_ID:
174       g_value_set_string (value, frogr_photoset_get_id (self));
175       break;
176     case PROP_LOCAL_ID:
177       g_value_set_string (value, frogr_photoset_get_local_id (self));
178       break;
179     case PROP_PRIMARY_PHOTO_ID:
180       g_value_set_string (value, frogr_photoset_get_primary_photo_id (self));
181       break;
182     case PROP_N_PHOTOS:
183       g_value_set_int (value, frogr_photoset_get_n_photos (self));
184       break;
185     default:
186       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
187       break;
188     }
189 }
190 
191 static void
_frogr_photoset_finalize(GObject * object)192 _frogr_photoset_finalize (GObject *object)
193 {
194   FrogrPhotoSet *self = FROGR_PHOTOSET (object);
195 
196   /* free strings */
197   g_free (self->title);
198   g_free (self->description);
199   g_free (self->id);
200   g_free (self->local_id);
201   g_free (self->primary_photo_id);
202 
203   /* call super class */
204   G_OBJECT_CLASS (frogr_photoset_parent_class)->finalize(object);
205 }
206 
207 static void
frogr_photoset_class_init(FrogrPhotoSetClass * klass)208 frogr_photoset_class_init(FrogrPhotoSetClass *klass)
209 {
210   GObjectClass *obj_class = G_OBJECT_CLASS(klass);
211 
212   /* GtkObject signals */
213   obj_class->set_property = _frogr_photoset_set_property;
214   obj_class->get_property = _frogr_photoset_get_property;
215   obj_class->finalize = _frogr_photoset_finalize;
216 
217   /* Install properties */
218   g_object_class_install_property (obj_class,
219                                    PROP_TITLE,
220                                    g_param_spec_string ("title",
221                                                         "title",
222                                                         "Set's title",
223                                                         NULL,
224                                                         G_PARAM_READWRITE));
225   g_object_class_install_property (obj_class,
226                                    PROP_DESCRIPTION,
227                                    g_param_spec_string ("description",
228                                                         "description",
229                                                         "Set's description",
230                                                         NULL,
231                                                         G_PARAM_READWRITE));
232   g_object_class_install_property (obj_class,
233                                    PROP_ID,
234                                    g_param_spec_string ("id",
235                                                         "id",
236                                                         "Photoset ID from flickr",
237                                                         NULL,
238                                                         G_PARAM_READWRITE));
239   g_object_class_install_property (obj_class,
240                                    PROP_LOCAL_ID,
241                                    g_param_spec_string ("local-id",
242                                                         "local-id",
243                                                         "Photoset ID locally generated"
244                                                         "(for new sets only)",
245                                                         NULL,
246                                                         G_PARAM_READWRITE));
247   g_object_class_install_property (obj_class,
248                                    PROP_PRIMARY_PHOTO_ID,
249                                    g_param_spec_string ("primary-photo-id",
250                                                         "primary-photo-id",
251                                                         "ID of the primary photo "
252                                                         "for the set",
253                                                         NULL,
254                                                         G_PARAM_READWRITE));
255   g_object_class_install_property (obj_class,
256                                    PROP_N_PHOTOS,
257                                    g_param_spec_int ("n-photos",
258                                                      "n-photos",
259                                                      "Number of photos "
260                                                      "inside the set",
261                                                      0,
262                                                      G_MAXINT,
263                                                      0,
264                                                      G_PARAM_READWRITE));
265 }
266 
267 static void
frogr_photoset_init(FrogrPhotoSet * self)268 frogr_photoset_init (FrogrPhotoSet *self)
269 {
270   /* Default values */
271   self->title = NULL;
272   self->description = NULL;
273   self->id = NULL;
274   self->local_id = NULL;
275   self->primary_photo_id = NULL;
276   self->n_photos = 0;
277 }
278 
279 
280 /* Public API */
281 
282 FrogrPhotoSet *
frogr_photoset_new(const gchar * id,const gchar * title,const gchar * description)283 frogr_photoset_new (const gchar *id,
284                     const gchar *title,
285                     const gchar *description)
286 {
287   g_return_val_if_fail (title, NULL);
288   g_return_val_if_fail (description, NULL);
289 
290   return FROGR_PHOTOSET (g_object_new(FROGR_TYPE_PHOTOSET,
291                                       "id", id,
292                                       "title", title,
293                                       "description", description,
294                                       NULL));
295 }
296 
297 FrogrPhotoSet *
frogr_photoset_new_local(const gchar * title,const gchar * description)298 frogr_photoset_new_local (const gchar *title,
299                           const gchar *description)
300 {
301   FrogrPhotoSet *new_set;
302   g_autofree gchar *id = NULL;
303 
304   g_return_val_if_fail (title, NULL);
305   g_return_val_if_fail (description, NULL);
306 
307   new_set = frogr_photoset_new (NULL, title, description);
308 
309   /* We always need to have an id in locally created photosets */
310   id = _create_temporary_id_for_photoset ();
311   frogr_photoset_set_local_id (new_set, id);
312 
313   return new_set;
314 }
315 
316 /* Data Managing functions */
317 
318 const gchar *
frogr_photoset_get_title(FrogrPhotoSet * self)319 frogr_photoset_get_title (FrogrPhotoSet *self)
320 {
321   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), NULL);
322   return (const gchar *)self->title;
323 }
324 
325 void
frogr_photoset_set_title(FrogrPhotoSet * self,const gchar * title)326 frogr_photoset_set_title (FrogrPhotoSet *self,
327                           const gchar *title)
328 {
329   g_return_if_fail(FROGR_IS_PHOTOSET(self));
330   g_return_if_fail(title != NULL);
331 
332   g_free (self->title);
333   self->title = g_strdup (title);
334 }
335 
336 const gchar *
frogr_photoset_get_description(FrogrPhotoSet * self)337 frogr_photoset_get_description (FrogrPhotoSet *self)
338 {
339   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), NULL);
340   return (const gchar *)self->description;
341 }
342 
343 void
frogr_photoset_set_description(FrogrPhotoSet * self,const gchar * description)344 frogr_photoset_set_description (FrogrPhotoSet *self,
345                                 const gchar *description)
346 {
347   g_return_if_fail(FROGR_IS_PHOTOSET(self));
348   g_free (self->description);
349   self->description = g_strdup (description);
350 }
351 
352 const gchar *
frogr_photoset_get_id(FrogrPhotoSet * self)353 frogr_photoset_get_id (FrogrPhotoSet *self)
354 {
355   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), NULL);
356   return (const gchar *)self->id;
357 }
358 
359 void
frogr_photoset_set_id(FrogrPhotoSet * self,const gchar * id)360 frogr_photoset_set_id (FrogrPhotoSet *self,
361                        const gchar *id)
362 {
363   g_return_if_fail(FROGR_IS_PHOTOSET(self));
364   g_free (self->id);
365   self->id = g_strdup (id);
366 }
367 
368 const gchar *
frogr_photoset_get_local_id(FrogrPhotoSet * self)369 frogr_photoset_get_local_id (FrogrPhotoSet *self)
370 {
371   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), NULL);
372   return (const gchar *)self->local_id;
373 }
374 
375 void
frogr_photoset_set_local_id(FrogrPhotoSet * self,const gchar * id)376 frogr_photoset_set_local_id (FrogrPhotoSet *self,
377                              const gchar *id)
378 {
379   g_return_if_fail(FROGR_IS_PHOTOSET(self));
380   g_free (self->local_id);
381   self->local_id = g_strdup (id);
382 }
383 
384 const gchar *
frogr_photoset_get_primary_photo_id(FrogrPhotoSet * self)385 frogr_photoset_get_primary_photo_id (FrogrPhotoSet *self)
386 {
387   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), NULL);
388   return (const gchar *)self->primary_photo_id;
389 }
390 
391 void
frogr_photoset_set_primary_photo_id(FrogrPhotoSet * self,const gchar * primary_photo_id)392 frogr_photoset_set_primary_photo_id (FrogrPhotoSet *self,
393                                      const gchar *primary_photo_id)
394 {
395   g_return_if_fail(FROGR_IS_PHOTOSET(self));
396   g_free (self->primary_photo_id);
397   self->primary_photo_id = g_strdup (primary_photo_id);
398 }
399 
400 gint
frogr_photoset_get_n_photos(FrogrPhotoSet * self)401 frogr_photoset_get_n_photos (FrogrPhotoSet *self)
402 {
403   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), FALSE);
404   return self->n_photos;
405 }
406 
407 void
frogr_photoset_set_n_photos(FrogrPhotoSet * self,gint n)408 frogr_photoset_set_n_photos (FrogrPhotoSet *self,
409                              gint n)
410 {
411   g_return_if_fail(FROGR_IS_PHOTOSET(self));
412   self->n_photos = n;
413 }
414 
415 gboolean
frogr_photoset_is_local(FrogrPhotoSet * self)416 frogr_photoset_is_local (FrogrPhotoSet *self)
417 {
418   g_return_val_if_fail(FROGR_IS_PHOTOSET(self), FALSE);
419   return self->id == NULL && self->local_id != NULL;
420 }
421 
422 gint
frogr_photoset_compare(FrogrPhotoSet * self,FrogrPhotoSet * other)423 frogr_photoset_compare (FrogrPhotoSet *self, FrogrPhotoSet *other)
424 {
425   g_return_val_if_fail (FROGR_IS_PHOTOSET (self), 1);
426   g_return_val_if_fail (FROGR_IS_PHOTOSET (other), -1);
427 
428   if (self == other)
429     return 0;
430 
431   if (self->id != NULL && other->id != NULL)
432     return g_strcmp0 (self->id, other->id);
433 
434   if (self->local_id != NULL && other->local_id != NULL)
435     return g_strcmp0 (self->local_id, other->local_id);
436 
437   if (self->id != NULL)
438     return 1;
439   else
440     return -1;
441 }
442