Mercurial > pidgin
comparison libpurple/protocols/myspace/myspace.c @ 17662:7b890c79aabf
Add msim_markup_to_html() to convert MySpaceIM-style markup to Purple-compatible
HTML, on incoming messages. So far, the <f> tag is supported, with font face,
size, and bold/italic/underline decoration.
Also add msim_test_xml(), containing experiments in using xmlnode to parse
MySpaceIM markup.
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Mon, 25 Jun 2007 04:11:06 +0000 |
parents | 38030f1a2e56 |
children | 814992cefc9c |
comparison
equal
deleted
inserted
replaced
17661:38030f1a2e56 | 17662:7b890c79aabf |
---|---|
675 msim_msg_free(msg); | 675 msim_msg_free(msg); |
676 | 676 |
677 return rc; | 677 return rc; |
678 } | 678 } |
679 | 679 |
680 /** Convert a font point size to purple's HTML font size. | |
681 * | |
682 * Based on libpurple/protocols/bonjour/jabber.c. | |
683 */ | |
684 static guint | |
685 msim_font_size_to_purple(int size) | |
686 { | |
687 if (size > 24) { | |
688 return 7; | |
689 } else if (size >= 21) { | |
690 return 6; | |
691 } else if (size >= 17) { | |
692 return 5; | |
693 } else if (size >= 14) { | |
694 return 4; | |
695 } else if (size >= 12) { | |
696 return 3; | |
697 } else if (size >= 10) { | |
698 return 2; | |
699 } | |
700 | |
701 return 1; | |
702 } | |
703 | |
704 /** Convert a msim markup font height to points. */ | |
705 static guint | |
706 msim_font_height_to_point(guint height) | |
707 { | |
708 /* See also: libpurple/protocols/bonjour/jabber.c | |
709 * _font_size_ichat_to_purple */ | |
710 switch (height) | |
711 { | |
712 case 11: return 8; | |
713 case 12: return 9; | |
714 case 13: return 10; | |
715 case 14: | |
716 case 15: return 11; | |
717 case 16: return 12; | |
718 case 17: | |
719 case 18: return 13; | |
720 case 19: return 14; | |
721 case 20: return 15; | |
722 case 21: return 16; | |
723 default: return 12; | |
724 } | |
725 } | |
726 | |
727 /** Convert an xmlnode of msim markup to an HTML string. | |
728 * @return An HTML string. Caller frees. | |
729 */ | |
730 static gchar *msim_markup_xmlnode_to_html(xmlnode *root) | |
731 { | |
732 xmlnode *node; | |
733 gchar *begin, *inner, *end; | |
734 gchar *final; | |
735 | |
736 if (!root) | |
737 return g_strdup(""); | |
738 | |
739 purple_debug_info("msim", "msim_markup_xmlnode_to_html: got root=%s\n", | |
740 root->name); | |
741 | |
742 begin = inner = end = NULL; | |
743 | |
744 if (!strcmp(root->name, "f")) | |
745 { | |
746 const gchar *face, *height_str, *decor_str; | |
747 GString *gs_end, *gs_begin; | |
748 guint decor, height; | |
749 | |
750 face = xmlnode_get_attrib(root, "n"); | |
751 height_str = xmlnode_get_attrib(root, "h"); | |
752 decor_str = xmlnode_get_attrib(root, "s"); | |
753 | |
754 if (height_str) | |
755 height = atol(height_str); | |
756 else | |
757 height = 12; | |
758 | |
759 if (decor_str) | |
760 decor = atol(decor_str); | |
761 else | |
762 decor = 0; | |
763 | |
764 gs_begin = g_string_new(""); | |
765 g_string_printf(gs_begin, "<font face='%s' size='%d'>", face, | |
766 msim_font_size_to_purple(msim_font_height_to_point(height))); | |
767 gs_end = g_string_new("</font>"); | |
768 | |
769 if (decor & 1) | |
770 { | |
771 g_string_append(gs_begin, "<b>"); | |
772 g_string_prepend(gs_end, "</b>"); | |
773 } | |
774 | |
775 if (decor & 2) | |
776 { | |
777 g_string_append(gs_begin, "<i>"); | |
778 g_string_append(gs_end, "</i>"); | |
779 } | |
780 | |
781 if (decor & 4) | |
782 { | |
783 g_string_append(gs_begin, "<u>"); | |
784 g_string_append(gs_end, "</u>"); | |
785 } | |
786 | |
787 | |
788 begin = gs_begin->str; | |
789 end = gs_end->str; | |
790 } else { | |
791 purple_debug_info("msim", "msim_markup_xmlnode_to_html: " | |
792 "unknown tag name=%s, ignoring", root->name); | |
793 begin = g_strdup(""); | |
794 end = g_strdup(""); | |
795 } | |
796 | |
797 /* Loop over all child nodes. */ | |
798 for (node = root->child; node != NULL; node = node->next) | |
799 { | |
800 switch (node->type) | |
801 { | |
802 case XMLNODE_TYPE_ATTRIB: | |
803 /* Attributes handled above. */ | |
804 break; | |
805 | |
806 case XMLNODE_TYPE_TAG: | |
807 /* A tag or tag with attributes. Recursively descend. */ | |
808 inner = msim_markup_xmlnode_to_html(node); | |
809 | |
810 purple_debug_info("msim", " ** node name=%s\n", node->name); | |
811 break; | |
812 | |
813 | |
814 case XMLNODE_TYPE_DATA: | |
815 /* Literal text. */ | |
816 inner = g_new0(char, node->data_sz + 1); | |
817 strncpy(inner, node->data, node->data_sz); | |
818 inner[node->data_sz + 1] = 0; | |
819 | |
820 purple_debug_info("msim", " ** node data=%s (%s)\n", inner, | |
821 node->data); | |
822 break; | |
823 | |
824 default: | |
825 purple_debug_info("msim", | |
826 "msim_markup_xmlnode_to_html: strange node\n"); | |
827 inner = g_strdup(""); | |
828 } | |
829 } | |
830 | |
831 final = g_strconcat(begin, inner, end, NULL); | |
832 g_free(begin); | |
833 g_free(inner); | |
834 g_free(end); | |
835 | |
836 purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n", | |
837 final); | |
838 | |
839 return final; | |
840 } | |
841 | |
842 /** Convert MySpaceIM markup to GtkIMHtml markup. | |
843 * TODO | |
844 * | |
845 * @return GtkIMHtml markup string, must be g_free()'d. */ | |
846 gchar * | |
847 msim_markup_to_html(const gchar *raw) | |
848 { | |
849 xmlnode *root; | |
850 gchar *str; | |
851 | |
852 root = xmlnode_from_str(raw, -1); | |
853 if (!root) | |
854 { | |
855 purple_debug_info("msim", "msim_markup_to_html: couldn't parse " | |
856 "%s as XML, returning raw\n", raw); | |
857 return g_strdup(raw); | |
858 } | |
859 | |
860 str = msim_markup_xmlnode_to_html(root); | |
861 purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str); | |
862 | |
863 xmlnode_free(root); | |
864 | |
865 return g_strdup(str); | |
866 } | |
867 | |
680 /** | 868 /** |
681 * Handle an incoming instant message. | 869 * Handle an incoming instant message. |
682 * | 870 * |
683 * @param session The session | 871 * @param session The session |
684 * @param msg Message from the server, containing 'f' (userid from) and 'msg'. | 872 * @param msg Message from the server, containing 'f' (userid from) and 'msg'. |
687 * @return TRUE if successful. | 875 * @return TRUE if successful. |
688 */ | 876 */ |
689 gboolean | 877 gboolean |
690 msim_incoming_im(MsimSession *session, MsimMessage *msg) | 878 msim_incoming_im(MsimSession *session, MsimMessage *msg) |
691 { | 879 { |
692 gchar *username; | 880 gchar *username, *msg_msim_markup, *msg_purple_markup; |
693 gchar *msg_text; | |
694 | 881 |
695 username = msim_msg_get_string(msg, "_username"); | 882 username = msim_msg_get_string(msg, "_username"); |
696 msg_text = msim_msg_get_string(msg, "msg"); | 883 msg_msim_markup = msim_msg_get_string(msg, "msg"); |
697 | 884 |
698 /* TODO: replace msim-markup with gtkimhtml. */ | 885 msg_purple_markup = msim_markup_to_html(msg_msim_markup); |
699 | 886 g_free(msg_msim_markup); |
700 serv_got_im(session->gc, username, msg_text, PURPLE_MESSAGE_RECV, time(NULL)); | 887 |
888 serv_got_im(session->gc, username, msg_purple_markup, | |
889 PURPLE_MESSAGE_RECV, time(NULL)); | |
701 | 890 |
702 g_free(username); | 891 g_free(username); |
703 g_free(msg_text); | 892 g_free(msg_purple_markup); |
704 | 893 |
705 return TRUE; | 894 return TRUE; |
706 } | 895 } |
707 | 896 |
708 /** | 897 /** |
2340 * Used to test or try out the internal workings of msimprpl. If you're reading | 2529 * Used to test or try out the internal workings of msimprpl. If you're reading |
2341 * this code for the first time, these functions can be instructive in how | 2530 * this code for the first time, these functions can be instructive in how |
2342 * msimprpl is architected. | 2531 * msimprpl is architected. |
2343 */ | 2532 */ |
2344 void | 2533 void |
2345 msim_test_all(void) __attribute__((__noreturn__())); | 2534 msim_test_all(void) |
2346 { | 2535 { |
2347 guint failures; | 2536 guint failures; |
2348 | 2537 |
2538 | |
2349 failures = 0; | 2539 failures = 0; |
2540 failures += msim_test_xml(); | |
2350 failures += msim_test_msg(); | 2541 failures += msim_test_msg(); |
2351 failures += msim_test_escaping(); | 2542 failures += msim_test_escaping(); |
2352 | 2543 |
2353 if (failures) | 2544 if (failures) |
2354 { | 2545 { |
2357 else | 2548 else |
2358 { | 2549 { |
2359 purple_debug_info("msim", "msim_test_all - all tests passed!\n"); | 2550 purple_debug_info("msim", "msim_test_all - all tests passed!\n"); |
2360 } | 2551 } |
2361 exit(0); | 2552 exit(0); |
2553 } | |
2554 | |
2555 int | |
2556 msim_test_xml(void) | |
2557 { | |
2558 gchar *msg_text; | |
2559 xmlnode *root, *n; | |
2560 guint failures; | |
2561 char *s; | |
2562 int len; | |
2563 | |
2564 failures = 0; | |
2565 | |
2566 msg_text = "<p><f n=\"Arial\" h=\"12\">woo!</f>xxx<c v='black'>yyy</c></p>"; | |
2567 | |
2568 purple_debug_info("msim", "msim_test_xml: msg_text=%s\n", msg_text); | |
2569 | |
2570 root = xmlnode_from_str(msg_text, -1); | |
2571 if (!root) | |
2572 { | |
2573 purple_debug_info("msim", "there is no root\n"); | |
2574 exit(0); | |
2575 } | |
2576 | |
2577 purple_debug_info("msim", "root name=%s, child name=%s\n", root->name, | |
2578 root->child->name); | |
2579 | |
2580 purple_debug_info("msim", "last child name=%s\n", root->lastchild->name); | |
2581 purple_debug_info("msim", "Root xml=%s\n", | |
2582 xmlnode_to_str(root, &len)); | |
2583 purple_debug_info("msim", "Child xml=%s\n", | |
2584 xmlnode_to_str(root->child, &len)); | |
2585 purple_debug_info("msim", "Lastchild xml=%s\n", | |
2586 xmlnode_to_str(root->lastchild, &len)); | |
2587 purple_debug_info("msim", "Next xml=%s\n", | |
2588 xmlnode_to_str(root->next, &len)); | |
2589 purple_debug_info("msim", "Next data=%s\n", | |
2590 xmlnode_get_data(root->next)); | |
2591 purple_debug_info("msim", "Child->next xml=%s\n", | |
2592 xmlnode_to_str(root->child->next, &len)); | |
2593 | |
2594 for (n = root->child; n; n = n->next) | |
2595 { | |
2596 if (n->name) | |
2597 { | |
2598 purple_debug_info("msim", " ** n=%s\n",n->name); | |
2599 } else { | |
2600 purple_debug_info("msim", " ** n data=%s\n", n->data); | |
2601 } | |
2602 } | |
2603 | |
2604 purple_debug_info("msim", "root data=%s, child data=%s, child 'h'=%s\n", | |
2605 xmlnode_get_data(root), | |
2606 xmlnode_get_data(root->child), | |
2607 xmlnode_get_attrib(root->child, "h")); | |
2608 | |
2609 | |
2610 for (n = root->child; | |
2611 n != NULL; | |
2612 n = n->next) | |
2613 { | |
2614 purple_debug_info("msim", "next name=%s\n", n->name); | |
2615 } | |
2616 | |
2617 s = xmlnode_to_str(root, &len); | |
2618 s[len] = 0; | |
2619 | |
2620 purple_debug_info("msim", "str: %s\n", s); | |
2621 g_free(s); | |
2622 | |
2623 xmlnode_free(root); | |
2624 | |
2625 exit(0); | |
2626 | |
2627 return failures; | |
2362 } | 2628 } |
2363 | 2629 |
2364 /** Test MsimMessage for basic functionality. */ | 2630 /** Test MsimMessage for basic functionality. */ |
2365 int | 2631 int |
2366 msim_test_msg(void) | 2632 msim_test_msg(void) |