comparison libpurple/protocols/gg/gg.c @ 24483:4d50b5d09d4a

Support displaying buddy icons from Gadu-Gadu buddies. Fixes #220. committer: John Bailey <rekkanoryo@rekkanoryo.org>
author Adam Strzelecki <ono@java.pl>
date Sun, 23 Nov 2008 04:11:36 +0000
parents 0320b4a33432
children 0d3af2ecf4ad
comparison
equal deleted inserted replaced
24482:39841a84c944 24483:4d50b5d09d4a
1239 break; 1239 break;
1240 } 1240 }
1241 } 1241 }
1242 /* }}} */ 1242 /* }}} */
1243 1243
1244
1245 /* static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */
1246 static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev)
1247 {
1248 gint imgid = 0;
1249 GGPInfo *info = gc->proto_data;
1250 GList *entry = g_list_first(info->pending_richtext_messages);
1251 gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32);
1252
1253 imgid = purple_imgstore_add_with_id(
1254 g_memdup(ev->event.image_reply.image, ev->event.image_reply.size),
1255 ev->event.image_reply.size,
1256 ev->event.image_reply.filename);
1257
1258 purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32);
1259
1260 while(entry) {
1261 if (strstr((gchar *)entry->data, handlerid) != NULL) {
1262 gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3);
1263 gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]);
1264 purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data);
1265 g_strfreev(split);
1266 info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
1267 /* We don't have any more images to download */
1268 if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
1269 gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
1270 serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, ev->event.msg.time);
1271 g_free(buf);
1272 purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
1273 g_free(text);
1274 break;
1275 }
1276 info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text);
1277 break;
1278 }
1279 entry = g_list_next(entry);
1280 }
1281 g_free(handlerid);
1282
1283 return;
1284 }
1285 /* }}} */
1286
1287
1244 /** 1288 /**
1245 * Dispatch a message received from a buddy. 1289 * Dispatch a message received from a buddy.
1246 * 1290 *
1247 * @param gc PurpleConnection. 1291 * @param gc PurpleConnection.
1248 * @param ev Gadu-Gadu event structure. 1292 * @param ev Gadu-Gadu event structure.
1293 *
1294 * Image receiving, some code borrowed from Kadu http://www.kadu.net
1249 */ 1295 */
1250 /* static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */ 1296 /* static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */
1251 static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) 1297 static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev)
1252 { 1298 {
1253 GGPInfo *info = gc->proto_data; 1299 GGPInfo *info = gc->proto_data;
1262 "CP1250", "UTF-8"); 1308 "CP1250", "UTF-8");
1263 purple_str_strip_char(tmp, '\r'); 1309 purple_str_strip_char(tmp, '\r');
1264 msg = g_markup_escape_text(tmp, -1); 1310 msg = g_markup_escape_text(tmp, -1);
1265 g_free(tmp); 1311 g_free(tmp);
1266 1312
1267 purple_debug_info("gg", "msg form (%s): %s (class = %d; rcpt_count = %d)\n", 1313 /* We got richtext message */
1314 if (ev->event.msg.formats_length)
1315 {
1316 gboolean got_image = FALSE, bold = FALSE, italic = FALSE, under= FALSE;
1317 char *cformats = (char *)ev->event.msg.formats;
1318 char *cformats_end = cformats + ev->event.msg.formats_length;
1319 gint increased_len = 0;
1320 struct gg_msg_richtext_format *actformat;
1321 struct gg_msg_richtext_image *actimage;
1322 GString *message = g_string_new(msg);
1323 gchar *handlerid;
1324
1325 purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length);
1326
1327 while (cformats < cformats_end)
1328 {
1329 gint byteoffset;
1330 actformat = (struct gg_msg_richtext_format *)cformats;
1331 cformats += sizeof(struct gg_msg_richtext_format);
1332 byteoffset = g_utf8_offset_to_pointer(message->str, actformat->position + increased_len) - message->str;
1333
1334 if(actformat->position == 0 && actformat->font == 0) {
1335 purple_debug_warning("gg", "ggp_recv_message_handler: bogus formatting (inc: %i)\n", increased_len);
1336 continue;
1337 }
1338 purple_debug_info("gg", "ggp_recv_message_handler: format at pos: %i, image:%i, bold:%i, italic: %i, under:%i (inc: %i)\n",
1339 actformat->position,
1340 (actformat->font & GG_FONT_IMAGE) != 0,
1341 (actformat->font & GG_FONT_BOLD) != 0,
1342 (actformat->font & GG_FONT_ITALIC) != 0,
1343 (actformat->font & GG_FONT_UNDERLINE) != 0,
1344 increased_len);
1345
1346 if (actformat->font & GG_FONT_IMAGE) {
1347 got_image = TRUE;
1348 actimage = (struct gg_msg_richtext_image*)(cformats);
1349 cformats += sizeof(struct gg_msg_richtext_image);
1350 purple_debug_info("gg", "ggp_recv_message_handler: image received, size: %d, crc32: %i\n", actimage->size, actimage->crc32);
1351
1352 /* Checking for errors, image size shouldn't be
1353 * larger than 255.000 bytes */
1354 if (actimage->size > 255000) {
1355 purple_debug_warning("gg", "ggp_recv_message_handler: received image large than 255 kb\n");
1356 continue;
1357 }
1358
1359 gg_image_request(info->session, ev->event.msg.sender,
1360 actimage->size, actimage->crc32);
1361
1362 handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32);
1363 g_string_insert(message, byteoffset, handlerid);
1364 increased_len += strlen(handlerid);
1365 g_free(handlerid);
1366 continue;
1367 }
1368
1369 if (actformat->font & GG_FONT_BOLD) {
1370 if (bold == FALSE) {
1371 g_string_insert(message, byteoffset, "<b>");
1372 increased_len += 3;
1373 bold = TRUE;
1374 }
1375 } else if (bold) {
1376 g_string_insert(message, byteoffset, "</b>");
1377 increased_len += 4;
1378 bold = FALSE;
1379 }
1380
1381 if (actformat->font & GG_FONT_ITALIC) {
1382 if (italic == FALSE) {
1383 g_string_insert(message, byteoffset, "<i>");
1384 increased_len += 3;
1385 italic = TRUE;
1386 }
1387 } else if (italic) {
1388 g_string_insert(message, byteoffset, "</i>");
1389 increased_len += 4;
1390 italic = FALSE;
1391 }
1392
1393 if (actformat->font & GG_FONT_UNDERLINE) {
1394 if (under == FALSE) {
1395 g_string_insert(message, byteoffset, "<u>");
1396 increased_len += 3;
1397 under = TRUE;
1398 }
1399 } else if (under) {
1400 g_string_insert(message, byteoffset, "</u>");
1401 increased_len += 4;
1402 under = FALSE;
1403 }
1404 }
1405
1406 msg = message->str;
1407 g_string_free(message, FALSE);
1408
1409 if (got_image) {
1410 info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg);
1411 return;
1412 }
1413 }
1414
1415 purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d)\n",
1268 from, msg, ev->event.msg.msgclass, 1416 from, msg, ev->event.msg.msgclass,
1269 ev->event.msg.recipients_count); 1417 ev->event.msg.recipients_count);
1270 1418
1271 if (ev->event.msg.recipients_count == 0) { 1419 if (ev->event.msg.recipients_count == 0) {
1272 serv_got_im(gc, from, msg, 0, ev->event.msg.time); 1420 serv_got_im(gc, from, msg, 0, ev->event.msg.time);
1298 PURPLE_MESSAGE_RECV, msg, ev->event.msg.time); 1446 PURPLE_MESSAGE_RECV, msg, ev->event.msg.time);
1299 g_free(buddy_name); 1447 g_free(buddy_name);
1300 } 1448 }
1301 g_free(msg); 1449 g_free(msg);
1302 g_free(from); 1450 g_free(from);
1451 }
1452 /* }}} */
1453
1454 /*
1455 */
1456 /* static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev) {{{ */
1457 static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev)
1458 {
1459 GGPInfo *info = gc->proto_data;
1460 PurpleStoredImage *image;
1461 gint imgid = (gint) g_hash_table_lookup(info->pending_images, &ev->event.image_request.crc32);
1462
1463 purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u\n", ev->event.image_request.crc32);
1464
1465 if(imgid)
1466 {
1467 if((image = purple_imgstore_find_by_id(imgid))) {
1468 gint image_size = purple_imgstore_get_size(image);
1469 gconstpointer image_bin = purple_imgstore_get_data(image);
1470 const char *image_filename = purple_imgstore_get_filename(image);
1471
1472 purple_debug_info("gg", "ggp_send_image_handler: sending image imgid: %i, crc: %u\n", imgid, ev->event.image_request.crc32);
1473 gg_image_reply(info->session, (unsigned long int)ev->event.image_request.sender, image_filename, image_bin, image_size);
1474 purple_imgstore_unref(image);
1475 } else {
1476 purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32);
1477 }
1478 g_hash_table_remove(info->pending_images, &ev->event.image_request.crc32);
1479 }
1303 } 1480 }
1304 /* }}} */ 1481 /* }}} */
1305 1482
1306 /* 1483 /*
1307 */ 1484 */
1328 break; 1505 break;
1329 case GG_EVENT_MSG: 1506 case GG_EVENT_MSG:
1330 ggp_recv_message_handler(gc, ev); 1507 ggp_recv_message_handler(gc, ev);
1331 break; 1508 break;
1332 case GG_EVENT_ACK: 1509 case GG_EVENT_ACK:
1510 /* Changing %u to %i fixes compiler warning */
1333 purple_debug_info("gg", 1511 purple_debug_info("gg",
1334 "message sent to: %u, delivery status=%d, seq=%d\n", 1512 "ggp_callback_recv: message sent to: %i, delivery status=%d, seq=%d\n",
1335 ev->event.ack.recipient, ev->event.ack.status, 1513 ev->event.ack.recipient, ev->event.ack.status,
1336 ev->event.ack.seq); 1514 ev->event.ack.seq);
1515 break;
1516 case GG_EVENT_IMAGE_REPLY:
1517 ggp_recv_image_handler(gc, ev);
1518 break;
1519 case GG_EVENT_IMAGE_REQUEST:
1520 ggp_send_image_handler(gc, ev);
1337 break; 1521 break;
1338 case GG_EVENT_NOTIFY: 1522 case GG_EVENT_NOTIFY:
1339 case GG_EVENT_NOTIFY_DESCR: 1523 case GG_EVENT_NOTIFY_DESCR:
1340 { 1524 {
1341 struct gg_notify_reply *n; 1525 struct gg_notify_reply *n;
1563 /* static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) {{{ */ 1747 /* static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) {{{ */
1564 static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) 1748 static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full)
1565 { 1749 {
1566 PurpleStatus *status; 1750 PurpleStatus *status;
1567 char *text, *tmp; 1751 char *text, *tmp;
1568 const char *msg, *name; 1752 const char *msg, *name, *alias;
1569 1753
1570 g_return_if_fail(b != NULL); 1754 g_return_if_fail(b != NULL);
1571 1755
1572 status = purple_presence_get_active_status(purple_buddy_get_presence(b)); 1756 status = purple_presence_get_active_status(purple_buddy_get_presence(b));
1573 msg = purple_status_get_attr_string(status, "message"); 1757 msg = purple_status_get_attr_string(status, "message");
1574 name = purple_status_get_name(status); 1758 name = purple_status_get_name(status);
1759 alias = purple_buddy_get_alias(b);
1760
1761 purple_notify_user_info_add_pair (user_info, _("Alias"), alias);
1575 1762
1576 if (msg != NULL) { 1763 if (msg != NULL) {
1577 text = g_markup_escape_text(msg, -1); 1764 text = g_markup_escape_text(msg, -1);
1578 if (PURPLE_BUDDY_IS_ONLINE(b)) { 1765 if (PURPLE_BUDDY_IS_ONLINE(b)) {
1579 tmp = g_strdup_printf("%s: %s", name, text); 1766 tmp = g_strdup_printf("%s: %s", name, text);
1704 info->session = NULL; 1891 info->session = NULL;
1705 info->chats = NULL; 1892 info->chats = NULL;
1706 info->chats_count = 0; 1893 info->chats_count = 0;
1707 info->token = NULL; 1894 info->token = NULL;
1708 info->searches = ggp_search_new(); 1895 info->searches = ggp_search_new();
1896 info->pending_richtext_messages = NULL;
1897 info->pending_images = g_hash_table_new(g_int_hash, g_int_equal);
1709 1898
1710 gc->proto_data = info; 1899 gc->proto_data = info;
1711 1900
1712 glp->uin = ggp_get_uin(account); 1901 glp->uin = ggp_get_uin(account);
1713 glp->password = (char *)purple_account_get_password(account); 1902 glp->password = (char *)purple_account_get_password(account);
1903 glp->image_size = 255;
1714 1904
1715 presence = purple_account_get_presence(account); 1905 presence = purple_account_get_presence(account);
1716 status = purple_presence_get_active_status(presence); 1906 status = purple_presence_get_active_status(presence);
1717 1907
1718 glp->async = 1; 1908 glp->async = 1;
1758 * upon the contents of info->searches, which we are about to destroy. 1948 * upon the contents of info->searches, which we are about to destroy.
1759 */ 1949 */
1760 purple_notify_close_with_handle(gc); 1950 purple_notify_close_with_handle(gc);
1761 1951
1762 ggp_search_destroy(info->searches); 1952 ggp_search_destroy(info->searches);
1953 g_list_free(info->pending_richtext_messages);
1954 g_hash_table_destroy(info->pending_images);
1763 g_free(info); 1955 g_free(info);
1764 gc->proto_data = NULL; 1956 gc->proto_data = NULL;
1765 } 1957 }
1766 1958
1767 if (gc->inpa > 0) 1959 if (gc->inpa > 0)
1777 static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg, 1969 static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg,
1778 PurpleMessageFlags flags) 1970 PurpleMessageFlags flags)
1779 { 1971 {
1780 GGPInfo *info = gc->proto_data; 1972 GGPInfo *info = gc->proto_data;
1781 char *tmp, *plain; 1973 char *tmp, *plain;
1782 int ret = 0; 1974 int ret = 1;
1783 1975 unsigned char format[1024];
1784 if (strlen(msg) == 0) { 1976 unsigned int format_length = sizeof(struct gg_msg_richtext);
1977 gint pos = 0;
1978 GData *attribs;
1979 const char *start, *end = NULL, *last;
1980
1981 if (msg == NULL || *msg == 0) {
1785 return 0; 1982 return 0;
1786 } 1983 }
1787 1984
1788 purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg); 1985 last = msg;
1789 plain = purple_unescape_html(msg); 1986
1987 /* Check if the message is richtext */
1988 /* TODO: Check formatting, too */
1989 if(purple_markup_find_tag("img", last, &start, &end, &attribs)) {
1990
1991 GString *string_buffer = g_string_new(NULL);
1992 struct gg_msg_richtext fmt;
1993
1994 do {
1995 PurpleStoredImage *image;
1996 const char *id;
1997
1998 /* Add text before the image */
1999 if(start - last) {
2000 pos = pos + g_utf8_strlen(last, start - last);
2001 g_string_append_len(string_buffer, last, start - last);
2002 }
2003
2004 if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) {
2005 struct gg_msg_richtext_format actformat;
2006 struct gg_msg_richtext_image actimage;
2007 gint image_size = purple_imgstore_get_size(image);
2008 gconstpointer image_bin = purple_imgstore_get_data(image);
2009 const char *image_filename = purple_imgstore_get_filename(image);
2010 uint32_t crc32 = gg_crc32(0, image_bin, image_size);
2011
2012 g_hash_table_insert(info->pending_images, &crc32, (gpointer)atoi(id));
2013 purple_imgstore_ref(image);
2014 purple_debug_info("gg", "ggp_send_im_richtext: got crc: %i for imgid: %i\n", crc32, atoi(id));
2015
2016 actformat.font = GG_FONT_IMAGE;
2017 actformat.position = pos;
2018
2019 actimage.unknown1 = 0x0109;
2020 actimage.size = gg_fix32(image_size);
2021 actimage.crc32 = gg_fix32(crc32);
2022
2023 if (actimage.size > 255000) {
2024 purple_debug_warning("gg", "ggp_send_im_richtext: image over 255kb!\n");
2025 continue;
2026 }
2027
2028 purple_debug_info("gg", "ggp_send_im_richtext: adding images to richtext, size: %i, crc32: %u, name: %s\n", actimage.size, actimage.crc32, image_filename);
2029
2030 memcpy(format + format_length, &actformat, sizeof(actformat));
2031 format_length += sizeof(actformat);
2032 memcpy(format + format_length, &actimage, sizeof(actimage));
2033 format_length += sizeof(actimage);
2034 } else {
2035 purple_debug_error("gg", "ggp_send_im_richtext: image not found in the image store!");
2036 }
2037
2038 last = end + 1;
2039 g_datalist_clear(&attribs);
2040
2041 } while(purple_markup_find_tag("img", last, &start, &end, &attribs));
2042
2043 /* Add text after the images */
2044 if(last && *last) {
2045 pos = pos + g_utf8_strlen(last, -1);
2046 g_string_append(string_buffer, last);
2047 }
2048
2049 fmt.flag = 2;
2050 fmt.length = format_length - sizeof(fmt);
2051 memcpy(format, &fmt, sizeof(fmt));
2052
2053 purple_debug_info("gg", "ggp_send_im: richtext msg = %s\n", string_buffer->str);
2054 plain = purple_unescape_html(string_buffer->str);
2055 g_string_free(string_buffer, TRUE);
2056 } else {
2057 purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg);
2058 plain = purple_unescape_html(msg);
2059 }
2060
1790 tmp = charset_convert(plain, "UTF-8", "CP1250"); 2061 tmp = charset_convert(plain, "UTF-8", "CP1250");
1791 2062
1792 if (NULL == tmp || strlen(tmp) == 0) { 2063 if (tmp && (format_length - sizeof(struct gg_msg_richtext))) {
2064 if(gg_send_message_richtext(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), (unsigned char *)tmp, format, format_length) < 0) {
2065 ret = -1;
2066 } else {
2067 ret = 1;
2068 }
2069 } else if (NULL == tmp || *tmp == 0) {
1793 ret = 0; 2070 ret = 0;
1794 } else if (strlen(tmp) > GG_MSG_MAXSIZE) { 2071 } else if (strlen(tmp) > GG_MSG_MAXSIZE) {
1795 ret = -E2BIG; 2072 ret = -E2BIG;
1796 } else if (gg_send_message(info->session, GG_CLASS_CHAT, 2073 } else if (gg_send_message(info->session, GG_CLASS_CHAT,
1797 ggp_str_to_uin(who), (unsigned char *)tmp) < 0) { 2074 ggp_str_to_uin(who), (unsigned char *)tmp) < 0) {
2101 /* }}} */ 2378 /* }}} */
2102 2379
2103 /* prpl_info setup {{{ */ 2380 /* prpl_info setup {{{ */
2104 static PurplePluginProtocolInfo prpl_info = 2381 static PurplePluginProtocolInfo prpl_info =
2105 { 2382 {
2106 OPT_PROTO_REGISTER_NOSCREENNAME, 2383 OPT_PROTO_REGISTER_NOSCREENNAME | OPT_PROTO_IM_IMAGE,
2107 NULL, /* user_splits */ 2384 NULL, /* user_splits */
2108 NULL, /* protocol_options */ 2385 NULL, /* protocol_options */
2109 {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ 2386 {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
2110 ggp_list_icon, /* list_icon */ 2387 ggp_list_icon, /* list_icon */
2111 NULL, /* list_emblem */ 2388 NULL, /* list_emblem */