libpurple/protocols/jabber/message.c

branch
soc.2013.gobjectification.plugins
changeset 37133
832cd077145e
parent 37103
cdc96a002b33
parent 35788
afa6d777bc7c
child 37134
07746c9a04bf
equal deleted inserted replaced
37132:f4740b6e7525 37133:832cd077145e
22 */ 22 */
23 #include "internal.h" 23 #include "internal.h"
24 24
25 #include "debug.h" 25 #include "debug.h"
26 #include "notify.h" 26 #include "notify.h"
27 #include "smiley-custom.h"
28 #include "smiley-parser.h"
27 #include "server.h" 29 #include "server.h"
28 #include "util.h" 30 #include "util.h"
29 #include "adhoccommands.h" 31 #include "adhoccommands.h"
30 #include "buddy.h" 32 #include "buddy.h"
31 #include "chat.h" 33 #include "chat.h"
435 if (purple_email_is_valid(alt)) { 437 if (purple_email_is_valid(alt)) {
436 gchar *safe_alt = g_strdup_printf("smiley:%s", alt); 438 gchar *safe_alt = g_strdup_printf("smiley:%s", alt);
437 out = g_string_append(out, safe_alt); 439 out = g_string_append(out, safe_alt);
438 g_free(safe_alt); 440 g_free(safe_alt);
439 } else { 441 } else {
440 out = g_string_append(out, alt); 442 gchar *alt_escaped = g_markup_escape_text(alt, -1);
443 out = g_string_append(out, alt_escaped);
444 g_free(alt_escaped);
441 } 445 }
442 } else { 446 } else {
443 out = g_string_append(out, src); 447 out = g_string_append(out, src);
444 } 448 }
445 pos += pos2 - pos; 449 pos += pos2 - pos;
481 } 485 }
482 } 486 }
483 } 487 }
484 488
485 static void 489 static void
486 jabber_message_request_data_cb(JabberData *data, gchar *alt, 490 jabber_message_remote_smiley_got(JabberData *data, gchar *alt, gpointer _smiley)
487 gpointer userdata) 491 {
488 { 492 PurpleRemoteSmiley *smiley = _smiley;
489 PurpleConversation *conv = PURPLE_CONVERSATION(userdata); 493
494 g_free(alt); /* we really don't need it */
490 495
491 if (data) { 496 if (data) {
492 purple_conversation_custom_smiley_write(conv, alt, 497 purple_debug_info("jabber",
493 jabber_data_get_data(data), 498 "smiley data retrieved successfully");
494 jabber_data_get_size(data)); 499 purple_remote_smiley_write(smiley, jabber_data_get_data(data),
495 purple_conversation_custom_smiley_close(conv, alt); 500 jabber_data_get_size(data));
496 } 501 purple_remote_smiley_close(smiley);
497 502 } else {
498 g_free(alt); 503 purple_debug_error("jabber", "failed retrieving smiley data");
504 purple_remote_smiley_failed(smiley);
505 }
506
507 g_object_unref(smiley);
508 }
509
510 static void
511 jabber_message_remote_smiley_add(JabberStream *js, PurpleConversation *conv,
512 const gchar *from, const gchar *shortcut, const gchar *cid)
513 {
514 PurpleRemoteSmiley *smiley;
515 const JabberData *jdata;
516
517 purple_debug_misc("jabber", "about to add remote smiley %s to the conv",
518 shortcut);
519
520 smiley = purple_conversation_add_remote_smiley(conv, shortcut);
521 if (!smiley) {
522 purple_debug_misc("jabber", "smiley was already present");
523 return;
524 }
525
526 /* TODO: cache lookup by "cid" */
527
528 jdata = jabber_data_find_remote_by_cid(js, from, cid);
529 if (jdata) {
530 purple_debug_info("jabber", "smiley data is already known");
531
532 purple_remote_smiley_write(smiley, jabber_data_get_data(jdata),
533 jabber_data_get_size(jdata));
534 purple_remote_smiley_close(smiley);
535 } else {
536 gchar *alt = g_strdup(shortcut); /* it it really necessary? */
537
538 purple_debug_info("jabber", "smiley data is unknown, "
539 "need to request it");
540
541 g_object_ref(smiley);
542 jabber_data_request(js, cid, from, alt, FALSE,
543 jabber_message_remote_smiley_got, smiley);
544 }
499 } 545 }
500 546
501 void jabber_message_parse(JabberStream *js, PurpleXmlNode *packet) 547 void jabber_message_parse(JabberStream *js, PurpleXmlNode *packet)
502 { 548 {
503 JabberMessage *jm; 549 JabberMessage *jm;
598 char *c; 644 char *c;
599 645
600 const PurpleConnection *gc = js->gc; 646 const PurpleConnection *gc = js->gc;
601 PurpleAccount *account = purple_connection_get_account(gc); 647 PurpleAccount *account = purple_connection_get_account(gc);
602 PurpleConversation *conv = NULL; 648 PurpleConversation *conv = NULL;
603 GList *smiley_refs = NULL; 649 GList *smiley_refs = NULL, *it;
604 gchar *reformatted_xhtml; 650 gchar *reformatted_xhtml;
605 651
606 if (purple_account_get_bool(account, "custom_smileys", TRUE)) { 652 if (purple_account_get_bool(account, "custom_smileys", TRUE)) {
607 /* find a list of smileys ("cid" and "alt" text pairs) 653 /* find a list of smileys ("cid" and "alt" text pairs)
608 occuring in the message */ 654 occuring in the message */
650 696
651 /* add known custom emoticons to the conversation */ 697 /* add known custom emoticons to the conversation */
652 /* note: if there were no smileys in the incoming message, or 698 /* note: if there were no smileys in the incoming message, or
653 if receiving custom smileys is turned off, smiley_refs will 699 if receiving custom smileys is turned off, smiley_refs will
654 be NULL */ 700 be NULL */
655 for (; conv && smiley_refs ; smiley_refs = g_list_delete_link(smiley_refs, smiley_refs)) { 701 for (it = smiley_refs; it; it = g_list_next(it)) {
656 JabberSmileyRef *ref = (JabberSmileyRef *) smiley_refs->data; 702 JabberSmileyRef *ref = it->data;
657 const gchar *cid = ref->cid; 703
658 gchar *alt = g_strdup(ref->alt); 704 if (conv) {
659 705 jabber_message_remote_smiley_add(js,
660 purple_debug_info("jabber", 706 conv, from, ref->alt, ref->cid);
661 "about to add custom smiley %s to the conv\n", alt);
662 if (purple_conversation_custom_smiley_add(conv, alt, "cid", cid,
663 TRUE)) {
664 const JabberData *data =
665 jabber_data_find_remote_by_cid(js, from, cid);
666 /* if data is already known, we write it immediatly */
667 if (data) {
668 purple_debug_info("jabber",
669 "data is already known\n");
670 purple_conversation_custom_smiley_write(conv, alt,
671 jabber_data_get_data(data),
672 jabber_data_get_size(data));
673 purple_conversation_custom_smiley_close(conv, alt);
674 } else {
675 /* we need to request the smiley (data) */
676 purple_debug_info("jabber",
677 "data is unknown, need to request it\n");
678 jabber_data_request(js, cid, from, alt, FALSE,
679 jabber_message_request_data_cb, conv);
680 }
681 } 707 }
708
682 g_free(ref->cid); 709 g_free(ref->cid);
683 g_free(ref->alt); 710 g_free(ref->alt);
684 g_free(ref); 711 g_free(ref);
685 } 712 }
713 g_list_free(smiley_refs);
686 714
687 /* Convert all newlines to whitespace. Technically, even regular, non-XML HTML is supposed to ignore newlines, but Pidgin has, as convention 715 /* Convert all newlines to whitespace. Technically, even regular, non-XML HTML is supposed to ignore newlines, but Pidgin has, as convention
688 * treated \n as a newline for compatibility with other protocols 716 * treated \n as a newline for compatibility with other protocols
689 */ 717 */
690 for (c = jm->xhtml; *c != '\0'; c++) { 718 for (c = jm->xhtml; *c != '\0'; c++) {
819 } else { 847 } else {
820 return "image/x-icon"; /* or something... */ 848 return "image/x-icon"; /* or something... */
821 } 849 }
822 } 850 }
823 851
824 static GList *
825 jabber_message_xhtml_find_smileys(const char *xhtml)
826 {
827 GList *smileys = purple_smileys_get_all();
828 GList *found_smileys = NULL;
829
830 for (; smileys ; smileys = g_list_delete_link(smileys, smileys)) {
831 PurpleSmiley *smiley = (PurpleSmiley *) smileys->data;
832
833 const gchar *shortcut = purple_smiley_get_shortcut(smiley);
834 const gssize len = strlen(shortcut);
835
836 gchar *escaped = g_markup_escape_text(shortcut, len);
837 const char *pos = strstr(xhtml, escaped);
838
839 if (pos) {
840 found_smileys = g_list_append(found_smileys, smiley);
841 }
842
843 g_free(escaped);
844 }
845
846 return found_smileys;
847 }
848
849 static gchar *
850 jabber_message_get_smileyfied_xhtml(const gchar *xhtml, const GList *smileys)
851 {
852 /* create XML element for all smileys (img tags) */
853 GString *result = g_string_new(NULL);
854 int pos = 0;
855 int length = strlen(xhtml);
856
857 while (pos < length) {
858 const GList *iterator;
859 gboolean found_smiley = FALSE;
860
861 for (iterator = smileys ; iterator ;
862 iterator = g_list_next(iterator)) {
863 const PurpleSmiley *smiley = (PurpleSmiley *) iterator->data;
864 const gchar *shortcut = purple_smiley_get_shortcut(smiley);
865 const gssize len = strlen(shortcut);
866 gchar *escaped = g_markup_escape_text(shortcut, len);
867
868 if (g_str_has_prefix(&(xhtml[pos]), escaped)) {
869 /* we found the current smiley at this position */
870 const JabberData *data =
871 jabber_data_find_local_by_alt(shortcut);
872 PurpleXmlNode *img = jabber_data_get_xhtml_im(data, shortcut);
873 int len;
874 gchar *img_text = purple_xmlnode_to_str(img, &len);
875
876 found_smiley = TRUE;
877 result = g_string_append(result, img_text);
878 g_free(img_text);
879 pos += strlen(escaped);
880 g_free(escaped);
881 purple_xmlnode_free(img);
882 break;
883 } else {
884 /* cleanup from the before the next round... */
885 g_free(escaped);
886 }
887 }
888 if (!found_smiley) {
889 /* there was no smiley here, just copy one byte */
890 result = g_string_append_c(result, xhtml[pos]);
891 pos++;
892 }
893 }
894
895 return g_string_free(result, FALSE);
896 }
897
898 static gboolean 852 static gboolean
899 jabber_conv_support_custom_smileys(JabberStream *js, 853 jabber_conv_support_custom_smileys(JabberStream *js,
900 PurpleConversation *conv, 854 PurpleConversation *conv,
901 const gchar *who) 855 const gchar *who)
902 { 856 {
924 } else { 878 } else {
925 return FALSE; 879 return FALSE;
926 } 880 }
927 } 881 }
928 882
883 static gboolean
884 jabber_message_smileyify_cb(GString *out, PurpleSmiley *smiley,
885 PurpleConversation *_empty, gpointer _unused)
886 {
887 const gchar *shortcut;
888 const JabberData *data;
889 PurpleXmlNode *smiley_node;
890 gchar *node_xml;
891
892 shortcut = purple_smiley_get_shortcut(smiley);
893 data = jabber_data_find_local_by_alt(shortcut);
894
895 if (!data)
896 return FALSE;
897
898 smiley_node = jabber_data_get_xhtml_im(data, shortcut);
899 node_xml = purple_xmlnode_to_str(smiley_node, NULL);
900
901 g_string_append(out, node_xml);
902
903 purple_xmlnode_free(smiley_node);
904 g_free(node_xml);
905
906 return TRUE;
907 }
908
929 static char * 909 static char *
930 jabber_message_smileyfy_xhtml(JabberMessage *jm, const char *xhtml) 910 jabber_message_smileyfy_xhtml(JabberMessage *jm, const char *xhtml)
931 { 911 {
932 PurpleAccount *account = purple_connection_get_account(jm->js->gc); 912 PurpleAccount *account = purple_connection_get_account(jm->js->gc);
933 PurpleConversation *conv = 913 GList *found_smileys, *it, *it_next;
934 purple_conversations_find_with_account(jm->to, 914 PurpleConversation *conv;
935 account); 915 gboolean has_too_large_smiley = FALSE;
936 916 gchar *smileyfied_xhtml = NULL;
937 if (jabber_conv_support_custom_smileys(jm->js, conv, jm->to)) { 917
938 GList *found_smileys = jabber_message_xhtml_find_smileys(xhtml); 918 conv = purple_conversations_find_with_account(jm->to, account);
939 919
940 if (found_smileys) { 920 if (!jabber_conv_support_custom_smileys(jm->js, conv, jm->to))
941 gchar *smileyfied_xhtml = NULL; 921 return NULL;
942 const GList *iterator; 922
943 GList *valid_smileys = NULL; 923 found_smileys = purple_smiley_find(purple_smiley_custom_get_list(),
944 gboolean has_too_large_smiley = FALSE; 924 xhtml, TRUE);
945 925 if (!found_smileys)
946 for (iterator = found_smileys; iterator ; 926 return NULL;
947 iterator = g_list_next(iterator)) { 927
948 PurpleSmiley *smiley = (PurpleSmiley *) iterator->data; 928 for (it = found_smileys; it; it = it_next) {
949 const gchar *shortcut = purple_smiley_get_shortcut(smiley); 929 PurpleSmiley *smiley = it->data;
950 const JabberData *data = 930 PurpleStoredImage *smiley_image;
951 jabber_data_find_local_by_alt(shortcut); 931 gboolean valid = TRUE;
952 PurpleStoredImage *image = purple_smiley_get_stored_image(smiley); 932
953 933 it_next = g_list_next(it);
954 if (purple_imgstore_get_size(image) <= JABBER_DATA_MAX_SIZE) { 934
955 /* the object has not been sent before */ 935 smiley_image = purple_smiley_get_image(smiley);
956 if (!data) { 936 if (!smiley_image) {
957 const gchar *ext = purple_imgstore_get_extension(image); 937 valid = FALSE;
958 JabberStream *js = jm->js; 938 purple_debug_warning("jabber", "broken smiley %s",
959 939 purple_smiley_get_shortcut(smiley));
960 JabberData *new_data = 940 } else if (purple_imgstore_get_size(smiley_image) >
961 jabber_data_create_from_data(purple_imgstore_get_data(image), 941 JABBER_DATA_MAX_SIZE)
962 purple_imgstore_get_size(image), 942 {
963 jabber_message_get_mimetype_from_ext(ext), FALSE, js); 943 has_too_large_smiley = TRUE;
964 purple_debug_info("jabber", 944 valid = FALSE;
965 "cache local smiley alt = %s, cid = %s\n", 945 purple_debug_warning("jabber", "Refusing to send "
966 shortcut, jabber_data_get_cid(new_data)); 946 "smiley %s (too large, max is %d)",
967 jabber_data_associate_local(new_data, shortcut); 947 purple_smiley_get_shortcut(smiley),
968 } 948 JABBER_DATA_MAX_SIZE);
969 valid_smileys = g_list_append(valid_smileys, smiley); 949 }
970 } else { 950
971 has_too_large_smiley = TRUE; 951 if (!valid)
972 purple_debug_warning("jabber", "Refusing to send smiley %s " 952 found_smileys = g_list_delete_link(found_smileys, it);
973 "(too large, max is %d)\n", 953 }
974 purple_smiley_get_shortcut(smiley), 954
975 JABBER_DATA_MAX_SIZE); 955 if (has_too_large_smiley) {
976 } 956 purple_conversation_write(conv, NULL,
977 } 957 _("A custom smiley in the message is too large to send."),
978 958 PURPLE_MESSAGE_ERROR, time(NULL));
979 if (has_too_large_smiley) { 959 }
980 purple_conversation_write(conv, NULL, 960
981 _("A custom smiley in the message is too large to send."), 961 if (!found_smileys)
982 PURPLE_MESSAGE_ERROR, time(NULL)); 962 return NULL;
983 } 963
984 964 for (it = found_smileys; it; it = g_list_next(it)) {
985 smileyfied_xhtml = 965 PurpleSmiley *smiley = it->data;
986 jabber_message_get_smileyfied_xhtml(xhtml, valid_smileys); 966 PurpleStoredImage *smiley_image;
987 g_list_free(found_smileys); 967 const gchar *shortcut = purple_smiley_get_shortcut(smiley);
988 g_list_free(valid_smileys); 968 const gchar *mimetype;
989 969 JabberData *jdata;
990 return smileyfied_xhtml; 970
991 } 971 /* the object has been sent before */
992 } 972 if (jabber_data_find_local_by_alt(shortcut))
993 973 continue;
994 return NULL; 974
975 smiley_image = purple_smiley_get_image(smiley);
976 g_assert(smiley_image != NULL);
977
978 mimetype = jabber_message_get_mimetype_from_ext(
979 purple_imgstore_get_extension(smiley_image));
980
981 jdata = jabber_data_create_from_data(
982 purple_imgstore_get_data(smiley_image),
983 purple_imgstore_get_size(smiley_image),
984 mimetype, FALSE, jm->js);
985
986 purple_debug_info("jabber", "cache local smiley alt=%s, cid=%s",
987 shortcut, jabber_data_get_cid(jdata));
988 jabber_data_associate_local(jdata, shortcut);
989 }
990
991 g_list_free(found_smileys);
992
993 smileyfied_xhtml = purple_smiley_parse_custom(xhtml,
994 jabber_message_smileyify_cb, NULL);
995
996 return smileyfied_xhtml;
995 } 997 }
996 998
997 void jabber_message_send(JabberMessage *jm) 999 void jabber_message_send(JabberMessage *jm)
998 { 1000 {
999 PurpleXmlNode *message, *child; 1001 PurpleXmlNode *message, *child;

mercurial