Mercurial > pidgin.yaz
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 |