pidgin/pidgin

Replace all CRLF line-endings with LF line endings (Unix-style). This fixes
some compilation errors on Solaris.

Closes #3096.
--- a/libpurple/protocols/myspace/markup.c Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/markup.c Tue Sep 18 00:47:51 2007 +0000
@@ -1,698 +1,698 @@
-/* MySpaceIM Protocol Plugin - markup
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "myspace.h"
-
-typedef void (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
-
-/* Internal functions */
-
-static guint msim_point_to_purple_size(MsimSession *session, guint point);
-static guint msim_purple_size_to_point(MsimSession *session, guint size);
-static guint msim_height_to_point(MsimSession *session, guint height);
-static guint msim_point_to_height(MsimSession *session, guint point);
-
-static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
-static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
-static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f);
-static gchar *msim_convert_smileys_to_markup(gchar *before);
-static double msim_round(double round);
-
-
-/* Globals */
-
-/* The names in in emoticon_names (for <i n=whatever>) map to corresponding
- * entries in emoticon_symbols (for the ASCII representation of the emoticon).
- *
- * Multiple emoticon symbols in Pidgin can map to one name. List the
- * canonical form, as inserted by the "Smile!" dialog, first. For example,
- * :) comes before :-), because although both are recognized as 'happy',
- * the first is inserted by the smiley button (first symbol in theme).
- *
- * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */
-static struct MSIM_EMOTICON
-{
- gchar *name;
- gchar *symbol;
-} msim_emoticons[] = {
- /* Unfortunately, this list duplicates much of the file
- * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because
- * that file is part of Pidgin, but we're part of libpurple.
- */
- { "bigsmile", ":D" },
- { "bigsmile", ":-D" },
- { "devil", "}:)" },
- { "frazzled", ":Z" },
- { "geek", "B)" },
- { "googles", "%)" },
- { "growl", ":E" },
- { "laugh", ":))" }, /* Must be before ':)' */
- { "happy", ":)" },
- { "happy", ":-)" },
- { "happi", ":)" },
- { "heart", ":X" },
- { "mohawk", "-:" },
- { "mad", "X(" },
- { "messed", "X)" },
- { "nerd", "Q)" },
- { "oops", ":G" },
- { "pirate", "P)" },
- { "scared", ":O" },
- { "sidefrown", ":{" },
- { "sinister", ":B" },
- { "smirk", ":," },
- { "straight", ":|" },
- { "tongue", ":P" },
- { "tongue", ":p" },
- { "tongy", ":P" },
- { "upset", "B|" },
- { "wink", ";-)" },
- { "wink", ";)" },
- { "winc", ";)" },
- { "worried", ":[" },
- { "kiss", ":x" },
- { NULL, NULL }
-};
-
-
-
-/* Indexes of this array + 1 map HTML font size to scale of normal font size. *
- * Based on _point_sizes from libpurple/gtkimhtml.c
- * 1 2 3 4 5 6 7 */
-static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 };
-
-#define MAX_FONT_SIZE 7 /* Purple maximum font size */
-#define POINTS_PER_INCH 72 /* How many pt's in an inch */
-
-/* Text formatting bits for <f s=#> */
-#define MSIM_TEXT_BOLD 1
-#define MSIM_TEXT_ITALIC 2
-#define MSIM_TEXT_UNDERLINE 4
-
-/* Default baseline size of purple's fonts, in points. What is size 3 in points.
- * _font_scale specifies scaling factor relative to this point size. Note this
- * is only the default; it is configurable in account options. */
-#define MSIM_BASE_FONT_POINT_SIZE 8
-
-/* Default display's DPI. 96 is common but it can differ. Also configurable
- * in account options. */
-#define MSIM_DEFAULT_DPI 96
-
-
-/* round is part of C99, but sometimes is unavailable before then.
- * Based on http://forums.belution.com/en/cpp/000/050/13.shtml
- */
-double msim_round(double value)
-{
- if (value < 0) {
- return -(floor(-value + 0.5));
- } else {
- return floor( value + 0.5);
- }
-}
-
-
-/** Convert typographical font point size to HTML font size.
- * Based on libpurple/gtkimhtml.c */
-static guint
-msim_point_to_purple_size(MsimSession *session, guint point)
-{
- guint size, this_point, base;
- gdouble scale;
-
- base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
-
- for (size = 0;
- size < sizeof(_font_scale) / sizeof(_font_scale[0]);
- ++size) {
- scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
- this_point = (guint)msim_round(scale * base);
-
- if (this_point >= point) {
- purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n",
- point, size);
- return size;
- }
- }
-
- /* No HTML font size was this big; return largest possible. */
- return this_point;
-}
-
-/** Convert HTML font size to point size. */
-static guint
-msim_purple_size_to_point(MsimSession *session, guint size)
-{
- gdouble scale;
- guint point;
- guint base;
-
- scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
-
- base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
-
- point = (guint)msim_round(scale * base);
-
- purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n",
- size, point);
-
- return point;
-}
-
-/** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */
-static guint
-msim_height_to_point(MsimSession *session, guint height)
-{
- guint dpi;
-
- dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI);
-
- return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height);
-
- /* See also: libpurple/protocols/bonjour/jabber.c
- * _font_size_ichat_to_purple */
-}
-
-/** Convert point size to msim pixel height font size specification, for outgoing messages. */
-static guint
-msim_point_to_height(MsimSession *session, guint point)
-{
- guint dpi;
-
- dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI);
-
- return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point);
-}
-
-/** Convert the msim markup <f> (font) tag into HTML. */
-static void
-msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *face, *height_str, *decor_str;
- GString *gs_end, *gs_begin;
- guint decor, height;
-
- face = xmlnode_get_attrib(root, "f");
- height_str = xmlnode_get_attrib(root, "h");
- decor_str = xmlnode_get_attrib(root, "s");
-
- if (height_str) {
- height = atol(height_str);
- } else {
- height = 12;
- }
-
- if (decor_str) {
- decor = atol(decor_str);
- } else {
- decor = 0;
- }
-
- gs_begin = g_string_new("");
- /* TODO: get font size working */
- if (height && !face) {
- g_string_printf(gs_begin, "<font size='%d'>",
- msim_point_to_purple_size(session, msim_height_to_point(session, height)));
- } else if (height && face) {
- g_string_printf(gs_begin, "<font face='%s' size='%d'>", face,
- msim_point_to_purple_size(session, msim_height_to_point(session, height)));
- } else {
- g_string_printf(gs_begin, "<font>");
- }
-
- /* No support for font-size CSS? */
- /* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face,
- msim_height_to_point(height)); */
-
- gs_end = g_string_new("</font>");
-
- if (decor & MSIM_TEXT_BOLD) {
- g_string_append(gs_begin, "<b>");
- g_string_prepend(gs_end, "</b>");
- }
-
- if (decor & MSIM_TEXT_ITALIC) {
- g_string_append(gs_begin, "<i>");
- g_string_append(gs_end, "</i>");
- }
-
- if (decor & MSIM_TEXT_UNDERLINE) {
- g_string_append(gs_begin, "<u>");
- g_string_append(gs_end, "</u>");
- }
-
-
- *begin = gs_begin->str;
- *end = gs_end->str;
-}
-
-/** Convert a msim markup color to a color suitable for libpurple.
- *
- * @param msim Either a color name, or an rgb(x,y,z) code.
- *
- * @return A new string, either a color name or #rrggbb code. Must g_free().
- */
-static char *
-msim_color_to_purple(const char *msim)
-{
- guint red, green, blue;
-
- if (!msim) {
- return g_strdup("black");
- }
-
- if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) {
- /* Color name. */
- return g_strdup(msim);
- }
- /* TODO: rgba (alpha). */
-
- return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue);
-}
-
-/** Convert the msim markup <a> (anchor) tag into HTML. */
-static void
-msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *href;
-
- href = xmlnode_get_attrib(root, "h");
- if (!href) {
- href = "";
- }
-
- *begin = g_strdup_printf("<a href=\"%s\">%s", href, href);
- *end = g_strdup("</a>");
-}
-
-/** Convert the msim markup <p> (paragraph) tag into HTML. */
-static void
-msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- /* Just pass through unchanged.
- *
- * Note: attributes currently aren't passed, if there are any. */
- *begin = g_strdup("<p>");
- *end = g_strdup("</p>");
-}
-
-/** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */
-static void
-msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *color;
- gchar *purple_color;
-
- color = xmlnode_get_attrib(root, "v");
- if (!color) {
- purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr");
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: log as unrecognized */
- return;
- }
-
- purple_color = msim_color_to_purple(color);
-
- *begin = g_strdup_printf("<font color='%s'>", purple_color);
-
- g_free(purple_color);
-
- /* *begin = g_strdup_printf("<span style='color: %s'>", color); */
- *end = g_strdup("</font>");
-}
-
-/** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */
-static void
-msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *color;
- gchar *purple_color;
-
- color = xmlnode_get_attrib(root, "v");
- if (!color) {
- *begin = g_strdup("");
- *end = g_strdup("");
- purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr");
- /* TODO: log as unrecognized. */
- return;
- }
-
- purple_color = msim_color_to_purple(color);
-
- /* TODO: find out how to set background color. */
- *begin = g_strdup_printf("<span style='background-color: %s'>",
- purple_color);
- g_free(purple_color);
-
- *end = g_strdup("</p>");
-}
-
-/** Convert the msim markup <i> tag (emoticon image) into HTML. */
-static void
-msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
-{
- const gchar *name;
- guint i;
- struct MSIM_EMOTICON *emote;
-
- name = xmlnode_get_attrib(root, "n");
- if (!name) {
- purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n");
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: log as unrecognized */
- return;
- }
-
- /* Find and use canonical form of smiley symbol. */
- for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
- if (g_str_equal(name, emote->name)) {
- *begin = g_strdup(emote->symbol);
- *end = g_strdup("");
- return;
- }
- }
-
- /* Couldn't find it, sorry. Try to degrade gracefully. */
- *begin = g_strdup_printf("**%s**", name);
- *end = g_strdup("");
-}
-
-/** Convert an individual msim markup tag to HTML. */
-static void
-msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin,
- gchar **end)
-{
- if (g_str_equal(root->name, "f")) {
- msim_markup_f_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "a")) {
- msim_markup_a_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "p")) {
- msim_markup_p_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "c")) {
- msim_markup_c_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "b")) {
- msim_markup_b_to_html(session, root, begin, end);
- } else if (g_str_equal(root->name, "i")) {
- msim_markup_i_to_html(session, root, begin, end);
- } else {
- purple_debug_info("msim", "msim_markup_tag_to_html: "
- "unknown tag name=%s, ignoring",
- (root && root->name) ? root->name : "(NULL)");
- *begin = g_strdup("");
- *end = g_strdup("");
- }
-}
-
-/** Convert an individual HTML tag to msim markup. */
-static void
-html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin,
- gchar **end)
-{
- if (!purple_utf8_strcasecmp(root->name, "root") ||
- !purple_utf8_strcasecmp(root->name, "html")) {
- *begin = g_strdup("");
- *end = g_strdup("");
- /* TODO: Coalesce nested tags into one <f> tag!
- * Currently, the 's' value will be overwritten when b/i/u is nested
- * within another one, and only the inner-most formatting will be
- * applied to the text. */
- } else if (!purple_utf8_strcasecmp(root->name, "b")) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
- *end = g_strdup("</f>");
- } else if (!purple_utf8_strcasecmp(root->name, "i")) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
- *end = g_strdup("</f>");
- } else if (!purple_utf8_strcasecmp(root->name, "u")) {
- *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE);
- *end = g_strdup("</f>");
- } else if (!purple_utf8_strcasecmp(root->name, "a")) {
- const gchar *href, *link_text;
-
- href = xmlnode_get_attrib(root, "href");
-
- if (!href) {
- href = xmlnode_get_attrib(root, "HREF");
- }
-
- link_text = xmlnode_get_data(root);
-
- if (href) {
- if (g_str_equal(link_text, href)) {
- /* Purple gives us: <a href="URL">URL</a>
- * Translate to <a h='URL' />
- * Displayed as text of URL with link to URL
- */
- *begin = g_strdup_printf("<a h='%s' />", href);
- } else {
- /* But if we get: <a href="URL">text</a>
- * Translate to: text: <a h='URL' />
- *
- * Because official client only supports self-closed <a>
- * tags; you can't change the link text.
- */
- *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href);
- }
- } else {
- *begin = g_strdup("<a />");
- }
-
- /* Sorry, kid. MySpace doesn't support you within <a> tags. */
- xmlnode_free(root->child);
- root->child = NULL;
-
- *end = g_strdup("");
- } else if (!purple_utf8_strcasecmp(root->name, "font")) {
- const gchar *size;
- const gchar *face;
-
- size = xmlnode_get_attrib(root, "size");
- face = xmlnode_get_attrib(root, "face");
-
- if (face && size) {
- *begin = g_strdup_printf("<f f='%s' h='%d'>", face,
- msim_point_to_height(session,
- msim_purple_size_to_point(session, atoi(size))));
- } else if (face) {
- *begin = g_strdup_printf("<f f='%s'>", face);
- } else if (size) {
- *begin = g_strdup_printf("<f h='%d'>",
- msim_point_to_height(session,
- msim_purple_size_to_point(session, atoi(size))));
- } else {
- *begin = g_strdup("<f>");
- }
-
- *end = g_strdup("</f>");
-
- /* TODO: color (bg uses <body>), emoticons */
- } else {
-
-#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS
- *begin = g_strdup_printf("[%s]", root->name);
- *end = g_strdup_printf("[/%s]", root->name);
-#else
- *begin = g_strdup("");
- *end = g_strdup("");
-#endif
- }
-}
-
-/** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup.
- *
- * @param f Function to convert tags.
- *
- * @return An HTML string. Caller frees.
- */
-static gchar *
-msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f)
-{
- xmlnode *node;
- gchar *begin, *inner, *end;
- GString *final;
-
- if (!root || !root->name) {
- return g_strdup("");
- }
-
- purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n",
- root->name);
-
- begin = inner = end = NULL;
-
- final = g_string_new("");
-
- f(session, root, &begin, &end);
-
- g_string_append(final, begin);
-
- /* Loop over all child nodes. */
- for (node = root->child; node != NULL; node = node->next) {
- switch (node->type) {
- case XMLNODE_TYPE_ATTRIB:
- /* Attributes handled above. */
- break;
-
- case XMLNODE_TYPE_TAG:
- /* A tag or tag with attributes. Recursively descend. */
- inner = msim_convert_xmlnode(session, node, f);
- g_return_val_if_fail(inner != NULL, NULL);
-
- purple_debug_info("msim", " ** node name=%s\n",
- (node && node->name) ? node->name : "(NULL)");
- break;
-
- case XMLNODE_TYPE_DATA:
- /* Literal text. */
- inner = g_new0(char, node->data_sz + 1);
- strncpy(inner, node->data, node->data_sz);
- inner[node->data_sz] = 0;
-
- purple_debug_info("msim", " ** node data=%s\n",
- inner ? inner : "(NULL)");
- break;
-
- default:
- purple_debug_info("msim",
- "msim_convert_xmlnode: strange node\n");
- inner = g_strdup("");
- }
-
- if (inner) {
- g_string_append(final, inner);
- }
- }
-
- /* TODO: Note that msim counts each piece of text enclosed by <f> as
- * a paragraph and will display each on its own line. You actually have
- * to _nest_ <f> tags to intersperse different text in one paragraph!
- * Comment out this line below to see. */
- g_string_append(final, end);
-
- purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n",
- (final && final->str) ? final->str : "(NULL)");
-
- return final->str;
-}
-
-/** Convert XML to something based on MSIM_XMLNODE_CONVERT. */
-static gchar *
-msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f)
-{
- xmlnode *root;
- gchar *str;
- gchar *enclosed_raw;
-
- g_return_val_if_fail(raw != NULL, NULL);
-
- /* Enclose text in one root tag, to try to make it valid XML for parsing. */
- enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL);
-
- root = xmlnode_from_str(enclosed_raw, -1);
-
- if (!root) {
- purple_debug_info("msim", "msim_markup_to_html: couldn't parse "
- "%s as XML, returning raw: %s\n", enclosed_raw, raw);
- /* TODO: msim_unrecognized */
- g_free(enclosed_raw);
- return g_strdup(raw);
- }
-
- g_free(enclosed_raw);
-
- str = msim_convert_xmlnode(session, root, f);
- g_return_val_if_fail(str != NULL, NULL);
- purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str);
-
- xmlnode_free(root);
-
- return str;
-}
-
-/** Convert plaintext smileys to <i> markup tags.
- *
- * @param before Original text with ASCII smileys. Will be freed.
- * @return A new string with <i> tags, if applicable. Must be g_free()'d.
- */
-static gchar *
-msim_convert_smileys_to_markup(gchar *before)
-{
- gchar *old, *new, *replacement;
- guint i;
- struct MSIM_EMOTICON *emote;
-
- old = before;
- new = NULL;
-
- for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
- gchar *name, *symbol;
-
- name = emote->name;
- symbol = emote->symbol;
-
- replacement = g_strdup_printf("<i n=\"%s\"/>", name);
-
- purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n",
- symbol ? symbol : "(NULL)",
- replacement ? replacement : "(NULL)");
- new = purple_strreplace(old, symbol, replacement);
-
- g_free(replacement);
- g_free(old);
-
- old = new;
- }
-
- return new;
-}
-
-
-/** High-level function to convert MySpaceIM markup to Purple (HTML) markup.
- *
- * @return Purple markup string, must be g_free()'d. */
-gchar *
-msim_markup_to_html(MsimSession *session, const gchar *raw)
-{
- return msim_convert_xml(session, raw,
- (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html));
-}
-
-/** High-level function to convert Purple (HTML) to MySpaceIM markup.
- *
- * TODO: consider using purple_markup_html_to_xhtml() to make valid XML.
- *
- * @return HTML markup string, must be g_free()'d. */
-gchar *
-html_to_msim_markup(MsimSession *session, const gchar *raw)
-{
- gchar *markup;
-
- markup = msim_convert_xml(session, raw,
- (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup));
-
- if (purple_account_get_bool(session->account, "emoticons", TRUE)) {
- /* Frees markup and allocates a new one. */
- markup = msim_convert_smileys_to_markup(markup);
- }
-
- return markup;
-}
-
-
+/* MySpaceIM Protocol Plugin - markup
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "myspace.h"
+
+typedef void (*MSIM_XMLNODE_CONVERT)(MsimSession *, xmlnode *, gchar **, gchar **);
+
+/* Internal functions */
+
+static guint msim_point_to_purple_size(MsimSession *session, guint point);
+static guint msim_purple_size_to_point(MsimSession *session, guint size);
+static guint msim_height_to_point(MsimSession *session, guint height);
+static guint msim_point_to_height(MsimSession *session, guint point);
+
+static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
+static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end);
+static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f);
+static gchar *msim_convert_smileys_to_markup(gchar *before);
+static double msim_round(double round);
+
+
+/* Globals */
+
+/* The names in in emoticon_names (for <i n=whatever>) map to corresponding
+ * entries in emoticon_symbols (for the ASCII representation of the emoticon).
+ *
+ * Multiple emoticon symbols in Pidgin can map to one name. List the
+ * canonical form, as inserted by the "Smile!" dialog, first. For example,
+ * :) comes before :-), because although both are recognized as 'happy',
+ * the first is inserted by the smiley button (first symbol in theme).
+ *
+ * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */
+static struct MSIM_EMOTICON
+{
+ gchar *name;
+ gchar *symbol;
+} msim_emoticons[] = {
+ /* Unfortunately, this list duplicates much of the file
+ * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because
+ * that file is part of Pidgin, but we're part of libpurple.
+ */
+ { "bigsmile", ":D" },
+ { "bigsmile", ":-D" },
+ { "devil", "}:)" },
+ { "frazzled", ":Z" },
+ { "geek", "B)" },
+ { "googles", "%)" },
+ { "growl", ":E" },
+ { "laugh", ":))" }, /* Must be before ':)' */
+ { "happy", ":)" },
+ { "happy", ":-)" },
+ { "happi", ":)" },
+ { "heart", ":X" },
+ { "mohawk", "-:" },
+ { "mad", "X(" },
+ { "messed", "X)" },
+ { "nerd", "Q)" },
+ { "oops", ":G" },
+ { "pirate", "P)" },
+ { "scared", ":O" },
+ { "sidefrown", ":{" },
+ { "sinister", ":B" },
+ { "smirk", ":," },
+ { "straight", ":|" },
+ { "tongue", ":P" },
+ { "tongue", ":p" },
+ { "tongy", ":P" },
+ { "upset", "B|" },
+ { "wink", ";-)" },
+ { "wink", ";)" },
+ { "winc", ";)" },
+ { "worried", ":[" },
+ { "kiss", ":x" },
+ { NULL, NULL }
+};
+
+
+
+/* Indexes of this array + 1 map HTML font size to scale of normal font size. *
+ * Based on _point_sizes from libpurple/gtkimhtml.c
+ * 1 2 3 4 5 6 7 */
+static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 };
+
+#define MAX_FONT_SIZE 7 /* Purple maximum font size */
+#define POINTS_PER_INCH 72 /* How many pt's in an inch */
+
+/* Text formatting bits for <f s=#> */
+#define MSIM_TEXT_BOLD 1
+#define MSIM_TEXT_ITALIC 2
+#define MSIM_TEXT_UNDERLINE 4
+
+/* Default baseline size of purple's fonts, in points. What is size 3 in points.
+ * _font_scale specifies scaling factor relative to this point size. Note this
+ * is only the default; it is configurable in account options. */
+#define MSIM_BASE_FONT_POINT_SIZE 8
+
+/* Default display's DPI. 96 is common but it can differ. Also configurable
+ * in account options. */
+#define MSIM_DEFAULT_DPI 96
+
+
+/* round is part of C99, but sometimes is unavailable before then.
+ * Based on http://forums.belution.com/en/cpp/000/050/13.shtml
+ */
+double msim_round(double value)
+{
+ if (value < 0) {
+ return -(floor(-value + 0.5));
+ } else {
+ return floor( value + 0.5);
+ }
+}
+
+
+/** Convert typographical font point size to HTML font size.
+ * Based on libpurple/gtkimhtml.c */
+static guint
+msim_point_to_purple_size(MsimSession *session, guint point)
+{
+ guint size, this_point, base;
+ gdouble scale;
+
+ base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
+
+ for (size = 0;
+ size < sizeof(_font_scale) / sizeof(_font_scale[0]);
+ ++size) {
+ scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
+ this_point = (guint)msim_round(scale * base);
+
+ if (this_point >= point) {
+ purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n",
+ point, size);
+ return size;
+ }
+ }
+
+ /* No HTML font size was this big; return largest possible. */
+ return this_point;
+}
+
+/** Convert HTML font size to point size. */
+static guint
+msim_purple_size_to_point(MsimSession *session, guint size)
+{
+ gdouble scale;
+ guint point;
+ guint base;
+
+ scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1];
+
+ base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE);
+
+ point = (guint)msim_round(scale * base);
+
+ purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n",
+ size, point);
+
+ return point;
+}
+
+/** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */
+static guint
+msim_height_to_point(MsimSession *session, guint height)
+{
+ guint dpi;
+
+ dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI);
+
+ return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height);
+
+ /* See also: libpurple/protocols/bonjour/jabber.c
+ * _font_size_ichat_to_purple */
+}
+
+/** Convert point size to msim pixel height font size specification, for outgoing messages. */
+static guint
+msim_point_to_height(MsimSession *session, guint point)
+{
+ guint dpi;
+
+ dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI);
+
+ return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point);
+}
+
+/** Convert the msim markup <f> (font) tag into HTML. */
+static void
+msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ const gchar *face, *height_str, *decor_str;
+ GString *gs_end, *gs_begin;
+ guint decor, height;
+
+ face = xmlnode_get_attrib(root, "f");
+ height_str = xmlnode_get_attrib(root, "h");
+ decor_str = xmlnode_get_attrib(root, "s");
+
+ if (height_str) {
+ height = atol(height_str);
+ } else {
+ height = 12;
+ }
+
+ if (decor_str) {
+ decor = atol(decor_str);
+ } else {
+ decor = 0;
+ }
+
+ gs_begin = g_string_new("");
+ /* TODO: get font size working */
+ if (height && !face) {
+ g_string_printf(gs_begin, "<font size='%d'>",
+ msim_point_to_purple_size(session, msim_height_to_point(session, height)));
+ } else if (height && face) {
+ g_string_printf(gs_begin, "<font face='%s' size='%d'>", face,
+ msim_point_to_purple_size(session, msim_height_to_point(session, height)));
+ } else {
+ g_string_printf(gs_begin, "<font>");
+ }
+
+ /* No support for font-size CSS? */
+ /* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face,
+ msim_height_to_point(height)); */
+
+ gs_end = g_string_new("</font>");
+
+ if (decor & MSIM_TEXT_BOLD) {
+ g_string_append(gs_begin, "<b>");
+ g_string_prepend(gs_end, "</b>");
+ }
+
+ if (decor & MSIM_TEXT_ITALIC) {
+ g_string_append(gs_begin, "<i>");
+ g_string_append(gs_end, "</i>");
+ }
+
+ if (decor & MSIM_TEXT_UNDERLINE) {
+ g_string_append(gs_begin, "<u>");
+ g_string_append(gs_end, "</u>");
+ }
+
+
+ *begin = gs_begin->str;
+ *end = gs_end->str;
+}
+
+/** Convert a msim markup color to a color suitable for libpurple.
+ *
+ * @param msim Either a color name, or an rgb(x,y,z) code.
+ *
+ * @return A new string, either a color name or #rrggbb code. Must g_free().
+ */
+static char *
+msim_color_to_purple(const char *msim)
+{
+ guint red, green, blue;
+
+ if (!msim) {
+ return g_strdup("black");
+ }
+
+ if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) {
+ /* Color name. */
+ return g_strdup(msim);
+ }
+ /* TODO: rgba (alpha). */
+
+ return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue);
+}
+
+/** Convert the msim markup <a> (anchor) tag into HTML. */
+static void
+msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ const gchar *href;
+
+ href = xmlnode_get_attrib(root, "h");
+ if (!href) {
+ href = "";
+ }
+
+ *begin = g_strdup_printf("<a href=\"%s\">%s", href, href);
+ *end = g_strdup("</a>");
+}
+
+/** Convert the msim markup <p> (paragraph) tag into HTML. */
+static void
+msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ /* Just pass through unchanged.
+ *
+ * Note: attributes currently aren't passed, if there are any. */
+ *begin = g_strdup("<p>");
+ *end = g_strdup("</p>");
+}
+
+/** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */
+static void
+msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ const gchar *color;
+ gchar *purple_color;
+
+ color = xmlnode_get_attrib(root, "v");
+ if (!color) {
+ purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr");
+ *begin = g_strdup("");
+ *end = g_strdup("");
+ /* TODO: log as unrecognized */
+ return;
+ }
+
+ purple_color = msim_color_to_purple(color);
+
+ *begin = g_strdup_printf("<font color='%s'>", purple_color);
+
+ g_free(purple_color);
+
+ /* *begin = g_strdup_printf("<span style='color: %s'>", color); */
+ *end = g_strdup("</font>");
+}
+
+/** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */
+static void
+msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ const gchar *color;
+ gchar *purple_color;
+
+ color = xmlnode_get_attrib(root, "v");
+ if (!color) {
+ *begin = g_strdup("");
+ *end = g_strdup("");
+ purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr");
+ /* TODO: log as unrecognized. */
+ return;
+ }
+
+ purple_color = msim_color_to_purple(color);
+
+ /* TODO: find out how to set background color. */
+ *begin = g_strdup_printf("<span style='background-color: %s'>",
+ purple_color);
+ g_free(purple_color);
+
+ *end = g_strdup("</p>");
+}
+
+/** Convert the msim markup <i> tag (emoticon image) into HTML. */
+static void
+msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end)
+{
+ const gchar *name;
+ guint i;
+ struct MSIM_EMOTICON *emote;
+
+ name = xmlnode_get_attrib(root, "n");
+ if (!name) {
+ purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n");
+ *begin = g_strdup("");
+ *end = g_strdup("");
+ /* TODO: log as unrecognized */
+ return;
+ }
+
+ /* Find and use canonical form of smiley symbol. */
+ for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
+ if (g_str_equal(name, emote->name)) {
+ *begin = g_strdup(emote->symbol);
+ *end = g_strdup("");
+ return;
+ }
+ }
+
+ /* Couldn't find it, sorry. Try to degrade gracefully. */
+ *begin = g_strdup_printf("**%s**", name);
+ *end = g_strdup("");
+}
+
+/** Convert an individual msim markup tag to HTML. */
+static void
+msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin,
+ gchar **end)
+{
+ if (g_str_equal(root->name, "f")) {
+ msim_markup_f_to_html(session, root, begin, end);
+ } else if (g_str_equal(root->name, "a")) {
+ msim_markup_a_to_html(session, root, begin, end);
+ } else if (g_str_equal(root->name, "p")) {
+ msim_markup_p_to_html(session, root, begin, end);
+ } else if (g_str_equal(root->name, "c")) {
+ msim_markup_c_to_html(session, root, begin, end);
+ } else if (g_str_equal(root->name, "b")) {
+ msim_markup_b_to_html(session, root, begin, end);
+ } else if (g_str_equal(root->name, "i")) {
+ msim_markup_i_to_html(session, root, begin, end);
+ } else {
+ purple_debug_info("msim", "msim_markup_tag_to_html: "
+ "unknown tag name=%s, ignoring",
+ (root && root->name) ? root->name : "(NULL)");
+ *begin = g_strdup("");
+ *end = g_strdup("");
+ }
+}
+
+/** Convert an individual HTML tag to msim markup. */
+static void
+html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin,
+ gchar **end)
+{
+ if (!purple_utf8_strcasecmp(root->name, "root") ||
+ !purple_utf8_strcasecmp(root->name, "html")) {
+ *begin = g_strdup("");
+ *end = g_strdup("");
+ /* TODO: Coalesce nested tags into one <f> tag!
+ * Currently, the 's' value will be overwritten when b/i/u is nested
+ * within another one, and only the inner-most formatting will be
+ * applied to the text. */
+ } else if (!purple_utf8_strcasecmp(root->name, "b")) {
+ *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
+ *end = g_strdup("</f>");
+ } else if (!purple_utf8_strcasecmp(root->name, "i")) {
+ *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
+ *end = g_strdup("</f>");
+ } else if (!purple_utf8_strcasecmp(root->name, "u")) {
+ *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE);
+ *end = g_strdup("</f>");
+ } else if (!purple_utf8_strcasecmp(root->name, "a")) {
+ const gchar *href, *link_text;
+
+ href = xmlnode_get_attrib(root, "href");
+
+ if (!href) {
+ href = xmlnode_get_attrib(root, "HREF");
+ }
+
+ link_text = xmlnode_get_data(root);
+
+ if (href) {
+ if (g_str_equal(link_text, href)) {
+ /* Purple gives us: <a href="URL">URL</a>
+ * Translate to <a h='URL' />
+ * Displayed as text of URL with link to URL
+ */
+ *begin = g_strdup_printf("<a h='%s' />", href);
+ } else {
+ /* But if we get: <a href="URL">text</a>
+ * Translate to: text: <a h='URL' />
+ *
+ * Because official client only supports self-closed <a>
+ * tags; you can't change the link text.
+ */
+ *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href);
+ }
+ } else {
+ *begin = g_strdup("<a />");
+ }
+
+ /* Sorry, kid. MySpace doesn't support you within <a> tags. */
+ xmlnode_free(root->child);
+ root->child = NULL;
+
+ *end = g_strdup("");
+ } else if (!purple_utf8_strcasecmp(root->name, "font")) {
+ const gchar *size;
+ const gchar *face;
+
+ size = xmlnode_get_attrib(root, "size");
+ face = xmlnode_get_attrib(root, "face");
+
+ if (face && size) {
+ *begin = g_strdup_printf("<f f='%s' h='%d'>", face,
+ msim_point_to_height(session,
+ msim_purple_size_to_point(session, atoi(size))));
+ } else if (face) {
+ *begin = g_strdup_printf("<f f='%s'>", face);
+ } else if (size) {
+ *begin = g_strdup_printf("<f h='%d'>",
+ msim_point_to_height(session,
+ msim_purple_size_to_point(session, atoi(size))));
+ } else {
+ *begin = g_strdup("<f>");
+ }
+
+ *end = g_strdup("</f>");
+
+ /* TODO: color (bg uses <body>), emoticons */
+ } else {
+
+#ifdef MSIM_MARKUP_SHOW_UNKNOWN_TAGS
+ *begin = g_strdup_printf("[%s]", root->name);
+ *end = g_strdup_printf("[/%s]", root->name);
+#else
+ *begin = g_strdup("");
+ *end = g_strdup("");
+#endif
+ }
+}
+
+/** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup.
+ *
+ * @param f Function to convert tags.
+ *
+ * @return An HTML string. Caller frees.
+ */
+static gchar *
+msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f)
+{
+ xmlnode *node;
+ gchar *begin, *inner, *end;
+ GString *final;
+
+ if (!root || !root->name) {
+ return g_strdup("");
+ }
+
+ purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n",
+ root->name);
+
+ begin = inner = end = NULL;
+
+ final = g_string_new("");
+
+ f(session, root, &begin, &end);
+
+ g_string_append(final, begin);
+
+ /* Loop over all child nodes. */
+ for (node = root->child; node != NULL; node = node->next) {
+ switch (node->type) {
+ case XMLNODE_TYPE_ATTRIB:
+ /* Attributes handled above. */
+ break;
+
+ case XMLNODE_TYPE_TAG:
+ /* A tag or tag with attributes. Recursively descend. */
+ inner = msim_convert_xmlnode(session, node, f);
+ g_return_val_if_fail(inner != NULL, NULL);
+
+ purple_debug_info("msim", " ** node name=%s\n",
+ (node && node->name) ? node->name : "(NULL)");
+ break;
+
+ case XMLNODE_TYPE_DATA:
+ /* Literal text. */
+ inner = g_new0(char, node->data_sz + 1);
+ strncpy(inner, node->data, node->data_sz);
+ inner[node->data_sz] = 0;
+
+ purple_debug_info("msim", " ** node data=%s\n",
+ inner ? inner : "(NULL)");
+ break;
+
+ default:
+ purple_debug_info("msim",
+ "msim_convert_xmlnode: strange node\n");
+ inner = g_strdup("");
+ }
+
+ if (inner) {
+ g_string_append(final, inner);
+ }
+ }
+
+ /* TODO: Note that msim counts each piece of text enclosed by <f> as
+ * a paragraph and will display each on its own line. You actually have
+ * to _nest_ <f> tags to intersperse different text in one paragraph!
+ * Comment out this line below to see. */
+ g_string_append(final, end);
+
+ purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n",
+ (final && final->str) ? final->str : "(NULL)");
+
+ return final->str;
+}
+
+/** Convert XML to something based on MSIM_XMLNODE_CONVERT. */
+static gchar *
+msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f)
+{
+ xmlnode *root;
+ gchar *str;
+ gchar *enclosed_raw;
+
+ g_return_val_if_fail(raw != NULL, NULL);
+
+ /* Enclose text in one root tag, to try to make it valid XML for parsing. */
+ enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL);
+
+ root = xmlnode_from_str(enclosed_raw, -1);
+
+ if (!root) {
+ purple_debug_info("msim", "msim_markup_to_html: couldn't parse "
+ "%s as XML, returning raw: %s\n", enclosed_raw, raw);
+ /* TODO: msim_unrecognized */
+ g_free(enclosed_raw);
+ return g_strdup(raw);
+ }
+
+ g_free(enclosed_raw);
+
+ str = msim_convert_xmlnode(session, root, f);
+ g_return_val_if_fail(str != NULL, NULL);
+ purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str);
+
+ xmlnode_free(root);
+
+ return str;
+}
+
+/** Convert plaintext smileys to <i> markup tags.
+ *
+ * @param before Original text with ASCII smileys. Will be freed.
+ * @return A new string with <i> tags, if applicable. Must be g_free()'d.
+ */
+static gchar *
+msim_convert_smileys_to_markup(gchar *before)
+{
+ gchar *old, *new, *replacement;
+ guint i;
+ struct MSIM_EMOTICON *emote;
+
+ old = before;
+ new = NULL;
+
+ for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) {
+ gchar *name, *symbol;
+
+ name = emote->name;
+ symbol = emote->symbol;
+
+ replacement = g_strdup_printf("<i n=\"%s\"/>", name);
+
+ purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n",
+ symbol ? symbol : "(NULL)",
+ replacement ? replacement : "(NULL)");
+ new = purple_strreplace(old, symbol, replacement);
+
+ g_free(replacement);
+ g_free(old);
+
+ old = new;
+ }
+
+ return new;
+}
+
+
+/** High-level function to convert MySpaceIM markup to Purple (HTML) markup.
+ *
+ * @return Purple markup string, must be g_free()'d. */
+gchar *
+msim_markup_to_html(MsimSession *session, const gchar *raw)
+{
+ return msim_convert_xml(session, raw,
+ (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html));
+}
+
+/** High-level function to convert Purple (HTML) to MySpaceIM markup.
+ *
+ * TODO: consider using purple_markup_html_to_xhtml() to make valid XML.
+ *
+ * @return HTML markup string, must be g_free()'d. */
+gchar *
+html_to_msim_markup(MsimSession *session, const gchar *raw)
+{
+ gchar *markup;
+
+ markup = msim_convert_xml(session, raw,
+ (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup));
+
+ if (purple_account_get_bool(session->account, "emoticons", TRUE)) {
+ /* Frees markup and allocates a new one. */
+ markup = msim_convert_smileys_to_markup(markup);
+ }
+
+ return markup;
+}
+
+
--- a/libpurple/protocols/myspace/markup.h Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/markup.h Tue Sep 18 00:47:51 2007 +0000
@@ -1,27 +1,27 @@
-/* MySpaceIM Protocol Plugin - markup
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MYSPACE_MARKUP_H
-#define _MYSPACE_MARKUP_H
-
-/* High-level msim markup <=> Purple html conversion functions. */
-gchar *msim_markup_to_html(MsimSession *, const gchar *raw);
-gchar *html_to_msim_markup(MsimSession *, const gchar *raw);
-
-#endif /* !_MYSPACE_MARKUP_H */
+/* MySpaceIM Protocol Plugin - markup
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSPACE_MARKUP_H
+#define _MYSPACE_MARKUP_H
+
+/* High-level msim markup <=> Purple html conversion functions. */
+gchar *msim_markup_to_html(MsimSession *, const gchar *raw);
+gchar *html_to_msim_markup(MsimSession *, const gchar *raw);
+
+#endif /* !_MYSPACE_MARKUP_H */
--- a/libpurple/protocols/myspace/session.c Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/session.c Tue Sep 18 00:47:51 2007 +0000
@@ -1,95 +1,95 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include "myspace.h"
-
-/* Session methods */
-
-/**
- * Create a new MSIM session.
- *
- * @param acct The account to create the session from.
- *
- * @return Pointer to a new session. Free with msim_session_destroy.
- */
-MsimSession *
-msim_session_new(PurpleAccount *acct)
-{
- MsimSession *session;
-
- g_return_val_if_fail(acct != NULL, NULL);
-
- session = g_new0(MsimSession, 1);
-
- session->magic = MSIM_SESSION_STRUCT_MAGIC;
- session->account = acct;
- session->gc = purple_account_get_connection(acct);
- session->sesskey = 0;
- session->userid = 0;
- session->username = NULL;
- session->fd = -1;
-
- /* TODO: Remove. */
- session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */
- session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are,
- they could be integers inside gpointers
- or strings, so I don't freed them.
- Figure this out, once free cache. */
-
- /* Created in msim_process_server_info() */
- session->server_info = NULL;
-
- session->rxoff = 0;
- session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE);
- session->next_rid = 1;
- session->last_comm = time(NULL);
- session->inbox_status = 0;
-
- return session;
-}
-
-/**
- * Free a session.
- *
- * @param session The session to destroy.
- */
-void
-msim_session_destroy(MsimSession *session)
-{
- g_return_if_fail(MSIM_SESSION_VALID(session));
-
- session->magic = -1;
-
- g_free(session->rxbuf);
- g_free(session->username);
-
- /* TODO: Remove. */
- g_hash_table_destroy(session->user_lookup_cb);
- g_hash_table_destroy(session->user_lookup_cb_data);
-
- if (session->server_info) {
- msim_msg_free(session->server_info);
- }
-
- g_free(session);
-}
-
+/* MySpaceIM Protocol Plugin, session
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "myspace.h"
+
+/* Session methods */
+
+/**
+ * Create a new MSIM session.
+ *
+ * @param acct The account to create the session from.
+ *
+ * @return Pointer to a new session. Free with msim_session_destroy.
+ */
+MsimSession *
+msim_session_new(PurpleAccount *acct)
+{
+ MsimSession *session;
+
+ g_return_val_if_fail(acct != NULL, NULL);
+
+ session = g_new0(MsimSession, 1);
+
+ session->magic = MSIM_SESSION_STRUCT_MAGIC;
+ session->account = acct;
+ session->gc = purple_account_get_connection(acct);
+ session->sesskey = 0;
+ session->userid = 0;
+ session->username = NULL;
+ session->fd = -1;
+
+ /* TODO: Remove. */
+ session->user_lookup_cb = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, NULL); /* do NOT free function pointers! (values) */
+ session->user_lookup_cb_data = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, NULL);/* TODO: we don't know what the values are,
+ they could be integers inside gpointers
+ or strings, so I don't freed them.
+ Figure this out, once free cache. */
+
+ /* Created in msim_process_server_info() */
+ session->server_info = NULL;
+
+ session->rxoff = 0;
+ session->rxbuf = g_new0(gchar, MSIM_READ_BUF_SIZE);
+ session->next_rid = 1;
+ session->last_comm = time(NULL);
+ session->inbox_status = 0;
+
+ return session;
+}
+
+/**
+ * Free a session.
+ *
+ * @param session The session to destroy.
+ */
+void
+msim_session_destroy(MsimSession *session)
+{
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+
+ session->magic = -1;
+
+ g_free(session->rxbuf);
+ g_free(session->username);
+
+ /* TODO: Remove. */
+ g_hash_table_destroy(session->user_lookup_cb);
+ g_hash_table_destroy(session->user_lookup_cb_data);
+
+ if (session->server_info) {
+ msim_msg_free(session->server_info);
+ }
+
+ g_free(session);
+}
+
--- a/libpurple/protocols/myspace/session.h Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/session.h Tue Sep 18 00:47:51 2007 +0000
@@ -1,57 +1,57 @@
-/* MySpaceIM Protocol Plugin, session
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MYSPACE_SESSION_H
-#define _MYSPACE_SESSION_H
-
-/* Random number in every MsimSession, to ensure it is valid. */
-#define MSIM_SESSION_STRUCT_MAGIC 0xe4a6752b
-
-/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */
-typedef struct _MsimSession
-{
- guint magic; /**< MSIM_SESSION_STRUCT_MAGIC */
- PurpleAccount *account;
- PurpleConnection *gc;
- guint sesskey; /**< Session key from server */
- guint userid; /**< This user's numeric user ID */
- gchar *username; /**< This user's unique username */
- gint fd; /**< File descriptor to/from server */
-
- /* TODO: Remove. */
- GHashTable *user_lookup_cb; /**< Username -> userid lookup callback */
- GHashTable *user_lookup_cb_data; /**< Username -> userid lookup callback data */
-
- MsimMessage *server_info; /**< Parameters from server */
-
- gchar *rxbuf; /**< Receive buffer */
- guint rxoff; /**< Receive buffer offset */
- guint next_rid; /**< Next request/response ID */
- time_t last_comm; /**< Time received last communication */
- guint inbox_status; /**< Bit field of inbox notifications */
-} MsimSession;
-
-/* Check if an MsimSession is valid */
-#define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC)
-
-
-MsimSession *msim_session_new(PurpleAccount *acct);
-void msim_session_destroy(MsimSession *session);
-
-#endif /* !_MYSPACE_SESSION_H */
+/* MySpaceIM Protocol Plugin, session
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSPACE_SESSION_H
+#define _MYSPACE_SESSION_H
+
+/* Random number in every MsimSession, to ensure it is valid. */
+#define MSIM_SESSION_STRUCT_MAGIC 0xe4a6752b
+
+/* Everything needed to keep track of a session (proto_data field in PurpleConnection) */
+typedef struct _MsimSession
+{
+ guint magic; /**< MSIM_SESSION_STRUCT_MAGIC */
+ PurpleAccount *account;
+ PurpleConnection *gc;
+ guint sesskey; /**< Session key from server */
+ guint userid; /**< This user's numeric user ID */
+ gchar *username; /**< This user's unique username */
+ gint fd; /**< File descriptor to/from server */
+
+ /* TODO: Remove. */
+ GHashTable *user_lookup_cb; /**< Username -> userid lookup callback */
+ GHashTable *user_lookup_cb_data; /**< Username -> userid lookup callback data */
+
+ MsimMessage *server_info; /**< Parameters from server */
+
+ gchar *rxbuf; /**< Receive buffer */
+ guint rxoff; /**< Receive buffer offset */
+ guint next_rid; /**< Next request/response ID */
+ time_t last_comm; /**< Time received last communication */
+ guint inbox_status; /**< Bit field of inbox notifications */
+} MsimSession;
+
+/* Check if an MsimSession is valid */
+#define MSIM_SESSION_VALID(s) (session != NULL && session->magic == MSIM_SESSION_STRUCT_MAGIC)
+
+
+MsimSession *msim_session_new(PurpleAccount *acct);
+void msim_session_destroy(MsimSession *session);
+
+#endif /* !_MYSPACE_SESSION_H */
--- a/libpurple/protocols/myspace/user.c Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/user.c Tue Sep 18 00:47:51 2007 +0000
@@ -1,437 +1,437 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "myspace.h"
-
-static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user);
-static gchar *msim_format_now_playing(gchar *band, gchar *song);
-static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
- gsize len, const gchar *error_message);
-
-/** Format the "now playing" indicator, showing the artist and song.
- * @return Return a new string (must be g_free()'d), or NULL.
- */
-static gchar *
-msim_format_now_playing(gchar *band, gchar *song)
-{
- if ((band && strlen(band)) || (song && strlen(song))) {
- return g_strdup_printf("%s - %s",
- (band && strlen(band)) ? band : "Unknown Artist",
- (song && strlen(song)) ? song : "Unknown Song");
- } else {
- return NULL;
- }
-}
-/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
-MsimUser *
-msim_get_user_from_buddy(PurpleBuddy *buddy)
-{
- MsimUser *user;
-
- if (!buddy) {
- return NULL;
- }
-
- if (!buddy->proto_data) {
- /* No MsimUser for this buddy; make one. */
-
- /* TODO: where is this freed? */
- user = g_new0(MsimUser, 1);
- user->buddy = buddy;
- buddy->proto_data = (gpointer)user;
- }
-
- user = (MsimUser *)(buddy->proto_data);
-
- return user;
-}
-
-/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */
-MsimUser *
-msim_find_user(MsimSession *session, const gchar *username)
-{
- PurpleBuddy *buddy;
- MsimUser *user;
-
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- return NULL;
- }
-
- user = msim_get_user_from_buddy(buddy);
-
- return user;
-}
-
-/** Append user information to a PurpleNotifyUserInfo, given an MsimUser.
- * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile.
- */
-void
-msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
-{
- gchar *str;
- guint uid;
- guint cv;
-
- /* Useful to identify the account the tooltip refers to.
- * Other prpls show this. */
- if (user->username) {
- purple_notify_user_info_add_pair(user_info, _("User"), user->username);
- }
-
- uid = purple_blist_node_get_int(&user->buddy->node, "UserID");
-
- if (full) {
- /* TODO: link to username, if available */
- purple_notify_user_info_add_pair(user_info, _("Profile"),
- g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
- uid, uid));
- }
-
-
- /* a/s/l...the vitals */
- if (user->age) {
- purple_notify_user_info_add_pair(user_info, _("Age"),
- g_strdup_printf("%d", user->age));
- }
-
- if (user->gender && strlen(user->gender)) {
- purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender);
- }
-
- if (user->location && strlen(user->location)) {
- purple_notify_user_info_add_pair(user_info, _("Location"), user->location);
- }
-
- /* Other information */
- if (user->headline && strlen(user->headline)) {
- purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
- }
-
- str = msim_format_now_playing(user->band_name, user->song_name);
- if (str && strlen(str)) {
- purple_notify_user_info_add_pair(user_info, _("Song"), str);
- }
-
- /* Note: total friends only available if looked up by uid, not username. */
- if (user->total_friends) {
- purple_notify_user_info_add_pair(user_info, _("Total Friends"),
- g_strdup_printf("%d", user->total_friends));
- }
-
- if (full) {
- /* Client information */
-
- str = user->client_info;
- cv = user->client_cv;
-
- if (str && cv != 0) {
- purple_notify_user_info_add_pair(user_info, _("Client Version"),
- g_strdup_printf("%s (build %d)", str, cv));
- } else if (str) {
- purple_notify_user_info_add_pair(user_info, _("Client Version"),
- g_strdup(str));
- } else if (cv) {
- purple_notify_user_info_add_pair(user_info, _("Client Version"),
- g_strdup_printf("Build %d", cv));
- }
- }
-}
-
-/** Store a field of information about a buddy. */
-void
-msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
-{
- if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
- /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
- if (user->buddy)
- {
- purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name);
- purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str));
- }
- /* Need to store in MsimUser, too? What if not on blist? */
- } else if (g_str_equal(key_str, "Age")) {
- user->age = atol(value_str);
- } else if (g_str_equal(key_str, "Gender")) {
- user->gender = g_strdup(value_str);
- } else if (g_str_equal(key_str, "Location")) {
- user->location = g_strdup(value_str);
- } else if (g_str_equal(key_str, "TotalFriends")) {
- user->total_friends = atol(value_str);
- } else if (g_str_equal(key_str, "DisplayName")) {
- user->display_name = g_strdup(value_str);
- } else if (g_str_equal(key_str, "BandName")) {
- user->band_name = g_strdup(value_str);
- } else if (g_str_equal(key_str, "SongName")) {
- user->song_name = g_strdup(value_str);
- } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
- /* Ignore because PurpleBuddy knows this already */
- ;
- } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) {
- const gchar *previous_url;
-
- user->image_url = g_strdup(value_str);
-
- /* Instead of showing 'no photo' picture, show nothing. */
- if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
- {
- purple_buddy_icons_set_for_user(user->buddy->account,
- user->buddy->name,
- NULL, 0, NULL);
- return;
- }
-
- /* TODO: use ETag for checksum */
- previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy);
-
- /* Only download if URL changed */
- if (!previous_url || !g_str_equal(previous_url, user->image_url)) {
- purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user);
- }
- } else if (g_str_equal(key_str, "LastImageUpdated")) {
- /* TODO: use somewhere */
- user->last_image_updated = atol(value_str);
- } else if (g_str_equal(key_str, "Headline")) {
- user->headline = g_strdup(value_str);
- } else {
- /* TODO: other fields in MsimUser */
- gchar *msg;
-
- msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s",
- key_str, value_str);
-
- msim_unrecognized(NULL, NULL, msg);
-
- g_free(msg);
- }
-}
-
-/** Save buddy information to the buddy list from a user info reply message.
- *
- * @param session
- * @param msg The user information reply, with any amount of information.
- * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data.
- *
- * Variable information is saved to the passed MsimUser structure. Permanent
- * information (UserID) is stored in the blist node of the buddy list (and
- * ends up in blist.xml, persisted to disk) if it exists.
- *
- * If the function has no buddy information, this function
- * is a no-op (and returns FALSE).
- *
- */
-gboolean
-msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
-{
- gchar *username;
- MsimMessage *body, *body_node;
-
- g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
- g_return_val_if_fail(msg != NULL, FALSE);
-
- body = msim_msg_get_dictionary(msg, "body");
- if (!body) {
- return FALSE;
- }
-
- username = msim_msg_get_string(body, "UserName");
-
- if (!username) {
- purple_debug_info("msim",
- "msim_process_reply: not caching body, no UserName\n");
- msim_msg_free(body);
- g_free(username);
- return FALSE;
- }
-
- /* Null user = find and store in PurpleBuddy's proto_data */
- if (!user) {
- user = msim_find_user(session, username);
- if (!user) {
- msim_msg_free(body);
- g_free(username);
- return FALSE;
- }
- }
-
- /* TODO: make looping over MsimMessage's easier. */
- for (body_node = body;
- body_node != NULL;
- body_node = msim_msg_get_next_element_node(body_node))
- {
- const gchar *key_str;
- gchar *value_str;
- MsimMessageElement *elem;
-
- elem = (MsimMessageElement *)body_node->data;
- key_str = elem->name;
-
- value_str = msim_msg_get_string_from_element(elem);
- msim_store_user_info_each(key_str, value_str, user);
- g_free(value_str);
- }
-
- if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
- msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
- /* TODO: do something with our own IM info, if we need it for some
- * specific purpose. Otherwise it is available on the buddy list,
- * if the user has themselves as their own buddy.
- *
- * However, much of the info is already available in MsimSession,
- * stored in msim_we_are_logged_on(). */
- } else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
- msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
- /* TODO: same as above, but for MySpace info. */
- }
-
- msim_msg_free(body);
-
- return TRUE;
-}
-
-/**
- * Asynchronously lookup user information, calling callback when receive result.
- *
- * @param session
- * @param user The user id, email address, or username. Not freed.
- * @param cb Callback, called with user information when available.
- * @param data An arbitray data pointer passed to the callback.
- */
-/* TODO: change to not use callbacks */
-void
-msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
-{
- MsimMessage *body;
- gchar *field_name;
- guint rid, cmd, dsn, lid;
-
- g_return_if_fail(MSIM_SESSION_VALID(session));
- g_return_if_fail(user != NULL);
- /* Callback can be null to not call anything, just lookup & store information. */
- /*g_return_if_fail(cb != NULL);*/
-
- purple_debug_info("msim", "msim_lookup_userid: "
- "asynchronously looking up <%s>\n", user);
-
- msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data);
-
- /* Setup callback. Response will be associated with request using 'rid'. */
- rid = msim_new_reply_callback(session, cb, data);
-
- /* Send request */
-
- cmd = MSIM_CMD_GET;
-
- if (msim_is_userid(user)) {
- field_name = "UserID";
- dsn = MG_MYSPACE_INFO_BY_ID_DSN;
- lid = MG_MYSPACE_INFO_BY_ID_LID;
- } else if (msim_is_email(user)) {
- field_name = "Email";
- dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
- lid = MG_MYSPACE_INFO_BY_STRING_LID;
- } else {
- field_name = "UserName";
- dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
- lid = MG_MYSPACE_INFO_BY_STRING_LID;
- }
-
- body = msim_msg_new(
- field_name, MSIM_TYPE_STRING, g_strdup(user),
- NULL);
-
- g_return_if_fail(msim_send(session,
- "persist", MSIM_TYPE_INTEGER, 1,
- "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
- "cmd", MSIM_TYPE_INTEGER, 1,
- "dsn", MSIM_TYPE_INTEGER, dsn,
- "uid", MSIM_TYPE_INTEGER, session->userid,
- "lid", MSIM_TYPE_INTEGER, lid,
- "rid", MSIM_TYPE_INTEGER, rid,
- "body", MSIM_TYPE_DICTIONARY, body,
- NULL));
-}
-
-
-/**
- * Check if a string is a userid (all numeric).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is userid, FALSE if not.
- */
-gboolean
-msim_is_userid(const gchar *user)
-{
- g_return_val_if_fail(user != NULL, FALSE);
-
- return strspn(user, "0123456789") == strlen(user);
-}
-
-/**
- * Check if a string is an email address (contains an @).
- *
- * @param user The user id, email, or name.
- *
- * @return TRUE if is an email, FALSE if not.
- *
- * This function is not intended to be used as a generic
- * means of validating email addresses, but to distinguish
- * between a user represented by an email address from
- * other forms of identification.
- */
-gboolean
-msim_is_email(const gchar *user)
-{
- g_return_val_if_fail(user != NULL, FALSE);
-
- return strchr(user, '@') != NULL;
-}
-
-
-/** Callback for when a buddy icon finished being downloaded. */
-static void
-msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
- gpointer user_data,
- const gchar *url_text,
- gsize len,
- const gchar *error_message)
-{
- MsimUser *user;
-
- user = (MsimUser *)user_data;
-
- purple_debug_info("msim_downloaded_buddy_icon",
- "Downloaded %d bytes\n", len);
-
- if (!url_text) {
- purple_debug_info("msim_downloaded_buddy_icon",
- "failed to download icon for %s",
- user->buddy->name);
- return;
- }
-
- purple_buddy_icons_set_for_user(user->buddy->account,
- user->buddy->name,
- g_memdup((gchar *)url_text, len), len,
- /* Use URL itself as buddy icon "checksum" (TODO: ETag) */
- user->image_url); /* checksum */
-}
-
-
+/* MySpaceIM Protocol Plugin, header file
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "myspace.h"
+
+static void msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user);
+static gchar *msim_format_now_playing(gchar *band, gchar *song);
+static void msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text,
+ gsize len, const gchar *error_message);
+
+/** Format the "now playing" indicator, showing the artist and song.
+ * @return Return a new string (must be g_free()'d), or NULL.
+ */
+static gchar *
+msim_format_now_playing(gchar *band, gchar *song)
+{
+ if ((band && strlen(band)) || (song && strlen(song))) {
+ return g_strdup_printf("%s - %s",
+ (band && strlen(band)) ? band : "Unknown Artist",
+ (song && strlen(song)) ? song : "Unknown Song");
+ } else {
+ return NULL;
+ }
+}
+/** Get the MsimUser from a PurpleBuddy, creating it if needed. */
+MsimUser *
+msim_get_user_from_buddy(PurpleBuddy *buddy)
+{
+ MsimUser *user;
+
+ if (!buddy) {
+ return NULL;
+ }
+
+ if (!buddy->proto_data) {
+ /* No MsimUser for this buddy; make one. */
+
+ /* TODO: where is this freed? */
+ user = g_new0(MsimUser, 1);
+ user->buddy = buddy;
+ buddy->proto_data = (gpointer)user;
+ }
+
+ user = (MsimUser *)(buddy->proto_data);
+
+ return user;
+}
+
+/** Find and return an MsimUser * representing a user on the buddy list, or NULL. */
+MsimUser *
+msim_find_user(MsimSession *session, const gchar *username)
+{
+ PurpleBuddy *buddy;
+ MsimUser *user;
+
+ buddy = purple_find_buddy(session->account, username);
+ if (!buddy) {
+ return NULL;
+ }
+
+ user = msim_get_user_from_buddy(buddy);
+
+ return user;
+}
+
+/** Append user information to a PurpleNotifyUserInfo, given an MsimUser.
+ * Used by msim_tooltip_text() and msim_get_info_cb() to show a user's profile.
+ */
+void
+msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full)
+{
+ gchar *str;
+ guint uid;
+ guint cv;
+
+ /* Useful to identify the account the tooltip refers to.
+ * Other prpls show this. */
+ if (user->username) {
+ purple_notify_user_info_add_pair(user_info, _("User"), user->username);
+ }
+
+ uid = purple_blist_node_get_int(&user->buddy->node, "UserID");
+
+ if (full) {
+ /* TODO: link to username, if available */
+ purple_notify_user_info_add_pair(user_info, _("Profile"),
+ g_strdup_printf("<a href=\"http://myspace.com/%d\">http://myspace.com/%d</a>",
+ uid, uid));
+ }
+
+
+ /* a/s/l...the vitals */
+ if (user->age) {
+ purple_notify_user_info_add_pair(user_info, _("Age"),
+ g_strdup_printf("%d", user->age));
+ }
+
+ if (user->gender && strlen(user->gender)) {
+ purple_notify_user_info_add_pair(user_info, _("Gender"), user->gender);
+ }
+
+ if (user->location && strlen(user->location)) {
+ purple_notify_user_info_add_pair(user_info, _("Location"), user->location);
+ }
+
+ /* Other information */
+ if (user->headline && strlen(user->headline)) {
+ purple_notify_user_info_add_pair(user_info, _("Headline"), user->headline);
+ }
+
+ str = msim_format_now_playing(user->band_name, user->song_name);
+ if (str && strlen(str)) {
+ purple_notify_user_info_add_pair(user_info, _("Song"), str);
+ }
+
+ /* Note: total friends only available if looked up by uid, not username. */
+ if (user->total_friends) {
+ purple_notify_user_info_add_pair(user_info, _("Total Friends"),
+ g_strdup_printf("%d", user->total_friends));
+ }
+
+ if (full) {
+ /* Client information */
+
+ str = user->client_info;
+ cv = user->client_cv;
+
+ if (str && cv != 0) {
+ purple_notify_user_info_add_pair(user_info, _("Client Version"),
+ g_strdup_printf("%s (build %d)", str, cv));
+ } else if (str) {
+ purple_notify_user_info_add_pair(user_info, _("Client Version"),
+ g_strdup(str));
+ } else if (cv) {
+ purple_notify_user_info_add_pair(user_info, _("Client Version"),
+ g_strdup_printf("Build %d", cv));
+ }
+ }
+}
+
+/** Store a field of information about a buddy. */
+void
+msim_store_user_info_each(const gchar *key_str, gchar *value_str, MsimUser *user)
+{
+ if (g_str_equal(key_str, "UserID") || g_str_equal(key_str, "ContactID")) {
+ /* Save to buddy list, if it exists, for quick cached uid lookup with msim_uid2username_from_blist(). */
+ if (user->buddy)
+ {
+ purple_debug_info("msim", "associating uid %s with username %s\n", key_str, user->buddy->name);
+ purple_blist_node_set_int(&user->buddy->node, "UserID", atol(value_str));
+ }
+ /* Need to store in MsimUser, too? What if not on blist? */
+ } else if (g_str_equal(key_str, "Age")) {
+ user->age = atol(value_str);
+ } else if (g_str_equal(key_str, "Gender")) {
+ user->gender = g_strdup(value_str);
+ } else if (g_str_equal(key_str, "Location")) {
+ user->location = g_strdup(value_str);
+ } else if (g_str_equal(key_str, "TotalFriends")) {
+ user->total_friends = atol(value_str);
+ } else if (g_str_equal(key_str, "DisplayName")) {
+ user->display_name = g_strdup(value_str);
+ } else if (g_str_equal(key_str, "BandName")) {
+ user->band_name = g_strdup(value_str);
+ } else if (g_str_equal(key_str, "SongName")) {
+ user->song_name = g_strdup(value_str);
+ } else if (g_str_equal(key_str, "UserName") || g_str_equal(key_str, "IMName") || g_str_equal(key_str, "NickName")) {
+ /* Ignore because PurpleBuddy knows this already */
+ ;
+ } else if (g_str_equal(key_str, "ImageURL") || g_str_equal(key_str, "AvatarURL")) {
+ const gchar *previous_url;
+
+ user->image_url = g_strdup(value_str);
+
+ /* Instead of showing 'no photo' picture, show nothing. */
+ if (g_str_equal(user->image_url, "http://x.myspace.com/images/no_pic.gif"))
+ {
+ purple_buddy_icons_set_for_user(user->buddy->account,
+ user->buddy->name,
+ NULL, 0, NULL);
+ return;
+ }
+
+ /* TODO: use ETag for checksum */
+ previous_url = purple_buddy_icons_get_checksum_for_user(user->buddy);
+
+ /* Only download if URL changed */
+ if (!previous_url || !g_str_equal(previous_url, user->image_url)) {
+ purple_util_fetch_url(user->image_url, TRUE, NULL, TRUE, msim_downloaded_buddy_icon, (gpointer)user);
+ }
+ } else if (g_str_equal(key_str, "LastImageUpdated")) {
+ /* TODO: use somewhere */
+ user->last_image_updated = atol(value_str);
+ } else if (g_str_equal(key_str, "Headline")) {
+ user->headline = g_strdup(value_str);
+ } else {
+ /* TODO: other fields in MsimUser */
+ gchar *msg;
+
+ msg = g_strdup_printf("msim_store_user_info_each: unknown field %s=%s",
+ key_str, value_str);
+
+ msim_unrecognized(NULL, NULL, msg);
+
+ g_free(msg);
+ }
+}
+
+/** Save buddy information to the buddy list from a user info reply message.
+ *
+ * @param session
+ * @param msg The user information reply, with any amount of information.
+ * @param user The structure to save to, or NULL to save in PurpleBuddy->proto_data.
+ *
+ * Variable information is saved to the passed MsimUser structure. Permanent
+ * information (UserID) is stored in the blist node of the buddy list (and
+ * ends up in blist.xml, persisted to disk) if it exists.
+ *
+ * If the function has no buddy information, this function
+ * is a no-op (and returns FALSE).
+ *
+ */
+gboolean
+msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user)
+{
+ gchar *username;
+ MsimMessage *body, *body_node;
+
+ g_return_val_if_fail(MSIM_SESSION_VALID(session), FALSE);
+ g_return_val_if_fail(msg != NULL, FALSE);
+
+ body = msim_msg_get_dictionary(msg, "body");
+ if (!body) {
+ return FALSE;
+ }
+
+ username = msim_msg_get_string(body, "UserName");
+
+ if (!username) {
+ purple_debug_info("msim",
+ "msim_process_reply: not caching body, no UserName\n");
+ msim_msg_free(body);
+ g_free(username);
+ return FALSE;
+ }
+
+ /* Null user = find and store in PurpleBuddy's proto_data */
+ if (!user) {
+ user = msim_find_user(session, username);
+ if (!user) {
+ msim_msg_free(body);
+ g_free(username);
+ return FALSE;
+ }
+ }
+
+ /* TODO: make looping over MsimMessage's easier. */
+ for (body_node = body;
+ body_node != NULL;
+ body_node = msim_msg_get_next_element_node(body_node))
+ {
+ const gchar *key_str;
+ gchar *value_str;
+ MsimMessageElement *elem;
+
+ elem = (MsimMessageElement *)body_node->data;
+ key_str = elem->name;
+
+ value_str = msim_msg_get_string_from_element(elem);
+ msim_store_user_info_each(key_str, value_str, user);
+ g_free(value_str);
+ }
+
+ if (msim_msg_get_integer(msg, "dsn") == MG_OWN_IM_INFO_DSN &&
+ msim_msg_get_integer(msg, "lid") == MG_OWN_IM_INFO_LID) {
+ /* TODO: do something with our own IM info, if we need it for some
+ * specific purpose. Otherwise it is available on the buddy list,
+ * if the user has themselves as their own buddy.
+ *
+ * However, much of the info is already available in MsimSession,
+ * stored in msim_we_are_logged_on(). */
+ } else if (msim_msg_get_integer(msg, "dsn") == MG_OWN_MYSPACE_INFO_DSN &&
+ msim_msg_get_integer(msg, "lid") == MG_OWN_MYSPACE_INFO_LID) {
+ /* TODO: same as above, but for MySpace info. */
+ }
+
+ msim_msg_free(body);
+
+ return TRUE;
+}
+
+/**
+ * Asynchronously lookup user information, calling callback when receive result.
+ *
+ * @param session
+ * @param user The user id, email address, or username. Not freed.
+ * @param cb Callback, called with user information when available.
+ * @param data An arbitray data pointer passed to the callback.
+ */
+/* TODO: change to not use callbacks */
+void
+msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data)
+{
+ MsimMessage *body;
+ gchar *field_name;
+ guint rid, cmd, dsn, lid;
+
+ g_return_if_fail(MSIM_SESSION_VALID(session));
+ g_return_if_fail(user != NULL);
+ /* Callback can be null to not call anything, just lookup & store information. */
+ /*g_return_if_fail(cb != NULL);*/
+
+ purple_debug_info("msim", "msim_lookup_userid: "
+ "asynchronously looking up <%s>\n", user);
+
+ msim_msg_dump("msim_lookup_user: data=%s\n", (MsimMessage *)data);
+
+ /* Setup callback. Response will be associated with request using 'rid'. */
+ rid = msim_new_reply_callback(session, cb, data);
+
+ /* Send request */
+
+ cmd = MSIM_CMD_GET;
+
+ if (msim_is_userid(user)) {
+ field_name = "UserID";
+ dsn = MG_MYSPACE_INFO_BY_ID_DSN;
+ lid = MG_MYSPACE_INFO_BY_ID_LID;
+ } else if (msim_is_email(user)) {
+ field_name = "Email";
+ dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
+ lid = MG_MYSPACE_INFO_BY_STRING_LID;
+ } else {
+ field_name = "UserName";
+ dsn = MG_MYSPACE_INFO_BY_STRING_DSN;
+ lid = MG_MYSPACE_INFO_BY_STRING_LID;
+ }
+
+ body = msim_msg_new(
+ field_name, MSIM_TYPE_STRING, g_strdup(user),
+ NULL);
+
+ g_return_if_fail(msim_send(session,
+ "persist", MSIM_TYPE_INTEGER, 1,
+ "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
+ "cmd", MSIM_TYPE_INTEGER, 1,
+ "dsn", MSIM_TYPE_INTEGER, dsn,
+ "uid", MSIM_TYPE_INTEGER, session->userid,
+ "lid", MSIM_TYPE_INTEGER, lid,
+ "rid", MSIM_TYPE_INTEGER, rid,
+ "body", MSIM_TYPE_DICTIONARY, body,
+ NULL));
+}
+
+
+/**
+ * Check if a string is a userid (all numeric).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is userid, FALSE if not.
+ */
+gboolean
+msim_is_userid(const gchar *user)
+{
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ return strspn(user, "0123456789") == strlen(user);
+}
+
+/**
+ * Check if a string is an email address (contains an @).
+ *
+ * @param user The user id, email, or name.
+ *
+ * @return TRUE if is an email, FALSE if not.
+ *
+ * This function is not intended to be used as a generic
+ * means of validating email addresses, but to distinguish
+ * between a user represented by an email address from
+ * other forms of identification.
+ */
+gboolean
+msim_is_email(const gchar *user)
+{
+ g_return_val_if_fail(user != NULL, FALSE);
+
+ return strchr(user, '@') != NULL;
+}
+
+
+/** Callback for when a buddy icon finished being downloaded. */
+static void
+msim_downloaded_buddy_icon(PurpleUtilFetchUrlData *url_data,
+ gpointer user_data,
+ const gchar *url_text,
+ gsize len,
+ const gchar *error_message)
+{
+ MsimUser *user;
+
+ user = (MsimUser *)user_data;
+
+ purple_debug_info("msim_downloaded_buddy_icon",
+ "Downloaded %d bytes\n", len);
+
+ if (!url_text) {
+ purple_debug_info("msim_downloaded_buddy_icon",
+ "failed to download icon for %s",
+ user->buddy->name);
+ return;
+ }
+
+ purple_buddy_icons_set_for_user(user->buddy->account,
+ user->buddy->name,
+ g_memdup((gchar *)url_text, len), len,
+ /* Use URL itself as buddy icon "checksum" (TODO: ETag) */
+ user->image_url); /* checksum */
+}
+
+
--- a/libpurple/protocols/myspace/user.h Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/user.h Tue Sep 18 00:47:51 2007 +0000
@@ -1,55 +1,55 @@
-/* MySpaceIM Protocol Plugin, header file
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MYSPACE_USER_H
-#define _MYSPACE_USER_H
-
-/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */
-/* GHashTable? */
-typedef struct _MsimUser
-{
- PurpleBuddy *buddy;
- guint client_cv;
- gchar *client_info;
- guint age;
- gchar *gender;
- gchar *location;
- guint total_friends;
- gchar *headline;
- gchar *display_name;
- /* Note: uid is in &buddy->node (set_blist_node_int), since it never changes */
- gchar *username;
- gchar *band_name, *song_name;
- gchar *image_url;
- guint last_image_updated;
-} MsimUser;
-
-/* Callback function pointer type for when a user's information is received,
- * initiated from a user lookup. */
-typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, MsimMessage *userinfo, gpointer data);
-
-MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy);
-MsimUser *msim_find_user(MsimSession *session, const gchar *username);
-void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
-gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user);
-gboolean msim_is_userid(const gchar *user);
-gboolean msim_is_email(const gchar *user);
-void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
-
-#endif /* !_MYSPACE_USER_H */
+/* MySpaceIM Protocol Plugin, header file
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSPACE_USER_H
+#define _MYSPACE_USER_H
+
+/* Hold ephemeral information about buddies, for proto_data of PurpleBuddy. */
+/* GHashTable? */
+typedef struct _MsimUser
+{
+ PurpleBuddy *buddy;
+ guint client_cv;
+ gchar *client_info;
+ guint age;
+ gchar *gender;
+ gchar *location;
+ guint total_friends;
+ gchar *headline;
+ gchar *display_name;
+ /* Note: uid is in &buddy->node (set_blist_node_int), since it never changes */
+ gchar *username;
+ gchar *band_name, *song_name;
+ gchar *image_url;
+ guint last_image_updated;
+} MsimUser;
+
+/* Callback function pointer type for when a user's information is received,
+ * initiated from a user lookup. */
+typedef void (*MSIM_USER_LOOKUP_CB)(MsimSession *session, MsimMessage *userinfo, gpointer data);
+
+MsimUser *msim_get_user_from_buddy(PurpleBuddy *buddy);
+MsimUser *msim_find_user(MsimSession *session, const gchar *username);
+void msim_append_user_info(MsimSession *session, PurpleNotifyUserInfo *user_info, MsimUser *user, gboolean full);
+gboolean msim_store_user_info(MsimSession *session, MsimMessage *msg, MsimUser *user);
+gboolean msim_is_userid(const gchar *user);
+gboolean msim_is_email(const gchar *user);
+void msim_lookup_user(MsimSession *session, const gchar *user, MSIM_USER_LOOKUP_CB cb, gpointer data);
+
+#endif /* !_MYSPACE_USER_H */
--- a/libpurple/protocols/myspace/zap.c Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/zap.c Tue Sep 18 00:47:51 2007 +0000
@@ -1,265 +1,265 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "myspace.h"
-#include "zap.h"
-
-static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code);
-static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr);
-
-
-/** Get zap types. */
-GList *
-msim_attention_types(PurpleAccount *acct)
-{
- static GList *types = NULL;
- MsimAttentionType* attn;
-
- if (!types) {
-#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing) \
- attn = g_new0(MsimAttentionType, 1); \
- attn->icon_name = icn; \
- attn->name = nme; \
- attn->incoming_description = incoming; \
- attn->outgoing_description = outgoing; \
- types = g_list_append(types, attn);
-
- /* TODO: icons for each zap */
- _MSIM_ADD_NEW_ATTENTION(NULL, _("zap"), _("zapped"), _("Zapping"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("whack"), _("whacked"), _("Whacking"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("torch"), _("torched"), _("Torching"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("smooch"), _("smooched"), _("Smooching"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("hug"), _("hugged"), _("Hugging"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("bslap"), _("bslapped"), _("Bslapping"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("goose"), _("goosed"), _("Goosing"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("hi-five"), _("hi-fived"), _("Hi-fiving"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("punk"), _("punk'd"), _("Punking"));
- _MSIM_ADD_NEW_ATTENTION(NULL, _("raspberry"), _("raspberried"), _("Raspberry'ing"));
- }
-
- return types;
-}
-
-/** Send a zap */
-gboolean
-msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
-{
- GList *types;
- MsimSession *session;
- MsimAttentionType *attn;
- PurpleBuddy *buddy;
-
- session = (MsimSession *)gc->proto_data;
-
- /* Look for this attention type, by the code index given. */
- types = msim_attention_types(gc->account);
- attn = (MsimAttentionType *)g_list_nth_data(types, code);
-
- if (!attn) {
- purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
- return FALSE;
- }
-
- buddy = purple_find_buddy(session->account, username);
- if (!buddy) {
- return FALSE;
- }
-
- msim_send_zap(session, username, code);
-
- return TRUE;
-}
-
-/** Send a zap to a user. */
-static gboolean
-msim_send_zap(MsimSession *session, const gchar *username, guint code)
-{
- gchar *zap_string;
- gboolean rc;
-#ifndef MSIM_USE_ATTENTION_API
- GList *types;
- MsimAttentionType *attn;
- gchar *zap_description;
-#endif
-
- g_return_val_if_fail(session != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
-
-
-#ifdef MSIM_USE_ATTENTION_API
- /* serv_send_attention(session->gc, username, code); */
-#else
- types = msim_attention_types(session->account);
-
- attn = g_list_nth_data(types, code);
- if (!attn) {
- return FALSE;
- }
-
-
- zap_description = g_strdup_printf("*** Attention: %s %s ***", attn->outgoing_description,
- username);
-
- serv_got_im(session->gc, username, zap_description,
- PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_SYSTEM, time(NULL));
-
- g_free(zap_description);
-#endif
-
- /* Construct and send the actual zap command. */
- zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
-
- if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
- purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s",
- username, zap_string);
- rc = FALSE;
- } else {
- rc = TRUE;
- }
-
- g_free(zap_string);
-
- return rc;
-
-}
-
-/** Zap someone. Callback from msim_blist_node_menu zap menu. */
-static void
-msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
-{
- PurpleBuddy *buddy;
- PurpleAccount *account;
- PurpleConnection *gc;
- MsimSession *session;
- guint zap;
-
- if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- /* Only know about buddies for now. */
- return;
- }
-
- g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
- buddy = (PurpleBuddy *)node;
-
- /* Find the session */
- account = buddy->account;
- gc = purple_account_get_connection(account);
- session = (MsimSession *)gc->proto_data;
-
- zap = GPOINTER_TO_INT(zap_num_ptr);
-
-#ifdef MSIM_USE_ATTENTION_API
- serv_send_attention(session->gc, buddy->name, zap);
-#else
- g_return_if_fail(msim_send_zap(session, buddy->name, zap));
-#endif
-}
-
-/** Return menu, if any, for a buddy list node. */
-GList *
-msim_blist_node_menu(PurpleBlistNode *node)
-{
- GList *menu, *zap_menu;
- GList *types;
- PurpleMenuAction *act;
- /* Warning: hardcoded to match that in msim_attention_types. */
- const gchar *zap_names[10];
- guint i;
-
- if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- /* Only know about buddies for now. */
- return NULL;
- }
-
- /* Names from official client. */
- types = msim_attention_types(NULL);
- i = 0;
- do
- {
- MsimAttentionType *attn;
-
- attn = (MsimAttentionType *)types->data;
- zap_names[i] = attn->name;
- ++i;
- } while ((types = g_list_next(types)));
-
- menu = zap_menu = NULL;
-
- /* TODO: get rid of once is accessible directly in GUI */
- for (i = 0; i < sizeof(zap_names) / sizeof(zap_names[0]); ++i) {
- act = purple_menu_action_new(zap_names[i], PURPLE_CALLBACK(msim_send_zap_from_menu),
- GUINT_TO_POINTER(i), NULL);
- zap_menu = g_list_append(zap_menu, act);
- }
-
- act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu);
- menu = g_list_append(menu, act);
-
- return menu;
-}
-
-/** Process an incoming zap. */
-gboolean
-msim_incoming_zap(MsimSession *session, MsimMessage *msg)
-{
- gchar *msg_text, *username;
- gint zap;
-#ifndef MSIM_USE_ATTENTION_API
- const gchar *zap_past_tense[10];
- gchar *zap_text;
-
- zap_past_tense[0] = _("zapped");
- zap_past_tense[1] = _("whacked");
- zap_past_tense[2] = _("torched");
- zap_past_tense[3] = _("smooched");
- zap_past_tense[4] = _("hugged");
- zap_past_tense[5] = _("bslapped");
- zap_past_tense[6] = _("goosed");
- zap_past_tense[7] = _("hi-fived");
- zap_past_tense[8] = _("punk'd");
- zap_past_tense[9] = _("raspberried");
-#endif
-
- msg_text = msim_msg_get_string(msg, "msg");
- username = msim_msg_get_string(msg, "_username");
-
- g_return_val_if_fail(msg_text != NULL, FALSE);
- g_return_val_if_fail(username != NULL, FALSE);
-
- g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE);
-
- zap = CLAMP(zap, 0, 9);
-
-#ifdef MSIM_USE_ATTENTION_API
- serv_got_attention(session->gc, username, zap);
-#else
- zap_text = g_strdup_printf(_("*** You have been %s! ***"), zap_past_tense[zap]);
- serv_got_im(session->gc, username, zap_text,
- PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM, time(NULL));
- g_free(zap_text);
-#endif
-
- g_free(msg_text);
- g_free(username);
-
- return TRUE;
-}
-
-
+/* MySpaceIM Protocol Plugin - zap support
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "myspace.h"
+#include "zap.h"
+
+static gboolean msim_send_zap(MsimSession *session, const gchar *username, guint code);
+static void msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr);
+
+
+/** Get zap types. */
+GList *
+msim_attention_types(PurpleAccount *acct)
+{
+ static GList *types = NULL;
+ MsimAttentionType* attn;
+
+ if (!types) {
+#define _MSIM_ADD_NEW_ATTENTION(icn, nme, incoming, outgoing) \
+ attn = g_new0(MsimAttentionType, 1); \
+ attn->icon_name = icn; \
+ attn->name = nme; \
+ attn->incoming_description = incoming; \
+ attn->outgoing_description = outgoing; \
+ types = g_list_append(types, attn);
+
+ /* TODO: icons for each zap */
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("zap"), _("zapped"), _("Zapping"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("whack"), _("whacked"), _("Whacking"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("torch"), _("torched"), _("Torching"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("smooch"), _("smooched"), _("Smooching"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("hug"), _("hugged"), _("Hugging"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("bslap"), _("bslapped"), _("Bslapping"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("goose"), _("goosed"), _("Goosing"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("hi-five"), _("hi-fived"), _("Hi-fiving"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("punk"), _("punk'd"), _("Punking"));
+ _MSIM_ADD_NEW_ATTENTION(NULL, _("raspberry"), _("raspberried"), _("Raspberry'ing"));
+ }
+
+ return types;
+}
+
+/** Send a zap */
+gboolean
+msim_send_attention(PurpleConnection *gc, const gchar *username, guint code)
+{
+ GList *types;
+ MsimSession *session;
+ MsimAttentionType *attn;
+ PurpleBuddy *buddy;
+
+ session = (MsimSession *)gc->proto_data;
+
+ /* Look for this attention type, by the code index given. */
+ types = msim_attention_types(gc->account);
+ attn = (MsimAttentionType *)g_list_nth_data(types, code);
+
+ if (!attn) {
+ purple_debug_info("msim_send_attention", "got invalid zap code %d\n", code);
+ return FALSE;
+ }
+
+ buddy = purple_find_buddy(session->account, username);
+ if (!buddy) {
+ return FALSE;
+ }
+
+ msim_send_zap(session, username, code);
+
+ return TRUE;
+}
+
+/** Send a zap to a user. */
+static gboolean
+msim_send_zap(MsimSession *session, const gchar *username, guint code)
+{
+ gchar *zap_string;
+ gboolean rc;
+#ifndef MSIM_USE_ATTENTION_API
+ GList *types;
+ MsimAttentionType *attn;
+ gchar *zap_description;
+#endif
+
+ g_return_val_if_fail(session != NULL, FALSE);
+ g_return_val_if_fail(username != NULL, FALSE);
+
+
+#ifdef MSIM_USE_ATTENTION_API
+ /* serv_send_attention(session->gc, username, code); */
+#else
+ types = msim_attention_types(session->account);
+
+ attn = g_list_nth_data(types, code);
+ if (!attn) {
+ return FALSE;
+ }
+
+
+ zap_description = g_strdup_printf("*** Attention: %s %s ***", attn->outgoing_description,
+ username);
+
+ serv_got_im(session->gc, username, zap_description,
+ PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_SYSTEM, time(NULL));
+
+ g_free(zap_description);
+#endif
+
+ /* Construct and send the actual zap command. */
+ zap_string = g_strdup_printf("!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", code);
+
+ if (!msim_send_bm(session, username, zap_string, MSIM_BM_ACTION)) {
+ purple_debug_info("msim_send_zap_from_menu", "msim_send_bm failed: zapping %s with %s",
+ username, zap_string);
+ rc = FALSE;
+ } else {
+ rc = TRUE;
+ }
+
+ g_free(zap_string);
+
+ return rc;
+
+}
+
+/** Zap someone. Callback from msim_blist_node_menu zap menu. */
+static void
+msim_send_zap_from_menu(PurpleBlistNode *node, gpointer zap_num_ptr)
+{
+ PurpleBuddy *buddy;
+ PurpleAccount *account;
+ PurpleConnection *gc;
+ MsimSession *session;
+ guint zap;
+
+ if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ /* Only know about buddies for now. */
+ return;
+ }
+
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+ buddy = (PurpleBuddy *)node;
+
+ /* Find the session */
+ account = buddy->account;
+ gc = purple_account_get_connection(account);
+ session = (MsimSession *)gc->proto_data;
+
+ zap = GPOINTER_TO_INT(zap_num_ptr);
+
+#ifdef MSIM_USE_ATTENTION_API
+ serv_send_attention(session->gc, buddy->name, zap);
+#else
+ g_return_if_fail(msim_send_zap(session, buddy->name, zap));
+#endif
+}
+
+/** Return menu, if any, for a buddy list node. */
+GList *
+msim_blist_node_menu(PurpleBlistNode *node)
+{
+ GList *menu, *zap_menu;
+ GList *types;
+ PurpleMenuAction *act;
+ /* Warning: hardcoded to match that in msim_attention_types. */
+ const gchar *zap_names[10];
+ guint i;
+
+ if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ /* Only know about buddies for now. */
+ return NULL;
+ }
+
+ /* Names from official client. */
+ types = msim_attention_types(NULL);
+ i = 0;
+ do
+ {
+ MsimAttentionType *attn;
+
+ attn = (MsimAttentionType *)types->data;
+ zap_names[i] = attn->name;
+ ++i;
+ } while ((types = g_list_next(types)));
+
+ menu = zap_menu = NULL;
+
+ /* TODO: get rid of once is accessible directly in GUI */
+ for (i = 0; i < sizeof(zap_names) / sizeof(zap_names[0]); ++i) {
+ act = purple_menu_action_new(zap_names[i], PURPLE_CALLBACK(msim_send_zap_from_menu),
+ GUINT_TO_POINTER(i), NULL);
+ zap_menu = g_list_append(zap_menu, act);
+ }
+
+ act = purple_menu_action_new(_("Zap"), NULL, NULL, zap_menu);
+ menu = g_list_append(menu, act);
+
+ return menu;
+}
+
+/** Process an incoming zap. */
+gboolean
+msim_incoming_zap(MsimSession *session, MsimMessage *msg)
+{
+ gchar *msg_text, *username;
+ gint zap;
+#ifndef MSIM_USE_ATTENTION_API
+ const gchar *zap_past_tense[10];
+ gchar *zap_text;
+
+ zap_past_tense[0] = _("zapped");
+ zap_past_tense[1] = _("whacked");
+ zap_past_tense[2] = _("torched");
+ zap_past_tense[3] = _("smooched");
+ zap_past_tense[4] = _("hugged");
+ zap_past_tense[5] = _("bslapped");
+ zap_past_tense[6] = _("goosed");
+ zap_past_tense[7] = _("hi-fived");
+ zap_past_tense[8] = _("punk'd");
+ zap_past_tense[9] = _("raspberried");
+#endif
+
+ msg_text = msim_msg_get_string(msg, "msg");
+ username = msim_msg_get_string(msg, "_username");
+
+ g_return_val_if_fail(msg_text != NULL, FALSE);
+ g_return_val_if_fail(username != NULL, FALSE);
+
+ g_return_val_if_fail(sscanf(msg_text, "!!!ZAP_SEND!!!=RTE_BTN_ZAPS_%d", &zap) == 1, FALSE);
+
+ zap = CLAMP(zap, 0, 9);
+
+#ifdef MSIM_USE_ATTENTION_API
+ serv_got_attention(session->gc, username, zap);
+#else
+ zap_text = g_strdup_printf(_("*** You have been %s! ***"), zap_past_tense[zap]);
+ serv_got_im(session->gc, username, zap_text,
+ PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM, time(NULL));
+ g_free(zap_text);
+#endif
+
+ g_free(msg_text);
+ g_free(username);
+
+ return TRUE;
+}
+
+
--- a/libpurple/protocols/myspace/zap.h Mon Sep 17 03:34:11 2007 +0000
+++ b/libpurple/protocols/myspace/zap.h Tue Sep 18 00:47:51 2007 +0000
@@ -1,28 +1,28 @@
-/* MySpaceIM Protocol Plugin - zap support
- *
- * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MYSPACE_ZAP_H
-#define _MYSPACE_ZAP_H
-
-GList *msim_attention_types(PurpleAccount *acct);
-gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code);
-GList *msim_blist_node_menu(PurpleBlistNode *node);
-gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg);
-
-#endif /* !_MYSPACE_ZAP_H */
+/* MySpaceIM Protocol Plugin - zap support
+ *
+ * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MYSPACE_ZAP_H
+#define _MYSPACE_ZAP_H
+
+GList *msim_attention_types(PurpleAccount *acct);
+gboolean msim_send_attention(PurpleConnection *gc, const gchar *username, guint code);
+GList *msim_blist_node_menu(PurpleBlistNode *node);
+gboolean msim_incoming_zap(MsimSession *session, MsimMessage *msg);
+
+#endif /* !_MYSPACE_ZAP_H */