rename accountopt.[ch] to purpleaccountoption.[ch]
[pidgin-git.git] / libpurple / image-store.c
blob4c6868fc819779e07d7c068f5cf96c8c1eabf4ca
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
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.
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.
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 02111-1301 USA
22 #include "image-store.h"
24 #include "eventloop.h"
25 #include "glibcompat.h"
26 #include "util.h"
28 #define TEMP_IMAGE_TIMEOUT 5
30 static GHashTable *id_to_image = NULL;
31 static guint last_id = 0;
33 /* keys: timeout handle */
34 static GHashTable *temp_images = NULL;
36 /* keys: img id */
37 static GSList *perm_images = NULL;
39 static void
40 image_reset_id(gpointer _id)
42 g_return_if_fail(id_to_image != NULL);
44 g_hash_table_remove(id_to_image, _id);
47 static guint
48 image_set_id(PurpleImage *image)
50 /* Use the next unused id number. We do it in a loop on the off chance
51 * that next id wraps back around to 0 and the hash table still contains
52 * entries from the first time around.
54 while (TRUE) {
55 last_id++;
57 if (G_UNLIKELY(last_id == 0))
58 continue;
60 if (purple_image_store_get(last_id) == NULL)
61 break;
64 g_object_set_data_full(G_OBJECT(image), "purple-image-store-id",
65 GINT_TO_POINTER(last_id), image_reset_id);
66 g_hash_table_insert(id_to_image, GINT_TO_POINTER(last_id), image);
67 return last_id;
70 static guint
71 image_get_id(PurpleImage *image)
73 return GPOINTER_TO_INT(g_object_get_data(G_OBJECT(image),
74 "purple-image-store-id"));
77 guint
78 purple_image_store_add(PurpleImage *image)
80 guint id;
82 g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0);
84 id = image_get_id(image);
85 if (id > 0)
86 return id;
88 id = image_set_id(image);
90 g_object_ref(image);
91 perm_images = g_slist_prepend(perm_images, image);
93 return id;
96 guint
97 purple_image_store_add_weak(PurpleImage *image)
99 guint id;
101 g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0);
103 id = image_get_id(image);
104 if (id > 0)
105 return id;
107 return image_set_id(image);
110 static gboolean
111 remove_temporary(gpointer _image)
113 PurpleImage *image = _image;
114 guint handle;
116 handle = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(image),
117 "purple-image-store-handle"));
119 g_hash_table_remove(temp_images, GINT_TO_POINTER(handle));
121 return G_SOURCE_REMOVE;
124 static void
125 cancel_temporary(gpointer key, gpointer value, gpointer _unused)
127 g_source_remove(GPOINTER_TO_INT(key));
130 guint
131 purple_image_store_add_temporary(PurpleImage *image)
133 guint id;
134 guint handle;
136 g_return_val_if_fail(PURPLE_IS_IMAGE(image), 0);
138 id = image_get_id(image);
139 /* XXX: add_temporary doesn't extend previous temporary call, sorry */
140 if (id > 0)
141 return id;
143 id = image_set_id(image);
145 g_object_ref(image);
146 handle = g_timeout_add_seconds(TEMP_IMAGE_TIMEOUT,
147 remove_temporary, image);
148 g_object_set_data(G_OBJECT(image), "purple-image-store-handle",
149 GINT_TO_POINTER(handle));
150 g_hash_table_insert(temp_images, GINT_TO_POINTER(handle), image);
152 return id;
155 PurpleImage *
156 purple_image_store_get(guint id)
158 return g_hash_table_lookup(id_to_image, GINT_TO_POINTER(id));
161 /* TODO: handle PURPLE_IMAGE_STORE_STOCK_PROTOCOL */
162 PurpleImage *
163 purple_image_store_get_from_uri(const gchar *uri)
165 guint64 longid;
166 guint id;
167 gchar *endptr;
168 gchar endchar;
170 g_return_val_if_fail(uri != NULL, NULL);
172 if (!purple_str_has_prefix(uri, PURPLE_IMAGE_STORE_PROTOCOL))
173 return NULL;
175 uri += sizeof(PURPLE_IMAGE_STORE_PROTOCOL) - 1;
176 if (uri[0] == '-')
177 return NULL;
179 longid = g_ascii_strtoull(uri, &endptr, 10);
180 endchar = endptr[0];
181 if (endchar != '\0' && endchar != '"' &&
182 endchar != '\'' && endchar != ' ')
184 return NULL;
187 id = longid;
188 if (id != longid)
189 return NULL;
191 return purple_image_store_get(id);
194 gchar *
195 purple_image_store_get_uri(PurpleImage *image)
197 const gchar *path;
198 guint img_id;
200 g_return_val_if_fail(PURPLE_IS_IMAGE(image), NULL);
202 path = purple_image_get_path(image);
204 if (path)
205 return g_filename_to_uri(path, NULL, NULL);
207 img_id = purple_image_store_add_weak(image);
208 return g_strdup_printf(PURPLE_IMAGE_STORE_PROTOCOL "%u", img_id);
211 void
212 _purple_image_store_init(void)
214 id_to_image = g_hash_table_new(g_direct_hash, g_direct_equal);
215 temp_images = g_hash_table_new_full(g_direct_hash, g_direct_equal,
216 NULL, g_object_unref);
219 void
220 _purple_image_store_uninit(void)
222 g_slist_free_full(perm_images, g_object_unref);
223 perm_images = NULL;
225 g_hash_table_foreach(temp_images, cancel_temporary, NULL);
226 g_hash_table_destroy(temp_images);
227 temp_images = NULL;
229 g_hash_table_destroy(id_to_image);
230 id_to_image = NULL;