/**
* Copyright (C) 2007-2008 Felipe Contreras
* Copyright (C) 2005 Sanoi <sanoix@gmail.com>
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "pecan_util.h"
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include "msn.h"
#include <string.h>
#ifdef HAVE_LIBPURPLE
/* libpurple stuff. */
#include "fix_purple_win32.h"
#include <util.h>
#include <cipher.h>
#define BUFSIZE 256
#endif /* HAVE_LIBPURPLE */
gchar *
pecan_url_decode (const gchar *url)
{
gchar *new;
const gchar *src;
gchar *dest;
/*
Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.
*/
dest = new = g_malloc (strlen (url) + 1);
src = url;
while (*src != '\0')
{
if (*src == '%')
{
gint v1;
gint v2;
v1 = g_ascii_xdigit_value (src[1]);
v2 = g_ascii_xdigit_value (src[2]);
if ((v1 >= 0) && (v2 >= 0))
{
*dest = (v1 * 16) + v2;
}
else
{
/* Malformed */
g_free (new);
return NULL;
}
src += 3;
}
else
{
*dest = *src;
src++;
}
dest++;
}
*dest = '\0';
return new;
}
#ifdef HAVE_LIBPURPLE
void
msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
{
char *cur;
GString *pre = g_string_new(NULL);
GString *post = g_string_new(NULL);
unsigned int colors[3];
if (pre_ret != NULL) *pre_ret = NULL;
if (post_ret != NULL) *post_ret = NULL;
cur = strstr(mime, "FN=");
if (cur && (*(cur = cur + 3) != ';'))
{
pre = g_string_append(pre, "<FONT FACE=\"");
while (*cur && *cur != ';')
{
pre = g_string_append_c(pre, *cur);
cur++;
}
pre = g_string_append(pre, "\">");
post = g_string_prepend(post, "</FONT>");
}
cur = strstr(mime, "EF=");
if (cur && (*(cur = cur + 3) != ';'))
{
while (*cur && *cur != ';')
{
pre = g_string_append_c(pre, '<');
pre = g_string_append_c(pre, *cur);
pre = g_string_append_c(pre, '>');
post = g_string_prepend_c(post, '>');
post = g_string_prepend_c(post, *cur);
post = g_string_prepend_c(post, '/');
post = g_string_prepend_c(post, '<');
cur++;
}
}
cur = strstr(mime, "CO=");
if (cur && (*(cur = cur + 3) != ';'))
{
int i;
i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
if (i > 0)
{
char tag[64];
if (i == 1)
{
colors[1] = 0;
colors[2] = 0;
}
else if (i == 2)
{
unsigned int temp = colors[0];
colors[0] = colors[1];
colors[1] = temp;
colors[2] = 0;
}
else if (i == 3)
{
unsigned int temp = colors[2];
colors[2] = colors[0];
colors[0] = temp;
}
g_snprintf(tag, sizeof(tag),
"<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
colors[0], colors[1], colors[2]);
pre = g_string_append(pre, tag);
post = g_string_prepend(post, "</FONT>");
}
}
cur = strstr(mime, "RL=");
if (cur && (*(cur = cur + 3) != ';'))
{
if (*cur == '1')
{
/* RTL text was received */
pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
post = g_string_prepend(post, "</SPAN>");
}
}
cur = g_strdup(purple_url_decode(pre->str));
g_string_free(pre, TRUE);
if (pre_ret != NULL)
*pre_ret = cur;
else
g_free(cur);
cur = g_strdup(purple_url_decode(post->str));
g_string_free(post, TRUE);
if (post_ret != NULL)
*post_ret = cur;
else
g_free(cur);
}
/*
* We need this because we're only supposed to encode spaces in the font
* names. purple_url_encode() isn't acceptable.
*/
static const char *
encode_spaces(const char *str)
{
static char buf[MSN_BUF_LEN];
const char *c;
char *d;
g_return_val_if_fail(str != NULL, NULL);
for (c = str, d = buf; *c != '\0'; c++)
{
if (*c == ' ')
{
*d++ = '%';
*d++ = '2';
*d++ = '0';
}
else
*d++ = *c;
}
return buf;
}
/*
* Taken from the zephyr plugin.
* This parses HTML formatting (put out by one of the gtkimhtml widgets
* and converts it to msn formatting. It doesn't deal with the tag closing,
* but gtkimhtml widgets give valid html.
* It currently deals properly with <b>, <u>, <i>, <font face=...>,
* <font color=...>, <span dir=...>, <span style="direction: ...">.
* It ignores <font back=...> and <font size=...>
*/
void
msn_import_html(const char *html, char **attributes, char **message)
{
int len, retcount = 0;
const char *c;
char *msg;
char *fontface = NULL;
char fonteffect[4];
char fontcolor[7];
char direction = '0';
gboolean has_bold = FALSE;
gboolean has_italic = FALSE;
gboolean has_underline = FALSE;
gboolean has_strikethrough = FALSE;
g_return_if_fail(html != NULL);
g_return_if_fail(attributes != NULL);
g_return_if_fail(message != NULL);
len = strlen(html);
msg = g_malloc0(len + 1);
memset(fontcolor, 0, sizeof(fontcolor));
strcat(fontcolor, "0");
memset(fonteffect, 0, sizeof(fonteffect));
for (c = html; *c != '\0';)
{
if (*c == '<')
{
if (!g_ascii_strncasecmp(c + 1, "br>", 3))
{
msg[retcount++] = '\r';
msg[retcount++] = '\n';
c += 4;
}
else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
{
if (!has_italic)
{
strcat(fonteffect, "I");
has_italic = TRUE;
}
c += 3;
}
else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
{
if (!has_bold)
{
strcat(fonteffect, "B");
has_bold = TRUE;
}
c += 3;
}
else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
{
if (!has_underline)
{
strcat(fonteffect, "U");
has_underline = TRUE;
}
c += 3;
}
else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
{
if (!has_strikethrough)
{
strcat(fonteffect, "S");
has_strikethrough = TRUE;
}
c += 3;
}
else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
{
c += 9;
if (!g_ascii_strncasecmp(c, "mailto:", 7))
c += 7;
while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
msg[retcount++] = *c++;
if (*c != '\0')
c += 2;
/* ignore descriptive string */
while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
c++;
if (*c != '\0')
c += 4;
}
else if (!g_ascii_strncasecmp(c + 1, "span", 4))
{
/* Bi-directional text support using CSS properties in span tags */
c += 5;
while (*c != '\0' && *c != '>')
{
while (*c == ' ')
c++;
if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
{
c += 9;
direction = '1';
}
else if (!g_ascii_strncasecmp(c, "style=\"", 7))
{
/* Parse inline CSS attributes */
char *css_attributes;
int attr_len = 0;
c += 7;
while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
attr_len++;
if (*(c + attr_len) == '"')
{
char *attr_dir;
css_attributes = g_strndup(c, attr_len);
attr_dir = purple_markup_get_css_property(css_attributes, "direction");
if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
direction = '1';
g_free(attr_dir);
g_free(css_attributes);
}
}
else
{
c++;
}
}
if (*c == '>')
c++;
}
else if (!g_ascii_strncasecmp(c + 1, "font", 4))
{
c += 5;
while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
c++;
if (!g_ascii_strncasecmp(c, "color=\"#", 7))
{
c += 8;
fontcolor[0] = *(c + 4);
fontcolor[1] = *(c + 5);
fontcolor[2] = *(c + 2);
fontcolor[3] = *(c + 3);
fontcolor[4] = *c;
fontcolor[5] = *(c + 1);
c += 8;
}
else if (!g_ascii_strncasecmp(c, "face=\"", 6))
{
const char *end = NULL;
const char *comma = NULL;
unsigned int namelen = 0;
c += 6;
end = strchr(c, '\"');
comma = strchr(c, ',');
if (comma == NULL || comma > end)
namelen = (unsigned int)(end - c);
else
namelen = (unsigned int)(comma - c);
fontface = g_strndup(c, namelen);
c = end + 2;
}
else
{
/* Drop all unrecognized/misparsed font tags */
while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
c++;
if (*c != '\0')
c += 2;
}
}
else
{
while ((*c != '\0') && (*c != '>'))
c++;
if (*c != '\0')
c++;
}
}
else if (*c == '&')
{
if (!g_ascii_strncasecmp(c, "<", 4))
{
msg[retcount++] = '<';
c += 4;
}
else if (!g_ascii_strncasecmp(c, "&a