comparison libpurple/protocols/yahoo/util.c @ 28363:b289449f3e9f

Make outgoing yahoo messages with links, font color, font face or font size formatting work somewhat correctly. Not heavily tested, but it's definitely an improvement
author Mark Doliner <mark@kingant.net>
date Thu, 20 Aug 2009 01:11:26 +0000
parents c06114f3d58d
children 2d2856a2e7c2
comparison
equal deleted inserted replaced
28362:c06114f3d58d 28363:b289449f3e9f
658 /* This probably isn't necessary, especially if we made the outter HTML 658 /* This probably isn't necessary, especially if we made the outter HTML
659 * node an empty span. But the HTML is simpler this way. */ 659 * node an empty span. But the HTML is simpler this way. */
660 xmlstr2 = g_strndup(xmlstr1 + 6, strlen(xmlstr1) - 13); 660 xmlstr2 = g_strndup(xmlstr1 + 6, strlen(xmlstr1) - 13);
661 g_free(xmlstr1); 661 g_free(xmlstr1);
662 662
663 purple_debug_misc("yahoo", "yahoo_codes_to_html: Returning string: '%s'.\n", xmlstr2); 663 purple_debug_misc("yahoo", "yahoo_codes_to_html(%s)=%s\n", x, xmlstr2);
664 return xmlstr2; 664 return xmlstr2;
665 } 665 }
666 666
667 /* borrowed from gtkimhtml */ 667 /* borrowed from gtkimhtml */
668 #define MAX_FONT_SIZE 7 668 #define MAX_FONT_SIZE 7
671 671
672 enum fontattr_type 672 enum fontattr_type
673 { 673 {
674 FATYPE_SIZE, 674 FATYPE_SIZE,
675 FATYPE_COLOR, 675 FATYPE_COLOR,
676 FATYPE_FACE, 676 FATYPE_FACE
677 FATYPE_JUNK
678 }; 677 };
679 678
680 typedef struct 679 typedef struct
681 { 680 {
682 enum fontattr_type type; 681 enum fontattr_type type;
683 union { 682 union {
684 int size; 683 int size;
685 char *color; 684 char *color;
686 char *face; 685 char *face;
687 char *junk;
688 } u; 686 } u;
689 } fontattr; 687 } fontattr;
690 688
691 typedef struct 689 typedef struct
692 { 690 {
714 g_free(l->data); 712 g_free(l->data);
715 l = g_slist_delete_link(l, l); 713 l = g_slist_delete_link(l, l);
716 } 714 }
717 } 715 }
718 716
719 static void _parse_font_tag(const char *src, GString *dest, int *i, int *j, 717 static void parse_font_tag(const char *src, GString *dest, const char *tag_name, const char *tag,
720 int len, GSList **colors, GSList **tags, GQueue *ftattr) 718 int src_len, GSList **colors, GSList **tags, GQueue *ftattr)
721 { 719 {
722 int m, n, vstart; 720 const char *start;
723 gboolean quote = FALSE, done = FALSE; 721 const char *end;
724 722 GData *attributes;
725 m = *j; 723 const char *attribute;
726 724 gboolean needendtag;
727 while (1) { 725 fontattr *f;
728 m++; 726 GString *tmp;
729 727
730 if (m >= len) { 728 purple_markup_find_tag(tag_name, tag, &start, &end, &attributes);
731 g_string_append(dest, &src[*i]); 729
732 *i = len; 730 attribute = g_datalist_get_data(&attributes, "color");
733 break; 731 if (attribute != NULL) {
734 } 732 f = g_new(fontattr, 1);
735 733 f->type = FATYPE_COLOR;
736 if (src[m] == '=') { 734 f->u.color = g_strdup(attribute);
737 n = vstart = m; 735 if (!ftattr)
738 while (1) { 736 ftattr = g_queue_new();
739 n++; 737 g_queue_push_head(ftattr, f);
740 738 }
741 if (n >= len) { 739
742 m = n; 740 attribute = g_datalist_get_data(&attributes, "face");
743 break; 741 if (attribute != NULL) {
742 f = g_new(fontattr, 1);
743 f->type = FATYPE_FACE;
744 f->u.face = g_strdup(attribute);
745 if (!ftattr)
746 ftattr = g_queue_new();
747 g_queue_push_tail(ftattr, f);
748 }
749
750 attribute = g_datalist_get_data(&attributes, "size");
751 if (attribute != NULL) {
752 f = g_new(fontattr, 1);
753 f->type = FATYPE_SIZE;
754 f->u.size = POINT_SIZE(strtol(attribute, NULL, 10));
755 if (!ftattr)
756 ftattr = g_queue_new();
757 g_queue_push_tail(ftattr, f);
758 }
759
760 g_datalist_clear(&attributes);
761
762 needendtag = FALSE;
763 tmp = g_string_new(NULL);
764
765 if (ftattr != NULL && !g_queue_is_empty(ftattr)) {
766 while ((f = g_queue_pop_tail(ftattr))) {
767 switch (f->type) {
768 case FATYPE_SIZE:
769 if (!needendtag) {
770 needendtag = TRUE;
771 g_string_append(dest, "<font ");
744 } 772 }
745 773
746 if (src[n] == '"') { 774 g_string_append_printf(dest, "size=\"%d\" ", f->u.size);
747 if (!quote) { 775 break;
748 quote = TRUE; 776 case FATYPE_FACE:
749 vstart = n; 777 if (!needendtag) {
750 continue; 778 needendtag = TRUE;
751 } else { 779 g_string_append(dest, "<font ");
752 done = 1;
753 }
754 } 780 }
755 781
756 if (!quote && ((src[n] == ' ') || (src[n] == '>'))) 782 g_string_append_printf(dest, "face=\"%s\" ", f->u.face);
757 done = TRUE; 783 break;
758 784
759 if (done) { 785 case FATYPE_COLOR:
760 if (!g_ascii_strncasecmp(&src[*j+1], "FACE", m - *j - 1)) { 786 if (needendtag) {
761 fontattr *f; 787 g_string_append(tmp, "</font>");
762 788 dest->str[dest->len-1] = '>';
763 f = g_new(fontattr, 1); 789 needendtag = TRUE;
764 f->type = FATYPE_FACE;
765 f->u.face = g_strndup(&src[vstart+1], n-vstart-1);
766 if (!ftattr)
767 ftattr = g_queue_new();
768 g_queue_push_tail(ftattr, f);
769 m = n;
770 break;
771 } else if (!g_ascii_strncasecmp(&src[*j+1], "SIZE", m - *j - 1)) {
772 fontattr *f;
773
774 f = g_new(fontattr, 1);
775 f->type = FATYPE_SIZE;
776 f->u.size = POINT_SIZE(strtol(&src[vstart+1], NULL, 10));
777 if (!ftattr)
778 ftattr = g_queue_new();
779 g_queue_push_tail(ftattr, f);
780 m = n;
781 break;
782 } else if (!g_ascii_strncasecmp(&src[*j+1], "COLOR", m - *j - 1)) {
783 fontattr *f;
784
785 f = g_new(fontattr, 1);
786 f->type = FATYPE_COLOR;
787 f->u.color = g_strndup(&src[vstart+1], n-vstart-1);
788 if (!ftattr)
789 ftattr = g_queue_new();
790 g_queue_push_head(ftattr, f);
791 m = n;
792 break;
793 } else {
794 fontattr *f;
795
796 f = g_new(fontattr, 1);
797 f->type = FATYPE_JUNK;
798 f->u.junk = g_strndup(&src[*j+1], n-*j);
799 if (!ftattr)
800 ftattr = g_queue_new();
801 g_queue_push_tail(ftattr, f);
802 m = n;
803 break;
804 }
805
806 } 790 }
791
792 g_string_append(tmp, *colors ? (*colors)->data : "\033[#000000m");
793 g_string_append_printf(dest, "\033[%sm", f->u.color);
794 *colors = g_slist_prepend(*colors,
795 g_strdup_printf("\033[%sm", f->u.color));
796 break;
807 } 797 }
808 } 798 fontattr_free(f);
809 799 }
810 if (src[m] == ' ') 800
811 *j = m; 801 g_queue_free(ftattr);
812 802 ftattr = NULL;
813 if (src[m] == '>') { 803
814 gboolean needendtag = FALSE; 804 if (needendtag) {
815 fontattr *f; 805 dest->str[dest->len-1] = '>';
816 GString *tmp = g_string_new(NULL); 806 *tags = g_slist_prepend(*tags, g_strdup("</font>"));
817 807 g_string_free(tmp, TRUE);
818 if (!g_queue_is_empty(ftattr)) { 808 } else {
819 while ((f = g_queue_pop_tail(ftattr))) { 809 *tags = g_slist_prepend(*tags, tmp->str);
820 switch (f->type) { 810 g_string_free(tmp, FALSE);
821 case FATYPE_SIZE:
822 if (!needendtag) {
823 needendtag = TRUE;
824 g_string_append(dest, "<font ");
825 }
826
827 g_string_append_printf(dest, "size=\"%d\" ", f->u.size);
828 break;
829 case FATYPE_FACE:
830 if (!needendtag) {
831 needendtag = TRUE;
832 g_string_append(dest, "<font ");
833 }
834
835 g_string_append_printf(dest, "face=\"%s\" ", f->u.face);
836 break;
837 case FATYPE_JUNK:
838 if (!needendtag) {
839 needendtag = TRUE;
840 g_string_append(dest, "<font ");
841 }
842
843 g_string_append(dest, f->u.junk);
844 break;
845
846 case FATYPE_COLOR:
847 if (needendtag) {
848 g_string_append(tmp, "</font>");
849 dest->str[dest->len-1] = '>';
850 needendtag = TRUE;
851 }
852
853 g_string_append(tmp, *colors ? (*colors)->data : "\033[#000000m");
854 g_string_append_printf(dest, "\033[%sm", f->u.color);
855 *colors = g_slist_prepend(*colors,
856 g_strdup_printf("\033[%sm", f->u.color));
857 break;
858 }
859 fontattr_free(f);
860 }
861
862 g_queue_free(ftattr);
863 ftattr = NULL;
864
865 if (needendtag) {
866 dest->str[dest->len-1] = '>';
867 *tags = g_slist_prepend(*tags, g_strdup("</font>"));
868 g_string_free(tmp, TRUE);
869 } else {
870 *tags = g_slist_prepend(*tags, tmp->str);
871 g_string_free(tmp, FALSE);
872 }
873 }
874
875 *i = *j = m;
876 break;
877 } 811 }
878 } 812 }
879 } 813 }
880 814
881 char *yahoo_html_to_codes(const char *src) 815 char *yahoo_html_to_codes(const char *src)
927 861
928 tag = g_strndup(src + i, j - i + 1); 862 tag = g_strndup(src + i, j - i + 1);
929 tag_name = yahoo_markup_get_tag_name(tag, &is_closing_tag); 863 tag_name = yahoo_markup_get_tag_name(tag, &is_closing_tag);
930 864
931 if (g_str_equal(tag_name, "a")) { 865 if (g_str_equal(tag_name, "a")) {
932 j += 7; 866 const char *start;
933 g_string_append(dest, "\033[lm"); 867 const char *end;
934 if (purple_str_has_prefix(src + j, "mailto:")) 868 GData *attributes;
935 j += sizeof("mailto:") - 1; 869 const char *attribute;
936 while (1) { 870
937 g_string_append_c(dest, src[j]); 871 /*
938 if (++j >= src_len) { 872 * TODO: Ideally we would replace this:
939 i = src_len; 873 * <a href="http://pidgin.im/">Pidgin</a>
940 break; 874 * with this:
941 } 875 * Pidgin (http://pidgin.im/)
942 if (src[j] == '"') { 876 *
943 g_string_append(dest, "\033[xlm"); 877 * Currently we drop the text within the <a> tag and
944 while (1) { 878 * just show the URL. Doing it the fancy way is
945 if (++j >= src_len) { 879 * complicated when dealing with HTML tags within the
946 i = src_len; 880 * <a> tag.
947 break; 881 */
948 } 882
949 if (!g_ascii_strncasecmp(&src[j], "</A>", 4)) { 883 /* Append the URL */
950 j += 3; 884 purple_markup_find_tag(tag_name, tag, &start, &end, &attributes);
951 break; 885 attribute = g_datalist_get_data(&attributes, "href");
952 } 886 if (attribute != NULL) {
953 } 887 if (purple_str_has_prefix(attribute, "mailto:"))
954 i = j; 888 attribute += 7;
955 break; 889 g_string_append(dest, attribute);
956 }
957 } 890 }
891 g_datalist_clear(&attributes);
892
893 /* Skip past the closing </a> tag */
894 end = purple_strcasestr(src + j, "</a>");
895 if (end != NULL)
896 j = end - src + 3;
958 897
959 } else if (g_str_equal(tag_name, "font")) { 898 } else if (g_str_equal(tag_name, "font")) {
960 _parse_font_tag(src, dest, &i, &j, src_len, &colors, &tags, ftattr); 899 parse_font_tag(src, dest, tag_name, tag, src_len, &colors, &tags, ftattr);
961 } else if (g_str_equal(tag_name, "b")) { 900 } else if (g_str_equal(tag_name, "b")) {
962 g_string_append(dest, "\033[1m"); 901 g_string_append(dest, "\033[1m");
963 current_state.bold = TRUE; 902 current_state.bold = TRUE;
964 } else if (g_str_equal(tag_name, "/b")) { 903 } else if (g_str_equal(tag_name, "/b")) {
965 if (current_state.bold) { 904 if (current_state.bold) {
981 if (current_state.underline) { 920 if (current_state.underline) {
982 g_string_append(dest, "\033[x4m"); 921 g_string_append(dest, "\033[x4m");
983 current_state.underline = FALSE; 922 current_state.underline = FALSE;
984 } 923 }
985 } else if (g_str_equal(tag_name, "/a")) { 924 } else if (g_str_equal(tag_name, "/a")) {
986 g_string_append(dest, "\033[xlm"); 925 /* Do nothing */
987 } else if (g_str_equal(tag_name, "br")) { 926 } else if (g_str_equal(tag_name, "br")) {
988 g_string_append_c(dest, '\n'); 927 g_string_append_c(dest, '\n');
989 } else if (g_str_equal(tag_name, "/font")) { 928 } else if (g_str_equal(tag_name, "/font")) {
990 if (tags != NULL) { 929 if (tags != NULL) {
991 char *etag = tags->data; 930 char *etag = tags->data;
1021 g_string_append_c(dest, src[i]); 960 g_string_append_c(dest, src[i]);
1022 } 961 }
1023 } 962 }
1024 963
1025 esc = g_strescape(dest->str, NULL); 964 esc = g_strescape(dest->str, NULL);
1026 purple_debug_misc("yahoo", "yahoo_html_to_codes: Returning string: '%s'.\n", esc); 965 purple_debug_misc("yahoo", "yahoo_html_to_codes(%s)=%s\n", src, esc);
1027 g_free(esc); 966 g_free(esc);
1028 967
1029 yahoo_htc_list_cleanup(colors); 968 yahoo_htc_list_cleanup(colors);
1030 yahoo_htc_list_cleanup(tags); 969 yahoo_htc_list_cleanup(tags);
1031 970