summaryrefslogtreecommitdiff
path: root/libpurple/protocols/oscar
diff options
context:
space:
mode:
Diffstat (limited to 'libpurple/protocols/oscar')
-rw-r--r--libpurple/protocols/oscar/Makefile.am10
-rw-r--r--libpurple/protocols/oscar/Makefile.mingw16
-rw-r--r--libpurple/protocols/oscar/authorization.c153
-rw-r--r--libpurple/protocols/oscar/bstream.c127
-rw-r--r--libpurple/protocols/oscar/clientlogin.c11
-rw-r--r--libpurple/protocols/oscar/encoding.c235
-rw-r--r--libpurple/protocols/oscar/encoding.h46
-rw-r--r--libpurple/protocols/oscar/family_admin.c10
-rw-r--r--libpurple/protocols/oscar/family_advert.c51
-rw-r--r--libpurple/protocols/oscar/family_alert.c4
-rw-r--r--libpurple/protocols/oscar/family_auth.c34
-rw-r--r--libpurple/protocols/oscar/family_bart.c4
-rw-r--r--libpurple/protocols/oscar/family_bos.c92
-rw-r--r--libpurple/protocols/oscar/family_buddy.c111
-rw-r--r--libpurple/protocols/oscar/family_chat.c218
-rw-r--r--libpurple/protocols/oscar/family_chatnav.c82
-rw-r--r--libpurple/protocols/oscar/family_feedbag.c208
-rw-r--r--libpurple/protocols/oscar/family_icbm.c1621
-rw-r--r--libpurple/protocols/oscar/family_icq.c403
-rw-r--r--libpurple/protocols/oscar/family_invite.c53
-rw-r--r--libpurple/protocols/oscar/family_locate.c270
-rw-r--r--libpurple/protocols/oscar/family_odir.c264
-rw-r--r--libpurple/protocols/oscar/family_oservice.c212
-rw-r--r--libpurple/protocols/oscar/family_userlookup.c2
-rw-r--r--libpurple/protocols/oscar/flap_connection.c28
-rw-r--r--libpurple/protocols/oscar/libaim.c9
-rw-r--r--libpurple/protocols/oscar/libicq.c10
-rw-r--r--libpurple/protocols/oscar/misc.c36
-rw-r--r--libpurple/protocols/oscar/msgcookie.c15
-rw-r--r--libpurple/protocols/oscar/odc.c11
-rw-r--r--libpurple/protocols/oscar/oft.c2
-rw-r--r--libpurple/protocols/oscar/oscar.c2229
-rw-r--r--libpurple/protocols/oscar/oscar.h583
-rw-r--r--libpurple/protocols/oscar/oscar_data.c4
-rw-r--r--libpurple/protocols/oscar/oscarcommon.h1
-rw-r--r--libpurple/protocols/oscar/peer_proxy.c10
-rw-r--r--libpurple/protocols/oscar/rxhandlers.c191
-rw-r--r--libpurple/protocols/oscar/snac.c16
-rw-r--r--libpurple/protocols/oscar/tlv.c52
-rw-r--r--libpurple/protocols/oscar/userinfo.c553
-rw-r--r--libpurple/protocols/oscar/util.c205
-rw-r--r--libpurple/protocols/oscar/visibility.c199
-rw-r--r--libpurple/protocols/oscar/visibility.h (renamed from libpurple/protocols/oscar/family_translate.c)30
43 files changed, 2442 insertions, 5979 deletions
diff --git a/libpurple/protocols/oscar/Makefile.am b/libpurple/protocols/oscar/Makefile.am
index 5dfcba37df..4cf5e4995b 100644
--- a/libpurple/protocols/oscar/Makefile.am
+++ b/libpurple/protocols/oscar/Makefile.am
@@ -6,10 +6,11 @@ EXTRA_DIST = \
pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION)
OSCARSOURCES = \
+ authorization.c \
bstream.c \
clientlogin.c \
+ encoding.c \
family_admin.c \
- family_advert.c \
family_alert.c \
family_auth.c \
family_bart.c \
@@ -19,14 +20,11 @@ OSCARSOURCES = \
family_chatnav.c \
family_icq.c \
family_icbm.c \
- family_invite.c \
family_locate.c \
- family_odir.c \
family_oservice.c \
family_popup.c \
family_feedbag.c \
family_stats.c \
- family_translate.c \
family_userlookup.c \
flap_connection.c \
misc.c \
@@ -44,7 +42,9 @@ OSCARSOURCES = \
snac.c \
snactypes.h \
tlv.c \
- util.c
+ userinfo.c \
+ util.c \
+ visibility.c
AM_CFLAGS = $(st)
diff --git a/libpurple/protocols/oscar/Makefile.mingw b/libpurple/protocols/oscar/Makefile.mingw
index e9b7edd5fd..fa70dd433f 100644
--- a/libpurple/protocols/oscar/Makefile.mingw
+++ b/libpurple/protocols/oscar/Makefile.mingw
@@ -41,10 +41,11 @@ LIB_PATHS += -L$(GTK_TOP)/lib \
## SOURCES, OBJECTS
##
C_SRC = \
+ authorization.c \
bstream.c \
clientlogin.c \
+ encoding.c \
family_admin.c \
- family_advert.c \
family_alert.c \
family_auth.c \
family_bart.c \
@@ -52,16 +53,13 @@ C_SRC = \
family_buddy.c \
family_chat.c \
family_chatnav.c \
- family_icq.c \
+ family_feedbag.c \
family_icbm.c \
- family_invite.c \
+ family_icq.c \
family_locate.c \
- family_odir.c \
- family_popup.c \
family_oservice.c \
- family_feedbag.c \
+ family_popup.c \
family_stats.c \
- family_translate.c \
family_userlookup.c \
flap_connection.c \
misc.c \
@@ -75,7 +73,9 @@ C_SRC = \
rxhandlers.c \
snac.c \
tlv.c \
- util.c
+ userinfo.c \
+ util.c \
+ visibility.c
OBJECTS = $(C_SRC:%.c=%.o)
diff --git a/libpurple/protocols/oscar/authorization.c b/libpurple/protocols/oscar/authorization.c
new file mode 100644
index 0000000000..877605c3a2
--- /dev/null
+++ b/libpurple/protocols/oscar/authorization.c
@@ -0,0 +1,153 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+*/
+
+/*
+ * Everything related to OSCAR authorization requests.
+ */
+
+#include "oscar.h"
+#include "request.h"
+
+static void
+oscar_auth_request(struct name_data *data, char *msg)
+{
+ PurpleConnection *gc;
+ OscarData *od;
+ PurpleAccount *account;
+ PurpleBuddy *buddy;
+ PurpleGroup *group;
+ const char *bname, *gname;
+
+ gc = data->gc;
+ od = purple_connection_get_protocol_data(gc);
+ account = purple_connection_get_account(gc);
+ buddy = purple_find_buddy(account, data->name);
+ if (buddy != NULL)
+ group = purple_buddy_get_group(buddy);
+ else
+ group = NULL;
+
+ if (group != NULL)
+ {
+ bname = purple_buddy_get_name(buddy);
+ gname = purple_group_get_name(group);
+ purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n",
+ bname, gname);
+ aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
+ if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))
+ {
+ aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
+
+ /* Mobile users should always be online */
+ if (bname[0] == '+') {
+ purple_prpl_got_user_status(account,
+ purple_buddy_get_name(buddy),
+ OSCAR_STATUS_ID_AVAILABLE, NULL);
+ purple_prpl_got_user_status(account,
+ purple_buddy_get_name(buddy),
+ OSCAR_STATUS_ID_MOBILE, NULL);
+ }
+ }
+ }
+
+ oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_grant(gpointer cbdata)
+{
+ struct name_data *data = cbdata;
+ PurpleConnection *gc = data->gc;
+ OscarData *od = purple_connection_get_protocol_data(gc);
+
+ aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
+
+ oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_dontgrant(struct name_data *data, char *msg)
+{
+ PurpleConnection *gc = data->gc;
+ OscarData *od = purple_connection_get_protocol_data(gc);
+
+ aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
+
+ oscar_free_name_data(data);
+}
+
+static void
+oscar_auth_dontgrant_msgprompt(gpointer cbdata)
+{
+ struct name_data *data = cbdata;
+ purple_request_input(data->gc, NULL, _("Authorization Denied Message:"),
+ NULL, _("No reason given."), TRUE, FALSE, NULL,
+ _("_OK"), G_CALLBACK(oscar_auth_dontgrant),
+ _("_Cancel"), G_CALLBACK(oscar_free_name_data),
+ purple_connection_get_account(data->gc), data->name, NULL,
+ data);
+}
+
+/* When you ask other people for authorization */
+void
+oscar_auth_sendrequest(PurpleConnection *gc, const char *name)
+{
+ struct name_data *data;
+
+ data = g_new0(struct name_data, 1);
+ data->gc = gc;
+ data->name = g_strdup(name);
+
+ purple_request_input(data->gc, NULL, _("Authorization Request Message:"),
+ NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
+ _("_OK"), G_CALLBACK(oscar_auth_request),
+ _("_Cancel"), G_CALLBACK(oscar_free_name_data),
+ purple_connection_get_account(gc), name, NULL,
+ data);
+}
+
+void
+oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
+{
+ PurpleBuddy *buddy;
+ PurpleConnection *gc;
+
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+ buddy = (PurpleBuddy *) node;
+ gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+ oscar_auth_sendrequest(gc, purple_buddy_get_name(buddy));
+}
+
+/* When other people ask you for authorization */
+void
+oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason)
+{
+ PurpleAccount* account = purple_connection_get_account(gc);
+ struct name_data *data = g_new(struct name_data, 1);
+
+ data->gc = gc;
+ data->name = name;
+ data->nick = nick;
+
+ purple_account_request_authorization(account, data->name, NULL, data->nick,
+ reason, purple_find_buddy(account, data->name) != NULL,
+ oscar_auth_grant, oscar_auth_dontgrant_msgprompt, data);
+} \ No newline at end of file
diff --git a/libpurple/protocols/oscar/bstream.c b/libpurple/protocols/oscar/bstream.c
index cee0c87b54..31acac2724 100644
--- a/libpurple/protocols/oscar/bstream.c
+++ b/libpurple/protocols/oscar/bstream.c
@@ -24,7 +24,7 @@
#include "oscar.h"
-int byte_stream_new(ByteStream *bs, guint32 len)
+int byte_stream_new(ByteStream *bs, size_t len)
{
if (bs == NULL)
return -1;
@@ -32,9 +32,8 @@ int byte_stream_new(ByteStream *bs, guint32 len)
return byte_stream_init(bs, g_malloc(len), len);
}
-int byte_stream_init(ByteStream *bs, guint8 *data, int len)
+int byte_stream_init(ByteStream *bs, guint8 *data, size_t len)
{
-
if (bs == NULL)
return -1;
@@ -50,7 +49,7 @@ void byte_stream_destroy(ByteStream *bs)
g_free(bs->data);
}
-int byte_stream_empty(ByteStream *bs)
+int byte_stream_bytes_left(ByteStream *bs)
{
return bs->len - bs->offset;
}
@@ -60,229 +59,172 @@ int byte_stream_curpos(ByteStream *bs)
return bs->offset;
}
-int byte_stream_setpos(ByteStream *bs, unsigned int off)
+int byte_stream_setpos(ByteStream *bs, size_t off)
{
-
- if (off > bs->len)
- return -1;
+ g_return_val_if_fail(off <= bs->len, -1);
bs->offset = off;
-
return off;
}
void byte_stream_rewind(ByteStream *bs)
{
-
byte_stream_setpos(bs, 0);
-
- return;
}
/*
* N can be negative, which can be used for going backwards
- * in a bstream. I'm not sure if libfaim actually does
- * this anywhere...
+ * in a bstream.
*/
int byte_stream_advance(ByteStream *bs, int n)
{
-
- if ((byte_stream_curpos(bs) + n < 0) || (byte_stream_empty(bs) < n))
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_curpos(bs) + n >= 0, 0);
+ g_return_val_if_fail(n <= byte_stream_bytes_left(bs), 0);
bs->offset += n;
-
return n;
}
guint8 byte_stream_get8(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 1)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
bs->offset++;
-
return aimutil_get8(bs->data + bs->offset - 1);
}
guint16 byte_stream_get16(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 2)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
bs->offset += 2;
-
return aimutil_get16(bs->data + bs->offset - 2);
}
guint32 byte_stream_get32(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 4)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
bs->offset += 4;
-
return aimutil_get32(bs->data + bs->offset - 4);
}
guint8 byte_stream_getle8(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 1)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
bs->offset++;
-
return aimutil_getle8(bs->data + bs->offset - 1);
}
guint16 byte_stream_getle16(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 2)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
bs->offset += 2;
-
return aimutil_getle16(bs->data + bs->offset - 2);
}
guint32 byte_stream_getle32(ByteStream *bs)
{
-
- if (byte_stream_empty(bs) < 4)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
bs->offset += 4;
-
return aimutil_getle32(bs->data + bs->offset - 4);
}
-static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, int len)
+static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, size_t len)
{
memcpy(buf, bs->data + bs->offset, len);
bs->offset += len;
}
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len)
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len)
{
-
- if (byte_stream_empty(bs) < len)
- return 0;
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
byte_stream_getrawbuf_nocheck(bs, buf, len);
return len;
}
-guint8 *byte_stream_getraw(ByteStream *bs, int len)
+guint8 *byte_stream_getraw(ByteStream *bs, size_t len)
{
guint8 *ob;
- if (byte_stream_empty(bs) < len)
- return NULL;
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
ob = g_malloc(len);
-
byte_stream_getrawbuf_nocheck(bs, ob, len);
-
return ob;
}
-char *byte_stream_getstr(ByteStream *bs, int len)
+char *byte_stream_getstr(ByteStream *bs, size_t len)
{
char *ob;
- if (byte_stream_empty(bs) < len)
- return NULL;
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL);
ob = g_malloc(len + 1);
-
byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len);
-
ob[len] = '\0';
-
return ob;
}
int byte_stream_put8(ByteStream *bs, guint8 v)
{
-
- if (byte_stream_empty(bs) < 1)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
bs->offset += aimutil_put8(bs->data + bs->offset, v);
-
return 1;
}
int byte_stream_put16(ByteStream *bs, guint16 v)
{
-
- if (byte_stream_empty(bs) < 2)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
bs->offset += aimutil_put16(bs->data + bs->offset, v);
-
return 2;
}
int byte_stream_put32(ByteStream *bs, guint32 v)
{
-
- if (byte_stream_empty(bs) < 4)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
bs->offset += aimutil_put32(bs->data + bs->offset, v);
-
return 1;
}
int byte_stream_putle8(ByteStream *bs, guint8 v)
{
-
- if (byte_stream_empty(bs) < 1)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0);
bs->offset += aimutil_putle8(bs->data + bs->offset, v);
-
return 1;
}
int byte_stream_putle16(ByteStream *bs, guint16 v)
{
-
- if (byte_stream_empty(bs) < 2)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0);
bs->offset += aimutil_putle16(bs->data + bs->offset, v);
-
return 2;
}
int byte_stream_putle32(ByteStream *bs, guint32 v)
{
-
- if (byte_stream_empty(bs) < 4)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0);
bs->offset += aimutil_putle32(bs->data + bs->offset, v);
-
return 1;
}
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len)
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len)
{
-
- if (byte_stream_empty(bs) < len)
- return 0; /* XXX throw an exception */
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
memcpy(bs->data + bs->offset, v, len);
bs->offset += len;
-
return len;
}
@@ -291,19 +233,14 @@ int byte_stream_putstr(ByteStream *bs, const char *str)
return byte_stream_putraw(bs, (guint8 *)str, strlen(str));
}
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len)
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len)
{
-
- if (byte_stream_empty(srcbs) < len)
- return 0; /* XXX throw exception (underrun) */
-
- if (byte_stream_empty(bs) < len)
- return 0; /* XXX throw exception (overflow) */
+ g_return_val_if_fail(byte_stream_bytes_left(srcbs) >= len, 0);
+ g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0);
memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len);
bs->offset += len;
srcbs->offset += len;
-
return len;
}
diff --git a/libpurple/protocols/oscar/clientlogin.c b/libpurple/protocols/oscar/clientlogin.c
index 1ae6bc686a..9221e5c49d 100644
--- a/libpurple/protocols/oscar/clientlogin.c
+++ b/libpurple/protocols/oscar/clientlogin.c
@@ -428,6 +428,9 @@ static gboolean parse_client_login_response(PurpleConnection *gc, const gchar *r
"was %d (%d): %s\n", status_code, status_detail_code, response);
if (status_code == 330 && status_detail_code == 3011) {
+ PurpleAccount *account = purple_connection_get_account(gc);
+ if (!purple_account_get_remember_password(account))
+ purple_account_set_password(account, NULL);
purple_connection_error_reason(gc,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
_("Incorrect password"));
@@ -515,8 +518,12 @@ static void client_login_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data
if (error_message != NULL || len == 0) {
gchar *tmp;
- tmp = g_strdup_printf(_("Error requesting %s: %s"),
- URL_CLIENT_LOGIN, error_message);
+ if (error_message != NULL)
+ tmp = g_strdup_printf(_("Error requesting %s: %s"),
+ URL_CLIENT_LOGIN, error_message);
+ else
+ tmp = g_strdup_printf(_("Error requesting %s"),
+ URL_CLIENT_LOGIN);
purple_connection_error_reason(gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
g_free(tmp);
diff --git a/libpurple/protocols/oscar/encoding.c b/libpurple/protocols/oscar/encoding.c
new file mode 100644
index 0000000000..985f2cb295
--- /dev/null
+++ b/libpurple/protocols/oscar/encoding.c
@@ -0,0 +1,235 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+*/
+
+#include "encoding.h"
+
+static gchar *
+encoding_extract(const char *encoding)
+{
+ char *begin, *end;
+
+ if (encoding == NULL) {
+ return NULL;
+ }
+
+ if (!g_str_has_prefix(encoding, "text/aolrtf; charset=") &&
+ !g_str_has_prefix(encoding, "text/x-aolrtf; charset=") &&
+ !g_str_has_prefix(encoding, "text/plain; charset=")) {
+ return g_strdup(encoding);
+ }
+
+ begin = strchr(encoding, '"');
+ end = strrchr(encoding, '"');
+
+ if ((begin == NULL) || (end == NULL) || (begin >= end)) {
+ return g_strdup(encoding);
+ }
+
+ return g_strndup(begin+1, (end-1) - begin);
+}
+
+gchar *
+oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen)
+{
+ gchar *utf8 = NULL;
+ const gchar *glib_encoding = NULL;
+ gchar *extracted_encoding = encoding_extract(encoding);
+
+ if (extracted_encoding == NULL || *extracted_encoding == '\0') {
+ purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
+ } else if (!g_ascii_strcasecmp(extracted_encoding, "iso-8859-1")) {
+ glib_encoding = "iso-8859-1";
+ } else if (!g_ascii_strcasecmp(extracted_encoding, "ISO-8859-1-Windows-3.1-Latin-1") || !g_ascii_strcasecmp(extracted_encoding, "us-ascii")) {
+ glib_encoding = "Windows-1252";
+ } else if (!g_ascii_strcasecmp(extracted_encoding, "unicode-2-0")) {
+ glib_encoding = "UTF-16BE";
+ } else if (g_ascii_strcasecmp(extracted_encoding, "utf-8")) {
+ purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", attempting to convert to UTF-8 anyway\n", extracted_encoding);
+ glib_encoding = extracted_encoding;
+ }
+
+ if (glib_encoding != NULL) {
+ utf8 = g_convert(text, textlen, "UTF-8", glib_encoding, NULL, NULL, NULL);
+ }
+
+ /*
+ * If utf8 is still NULL then either the encoding is utf-8 or
+ * we have been unable to convert the text to utf-8 from the encoding
+ * that was specified. So we check if the text is valid utf-8 then
+ * just copy it.
+ */
+ if (utf8 == NULL) {
+ if (textlen != 0 && *text != '\0' && !g_utf8_validate(text, textlen, NULL))
+ utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)"));
+ else
+ utf8 = g_strndup(text, textlen);
+ }
+
+ g_free(extracted_encoding);
+ return utf8;
+}
+
+gchar *
+oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg)
+{
+ const char *charset = NULL;
+ char *ret = NULL;
+
+ if (msg == NULL)
+ return NULL;
+
+ if (g_utf8_validate(msg, -1, NULL))
+ return g_strdup(msg);
+
+ if (od->icq)
+ charset = purple_account_get_string(account, "encoding", NULL);
+
+ if(charset && *charset)
+ ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL);
+
+ if(!ret)
+ ret = purple_utf8_try_convert(msg);
+
+ return ret;
+}
+
+static gchar *
+oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
+{
+ gchar *ret = NULL;
+ GError *err = NULL;
+
+ if ((charsetstr == NULL) || (*charsetstr == '\0'))
+ return NULL;
+
+ if (g_ascii_strcasecmp("UTF-8", charsetstr)) {
+ if (fallback)
+ ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err);
+ else
+ ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err);
+ if (err != NULL) {
+ purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
+ charsetstr, err->message);
+ g_error_free(err);
+ }
+ } else {
+ if (g_utf8_validate(data, datalen, NULL))
+ ret = g_strndup(data, datalen);
+ else
+ purple_debug_warning("oscar", "String is not valid UTF-8.\n");
+ }
+
+ return ret;
+}
+
+gchar *
+oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen)
+{
+ gchar *ret = NULL;
+ /* charsetstr1 is always set to what the correct encoding should be. */
+ const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL;
+
+ if ((datalen == 0) || (data == NULL))
+ return NULL;
+
+ if (charset == AIM_CHARSET_UNICODE) {
+ charsetstr1 = "UTF-16BE";
+ charsetstr2 = "UTF-8";
+ } else if (charset == AIM_CHARSET_LATIN_1) {
+ if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn))
+ charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+ else
+ charsetstr1 = "ISO-8859-1";
+ charsetstr2 = "UTF-8";
+ } else if (charset == AIM_CHARSET_ASCII) {
+ /* Should just be "ASCII" */
+ charsetstr1 = "ASCII";
+ charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+ } else if (charset == 0x000d) {
+ /* iChat sending unicode over a Direct IM connection = UTF-8 */
+ /* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
+ charsetstr1 = "UTF-8";
+ charsetstr2 = "ISO-8859-1";
+ charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+ } else {
+ /* Unknown, hope for valid UTF-8... */
+ charsetstr1 = "UTF-8";
+ charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
+ }
+
+ purple_debug_info("oscar", "Parsing IM, charset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n",
+ charset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : ""));
+
+ ret = oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE);
+ if (ret == NULL) {
+ if (charsetstr3 != NULL) {
+ /* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */
+ ret = oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE);
+ if (ret == NULL)
+ ret = oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE);
+ } else {
+ /* Try charsetstr2, allowing substitutions */
+ ret = oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE);
+ }
+ }
+ if (ret == NULL) {
+ char *str, *salvage, *tmp;
+
+ str = g_malloc(datalen + 1);
+ strncpy(str, data, datalen);
+ str[datalen] = '\0';
+ salvage = purple_utf8_salvage(str);
+ tmp = g_strdup_printf(_("(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)"),
+ sourcebn, sourcebn);
+ ret = g_strdup_printf("%s %s", salvage, tmp);
+ g_free(tmp);
+ g_free(str);
+ g_free(salvage);
+ }
+
+ return ret;
+}
+
+static guint16
+get_simplest_charset(const char *utf8)
+{
+ while (*utf8)
+ {
+ if ((unsigned char)(*utf8) > 0x7f) {
+ /* not ASCII! */
+ return AIM_CHARSET_UNICODE;
+ }
+ utf8++;
+ }
+ return AIM_CHARSET_ASCII;
+}
+
+gchar *
+oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr)
+{
+ guint16 msg_charset = get_simplest_charset(msg);
+ if (charset != NULL) {
+ *charset = msg_charset;
+ }
+ if (charsetstr != NULL) {
+ *charsetstr = msg_charset == AIM_CHARSET_ASCII ? "us-ascii" : "unicode-2-0";
+ }
+ return g_convert(msg, -1, msg_charset == AIM_CHARSET_ASCII ? "ASCII" : "UTF-16BE", "UTF-8", NULL, result_len, NULL);
+}
diff --git a/libpurple/protocols/oscar/encoding.h b/libpurple/protocols/oscar/encoding.h
new file mode 100644
index 0000000000..5f47ec47bf
--- /dev/null
+++ b/libpurple/protocols/oscar/encoding.h
@@ -0,0 +1,46 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+*/
+
+#ifndef _ENCODING_H_
+#define _ENCODING_H_
+
+#include "oscar.h"
+#include "oscarcommon.h"
+
+gchar * oscar_encoding_to_utf8(const char *encoding, const char *text, int textlen);
+gchar * oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg);
+
+/**
+ * This attemps to decode an incoming IM into a UTF8 string.
+ *
+ * We try decoding using two different character sets. The charset
+ * specified in the IM determines the order in which we attempt to
+ * decode. We do this because there are lots of broken ICQ clients
+ * that don't correctly send non-ASCII messages. And if Purple isn't
+ * able to deal with that crap, then people complain like banshees.
+ */
+gchar * oscar_decode_im(PurpleAccount *account, const char *sourcebn, guint16 charset, const gchar *data, gsize datalen);
+
+/**
+ * Figure out what encoding to use when sending a given outgoing message.
+ */
+gchar * oscar_encode_im(const gchar *msg, gsize *result_len, guint16 *charset, gchar **charsetstr);
+
+#endif \ No newline at end of file
diff --git a/libpurple/protocols/oscar/family_admin.c b/libpurple/protocols/oscar/family_admin.c
index c276f12cb9..d199a789c1 100644
--- a/libpurple/protocols/oscar/family_admin.c
+++ b/libpurple/protocols/oscar/family_admin.c
@@ -47,7 +47,7 @@ aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info)
byte_stream_put16(&bs, 0x0000);
snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -68,7 +68,7 @@ infochange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fr
perms = byte_stream_get16(bs);
tlvcount = byte_stream_get16(bs);
- while (tlvcount && byte_stream_empty(bs)) {
+ while (tlvcount && byte_stream_bytes_left(bs)) {
guint16 type, length;
type = byte_stream_get16(bs);
@@ -127,7 +127,7 @@ aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick)
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -154,7 +154,7 @@ aim_admin_changepasswd(OscarData *od, FlapConnection *conn, const char *newpw, c
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -177,7 +177,7 @@ aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail)
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ADMIN, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
}
diff --git a/libpurple/protocols/oscar/family_advert.c b/libpurple/protocols/oscar/family_advert.c
deleted file mode 100644
index fcd1677ce6..0000000000
--- a/libpurple/protocols/oscar/family_advert.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-*/
-
-/*
- * Family 0x0005 - Advertisements.
- *
- */
-
-#include "oscar.h"
-
-void
-aim_ads_requestads(OscarData *od, FlapConnection *conn)
-{
- aim_genericreq_n(od, conn, SNAC_FAMILY_ADVERT, 0x0002);
-}
-
-static int snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *rx, aim_modsnac_t *snac, ByteStream *bs)
-{
- return 0;
-}
-
-int adverts_modfirst(OscarData *od, aim_module_t *mod)
-{
-
- mod->family = SNAC_FAMILY_ADVERT;
- mod->version = 0x0001;
- mod->toolid = 0x0001;
- mod->toolversion = 0x0001;
- mod->flags = 0;
- strncpy(mod->name, "advert", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
diff --git a/libpurple/protocols/oscar/family_alert.c b/libpurple/protocols/oscar/family_alert.c
index df6f909d7a..58f535a7a2 100644
--- a/libpurple/protocols/oscar/family_alert.c
+++ b/libpurple/protocols/oscar/family_alert.c
@@ -73,7 +73,7 @@ aim_email_sendcookies(OscarData *od)
byte_stream_put16(&bs, 0x0631);
snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0006, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
@@ -189,7 +189,7 @@ aim_email_activate(OscarData *od)
byte_stream_put32(&bs, 0x00000000);
snacid = aim_cachesnac(od, SNAC_FAMILY_ALERT, 0x0016, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ALERT, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
diff --git a/libpurple/protocols/oscar/family_auth.c b/libpurple/protocols/oscar/family_auth.c
index db7a1a0920..ac011df63d 100644
--- a/libpurple/protocols/oscar/family_auth.c
+++ b/libpurple/protocols/oscar/family_auth.c
@@ -56,17 +56,10 @@ static int
aim_encode_password(const char *password, guint8 *encoded)
{
guint8 encoding_table[] = {
-#if 0 /* old v1 table */
- 0xf3, 0xb3, 0x6c, 0x99,
- 0x95, 0x3f, 0xac, 0xb6,
- 0xc5, 0xfa, 0x6b, 0x63,
- 0x69, 0x6c, 0xc3, 0x9f
-#else /* v2.1 table, also works for ICQ */
0xf3, 0x26, 0x81, 0xc4,
0x39, 0x86, 0xdb, 0x92,
0x71, 0xa3, 0xb9, 0xe6,
0x53, 0x7a, 0x95, 0x7c
-#endif
};
unsigned int i;
@@ -234,7 +227,7 @@ aim_send_login(OscarData *od, FlapConnection *conn, const char *sn, const char *
frame = flap_frame_new(od, 0x02, 1152);
snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0002, 0x0000, NULL, 0);
- aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, 0x0000, snacid);
+ aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0002, snacid);
aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
@@ -385,12 +378,6 @@ parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
if (aim_tlv_gettlv(tlvlist, 0x0043, 1))
info->latestbeta.name = aim_tlv_getstr(tlvlist, 0x0043, 1);
-#if 0
- if (aim_tlv_gettlv(tlvlist, 0x0048, 1)) {
- /* beta serial */
- }
-#endif
-
if (aim_tlv_gettlv(tlvlist, 0x0044, 1))
info->latestrelease.build = aim_tlv_get32(tlvlist, 0x0044, 1);
if (aim_tlv_gettlv(tlvlist, 0x0045, 1))
@@ -400,27 +387,12 @@ parse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
if (aim_tlv_gettlv(tlvlist, 0x0047, 1))
info->latestrelease.name = aim_tlv_getstr(tlvlist, 0x0047, 1);
-#if 0
- if (aim_tlv_gettlv(tlvlist, 0x0049, 1)) {
- /* lastest release serial */
- }
-#endif
-
/*
* URL to change password.
*/
if (aim_tlv_gettlv(tlvlist, 0x0054, 1))
info->chpassurl = aim_tlv_getstr(tlvlist, 0x0054, 1);
-#if 0
- /*
- * Unknown. Seen on an @mac.com username with value of 0x003f
- */
- if (aim_tlv_gettlv(tlvlist, 0x0055, 1)) {
- /* Unhandled */
- }
-#endif
-
od->authinfo = info;
if ((userfunc = aim_callhandler(od, snac ? snac->family : SNAC_FAMILY_AUTH, snac ? snac->subtype : 0x0003)))
@@ -504,7 +476,7 @@ aim_request_login(OscarData *od, FlapConnection *conn, const char *sn)
frame = flap_frame_new(od, 0x02, 10+2+2+strlen(sn)+8);
snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, 0x0006, 0x0000, NULL, 0);
- aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, 0x0000, snacid);
+ aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, 0x0006, snacid);
aim_tlvlist_add_str(&tlvlist, 0x0001, sn);
@@ -602,7 +574,7 @@ aim_auth_securid_send(OscarData *od, const char *securid)
frame = flap_frame_new(od, 0x02, 10+2+len);
snacid = aim_cachesnac(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, NULL, 0);
- aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0x0000, 0);
+ aim_putsnac(&frame->data, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_RESPONSE, 0);
byte_stream_put16(&frame->data, len);
byte_stream_putstr(&frame->data, securid);
diff --git a/libpurple/protocols/oscar/family_bart.c b/libpurple/protocols/oscar/family_bart.c
index ee388456bd..cd7ca43839 100644
--- a/libpurple/protocols/oscar/family_bart.c
+++ b/libpurple/protocols/oscar/family_bart.c
@@ -56,7 +56,7 @@ aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen)
byte_stream_putraw(&bs, icon, iconlen);
snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
@@ -121,7 +121,7 @@ aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const guint
byte_stream_putraw(&bs, iconcsum, iconcsumlen);
snacid = aim_cachesnac(od, SNAC_FAMILY_BART, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_BART, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
diff --git a/libpurple/protocols/oscar/family_bos.c b/libpurple/protocols/oscar/family_bos.c
index 2790b2ed82..16defd2076 100644
--- a/libpurple/protocols/oscar/family_bos.c
+++ b/libpurple/protocols/oscar/family_bos.c
@@ -68,98 +68,6 @@ static int rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFr
return ret;
}
-/*
- * Subtype 0x0004 - Set group permission mask.
- *
- * Normally 0x1f (all classes).
- *
- * The group permission mask allows you to keep users of a certain
- * class or classes from talking to you. The mask should be
- * a bitwise OR of all the user classes you want to see you.
- *
- */
-void
-aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask)
-{
- aim_genericreq_l(od, conn, SNAC_FAMILY_BOS, 0x0004, &mask);
-}
-
-/*
- * Stubtypes 0x0005, 0x0006, 0x0007, and 0x0008 - Modify permit/deny lists.
- *
- * Changes your visibility depending on changetype:
- *
- * AIM_VISIBILITYCHANGE_PERMITADD: Lets provided list of names see you
- * AIM_VISIBILITYCHANGE_PERMIDREMOVE: Removes listed names from permit list
- * AIM_VISIBILITYCHANGE_DENYADD: Hides you from provided list of names
- * AIM_VISIBILITYCHANGE_DENYREMOVE: Lets list see you again
- *
- * list should be a list of "Buddy Name One&BuddyNameTwo&" etc.
- *
- * Equivelents to options in WinAIM:
- * - Allow all users to contact me: Send an AIM_VISIBILITYCHANGE_DENYADD
- * with only your name on it.
- * - Allow only users on my Buddy List: Send an
- * AIM_VISIBILITYCHANGE_PERMITADD with the list the same as your
- * buddy list
- * - Allow only the uesrs below: Send an AIM_VISIBILITYCHANGE_PERMITADD
- * with everyone listed that you want to see you.
- * - Block all users: Send an AIM_VISIBILITYCHANGE_PERMITADD with only
- * yourself in the list
- * - Block the users below: Send an AIM_VISIBILITYCHANGE_DENYADD with
- * the list of users to be blocked
- *
- * XXX ye gods.
- */
-int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist)
-{
- ByteStream bs;
- int packlen = 0;
- guint16 subtype;
- char *localcpy = NULL, *tmpptr = NULL;
- int i;
- int listcount;
- aim_snacid_t snacid;
-
- if (!denylist)
- return -EINVAL;
-
- if (changetype == AIM_VISIBILITYCHANGE_PERMITADD)
- subtype = 0x05;
- else if (changetype == AIM_VISIBILITYCHANGE_PERMITREMOVE)
- subtype = 0x06;
- else if (changetype == AIM_VISIBILITYCHANGE_DENYADD)
- subtype = 0x07;
- else if (changetype == AIM_VISIBILITYCHANGE_DENYREMOVE)
- subtype = 0x08;
- else
- return -EINVAL;
-
- localcpy = g_strdup(denylist);
-
- listcount = aimutil_itemcnt(localcpy, '&');
- packlen = aimutil_tokslen(localcpy, 99, '&') + listcount-1;
-
- byte_stream_new(&bs, packlen);
-
- for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
- tmpptr = aimutil_itemindex(localcpy, i, '&');
-
- byte_stream_put8(&bs, strlen(tmpptr));
- byte_stream_putstr(&bs, tmpptr);
-
- g_free(tmpptr);
- }
- g_free(localcpy);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_BOS, subtype, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BOS, subtype, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
static int
snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
diff --git a/libpurple/protocols/oscar/family_buddy.c b/libpurple/protocols/oscar/family_buddy.c
index 7efd60e520..a58232a058 100644
--- a/libpurple/protocols/oscar/family_buddy.c
+++ b/libpurple/protocols/oscar/family_buddy.c
@@ -88,117 +88,6 @@ rights(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
}
/*
- * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add buddy to list.
- *
- * Adds a single buddy to your buddy list after login.
- * XXX This should just be an extension of setbuddylist()
- *
- */
-int
-aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn)
-{
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!sn || !strlen(sn))
- return -EINVAL;
-
- byte_stream_new(&bs, 1+strlen(sn));
-
- byte_stream_put8(&bs, strlen(sn));
- byte_stream_putstr(&bs, sn);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, sn, strlen(sn)+1);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * Subtype 0x0004 (SNAC_SUBTYPE_BUDDY_ADDBUDDY) - Add multiple buddies to your buddy list.
- *
- * This just builds the "set buddy list" command then queues it.
- *
- * buddy_list = "Buddy Name One&BuddyNameTwo&";
- *
- * XXX Clean this up.
- *
- */
-int
-aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list)
-{
- ByteStream bs;
- aim_snacid_t snacid;
- int len = 0;
- char *localcpy = NULL;
- char *tmpptr = NULL;
-
- if (!buddy_list || !(localcpy = g_strdup(buddy_list)))
- return -EINVAL;
-
- for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
- purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT
- ")\n", tmpptr, strlen(tmpptr));
- len += 1 + strlen(tmpptr);
- tmpptr = strtok(NULL, "&");
- }
-
- byte_stream_new(&bs, len);
-
- strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
-
- for (tmpptr = strtok(localcpy, "&"); tmpptr; ) {
-
- purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT
- ")\n", tmpptr, strlen(tmpptr));
-
- byte_stream_put8(&bs, strlen(tmpptr));
- byte_stream_putstr(&bs, tmpptr);
- tmpptr = strtok(NULL, "&");
- }
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0004, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- g_free(localcpy);
-
- return 0;
-}
-
-/*
- * Subtype 0x0005 (SNAC_SUBTYPE_BUDDY_REMBUDDY) - Remove buddy from list.
- *
- * XXX generalise to support removing multiple buddies (basically, its
- * the same as setbuddylist() but with a different snac subtype).
- *
- */
-int
-aim_buddylist_removebuddy(OscarData *od, FlapConnection *conn, const char *sn)
-{
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!sn || !strlen(sn))
- return -EINVAL;
-
- byte_stream_new(&bs, 1 + strlen(sn));
-
- byte_stream_put8(&bs, strlen(sn));
- byte_stream_putstr(&bs, sn);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, sn, strlen(sn)+1);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_BUDDY, 0x0005, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
* Subtypes 0x000b (SNAC_SUBTYPE_BUDDY_ONCOMING) and 0x000c (SNAC_SUBTYPE_BUDDY_OFFGOING) - Change in buddy status
*
* Oncoming Buddy notifications contain a subset of the
diff --git a/libpurple/protocols/oscar/family_chat.c b/libpurple/protocols/oscar/family_chat.c
index 9e25b22cc3..89fa331c0c 100644
--- a/libpurple/protocols/oscar/family_chat.c
+++ b/libpurple/protocols/oscar/family_chat.c
@@ -47,74 +47,6 @@ flap_connection_destroy_chat(OscarData *od, FlapConnection *conn)
return;
}
-char *
-aim_chat_getname(FlapConnection *conn)
-{
- struct chatconnpriv *ccp;
-
- if (!conn)
- return NULL;
-
- if (conn->type != SNAC_FAMILY_CHAT)
- return NULL;
-
- ccp = (struct chatconnpriv *)conn->internal;
-
- return ccp->name;
-}
-
-/* XXX get this into conn.c -- evil!! */
-FlapConnection *
-aim_chat_getconn(OscarData *od, const char *name)
-{
- GSList *cur;
-
- for (cur = od->oscar_connections; cur; cur = cur->next)
- {
- FlapConnection *conn;
- struct chatconnpriv *ccp;
-
- conn = cur->data;
- ccp = (struct chatconnpriv *)conn->internal;
-
- if (conn->type != SNAC_FAMILY_CHAT)
- continue;
- if (!conn->internal)
- {
- purple_debug_misc("oscar", "%sfaim: chat: chat connection with no name! (fd = %d)\n",
- conn->gsc ? "(ssl) " : "", conn->gsc ? conn->gsc->fd : conn->fd);
- continue;
- }
-
- if (strcmp(ccp->name, name) == 0)
- return conn;
- }
-
- return NULL;
-}
-
-int
-aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance)
-{
- struct chatconnpriv *ccp;
-
- if (!conn || !roomname)
- return -EINVAL;
-
- if (conn->internal)
- g_free(conn->internal);
-
- ccp = g_new(struct chatconnpriv, 1);
-
- ccp->exchange = exchange;
- ccp->name = g_strdup(roomname);
- ccp->instance = instance;
-
- conn->internal = (void *)ccp;
-
- return 0;
-}
-
int
aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
{
@@ -129,19 +61,6 @@ aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo)
return 0;
}
-int
-aim_chat_leaveroom(OscarData *od, const char *name)
-{
- FlapConnection *conn;
-
- if (!(conn = aim_chat_getconn(od, name)))
- return -ENOENT;
-
- flap_connection_close(od, conn);
-
- return 0;
-}
-
/*
* Subtype 0x0002 - General room information. Lots of stuff.
*
@@ -153,21 +72,12 @@ aim_chat_leaveroom(OscarData *od, const char *name)
static int
infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- aim_userinfo_t *userinfo = NULL;
aim_rxcallback_t userfunc;
int ret = 0;
- int usercount;
guint8 detaillevel = 0;
- char *roomname;
struct aim_chat_roominfo roominfo;
- guint16 tlvcount = 0;
GSList *tlvlist;
- aim_tlv_t *tlv;
- char *roomdesc;
- guint16 flags;
- guint32 creationtime;
guint16 maxmsglen, maxvisiblemsglen;
- guint16 unknown_d2, unknown_d5;
aim_chat_readroominfo(bs, &roominfo);
@@ -178,139 +88,27 @@ infoupdate(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fr
return 1;
}
- tlvcount = byte_stream_get16(bs);
-
/*
* Everything else are TLVs.
*/
tlvlist = aim_tlvlist_read(bs);
/*
- * TLV type 0x006a is the room name in Human Readable Form.
- */
- roomname = aim_tlv_getstr(tlvlist, 0x006a, 1);
-
- /*
- * Type 0x006f: Number of occupants.
- */
- usercount = aim_tlv_get16(tlvlist, 0x006f, 1);
-
- /*
- * Type 0x0073: Occupant list.
- */
- tlv = aim_tlv_gettlv(tlvlist, 0x0073, 1);
- if (tlv != NULL)
- {
- int curoccupant = 0;
- ByteStream occbs;
-
- /* Allocate enough userinfo structs for all occupants */
- userinfo = g_new0(aim_userinfo_t, usercount);
-
- byte_stream_init(&occbs, tlv->value, tlv->length);
-
- while (curoccupant < usercount)
- aim_info_extract(od, &occbs, &userinfo[curoccupant++]);
- }
-
- /*
- * Type 0x00c9: Flags. (AIM_CHATROOM_FLAG)
- */
- flags = aim_tlv_get16(tlvlist, 0x00c9, 1);
-
- /*
- * Type 0x00ca: Creation time (4 bytes)
- */
- creationtime = aim_tlv_get32(tlvlist, 0x00ca, 1);
-
- /*
* Type 0x00d1: Maximum Message Length
*/
maxmsglen = aim_tlv_get16(tlvlist, 0x00d1, 1);
/*
- * Type 0x00d2: Unknown. (2 bytes)
- */
- unknown_d2 = aim_tlv_get16(tlvlist, 0x00d2, 1);
-
- /*
- * Type 0x00d3: Room Description
- */
- roomdesc = aim_tlv_getstr(tlvlist, 0x00d3, 1);
-
-#if 0
- /*
- * Type 0x000d4: Unknown (flag only)
- */
- if (aim_tlv_gettlv(tlvlist, 0x000d4, 1)) {
- /* Unhandled */
- }
-#endif
-
- /*
- * Type 0x00d5: Unknown. (1 byte)
- */
- unknown_d5 = aim_tlv_get8(tlvlist, 0x00d5, 1);
-
-#if 0
- /*
- * Type 0x00d6: Encoding 1 ("us-ascii")
- */
- if (aim_tlv_gettlv(tlvlist, 0x000d6, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d7: Language 1 ("en")
- */
- if (aim_tlv_gettlv(tlvlist, 0x000d7, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d8: Encoding 2 ("us-ascii")
- */
- if (aim_tlv_gettlv(tlvlist, 0x000d8, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d9: Language 2 ("en")
- */
- if (aim_tlv_gettlv(tlvlist, 0x000d9, 1)) {
- /* Unhandled */
- }
-#endif
-
- /*
* Type 0x00da: Maximum visible message length
*/
maxvisiblemsglen = aim_tlv_get16(tlvlist, 0x00da, 1);
if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
- ret = userfunc(od, conn,
- frame,
- &roominfo,
- roomname,
- usercount,
- userinfo,
- roomdesc,
- flags,
- creationtime,
- maxmsglen,
- unknown_d2,
- unknown_d5,
- maxvisiblemsglen);
+ ret = userfunc(od, conn, frame, maxmsglen, maxvisiblemsglen);
}
g_free(roominfo.name);
- while (usercount > 0)
- aim_info_free(&userinfo[--usercount]);
-
- g_free(userinfo);
- g_free(roomname);
- g_free(roomdesc);
aim_tlvlist_free(tlvlist);
return ret;
@@ -324,7 +122,7 @@ userlistchange(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame
aim_rxcallback_t userfunc;
int curcount = 0, ret = 0;
- while (byte_stream_empty(bs)) {
+ while (byte_stream_bytes_left(bs)) {
curcount++;
userinfo = g_realloc(userinfo, curcount * sizeof(aim_userinfo_t));
aim_info_extract(od, bs, &userinfo[curcount-1]);
@@ -434,7 +232,7 @@ aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_CHAT, 0x0005, snacid, &bs);
byte_stream_destroy(&bs);
@@ -523,16 +321,6 @@ incomingim_ch3(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame
aim_info_extract(od, &tbs, &userinfo);
}
-#if 0
- /*
- * Type 0x0001: If present, it means it was a message to the
- * room (as opposed to a whisper).
- */
- if (aim_tlv_gettlv(tlvlist, 0x0001, 1)) {
- /* Unhandled */
- }
-#endif
-
/*
* Type 0x0005: Message Block. Conains more TLVs.
*/
diff --git a/libpurple/protocols/oscar/family_chatnav.c b/libpurple/protocols/oscar/family_chatnav.c
index 1509b3c14e..6df24b2dde 100644
--- a/libpurple/protocols/oscar/family_chatnav.c
+++ b/libpurple/protocols/oscar/family_chatnav.c
@@ -37,7 +37,8 @@ error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
guint16 error, chatnav_error;
GSList *tlvlist;
- if (!(snac2 = aim_remsnac(od, snac->id))) {
+ snac2 = aim_remsnac(od, snac->id);
+ if (!snac2) {
purple_debug_warning("oscar", "chatnav error: received response to unknown request (%08x)\n", snac->id);
return 0;
}
@@ -67,8 +68,7 @@ error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
ret = 1;
}
- if (snac2)
- g_free(snac2->data);
+ g_free(snac2->data);
g_free(snac2);
return ret;
@@ -139,7 +139,7 @@ int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name
aim_tlvlist_free(tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_CHATNAV, 0x0008, snacid, &bs);
byte_stream_destroy(&bs);
@@ -185,32 +185,6 @@ parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFram
exchanges[curexchange-1].number = byte_stream_get16(&tbs);
innerlist = aim_tlvlist_read(&tbs);
-#if 0
- /*
- * Type 0x000a: Unknown.
- *
- * Usually three bytes: 0x0114 (exchange 1) or 0x010f (others).
- *
- */
- if (aim_tlv_gettlv(innerlist, 0x000a, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x000d: Unknown.
- */
- if (aim_tlv_gettlv(innerlist, 0x000d, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x0004: Unknown
- */
- if (aim_tlv_gettlv(innerlist, 0x0004, 1)) {
- /* Unhandled */
- }
-#endif
-
/*
* Type 0x0002: Unknown
*/
@@ -234,36 +208,6 @@ parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFram
if (aim_tlv_gettlv(innerlist, 0x00c9, 1))
exchanges[curexchange-1].flags = aim_tlv_get16(innerlist, 0x00c9, 1);
-#if 0
- /*
- * Type 0x00ca: Creation Date
- */
- if (aim_tlv_gettlv(innerlist, 0x00ca, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d0: Mandatory Channels?
- */
- if (aim_tlv_gettlv(innerlist, 0x00d0, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d1: Maximum Message length
- */
- if (aim_tlv_gettlv(innerlist, 0x00d1, 1)) {
- /* Unhandled */
- }
-
- /*
- * Type 0x00d2: Maximum Occupancy?
- */
- if (aim_tlv_gettlv(innerlist, 0x00d2, 1)) {
- /* Unhandled */
- }
-#endif
-
/*
* Type 0x00d3: Exchange Description
*/
@@ -272,15 +216,6 @@ parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFram
else
exchanges[curexchange-1].name = NULL;
-#if 0
- /*
- * Type 0x00d4: Exchange Description URL
- */
- if (aim_tlv_gettlv(innerlist, 0x00d4, 1)) {
- /* Unhandled */
- }
-#endif
-
/*
* Type 0x00d5: Creation Permissions
*
@@ -327,15 +262,6 @@ parseinfo_perms(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFram
else
exchanges[curexchange-1].lang2 = NULL;
-#if 0
- /*
- * Type 0x00da: Unknown
- */
- if (aim_tlv_gettlv(innerlist, 0x00da, 1)) {
- /* Unhandled */
- }
-#endif
-
aim_tlvlist_free(innerlist);
}
diff --git a/libpurple/protocols/oscar/family_feedbag.c b/libpurple/protocols/oscar/family_feedbag.c
index 37e9518cd3..c685f51ec8 100644
--- a/libpurple/protocols/oscar/family_feedbag.c
+++ b/libpurple/protocols/oscar/family_feedbag.c
@@ -660,10 +660,8 @@ int aim_ssi_cleanlist(OscarData *od)
if (!cur->name) {
if (cur->type == AIM_SSI_TYPE_BUDDY)
aim_ssi_delbuddy(od, NULL, NULL);
- else if (cur->type == AIM_SSI_TYPE_PERMIT)
- aim_ssi_delpermit(od, NULL);
- else if (cur->type == AIM_SSI_TYPE_DENY)
- aim_ssi_deldeny(od, NULL);
+ else if (cur->type == AIM_SSI_TYPE_PERMIT || cur->type == AIM_SSI_TYPE_DENY || cur->type == AIM_SSI_TYPE_ICQDENY)
+ aim_ssi_del_from_private_list(od, NULL, cur->type);
} else if ((cur->type == AIM_SSI_TYPE_BUDDY) && ((cur->gid == 0x0000) || (!aim_ssi_itemlist_find(od->ssi.local, cur->gid, 0x0000)))) {
char *alias = aim_ssi_getalias(od->ssi.local, NULL, cur->name);
aim_ssi_addbuddy(od, cur->name, "orphans", NULL, alias, NULL, NULL, FALSE);
@@ -748,51 +746,31 @@ int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList
return aim_ssi_sync(od);
}
-/**
- * Add a permit buddy to the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item..
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_addpermit(OscarData *od, const char *name)
+int
+aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type)
{
-
if (!od || !name || !od->ssi.received_data)
return -EINVAL;
- /* Make sure the master group exists */
if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL)
- aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
- /* Add that bad boy */
- aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, NULL);
+ aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, list_type, NULL);
- /* Sync our local list with the server list */
+ aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, list_type, NULL);
return aim_ssi_sync(od);
}
-/**
- * Add a deny buddy to the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item..
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_adddeny(OscarData *od, const char *name)
+int
+aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type)
{
+ struct aim_ssi_item *del;
- if (!od || !name || !od->ssi.received_data)
+ if (!od)
return -EINVAL;
- /* Make sure the master group exists */
- if (aim_ssi_itemlist_find(od->ssi.local, 0x0000, 0x0000) == NULL)
- aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, AIM_SSI_TYPE_GROUP, NULL);
-
- /* Add that bad boy */
- aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
+ if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type)))
+ return -EINVAL;
- /* Sync our local list with the server list */
+ aim_ssi_itemlist_del(&od->ssi.local, del);
return aim_ssi_sync(od);
}
@@ -860,56 +838,6 @@ int aim_ssi_delgroup(OscarData *od, const char *group)
}
/**
- * Deletes a permit buddy from the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_delpermit(OscarData *od, const char *name)
-{
- struct aim_ssi_item *del;
-
- if (!od)
- return -EINVAL;
-
- /* Find the item */
- if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_PERMIT)))
- return -EINVAL;
-
- /* Remove the item from the list */
- aim_ssi_itemlist_del(&od->ssi.local, del);
-
- /* Sync our local list with the server list */
- return aim_ssi_sync(od);
-}
-
-/**
- * Deletes a deny buddy from the list.
- *
- * @param od The oscar odion.
- * @param name The name of the item, or NULL.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_ssi_deldeny(OscarData *od, const char *name)
-{
- struct aim_ssi_item *del;
-
- if (!od)
- return -EINVAL;
-
- /* Find the item */
- if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, AIM_SSI_TYPE_DENY)))
- return -EINVAL;
-
- /* Remove the item from the list */
- aim_ssi_itemlist_del(&od->ssi.local, del);
-
- /* Sync our local list with the server list */
- return aim_ssi_sync(od);
-}
-
-/**
* Move a buddy from one group to another group. This basically just deletes the
* buddy and re-adds it.
*
@@ -1030,17 +958,16 @@ int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn)
* Stores your permit/deny setting on the server, and starts using it.
*
* @param od The oscar odion.
- * @param permdeny Your permit/deny setting. Can be one of the following:
+ * @param permdeny Your permit/deny setting. For ICQ accounts, it actually affects your visibility
+ * and has nothing to do with blocking. Can be one of the following:
* 1 - Allow all users
* 2 - Block all users
* 3 - Allow only the users below
* 4 - Block only the users below
* 5 - Allow only users on my buddy list
- * @param vismask A bitmask of the class of users to whom you want to be
- * visible. See the AIM_FLAG_BLEH #defines in oscar.h
* @return Return 0 if no errors, otherwise return the error number.
*/
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask)
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny)
{
struct aim_ssi_item *tmp;
@@ -1059,9 +986,6 @@ int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask)
/* Need to add the 0x00ca TLV to the TLV chain */
aim_tlvlist_replace_8(&tmp->data, 0x00ca, permdeny);
- /* Need to add the 0x00cb TLV to the TLV chain */
- aim_tlvlist_replace_32(&tmp->data, 0x00cb, vismask);
-
/* Sync our local list with the server list */
return aim_ssi_sync(od);
}
@@ -1231,41 +1155,6 @@ int aim_ssi_reqdata(OscarData *od)
}
/*
- * Subtype 0x0005 - Request SSI Data when you have a timestamp and revision
- * number.
- *
- * The data will only be sent if it is newer than the posted local
- * timestamp and revision.
- *
- * Note that the client should never increment the revision, only the server.
- *
- */
-int aim_ssi_reqifchanged(OscarData *od, time_t timestamp, guint16 numitems)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
- return -EINVAL;
-
- byte_stream_new(&bs, 4+2);
-
- byte_stream_put32(&bs, timestamp);
- byte_stream_put16(&bs, numitems);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- /* Free any current data, just in case */
- aim_ssi_freelist(od);
-
- return 0;
-}
-
-/*
* Subtype 0x0006 - SSI Data.
*/
static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -1281,7 +1170,7 @@ static int parsedata(OscarData *od, FlapConnection *conn, aim_module_t *mod, Fla
od->ssi.numitems += byte_stream_get16(bs); /* # of items in this SSI SNAC */
/* Read in the list */
- while (byte_stream_empty(bs) > 4) { /* last four bytes are timestamp */
+ while (byte_stream_bytes_left(bs) > 4) { /* last four bytes are timestamp */
if ((namelen = byte_stream_get16(bs)))
name = byte_stream_getstr(bs, namelen);
else
@@ -1378,7 +1267,7 @@ static int aim_ssi_addmoddel(OscarData *od)
}
snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1399,7 +1288,7 @@ static int parseadd(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
guint16 len, gid, bid, type;
GSList *data;
- while (byte_stream_empty(bs)) {
+ while (byte_stream_bytes_left(bs)) {
if ((len = byte_stream_get16(bs)))
name = byte_stream_getstr(bs, len);
else
@@ -1437,7 +1326,7 @@ static int parsemod(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
GSList *data;
struct aim_ssi_item *item;
- while (byte_stream_empty(bs)) {
+ while (byte_stream_bytes_left(bs)) {
if ((len = byte_stream_get16(bs)))
name = byte_stream_getstr(bs, len);
else
@@ -1489,7 +1378,7 @@ static int parsedel(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
guint16 gid, bid;
struct aim_ssi_item *del;
- while (byte_stream_empty(bs)) {
+ while (byte_stream_bytes_left(bs)) {
byte_stream_advance(bs, byte_stream_get16(bs));
gid = byte_stream_get16(bs);
bid = byte_stream_get16(bs);
@@ -1522,7 +1411,7 @@ static int parseack(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
/* Read in the success/failure flags from the ack SNAC */
cur = od->ssi.pending;
- while (cur && (byte_stream_empty(bs)>0)) {
+ while (cur && (byte_stream_bytes_left(bs)>0)) {
cur->ack = byte_stream_get16(bs);
cur = cur->next;
}
@@ -1678,45 +1567,6 @@ int aim_ssi_modend(OscarData *od)
}
/*
- * Subtype 0x0014 - Grant authorization
- *
- * Authorizes a contact so they can add you to their contact list.
- *
- */
-int aim_ssi_sendauth(OscarData *od, char *bn, char *msg)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !bn)
- return -EINVAL;
-
- byte_stream_new(&bs, 1+strlen(bn) + 2+(msg ? strlen(msg)+1 : 0) + 2);
-
- /* Username */
- byte_stream_put8(&bs, strlen(bn));
- byte_stream_putstr(&bs, bn);
-
- /* Message (null terminated) */
- byte_stream_put16(&bs, msg ? strlen(msg) : 0);
- if (msg) {
- byte_stream_putstr(&bs, msg);
- byte_stream_put8(&bs, 0x00);
- }
-
- /* Unknown */
- byte_stream_put16(&bs, 0x0000);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
* Subtype 0x0015 - Receive an authorization grant
*/
static int receiveauthgrant(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -1783,7 +1633,7 @@ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg)
byte_stream_put16(&bs, 0x0000);
snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1863,7 +1713,7 @@ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg
byte_stream_put16(&bs, 0x0000);
snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1935,6 +1785,16 @@ static int receiveadded(OscarData *od, FlapConnection *conn, aim_module_t *mod,
return ret;
}
+/*
+ * If we're on ICQ, then AIM_SSI_TYPE_DENY is used for the "permanently invisible" list.
+ * AIM_SSI_TYPE_ICQDENY is used for blocking users instead.
+ */
+guint16
+aim_ssi_getdenyentrytype(OscarData* od)
+{
+ return od->icq ? AIM_SSI_TYPE_ICQDENY : AIM_SSI_TYPE_DENY;
+}
+
static int
snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
diff --git a/libpurple/protocols/oscar/family_icbm.c b/libpurple/protocols/oscar/family_icbm.c
index a01a6e56f1..73a3aa7862 100644
--- a/libpurple/protocols/oscar/family_icbm.c
+++ b/libpurple/protocols/oscar/family_icbm.c
@@ -44,6 +44,7 @@
* Make sure flap_connection_findbygroup is used by all functions.
*/
+#include "encoding.h"
#include "oscar.h"
#include "peer.h"
@@ -53,6 +54,25 @@
#include "util.h"
+static const char * const errcodereason[] = {
+ N_("Invalid error"),
+ N_("Not logged in"),
+ N_("Cannot receive IM due to parental controls"),
+ N_("Cannot send SMS without accepting terms"),
+ N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */
+ N_("Cannot send SMS to this country"),
+ N_("Unknown error"), /* Undocumented */
+ N_("Unknown error"), /* Undocumented */
+ N_("Cannot send SMS to unknown country"),
+ N_("Bot accounts cannot initiate IMs"),
+ N_("Bot account cannot IM this user"),
+ N_("Bot account reached IM limit"),
+ N_("Bot account reached daily IM limit"),
+ N_("Bot account reached monthly IM limit"),
+ N_("Unable to receive offline messages"),
+ N_("Offline message store full")
+};
+static const int errcodereasonlen = G_N_ELEMENTS(errcodereason);
/**
* Add a standard ICBM header to the given bstream with the given
@@ -89,97 +109,42 @@ void aim_icbm_makecookie(guchar *cookie)
}
/*
- * Takes a msghdr (and a length) and returns a client type
- * code. Note that this is *only a guess* and has a low likelihood
- * of actually being accurate.
- *
- * Its based on experimental data, with the help of Eric Warmenhoven
- * who seems to have collected a wide variety of different AIM clients.
- *
- *
- * Heres the current collection:
- * 0501 0003 0101 0101 01 AOL Mobile Communicator, WinAIM 1.0.414
- * 0501 0003 0101 0201 01 WinAIM 2.0.847, 2.1.1187, 3.0.1464,
- * 4.3.2229, 4.4.2286
- * 0501 0004 0101 0102 0101 WinAIM 4.1.2010, libfaim (right here)
- * 0501 0003 0101 02 WinAIM 5
- * 0501 0001 01 iChat x.x, mobile buddies
- * 0501 0001 0101 01 AOL v6.0, CompuServe 2000 v6.0, any TOC client
- * 0501 0002 0106 WinICQ 5.45.1.3777.85
- *
- * Note that in this function, only the feature bytes are tested, since
- * the rest will always be the same.
- *
- */
-guint16 aim_im_fingerprint(const guint8 *msghdr, int len)
-{
- static const struct {
- guint16 clientid;
- int len;
- guint8 data[10];
- } fingerprints[] = {
- /* AOL Mobile Communicator, WinAIM 1.0.414 */
- { AIM_CLIENTTYPE_MC,
- 3, {0x01, 0x01, 0x01}},
-
- /* WinAIM 2.0.847, 2.1.1187, 3.0.1464, 4.3.2229, 4.4.2286 */
- { AIM_CLIENTTYPE_WINAIM,
- 3, {0x01, 0x01, 0x02}},
-
- /* WinAIM 4.1.2010, libfaim */
- { AIM_CLIENTTYPE_WINAIM41,
- 4, {0x01, 0x01, 0x01, 0x02}},
-
- /* AOL v6.0, CompuServe 2000 v6.0, any TOC client */
- { AIM_CLIENTTYPE_AOL_TOC,
- 1, {0x01}},
-
- { 0, 0, {0x00}}
- };
- int i;
-
- if (!msghdr || (len <= 0))
- return AIM_CLIENTTYPE_UNKNOWN;
-
- for (i = 0; fingerprints[i].len; i++) {
- if (fingerprints[i].len != len)
- continue;
- if (memcmp(fingerprints[i].data, msghdr, fingerprints[i].len) == 0)
- return fingerprints[i].clientid;
- }
-
- return AIM_CLIENTTYPE_UNKNOWN;
-}
-
-/*
* Subtype 0x0001 - Error
*/
static int
error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- int ret = 0;
- aim_rxcallback_t userfunc;
aim_snac_t *snac2;
guint16 reason, errcode = 0;
- char *bn;
+ const char *bn;
GSList *tlvlist;
+ PurpleConnection *gc = od->gc;
+#ifdef TODOFT
+ PurpleXfer *xfer;
+#endif
+ const char *reason_str;
+ char *buf;
- if (!(snac2 = aim_remsnac(od, snac->id))) {
+ snac2 = aim_remsnac(od, snac->id);
+ if (!snac2) {
purple_debug_misc("oscar", "icbm error: received response from unknown request!\n");
- return 0;
+ return 1;
}
if (snac2->family != SNAC_FAMILY_ICBM) {
purple_debug_misc("oscar", "icbm error: received response from invalid request! %d\n", snac2->family);
g_free(snac2->data);
g_free(snac2);
- return 0;
+ return 1;
}
- if (!(bn = snac2->data)) {
+ /* Data is assumed to be the destination bn */
+ bn = snac2->data;
+ if (!bn || bn[0] == '\0') {
purple_debug_misc("oscar", "icbm error: received response from request without a buddy name!\n");
+ g_free(snac2->data);
g_free(snac2);
- return 0;
+ return 1;
}
reason = byte_stream_get16(bs);
@@ -189,15 +154,43 @@ error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
errcode = aim_tlv_get16(tlvlist, 0x0008, 1);
aim_tlvlist_free(tlvlist);
+ purple_debug_error("oscar",
+ "Message error with bn %s and reason %hu and errcode %hu\n",
+ (bn != NULL ? bn : ""), reason, errcode);
+
+#ifdef TODOFT
+ /* If this was a file transfer request, bn is a cookie */
+ if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, bn))) {
+ purple_xfer_cancel_remote(xfer);
+ return 1;
+ }
+#endif
+
/* Notify the user that the message wasn't delivered */
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, reason, errcode, bn);
+ reason_str = oscar_get_msgerr_reason(reason);
+ if (errcode != 0 && errcode < errcodereasonlen)
+ buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str,
+ _(errcodereason[errcode]));
+ else
+ buf = g_strdup_printf(_("Unable to send message: %s"), reason_str);
- if (snac2)
- g_free(snac2->data);
+ if (!purple_conv_present_error(bn, purple_connection_get_account(gc), buf)) {
+ g_free(buf);
+ if (errcode != 0 && errcode < errcodereasonlen)
+ buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"),
+ bn ? bn : "(unknown)", reason_str,
+ _(errcodereason[errcode]));
+ else
+ buf = g_strdup_printf(_("Unable to send message to %s: %s"),
+ bn ? bn : "(unknown)", reason_str);
+ purple_notify_error(od->gc, NULL, buf, reason_str);
+ }
+ g_free(buf);
+
+ g_free(snac2->data);
g_free(snac2);
- return ret;
+ return 1;
}
/**
@@ -232,7 +225,7 @@ int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params)
byte_stream_put32(&bs, params->minmsginterval);
snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
@@ -274,7 +267,8 @@ static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *m
| AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED
| AIM_IMPARAM_FLAG_EVENTS_ALLOWED
| AIM_IMPARAM_FLAG_SMS_SUPPORTED
- | AIM_IMPARAM_FLAG_OFFLINE_MSGS_ALLOWED;
+ | AIM_IMPARAM_FLAG_OFFLINE_MSGS_ALLOWED
+ | AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ;
params.maxmsglen = 8000;
params.minmsginterval = 0;
@@ -289,40 +283,14 @@ static int aim_im_paraminfo(OscarData *od, FlapConnection *conn, aim_module_t *m
*
* Possible flags:
* AIM_IMFLAGS_AWAY -- Marks the message as an autoresponse
- * AIM_IMFLAGS_ACK -- Requests that the server send an ack
- * when the message is received (of type SNAC_FAMILY_ICBM/0x000c)
* AIM_IMFLAGS_OFFLINE--If destination is offline, store it until they are
* online (probably ICQ only).
*
- * Generally, you should use the lowest encoding possible to send
- * your message. If you only use basic punctuation and the generic
- * Latin alphabet, use ASCII7 (no flags). If you happen to use non-ASCII7
- * characters, but they are all clearly defined in ISO-8859-1, then
- * use that. Keep in mind that not all characters in the PC ASCII8
- * character set are defined in the ISO standard. For those cases (most
- * notably when the (r) symbol is used), you must use the full UNICODE
- * encoding for your message. In UNICODE mode, _all_ characters must
- * occupy 16bits, including ones that are not special. (Remember that
- * the first 128 UNICODE symbols are equivalent to ASCII7, however they
- * must be prefixed with a zero high order byte.)
- *
- * I strongly discourage the use of UNICODE mode, mainly because none
- * of the clients I use can parse those messages (and besides that,
- * wchars are difficult and non-portable to handle in most UNIX environments).
- * If you really need to include special characters, use the HTML UNICODE
- * entities. These are of the form &#2026; where 2026 is the hex
- * representation of the UNICODE index (in this case, UNICODE
- * "Horizontal Ellipsis", or 133 in in ASCII8).
- *
* Implementation note: Since this is one of the most-used functions
* in all of libfaim, it is written with performance in mind. As such,
* it is not as clear as it could be in respect to how this message is
* supposed to be layed out. Most obviously, tlvlists should be used
* instead of writing out the bytes manually.
- *
- * XXX - more precise verification that we never send SNACs larger than 8192
- * XXX - check SNAC size for multipart
- *
*/
int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
{
@@ -331,7 +299,6 @@ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
ByteStream data;
guchar cookie[8];
int msgtlvlen;
- static const guint8 deffeatures[] = { 0x01, 0x01, 0x01, 0x02 };
if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
return -EINVAL;
@@ -339,37 +306,17 @@ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
if (!args)
return -EINVAL;
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- if (args->mpmsg->numparts == 0)
- return -EINVAL;
- } else {
- if (!args->msg || (args->msglen <= 0))
- return -EINVAL;
+ if (!args->msg || (args->msglen <= 0))
+ return -EINVAL;
- if (args->msglen > MAXMSGLEN)
- return -E2BIG;
- }
+ if (args->msglen > MAXMSGLEN)
+ return -E2BIG;
/* Painfully calculate the size of the message TLV */
msgtlvlen = 1 + 1; /* 0501 */
-
- if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES)
- msgtlvlen += 2 + args->featureslen;
- else
- msgtlvlen += 2 + sizeof(deffeatures);
-
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- aim_mpmsg_section_t *sec;
-
- for (sec = args->mpmsg->parts; sec; sec = sec->next) {
- msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
- msgtlvlen += 4 /* charset */ + sec->datalen;
- }
-
- } else {
- msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
- msgtlvlen += 4 /* charset */ + args->msglen;
- }
+ msgtlvlen += 2 + args->featureslen;
+ msgtlvlen += 2 /* 0101 */ + 2 /* block len */;
+ msgtlvlen += 4 /* charset */ + args->msglen;
byte_stream_new(&data, msgtlvlen + 128);
@@ -385,52 +332,31 @@ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
/* Features TLV (type 0x0501) */
byte_stream_put16(&data, 0x0501);
- if (args->flags & AIM_IMFLAGS_CUSTOMFEATURES) {
- byte_stream_put16(&data, args->featureslen);
- byte_stream_putraw(&data, args->features, args->featureslen);
- } else {
- byte_stream_put16(&data, sizeof(deffeatures));
- byte_stream_putraw(&data, deffeatures, sizeof(deffeatures));
- }
-
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- aim_mpmsg_section_t *sec;
-
- /* Insert each message part in a TLV (type 0x0101) */
- for (sec = args->mpmsg->parts; sec; sec = sec->next) {
- byte_stream_put16(&data, 0x0101);
- byte_stream_put16(&data, sec->datalen + 4);
- byte_stream_put16(&data, sec->charset);
- byte_stream_put16(&data, sec->charsubset);
- byte_stream_putraw(&data, (guchar *)sec->data, sec->datalen);
- }
-
- } else {
+ byte_stream_put16(&data, args->featureslen);
+ byte_stream_putraw(&data, args->features, args->featureslen);
- /* Insert message text in a TLV (type 0x0101) */
- byte_stream_put16(&data, 0x0101);
+ /* Insert message text in a TLV (type 0x0101) */
+ byte_stream_put16(&data, 0x0101);
- /* Message block length */
- byte_stream_put16(&data, args->msglen + 0x04);
+ /* Message block length */
+ byte_stream_put16(&data, args->msglen + 0x04);
- /* Character set */
- byte_stream_put16(&data, args->charset);
- byte_stream_put16(&data, args->charsubset);
+ /* Character set */
+ byte_stream_put16(&data, args->charset);
+ /* Character subset -- we always use 0 here */
+ byte_stream_put16(&data, 0x0);
- /* Message. Not terminated */
- byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);
- }
+ /* Message. Not terminated */
+ byte_stream_putraw(&data, (guchar *)args->msg, args->msglen);
/* Set the Autoresponse flag */
if (args->flags & AIM_IMFLAGS_AWAY) {
byte_stream_put16(&data, 0x0004);
byte_stream_put16(&data, 0x0000);
} else {
- if (args->flags & AIM_IMFLAGS_ACK) {
- /* Set the Request Acknowledge flag */
- byte_stream_put16(&data, 0x0003);
- byte_stream_put16(&data, 0x0000);
- }
+ /* Set the Request Acknowledge flag */
+ byte_stream_put16(&data, 0x0003);
+ byte_stream_put16(&data, 0x0000);
if (args->flags & AIM_IMFLAGS_OFFLINE) {
/* Allow this message to be queued as an offline message */
@@ -465,7 +391,7 @@ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
/* XXX - should be optional */
snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, args->destbn, strlen(args->destbn)+1);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &data);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &data);
byte_stream_destroy(&data);
/* clean out SNACs over 60sec old */
@@ -475,33 +401,6 @@ int aim_im_sendch1_ext(OscarData *od, struct aim_sendimext_args *args)
}
/*
- * Simple wrapper for aim_im_sendch1_ext()
- *
- * You cannot use aim_send_im if you need the HASICON flag. You must
- * use aim_im_sendch1_ext directly for that.
- *
- * aim_send_im also cannot be used if you require UNICODE messages, because
- * that requires an explicit message length. Use aim_im_sendch1_ext().
- *
- */
-int aim_im_sendch1(OscarData *od, const char *bn, guint16 flags, const char *msg)
-{
- struct aim_sendimext_args args;
-
- args.destbn = bn;
- args.flags = flags;
- args.msg = msg;
- args.msglen = strlen(msg);
- args.charset = 0x0000;
- args.charsubset = 0x0000;
-
- /* Make these don't get set by accident -- they need aim_im_sendch1_ext */
- args.flags &= ~(AIM_IMFLAGS_CUSTOMFEATURES | AIM_IMFLAGS_HASICON | AIM_IMFLAGS_MULTIPART);
-
- return aim_im_sendch1_ext(od, &args);
-}
-
-/*
* Subtype 0x0006 - Send a chat invitation.
*/
int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
@@ -572,7 +471,7 @@ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, gu
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
@@ -642,100 +541,7 @@ int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int i
byte_stream_put16(&bs, 0x0003);
byte_stream_put16(&bs, 0x0000);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * Subtype 0x0006 - Send a rich text message.
- *
- * This only works for ICQ 2001b (thats 2001 not 2000). Better, only
- * send it to clients advertising the RTF capability. In fact, if you send
- * it to a client that doesn't support that capability, the server will gladly
- * bounce it back to you.
- *
- * You'd think this would be in icq.c, but, well, I'm trying to stick with
- * the one-group-per-file scheme as much as possible. This could easily
- * be an exception, since Rendezvous IMs are external of the Oscar core,
- * and therefore are undefined. Really I just need to think of a good way to
- * make an interface similar to what AOL actually uses. But I'm not using COM.
- *
- */
-int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- guchar cookie[8];
- const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */
- int servdatalen;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)))
- return -EINVAL;
-
- if (!args || !args->destbn || !args->rtfmsg)
- return -EINVAL;
-
- servdatalen = 2+2+16+2+4+1+2 + 2+2+4+4+4 + 2+4+2+strlen(args->rtfmsg)+1 + 4+4+4+strlen(rtfcap)+1;
-
- aim_icbm_makecookie(cookie);
-
- byte_stream_new(&bs, 128+servdatalen);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
- /* ICBM header */
- aim_im_puticbm(&bs, cookie, 0x0002, args->destbn);
-
- /* TLV t(0005) - Encompasses everything below. */
- byte_stream_put16(&bs, 0x0005);
- byte_stream_put16(&bs, 2+8+16 + 2+2+2 + 2+2 + 2+2+servdatalen);
-
- byte_stream_put16(&bs, 0x0000);
- byte_stream_putraw(&bs, cookie, 8);
- byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
-
- /* t(000a) l(0002) v(0001) */
- byte_stream_put16(&bs, 0x000a);
- byte_stream_put16(&bs, 0x0002);
- byte_stream_put16(&bs, 0x0001);
-
- /* t(000f) l(0000) v() */
- byte_stream_put16(&bs, 0x000f);
- byte_stream_put16(&bs, 0x0000);
-
- /* Service Data TLV */
- byte_stream_put16(&bs, 0x2711);
- byte_stream_put16(&bs, servdatalen);
-
- byte_stream_putle16(&bs, 11 + 16 /* 11 + (sizeof CLSID) */);
- byte_stream_putle16(&bs, 9);
- byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
- byte_stream_putle16(&bs, 0);
- byte_stream_putle32(&bs, 0);
- byte_stream_putle8(&bs, 0);
- byte_stream_putle16(&bs, 0x03ea); /* trid1 */
-
- byte_stream_putle16(&bs, 14);
- byte_stream_putle16(&bs, 0x03eb); /* trid2 */
- byte_stream_putle32(&bs, 0);
- byte_stream_putle32(&bs, 0);
- byte_stream_putle32(&bs, 0);
-
- byte_stream_putle16(&bs, 0x0001);
- byte_stream_putle32(&bs, 0);
- byte_stream_putle16(&bs, strlen(args->rtfmsg)+1);
- byte_stream_putraw(&bs, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
-
- byte_stream_putle32(&bs, args->fgcolor);
- byte_stream_putle32(&bs, args->bgcolor);
- byte_stream_putle32(&bs, strlen(rtfcap)+1);
- byte_stream_putraw(&bs, (const guint8 *)rtfcap, strlen(rtfcap)+1);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
@@ -788,7 +594,7 @@ aim_im_sendch2_cancel(PeerConnection *peer_conn)
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -823,7 +629,7 @@ aim_im_sendch2_connected(PeerConnection *peer_conn)
byte_stream_putraw(&bs, peer_conn->cookie, 8);
byte_stream_putcaps(&bs, peer_conn->type);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -878,7 +684,7 @@ aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *bn,
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -941,7 +747,7 @@ aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *bn, c
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -988,17 +794,6 @@ aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char
aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
/* TODO: Send 0x0016 and 0x0017 */
-#if 0
- /* TODO: If the following is ever enabled, ensure that it is
- * not sent with a receive redirect or stage 3 proxy
- * redirect for a file receive (same conditions for
- * sending 0x000f above)
- */
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en");
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii");
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file.");
-#endif
-
if (filename != NULL)
{
ByteStream inner_bs;
@@ -1027,7 +822,7 @@ aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -1080,17 +875,6 @@ aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *
aim_tlvlist_add_raw(&inner_tlvlist, 0x0016, 4, ip_comp);
aim_tlvlist_add_16(&inner_tlvlist, 0x0017, ~pin);
-#if 0
- /* TODO: If the following is ever enabled, ensure that it is
- * not sent with a receive redirect or stage 3 proxy
- * redirect for a file receive (same conditions for
- * sending 0x000f above)
- */
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000e, 2, "en");
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000d, 8, "us-ascii");
- aim_tlvlist_add_raw(&inner_tlvlist, 0x000c, 24, "Please accept this file.");
-#endif
-
if (filename != NULL)
{
ByteStream filename_bs;
@@ -1120,530 +904,57 @@ aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *
aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, snacid, &bs);
byte_stream_destroy(&bs);
}
-/**
- * Subtype 0x0006 - Request the status message of the given ICQ user.
- *
- * @param od The oscar session.
- * @param bn The UIN of the user of whom you wish to request info.
- * @param type The type of info you wish to request. This should be the current
- * state of the user, as one of the AIM_ICQ_STATE_* defines.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- guchar cookie[8];
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM)) || !bn)
- return -EINVAL;
-
- aim_icbm_makecookie(cookie);
-
- byte_stream_new(&bs, 8+2+1+strlen(bn) + 4+0x5e + 4);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
- /* ICBM header */
- aim_im_puticbm(&bs, cookie, 0x0002, bn);
-
- /* TLV t(0005) - Encompasses almost everything below. */
- byte_stream_put16(&bs, 0x0005); /* T */
- byte_stream_put16(&bs, 0x005e); /* L */
- { /* V */
- byte_stream_put16(&bs, 0x0000);
-
- /* Cookie */
- byte_stream_putraw(&bs, cookie, 8);
-
- /* Put the 16 byte server relay capability */
- byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
-
- /* TLV t(000a) */
- byte_stream_put16(&bs, 0x000a);
- byte_stream_put16(&bs, 0x0002);
- byte_stream_put16(&bs, 0x0001);
-
- /* TLV t(000f) */
- byte_stream_put16(&bs, 0x000f);
- byte_stream_put16(&bs, 0x0000);
-
- /* TLV t(2711) */
- byte_stream_put16(&bs, 0x2711);
- byte_stream_put16(&bs, 0x0036);
- { /* V */
- byte_stream_putle16(&bs, 0x001b); /* L */
- byte_stream_putle16(&bs, 0x0009); /* Protocol version */
- byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
- byte_stream_putle16(&bs, 0x0000); /* Unknown */
- byte_stream_putle16(&bs, 0x0001); /* Client features? */
- byte_stream_putle16(&bs, 0x0000); /* Unknown */
- byte_stream_putle8(&bs, 0x00); /* Unkizown */
- byte_stream_putle16(&bs, 0xffff); /* Sequence number? XXX - This should decrement by 1 with each request */
-
- byte_stream_putle16(&bs, 0x000e); /* L */
- byte_stream_putle16(&bs, 0xffff); /* Sequence number? XXX - This should decrement by 1 with each request */
- byte_stream_putle32(&bs, 0x00000000); /* Unknown */
- byte_stream_putle32(&bs, 0x00000000); /* Unknown */
- byte_stream_putle32(&bs, 0x00000000); /* Unknown */
-
- /* The type of status message being requested */
- if (type & AIM_ICQ_STATE_CHAT)
- byte_stream_putle16(&bs, 0x03ec);
- else if(type & AIM_ICQ_STATE_DND)
- byte_stream_putle16(&bs, 0x03eb);
- else if(type & AIM_ICQ_STATE_OUT)
- byte_stream_putle16(&bs, 0x03ea);
- else if(type & AIM_ICQ_STATE_BUSY)
- byte_stream_putle16(&bs, 0x03e9);
- else if(type & AIM_ICQ_STATE_AWAY)
- byte_stream_putle16(&bs, 0x03e8);
-
- byte_stream_putle16(&bs, 0x0001); /* Status? */
- byte_stream_putle16(&bs, 0x0001); /* Priority of this message? */
- byte_stream_putle16(&bs, 0x0001); /* L */
- byte_stream_putle8(&bs, 0x00); /* String of length L */
- } /* End TLV t(2711) */
- } /* End TLV t(0005) */
-
- /* TLV t(0003) */
- byte_stream_put16(&bs, 0x0003);
- byte_stream_put16(&bs, 0x0000);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/**
- * Subtype 0x0006 - Send an ICQ-esque ICBM.
- *
- * This can be used to send an ICQ authorization reply (deny or grant). It is the "old way."
- * The new way is to use SSI. I like the new way a lot better. This seems like such a hack,
- * mostly because it's in network byte order. Figuring this stuff out sometimes takes a while,
- * but thats ok, because it gives me time to try to figure out what kind of drugs the AOL people
- * were taking when they merged the two protocols.
- *
- * @param bn The destination buddy name.
- * @param type The type of message. 0x0007 for authorization denied. 0x0008 for authorization granted.
- * @param message The message you want to send, it should be null terminated.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- guchar cookie[8];
-
- if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
- return -EINVAL;
-
- if (!bn || !type || !message)
- return -EINVAL;
-
- byte_stream_new(&bs, 8+3+strlen(bn)+12+strlen(message)+1+4);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0006, 0x0000, NULL, 0);
-
- aim_icbm_makecookie(cookie);
-
- /* ICBM header */
- aim_im_puticbm(&bs, cookie, 0x0004, bn);
-
- /*
- * TLV t(0005)
- *
- * ICQ data (the UIN and the message).
- */
- byte_stream_put16(&bs, 0x0005);
- byte_stream_put16(&bs, 4 + 2+2+strlen(message)+1);
-
- /*
- * Your UIN
- */
- byte_stream_putuid(&bs, od);
-
- /*
- * TLV t(type) l(strlen(message)+1) v(message+NULL)
- */
- byte_stream_putle16(&bs, type);
- byte_stream_putle16(&bs, strlen(message)+1);
- byte_stream_putraw(&bs, (const guint8 *)message, strlen(message)+1);
-
- /*
- * TLV t(0006) l(0000) v()
- */
- byte_stream_put16(&bs, 0x0006);
- byte_stream_put16(&bs, 0x0000);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0006, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * XXX - I don't see when this would ever get called...
- */
-static int outgoingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- guchar cookie[8];
- guint16 channel;
- GSList *tlvlist;
- char *bn;
- int bnlen;
- guint16 icbmflags = 0;
- guint8 flag1 = 0, flag2 = 0;
- gchar *msg = NULL;
- aim_tlv_t *msgblock;
-
- /* ICBM Cookie. */
- aim_icbm_makecookie(cookie);
-
- /* Channel ID */
- channel = byte_stream_get16(bs);
-
- if (channel != 0x01) {
- purple_debug_misc("oscar", "icbm: ICBM recieved on unsupported channel. Ignoring. (chan = %04x)\n", channel);
- return 0;
- }
-
- bnlen = byte_stream_get8(bs);
- bn = byte_stream_getstr(bs, bnlen);
-
- tlvlist = aim_tlvlist_read(bs);
-
- if (aim_tlv_gettlv(tlvlist, 0x0003, 1))
- icbmflags |= AIM_IMFLAGS_ACK;
- if (aim_tlv_gettlv(tlvlist, 0x0004, 1))
- icbmflags |= AIM_IMFLAGS_AWAY;
-
- if ((msgblock = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
- ByteStream mbs;
- int featurelen, msglen;
-
- byte_stream_init(&mbs, msgblock->value, msgblock->length);
-
- byte_stream_get8(&mbs);
- byte_stream_get8(&mbs);
- for (featurelen = byte_stream_get16(&mbs); featurelen; featurelen--)
- byte_stream_get8(&mbs);
- byte_stream_get8(&mbs);
- byte_stream_get8(&mbs);
-
- msglen = byte_stream_get16(&mbs) - 4; /* final block length */
-
- flag1 = byte_stream_get16(&mbs);
- flag2 = byte_stream_get16(&mbs);
-
- msg = byte_stream_getstr(&mbs, msglen);
- }
-
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, channel, bn, msg, icbmflags, flag1, flag2);
-
- g_free(bn);
- g_free(msg);
- aim_tlvlist_free(tlvlist);
-
- return ret;
-}
-
-/*
- * Ahh, the joys of nearly ridiculous over-engineering.
- *
- * Not only do AIM ICBM's support multiple channels. Not only do they
- * support multiple character sets. But they support multiple character
- * sets / encodings within the same ICBM.
- *
- * These multipart messages allow for complex space savings techniques, which
- * seem utterly unnecessary by today's standards. In fact, there is only
- * one client still in popular use that still uses this method: AOL for the
- * Macintosh, Version 5.0. Obscure, yes, I know.
- *
- * In modern (non-"legacy") clients, if the user tries to send a character
- * that is not ISO-8859-1 or ASCII, the client will send the entire message
- * as UNICODE, meaning that every character in the message will occupy the
- * full 16 bit UNICODE field, even if the high order byte would be zero.
- * Multipart messages prevent this wasted space by allowing the client to
- * only send the characters in UNICODE that need to be sent that way, and
- * the rest of the message can be sent in whatever the native character
- * set is (probably ASCII).
- *
- * An important note is that sections will be displayed in the order that
- * they appear in the ICBM. There is no facility for merging or rearranging
- * sections at run time. So if you have, say, ASCII then UNICODE then ASCII,
- * you must supply two ASCII sections with a UNICODE in the middle, and incur
- * the associated overhead.
- *
- * Normally I would have laughed and given a firm 'no' to supporting this
- * seldom-used feature, but something is attracting me to it. In the future,
- * it may be possible to abuse this to send mixed-media messages to other
- * open source clients (like encryption or something) -- see faimtest for
- * examples of how to do this.
- *
- * I would definitely recommend avoiding this feature unless you really
- * know what you are doing, and/or you have something neat to do with it.
- *
- */
-int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm)
-{
-
- memset(mpm, 0, sizeof(aim_mpmsg_t));
-
- return 0;
-}
-
-static int mpmsg_addsection(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, gchar *data, guint16 datalen)
-{
- aim_mpmsg_section_t *sec;
-
- sec = g_malloc(sizeof(aim_mpmsg_section_t));
-
- sec->charset = charset;
- sec->charsubset = charsubset;
- sec->data = data;
- sec->datalen = datalen;
- sec->next = NULL;
-
- if (!mpm->parts)
- mpm->parts = sec;
- else {
- aim_mpmsg_section_t *cur;
-
- for (cur = mpm->parts; cur->next; cur = cur->next)
- ;
- cur->next = sec;
- }
-
- mpm->numparts++;
-
- return 0;
-}
-
-int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen)
-{
- gchar *dup;
-
- dup = g_malloc(datalen);
- memcpy(dup, data, datalen);
-
- if (mpmsg_addsection(od, mpm, charset, charsubset, dup, datalen) == -1) {
- g_free(dup);
- return -1;
- }
-
- return 0;
-}
-
-/* XXX - should provide a way of saying ISO-8859-1 specifically */
-int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii)
-{
- gchar *dup;
-
- if (!(dup = g_strdup(ascii)))
- return -1;
-
- if (mpmsg_addsection(od, mpm, 0x0000, 0x0000, dup, strlen(ascii)) == -1) {
- g_free(dup);
- return -1;
- }
-
- return 0;
-}
-
-int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen)
-{
- gchar *buf;
- ByteStream bs;
- int i;
-
- buf = g_malloc(unicodelen * 2);
-
- byte_stream_init(&bs, (guchar *)buf, unicodelen * 2);
-
- /* We assume unicode is in /host/ byte order -- convert to network */
- for (i = 0; i < unicodelen; i++)
- byte_stream_put16(&bs, unicode[i]);
-
- if (mpmsg_addsection(od, mpm, 0x0002, 0x0000, buf, byte_stream_curpos(&bs)) == -1) {
- g_free(buf);
- return -1;
- }
-
- return 0;
-}
-
-void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm)
-{
- aim_mpmsg_section_t *cur;
-
- for (cur = mpm->parts; cur; ) {
- aim_mpmsg_section_t *tmp;
-
- tmp = cur->next;
- g_free(cur->data);
- g_free(cur);
- cur = tmp;
- }
-
- mpm->numparts = 0;
- mpm->parts = NULL;
-
- return;
-}
-
-/*
- * Start by building the multipart structures, then pick the first
- * human-readable section and stuff it into args->msg so no one gets
- * suspicious.
- */
-static int incomingim_ch1_parsemsgs(OscarData *od, aim_userinfo_t *userinfo, guint8 *data, int len, struct aim_incomingim_ch1_args *args)
+static void
+incomingim_ch1_parsemsg(OscarData *od, aim_userinfo_t *userinfo, ByteStream *message, struct aim_incomingim_ch1_args *args)
{
- /* Should this be ASCII -> UNICODE -> Custom */
- static const guint16 charsetpri[] = {
- AIM_CHARSET_ASCII, /* ASCII first */
- AIM_CHARSET_LATIN_1, /* then ISO-8859-1 */
- AIM_CHARSET_UNICODE, /* UNICODE as last resort */
- };
- static const int charsetpricount = 3;
- int i;
- ByteStream mbs;
- aim_mpmsg_section_t *sec;
-
- byte_stream_init(&mbs, data, len);
-
- while (byte_stream_empty(&mbs)) {
- guint16 msglen, flag1, flag2;
- gchar *msgbuf;
-
- byte_stream_get8(&mbs); /* 01 */
- byte_stream_get8(&mbs); /* 01 */
-
- /* Message string length, including character set info. */
- msglen = byte_stream_get16(&mbs);
- if (msglen > byte_stream_empty(&mbs))
- {
- purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
- break;
- }
-
- /* Character set info */
- flag1 = byte_stream_get16(&mbs);
- flag2 = byte_stream_get16(&mbs);
-
- /* Message. */
- msglen -= 4;
-
- /*
- * For now, we don't care what the encoding is. Just copy
- * it into a multipart struct and deal with it later. However,
- * always pad the ending with a NULL. This makes it easier
- * to treat ASCII sections as strings. It won't matter for
- * UNICODE or binary data, as you should never read past
- * the specified data length, which will not include the pad.
- *
- * XXX - There's an API bug here. For sending, the UNICODE is
- * given in host byte order (aim_mpmsg_addunicode), but here
- * the received messages are given in network byte order.
- *
- */
- msgbuf = (gchar *)byte_stream_getraw(&mbs, msglen);
- mpmsg_addsection(od, &args->mpmsg, flag1, flag2, msgbuf, msglen);
-
- } /* while */
-
- args->icbmflags |= AIM_IMFLAGS_MULTIPART; /* always set */
-
+ PurpleAccount *account = purple_connection_get_account(od->gc);
/*
- * Clients that support multiparts should never use args->msg, as it
- * will point to an arbitrary section.
- *
- * Here, we attempt to provide clients that do not support multipart
- * messages with something to look at -- hopefully a human-readable
- * string. But, failing that, a UNICODE message, or nothing at all.
- *
- * Which means that even if args->msg is NULL, it does not mean the
- * message was blank.
- *
+ * We're interested in the inner TLV 0x101, which contains precious, precious message.
*/
- for (i = 0; i < charsetpricount; i++) {
- for (sec = args->mpmsg.parts; sec; sec = sec->next) {
-
- if (sec->charset != charsetpri[i])
- continue;
-
- /* Great. We found one. Fill it in. */
- args->charset = sec->charset;
- args->charsubset = sec->charsubset;
-
- /* Set up the simple flags */
- switch (args->charsubset)
- {
- case 0x0000:
- /* standard subencoding? */
- break;
- case 0x000b:
- args->icbmflags |= AIM_IMFLAGS_SUBENC_MACINTOSH;
- break;
- case 0xffff:
- /* no subencoding */
- break;
- default:
- break;
- }
-
- args->msg = sec->data;
- args->msglen = sec->datalen;
-
- return 0;
+ while (byte_stream_bytes_left(message) >= 4) {
+ guint16 type = byte_stream_get16(message);
+ guint16 length = byte_stream_get16(message);
+ if (type == 0x101) {
+ gchar *msg;
+ guint16 msglen = length - 4; /* charset + charsubset */
+ guint16 charset = byte_stream_get16(message);
+ byte_stream_advance(message, 2); /* charsubset */
+
+ msg = byte_stream_getstr(message, msglen);
+ args->msg = oscar_decode_im(account, userinfo->bn, charset, msg, msglen);
+ } else {
+ byte_stream_advance(message, length);
}
}
-
- /* No human-readable sections found. Oh well. */
- args->charset = args->charsubset = 0xffff;
- args->msg = NULL;
- args->msglen = 0;
-
- return 0;
}
-static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
+static int
+incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, guint16 channel, aim_userinfo_t *userinfo, ByteStream *bs, guint8 *cookie)
{
- guint16 type, length, magic1, msglen = 0;
+ guint16 type, length;
aim_rxcallback_t userfunc;
int ret = 0;
- int rev = 0;
struct aim_incomingim_ch1_args args;
unsigned int endpos;
memset(&args, 0, sizeof(args));
- aim_mpmsg_init(od, &args.mpmsg);
-
/*
* This used to be done using tlvchains. For performance reasons,
* I've changed it to process the TLVs in-place. This avoids lots
* of per-IM memory allocations.
*/
- while (byte_stream_empty(bs) >= 4)
+ while (byte_stream_bytes_left(bs) >= 4)
{
type = byte_stream_get16(bs);
length = byte_stream_get16(bs);
- if (length > byte_stream_empty(bs))
+ if (length > byte_stream_bytes_left(bs))
{
purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
break;
@@ -1652,93 +963,20 @@ static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod
endpos = byte_stream_curpos(bs) + length;
if (type == 0x0002) { /* Message Block */
-
- /*
- * This TLV consists of the following:
- * - 0501 -- Unknown
- * - Features: Don't know how to interpret these
- * - 0101 -- Unknown
- * - Message
- *
- * Slick and possible others reverse 'Features' and 'Messages' section.
- * Thus, the TLV could have following layout:
- * - 0101 -- Unknown (possibly magic for message section)
- * - Message
- * - 0501 -- Unknown (possibly magic for features section)
- * - Features: Don't know how to interpret these
- */
-
- magic1 = byte_stream_get16(bs); /* 0501 or 0101 */
- if (magic1 == 0x101) /* Bad, message comes before attributes */
- {
- /* Jump to the features section */
- msglen = byte_stream_get16(bs);
- bs->offset += msglen;
- rev = 1;
-
- magic1 = byte_stream_get16(bs); /* 0501 */
- }
-
- if (magic1 != 0x501)
- {
- purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
- break;
- }
-
- args.featureslen = byte_stream_get16(bs);
- if (args.featureslen > byte_stream_empty(bs))
- {
- purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
- break;
- }
- if (args.featureslen == 0)
- {
- args.features = NULL;
- }
- else
- {
- args.features = byte_stream_getraw(bs, args.featureslen);
- args.icbmflags |= AIM_IMFLAGS_CUSTOMFEATURES;
- }
-
- if (rev)
- {
- /* Fix buffer back to message */
- bs->offset -= args.featureslen + 2 + 2 + msglen + 2 + 2;
- }
-
- magic1 = byte_stream_get16(bs); /* 01 01 */
- if (magic1 != 0x101) /* Bad, message comes before attributes */
- {
- purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
- break;
- }
- msglen = byte_stream_get16(bs);
-
- /*
- * The rest of the TLV contains one or more message
- * blocks...
- */
- incomingim_ch1_parsemsgs(od, userinfo, bs->data + bs->offset - 2 - 2 /* XXX evil!!! */, msglen + 2 + 2, &args);
-
+ ByteStream tlv02;
+ byte_stream_init(&tlv02, bs->data + bs->offset, length);
+ incomingim_ch1_parsemsg(od, userinfo, &tlv02, &args);
} else if (type == 0x0003) { /* Server Ack Requested */
-
args.icbmflags |= AIM_IMFLAGS_ACK;
-
} else if (type == 0x0004) { /* Message is Auto Response */
-
args.icbmflags |= AIM_IMFLAGS_AWAY;
-
} else if (type == 0x0006) { /* Message was received offline. */
-
/*
* This flag is set on incoming offline messages for both
* AIM and ICQ accounts.
*/
args.icbmflags |= AIM_IMFLAGS_OFFLINE;
-
} else if (type == 0x0008) { /* I-HAVE-A-REALLY-PURTY-ICON Flag */
-
args.iconlen = byte_stream_get32(bs);
byte_stream_get16(bs); /* 0x0001 */
args.iconsum = byte_stream_get16(bs);
@@ -1756,39 +994,16 @@ static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod
*/
if (args.iconlen)
args.icbmflags |= AIM_IMFLAGS_HASICON;
-
} else if (type == 0x0009) {
-
args.icbmflags |= AIM_IMFLAGS_BUDDYREQ;
-
} else if (type == 0x000b) { /* Non-direct connect typing notification */
-
args.icbmflags |= AIM_IMFLAGS_TYPINGNOT;
-
} else if (type == 0x0016) {
-
/*
* UTC timestamp for when the message was sent. Only
* provided for offline messages.
*/
args.timestamp = byte_stream_get32(bs);
-
- } else if (type == 0x0017) {
-
- if (length > byte_stream_empty(bs))
- {
- purple_debug_misc("oscar", "Received an IM containing an invalid message part from %s. They are probably trying to do something malicious.\n", userinfo->bn);
- break;
- }
- g_free(args.extdata);
- args.extdatalen = length;
- if (args.extdatalen == 0)
- args.extdata = NULL;
- else
- args.extdata = byte_stream_getraw(bs, args.extdatalen);
-
- } else {
- purple_debug_misc("oscar", "incomingim_ch1: unknown TLV 0x%04x (len %d)\n", type, length);
}
/*
@@ -1806,10 +1021,7 @@ static int incomingim_ch1(OscarData *od, FlapConnection *conn, aim_module_t *mod
if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
ret = userfunc(od, conn, frame, channel, userinfo, &args);
- aim_mpmsg_free(od, &args.mpmsg);
- g_free(args.features);
- g_free(args.extdata);
-
+ g_free(args.msg);
return ret;
}
@@ -1835,7 +1047,7 @@ incomingim_ch2_buddylist(OscarData *od, FlapConnection *conn, aim_module_t *mod,
* ...
* ...
*/
- while (byte_stream_empty(servdata))
+ while (byte_stream_bytes_left(servdata))
{
guint16 gnlen, numb;
int i;
@@ -1907,7 +1119,7 @@ incomingim_ch2_chat(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
static void
incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
{
- g_free((char *)args->info.rtfmsg.rtfmsg);
+ g_free((char *)args->info.rtfmsg.msg);
}
/*
@@ -1921,33 +1133,34 @@ incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
static void
incomingim_ch2_icqserverrelay(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, aim_userinfo_t *userinfo, IcbmArgsCh2 *args, ByteStream *servdata)
{
- guint16 hdrlen, anslen, msglen;
-
- if (byte_stream_empty(servdata) < 24)
- /* Someone sent us a short server relay ICBM. Weird. (Maybe?) */
- return;
+ guint16 hdrlen, msglen;
- hdrlen = byte_stream_getle16(servdata);
- byte_stream_advance(servdata, hdrlen);
+ args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
- hdrlen = byte_stream_getle16(servdata);
+#define SKIP_HEADER(expected_hdrlen) \
+ hdrlen = byte_stream_getle16(servdata); \
+ if (hdrlen != expected_hdrlen) { \
+ purple_debug_warning("oscar", "Expected to find a header with length " #expected_hdrlen "; ignoring message"); \
+ return; \
+ } \
byte_stream_advance(servdata, hdrlen);
- args->info.rtfmsg.msgtype = byte_stream_getle16(servdata);
+ SKIP_HEADER(0x001b);
+ SKIP_HEADER(0x000e);
- anslen = byte_stream_getle32(servdata);
- byte_stream_advance(servdata, anslen);
+ args->info.rtfmsg.msgtype = byte_stream_get8(servdata);
+ /*
+ * Copied from http://iserverd.khstu.ru/oscar/message.html:
+ * xx byte message flags
+ * xx xx word (LE) status code
+ * xx xx word (LE) priority code
+ *
+ * We don't need any of these, so just skip them.
+ */
+ byte_stream_advance(servdata, 1 + 2 + 2);
msglen = byte_stream_getle16(servdata);
- args->info.rtfmsg.rtfmsg = byte_stream_getstr(servdata, msglen);
-
- args->info.rtfmsg.fgcolor = byte_stream_getle32(servdata);
- args->info.rtfmsg.bgcolor = byte_stream_getle32(servdata);
-
- hdrlen = byte_stream_getle32(servdata);
- byte_stream_advance(servdata, hdrlen);
-
- args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
+ args->info.rtfmsg.msg = byte_stream_getstr(servdata, msglen);
}
static void
@@ -2107,7 +1320,7 @@ static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod
/*
* Terminate connection/error code. 0x0001 means the other user
- * canceled the connection.
+ * cancelled the connection.
*/
if (aim_tlv_gettlv(list2, 0x000b, 1))
args.errorcode = aim_tlv_get16(list2, 0x000b, 1);
@@ -2132,20 +1345,6 @@ static int incomingim_ch2(OscarData *od, FlapConnection *conn, aim_module_t *mod
if (aim_tlv_gettlv(list2, 0x000e, 1))
args.language = aim_tlv_getstr(list2, 0x000e, 1);
-#if 0
- /*
- * Unknown -- no value
- *
- * Maybe means we should connect directly to transfer the file?
- * Also used in ICQ Lite Beta 4.0 URLs. Also empty.
- */
- /* I don't think this indicates a direct transfer; this flag is
- * also present in a stage 1 proxied file send request -- Jonathan */
- if (aim_tlv_gettlv(list2, 0x000f, 1)) {
- /* Unhandled */
- }
-#endif
-
/*
* Flag meaning we should proxy the file transfer through an AIM server
*/
@@ -2340,38 +1539,6 @@ static int incomingim(OscarData *od, FlapConnection *conn, aim_module_t *mod, Fl
return ret;
}
-/*
- * Subtype 0x0008 - Send a warning to bn.
- *
- * Flags:
- * AIM_WARN_ANON Send as an anonymous (doesn't count as much)
- *
- * returns -1 on error (couldn't alloc packet), 0 on success.
- *
- */
-int aim_im_warn(OscarData *od, FlapConnection *conn, const char *bn, guint32 flags)
-{
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!od || !conn || !bn)
- return -EINVAL;
-
- byte_stream_new(&bs, strlen(bn)+3);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0008, 0x0000, bn, strlen(bn)+1);
-
- byte_stream_put16(&bs, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
- byte_stream_put8(&bs, strlen(bn));
- byte_stream_putstr(&bs, bn);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0008, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
/* Subtype 0x000a */
static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
@@ -2380,7 +1547,7 @@ static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, Fl
guint16 channel, nummissed, reason;
aim_userinfo_t userinfo;
- while (byte_stream_empty(bs)) {
+ while (byte_stream_bytes_left(bs)) {
channel = byte_stream_get16(bs);
aim_info_extract(od, bs, &userinfo);
@@ -2400,9 +1567,7 @@ static int missedcall(OscarData *od, FlapConnection *conn, aim_module_t *mod, Fl
* Subtype 0x000b
*
* Possible codes:
- * AIM_TRANSFER_DENY_NOTSUPPORTED -- "client does not support"
* AIM_TRANSFER_DENY_DECLINE -- "client has declined transfer"
- * AIM_TRANSFER_DENY_NOTACCEPTING -- "client is not accepting transfers"
*
*/
int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code)
@@ -2429,186 +1594,57 @@ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, gui
aim_tlvlist_write(&bs, &tlvlist);
aim_tlvlist_free(tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x000b, snacid, &bs);
byte_stream_destroy(&bs);
return 0;
}
-static void parse_status_note_text(OscarData *od, guchar *cookie, char *bn, ByteStream *bs)
+/*
+ * Subtype 0x000b.
+ * Send confirmation for a channel 2 message (Miranda wants it by default).
+ */
+void
+aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie)
{
- struct aim_icq_info *info;
- struct aim_icq_info *prev_info;
- char *response;
- char *encoding;
- char *stripped_encoding;
- char *status_note_title;
- char *status_note_text;
- char *stripped_status_note_text;
- char *status_note;
- guint32 length;
- guint16 version;
- guint32 capability;
- guint8 message_type;
- guint16 status_code;
- guint16 text_length;
- guint32 request_length;
- guint32 response_length;
- guint32 encoding_length;
- PurpleAccount *account;
- PurpleBuddy *buddy;
- PurplePresence *presence;
- PurpleStatus *status;
-
- for (prev_info = NULL, info = od->icq_info; info != NULL; prev_info = info, info = info->next)
- {
- if (memcmp(&info->icbm_cookie, cookie, 8) == 0)
- {
- if (prev_info == NULL)
- od->icq_info = info->next;
- else
- prev_info->next = info->next;
-
- break;
- }
- }
-
- if (info == NULL)
- return;
-
- status_note_title = info->status_note_title;
- g_free(info);
-
- length = byte_stream_getle16(bs);
- if (length != 27) {
- purple_debug_misc("oscar", "clientautoresp: incorrect header "
- "size; expected 27, received %u.\n", length);
- g_free(status_note_title);
- return;
- }
-
- version = byte_stream_getle16(bs);
- if (version != 9) {
- purple_debug_misc("oscar", "clientautoresp: incorrect version; "
- "expected 9, received %u.\n", version);
- g_free(status_note_title);
- return;
- }
-
- capability = aim_locate_getcaps(od, bs, 0x10);
- if (capability != OSCAR_CAPABILITY_EMPTY) {
- purple_debug_misc("oscar", "clientautoresp: plugin ID is not null.\n");
- g_free(status_note_title);
- return;
- }
-
- byte_stream_advance(bs, 2); /* unknown */
- byte_stream_advance(bs, 4); /* client capabilities flags */
- byte_stream_advance(bs, 1); /* unknown */
- byte_stream_advance(bs, 2); /* downcouner? */
-
- length = byte_stream_getle16(bs);
- if (length != 14) {
- purple_debug_misc("oscar", "clientautoresp: incorrect header "
- "size; expected 14, received %u.\n", length);
- g_free(status_note_title);
- return;
- }
-
- byte_stream_advance(bs, 2); /* downcounter? */
- byte_stream_advance(bs, 12); /* unknown */
-
- message_type = byte_stream_get8(bs);
- if (message_type != 0x1a) {
- purple_debug_misc("oscar", "clientautoresp: incorrect message "
- "type; expected 0x1a, received 0x%x.\n", message_type);
- g_free(status_note_title);
- return;
- }
-
- byte_stream_advance(bs, 1); /* message flags */
-
- status_code = byte_stream_getle16(bs);
- if (status_code != 0) {
- purple_debug_misc("oscar", "clientautoresp: incorrect status "
- "code; expected 0, received %u.\n", status_code);
- g_free(status_note_title);
- return;
- }
-
- byte_stream_advance(bs, 2); /* priority code */
-
- text_length = byte_stream_getle16(bs);
- byte_stream_advance(bs, text_length); /* text */
-
- length = byte_stream_getle16(bs);
- byte_stream_advance(bs, 18); /* unknown */
-
- request_length = byte_stream_getle32(bs);
- if (length != 18 + 4 + request_length + 17) {
- purple_debug_misc("oscar", "clientautoresp: incorrect block; "
- "expected length is %u, got %u.\n",
- 18 + 4 + request_length + 17, length);
- g_free(status_note_title);
- return;
- }
-
- byte_stream_advance(bs, request_length); /* x request */
- byte_stream_advance(bs, 17); /* unknown */
-
- length = byte_stream_getle32(bs);
- response_length = byte_stream_getle32(bs);
- response = byte_stream_getstr(bs, response_length);
- encoding_length = byte_stream_getle32(bs);
- if (length != 4 + response_length + 4 + encoding_length) {
- purple_debug_misc("oscar", "clientautoresp: incorrect block; "
- "expected length is %u, got %u.\n",
- 4 + response_length + 4 + encoding_length, length);
- g_free(status_note_title);
- g_free(response);
- return;
- }
-
- encoding = byte_stream_getstr(bs, encoding_length);
-
- account = purple_connection_get_account(od->gc);
-
- stripped_encoding = oscar_encoding_extract(encoding);
- status_note_text = oscar_encoding_to_utf8(account, stripped_encoding, response, response_length);
- stripped_status_note_text = purple_markup_strip_html(status_note_text);
+ ByteStream bs;
+ aim_snacid_t snacid;
+ guint32 header_size, data_size;
+ guint16 cookie2 = (guint16)g_random_int();
- if (stripped_status_note_text != NULL && stripped_status_note_text[0] != 0)
- status_note = g_strdup_printf("%s: %s", status_note_title, stripped_status_note_text);
- else
- status_note = g_strdup(status_note_title);
+ purple_debug_misc("oscar", "Sending message ack to %s\n", bn);
- g_free(status_note_title);
- g_free(response);
- g_free(encoding);
- g_free(stripped_encoding);
- g_free(status_note_text);
- g_free(stripped_status_note_text);
+ header_size = 8 + 2 + 1 + strlen(bn) + 2;
+ data_size = 2 + 1 + 16 + 4*2 + 2*3 + 4*3 + 1*2 + 2*3 + 1;
+ byte_stream_new(&bs, header_size + data_size);
- buddy = purple_find_buddy(account, bn);
- if (buddy == NULL)
- {
- purple_debug_misc("oscar", "clientautoresp: buddy %s was not found.\n", bn);
- g_free(status_note);
- return;
- }
-
- purple_debug_misc("oscar", "clientautoresp: setting status "
- "message to \"%s\".\n", status_note);
-
- presence = purple_buddy_get_presence(buddy);
- status = purple_presence_get_active_status(presence);
+ /* The message header. */
+ aim_im_puticbm(&bs, cookie, 0x0002, bn);
+ byte_stream_put16(&bs, 0x0003); /* reason */
- purple_prpl_got_user_status(account, bn,
- purple_status_get_id(status),
- "message", status_note, NULL);
+ /* The actual message. */
+ byte_stream_putle16(&bs, 0x1b); /* subheader #1 length */
+ byte_stream_put8(&bs, 0x08); /* protocol version */
+ byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
+ byte_stream_put32(&bs, 0x3); /* client features */
+ byte_stream_put32(&bs, 0x0004); /* DC type */
+ byte_stream_put16(&bs, cookie2); /* a cookie, chosen by fair dice roll */
+ byte_stream_putle16(&bs, 0x0e); /* header #2 len? */
+ byte_stream_put16(&bs, cookie2); /* the same cookie again */
+ byte_stream_put32(&bs, 0); /* unknown */
+ byte_stream_put32(&bs, 0); /* unknown */
+ byte_stream_put32(&bs, 0); /* unknown */
+ byte_stream_put8(&bs, 0x01); /* plain text message */
+ byte_stream_put8(&bs, 0x00); /* no message flags */
+ byte_stream_put16(&bs, 0x0000); /* no icq status */
+ byte_stream_put16(&bs, 0x0100); /* priority */
+ byte_stream_putle16(&bs, 1); /* query message len */
+ byte_stream_put8(&bs, 0x00); /* empty query message */
- g_free(status_note);
+ snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x000b, 0x0000, NULL, 0);
+ flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_ICBM, 0x000b, snacid, &bs);
+ byte_stream_destroy(&bs);
}
/*
@@ -2625,10 +1661,9 @@ static int clientautoresp(OscarData *od, FlapConnection *conn, aim_module_t *mod
guchar *cookie;
guint8 bnlen;
char *xml = NULL;
- int hdrlen;
+ guint16 hdrlen;
int curpos;
- int num1,num2;
- char *desc, *title, *temp;
+ guint16 num1, num2;
PurpleAccount *account;
PurpleBuddy *buddy;
PurplePresence *presence;
@@ -2642,54 +1677,64 @@ static int clientautoresp(OscarData *od, FlapConnection *conn, aim_module_t *mod
if (channel == 0x0002)
{
- hdrlen = byte_stream_getle16(bs);
- if ( ((hdrlen == 27 ) && (bs->len > (27 + 51)))) {
- byte_stream_advance(bs, 51);
- num1 = byte_stream_getle16(bs);
- num2 = byte_stream_getle16(bs);
- purple_debug_misc("oscar", "X-Status: Num1 %i, num2 %i\n",num1, num2);
-
- if(((num1 == 0x4f00)&&(num2 == 0x3b00))) {
- byte_stream_advance(bs, 86);
- curpos = byte_stream_curpos(bs);
- xml = byte_stream_getstr(bs, bs->len - curpos);
- purple_debug_misc("oscar", "X-Status: Received XML reply\n");
- if(xml) {
- /* purple_debug_misc("oscar", "X-Status: XML reply: %s\n", (const char*) xml); */
- if ((desc=strstr(xml,"&lt;desc&gt;")) != NULL) {
- temp=strstr(xml,"&lt;/desc&gt;");
- temp[0]=0;
- desc=desc+12;
- }
- if ((title=strstr(xml,"&lt;title&gt;")) != NULL) {
- temp=strstr(xml,"&lt;/title&gt;");
- temp[0]=0;
- title=title+13;
- } else {
- title="";
- }
- strcpy(xml,title);
- if (desc) {
- strcat(xml, " - ");
- strcat(xml, desc);
+ hdrlen = byte_stream_getle16(bs);
+ if (hdrlen == 27 && bs->len > (27 + 51)) {
+ byte_stream_advance(bs, 51);
+ num1 = byte_stream_getle16(bs);
+ num2 = byte_stream_getle16(bs);
+ purple_debug_misc("oscar", "X-Status: num1 %hu, num2 %hu\n", num1, num2);
+
+ if (num1 == 0x4f00 && num2 == 0x3b00) {
+ byte_stream_advance(bs, 86);
+ curpos = byte_stream_curpos(bs);
+ xml = byte_stream_getstr(bs, bs->len - curpos);
+ purple_debug_misc("oscar", "X-Status: Received XML reply\n");
+ if (xml) {
+ GString *xstatus;
+ char *tmp1, *tmp2;
+
+ /* purple_debug_misc("oscar", "X-Status: XML reply: %s\n", xml); */
+
+ xstatus = g_string_new(NULL);
+
+ tmp1 = strstr(xml, "&lt;title&gt;");
+ if (tmp1 != NULL) {
+ tmp1 += 13;
+ tmp2 = strstr(tmp1, "&lt;/title&gt;");
+ if (tmp2 != NULL)
+ g_string_append_len(xstatus, tmp1, tmp2 - tmp1);
+ }
+ tmp1 = strstr(xml, "&lt;desc&gt;");
+ if (tmp1 != NULL) {
+ tmp1 += 12;
+ tmp2 = strstr(tmp1, "&lt;/desc&gt;");
+ if (tmp2 != NULL) {
+ if (xstatus->len > 0)
+ g_string_append(xstatus, " - ");
+ g_string_append_len(xstatus, tmp1, tmp2 - tmp1);
+ }
}
- purple_debug_misc("oscar", "X-Status reply: %s\n", (const char*)xml);
- account = purple_connection_get_account(od->gc);
- buddy = purple_find_buddy(account, bn);
- presence = purple_buddy_get_presence(buddy);
- status = purple_presence_get_active_status(presence);
- purple_prpl_got_user_status(account, bn,
- purple_status_get_id(status), "message", xml, NULL);
- } else {
- purple_debug_misc("oscar", "X-Status: Can't get XML reply string\n");
+ if (xstatus->len > 0) {
+ purple_debug_misc("oscar", "X-Status reply: %s\n", xstatus->str);
+ account = purple_connection_get_account(od->gc);
+ buddy = purple_find_buddy(account, bn);
+ presence = purple_buddy_get_presence(buddy);
+ status = purple_presence_get_active_status(presence);
+ purple_prpl_got_user_status(account, bn,
+ purple_status_get_id(status),
+ "message", xstatus->str, NULL);
+ }
+ g_string_free(xstatus, TRUE);
+ } else {
+ purple_debug_misc("oscar", "X-Status: Can't get XML reply string\n");
}
- } else {
- purple_debug_misc("oscar", "X-Status: 0x0004, 0x000b not an xstatus reply\n" );
- /* if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, channel, sn, reason); */
+ } else {
+ purple_debug_misc("oscar", "X-Status: 0x0004, 0x000b not an xstatus reply\n");
+ /* if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
+ ret = userfunc(od, conn, frame, channel, sn, reason); */
}
-
- }
+
+ }
} else if (channel == 0x0004) { /* ICQ message */
switch (reason) {
@@ -2754,16 +1799,10 @@ static int clientautoresp(OscarData *od, FlapConnection *conn, aim_module_t *mod
}
/*
- * Subtype 0x000c - Receive an ack after sending an ICBM.
- *
- * You have to have send the message with the AIM_IMFLAGS_ACK flag set
- * (TLV t(0003)). The ack contains the ICBM header of the message you
- * sent.
- *
+ * Subtype 0x000c - Receive an ack after sending an ICBM. The ack contains the ICBM header of the message you sent.
*/
static int msgack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- aim_rxcallback_t userfunc;
guint16 ch;
guchar *cookie;
char *bn;
@@ -2773,8 +1812,7 @@ static int msgack(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFr
ch = byte_stream_get16(bs);
bn = byte_stream_getstr(bs, byte_stream_get8(bs));
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, ch, bn);
+ purple_debug_info("oscar", "Sent message to %s.\n", bn);
g_free(bn);
g_free(cookie);
@@ -2825,7 +1863,7 @@ int aim_im_sendmtn(OscarData *od, guint16 channel, const char *bn, guint16 event
if (!bn)
return -EINVAL;
- byte_stream_new(&bs, 11+strlen(bn)+2);
+ byte_stream_new(&bs, 11 + strlen(bn) + 2);
snacid = aim_cachesnac(od, SNAC_FAMILY_ICBM, 0x0014, 0x0000, NULL, 0);
@@ -2849,7 +1887,7 @@ int aim_im_sendmtn(OscarData *od, guint16 channel, const char *bn, guint16 event
*/
byte_stream_put16(&bs, event);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICBM, 0x0014, snacid, &bs);
byte_stream_destroy(&bs);
@@ -2871,38 +1909,36 @@ int icq_im_xstatus_request(OscarData *od, const char *sn)
char *statxml;
int xmllen;
- static const guint8 pluginid[] =
- {
- 0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F, 0x11, 0xD1,
- 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00
+ static const guint8 pluginid[] = {
+ 0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F, 0x11, 0xD1,
+ 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00
};
-
- static const guint8 c_plugindata[] =
- {
- 0x1B, 0x00, 0x0A,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x00, 0x4F, 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, 0x9C,
- 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69, 0x70,
- 0x74, 0x20, 0x50, 0x6C, 0x75, 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
- 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41,
- 0x72, 0x72, 0x69, 0x76, 0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00
+
+ static const guint8 c_plugindata[] = {
+ 0x1B, 0x00, 0x0A,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x4F, 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0, 0x9C,
+ 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x53, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x20, 0x50, 0x6C, 0x75, 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
+ 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41,
+ 0x72, 0x72, 0x69, 0x76, 0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00
};
-
+
if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
return -EINVAL;
if (!sn)
return -EINVAL;
- fmt = "<N><QUERY>&lt;Q&gt;&lt;PluginID&gt;srvMng&lt;/PluginID&gt;&lt;/Q&gt;</QUERY><NOTIFY>&lt;srv&gt;&lt;id&gt;cAwaySrv&lt;/id&gt;&lt;req&gt;&lt;id&gt;AwayStat&lt;/id&gt;&lt;trans&gt;2&lt;/trans&gt;&lt;senderId&gt;%s&lt;/senderId&gt;&lt;/req&gt;&lt;/srv&gt;</NOTIFY></N>\r\n";
+ fmt = "<N><QUERY>&lt;Q&gt;&lt;PluginID&gt;srvMng&lt;/PluginID&gt;&lt;/Q&gt;</QUERY><NOTIFY>&lt;srv&gt;&lt;id&gt;cAwaySrv&lt;/id&gt;&lt;req&gt;&lt;id&gt;AwayStat&lt;/id&gt;&lt;trans&gt;2&lt;/trans&gt;&lt;senderId&gt;%s&lt;/senderId&gt;&lt;/req&gt;&lt;/srv&gt;</NOTIFY></N>\r\n";
account = purple_connection_get_account(od->gc);
xmllen = strlen(fmt) - 2 + strlen(account->username);
- statxml = (char*) g_malloc(xmllen);
+ statxml = g_malloc(xmllen);
snprintf(statxml, xmllen, fmt, account->username);
aim_icbm_makecookie(cookie);
@@ -2911,38 +1947,36 @@ int icq_im_xstatus_request(OscarData *od, const char *sn)
+ 2 + 2 + 8 + 16 + 2 + 2 + 2 + 2 + 2
+ 2 + 2 + sizeof(c_plugindata) + xmllen
+ 2 + 2);
-
+
snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
aim_im_puticbm(&bs, cookie, 0x0002, sn);
byte_stream_new(&header, (7*2) + 16 + 8 + 2 + sizeof(c_plugindata) + xmllen); /* TLV 0x0005 Stream + Size */
- byte_stream_new(&plugindata, (sizeof(c_plugindata) + xmllen));
-
byte_stream_put16(&header, 0x0000); /* Message Type: Request */
byte_stream_putraw(&header, cookie, sizeof(cookie)); /* Message ID */
byte_stream_putraw(&header, pluginid, sizeof(pluginid)); /* Plugin ID */
-
+
aim_tlvlist_add_16(&inner_tlvlist, 0x000a, 0x0001);
aim_tlvlist_add_noval(&inner_tlvlist, 0x000f);
-
+
/* Add Plugin Specific Data */
+ byte_stream_new(&plugindata, (sizeof(c_plugindata) + xmllen));
byte_stream_putraw(&plugindata, c_plugindata, sizeof(c_plugindata)); /* Content of TLV 0x2711 */
byte_stream_putstr(&plugindata, statxml);
aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, (sizeof(c_plugindata) + xmllen), plugindata.data);
-
+
aim_tlvlist_write(&header, &inner_tlvlist);
-
-
+ aim_tlvlist_free(inner_tlvlist);
+
aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&header), header.data);
- aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); /* Empty TLV 0x0003 */
-
+ aim_tlvlist_add_noval(&outer_tlvlist, 0x0003); /* Empty TLV 0x0003 */
+
aim_tlvlist_write(&bs, &outer_tlvlist);
-
+
purple_debug_misc("oscar", "X-Status Request\n");
- flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, TRUE);
+ flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, TRUE);
- aim_tlvlist_free(inner_tlvlist);
aim_tlvlist_free(outer_tlvlist);
byte_stream_destroy(&header);
byte_stream_destroy(&plugindata);
@@ -2959,58 +1993,65 @@ int icq_relay_xstatus(OscarData *od, const char *sn, const guchar *cookie)
aim_snacid_t snacid;
PurpleAccount *account;
PurpleStatus *status;
- const char *fmt;
- const char *formatted_msg;
- char *msg;
- char *statxml;
+ const char *fmt;
+ const char *formatted_msg;
+ char *msg;
+ char *statxml;
const char *title;
int len;
-
+
static const guint8 plugindata[] = {
- 0x1B, 0x00,
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4F,
- 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0,
- 0x9C, 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00,
- 0x00, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x50, 0x6C, 0x75,
- 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
- 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xF3, 0x01, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00
- };
+ 0x1B, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD1, 0x0E, 0x00, 0xF9, 0xD1,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x4F,
+ 0x00, 0x3B, 0x60, 0xB3, 0xEF, 0xD8, 0x2A, 0x6C, 0x45, 0xA4, 0xE0,
+ 0x9C, 0x5A, 0x5E, 0x67, 0xE8, 0x65, 0x08, 0x00, 0x2A, 0x00, 0x00,
+ 0x00, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x50, 0x6C, 0x75,
+ 0x67, 0x2D, 0x69, 0x6E, 0x3A, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74,
+ 0x65, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x72, 0x72, 0x69, 0x76, 0x65, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xF3, 0x01, 0x00, 0x00, 0xEF, 0x01, 0x00, 0x00
+ };
fmt = "<NR><RES>&lt;ret event='OnRemoteNotification'&gt;&lt;srv&gt;&lt;id&gt;cAwaySrv&lt;/id&gt;&lt;val srv_id='cAwaySrv'&gt;&lt;Root&gt;&lt;CASXtraSetAwayMessage&gt;&lt;/CASXtraSetAwayMessage&gt;&l t;uin&gt;%s&lt;/uin&gt;&lt;index&gt;1&lt;/index&gt;&lt;title&gt;%s&lt;/title&gt;&lt;desc&gt;%s&lt;/desc&gt;&lt;/Root&gt;&lt;/val&gt;&lt;/srv&gt;&lt;srv&gt;&lt;id&gt;cRandomizerSrv&lt;/id&gt;&lt;val srv_id='cRandomizerSrv'&gt;undefined&lt;/val&gt;&lt;/srv&gt;&lt;/ret&gt;</RES></NR>\r\n";
-
-
+
if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
return -EINVAL;
if (!sn)
return -EINVAL;
-
+
account = purple_connection_get_account(od->gc);
- if(!account) return -EINVAL;
-
-/* if (!strcmp(account->username, sn))
+ if (!account)
+ return -EINVAL;
+
+ /* if (!strcmp(account->username, sn))
icq_im_xstatus_request(od, sn); */
-
- status = purple_presence_get_active_status(account->presence);
- if (!status) return -EINVAL;
- title = purple_status_get_name(status);
- if (!title) return -EINVAL;
+
+ status = purple_presence_get_active_status(account->presence);
+ if (!status)
+ return -EINVAL;
+
+ title = purple_status_get_name(status);
+ if (!title)
+ return -EINVAL;
+
formatted_msg = purple_status_get_attr_string(status, "message");
- if (!formatted_msg) return -EINVAL;
- msg = purple_markup_strip_html(formatted_msg);
- if (!msg) return -EINVAL;
- len = strlen(fmt)-6+strlen(account->username)+strlen(title)+strlen(msg);
- statxml = (char*) g_malloc(len);
+ if (!formatted_msg)
+ return -EINVAL;
- snprintf(statxml, len, fmt,
- account->username, title, msg);
+ msg = purple_markup_strip_html(formatted_msg);
+ if (!msg)
+ return -EINVAL;
+
+ len = strlen(fmt) - 6 + strlen(account->username) + strlen(title) + strlen(msg);
+ statxml = g_malloc(len);
+
+ snprintf(statxml, len, fmt, account->username, title, msg);
purple_debug_misc("oscar", "X-Status AutoReply: %s, %s\n", formatted_msg, msg);
@@ -3021,8 +2062,8 @@ int icq_relay_xstatus(OscarData *od, const char *sn, const guchar *cookie)
byte_stream_put16(&bs, 0x0003);
byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
byte_stream_putraw(&bs, (const guint8*)statxml, strlen(statxml));
-
- flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs, TRUE);
+
+ flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x000b, snacid, &bs, TRUE);
g_free(statxml);
g_free(msg);
@@ -3067,8 +2108,6 @@ snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
return error(od, conn, mod, frame, snac, bs);
else if (snac->subtype == 0x0005)
return aim_im_paraminfo(od, conn, mod, frame, snac, bs);
- else if (snac->subtype == 0x0006)
- return outgoingim(od, conn, mod, frame, snac, bs);
else if (snac->subtype == 0x0007)
return incomingim(od, conn, mod, frame, snac, bs);
else if (snac->subtype == 0x000a)
diff --git a/libpurple/protocols/oscar/family_icq.c b/libpurple/protocols/oscar/family_icq.c
index 3c796a299e..92008e8319 100644
--- a/libpurple/protocols/oscar/family_icq.c
+++ b/libpurple/protocols/oscar/family_icq.c
@@ -23,77 +23,104 @@
*
*/
+#include "encoding.h"
#include "oscar.h"
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-int aim_icq_reqofflinemsgs(OscarData *od)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- int bslen;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
- return -EINVAL;
-
- purple_debug_info("oscar", "Requesting offline messages\n");
-
- bslen = 2 + 4 + 2 + 2;
-
- byte_stream_new(&bs, 4 + bslen);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+#define AIM_ICQ_INFO_REQUEST 0x04b2
+#define AIM_ICQ_ALIAS_REQUEST 0x04ba
- /* For simplicity, don't bother using a tlvlist */
- byte_stream_put16(&bs, 0x0001);
- byte_stream_put16(&bs, bslen);
-
- byte_stream_putle16(&bs, bslen - 2);
- byte_stream_putuid(&bs, od);
- byte_stream_putle16(&bs, 0x003c); /* I command thee. */
- byte_stream_putle16(&bs, snacid); /* eh. */
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+static
+int compare_icq_infos(gconstpointer a, gconstpointer b)
+{
+ const struct aim_icq_info* aa = a;
+ const guint16* bb = b;
+ return aa->reqid - *bb;
+}
- byte_stream_destroy(&bs);
+static void aim_icq_freeinfo(struct aim_icq_info *info) {
+ int i;
- return 0;
+ if (!info)
+ return;
+ g_free(info->nick);
+ g_free(info->first);
+ g_free(info->last);
+ g_free(info->email);
+ g_free(info->homecity);
+ g_free(info->homestate);
+ g_free(info->homephone);
+ g_free(info->homefax);
+ g_free(info->homeaddr);
+ g_free(info->mobile);
+ g_free(info->homezip);
+ g_free(info->personalwebpage);
+ if (info->email2)
+ for (i = 0; i < info->numaddresses; i++)
+ g_free(info->email2[i]);
+ g_free(info->email2);
+ g_free(info->workcity);
+ g_free(info->workstate);
+ g_free(info->workphone);
+ g_free(info->workfax);
+ g_free(info->workaddr);
+ g_free(info->workzip);
+ g_free(info->workcompany);
+ g_free(info->workdivision);
+ g_free(info->workposition);
+ g_free(info->workwebpage);
+ g_free(info->info);
+ g_free(info->status_note_title);
+ g_free(info->auth_request_reason);
}
-int aim_icq_ackofflinemsgs(OscarData *od)
+static
+int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
{
- ByteStream bs;
- FlapFrame *frame;
- aim_snacid_t snacid;
- int bslen;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
- return -EINVAL;
-
- purple_debug_info("oscar", "Acknowledged receipt of offline messages\n");
-
- bslen = 2 + 4 + 2 + 2;
-
- byte_stream_new(&bs, 4 + bslen);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
- /* For simplicity, don't bother using a tlvlist */
- byte_stream_put16(&bs, 0x0001);
- byte_stream_put16(&bs, bslen);
-
- byte_stream_putle16(&bs, bslen - 2);
- byte_stream_putuid(&bs, od);
- byte_stream_putle16(&bs, 0x003e); /* I command thee. */
- byte_stream_putle16(&bs, snacid); /* eh. */
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
+ aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
+ guint16 *request_type;
+ GSList *original_info_ptr;
+ struct aim_icq_info *original_info;
+ guint16 reason;
+ gchar *uin;
+
+ if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
+ purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
+ g_free(original_snac);
+ return 0;
+ }
+
+ request_type = original_snac->data;
+ original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
+ original_info = original_info_ptr->data;
+
+ if (!original_info_ptr) {
+ purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
+ g_free(original_snac);
+ return 0;
+ }
+
+ reason = byte_stream_get16(bs);
+ uin = g_strdup_printf("%u", original_info->uin);
+ switch (*request_type) {
+ case AIM_ICQ_INFO_REQUEST:
+ oscar_user_info_display_error(od, reason, uin);
+ break;
+ case AIM_ICQ_ALIAS_REQUEST:
+ /* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
+ if (original_info->for_auth_request)
+ oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
+ break;
+ default:
+ purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
+ break;
+ }
- return 0;
+ aim_icq_freeinfo(original_info);
+ od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
+ g_free(original_snac->data);
+ g_free(original_snac);
+ return 1;
}
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
int
aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
@@ -130,7 +157,7 @@ aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
byte_stream_putle8(&bs, 0x00);
byte_stream_putle8(&bs, !auth_required);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
@@ -180,7 +207,7 @@ int aim_icq_changepasswd(OscarData *od, const char *passwd)
byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
byte_stream_putle8(&bs, '\0');
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
@@ -194,6 +221,7 @@ int aim_icq_getallinfo(OscarData *od, const char *uin)
aim_snacid_t snacid;
int bslen;
struct aim_icq_info *info;
+ guint16 request_type = AIM_ICQ_INFO_REQUEST;
if (!uin || uin[0] < '0' || uin[0] > '9')
return -EINVAL;
@@ -205,7 +233,7 @@ int aim_icq_getallinfo(OscarData *od, const char *uin)
byte_stream_new(&bs, 4 + bslen);
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+ snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
/* For simplicity, don't bother using a tlvlist */
byte_stream_put16(&bs, 0x0001);
@@ -215,10 +243,10 @@ int aim_icq_getallinfo(OscarData *od, const char *uin)
byte_stream_putuid(&bs, od);
byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
byte_stream_putle16(&bs, snacid); /* eh. */
- byte_stream_putle16(&bs, 0x04b2); /* shrug. */
+ byte_stream_putle16(&bs, request_type); /* shrug. */
byte_stream_putle32(&bs, atoi(uin));
- flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
+ flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
byte_stream_destroy(&bs);
@@ -226,19 +254,19 @@ int aim_icq_getallinfo(OscarData *od, const char *uin)
info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
info->reqid = snacid;
info->uin = atoi(uin);
- info->next = od->icq_info;
- od->icq_info = info;
+ od->icq_info = g_slist_prepend(od->icq_info, info);
return 0;
}
-int aim_icq_getalias(OscarData *od, const char *uin)
+int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
{
FlapConnection *conn;
ByteStream bs;
aim_snacid_t snacid;
int bslen;
struct aim_icq_info *info;
+ guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
if (!uin || uin[0] < '0' || uin[0] > '9')
return -EINVAL;
@@ -252,7 +280,7 @@ int aim_icq_getalias(OscarData *od, const char *uin)
byte_stream_new(&bs, 4 + bslen);
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
+ snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
/* For simplicity, don't bother using a tlvlist */
byte_stream_put16(&bs, 0x0001);
@@ -262,10 +290,10 @@ int aim_icq_getalias(OscarData *od, const char *uin)
byte_stream_putuid(&bs, od);
byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
byte_stream_putle16(&bs, snacid); /* eh. */
- byte_stream_putle16(&bs, 0x04ba); /* shrug. */
+ byte_stream_putle16(&bs, request_type); /* shrug. */
byte_stream_putle32(&bs, atoi(uin));
- flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
+ flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs, FALSE);
byte_stream_destroy(&bs);
@@ -273,88 +301,12 @@ int aim_icq_getalias(OscarData *od, const char *uin)
info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
info->reqid = snacid;
info->uin = atoi(uin);
- info->next = od->icq_info;
- od->icq_info = info;
-
- return 0;
-}
-
-int aim_icq_getsimpleinfo(OscarData *od, const char *uin)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- int bslen;
-
- if (!uin || uin[0] < '0' || uin[0] > '9')
- return -EINVAL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
- return -EINVAL;
-
- bslen = 2 + 4 + 2 + 2 + 2 + 4;
-
- byte_stream_new(&bs, 4 + bslen);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
- /* For simplicity, don't bother using a tlvlist */
- byte_stream_put16(&bs, 0x0001);
- byte_stream_put16(&bs, bslen);
-
- byte_stream_putle16(&bs, bslen - 2);
- byte_stream_putuid(&bs, od);
- byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
- byte_stream_putle16(&bs, snacid); /* eh. */
- byte_stream_putle16(&bs, 0x051f); /* shrug. */
- byte_stream_putle32(&bs, atoi(uin));
-
- flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-#if 0
-int aim_icq_sendxmlreq(OscarData *od, const char *xml)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- int bslen;
-
- if (!xml || !strlen(xml))
- return -EINVAL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
- return -EINVAL;
-
- bslen = 2 + 10 + 2 + strlen(xml) + 1;
-
- byte_stream_new(&bs, 4 + bslen);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
-
- /* For simplicity, don't bother using a tlvlist */
- byte_stream_put16(&bs, 0x0001);
- byte_stream_put16(&bs, bslen);
-
- byte_stream_putle16(&bs, bslen - 2);
- byte_stream_putuid(&bs, od);
- byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
- byte_stream_putle16(&bs, snacid); /* eh. */
- byte_stream_putle16(&bs, 0x0998); /* shrug. */
- byte_stream_putle16(&bs, strlen(xml) + 1);
- byte_stream_putraw(&bs, (guint8 *)xml, strlen(xml) + 1);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
+ info->for_auth_request = for_auth_request;
+ info->auth_request_reason = g_strdup(auth_request_reason);
+ od->icq_info = g_slist_prepend(od->icq_info, info);
return 0;
}
-#endif
/*
* Send an SMS message. This is the non-US way. The US-way is to IM
@@ -446,7 +398,7 @@ int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char
byte_stream_putstr(&bs, xml);
byte_stream_put8(&bs, 0x00);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
@@ -456,49 +408,35 @@ int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char
return 0;
}
-static void aim_icq_freeinfo(struct aim_icq_info *info) {
- int i;
-
- if (!info)
- return;
- g_free(info->nick);
- g_free(info->first);
- g_free(info->last);
- g_free(info->email);
- g_free(info->homecity);
- g_free(info->homestate);
- g_free(info->homephone);
- g_free(info->homefax);
- g_free(info->homeaddr);
- g_free(info->mobile);
- g_free(info->homezip);
- g_free(info->personalwebpage);
- if (info->email2)
- for (i = 0; i < info->numaddresses; i++)
- g_free(info->email2[i]);
- g_free(info->email2);
- g_free(info->workcity);
- g_free(info->workstate);
- g_free(info->workphone);
- g_free(info->workfax);
- g_free(info->workaddr);
- g_free(info->workzip);
- g_free(info->workcompany);
- g_free(info->workdivision);
- g_free(info->workposition);
- g_free(info->workwebpage);
- g_free(info->info);
- g_free(info->status_note_title);
- g_free(info);
+static int
+gotalias(OscarData *od, struct aim_icq_info *info)
+{
+ PurpleConnection *gc = od->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ gchar who[16], *utf8;
+ PurpleBuddy *b;
+
+ if (info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
+ if (info->for_auth_request) {
+ oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
+ } else {
+ g_snprintf(who, sizeof(who), "%u", info->uin);
+ serv_got_alias(gc, who, utf8);
+ if ((b = purple_find_buddy(account, who))) {
+ purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
+ }
+ g_free(utf8);
+ }
+ }
+ return 1;
}
/**
* Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
*/
static int
-icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
+icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
{
- int ret = 0;
GSList *tlvlist;
aim_tlv_t *datatlv;
ByteStream qbs;
@@ -520,53 +458,23 @@ icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
- if (cmd == 0x0041) { /* offline message */
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
- struct aim_icq_offlinemsg msg;
- aim_rxcallback_t userfunc;
-
- memset(&msg, 0, sizeof(msg));
-
- msg.sender = byte_stream_getle32(&qbs);
- msg.year = byte_stream_getle16(&qbs);
- msg.month = byte_stream_getle8(&qbs);
- msg.day = byte_stream_getle8(&qbs);
- msg.hour = byte_stream_getle8(&qbs);
- msg.minute = byte_stream_getle8(&qbs);
- msg.type = byte_stream_getle8(&qbs);
- msg.flags = byte_stream_getle8(&qbs);
- msg.msglen = byte_stream_getle16(&qbs);
- msg.msg = byte_stream_getstr(&qbs, msg.msglen);
-
- if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG)))
- ret = userfunc(od, conn, frame, &msg);
-
- g_free(msg.msg);
-
- } else if (cmd == 0x0042) {
- aim_rxcallback_t userfunc;
-
- if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE)))
- ret = userfunc(od, conn, frame);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-
- } else if (cmd == 0x07da) { /* information */
+ if (cmd == 0x07da) { /* information */
guint16 subtype;
+ GSList *info_ptr;
struct aim_icq_info *info;
- aim_rxcallback_t userfunc;
subtype = byte_stream_getle16(&qbs);
byte_stream_advance(&qbs, 1); /* 0x0a */
/* find other data from the same request */
- for (info = od->icq_info; info && (info->reqid != reqid); info = info->next);
- if (!info) {
- info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
- info->reqid = reqid;
- info->next = od->icq_info;
- od->icq_info = info;
+ info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
+ if (!info_ptr) {
+ struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
+ new_info->reqid = reqid;
+ info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
}
+ info = info_ptr->data;
switch (subtype) {
case 0x00a0: { /* hide ip status */
/* nothing */
@@ -818,10 +726,9 @@ icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
memcpy(&info->icbm_cookie, cookie, 8);
- info->next = od->icq_info;
- od->icq_info = info;
+ od->icq_info = g_slist_prepend(od->icq_info, info);
- flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE);
+ flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, snacid, &bs, FALSE);
byte_stream_destroy(&bs);
}
@@ -834,35 +741,28 @@ icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
if (!(snac->flags & 0x0001)) {
if (subtype != 0x0104)
- if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO)))
- ret = userfunc(od, conn, frame, info);
+ oscar_user_info_display_icq(od, info);
if (info->uin && info->nick)
- if ((userfunc = aim_callhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS)))
- ret = userfunc(od, conn, frame, info);
-
- if (od->icq_info == info) {
- od->icq_info = info->next;
- } else {
- struct aim_icq_info *cur;
- for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
- if (cur->next)
- cur->next = cur->next->next;
- }
+ gotalias(od, info);
+
aim_icq_freeinfo(info);
+ od->icq_info = g_slist_remove(od->icq_info, info);
}
}
aim_tlvlist_free(tlvlist);
- return ret;
+ return 1;
}
static int
snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- if (snac->subtype == 0x0003)
- return icqresponse(od, conn, mod, frame, snac, bs);
+ if (snac->subtype == 0x0001)
+ return error(od, snac, bs);
+ else if (snac->subtype == 0x0003)
+ return icqresponse(od, snac, bs);
return 0;
}
@@ -870,15 +770,10 @@ snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
static void
icq_shutdown(OscarData *od, aim_module_t *mod)
{
- struct aim_icq_info *del;
-
- while (od->icq_info) {
- del = od->icq_info;
- od->icq_info = od->icq_info->next;
- aim_icq_freeinfo(del);
- }
-
- return;
+ GSList *cur;
+ for (cur = od->icq_info; cur; cur = cur->next)
+ aim_icq_freeinfo(cur->data);
+ g_slist_free(od->icq_info);
}
int
diff --git a/libpurple/protocols/oscar/family_invite.c b/libpurple/protocols/oscar/family_invite.c
deleted file mode 100644
index bd9cbd25fb..0000000000
--- a/libpurple/protocols/oscar/family_invite.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-*/
-
-/*
- * Family 0x0006 - This isn't really ever used by anyone anymore.
- *
- * Once upon a time, there used to be a menu item in AIM clients that
- * said something like "Invite a friend to use AIM..." and then it would
- * ask for an email address and it would sent a mail to them saying
- * how perfectly wonderful the AIM service is and why you should use it
- * and click here if you hate the person who sent this to you and want to
- * complain and yell at them in a small box with pretty fonts.
- *
- * I could've sworn libfaim had this implemented once, a long long time ago,
- * but I can't find it.
- *
- * I'm mainly adding this so that I can keep advertising that we support
- * group 6, even though we don't.
- *
- */
-
-#include "oscar.h"
-
-int invite_modfirst(OscarData *od, aim_module_t *mod)
-{
-
- mod->family = SNAC_FAMILY_INVITE;
- mod->version = 0x0001;
- mod->toolid = 0x0110;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "invite", sizeof(mod->name));
- mod->snachandler = NULL;
-
- return 0;
-}
diff --git a/libpurple/protocols/oscar/family_locate.c b/libpurple/protocols/oscar/family_locate.c
index eebf72c96c..8296aaca59 100644
--- a/libpurple/protocols/oscar/family_locate.c
+++ b/libpurple/protocols/oscar/family_locate.c
@@ -245,6 +245,10 @@ static const struct {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {OSCAR_CAPABILITY_HTML_MSGS,
+ {0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a, 0x49, 0x15,
+ 0x88, 0xf2, 0x13, 0xfc, 0x00, 0x97, 0x9e, 0xa8}},
+
{OSCAR_CAPABILITY_LAST,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@@ -583,7 +587,7 @@ aim_locate_getcaps(OscarData *od, ByteStream *bs, int len)
guint64 flags = 0;
int offset;
- for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
+ for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
guint8 *cap;
int i, identified;
@@ -617,7 +621,7 @@ aim_receive_custom_icon(OscarData *od, ByteStream *bs, int len)
int offset;
const char *result = NULL;
- for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x10) {
+ for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x10) {
/* check wheather this capability is a custom user icon */
guint8 *cap;
int i;
@@ -643,7 +647,7 @@ aim_locate_getcaps_short(OscarData *od, ByteStream *bs, int len)
guint64 flags = 0;
int offset;
- for (offset = 0; byte_stream_empty(bs) && (offset < len); offset += 0x02) {
+ for (offset = 0; byte_stream_bytes_left(bs) && (offset < len); offset += 0x02) {
guint8 *cap;
int i, identified;
@@ -674,16 +678,13 @@ byte_stream_putcaps(ByteStream *bs, guint64 caps)
if (!bs)
return -EINVAL;
- for (i = 0; byte_stream_empty(bs); i++) {
-
+ for (i = 0; byte_stream_bytes_left(bs); i++) {
if (aim_caps[i].flag == OSCAR_CAPABILITY_LAST)
break;
if (caps & aim_caps[i].flag)
byte_stream_putraw(bs, aim_caps[i].data, 0x10);
-
}
-
return 0;
}
@@ -804,7 +805,7 @@ aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
type = byte_stream_get16(bs);
length = byte_stream_get16(bs);
curpos = byte_stream_curpos(bs);
- endpos = curpos + MIN(length, byte_stream_empty(bs));
+ endpos = curpos + MIN(length, byte_stream_bytes_left(bs));
if (type == 0x0001) {
/*
@@ -1010,7 +1011,7 @@ aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
number2 = byte_stream_get8(bs);
length2 = byte_stream_get8(bs);
- endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_empty(bs));
+ endpos2 = byte_stream_curpos(bs) + MIN(length2, byte_stream_bytes_left(bs));
switch (type2) {
case 0x0000: { /* This is an official buddy icon? */
@@ -1165,73 +1166,18 @@ aim_info_extract(OscarData *od, ByteStream *bs, aim_userinfo_t *outinfo)
return 0;
}
-/* Apparently, this is never called.
- * If you activate it, figure out a way to know what mood to pass to
- * aim_tlvlist_add_caps() below. --rlaager */
-#if 0
-/*
- * Inverse of aim_info_extract()
- */
-int
-aim_putuserinfo(ByteStream *bs, aim_userinfo_t *info)
-{
- GSList *tlvlist = NULL;
-
- if (!bs || !info)
- return -EINVAL;
-
- byte_stream_put8(bs, strlen(info->bn));
- byte_stream_putstr(bs, info->bn);
-
- byte_stream_put16(bs, info->warnlevel);
-
- if (info->present & AIM_USERINFO_PRESENT_FLAGS)
- aim_tlvlist_add_16(&tlvlist, 0x0001, info->flags);
- if (info->present & AIM_USERINFO_PRESENT_MEMBERSINCE)
- aim_tlvlist_add_32(&tlvlist, 0x0002, info->membersince);
- if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
- aim_tlvlist_add_32(&tlvlist, 0x0003, info->onlinesince);
- if (info->present & AIM_USERINFO_PRESENT_IDLE)
- aim_tlvlist_add_16(&tlvlist, 0x0004, info->idletime);
-
-/* XXX - So, ICQ_OSCAR_SUPPORT is never defined anywhere... */
-#ifdef ICQ_OSCAR_SUPPORT
- if (atoi(info->bn) != 0) {
- if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS)
- aim_tlvlist_add_16(&tlvlist, 0x0006, info->icqinfo.status);
- if (info->present & AIM_USERINFO_PRESENT_ICQIPADDR)
- aim_tlvlist_add_32(&tlvlist, 0x000a, info->icqinfo.ipaddr);
- }
-#endif
-
- if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES) {
- aim_tlvlist_add_caps(&tlvlist, 0x000d, info->capabilities, NULL);
- }
-
- if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
- aim_tlvlist_add_32(&tlvlist, (guint16)((info->flags & AIM_FLAG_AOL) ? 0x0010 : 0x000f), info->sessionlen);
-
- byte_stream_put16(bs, aim_tlvlist_count(tlvlist));
- aim_tlvlist_write(bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- return 0;
-}
-#endif
-
/*
* Subtype 0x0001
*/
static int
error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- int ret = 0;
- aim_rxcallback_t userfunc;
aim_snac_t *snac2;
guint16 reason;
char *bn;
- if (!(snac2 = aim_remsnac(od, snac->id))) {
+ snac2 = aim_remsnac(od, snac->id);
+ if (!snac2) {
purple_debug_misc("oscar", "locate error: received response from unknown request!\n");
return 0;
}
@@ -1243,7 +1189,8 @@ error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
return 0;
}
- if (!(bn = snac2->data)) {
+ bn = snac2->data;
+ if (!bn) {
purple_debug_misc("oscar", "locate error: received response from request without a buddy name!\n");
g_free(snac2);
return 0;
@@ -1251,15 +1198,12 @@ error(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame,
reason = byte_stream_get16(bs);
- /* Notify the user that we do not have info for this buddy */
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, reason, bn);
+ oscar_user_info_display_error(od, reason, bn);
- if (snac2)
- g_free(snac2->data);
+ g_free(snac2->data);
g_free(snac2);
- return ret;
+ return 1;
}
/*
@@ -1389,7 +1333,7 @@ aim_locate_setprofile(OscarData *od,
aim_tlvlist_write(&bs, &tlvlist);
aim_tlvlist_free(tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1423,41 +1367,7 @@ aim_locate_setcaps(OscarData *od, guint64 caps)
aim_tlvlist_write(&bs, &tlvlist);
aim_tlvlist_free(tlvlist);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * Subtype 0x0005 - Request info of another AIM user.
- *
- * @param bn The buddy name whose info you wish to request.
- * @param infotype The type of info you wish to request.
- * 0x0001 - Info/profile
- * 0x0003 - Away message
- * 0x0004 - Capabilities
- */
-int
-aim_locate_getinfo(OscarData *od, const char *bn, guint16 infotype)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
- return -EINVAL;
-
- byte_stream_new(&bs, 2+1+strlen(bn));
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, NULL, 0);
-
- byte_stream_put16(&bs, infotype);
- byte_stream_put8(&bs, strlen(bn));
- byte_stream_putstr(&bs, bn);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0005, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1469,7 +1379,6 @@ static int
userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
int ret = 0;
- aim_rxcallback_t userfunc;
aim_userinfo_t *userinfo, *userinfo2;
GSList *tlvlist;
aim_tlv_t *tlv = NULL;
@@ -1521,140 +1430,12 @@ userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fram
g_free(userinfo);
/* Show the info to the user */
- if (userinfo2 != NULL && ((userfunc = aim_callhandler(od, snac->family, snac->subtype))))
- ret = userfunc(od, conn, frame, userinfo2);
+ oscar_user_info_display_aim(od, userinfo2);
return ret;
}
/*
- * Subtype 0x0009 - Set directory profile data.
- *
- * This is not the same as aim_location_setprofile!
- * privacy: 1 to allow searching, 0 to disallow.
- *
- */
-int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tlvlist = NULL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
- return -EINVAL;
-
- aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);
-
- if (first)
- aim_tlvlist_add_str(&tlvlist, 0x0001, first);
- if (last)
- aim_tlvlist_add_str(&tlvlist, 0x0002, last);
- if (middle)
- aim_tlvlist_add_str(&tlvlist, 0x0003, middle);
- if (maiden)
- aim_tlvlist_add_str(&tlvlist, 0x0004, maiden);
-
- if (state)
- aim_tlvlist_add_str(&tlvlist, 0x0007, state);
- if (city)
- aim_tlvlist_add_str(&tlvlist, 0x0008, city);
-
- if (nickname)
- aim_tlvlist_add_str(&tlvlist, 0x000c, nickname);
- if (zip)
- aim_tlvlist_add_str(&tlvlist, 0x000d, zip);
-
- if (street)
- aim_tlvlist_add_str(&tlvlist, 0x0021, street);
-
- byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, NULL, 0);
-
- aim_tlvlist_write(&bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x0009, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * Subtype 0x000b - Huh? What is this?
- */
-int aim_locate_000b(OscarData *od, const char *bn)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
-
- return -EINVAL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !bn)
- return -EINVAL;
-
- byte_stream_new(&bs, 1+strlen(bn));
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, NULL, 0);
-
- byte_stream_put8(&bs, strlen(bn));
- byte_stream_putstr(&bs, bn);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000b, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-/*
- * Subtype 0x000f
- *
- * XXX pass these in better
- *
- */
-int
-aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tlvlist = NULL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)))
- return -EINVAL;
-
- /* ?? privacy ?? */
- aim_tlvlist_add_16(&tlvlist, 0x000a, privacy);
-
- if (interest1)
- aim_tlvlist_add_str(&tlvlist, 0x0000b, interest1);
- if (interest2)
- aim_tlvlist_add_str(&tlvlist, 0x0000b, interest2);
- if (interest3)
- aim_tlvlist_add_str(&tlvlist, 0x0000b, interest3);
- if (interest4)
- aim_tlvlist_add_str(&tlvlist, 0x0000b, interest4);
- if (interest5)
- aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5);
-
- byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, NULL, 0);
-
- aim_tlvlist_write(&bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- flap_connection_send_snac(od, conn, SNAC_FAMILY_LOCATE, 0x000f, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
- return 0;
-}
-
-/*
* Subtype 0x0015 - Request the info of a user using the short method. This is
* what iChat uses. It normally is VERY leniently rate limited.
*
@@ -1682,7 +1463,7 @@ aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags)
byte_stream_putstr(&bs, bn);
snacid = aim_cachesnac(od, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, bn, strlen(bn)+1);
- flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, 0x0000, snacid, &bs, FALSE);
+ flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_LOCATE, 0x0015, snacid, &bs, FALSE);
byte_stream_destroy(&bs);
@@ -1730,15 +1511,6 @@ locate_modfirst(OscarData *od, aim_module_t *mod)
return 0;
}
-#if 0 //rlaager
-const char* aim_get_custom_icon_mood(gint32 no)
-{
- if (no >= G_N_ELEMENTS(aim_custom_icons) || no < 1)
- return NULL;
- return aim_custom_icons[no].mood.mood;
-}
-#endif
-
const char*
icq_get_custom_icon_description(const char *mood)
{
diff --git a/libpurple/protocols/oscar/family_odir.c b/libpurple/protocols/oscar/family_odir.c
deleted file mode 100644
index be1638fb39..0000000000
--- a/libpurple/protocols/oscar/family_odir.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Purple's oscar protocol plugin
- * This file is the legal property of its developers.
- * Please see the AUTHORS file distributed alongside this file.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-*/
-
-/*
- * Family 0x000f - Newer Search Method
- *
- * Used for searching for other AIM users by email address, name,
- * location, commmon interests, and a few other similar things.
- *
- */
-
-#include "oscar.h"
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * Search for an AIM buddy based on their email address.
- *
- * @param od The oscar session.
- * @param region Should be "us-ascii" unless you know what you're doing.
- * @param email The email address you want to search for.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_email(OscarData *od, const char *region, const char *email)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tlvlist = NULL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region || !email)
- return -EINVAL;
-
- /* Create a TLV chain, write it to the outgoing frame, then free the chain */
- aim_tlvlist_add_str(&tlvlist, 0x001c, region);
- aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */
- aim_tlvlist_add_str(&tlvlist, 0x0005, email);
-
- byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
- aim_tlvlist_write(&bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * Search for an AIM buddy based on various info
- * about the person.
- *
- * @param od The oscar session.
- * @param region Should be "us-ascii" unless you know what you're doing.
- * @param first The first name of the person you want to search for.
- * @param middle The middle name of the person you want to search for.
- * @param last The last name of the person you want to search for.
- * @param maiden The maiden name of the person you want to search for.
- * @param nick The nick name of the person you want to search for.
- * @param city The city where the person you want to search for resides.
- * @param state The state where the person you want to search for resides.
- * @param country The country where the person you want to search for resides.
- * @param zip The zip code where the person you want to search for resides.
- * @param address The street address where the person you want to seach for resides.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_name(OscarData *od, const char *region, const char *first, const char *middle, const char *last, const char *maiden, const char *nick, const char *city, const char *state, const char *country, const char *zip, const char *address)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tlvlist = NULL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region)
- return -EINVAL;
-
- /* Create a TLV chain, write it to the outgoing frame, then free the chain */
- aim_tlvlist_add_str(&tlvlist, 0x001c, region);
- aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0000); /* Type of search */
- if (first)
- aim_tlvlist_add_str(&tlvlist, 0x0001, first);
- if (last)
- aim_tlvlist_add_str(&tlvlist, 0x0002, last);
- if (middle)
- aim_tlvlist_add_str(&tlvlist, 0x0003, middle);
- if (maiden)
- aim_tlvlist_add_str(&tlvlist, 0x0004, maiden);
- if (country)
- aim_tlvlist_add_str(&tlvlist, 0x0006, country);
- if (state)
- aim_tlvlist_add_str(&tlvlist, 0x0007, state);
- if (city)
- aim_tlvlist_add_str(&tlvlist, 0x0008, city);
- if (nick)
- aim_tlvlist_add_str(&tlvlist, 0x000c, nick);
- if (zip)
- aim_tlvlist_add_str(&tlvlist, 0x000d, zip);
- if (address)
- aim_tlvlist_add_str(&tlvlist, 0x0021, address);
-
- byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
- aim_tlvlist_write(&bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-
-/**
- * Subtype 0x0002 - Submit a User Search Request
- *
- * @param od The oscar session.
- * @param interest1 An interest you want to search for.
- * @return Return 0 if no errors, otherwise return the error number.
- */
-int aim_odir_interest(OscarData *od, const char *region, const char *interest)
-{
- FlapConnection *conn;
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tlvlist = NULL;
-
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ODIR)) || !region)
- return -EINVAL;
-
- /* Create a TLV chain, write it to the outgoing frame, then free the chain */
- aim_tlvlist_add_str(&tlvlist, 0x001c, region);
- aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */
- if (interest)
- aim_tlvlist_add_str(&tlvlist, 0x0001, interest);
-
- byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
-
- aim_tlvlist_write(&bs, &tlvlist);
- aim_tlvlist_free(tlvlist);
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_ODIR, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_ODIR, 0x0002, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-
- return 0;
-}
-
-
-/**
- * Subtype 0x0003 - Receive Reply From a User Search
- *
- */
-static int parseresults(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
- int ret = 0;
- aim_rxcallback_t userfunc;
- guint16 tmp, numresults;
- struct aim_odir *results = NULL;
-
- tmp = byte_stream_get16(bs); /* Unknown */
- tmp = byte_stream_get16(bs); /* Unknown */
- byte_stream_advance(bs, tmp);
-
- numresults = byte_stream_get16(bs); /* Number of results to follow */
-
- /* Allocate a linked list, 1 node per result */
- while (numresults) {
- struct aim_odir *new;
- GSList *tlvlist = aim_tlvlist_readnum(bs, byte_stream_get16(bs));
- new = (struct aim_odir *)g_malloc(sizeof(struct aim_odir));
- new->first = aim_tlv_getstr(tlvlist, 0x0001, 1);
- new->last = aim_tlv_getstr(tlvlist, 0x0002, 1);
- new->middle = aim_tlv_getstr(tlvlist, 0x0003, 1);
- new->maiden = aim_tlv_getstr(tlvlist, 0x0004, 1);
- new->email = aim_tlv_getstr(tlvlist, 0x0005, 1);
- new->country = aim_tlv_getstr(tlvlist, 0x0006, 1);
- new->state = aim_tlv_getstr(tlvlist, 0x0007, 1);
- new->city = aim_tlv_getstr(tlvlist, 0x0008, 1);
- new->bn = aim_tlv_getstr(tlvlist, 0x0009, 1);
- new->interest = aim_tlv_getstr(tlvlist, 0x000b, 1);
- new->nick = aim_tlv_getstr(tlvlist, 0x000c, 1);
- new->zip = aim_tlv_getstr(tlvlist, 0x000d, 1);
- new->region = aim_tlv_getstr(tlvlist, 0x001c, 1);
- new->address = aim_tlv_getstr(tlvlist, 0x0021, 1);
- new->next = results;
- results = new;
- numresults--;
- }
-
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
- ret = userfunc(od, conn, frame, results);
-
- /* Now free everything from above */
- while (results) {
- struct aim_odir *del = results;
- results = results->next;
- g_free(del->first);
- g_free(del->last);
- g_free(del->middle);
- g_free(del->maiden);
- g_free(del->email);
- g_free(del->country);
- g_free(del->state);
- g_free(del->city);
- g_free(del->bn);
- g_free(del->interest);
- g_free(del->nick);
- g_free(del->zip);
- g_free(del->region);
- g_free(del->address);
- g_free(del);
- }
-
- return ret;
-}
-
-static int
-snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
-{
- if (snac->subtype == 0x0003)
- return parseresults(od, conn, mod, frame, snac, bs);
-
- return 0;
-}
-
-int
-odir_modfirst(OscarData *od, aim_module_t *mod)
-{
- mod->family = SNAC_FAMILY_ODIR;
- mod->version = 0x0001;
- mod->toolid = 0x0010;
- mod->toolversion = 0x0629;
- mod->flags = 0;
- strncpy(mod->name, "odir", sizeof(mod->name));
- mod->snachandler = snachandler;
-
- return 0;
-}
diff --git a/libpurple/protocols/oscar/family_oservice.c b/libpurple/protocols/oscar/family_oservice.c
index 9b554aab0e..b566642289 100644
--- a/libpurple/protocols/oscar/family_oservice.c
+++ b/libpurple/protocols/oscar/family_oservice.c
@@ -73,7 +73,7 @@ aim_srv_clientready(OscarData *od, FlapConnection *conn)
}
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -97,7 +97,7 @@ hostonline(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fr
{
int group;
- while (byte_stream_empty(bs))
+ while (byte_stream_bytes_left(bs))
{
group = byte_stream_get16(bs);
conn->groups = g_slist_prepend(conn->groups, GUINT_TO_POINTER(group));
@@ -141,7 +141,7 @@ aim_srv_requestnew(OscarData *od, guint16 serviceid)
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -187,7 +187,7 @@ aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 ins
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, &csi, sizeof(csi));
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0004, snacid, &bs);
byte_stream_destroy(&bs);
@@ -444,30 +444,7 @@ aim_srv_rates_addparam(OscarData *od, FlapConnection *conn)
}
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-}
-
-/* Subtype 0x0009 - Delete Rate Parameter */
-void
-aim_srv_rates_delparam(OscarData *od, FlapConnection *conn)
-{
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *tmp;
-
- byte_stream_new(&bs, 502);
-
- for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next)
- {
- struct rateclass *rateclass;
- rateclass = tmp->data;
- byte_stream_put16(&bs, rateclass->classid);
- }
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0009, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0008, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -558,40 +535,6 @@ serverpause(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *f
return ret;
}
-/*
- * Subtype 0x000c - Service Pause Acknowledgement
- *
- * It is rather important that aim_srv_sendpauseack() gets called for the exact
- * same connection that the Server Pause callback was called for, since
- * libfaim extracts the data for the SNAC from the connection structure.
- *
- * Of course, if you don't do that, more bad things happen than just what
- * libfaim can cause.
- *
- */
-void
-aim_srv_sendpauseack(OscarData *od, FlapConnection *conn)
-{
- ByteStream bs;
- aim_snacid_t snacid;
- GSList *cur;
-
- byte_stream_new(&bs, 1014);
-
- /*
- * This list should have all the groups that the original
- * Host Online / Server Ready said this host supports. And
- * we want them all back after the migration.
- */
- for (cur = conn->groups; cur != NULL; cur = cur->next)
- byte_stream_put16(&bs, GPOINTER_TO_UINT(cur->data));
-
- snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x000c, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-}
-
/* Subtype 0x000d - Service Resume */
static int
serverresume(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
@@ -643,7 +586,7 @@ evilnotify(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fr
newevil = byte_stream_get16(bs);
- if (byte_stream_empty(bs))
+ if (byte_stream_bytes_left(bs))
aim_info_extract(od, bs, &userinfo);
if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
@@ -770,36 +713,6 @@ motd(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, a
}
/*
- * Subtype 0x0014 - Set privacy flags
- *
- * Normally 0x03.
- *
- * Bit 1: Allows other AIM users to see how long you've been idle.
- * Bit 2: Allows other AIM users to see how long you've been a member.
- *
- */
-void
-aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32 flags)
-{
- aim_genericreq_l(od, conn, SNAC_FAMILY_OSERVICE, 0x0014, &flags);
-}
-
-/*
- * Subtype 0x0016 - No-op
- *
- * WinAIM sends these every 4min or so to keep the connection alive. Its not
- * really necessary.
- *
- * Wha? No? Since when? I think WinAIM sends an empty channel 5
- * FLAP as a no-op...
- */
-void
-aim_srv_nop(OscarData *od, FlapConnection *conn)
-{
- aim_genericreq_n(od, conn, SNAC_FAMILY_OSERVICE, 0x0016);
-}
-
-/*
* Subtype 0x0017 - Set client versions
*
* If you've seen the clientonline/clientready SNAC you're probably
@@ -837,7 +750,7 @@ aim_srv_setversions(OscarData *od, FlapConnection *conn)
}
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0017, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -850,8 +763,8 @@ hostversions(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *
guint8 *versions;
/* This is frivolous. (Thank you SmarterChild.) */
- vercount = byte_stream_empty(bs)/4;
- versions = byte_stream_getraw(bs, byte_stream_empty(bs));
+ vercount = byte_stream_bytes_left(bs)/4;
+ versions = byte_stream_getraw(bs, byte_stream_bytes_left(bs));
g_free(versions);
/*
@@ -899,16 +812,6 @@ aim_srv_setextrainfo(OscarData *od,
AIM_ICQ_STATE_HIDEIP | AIM_ICQ_STATE_DIRECTREQUIREAUTH);
}
-#if 0
- if (other_stuff_that_isnt_implemented)
- {
- aim_tlvlist_add_raw(&tlvlist, 0x000c, 0x0025,
- chunk_of_x25_bytes_with_ip_address_etc);
- aim_tlvlist_add_raw(&tlvlist, 0x0011, 0x0005, unknown 0x01 61 10 f6 41);
- aim_tlvlist_add_16(&tlvlist, 0x0012, unknown 0x00 00);
- }
-#endif
-
if (setstatusmsg)
{
size_t statusmsglen, itmsurllen;
@@ -932,13 +835,57 @@ aim_srv_setextrainfo(OscarData *od,
aim_tlvlist_free(tlvlist);
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs);
byte_stream_destroy(&bs);
return 0;
}
+/* Send dummy DC (direct connect) information to the server.
+ * Direct connect is ICQ's counterpart for AIM's DirectIM,
+ * as far as I can tell. Anyway, we don't support it;
+ * the reason to send this packet is that some clients
+ * (Miranda, QIP) won't send us channel 2 ICBM messages
+ * unless we specify DC version >= 8.
+ *
+ * See #12044 for more information.
+ */
+void
+aim_srv_set_dc_info(OscarData *od)
+{
+ ByteStream bs, tlv0c;
+ aim_snacid_t snacid;
+ GSList *tlvlist = NULL;
+
+ /* http://iserverd.khstu.ru/oscar/snac_01_1e.html has a nice analysis of what goes in 0xc tlv.
+ * Kopete sends a dummy DC info, too, so I just copied the values from them.
+ */
+ byte_stream_new(&tlv0c, 4*2 + 1 + 2 + 4*6 + 2);
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put8(&tlv0c, 0x0); /* We don't support DC */
+ byte_stream_put16(&tlv0c, 8); /* DC version */
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put32(&tlv0c, 0x50);
+ byte_stream_put32(&tlv0c, 0x3);
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put32(&tlv0c, 0x0);
+ byte_stream_put16(&tlv0c, 0x0);
+ aim_tlvlist_add_raw(&tlvlist, 0x000c, byte_stream_curpos(&tlv0c), tlv0c.data);
+ byte_stream_destroy(&tlv0c);
+
+ byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
+ aim_tlvlist_write(&bs, &tlvlist);
+ aim_tlvlist_free(tlvlist);
+
+ snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x001e, 0x0000, NULL, 0);
+ flap_connection_send_snac(od, flap_connection_findbygroup(od, SNAC_FAMILY_ICBM), SNAC_FAMILY_OSERVICE, 0x001e, snacid, &bs);
+
+ byte_stream_destroy(&bs);
+}
+
/**
* Starting this past week (26 Mar 2001, say), AOL has started sending
* this nice little extra SNAC. AFAIK, it has never been used until now.
@@ -1077,7 +1024,7 @@ aim_sendmemblock(OscarData *od, FlapConnection *conn, guint32 offset, guint32 le
}
snacid = aim_cachesnac(od, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_OSERVICE, 0x0020, snacid, &bs);
byte_stream_destroy(&bs);
@@ -1094,8 +1041,6 @@ aim_sendmemblock(OscarData *od, FlapConnection *conn, guint32 offset, guint32 le
static int
aim_parse_extstatus(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
- int ret = 0;
- aim_rxcallback_t userfunc;
guint16 type;
guint8 flags, length;
@@ -1108,25 +1053,54 @@ aim_parse_extstatus(OscarData *od, FlapConnection *conn, aim_module_t *mod, Flap
* A flag of 0x40 could mean "I don't have your icon, upload it"
*/
- if ((userfunc = aim_callhandler(od, snac->family, snac->subtype))) {
- switch (type) {
+ switch (type) {
case 0x0000:
case 0x0001: { /* buddy icon checksum */
/* not sure what the difference between 1 and 0 is */
guint8 *md5 = byte_stream_getraw(bs, length);
- ret = userfunc(od, conn, frame, type, flags, length, md5);
+
+ if ((flags == 0x00) || (flags == 0x41)) {
+ if (!flap_connection_getbytype(od, SNAC_FAMILY_BART) && !od->iconconnecting) {
+ od->iconconnecting = TRUE;
+ od->set_icon = TRUE;
+ aim_srv_requestnew(od, SNAC_FAMILY_BART);
+ } else {
+ PurpleAccount *account = purple_connection_get_account(od->gc);
+ PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
+ if (img == NULL) {
+ aim_ssi_delicon(od);
+ } else {
+
+ purple_debug_info("oscar",
+ "Uploading icon to icon server\n");
+ aim_bart_upload(od, purple_imgstore_get_data(img),
+ purple_imgstore_get_size(img));
+ purple_imgstore_unref(img);
+ }
+ }
+ } else if (flags == 0x81) {
+ PurpleAccount *account = purple_connection_get_account(od->gc);
+ PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
+ if (img == NULL)
+ aim_ssi_delicon(od);
+ else {
+ aim_ssi_seticon(od, md5, length);
+ purple_imgstore_unref(img);
+ }
+ }
+
g_free(md5);
- } break;
- case 0x0002: { /* available message */
+ } break;
+
+ case 0x0002: {
+ /* We just set an available message? */
/* there is a second length that is just for the message */
char *msg = byte_stream_getstr(bs, byte_stream_get16(bs));
- ret = userfunc(od, conn, frame, msg);
g_free(msg);
- } break;
- }
+ } break;
}
- return ret;
+ return 0;
}
static int
diff --git a/libpurple/protocols/oscar/family_userlookup.c b/libpurple/protocols/oscar/family_userlookup.c
index 9f766c142d..056e43d4e4 100644
--- a/libpurple/protocols/oscar/family_userlookup.c
+++ b/libpurple/protocols/oscar/family_userlookup.c
@@ -75,7 +75,7 @@ int aim_search_address(OscarData *od, const char *address)
byte_stream_putstr(&bs, address);
snacid = aim_cachesnac(od, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, address, strlen(address)+1);
- flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, SNAC_FAMILY_USERLOOKUP, 0x0002, snacid, &bs);
byte_stream_destroy(&bs);
diff --git a/libpurple/protocols/oscar/flap_connection.c b/libpurple/protocols/oscar/flap_connection.c
index 3255e0f37a..8b4dc621d4 100644
--- a/libpurple/protocols/oscar/flap_connection.c
+++ b/libpurple/protocols/oscar/flap_connection.c
@@ -212,7 +212,7 @@ static gboolean flap_connection_send_queued(gpointer data)
* only if all high priority SNACs have been sent.
*/
void
-flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
+flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
{
FlapFrame *frame;
guint32 length;
@@ -222,7 +222,7 @@ flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, gui
length = data != NULL ? data->offset : 0;
frame = flap_frame_new(od, 0x02, 10 + length);
- aim_putsnac(&frame->data, family, subtype, flags, snacid);
+ aim_putsnac(&frame->data, family, subtype, snacid);
if (length > 0)
{
@@ -284,9 +284,9 @@ flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, gui
}
void
-flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data)
+flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data)
{
- flap_connection_send_snac_with_priority(od, conn, family, subtype, flags, snacid, data, TRUE);
+ flap_connection_send_snac_with_priority(od, conn, family, subtype, snacid, data, TRUE);
}
/**
@@ -733,7 +733,7 @@ parse_snac(OscarData *od, FlapConnection *conn, FlapFrame *frame)
aim_module_t *cur;
aim_modsnac_t snac;
- if (byte_stream_empty(&frame->data) < 10)
+ if (byte_stream_bytes_left(&frame->data) < 10)
return;
snac.family = byte_stream_get16(&frame->data);
@@ -800,7 +800,7 @@ parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame)
GSList *tlvlist;
char *msg = NULL;
- if (byte_stream_empty(&frame->data) == 0) {
+ if (byte_stream_bytes_left(&frame->data) == 0) {
/* XXX should do something with this */
return;
}
@@ -931,18 +931,6 @@ flap_connection_recv(FlapConnection *conn)
break;
}
- /* Verify the sequence number sent by the server. */
-#if 0
- /* TODO: Need to initialize conn->seqnum_in somewhere before we can use this. */
- if (aimutil_get16(&conn->header[1]) != conn->seqnum_in++)
- {
- /* Received an out-of-order FLAP! */
- flap_connection_schedule_destroy(conn,
- OSCAR_DISCONNECT_INVALID_DATA, NULL);
- break;
- }
-#endif
-
/* Initialize a new temporary FlapFrame for incoming data */
conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]);
conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]);
@@ -1074,8 +1062,8 @@ flap_connection_send_byte_stream(ByteStream *bs, FlapConnection *conn, size_t co
return;
/* Make sure we don't send past the end of the bs */
- if (count > byte_stream_empty(bs))
- count = byte_stream_empty(bs); /* truncate to remaining space */
+ if (count > byte_stream_bytes_left(bs))
+ count = byte_stream_bytes_left(bs); /* truncate to remaining space */
if (count == 0)
return;
diff --git a/libpurple/protocols/oscar/libaim.c b/libpurple/protocols/oscar/libaim.c
index 5345b25d63..3862930728 100644
--- a/libpurple/protocols/oscar/libaim.c
+++ b/libpurple/protocols/oscar/libaim.c
@@ -20,11 +20,12 @@
*
*/
-/* libaim is the AIM protocol plugin. It is linked against liboscarcommon,
+/* libaim is the AIM protocol plugin. It is linked against liboscar,
* which contains all the shared implementation code with libicq
*/
#include "oscarcommon.h"
+#include "oscar.h"
static PurplePluginProtocolInfo prpl_info =
{
@@ -57,7 +58,7 @@ static PurplePluginProtocolInfo prpl_info =
oscar_add_deny, /* add_deny */
oscar_rem_permit, /* rem_permit */
oscar_rem_deny, /* rem_deny */
- oscar_set_permit_deny, /* set_permit_deny */
+ oscar_set_aim_permdeny, /* set_permit_deny */
oscar_join_chat, /* join_chat */
NULL, /* reject_chat */
oscar_get_chat_name, /* get_chat_name */
@@ -97,7 +98,9 @@ static PurplePluginProtocolInfo prpl_info =
NULL, /* get_account_text_table */
NULL, /* initiate_media */
NULL, /* get_media_caps */
- NULL /* get_moods */
+ NULL, /* get_moods */
+ NULL, /* set_public_alias */
+ NULL /* get_public_alias */
};
static PurplePluginInfo info =
diff --git a/libpurple/protocols/oscar/libicq.c b/libpurple/protocols/oscar/libicq.c
index 2972466075..f7bfecaa79 100644
--- a/libpurple/protocols/oscar/libicq.c
+++ b/libpurple/protocols/oscar/libicq.c
@@ -20,7 +20,7 @@
*
*/
-/* libicq is the ICQ protocol plugin. It is linked against liboscarcommon,
+/* libicq is the ICQ protocol plugin. It is linked against liboscar,
* which contains all the shared implementation code with libaim
*/
@@ -63,11 +63,11 @@ static PurplePluginProtocolInfo prpl_info =
NULL, /* add_buddies */
oscar_remove_buddy, /* remove_buddy */
NULL, /* remove_buddies */
- oscar_add_permit, /* add_permit */
+ NULL, /* add_permit */
oscar_add_deny, /* add_deny */
- oscar_rem_permit, /* rem_permit */
+ NULL, /* rem_permit */
oscar_rem_deny, /* rem_deny */
- oscar_set_permit_deny, /* set_permit_deny */
+ NULL, /* set_permit_deny */
oscar_join_chat, /* join_chat */
NULL, /* reject_chat */
oscar_get_chat_name, /* get_chat_name */
@@ -109,6 +109,8 @@ static PurplePluginProtocolInfo prpl_info =
NULL, /* initiate_media */
NULL, /* can_do_media */
oscar_get_purple_moods, /* get_moods */
+ NULL, /* set_public_alias */
+ NULL /* get_public_alias */
};
static PurplePluginInfo info =
diff --git a/libpurple/protocols/oscar/misc.c b/libpurple/protocols/oscar/misc.c
index 4ddc562641..ed6b569914 100644
--- a/libpurple/protocols/oscar/misc.c
+++ b/libpurple/protocols/oscar/misc.c
@@ -41,7 +41,7 @@ aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 su
{
aim_snacid_t snacid = 0x00000000;
- flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+ flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
}
void
@@ -51,7 +51,7 @@ aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, gui
snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
- flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+ flap_connection_send_snac(od, conn, family, subtype, snacid, NULL);
}
void
@@ -72,30 +72,7 @@ aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 su
byte_stream_put32(&bs, *longdata);
- flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs);
-
- byte_stream_destroy(&bs);
-}
-
-void
-aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata)
-{
- ByteStream bs;
- aim_snacid_t snacid;
-
- if (!shortdata)
- {
- aim_genericreq_n(od, conn, family, subtype);
- return;
- }
-
- byte_stream_new(&bs, 2);
-
- snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
-
- byte_stream_put16(&bs, *shortdata);
-
- flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, &bs);
+ flap_connection_send_snac(od, conn, family, subtype, snacid, &bs);
byte_stream_destroy(&bs);
}
@@ -114,15 +91,16 @@ generror(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *fram
snac2 = aim_remsnac(od, snac->id);
- if (byte_stream_empty(bs))
+ if (byte_stream_bytes_left(bs))
error = byte_stream_get16(bs);
if ((userfunc = aim_callhandler(od, snac->family, snac->subtype)))
ret = userfunc(od, conn, frame, error, snac2 ? snac2->data : NULL);
- if (snac2)
+ if (snac2) {
g_free(snac2->data);
- g_free(snac2);
+ g_free(snac2);
+ }
return ret;
}
diff --git a/libpurple/protocols/oscar/msgcookie.c b/libpurple/protocols/oscar/msgcookie.c
index d344b0991c..19a3e43aea 100644
--- a/libpurple/protocols/oscar/msgcookie.c
+++ b/libpurple/protocols/oscar/msgcookie.c
@@ -177,18 +177,3 @@ int aim_cookie_free(OscarData *od, IcbmCookie *cookie)
return 0;
}
-
-/* XXX I hate switch */
-int aim_msgcookie_gettype(guint64 type)
-{
- /* XXX: hokey-assed. needs fixed. */
- switch(type) {
- case OSCAR_CAPABILITY_BUDDYICON: return AIM_COOKIETYPE_OFTICON;
- case OSCAR_CAPABILITY_TALK: return AIM_COOKIETYPE_OFTVOICE;
- case OSCAR_CAPABILITY_DIRECTIM: return AIM_COOKIETYPE_OFTIMAGE;
- case OSCAR_CAPABILITY_CHAT: return AIM_COOKIETYPE_CHAT;
- case OSCAR_CAPABILITY_GETFILE: return AIM_COOKIETYPE_OFTGET;
- case OSCAR_CAPABILITY_SENDFILE: return AIM_COOKIETYPE_OFTSEND;
- default: return AIM_COOKIETYPE_UNKNOWN;
- }
-}
diff --git a/libpurple/protocols/oscar/odc.c b/libpurple/protocols/oscar/odc.c
index eb741b3cb2..e2a7745128 100644
--- a/libpurple/protocols/oscar/odc.c
+++ b/libpurple/protocols/oscar/odc.c
@@ -19,6 +19,7 @@
*/
/* From the oscar PRPL */
+#include "encoding.h"
#include "oscar.h"
#include "peer.h"
@@ -89,7 +90,7 @@ peer_odc_send(PeerConnection *conn, OdcFrame *frame)
ByteStream bs;
purple_debug_info("oscar", "Outgoing ODC frame to %s with "
- "type=0x%04x, flags=0x%04x, payload length=%u\n",
+ "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
conn->bn, frame->type, frame->flags, frame->payload.len);
account = purple_connection_get_account(conn->od->gc);
@@ -366,8 +367,7 @@ peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int e
g_datalist_clear(&attributes);
/* Append the message up to the tag */
- utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
- encoding, 0x0000, tmp, start - tmp);
+ utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, start - tmp);
if (utf8 != NULL) {
g_string_append(newmsg, utf8);
g_free(utf8);
@@ -386,8 +386,7 @@ peer_odc_handle_payload(PeerConnection *conn, const char *msg, size_t len, int e
/* Append any remaining message data */
if (tmp <= msgend)
{
- utf8 = purple_plugin_oscar_decode_im_part(account, conn->bn,
- encoding, 0x0000, tmp, msgend - tmp);
+ utf8 = oscar_decode_im(account, conn->bn, encoding, tmp, msgend - tmp);
if (utf8 != NULL) {
g_string_append(newmsg, utf8);
g_free(utf8);
@@ -506,7 +505,7 @@ peer_odc_recv_frame(PeerConnection *conn, ByteStream *bs)
byte_stream_getrawbuf(bs, frame->bn, 32);
purple_debug_info("oscar", "Incoming ODC frame from %s with "
- "type=0x%04x, flags=0x%04x, payload length=%u\n",
+ "type=0x%04x, flags=0x%04x, payload length=%" G_GSIZE_FORMAT "\n",
frame->bn, frame->type, frame->flags, frame->payload.len);
if (!conn->ready)
diff --git a/libpurple/protocols/oscar/oft.c b/libpurple/protocols/oscar/oft.c
index 47891cebca..aa2d84b380 100644
--- a/libpurple/protocols/oscar/oft.c
+++ b/libpurple/protocols/oscar/oft.c
@@ -240,7 +240,7 @@ void
peer_oft_close(PeerConnection *conn)
{
/*
- * If canceled by local user, and we're receiving a file, and
+ * If cancelled by local user, and we're receiving a file, and
* we're not connected/ready then send an ICBM cancel message.
*/
if ((purple_xfer_get_status(conn->xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) &&
diff --git a/libpurple/protocols/oscar/oscar.c b/libpurple/protocols/oscar/oscar.c
index 078de9055a..554877e2c5 100644
--- a/libpurple/protocols/oscar/oscar.c
+++ b/libpurple/protocols/oscar/oscar.c
@@ -37,6 +37,7 @@
#include "conversation.h"
#include "core.h"
#include "debug.h"
+#include "encoding.h"
#include "imgstore.h"
#include "network.h"
#include "notify.h"
@@ -46,27 +47,12 @@
#include "request.h"
#include "util.h"
#include "version.h"
+#include "visibility.h"
#include "oscarcommon.h"
#include "oscar.h"
#include "peer.h"
-#define OSCAR_STATUS_ID_INVISIBLE "invisible"
-#define OSCAR_STATUS_ID_OFFLINE "offline"
-#define OSCAR_STATUS_ID_AVAILABLE "available"
-#define OSCAR_STATUS_ID_AWAY "away"
-#define OSCAR_STATUS_ID_DND "dnd"
-#define OSCAR_STATUS_ID_NA "na"
-#define OSCAR_STATUS_ID_OCCUPIED "occupied"
-#define OSCAR_STATUS_ID_FREE4CHAT "free4chat"
-#define OSCAR_STATUS_ID_CUSTOM "custom"
-#define OSCAR_STATUS_ID_MOBILE "mobile"
-#define OSCAR_STATUS_ID_EVIL "evil"
-#define OSCAR_STATUS_ID_DEPRESSION "depression"
-#define OSCAR_STATUS_ID_ATHOME "athome"
-#define OSCAR_STATUS_ID_ATWORK "atwork"
-#define OSCAR_STATUS_ID_LUNCH "lunch"
-
#define AIMHASHDATA "http://pidgin.im/aim_data.php3"
#define OSCAR_CONNECT_STEPS 6
@@ -82,11 +68,11 @@ static guint64 purple_caps =
| OSCAR_CAPABILITY_TYPING
| OSCAR_CAPABILITY_ICQSERVERRELAY
| OSCAR_CAPABILITY_NEWCAPS
- | OSCAR_CAPABILITY_XTRAZ;
+ | OSCAR_CAPABILITY_XTRAZ
+ | OSCAR_CAPABILITY_HTML_MSGS;
static guint8 features_aim[] = {0x01, 0x01, 0x01, 0x02};
-static guint8 features_icq[] = {0x01, 0x06};
-static guint8 features_icq_offline[] = {0x01};
+static guint8 features_icq[] = {0x01};
static guint8 ck[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct create_room {
@@ -100,84 +86,6 @@ struct oscar_ask_directim_data
char *who;
};
-/*
- * Various PRPL-specific buddy info that we want to keep track of
- * Some other info is maintained by locate.c, and I'd like to move
- * the rest of this to libfaim, mostly im.c
- *
- * TODO: More of this should use the status API.
- */
-struct buddyinfo {
- gboolean typingnot;
- guint32 ipaddr;
-
- unsigned long ico_me_len;
- unsigned long ico_me_csum;
- time_t ico_me_time;
- gboolean ico_informed;
-
- unsigned long ico_len;
- unsigned long ico_csum;
- time_t ico_time;
- gboolean ico_need;
- gboolean ico_sent;
-};
-
-struct name_data {
- PurpleConnection *gc;
- gchar *name;
- gchar *nick;
-};
-
-static const char * const msgerrreason[] = {
- N_("Invalid error"),
- N_("Invalid SNAC"),
- N_("Rate to host"),
- N_("Rate to client"),
- N_("Not logged in"),
- N_("Service unavailable"),
- N_("Service not defined"),
- N_("Obsolete SNAC"),
- N_("Not supported by host"),
- N_("Not supported by client"),
- N_("Refused by client"),
- N_("Reply too big"),
- N_("Responses lost"),
- N_("Request denied"),
- N_("Busted SNAC payload"),
- N_("Insufficient rights"),
- N_("In local permit/deny"),
- N_("Warning level too high (sender)"),
- N_("Warning level too high (receiver)"),
- N_("User temporarily unavailable"),
- N_("No match"),
- N_("List overflow"),
- N_("Request ambiguous"),
- N_("Queue full"),
- N_("Not while on AOL")
-};
-static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
-
-static const char * const errcodereason[] = {
- N_("Invalid error"),
- N_("Not logged in"),
- N_("Cannot receive IM due to parental controls"),
- N_("Cannot send SMS without accepting terms"),
- N_("Cannot send SMS"), /* SMS_WITHOUT_DISCLAIMER is weird */
- N_("Cannot send SMS to this country"),
- N_("Unknown error"), /* Undocumented */
- N_("Unknown error"), /* Undocumented */
- N_("Cannot send SMS to unknown country"),
- N_("Bot accounts cannot initiate IMs"),
- N_("Bot account cannot IM this user"),
- N_("Bot account reached IM limit"),
- N_("Bot account reached daily IM limit"),
- N_("Bot account reached monthly IM limit"),
- N_("Unable to receive offline messages"),
- N_("Offline message store full")
-};
-static const int errcodereasonlen = G_N_ELEMENTS(errcodereason);
-
/* All the libfaim->purple callback functions */
/* Only used when connecting with the old-style BUCP login */
@@ -193,7 +101,6 @@ static int purple_parse_offgoing (OscarData *, FlapConnection *, FlapFrame *,
static int purple_parse_incoming_im(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_misses (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_clientauto (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_userinfo (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_motd (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_chatnav_info (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_conv_chat_join (OscarData *, FlapConnection *, FlapFrame *, ...);
@@ -202,27 +109,16 @@ static int purple_conv_chat_info_update (OscarData *, FlapConnection *, FlapFram
static int purple_conv_chat_incoming_msg(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_email_parseupdate(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_icon_parseicon (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int oscar_icon_req (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_msgack (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_evilnotify (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_searcherror(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_searchreply(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_bosrights (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_connerr (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_msgerr (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_mtn (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_locaterights(OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_buddyrights(OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_parse_locerr (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_parse_genericerr (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_memrequest (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_selfinfo (OscarData *, FlapConnection *, FlapFrame *, ...);
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-static int purple_offlinemsg (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_offlinemsgdone (OscarData *, FlapConnection *, FlapFrame *, ...);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-static int purple_icqalias (OscarData *, FlapConnection *, FlapFrame *, ...);
-static int purple_icqinfo (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_popup (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_ssi_parseerr (OscarData *, FlapConnection *, FlapFrame *, ...);
static int purple_ssi_parserights (OscarData *, FlapConnection *, FlapFrame *, ...);
@@ -238,10 +134,10 @@ static void purple_icons_fetch(PurpleConnection *gc);
void oscar_set_info(PurpleConnection *gc, const char *info);
static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
-static void oscar_set_extendedstatus(PurpleConnection *gc);
+static void oscar_set_extended_status(PurpleConnection *gc);
static gboolean purple_ssi_rerequestdata(gpointer data);
-static void oscar_free_name_data(struct name_data *data) {
+void oscar_free_name_data(struct name_data *data) {
g_free(data->name);
g_free(data->nick);
g_free(data);
@@ -256,536 +152,6 @@ const char *oscar_get_locale_charset(void) {
}
#endif
-/**
- * Determine how we can send this message. Per the warnings elsewhere
- * in this file, these little checks determine the simplest encoding
- * we can use for a given message send using it.
- */
-static guint32
-oscar_charset_check(const char *utf8)
-{
- int i = 0;
- int charset = AIM_CHARSET_ASCII;
-
- /*
- * Can we get away with using our custom encoding?
- */
- while (utf8[i])
- {
- if ((unsigned char)utf8[i] > 0x7f) {
- /* not ASCII! */
- charset = AIM_CHARSET_LATIN_1;
- break;
- }
- i++;
- }
-
- /*
- * Must we send this message as UNICODE (in the UTF-16BE encoding)?
- */
- while (utf8[i])
- {
- /* ISO-8859-1 is 0x00-0xbf in the first byte
- * followed by 0xc0-0xc3 in the second */
- if ((unsigned char)utf8[i] < 0x80) {
- i++;
- continue;
- } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 &&
- ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) {
- i += 2;
- continue;
- }
- charset = AIM_CHARSET_UNICODE;
- break;
- }
-
- return charset;
-}
-
-/**
- * Take a string of the form charset="bleh" where bleh is
- * one of us-ascii, utf-8, iso-8859-1, or unicode-2-0, and
- * return a newly allocated string containing bleh.
- */
-gchar *
-oscar_encoding_extract(const char *encoding)
-{
- gchar *ret = NULL;
- char *begin, *end;
-
- g_return_val_if_fail(encoding != NULL, NULL);
-
- /* Make sure encoding begins with charset= */
- if (strncmp(encoding, "text/aolrtf; charset=", 21) &&
- strncmp(encoding, "text/x-aolrtf; charset=", 23) &&
- strncmp(encoding, "text/plain; charset=", 20))
- {
- return NULL;
- }
-
- begin = strchr(encoding, '"');
- end = strrchr(encoding, '"');
-
- if ((begin == NULL) || (end == NULL) || (begin >= end))
- return NULL;
-
- ret = g_strndup(begin+1, (end-1) - begin);
-
- return ret;
-}
-
-gchar *
-oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen)
-{
- gchar *utf8 = NULL;
-
- if ((encoding == NULL) || encoding[0] == '\0') {
- purple_debug_info("oscar", "Empty encoding, assuming UTF-8\n");
- } else if (!g_ascii_strcasecmp(encoding, "iso-8859-1")) {
- utf8 = g_convert(text, textlen, "UTF-8", "iso-8859-1", NULL, NULL, NULL);
- } else if (!g_ascii_strcasecmp(encoding, "ISO-8859-1-Windows-3.1-Latin-1") ||
- !g_ascii_strcasecmp(encoding, "us-ascii"))
- {
- utf8 = g_convert(text, textlen, "UTF-8", "Windows-1252", NULL, NULL, NULL);
- } else if (!g_ascii_strcasecmp(encoding, "unicode-2-0")) {
- /* Some official ICQ clients are apparently total crack,
- * and have been known to save a UTF-8 string converted
- * from the locale character set to UTF-16 (not from UTF-8
- * to UTF-16!) in the away message. This hack should find
- * and do something (un)reasonable with that, and not
- * mess up too much else. */
- const gchar *charset = purple_account_get_string(account, "encoding", NULL);
- if (charset) {
- gsize len;
- utf8 = g_convert(text, textlen, charset, "UTF-16BE", &len, NULL, NULL);
- if (!utf8 || len != textlen || !g_utf8_validate(utf8, -1, NULL)) {
- g_free(utf8);
- utf8 = NULL;
- } else {
- purple_debug_info("oscar", "Used broken ICQ fallback encoding\n");
- }
- }
- if (!utf8)
- utf8 = g_convert(text, textlen, "UTF-8", "UTF-16BE", NULL, NULL, NULL);
- } else if (g_ascii_strcasecmp(encoding, "utf-8")) {
- purple_debug_warning("oscar", "Unrecognized character encoding \"%s\", "
- "attempting to convert to UTF-8 anyway\n", encoding);
- utf8 = g_convert(text, textlen, "UTF-8", encoding, NULL, NULL, NULL);
- }
-
- /*
- * If utf8 is still NULL then either the encoding is utf-8 or
- * we have been unable to convert the text to utf-8 from the encoding
- * that was specified. So we check if the text is valid utf-8 then
- * just copy it.
- */
- if (utf8 == NULL) {
- if (textlen != 0 && *text != '\0'
- && !g_utf8_validate(text, textlen, NULL))
- utf8 = g_strdup(_("(There was an error receiving this message. The buddy you are speaking with is probably using a different encoding than expected. If you know what encoding he is using, you can specify it in the advanced account options for your AIM/ICQ account.)"));
- else
- utf8 = g_strndup(text, textlen);
- }
-
- return utf8;
-}
-
-static gchar *
-oscar_utf8_try_convert(PurpleAccount *account, OscarData *od, const gchar *msg)
-{
- const char *charset = NULL;
- char *ret = NULL;
-
- if (od->icq)
- charset = purple_account_get_string(account, "encoding", NULL);
-
- if(charset && *charset)
- ret = g_convert(msg, -1, "UTF-8", charset, NULL, NULL, NULL);
-
- if(!ret)
- ret = purple_utf8_try_convert(msg);
-
- return ret;
-}
-
-static gchar *
-purple_plugin_oscar_convert_to_utf8(const gchar *data, gsize datalen, const char *charsetstr, gboolean fallback)
-{
- gchar *ret = NULL;
- GError *err = NULL;
-
- if ((charsetstr == NULL) || (*charsetstr == '\0'))
- return NULL;
-
- if (g_ascii_strcasecmp("UTF-8", charsetstr)) {
- if (fallback)
- ret = g_convert_with_fallback(data, datalen, "UTF-8", charsetstr, "?", NULL, NULL, &err);
- else
- ret = g_convert(data, datalen, "UTF-8", charsetstr, NULL, NULL, &err);
- if (err != NULL) {
- purple_debug_warning("oscar", "Conversion from %s failed: %s.\n",
- charsetstr, err->message);
- g_error_free(err);
- }
- } else {
- if (g_utf8_validate(data, datalen, NULL))
- ret = g_strndup(data, datalen);
- else
- purple_debug_warning("oscar", "String is not valid UTF-8.\n");
- }
-
- return ret;
-}
-
-/**
- * This attemps to decode an incoming IM into a UTF8 string.
- *
- * We try decoding using two different character sets. The charset
- * specified in the IM determines the order in which we attempt to
- * decode. We do this because there are lots of broken ICQ clients
- * that don't correctly send non-ASCII messages. And if Purple isn't
- * able to deal with that crap, then people complain like banshees.
- * charsetstr1 is always set to what the correct encoding should be.
- */
-gchar *
-purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen)
-{
- gchar *ret = NULL;
- const gchar *charsetstr1, *charsetstr2, *charsetstr3 = NULL;
-
- if ((datalen == 0) || (data == NULL))
- return NULL;
-
- if (charset == AIM_CHARSET_UNICODE) {
- charsetstr1 = "UTF-16BE";
- charsetstr2 = "UTF-8";
- } else if (charset == AIM_CHARSET_LATIN_1) {
- if ((sourcebn != NULL) && oscar_util_valid_name_icq(sourcebn))
- charsetstr1 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
- else
- charsetstr1 = "ISO-8859-1";
- charsetstr2 = "UTF-8";
- } else if (charset == AIM_CHARSET_ASCII) {
- /* Should just be "ASCII" */
- charsetstr1 = "ASCII";
- charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
- } else if (charset == 0x000d) {
- /* iChat sending unicode over a Direct IM connection = UTF-8 */
- /* Mobile AIM client on multiple devices (including Blackberry Tour, Nokia 3100, and LG VX6000) = ISO-8859-1 */
- charsetstr1 = "UTF-8";
- charsetstr2 = "ISO-8859-1";
- charsetstr3 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
- } else {
- /* Unknown, hope for valid UTF-8... */
- charsetstr1 = "UTF-8";
- charsetstr2 = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
- }
-
- purple_debug_info("oscar", "Parsing IM part, charset=0x%04hx, charsubset=0x%04hx, datalen=%" G_GSIZE_FORMAT ", choice1=%s, choice2=%s, choice3=%s\n",
- charset, charsubset, datalen, charsetstr1, charsetstr2, (charsetstr3 ? charsetstr3 : ""));
-
- ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr1, FALSE);
- if (ret == NULL) {
- if (charsetstr3 != NULL) {
- /* Try charsetstr2 without allowing substitutions, then fall through to charsetstr3 if needed */
- ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, FALSE);
- if (ret == NULL)
- ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr3, TRUE);
- } else {
- /* Try charsetstr2, allowing substitutions */
- ret = purple_plugin_oscar_convert_to_utf8(data, datalen, charsetstr2, TRUE);
- }
- }
- if (ret == NULL) {
- char *str, *salvage, *tmp;
-
- str = g_malloc(datalen + 1);
- strncpy(str, data, datalen);
- str[datalen] = '\0';
- salvage = purple_utf8_salvage(str);
- tmp = g_strdup_printf(_("(There was an error receiving this message. Either you and %s have different encodings selected, or %s has a buggy client.)"),
- sourcebn, sourcebn);
- ret = g_strdup_printf("%s %s", salvage, tmp);
- g_free(tmp);
- g_free(str);
- g_free(salvage);
- }
-
- return ret;
-}
-
-/**
- * Figure out what encoding to use when sending a given outgoing message.
- */
-static void
-purple_plugin_oscar_convert_to_best_encoding(PurpleConnection *gc,
- const char *destbn, const gchar *from,
- gchar **msg, int *msglen_int,
- guint16 *charset, guint16 *charsubset)
-{
- OscarData *od = purple_connection_get_protocol_data(gc);
- PurpleAccount *account = purple_connection_get_account(gc);
- GError *err = NULL;
- aim_userinfo_t *userinfo = NULL;
- const gchar *charsetstr;
- gsize msglen;
-
- /* Attempt to send as ASCII */
- if (oscar_charset_check(from) == AIM_CHARSET_ASCII) {
- *msg = g_convert(from, -1, "ASCII", "UTF-8", NULL, &msglen, NULL);
- *charset = AIM_CHARSET_ASCII;
- *charsubset = 0x0000;
- *msglen_int = msglen;
- return;
- }
-
- /*
- * If we're sending to an ICQ user, and they are in our
- * buddy list, and they are advertising the Unicode
- * capability, and they are online, then attempt to send
- * as UTF-16BE.
- */
- if ((destbn != NULL) && oscar_util_valid_name_icq(destbn))
- userinfo = aim_locate_finduserinfo(od, destbn);
-
- if ((userinfo != NULL) && (userinfo->capabilities & OSCAR_CAPABILITY_UNICODE))
- {
- PurpleBuddy *b;
- b = purple_find_buddy(account, destbn);
- if ((b != NULL) && (PURPLE_BUDDY_IS_ONLINE(b)))
- {
- *msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err);
- if (*msg != NULL)
- {
- *charset = AIM_CHARSET_UNICODE;
- *charsubset = 0x0000;
- *msglen_int = msglen;
- return;
- }
-
- purple_debug_error("oscar", "Conversion from UTF-8 to UTF-16BE failed: %s.\n",
- err->message);
- g_error_free(err);
- err = NULL;
- }
- }
-
- /*
- * If this is AIM then attempt to send as ISO-8859-1. If this is
- * ICQ then attempt to send as the user specified character encoding.
- */
- charsetstr = "ISO-8859-1";
- if ((destbn != NULL) && oscar_util_valid_name_icq(destbn))
- charsetstr = purple_account_get_string(account, "encoding", OSCAR_DEFAULT_CUSTOM_ENCODING);
-
- /*
- * XXX - We need a way to only attempt to convert if we KNOW "from"
- * can be converted to "charsetstr"
- */
- *msg = g_convert(from, -1, charsetstr, "UTF-8", NULL, &msglen, &err);
- if (*msg != NULL) {
- *charset = AIM_CHARSET_LATIN_1;
- *charsubset = 0x0000;
- *msglen_int = msglen;
- return;
- }
-
- purple_debug_info("oscar", "Conversion from UTF-8 to %s failed (%s). Falling back to unicode.\n",
- charsetstr, err->message);
- g_error_free(err);
- err = NULL;
-
- /*
- * Nothing else worked, so send as UTF-16BE.
- */
- *msg = g_convert(from, -1, "UTF-16BE", "UTF-8", NULL, &msglen, &err);
- if (*msg != NULL) {
- *charset = AIM_CHARSET_UNICODE;
- *charsubset = 0x0000;
- *msglen_int = msglen;
- return;
- }
-
- purple_debug_error("oscar", "Error converting a Unicode message: %s\n", err->message);
- g_error_free(err);
- err = NULL;
-
- purple_debug_error("oscar", "This should NEVER happen! Sending UTF-8 text flagged as ASCII.\n");
- *msg = g_strdup(from);
- *msglen_int = strlen(*msg);
- *charset = AIM_CHARSET_ASCII;
- *charsubset = 0x0000;
- return;
-}
-
-/**
- * Looks for %n, %d, or %t in a string, and replaces them with the
- * specified name, date, and time, respectively.
- *
- * @param str The string that may contain the special variables.
- * @param name The sender name.
- *
- * @return A newly allocated string where the special variables are
- * expanded. This should be g_free'd by the caller.
- */
-static gchar *
-purple_str_sub_away_formatters(const char *str, const char *name)
-{
- char *c;
- GString *cpy;
- time_t t;
- struct tm *tme;
-
- g_return_val_if_fail(str != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- /* Create an empty GString that is hopefully big enough for most messages */
- cpy = g_string_sized_new(1024);
-
- t = time(NULL);
- tme = localtime(&t);
-
- c = (char *)str;
- while (*c) {
- switch (*c) {
- case '%':
- if (*(c + 1)) {
- switch (*(c + 1)) {
- case 'n':
- /* append name */
- g_string_append(cpy, name);
- c++;
- break;
- case 'd':
- /* append date */
- g_string_append(cpy, purple_date_format_short(tme));
- c++;
- break;
- case 't':
- /* append time */
- g_string_append(cpy, purple_time_format(tme));
- c++;
- break;
- default:
- g_string_append_c(cpy, *c);
- }
- } else {
- g_string_append_c(cpy, *c);
- }
- break;
- default:
- g_string_append_c(cpy, *c);
- }
- c++;
- }
-
- return g_string_free(cpy, FALSE);
-}
-
-static gchar *oscar_caps_to_string(guint64 caps)
-{
- GString *str;
- const gchar *tmp;
- guint64 bit = 1;
-
- str = g_string_new("");
-
- if (!caps) {
- return NULL;
- } else while (bit <= OSCAR_CAPABILITY_LAST) {
- if (bit & caps) {
- switch (bit) {
- case OSCAR_CAPABILITY_BUDDYICON:
- tmp = _("Buddy Icon");
- break;
- case OSCAR_CAPABILITY_TALK:
- tmp = _("Voice");
- break;
- case OSCAR_CAPABILITY_DIRECTIM:
- tmp = _("AIM Direct IM");
- break;
- case OSCAR_CAPABILITY_CHAT:
- tmp = _("Chat");
- break;
- case OSCAR_CAPABILITY_GETFILE:
- tmp = _("Get File");
- break;
- case OSCAR_CAPABILITY_SENDFILE:
- tmp = _("Send File");
- break;
- case OSCAR_CAPABILITY_GAMES:
- case OSCAR_CAPABILITY_GAMES2:
- tmp = _("Games");
- break;
- case OSCAR_CAPABILITY_XTRAZ:
- case OSCAR_CAPABILITY_NEWCAPS:
- tmp = _("ICQ Xtraz");
- break;
- case OSCAR_CAPABILITY_ADDINS:
- tmp = _("Add-Ins");
- break;
- case OSCAR_CAPABILITY_SENDBUDDYLIST:
- tmp = _("Send Buddy List");
- break;
- case OSCAR_CAPABILITY_ICQ_DIRECT:
- tmp = _("ICQ Direct Connect");
- break;
- case OSCAR_CAPABILITY_APINFO:
- tmp = _("AP User");
- break;
- case OSCAR_CAPABILITY_ICQRTF:
- tmp = _("ICQ RTF");
- break;
- case OSCAR_CAPABILITY_EMPTY:
- tmp = _("Nihilist");
- break;
- case OSCAR_CAPABILITY_ICQSERVERRELAY:
- tmp = _("ICQ Server Relay");
- break;
- case OSCAR_CAPABILITY_UNICODEOLD:
- tmp = _("Old ICQ UTF8");
- break;
- case OSCAR_CAPABILITY_TRILLIANCRYPT:
- tmp = _("Trillian Encryption");
- break;
- case OSCAR_CAPABILITY_UNICODE:
- tmp = _("ICQ UTF8");
- break;
- case OSCAR_CAPABILITY_HIPTOP:
- tmp = _("Hiptop");
- break;
- case OSCAR_CAPABILITY_SECUREIM:
- tmp = _("Security Enabled");
- break;
- case OSCAR_CAPABILITY_VIDEO:
- tmp = _("Video Chat");
- break;
- /* Not actually sure about this one... WinAIM doesn't show anything */
- case OSCAR_CAPABILITY_ICHATAV:
- tmp = _("iChat AV");
- break;
- case OSCAR_CAPABILITY_LIVEVIDEO:
- tmp = _("Live Video");
- break;
- case OSCAR_CAPABILITY_CAMERA:
- tmp = _("Camera");
- break;
- case OSCAR_CAPABILITY_ICHAT_SCREENSHARE:
- tmp = _("Screen Sharing");
- break;
- default:
- tmp = NULL;
- break;
- }
- if (tmp)
- g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp);
- }
- bit <<= 1;
- }
-
- return g_string_free(str, FALSE);
-}
-
static char *oscar_icqstatus(int state) {
/* Make a cute little string that shows the status of the dude or dudet */
if (state & AIM_ICQ_STATE_CHAT)
@@ -816,255 +182,6 @@ static char *oscar_icqstatus(int state) {
return g_strdup(_("Online"));
}
-static void
-oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value)
-{
- if (value && value[0]) {
- purple_notify_user_info_add_pair(user_info, name, value);
- }
-}
-
-static void
-oscar_user_info_convert_and_add_pair(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
- const char *name, const char *value)
-{
- gchar *utf8;
-
- if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
- purple_notify_user_info_add_pair(user_info, name, utf8);
- g_free(utf8);
- }
-}
-
-static void
-oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
- const char *name, const char *value)
-{
- gchar *utf8;
-
- if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
- purple_notify_user_info_add_pair(user_info, name, utf8);
- g_free(utf8);
- }
-}
-
-/**
- * @brief Append the status information to a user_info struct
- *
- * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
- *
- * @param gc The PurpleConnection
- * @param user_info A PurpleNotifyUserInfo object to which status information will be added
- * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
- * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
- * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped.
- */
-static void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags)
-{
- PurpleAccount *account = purple_connection_get_account(gc);
- OscarData *od;
- PurplePresence *presence = NULL;
- PurpleStatus *status = NULL;
- gchar *message = NULL, *itmsurl = NULL, *tmp;
- gboolean is_away;
-
- od = purple_connection_get_protocol_data(gc);
-
- if (b == NULL && userinfo == NULL)
- return;
-
- if (b == NULL)
- b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn);
- else
- userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
- if (b) {
- presence = purple_buddy_get_presence(b);
- status = purple_presence_get_active_status(presence);
- }
-
- /* If we have both b and userinfo we favor userinfo, because if we're
- viewing someone's profile then we want the HTML away message, and
- the "message" attribute of the status contains only the plaintext
- message. */
- if (userinfo) {
- if ((userinfo->flags & AIM_FLAG_AWAY)
- && userinfo->away_len > 0
- && userinfo->away != NULL
- && userinfo->away_encoding != NULL)
- {
- /* Away message */
- tmp = oscar_encoding_extract(userinfo->away_encoding);
- message = oscar_encoding_to_utf8(account,
- tmp, userinfo->away, userinfo->away_len);
- g_free(tmp);
- } else {
- /*
- * Available message or non-HTML away message (because that's
- * all we have right now.
- */
- if ((userinfo->status != NULL) && userinfo->status[0] != '\0') {
- message = oscar_encoding_to_utf8(account,
- userinfo->status_encoding, userinfo->status,
- userinfo->status_len);
- }
-#if defined (_WIN32) || defined (__APPLE__)
- if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0'))
- itmsurl = oscar_encoding_to_utf8(account, userinfo->itmsurl_encoding,
- userinfo->itmsurl, userinfo->itmsurl_len);
-#endif
- }
- } else {
- message = g_strdup(purple_status_get_attr_string(status, "message"));
- itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl"));
- }
-
- is_away = ((status && !purple_status_is_available(status)) ||
- (userinfo && (userinfo->flags & AIM_FLAG_AWAY)));
-
- if (strip_html_tags) {
- /* Away messages are HTML, but available messages were originally plain text.
- * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags.
- */
- /*
- * It seems like the above comment no longer applies. All messages need
- * to be escaped.
- */
- if (message) {
- gchar *tmp2;
- tmp = purple_markup_strip_html(message);
- g_free(message);
- tmp2 = g_markup_escape_text(tmp, -1);
- g_free(tmp);
- message = tmp2;
- }
-
- } else {
- if (itmsurl) {
- tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
- itmsurl, message);
- g_free(message);
- message = tmp;
- }
- }
- g_free(itmsurl);
-
- if (message) {
- tmp = purple_str_sub_away_formatters(message, purple_account_get_username(account));
- g_free(message);
- message = tmp;
- }
-
- if (b) {
- if (purple_presence_is_online(presence)) {
- if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || is_away || !message || !(*message)) {
- /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message.
- * If the status name and the message are the same, only show one. */
- const char *status_name = purple_status_get_name(status);
- if (status_name && message && !strcmp(status_name, message))
- status_name = NULL;
-
- tmp = g_strdup_printf("%s%s%s",
- status_name ? status_name : "",
- ((status_name && message) && *message) ? ": " : "",
- (message && *message) ? message : "");
- g_free(message);
- message = tmp;
- }
-
- } else if (aim_ssi_waitingforauth(od->ssi.local,
- aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)),
- purple_buddy_get_name(b)))
- {
- /* Note if an offline buddy is not authorized */
- tmp = g_strdup_printf("%s%s%s",
- _("Not Authorized"),
- (message && *message) ? ": " : "",
- (message && *message) ? message : "");
- g_free(message);
- message = tmp;
- } else {
- g_free(message);
- message = g_strdup(_("Offline"));
- }
- }
-
- if (presence) {
- const char *mood;
- const char *description;
- status = purple_presence_get_status(presence, "mood");
- mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
- description = icq_get_custom_icon_description(mood);
- if (description && *description)
- purple_notify_user_info_add_pair(user_info, _("Mood"), _(description));
- }
-
- purple_notify_user_info_add_pair(user_info, _("Status"), message);
- g_free(message);
-}
-
-static void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo)
-{
- OscarData *od;
- PurpleAccount *account;
- PurplePresence *presence = NULL;
- PurpleStatus *status = NULL;
- PurpleGroup *g = NULL;
- struct buddyinfo *bi = NULL;
- char *tmp;
- const char *bname = NULL, *gname = NULL;
-
- od = purple_connection_get_protocol_data(gc);
- account = purple_connection_get_account(gc);
-
- if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
- return;
-
- if (userinfo == NULL)
- userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
-
- if (b == NULL)
- b = purple_find_buddy(account, userinfo->bn);
-
- if (b != NULL) {
- bname = purple_buddy_get_name(b);
- g = purple_buddy_get_group(b);
- gname = purple_group_get_name(g);
- presence = purple_buddy_get_presence(b);
- status = purple_presence_get_active_status(presence);
- }
-
- if (userinfo != NULL)
- bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
-
- if ((bi != NULL) && (bi->ipaddr != 0)) {
- tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
- (bi->ipaddr & 0xff000000) >> 24,
- (bi->ipaddr & 0x00ff0000) >> 16,
- (bi->ipaddr & 0x0000ff00) >> 8,
- (bi->ipaddr & 0x000000ff));
- oscar_user_info_add_pair(user_info, _("IP Address"), tmp);
- g_free(tmp);
- }
-
- if ((userinfo != NULL) && (userinfo->warnlevel != 0)) {
- tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5));
- oscar_user_info_add_pair(user_info, _("Warning Level"), tmp);
- g_free(tmp);
- }
-
- if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) {
- tmp = aim_ssi_getcomment(od->ssi.local, gname, bname);
- if (tmp != NULL) {
- char *tmp2 = g_markup_escape_text(tmp, strlen(tmp));
- g_free(tmp);
-
- oscar_user_info_convert_and_add_pair(account, od, user_info, _("Buddy Comment"), tmp2);
- g_free(tmp2);
- }
- }
-}
-
static char *extract_name(const char *name) {
char *tmp, *x;
int i, j;
@@ -1547,25 +664,13 @@ oscar_login(PurpleAccount *account)
oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_INCOMING, purple_parse_incoming_im, 0);
oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MISSEDCALL, purple_parse_misses, 0);
oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_CLIENTAUTORESP, purple_parse_clientauto, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ERROR, purple_parse_msgerr, 0);
oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_MTN, purple_parse_mtn, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_ICBM, SNAC_SUBTYPE_ICBM_ACK, purple_parse_msgack, 0);
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
- oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSG, purple_offlinemsg, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_OFFLINEMSGCOMPLETE, purple_offlinemsgdone, 0);
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
- oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_ALIAS, purple_icqalias, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_ICQ, SNAC_SUBTYPE_ICQ_INFO, purple_icqinfo, 0);
oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_RIGHTSINFO, purple_parse_locaterights, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_USERINFO, purple_parse_userinfo, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_LOCATE, SNAC_SUBTYPE_LOCATE_ERROR, purple_parse_locerr, 0);
oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0001, purple_parse_genericerr, 0);
oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x000f, purple_selfinfo, 0);
oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x001f, purple_memrequest, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, 0x0021, oscar_icon_req,0);
oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_REDIRECT, purple_handle_redirect, 0);
oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_MOTD, purple_parse_motd, 0);
- oscar_data_addhandler(od, SNAC_FAMILY_OSERVICE, SNAC_SUBTYPE_OSERVICE_EVIL, purple_parse_evilnotify, 0);
oscar_data_addhandler(od, SNAC_FAMILY_POPUP, 0x0002, purple_popup, 0);
oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, SNAC_SUBTYPE_USERLOOKUP_ERROR, purple_parse_searcherror, 0);
oscar_data_addhandler(od, SNAC_FAMILY_USERLOOKUP, 0x0003, purple_parse_searchreply, 0);
@@ -1580,11 +685,11 @@ oscar_login(PurpleAccount *account)
return;
}
+ gc->flags |= PURPLE_CONNECTION_HTML;
if (oscar_util_valid_name_icq((purple_account_get_username(account)))) {
od->icq = TRUE;
gc->flags |= PURPLE_CONNECTION_SUPPORT_MOODS;
} else {
- gc->flags |= PURPLE_CONNECTION_HTML;
gc->flags |= PURPLE_CONNECTION_AUTO_RESP;
}
@@ -1825,34 +930,6 @@ static int purple_memrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr,
AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
return 1;
}
- /* uncomment this when you're convinced it's right. remember, it's been wrong before. */
-#if 0
- if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
- char *buf;
- int i = 8;
- if (modname)
- i += strlen(modname);
- buf = g_malloc(i);
- i = 0;
- if (modname) {
- memcpy(buf, modname, strlen(modname));
- i += strlen(modname);
- }
- buf[i++] = offset & 0xff;
- buf[i++] = (offset >> 8) & 0xff;
- buf[i++] = (offset >> 16) & 0xff;
- buf[i++] = (offset >> 24) & 0xff;
- buf[i++] = len & 0xff;
- buf[i++] = (len >> 8) & 0xff;
- buf[i++] = (len >> 16) & 0xff;
- buf[i++] = (len >> 24) & 0xff;
- purple_debug_misc("oscar", "len + offset is invalid, "
- "hashing request\n");
- aim_sendmemblock(od, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
- g_free(buf);
- return 1;
- }
-#endif
pos = g_new0(struct pieceofcrap, 1);
pos->gc = od->gc;
@@ -2307,18 +1384,18 @@ static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame
purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
}
- if (info->status != NULL && info->status[0] != '\0')
+ if (info->status != NULL && info->status[0] != '\0') {
/* Grab the available message */
- message = oscar_encoding_to_utf8(account, info->status_encoding,
- info->status, info->status_len);
+ message = oscar_encoding_to_utf8(info->status_encoding, info->status, info->status_len);
+ }
tmp2 = tmp = (message ? purple_markup_escape_text(message, -1) : NULL);
if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) {
- if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
+ if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) {
/* Grab the iTunes Music Store URL */
- itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
- info->itmsurl, info->itmsurl_len);
+ itmsurl = oscar_encoding_to_utf8(info->itmsurl_encoding, info->itmsurl, info->itmsurl_len);
+ }
if (tmp2 == NULL && itmsurl != NULL)
/*
@@ -2424,17 +1501,11 @@ static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t
PurpleMessageFlags flags = 0;
struct buddyinfo *bi;
PurpleStoredImage *img;
- GString *message;
gchar *tmp;
- aim_mpmsg_section_t *curpart;
const char *start, *end;
GData *attribs;
- purple_debug_misc("oscar", "Received IM from %s with %d parts\n",
- userinfo->bn, args->mpmsg.numparts);
-
- if (args->mpmsg.numparts == 0)
- return 1;
+ purple_debug_misc("oscar", "Received IM from %s\n", userinfo->bn);
bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
if (!bi) {
@@ -2474,38 +1545,7 @@ static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t
}
purple_imgstore_unref(img);
- message = g_string_new("");
- curpart = args->mpmsg.parts;
- while (curpart != NULL) {
- tmp = purple_plugin_oscar_decode_im_part(account, userinfo->bn, curpart->charset,
- curpart->charsubset, curpart->data, curpart->datalen);
- if (tmp != NULL) {
- g_string_append(message, tmp);
- g_free(tmp);
- }
-
- curpart = curpart->next;
- }
- tmp = g_string_free(message, FALSE);
-
- /*
- * If the message is from an ICQ user and to an ICQ user then escape any HTML,
- * because HTML is not sent over ICQ as a means to format a message.
- * So any HTML we receive is intended to be displayed. Also, \r\n must be
- * replaced with <br>
- *
- * Note: There *may* be some clients which send messages as HTML formatted -
- * they need to be special-cased somehow.
- */
- if (od->icq && oscar_util_valid_name_icq(userinfo->bn)) {
- /* being recevied by ICQ from ICQ - escape HTML so it is displayed as sent */
- gchar *tmp2 = g_markup_escape_text(tmp, -1);
- g_free(tmp);
- tmp = tmp2;
- tmp2 = purple_strreplace(tmp, "\r\n", "<br>");
- g_free(tmp);
- tmp = tmp2;
- }
+ tmp = g_strdup(args->msg);
/*
* Convert iChat color tags to normal font tags.
@@ -2589,8 +1629,7 @@ static int incomingim_chan1(OscarData *od, FlapConnection *conn, aim_userinfo_t
tmp = tmp2;
}
- serv_got_im(gc, userinfo->bn, tmp, flags,
- (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
+ serv_got_im(gc, userinfo->bn, tmp, flags, (args->icbmflags & AIM_IMFLAGS_OFFLINE) ? args->timestamp : time(NULL));
g_free(tmp);
return 1;
@@ -2618,35 +1657,20 @@ incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
G_GUINT64_FORMAT ", user %s, status %hu\n",
args->type, userinfo->bn, args->status);
- if (args->msg != NULL)
- {
- if (args->encoding != NULL)
- {
- char *encoding = NULL;
- encoding = oscar_encoding_extract(args->encoding);
- message = oscar_encoding_to_utf8(account, encoding, args->msg,
- args->msglen);
- g_free(encoding);
- } else {
- if (g_utf8_validate(args->msg, args->msglen, NULL))
- message = g_strdup(args->msg);
- }
+ if (args->msg != NULL) {
+ message = oscar_encoding_to_utf8(args->encoding, args->msg, args->msglen);
}
if (args->type & OSCAR_CAPABILITY_CHAT)
{
- char *encoding, *utf8name, *tmp;
+ char *utf8name, *tmp;
GHashTable *components;
if (!args->info.chat.roominfo.name || !args->info.chat.roominfo.exchange) {
g_free(message);
return 1;
}
- encoding = args->encoding ? oscar_encoding_extract(args->encoding) : NULL;
- utf8name = oscar_encoding_to_utf8(account, encoding,
- args->info.chat.roominfo.name,
- args->info.chat.roominfo.namelen);
- g_free(encoding);
+ utf8name = oscar_encoding_to_utf8(args->encoding, args->info.chat.roominfo.name, args->info.chat.roominfo.namelen);
tmp = extract_name(utf8name);
if (tmp != NULL)
@@ -2667,8 +1691,7 @@ incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
components);
}
- else if ((args->type & OSCAR_CAPABILITY_SENDFILE) ||
- (args->type & OSCAR_CAPABILITY_DIRECTIM))
+ else if ((args->type & OSCAR_CAPABILITY_SENDFILE) || (args->type & OSCAR_CAPABILITY_DIRECTIM))
{
if (args->status == AIM_RENDEZVOUS_PROPOSE)
{
@@ -2676,7 +1699,7 @@ incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
}
else if (args->status == AIM_RENDEZVOUS_CANCEL)
{
- /* The other user canceled a peer request */
+ /* The other user cancelled a peer request */
PeerConnection *conn;
conn = peer_connection_find_by_cookie(od, userinfo->bn, args->cookie);
@@ -2721,29 +1744,27 @@ incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
purple_debug_info("oscar", "Got an ICQ Server Relay message of "
"type %d\n", args->info.rtfmsg.msgtype);
- if (args->info.rtfmsg.msgtype == 1)
- {
- if (args->info.rtfmsg.rtfmsg != NULL)
- {
- char *rtfmsg = NULL;
- if (args->encoding != NULL) {
- char *encoding = oscar_encoding_extract(args->encoding);
- rtfmsg = oscar_encoding_to_utf8(account, encoding,
- args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg));
- g_free(encoding);
- } else {
- if (g_utf8_validate(args->info.rtfmsg.rtfmsg, strlen(args->info.rtfmsg.rtfmsg), NULL))
- rtfmsg = g_strdup(args->info.rtfmsg.rtfmsg);
- }
- if (rtfmsg) {
- serv_got_im(gc, userinfo->bn, rtfmsg, flags, time(NULL));
- g_free(rtfmsg);
- }
+ if (args->info.rtfmsg.msgtype == 1) {
+ if (args->info.rtfmsg.msg != NULL) {
+ char *rtfmsg = oscar_encoding_to_utf8(args->encoding, args->info.rtfmsg.msg, strlen(args->info.rtfmsg.msg));
+ char *tmp, *tmp2;
+
+ /* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even
+ * the official client doesn't parse them as RTF). Therefore, we should escape them before
+ * showing to the user. */
+ tmp = g_markup_escape_text(rtfmsg, -1);
+ g_free(rtfmsg);
+ tmp2 = purple_strreplace(tmp, "\r\n", "<br>");
+ g_free(tmp);
+
+ serv_got_im(gc, userinfo->bn, tmp2, flags, time(NULL));
+ aim_im_send_icq_confirmation(od, userinfo->bn, args->cookie);
+ g_free(tmp2);
}
- } else if (args->info.rtfmsg.msgtype == 26)
+ } else if (args->info.rtfmsg.msgtype == 26) {
purple_debug_info("oscar", "Sending X-Status Reply\n");
icq_relay_xstatus(od, userinfo->bn, args->cookie);
-
+ }
}
else
{
@@ -2756,122 +1777,6 @@ incomingim_chan2(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
return 1;
}
-/*
- * Authorization Functions
- * Most of these are callbacks from dialogs. They're used by both
- * methods of authorization (SSI and old-school channel 4 ICBM)
- */
-/* When you ask other people for authorization */
-static void
-purple_auth_request(struct name_data *data, char *msg)
-{
- PurpleConnection *gc;
- OscarData *od;
- PurpleAccount *account;
- PurpleBuddy *buddy;
- PurpleGroup *group;
- const char *bname, *gname;
-
- gc = data->gc;
- od = purple_connection_get_protocol_data(gc);
- account = purple_connection_get_account(gc);
- buddy = purple_find_buddy(account, data->name);
- if (buddy != NULL)
- group = purple_buddy_get_group(buddy);
- else
- group = NULL;
-
- if (group != NULL)
- {
- bname = purple_buddy_get_name(buddy);
- gname = purple_group_get_name(group);
- purple_debug_info("oscar", "ssi: adding buddy %s to group %s\n",
- bname, gname);
- aim_ssi_sendauthrequest(od, data->name, msg ? msg : _("Please authorize me so I can add you to my buddy list."));
- if (!aim_ssi_itemlist_finditem(od->ssi.local, gname, bname, AIM_SSI_TYPE_BUDDY))
- {
- aim_ssi_addbuddy(od, bname, gname, NULL, purple_buddy_get_alias_only(buddy), NULL, NULL, TRUE);
-
- /* Mobile users should always be online */
- if (bname[0] == '+') {
- purple_prpl_got_user_status(account,
- purple_buddy_get_name(buddy),
- OSCAR_STATUS_ID_AVAILABLE, NULL);
- purple_prpl_got_user_status(account,
- purple_buddy_get_name(buddy),
- OSCAR_STATUS_ID_MOBILE, NULL);
- }
- }
- }
-
- oscar_free_name_data(data);
-}
-
-static void
-purple_auth_sendrequest(PurpleConnection *gc, const char *name)
-{
- struct name_data *data;
-
- data = g_new0(struct name_data, 1);
- data->gc = gc;
- data->name = g_strdup(name);
-
- purple_request_input(data->gc, NULL, _("Authorization Request Message:"),
- NULL, _("Please authorize me!"), TRUE, FALSE, NULL,
- _("_OK"), G_CALLBACK(purple_auth_request),
- _("_Cancel"), G_CALLBACK(oscar_free_name_data),
- purple_connection_get_account(gc), name, NULL,
- data);
-}
-
-static void
-purple_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored)
-{
- PurpleBuddy *buddy;
- PurpleConnection *gc;
-
- g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
- buddy = (PurpleBuddy *) node;
- gc = purple_account_get_connection(purple_buddy_get_account(buddy));
- purple_auth_sendrequest(gc, purple_buddy_get_name(buddy));
-}
-
-/* When other people ask you for authorization */
-static void
-purple_auth_grant(gpointer cbdata)
-{
- struct name_data *data = cbdata;
- PurpleConnection *gc = data->gc;
- OscarData *od = purple_connection_get_protocol_data(gc);
-
- aim_ssi_sendauthreply(od, data->name, 0x01, NULL);
-
- oscar_free_name_data(data);
-}
-
-/* When other people ask you for authorization */
-static void
-purple_auth_dontgrant(struct name_data *data, char *msg)
-{
- PurpleConnection *gc = data->gc;
- OscarData *od = purple_connection_get_protocol_data(gc);
-
- aim_ssi_sendauthreply(od, data->name, 0x00, msg ? msg : _("No reason given."));
-}
-
-static void
-purple_auth_dontgrant_msgprompt(gpointer cbdata)
-{
- struct name_data *data = cbdata;
- purple_request_input(data->gc, NULL, _("Authorization Denied Message:"),
- NULL, _("No reason given."), TRUE, FALSE, NULL,
- _("_OK"), G_CALLBACK(purple_auth_dontgrant),
- _("_Cancel"), G_CALLBACK(oscar_free_name_data),
- purple_connection_get_account(data->gc), data->name, NULL,
- data);
-}
-
/* When someone sends you buddies */
static void
purple_icq_buddyadd(struct name_data *data)
@@ -2915,7 +1820,7 @@ incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
purple_str_strip_char(msg1[i], '\r');
/* TODO: Should use an encoding other than ASCII? */
- msg2[i] = purple_plugin_oscar_decode_im_part(account, uin, AIM_CHARSET_ASCII, 0x0000, msg1[i], strlen(msg1[i]));
+ msg2[i] = oscar_decode_im(account, uin, AIM_CHARSET_ASCII, msg1[i], strlen(msg1[i]));
g_free(uin);
}
msg2[i] = NULL;
@@ -2968,24 +1873,17 @@ incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
case 0x06: { /* Someone requested authorization */
if (i >= 6) {
- struct name_data *data = g_new(struct name_data, 1);
gchar *bn = g_strdup_printf("%u", args->uin);
gchar *reason = NULL;
if (msg2[5] != NULL)
- reason = purple_plugin_oscar_decode_im_part(account, bn, AIM_CHARSET_LATIN_1, 0x0000, msg2[5], strlen(msg2[5]));
+ reason = oscar_decode_im(account, bn, AIM_CHARSET_LATIN_1, msg2[5], strlen(msg2[5]));
purple_debug_info("oscar",
"Received an authorization request from UIN %u\n",
args->uin);
- data->gc = gc;
- data->name = bn;
- data->nick = NULL;
-
- purple_account_request_authorization(account, bn, NULL, NULL,
- reason, purple_find_buddy(account, bn) != NULL,
- purple_auth_grant,
- purple_auth_dontgrant_msgprompt, data);
+ aim_icq_getalias(od, bn, TRUE, reason);
+ g_free(bn);
g_free(reason);
}
} break;
@@ -3087,7 +1985,8 @@ incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
case 0x1a: { /* Handle SMS or someone has sent you a greeting card or requested buddies? */
ByteStream qbs;
- int smstype, taglen, smslen;
+ guint16 smstype;
+ guint32 taglen, smslen;
char *tagstr = NULL, *smsmsg = NULL;
xmlnode *xmlroot = NULL, *xmltmp = NULL;
gchar *uin = NULL, *message = NULL;
@@ -3101,12 +2000,23 @@ incomingim_chan4(OscarData *od, FlapConnection *conn, aim_userinfo_t *userinfo,
if (smstype != 0)
break;
taglen = byte_stream_getle32(&qbs);
+ if (taglen > 2000) {
+ /* Avoid trying to allocate large amounts of memory, in
+ case we get something unexpected. */
+ break;
+ }
tagstr = byte_stream_getstr(&qbs, taglen);
if (tagstr == NULL)
break;
byte_stream_advance(&qbs, 3);
byte_stream_advance(&qbs, 4);
smslen = byte_stream_getle32(&qbs);
+ if (smslen > 2000) {
+ /* Avoid trying to allocate large amounts of memory, in
+ case we get something unexpected. */
+ g_free(tagstr);
+ break;
+ }
smsmsg = byte_stream_getstr(&qbs, smslen);
/* Check if this is an SMS being sent from server */
@@ -3393,67 +2303,8 @@ static int purple_parse_genericerr(OscarData *od, FlapConnection *conn, FlapFram
reason = (guint16) va_arg(ap, unsigned int);
va_end(ap);
- purple_debug_error("oscar",
- "snac threw error (reason 0x%04hx: %s)\n", reason,
- (reason < msgerrreasonlen) ? msgerrreason[reason] : "unknown");
- return 1;
-}
-
-static int purple_parse_msgerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- PurpleConnection *gc = od->gc;
-#ifdef TODOFT
- OscarData *od = purple_connection_get_protocol_data(gc);
- PurpleXfer *xfer;
-#endif
- va_list ap;
- guint16 reason, errcode;
- char *data, *reason_str, *buf;
-
- va_start(ap, fr);
- reason = (guint16)va_arg(ap, unsigned int);
- errcode = (guint16)va_arg(ap, unsigned int);
- data = va_arg(ap, char *);
- va_end(ap);
-
- purple_debug_error("oscar",
- "Message error with data %s and reason %hu and errcode %hu\n",
- (data != NULL ? data : ""), reason, errcode);
-
- if ((data == NULL) || (*data == '\0'))
- /* We can't do anything if data is empty */
- return 1;
-
-#ifdef TODOFT
- /* If this was a file transfer request, data is a cookie */
- if ((xfer = oscar_find_xfer_by_cookie(od->file_transfers, data))) {
- purple_xfer_cancel_remote(xfer);
- return 1;
- }
-#endif
-
- /* Data is assumed to be the destination bn */
-
- reason_str = g_strdup((reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason"));
- if (errcode != 0 && errcode < errcodereasonlen)
- buf = g_strdup_printf(_("Unable to send message: %s (%s)"), reason_str,
- _(errcodereason[errcode]));
- else
- buf = g_strdup_printf(_("Unable to send message: %s"), reason_str);
-
- if (!purple_conv_present_error(data, purple_connection_get_account(gc), buf)) {
- g_free(buf);
- if (errcode != 0 && errcode < errcodereasonlen)
- buf = g_strdup_printf(_("Unable to send message to %s: %s (%s)"),
- data ? data : "(unknown)", reason_str,
- _(errcodereason[errcode]));
- else
- buf = g_strdup_printf(_("Unable to send message to %s: %s"),
- data ? data : "(unknown)", reason_str);
- purple_notify_error(od->gc, NULL, buf, reason_str);
- }
- g_free(buf);
- g_free(reason_str);
-
+ purple_debug_error("oscar", "snac threw error (reason 0x%04hx: %s)\n",
+ reason, oscar_get_msgerr_reason(reason));
return 1;
}
@@ -3496,104 +2347,6 @@ static int purple_parse_mtn(OscarData *od, FlapConnection *conn, FlapFrame *fr,
return 1;
}
-/*
- * We get this error when there was an error in the locate family. This
- * happens when you request info of someone who is offline.
- */
-static int purple_parse_locerr(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- gchar *buf;
- va_list ap;
- guint16 reason;
- char *destn;
- PurpleNotifyUserInfo *user_info;
-
- va_start(ap, fr);
- reason = (guint16) va_arg(ap, unsigned int);
- destn = va_arg(ap, char *);
- va_end(ap);
-
- if (destn == NULL)
- return 1;
-
- user_info = purple_notify_user_info_new();
- buf = g_strdup_printf(_("User information not available: %s"), (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason."));
- purple_notify_user_info_add_pair(user_info, NULL, buf);
- purple_notify_userinfo(od->gc, destn, user_info, NULL, NULL);
- purple_notify_user_info_destroy(user_info);
- purple_conv_present_error(destn, purple_connection_get_account(od->gc), buf);
- g_free(buf);
-
- return 1;
-}
-
-static int purple_parse_userinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- PurpleConnection *gc = od->gc;
- PurpleAccount *account = purple_connection_get_account(gc);
- PurpleNotifyUserInfo *user_info;
- gchar *tmp = NULL, *info_utf8 = NULL;
- va_list ap;
- aim_userinfo_t *userinfo;
-
- va_start(ap, fr);
- userinfo = va_arg(ap, aim_userinfo_t *);
- va_end(ap);
-
- user_info = purple_notify_user_info_new();
-
- oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE);
-
- if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
- tmp = purple_str_seconds_to_string(userinfo->idletime*60);
- oscar_user_info_add_pair(user_info, _("Idle"), tmp);
- g_free(tmp);
- }
-
- oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
-
- if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
- /* An SMS contact is always online; its Online Since value is not useful */
- time_t t = userinfo->onlinesince;
- oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
- }
-
- if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) {
- time_t t = userinfo->membersince;
- oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t)));
- }
-
- if (userinfo->capabilities != 0) {
- tmp = oscar_caps_to_string(userinfo->capabilities);
- oscar_user_info_add_pair(user_info, _("Capabilities"), tmp);
- g_free(tmp);
- }
-
- /* Info */
- if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) {
- tmp = oscar_encoding_extract(userinfo->info_encoding);
- info_utf8 = oscar_encoding_to_utf8(account, tmp, userinfo->info,
- userinfo->info_len);
- g_free(tmp);
- if (info_utf8 != NULL) {
- tmp = purple_str_sub_away_formatters(info_utf8, purple_account_get_username(account));
- purple_notify_user_info_add_section_break(user_info);
- oscar_user_info_add_pair(user_info, _("Profile"), tmp);
- g_free(tmp);
- g_free(info_utf8);
- }
- }
-
- purple_notify_user_info_add_section_break(user_info);
- tmp = g_strdup_printf("<a href=\"http://profiles.aim.com/%s\">%s</a>",
- purple_normalize(account, userinfo->bn), _("View web profile"));
- purple_notify_user_info_add_pair(user_info, NULL, tmp);
- g_free(tmp);
-
- purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL);
- purple_notify_user_info_destroy(user_info);
-
- return 1;
-}
-
static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
{
char *msg;
@@ -3736,13 +2489,7 @@ static int purple_conv_chat_leave(OscarData *od, FlapConnection *conn, FlapFrame
static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
va_list ap;
- aim_userinfo_t *userinfo;
- struct aim_chat_roominfo *roominfo;
- char *roomname;
- int usercount;
- char *roomdesc;
- guint16 unknown_c9, unknown_d2, unknown_d5, maxmsglen, maxvisiblemsglen;
- guint32 creationtime;
+ guint16 maxmsglen, maxvisiblemsglen;
PurpleConnection *gc = od->gc;
struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
@@ -3750,16 +2497,7 @@ static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, Fla
return 1;
va_start(ap, fr);
- roominfo = va_arg(ap, struct aim_chat_roominfo *);
- roomname = va_arg(ap, char *);
- usercount= va_arg(ap, int);
- userinfo = va_arg(ap, aim_userinfo_t *);
- roomdesc = va_arg(ap, char *);
- unknown_c9 = (guint16)va_arg(ap, unsigned int);
- creationtime = va_arg(ap, guint32);
maxmsglen = (guint16)va_arg(ap, unsigned int);
- unknown_d2 = (guint16)va_arg(ap, unsigned int);
- unknown_d5 = (guint16)va_arg(ap, unsigned int);
maxvisiblemsglen = (guint16)va_arg(ap, unsigned int);
va_end(ap);
@@ -3775,7 +2513,6 @@ static int purple_conv_chat_info_update(OscarData *od, FlapConnection *conn, Fla
static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
PurpleConnection *gc = od->gc;
- PurpleAccount *account = purple_connection_get_account(gc);
struct chat_connection *ccon = find_oscar_chat_by_conn(gc, conn);
gchar *utf8;
va_list ap;
@@ -3794,10 +2531,7 @@ static int purple_conv_chat_incoming_msg(OscarData *od, FlapConnection *conn, Fl
charset = va_arg(ap, char *);
va_end(ap);
- utf8 = oscar_encoding_to_utf8(account, charset, msg, len);
- if (utf8 == NULL)
- /* The conversion failed! */
- utf8 = g_strdup(_("[Unable to display a message from this user because it contained invalid characters.]"));
+ utf8 = oscar_encoding_to_utf8(charset, msg, len);
serv_got_chat_in(gc, ccon->id, info->bn, 0, utf8, time(NULL));
g_free(utf8);
@@ -3915,41 +2649,6 @@ purple_icons_fetch(PurpleConnection *gc)
purple_debug_misc("oscar", "no more icons to request\n");
}
-/*
- * Received in response to an IM sent with the AIM_IMFLAGS_ACK option.
- */
-static int purple_parse_msgack(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- va_list ap;
- guint16 type;
- char *bn;
-
- va_start(ap, fr);
- type = (guint16) va_arg(ap, unsigned int);
- bn = va_arg(ap, char *);
- va_end(ap);
-
- purple_debug_info("oscar", "Sent message to %s.\n", bn);
-
- return 1;
-}
-
-static int purple_parse_evilnotify(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
-#ifdef CRAZY_WARNING
- va_list ap;
- guint16 newevil;
- aim_userinfo_t *userinfo;
-
- va_start(ap, fr);
- newevil = (guint16) va_arg(ap, unsigned int);
- userinfo = va_arg(ap, aim_userinfo_t *);
- va_end(ap);
-
- purple_prpl_got_account_warning_level(account, (userinfo && userinfo->bn) ? userinfo->bn : NULL, (newevil/10.0) + 0.5);
-#endif
-
- return 1;
-}
-
static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
int warning_level;
va_list ap;
@@ -3970,10 +2669,6 @@ static int purple_selfinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, .
*/
warning_level = info->warnlevel/10.0 + 0.5;
-#ifdef CRAZY_WARNING
- purple_presence_set_warning_level(presence, warning_level);
-#endif
-
return 1;
}
@@ -4112,16 +2807,14 @@ static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr,
tmp = purple_markup_strip_html(message);
itmsurl = purple_status_get_attr_string(status, "itmsurl");
aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl);
+ aim_srv_set_dc_info(od);
g_free(tmp);
presence = purple_status_get_presence(status);
aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence));
if (od->icq) {
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
- aim_icq_reqofflinemsgs(od);
-#endif
- oscar_set_extendedstatus(gc);
+ oscar_set_extended_status(gc);
aim_icq_setsecurity(od,
purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
@@ -4153,206 +2846,6 @@ static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr,
return 1;
}
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-static int purple_offlinemsg(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- va_list ap;
- struct aim_icq_offlinemsg *msg;
- struct aim_incomingim_ch4_args args;
- time_t t;
-
- va_start(ap, fr);
- msg = va_arg(ap, struct aim_icq_offlinemsg *);
- va_end(ap);
-
- purple_debug_info("oscar",
- "Received offline message. Converting to channel 4 ICBM...\n");
- args.uin = msg->sender;
- args.type = msg->type;
- args.flags = msg->flags;
- args.msglen = msg->msglen;
- args.msg = msg->msg;
- t = purple_time_build(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0);
- incomingim_chan4(od, conn, NULL, &args, t);
-
- return 1;
-}
-
-static int purple_offlinemsgdone(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
- aim_icq_ackofflinemsgs(od);
- return 1;
-}
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
-
-static int purple_icqinfo(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
- PurpleConnection *gc;
- PurpleAccount *account;
- PurpleBuddy *buddy;
- struct buddyinfo *bi;
- gchar who[16];
- PurpleNotifyUserInfo *user_info;
- gchar *utf8;
- gchar *buf;
- const gchar *alias;
- va_list ap;
- struct aim_icq_info *info;
-
- gc = od->gc;
- account = purple_connection_get_account(gc);
-
- va_start(ap, fr);
- info = va_arg(ap, struct aim_icq_info *);
- va_end(ap);
-
- if (!info->uin)
- return 0;
-
- user_info = purple_notify_user_info_new();
-
- g_snprintf(who, sizeof(who), "%u", info->uin);
- buddy = purple_find_buddy(account, who);
- if (buddy != NULL)
- bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
- else
- bi = NULL;
-
- purple_notify_user_info_add_pair(user_info, _("UIN"), who);
- oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick);
- if ((bi != NULL) && (bi->ipaddr != 0)) {
- char *tstr = g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
- (bi->ipaddr & 0xff000000) >> 24,
- (bi->ipaddr & 0x00ff0000) >> 16,
- (bi->ipaddr & 0x0000ff00) >> 8,
- (bi->ipaddr & 0x000000ff));
- purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr);
- g_free(tstr);
- }
- oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first);
- oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last);
- if (info->email && info->email[0] && (utf8 = oscar_utf8_try_convert(account, od, info->email))) {
- buf = g_strdup_printf("<a href=\"mailto:%s\">%s</a>", utf8, utf8);
- purple_notify_user_info_add_pair(user_info, _("Email Address"), buf);
- g_free(buf);
- g_free(utf8);
- }
- if (info->numaddresses && info->email2) {
- int i;
- for (i = 0; i < info->numaddresses; i++) {
- if (info->email2[i] && info->email2[i][0] && (utf8 = oscar_utf8_try_convert(account, od, info->email2[i]))) {
- buf = g_strdup_printf("<a href=\"mailto:%s\">%s</a>", utf8, utf8);
- purple_notify_user_info_add_pair(user_info, _("Email Address"), buf);
- g_free(buf);
- g_free(utf8);
- }
- }
- }
- oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile);
-
- if (info->gender != 0)
- purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male")));
-
- if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) {
- /* Initialize the struct properly or strftime() will crash
- * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
- time_t t = time(NULL);
- struct tm *tm = localtime(&t);
-
- tm->tm_mday = (int)info->birthday;
- tm->tm_mon = (int)info->birthmonth - 1;
- tm->tm_year = (int)info->birthyear - 1900;
-
- /* To be 100% sure that the fields are re-normalized.
- * If you're sure strftime() ALWAYS does this EVERYWHERE,
- * feel free to remove it. --rlaager */
- mktime(tm);
-
- oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm));
- }
- if ((info->age > 0) && (info->age < 255)) {
- char age[5];
- snprintf(age, sizeof(age), "%hhd", info->age);
- purple_notify_user_info_add_pair(user_info, _("Age"), age);
- }
- if (info->personalwebpage && info->personalwebpage[0] && (utf8 = oscar_utf8_try_convert(account, od, info->personalwebpage))) {
- buf = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8);
- purple_notify_user_info_add_pair(user_info, _("Personal Web Page"), buf);
- g_free(buf);
- g_free(utf8);
- }
-
- if (buddy != NULL)
- oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE);
-
- oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info);
- purple_notify_user_info_add_section_break(user_info);
-
- if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
- purple_notify_user_info_add_section_header(user_info, _("Home Address"));
-
- oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr);
- oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity);
- oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate);
- oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip);
- }
- if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
- purple_notify_user_info_add_section_header(user_info, _("Work Address"));
-
- oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr);
- oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity);
- oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate);
- oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip);
- }
- if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
- purple_notify_user_info_add_section_header(user_info, _("Work Information"));
-
- oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany);
- oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision);
- oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition);
-
- if (info->workwebpage && info->workwebpage[0] && (utf8 = oscar_utf8_try_convert(account, od, info->workwebpage))) {
- char *webpage = g_strdup_printf("<a href=\"%s\">%s</a>", utf8, utf8);
- purple_notify_user_info_add_pair(user_info, _("Web Page"), webpage);
- g_free(webpage);
- g_free(utf8);
- }
- }
-
- if (buddy != NULL)
- alias = purple_buddy_get_alias(buddy);
- else
- alias = who;
- purple_notify_userinfo(gc, who, user_info, NULL, NULL);
- purple_notify_user_info_destroy(user_info);
-
- return 1;
-}
-
-static int purple_icqalias(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
-{
- PurpleConnection *gc = od->gc;
- PurpleAccount *account = purple_connection_get_account(gc);
- gchar who[16], *utf8;
- PurpleBuddy *b;
- va_list ap;
- struct aim_icq_info *info;
-
- va_start(ap, fr);
- info = va_arg(ap, struct aim_icq_info *);
- va_end(ap);
-
- if (info->uin && info->nick && info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
- g_snprintf(who, sizeof(who), "%u", info->uin);
- serv_got_alias(gc, who, utf8);
- if ((b = purple_find_buddy(account, who))) {
- purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
- }
- g_free(utf8);
- }
-
- return 1;
-}
-
static int purple_popup(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
{
PurpleConnection *gc = od->gc;
@@ -4577,8 +3070,8 @@ purple_odc_send_im(PeerConnection *conn, const char *message, PurpleMessageFlags
GString *msg;
GString *data;
gchar *tmp;
- int tmplen;
- guint16 charset, charsubset;
+ gsize tmplen;
+ guint16 charset;
GData *attribs;
const char *start, *end, *last;
int oscar_id = 0;
@@ -4639,8 +3132,7 @@ purple_odc_send_im(PeerConnection *conn, const char *message, PurpleMessageFlags
g_string_append(msg, "</BODY></HTML>");
/* Convert the message to a good encoding */
- purple_plugin_oscar_convert_to_best_encoding(conn->od->gc,
- conn->bn, msg->str, &tmp, &tmplen, &charset, &charsubset);
+ tmp = oscar_encode_im(msg->str, &tmplen, &charset, NULL);
g_string_free(msg, TRUE);
msg = g_string_new_len(tmp, tmplen);
g_free(tmp);
@@ -4687,7 +3179,7 @@ oscar_send_im(PurpleConnection *gc, const char *name, const char *message, Purpl
}
if (imflags & PURPLE_MESSAGE_AUTO_RESP)
- tmp1 = purple_str_sub_away_formatters(message, name);
+ tmp1 = oscar_util_format_string(message, name);
else
tmp1 = g_strdup(message);
@@ -4720,26 +3212,14 @@ oscar_send_im(PurpleConnection *gc, const char *name, const char *message, Purpl
g_hash_table_insert(od->buddyinfo, g_strdup(purple_normalize(account, name)), bi);
}
- args.flags = AIM_IMFLAGS_ACK | AIM_IMFLAGS_CUSTOMFEATURES;
+ args.flags = 0;
if (!is_sms && (!buddy || !PURPLE_BUDDY_IS_ONLINE(buddy)))
args.flags |= AIM_IMFLAGS_OFFLINE;
if (od->icq) {
- /* We have to present different "features" (whose meaning
- is unclear and are merely a result of protocol inspection)
- to offline ICQ buddies. Otherwise, the official
- ICQ client doesn't treat those messages as being "ANSI-
- encoded" (and instead, assumes them to be UTF-8).
- For more details, see SF issue 1179452.
- */
- if (buddy && PURPLE_BUDDY_IS_ONLINE(buddy)) {
- args.features = features_icq;
- args.featureslen = sizeof(features_icq);
- } else {
- args.features = features_icq_offline;
- args.featureslen = sizeof(features_icq_offline);
- }
+ args.features = features_icq;
+ args.featureslen = sizeof(features_icq);
} else {
args.features = features_aim;
args.featureslen = sizeof(features_aim);
@@ -4789,32 +3269,19 @@ oscar_send_im(PurpleConnection *gc, const char *name, const char *message, Purpl
args.destbn = name;
- /*
- * If we're IMing an SMS user or an ICQ user from an ICQ account, then strip HTML.
- */
if (oscar_util_valid_name_sms(name)) {
- /* Messaging an SMS (mobile) user */
+ /* Messaging an SMS (mobile) user--strip HTML */
tmp2 = purple_markup_strip_html(tmp1);
is_html = FALSE;
- } else if (od->icq) {
- if (oscar_util_valid_name_icq(name)) {
- /* From ICQ to ICQ */
- tmp2 = purple_markup_strip_html(tmp1);
- is_html = FALSE;
- } else {
- /* From ICQ to AIM */
- tmp2 = g_strdup(tmp1);
- is_html = TRUE;
- }
} else {
- /* From AIM to AIM and AIM to ICQ */
- tmp2 = g_strdup(tmp1);
+ /* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */
+ tmp2 = g_strdup_printf("<HTML><BODY>%s</BODY></HTML>", tmp1);
is_html = TRUE;
}
g_free(tmp1);
tmp1 = tmp2;
- purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset);
+ args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
if (is_html && (args.msglen > MAXMSGLEN)) {
/* If the length was too long, try stripping the HTML and then running it back through
* purple_strdup_withhtml() and the encoding process. The result may be shorter. */
@@ -4831,14 +3298,12 @@ oscar_send_im(PurpleConnection *gc, const char *name, const char *message, Purpl
g_free(tmp1);
tmp1 = tmp2;
- purple_plugin_oscar_convert_to_best_encoding(gc, name, tmp1, (char **)&args.msg, &args.msglen, &args.charset, &args.charsubset);
-
+ args.msg = oscar_encode_im(tmp1, &args.msglen, &args.charset, NULL);
purple_debug_info("oscar", "Sending %s as %s because the original was too long.\n",
message, (char *)args.msg);
}
- purple_debug_info("oscar", "Sending IM, charset=0x%04hx, charsubset=0x%04hx, length=%d\n",
- args.charset, args.charsubset, args.msglen);
+ purple_debug_info("oscar", "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT "\n", args.charset, args.msglen);
ret = aim_im_sendch1_ext(od, &args);
g_free((char *)args.msg);
}
@@ -4865,43 +3330,11 @@ void oscar_get_info(PurpleConnection *gc, const char *name) {
aim_locate_getinfoshort(od, name, 0x00000003);
}
-#if 0
-static void oscar_set_dir(PurpleConnection *gc, const char *first, const char *middle, const char *last,
- const char *maiden, const char *city, const char *state, const char *country, int web) {
- /* XXX - some of these things are wrong, but i'm lazy */
- OscarData *od = purple_connection_get_protocol_data(gc);
- aim_locate_setdirinfo(od, first, middle, last,
- maiden, NULL, NULL, city, state, NULL, 0, web);
-}
-#endif
-
void oscar_set_idle(PurpleConnection *gc, int time) {
OscarData *od = purple_connection_get_protocol_data(gc);
aim_srv_setidle(od, time);
}
-static
-gchar *purple_prpl_oscar_convert_to_infotext(const gchar *str, gsize *ret_len, char **encoding)
-{
- int charset = 0;
- char *encoded = NULL;
-
- charset = oscar_charset_check(str);
- if (charset == AIM_CHARSET_UNICODE) {
- encoded = g_convert(str, -1, "UTF-16BE", "UTF-8", NULL, ret_len, NULL);
- *encoding = "unicode-2-0";
- } else if (charset == AIM_CHARSET_LATIN_1) {
- encoded = g_convert(str, -1, "ISO-8859-1", "UTF-8", NULL, ret_len, NULL);
- *encoding = "iso-8859-1";
- } else {
- encoded = g_strdup(str);
- *ret_len = strlen(str);
- *encoding = "us-ascii";
- }
-
- return encoded;
-}
-
void
oscar_set_info(PurpleConnection *gc, const char *rawinfo)
{
@@ -4913,8 +3346,8 @@ oscar_set_info(PurpleConnection *gc, const char *rawinfo)
oscar_set_info_and_status(account, TRUE, rawinfo, FALSE, status);
}
-static void
-oscar_set_extendedstatus(PurpleConnection *gc)
+static guint32
+oscar_get_extended_status(PurpleConnection *gc)
{
OscarData *od;
PurpleAccount *account;
@@ -4958,7 +3391,13 @@ oscar_set_extendedstatus(PurpleConnection *gc)
else if (!strcmp(status_id, OSCAR_STATUS_ID_CUSTOM))
data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY;
- aim_srv_setextrainfo(od, TRUE, data, FALSE, NULL, NULL);
+ return data;
+}
+
+static void
+oscar_set_extended_status(PurpleConnection *gc)
+{
+ aim_srv_setextrainfo(purple_connection_get_protocol_data(gc), TRUE, oscar_get_extended_status(gc), FALSE, NULL, NULL);
}
static void
@@ -4999,7 +3438,7 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
else if (rawinfo != NULL)
{
char *htmlinfo = purple_strdup_withhtml(rawinfo);
- info = purple_prpl_oscar_convert_to_infotext(htmlinfo, &infolen, &info_encoding);
+ info = oscar_encode_im(htmlinfo, &infolen, NULL, &info_encoding);
g_free(htmlinfo);
if (infolen > od->rights.maxsiglen)
@@ -5032,7 +3471,7 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
/* We do this for icq too so that they work for old third party clients */
linkified = purple_markup_linkify(status_html);
- away = purple_prpl_oscar_convert_to_infotext(linkified, &awaylen, &away_encoding);
+ away = oscar_encode_im(linkified, &awaylen, NULL, &away_encoding);
g_free(linkified);
if (awaylen > od->rights.maxawaymsglen)
@@ -5061,8 +3500,6 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
const char *status_html;
status_html = purple_status_get_attr_string(status, "message");
- if (od->icq && (status_html == NULL || status_html[0] == '\0'))
- status_html = purple_status_type_get_name(status_type);
if (status_html != NULL)
{
status_text = purple_markup_strip_html(status_html);
@@ -5075,28 +3512,27 @@ oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *
}
itmsurl = purple_status_get_attr_string(status, "itmsurl");
-
- /* TODO: Combine these two calls! */
- aim_srv_setextrainfo(od, FALSE, 0, TRUE, status_text, itmsurl);
- oscar_set_extendedstatus(gc);
+
+ aim_srv_setextrainfo(od, TRUE, oscar_get_extended_status(gc), TRUE, status_text, itmsurl);
g_free(status_text);
}
}
static void
-oscar_set_status_icq(PurpleAccount *account)
+oscar_set_icq_permdeny(PurpleAccount *account)
{
PurpleConnection *gc = purple_account_get_connection(account);
-
- /* Our permit/deny setting affects our invisibility */
- oscar_set_permit_deny(gc);
+ OscarData *od = purple_connection_get_protocol_data(gc);
+ gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
/*
- * TODO: I guess we should probably wait and do this after we get
- * confirmation from the above SSI call? Right now other people
- * see our status blip to "invisible" before we appear offline.
+ * For ICQ the permit/deny setting controls who can see you
+ * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS
+ * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise.
+ * In the former case, we are visible only to buddies on our "permanently visible" list.
+ * In the latter, we are invisible only to buddies on our "permanently invisible" list.
*/
- oscar_set_extendedstatus(gc);
+ aim_ssi_setpermdeny(od, invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS);
}
void
@@ -5122,21 +3558,14 @@ oscar_set_status(PurpleAccount *account, PurpleStatus *status)
return;
}
+ if (od->icq) {
+ /* Set visibility */
+ oscar_set_icq_permdeny(account);
+ }
+
/* Set the AIM-style away message for both AIM and ICQ accounts */
oscar_set_info_and_status(account, FALSE, NULL, TRUE, status);
-
- /* Set the ICQ status for ICQ accounts only */
- if (od->icq)
- oscar_set_status_icq(account);
-}
-
-#ifdef CRAZY_WARN
-void
-oscar_warn(PurpleConnection *gc, const char *name, gboolean anonymous) {
- OscarData *od = purple_connection_get_protocol_data(gc);
- aim_im_warn(od, od->conn, name, anonymous ? AIM_WARN_ANON : 0);
}
-#endif
void
oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
@@ -5179,13 +3608,13 @@ oscar_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
aim_ssi_itemlist_findparentname(od->ssi.local, bname),
bname)) {
/* Not authorized -- Re-request authorization */
- purple_auth_sendrequest(gc, bname);
+ oscar_auth_sendrequest(gc, bname);
}
}
/* XXX - Should this be done from AIM accounts, as well? */
if (od->icq)
- aim_icq_getalias(od, bname);
+ aim_icq_getalias(od, bname, FALSE, NULL);
}
void oscar_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
@@ -5295,8 +3724,6 @@ static int purple_ssi_parseerr(OscarData *od, FlapConnection *conn, FlapFrame *f
return 1;
}
- oscar_set_status_icq(purple_connection_get_account(gc));
-
return 1;
}
@@ -5337,12 +3764,14 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
PurpleAccount *account;
PurpleGroup *g;
PurpleBuddy *b;
+ GSList *cur, *next, *buddies;
struct aim_ssi_item *curitem;
guint32 tmp;
PurpleStoredImage *img;
va_list ap;
guint16 fmtver, numitems;
guint32 timestamp;
+ guint16 deny_entry_type = aim_ssi_getdenyentrytype(od);
gc = od->gc;
od = purple_connection_get_protocol_data(gc);
@@ -5355,110 +3784,109 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
va_end(ap);
/* Don't attempt to re-request our buddy list later */
- if (od->getblisttimer != 0)
+ if (od->getblisttimer != 0) {
purple_timeout_remove(od->getblisttimer);
- od->getblisttimer = 0;
+ od->getblisttimer = 0;
+ }
- purple_debug_info("oscar",
- "ssi: syncing local list and server list\n");
+ purple_debug_info("oscar", "ssi: syncing local list and server list\n");
/* Clean the buddy list */
aim_ssi_cleanlist(od);
- { /* If not in server list then prune from local list */
- GSList *cur, *next;
- GSList *buddies = purple_find_buddies(account, NULL);
-
- /* Buddies */
- cur = NULL;
-
- while(buddies) {
- PurpleGroup *g;
- const char *gname;
- const char *bname;
-
- b = buddies->data;
- g = purple_buddy_get_group(b);
- gname = purple_group_get_name(g);
- bname = purple_buddy_get_name(b);
-
- if (aim_ssi_itemlist_exists(od->ssi.local, bname)) {
- /* If the buddy is an ICQ user then load his nickname */
- const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick");
- char *alias;
- const char *balias;
- if (servernick)
- serv_got_alias(gc, bname, servernick);
-
- /* Store local alias on server */
- alias = aim_ssi_getalias(od->ssi.local, gname, bname);
- balias = purple_buddy_get_local_buddy_alias(b);
- if (!alias && balias && *balias)
- aim_ssi_aliasbuddy(od, gname, bname, balias);
- g_free(alias);
- } else {
- purple_debug_info("oscar",
- "ssi: removing buddy %s from local list\n", bname);
- /* We can't actually remove now because it will screw up our looping */
- cur = g_slist_prepend(cur, b);
- }
- buddies = g_slist_delete_link(buddies, buddies);
- }
+ /*** Begin code for pruning buddies from local list if they're not in server list ***/
+
+ /* Buddies */
+ cur = NULL;
+ for (buddies = purple_find_buddies(account, NULL);
+ buddies;
+ buddies = g_slist_delete_link(buddies, buddies))
+ {
+ PurpleGroup *g;
+ const char *gname;
+ const char *bname;
- while (cur != NULL) {
- b = cur->data;
- cur = g_slist_remove(cur, b);
- purple_blist_remove_buddy(b);
+ b = buddies->data;
+ g = purple_buddy_get_group(b);
+ gname = purple_group_get_name(g);
+ bname = purple_buddy_get_name(b);
+
+ if (aim_ssi_itemlist_exists(od->ssi.local, bname)) {
+ /* If the buddy is an ICQ user then load his nickname */
+ const char *servernick = purple_blist_node_get_string((PurpleBlistNode*)b, "servernick");
+ char *alias;
+ const char *balias;
+ if (servernick)
+ serv_got_alias(gc, bname, servernick);
+
+ /* Store local alias on server */
+ alias = aim_ssi_getalias(od->ssi.local, gname, bname);
+ balias = purple_buddy_get_local_buddy_alias(b);
+ if (!alias && balias && *balias)
+ aim_ssi_aliasbuddy(od, gname, bname, balias);
+ g_free(alias);
+ } else {
+ purple_debug_info("oscar",
+ "ssi: removing buddy %s from local list\n", bname);
+ /* Queue the buddy for removal from the local list */
+ cur = g_slist_prepend(cur, b);
}
+ }
+ while (cur != NULL) {
+ purple_blist_remove_buddy(cur->data);
+ cur = g_slist_delete_link(cur, cur);
+ }
- /* Permit list */
- if (account->permit) {
- next = account->permit;
- while (next != NULL) {
- cur = next;
- next = next->next;
- if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
- purple_debug_info("oscar",
- "ssi: removing permit %s from local list\n", (const char *)cur->data);
- purple_privacy_permit_remove(account, cur->data, TRUE);
- }
+ /* Permit list (ICQ doesn't have one) */
+ if (!od->icq) {
+ next = account->permit;
+ while (next != NULL) {
+ cur = next;
+ next = next->next;
+ if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_PERMIT)) {
+ purple_debug_info("oscar",
+ "ssi: removing permit %s from local list\n", (const char *)cur->data);
+ purple_privacy_permit_remove(account, cur->data, TRUE);
}
}
+ }
- /* Deny list */
- if (account->deny) {
- next = account->deny;
- while (next != NULL) {
- cur = next;
- next = next->next;
- if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, AIM_SSI_TYPE_DENY)) {
- purple_debug_info("oscar",
- "ssi: removing deny %s from local list\n", (const char *)cur->data);
- purple_privacy_deny_remove(account, cur->data, TRUE);
- }
- }
+ /* Deny list */
+ next = account->deny;
+ while (next != NULL) {
+ cur = next;
+ next = next->next;
+ if (!aim_ssi_itemlist_finditem(od->ssi.local, NULL, cur->data, deny_entry_type)) {
+ purple_debug_info("oscar",
+ "ssi: removing deny %s from local list\n", (const char *)cur->data);
+ purple_privacy_deny_remove(account, cur->data, TRUE);
}
- /* Presence settings (idle time visibility) */
- tmp = aim_ssi_getpresence(od->ssi.local);
- if (tmp != 0xFFFFFFFF) {
- const char *idle_reporting_pref;
- gboolean report_idle;
+ }
- idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
- report_idle = strcmp(idle_reporting_pref, "none") != 0;
+ /* Presence settings (idle time visibility) */
+ tmp = aim_ssi_getpresence(od->ssi.local);
+ if (tmp != 0xFFFFFFFF) {
+ const char *idle_reporting_pref;
+ gboolean report_idle;
- if (report_idle)
- aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
- else
- aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
- }
+ idle_reporting_pref = purple_prefs_get_string("/purple/away/idle_reporting");
+ report_idle = strcmp(idle_reporting_pref, "none") != 0;
+
+ if (report_idle)
+ aim_ssi_setpresence(od, tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
+ else
+ aim_ssi_setpresence(od, tmp & ~AIM_SSI_PRESENCE_FLAG_SHOWIDLE);
+ }
+ /*** End code for pruning buddies from local list ***/
- } /* end pruning buddies from local list */
+ /*** Begin code for adding from server list to local list ***/
- /* Add from server list to local list */
for (curitem=od->ssi.local; curitem; curitem=curitem->next) {
- if ((curitem->name == NULL) || (g_utf8_validate(curitem->name, -1, NULL)))
+ if (curitem->name && !g_utf8_validate(curitem->name, -1, NULL))
+ /* Got node with invalid UTF-8 in the name. Skip it. */
+ break;
+
switch (curitem->type) {
case AIM_SSI_TYPE_BUDDY: { /* Buddy */
if (curitem->name) {
@@ -5467,13 +3895,7 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
groupitem = aim_ssi_itemlist_find(od->ssi.local, curitem->gid, 0x0000);
gname = groupitem ? groupitem->name : NULL;
- if (gname != NULL) {
- if (g_utf8_validate(gname, -1, NULL))
- gname_utf8 = g_strdup(gname);
- else
- gname_utf8 = oscar_utf8_try_convert(account, od, gname);
- } else
- gname_utf8 = NULL;
+ gname_utf8 = oscar_utf8_try_convert(account, od, gname);
g = purple_find_group(gname_utf8 ? gname_utf8 : _("Orphans"));
if (g == NULL) {
@@ -5482,14 +3904,7 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
}
alias = aim_ssi_getalias(od->ssi.local, gname, curitem->name);
- if (alias != NULL) {
- if (g_utf8_validate(alias, -1, NULL))
- alias_utf8 = g_strdup(alias);
- else
- alias_utf8 = oscar_utf8_try_convert(account, od, alias);
- g_free(alias);
- } else
- alias_utf8 = NULL;
+ alias_utf8 = oscar_utf8_try_convert(account, od, alias);
b = purple_find_buddy_in_group(account, curitem->name, g);
if (b) {
@@ -5531,13 +3946,7 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
char *gname_utf8;
gname = curitem->name;
- if (gname != NULL) {
- if (g_utf8_validate(gname, -1, NULL))
- gname_utf8 = g_strdup(gname);
- else
- gname_utf8 = oscar_utf8_try_convert(account, od, gname);
- } else
- gname_utf8 = NULL;
+ gname_utf8 = oscar_utf8_try_convert(account, od, gname);
if (gname_utf8 != NULL && purple_find_group(gname_utf8) == NULL) {
g = purple_group_new(gname_utf8);
@@ -5546,12 +3955,10 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
g_free(gname_utf8);
} break;
- case AIM_SSI_TYPE_PERMIT: { /* Permit buddy */
- if (curitem->name) {
- /* if (!find_permdeny_by_name(gc->permit, curitem->name)) { AAA */
- GSList *list;
- for (list=account->permit; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
- if (!list) {
+ case AIM_SSI_TYPE_PERMIT: { /* Permit buddy (unless we're on ICQ) */
+ if (!od->icq && curitem->name) {
+ for (cur = account->permit; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+ if (!cur) {
purple_debug_info("oscar",
"ssi: adding permit buddy %s to local list\n", curitem->name);
purple_privacy_permit_add(account, curitem->name, TRUE);
@@ -5559,11 +3966,11 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
}
} break;
+ case AIM_SSI_TYPE_ICQDENY:
case AIM_SSI_TYPE_DENY: { /* Deny buddy */
- if (curitem->name) {
- GSList *list;
- for (list=account->deny; (list && oscar_util_name_compare(curitem->name, list->data)); list=list->next);
- if (!list) {
+ if (curitem->type == deny_entry_type && curitem->name) {
+ for (cur = account->deny; (cur && oscar_util_name_compare(curitem->name, cur->data)); cur = cur->next);
+ if (!cur) {
purple_debug_info("oscar",
"ssi: adding deny buddy %s to local list\n", curitem->name);
purple_privacy_deny_add(account, curitem->name, TRUE);
@@ -5595,7 +4002,13 @@ static int purple_ssi_parselist(OscarData *od, FlapConnection *conn, FlapFrame *
} /* End of switch on curitem->type */
} /* End of for loop */
- oscar_set_status_icq(account);
+ /*** End code for adding from server list to local list ***/
+
+ if (od->icq) {
+ oscar_set_icq_permdeny(account);
+ } else {
+ oscar_set_aim_permdeny(gc);
+ }
/* Activate SSI */
/* Sending the enable causes other people to be able to see you, and you to see them */
@@ -5657,7 +4070,7 @@ static int purple_ssi_parseack(OscarData *od, FlapConnection *conn, FlapFrame *f
case 0x000e: { /* buddy requires authorization */
if ((retval->action == SNAC_SUBTYPE_FEEDBAG_ADD) && (retval->name))
- purple_auth_sendrequest(gc, retval->name);
+ oscar_auth_sendrequest(gc, retval->name);
} break;
default: { /* La la la */
@@ -5706,15 +4119,7 @@ purple_ssi_parseaddmod(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
gname_utf8 = gname ? oscar_utf8_try_convert(account, od, gname) : NULL;
alias = aim_ssi_getalias(od->ssi.local, gname, name);
- if (alias != NULL)
- {
- if (g_utf8_validate(alias, -1, NULL))
- alias_utf8 = g_strdup(alias);
- else
- alias_utf8 = oscar_utf8_try_convert(account, od, alias);
- }
- else
- alias_utf8 = NULL;
+ alias_utf8 = oscar_utf8_try_convert(account, od, alias);
g_free(alias);
b = purple_find_buddy(account, name);
@@ -5809,24 +4214,18 @@ static int purple_ssi_authgiven(OscarData *od, FlapConnection *conn, FlapFrame *
static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
{
- PurpleConnection *gc = od->gc;
va_list ap;
const char *bn;
- const char *msg;
- PurpleAccount *account = purple_connection_get_account(gc);
- struct name_data *data;
- PurpleBuddy *buddy;
+ char *msg;
va_start(ap, fr);
bn = va_arg(ap, const char *);
- msg = va_arg(ap, const char *);
+ msg = va_arg(ap, char *);
va_end(ap);
purple_debug_info("oscar",
"ssi: received authorization request from %s\n", bn);
- buddy = purple_find_buddy(account, bn);
-
if (!msg) {
purple_debug_warning("oscar", "Received auth request from %s with "
"empty message\n", bn);
@@ -5836,16 +4235,7 @@ static int purple_ssi_authrequest(OscarData *od, FlapConnection *conn, FlapFrame
msg = NULL;
}
- data = g_new(struct name_data, 1);
- data->gc = gc;
- data->name = g_strdup(bn);
- data->nick = (buddy ? g_strdup(purple_buddy_get_alias_only(buddy)) : NULL);
-
- purple_account_request_authorization(account, bn, NULL,
- (buddy ? purple_buddy_get_alias_only(buddy) : NULL),
- msg, buddy != NULL, purple_auth_grant,
- purple_auth_dontgrant_msgprompt, data);
-
+ aim_icq_getalias(od, bn, TRUE, msg);
return 1;
}
@@ -6018,9 +4408,9 @@ int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMes
PurpleConversation *conv = NULL;
struct chat_connection *c = NULL;
char *buf, *buf2, *buf3;
- guint16 charset, charsubset;
- char *charsetstr = NULL;
- int len;
+ guint16 charset;
+ char *charsetstr;
+ gsize len;
if (!(conv = purple_find_chat(gc, id)))
return -EINVAL;
@@ -6036,7 +4426,7 @@ int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMes
"You cannot send IM Images in AIM chats."),
PURPLE_MESSAGE_ERROR, time(NULL));
- purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset);
+ buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
/*
* Evan S. suggested that maxvis really does mean "number of
* visible characters" and not "number of bytes"
@@ -6052,10 +4442,11 @@ int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMes
buf = purple_strdup_withhtml(buf3);
g_free(buf3);
- purple_plugin_oscar_convert_to_best_encoding(gc, NULL, buf, &buf2, &len, &charset, &charsubset);
+ buf2 = oscar_encode_im(buf, &len, &charset, &charsetstr);
if ((len > c->maxlen) || (len > c->maxvis)) {
- purple_debug_warning("oscar", "Could not send %s because (%i > maxlen %i) or (%i > maxvis %i)\n",
+ purple_debug_warning("oscar",
+ "Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i)\n",
buf2, len, c->maxlen, len, c->maxvis);
g_free(buf);
g_free(buf2);
@@ -6066,12 +4457,6 @@ int oscar_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMes
message, buf2);
}
- if (charset == AIM_CHARSET_ASCII)
- charsetstr = "us-ascii";
- else if (charset == AIM_CHARSET_UNICODE)
- charsetstr = "unicode-2-0";
- else if (charset == AIM_CHARSET_LATIN_1)
- charsetstr = "iso-8859-1";
aim_chat_send_im(od, c->conn, 0, buf2, len, charsetstr, "en");
g_free(buf2);
g_free(buf);
@@ -6226,7 +4611,7 @@ char *oscar_status_text(PurpleBuddy *b)
tmp1 = purple_markup_strip_html(message);
purple_util_chrreplace(tmp1, '\n', ' ');
tmp2 = g_markup_escape_text(tmp1, -1);
- ret = purple_str_sub_away_formatters(tmp2, purple_account_get_username(account));
+ ret = oscar_util_format_string(tmp2, purple_account_get_username(account));
g_free(tmp1);
g_free(tmp2);
}
@@ -6243,125 +4628,40 @@ char *oscar_status_text(PurpleBuddy *b)
return ret;
}
-
-static int oscar_icon_req(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
- PurpleConnection *gc = od->gc;
- va_list ap;
- guint16 type;
- guint8 flags = 0, length = 0;
- guchar *md5 = NULL;
-
- va_start(ap, fr);
- type = va_arg(ap, int);
-
- switch(type) {
- case 0x0000:
- case 0x0001: {
- flags = va_arg(ap, int);
- length = va_arg(ap, int);
- md5 = va_arg(ap, guchar *);
-
- if ((flags == 0x00) || (flags == 0x41)) {
- if (!flap_connection_getbytype(od, SNAC_FAMILY_BART) && !od->iconconnecting) {
- od->iconconnecting = TRUE;
- od->set_icon = TRUE;
- aim_srv_requestnew(od, SNAC_FAMILY_BART);
- } else {
- PurpleAccount *account = purple_connection_get_account(gc);
- PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
- if (img == NULL) {
- aim_ssi_delicon(od);
- } else {
-
- purple_debug_info("oscar",
- "Uploading icon to icon server\n");
- aim_bart_upload(od, purple_imgstore_get_data(img),
- purple_imgstore_get_size(img));
- purple_imgstore_unref(img);
- }
- }
- } else if (flags == 0x81) {
- PurpleAccount *account = purple_connection_get_account(gc);
- PurpleStoredImage *img = purple_buddy_icons_find_account_icon(account);
- if (img == NULL)
- aim_ssi_delicon(od);
- else {
- aim_ssi_seticon(od, md5, length);
- purple_imgstore_unref(img);
- }
- }
- } break;
-
- case 0x0002: { /* We just set an "available" message? */
- } break;
- }
-
- va_end(ap);
-
- return 0;
-}
-
-void oscar_set_permit_deny(PurpleConnection *gc) {
+void oscar_set_aim_permdeny(PurpleConnection *gc) {
PurpleAccount *account = purple_connection_get_account(gc);
OscarData *od = purple_connection_get_protocol_data(gc);
- PurplePrivacyType perm_deny;
/*
- * For ICQ the permit/deny setting controls who you can see you
- * online when you set your status to "invisible." If we're ICQ
- * and we're invisible then we need to use one of
- * PURPLE_PRIVACY_ALLOW_USERS or PURPLE_PRIVACY_ALLOW_BUDDYLIST or
- * PURPLE_PRIVACY_DENY_USERS if we actually want to be invisible
- * to anyone.
- *
- * These three permit/deny settings correspond to:
- * 1. Invisible to everyone except the people on my "permit" list
- * 2. Invisible to everyone except the people on my buddy list
- * 3. Invisible only to the people on my "deny" list
- *
- * It would be nice to allow cases 2 and 3, but our UI doesn't have
- * a nice way to do it. For now we just force case 1.
+ * Conveniently there is a one-to-one mapping between the
+ * values of libpurple's PurplePrivacyType and the values used
+ * by the oscar protocol.
*/
- if (od->icq && purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE))
- perm_deny = PURPLE_PRIVACY_ALLOW_USERS;
- else
- perm_deny = account->perm_deny;
-
- if (od->ssi.received_data)
- /*
- * Conveniently there is a one-to-one mapping between the
- * values of libpurple's PurplePrivacyType and the values used
- * by the oscar protocol.
- */
- aim_ssi_setpermdeny(od, perm_deny, 0xffffffff);
+ aim_ssi_setpermdeny(od, account->perm_deny);
}
void oscar_add_permit(PurpleConnection *gc, const char *who) {
OscarData *od = purple_connection_get_protocol_data(gc);
purple_debug_info("oscar", "ssi: About to add a permit\n");
- if (od->ssi.received_data)
- aim_ssi_addpermit(od, who);
+ aim_ssi_add_to_private_list(od, who, AIM_SSI_TYPE_PERMIT);
}
void oscar_add_deny(PurpleConnection *gc, const char *who) {
OscarData *od = purple_connection_get_protocol_data(gc);
purple_debug_info("oscar", "ssi: About to add a deny\n");
- if (od->ssi.received_data)
- aim_ssi_adddeny(od, who);
+ aim_ssi_add_to_private_list(od, who, aim_ssi_getdenyentrytype(od));
}
void oscar_rem_permit(PurpleConnection *gc, const char *who) {
OscarData *od = purple_connection_get_protocol_data(gc);
purple_debug_info("oscar", "ssi: About to delete a permit\n");
- if (od->ssi.received_data)
- aim_ssi_delpermit(od, who);
+ aim_ssi_del_from_private_list(od, who, AIM_SSI_TYPE_PERMIT);
}
void oscar_rem_deny(PurpleConnection *gc, const char *who) {
OscarData *od = purple_connection_get_protocol_data(gc);
purple_debug_info("oscar", "ssi: About to delete a deny\n");
- if (od->ssi.received_data)
- aim_ssi_deldeny(od, who);
+ aim_ssi_del_from_private_list(od, who, aim_ssi_getdenyentrytype(od));
}
GList *
@@ -6653,7 +4953,7 @@ oscar_close_directim(gpointer object, gpointer ignored)
peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED, NULL);
/* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo
- * window. Let the user know that we canceled the Direct IM. */
+ * window. Let the user know that we cancelled the Direct IM. */
conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name);
purple_conversation_write(conv, NULL, _("You closed the connection."),
PURPLE_MESSAGE_SYSTEM, time(NULL));
@@ -6693,7 +4993,6 @@ oscar_get_aim_info_cb(PurpleBlistNode *node, gpointer ignore)
static GList *
oscar_buddy_menu(PurpleBuddy *buddy) {
-
PurpleConnection *gc;
OscarData *od;
GList *menu;
@@ -6731,6 +5030,7 @@ oscar_buddy_menu(PurpleBuddy *buddy) {
PURPLE_CALLBACK(oscar_get_icqxstatusmsg),
NULL, NULL);
menu = g_list_prepend(menu, act);
+ menu = g_list_prepend(menu, create_visibility_menu_item(od, bname));
}
if (userinfo &&
@@ -6756,15 +5056,6 @@ oscar_buddy_menu(PurpleBuddy *buddy) {
}
menu = g_list_prepend(menu, act);
}
-#if 0
- /* TODO: This menu item should be added by the core */
- if (userinfo->capabilities & OSCAR_CAPABILITY_GETFILE) {
- act = purple_menu_action_new(_("Get File"),
- PURPLE_CALLBACK(oscar_ask_getfile),
- NULL, NULL);
- menu = g_list_prepend(menu, act);
- }
-#endif
}
if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
@@ -6778,7 +5069,7 @@ oscar_buddy_menu(PurpleBuddy *buddy) {
if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname))
{
act = purple_menu_action_new(_("Re-request Authorization"),
- PURPLE_CALLBACK(purple_auth_sendrequest_menu),
+ PURPLE_CALLBACK(oscar_auth_sendrequest_menu),
NULL, NULL);
menu = g_list_prepend(menu, act);
}
@@ -6815,7 +5106,7 @@ oscar_icq_privacy_opts(PurpleConnection *gc, PurpleRequestFields *fields)
purple_account_set_bool(account, "authorization", auth);
purple_account_set_bool(account, "web_aware", web_aware);
- oscar_set_extendedstatus(gc);
+ oscar_set_extended_status(gc);
aim_icq_setsecurity(od, auth, web_aware);
}
@@ -6930,41 +5221,29 @@ static void oscar_show_awaitingauth(PurplePluginAction *action)
{
PurpleConnection *gc = (PurpleConnection *) action->context;
OscarData *od = purple_connection_get_protocol_data(gc);
- gchar *text, *tmp;
- GSList *buddies;
- PurpleAccount *account;
- int num=0;
-
- text = g_strdup("");
- account = purple_connection_get_account(gc);
+ PurpleAccount *account = purple_connection_get_account(gc);
+ GSList *buddies, *filtered_buddies, *cur;
+ gchar *text;
buddies = purple_find_buddies(account, NULL);
- while (buddies) {
+ filtered_buddies = NULL;
+ for (cur = buddies; cur != NULL; cur = cur->next) {
PurpleBuddy *buddy;
const gchar *bname, *gname;
- buddy = buddies->data;
+ buddy = cur->data;
bname = purple_buddy_get_name(buddy);
gname = purple_group_get_name(purple_buddy_get_group(buddy));
if (aim_ssi_waitingforauth(od->ssi.local, gname, bname)) {
- const gchar *alias = purple_buddy_get_alias_only(buddy);
- if (alias)
- tmp = g_strdup_printf("%s %s (%s)<br>", text, bname, alias);
- else
- tmp = g_strdup_printf("%s %s<br>", text, bname);
- g_free(text);
- text = tmp;
-
- num++;
+ filtered_buddies = g_slist_prepend(filtered_buddies, buddy);
}
-
- buddies = g_slist_delete_link(buddies, buddies);
}
- if (!num) {
- g_free(text);
- text = g_strdup(_("<i>you are not waiting for authorization</i>"));
- }
+ g_slist_free(buddies);
+
+ filtered_buddies = g_slist_reverse(filtered_buddies);
+ text = oscar_format_buddies(filtered_buddies, _("you are not waiting for authorization"));
+ g_slist_free(filtered_buddies);
purple_notify_formatted(gc, NULL, _("You are awaiting authorization from "
"the following buddies"), _("You can re-request "
@@ -7179,6 +5458,12 @@ oscar_actions(PurplePlugin *plugin, gpointer context)
act = purple_plugin_action_new(_("Set Privacy Options..."),
oscar_show_icq_privacy_opts);
menu = g_list_prepend(menu, act);
+
+ act = purple_plugin_action_new("Show Visible List", oscar_show_visible_list);
+ menu = g_list_prepend(menu, act);
+
+ act = purple_plugin_action_new("Show Invisible List", oscar_show_invisible_list);
+ menu = g_list_prepend(menu, act);
}
else
{
@@ -7208,12 +5493,6 @@ oscar_actions(PurplePlugin *plugin, gpointer context)
oscar_show_find_email);
menu = g_list_prepend(menu, act);
-#if 0
- act = purple_plugin_action_new(_("Search for Buddy by Information"),
- show_find_info);
- menu = g_list_prepend(menu, act);
-#endif
-
menu = g_list_reverse(menu);
return menu;
diff --git a/libpurple/protocols/oscar/oscar.h b/libpurple/protocols/oscar/oscar.h
index a20d09faea..638536e793 100644
--- a/libpurple/protocols/oscar/oscar.h
+++ b/libpurple/protocols/oscar/oscar.h
@@ -103,16 +103,6 @@ extern "C" {
#define AIM_ICONIDENT "AVT1picture.id"
/*
- * Current Maximum Length for Chat Room Messages
- *
- * This is actually defined by the protocol to be
- * dynamic, but I have yet to see due cause to
- * define it dynamically here. Maybe later.
- *
- */
-#define MAXCHATMSGLEN 512
-
-/*
* Found by trial and error.
*/
#define MAXAVAILMSGLEN 251
@@ -143,167 +133,6 @@ struct _ClientInfo
const char *lang; /* two-letter abbrev */
};
-/* Needs to be checked */
-#define CLIENTINFO_AIM_3_5_1670 { \
- "AOL Instant Messenger (SM), version 3.5.1670/WIN32", \
- 0x0004, \
- 0x0003, 0x0005, \
- 0x0000, 0x0686, \
- 0x0000002a, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-/* Latest winaim without ssi */
-#define CLIENTINFO_AIM_4_1_2010 { \
- "AOL Instant Messenger (SM), version 4.1.2010/WIN32", \
- 0x0004, \
- 0x0004, 0x0001, \
- 0x0000, 0x07da, \
- 0x0000004b, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_4_3_2188 { \
- "AOL Instant Messenger (SM), version 4.3.2188/WIN32", \
- 0x0109, \
- 0x0400, 0x0003, \
- 0x0000, 0x088c, \
- 0x00000086, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_4_8_2540 { \
- "AOL Instant Messenger (SM), version 4.8.2540/WIN32", \
- 0x0109, \
- 0x0004, 0x0008, \
- 0x0000, 0x09ec, \
- 0x000000af, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_AIM_5_0_2938 { \
- "AOL Instant Messenger, version 5.0.2938/WIN32", \
- 0x0109, \
- 0x0005, 0x0000, \
- 0x0000, 0x0b7a, \
- 0x00000000, \
- "us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_1_3036 { \
- "AOL Instant Messenger, version 5.1.3036/WIN32", \
- 0x0109, \
- 0x0005, 0x0001, \
- 0x0000, 0x0bdc, \
- 0x000000d2, \
- "us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_5_3415 { \
- "AOL Instant Messenger, version 5.5.3415/WIN32", \
- 0x0109, \
- 0x0005, 0x0005, \
- 0x0000, 0x0057, \
- 0x000000ef, \
- "us", "en", \
-}
-
-#define CLIENTINFO_AIM_5_9_3702 { \
- "AOL Instant Messenger, version 5.9.3702/WIN32", \
- 0x0109, \
- 0x0005, 0x0009, \
- 0x0000, 0x0e76, \
- 0x00000111, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICHAT_1_0 { \
- "Apple iChat", \
- 0x311a, \
- 0x0001, 0x0000, \
- 0x0000, 0x003c, \
- 0x000000c6, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_ICQ_4_65_3281 { \
- "ICQ Inc. - Product of ICQ (TM) 2000b.4.65.1.3281.85", \
- 0x010a, \
- 0x0004, 0x0041, \
- 0x0001, 0x0cd1, \
- 0x00000055, \
- "us", "en", \
-}
-
-/* Needs to be checked */
-#define CLIENTINFO_ICQ_5_34_3728 { \
- "ICQ Inc. - Product of ICQ (TM).2002a.5.34.1.3728.85", \
- 0x010a, \
- 0x0005, 0x0022, \
- 0x0001, 0x0e8f, \
- 0x00000055, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICQ_5_45_3777 { \
- "ICQ Inc. - Product of ICQ (TM).2003a.5.45.1.3777.85", \
- 0x010a, \
- 0x0005, 0x002d, \
- 0x0001, 0x0ec1, \
- 0x00000055, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICQ6_6_0_6059 { \
- "ICQ Client", \
- 0x010a, \
- 0x0006, 0x0000, \
- 0x0000, 0x17ab, \
- 0x00007535, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_3_1068 { \
- "ICQBasic", \
- 0x010a, \
- 0x0014, 0x0003, \
- 0x0000, 0x042c, \
- 0x0000043d, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_34_3000 { \
- "ICQBasic", \
- 0x010a, \
- 0x0014, 0x0034, \
- 0x0000, 0x0bb8, \
- 0x0000043d, \
- "us", "en", \
-}
-
-#define CLIENTINFO_ICQBASIC_14_34_3096 { \
- "ICQBasic", \
- 0x010a, \
- 0x0014, 0x0034, \
- 0x0000, 0x0c18, \
- 0x0000043d, \
- "us", "en", \
-}
-
-#define CLIENTINFO_NETSCAPE_7_0_1 { \
- "Netscape 2000 an approved user of AOL Instant Messenger (SM)", \
- 0x1d0d, \
- 0x0007, 0x0000, \
- 0x0001, 0x0000, \
- 0x00000058, \
- "us", "en", \
-}
-
/*
* We need to use the major-minor-micro versions from the official
* AIM and ICQ programs here or AOL won't let us use certain features.
@@ -329,9 +158,6 @@ struct _ClientInfo
"us", "en", \
}
-#define CLIENTINFO_AIM_KNOWNGOOD CLIENTINFO_AIM_5_1_3036
-#define CLIENTINFO_ICQ_KNOWNGOOD CLIENTINFO_ICQBASIC_14_34_3096
-
typedef enum
{
OSCAR_DISCONNECT_DONE, /* not considered an error */
@@ -376,7 +202,24 @@ typedef enum
#define OSCAR_CAPABILITY_NEWCAPS 0x0000000020000000LL
#define OSCAR_CAPABILITY_XTRAZ 0x0000000040000000LL
#define OSCAR_CAPABILITY_GENERICUNKNOWN 0x0000000080000000LL
-#define OSCAR_CAPABILITY_LAST 0x0000000100000000LL
+#define OSCAR_CAPABILITY_HTML_MSGS 0x0000000100000000LL
+#define OSCAR_CAPABILITY_LAST 0x0000000200000000LL
+
+#define OSCAR_STATUS_ID_INVISIBLE "invisible"
+#define OSCAR_STATUS_ID_OFFLINE "offline"
+#define OSCAR_STATUS_ID_AVAILABLE "available"
+#define OSCAR_STATUS_ID_AWAY "away"
+#define OSCAR_STATUS_ID_DND "dnd"
+#define OSCAR_STATUS_ID_NA "na"
+#define OSCAR_STATUS_ID_OCCUPIED "occupied"
+#define OSCAR_STATUS_ID_FREE4CHAT "free4chat"
+#define OSCAR_STATUS_ID_CUSTOM "custom"
+#define OSCAR_STATUS_ID_MOBILE "mobile"
+#define OSCAR_STATUS_ID_EVIL "evil"
+#define OSCAR_STATUS_ID_DEPRESSION "depression"
+#define OSCAR_STATUS_ID_ATHOME "athome"
+#define OSCAR_STATUS_ID_ATWORK "atwork"
+#define OSCAR_STATUS_ID_LUNCH "lunch"
/*
* Byte Stream type. Sort of.
@@ -395,8 +238,8 @@ typedef enum
struct _ByteStream
{
guint8 *data;
- guint32 len;
- guint32 offset;
+ size_t len;
+ size_t offset;
};
struct _QueuedSnac
@@ -526,7 +369,7 @@ struct _OscarData
*/
IcbmCookie *msgcookies;
- struct aim_icq_info *icq_info;
+ GSList *icq_info;
/** Only used when connecting with the old-style BUCP login. */
struct aim_authresp_info *authinfo;
@@ -580,10 +423,8 @@ struct _OscarData
#define AIM_ICQ_STATE_WEBAWARE 0x00010000
#define AIM_ICQ_STATE_HIDEIP 0x00020000
#define AIM_ICQ_STATE_BIRTHDAY 0x00080000
-#define AIM_ICQ_STATE_DIRECTDISABLED 0x00100000
#define AIM_ICQ_STATE_ICQHOMEPAGE 0x00200000
#define AIM_ICQ_STATE_DIRECTREQUIREAUTH 0x10000000
-#define AIM_ICQ_STATE_DIRECTCONTACTLIST 0x20000000
/**
* Only used when connecting with the old-style BUCP login.
@@ -669,8 +510,8 @@ void flap_connection_send(FlapConnection *conn, FlapFrame *frame);
void flap_connection_send_version(OscarData *od, FlapConnection *conn);
void flap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy);
void flap_connection_send_version_with_cookie_and_clientinfo(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy, ClientInfo *ci, gboolean allow_multiple_login);
-void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data);
-void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
+void flap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data);
+void flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority);
void flap_connection_send_keepalive(OscarData *od, FlapConnection *conn);
FlapFrame *flap_frame_new(OscarData *od, guint16 channel, int datalen);
@@ -682,64 +523,26 @@ void oscar_data_destroy(OscarData *);
void oscar_data_addhandler(OscarData *od, guint16 family, guint16 subtype, aim_rxcallback_t newhandler, guint16 flags);
aim_rxcallback_t aim_callhandler(OscarData *od, guint16 family, guint16 subtype);
-/* misc.c */
-#define AIM_VISIBILITYCHANGE_PERMITADD 0x05
-#define AIM_VISIBILITYCHANGE_PERMITREMOVE 0x06
-#define AIM_VISIBILITYCHANGE_DENYADD 0x07
-#define AIM_VISIBILITYCHANGE_DENYREMOVE 0x08
-
-#define AIM_PRIVFLAGS_ALLOWIDLE 0x01
-#define AIM_PRIVFLAGS_ALLOWMEMBERSINCE 0x02
-
-#define AIM_WARN_ANON 0x01
-
-
-
/* 0x0001 - family_oservice.c */
/* 0x0002 */ void aim_srv_clientready(OscarData *od, FlapConnection *conn);
/* 0x0004 */ void aim_srv_requestnew(OscarData *od, guint16 serviceid);
/* 0x0006 */ void aim_srv_reqrates(OscarData *od, FlapConnection *conn);
/* 0x0008 */ void aim_srv_rates_addparam(OscarData *od, FlapConnection *conn);
-/* 0x0009 */ void aim_srv_rates_delparam(OscarData *od, FlapConnection *conn);
-/* 0x000c */ void aim_srv_sendpauseack(OscarData *od, FlapConnection *conn);
/* 0x000e */ void aim_srv_reqpersonalinfo(OscarData *od, FlapConnection *conn);
/* 0x0011 */ void aim_srv_setidle(OscarData *od, guint32 idletime);
-/* 0x0014 */ void aim_srv_setprivacyflags(OscarData *od, FlapConnection *conn, guint32);
-/* 0x0016 */ void aim_srv_nop(OscarData *od, FlapConnection *conn);
/* 0x0017 */ void aim_srv_setversions(OscarData *od, FlapConnection *conn);
/* 0x001e */ int aim_srv_setextrainfo(OscarData *od, gboolean seticqstatus, guint32 icqstatus, gboolean setstatusmsg, const char *statusmsg, const char *itmsurl);
+void aim_srv_set_dc_info(OscarData *od);
void aim_bos_reqrights(OscarData *od, FlapConnection *conn);
-int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int, const char *);
-void aim_bos_setgroupperm(OscarData *od, FlapConnection *conn, guint32 mask);
-
-
-
-#define AIM_CLIENTTYPE_UNKNOWN 0x0000
-#define AIM_CLIENTTYPE_MC 0x0001
-#define AIM_CLIENTTYPE_WINAIM 0x0002
-#define AIM_CLIENTTYPE_WINAIM41 0x0003
-#define AIM_CLIENTTYPE_AOL_TOC 0x0004
-guint16 aim_im_fingerprint(const guint8 *msghdr, int len);
-#define AIM_RATE_CODE_CHANGE 0x0001
-#define AIM_RATE_CODE_WARNING 0x0002
#define AIM_RATE_CODE_LIMIT 0x0003
-#define AIM_RATE_CODE_CLEARLIMIT 0x0004
-void aim_ads_requestads(OscarData *od, FlapConnection *conn);
-
-
/* family_icbm.c */
-#define AIM_OFT_SUBTYPE_SEND_FILE 0x0001
#define AIM_OFT_SUBTYPE_SEND_DIR 0x0002
-#define AIM_OFT_SUBTYPE_GET_FILE 0x0011
-#define AIM_OFT_SUBTYPE_GET_LIST 0x0012
-#define AIM_TRANSFER_DENY_NOTSUPPORTED 0x0000
#define AIM_TRANSFER_DENY_DECLINE 0x0001
-#define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002
#define AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED 0x00000001
#define AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED 0x00000002
@@ -747,25 +550,19 @@ void aim_ads_requestads(OscarData *od, FlapConnection *conn);
#define AIM_IMPARAM_FLAG_SMS_SUPPORTED 0x00000010
#define AIM_IMPARAM_FLAG_OFFLINE_MSGS_ALLOWED 0x00000100
-/* This is what the server will give you if you don't set them yourself. */
-/* This is probably out of date. */
-#define AIM_IMPARAM_DEFAULTS { \
- 0, \
- AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \
- 512, /* !! Note how small this is. */ \
- (99.9)*10, (99.9)*10, \
- 1000 /* !! And how large this is. */ \
-}
-
-/* This is what most AIM versions use. */
-/* This is probably out of date. */
-#define AIM_IMPARAM_REASONABLE { \
- 0, \
- AIM_IMPARAM_FLAG_CHANNEL_MSGS_ALLOWED | AIM_IMPARAM_FLAG_MISSED_CALLS_ENABLED, \
- 8000, \
- (99.9)*10, (99.9)*10, \
- 0 \
-}
+/**
+ * This flag tells the server that we always send HTML in messages
+ * sent from an ICQ account to an ICQ account. (If this flag is
+ * not sent then plaintext is sent ICQ<-->ICQ (HTML is sent in all
+ * other cases)).
+ *
+ * If we send an HTML message to an old client that doesn't support
+ * HTML messages, then the oscar servers will merrily strip the HTML
+ * for us.
+ *
+ * All incoming IMs are treated as HTML.
+ */
+#define AIM_IMPARAM_FLAG_USE_HTML_FOR_ICQ 0x00000400
struct aim_icbmparameters
{
@@ -813,9 +610,6 @@ void oscar_chat_destroy(struct chat_connection *cc);
#define AIM_IMFLAGS_HASICON 0x0020 /* already has icon */
#define AIM_IMFLAGS_SUBENC_MACINTOSH 0x0040 /* damn that Steve Jobs! */
#define AIM_IMFLAGS_CUSTOMFEATURES 0x0080 /* features field present */
-#define AIM_IMFLAGS_EXTDATA 0x0100
-#define AIM_IMFLAGS_X 0x0200
-#define AIM_IMFLAGS_MULTIPART 0x0400 /* ->mpmsg section valid */
#define AIM_IMFLAGS_OFFLINE 0x0800 /* send to offline user */
#define AIM_IMFLAGS_TYPINGNOT 0x1000 /* typing notification */
@@ -824,30 +618,6 @@ void oscar_chat_destroy(struct chat_connection *cc);
#define AIM_CHARSET_LATIN_1 0x0003 /* ISO 8859-1 */
/*
- * Multipart message structures.
- */
-typedef struct aim_mpmsg_section_s
-{
- guint16 charset;
- guint16 charsubset;
- gchar *data;
- guint16 datalen;
- struct aim_mpmsg_section_s *next;
-} aim_mpmsg_section_t;
-
-typedef struct aim_mpmsg_s
-{
- unsigned int numparts;
- aim_mpmsg_section_t *parts;
-} aim_mpmsg_t;
-
-int aim_mpmsg_init(OscarData *od, aim_mpmsg_t *mpm);
-int aim_mpmsg_addraw(OscarData *od, aim_mpmsg_t *mpm, guint16 charset, guint16 charsubset, const gchar *data, guint16 datalen);
-int aim_mpmsg_addascii(OscarData *od, aim_mpmsg_t *mpm, const char *ascii);
-int aim_mpmsg_addunicode(OscarData *od, aim_mpmsg_t *mpm, const guint16 *unicode, guint16 unicodelen);
-void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm);
-
-/*
* Arguments to aim_send_im_ext().
*
* This is really complicated. But immensely versatile.
@@ -855,84 +625,39 @@ void aim_mpmsg_free(OscarData *od, aim_mpmsg_t *mpm);
*/
struct aim_sendimext_args
{
-
/* These are _required_ */
const char *destbn;
guint32 flags; /* often 0 */
- /* Only required if not using multipart messages */
const char *msg;
- int msglen;
-
- /* Required if ->msg is not provided */
- aim_mpmsg_t *mpmsg;
+ gsize msglen;
/* Only used if AIM_IMFLAGS_HASICON is set */
guint32 iconlen;
time_t iconstamp;
guint32 iconsum;
- /* Only used if AIM_IMFLAGS_CUSTOMFEATURES is set */
guint16 featureslen;
guint8 *features;
- /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set and mpmsg not used */
guint16 charset;
- guint16 charsubset;
-};
-
-/*
- * Arguments to aim_send_rtfmsg().
- */
-struct aim_sendrtfmsg_args
-{
- const char *destbn;
- guint32 fgcolor;
- guint32 bgcolor;
- const char *rtfmsg; /* must be in RTF */
};
/*
* This information is provided in the Incoming ICBM callback for
* Channel 1 ICBM's.
- *
- * Note that although CUSTOMFEATURES and CUSTOMCHARSET say they
- * are optional, both are always set by the current libfaim code.
- * That may or may not change in the future. It is mainly for
- * consistency with aim_sendimext_args.
- *
- * Multipart messages require some explanation. If you want to use them,
- * I suggest you read all the comments in family_icbm.c.
- *
*/
struct aim_incomingim_ch1_args
{
-
- /* Always provided */
- aim_mpmsg_t mpmsg;
guint32 icbmflags; /* some flags apply only to ->msg, not all mpmsg */
time_t timestamp; /* Only set for offline messages */
- /* Only provided if message has a human-readable section */
gchar *msg;
- int msglen;
/* Only provided if AIM_IMFLAGS_HASICON is set */
time_t iconstamp;
guint32 iconlen;
guint16 iconsum;
-
- /* Only provided if AIM_IMFLAGS_CUSTOMFEATURES is set */
- guint8 *features;
- guint8 featureslen;
-
- /* Only provided if AIM_IMFLAGS_EXTDATA is set */
- guint8 extdatalen;
- guint8 *extdata;
-
- /* Only used if AIM_IMFLAGS_CUSTOMCHARSET is set */
- guint16 charset;
- guint16 charsubset;
};
/* Valid values for channel 2 args->status */
@@ -967,10 +692,8 @@ struct _IcbmArgsCh2
struct aim_chat_roominfo roominfo;
} chat;
struct {
- guint16 msgtype;
- guint32 fgcolor;
- guint32 bgcolor;
- const char *rtfmsg;
+ guint8 msgtype;
+ const char *msg;
} rtfmsg;
struct {
guint16 subtype;
@@ -982,11 +705,6 @@ struct _IcbmArgsCh2
void *destructor; /* used internally only */
};
-/* Valid values for channel 4 args->type */
-#define AIM_ICQMSG_AUTHREQUEST 0x0006
-#define AIM_ICQMSG_AUTHDENIED 0x0007
-#define AIM_ICQMSG_AUTHGRANTED 0x0008
-
struct aim_incomingim_ch4_args
{
guint32 uin; /* Of the sender of the ICBM */
@@ -1003,7 +721,6 @@ struct aim_incomingim_ch4_args
/* 0x0006 */ int aim_im_sendch1(OscarData *, const char *destbn, guint16 flags, const char *msg);
/* 0x0006 */ int aim_im_sendch2_chatinvite(OscarData *od, const char *bn, const char *msg, guint16 exchange, const char *roomname, guint16 instance);
/* 0x0006 */ int aim_im_sendch2_icon(OscarData *od, const char *bn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum);
-/* 0x0006 */ int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args);
/* 0x0006 */ void aim_im_sendch2_cancel(PeerConnection *peer_conn);
/* 0x0006 */ void aim_im_sendch2_connected(PeerConnection *peer_conn);
@@ -1012,38 +729,23 @@ struct aim_incomingim_ch4_args
/* 0x0006 */ void aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
/* 0x0006 */ void aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *bn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles);
-/* 0x0006 */ int aim_im_sendch2_geticqaway(OscarData *od, const char *bn, int type);
-/* 0x0006 */ int aim_im_sendch4(OscarData *od, const char *bn, guint16 type, const char *message);
-/* 0x0008 */ int aim_im_warn(OscarData *od, FlapConnection *conn, const char *destbn, guint32 flags);
/* 0x000b */ int aim_im_denytransfer(OscarData *od, const char *bn, const guchar *cookie, guint16 code);
/* 0x0010 */ int aim_im_reqofflinemsgs(OscarData *od);
/* 0x0014 */ int aim_im_sendmtn(OscarData *od, guint16 type1, const char *bn, guint16 type2);
/* 0x000b */ int icq_relay_xstatus (OscarData *od, const char *sn, const guchar* cookie);
void aim_icbm_makecookie(guchar* cookie);
-gchar *oscar_encoding_extract(const char *encoding);
-gchar *oscar_encoding_to_utf8(PurpleAccount *account, const char *encoding, const char *text, int textlen);
-gchar *purple_plugin_oscar_decode_im_part(PurpleAccount *account, const char *sourcebn, guint16 charset, guint16 charsubset, const gchar *data, gsize datalen);
-
+void aim_im_send_icq_confirmation(OscarData *od, const char *bn, const guchar *cookie);
/* 0x0002 - family_locate.c */
/*
* AIM User Info, Standard Form.
*/
-#define AIM_FLAG_UNCONFIRMED 0x0001 /* "damned transients" */
#define AIM_FLAG_ADMINISTRATOR 0x0002
#define AIM_FLAG_AOL 0x0004
-#define AIM_FLAG_OSCAR_PAY 0x0008
-#define AIM_FLAG_FREE 0x0010
#define AIM_FLAG_AWAY 0x0020
-#define AIM_FLAG_ICQ 0x0040
#define AIM_FLAG_WIRELESS 0x0080
-#define AIM_FLAG_UNKNOWN100 0x0100
-#define AIM_FLAG_IMFORWARDING 0x0200
+#define AIM_FLAG_ICQ 0x0040
#define AIM_FLAG_ACTIVEBUDDY 0x0400
-#define AIM_FLAG_UNKNOWN800 0x0800
-#define AIM_FLAG_ONEWAYWIRELESS 0x1000
-#define AIM_FLAG_NOKNOCKKNOCK 0x00040000
-#define AIM_FLAG_FORWARD_MOBILE 0x00080000
#define AIM_USERINFO_PRESENT_FLAGS 0x00000001
#define AIM_USERINFO_PRESENT_MEMBERSINCE 0x00000002
@@ -1116,22 +818,8 @@ struct aim_invite_priv
guint16 instance;
};
-#define AIM_COOKIETYPE_UNKNOWN 0x00
-#define AIM_COOKIETYPE_ICBM 0x01
-#define AIM_COOKIETYPE_ADS 0x02
-#define AIM_COOKIETYPE_BOS 0x03
-#define AIM_COOKIETYPE_IM 0x04
-#define AIM_COOKIETYPE_CHAT 0x05
-#define AIM_COOKIETYPE_CHATNAV 0x06
-#define AIM_COOKIETYPE_INVITE 0x07
-/* we'll move OFT up a bit to give breathing room. not like it really
- * matters. */
-#define AIM_COOKIETYPE_OFTIM 0x10
-#define AIM_COOKIETYPE_OFTGET 0x11
-#define AIM_COOKIETYPE_OFTSEND 0x12
-#define AIM_COOKIETYPE_OFTVOICE 0x13
-#define AIM_COOKIETYPE_OFTIMAGE 0x14
-#define AIM_COOKIETYPE_OFTICON 0x15
+#define AIM_COOKIETYPE_CHAT 0x01
+#define AIM_COOKIETYPE_INVITE 0x02
aim_userinfo_t *aim_locate_finduserinfo(OscarData *od, const char *bn);
void aim_locate_dorequest(OscarData *od);
@@ -1139,10 +827,6 @@ void aim_locate_dorequest(OscarData *od);
/* 0x0002 */ int aim_locate_reqrights(OscarData *od);
/* 0x0004 */ int aim_locate_setcaps(OscarData *od, guint64 caps);
/* 0x0004 */ int aim_locate_setprofile(OscarData *od, const char *profile_encoding, const gchar *profile, const int profile_len, const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len);
-/* 0x0005 */ int aim_locate_getinfo(OscarData *od, const char *, guint16);
-/* 0x0009 */ int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy);
-/* 0x000b */ int aim_locate_000b(OscarData *od, const char *bn);
-/* 0x000f */ int aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy);
/* 0x0015 */ int aim_locate_getinfoshort(OscarData *od, const char *bn, guint32 flags);
guint64 aim_locate_getcaps(OscarData *od, ByteStream *bs, int len);
@@ -1157,25 +841,11 @@ int icq_im_xstatus_request(OscarData *od, const char *sn);
/* 0x0003 - family_buddy.c */
/* 0x0002 */ void aim_buddylist_reqrights(OscarData *, FlapConnection *);
-/* 0x0004 */ int aim_buddylist_set(OscarData *, FlapConnection *, const char *);
-/* 0x0004 */ int aim_buddylist_addbuddy(OscarData *, FlapConnection *, const char *);
-/* 0x0005 */ int aim_buddylist_removebuddy(OscarData *, FlapConnection *, const char *);
-
/* 0x000a - family_userlookup.c */
int aim_search_address(OscarData *, const char *);
-
-
-/* 0x000d - family_chatnav.c */
-/* 0x000e - family_chat.c */
-/* These apply to exchanges as well. */
-#define AIM_CHATROOM_FLAG_EVILABLE 0x0001
-#define AIM_CHATROOM_FLAG_NAV_ONLY 0x0002
-#define AIM_CHATROOM_FLAG_INSTANCING_ALLOWED 0x0004
-#define AIM_CHATROOM_FLAG_OCCUPANT_PEEK_ALLOWED 0x0008
-
struct aim_chat_exchangeinfo
{
guint16 number;
@@ -1191,41 +861,10 @@ struct aim_chat_exchangeinfo
#define AIM_CHATFLAGS_AWAY 0x0002
int aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language);
int aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance);
-int aim_chat_attachname(FlapConnection *conn, guint16 exchange, const char *roomname, guint16 instance);
-char *aim_chat_getname(FlapConnection *conn);
-FlapConnection *aim_chat_getconn(OscarData *, const char *name);
void aim_chatnav_reqrights(OscarData *od, FlapConnection *conn);
int aim_chatnav_createroom(OscarData *od, FlapConnection *conn, const char *name, guint16 exchange);
-int aim_chat_leaveroom(OscarData *od, const char *name);
-
-
-
-/* 0x000f - family_odir.c */
-struct aim_odir
-{
- char *first;
- char *last;
- char *middle;
- char *maiden;
- char *email;
- char *country;
- char *state;
- char *city;
- char *bn;
- char *interest;
- char *nick;
- char *zip;
- char *region;
- char *address;
- struct aim_odir *next;
-};
-
-int aim_odir_email(OscarData *, const char *, const char *);
-int aim_odir_name(OscarData *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *);
-int aim_odir_interest(OscarData *, const char *, const char *);
-
/* 0x0010 - family_bart.c */
@@ -1241,15 +880,9 @@ int aim_bart_request(OscarData *od, const char *bn, guint8 iconcsumtype, const g
#define AIM_SSI_TYPE_DENY 0x0003
#define AIM_SSI_TYPE_PDINFO 0x0004
#define AIM_SSI_TYPE_PRESENCEPREFS 0x0005
+#define AIM_SSI_TYPE_ICQDENY 0x000e
#define AIM_SSI_TYPE_ICONINFO 0x0014
-#define AIM_SSI_ACK_SUCCESS 0x0000
-#define AIM_SSI_ACK_ITEMNOTFOUND 0x0002
-#define AIM_SSI_ACK_IDNUMINUSE 0x000a
-#define AIM_SSI_ACK_ATMAX 0x000c
-#define AIM_SSI_ACK_INVALIDNAME 0x000d
-#define AIM_SSI_ACK_AUTHREQUIRED 0x000e
-
/* These flags are set in the 0x00c9 TLV of SSI type 0x0005 */
#define AIM_SSI_PRESENCE_FLAG_SHOWIDLE 0x00000400
#define AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES 0x00020000
@@ -1276,11 +909,9 @@ struct aim_ssi_tmp
/* These build the actual SNACs and queue them to be sent */
/* 0x0002 */ int aim_ssi_reqrights(OscarData *od);
/* 0x0004 */ int aim_ssi_reqdata(OscarData *od);
-/* 0x0005 */ int aim_ssi_reqifchanged(OscarData *od, time_t localstamp, guint16 localrev);
/* 0x0007 */ int aim_ssi_enable(OscarData *od);
/* 0x0011 */ int aim_ssi_modbegin(OscarData *od);
/* 0x0012 */ int aim_ssi_modend(OscarData *od);
-/* 0x0014 */ int aim_ssi_sendauth(OscarData *od, char *bn, char *msg);
/* 0x0018 */ int aim_ssi_sendauthrequest(OscarData *od, char *bn, const char *msg);
/* 0x001a */ int aim_ssi_sendauthreply(OscarData *od, char *bn, guint8 reply, const char *msg);
@@ -1297,49 +928,22 @@ gboolean aim_ssi_waitingforauth(struct aim_ssi_item *list, const char *gn, const
/* Client functions for changing SSI data */
int aim_ssi_addbuddy(OscarData *od, const char *name, const char *group, GSList *tlvlist, const char *alias, const char *comment, const char *smsnum, gboolean needauth);
-int aim_ssi_addpermit(OscarData *od, const char *name);
-int aim_ssi_adddeny(OscarData *od, const char *name);
int aim_ssi_delbuddy(OscarData *od, const char *name, const char *group);
int aim_ssi_delgroup(OscarData *od, const char *group);
-int aim_ssi_delpermit(OscarData *od, const char *name);
-int aim_ssi_deldeny(OscarData *od, const char *name);
int aim_ssi_movebuddy(OscarData *od, const char *oldgn, const char *newgn, const char *bn);
int aim_ssi_aliasbuddy(OscarData *od, const char *gn, const char *bn, const char *alias);
int aim_ssi_editcomment(OscarData *od, const char *gn, const char *bn, const char *alias);
int aim_ssi_rename_group(OscarData *od, const char *oldgn, const char *newgn);
int aim_ssi_cleanlist(OscarData *od);
int aim_ssi_deletelist(OscarData *od);
-int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny, guint32 vismask);
+int aim_ssi_setpermdeny(OscarData *od, guint8 permdeny);
int aim_ssi_setpresence(OscarData *od, guint32 presence);
int aim_ssi_seticon(OscarData *od, const guint8 *iconsum, guint8 iconsumlen);
int aim_ssi_delicon(OscarData *od);
+int aim_ssi_add_to_private_list(OscarData *od, const char* name, guint16 list_type);
+int aim_ssi_del_from_private_list(OscarData* od, const char* name, guint16 list_type);
-
-
-/* 0x0015 - family_icq.c */
-#define AIM_ICQ_INFO_SIMPLE 0x001
-#define AIM_ICQ_INFO_SUMMARY 0x002
-#define AIM_ICQ_INFO_EMAIL 0x004
-#define AIM_ICQ_INFO_PERSONAL 0x008
-#define AIM_ICQ_INFO_ADDITIONAL 0x010
-#define AIM_ICQ_INFO_WORK 0x020
-#define AIM_ICQ_INFO_INTERESTS 0x040
-#define AIM_ICQ_INFO_ORGS 0x080
-#define AIM_ICQ_INFO_UNKNOWN 0x100
-#define AIM_ICQ_INFO_HAVEALL 0x1ff
-
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-struct aim_icq_offlinemsg
-{
- guint32 sender;
- guint16 year;
- guint8 month, day, hour, minute;
- guint8 type;
- guint8 flags;
- char *msg;
- int msglen;
-};
-#endif /* OLDSTYLE_ICQ_OFFLINEMSGS */
+guint16 aim_ssi_getdenyentrytype(OscarData* od);
struct aim_icq_info
{
@@ -1396,22 +1000,17 @@ struct aim_icq_info
guint16 numaddresses;
char **email2;
- /* we keep track of these in a linked list because we're 1337 */
- struct aim_icq_info *next;
-
/* status note info */
guint8 icbm_cookie[8];
char *status_note_title;
+
+ gboolean for_auth_request;
+ char *auth_request_reason;
};
-#ifdef OLDSTYLE_ICQ_OFFLINEMSGS
-int aim_icq_reqofflinemsgs(OscarData *od);
-int aim_icq_ackofflinemsgs(OscarData *od);
-#endif
int aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware);
int aim_icq_changepasswd(OscarData *od, const char *passwd);
-int aim_icq_getsimpleinfo(OscarData *od, const char *uin);
-int aim_icq_getalias(OscarData *od, const char *uin);
+int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason);
int aim_icq_getallinfo(OscarData *od, const char *uin);
int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias);
@@ -1545,22 +1144,19 @@ void aim_tlvlist_remove(GSList **list, const guint16 type);
(((*((buf)+2)) << 16) & 0x00ff0000) + \
(((*((buf)+3)) << 24) & 0xff000000))
+const char *oscar_get_msgerr_reason(size_t reason);
int oscar_get_ui_info_int(const char *str, int default_value);
const char *oscar_get_ui_info_string(const char *str, const char *default_value);
gchar *oscar_get_clientstring(void);
guint16 aimutil_iconsum(const guint8 *buf, int buflen);
-int aimutil_tokslen(char *toSearch, int theindex, char dl);
-int aimutil_itemcnt(char *toSearch, char dl);
-char *aimutil_itemindex(char *toSearch, int theindex, char dl);
gboolean oscar_util_valid_name(const char *bn);
gboolean oscar_util_valid_name_icq(const char *bn);
gboolean oscar_util_valid_name_sms(const char *bn);
int oscar_util_name_compare(const char *bn1, const char *bn2);
-
-
-
+gchar *oscar_util_format_string(const char *str, const char *name);
+gchar *oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message);
typedef struct {
guint16 family;
@@ -1602,11 +1198,7 @@ int chatnav_modfirst(OscarData *od, aim_module_t *mod);
int chat_modfirst(OscarData *od, aim_module_t *mod);
int locate_modfirst(OscarData *od, aim_module_t *mod);
int service_modfirst(OscarData *od, aim_module_t *mod);
-int invite_modfirst(OscarData *od, aim_module_t *mod);
-int translate_modfirst(OscarData *od, aim_module_t *mod);
int popups_modfirst(OscarData *od, aim_module_t *mod);
-int adverts_modfirst(OscarData *od, aim_module_t *mod);
-int odir_modfirst(OscarData *od, aim_module_t *mod);
int bart_modfirst(OscarData *od, aim_module_t *mod);
int ssi_modfirst(OscarData *od, aim_module_t *mod);
int icq_modfirst(OscarData *od, aim_module_t *mod);
@@ -1615,15 +1207,14 @@ int email_modfirst(OscarData *od, aim_module_t *mod);
void aim_genericreq_n(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
void aim_genericreq_n_snacid(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype);
void aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *);
-void aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *);
/* bstream.c */
-int byte_stream_new(ByteStream *bs, guint32 len);
-int byte_stream_init(ByteStream *bs, guint8 *data, int len);
+int byte_stream_new(ByteStream *bs, size_t len);
+int byte_stream_init(ByteStream *bs, guint8 *data, size_t len);
void byte_stream_destroy(ByteStream *bs);
-int byte_stream_empty(ByteStream *bs);
+int byte_stream_bytes_left(ByteStream *bs);
int byte_stream_curpos(ByteStream *bs);
-int byte_stream_setpos(ByteStream *bs, unsigned int off);
+int byte_stream_setpos(ByteStream *bs, size_t off);
void byte_stream_rewind(ByteStream *bs);
int byte_stream_advance(ByteStream *bs, int n);
guint8 byte_stream_get8(ByteStream *bs);
@@ -1632,18 +1223,18 @@ guint32 byte_stream_get32(ByteStream *bs);
guint8 byte_stream_getle8(ByteStream *bs);
guint16 byte_stream_getle16(ByteStream *bs);
guint32 byte_stream_getle32(ByteStream *bs);
-int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, int len);
-guint8 *byte_stream_getraw(ByteStream *bs, int len);
-char *byte_stream_getstr(ByteStream *bs, int len);
+int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len);
+guint8 *byte_stream_getraw(ByteStream *bs, size_t len);
+char *byte_stream_getstr(ByteStream *bs, size_t len);
int byte_stream_put8(ByteStream *bs, guint8 v);
int byte_stream_put16(ByteStream *bs, guint16 v);
int byte_stream_put32(ByteStream *bs, guint32 v);
int byte_stream_putle8(ByteStream *bs, guint8 v);
int byte_stream_putle16(ByteStream *bs, guint16 v);
int byte_stream_putle32(ByteStream *bs, guint32 v);
-int byte_stream_putraw(ByteStream *bs, const guint8 *v, int len);
+int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len);
int byte_stream_putstr(ByteStream *bs, const char *str);
-int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, int len);
+int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len);
int byte_stream_putuid(ByteStream *bs, OscarData *od);
int byte_stream_putcaps(ByteStream *bs, guint64 caps);
@@ -1678,7 +1269,7 @@ aim_snacid_t aim_newsnac(OscarData *, aim_snac_t *newsnac);
aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 type, const guint16 flags, const void *data, const int datalen);
aim_snac_t *aim_remsnac(OscarData *, aim_snacid_t id);
void aim_cleansnacs(OscarData *, int maxage);
-int aim_putsnac(ByteStream *, guint16 family, guint16 type, guint16 flags, aim_snacid_t id);
+int aim_putsnac(ByteStream *, guint16 family, guint16 type, aim_snacid_t id);
struct chatsnacinfo {
guint16 exchange;
@@ -1705,13 +1296,53 @@ IcbmCookie *aim_uncachecookie(OscarData *od, guint8 *cookie, int type);
IcbmCookie *aim_mkcookie(guint8 *, int, void *);
IcbmCookie *aim_checkcookie(OscarData *, const unsigned char *, const int);
int aim_freecookie(OscarData *od, IcbmCookie *cookie);
-int aim_msgcookie_gettype(guint64 type);
int aim_cookie_free(OscarData *od, IcbmCookie *cookie);
int aim_chat_readroominfo(ByteStream *bs, struct aim_chat_roominfo *outinfo);
void flap_connection_destroy_chat(OscarData *od, FlapConnection *conn);
+/* userinfo.c - displaying user information */
+
+void oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags);
+void oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo);
+void oscar_user_info_display_error(OscarData *od, guint16 error_reason, char *buddy);
+void oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info);
+void oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo);
+
+/* authorization.c - OSCAR authorization requests */
+void oscar_auth_sendrequest(PurpleConnection *gc, const char *name);
+void oscar_auth_sendrequest_menu(PurpleBlistNode *node, gpointer ignored);
+void oscar_auth_recvrequest(PurpleConnection *gc, gchar *name, gchar *nick, gchar *reason);
+
+void oscar_set_aim_permdeny(PurpleConnection *gc);
+
+struct buddyinfo
+{
+ gboolean typingnot;
+ guint32 ipaddr;
+
+ unsigned long ico_me_len;
+ unsigned long ico_me_csum;
+ time_t ico_me_time;
+ gboolean ico_informed;
+
+ unsigned long ico_len;
+ unsigned long ico_csum;
+ time_t ico_time;
+ gboolean ico_need;
+ gboolean ico_sent;
+};
+
+struct name_data
+{
+ PurpleConnection *gc;
+ gchar *name;
+ gchar *nick;
+};
+
+void oscar_free_name_data(struct name_data *data);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpurple/protocols/oscar/oscar_data.c b/libpurple/protocols/oscar/oscar_data.c
index dcc43baa5d..8c0a9e17d9 100644
--- a/libpurple/protocols/oscar/oscar_data.c
+++ b/libpurple/protocols/oscar/oscar_data.c
@@ -53,17 +53,13 @@ oscar_data_new(void)
aim__registermodule(od, locate_modfirst);
aim__registermodule(od, buddylist_modfirst);
aim__registermodule(od, msg_modfirst);
- /* aim__registermodule(od, adverts_modfirst); */
- /* aim__registermodule(od, invite_modfirst); */
aim__registermodule(od, admin_modfirst);
aim__registermodule(od, popups_modfirst);
aim__registermodule(od, bos_modfirst);
aim__registermodule(od, search_modfirst);
aim__registermodule(od, stats_modfirst);
- /* aim__registermodule(od, translate_modfirst); */
aim__registermodule(od, chatnav_modfirst);
aim__registermodule(od, chat_modfirst);
- aim__registermodule(od, odir_modfirst);
aim__registermodule(od, bart_modfirst);
/* missing 0x11 - 0x12 */
aim__registermodule(od, ssi_modfirst);
diff --git a/libpurple/protocols/oscar/oscarcommon.h b/libpurple/protocols/oscar/oscarcommon.h
index a7af4cb62f..52433e5f99 100644
--- a/libpurple/protocols/oscar/oscarcommon.h
+++ b/libpurple/protocols/oscar/oscarcommon.h
@@ -77,7 +77,6 @@ void oscar_add_permit(PurpleConnection *gc, const char *who);
void oscar_add_deny(PurpleConnection *gc, const char *who);
void oscar_rem_permit(PurpleConnection *gc, const char *who);
void oscar_rem_deny(PurpleConnection *gc, const char *who);
-void oscar_set_permit_deny(PurpleConnection *gc);
void oscar_join_chat(PurpleConnection *gc, GHashTable *data);
char *oscar_get_chat_name(GHashTable *data);
void oscar_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name);
diff --git a/libpurple/protocols/oscar/peer_proxy.c b/libpurple/protocols/oscar/peer_proxy.c
index 1ef991b704..6bf5c07c80 100644
--- a/libpurple/protocols/oscar/peer_proxy.c
+++ b/libpurple/protocols/oscar/peer_proxy.c
@@ -32,8 +32,8 @@ peer_proxy_send(PeerConnection *conn, ProxyFrame *frame)
ByteStream bs;
purple_debug_info("oscar", "Outgoing peer proxy frame with "
- "type=0x%04hx, unknown=0x%08x, "
- "flags=0x%04hx, and payload length=%hd\n",
+ "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
+ "payload length=%" G_GSIZE_FORMAT "\n",
frame->type, frame->unknown,
frame->flags, frame->payload.len);
@@ -129,8 +129,8 @@ static void
peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
{
purple_debug_info("oscar", "Incoming peer proxy frame with "
- "type=0x%04hx, unknown=0x%08x, "
- "flags=0x%04hx, and payload length=%hd\n", frame->type,
+ "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
+ "payload length=%" G_GSIZE_FORMAT "\n", frame->type,
frame->unknown, frame->flags, frame->payload.len);
if (frame->type == PEER_PROXY_TYPE_CREATED)
@@ -168,7 +168,7 @@ peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
}
else if (frame->type == PEER_PROXY_TYPE_ERROR)
{
- if (byte_stream_empty(&frame->payload) >= 2)
+ if (byte_stream_bytes_left(&frame->payload) >= 2)
{
guint16 error;
const char *msg;
diff --git a/libpurple/protocols/oscar/rxhandlers.c b/libpurple/protocols/oscar/rxhandlers.c
index d378624d35..75675a9fbe 100644
--- a/libpurple/protocols/oscar/rxhandlers.c
+++ b/libpurple/protocols/oscar/rxhandlers.c
@@ -95,194 +95,3 @@ void aim__shutdownmodules(OscarData *od)
return;
}
-
-#if 0
-/*
- * Bleck functions get called when there's no non-bleck functions
- * around to cleanup the mess...
- */
-static int bleck(OscarData *od, FlapFrame *frame, ...)
-{
- guint16 family, subtype;
- guint16 maxf, maxs;
-
- static const char *channels[6] = {
- "Invalid (0)",
- "FLAP Version",
- "SNAC",
- "Invalid (3)",
- "Negotiation",
- "FLAP NOP"
- };
- static const int maxchannels = 5;
-
- /* XXX: this is ugly. and big just for debugging. */
- static const char *literals[14][25] = {
- {"Invalid",
- NULL
- },
- {"General",
- "Invalid",
- "Error",
- "Client Ready",
- "Server Ready",
- "Service Request",
- "Redirect",
- "Rate Information Request",
- "Rate Information",
- "Rate Information Ack",
- NULL,
- "Rate Information Change",
- "Server Pause",
- NULL,
- "Server Resume",
- "Request Personal User Information",
- "Personal User Information",
- "Evil Notification",
- NULL,
- "Migration notice",
- "Message of the Day",
- "Set Privacy Flags",
- "Well Known URL",
- "NOP"
- },
- {"Location",
- "Invalid",
- "Error",
- "Request Rights",
- "Rights Information",
- "Set user information",
- "Request User Information",
- "User Information",
- "Watcher Sub Request",
- "Watcher Notification"
- },
- {"Buddy List Management",
- "Invalid",
- "Error",
- "Request Rights",
- "Rights Information",
- "Add Buddy",
- "Remove Buddy",
- "Watcher List Query",
- "Watcher List Response",
- "Watcher SubRequest",
- "Watcher Notification",
- "Reject Notification",
- "Oncoming Buddy",
- "Offgoing Buddy"
- },
- {"Messeging",
- "Invalid",
- "Error",
- "Add ICBM Parameter",
- "Remove ICBM Parameter",
- "Request Parameter Information",
- "Parameter Information",
- "Outgoing Message",
- "Incoming Message",
- "Evil Request",
- "Evil Reply",
- "Missed Calls",
- "Message Error",
- "Host Ack"
- },
- {"Advertisements",
- "Invalid",
- "Error",
- "Request Ad",
- "Ad Data (GIFs)"
- },
- {"Invitation / Client-to-Client",
- "Invalid",
- "Error",
- "Invite a Friend",
- "Invitation Ack"
- },
- {"Administrative",
- "Invalid",
- "Error",
- "Information Request",
- "Information Reply",
- "Information Change Request",
- "Information Chat Reply",
- "Account Confirm Request",
- "Account Confirm Reply",
- "Account Delete Request",
- "Account Delete Reply"
- },
- {"Popups",
- "Invalid",
- "Error",
- "Display Popup"
- },
- {"BOS",
- "Invalid",
- "Error",
- "Request Rights",
- "Rights Response",
- "Set group permission mask",
- "Add permission list entries",
- "Delete permission list entries",
- "Add deny list entries",
- "Delete deny list entries",
- "Server Error"
- },
- {"User Lookup",
- "Invalid",
- "Error",
- "Search Request",
- "Search Response"
- },
- {"Stats",
- "Invalid",
- "Error",
- "Set minimum report interval",
- "Report Events"
- },
- {"Translate",
- "Invalid",
- "Error",
- "Translate Request",
- "Translate Reply",
- },
- {"Chat Navigation",
- "Invalid",
- "Error",
- "Request rights",
- "Request Exchange Information",
- "Request Room Information",
- "Request Occupant List",
- "Search for Room",
- "Outgoing Message",
- "Incoming Message",
- "Evil Request",
- "Evil Reply",
- "Chat Error",
- }
- };
-
- maxf = sizeof(literals) / sizeof(literals[0]);
- maxs = sizeof(literals[0]) / sizeof(literals[0][0]);
-
- if (frame->channel == 0x02) {
-
- family = byte_stream_get16(&frame->data);
- subtype = byte_stream_get16(&frame->data);
-
- if ((family < maxf) && (subtype+1 < maxs) && (literals[family][subtype] != NULL))
- purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (%s)\n", channels[frame->channel], family, subtype, literals[family][subtype+1]);
- else
- purple_debug_misc("oscar", "bleck: channel %s: null handler for %04x/%04x (no literal)\n", channels[frame->channel], family, subtype);
- } else {
-
- if (frame->channel <= maxchannels)
- purple_debug_misc("oscar", "bleck: channel %s (0x%02x)\n", channels[frame->channel], frame->channel);
- else
- purple_debug_misc("oscar", "bleck: unknown channel 0x%02x\n", frame->channel);
-
- }
-
- return 1;
-}
-#endif
diff --git a/libpurple/protocols/oscar/snac.c b/libpurple/protocols/oscar/snac.c
index 4988037f3e..451dfc6647 100644
--- a/libpurple/protocols/oscar/snac.c
+++ b/libpurple/protocols/oscar/snac.c
@@ -56,11 +56,9 @@ aim_snacid_t aim_cachesnac(OscarData *od, const guint16 family, const guint16 ty
snac.type = type;
snac.flags = flags;
- if (datalen) {
- if (!(snac.data = g_malloc(datalen)))
- return 0; /* er... */
- memcpy(snac.data, data, datalen);
- } else
+ if (datalen)
+ snac.data = g_memdup(data, datalen);
+ else
snac.data = NULL;
return aim_newsnac(od, &snac);
@@ -78,9 +76,7 @@ aim_snacid_t aim_newsnac(OscarData *od, aim_snac_t *newsnac)
if (!newsnac)
return 0;
- if (!(snac = g_malloc(sizeof(aim_snac_t))))
- return 0;
- memcpy(snac, newsnac, sizeof(aim_snac_t));
+ snac = g_memdup(newsnac, sizeof(aim_snac_t));
snac->issuetime = time(NULL);
index = snac->id % FAIM_SNAC_HASH_SIZE;
@@ -155,12 +151,12 @@ void aim_cleansnacs(OscarData *od, int maxage)
return;
}
-int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid)
+int aim_putsnac(ByteStream *bs, guint16 family, guint16 subtype, aim_snacid_t snacid)
{
byte_stream_put16(bs, family);
byte_stream_put16(bs, subtype);
- byte_stream_put16(bs, flags);
+ byte_stream_put16(bs, 0x0000);
byte_stream_put32(bs, snacid);
return 10;
diff --git a/libpurple/protocols/oscar/tlv.c b/libpurple/protocols/oscar/tlv.c
index 8c93f98005..67f18080c3 100644
--- a/libpurple/protocols/oscar/tlv.c
+++ b/libpurple/protocols/oscar/tlv.c
@@ -49,27 +49,7 @@ aim_tlv_read(GSList *list, ByteStream *bs)
type = byte_stream_get16(bs);
length = byte_stream_get16(bs);
-#if 0
- /*
- * This code hasn't been needed in years. It's been commented
- * out since 2003, at the latest. It seems likely that it was
- * just a bug in their server code that has since been fixed.
- * In any case, here's the orignal comment, kept for historical
- * purposes:
- *
- * Okay, so now AOL has decided that any TLV of
- * type 0x0013 can only be two bytes, despite
- * what the actual given length is. So here
- * we dump any invalid TLVs of that sort. Hopefully
- * there's no special cases to this special case.
- * - mid (30jun2000)
- */
- if ((type == 0x0013) && (length != 0x0002)) {
- length = 0x0002;
- return list;
- }
-#endif
- if (length > byte_stream_empty(bs)) {
+ if (length > byte_stream_bytes_left(bs)) {
aim_tlvlist_free(list);
return NULL;
}
@@ -108,7 +88,7 @@ GSList *aim_tlvlist_read(ByteStream *bs)
{
GSList *list = NULL;
- while (byte_stream_empty(bs) > 0) {
+ while (byte_stream_bytes_left(bs) > 0) {
list = aim_tlv_read(list, bs);
if (list == NULL)
return NULL;
@@ -142,7 +122,7 @@ GSList *aim_tlvlist_readnum(ByteStream *bs, guint16 num)
{
GSList *list = NULL;
- while ((byte_stream_empty(bs) > 0) && (num != 0)) {
+ while ((byte_stream_bytes_left(bs) > 0) && (num != 0)) {
list = aim_tlv_read(list, bs);
if (list == NULL)
return NULL;
@@ -177,7 +157,7 @@ GSList *aim_tlvlist_readlen(ByteStream *bs, guint16 len)
{
GSList *list = NULL;
- while ((byte_stream_empty(bs) > 0) && (len > 0)) {
+ while ((byte_stream_bytes_left(bs) > 0) && (len > 0)) {
list = aim_tlv_read(list, bs);
if (list == NULL)
return NULL;
@@ -391,6 +371,17 @@ int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
return aim_tlvlist_add_raw(list, type, strlen(value), (guint8 *)value);
}
+static int
+count_caps(guint64 caps)
+{
+ int set_bits = 0;
+ while (caps) {
+ set_bits += caps & 1;
+ caps >>= 1;
+ }
+ return set_bits;
+}
+
/**
* Adds a block of capability blocks to a TLV chain. The bitfield
* passed in should be a bitwise %OR of any of the %AIM_CAPS constants:
@@ -409,23 +400,24 @@ int aim_tlvlist_add_str(GSList **list, const guint16 type, const char *value)
*/
int aim_tlvlist_add_caps(GSList **list, const guint16 type, const guint64 caps, const char *mood)
{
- guint8 buf[256]; /* TODO: Don't use a fixed length buffer */
ByteStream bs;
+ guint32 bs_size;
guint8 *data;
if (caps == 0)
return 0; /* nothing there anyway */
- byte_stream_init(&bs, buf, sizeof(buf));
+ data = icq_get_custom_icon_data(mood);
+ bs_size = 16*(count_caps(caps) + (data != NULL ? 1 : 0));
+ byte_stream_new(&bs, bs_size);
byte_stream_putcaps(&bs, caps);
-
+
/* adding of custom icon GUID */
- data = icq_get_custom_icon_data(mood);
if (data != NULL)
byte_stream_putraw(&bs, data, 16);
- return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), buf);
+ return aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
}
/**
@@ -668,7 +660,7 @@ int aim_tlvlist_write(ByteStream *bs, GSList **list)
/* do an initial run to test total length */
goodbuflen = aim_tlvlist_size(*list);
- if (goodbuflen > byte_stream_empty(bs))
+ if (goodbuflen > byte_stream_bytes_left(bs))
return 0; /* not enough buffer */
/* do the real write-out */
diff --git a/libpurple/protocols/oscar/userinfo.c b/libpurple/protocols/oscar/userinfo.c
new file mode 100644
index 0000000000..5762977ad6
--- /dev/null
+++ b/libpurple/protocols/oscar/userinfo.c
@@ -0,0 +1,553 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+*/
+
+/*
+ * Displaying various information about buddies.
+ */
+
+#include "encoding.h"
+#include "oscar.h"
+
+static gchar *
+oscar_caps_to_string(guint64 caps)
+{
+ GString *str;
+ const gchar *tmp;
+ guint64 bit = 1;
+
+ str = g_string_new("");
+
+ if (!caps) {
+ return NULL;
+ } else while (bit <= OSCAR_CAPABILITY_LAST) {
+ if (bit & caps) {
+ switch (bit) {
+ case OSCAR_CAPABILITY_BUDDYICON:
+ tmp = _("Buddy Icon");
+ break;
+ case OSCAR_CAPABILITY_TALK:
+ tmp = _("Voice");
+ break;
+ case OSCAR_CAPABILITY_DIRECTIM:
+ tmp = _("AIM Direct IM");
+ break;
+ case OSCAR_CAPABILITY_CHAT:
+ tmp = _("Chat");
+ break;
+ case OSCAR_CAPABILITY_GETFILE:
+ tmp = _("Get File");
+ break;
+ case OSCAR_CAPABILITY_SENDFILE:
+ tmp = _("Send File");
+ break;
+ case OSCAR_CAPABILITY_GAMES:
+ case OSCAR_CAPABILITY_GAMES2:
+ tmp = _("Games");
+ break;
+ case OSCAR_CAPABILITY_XTRAZ:
+ case OSCAR_CAPABILITY_NEWCAPS:
+ tmp = _("ICQ Xtraz");
+ break;
+ case OSCAR_CAPABILITY_ADDINS:
+ tmp = _("Add-Ins");
+ break;
+ case OSCAR_CAPABILITY_SENDBUDDYLIST:
+ tmp = _("Send Buddy List");
+ break;
+ case OSCAR_CAPABILITY_ICQ_DIRECT:
+ tmp = _("ICQ Direct Connect");
+ break;
+ case OSCAR_CAPABILITY_APINFO:
+ tmp = _("AP User");
+ break;
+ case OSCAR_CAPABILITY_ICQRTF:
+ tmp = _("ICQ RTF");
+ break;
+ case OSCAR_CAPABILITY_EMPTY:
+ tmp = _("Nihilist");
+ break;
+ case OSCAR_CAPABILITY_ICQSERVERRELAY:
+ tmp = _("ICQ Server Relay");
+ break;
+ case OSCAR_CAPABILITY_UNICODEOLD:
+ tmp = _("Old ICQ UTF8");
+ break;
+ case OSCAR_CAPABILITY_TRILLIANCRYPT:
+ tmp = _("Trillian Encryption");
+ break;
+ case OSCAR_CAPABILITY_UNICODE:
+ tmp = _("ICQ UTF8");
+ break;
+ case OSCAR_CAPABILITY_HIPTOP:
+ tmp = _("Hiptop");
+ break;
+ case OSCAR_CAPABILITY_SECUREIM:
+ tmp = _("Security Enabled");
+ break;
+ case OSCAR_CAPABILITY_VIDEO:
+ tmp = _("Video Chat");
+ break;
+ /* Not actually sure about this one... WinAIM doesn't show anything */
+ case OSCAR_CAPABILITY_ICHATAV:
+ tmp = _("iChat AV");
+ break;
+ case OSCAR_CAPABILITY_LIVEVIDEO:
+ tmp = _("Live Video");
+ break;
+ case OSCAR_CAPABILITY_CAMERA:
+ tmp = _("Camera");
+ break;
+ case OSCAR_CAPABILITY_ICHAT_SCREENSHARE:
+ tmp = _("Screen Sharing");
+ break;
+ default:
+ tmp = NULL;
+ break;
+ }
+ if (tmp)
+ g_string_append_printf(str, "%s%s", (*(str->str) == '\0' ? "" : ", "), tmp);
+ }
+ bit <<= 1;
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+static void
+oscar_user_info_add_pair(PurpleNotifyUserInfo *user_info, const char *name, const char *value)
+{
+ if (value && value[0]) {
+ purple_notify_user_info_add_pair(user_info, name, value);
+ }
+}
+
+static void
+oscar_user_info_convert_and_add(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
+ const char *name, const char *value)
+{
+ gchar *utf8;
+
+ if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
+ purple_notify_user_info_add_pair(user_info, name, utf8);
+ g_free(utf8);
+ }
+}
+
+static void
+oscar_user_info_convert_and_add_hyperlink(PurpleAccount *account, OscarData *od, PurpleNotifyUserInfo *user_info,
+ const char *name, const char *value, const char *url_prefix)
+{
+ gchar *utf8;
+
+ if (value && value[0] && (utf8 = oscar_utf8_try_convert(account, od, value))) {
+ gchar *tmp = g_strdup_printf("<a href=\"%s%s\">%s</a>", url_prefix, utf8, utf8);
+ purple_notify_user_info_add_pair(user_info, name, tmp);
+ g_free(utf8);
+ g_free(tmp);
+ }
+}
+
+/**
+ * @brief Append the status information to a user_info struct
+ *
+ * The returned information is HTML-ready, appropriately escaped, as all information in a user_info struct should be HTML.
+ *
+ * @param gc The PurpleConnection
+ * @param user_info A PurpleNotifyUserInfo object to which status information will be added
+ * @param b The PurpleBuddy whose status is desired. This or the aim_userinfo_t (or both) must be passed to oscar_user_info_append_status().
+ * @param userinfo The aim_userinfo_t of the buddy whose status is desired. This or the PurpleBuddy (or both) must be passed to oscar_user_info_append_status().
+ * @param strip_html_tags If strip_html_tags is TRUE, tags embedded in the status message will be stripped, returning a non-formatted string. The string will still be HTML escaped.
+ */
+void
+oscar_user_info_append_status(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo, gboolean strip_html_tags)
+{
+ PurpleAccount *account = purple_connection_get_account(gc);
+ OscarData *od;
+ PurplePresence *presence = NULL;
+ PurpleStatus *status = NULL;
+ gchar *message = NULL, *itmsurl = NULL, *tmp;
+ gboolean is_away;
+
+ od = purple_connection_get_protocol_data(gc);
+
+ if (b == NULL && userinfo == NULL)
+ return;
+
+ if (b == NULL)
+ b = purple_find_buddy(purple_connection_get_account(gc), userinfo->bn);
+ else
+ userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
+
+ if (b) {
+ presence = purple_buddy_get_presence(b);
+ status = purple_presence_get_active_status(presence);
+ }
+
+ /* If we have both b and userinfo we favor userinfo, because if we're
+ viewing someone's profile then we want the HTML away message, and
+ the "message" attribute of the status contains only the plaintext
+ message. */
+ if (userinfo) {
+ if ((userinfo->flags & AIM_FLAG_AWAY) && userinfo->away_len > 0 && userinfo->away != NULL && userinfo->away_encoding != NULL) {
+ /* Away message */
+ message = oscar_encoding_to_utf8(userinfo->away_encoding, userinfo->away, userinfo->away_len);
+ } else {
+ /*
+ * Available message or non-HTML away message (because that's
+ * all we have right now.
+ */
+ if ((userinfo->status != NULL) && userinfo->status[0] != '\0') {
+ message = oscar_encoding_to_utf8(userinfo->status_encoding, userinfo->status, userinfo->status_len);
+ }
+#if defined (_WIN32) || defined (__APPLE__)
+ if (userinfo->itmsurl && (userinfo->itmsurl[0] != '\0')) {
+ itmsurl = oscar_encoding_to_utf8(userinfo->itmsurl_encoding, userinfo->itmsurl, userinfo->itmsurl_len);
+ }
+#endif
+ }
+ } else {
+ message = g_strdup(purple_status_get_attr_string(status, "message"));
+ itmsurl = g_strdup(purple_status_get_attr_string(status, "itmsurl"));
+ }
+
+ is_away = ((status && !purple_status_is_available(status)) ||
+ (userinfo && (userinfo->flags & AIM_FLAG_AWAY)));
+
+ if (strip_html_tags) {
+ /* Away messages are HTML, but available messages were originally plain text.
+ * We therefore need to strip away messages but not available messages if we're asked to remove HTML tags.
+ */
+ /*
+ * It seems like the above comment no longer applies. All messages need
+ * to be escaped.
+ */
+ if (message) {
+ gchar *tmp2;
+ tmp = purple_markup_strip_html(message);
+ g_free(message);
+ tmp2 = g_markup_escape_text(tmp, -1);
+ g_free(tmp);
+ message = tmp2;
+ }
+
+ } else {
+ if (itmsurl) {
+ tmp = g_strdup_printf("<a href=\"%s\">%s</a>",
+ itmsurl, message);
+ g_free(message);
+ message = tmp;
+ }
+ }
+ g_free(itmsurl);
+
+ if (message) {
+ tmp = oscar_util_format_string(message, purple_account_get_username(account));
+ g_free(message);
+ message = tmp;
+ }
+
+ if (b) {
+ if (purple_presence_is_online(presence)) {
+ if (oscar_util_valid_name_icq(purple_buddy_get_name(b)) || is_away || !message || !(*message)) {
+ /* Append the status name for online ICQ statuses, away AIM statuses, and for all buddies with no message.
+ * If the status name and the message are the same, only show one. */
+ const char *status_name = purple_status_get_name(status);
+ if (status_name && message && !strcmp(status_name, message))
+ status_name = NULL;
+
+ tmp = g_strdup_printf("%s%s%s",
+ status_name ? status_name : "",
+ ((status_name && message) && *message) ? ": " : "",
+ (message && *message) ? message : "");
+ g_free(message);
+ message = tmp;
+ }
+
+ } else if (aim_ssi_waitingforauth(od->ssi.local,
+ aim_ssi_itemlist_findparentname(od->ssi.local, purple_buddy_get_name(b)),
+ purple_buddy_get_name(b)))
+ {
+ /* Note if an offline buddy is not authorized */
+ tmp = g_strdup_printf("%s%s%s",
+ _("Not Authorized"),
+ (message && *message) ? ": " : "",
+ (message && *message) ? message : "");
+ g_free(message);
+ message = tmp;
+ } else {
+ g_free(message);
+ message = g_strdup(_("Offline"));
+ }
+ }
+
+ if (presence) {
+ const char *mood;
+ const char *description;
+ status = purple_presence_get_status(presence, "mood");
+ mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME);
+ description = icq_get_custom_icon_description(mood);
+ if (description && *description)
+ purple_notify_user_info_add_pair(user_info, _("Mood"), _(description));
+ }
+
+ purple_notify_user_info_add_pair(user_info, _("Status"), message);
+ g_free(message);
+}
+
+void
+oscar_user_info_append_extra_info(PurpleConnection *gc, PurpleNotifyUserInfo *user_info, PurpleBuddy *b, aim_userinfo_t *userinfo)
+{
+ OscarData *od;
+ PurpleAccount *account;
+ PurplePresence *presence = NULL;
+ PurpleStatus *status = NULL;
+ PurpleGroup *g = NULL;
+ struct buddyinfo *bi = NULL;
+ char *tmp;
+ const char *bname = NULL, *gname = NULL;
+
+ od = purple_connection_get_protocol_data(gc);
+ account = purple_connection_get_account(gc);
+
+ if ((user_info == NULL) || ((b == NULL) && (userinfo == NULL)))
+ return;
+
+ if (userinfo == NULL)
+ userinfo = aim_locate_finduserinfo(od, purple_buddy_get_name(b));
+
+ if (b == NULL)
+ b = purple_find_buddy(account, userinfo->bn);
+
+ if (b != NULL) {
+ bname = purple_buddy_get_name(b);
+ g = purple_buddy_get_group(b);
+ gname = purple_group_get_name(g);
+ presence = purple_buddy_get_presence(b);
+ status = purple_presence_get_active_status(presence);
+ }
+
+ if (userinfo != NULL)
+ bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, userinfo->bn));
+
+ if ((bi != NULL) && (bi->ipaddr != 0)) {
+ tmp = g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
+ (bi->ipaddr & 0xff000000) >> 24,
+ (bi->ipaddr & 0x00ff0000) >> 16,
+ (bi->ipaddr & 0x0000ff00) >> 8,
+ (bi->ipaddr & 0x000000ff));
+ oscar_user_info_add_pair(user_info, _("IP Address"), tmp);
+ g_free(tmp);
+ }
+
+ if ((userinfo != NULL) && (userinfo->warnlevel != 0)) {
+ tmp = g_strdup_printf("%d", (int)(userinfo->warnlevel/10.0 + .5));
+ oscar_user_info_add_pair(user_info, _("Warning Level"), tmp);
+ g_free(tmp);
+ }
+
+ if ((b != NULL) && (bname != NULL) && (g != NULL) && (gname != NULL)) {
+ tmp = aim_ssi_getcomment(od->ssi.local, gname, bname);
+ if (tmp != NULL) {
+ char *tmp2 = g_markup_escape_text(tmp, strlen(tmp));
+ g_free(tmp);
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Buddy Comment"), tmp2);
+ g_free(tmp2);
+ }
+ }
+}
+
+void
+oscar_user_info_display_error(OscarData *od, guint16 error_reason, gchar *buddy)
+{
+ PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
+ gchar *buf = g_strdup_printf(_("User information not available: %s"), oscar_get_msgerr_reason(error_reason));
+ purple_notify_user_info_add_pair(user_info, NULL, buf);
+ purple_notify_userinfo(od->gc, buddy, user_info, NULL, NULL);
+ purple_notify_user_info_destroy(user_info);
+ purple_conv_present_error(buddy, purple_connection_get_account(od->gc), buf);
+ g_free(buf);
+}
+
+void
+oscar_user_info_display_icq(OscarData *od, struct aim_icq_info *info)
+{
+ PurpleConnection *gc = od->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ PurpleBuddy *buddy;
+ struct buddyinfo *bi;
+ gchar who[16];
+ PurpleNotifyUserInfo *user_info;
+ const gchar *alias;
+
+ if (!info->uin)
+ return;
+
+ user_info = purple_notify_user_info_new();
+
+ g_snprintf(who, sizeof(who), "%u", info->uin);
+ buddy = purple_find_buddy(account, who);
+ if (buddy != NULL)
+ bi = g_hash_table_lookup(od->buddyinfo, purple_normalize(account, purple_buddy_get_name(buddy)));
+ else
+ bi = NULL;
+
+ purple_notify_user_info_add_pair(user_info, _("UIN"), who);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Nick"), info->nick);
+ if ((bi != NULL) && (bi->ipaddr != 0)) {
+ char *tstr = g_strdup_printf("%hhu.%hhu.%hhu.%hhu",
+ (bi->ipaddr & 0xff000000) >> 24,
+ (bi->ipaddr & 0x00ff0000) >> 16,
+ (bi->ipaddr & 0x0000ff00) >> 8,
+ (bi->ipaddr & 0x000000ff));
+ purple_notify_user_info_add_pair(user_info, _("IP Address"), tstr);
+ g_free(tstr);
+ }
+ oscar_user_info_convert_and_add(account, od, user_info, _("First Name"), info->first);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Last Name"), info->last);
+ oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email, "mailto:");
+ if (info->numaddresses && info->email2) {
+ int i;
+ for (i = 0; i < info->numaddresses; i++) {
+ oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Email Address"), info->email2[i], "mailto:");
+ }
+ }
+ oscar_user_info_convert_and_add(account, od, user_info, _("Mobile Phone"), info->mobile);
+
+ if (info->gender != 0)
+ purple_notify_user_info_add_pair(user_info, _("Gender"), (info->gender == 1 ? _("Female") : _("Male")));
+
+ if ((info->birthyear > 1900) && (info->birthmonth > 0) && (info->birthday > 0)) {
+ /* Initialize the struct properly or strftime() will crash
+ * under some conditions (e.g. Debian sarge w/ LANG=en_HK). */
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&t);
+
+ tm->tm_mday = (int)info->birthday;
+ tm->tm_mon = (int)info->birthmonth - 1;
+ tm->tm_year = (int)info->birthyear - 1900;
+
+ /* To be 100% sure that the fields are re-normalized.
+ * If you're sure strftime() ALWAYS does this EVERYWHERE,
+ * feel free to remove it. --rlaager */
+ mktime(tm);
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Birthday"), purple_date_format_short(tm));
+ }
+ if ((info->age > 0) && (info->age < 255)) {
+ char age[5];
+ snprintf(age, sizeof(age), "%hhd", info->age);
+ purple_notify_user_info_add_pair(user_info, _("Age"), age);
+ }
+ oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Personal Web Page"), info->email, "");
+ if (buddy != NULL)
+ oscar_user_info_append_status(gc, user_info, buddy, /* aim_userinfo_t */ NULL, /* strip_html_tags */ FALSE);
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Additional Information"), info->info);
+ purple_notify_user_info_add_section_break(user_info);
+
+ if ((info->homeaddr && (info->homeaddr[0])) || (info->homecity && info->homecity[0]) || (info->homestate && info->homestate[0]) || (info->homezip && info->homezip[0])) {
+ purple_notify_user_info_add_section_header(user_info, _("Home Address"));
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->homeaddr);
+ oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->homecity);
+ oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->homestate);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->homezip);
+ }
+ if ((info->workaddr && info->workaddr[0]) || (info->workcity && info->workcity[0]) || (info->workstate && info->workstate[0]) || (info->workzip && info->workzip[0])) {
+ purple_notify_user_info_add_section_header(user_info, _("Work Address"));
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Address"), info->workaddr);
+ oscar_user_info_convert_and_add(account, od, user_info, _("City"), info->workcity);
+ oscar_user_info_convert_and_add(account, od, user_info, _("State"), info->workstate);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Zip Code"), info->workzip);
+ }
+ if ((info->workcompany && info->workcompany[0]) || (info->workdivision && info->workdivision[0]) || (info->workposition && info->workposition[0]) || (info->workwebpage && info->workwebpage[0])) {
+ purple_notify_user_info_add_section_header(user_info, _("Work Information"));
+
+ oscar_user_info_convert_and_add(account, od, user_info, _("Company"), info->workcompany);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Division"), info->workdivision);
+ oscar_user_info_convert_and_add(account, od, user_info, _("Position"), info->workposition);
+ oscar_user_info_convert_and_add_hyperlink(account, od, user_info, _("Web Page"), info->email, "");
+ }
+
+ if (buddy != NULL)
+ alias = purple_buddy_get_alias(buddy);
+ else
+ alias = who;
+ purple_notify_userinfo(gc, who, user_info, NULL, NULL);
+ purple_notify_user_info_destroy(user_info);
+}
+
+void
+oscar_user_info_display_aim(OscarData *od, aim_userinfo_t *userinfo)
+{
+ PurpleConnection *gc = od->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+ PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
+ gchar *tmp = NULL, *info_utf8 = NULL, *base_profile_url = NULL;
+
+ oscar_user_info_append_status(gc, user_info, /* PurpleBuddy */ NULL, userinfo, /* strip_html_tags */ FALSE);
+
+ if ((userinfo->present & AIM_USERINFO_PRESENT_IDLE) && userinfo->idletime != 0) {
+ tmp = purple_str_seconds_to_string(userinfo->idletime*60);
+ oscar_user_info_add_pair(user_info, _("Idle"), tmp);
+ g_free(tmp);
+ }
+
+ oscar_user_info_append_extra_info(gc, user_info, NULL, userinfo);
+
+ if ((userinfo->present & AIM_USERINFO_PRESENT_ONLINESINCE) && !oscar_util_valid_name_sms(userinfo->bn)) {
+ /* An SMS contact is always online; its Online Since value is not useful */
+ time_t t = userinfo->onlinesince;
+ oscar_user_info_add_pair(user_info, _("Online Since"), purple_date_format_full(localtime(&t)));
+ }
+
+ if (userinfo->present & AIM_USERINFO_PRESENT_MEMBERSINCE) {
+ time_t t = userinfo->membersince;
+ oscar_user_info_add_pair(user_info, _("Member Since"), purple_date_format_full(localtime(&t)));
+ }
+
+ if (userinfo->capabilities != 0) {
+ tmp = oscar_caps_to_string(userinfo->capabilities);
+ oscar_user_info_add_pair(user_info, _("Capabilities"), tmp);
+ g_free(tmp);
+ }
+
+ /* Info */
+ if ((userinfo->info_len > 0) && (userinfo->info != NULL) && (userinfo->info_encoding != NULL)) {
+ info_utf8 = oscar_encoding_to_utf8(userinfo->info_encoding, userinfo->info, userinfo->info_len);
+ tmp = oscar_util_format_string(info_utf8, purple_account_get_username(account));
+ purple_notify_user_info_add_section_break(user_info);
+ oscar_user_info_add_pair(user_info, _("Profile"), tmp);
+ g_free(tmp);
+ g_free(info_utf8);
+ }
+
+ purple_notify_user_info_add_section_break(user_info);
+ base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com";
+ tmp = g_strdup_printf("<a href=\"%s/%s\">%s</a>",
+ base_profile_url, purple_normalize(account, userinfo->bn), _("View web profile"));
+ purple_notify_user_info_add_pair(user_info, NULL, tmp);
+ g_free(tmp);
+
+ purple_notify_userinfo(gc, userinfo->bn, user_info, NULL, NULL);
+ purple_notify_user_info_destroy(user_info);
+} \ No newline at end of file
diff --git a/libpurple/protocols/oscar/util.c b/libpurple/protocols/oscar/util.c
index b8b1cf7c2e..81211824eb 100644
--- a/libpurple/protocols/oscar/util.c
+++ b/libpurple/protocols/oscar/util.c
@@ -35,6 +35,40 @@
#include "win32dep.h"
#endif
+static const char * const msgerrreason[] = {
+ N_("Invalid error"),
+ N_("Invalid SNAC"),
+ N_("Server rate limit exceeded"),
+ N_("Client rate limit exceeded"),
+ N_("Not logged in"),
+ N_("Service unavailable"),
+ N_("Service not defined"),
+ N_("Obsolete SNAC"),
+ N_("Not supported by host"),
+ N_("Not supported by client"),
+ N_("Refused by client"),
+ N_("Reply too big"),
+ N_("Responses lost"),
+ N_("Request denied"),
+ N_("Busted SNAC payload"),
+ N_("Insufficient rights"),
+ N_("In local permit/deny"),
+ N_("Warning level too high (sender)"),
+ N_("Warning level too high (receiver)"),
+ N_("User temporarily unavailable"),
+ N_("No match"),
+ N_("List overflow"),
+ N_("Request ambiguous"),
+ N_("Queue full"),
+ N_("Not while on AOL")
+};
+static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
+
+const char *oscar_get_msgerr_reason(size_t reason)
+{
+ return (reason < msgerrreasonlen) ? _(msgerrreason[reason]) : _("Unknown reason");
+}
+
int oscar_get_ui_info_int(const char *str, int default_value)
{
GHashTable *ui_info;
@@ -73,91 +107,6 @@ gchar *oscar_get_clientstring(void)
return g_strdup_printf("%s/%s", name, version);;
}
-/*
- * Tokenizing functions. Used to portably replace strtok/sep.
- * -- DMP.
- *
- */
-/* TODO: Get rid of this and use glib functions */
-int
-aimutil_tokslen(char *toSearch, int theindex, char dl)
-{
- int curCount = 1;
- char *next;
- char *last;
- int toReturn;
-
- last = toSearch;
- next = strchr(toSearch, dl);
-
- while(curCount < theindex && next != NULL) {
- curCount++;
- last = next + 1;
- next = strchr(last, dl);
- }
-
- if ((curCount < theindex) || (next == NULL))
- toReturn = strlen(toSearch) - (curCount - 1);
- else
- toReturn = next - toSearch - (curCount - 1);
-
- return toReturn;
-}
-
-int
-aimutil_itemcnt(char *toSearch, char dl)
-{
- int curCount;
- char *next;
-
- curCount = 1;
-
- next = strchr(toSearch, dl);
-
- while(next != NULL) {
- curCount++;
- next = strchr(next + 1, dl);
- }
-
- return curCount;
-}
-
-char *
-aimutil_itemindex(char *toSearch, int theindex, char dl)
-{
- int curCount;
- char *next;
- char *last;
- char *toReturn;
-
- curCount = 0;
-
- last = toSearch;
- next = strchr(toSearch, dl);
-
- while (curCount < theindex && next != NULL) {
- curCount++;
- last = next + 1;
- next = strchr(last, dl);
- }
- next = strchr(last, dl);
-
- if (curCount < theindex) {
- toReturn = g_malloc(sizeof(char));
- *toReturn = '\0';
- } else {
- if (next == NULL) {
- toReturn = g_malloc((strlen(last) + 1) * sizeof(char));
- strcpy(toReturn, last);
- } else {
- toReturn = g_malloc((next - last + 1) * sizeof(char));
- memcpy(toReturn, last, (next - last));
- toReturn[next - last] = '\0';
- }
- }
- return toReturn;
-}
-
/**
* Calculate the checksum of a given icon.
*/
@@ -289,3 +238,89 @@ oscar_util_name_compare(const char *name1, const char *name2)
return 0;
}
+
+/**
+ * Looks for %n, %d, or %t in a string, and replaces them with the
+ * specified name, date, and time, respectively.
+ *
+ * @param str The string that may contain the special variables.
+ * @param name The sender name.
+ *
+ * @return A newly allocated string where the special variables are
+ * expanded. This should be g_free'd by the caller.
+ */
+gchar *
+oscar_util_format_string(const char *str, const char *name)
+{
+ char *c;
+ GString *cpy;
+ time_t t;
+ struct tm *tme;
+
+ g_return_val_if_fail(str != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ /* Create an empty GString that is hopefully big enough for most messages */
+ cpy = g_string_sized_new(1024);
+
+ t = time(NULL);
+ tme = localtime(&t);
+
+ c = (char *)str;
+ while (*c) {
+ switch (*c) {
+ case '%':
+ if (*(c + 1)) {
+ switch (*(c + 1)) {
+ case 'n':
+ /* append name */
+ g_string_append(cpy, name);
+ c++;
+ break;
+ case 'd':
+ /* append date */
+ g_string_append(cpy, purple_date_format_short(tme));
+ c++;
+ break;
+ case 't':
+ /* append time */
+ g_string_append(cpy, purple_time_format(tme));
+ c++;
+ break;
+ default:
+ g_string_append_c(cpy, *c);
+ }
+ } else {
+ g_string_append_c(cpy, *c);
+ }
+ break;
+ default:
+ g_string_append_c(cpy, *c);
+ }
+ c++;
+ }
+
+ return g_string_free(cpy, FALSE);
+}
+
+gchar *
+oscar_format_buddies(GSList *buddies, const gchar *no_buddies_message)
+{
+ GSList *cur;
+ GString *result;
+ if (!buddies) {
+ return g_strdup_printf("<i>%s</i>", no_buddies_message);
+ }
+ result = g_string_new("");
+ for (cur = buddies; cur != NULL; cur = cur->next) {
+ PurpleBuddy *buddy = cur->data;
+ const gchar *bname = purple_buddy_get_name(buddy);
+ const gchar *alias = purple_buddy_get_alias_only(buddy);
+ g_string_append(result, bname);
+ if (alias) {
+ g_string_append_printf(result, " (%s)", alias);
+ }
+ g_string_append(result, "<br>");
+ }
+ return g_string_free(result, FALSE);
+}
diff --git a/libpurple/protocols/oscar/visibility.c b/libpurple/protocols/oscar/visibility.c
new file mode 100644
index 0000000000..abec4688f8
--- /dev/null
+++ b/libpurple/protocols/oscar/visibility.c
@@ -0,0 +1,199 @@
+/*
+ * Purple's oscar protocol plugin
+ * This file is the legal property of its developers.
+ * Please see the AUTHORS file distributed alongside this file.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "visibility.h"
+#include "request.h"
+
+/* 4 separate strings are needed in order to ease translators' job */
+#define APPEAR_ONLINE N_("Appear Online")
+#define DONT_APPEAR_ONLINE N_("Don't Appear Online")
+#define APPEAR_OFFLINE N_("Appear Offline")
+#define DONT_APPEAR_OFFLINE N_("Don't Appear Offline")
+
+static guint16
+get_buddy_list_type(OscarData *od)
+{
+ PurpleAccount *account = purple_connection_get_account(od->gc);
+ return purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE) ? AIM_SSI_TYPE_PERMIT : AIM_SSI_TYPE_DENY;
+}
+
+static gboolean
+is_buddy_on_list(OscarData *od, const char *bname)
+{
+ return aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, get_buddy_list_type(od)) != NULL;
+}
+
+static void
+visibility_cb(PurpleBlistNode *node, gpointer whatever)
+{
+ PurpleBuddy *buddy = PURPLE_BUDDY(node);
+ const char* bname = purple_buddy_get_name(buddy);
+ OscarData *od = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy)));
+ guint16 list_type = get_buddy_list_type(od);
+
+ if (!is_buddy_on_list(od, bname)) {
+ aim_ssi_add_to_private_list(od, bname, list_type);
+ } else {
+ aim_ssi_del_from_private_list(od, bname, list_type);
+ }
+}
+
+PurpleMenuAction *
+create_visibility_menu_item(OscarData *od, const char *bname)
+{
+ PurpleAccount *account = purple_connection_get_account(od->gc);
+ gboolean invisible = purple_account_is_status_active(account, OSCAR_STATUS_ID_INVISIBLE);
+ gboolean on_list = is_buddy_on_list(od, bname);
+ const gchar *label;
+
+ if (invisible) {
+ label = on_list ? _(DONT_APPEAR_ONLINE) : _(APPEAR_ONLINE);
+ } else {
+ label = on_list ? _(DONT_APPEAR_OFFLINE) : _(APPEAR_OFFLINE);
+ }
+ return purple_menu_action_new(label, PURPLE_CALLBACK(visibility_cb), NULL, NULL);
+}
+
+typedef void (*ShowDialog)(PurplePluginAction *);
+
+struct list_remove_data
+{
+ PurplePluginAction *action;
+ ShowDialog show_dialog_again;
+ OscarData *od;
+ guint16 list_type;
+ const gchar *list_name;
+};
+
+static void
+list_remove_cb(struct list_remove_data *data, PurpleRequestFields *fields)
+{
+ ShowDialog show_dialog_again = data->show_dialog_again;
+ PurplePluginAction *action = data->action;
+ PurpleRequestField *field = purple_request_fields_get_field(fields, "list-items");
+ GList *sels = purple_request_field_list_get_selected(field);
+ for (; sels; sels = sels->next) {
+ const gchar *name = sels->data;
+ const gchar *bname = purple_request_field_list_get_data(field, name);
+
+ purple_debug_info("oscar", "Removing %s from %s\n", bname, data->list_name);
+
+ aim_ssi_del_from_private_list(data->od, bname, data->list_type);
+ }
+
+ g_free(data);
+ show_dialog_again(action);
+}
+
+static void
+list_close_cb(struct list_remove_data *data, gpointer ignored)
+{
+ g_free(data);
+}
+
+static void
+show_private_list(PurplePluginAction *action,
+ guint16 list_type,
+ const gchar *list_name,
+ const gchar *list_description,
+ const gchar *menu_action_name,
+ ShowDialog caller)
+{
+ PurpleConnection *gc = (PurpleConnection *) action->context;
+ OscarData *od = purple_connection_get_protocol_data(gc);
+ PurpleAccount *account = purple_connection_get_account(gc);
+ GSList *buddies, *cur;
+ gchar *desc;
+ struct list_remove_data *data;
+
+ PurpleRequestField *field;
+ PurpleRequestFields *fields = purple_request_fields_new();
+ PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
+
+ purple_request_fields_add_group(fields, group);
+
+ desc = g_strdup_printf(_("You can add a buddy to this list "
+ "by right-clicking on them and "
+ "selecting \"%s\""), menu_action_name);
+
+ field = purple_request_field_list_new("list-items", desc);
+ g_free(desc);
+
+ purple_request_field_group_add_field(group, field);
+
+ purple_request_field_list_set_multi_select(field, TRUE);
+ purple_request_field_set_required(field, TRUE);
+
+ buddies = purple_find_buddies(account, NULL);
+ for (cur = buddies; cur != NULL; cur = cur->next) {
+ PurpleBuddy *buddy;
+ const gchar *bname;
+
+ buddy = cur->data;
+ bname = purple_buddy_get_name(buddy);
+ if (aim_ssi_itemlist_finditem(od->ssi.local, NULL, bname, list_type)) {
+ const gchar *alias = purple_buddy_get_alias_only(buddy);
+ char *dname = alias ? g_strdup_printf("%s (%s)", bname, alias) : NULL;
+ purple_request_field_list_add(field, dname ? dname : bname, (void *)bname);
+ g_free(dname);
+ }
+ }
+
+ g_slist_free(buddies);
+
+ data = g_new0(struct list_remove_data, 1);
+ data->action = action;
+ data->show_dialog_again = caller;
+ data->od = od;
+ data->list_type = list_type;
+ data->list_name = list_name;
+
+ purple_request_fields(gc, list_name, list_description, NULL,
+ fields,
+ _("Close"), G_CALLBACK(list_close_cb),
+ _("Remove"), G_CALLBACK(list_remove_cb),
+ account, NULL, NULL,
+ data);
+}
+
+void
+oscar_show_visible_list(PurplePluginAction *action)
+{
+ show_private_list(action,
+ AIM_SSI_TYPE_PERMIT,
+ _("Visible List"),
+ _("These buddies will see "
+ "your status when you switch "
+ "to \"Invisible\""),
+ _(APPEAR_ONLINE),
+ oscar_show_visible_list);
+}
+
+void
+oscar_show_invisible_list(PurplePluginAction *action)
+{
+ show_private_list(action,
+ AIM_SSI_TYPE_DENY,
+ _("Invisible List"),
+ _("These buddies will always see you as offline"),
+ _(APPEAR_OFFLINE),
+ oscar_show_invisible_list);
+}
+
diff --git a/libpurple/protocols/oscar/family_translate.c b/libpurple/protocols/oscar/visibility.h
index 005528f116..77ea4c2c30 100644
--- a/libpurple/protocols/oscar/family_translate.c
+++ b/libpurple/protocols/oscar/visibility.h
@@ -18,29 +18,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
-/*
- * Family 0x000c - Translation.
- *
- * I have no idea why this group was issued. I have never seen anything
- * that uses it. From what I remember, the last time I tried to poke at
- * the server with this group, it whined about not supporting it.
- *
- * But we advertise it anyway, because its fun.
- *
- */
+#ifndef _VISIBILITY_H_
+#define _VISIBILITY_H_
#include "oscar.h"
+#include "plugin.h"
+#include "util.h"
-int translate_modfirst(OscarData *od, aim_module_t *mod)
-{
-
- mod->family = SNAC_FAMILY_TRANSLATE;
- mod->version = 0x0001;
- mod->toolid = 0x0104;
- mod->toolversion = 0x0001;
- mod->flags = 0;
- strncpy(mod->name, "translate", sizeof(mod->name));
- mod->snachandler = NULL;
+PurpleMenuAction * create_visibility_menu_item(OscarData *od, const char *bname);
+void oscar_show_visible_list(PurplePluginAction *action);
+void oscar_show_invisible_list(PurplePluginAction *action);
- return 0;
-}
+#endif \ No newline at end of file