Use correct memory functions for GG oauth.
[pidgin-git.git] / libpurple / protocols / gg / image-prpl.c
blob4d6c1ab32141ec89af1fc493573d315863d21521
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 * Rewritten from scratch during Google Summer of Code 2012
8 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
10 * Previously implemented by:
11 * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
12 * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
13 * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 #include "image-prpl.h"
32 #include <debug.h>
33 #include <glibcompat.h>
35 #include "gg.h"
36 #include "utils.h"
38 #include <image-store.h>
40 struct _ggp_image_session_data
42 GHashTable *recv_images;
43 GHashTable *sent_images;
46 typedef struct
48 PurpleImage *image;
49 gchar *conv_name; /* TODO: callback */
50 } ggp_image_sent;
52 static void ggp_image_sent_free(gpointer _sent_image)
54 ggp_image_sent *sent_image = _sent_image;
55 g_object_unref(sent_image->image);
56 g_free(sent_image->conv_name);
57 g_free(sent_image);
60 static uint64_t ggp_image_params_to_id(uint32_t crc32, uint32_t size)
62 return ((uint64_t)crc32 << 32) | size;
65 static inline ggp_image_session_data *
66 ggp_image_get_sdata(PurpleConnection *gc)
68 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
69 return accdata->image_data;
72 void ggp_image_setup(PurpleConnection *gc)
74 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
75 ggp_image_session_data *sdata = g_new0(ggp_image_session_data, 1);
77 accdata->image_data = sdata;
79 sdata->recv_images = g_hash_table_new_full(
80 g_int64_hash, g_int64_equal, g_free, g_object_unref);
81 sdata->sent_images = g_hash_table_new_full(
82 g_int64_hash, g_int64_equal, g_free,
83 ggp_image_sent_free);
86 void ggp_image_cleanup(PurpleConnection *gc)
88 ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
90 g_hash_table_destroy(sdata->recv_images);
91 g_hash_table_destroy(sdata->sent_images);
92 g_free(sdata);
95 ggp_image_prepare_result
96 ggp_image_prepare(PurpleConversation *conv, PurpleImage *image, uint64_t *id)
98 PurpleConnection *gc = purple_conversation_get_connection(conv);
99 ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
100 size_t image_size;
101 gconstpointer image_data;
102 uint32_t image_crc;
103 ggp_image_sent *sent_image;
105 g_return_val_if_fail(image, GGP_IMAGE_PREPARE_FAILURE);
107 image_size = purple_image_get_data_size(image);
109 if (image_size > GGP_IMAGE_SIZE_MAX) {
110 purple_debug_warning("gg", "ggp_image_prepare: image "
111 "is too big (max bytes: %d)\n", GGP_IMAGE_SIZE_MAX);
112 return GGP_IMAGE_PREPARE_TOO_BIG;
115 g_object_ref(image);
116 image_data = purple_image_get_data(image);
117 image_crc = gg_crc32(0, image_data, image_size);
119 purple_debug_info("gg", "ggp_image_prepare: image prepared "
120 "[crc=%u, size=%" G_GSIZE_FORMAT "]",
121 image_crc, image_size);
123 *id = ggp_image_params_to_id(image_crc, image_size);
125 g_object_ref(image);
126 sent_image = g_new(ggp_image_sent, 1);
127 sent_image->image = image;
128 sent_image->conv_name = g_strdup(purple_conversation_get_name(conv));
129 g_hash_table_insert(sdata->sent_images, ggp_uint64dup(*id),
130 sent_image);
132 return GGP_IMAGE_PREPARE_OK;
135 void ggp_image_recv(PurpleConnection *gc,
136 const struct gg_event_image_reply *image_reply)
138 ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
139 PurpleImage *img;
140 uint64_t id;
142 id = ggp_image_params_to_id(image_reply->crc32, image_reply->size);
143 img = g_hash_table_lookup(sdata->recv_images, &id);
144 if (!img) {
145 purple_debug_warning("gg", "ggp_image_recv: "
146 "image " GGP_IMAGE_ID_FORMAT " wasn't requested\n",
147 id);
148 return;
151 purple_debug_info("gg", "ggp_image_recv: got image "
152 "[crc=%u, size=%u, filename=%s, id=" GGP_IMAGE_ID_FORMAT "]",
153 image_reply->crc32, image_reply->size,
154 image_reply->filename, id);
156 img = purple_image_new_from_data(
157 (const guint8 *)image_reply->image,
158 image_reply->size
160 purple_image_set_friendly_filename(img, image_reply->filename);
162 g_hash_table_insert(sdata->recv_images, &id, img);
165 void ggp_image_send(PurpleConnection *gc,
166 const struct gg_event_image_request *image_request)
168 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
169 ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
170 ggp_image_sent *sent_image;
171 PurpleConversation *conv;
172 uint64_t id;
173 gchar *gg_filename;
175 purple_debug_info("gg", "ggp_image_send: got image request "
176 "[uin=%u, crc=%u, size=%u]\n",
177 image_request->sender,
178 image_request->crc32,
179 image_request->size);
181 id = ggp_image_params_to_id(image_request->crc32, image_request->size);
183 sent_image = g_hash_table_lookup(sdata->sent_images, &id);
185 if (sent_image == NULL && image_request->sender == ggp_str_to_uin(
186 purple_account_get_username(purple_connection_get_account(gc))))
188 purple_debug_misc("gg", "ggp_image_send: requested image "
189 "not found, but this may be another session request\n");
190 return;
192 if (sent_image == NULL) {
193 purple_debug_warning("gg", "ggp_image_send: requested image "
194 "not found\n");
195 return;
198 purple_debug_misc("gg", "ggp_image_send: requested image found "
199 "[id=" GGP_IMAGE_ID_FORMAT ", conv=%s]\n",
200 id, sent_image->conv_name);
202 g_return_if_fail(sent_image->image);
204 /* TODO: check allowed recipients */
205 gg_filename = g_strdup_printf(GGP_IMAGE_ID_FORMAT, id);
206 gg_image_reply(accdata->session, image_request->sender,
207 gg_filename,
208 purple_image_get_data(sent_image->image),
209 purple_image_get_data_size(sent_image->image));
210 g_free(gg_filename);
212 conv = purple_conversations_find_with_account(
213 sent_image->conv_name,
214 purple_connection_get_account(gc));
215 if (conv != NULL) {
216 gchar *msg = g_strdup_printf(_("Image delivered to %u."),
217 image_request->sender);
218 purple_conversation_write_system_message(conv, msg,
219 PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_NOTIFY);
220 g_free(msg);
224 PurpleImage *
225 ggp_image_request(PurpleConnection *gc, uin_t uin, uint64_t id)
227 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
228 ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
229 PurpleImage *img;
230 uint32_t crc = id >> 32;
231 uint32_t size = id;
233 if (size > GGP_IMAGE_SIZE_MAX && crc <= GGP_IMAGE_SIZE_MAX) {
234 uint32_t tmp;
235 purple_debug_warning("gg", "ggp_image_request: "
236 "crc and size are swapped!\n");
237 tmp = crc;
238 crc = size;
239 size = tmp;
240 id = ggp_image_params_to_id(crc, size);
243 img = g_hash_table_lookup(sdata->recv_images, &id);
244 if (img) {
245 purple_debug_info("gg", "ggp_image_request: "
246 "image " GGP_IMAGE_ID_FORMAT " got from cache", id);
247 return img;
251 g_hash_table_insert(sdata->recv_images, ggp_uint64dup(id), NULL);
253 purple_debug_info("gg", "ggp_image_request: requesting image "
254 GGP_IMAGE_ID_FORMAT, id);
255 if (gg_image_request(accdata->session, uin, size, crc) != 0)
256 purple_debug_error("gg", "ggp_image_request: failed");
258 return img;