These changes are reuired to make the Windows installer build.
[pidgin-git.git] / libpurple / smiley.c
blob304d292a476805e33125a7dc587a69e1b78b33c0
1 /**
2 * @file smiley.c Simley API
3 * @ingroup core
4 */
6 /* purple
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 #include "internal.h"
28 #include "dbus-maybe.h"
29 #include "debug.h"
30 #include "imgstore.h"
31 #include "smiley.h"
32 #include "util.h"
33 #include "xmlnode.h"
35 /**************************************************************************/
36 /* Main structures, members and constants */
37 /**************************************************************************/
39 struct _PurpleSmiley
41 GObject parent;
42 PurpleStoredImage *img; /**< The id of the stored image with the
43 the smiley data. */
44 char *shortcut; /**< Shortcut associated with the custom
45 smiley. This field will work as a
46 unique key by this API. */
47 char *checksum; /**< The smiley checksum. */
50 struct _PurpleSmileyClass
52 GObjectClass parent_class;
55 static GHashTable *smiley_shortcut_index = NULL; /* shortcut (char *) => smiley (PurpleSmiley*) */
56 static GHashTable *smiley_checksum_index = NULL; /* checksum (char *) => smiley (PurpleSmiley*) */
58 static guint save_timer = 0;
59 static gboolean smileys_loaded = FALSE;
60 static char *smileys_dir = NULL;
62 #define SMILEYS_DEFAULT_FOLDER "custom_smiley"
63 #define SMILEYS_LOG_ID "smileys"
65 #define XML_FILE_NAME "smileys.xml"
67 #define XML_ROOT_TAG "smileys"
68 #define XML_PROFILE_TAG "profile"
69 #define XML_PROFILE_NAME_ATTRIB_TAG "name"
70 #define XML_ACCOUNT_TAG "account"
71 #define XML_ACCOUNT_USERID_ATTRIB_TAG "userid"
72 #define XML_SMILEY_SET_TAG "smiley_set"
73 #define XML_SMILEY_TAG "smiley"
74 #define XML_SHORTCUT_ATTRIB_TAG "shortcut"
75 #define XML_CHECKSUM_ATRIB_TAG "checksum"
76 #define XML_FILENAME_ATRIB_TAG "filename"
79 /******************************************************************************
80 * XML descriptor file layout *
81 ******************************************************************************
83 * Although we are creating the profile XML structure here, now we
84 * won't handle it.
85 * So, we just add one profile named "default" that has no associated
86 * account elements, and have only the smiley_set that will contain
87 * all existent custom smiley.
89 * It's our "Highlander Profile" :-)
91 ******************************************************************************
93 * <smileys>
94 * <profile name="john.doe">
95 * <account userid="john.doe@jabber.org">
96 * <account userid="john.doe@gmail.com">
97 * <smiley_set>
98 * <smiley shortcut="aaa" checksum="xxxxxxxx" filename="file_name1.gif"/>
99 * <smiley shortcut="bbb" checksum="yyyyyyy" filename="file_name2.gif"/>
100 * </smiley_set>
101 * </profile>
102 * </smiley>
104 *****************************************************************************/
107 /*********************************************************************
108 * Forward declarations *
109 *********************************************************************/
111 static gboolean read_smiley_file(const char *path, guchar **data, size_t *len);
113 static char *get_file_full_path(const char *filename);
115 static PurpleSmiley *purple_smiley_create(const char *shortcut);
117 static PurpleSmiley *purple_smiley_load_file(const char *shortcut, const char *checksum,
118 const char *filename);
120 static void
121 purple_smiley_set_data_impl(PurpleSmiley *smiley, guchar *smiley_data,
122 size_t smiley_data_len);
124 static void
125 purple_smiley_data_store(PurpleStoredImage *stored_img);
127 static void
128 purple_smiley_data_unstore(const char *filename);
130 /*********************************************************************
131 * Writing to disk *
132 *********************************************************************/
134 static xmlnode *
135 smiley_to_xmlnode(PurpleSmiley *smiley)
137 xmlnode *smiley_node = NULL;
139 smiley_node = xmlnode_new(XML_SMILEY_TAG);
141 if (!smiley_node)
142 return NULL;
144 xmlnode_set_attrib(smiley_node, XML_SHORTCUT_ATTRIB_TAG,
145 smiley->shortcut);
147 xmlnode_set_attrib(smiley_node, XML_CHECKSUM_ATRIB_TAG,
148 smiley->checksum);
150 xmlnode_set_attrib(smiley_node, XML_FILENAME_ATRIB_TAG,
151 purple_imgstore_get_filename(smiley->img));
153 return smiley_node;
156 static void
157 add_smiley_to_main_node(gpointer key, gpointer value, gpointer user_data)
159 xmlnode *child_node;
161 child_node = smiley_to_xmlnode(value);
162 xmlnode_insert_child((xmlnode*)user_data, child_node);
165 static xmlnode *
166 smileys_to_xmlnode(void)
168 xmlnode *root_node, *profile_node, *smileyset_node;
170 root_node = xmlnode_new(XML_ROOT_TAG);
171 xmlnode_set_attrib(root_node, "version", "1.0");
173 /* See the top comments above to understand why initial tag elements
174 * are not being considered by now. */
175 profile_node = xmlnode_new(XML_PROFILE_TAG);
176 if (profile_node) {
177 xmlnode_set_attrib(profile_node, XML_PROFILE_NAME_ATTRIB_TAG, "Default");
178 xmlnode_insert_child(root_node, profile_node);
180 smileyset_node = xmlnode_new(XML_SMILEY_SET_TAG);
181 if (smileyset_node) {
182 xmlnode_insert_child(profile_node, smileyset_node);
183 g_hash_table_foreach(smiley_shortcut_index, add_smiley_to_main_node, smileyset_node);
187 return root_node;
190 static void
191 sync_smileys(void)
193 xmlnode *root_node;
194 char *data;
196 if (!smileys_loaded) {
197 purple_debug_error(SMILEYS_LOG_ID, "Attempted to save smileys before it "
198 "was read!\n");
199 return;
202 root_node = smileys_to_xmlnode();
203 data = xmlnode_to_formatted_str(root_node, NULL);
204 purple_util_write_data_to_file(XML_FILE_NAME, data, -1);
206 g_free(data);
207 xmlnode_free(root_node);
210 static gboolean
211 save_smileys_cb(gpointer data)
213 sync_smileys();
214 save_timer = 0;
215 return FALSE;
218 static void
219 purple_smileys_save(void)
221 if (save_timer == 0)
222 save_timer = purple_timeout_add_seconds(5, save_smileys_cb, NULL);
226 /*********************************************************************
227 * Reading from disk *
228 *********************************************************************/
230 static PurpleSmiley *
231 parse_smiley(xmlnode *smiley_node)
233 PurpleSmiley *smiley;
234 const char *shortcut = NULL;
235 const char *checksum = NULL;
236 const char *filename = NULL;
238 shortcut = xmlnode_get_attrib(smiley_node, XML_SHORTCUT_ATTRIB_TAG);
239 checksum = xmlnode_get_attrib(smiley_node, XML_CHECKSUM_ATRIB_TAG);
240 filename = xmlnode_get_attrib(smiley_node, XML_FILENAME_ATRIB_TAG);
242 if ((shortcut == NULL) || (checksum == NULL) || (filename == NULL))
243 return NULL;
245 smiley = purple_smiley_load_file(shortcut, checksum, filename);
247 return smiley;
250 static void
251 purple_smileys_load(void)
253 xmlnode *root_node, *profile_node;
254 xmlnode *smileyset_node = NULL;
255 xmlnode *smiley_node;
257 smileys_loaded = TRUE;
259 root_node = purple_util_read_xml_from_file(XML_FILE_NAME,
260 _(SMILEYS_LOG_ID));
262 if (root_node == NULL)
263 return;
265 /* See the top comments above to understand why initial tag elements
266 * are not being considered by now. */
267 profile_node = xmlnode_get_child(root_node, XML_PROFILE_TAG);
268 if (profile_node)
269 smileyset_node = xmlnode_get_child(profile_node, XML_SMILEY_SET_TAG);
271 if (smileyset_node) {
272 smiley_node = xmlnode_get_child(smileyset_node, XML_SMILEY_TAG);
273 for (; smiley_node != NULL;
274 smiley_node = xmlnode_get_next_twin(smiley_node)) {
275 PurpleSmiley *smiley;
277 smiley = parse_smiley(smiley_node);
281 xmlnode_free(root_node);
284 /*********************************************************************
285 * GObject Stuff *
286 *********************************************************************/
287 enum
289 PROP_0,
290 PROP_SHORTCUT,
291 PROP_IMGSTORE
294 #define PROP_SHORTCUT_S "shortcut"
295 #define PROP_IMGSTORE_S "image"
297 enum
299 SIG_DESTROY,
300 SIG_LAST
303 static guint signals[SIG_LAST];
304 static GObjectClass *parent_class;
306 static void
307 purple_smiley_init(GTypeInstance *instance, gpointer klass)
309 PurpleSmiley *smiley = PURPLE_SMILEY(instance);
310 PURPLE_DBUS_REGISTER_POINTER(smiley, PurpleSmiley);
313 static void
314 purple_smiley_get_property(GObject *object, guint param_id, GValue *value,
315 GParamSpec *spec)
317 PurpleSmiley *smiley = PURPLE_SMILEY(object);
318 switch (param_id) {
319 case PROP_SHORTCUT:
320 g_value_set_string(value, smiley->shortcut);
321 break;
322 case PROP_IMGSTORE:
323 g_value_set_pointer(value, smiley->img);
324 break;
325 default:
326 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, spec);
327 break;
331 static void
332 purple_smiley_set_property(GObject *object, guint param_id, const GValue *value,
333 GParamSpec *spec)
335 PurpleSmiley *smiley = PURPLE_SMILEY(object);
336 switch (param_id) {
337 case PROP_SHORTCUT:
339 const char *shortcut = g_value_get_string(value);
340 purple_smiley_set_shortcut(smiley, shortcut);
342 break;
343 case PROP_IMGSTORE:
345 PurpleStoredImage *img = g_value_get_pointer(value);
347 purple_imgstore_unref(smiley->img);
348 g_free(smiley->checksum);
350 smiley->img = img;
351 if (img) {
352 smiley->checksum = purple_util_get_image_checksum(
353 purple_imgstore_get_data(img),
354 purple_imgstore_get_size(img));
355 purple_smiley_data_store(img);
356 } else {
357 smiley->checksum = NULL;
360 g_object_notify(object, PROP_IMGSTORE_S);
362 break;
363 default:
364 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, spec);
365 break;
369 static void
370 purple_smiley_finalize(GObject *obj)
372 PurpleSmiley *smiley = PURPLE_SMILEY(obj);
374 if (g_hash_table_lookup(smiley_shortcut_index, smiley->shortcut)) {
375 g_hash_table_remove(smiley_shortcut_index, smiley->shortcut);
376 g_hash_table_remove(smiley_checksum_index, smiley->checksum);
379 g_free(smiley->shortcut);
380 g_free(smiley->checksum);
381 if (smiley->img)
382 purple_smiley_data_unstore(purple_imgstore_get_filename(smiley->img));
383 purple_imgstore_unref(smiley->img);
385 PURPLE_DBUS_UNREGISTER_POINTER(smiley);
387 purple_smileys_save();
390 static void
391 purple_smiley_dispose(GObject *gobj)
393 g_signal_emit(gobj, signals[SIG_DESTROY], 0);
394 parent_class->dispose(gobj);
397 static void
398 purple_smiley_class_init(PurpleSmileyClass *klass)
400 GObjectClass *gobj_class = G_OBJECT_CLASS(klass);
401 GParamSpec *pspec;
403 parent_class = g_type_class_peek_parent(klass);
405 gobj_class->get_property = purple_smiley_get_property;
406 gobj_class->set_property = purple_smiley_set_property;
407 gobj_class->finalize = purple_smiley_finalize;
408 gobj_class->dispose = purple_smiley_dispose;
410 /* Shortcut */
411 pspec = g_param_spec_string(PROP_SHORTCUT_S, _("Shortcut"),
412 _("The text-shortcut for the smiley"),
413 NULL,
414 G_PARAM_READWRITE);
415 g_object_class_install_property(gobj_class, PROP_SHORTCUT, pspec);
417 /* Stored Image */
418 pspec = g_param_spec_pointer(PROP_IMGSTORE_S, _("Stored Image"),
419 _("Stored Image. (that'll have to do for now)"),
420 G_PARAM_READWRITE);
421 g_object_class_install_property(gobj_class, PROP_IMGSTORE, pspec);
423 signals[SIG_DESTROY] = g_signal_new("destroy",
424 G_OBJECT_CLASS_TYPE(klass),
425 G_SIGNAL_RUN_LAST,
426 0, NULL, NULL,
427 g_cclosure_marshal_VOID__VOID,
428 G_TYPE_NONE, 0);
431 GType
432 purple_smiley_get_type(void)
434 static GType type = 0;
436 if(type == 0) {
437 static const GTypeInfo info = {
438 sizeof(PurpleSmileyClass),
439 NULL,
440 NULL,
441 (GClassInitFunc)purple_smiley_class_init,
442 NULL,
443 NULL,
444 sizeof(PurpleSmiley),
446 purple_smiley_init,
447 NULL,
450 type = g_type_register_static(G_TYPE_OBJECT,
451 "PurpleSmiley",
452 &info, 0);
455 return type;
458 /*********************************************************************
459 * Other Stuff *
460 *********************************************************************/
462 static char *get_file_full_path(const char *filename)
464 char *path;
466 path = g_build_filename(purple_smileys_get_storing_dir(), filename, NULL);
468 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
469 g_free(path);
470 return NULL;
473 return path;
476 static PurpleSmiley *
477 purple_smiley_load_file(const char *shortcut, const char *checksum, const char *filename)
479 PurpleSmiley *smiley = NULL;
480 guchar *smiley_data;
481 size_t smiley_data_len;
482 char *fullpath = NULL;
484 g_return_val_if_fail(shortcut != NULL, NULL);
485 g_return_val_if_fail(checksum != NULL, NULL);
486 g_return_val_if_fail(filename != NULL, NULL);
488 fullpath = get_file_full_path(filename);
489 if (!fullpath)
490 return NULL;
492 smiley = purple_smiley_create(shortcut);
493 if (!smiley) {
494 g_free(fullpath);
495 return NULL;
498 smiley->checksum = g_strdup(checksum);
500 if (read_smiley_file(fullpath, &smiley_data, &smiley_data_len))
501 purple_smiley_set_data_impl(smiley, smiley_data,
502 smiley_data_len);
503 else
504 purple_smiley_delete(smiley);
506 g_free(fullpath);
508 return smiley;
511 static void
512 purple_smiley_data_store(PurpleStoredImage *stored_img)
514 const char *dirname;
515 char *path;
516 FILE *file = NULL;
518 g_return_if_fail(stored_img != NULL);
520 if (!smileys_loaded)
521 return;
523 dirname = purple_smileys_get_storing_dir();
524 path = g_build_filename(dirname, purple_imgstore_get_filename(stored_img), NULL);
526 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
527 purple_debug_info(SMILEYS_LOG_ID, "Creating smileys directory.\n");
529 if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
530 purple_debug_error(SMILEYS_LOG_ID,
531 "Unable to create directory %s: %s\n",
532 dirname, g_strerror(errno));
536 if ((file = g_fopen(path, "wb")) != NULL) {
537 if (!fwrite(purple_imgstore_get_data(stored_img),
538 purple_imgstore_get_size(stored_img), 1, file)) {
539 purple_debug_error(SMILEYS_LOG_ID, "Error writing %s: %s\n",
540 path, g_strerror(errno));
541 } else {
542 purple_debug_info(SMILEYS_LOG_ID, "Wrote cache file: %s\n", path);
545 fclose(file);
546 } else {
547 purple_debug_error(SMILEYS_LOG_ID, "Unable to create file %s: %s\n",
548 path, g_strerror(errno));
549 g_free(path);
551 return;
554 g_free(path);
557 static void
558 purple_smiley_data_unstore(const char *filename)
560 const char *dirname;
561 char *path;
563 g_return_if_fail(filename != NULL);
565 dirname = purple_smileys_get_storing_dir();
566 path = g_build_filename(dirname, filename, NULL);
568 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
569 if (g_unlink(path))
570 purple_debug_error(SMILEYS_LOG_ID, "Failed to delete %s: %s\n",
571 path, g_strerror(errno));
572 else
573 purple_debug_info(SMILEYS_LOG_ID, "Deleted cache file: %s\n", path);
576 g_free(path);
579 static gboolean
580 read_smiley_file(const char *path, guchar **data, size_t *len)
582 GError *err = NULL;
584 if (!g_file_get_contents(path, (gchar **)data, len, &err)) {
585 purple_debug_error(SMILEYS_LOG_ID, "Error reading %s: %s\n",
586 path, err->message);
587 g_error_free(err);
589 return FALSE;
592 return TRUE;
595 static PurpleStoredImage *
596 purple_smiley_data_new(guchar *smiley_data, size_t smiley_data_len)
598 char *filename;
599 PurpleStoredImage *stored_img;
601 g_return_val_if_fail(smiley_data != NULL, NULL);
602 g_return_val_if_fail(smiley_data_len > 0, NULL);
604 filename = purple_util_get_image_filename(smiley_data, smiley_data_len);
606 if (filename == NULL) {
607 g_free(smiley_data);
608 return NULL;
611 stored_img = purple_imgstore_add(smiley_data, smiley_data_len, filename);
613 g_free(filename);
615 return stored_img;
618 static void
619 purple_smiley_set_data_impl(PurpleSmiley *smiley, guchar *smiley_data,
620 size_t smiley_data_len)
622 PurpleStoredImage *old_img, *new_img;
623 const char *old_filename = NULL;
624 const char *new_filename = NULL;
626 g_return_if_fail(smiley != NULL);
627 g_return_if_fail(smiley_data != NULL);
628 g_return_if_fail(smiley_data_len > 0);
630 old_img = smiley->img;
632 new_img = purple_smiley_data_new(smiley_data, smiley_data_len);
634 g_object_set(G_OBJECT(smiley), PROP_IMGSTORE_S, new_img, NULL);
636 /* If the old and new image files have different names we need
637 * to unstore old image file. */
638 if (!old_img)
639 return;
641 old_filename = purple_imgstore_get_filename(old_img);
642 new_filename = purple_imgstore_get_filename(smiley->img);
644 if (g_ascii_strcasecmp(old_filename, new_filename))
645 purple_smiley_data_unstore(old_filename);
646 purple_imgstore_unref(old_img);
650 /*****************************************************************************
651 * Public API functions *
652 *****************************************************************************/
654 static PurpleSmiley *
655 purple_smiley_create(const char *shortcut)
657 PurpleSmiley *smiley;
659 smiley = PURPLE_SMILEY(g_object_new(PURPLE_TYPE_SMILEY, PROP_SHORTCUT_S, shortcut, NULL));
661 return smiley;
664 PurpleSmiley *
665 purple_smiley_new(PurpleStoredImage *img, const char *shortcut)
667 PurpleSmiley *smiley = NULL;
669 g_return_val_if_fail(shortcut != NULL, NULL);
670 g_return_val_if_fail(img != NULL, NULL);
672 smiley = purple_smileys_find_by_shortcut(shortcut);
673 if (smiley)
674 return smiley;
676 smiley = purple_smiley_create(shortcut);
677 if (!smiley)
678 return NULL;
680 g_object_set(G_OBJECT(smiley), PROP_IMGSTORE_S, img, NULL);
682 return smiley;
685 static PurpleSmiley *
686 purple_smiley_new_from_stream(const char *shortcut, guchar *smiley_data,
687 size_t smiley_data_len)
689 PurpleSmiley *smiley;
691 g_return_val_if_fail(shortcut != NULL, NULL);
692 g_return_val_if_fail(smiley_data != NULL, NULL);
693 g_return_val_if_fail(smiley_data_len > 0, NULL);
695 smiley = purple_smileys_find_by_shortcut(shortcut);
696 if (smiley)
697 return smiley;
699 /* purple_smiley_create() sets shortcut */
700 smiley = purple_smiley_create(shortcut);
701 if (!smiley)
702 return NULL;
704 purple_smiley_set_data_impl(smiley, smiley_data, smiley_data_len);
706 purple_smiley_data_store(smiley->img);
708 return smiley;
711 PurpleSmiley *
712 purple_smiley_new_from_file(const char *shortcut, const char *filepath)
714 PurpleSmiley *smiley = NULL;
715 guchar *smiley_data;
716 size_t smiley_data_len;
718 g_return_val_if_fail(shortcut != NULL, NULL);
719 g_return_val_if_fail(filepath != NULL, NULL);
721 if (read_smiley_file(filepath, &smiley_data, &smiley_data_len)) {
722 smiley = purple_smiley_new_from_stream(shortcut, smiley_data,
723 smiley_data_len);
726 return smiley;
729 void
730 purple_smiley_delete(PurpleSmiley *smiley)
732 g_return_if_fail(smiley != NULL);
734 g_object_unref(smiley);
737 gboolean
738 purple_smiley_set_shortcut(PurpleSmiley *smiley, const char *shortcut)
740 g_return_val_if_fail(smiley != NULL, FALSE);
741 g_return_val_if_fail(shortcut != NULL, FALSE);
743 /* Check out whether the new shortcut is already being used. */
744 if (g_hash_table_lookup(smiley_shortcut_index, shortcut))
745 return FALSE;
747 /* Remove the old shortcut. */
748 if (smiley->shortcut)
749 g_hash_table_remove(smiley_shortcut_index, smiley->shortcut);
751 /* Insert the new shortcut. */
752 g_hash_table_insert(smiley_shortcut_index, g_strdup(shortcut), smiley);
754 g_free(smiley->shortcut);
755 smiley->shortcut = g_strdup(shortcut);
757 g_object_notify(G_OBJECT(smiley), PROP_SHORTCUT_S);
759 purple_smileys_save();
761 return TRUE;
764 void
765 purple_smiley_set_data(PurpleSmiley *smiley, guchar *smiley_data,
766 size_t smiley_data_len)
768 g_return_if_fail(smiley != NULL);
769 g_return_if_fail(smiley_data != NULL);
770 g_return_if_fail(smiley_data_len > 0);
772 /* Remove the previous entry */
773 g_hash_table_remove(smiley_checksum_index, smiley->checksum);
775 /* Update the file data. This also updates the checksum. */
776 purple_smiley_set_data_impl(smiley, smiley_data, smiley_data_len);
778 /* Reinsert the index item. */
779 g_hash_table_insert(smiley_checksum_index, g_strdup(smiley->checksum), smiley);
781 purple_smileys_save();
784 PurpleStoredImage *
785 purple_smiley_get_stored_image(const PurpleSmiley *smiley)
787 return purple_imgstore_ref(smiley->img);
790 const char *purple_smiley_get_shortcut(const PurpleSmiley *smiley)
792 g_return_val_if_fail(smiley != NULL, NULL);
794 return smiley->shortcut;
797 const char *
798 purple_smiley_get_checksum(const PurpleSmiley *smiley)
800 g_return_val_if_fail(smiley != NULL, NULL);
802 return smiley->checksum;
805 gconstpointer
806 purple_smiley_get_data(const PurpleSmiley *smiley, size_t *len)
808 g_return_val_if_fail(smiley != NULL, NULL);
810 if (smiley->img) {
811 if (len != NULL)
812 *len = purple_imgstore_get_size(smiley->img);
814 return purple_imgstore_get_data(smiley->img);
817 return NULL;
820 const char *
821 purple_smiley_get_extension(const PurpleSmiley *smiley)
823 if (smiley->img != NULL)
824 return purple_imgstore_get_extension(smiley->img);
826 return NULL;
829 char *purple_smiley_get_full_path(PurpleSmiley *smiley)
831 g_return_val_if_fail(smiley != NULL, NULL);
833 if (smiley->img == NULL)
834 return NULL;
836 return get_file_full_path(purple_imgstore_get_filename(smiley->img));
839 static void add_smiley_to_list(gpointer key, gpointer value, gpointer user_data)
841 GList** returninglist = (GList**)user_data;
843 *returninglist = g_list_append(*returninglist, value);
846 GList *
847 purple_smileys_get_all(void)
849 GList *returninglist = NULL;
851 g_hash_table_foreach(smiley_shortcut_index, add_smiley_to_list, &returninglist);
853 return returninglist;
856 PurpleSmiley *
857 purple_smileys_find_by_shortcut(const char *shortcut)
859 g_return_val_if_fail(shortcut != NULL, NULL);
861 return g_hash_table_lookup(smiley_shortcut_index, shortcut);
864 PurpleSmiley *
865 purple_smileys_find_by_checksum(const char *checksum)
867 g_return_val_if_fail(checksum != NULL, NULL);
869 return g_hash_table_lookup(smiley_checksum_index, checksum);
872 const char *
873 purple_smileys_get_storing_dir(void)
875 return smileys_dir;
878 void
879 purple_smileys_init(void)
881 smiley_shortcut_index = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
882 smiley_checksum_index = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
884 smileys_dir = g_build_filename(purple_user_dir(), SMILEYS_DEFAULT_FOLDER, NULL);
886 purple_smileys_load();
889 void
890 purple_smileys_uninit(void)
892 if (save_timer != 0) {
893 purple_timeout_remove(save_timer);
894 save_timer = 0;
895 sync_smileys();
898 g_hash_table_destroy(smiley_shortcut_index);
899 g_hash_table_destroy(smiley_checksum_index);
900 g_free(smileys_dir);