Mercurial > pidgin.yaz
annotate src/protocols/msn/buddyicon.c @ 5535:933739f789f9
[gaim-migrate @ 5935]
ding, dong, OPT_MISC_DEBUG is dead.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Mon, 26 May 2003 16:11:46 +0000 |
parents | 4f72b611f0ee |
children | 187c740f2a4e |
rev | line source |
---|---|
5351 | 1 /** |
2 * @file buddyicon.c Buddy icon support | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 #include "msn.h" | |
23 #include "buddyicon.h" | |
24 | |
25 #define PACKET_LENGTH 1500 | |
26 | |
5355
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
27 #define MAX_BUDDY_ICON_FILE_SIZE 8192 |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
28 |
5351 | 29 static const char alphabet[] = |
30 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | |
31 "0123456789+/"; | |
32 | |
33 static char * | |
34 __base64_enc(const char *data, int len) | |
35 { | |
36 char *dest; | |
37 char *buf; | |
38 | |
39 buf = dest = g_malloc(4 * len / 3 + 4); | |
40 | |
41 /* Encode 3 bytes at a time */ | |
42 while (len >= 3) { | |
43 buf[0] = alphabet[(data[0] >> 2) & 0x3F]; | |
44 buf[1] = alphabet[((data[0] << 4) & 0x30) | ((data[1] >> 4) & 0x0F)]; | |
45 buf[2] = alphabet[((data[1] << 2) & 0x3C) | ((data[2] >> 6) & 0x03)]; | |
46 buf[3] = alphabet[data[2] & 0x3F]; | |
47 data += 3; | |
48 buf += 4; | |
49 len -= 3; | |
50 } | |
51 | |
52 if (len > 0) { | |
53 buf[0] = alphabet[(data[0] >> 2) & 0x3F]; | |
54 buf[1] = alphabet[(data[0] << 4) & 0x30]; | |
55 | |
56 if (len > 1) { | |
57 buf[1] += (data[1] >> 4) & 0x0F; | |
58 buf[2] = alphabet[(data[1] << 2) & 0x3C]; | |
59 } | |
60 | |
61 else | |
62 buf[2] = '='; | |
63 | |
64 buf[3] = '='; | |
65 buf += 4; | |
66 } | |
67 | |
68 *buf = '\0'; | |
69 | |
70 return dest; | |
71 } | |
72 | |
73 static gboolean | |
74 __get_buddy_icon_info(struct gaim_account *account, char **base64, | |
75 char **md5sum, int *file_size, int *base64_size) | |
76 { | |
77 FILE *fp; | |
78 struct stat sb; | |
79 md5_state_t st; | |
80 md5_byte_t di[16]; | |
81 | |
82 if (base64 != NULL) *base64 = NULL; | |
83 if (md5sum != NULL) *md5sum = NULL; | |
84 if (file_size != NULL) *file_size = 0; | |
85 if (base64_size != NULL) *base64_size = 0; | |
86 | |
87 if (!stat(account->iconfile, &sb)) { | |
88 if (file_size != NULL) | |
89 *file_size = sb.st_size; | |
90 | |
91 if ((fp = fopen(account->iconfile, "rb")) != NULL) { | |
92 char *buf = g_malloc(sb.st_size + 1); | |
93 char *temp; | |
94 | |
95 fread(buf, 1, sb.st_size, fp); | |
96 | |
97 buf[sb.st_size] = '\0'; | |
98 | |
99 temp = __base64_enc(buf, sb.st_size); | |
100 | |
101 if (base64_size != NULL) | |
102 *base64_size = strlen(temp); | |
103 | |
104 if (base64 != NULL) | |
105 *base64 = temp; | |
106 else | |
107 g_free(temp); | |
108 | |
109 if (md5sum != NULL) { | |
110 char buf2[3]; | |
111 int i; | |
112 | |
113 md5_init(&st); | |
114 md5_append(&st, (const md5_byte_t *)buf, sb.st_size); | |
115 md5_finish(&st, di); | |
116 | |
117 *md5sum = g_new0(char, 33); | |
118 | |
119 for (i = 0; i < 16; i++) { | |
120 g_snprintf(buf2, sizeof(buf2), "%02x", di[i]); | |
121 strcat(*md5sum, buf2); | |
122 } | |
123 } | |
124 | |
125 g_free(buf); | |
126 | |
127 fclose(fp); | |
128 } | |
129 else { | |
130 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
131 "Cannot open buddy icon file!\n"); | |
132 | |
133 return FALSE; | |
134 } | |
135 } | |
136 | |
137 return TRUE; | |
138 } | |
139 | |
140 static gboolean | |
141 __send_icon_data(MsnSwitchBoard *swboard, MsnBuddyIconXfer *buddyicon) | |
142 { | |
143 struct gaim_connection *gc = swboard->servconn->session->account->gc; | |
144 char buf[MSN_BUF_LEN]; | |
145 MsnMessage *msg; | |
146 int len; | |
147 | |
148 len = MIN(PACKET_LENGTH - 4, | |
149 buddyicon->total_size - buddyicon->bytes_xfer); | |
150 | |
151 strcpy(buf, "ICON"); | |
152 | |
153 strncat(buf, buddyicon->data + buddyicon->bytes_xfer, len); | |
154 | |
155 msg = msn_message_new(); | |
156 msn_message_set_content_type(msg, "application/x-buddyicon"); | |
157 msn_message_set_receiver(msg, buddyicon->user); | |
158 msn_message_set_charset(msg, NULL); | |
159 msn_message_set_attr(msg, "User-Agent", NULL); | |
160 | |
161 msn_message_set_body(msg, buf); | |
162 | |
163 if (!msn_switchboard_send_msg(swboard, msg)) { | |
164 msn_message_destroy(msg); | |
165 | |
166 msn_buddy_icon_xfer_destroy(swboard->buddy_icon_xfer); | |
167 swboard->buddy_icon_xfer = NULL; | |
168 | |
169 hide_login_progress(gc, _("Write error")); | |
170 signoff(gc); | |
171 | |
172 return FALSE; | |
173 } | |
174 | |
175 msn_message_destroy(msg); | |
176 | |
177 buddyicon->bytes_xfer += len; | |
178 | |
179 if (buddyicon->bytes_xfer == buddyicon->total_size) { | |
180 msg = msn_message_new(); | |
181 msn_message_set_content_type(msg, "application/x-buddyicon"); | |
182 msn_message_set_receiver(msg, buddyicon->user); | |
183 msn_message_set_charset(msg, NULL); | |
184 msn_message_set_attr(msg, "User-Agent", NULL); | |
185 | |
186 msn_message_set_body(msg, "Command: COMPLETE\r\n"); | |
187 | |
188 msn_switchboard_send_msg(swboard, msg); | |
189 | |
190 msn_buddy_icon_xfer_destroy(swboard->buddy_icon_xfer); | |
191 swboard->buddy_icon_xfer = NULL; | |
192 } | |
193 | |
194 return TRUE; | |
195 } | |
196 | |
197 static gboolean | |
198 __process_invite(MsnServConn *servconn, const MsnMessage *msg) | |
199 { | |
200 MsnSession *session = servconn->session; | |
201 struct gaim_connection *gc = session->account->gc; | |
202 MsnMessage *new_msg; | |
203 MsnSwitchBoard *swboard; | |
204 MsnBuddyIconXfer *buddyicon; | |
205 struct buddy *b; | |
206 GHashTable *table; | |
207 const char *command; | |
208 | |
209 table = msn_message_get_hashtable_from_body(msg); | |
210 | |
211 command = g_hash_table_lookup(table, "Command"); | |
212 | |
213 if (command == NULL) { | |
214 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
215 "Missing Command from buddy icon message.\n"); | |
216 return TRUE; | |
217 } | |
218 | |
219 if (!strcmp(command, "INVITE")) { | |
220 MsnUser *user; | |
221 const char *md5sum = g_hash_table_lookup(table, "MD5SUM"); | |
222 const char *size_s = g_hash_table_lookup(table, "File-Size"); | |
223 const char *base64_size_s = g_hash_table_lookup(table, "Base64-Size"); | |
224 const char *passport; | |
225 | |
226 if (md5sum == NULL) { | |
227 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
228 "Missing MD5SUM from buddy icon message.\n"); | |
229 | |
230 return TRUE; | |
231 } | |
232 | |
233 if (size_s == NULL) { | |
234 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
235 "Missing File-Size from buddy icon message.\n"); | |
236 | |
237 return TRUE; | |
238 } | |
239 | |
240 if (base64_size_s == NULL) { | |
241 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
242 "Missing Bas64-Size from buddy icon message.\n"); | |
243 | |
244 return TRUE; | |
245 } | |
246 | |
5355
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
247 if (atoi(size_s) > MAX_BUDDY_ICON_FILE_SIZE) { |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
248 gaim_debug(GAIM_DEBUG_ERROR, "msn", |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
249 "User tried to send a buddy icon over 8KB! " |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
250 "Not accepting."); |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
251 return TRUE; |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
252 } |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
253 |
5351 | 254 user = msn_message_get_sender(msg); |
255 | |
256 passport = msn_user_get_passport(user); | |
257 | |
258 /* See if we actually need a new icon. */ | |
259 if ((b = gaim_find_buddy(gc->account, passport)) != NULL) { | |
260 const char *cur_md5sum; | |
261 | |
262 cur_md5sum = gaim_buddy_get_setting(b, "icon_checksum"); | |
263 | |
264 if (cur_md5sum != NULL && !strcmp(cur_md5sum, md5sum)) | |
265 return TRUE; | |
266 } | |
267 | |
268 /* Send a request for transfer. */ | |
269 new_msg = msn_message_new(); | |
270 msn_message_set_content_type(new_msg, "application/x-buddyicon"); | |
271 msn_message_set_receiver(new_msg, user); | |
272 msn_message_set_charset(new_msg, NULL); | |
273 msn_message_set_attr(new_msg, "User-Agent", NULL); | |
274 | |
275 msn_message_set_body(new_msg, "Command: REQUEST\r\n"); | |
276 | |
277 if ((swboard = msn_session_open_switchboard(session)) == NULL) { | |
278 msn_message_destroy(new_msg); | |
279 | |
280 hide_login_progress(gc, _("Write error")); | |
281 signoff(gc); | |
282 | |
283 return FALSE; | |
284 } | |
285 | |
286 swboard->hidden = TRUE; | |
287 msn_switchboard_set_user(swboard, user); | |
288 msn_switchboard_send_msg(swboard, new_msg); | |
289 | |
290 msn_message_destroy(new_msg); | |
291 | |
292 buddyicon = swboard->buddy_icon_xfer = msn_buddy_icon_xfer_new(); | |
293 | |
294 buddyicon->user = user; | |
295 msn_user_ref(buddyicon->user); | |
296 | |
297 buddyicon->md5sum = g_strdup(md5sum); | |
298 buddyicon->total_size = atoi(base64_size_s); | |
299 buddyicon->file_size = atoi(size_s); | |
300 | |
301 buddyicon->data = g_malloc(buddyicon->total_size + 1); | |
302 } | |
303 else if (!strcmp(command, "REQUEST")) { | |
304 swboard = (MsnSwitchBoard *)servconn->data; | |
305 | |
306 swboard->hidden = TRUE; | |
307 | |
308 swboard->buddy_icon_xfer = buddyicon = msn_buddy_icon_xfer_new(); | |
309 | |
310 if (!__get_buddy_icon_info(gc->account, | |
311 &buddyicon->data, | |
312 &buddyicon->md5sum, | |
313 &buddyicon->file_size, | |
314 &buddyicon->total_size)) { | |
315 | |
316 msn_buddy_icon_xfer_destroy(buddyicon); | |
317 | |
318 new_msg = msn_message_new(); | |
319 msn_message_set_content_type(new_msg, "application/x-buddyicon"); | |
320 msn_message_set_receiver(new_msg, msn_message_get_sender(msg)); | |
321 msn_message_set_charset(new_msg, NULL); | |
322 msn_message_set_attr(new_msg, "User-Agent", NULL); | |
323 | |
324 msn_message_set_body(new_msg, "Command: CANCEL\r\n"); | |
325 | |
326 if ((swboard = msn_session_open_switchboard(session)) == NULL) { | |
327 msn_message_destroy(new_msg); | |
328 | |
329 hide_login_progress(gc, _("Write error")); | |
330 signoff(gc); | |
331 | |
332 return FALSE; | |
333 } | |
334 | |
335 swboard->hidden = TRUE; | |
336 | |
337 msn_switchboard_send_msg(swboard, new_msg); | |
338 | |
339 msn_message_destroy(new_msg); | |
340 | |
341 msn_switchboard_destroy(swboard); | |
342 } | |
343 | |
344 return __send_icon_data(swboard, buddyicon); | |
345 } | |
346 else if (!strcmp(command, "ACK")) { | |
347 swboard = (MsnSwitchBoard *)servconn->data; | |
348 | |
349 buddyicon = swboard->buddy_icon_xfer; | |
350 | |
351 if (buddyicon != NULL) | |
352 return __send_icon_data(swboard, buddyicon); | |
353 } | |
354 else if (!strcmp(command, "COMPLETE")) { | |
355 const char *passport; | |
356 char *icon; | |
357 int icon_len; | |
358 | |
359 swboard = (MsnSwitchBoard *)servconn->data; | |
360 | |
361 buddyicon = swboard->buddy_icon_xfer; | |
362 | |
363 passport = msn_user_get_passport(buddyicon->user); | |
364 swboard->hidden = TRUE; | |
365 | |
366 frombase64(buddyicon->data, &icon, &icon_len); | |
367 | |
368 if ((b = gaim_find_buddy(gc->account, passport)) != NULL) { | |
369 gaim_buddy_set_setting(b, "icon_checksum", buddyicon->md5sum); | |
370 gaim_blist_save(); | |
371 } | |
372 | |
373 set_icon_data(gc, passport, icon, icon_len); | |
374 | |
375 g_free(icon); | |
376 | |
377 msn_buddy_icon_xfer_destroy(swboard->buddy_icon_xfer); | |
378 swboard->buddy_icon_xfer = NULL; | |
379 | |
380 msn_switchboard_destroy(swboard); | |
381 } | |
382 else if (!strcmp(command, "CANCEL")) { | |
383 swboard = (MsnSwitchBoard *)servconn->data; | |
384 | |
385 msn_buddy_icon_xfer_destroy(swboard->buddy_icon_xfer); | |
386 swboard->buddy_icon_xfer = NULL; | |
387 | |
388 msn_switchboard_destroy(swboard); | |
389 } | |
390 else { | |
391 gaim_debug(GAIM_DEBUG_ERROR, "msn", | |
392 "Unknown buddy icon message command: %s\n", command); | |
393 } | |
394 | |
395 return TRUE; | |
396 } | |
397 | |
398 static gboolean | |
399 __process_data(MsnServConn *servconn, const MsnMessage *msg) | |
400 { | |
401 struct gaim_connection *gc = servconn->session->account->gc; | |
402 MsnSwitchBoard *swboard; | |
403 MsnBuddyIconXfer *buddyicon; | |
404 MsnMessage *ack_msg; | |
405 const char *data; | |
406 int len; | |
407 | |
408 swboard = (MsnSwitchBoard *)servconn->data; | |
409 buddyicon = swboard->buddy_icon_xfer; | |
410 | |
411 data = msn_message_get_body(msg) + 4; | |
412 | |
413 len = strlen(data); | |
414 | |
415 /* Copy the data into our buffer. */ | |
416 strncpy(buddyicon->data + buddyicon->bytes_xfer, data, | |
417 buddyicon->total_size - buddyicon->bytes_xfer); | |
418 | |
419 buddyicon->bytes_xfer += len; | |
420 | |
421 /* Acknowledge this data. */ | |
422 ack_msg = msn_message_new(); | |
423 msn_message_set_content_type(ack_msg, "application/x-buddyicon"); | |
424 msn_message_set_receiver(ack_msg, msn_message_get_sender(msg)); | |
425 msn_message_set_charset(ack_msg, NULL); | |
426 msn_message_set_attr(ack_msg, "User-Agent", NULL); | |
427 msn_message_set_body(ack_msg, "Command: ACK\r\n"); | |
428 | |
429 if (!msn_switchboard_send_msg(swboard, ack_msg)) { | |
430 msn_message_destroy(ack_msg); | |
431 | |
432 msn_buddy_icon_xfer_destroy(swboard->buddy_icon_xfer); | |
433 swboard->buddy_icon_xfer = NULL; | |
434 | |
435 hide_login_progress(gc, _("Write error")); | |
436 signoff(gc); | |
437 | |
438 return FALSE; | |
439 } | |
440 | |
441 msn_message_destroy(ack_msg); | |
442 | |
443 return TRUE; | |
444 } | |
445 | |
446 MsnBuddyIconXfer * | |
447 msn_buddy_icon_xfer_new(void) | |
448 { | |
449 return g_new0(MsnBuddyIconXfer, 1); | |
450 } | |
451 | |
452 void | |
453 msn_buddy_icon_xfer_destroy(MsnBuddyIconXfer *xfer) | |
454 { | |
455 g_return_if_fail(xfer != NULL); | |
456 | |
457 if (xfer->user != NULL) | |
458 msn_user_unref(xfer->user); | |
459 | |
460 if (xfer->data != NULL) | |
461 g_free(xfer->data); | |
462 | |
463 g_free(xfer); | |
464 } | |
465 | |
466 gboolean | |
5506
4f72b611f0ee
[gaim-migrate @ 5905]
Christian Hammond <chipx86@chipx86.com>
parents:
5355
diff
changeset
|
467 msn_buddy_icon_msg(MsnServConn *servconn, MsnMessage *msg) |
5351 | 468 { |
469 if (!strncmp(msn_message_get_body(msg), "ICON", 4)) | |
470 return __process_data(servconn, msg); | |
471 else | |
472 return __process_invite(servconn, msg); | |
473 } | |
474 | |
475 void | |
476 msn_buddy_icon_invite(MsnSwitchBoard *swboard) | |
477 { | |
478 struct gaim_account *account = swboard->servconn->session->account; | |
479 struct gaim_connection *gc = account->gc; | |
480 MsnMessage *msg; | |
481 char buf[MSN_BUF_LEN]; | |
482 char *md5sum; | |
483 int file_size, base64_size; | |
484 | |
485 g_return_if_fail(swboard != NULL); | |
486 | |
487 if (*account->iconfile == '\0') | |
488 return; /* We don't have an icon to send. */ | |
489 | |
490 if (!__get_buddy_icon_info(account, NULL, &md5sum, | |
491 &file_size, &base64_size)) { | |
492 return; | |
493 } | |
494 | |
5355
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
495 if (file_size > MAX_BUDDY_ICON_FILE_SIZE) { |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
496 gaim_debug(GAIM_DEBUG_ERROR, "msn", |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
497 "The buddy icon is too large to send. Must be no more " |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
498 "than %d bytes!\n", MAX_BUDDY_ICON_FILE_SIZE); |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
499 return; |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
500 } |
6a57fd9b45e1
[gaim-migrate @ 5731]
Christian Hammond <chipx86@chipx86.com>
parents:
5351
diff
changeset
|
501 |
5351 | 502 msg = msn_message_new(); |
503 msn_message_set_content_type(msg, "application/x-buddyicon"); | |
504 msn_message_set_receiver(msg, msn_message_get_sender(msg)); | |
505 msn_message_set_charset(msg, NULL); | |
506 msn_message_set_attr(msg, "User-Agent", NULL); | |
507 | |
508 g_snprintf(buf, sizeof(buf), | |
509 "Command: INVITE\r\n" | |
510 "MD5SUM: %s\r\n" | |
511 "File-Size: %d\r\n" | |
512 "Base64-Size: %d\r\n", | |
513 md5sum, file_size, base64_size); | |
514 | |
515 g_free(md5sum); | |
516 | |
517 msn_message_set_body(msg, buf); | |
518 | |
519 if (!msn_switchboard_send_msg(swboard, msg)) { | |
520 msn_message_destroy(msg); | |
521 | |
522 hide_login_progress(gc, _("Write error")); | |
523 signoff(gc); | |
524 | |
525 return; | |
526 } | |
527 | |
528 msn_message_destroy(msg); | |
529 } |