# HG changeset patch
# User masca@cpw.pidgin.im
# Date 1284231805 0
# Node ID 6469c68fa0939c2b2624bcee48e2505e98711f49
# Parent c49697f075cfd162743d3f3b1c8c4251611fbb29# Parent 9af193ee13b7bac83ed49e6315df86d4ea581ca5
propagate from branch 'im.pidgin.pidgin' (head fabc09bf724818b9b50e1c41d4afd6549f298c05)
to branch 'im.pidgin.cpw.qulogic.msnp16' (head d8e8a3b3ec17b199432993002327e4ecf156d12b)
diff -r c49697f075cf -r 6469c68fa093 COPYRIGHT
--- a/COPYRIGHT Sun Aug 01 00:08:26 2010 +0000
+++ b/COPYRIGHT Sat Sep 11 19:03:25 2010 +0000
@@ -18,6 +18,7 @@
Copyright (C) 1998-2009 by the following:
Saleem Abdulrasool
+Jakub Adam
Dave Ahlswede
Manuel Amador
Matt Amato
diff -r c49697f075cf -r 6469c68fa093 ChangeLog
--- a/ChangeLog Sun Aug 01 00:08:26 2010 +0000
+++ b/ChangeLog Sat Sep 11 19:03:25 2010 +0000
@@ -1,6 +1,44 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
-version 2.7.3 (??/??/????):
+version 2.7.4 (MM/DD/YYYY):
+ General:
+ * Fix search path for Tk when compiling on Debian Squeeze. (#12465)
+
+ libpurple:
+ * Fall back to an ordinary request if a UI does not support showing a
+ request with an icon. Fixes receiving MSN file transfer requests
+ including a thumbnail in Finch.
+
+ Pidgin:
+ * Add support for the Gadu-Gadu protocol in the gevolution plugin to
+ provide Evolution integration with contacts with GG IDs. (#10709)
+ * Remap the "Set User Mood" shortcut to Control-D, which does not
+ conflict with the previous shortcut for Get Buddy Info on the
+ selected buddy.
+ * Add a plugin action menu (under Tools) for the Voice and Video
+ Settings plugin.
+
+ Finch:
+ * Add support for drop-down account options (like the SILC cipher
+ and HMAC options or the QQ protocol version).
+
+ XMPP:
+ * Unify the connection security-related settings into one dropdown.
+ * Fix a crash when multiple accounts are simultaneously performing
+ SASL authentication when built with Cyrus SASL support. (thanks
+ to Jan Kaluza) (#11560)
+ * Restore the ability to connect to XMPP servers that do not offer
+ Stream ID. (#12331)
+ * Added support for using Google's relay servers when making voice and
+ video calls to Google clients.
+
+ Yahoo/Yahoo JAPAN:
+ * Stop doing unnecessary lookups of certain alias information. This
+ solves deadlocks when a given Yahoo account has a ridiculously large
+ (>500 buddies) list and may improve login speed for those on slow
+ connections. (#12532)
+
+version 2.7.3 (08/10/2010):
General:
* Use silent build rules for automake >1.11. You can enable verbose
builds with the --disable-silent-rules configure option, or using
@@ -25,6 +63,8 @@
MSN:
* Support for web-based buddy icons, used when a buddy logs in to the
messenger on the Live website.
+ * Fix file transfers with some clients that don't support direct
+ connections (e.g., papyon, telepathy-butterfly, etc.) (#12150)
MXit:
* Fix filename for the Shocked emoticon. (#12364)
@@ -38,7 +78,9 @@
* If a buddy is offline and we see from their profile that they have
updated their avatar, request the new avatar image from the server.
* Fix a possible crash if a link is clicked while disconnected.
- * New MXit Moods and Emoticons.
+ * Unescape any escaped characters in a chatroom nickname.
+ * Add the new MXit moods and emoticons.
+ * MXit emoticons added to the small emoticon theme.
XMPP:
* Allow connecting to servers that only advertise GSSAPI and expect
@@ -67,7 +109,7 @@
version 2.7.2 (07/21/2010):
AIM and ICQ:
* Fix a crash bug related to X-Status messages that can be triggered by
- remove users. This is CVE-2010-2528.
+ remote users. This is CVE-2010-2528.
* Fix a rare crash bug caused by certain incoming SMS messages
(discovered by Jan Kaluza--thanks Jan!).
* Change HTML sent from ICQ accounts so that official ICQ clients
diff -r c49697f075cf -r 6469c68fa093 ChangeLog.API
--- a/ChangeLog.API Sun Aug 01 00:08:26 2010 +0000
+++ b/ChangeLog.API Sat Sep 11 19:03:25 2010 +0000
@@ -1,6 +1,16 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
-version 2.7.3 (??/??/????):
+version 2.7.4 (MM/DD/YYYY):
+ Perl:
+ Added:
+ * Purple::BuddyList::Chat::get_components
+
+ Changed:
+ * Purple::BuddyList::Chat::new now works properly. Thanks
+ to Rafael in devel@conference.pidgin.im for reporting and
+ testing.
+
+version 2.7.3 (08/10/2010):
libpurple:
Fixed:
* purple_account_[gs]et_public_alias no longer crash when
diff -r c49697f075cf -r 6469c68fa093 NEWS
--- a/NEWS Sun Aug 01 00:08:26 2010 +0000
+++ b/NEWS Sat Sep 11 19:03:25 2010 +0000
@@ -2,6 +2,16 @@
Our development blog is available at: http://planet.pidgin.im
+2.7.3 (08/10/2010):
+ Mark: Lots of little incremental[1] bug fixes and enhancements in this
+ release.
+
+ [1] No whales were harmed[2] during the creation of this release.
+ [2] Probably.
+
+ John: Finally got some fixes out there for you Yahoo users behind some
+ particularly annoying firewalls and proxies, among other fixes. Enjoy!
+
2.7.2 (07/21/2010):
Mark: We discovered a security issue in Pidgin 2.7.0 and 2.7.1 and
decided to release a patched version quickly. This release contains
diff -r c49697f075cf -r 6469c68fa093 configure.ac
--- a/configure.ac Sun Aug 01 00:08:26 2010 +0000
+++ b/configure.ac Sat Sep 11 19:03:25 2010 +0000
@@ -46,7 +46,7 @@
m4_define([purple_lt_current], [7])
m4_define([purple_major_version], [2])
m4_define([purple_minor_version], [7])
-m4_define([purple_micro_version], [3])
+m4_define([purple_micro_version], [4])
m4_define([purple_version_suffix], [devel])
m4_define([purple_version],
[purple_major_version.purple_minor_version.purple_micro_version])
@@ -55,7 +55,7 @@
m4_define([gnt_lt_current], [8])
m4_define([gnt_major_version], [2])
m4_define([gnt_minor_version], [8])
-m4_define([gnt_micro_version], [0])
+m4_define([gnt_micro_version], [1])
m4_define([gnt_version_suffix], [devel])
m4_define([gnt_version],
[gnt_major_version.gnt_minor_version.gnt_micro_version])
@@ -2248,6 +2248,7 @@
TKCONFIG=no
TKCONFIGDIRS="/usr/lib \
/usr/lib64 \
+ /usr/lib/tk8.5 \
/usr/lib/tk8.4 \
/usr/lib/tk8.3 \
/usr/lib/tk8.2 \
diff -r c49697f075cf -r 6469c68fa093 finch/gntaccount.c
--- a/finch/gntaccount.c Sun Aug 01 00:08:26 2010 +0000
+++ b/finch/gntaccount.c Sat Sep 11 19:03:25 2010 +0000
@@ -236,7 +236,8 @@
}
else if (type == PURPLE_PREF_STRING_LIST)
{
- /* TODO: */
+ gchar *value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(entry));
+ purple_account_set_string(account, setting, value);
}
else
{
@@ -430,8 +431,26 @@
if (type == PURPLE_PREF_STRING_LIST)
{
- /* TODO: Use a combobox */
- /* Don't forget to append the widget to prpl_entries */
+ GntWidget *combo = gnt_combo_box_new();
+ GList *opt_iter = purple_account_option_get_list(option);
+ const char *dv = purple_account_option_get_default_list_value(option);
+ const char *active = dv;
+
+ if (account)
+ active = purple_account_get_string(account,
+ purple_account_option_get_setting(option), dv);
+
+ gnt_box_add_widget(GNT_BOX(box), combo);
+ dialog->prpl_entries = g_list_append(dialog->prpl_entries, combo);
+
+ for ( ; opt_iter; opt_iter = opt_iter->next)
+ {
+ PurpleKeyValuePair *kvp = opt_iter->data;
+ gnt_combo_box_add_data(GNT_COMBO_BOX(combo), kvp->value, kvp->key);
+
+ if (g_str_equal(kvp->value, active))
+ gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), kvp->value);
+ }
}
else
{
diff -r c49697f075cf -r 6469c68fa093 finch/gntft.c
--- a/finch/gntft.c Sun Aug 01 00:08:26 2010 +0000
+++ b/finch/gntft.c Sat Sep 11 19:03:25 2010 +0000
@@ -383,12 +383,10 @@
return;
}
- data = FINCHXFER(xfer);
-
update_title_progress();
if (purple_xfer_is_canceled(xfer))
- status = _("Canceled");
+ status = _("Cancelled");
else
status = _("Failed");
@@ -402,7 +400,7 @@
char *size_str, *remaining_str;
time_t current_time;
char prog_str[5];
- double kb_sent, kb_rem;
+ double kb_sent;
double kbps = 0.0;
time_t elapsed, now;
char *kbsec;
@@ -412,7 +410,6 @@
now = time(NULL);
kb_sent = purple_xfer_get_bytes_sent(xfer) / 1024.0;
- kb_rem = purple_xfer_get_bytes_remaining(xfer) / 1024.0;
elapsed = (purple_xfer_get_start_time(xfer) > 0 ? now - purple_xfer_get_start_time(xfer) : 0);
kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0);
diff -r c49697f075cf -r 6469c68fa093 finch/gntft.h
--- a/finch/gntft.h Sun Aug 01 00:08:26 2010 +0000
+++ b/finch/gntft.h Sat Sep 11 19:03:25 2010 +0000
@@ -72,9 +72,9 @@
void finch_xfer_dialog_remove_xfer(PurpleXfer *xfer);
/**
- * Indicate in a file transfer dialog that a transfer was canceled.
+ * Indicate in a file transfer dialog that a transfer was cancelled.
*
- * @param xfer The file transfer that was canceled.
+ * @param xfer The file transfer that was cancelled.
*/
void finch_xfer_dialog_cancel_xfer(PurpleXfer *xfer);
diff -r c49697f075cf -r 6469c68fa093 finch/libgnt/gntentry.c
--- a/finch/libgnt/gntentry.c Sun Aug 01 00:08:26 2010 +0000
+++ b/finch/libgnt/gntentry.c Sat Sep 11 19:03:25 2010 +0000
@@ -480,8 +480,7 @@
{
GntEntry *entry = GNT_ENTRY(bind);
GList *iter;
- const char *current , *pos;
- int len;
+ const char *current;
if (entry->history->prev && entry->search->needle)
current = entry->search->needle;
@@ -491,13 +490,11 @@
if (!entry->histlength || !entry->history->next || !*current)
return FALSE;
- len = g_utf8_strlen(current, -1);
-
for (iter = entry->history->next; iter; iter = iter->next) {
const char *str = iter->data;
/* A more utf8-friendly version of strstr would have been better, but
* for now, this will have to do. */
- if ((pos = strstr(str, current)))
+ if (strstr(str, current) != NULL)
break;
}
diff -r c49697f075cf -r 6469c68fa093 finch/libgnt/gnttextview.c
--- a/finch/libgnt/gnttextview.c Sun Aug 01 00:08:26 2010 +0000
+++ b/finch/libgnt/gnttextview.c Sat Sep 11 19:03:25 2010 +0000
@@ -711,7 +711,7 @@
int gnt_text_view_get_lines_above(GntTextView *view)
{
int above = 0;
- GList *list = view->list;
+ GList *list;
list = g_list_nth(view->list, GNT_WIDGET(view)->priv.height);
if (!list)
return 0;
diff -r c49697f075cf -r 6469c68fa093 libpurple/account.c
--- a/libpurple/account.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/account.c Sat Sep 11 19:03:25 2010 +0000
@@ -513,6 +513,25 @@
}
static void
+migrate_xmpp_encryption(PurpleAccount *account)
+{
+ /* When this is removed, nuke the "old_ssl" and "require_tls" settings */
+ if (g_str_equal(purple_account_get_protocol_id(account), "prpl-jabber")) {
+ const char *sec = purple_account_get_string(account, "connection_security", "");
+
+ if (g_str_equal("", sec)) {
+ const char *val = "require_tls";
+ if (purple_account_get_bool(account, "old_ssl", FALSE))
+ val = "old_ssl";
+ else if (!purple_account_get_bool(account, "require_tls", TRUE))
+ val = "opportunistic_tls";
+
+ purple_account_set_string(account, "connection_security", val);
+ }
+ }
+}
+
+static void
parse_settings(xmlnode *node, PurpleAccount *account)
{
const char *ui;
@@ -579,6 +598,9 @@
/* we do this here because we need access to account settings to determine
* if we can/should migrate an old Yahoo! JAPAN account */
migrate_yahoo_japan(account);
+ /* we do this here because we need to do it before the user views the
+ * Edit Account dialog. */
+ migrate_xmpp_encryption(account);
}
static GList *
@@ -1129,7 +1151,7 @@
static void
request_password_cancel_cb(PurpleAccount *account, PurpleRequestFields *fields)
{
- /* Disable the account as the user has canceled connecting */
+ /* Disable the account as the user has cancelled connecting */
purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/conversation.c
--- a/libpurple/conversation.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/conversation.c Sat Sep 11 19:03:25 2010 +0000
@@ -1124,7 +1124,6 @@
purple_conv_im_start_typing_timeout(PurpleConvIm *im, int timeout)
{
PurpleConversation *conv;
- const char *name;
g_return_if_fail(im != NULL);
@@ -1132,7 +1131,6 @@
purple_conv_im_stop_typing_timeout(im);
conv = purple_conv_im_get_conversation(im);
- name = purple_conversation_get_name(conv);
im->typing_timeout = purple_timeout_add_seconds(timeout, reset_typing_cb, conv);
}
@@ -1520,7 +1518,6 @@
PurpleAccount *account;
PurpleConversation *conv;
PurpleConnection *gc;
- PurplePluginProtocolInfo *prpl_info;
g_return_if_fail(chat != NULL);
g_return_if_fail(who != NULL);
@@ -1529,7 +1526,6 @@
conv = purple_conv_chat_get_conversation(chat);
gc = purple_conversation_get_gc(conv);
account = purple_connection_get_account(gc);
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
/* Don't display this if the person who wrote it is ignored. */
if (purple_conv_chat_is_user_ignored(chat, who))
diff -r c49697f075cf -r 6469c68fa093 libpurple/debug.h
--- a/libpurple/debug.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/debug.h Sat Sep 11 19:03:25 2010 +0000
@@ -176,20 +176,24 @@
gboolean purple_debug_is_verbose(void);
/**
- * Enable or disable verbose debugging. This ordinarily should only be called
+ * Enable or disable unsafe debugging. This ordinarily should only be called
* by #purple_debug_init, but there are cases where this can be useful for
* plugins.
*
- * @param unsafe TRUE to enable verbose debugging or FALSE to disable it.
+ * @param unsafe TRUE to enable debug logging of messages that could
+ * potentially contain passwords and other sensitive information.
+ * FALSE to disable it.
*
* @since 2.6.0
*/
void purple_debug_set_unsafe(gboolean unsafe);
/**
- * Check if unsafe debugging is enabled.
+ * Check if unsafe debugging is enabled. Defaults to FALSE.
*
- * @return TRUE if verbose debugging is enabled, FALSE if it is not.
+ * @return TRUE if the debug logging of all messages is enabled, FALSE
+ * if messages that could potentially contain passwords and other
+ * sensitive information are not logged.
*
* @since 2.6.0
*/
diff -r c49697f075cf -r 6469c68fa093 libpurple/desktopitem.c
--- a/libpurple/desktopitem.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/desktopitem.c Sat Sep 11 19:03:25 2010 +0000
@@ -330,7 +330,7 @@
if (c == EOF && pos == 0)
return NULL;
- buf[pos++] = '\0';
+ buf[pos] = '\0';
return buf;
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/ft.c
--- a/libpurple/ft.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/ft.c Sat Sep 11 19:03:25 2010 +0000
@@ -752,6 +752,7 @@
return xfer->status;
}
+/* FIXME: Rename with cancelled for 3.0.0. */
gboolean
purple_xfer_is_canceled(const PurpleXfer *xfer)
{
diff -r c49697f075cf -r 6469c68fa093 libpurple/ft.h
--- a/libpurple/ft.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/ft.h Sat Sep 11 19:03:25 2010 +0000
@@ -58,8 +58,8 @@
PURPLE_XFER_STATUS_ACCEPTED, /**< Receive accepted, but destination file not selected yet */
PURPLE_XFER_STATUS_STARTED, /**< purple_xfer_start has been called. */
PURPLE_XFER_STATUS_DONE, /**< The xfer completed successfully. */
- PURPLE_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was canceled by us. */
- PURPLE_XFER_STATUS_CANCEL_REMOTE /**< The xfer was canceled by the other end, or we couldn't connect. */
+ PURPLE_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was cancelled by us. */
+ PURPLE_XFER_STATUS_CANCEL_REMOTE /**< The xfer was cancelled by the other end, or we couldn't connect. */
} PurpleXferStatusType;
/**
@@ -304,11 +304,12 @@
PurpleXferStatusType purple_xfer_get_status(const PurpleXfer *xfer);
/**
- * Returns true if the file transfer was canceled.
+ * Returns true if the file transfer was cancelled.
*
* @param xfer The file transfer.
*
- * @return Whether or not the transfer was canceled.
+ * @return Whether or not the transfer was cancelled.
+ * FIXME: This should be renamed using cancelled for 3.0.0.
*/
gboolean purple_xfer_is_canceled(const PurpleXfer *xfer);
diff -r c49697f075cf -r 6469c68fa093 libpurple/log.c
--- a/libpurple/log.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/log.c Sat Sep 11 19:03:25 2010 +0000
@@ -1681,7 +1681,6 @@
struct tm tm;
char month[4];
struct old_logger_data *data = NULL;
- char *newlog;
int logfound = 0;
int lastoff = 0;
int newlen;
@@ -1783,7 +1782,7 @@
}
while (fgets(buf, BUF_LONG, file)) {
- if ((newlog = strstr(buf, "---- New C"))) {
+ if (strstr(buf, "---- New C") != NULL) {
int length;
int offset;
char convostart[32];
diff -r c49697f075cf -r 6469c68fa093 libpurple/media.c
--- a/libpurple/media.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/media.c Sat Sep 11 19:03:25 2010 +0000
@@ -515,7 +515,8 @@
if (!media->priv->sessions) {
purple_debug_info("media", "Creating hash table for sessions\n");
- media->priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+ media->priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
}
g_hash_table_insert(media->priv->sessions, g_strdup(session->id), session);
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/media/backend-fs2.c
--- a/libpurple/media/backend-fs2.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/media/backend-fs2.c Sat Sep 11 19:03:25 2010 +0000
@@ -208,11 +208,7 @@
}
if (priv->participants) {
- GList *participants =
- g_hash_table_get_values(priv->participants);
- for (; participants; participants = g_list_delete_link(
- participants, participants))
- g_object_unref(participants->data);
+ g_hash_table_destroy(priv->participants);
priv->participants = NULL;
}
@@ -1425,7 +1421,8 @@
if (!priv->sessions) {
purple_debug_info("backend-fs2",
"Creating hash table for sessions\n");
- priv->sessions = g_hash_table_new(g_str_hash, g_str_equal);
+ priv->sessions = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
}
g_hash_table_insert(priv->sessions, g_strdup(session->id), session);
@@ -1461,7 +1458,7 @@
purple_debug_info("backend-fs2",
"Creating hash table for participants\n");
priv->participants = g_hash_table_new_full(g_str_hash,
- g_str_equal, g_free, NULL);
+ g_str_equal, g_free, g_object_unref);
}
g_hash_table_insert(priv->participants, g_strdup(name), participant);
@@ -1564,6 +1561,30 @@
(GSourceFunc)src_pad_added_cb_cb, stream);
}
+static GValueArray *
+append_relay_info(GValueArray *relay_info, const gchar *ip, gint port,
+ const gchar *username, const gchar *password, const gchar *type)
+{
+ GValue value;
+ GstStructure *turn_setup = gst_structure_new("relay-info",
+ "ip", G_TYPE_STRING, ip,
+ "port", G_TYPE_UINT, port,
+ "username", G_TYPE_STRING, username,
+ "password", G_TYPE_STRING, password,
+ "relay-type", G_TYPE_STRING, type,
+ NULL);
+
+ if (turn_setup) {
+ memset(&value, 0, sizeof(GValue));
+ g_value_init(&value, GST_TYPE_STRUCTURE);
+ gst_value_set_structure(&value, turn_setup);
+ relay_info = g_value_array_append(relay_info, &value);
+ gst_structure_free(turn_setup);
+ }
+
+ return relay_info;
+}
+
static gboolean
create_stream(PurpleMediaBackendFs2 *self,
const gchar *sess_id, const gchar *who,
@@ -1584,6 +1605,18 @@
PurpleMediaBackendFs2Session *session;
PurpleMediaBackendFs2Stream *stream;
FsParticipant *participant;
+ /* check if the prpl has already specified a relay-info
+ we need to do this to allow them to override when using non-standard
+ TURN modes, like Google f.ex. */
+ gboolean got_turn_from_prpl = FALSE;
+ int i;
+
+ for (i = 0 ; i < num_params ; i++) {
+ if (purple_strequal(params[i].name, "relay-info")) {
+ got_turn_from_prpl = TRUE;
+ break;
+ }
+ }
memcpy(_params, params, sizeof(GParameter) * num_params);
@@ -1603,34 +1636,24 @@
++_num_params;
}
- if (turn_ip && !strcmp("nice", transmitter)) {
+ if (turn_ip && !strcmp("nice", transmitter) && !got_turn_from_prpl) {
GValueArray *relay_info = g_value_array_new(0);
- GValue value;
- gint turn_port = purple_prefs_get_int(
- "/purple/network/turn_port");
+ gint port;
const gchar *username = purple_prefs_get_string(
"/purple/network/turn_username");
const gchar *password = purple_prefs_get_string(
"/purple/network/turn_password");
- GstStructure *turn_setup = gst_structure_new("relay-info",
- "ip", G_TYPE_STRING, turn_ip,
- "port", G_TYPE_UINT, turn_port,
- "username", G_TYPE_STRING, username,
- "password", G_TYPE_STRING, password,
- NULL);
- if (!turn_setup) {
- purple_debug_error("backend-fs2",
- "Error creating relay info structure");
- return FALSE;
+ /* UDP */
+ port = purple_prefs_get_int("/purple/network/turn_port");
+ if (port > 0) {
+ relay_info = append_relay_info(relay_info, turn_ip, port, username,
+ password, "udp");
}
- memset(&value, 0, sizeof(GValue));
- g_value_init(&value, GST_TYPE_STRUCTURE);
- gst_value_set_structure(&value, turn_setup);
- relay_info = g_value_array_append(relay_info, &value);
- gst_structure_free(turn_setup);
-
+ /* should add TCP and perhaps TLS relaying options when these are
+ supported by libnice using non-google mode */
+
purple_debug_info("backend-fs2",
"Setting relay-info on new stream\n");
_params[_num_params].name = "relay-info";
@@ -1791,7 +1814,7 @@
const gchar *sess_id)
{
PurpleMediaBackendFs2Private *priv;
- gboolean ret;
+ gboolean ret = FALSE;
g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), FALSE);
@@ -1837,15 +1860,12 @@
purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
const gchar *sess_id)
{
- PurpleMediaBackendFs2Private *priv;
PurpleMediaBackendFs2Session *session;
GList *fscodecs;
GList *codecs;
g_return_val_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self), NULL);
- priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
-
session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
if (session == NULL)
@@ -2014,13 +2034,10 @@
const gchar *sess_id, const gchar *who, double level)
{
#ifdef USE_VV
- PurpleMediaBackendFs2Private *priv;
GList *streams;
g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
- priv = PURPLE_MEDIA_BACKEND_FS2_GET_PRIVATE(self);
-
purple_prefs_set_int("/purple/media/audio/volume/output", level);
streams = get_streams(self, sess_id, who);
diff -r c49697f075cf -r 6469c68fa093 libpurple/media/codec.c
--- a/libpurple/media/codec.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/media/codec.c Sat Sep 11 19:03:25 2010 +0000
@@ -83,9 +83,11 @@
PURPLE_MEDIA_CODEC_GET_PRIVATE(info);
g_free(priv->encoding_name);
for (; priv->optional_params; priv->optional_params =
- g_list_delete_link(priv->optional_params,
- priv->optional_params)) {
- g_free(priv->optional_params->data);
+ g_list_delete_link(priv->optional_params, priv->optional_params)) {
+ PurpleKeyValuePair *param = priv->optional_params->data;
+ g_free(param->key);
+ g_free(param->value);
+ g_free(param);
}
}
@@ -302,10 +304,10 @@
g_free(param->key);
g_free(param->value);
- g_free(param);
priv->optional_params =
g_list_remove(priv->optional_params, param);
+ g_free(param);
}
PurpleKeyValuePair *
diff -r c49697f075cf -r 6469c68fa093 libpurple/media/codec.h
--- a/libpurple/media/codec.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/media/codec.h Sat Sep 11 19:03:25 2010 +0000
@@ -121,7 +121,8 @@
*
* @param The codec to get the optional parameters from.
*
- * @return The list of optional parameters.
+ * @return The list of optional parameters. The list is owned by the codec and
+ * should not be freed.
*
* @since 2.6.0
*/
diff -r c49697f075cf -r 6469c68fa093 libpurple/network.c
--- a/libpurple/network.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/network.c Sat Sep 11 19:03:25 2010 +0000
@@ -98,6 +98,7 @@
PurpleNetworkListenCallback cb;
gpointer cb_data;
UPnPMappingAddRemove *mapping_data;
+ int timer;
};
#ifdef HAVE_NETWORKMANAGER
@@ -373,6 +374,7 @@
gint *value = g_new(gint, 1);
listen_data = data;
+ listen_data->timer = 0;
/* add port mapping to hash table */
*key = purple_network_get_port_from_fd(listen_data->listenfd);
@@ -504,7 +506,7 @@
{
purple_debug_info("network", "Skipping external port mapping.\n");
/* The pmp_map_cb does what we want to do */
- purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
+ listen_data->timer = purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
}
/* Attempt a NAT-PMP Mapping, which will return immediately */
else if (purple_pmp_create_map(((socket_type == SOCK_STREAM) ? PURPLE_PMP_TYPE_TCP : PURPLE_PMP_TYPE_UDP),
@@ -512,7 +514,7 @@
{
purple_debug_info("network", "Created NAT-PMP mapping on port %i\n", actual_port);
/* We want to return listen_data now, and on the next run loop trigger the cb and destroy listen_data */
- purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
+ listen_data->timer = purple_timeout_add(0, purple_network_finish_pmp_map_cb, listen_data);
}
else
{
@@ -584,6 +586,9 @@
if (listen_data->mapping_data != NULL)
purple_upnp_cancel_port_mapping(listen_data->mapping_data);
+ if (listen_data->timer > 0)
+ purple_timeout_remove(listen_data->timer);
+
g_free(listen_data);
}
@@ -1072,12 +1077,10 @@
if (protocol) {
purple_network_upnp_mapping_remove(&port, protocol, NULL);
- g_hash_table_remove(upnp_port_mappings, protocol);
} else {
protocol = g_hash_table_lookup(nat_pmp_port_mappings, &port);
if (protocol) {
purple_network_nat_pmp_mapping_remove(&port, protocol, NULL);
- g_hash_table_remove(nat_pmp_port_mappings, protocol);
}
}
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/network.h
--- a/libpurple/network.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/network.h Sat Sep 11 19:03:25 2010 +0000
@@ -239,7 +239,7 @@
* by passing in the return value from either purple_network_listen()
* or purple_network_listen_range().
*
- * @param listen_data This listener attempt will be canceled and
+ * @param listen_data This listener attempt will be cancelled and
* the struct will be freed.
*/
void purple_network_listen_cancel(PurpleNetworkListenData *listen_data);
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/idle.c
--- a/libpurple/plugins/idle.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/idle.c Sat Sep 11 19:03:25 2010 +0000
@@ -110,9 +110,6 @@
for(iter = list; iter; iter = iter->next) {
acct = (PurpleAccount *)(iter->data);
- if(acct)
- prpl_id = purple_account_get_protocol_id(acct);
-
if(acct && idleable_filter(acct)) {
purple_debug_misc("idle", "Idling %s.\n",
purple_account_get_username(acct));
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/perl/common/BuddyList.xs
--- a/libpurple/plugins/perl/common/BuddyList.xs Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/perl/common/BuddyList.xs Sat Sep 11 19:03:25 2010 +0000
@@ -2,6 +2,13 @@
#include "module.h"
#include "../perl-handlers.h"
+static void
+chat_components_foreach(gpointer key, gpointer value, gpointer user_data)
+{
+ HV *hv = user_data;
+ hv_store(hv, key, strlen(key), newSVpv(value, 0), 0);
+}
+
MODULE = Purple::BuddyList PACKAGE = Purple PREFIX = purple_
PROTOTYPES: ENABLE
@@ -331,6 +338,19 @@
purple_chat_get_name(chat)
Purple::BuddyList::Chat chat
+HV *
+purple_chat_get_components(chat)
+ Purple::BuddyList::Chat chat
+INIT:
+ HV * t_HV;
+ GHashTable * t_GHash;
+CODE:
+ t_GHash = purple_chat_get_components(chat);
+ RETVAL = t_HV = newHV();
+ g_hash_table_foreach(t_GHash, chat_components_foreach, t_HV);
+OUTPUT:
+ RETVAL
+
Purple::BuddyList::Chat
purple_chat_new(account, alias, components)
Purple::Account account
@@ -345,14 +365,14 @@
char *t_key, *t_value;
CODE:
t_HV = (HV *)SvRV(components);
- t_GHash = g_hash_table_new(g_str_hash, g_str_equal);
+ t_GHash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
for (t_HE = hv_iternext(t_HV); t_HE != NULL; t_HE = hv_iternext(t_HV) ) {
t_key = hv_iterkey(t_HE, &len);
t_SV = *hv_fetch(t_HV, t_key, len, 0);
t_value = SvPVutf8_nolen(t_SV);
- g_hash_table_insert(t_GHash, t_key, t_value);
+ g_hash_table_insert(t_GHash, g_strdup(t_key), g_strdup(t_value));
}
RETVAL = purple_chat_new(account, alias, t_GHash);
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/perl/common/Server.xs
--- a/libpurple/plugins/perl/common/Server.xs Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/perl/common/Server.xs Sat Sep 11 19:03:25 2010 +0000
@@ -144,6 +144,7 @@
g_hash_table_insert(t_GHash, t_key, t_value);
}
serv_join_chat(conn, t_GHash);
+ g_hash_table_destroy(t_GHash);
void
serv_move_buddy(buddy, group1, group2)
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/signals-test.c
--- a/libpurple/plugins/signals-test.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/signals-test.c Sat Sep 11 19:03:25 2010 +0000
@@ -592,12 +592,12 @@
static void
ft_recv_cancel_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file receive canceled\n");
+ purple_debug_misc("signals test", "file receive cancelled\n");
}
static void
ft_send_cancel_cb(PurpleXfer *xfer, gpointer data) {
- purple_debug_misc("signals test", "file send canceled\n");
+ purple_debug_misc("signals test", "file send cancelled\n");
}
static void
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/tcl/tcl_cmd.c
--- a/libpurple/plugins/tcl/tcl_cmd.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/tcl/tcl_cmd.c Sat Sep 11 19:03:25 2010 +0000
@@ -125,7 +125,7 @@
gchar **args, gchar **errors,
struct tcl_cmd_handler *handler)
{
- int retval, error, i;
+ int retval, i;
Tcl_Obj *command, *arg, *tclargs, *result;
command = Tcl_NewListObj(0, NULL);
@@ -153,8 +153,7 @@
}
Tcl_ListObjAppendElement(handler->interp, command, tclargs);
- if ((error = Tcl_EvalObjEx(handler->interp, command,
- TCL_EVAL_GLOBAL)) != TCL_OK) {
+ if (Tcl_EvalObjEx(handler->interp, command, TCL_EVAL_GLOBAL) != TCL_OK) {
gchar *errorstr;
errorstr = g_strdup_printf("error evaluating callback: %s\n",
@@ -164,8 +163,8 @@
retval = PURPLE_CMD_RET_FAILED;
} else {
result = Tcl_GetObjResult(handler->interp);
- if ((error = Tcl_GetIntFromObj(handler->interp, result,
- &retval)) != TCL_OK) {
+ if (Tcl_GetIntFromObj(handler->interp, result,
+ &retval) != TCL_OK) {
gchar *errorstr;
errorstr = g_strdup_printf("Error retreiving procedure result: %s\n",
diff -r c49697f075cf -r 6469c68fa093 libpurple/plugins/tcl/tcl_signals.c
--- a/libpurple/plugins/tcl/tcl_signals.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/plugins/tcl/tcl_signals.c Sat Sep 11 19:03:25 2010 +0000
@@ -160,7 +160,7 @@
{
GString *name, *val;
PurpleBlistNode *node;
- int error, i;
+ int i;
void *retval = NULL;
Tcl_Obj *cmd, *arg, *result;
void **vals; /* Used for inout parameters */
@@ -335,7 +335,7 @@
}
/* Call the friggin' procedure already */
- if ((error = Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL)) != TCL_OK) {
+ if (Tcl_EvalObjEx(handler->interp, cmd, TCL_EVAL_GLOBAL) != TCL_OK) {
purple_debug(PURPLE_DEBUG_ERROR, "tcl", "error evaluating callback: %s\n",
Tcl_GetString(Tcl_GetObjResult(handler->interp)));
} else {
@@ -345,7 +345,7 @@
if (purple_value_get_type(handler->returntype) == PURPLE_TYPE_STRING) {
retval = (void *)g_strdup(Tcl_GetString(result));
} else {
- if ((error = Tcl_GetIntFromObj(handler->interp, result, (int *)&retval)) != TCL_OK) {
+ if (Tcl_GetIntFromObj(handler->interp, result, (int *)&retval) != TCL_OK) {
purple_debug(PURPLE_DEBUG_ERROR, "tcl", "Error retrieving procedure result: %s\n",
Tcl_GetString(Tcl_GetObjResult(handler->interp)));
retval = NULL;
diff -r c49697f075cf -r 6469c68fa093 libpurple/prefs.c
--- a/libpurple/prefs.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/prefs.c Sat Sep 11 19:03:25 2010 +0000
@@ -506,7 +506,6 @@
return g_strdup("/");
name = g_string_new(pref->name);
- parent = pref->parent;
for(parent = pref->parent; parent && parent->name; parent = parent->parent) {
name = g_string_prepend_c(name, '/');
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/bonjour/bonjour.c
--- a/libpurple/protocols/bonjour/bonjour.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c Sat Sep 11 19:03:25 2010 +0000
@@ -206,18 +206,12 @@
{
PurpleConnection *gc;
BonjourData *bd;
- gboolean disconnected;
- PurpleStatusType *type;
- int primitive;
PurplePresence *presence;
const char *message, *bonjour_status;
gchar *stripped;
gc = purple_account_get_connection(account);
bd = gc->proto_data;
- disconnected = purple_account_is_disconnected(account);
- type = purple_status_get_type(status);
- primitive = purple_status_type_get_primitive(type);
presence = purple_account_get_presence(account);
message = purple_status_get_attr_string(status, "message");
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/bonjour/jabber.c
--- a/libpurple/protocols/bonjour/jabber.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/bonjour/jabber.c Sat Sep 11 19:03:25 2010 +0000
@@ -1273,7 +1273,6 @@
static void
xep_iq_parse(xmlnode *packet, PurpleBuddy *pb)
{
- xmlnode *child;
PurpleAccount *account;
PurpleConnection *gc;
@@ -1283,7 +1282,7 @@
account = purple_buddy_get_account(pb);
gc = purple_account_get_connection(account);
- if ((child = xmlnode_get_child(packet, "si")) || (child = xmlnode_get_child(packet, "error")))
+ if (xmlnode_get_child(packet, "si") != NULL || xmlnode_get_child(packet, "error") != NULL)
xep_si_parse(gc, packet, pb);
else
xep_bytestreams_parse(gc, packet, pb);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/bonjour/mdns_avahi.c
--- a/libpurple/protocols/bonjour/mdns_avahi.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/bonjour/mdns_avahi.c Sat Sep 11 19:03:25 2010 +0000
@@ -115,7 +115,6 @@
AvahiStringList *l;
size_t size;
char *key, *value;
- int ret;
char ip[AVAHI_ADDRESS_STR_MAX];
AvahiBuddyImplData *b_impl;
AvahiSvcResolverData *rd;
@@ -202,7 +201,7 @@
/* Obtain the parameters from the text_record */
clear_bonjour_buddy_values(bb);
for(l = txt; l != NULL; l = l->next) {
- if ((ret = avahi_string_list_get_pair(l, &key, &value, &size)) < 0)
+ if (avahi_string_list_get_pair(l, &key, &value, &size) < 0)
continue;
set_bonjour_buddy_value(bb, key, value, size);
/* TODO: Since we're using the glib allocator, I think we
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/Makefile.am
--- a/libpurple/protocols/jabber/Makefile.am Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/Makefile.am Sat Sep 11 19:03:25 2010 +0000
@@ -26,8 +26,20 @@
data.h \
disco.c \
disco.h \
- google.c \
- google.h \
+ google/gmail.c \
+ google/gmail.h \
+ google/google.c \
+ google/google.h \
+ google/google_presence.c \
+ google/google_presence.h \
+ google/google_roster.c \
+ google/google_roster.h \
+ google/google_session.c \
+ google/google_session.h \
+ google/jingleinfo.c \
+ google/jingleinfo.h \
+ google/relay.c \
+ google/relay.h \
ibb.c \
ibb.h \
iq.c \
@@ -98,7 +110,10 @@
st =
pkg_LTLIBRARIES = libjabber.la libxmpp.la
libjabber_la_SOURCES = $(JABBERSOURCES)
-libjabber_la_LIBADD = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)
+libjabber_la_LIBADD = $(GLIB_LIBS) $(SASL_LIBS) $(LIBXML_LIBS) $(IDN_LIBS)\
+ $(FARSIGHT_LIBS) \
+ $(GSTREAMER_LIBS) \
+ $(GSTINTERFACES_LIBS)
libxmpp_la_SOURCES = libxmpp.c
libxmpp_la_LIBADD = libjabber.la
@@ -111,4 +126,7 @@
$(DEBUG_CFLAGS) \
$(GLIB_CFLAGS) \
$(IDN_CFLAGS) \
- $(LIBXML_CFLAGS)
+ $(LIBXML_CFLAGS) \
+ $(FARSIGHT_CFLAGS) \
+ $(GSTREAMER_CFLAGS) \
+ $(GSTINTERFACES_CFLAGS)
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/Makefile.mingw
--- a/libpurple/protocols/jabber/Makefile.mingw Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/Makefile.mingw Sat Sep 11 19:03:25 2010 +0000
@@ -55,7 +55,13 @@
chat.c \
data.c \
disco.c \
- google.c \
+ google/gmail.c \
+ google/google.c \
+ google/google_presence.c \
+ google/google_roster.c \
+ google/google_session.c \
+ google/jingleinfo.c \
+ google/relay.c \
ibb.c \
iq.c \
jabber.c \
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/auth.c
--- a/libpurple/protocols/jabber/auth.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/auth.c Sat Sep 11 19:03:25 2010 +0000
@@ -123,7 +123,7 @@
if (!PURPLE_CONNECTION_IS_VALID(gc))
return;
- /* Disable the account as the user has canceled connecting */
+ /* Disable the account as the user has cancelled connecting */
purple_account_set_enabled(purple_connection_get_account(gc), purple_core_get_ui(), FALSE);
}
#endif
@@ -251,7 +251,8 @@
g_free(msg);
} else if (type == JABBER_IQ_RESULT) {
query = xmlnode_get_child(packet, "query");
- if(js->stream_id && xmlnode_get_child(query, "digest")) {
+ if (js->stream_id && *js->stream_id &&
+ xmlnode_get_child(query, "digest")) {
char *s, *hash;
iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
@@ -269,8 +270,10 @@
g_free(s);
jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
jabber_iq_send(iq);
-
- } else if(js->stream_id && (x = xmlnode_get_child(query, "crammd5"))) {
+ } else if ((x = xmlnode_get_child(query, "crammd5"))) {
+ /* For future reference, this appears to be a custom OS X extension
+ * to non-SASL authentication.
+ */
const char *challenge;
gchar digest[33];
PurpleCipherContext *hmac;
@@ -340,7 +343,8 @@
* is requiring SSL/TLS, we need to enforce it.
*/
if (!jabber_stream_is_ssl(js) &&
- purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) {
+ g_str_equal("require_tls",
+ purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
purple_connection_error_reason(js->gc,
PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
_("You require encryption, but it is not available on this server."));
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/auth_cyrus.c
--- a/libpurple/protocols/jabber/auth_cyrus.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/auth_cyrus.c Sat Sep 11 19:03:25 2010 +0000
@@ -94,7 +94,6 @@
PurpleAccount *account;
const char *pw;
size_t len;
- static sasl_secret_t *x = NULL;
account = purple_connection_get_account(js->gc);
pw = purple_account_get_password(account);
@@ -103,15 +102,16 @@
return SASL_BADPARAM;
len = strlen(pw);
- x = (sasl_secret_t *) realloc(x, sizeof(sasl_secret_t) + len);
-
- if (!x)
+ /* Not an off-by-one because sasl_secret_t defines char data[1] */
+ /* TODO: This can probably be moved to glib's allocator */
+ js->sasl_secret = malloc(sizeof(sasl_secret_t) + len);
+ if (!js->sasl_secret)
return SASL_NOMEM;
- x->len = len;
- strcpy((char*)x->data, pw);
+ js->sasl_secret->len = len;
+ strcpy((char*)js->sasl_secret->data, pw);
- *secret = x;
+ *secret = js->sasl_secret;
return SASL_OK;
}
@@ -176,7 +176,7 @@
account = purple_connection_get_account(gc);
js = purple_connection_get_protocol_data(gc);
- /* Disable the account as the user has canceled connecting */
+ /* Disable the account as the user has cancelled connecting */
purple_account_set_enabled(account, purple_core_get_ui(), FALSE);
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/bosh.c
--- a/libpurple/protocols/jabber/bosh.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/bosh.c Sat Sep 11 19:03:25 2010 +0000
@@ -711,11 +711,10 @@
/* Make sure Content-Length is in headers, not body */
if (content_length && (!end_of_headers || content_length < end_of_headers)) {
const char *sep;
- const char *eol;
int len;
if ((sep = strstr(content_length, ": ")) == NULL ||
- (eol = strstr(sep, "\r\n")) == NULL)
+ strstr(sep, "\r\n") == NULL)
/*
* The packet ends in the middle of the Content-Length line.
* We'll try again later when we have more.
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/buddy.c
--- a/libpurple/protocols/jabber/buddy.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/buddy.c Sat Sep 11 19:03:25 2010 +0000
@@ -38,7 +38,7 @@
#include "xdata.h"
#include "pep.h"
#include "adhoccommands.h"
-#include "google.h"
+#include "google/google.h"
typedef struct {
long idle_seconds;
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/chat.c
--- a/libpurple/protocols/jabber/chat.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/chat.c Sat Sep 11 19:03:25 2010 +0000
@@ -173,8 +173,10 @@
xmlnode_set_namespace(x, "http://jabber.org/protocol/muc#user");
invite = xmlnode_new_child(x, "invite");
xmlnode_set_attrib(invite, "to", name);
- body = xmlnode_new_child(invite, "reason");
- xmlnode_insert_data(body, msg, -1);
+ if (msg) {
+ body = xmlnode_new_child(invite, "reason");
+ xmlnode_insert_data(body, msg, -1);
+ }
} else {
xmlnode_set_attrib(message, "to", name);
/*
@@ -184,14 +186,17 @@
*
* Left here for compatibility.
*/
- body = xmlnode_new_child(message, "body");
- xmlnode_insert_data(body, msg, -1);
+ if (msg) {
+ body = xmlnode_new_child(message, "body");
+ xmlnode_insert_data(body, msg, -1);
+ }
x = xmlnode_new_child(message, "x");
xmlnode_set_attrib(x, "jid", room_jid);
/* The better place for it! XEP-0249 style. */
- xmlnode_set_attrib(x, "reason", msg);
+ if (msg)
+ xmlnode_set_attrib(x, "reason", msg);
xmlnode_set_namespace(x, "jabber:x:conference");
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/disco.c
--- a/libpurple/protocols/jabber/disco.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/disco.c Sat Sep 11 19:03:25 2010 +0000
@@ -30,7 +30,9 @@
#include "adhoccommands.h"
#include "buddy.h"
#include "disco.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/gmail.h"
+#include "google/jingleinfo.h"
#include "iq.h"
#include "jabber.h"
#include "jingle/jingle.h"
@@ -604,7 +606,7 @@
/* we don't actually care about the specific nodes,
* so we won't query them */
- if((node = xmlnode_get_attrib(child, "node")))
+ if(xmlnode_get_attrib(child, "node") != NULL)
continue;
iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_DISCO_INFO);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google.c
--- a/libpurple/protocols/jabber/google.c Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1429 +0,0 @@
-/**
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#include "internal.h"
-#include "debug.h"
-#include "mediamanager.h"
-#include "util.h"
-#include "privacy.h"
-#include "dnsquery.h"
-#include "network.h"
-
-#include "buddy.h"
-#include "google.h"
-#include "jabber.h"
-#include "presence.h"
-#include "roster.h"
-#include "iq.h"
-#include "chat.h"
-
-#include "jingle/jingle.h"
-
-#ifdef USE_VV
-
-typedef struct {
- char *id;
- char *initiator;
-} GoogleSessionId;
-
-typedef enum {
- UNINIT,
- SENT_INITIATE,
- RECEIVED_INITIATE,
- IN_PRORESS,
- TERMINATED
-} GoogleSessionState;
-
-typedef struct {
- GoogleSessionId id;
- GoogleSessionState state;
- PurpleMedia *media;
- JabberStream *js;
- char *remote_jid;
- gboolean video;
-} GoogleSession;
-
-static gboolean
-google_session_id_equal(gconstpointer a, gconstpointer b)
-{
- GoogleSessionId *c = (GoogleSessionId*)a;
- GoogleSessionId *d = (GoogleSessionId*)b;
-
- return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator);
-}
-
-static void
-google_session_destroy(GoogleSession *session)
-{
- g_free(session->id.id);
- g_free(session->id.initiator);
- g_free(session->remote_jid);
- g_free(session);
-}
-
-static xmlnode *
-google_session_create_xmlnode(GoogleSession *session, const char *type)
-{
- xmlnode *node = xmlnode_new("session");
- xmlnode_set_namespace(node, NS_GOOGLE_SESSION);
- xmlnode_set_attrib(node, "id", session->id.id);
- xmlnode_set_attrib(node, "initiator", session->id.initiator);
- xmlnode_set_attrib(node, "type", type);
- return node;
-}
-
-static void
-google_session_send_candidates(PurpleMedia *media, gchar *session_id,
- gchar *participant, GoogleSession *session)
-{
- GList *candidates = purple_media_get_local_candidates(
- session->media, session_id, session->remote_jid), *iter;
- PurpleMediaCandidate *transport;
- gboolean video = FALSE;
-
- if (!strcmp(session_id, "google-video"))
- video = TRUE;
-
- for (iter = candidates; iter; iter = iter->next) {
- JabberIq *iq;
- gchar *ip, *port, *username, *password;
- gchar pref[16];
- PurpleMediaCandidateType type;
- xmlnode *sess;
- xmlnode *candidate;
- guint component_id;
- transport = PURPLE_MEDIA_CANDIDATE(iter->data);
- component_id = purple_media_candidate_get_component_id(
- transport);
-
- iq = jabber_iq_new(session->js, JABBER_IQ_SET);
- sess = google_session_create_xmlnode(session, "candidates");
- xmlnode_insert_child(iq->node, sess);
- xmlnode_set_attrib(iq->node, "to", session->remote_jid);
-
- candidate = xmlnode_new("candidate");
-
- ip = purple_media_candidate_get_ip(transport);
- port = g_strdup_printf("%d",
- purple_media_candidate_get_port(transport));
- g_ascii_dtostr(pref, 16,
- purple_media_candidate_get_priority(transport) / 1000.0);
- username = purple_media_candidate_get_username(transport);
- password = purple_media_candidate_get_password(transport);
- type = purple_media_candidate_get_candidate_type(transport);
-
- xmlnode_set_attrib(candidate, "address", ip);
- xmlnode_set_attrib(candidate, "port", port);
- xmlnode_set_attrib(candidate, "name",
- component_id == PURPLE_MEDIA_COMPONENT_RTP ?
- video ? "video_rtp" : "rtp" :
- component_id == PURPLE_MEDIA_COMPONENT_RTCP ?
- video ? "video_rtcp" : "rtcp" : "none");
- xmlnode_set_attrib(candidate, "username", username);
- /*
- * As of this writing, Farsight 2 in Google compatibility
- * mode doesn't provide a password. The Gmail client
- * requires this to be set.
- */
- xmlnode_set_attrib(candidate, "password",
- password != NULL ? password : "");
- xmlnode_set_attrib(candidate, "preference", pref);
- xmlnode_set_attrib(candidate, "protocol",
- purple_media_candidate_get_protocol(transport)
- == PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ?
- "udp" : "tcp");
- xmlnode_set_attrib(candidate, "type", type ==
- PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" :
- type ==
- PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" :
- type ==
- PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
- NULL);
- xmlnode_set_attrib(candidate, "generation", "0");
- xmlnode_set_attrib(candidate, "network", "0");
- xmlnode_insert_child(sess, candidate);
-
- g_free(ip);
- g_free(port);
- g_free(username);
- g_free(password);
-
- jabber_iq_send(iq);
- }
- purple_media_candidate_list_free(candidates);
-}
-
-static void
-google_session_ready(GoogleSession *session)
-{
- PurpleMedia *media = session->media;
- if (purple_media_codecs_ready(media, NULL) &&
- purple_media_candidates_prepared(media, NULL, NULL)) {
- gchar *me = g_strdup_printf("%s@%s/%s",
- session->js->user->node,
- session->js->user->domain,
- session->js->user->resource);
- JabberIq *iq;
- xmlnode *sess, *desc, *payload;
- GList *codecs, *iter;
- gboolean is_initiator = !strcmp(session->id.initiator, me);
-
- if (!is_initiator &&
- !purple_media_accepted(media, NULL, NULL)) {
- g_free(me);
- return;
- }
-
- iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
- if (is_initiator) {
- xmlnode_set_attrib(iq->node, "to", session->remote_jid);
- xmlnode_set_attrib(iq->node, "from", session->id.initiator);
- sess = google_session_create_xmlnode(session, "initiate");
- } else {
- google_session_send_candidates(session->media,
- "google-voice", session->remote_jid,
- session);
- google_session_send_candidates(session->media,
- "google-video", session->remote_jid,
- session);
- xmlnode_set_attrib(iq->node, "to", session->remote_jid);
- xmlnode_set_attrib(iq->node, "from", me);
- sess = google_session_create_xmlnode(session, "accept");
- }
- xmlnode_insert_child(iq->node, sess);
- desc = xmlnode_new_child(sess, "description");
- if (session->video)
- xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO);
- else
- xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE);
-
- codecs = purple_media_get_codecs(media, "google-video");
-
- for (iter = codecs; iter; iter = g_list_next(iter)) {
- PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
- gchar *id = g_strdup_printf("%d",
- purple_media_codec_get_id(codec));
- gchar *encoding_name =
- purple_media_codec_get_encoding_name(codec);
- payload = xmlnode_new_child(desc, "payload-type");
- xmlnode_set_attrib(payload, "id", id);
- xmlnode_set_attrib(payload, "name", encoding_name);
- xmlnode_set_attrib(payload, "width", "320");
- xmlnode_set_attrib(payload, "height", "200");
- xmlnode_set_attrib(payload, "framerate", "30");
- g_free(encoding_name);
- g_free(id);
- }
- purple_media_codec_list_free(codecs);
-
- codecs = purple_media_get_codecs(media, "google-voice");
-
- for (iter = codecs; iter; iter = g_list_next(iter)) {
- PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
- gchar *id = g_strdup_printf("%d",
- purple_media_codec_get_id(codec));
- gchar *encoding_name =
- purple_media_codec_get_encoding_name(codec);
- gchar *clock_rate = g_strdup_printf("%d",
- purple_media_codec_get_clock_rate(codec));
- payload = xmlnode_new_child(desc, "payload-type");
- if (session->video)
- xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE);
- xmlnode_set_attrib(payload, "id", id);
- /*
- * Hack to make Gmail accept speex as the codec.
- * It shouldn't have to be case sensitive.
- */
- if (purple_strequal(encoding_name, "SPEEX"))
- xmlnode_set_attrib(payload, "name", "speex");
- else
- xmlnode_set_attrib(payload, "name", encoding_name);
- xmlnode_set_attrib(payload, "clockrate", clock_rate);
- g_free(clock_rate);
- g_free(encoding_name);
- g_free(id);
- }
- purple_media_codec_list_free(codecs);
-
- jabber_iq_send(iq);
-
- if (is_initiator) {
- google_session_send_candidates(session->media,
- "google-voice", session->remote_jid,
- session);
- google_session_send_candidates(session->media,
- "google-video", session->remote_jid,
- session);
- }
-
- g_signal_handlers_disconnect_by_func(G_OBJECT(session->media),
- G_CALLBACK(google_session_ready), session);
- }
-}
-
-static void
-google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
- gchar *sid, gchar *name, GoogleSession *session)
-{
- if (sid == NULL && name == NULL) {
- if (state == PURPLE_MEDIA_STATE_END) {
- google_session_destroy(session);
- }
- }
-}
-
-static void
-google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
- gchar *sid, gchar *name, gboolean local,
- GoogleSession *session)
-{
- if (sid != NULL || name != NULL)
- return;
-
- if (type == PURPLE_MEDIA_INFO_HANGUP) {
- xmlnode *sess;
- JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
- xmlnode_set_attrib(iq->node, "to", session->remote_jid);
- sess = google_session_create_xmlnode(session, "terminate");
- xmlnode_insert_child(iq->node, sess);
-
- jabber_iq_send(iq);
- } else if (type == PURPLE_MEDIA_INFO_REJECT) {
- xmlnode *sess;
- JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
-
- xmlnode_set_attrib(iq->node, "to", session->remote_jid);
- sess = google_session_create_xmlnode(session, "reject");
- xmlnode_insert_child(iq->node, sess);
-
- jabber_iq_send(iq);
- } else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) {
- google_session_ready(session);
- }
-}
-
-static GParameter *
-jabber_google_session_get_params(JabberStream *js, guint *num)
-{
- guint num_params;
- GParameter *params = jingle_get_params(js, &num_params);
- GParameter *new_params = g_new0(GParameter, num_params + 1);
-
- memcpy(new_params, params, sizeof(GParameter) * num_params);
-
- purple_debug_info("jabber", "setting Google jingle compatibility param\n");
- new_params[num_params].name = "compatibility-mode";
- g_value_init(&new_params[num_params].value, G_TYPE_UINT);
- g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */
-
- g_free(params);
- *num = num_params + 1;
- return new_params;
-}
-
-
-gboolean
-jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type)
-{
- GoogleSession *session;
- JabberBuddy *jb;
- JabberBuddyResource *jbr;
- gchar *jid;
- GParameter *params;
- guint num_params;
-
- /* construct JID to send to */
- jb = jabber_buddy_find(js, who, FALSE);
- if (!jb) {
- purple_debug_error("jingle-rtp",
- "Could not find Jabber buddy\n");
- return FALSE;
- }
- jbr = jabber_buddy_find_resource(jb, NULL);
- if (!jbr) {
- purple_debug_error("jingle-rtp",
- "Could not find buddy's resource\n");
- }
-
- if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
- jid = g_strdup_printf("%s/%s", who, jbr->name);
- } else {
- jid = g_strdup(who);
- }
-
- session = g_new0(GoogleSession, 1);
- session->id.id = jabber_get_next_id(js);
- session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node,
- js->user->domain, js->user->resource);
- session->state = SENT_INITIATE;
- session->js = js;
- session->remote_jid = jid;
-
- if (type & PURPLE_MEDIA_VIDEO)
- session->video = TRUE;
-
- session->media = purple_media_manager_create_media(
- purple_media_manager_get(),
- purple_connection_get_account(js->gc),
- "fsrtpconference", session->remote_jid, TRUE);
-
- purple_media_set_prpl_data(session->media, session);
-
- g_signal_connect_swapped(G_OBJECT(session->media),
- "candidates-prepared",
- G_CALLBACK(google_session_ready), session);
- g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed",
- G_CALLBACK(google_session_ready), session);
- g_signal_connect(G_OBJECT(session->media), "state-changed",
- G_CALLBACK(google_session_state_changed_cb), session);
- g_signal_connect(G_OBJECT(session->media), "stream-info",
- G_CALLBACK(google_session_stream_info_cb), session);
-
- params = jabber_google_session_get_params(js, &num_params);
-
- if (purple_media_add_stream(session->media, "google-voice",
- session->remote_jid, PURPLE_MEDIA_AUDIO,
- TRUE, "nice", num_params, params) == FALSE ||
- (session->video && purple_media_add_stream(
- session->media, "google-video",
- session->remote_jid, PURPLE_MEDIA_VIDEO,
- TRUE, "nice", num_params, params) == FALSE)) {
- purple_media_error(session->media, "Error adding stream.");
- purple_media_end(session->media, NULL, NULL);
- g_free(params);
- return FALSE;
- }
-
- g_free(params);
-
- return (session->media != NULL) ? TRUE : FALSE;
-}
-
-static gboolean
-google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
- JabberIq *result;
- GList *codecs = NULL, *video_codecs = NULL;
- xmlnode *desc_element, *codec_element;
- PurpleMediaCodec *codec;
- const char *xmlns;
- GParameter *params;
- guint num_params;
-
- if (session->state != UNINIT) {
- purple_debug_error("jabber", "Received initiate for active session.\n");
- return FALSE;
- }
-
- desc_element = xmlnode_get_child(sess, "description");
- xmlns = xmlnode_get_namespace(desc_element);
-
- if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
- session->video = FALSE;
- else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO))
- session->video = TRUE;
- else {
- purple_debug_error("jabber", "Received initiate with "
- "invalid namespace %s.\n", xmlns);
- return FALSE;
- }
-
- session->media = purple_media_manager_create_media(
- purple_media_manager_get(),
- purple_connection_get_account(js->gc),
- "fsrtpconference", session->remote_jid, FALSE);
-
- purple_media_set_prpl_data(session->media, session);
-
- g_signal_connect_swapped(G_OBJECT(session->media),
- "candidates-prepared",
- G_CALLBACK(google_session_ready), session);
- g_signal_connect_swapped(G_OBJECT(session->media), "codecs-changed",
- G_CALLBACK(google_session_ready), session);
- g_signal_connect(G_OBJECT(session->media), "state-changed",
- G_CALLBACK(google_session_state_changed_cb), session);
- g_signal_connect(G_OBJECT(session->media), "stream-info",
- G_CALLBACK(google_session_stream_info_cb), session);
-
- params = jabber_google_session_get_params(js, &num_params);
-
- if (purple_media_add_stream(session->media, "google-voice",
- session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE,
- "nice", num_params, params) == FALSE ||
- (session->video && purple_media_add_stream(
- session->media, "google-video",
- session->remote_jid, PURPLE_MEDIA_VIDEO,
- FALSE, "nice", num_params, params) == FALSE)) {
- purple_media_error(session->media, "Error adding stream.");
- purple_media_stream_info(session->media,
- PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE);
- g_free(params);
- return FALSE;
- }
-
- g_free(params);
-
- for (codec_element = xmlnode_get_child(desc_element, "payload-type");
- codec_element; codec_element = codec_element->next) {
- const char *id, *encoding_name, *clock_rate,
- *width, *height, *framerate;
- gboolean video;
- if (codec_element->name &&
- strcmp(codec_element->name, "payload-type"))
- continue;
-
- xmlns = xmlnode_get_namespace(codec_element);
- encoding_name = xmlnode_get_attrib(codec_element, "name");
- id = xmlnode_get_attrib(codec_element, "id");
-
- if (!session->video ||
- (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) {
- clock_rate = xmlnode_get_attrib(
- codec_element, "clockrate");
- video = FALSE;
- } else {
- width = xmlnode_get_attrib(codec_element, "width");
- height = xmlnode_get_attrib(codec_element, "height");
- framerate = xmlnode_get_attrib(
- codec_element, "framerate");
- clock_rate = "90000";
- video = TRUE;
- }
-
- if (id) {
- codec = purple_media_codec_new(atoi(id), encoding_name,
- video ? PURPLE_MEDIA_VIDEO :
- PURPLE_MEDIA_AUDIO,
- clock_rate ? atoi(clock_rate) : 0);
- if (video)
- video_codecs = g_list_append(
- video_codecs, codec);
- else
- codecs = g_list_append(codecs, codec);
- }
- }
-
- if (codecs)
- purple_media_set_remote_codecs(session->media, "google-voice",
- session->remote_jid, codecs);
- if (video_codecs)
- purple_media_set_remote_codecs(session->media, "google-video",
- session->remote_jid, video_codecs);
-
- purple_media_codec_list_free(codecs);
- purple_media_codec_list_free(video_codecs);
-
- result = jabber_iq_new(js, JABBER_IQ_RESULT);
- jabber_iq_set_id(result, iq_id);
- xmlnode_set_attrib(result->node, "to", session->remote_jid);
- jabber_iq_send(result);
-
- return TRUE;
-}
-
-static void
-google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
- JabberIq *result;
- GList *list = NULL, *video_list = NULL;
- xmlnode *cand;
- static int name = 0;
- char n[4];
-
- for (cand = xmlnode_get_child(sess, "candidate"); cand;
- cand = xmlnode_get_next_twin(cand)) {
- PurpleMediaCandidate *info;
- const gchar *cname = xmlnode_get_attrib(cand, "name");
- const gchar *type = xmlnode_get_attrib(cand, "type");
- const gchar *protocol = xmlnode_get_attrib(cand, "protocol");
- const gchar *address = xmlnode_get_attrib(cand, "address");
- const gchar *port = xmlnode_get_attrib(cand, "port");
- guint component_id;
-
- if (cname && type && address && port) {
- PurpleMediaCandidateType candidate_type;
-
- g_snprintf(n, sizeof(n), "S%d", name++);
-
- if (g_str_equal(type, "local"))
- candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
- else if (g_str_equal(type, "stun"))
- candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX;
- else if (g_str_equal(type, "relay"))
- candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
- else
- candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
-
- if (purple_strequal(cname, "rtcp") ||
- purple_strequal(cname, "video_rtcp"))
- component_id = PURPLE_MEDIA_COMPONENT_RTCP;
- else
- component_id = PURPLE_MEDIA_COMPONENT_RTP;
-
- info = purple_media_candidate_new(n, component_id,
- candidate_type,
- purple_strequal(protocol, "udp") ?
- PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
- PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
- address,
- atoi(port));
- g_object_set(info, "username", xmlnode_get_attrib(cand, "username"),
- "password", xmlnode_get_attrib(cand, "password"), NULL);
- if (!strncmp(cname, "video_", 6))
- video_list = g_list_append(video_list, info);
- else
- list = g_list_append(list, info);
- }
- }
-
- if (list)
- purple_media_add_remote_candidates(
- session->media, "google-voice",
- session->remote_jid, list);
- if (video_list)
- purple_media_add_remote_candidates(
- session->media, "google-video",
- session->remote_jid, video_list);
- purple_media_candidate_list_free(list);
- purple_media_candidate_list_free(video_list);
-
- result = jabber_iq_new(js, JABBER_IQ_RESULT);
- jabber_iq_set_id(result, iq_id);
- xmlnode_set_attrib(result->node, "to", session->remote_jid);
- jabber_iq_send(result);
-}
-
-static void
-google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
- xmlnode *desc_element = xmlnode_get_child(sess, "description");
- xmlnode *codec_element = xmlnode_get_child(
- desc_element, "payload-type");
- GList *codecs = NULL, *video_codecs = NULL;
- JabberIq *result = NULL;
- const gchar *xmlns = xmlnode_get_namespace(desc_element);
- gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO));
-
- for (; codec_element; codec_element = codec_element->next) {
- const gchar *xmlns, *encoding_name, *id,
- *clock_rate, *width, *height, *framerate;
- gboolean video_codec = FALSE;
-
- if (!purple_strequal(codec_element->name, "payload-type"))
- continue;
-
- xmlns = xmlnode_get_namespace(codec_element);
- encoding_name = xmlnode_get_attrib(codec_element, "name");
- id = xmlnode_get_attrib(codec_element, "id");
-
- if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
- clock_rate = xmlnode_get_attrib(
- codec_element, "clockrate");
- else {
- clock_rate = "90000";
- width = xmlnode_get_attrib(codec_element, "width");
- height = xmlnode_get_attrib(codec_element, "height");
- framerate = xmlnode_get_attrib(
- codec_element, "framerate");
- video_codec = TRUE;
- }
-
- if (id && encoding_name) {
- PurpleMediaCodec *codec = purple_media_codec_new(
- atoi(id), encoding_name,
- video_codec ? PURPLE_MEDIA_VIDEO :
- PURPLE_MEDIA_AUDIO,
- clock_rate ? atoi(clock_rate) : 0);
- if (video_codec)
- video_codecs = g_list_append(
- video_codecs, codec);
- else
- codecs = g_list_append(codecs, codec);
- }
- }
-
- if (codecs)
- purple_media_set_remote_codecs(session->media, "google-voice",
- session->remote_jid, codecs);
- if (video_codecs)
- purple_media_set_remote_codecs(session->media, "google-video",
- session->remote_jid, video_codecs);
-
- purple_media_stream_info(session->media, PURPLE_MEDIA_INFO_ACCEPT,
- NULL, NULL, FALSE);
-
- result = jabber_iq_new(js, JABBER_IQ_RESULT);
- jabber_iq_set_id(result, iq_id);
- xmlnode_set_attrib(result->node, "to", session->remote_jid);
- jabber_iq_send(result);
-}
-
-static void
-google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess)
-{
- purple_media_end(session->media, NULL, NULL);
-}
-
-static void
-google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess)
-{
- purple_media_end(session->media, NULL, NULL);
-}
-
-static void
-google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
-{
- const char *type = xmlnode_get_attrib(sess, "type");
-
- if (!strcmp(type, "initiate")) {
- google_session_handle_initiate(js, session, sess, iq_id);
- } else if (!strcmp(type, "accept")) {
- google_session_handle_accept(js, session, sess, iq_id);
- } else if (!strcmp(type, "reject")) {
- google_session_handle_reject(js, session, sess);
- } else if (!strcmp(type, "terminate")) {
- google_session_handle_terminate(js, session, sess);
- } else if (!strcmp(type, "candidates")) {
- google_session_handle_candidates(js, session, sess, iq_id);
- }
-}
-
-void
-jabber_google_session_parse(JabberStream *js, const char *from,
- JabberIqType type, const char *iq_id,
- xmlnode *session_node)
-{
- GoogleSession *session = NULL;
- GoogleSessionId id;
-
- xmlnode *desc_node;
-
- GList *iter = NULL;
-
- if (type != JABBER_IQ_SET)
- return;
-
- id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
- if (!id.id)
- return;
-
- id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
- if (!id.initiator)
- return;
-
- iter = purple_media_manager_get_media_by_account(
- purple_media_manager_get(),
- purple_connection_get_account(js->gc));
- for (; iter; iter = g_list_delete_link(iter, iter)) {
- GoogleSession *gsession =
- purple_media_get_prpl_data(iter->data);
- if (google_session_id_equal(&(gsession->id), &id)) {
- session = gsession;
- break;
- }
- }
- if (iter != NULL) {
- g_list_free(iter);
- }
-
- if (session) {
- google_session_parse_iq(js, session, session_node, iq_id);
- return;
- }
-
- /* If the session doesn't exist, this has to be an initiate message */
- if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate"))
- return;
- desc_node = xmlnode_get_child(session_node, "description");
- if (!desc_node)
- return;
- session = g_new0(GoogleSession, 1);
- session->id.id = g_strdup(id.id);
- session->id.initiator = g_strdup(id.initiator);
- session->state = UNINIT;
- session->js = js;
- session->remote_jid = g_strdup(session->id.initiator);
-
- google_session_handle_initiate(js, session, session_node, iq_id);
-}
-#endif /* USE_VV */
-
-static void
-jabber_gmail_parse(JabberStream *js, const char *from,
- JabberIqType type, const char *id,
- xmlnode *packet, gpointer nul)
-{
- xmlnode *child;
- xmlnode *message;
- const char *to, *url;
- const char *in_str;
- char *to_name;
-
- int i, count = 1, returned_count;
-
- const char **tos, **froms, **urls;
- char **subjects;
-
- if (type == JABBER_IQ_ERROR)
- return;
-
- child = xmlnode_get_child(packet, "mailbox");
- if (!child)
- return;
-
- in_str = xmlnode_get_attrib(child, "total-matched");
- if (in_str && *in_str)
- count = atoi(in_str);
-
- /* If Gmail doesn't tell us who the mail is to, let's use our JID */
- to = xmlnode_get_attrib(packet, "to");
-
- message = xmlnode_get_child(child, "mail-thread-info");
-
- if (count == 0 || !message) {
- if (count > 0) {
- char *bare_jid = jabber_get_bare_jid(to);
- const char *default_tos[2] = { bare_jid };
-
- purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL);
- g_free(bare_jid);
- } else {
- purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL);
- }
-
- return;
- }
-
- /* Loop once to see how many messages were returned so we can allocate arrays
- * accordingly */
- for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message));
-
- froms = g_new0(const char* , returned_count + 1);
- tos = g_new0(const char* , returned_count + 1);
- subjects = g_new0(char* , returned_count + 1);
- urls = g_new0(const char* , returned_count + 1);
-
- to = xmlnode_get_attrib(packet, "to");
- to_name = jabber_get_bare_jid(to);
- url = xmlnode_get_attrib(child, "url");
- if (!url || !*url)
- url = "http://www.gmail.com";
-
- message= xmlnode_get_child(child, "mail-thread-info");
- for (i=0; message; message = xmlnode_get_next_twin(message), i++) {
- xmlnode *sender_node, *subject_node;
- const char *from, *tid;
- char *subject;
-
- subject_node = xmlnode_get_child(message, "subject");
- sender_node = xmlnode_get_child(message, "senders");
- sender_node = xmlnode_get_child(sender_node, "sender");
-
- while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") ||
- !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0")))
- sender_node = xmlnode_get_next_twin(sender_node);
-
- if (!sender_node) {
- i--;
- continue;
- }
-
- from = xmlnode_get_attrib(sender_node, "name");
- if (!from || !*from)
- from = xmlnode_get_attrib(sender_node, "address");
- subject = xmlnode_get_data(subject_node);
- /*
- * url = xmlnode_get_attrib(message, "url");
- */
- tos[i] = (to_name != NULL ? to_name : "");
- froms[i] = (from != NULL ? from : "");
- subjects[i] = (subject != NULL ? subject : g_strdup(""));
- urls[i] = url;
-
- tid = xmlnode_get_attrib(message, "tid");
- if (tid &&
- (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) {
- g_free(js->gmail_last_tid);
- js->gmail_last_tid = g_strdup(tid);
- }
- }
-
- if (i>0)
- purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos,
- urls, NULL, NULL);
-
- g_free(to_name);
- g_free(tos);
- g_free(froms);
- for (i = 0; i < returned_count; i++)
- g_free(subjects[i]);
- g_free(subjects);
- g_free(urls);
-
- in_str = xmlnode_get_attrib(child, "result-time");
- if (in_str && *in_str) {
- g_free(js->gmail_last_time);
- js->gmail_last_time = g_strdup(in_str);
- }
-}
-
-void
-jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
- const char *id, xmlnode *new_mail)
-{
- xmlnode *query;
- JabberIq *iq;
-
- /* bail if the user isn't interested */
- if (!purple_account_get_check_mail(js->gc->account))
- return;
-
- /* Is this an initial incoming mail notification? If so, send a request for more info */
- if (type != JABBER_IQ_SET)
- return;
-
- /* Acknowledge the notification */
- iq = jabber_iq_new(js, JABBER_IQ_RESULT);
- if (from)
- xmlnode_set_attrib(iq->node, "to", from);
- xmlnode_set_attrib(iq->node, "id", id);
- jabber_iq_send(iq);
-
- purple_debug_misc("jabber",
- "Got new mail notification. Sending request for more info\n");
-
- iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
- jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
- query = xmlnode_get_child(iq->node, "query");
-
- if (js->gmail_last_time)
- xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time);
- if (js->gmail_last_tid)
- xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid);
-
- jabber_iq_send(iq);
- return;
-}
-
-void jabber_gmail_init(JabberStream *js) {
- JabberIq *iq;
- xmlnode *usersetting, *mailnotifications;
-
- if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
- return;
-
- /*
- * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html:
- * To ensure better compatibility with other clients, rather than
- * setting this value to "false" to turn off notifications, it is
- * recommended that a client set this to "true" and filter incoming
- * email notifications itself.
- */
- iq = jabber_iq_new(js, JABBER_IQ_SET);
- usersetting = xmlnode_new_child(iq->node, "usersetting");
- xmlnode_set_namespace(usersetting, "google:setting");
- mailnotifications = xmlnode_new_child(usersetting, "mailnotifications");
- xmlnode_set_attrib(mailnotifications, "value", "true");
- jabber_iq_send(iq);
-
- iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
- jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
- jabber_iq_send(iq);
-}
-
-void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item)
-{
- PurpleAccount *account = purple_connection_get_account(js->gc);
- GSList *list = account->deny;
- const char *jid = xmlnode_get_attrib(item, "jid");
- char *jid_norm = (char *)jabber_normalize(account, jid);
-
- while (list) {
- if (!strcmp(jid_norm, (char*)list->data)) {
- xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
- xmlnode_set_attrib(query, "gr:ext", "2");
- xmlnode_set_attrib(item, "gr:t", "B");
- return;
- }
- list = list->next;
- }
-}
-
-gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item)
-{
- PurpleAccount *account = purple_connection_get_account(js->gc);
- const char *jid = xmlnode_get_attrib(item, "jid");
- gboolean on_block_list = FALSE;
-
- char *jid_norm;
-
- const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER);
- const char *subscription = xmlnode_get_attrib(item, "subscription");
- const char *ask = xmlnode_get_attrib(item, "ask");
-
- if ((!subscription || !strcmp(subscription, "none")) && !ask) {
- /* The Google Talk servers will automatically add people from your Gmail address book
- * with subscription=none. If we see someone with subscription=none, ignore them.
- */
- return FALSE;
- }
-
- jid_norm = g_strdup(jabber_normalize(account, jid));
-
- on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm,
- (GCompareFunc)strcmp);
-
- if (grt && (*grt == 'H' || *grt == 'h')) {
- /* Hidden; don't show this buddy. */
- GSList *buddies = purple_find_buddies(account, jid_norm);
- if (buddies)
- purple_debug_info("jabber", "Removing %s from local buddy list\n",
- jid_norm);
-
- for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) {
- purple_blist_remove_buddy(buddies->data);
- }
-
- g_free(jid_norm);
- return FALSE;
- }
-
- if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) {
- purple_debug_info("jabber", "Blocking %s\n", jid_norm);
- purple_privacy_deny_add(account, jid_norm, TRUE);
- } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){
- purple_debug_info("jabber", "Unblocking %s\n", jid_norm);
- purple_privacy_deny_remove(account, jid_norm, TRUE);
- }
-
- g_free(jid_norm);
- return TRUE;
-}
-
-void jabber_google_roster_add_deny(JabberStream *js, const char *who)
-{
- PurpleAccount *account;
- GSList *buddies;
- JabberIq *iq;
- xmlnode *query;
- xmlnode *item;
- xmlnode *group;
- PurpleBuddy *b;
- JabberBuddy *jb;
- const char *balias;
-
- jb = jabber_buddy_find(js, who, TRUE);
-
- account = purple_connection_get_account(js->gc);
- buddies = purple_find_buddies(account, who);
- if(!buddies)
- return;
-
- b = buddies->data;
-
- iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
-
- query = xmlnode_get_child(iq->node, "query");
- item = xmlnode_new_child(query, "item");
-
- while(buddies) {
- PurpleGroup *g;
-
- b = buddies->data;
- g = purple_buddy_get_group(b);
-
- group = xmlnode_new_child(item, "group");
- xmlnode_insert_data(group, purple_group_get_name(g), -1);
-
- buddies = buddies->next;
- }
-
- balias = purple_buddy_get_local_buddy_alias(b);
- xmlnode_set_attrib(item, "jid", who);
- xmlnode_set_attrib(item, "name", balias ? balias : "");
- xmlnode_set_attrib(item, "gr:t", "B");
- xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
- xmlnode_set_attrib(query, "gr:ext", "2");
-
- jabber_iq_send(iq);
-
- /* Synthesize a sign-off */
- if (jb) {
- JabberBuddyResource *jbr;
- GList *l = jb->resources;
- while (l) {
- jbr = l->data;
- if (jbr && jbr->name)
- {
- purple_debug_misc("jabber", "Removing resource %s\n", jbr->name);
- jabber_buddy_remove_resource(jb, jbr->name);
- }
- l = l->next;
- }
- }
-
- purple_prpl_got_user_status(account, who, "offline", NULL);
-}
-
-void jabber_google_roster_rem_deny(JabberStream *js, const char *who)
-{
- GSList *buddies;
- JabberIq *iq;
- xmlnode *query;
- xmlnode *item;
- xmlnode *group;
- PurpleBuddy *b;
- const char *balias;
-
- buddies = purple_find_buddies(purple_connection_get_account(js->gc), who);
- if(!buddies)
- return;
-
- b = buddies->data;
-
- iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
-
- query = xmlnode_get_child(iq->node, "query");
- item = xmlnode_new_child(query, "item");
-
- while(buddies) {
- PurpleGroup *g;
-
- b = buddies->data;
- g = purple_buddy_get_group(b);
-
- group = xmlnode_new_child(item, "group");
- xmlnode_insert_data(group, purple_group_get_name(g), -1);
-
- buddies = buddies->next;
- }
-
- balias = purple_buddy_get_local_buddy_alias(b);
- xmlnode_set_attrib(item, "jid", who);
- xmlnode_set_attrib(item, "name", balias ? balias : "");
- xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
- xmlnode_set_attrib(query, "gr:ext", "2");
-
- jabber_iq_send(iq);
-
- /* See if he's online */
- jabber_presence_subscription_set(js, who, "probe");
-}
-
-/* This does two passes on the string. The first pass goes through
- * and determine if all the structured text is properly balanced, and
- * how many instances of each there is. The second pass goes and converts
- * everything to HTML, depending on what's figured out by the first pass.
- * It will short circuit once it knows it has no more replacements to make
- */
-char *jabber_google_format_to_html(const char *text)
-{
- const char *p;
-
- /* The start of the screen may be consdiered a space for this purpose */
- gboolean preceding_space = TRUE;
-
- gboolean in_bold = FALSE, in_italic = FALSE;
- gboolean in_tag = FALSE;
-
- gint bold_count = 0, italic_count = 0;
-
- GString *str;
-
- for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
- gunichar c = g_utf8_get_char(p);
- if (c == '*' && !in_tag) {
- if (in_bold && (g_unichar_isspace(*(p+1)) ||
- *(p+1) == '\0' ||
- *(p+1) == '<')) {
- bold_count++;
- in_bold = FALSE;
- } else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) {
- bold_count++;
- in_bold = TRUE;
- }
- preceding_space = TRUE;
- } else if (c == '_' && !in_tag) {
- if (in_italic && (g_unichar_isspace(*(p+1)) ||
- *(p+1) == '\0' ||
- *(p+1) == '<')) {
- italic_count++;
- in_italic = FALSE;
- } else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) {
- italic_count++;
- in_italic = TRUE;
- }
- preceding_space = TRUE;
- } else if (c == '<' && !in_tag) {
- in_tag = TRUE;
- } else if (c == '>' && in_tag) {
- in_tag = FALSE;
- } else if (!in_tag) {
- if (g_unichar_isspace(c))
- preceding_space = TRUE;
- else
- preceding_space = FALSE;
- }
- }
-
- str = g_string_new(NULL);
- in_bold = in_italic = in_tag = FALSE;
- preceding_space = TRUE;
-
- for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
- gunichar c = g_utf8_get_char(p);
-
- if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) {
- g_string_append(str, p);
- return g_string_free(str, FALSE);
- }
-
-
- if (c == '*' && !in_tag) {
- if (in_bold &&
- (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */
- str = g_string_append(str, "");
- in_bold = FALSE;
- bold_count--;
- } else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) {
- str = g_string_append(str, "");
- bold_count--;
- in_bold = TRUE;
- } else {
- str = g_string_append_unichar(str, c);
- }
- preceding_space = TRUE;
- } else if (c == '_' && !in_tag) {
- if (in_italic &&
- (g_unichar_isspace(*(p+1))||*(p+1)=='<')) {
- str = g_string_append(str, "");
- italic_count--;
- in_italic = FALSE;
- } else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) {
- str = g_string_append(str, "");
- italic_count--;
- in_italic = TRUE;
- } else {
- str = g_string_append_unichar(str, c);
- }
- preceding_space = TRUE;
- } else if (c == '<' && !in_tag) {
- str = g_string_append_unichar(str, c);
- in_tag = TRUE;
- } else if (c == '>' && in_tag) {
- str = g_string_append_unichar(str, c);
- in_tag = FALSE;
- } else if (!in_tag) {
- str = g_string_append_unichar(str, c);
- if (g_unichar_isspace(c))
- preceding_space = TRUE;
- else
- preceding_space = FALSE;
- } else {
- str = g_string_append_unichar(str, c);
- }
- }
- return g_string_free(str, FALSE);
-}
-
-void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr)
-{
- if (!js->googletalk)
- return;
- if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) {
- purple_prpl_got_user_status(js->gc->account, user, "tune",
- PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL);
- g_free(jbr->status);
- jbr->status = NULL;
- } else {
- purple_prpl_got_user_status_deactive(js->gc->account, user, "tune");
- }
-}
-
-char *jabber_google_presence_outgoing(PurpleStatus *tune)
-{
- const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
- return attr ? g_strdup_printf("♫ %s", attr) : g_strdup("");
-}
-
-static void
-jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
- const char *error_message)
-{
- JabberStream *js = (JabberStream *) data;
-
- if (error_message) {
- purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
- error_message);
- g_slist_free(hosts);
- js->stun_query = NULL;
- return;
- }
-
- if (hosts && g_slist_next(hosts)) {
- struct sockaddr *addr = g_slist_next(hosts)->data;
- char dst[INET6_ADDRSTRLEN];
- int port;
-
- if (addr->sa_family == AF_INET6) {
- inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr,
- dst, sizeof(dst));
- port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
- } else {
- inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr,
- dst, sizeof(dst));
- port = ntohs(((struct sockaddr_in *) addr)->sin_port);
- }
-
- if (js->stun_ip)
- g_free(js->stun_ip);
- js->stun_ip = g_strdup(dst);
- js->stun_port = port;
-
- purple_debug_info("jabber", "set Google STUN IP/port address: "
- "%s:%d\n", dst, port);
-
- /* unmark ongoing query */
- js->stun_query = NULL;
- }
-
- while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- /* Free the address */
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
- }
-}
-
-static void
-jabber_google_jingle_info_common(JabberStream *js, const char *from,
- JabberIqType type, xmlnode *query)
-{
- const xmlnode *stun = xmlnode_get_child(query, "stun");
- gchar *my_bare_jid;
-
- /*
- * Make sure that random people aren't sending us STUN servers. Per
- * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these
- * stanzas are stamped from our bare JID.
- */
- if (from) {
- my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
- if (!purple_strequal(from, my_bare_jid)) {
- purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n",
- from);
- g_free(my_bare_jid);
- return;
- }
-
- g_free(my_bare_jid);
- }
-
- if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET)
- return;
-
- purple_debug_info("jabber", "got google:jingleinfo\n");
-
- if (stun) {
- xmlnode *server = xmlnode_get_child(stun, "server");
-
- if (server) {
- const gchar *host = xmlnode_get_attrib(server, "host");
- const gchar *udp = xmlnode_get_attrib(server, "udp");
-
- if (host && udp) {
- int port = atoi(udp);
- /* if there, would already be an ongoing query,
- cancel it */
- if (js->stun_query)
- purple_dnsquery_destroy(js->stun_query);
-
- js->stun_query = purple_dnsquery_a(host, port,
- jabber_google_stun_lookup_cb, js);
- }
- }
- }
- /* should perhaps handle relays later on, or maybe wait until
- Google supports a common standard... */
-}
-
-static void
-jabber_google_jingle_info_cb(JabberStream *js, const char *from,
- JabberIqType type, const char *id,
- xmlnode *packet, gpointer data)
-{
- xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
- NS_GOOGLE_JINGLE_INFO);
-
- if (query)
- jabber_google_jingle_info_common(js, from, type, query);
- else
- purple_debug_warning("jabber", "Got invalid google:jingleinfo\n");
-}
-
-void
-jabber_google_handle_jingle_info(JabberStream *js, const char *from,
- JabberIqType type, const char *id,
- xmlnode *child)
-{
- jabber_google_jingle_info_common(js, from, type, child);
-}
-
-void
-jabber_google_send_jingle_info(JabberStream *js)
-{
- JabberIq *jingle_info =
- jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO);
-
- jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb,
- NULL);
- purple_debug_info("jabber", "sending google:jingleinfo query\n");
- jabber_iq_send(jingle_info);
-}
-
-void google_buddy_node_chat(PurpleBlistNode *node, gpointer data)
-{
- PurpleBuddy *buddy;
- PurpleConnection *gc;
- JabberStream *js;
- JabberChat *chat;
- gchar *room;
- gchar *uuid = purple_uuid_random();
-
- g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
-
- buddy = PURPLE_BUDDY(node);
- gc = purple_account_get_connection(purple_buddy_get_account(buddy));
- g_return_if_fail(gc != NULL);
- js = purple_connection_get_protocol_data(gc);
-
- room = g_strdup_printf("private-chat-%s", uuid);
- chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node,
- NULL, NULL);
- if (chat) {
- chat->muc = TRUE;
- jabber_chat_invite(gc, chat->id, "", purple_buddy_get_name(buddy));
- }
-
- g_free(room);
- g_free(uuid);
-}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google.h
--- a/libpurple/protocols/jabber/google.h Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/**
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#ifndef PURPLE_JABBER_GOOGLE_H_
-#define PURPLE_JABBER_GOOGLE_H_
-
-/* This is a place for Google Talk-specific XMPP extensions to live
- * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */
-
-#include "jabber.h"
-
-#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com"
-
-void jabber_gmail_init(JabberStream *js);
-void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
- const char *id, xmlnode *new_mail);
-
-void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item);
-
-/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE
- * if this roster item should continue to be processed
- */
-gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item);
-
-void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr);
-char *jabber_google_presence_outgoing(PurpleStatus *tune);
-
-void jabber_google_roster_add_deny(JabberStream *js, const char *who);
-void jabber_google_roster_rem_deny(JabberStream *js, const char *who);
-
-char *jabber_google_format_to_html(const char *text);
-
-gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type);
-void jabber_google_session_parse(JabberStream *js, const char *from, JabberIqType type, const char *iq, xmlnode *session);
-
-void jabber_google_handle_jingle_info(JabberStream *js, const char *from,
- JabberIqType type, const char *id,
- xmlnode *child);
-void jabber_google_send_jingle_info(JabberStream *js);
-
-void google_buddy_node_chat(PurpleBlistNode *node, gpointer data);
-
-#endif /* PURPLE_JABBER_GOOGLE_H_ */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/gmail.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/gmail.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,207 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "jabber.h"
+#include "gmail.h"
+
+static void
+jabber_gmail_parse(JabberStream *js, const char *from,
+ JabberIqType type, const char *id,
+ xmlnode *packet, gpointer nul)
+{
+ xmlnode *child;
+ xmlnode *message;
+ const char *to, *url;
+ const char *in_str;
+ char *to_name;
+
+ int i, count = 1, returned_count;
+
+ const char **tos, **froms, **urls;
+ char **subjects;
+
+ if (type == JABBER_IQ_ERROR)
+ return;
+
+ child = xmlnode_get_child(packet, "mailbox");
+ if (!child)
+ return;
+
+ in_str = xmlnode_get_attrib(child, "total-matched");
+ if (in_str && *in_str)
+ count = atoi(in_str);
+
+ /* If Gmail doesn't tell us who the mail is to, let's use our JID */
+ to = xmlnode_get_attrib(packet, "to");
+
+ message = xmlnode_get_child(child, "mail-thread-info");
+
+ if (count == 0 || !message) {
+ if (count > 0) {
+ char *bare_jid = jabber_get_bare_jid(to);
+ const char *default_tos[2] = { bare_jid };
+
+ purple_notify_emails(js->gc, count, FALSE, NULL, NULL, default_tos, NULL, NULL, NULL);
+ g_free(bare_jid);
+ } else {
+ purple_notify_emails(js->gc, count, FALSE, NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+
+ return;
+ }
+
+ /* Loop once to see how many messages were returned so we can allocate arrays
+ * accordingly */
+ for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message));
+
+ froms = g_new0(const char* , returned_count + 1);
+ tos = g_new0(const char* , returned_count + 1);
+ subjects = g_new0(char* , returned_count + 1);
+ urls = g_new0(const char* , returned_count + 1);
+
+ to = xmlnode_get_attrib(packet, "to");
+ to_name = jabber_get_bare_jid(to);
+ url = xmlnode_get_attrib(child, "url");
+ if (!url || !*url)
+ url = "http://www.gmail.com";
+
+ message= xmlnode_get_child(child, "mail-thread-info");
+ for (i=0; message; message = xmlnode_get_next_twin(message), i++) {
+ xmlnode *sender_node, *subject_node;
+ const char *from, *tid;
+ char *subject;
+
+ subject_node = xmlnode_get_child(message, "subject");
+ sender_node = xmlnode_get_child(message, "senders");
+ sender_node = xmlnode_get_child(sender_node, "sender");
+
+ while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") ||
+ !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0")))
+ sender_node = xmlnode_get_next_twin(sender_node);
+
+ if (!sender_node) {
+ i--;
+ continue;
+ }
+
+ from = xmlnode_get_attrib(sender_node, "name");
+ if (!from || !*from)
+ from = xmlnode_get_attrib(sender_node, "address");
+ subject = xmlnode_get_data(subject_node);
+ /*
+ * url = xmlnode_get_attrib(message, "url");
+ */
+ tos[i] = (to_name != NULL ? to_name : "");
+ froms[i] = (from != NULL ? from : "");
+ subjects[i] = (subject != NULL ? subject : g_strdup(""));
+ urls[i] = url;
+
+ tid = xmlnode_get_attrib(message, "tid");
+ if (tid &&
+ (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) {
+ g_free(js->gmail_last_tid);
+ js->gmail_last_tid = g_strdup(tid);
+ }
+ }
+
+ if (i>0)
+ purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos,
+ urls, NULL, NULL);
+
+ g_free(to_name);
+ g_free(tos);
+ g_free(froms);
+ for (i = 0; i < returned_count; i++)
+ g_free(subjects[i]);
+ g_free(subjects);
+ g_free(urls);
+
+ in_str = xmlnode_get_attrib(child, "result-time");
+ if (in_str && *in_str) {
+ g_free(js->gmail_last_time);
+ js->gmail_last_time = g_strdup(in_str);
+ }
+}
+
+void
+jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+ const char *id, xmlnode *new_mail)
+{
+ xmlnode *query;
+ JabberIq *iq;
+
+ /* bail if the user isn't interested */
+ if (!purple_account_get_check_mail(js->gc->account))
+ return;
+
+ /* Is this an initial incoming mail notification? If so, send a request for more info */
+ if (type != JABBER_IQ_SET)
+ return;
+
+ /* Acknowledge the notification */
+ iq = jabber_iq_new(js, JABBER_IQ_RESULT);
+ if (from)
+ xmlnode_set_attrib(iq->node, "to", from);
+ xmlnode_set_attrib(iq->node, "id", id);
+ jabber_iq_send(iq);
+
+ purple_debug_misc("jabber",
+ "Got new mail notification. Sending request for more info\n");
+
+ iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
+ jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
+ query = xmlnode_get_child(iq->node, "query");
+
+ if (js->gmail_last_time)
+ xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time);
+ if (js->gmail_last_tid)
+ xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid);
+
+ jabber_iq_send(iq);
+ return;
+}
+
+void jabber_gmail_init(JabberStream *js) {
+ JabberIq *iq;
+ xmlnode *usersetting, *mailnotifications;
+
+ if (!purple_account_get_check_mail(purple_connection_get_account(js->gc)))
+ return;
+
+ /*
+ * Quoting http://code.google.com/apis/talk/jep_extensions/usersettings.html:
+ * To ensure better compatibility with other clients, rather than
+ * setting this value to "false" to turn off notifications, it is
+ * recommended that a client set this to "true" and filter incoming
+ * email notifications itself.
+ */
+ iq = jabber_iq_new(js, JABBER_IQ_SET);
+ usersetting = xmlnode_new_child(iq->node, "usersetting");
+ xmlnode_set_namespace(usersetting, "google:setting");
+ mailnotifications = xmlnode_new_child(usersetting, "mailnotifications");
+ xmlnode_set_attrib(mailnotifications, "value", "true");
+ jabber_iq_send(iq);
+
+ iq = jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_MAIL_NOTIFY);
+ jabber_iq_set_callback(iq, jabber_gmail_parse, NULL);
+ jabber_iq_send(iq);
+}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/gmail.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/gmail.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,30 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_GMAIL_H_
+#define PURPLE_JABBER_GOOGLE_GMAIL_H_
+
+#include "jabber.h"
+
+void jabber_gmail_init(JabberStream *js);
+void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+ const char *id, xmlnode *new_mail);
+
+#endif /* PURPLE_JABBER_GOOGLE_GMAIL_H_ */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,172 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+
+#include "google.h"
+#include "jabber.h"
+#include "chat.h"
+
+/* This does two passes on the string. The first pass goes through
+ * and determine if all the structured text is properly balanced, and
+ * how many instances of each there is. The second pass goes and converts
+ * everything to HTML, depending on what's figured out by the first pass.
+ * It will short circuit once it knows it has no more replacements to make
+ */
+char *jabber_google_format_to_html(const char *text)
+{
+ const char *p;
+
+ /* The start of the screen may be consdiered a space for this purpose */
+ gboolean preceding_space = TRUE;
+
+ gboolean in_bold = FALSE, in_italic = FALSE;
+ gboolean in_tag = FALSE;
+
+ gint bold_count = 0, italic_count = 0;
+
+ GString *str;
+
+ for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
+ gunichar c = g_utf8_get_char(p);
+ if (c == '*' && !in_tag) {
+ if (in_bold && (g_unichar_isspace(*(p+1)) ||
+ *(p+1) == '\0' ||
+ *(p+1) == '<')) {
+ bold_count++;
+ in_bold = FALSE;
+ } else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) {
+ bold_count++;
+ in_bold = TRUE;
+ }
+ preceding_space = TRUE;
+ } else if (c == '_' && !in_tag) {
+ if (in_italic && (g_unichar_isspace(*(p+1)) ||
+ *(p+1) == '\0' ||
+ *(p+1) == '<')) {
+ italic_count++;
+ in_italic = FALSE;
+ } else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) {
+ italic_count++;
+ in_italic = TRUE;
+ }
+ preceding_space = TRUE;
+ } else if (c == '<' && !in_tag) {
+ in_tag = TRUE;
+ } else if (c == '>' && in_tag) {
+ in_tag = FALSE;
+ } else if (!in_tag) {
+ if (g_unichar_isspace(c))
+ preceding_space = TRUE;
+ else
+ preceding_space = FALSE;
+ }
+ }
+
+ str = g_string_new(NULL);
+ in_bold = in_italic = in_tag = FALSE;
+ preceding_space = TRUE;
+
+ for (p = text; *p != '\0'; p = g_utf8_next_char(p)) {
+ gunichar c = g_utf8_get_char(p);
+
+ if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) {
+ g_string_append(str, p);
+ return g_string_free(str, FALSE);
+ }
+
+
+ if (c == '*' && !in_tag) {
+ if (in_bold &&
+ (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */
+ str = g_string_append(str, "");
+ in_bold = FALSE;
+ bold_count--;
+ } else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) {
+ str = g_string_append(str, "");
+ bold_count--;
+ in_bold = TRUE;
+ } else {
+ str = g_string_append_unichar(str, c);
+ }
+ preceding_space = TRUE;
+ } else if (c == '_' && !in_tag) {
+ if (in_italic &&
+ (g_unichar_isspace(*(p+1))||*(p+1)=='<')) {
+ str = g_string_append(str, "");
+ italic_count--;
+ in_italic = FALSE;
+ } else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) {
+ str = g_string_append(str, "");
+ italic_count--;
+ in_italic = TRUE;
+ } else {
+ str = g_string_append_unichar(str, c);
+ }
+ preceding_space = TRUE;
+ } else if (c == '<' && !in_tag) {
+ str = g_string_append_unichar(str, c);
+ in_tag = TRUE;
+ } else if (c == '>' && in_tag) {
+ str = g_string_append_unichar(str, c);
+ in_tag = FALSE;
+ } else if (!in_tag) {
+ str = g_string_append_unichar(str, c);
+ if (g_unichar_isspace(c))
+ preceding_space = TRUE;
+ else
+ preceding_space = FALSE;
+ } else {
+ str = g_string_append_unichar(str, c);
+ }
+ }
+ return g_string_free(str, FALSE);
+}
+
+
+
+void google_buddy_node_chat(PurpleBlistNode *node, gpointer data)
+{
+ PurpleBuddy *buddy;
+ PurpleConnection *gc;
+ JabberStream *js;
+ JabberChat *chat;
+ gchar *room;
+ gchar *uuid = purple_uuid_random();
+
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
+
+ buddy = PURPLE_BUDDY(node);
+ gc = purple_account_get_connection(purple_buddy_get_account(buddy));
+ g_return_if_fail(gc != NULL);
+ js = purple_connection_get_protocol_data(gc);
+
+ room = g_strdup_printf("private-chat-%s", uuid);
+ chat = jabber_join_chat(js, room, GOOGLE_GROUPCHAT_SERVER, js->user->node,
+ NULL, NULL);
+ if (chat) {
+ chat->muc = TRUE;
+ jabber_chat_invite(gc, chat->id, "", purple_buddy_get_name(buddy));
+ }
+
+ g_free(room);
+ g_free(uuid);
+}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,35 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_H_
+#define PURPLE_JABBER_GOOGLE_H_
+
+/* This is a place for Google Talk-specific XMPP extensions to live
+ * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */
+
+#include "jabber.h"
+
+#define GOOGLE_GROUPCHAT_SERVER "groupchat.google.com"
+
+char *jabber_google_format_to_html(const char *text);
+
+void google_buddy_node_chat(PurpleBlistNode *node, gpointer data);
+
+#endif /* PURPLE_JABBER_GOOGLE_H_ */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_presence.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_presence.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,43 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "google_presence.h"
+
+void jabber_google_presence_incoming(JabberStream *js, const char *user, JabberBuddyResource *jbr)
+{
+ if (!js->googletalk)
+ return;
+ if (jbr->status && purple_str_has_prefix(jbr->status, "♫ ")) {
+ purple_prpl_got_user_status(js->gc->account, user, "tune",
+ PURPLE_TUNE_TITLE, jbr->status + strlen("♫ "), NULL);
+ g_free(jbr->status);
+ jbr->status = NULL;
+ } else {
+ purple_prpl_got_user_status_deactive(js->gc->account, user, "tune");
+ }
+}
+
+char *jabber_google_presence_outgoing(PurpleStatus *tune)
+{
+ const char *attr = purple_status_get_attr_string(tune, PURPLE_TUNE_TITLE);
+ return attr ? g_strdup_printf("♫ %s", attr) : g_strdup("");
+}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_presence.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_presence.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,32 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_PRESENCE_H_
+#define PURPLE_JABBER_GOOGLE_PRESENCE_H_
+
+#include "jabber.h"
+#include "buddy.h"
+#include "status.h"
+
+void jabber_google_presence_incoming(JabberStream *js, const char *who, JabberBuddyResource *jbr);
+char *jabber_google_presence_outgoing(PurpleStatus *tune);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_PRESENCE_H_ */
\ No newline at end of file
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_roster.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_roster.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,206 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "google_roster.h"
+#include "jabber.h"
+#include "presence.h"
+#include "debug.h"
+#include "xmlnode.h"
+
+void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item)
+{
+ PurpleAccount *account = purple_connection_get_account(js->gc);
+ GSList *list = account->deny;
+ const char *jid = xmlnode_get_attrib(item, "jid");
+ char *jid_norm = (char *)jabber_normalize(account, jid);
+
+ while (list) {
+ if (!strcmp(jid_norm, (char*)list->data)) {
+ xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+ xmlnode_set_attrib(query, "gr:ext", "2");
+ xmlnode_set_attrib(item, "gr:t", "B");
+ return;
+ }
+ list = list->next;
+ }
+}
+
+gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item)
+{
+ PurpleAccount *account = purple_connection_get_account(js->gc);
+ const char *jid = xmlnode_get_attrib(item, "jid");
+ gboolean on_block_list = FALSE;
+
+ char *jid_norm;
+
+ const char *grt = xmlnode_get_attrib_with_namespace(item, "t", NS_GOOGLE_ROSTER);
+ const char *subscription = xmlnode_get_attrib(item, "subscription");
+ const char *ask = xmlnode_get_attrib(item, "ask");
+
+ if ((!subscription || !strcmp(subscription, "none")) && !ask) {
+ /* The Google Talk servers will automatically add people from your Gmail address book
+ * with subscription=none. If we see someone with subscription=none, ignore them.
+ */
+ return FALSE;
+ }
+
+ jid_norm = g_strdup(jabber_normalize(account, jid));
+
+ on_block_list = NULL != g_slist_find_custom(account->deny, jid_norm,
+ (GCompareFunc)strcmp);
+
+ if (grt && (*grt == 'H' || *grt == 'h')) {
+ /* Hidden; don't show this buddy. */
+ GSList *buddies = purple_find_buddies(account, jid_norm);
+ if (buddies)
+ purple_debug_info("jabber", "Removing %s from local buddy list\n",
+ jid_norm);
+
+ for ( ; buddies; buddies = g_slist_delete_link(buddies, buddies)) {
+ purple_blist_remove_buddy(buddies->data);
+ }
+
+ g_free(jid_norm);
+ return FALSE;
+ }
+
+ if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) {
+ purple_debug_info("jabber", "Blocking %s\n", jid_norm);
+ purple_privacy_deny_add(account, jid_norm, TRUE);
+ } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){
+ purple_debug_info("jabber", "Unblocking %s\n", jid_norm);
+ purple_privacy_deny_remove(account, jid_norm, TRUE);
+ }
+
+ g_free(jid_norm);
+ return TRUE;
+}
+
+void jabber_google_roster_add_deny(JabberStream *js, const char *who)
+{
+ PurpleAccount *account;
+ GSList *buddies;
+ JabberIq *iq;
+ xmlnode *query;
+ xmlnode *item;
+ xmlnode *group;
+ PurpleBuddy *b;
+ JabberBuddy *jb;
+ const char *balias;
+
+ jb = jabber_buddy_find(js, who, TRUE);
+
+ account = purple_connection_get_account(js->gc);
+ buddies = purple_find_buddies(account, who);
+ if(!buddies)
+ return;
+
+ b = buddies->data;
+
+ iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
+
+ query = xmlnode_get_child(iq->node, "query");
+ item = xmlnode_new_child(query, "item");
+
+ while(buddies) {
+ PurpleGroup *g;
+
+ b = buddies->data;
+ g = purple_buddy_get_group(b);
+
+ group = xmlnode_new_child(item, "group");
+ xmlnode_insert_data(group, purple_group_get_name(g), -1);
+
+ buddies = buddies->next;
+ }
+
+ balias = purple_buddy_get_local_buddy_alias(b);
+ xmlnode_set_attrib(item, "jid", who);
+ xmlnode_set_attrib(item, "name", balias ? balias : "");
+ xmlnode_set_attrib(item, "gr:t", "B");
+ xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+ xmlnode_set_attrib(query, "gr:ext", "2");
+
+ jabber_iq_send(iq);
+
+ /* Synthesize a sign-off */
+ if (jb) {
+ JabberBuddyResource *jbr;
+ GList *l = jb->resources;
+ while (l) {
+ jbr = l->data;
+ if (jbr && jbr->name)
+ {
+ purple_debug_misc("jabber", "Removing resource %s\n", jbr->name);
+ jabber_buddy_remove_resource(jb, jbr->name);
+ }
+ l = l->next;
+ }
+ }
+
+ purple_prpl_got_user_status(account, who, "offline", NULL);
+}
+
+void jabber_google_roster_rem_deny(JabberStream *js, const char *who)
+{
+ GSList *buddies;
+ JabberIq *iq;
+ xmlnode *query;
+ xmlnode *item;
+ xmlnode *group;
+ PurpleBuddy *b;
+ const char *balias;
+
+ buddies = purple_find_buddies(purple_connection_get_account(js->gc), who);
+ if(!buddies)
+ return;
+
+ b = buddies->data;
+
+ iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster");
+
+ query = xmlnode_get_child(iq->node, "query");
+ item = xmlnode_new_child(query, "item");
+
+ while(buddies) {
+ PurpleGroup *g;
+
+ b = buddies->data;
+ g = purple_buddy_get_group(b);
+
+ group = xmlnode_new_child(item, "group");
+ xmlnode_insert_data(group, purple_group_get_name(g), -1);
+
+ buddies = buddies->next;
+ }
+
+ balias = purple_buddy_get_local_buddy_alias(b);
+ xmlnode_set_attrib(item, "jid", who);
+ xmlnode_set_attrib(item, "name", balias ? balias : "");
+ xmlnode_set_attrib(query, "xmlns:gr", NS_GOOGLE_ROSTER);
+ xmlnode_set_attrib(query, "gr:ext", "2");
+
+ jabber_iq_send(iq);
+
+ /* See if he's online */
+ jabber_presence_subscription_set(js, who, "probe");
+}
+
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_roster.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_roster.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,37 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_
+#define PURPLE_JABBER_GOOGLE_ROSTER_H_
+
+#include "jabber.h"
+
+void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item);
+
+/* Returns FALSE if this should short-circuit processing of this roster item, or TRUE
+ * if this roster item should continue to be processed
+ */
+gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item);
+
+void jabber_google_roster_add_deny(JabberStream *js, const char *who);
+void jabber_google_roster_rem_deny(JabberStream *js, const char *who);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_session.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_session.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,866 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "google_session.h"
+#include "relay.h"
+
+#include "jingle/jingle.h"
+
+#ifdef USE_VV
+
+typedef struct {
+ PurpleMedia *media;
+ gboolean video;
+ GList *remote_audio_candidates; /* list of PurpleMediaCandidate */
+ GList *remote_video_candidates; /* list of PurpleMediaCandidate */
+ gboolean added_streams; /* this indicates if the streams have been
+ to media (ie. after getting relay credentials */
+} GoogleAVSessionData;
+
+static gboolean
+google_session_id_equal(gconstpointer a, gconstpointer b)
+{
+ GoogleSessionId *c = (GoogleSessionId*)a;
+ GoogleSessionId *d = (GoogleSessionId*)b;
+
+ return !strcmp(c->id, d->id) && !strcmp(c->initiator, d->initiator);
+}
+
+static void
+google_session_destroy(GoogleSession *session)
+{
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+ g_free(session->id.id);
+ g_free(session->id.initiator);
+ g_free(session->remote_jid);
+
+ if (session_data->remote_audio_candidates)
+ purple_media_candidate_list_free(session_data->remote_audio_candidates);
+
+ if (session_data->remote_video_candidates)
+ purple_media_candidate_list_free(session_data->remote_video_candidates);
+
+ g_free(session->session_data);
+ g_free(session);
+}
+
+static xmlnode *
+google_session_create_xmlnode(GoogleSession *session, const char *type)
+{
+ xmlnode *node = xmlnode_new("session");
+ xmlnode_set_namespace(node, NS_GOOGLE_SESSION);
+ xmlnode_set_attrib(node, "id", session->id.id);
+ xmlnode_set_attrib(node, "initiator", session->id.initiator);
+ xmlnode_set_attrib(node, "type", type);
+ return node;
+}
+
+static void
+google_session_send_candidates(PurpleMedia *media, gchar *session_id,
+ gchar *participant, GoogleSession *session)
+{
+ PurpleMedia *session_media =
+ ((GoogleAVSessionData *) session->session_data)->media;
+ GList *candidates =
+ purple_media_get_local_candidates(session_media, session_id,
+ session->remote_jid);
+ GList *iter;
+ PurpleMediaCandidate *transport;
+ gboolean video = FALSE;
+
+ if (!strcmp(session_id, "google-video"))
+ video = TRUE;
+
+ for (iter = candidates; iter; iter = iter->next) {
+ JabberIq *iq;
+ gchar *ip, *port, *username, *password;
+ gchar pref[16];
+ PurpleMediaCandidateType type;
+ xmlnode *sess;
+ xmlnode *candidate;
+ guint component_id;
+ transport = PURPLE_MEDIA_CANDIDATE(iter->data);
+ component_id = purple_media_candidate_get_component_id(
+ transport);
+
+ iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+ sess = google_session_create_xmlnode(session, "candidates");
+ xmlnode_insert_child(iq->node, sess);
+ xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+
+ candidate = xmlnode_new("candidate");
+
+ ip = purple_media_candidate_get_ip(transport);
+ port = g_strdup_printf("%d",
+ purple_media_candidate_get_port(transport));
+ g_ascii_dtostr(pref, 16,
+ purple_media_candidate_get_priority(transport) / 1000.0);
+ username = purple_media_candidate_get_username(transport);
+ password = purple_media_candidate_get_password(transport);
+ type = purple_media_candidate_get_candidate_type(transport);
+
+ xmlnode_set_attrib(candidate, "address", ip);
+ xmlnode_set_attrib(candidate, "port", port);
+ xmlnode_set_attrib(candidate, "name",
+ component_id == PURPLE_MEDIA_COMPONENT_RTP ?
+ video ? "video_rtp" : "rtp" :
+ component_id == PURPLE_MEDIA_COMPONENT_RTCP ?
+ video ? "video_rtcp" : "rtcp" : "none");
+ xmlnode_set_attrib(candidate, "username", username);
+ /*
+ * As of this writing, Farsight 2 in Google compatibility
+ * mode doesn't provide a password. The Gmail client
+ * requires this to be set.
+ */
+ xmlnode_set_attrib(candidate, "password",
+ password != NULL ? password : "");
+ xmlnode_set_attrib(candidate, "preference", pref);
+ xmlnode_set_attrib(candidate, "protocol",
+ purple_media_candidate_get_protocol(transport)
+ == PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ?
+ "udp" : "tcp");
+ xmlnode_set_attrib(candidate, "type", type ==
+ PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "local" :
+ type ==
+ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "stun" :
+ type ==
+ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
+ NULL);
+ xmlnode_set_attrib(candidate, "generation", "0");
+ xmlnode_set_attrib(candidate, "network", "0");
+ xmlnode_insert_child(sess, candidate);
+
+ g_free(ip);
+ g_free(port);
+ g_free(username);
+ g_free(password);
+
+ jabber_iq_send(iq);
+ }
+ purple_media_candidate_list_free(candidates);
+}
+
+static void
+google_session_ready(GoogleSession *session)
+{
+ PurpleMedia *media =
+ ((GoogleAVSessionData *)session->session_data)->media;
+ gboolean video =
+ ((GoogleAVSessionData *)session->session_data)->video;
+ if (purple_media_codecs_ready(media, NULL) &&
+ purple_media_candidates_prepared(media, NULL, NULL)) {
+ gchar *me = g_strdup_printf("%s@%s/%s",
+ session->js->user->node,
+ session->js->user->domain,
+ session->js->user->resource);
+ JabberIq *iq;
+ xmlnode *sess, *desc, *payload;
+ GList *codecs, *iter;
+ gboolean is_initiator = !strcmp(session->id.initiator, me);
+
+ if (!is_initiator &&
+ !purple_media_accepted(media, NULL, NULL)) {
+ g_free(me);
+ return;
+ }
+
+ iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+ if (is_initiator) {
+ xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+ xmlnode_set_attrib(iq->node, "from", session->id.initiator);
+ sess = google_session_create_xmlnode(session, "initiate");
+ } else {
+ google_session_send_candidates(media,
+ "google-voice", session->remote_jid,
+ session);
+ google_session_send_candidates(media,
+ "google-video", session->remote_jid,
+ session);
+ xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+ xmlnode_set_attrib(iq->node, "from", me);
+ sess = google_session_create_xmlnode(session, "accept");
+ }
+ xmlnode_insert_child(iq->node, sess);
+ desc = xmlnode_new_child(sess, "description");
+ if (video)
+ xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_VIDEO);
+ else
+ xmlnode_set_namespace(desc, NS_GOOGLE_SESSION_PHONE);
+
+ codecs = purple_media_get_codecs(media, "google-video");
+
+ for (iter = codecs; iter; iter = g_list_next(iter)) {
+ PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
+ gchar *id = g_strdup_printf("%d",
+ purple_media_codec_get_id(codec));
+ gchar *encoding_name =
+ purple_media_codec_get_encoding_name(codec);
+ payload = xmlnode_new_child(desc, "payload-type");
+ xmlnode_set_attrib(payload, "id", id);
+ xmlnode_set_attrib(payload, "name", encoding_name);
+ xmlnode_set_attrib(payload, "width", "320");
+ xmlnode_set_attrib(payload, "height", "200");
+ xmlnode_set_attrib(payload, "framerate", "30");
+ g_free(encoding_name);
+ g_free(id);
+ }
+ purple_media_codec_list_free(codecs);
+
+ codecs = purple_media_get_codecs(media, "google-voice");
+
+ for (iter = codecs; iter; iter = g_list_next(iter)) {
+ PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
+ gchar *id = g_strdup_printf("%d",
+ purple_media_codec_get_id(codec));
+ gchar *encoding_name =
+ purple_media_codec_get_encoding_name(codec);
+ gchar *clock_rate = g_strdup_printf("%d",
+ purple_media_codec_get_clock_rate(codec));
+ payload = xmlnode_new_child(desc, "payload-type");
+ if (video)
+ xmlnode_set_namespace(payload, NS_GOOGLE_SESSION_PHONE);
+ xmlnode_set_attrib(payload, "id", id);
+ /*
+ * Hack to make Gmail accept speex as the codec.
+ * It shouldn't have to be case sensitive.
+ */
+ if (purple_strequal(encoding_name, "SPEEX"))
+ xmlnode_set_attrib(payload, "name", "speex");
+ else
+ xmlnode_set_attrib(payload, "name", encoding_name);
+ xmlnode_set_attrib(payload, "clockrate", clock_rate);
+ g_free(clock_rate);
+ g_free(encoding_name);
+ g_free(id);
+ }
+ purple_media_codec_list_free(codecs);
+
+ jabber_iq_send(iq);
+
+ if (is_initiator) {
+ google_session_send_candidates(media,
+ "google-voice", session->remote_jid,
+ session);
+ google_session_send_candidates(media,
+ "google-video", session->remote_jid,
+ session);
+ }
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+ G_CALLBACK(google_session_ready), session);
+ }
+}
+
+static void
+google_session_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+ gchar *sid, gchar *name, GoogleSession *session)
+{
+ if (sid == NULL && name == NULL) {
+ if (state == PURPLE_MEDIA_STATE_END) {
+ google_session_destroy(session);
+ }
+ }
+}
+
+static void
+google_session_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+ gchar *sid, gchar *name, gboolean local,
+ GoogleSession *session)
+{
+ if (sid != NULL || name != NULL)
+ return;
+
+ if (type == PURPLE_MEDIA_INFO_HANGUP) {
+ xmlnode *sess;
+ JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+ xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+ sess = google_session_create_xmlnode(session, "terminate");
+ xmlnode_insert_child(iq->node, sess);
+
+ jabber_iq_send(iq);
+ } else if (type == PURPLE_MEDIA_INFO_REJECT) {
+ xmlnode *sess;
+ JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
+
+ xmlnode_set_attrib(iq->node, "to", session->remote_jid);
+ sess = google_session_create_xmlnode(session, "reject");
+ xmlnode_insert_child(iq->node, sess);
+
+ jabber_iq_send(iq);
+ } else if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE) {
+ google_session_ready(session);
+ }
+}
+
+static GParameter *
+jabber_google_session_get_params(JabberStream *js, const gchar *relay_ip,
+ guint16 relay_udp, guint16 relay_tcp, guint16 relay_ssltcp,
+ const gchar *relay_username, const gchar *relay_password, guint *num)
+{
+ guint num_params;
+ GParameter *params =
+ jingle_get_params(js, relay_ip, relay_udp, relay_tcp, relay_ssltcp,
+ relay_username, relay_password, &num_params);
+ GParameter *new_params = g_new0(GParameter, num_params + 1);
+
+ memcpy(new_params, params, sizeof(GParameter) * num_params);
+
+ purple_debug_info("jabber", "setting Google jingle compatibility param\n");
+ new_params[num_params].name = "compatibility-mode";
+ g_value_init(&new_params[num_params].value, G_TYPE_UINT);
+ g_value_set_uint(&new_params[num_params].value, 1); /* NICE_COMPATIBILITY_GOOGLE */
+
+ g_free(params);
+ *num = num_params + 1;
+ return new_params;
+}
+
+
+static void
+jabber_google_relay_response_session_initiate_cb(GoogleSession *session,
+ const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+ const gchar *relay_username, const gchar *relay_password)
+{
+ GParameter *params;
+ guint num_params;
+ JabberStream *js = session->js;
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+
+ session_data->media = purple_media_manager_create_media(
+ purple_media_manager_get(),
+ purple_connection_get_account(js->gc),
+ "fsrtpconference", session->remote_jid, TRUE);
+
+ purple_media_set_prpl_data(session_data->media, session);
+
+ g_signal_connect_swapped(G_OBJECT(session_data->media),
+ "candidates-prepared",
+ G_CALLBACK(google_session_ready), session);
+ g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed",
+ G_CALLBACK(google_session_ready), session);
+ g_signal_connect(G_OBJECT(session_data->media), "state-changed",
+ G_CALLBACK(google_session_state_changed_cb), session);
+ g_signal_connect(G_OBJECT(session_data->media), "stream-info",
+ G_CALLBACK(google_session_stream_info_cb), session);
+
+ params =
+ jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp,
+ relay_ssltcp, relay_username, relay_password, &num_params);
+
+ if (purple_media_add_stream(session_data->media, "google-voice",
+ session->remote_jid, PURPLE_MEDIA_AUDIO,
+ TRUE, "nice", num_params, params) == FALSE ||
+ (session_data->video && purple_media_add_stream(
+ session_data->media, "google-video",
+ session->remote_jid, PURPLE_MEDIA_VIDEO,
+ TRUE, "nice", num_params, params) == FALSE)) {
+ purple_media_error(session_data->media, "Error adding stream.");
+ purple_media_end(session_data->media, NULL, NULL);
+ g_free(params);
+ } else {
+ session_data->added_streams = TRUE;
+ }
+
+ g_free(params);
+}
+
+
+gboolean
+jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type)
+{
+ GoogleSession *session;
+ JabberBuddy *jb;
+ JabberBuddyResource *jbr;
+ gchar *jid;
+ GoogleAVSessionData *session_data = NULL;
+
+ /* construct JID to send to */
+ jb = jabber_buddy_find(js, who, FALSE);
+ if (!jb) {
+ purple_debug_error("jingle-rtp",
+ "Could not find Jabber buddy\n");
+ return FALSE;
+ }
+ jbr = jabber_buddy_find_resource(jb, NULL);
+ if (!jbr) {
+ purple_debug_error("jingle-rtp",
+ "Could not find buddy's resource\n");
+ }
+
+ if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
+ jid = g_strdup_printf("%s/%s", who, jbr->name);
+ } else {
+ jid = g_strdup(who);
+ }
+
+ session = g_new0(GoogleSession, 1);
+ session->id.id = jabber_get_next_id(js);
+ session->id.initiator = g_strdup_printf("%s@%s/%s", js->user->node,
+ js->user->domain, js->user->resource);
+ session->state = SENT_INITIATE;
+ session->js = js;
+ session->remote_jid = jid;
+ session_data = g_new0(GoogleAVSessionData, 1);
+ session->session_data = session_data;
+
+ if (type & PURPLE_MEDIA_VIDEO)
+ session_data->video = TRUE;
+
+ /* if we got a relay token and relay host in google:jingleinfo, issue an
+ HTTP request to get that data */
+ if (js->google_relay_host && js->google_relay_token) {
+ jabber_google_do_relay_request(js, session,
+ jabber_google_relay_response_session_initiate_cb);
+ } else {
+ jabber_google_relay_response_session_initiate_cb(session, NULL, 0, 0, 0,
+ NULL, NULL);
+ }
+
+ /* we don't actually know yet wether it succeeded... maybe this is very
+ wrong... */
+ return TRUE;
+}
+
+static void
+jabber_google_relay_response_session_handle_initiate_cb(GoogleSession *session,
+ const gchar *relay_ip, guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+ const gchar *relay_username, const gchar *relay_password)
+{
+ GParameter *params;
+ guint num_params;
+ JabberStream *js = session->js;
+ xmlnode *codec_element;
+ xmlnode *desc_element;
+ const gchar *xmlns;
+ PurpleMediaCodec *codec;
+ GList *video_codecs = NULL;
+ GList *codecs = NULL;
+ JabberIq *result;
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+
+ params =
+ jabber_google_session_get_params(js, relay_ip, relay_udp, relay_tcp,
+ relay_ssltcp, relay_username, relay_password, &num_params);
+
+ if (purple_media_add_stream(session_data->media, "google-voice",
+ session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE,
+ "nice", num_params, params) == FALSE ||
+ (session_data->video && purple_media_add_stream(
+ session_data->media, "google-video",
+ session->remote_jid, PURPLE_MEDIA_VIDEO,
+ FALSE, "nice", num_params, params) == FALSE)) {
+ purple_media_error(session_data->media, "Error adding stream.");
+ purple_media_stream_info(session_data->media,
+ PURPLE_MEDIA_INFO_REJECT, NULL, NULL, TRUE);
+ } else {
+ /* successfully added stream(s) */
+ session_data->added_streams = TRUE;
+
+ if (session_data->remote_audio_candidates) {
+ purple_media_add_remote_candidates(session_data->media,
+ "google-voice", session->remote_jid,
+ session_data->remote_audio_candidates);
+ purple_media_candidate_list_free(session_data->remote_audio_candidates);
+ session_data->remote_audio_candidates = NULL;
+ }
+ if (session_data->remote_video_candidates) {
+ purple_media_add_remote_candidates(session_data->media,
+ "google-video", session->remote_jid,
+ session_data->remote_video_candidates);
+ purple_media_candidate_list_free(session_data->remote_video_candidates);
+ session_data->remote_video_candidates = NULL;
+ }
+ }
+
+ g_free(params);
+
+ for (codec_element = xmlnode_get_child(desc_element, "payload-type");
+ codec_element; codec_element = codec_element->next) {
+ const char *id, *encoding_name, *clock_rate,
+ *width, *height, *framerate;
+ gboolean video;
+ if (codec_element->name &&
+ strcmp(codec_element->name, "payload-type"))
+ continue;
+
+ xmlns = xmlnode_get_namespace(codec_element);
+ encoding_name = xmlnode_get_attrib(codec_element, "name");
+ id = xmlnode_get_attrib(codec_element, "id");
+
+ if (!session_data->video ||
+ (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_PHONE))) {
+ clock_rate = xmlnode_get_attrib(
+ codec_element, "clockrate");
+ video = FALSE;
+ } else {
+ width = xmlnode_get_attrib(codec_element, "width");
+ height = xmlnode_get_attrib(codec_element, "height");
+ framerate = xmlnode_get_attrib(
+ codec_element, "framerate");
+ clock_rate = "90000";
+ video = TRUE;
+ }
+
+ if (id) {
+ codec = purple_media_codec_new(atoi(id), encoding_name,
+ video ? PURPLE_MEDIA_VIDEO :
+ PURPLE_MEDIA_AUDIO,
+ clock_rate ? atoi(clock_rate) : 0);
+ if (video)
+ video_codecs = g_list_append(
+ video_codecs, codec);
+ else
+ codecs = g_list_append(codecs, codec);
+ }
+ }
+
+ if (codecs)
+ purple_media_set_remote_codecs(session_data->media, "google-voice",
+ session->remote_jid, codecs);
+ if (video_codecs)
+ purple_media_set_remote_codecs(session_data->media, "google-video",
+ session->remote_jid, video_codecs);
+
+ purple_media_codec_list_free(codecs);
+ purple_media_codec_list_free(video_codecs);
+
+ result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ jabber_iq_set_id(result, session->iq_id);
+ xmlnode_set_attrib(result->node, "to", session->remote_jid);
+ jabber_iq_send(result);
+}
+
+static gboolean
+google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+ xmlnode *desc_element;
+ const gchar *xmlns;
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+
+ if (session->state != UNINIT) {
+ purple_debug_error("jabber", "Received initiate for active session.\n");
+ return FALSE;
+ }
+
+ desc_element = xmlnode_get_child(sess, "description");
+ xmlns = xmlnode_get_namespace(desc_element);
+
+ if (purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
+ session_data->video = FALSE;
+ else if (purple_strequal(xmlns, NS_GOOGLE_SESSION_VIDEO))
+ session_data->video = TRUE;
+ else {
+ purple_debug_error("jabber", "Received initiate with "
+ "invalid namespace %s.\n", xmlns);
+ return FALSE;
+ }
+
+ session_data->media = purple_media_manager_create_media(
+ purple_media_manager_get(),
+ purple_connection_get_account(js->gc),
+ "fsrtpconference", session->remote_jid, FALSE);
+
+ purple_media_set_prpl_data(session_data->media, session);
+
+ g_signal_connect_swapped(G_OBJECT(session_data->media),
+ "candidates-prepared",
+ G_CALLBACK(google_session_ready), session);
+ g_signal_connect_swapped(G_OBJECT(session_data->media), "codecs-changed",
+ G_CALLBACK(google_session_ready), session);
+ g_signal_connect(G_OBJECT(session_data->media), "state-changed",
+ G_CALLBACK(google_session_state_changed_cb), session);
+ g_signal_connect(G_OBJECT(session_data->media), "stream-info",
+ G_CALLBACK(google_session_stream_info_cb), session);
+
+ session->iq_id = g_strdup(iq_id);
+
+ if (js->google_relay_host && js->google_relay_token) {
+ jabber_google_do_relay_request(js, session,
+ jabber_google_relay_response_session_handle_initiate_cb);
+ } else {
+ jabber_google_relay_response_session_handle_initiate_cb(session, NULL,
+ 0, 0, 0, NULL, NULL);
+ }
+
+ return TRUE;
+}
+
+
+static void
+google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+ JabberIq *result;
+ GList *list = NULL, *video_list = NULL;
+ xmlnode *cand;
+ static int name = 0;
+ char n[4];
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+
+ for (cand = xmlnode_get_child(sess, "candidate"); cand;
+ cand = xmlnode_get_next_twin(cand)) {
+ PurpleMediaCandidate *info;
+ const gchar *cname = xmlnode_get_attrib(cand, "name");
+ const gchar *type = xmlnode_get_attrib(cand, "type");
+ const gchar *protocol = xmlnode_get_attrib(cand, "protocol");
+ const gchar *address = xmlnode_get_attrib(cand, "address");
+ const gchar *port = xmlnode_get_attrib(cand, "port");
+ const gchar *preference = xmlnode_get_attrib(cand, "preference");
+ guint component_id;
+
+ if (cname && type && address && port) {
+ PurpleMediaCandidateType candidate_type;
+ guint prio = preference ? atof(preference) * 1000 : 0;
+
+ g_snprintf(n, sizeof(n), "S%d", name++);
+
+ if (g_str_equal(type, "local"))
+ candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
+ else if (g_str_equal(type, "stun"))
+ candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX;
+ else if (g_str_equal(type, "relay"))
+ candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
+ else
+ candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
+
+ if (purple_strequal(cname, "rtcp") ||
+ purple_strequal(cname, "video_rtcp"))
+ component_id = PURPLE_MEDIA_COMPONENT_RTCP;
+ else
+ component_id = PURPLE_MEDIA_COMPONENT_RTP;
+
+ info = purple_media_candidate_new(n, component_id,
+ candidate_type,
+ purple_strequal(protocol, "udp") ?
+ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
+ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+ address,
+ atoi(port));
+ g_object_set(info, "username", xmlnode_get_attrib(cand, "username"),
+ "password", xmlnode_get_attrib(cand, "password"),
+ "priority", prio, NULL);
+ if (!strncmp(cname, "video_", 6)) {
+ if (session_data->added_streams) {
+ video_list = g_list_append(video_list, info);
+ } else {
+ session_data->remote_video_candidates =
+ g_list_append(session_data->remote_video_candidates,
+ info);
+ }
+ } else {
+ if (session_data->added_streams) {
+ list = g_list_append(list, info);
+ } else {
+ session_data->remote_audio_candidates =
+ g_list_append(session_data->remote_audio_candidates,
+ info);
+ }
+ }
+ }
+ }
+
+ if (list) {
+ purple_media_add_remote_candidates(session_data->media, "google-voice",
+ session->remote_jid, list);
+ purple_media_candidate_list_free(list);
+ }
+ if (video_list) {
+ purple_media_add_remote_candidates(session_data->media, "google-video",
+ session->remote_jid, video_list);
+ purple_media_candidate_list_free(video_list);
+ }
+
+ result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ jabber_iq_set_id(result, iq_id);
+ xmlnode_set_attrib(result->node, "to", session->remote_jid);
+ jabber_iq_send(result);
+}
+
+static void
+google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+ xmlnode *desc_element = xmlnode_get_child(sess, "description");
+ xmlnode *codec_element = xmlnode_get_child(
+ desc_element, "payload-type");
+ GList *codecs = NULL, *video_codecs = NULL;
+ JabberIq *result = NULL;
+ const gchar *xmlns = xmlnode_get_namespace(desc_element);
+ gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_SESSION_VIDEO));
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+
+ for (; codec_element; codec_element = codec_element->next) {
+ const gchar *xmlns, *encoding_name, *id,
+ *clock_rate, *width, *height, *framerate;
+ gboolean video_codec = FALSE;
+
+ if (!purple_strequal(codec_element->name, "payload-type"))
+ continue;
+
+ xmlns = xmlnode_get_namespace(codec_element);
+ encoding_name = xmlnode_get_attrib(codec_element, "name");
+ id = xmlnode_get_attrib(codec_element, "id");
+
+ if (!video || purple_strequal(xmlns, NS_GOOGLE_SESSION_PHONE))
+ clock_rate = xmlnode_get_attrib(
+ codec_element, "clockrate");
+ else {
+ clock_rate = "90000";
+ width = xmlnode_get_attrib(codec_element, "width");
+ height = xmlnode_get_attrib(codec_element, "height");
+ framerate = xmlnode_get_attrib(
+ codec_element, "framerate");
+ video_codec = TRUE;
+ }
+
+ if (id && encoding_name) {
+ PurpleMediaCodec *codec = purple_media_codec_new(
+ atoi(id), encoding_name,
+ video_codec ? PURPLE_MEDIA_VIDEO :
+ PURPLE_MEDIA_AUDIO,
+ clock_rate ? atoi(clock_rate) : 0);
+ if (video_codec)
+ video_codecs = g_list_append(
+ video_codecs, codec);
+ else
+ codecs = g_list_append(codecs, codec);
+ }
+ }
+
+ if (codecs)
+ purple_media_set_remote_codecs(session_data->media, "google-voice",
+ session->remote_jid, codecs);
+ if (video_codecs)
+ purple_media_set_remote_codecs(session_data->media, "google-video",
+ session->remote_jid, video_codecs);
+
+ purple_media_stream_info(session_data->media, PURPLE_MEDIA_INFO_ACCEPT,
+ NULL, NULL, FALSE);
+
+ result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ jabber_iq_set_id(result, iq_id);
+ xmlnode_set_attrib(result->node, "to", session->remote_jid);
+ jabber_iq_send(result);
+}
+
+static void
+google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess)
+{
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+ purple_media_end(session_data->media, NULL, NULL);
+}
+
+static void
+google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess)
+{
+ GoogleAVSessionData *session_data =
+ (GoogleAVSessionData *) session->session_data;
+ purple_media_end(session_data->media, NULL, NULL);
+}
+
+static void
+google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
+{
+ const char *type = xmlnode_get_attrib(sess, "type");
+
+ if (!strcmp(type, "initiate")) {
+ google_session_handle_initiate(js, session, sess, iq_id);
+ } else if (!strcmp(type, "accept")) {
+ google_session_handle_accept(js, session, sess, iq_id);
+ } else if (!strcmp(type, "reject")) {
+ google_session_handle_reject(js, session, sess);
+ } else if (!strcmp(type, "terminate")) {
+ google_session_handle_terminate(js, session, sess);
+ } else if (!strcmp(type, "candidates")) {
+ google_session_handle_candidates(js, session, sess, iq_id);
+ }
+}
+
+void
+jabber_google_session_parse(JabberStream *js, const char *from,
+ JabberIqType type, const char *iq_id,
+ xmlnode *session_node)
+{
+ GoogleSession *session = NULL;
+ GoogleSessionId id;
+
+ xmlnode *desc_node;
+
+ GList *iter = NULL;
+
+ if (type != JABBER_IQ_SET)
+ return;
+
+ id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
+ if (!id.id)
+ return;
+
+ id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
+ if (!id.initiator)
+ return;
+
+ iter = purple_media_manager_get_media_by_account(
+ purple_media_manager_get(),
+ purple_connection_get_account(js->gc));
+ for (; iter; iter = g_list_delete_link(iter, iter)) {
+ GoogleSession *gsession =
+ purple_media_get_prpl_data(iter->data);
+ if (google_session_id_equal(&(gsession->id), &id)) {
+ session = gsession;
+ break;
+ }
+ }
+ if (iter != NULL) {
+ g_list_free(iter);
+ }
+
+ if (session) {
+ google_session_parse_iq(js, session, session_node, iq_id);
+ return;
+ }
+
+ /* If the session doesn't exist, this has to be an initiate message */
+ if (strcmp(xmlnode_get_attrib(session_node, "type"), "initiate"))
+ return;
+ desc_node = xmlnode_get_child(session_node, "description");
+ if (!desc_node)
+ return;
+ session = g_new0(GoogleSession, 1);
+ session->id.id = g_strdup(id.id);
+ session->id.initiator = g_strdup(id.initiator);
+ session->state = UNINIT;
+ session->js = js;
+ session->remote_jid = g_strdup(session->id.initiator);
+ session->session_data = g_new0(GoogleAVSessionData, 1);
+
+ google_session_handle_initiate(js, session, session_node, iq_id);
+}
+#endif /* USE_VV */
+
+
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/google_session.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/google_session.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,54 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_SESSION_H_
+#define PURPLE_JABBER_GOOGLE_SESSION_H_
+
+#include "jabber.h"
+
+typedef struct {
+ char *id;
+ char *initiator;
+} GoogleSessionId;
+
+typedef enum {
+ UNINIT,
+ SENT_INITIATE,
+ RECEIVED_INITIATE,
+ IN_PRORESS,
+ TERMINATED
+} GoogleSessionState;
+
+typedef struct {
+ GoogleSessionId id;
+ GoogleSessionState state;
+ JabberStream *js;
+ char *remote_jid;
+ char *iq_id;
+ gpointer session_data;
+} GoogleSession;
+
+gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who,
+ PurpleMediaSessionType type);
+
+void jabber_google_session_parse(JabberStream *js, const char *from,
+ JabberIqType type, const char *iq, xmlnode *session);
+
+#endif /* PURPLE_JABBER_GOOGLE_SESSION_H_ */
\ No newline at end of file
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/jingleinfo.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/jingleinfo.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,174 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+#include "jingleinfo.h"
+
+static void
+jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
+ const char *error_message)
+{
+ JabberStream *js = (JabberStream *) data;
+
+ if (error_message) {
+ purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
+ error_message);
+ g_slist_free(hosts);
+ js->stun_query = NULL;
+ return;
+ }
+
+ if (hosts && g_slist_next(hosts)) {
+ struct sockaddr *addr = g_slist_next(hosts)->data;
+ char dst[INET6_ADDRSTRLEN];
+ int port;
+
+ if (addr->sa_family == AF_INET6) {
+ inet_ntop(addr->sa_family, &((struct sockaddr_in6 *) addr)->sin6_addr,
+ dst, sizeof(dst));
+ port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
+ } else {
+ inet_ntop(addr->sa_family, &((struct sockaddr_in *) addr)->sin_addr,
+ dst, sizeof(dst));
+ port = ntohs(((struct sockaddr_in *) addr)->sin_port);
+ }
+
+ if (js->stun_ip)
+ g_free(js->stun_ip);
+ js->stun_ip = g_strdup(dst);
+ js->stun_port = port;
+
+ purple_debug_info("jabber", "set Google STUN IP/port address: "
+ "%s:%d\n", dst, port);
+
+ /* unmark ongoing query */
+ js->stun_query = NULL;
+ }
+
+ while (hosts != NULL) {
+ hosts = g_slist_delete_link(hosts, hosts);
+ /* Free the address */
+ g_free(hosts->data);
+ hosts = g_slist_delete_link(hosts, hosts);
+ }
+}
+
+static void
+jabber_google_jingle_info_common(JabberStream *js, const char *from,
+ JabberIqType type, xmlnode *query)
+{
+ const xmlnode *stun = xmlnode_get_child(query, "stun");
+ const xmlnode *relay = xmlnode_get_child(query, "relay");
+ gchar *my_bare_jid;
+
+ /*
+ * Make sure that random people aren't sending us STUN servers. Per
+ * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these
+ * stanzas are stamped from our bare JID.
+ */
+ if (from) {
+ my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
+ if (!purple_strequal(from, my_bare_jid)) {
+ purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n",
+ from);
+ g_free(my_bare_jid);
+ return;
+ }
+
+ g_free(my_bare_jid);
+ }
+
+ if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET)
+ return;
+
+ purple_debug_info("jabber", "got google:jingleinfo\n");
+
+ if (stun) {
+ xmlnode *server = xmlnode_get_child(stun, "server");
+
+ if (server) {
+ const gchar *host = xmlnode_get_attrib(server, "host");
+ const gchar *udp = xmlnode_get_attrib(server, "udp");
+
+ if (host && udp) {
+ int port = atoi(udp);
+ /* if there, would already be an ongoing query,
+ cancel it */
+ if (js->stun_query)
+ purple_dnsquery_destroy(js->stun_query);
+
+ js->stun_query = purple_dnsquery_a(host, port,
+ jabber_google_stun_lookup_cb, js);
+ }
+ }
+ }
+
+ if (relay) {
+ xmlnode *token = xmlnode_get_child(relay, "token");
+ xmlnode *server = xmlnode_get_child(relay, "server");
+
+ if (token) {
+ gchar *relay_token = xmlnode_get_data(token);
+
+ /* we let js own the string returned from xmlnode_get_data */
+ js->google_relay_token = relay_token;
+ }
+
+ if (server) {
+ js->google_relay_host =
+ g_strdup(xmlnode_get_attrib(server, "host"));
+ }
+ }
+}
+
+static void
+jabber_google_jingle_info_cb(JabberStream *js, const char *from,
+ JabberIqType type, const char *id,
+ xmlnode *packet, gpointer data)
+{
+ xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
+ NS_GOOGLE_JINGLE_INFO);
+
+ if (query)
+ jabber_google_jingle_info_common(js, from, type, query);
+ else
+ purple_debug_warning("jabber", "Got invalid google:jingleinfo\n");
+}
+
+void
+jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+ JabberIqType type, const char *id,
+ xmlnode *child)
+{
+ jabber_google_jingle_info_common(js, from, type, child);
+}
+
+void
+jabber_google_send_jingle_info(JabberStream *js)
+{
+ JabberIq *jingle_info =
+ jabber_iq_new_query(js, JABBER_IQ_GET, NS_GOOGLE_JINGLE_INFO);
+
+ jabber_iq_set_callback(jingle_info, jabber_google_jingle_info_cb,
+ NULL);
+ purple_debug_info("jabber", "sending google:jingleinfo query\n");
+ jabber_iq_send(jingle_info);
+}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/jingleinfo.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/jingleinfo.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,32 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef PURPLE_JABBER_GOOGLE_ROSTER_H_
+#define PURPLE_JABBER_GOOGLE_ROSTER_H_
+
+#include "jabber.h"
+
+void jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+ JabberIqType type, const char *id,
+ xmlnode *child);
+void jabber_google_send_jingle_info(JabberStream *js);
+
+
+#endif /* PURPLE_JABBER_GOOGLE_ROSTER_H_ */
\ No newline at end of file
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/relay.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/relay.c Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,151 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "debug.h"
+
+#include "relay.h"
+
+typedef struct {
+ GoogleSession *session;
+ JabberGoogleRelayCallback *cb;
+} JabberGoogleRelayCallbackData;
+
+static void
+jabber_google_relay_parse_response(const gchar *response, gchar **ip,
+ guint *udp, guint *tcp, guint *ssltcp, gchar **username, gchar **password)
+{
+ gchar **lines = g_strsplit(response, "\n", -1);
+ int i = 0;
+
+ for (; lines[i] ; i++) {
+ gchar *line = lines[i];
+ gchar **parts = g_strsplit(line, "=", 2);
+
+ if (parts[0] && parts[1]) {
+ if (purple_strequal(parts[0], "relay.ip")) {
+ *ip = g_strdup(parts[1]);
+ } else if (purple_strequal(parts[0], "relay.udp_port")) {
+ *udp = atoi(parts[1]);
+ } else if (purple_strequal(parts[0], "relay.tcp_port")) {
+ *tcp = atoi(parts[1]);
+ } else if (purple_strequal(parts[0], "relay.ssltcp_port")) {
+ *ssltcp = atoi(parts[1]);
+ } else if (purple_strequal(parts[0], "username")) {
+ *username = g_strdup(parts[1]);
+ } else if (purple_strequal(parts[0], "password")) {
+ *password = g_strdup(parts[1]);
+ }
+ }
+ g_strfreev(parts);
+ }
+
+ g_strfreev(lines);
+}
+
+static void
+jabber_google_relay_remove_url_data(JabberStream *js,
+ PurpleUtilFetchUrlData *url_data)
+{
+ GList *iter = js->google_relay_requests;
+
+ while (iter) {
+ if (iter->data == url_data) {
+ js->google_relay_requests =
+ g_list_delete_link(js->google_relay_requests, iter);
+ break;
+ }
+ }
+}
+
+static void
+jabber_google_relay_fetch_cb(PurpleUtilFetchUrlData *url_data,
+ gpointer user_data, const gchar *url_text, gsize len,
+ const gchar *error_message)
+{
+ JabberGoogleRelayCallbackData *data =
+ (JabberGoogleRelayCallbackData *) user_data;
+ GoogleSession *session = data->session;
+ JabberStream *js = session->js;
+ JabberGoogleRelayCallback *cb = data->cb;
+ gchar *relay_ip = NULL;
+ guint relay_udp = 0;
+ guint relay_tcp = 0;
+ guint relay_ssltcp = 0;
+ gchar *relay_username = NULL;
+ gchar *relay_password = NULL;
+
+ g_free(data);
+
+ if (url_data) {
+ jabber_google_relay_remove_url_data(js, url_data);
+ }
+
+ purple_debug_info("jabber", "got response on HTTP request to relay server\n");
+
+ if (url_text && len > 0) {
+ purple_debug_info("jabber", "got Google relay request response:\n%s\n",
+ url_text);
+ jabber_google_relay_parse_response(url_text, &relay_ip, &relay_udp,
+ &relay_tcp, &relay_ssltcp, &relay_username, &relay_password);
+ }
+
+ if (cb)
+ cb(session, relay_ip, relay_udp, relay_tcp, relay_ssltcp,
+ relay_username, relay_password);
+
+ g_free(relay_ip);
+ g_free(relay_username);
+ g_free(relay_password);
+}
+
+void
+jabber_google_do_relay_request(JabberStream *js, GoogleSession *session,
+ JabberGoogleRelayCallback cb)
+{
+ PurpleUtilFetchUrlData *url_data = NULL;
+ gchar *url = g_strdup_printf("http://%s", js->google_relay_host);
+ /* yes, the relay token is included twice as different request headers,
+ this is apparently needed to make Google's relay servers work... */
+ gchar *request =
+ g_strdup_printf("GET /create_session HTTP/1.0\r\n"
+ "Host: %s\r\n"
+ "X-Talk-Google-Relay-Auth: %s\r\n"
+ "X-Google-Relay-Auth: %s\r\n\r\n",
+ js->google_relay_host, js->google_relay_token, js->google_relay_token);
+ JabberGoogleRelayCallbackData *data = g_new0(JabberGoogleRelayCallbackData, 1);
+
+ data->session = session;
+ data->cb = cb;
+ purple_debug_info("jabber",
+ "sending Google relay request %s to %s\n", request, url);
+ url_data =
+ purple_util_fetch_url_request(url, FALSE, NULL, FALSE, request, FALSE,
+ jabber_google_relay_fetch_cb, data);
+ if (url_data) {
+ js->google_relay_requests =
+ g_list_prepend(js->google_relay_requests, url_data);
+ } else {
+ purple_debug_error("jabber", "unable to create Google relay request\n");
+ jabber_google_relay_fetch_cb(NULL, data, NULL, 0, NULL);
+ }
+ g_free(url);
+ g_free(request);
+}
\ No newline at end of file
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/google/relay.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/google/relay.h Sat Sep 11 19:03:25 2010 +0000
@@ -0,0 +1,33 @@
+/**
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#ifndef JABBER_GOOGLE_RELAY
+#define JABBER_GOOGLE_RELAY
+
+#include "google_session.h"
+
+typedef void (JabberGoogleRelayCallback)(GoogleSession *session, const gchar *ip,
+ guint udp_port, guint tcp_port, guint tls_port,
+ const gchar *username, const gchar *password);
+
+void jabber_google_do_relay_request(JabberStream *js, GoogleSession *session,
+ JabberGoogleRelayCallback cb);
+
+#endif /* JABBER_GOOGLE_RELAY */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/iq.c
--- a/libpurple/protocols/jabber/iq.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/iq.c Sat Sep 11 19:03:25 2010 +0000
@@ -28,7 +28,10 @@
#include "buddy.h"
#include "disco.h"
-#include "google.h"
+#include "google/gmail.h"
+#include "google/google.h"
+#include "google/jingleinfo.h"
+#include "google/google_session.h"
#include "iq.h"
#include "jingle/jingle.h"
#include "oob.h"
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c Sat Sep 11 19:03:25 2010 +0000
@@ -51,7 +51,9 @@
#include "chat.h"
#include "data.h"
#include "disco.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_roster.h"
+#include "google/google_session.h"
#include "ibb.h"
#include "iq.h"
#include "jutil.h"
@@ -205,7 +207,7 @@
* resource string from being unreasonably long on systems which stuff the
* whole FQDN in the hostname */
if((dot = strchr(hostname, '.')))
- dot = '\0';
+ *dot = '\0';
return purple_strreplace(input, "__HOSTNAME__", hostname);
}
@@ -232,7 +234,7 @@
return TRUE;
}
- if(purple_account_get_bool(account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS)) {
+ if (g_str_equal("require_tls", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
purple_connection_error_reason(js->gc,
PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
_("You require encryption, but no TLS/SSL support was found."));
@@ -244,12 +246,16 @@
void jabber_stream_features_parse(JabberStream *js, xmlnode *packet)
{
- if(xmlnode_get_child(packet, "starttls")) {
- if(jabber_process_starttls(js, packet)) {
+ PurpleAccount *account = purple_connection_get_account(js->gc);
+ const char *connection_security =
+ purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS);
+
+ if (xmlnode_get_child(packet, "starttls")) {
+ if (jabber_process_starttls(js, packet)) {
jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION);
return;
}
- } else if(purple_account_get_bool(js->gc->account, "require_tls", JABBER_DEFAULT_REQUIRE_TLS) && !jabber_stream_is_ssl(js)) {
+ } else if (g_str_equal(connection_security, "require_tls") && !jabber_stream_is_ssl(js)) {
purple_connection_error_reason(js->gc,
PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
_("You require encryption, but it is not available on this server."));
@@ -567,8 +573,7 @@
if (NULL == packet)
return;
- if (!PURPLE_CONNECTION_IS_VALID(pc))
- return;
+ g_return_if_fail(PURPLE_CONNECTION_IS_VALID(pc));
js = purple_connection_get_protocol_data(pc);
@@ -625,7 +630,7 @@
/* TODO: It should be possible to make this check unnecessary */
if(!PURPLE_CONNECTION_IS_VALID(gc)) {
purple_ssl_close(gsc);
- return;
+ g_return_if_reached();
}
while((len = purple_ssl_read(gsc, buf, sizeof(buf) - 1)) > 0) {
@@ -660,8 +665,7 @@
int len;
static char buf[4096];
- if(!PURPLE_CONNECTION_IS_VALID(gc))
- return;
+ g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
if((len = read(js->fd, buf, sizeof(buf) - 1)) > 0) {
gc->last_received = time(NULL);
@@ -721,7 +725,7 @@
/* TODO: It should be possible to make this check unnecessary */
if(!PURPLE_CONNECTION_IS_VALID(gc)) {
purple_ssl_close(gsc);
- return;
+ g_return_if_reached();
}
js = gc->proto_data;
@@ -816,8 +820,7 @@
JabberStream *js;
/* If the connection is already disconnected, we don't need to do anything else */
- if(!PURPLE_CONNECTION_IS_VALID(gc))
- return;
+ g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc));
js = gc->proto_data;
js->gsc = NULL;
@@ -975,6 +978,9 @@
js->stun_ip = NULL;
js->stun_port = 0;
js->stun_query = NULL;
+ js->google_relay_token = NULL;
+ js->google_relay_host = NULL;
+ js->google_relay_requests = NULL;
/* if we are idle, set idle-ness on the stream (this could happen if we get
disconnected and the reconnects while being idle. I don't think it makes
@@ -1017,7 +1023,7 @@
js->certificate_CN = g_strdup(connect_server[0] ? connect_server : js->user->domain);
/* if they've got old-ssl mode going, we probably want to ignore SRV lookups */
- if(purple_account_get_bool(account, "old_ssl", FALSE)) {
+ if (g_str_equal("old_ssl", purple_account_get_string(account, "connection_security", JABBER_DEFAULT_REQUIRE_TLS))) {
if(purple_ssl_is_supported()) {
js->gsc = purple_ssl_connect(account, js->certificate_CN,
purple_account_get_int(account, "port", 5223),
@@ -1634,6 +1640,8 @@
if(js->sasl_mechs)
g_string_free(js->sasl_mechs, TRUE);
g_free(js->sasl_cb);
+ /* Note: _not_ g_free. See auth_cyrus.c:jabber_sasl_cb_secret */
+ free(js->sasl_secret);
#endif
g_free(js->serverFQDN);
while(js->commands) {
@@ -1676,6 +1684,21 @@
js->stun_query = NULL;
}
+ /* remove Google relay-related stuff */
+ g_free(js->google_relay_token);
+ g_free(js->google_relay_host);
+ if (js->google_relay_requests) {
+ while (js->google_relay_requests) {
+ PurpleUtilFetchUrlData *url_data =
+ (PurpleUtilFetchUrlData *) js->google_relay_requests->data;
+ purple_util_fetch_url_cancel(url_data);
+ g_free(url_data);
+ js->google_relay_requests =
+ g_list_delete_link(js->google_relay_requests,
+ js->google_relay_requests);
+ }
+ }
+
g_free(js);
gc->proto_data = NULL;
@@ -3232,9 +3255,9 @@
g_free(resource);
if (type & PURPLE_MEDIA_AUDIO &&
- !jabber_resource_has_capability(jbr,
- JINGLE_APP_RTP_SUPPORT_AUDIO) &&
- jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE))
+ !jabber_resource_has_capability(jbr,
+ JINGLE_APP_RTP_SUPPORT_AUDIO) &&
+ jabber_resource_has_capability(jbr, NS_GOOGLE_VOICE))
return jabber_google_session_initiate(js, who, type);
else
return jingle_rtp_initiate_media(js, who, type);
@@ -3496,7 +3519,7 @@
if (js->pep) {
/* if no argument was given, unset mood */
- if (!args | !args[0]) {
+ if (!args || !args[0]) {
jabber_mood_set(js, NULL, NULL);
} else if (!args[1]) {
jabber_mood_set(js, args[0], NULL);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jabber.h
--- a/libpurple/protocols/jabber/jabber.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.h Sat Sep 11 19:03:25 2010 +0000
@@ -80,7 +80,7 @@
#define CAPS0115_NODE "http://pidgin.im/"
-#define JABBER_DEFAULT_REQUIRE_TLS TRUE
+#define JABBER_DEFAULT_REQUIRE_TLS "require_starttls"
#define JABBER_DEFAULT_FT_PROXIES "proxy.eu.jabber.org"
/* Index into attention_types list */
@@ -206,6 +206,7 @@
#ifdef HAVE_CYRUS_SASL
sasl_conn_t *sasl;
sasl_callback_t *sasl_cb;
+ sasl_secret_t *sasl_secret;
const char *current_mech;
int auth_fail_count;
@@ -275,7 +276,12 @@
gchar *stun_ip;
int stun_port;
PurpleDnsQueryData *stun_query;
- /* later add stuff to handle TURN relays... */
+
+ /* stuff for Google's relay handling */
+ gchar *google_relay_token;
+ gchar *google_relay_host;
+ GList *google_relay_requests; /* the HTTP requests to get */
+ /* relay info */
};
typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jingle/jingle.c
--- a/libpurple/protocols/jabber/jingle/jingle.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.c Sat Sep 11 19:03:25 2010 +0000
@@ -35,6 +35,9 @@
#include "rtp.h"
#include
+#ifdef USE_VV
+#include
+#endif
GType
jingle_get_type(const gchar *type)
@@ -431,32 +434,91 @@
jingle_terminate_sessions_gh, NULL);
}
+#ifdef USE_VV
+static GValueArray *
+jingle_create_relay_info(const gchar *ip, guint port, const gchar *username,
+ const gchar *password, const gchar *relay_type, GValueArray *relay_info)
+{
+ GValue value;
+ GstStructure *turn_setup = gst_structure_new("relay-info",
+ "ip", G_TYPE_STRING, ip,
+ "port", G_TYPE_UINT, port,
+ "username", G_TYPE_STRING, username,
+ "password", G_TYPE_STRING, password,
+ "relay-type", G_TYPE_STRING, relay_type,
+ NULL);
+ purple_debug_info("jabber", "created gst_structure %" GST_PTR_FORMAT "\n",
+ turn_setup);
+ if (turn_setup) {
+ memset(&value, 0, sizeof(GValue));
+ g_value_init(&value, GST_TYPE_STRUCTURE);
+ gst_value_set_structure(&value, turn_setup);
+ relay_info = g_value_array_append(relay_info, &value);
+ gst_structure_free(turn_setup);
+ }
+ return relay_info;
+}
+
GParameter *
-jingle_get_params(JabberStream *js, guint *num)
+jingle_get_params(JabberStream *js, const gchar *relay_ip, guint relay_udp,
+ guint relay_tcp, guint relay_ssltcp, const gchar *relay_username,
+ const gchar *relay_password, guint *num)
{
/* don't set a STUN server if one is set globally in prefs, in that case
this will be handled in media.c */
gboolean has_account_stun = js->stun_ip && !purple_network_get_stun_ip();
- guint num_params = has_account_stun ? 2 : 0;
+ guint num_params = has_account_stun ?
+ (relay_ip ? 3 : 2) : (relay_ip ? 1 : 0);
GParameter *params = NULL;
-
+ int next_index = 0;
+
if (num_params > 0) {
params = g_new0(GParameter, num_params);
- purple_debug_info("jabber",
- "setting param stun-ip for stream using auto-discovered IP: %s\n",
- js->stun_ip);
- params[0].name = "stun-ip";
- g_value_init(¶ms[0].value, G_TYPE_STRING);
- g_value_set_string(¶ms[0].value, js->stun_ip);
- purple_debug_info("jabber",
- "setting param stun-port for stream using auto-discovered port: %d\n",
- js->stun_port);
- params[1].name = "stun-port";
- g_value_init(¶ms[1].value, G_TYPE_UINT);
- g_value_set_uint(¶ms[1].value, js->stun_port);
+ if (has_account_stun) {
+ purple_debug_info("jabber",
+ "setting param stun-ip for stream using Google auto-config: %s\n",
+ js->stun_ip);
+ params[next_index].name = "stun-ip";
+ g_value_init(¶ms[next_index].value, G_TYPE_STRING);
+ g_value_set_string(¶ms[next_index].value, js->stun_ip);
+ purple_debug_info("jabber",
+ "setting param stun-port for stream using Google auto-config: %d\n",
+ js->stun_port);
+ next_index++;
+ params[next_index].name = "stun-port";
+ g_value_init(¶ms[next_index].value, G_TYPE_UINT);
+ g_value_set_uint(¶ms[next_index].value, js->stun_port);
+ next_index++;
+ }
+
+ if (relay_ip) {
+ GValueArray *relay_info = g_value_array_new(0);
+
+ if (relay_udp) {
+ relay_info =
+ jingle_create_relay_info(relay_ip, relay_udp, relay_username,
+ relay_password, "udp", relay_info);
+ }
+ if (relay_tcp) {
+ relay_info =
+ jingle_create_relay_info(relay_ip, relay_tcp, relay_username,
+ relay_password, "tcp", relay_info);
+ }
+ if (relay_ssltcp) {
+ relay_info =
+ jingle_create_relay_info(relay_ip, relay_ssltcp, relay_username,
+ relay_password, "tls", relay_info);
+ }
+ params[next_index].name = "relay-info";
+ g_value_init(¶ms[next_index].value, G_TYPE_VALUE_ARRAY);
+ g_value_set_boxed(¶ms[next_index].value, relay_info);
+ g_value_array_free(relay_info);
+ }
}
*num = num_params;
return params;
}
+#endif
+
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jingle/jingle.h
--- a/libpurple/protocols/jabber/jingle/jingle.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.h Sat Sep 11 19:03:25 2010 +0000
@@ -78,9 +78,13 @@
void jingle_terminate_sessions(JabberStream *js);
+#ifdef USE_VV
/* create a GParam array given autoconfigured STUN (and later perhaps TURN).
if google_talk is TRUE, set compatability mode to GOOGLE_TALK */
-GParameter *jingle_get_params(JabberStream *js, guint *num_params);
+GParameter *jingle_get_params(JabberStream *js, const gchar *relay_ip,
+ guint relay_udp, guint relay_tcp, guint relay_ssltcp,
+ const gchar *relay_username, const gchar *relay_password, guint *num_params);
+#endif
#ifdef __cplusplus
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jingle/rtp.c
--- a/libpurple/protocols/jabber/jingle/rtp.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c Sat Sep 11 19:03:25 2010 +0000
@@ -611,7 +611,8 @@
: PURPLE_MEDIA_RECV_VIDEO;
params =
- jingle_get_params(jingle_session_get_js(session), &num_params);
+ jingle_get_params(jingle_session_get_js(session), NULL, 0, 0, 0,
+ NULL, NULL, &num_params);
creator = jingle_content_get_creator(content);
if (!strcmp(creator, "initiator"))
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/jingle/transport.c
--- a/libpurple/protocols/jabber/jingle/transport.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/jingle/transport.c Sat Sep 11 19:03:25 2010 +0000
@@ -111,8 +111,6 @@
JingleTransport *transport;
g_return_if_fail(JINGLE_IS_TRANSPORT(object));
- transport = JINGLE_TRANSPORT(object);
-
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -125,8 +123,6 @@
{
JingleTransport *transport;
g_return_if_fail(JINGLE_IS_TRANSPORT(object));
-
- transport = JINGLE_TRANSPORT(object);
switch (prop_id) {
default:
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/libxmpp.c
--- a/libpurple/protocols/jabber/libxmpp.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c Sat Sep 11 19:03:25 2010 +0000
@@ -41,7 +41,7 @@
#include "si.h"
#include "message.h"
#include "presence.h"
-#include "google.h"
+#include "google/google.h"
#include "pep.h"
#include "usermood.h"
#include "usertune.h"
@@ -253,6 +253,7 @@
{
PurpleAccountUserSplit *split;
PurpleAccountOption *option;
+ GList *encryption_values = NULL;
/* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */
split = purple_account_user_split_new(_("Domain"), NULL, '@');
@@ -263,13 +264,26 @@
purple_account_user_split_set_reverse(split, FALSE);
prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
- option = purple_account_option_bool_new(_("Require SSL/TLS"), "require_tls", JABBER_DEFAULT_REQUIRE_TLS);
- prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
- option);
+#define ADD_VALUE(list, desc, v) { \
+ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \
+ kvp->key = g_strdup((desc)); \
+ kvp->value = g_strdup((v)); \
+ list = g_list_prepend(list, kvp); \
+}
- option = purple_account_option_bool_new(_("Force old (port 5223) SSL"), "old_ssl", FALSE);
+ ADD_VALUE(encryption_values, _("Require encryption"), "require_tls");
+ ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls");
+ ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl");
+#if 0
+ ADD_VALUE(encryption_values, "None", "none");
+#endif
+ encryption_values = g_list_reverse(encryption_values);
+
+#undef ADD_VALUE
+
+ option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values);
prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
- option);
+ option);
option = purple_account_option_bool_new(
_("Allow plaintext auth over unencrypted streams"),
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/message.c
--- a/libpurple/protocols/jabber/message.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/message.c Sat Sep 11 19:03:25 2010 +0000
@@ -30,7 +30,7 @@
#include "buddy.h"
#include "chat.h"
#include "data.h"
-#include "google.h"
+#include "google/google.h"
#include "message.h"
#include "xmlnode.h"
#include "pep.h"
@@ -296,7 +296,6 @@
}
static void handle_buzz(JabberMessage *jm) {
- PurpleBuddy *buddy;
PurpleAccount *account;
/* Delayed buzz MUST NOT be accepted */
@@ -309,7 +308,7 @@
account = purple_connection_get_account(jm->js->gc);
- if ((buddy = purple_find_buddy(account, jm->from)) == NULL)
+ if (purple_find_buddy(account, jm->from) == NULL)
return; /* Do not accept buzzes from unknown people */
/* xmpp only has 1 attention type, so index is 0 */
@@ -587,8 +586,10 @@
jm->thread_id = xmlnode_get_data(child);
} else if(!strcmp(child->name, "body") && !strcmp(xmlns, NS_XMPP_CLIENT)) {
if(!jm->body) {
- char *msg = xmlnode_to_str(child, NULL);
- jm->body = purple_strdup_withhtml(msg);
+ char *msg = xmlnode_get_data(child);
+ char *escaped = purple_markup_escape_text(msg, -1);
+ jm->body = purple_strdup_withhtml(escaped);
+ g_free(escaped);
g_free(msg);
}
} else if(!strcmp(child->name, "html") && !strcmp(xmlns, NS_XHTML_IM)) {
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/oob.c
--- a/libpurple/protocols/jabber/oob.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/oob.c Sat Sep 11 19:03:25 2010 +0000
@@ -185,7 +185,7 @@
jabber_oob_xfer_recv_error(xfer, "406");
}
-static void jabber_oob_xfer_recv_canceled(PurpleXfer *xfer) {
+static void jabber_oob_xfer_recv_cancelled(PurpleXfer *xfer) {
jabber_oob_xfer_recv_error(xfer, "404");
}
@@ -233,7 +233,7 @@
purple_xfer_set_init_fnc(xfer, jabber_oob_xfer_init);
purple_xfer_set_end_fnc(xfer, jabber_oob_xfer_end);
purple_xfer_set_request_denied_fnc(xfer, jabber_oob_xfer_recv_denied);
- purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_canceled);
+ purple_xfer_set_cancel_recv_fnc(xfer, jabber_oob_xfer_recv_cancelled);
purple_xfer_set_read_fnc(xfer, jabber_oob_xfer_read);
purple_xfer_set_start_fnc(xfer, jabber_oob_xfer_start);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/parser.c
--- a/libpurple/protocols/jabber/parser.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/parser.c Sat Sep 11 19:03:25 2010 +0000
@@ -93,10 +93,25 @@
}
}
- if (js->stream_id == NULL)
+ if (js->stream_id == NULL) {
+#if 0
+ /* This was underspecified in rfc3920 as only being a SHOULD, so
+ * we cannot rely on it. See #12331 and Oracle's server.
+ */
purple_connection_error_reason(js->gc,
PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
_("XMPP stream missing ID"));
+#else
+ /* Instead, let's make up a placeholder stream ID, which we need
+ * to do because we flag on it being NULL as a special case
+ * in this parsing code.
+ */
+ js->stream_id = g_strdup("");
+ purple_debug_info("jabber", "Server failed to specify a stream "
+ "ID (underspecified in rfc3920, but intended "
+ "to be a MUST; digest legacy auth may fail.");
+#endif
+ }
} else {
if(js->current)
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/presence.c
--- a/libpurple/protocols/jabber/presence.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/presence.c Sat Sep 11 19:03:25 2010 +0000
@@ -34,7 +34,8 @@
#include "buddy.h"
#include "chat.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_presence.h"
#include "presence.h"
#include "iq.h"
#include "jutil.h"
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/roster.c
--- a/libpurple/protocols/jabber/roster.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/roster.c Sat Sep 11 19:03:25 2010 +0000
@@ -27,7 +27,8 @@
#include "buddy.h"
#include "chat.h"
-#include "google.h"
+#include "google/google.h"
+#include "google/google_roster.h"
#include "presence.h"
#include "roster.h"
#include "iq.h"
@@ -76,12 +77,9 @@
void jabber_roster_request(JabberStream *js)
{
- PurpleAccount *account;
JabberIq *iq;
xmlnode *query;
- account = purple_connection_get_account(js->gc);
-
iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster");
query = xmlnode_get_child(iq->node, "query");
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/jabber/si.c
--- a/libpurple/protocols/jabber/si.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/jabber/si.c Sat Sep 11 19:03:25 2010 +0000
@@ -1666,12 +1666,8 @@
void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file)
{
- JabberStream *js;
-
PurpleXfer *xfer;
- js = gc->proto_data;
-
xfer = jabber_si_new_xfer(gc, who);
if (file)
@@ -1734,7 +1730,7 @@
/* if they've already sent us this file transfer with the same damn id
* then we're gonna ignore it, until I think of something better to do
* with it */
- if((xfer = jabber_si_xfer_find(js, stream_id, from)))
+ if(jabber_si_xfer_find(js, stream_id, from) != NULL)
return;
jsx = g_new0(JabberSIXfer, 1);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/contact.c
--- a/libpurple/protocols/msn/contact.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/contact.c Sat Sep 11 19:03:25 2010 +0000
@@ -527,16 +527,20 @@
g_return_if_fail(session != NULL);
if (resp != NULL) {
+#ifdef MSN_PARTIAL_LISTS
const char *abLastChange;
const char *dynamicItemLastChange;
+#endif
purple_debug_misc("msn", "Got the contact list!\n");
msn_parse_contact_list(session, resp->xml);
+#ifdef MSN_PARTIAL_LISTS
abLastChange = purple_account_get_string(session->account,
"ablastChange", NULL);
dynamicItemLastChange = purple_account_get_string(session->account,
- "dynamicItemLastChange", NULL);
+ "DynamicItemLastChanged", NULL);
+#endif
if (state->partner_scenario == MSN_PS_INITIAL) {
#ifdef MSN_PARTIAL_LISTS
@@ -684,20 +688,20 @@
xmlnode *annotation;
MsnUser *user;
+ g_free(passport);
+ g_free(Name);
+ g_free(uid);
+ g_free(type);
+ g_free(mobile_number);
+ g_free(alias);
+ passport = Name = uid = type = mobile_number = alias = NULL;
+ mobile = FALSE;
+
if (!(contactId = xmlnode_get_child(contactNode,"contactId"))
|| !(contactInfo = xmlnode_get_child(contactNode, "contactInfo"))
|| !(contactType = xmlnode_get_child(contactInfo, "contactType")))
continue;
- g_free(passport);
- g_free(Name);
- g_free(alias);
- g_free(uid);
- g_free(type);
- g_free(mobile_number);
- passport = Name = uid = type = mobile_number = alias = NULL;
- mobile = FALSE;
-
uid = xmlnode_get_data(contactId);
type = xmlnode_get_data(contactType);
@@ -836,6 +840,7 @@
g_free(uid);
g_free(type);
g_free(mobile_number);
+ g_free(alias);
}
static gboolean
@@ -885,7 +890,7 @@
msn_parse_addressbook_groups(session, groups);
}
- /*add a default No group to set up the no group Membership*/
+ /* Add an "Other Contacts" group for buddies who aren't in a group */
msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID,
MSN_INDIVIDUALS_GROUP_NAME);
purple_debug_misc("msn", "AB group_id:%s name:%s\n",
@@ -895,7 +900,7 @@
purple_blist_add_group(g, NULL);
}
- /*add a default No group to set up the no group Membership*/
+ /* Add a "Non-IM Contacts" group */
msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
purple_debug_misc("msn", "AB group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME);
if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL) {
@@ -1564,7 +1569,7 @@
if (list == MSN_LIST_PL) {
partner_scenario = MSN_PS_CONTACT_API;
- if (user && user->networkid != MSN_NETWORK_PASSPORT)
+ if (user->networkid != MSN_NETWORK_PASSPORT)
member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML,
"EmailMember", "Email",
user->member_id_on_pending_list);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/directconn.h
--- a/libpurple/protocols/msn/directconn.h Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/directconn.h Sat Sep 11 19:03:25 2010 +0000
@@ -131,7 +131,7 @@
* Creates, initializes, and returns a new MsnDirectConn structure.
*/
MsnDirectConn *
-msn_dc_new(MsnSlpCall *slplink);
+msn_dc_new(MsnSlpCall *slpcall);
/*
* Destroys an MsnDirectConn structure. Frees every buffer allocated earlier
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/httpconn.c
--- a/libpurple/protocols/msn/httpconn.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/httpconn.c Sat Sep 11 19:03:25 2010 +0000
@@ -239,6 +239,9 @@
}
else
{
+ /* I'll be honest, I don't fully understand all this, but this
+ * causes crashes, Stu. */
+#if 0
MsnServConn *servconn;
/* It's going to die. */
@@ -246,10 +249,9 @@
servconn = httpconn->servconn;
- /* I'll be honest, I don't fully understand all this, but this
- * causes crashes, Stu. */
- /* if (servconn != NULL)
- servconn->wasted = TRUE; */
+ if (servconn != NULL)
+ servconn->wasted = TRUE;
+#endif
g_free(full_session_id);
g_free(session_id);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/msn.c
--- a/libpurple/protocols/msn/msn.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/msn.c Sat Sep 11 19:03:25 2010 +0000
@@ -728,7 +728,6 @@
{
PurpleBuddy *buddy;
PurpleConnection *gc;
- MsnSession *session;
MsnMobileData *data;
PurpleAccount *account;
const char *name;
@@ -740,8 +739,6 @@
gc = purple_account_get_connection(account);
name = purple_buddy_get_name(buddy);
- session = gc->proto_data;
-
data = g_new0(MsnMobileData, 1);
data->gc = gc;
data->passport = name;
@@ -2208,11 +2205,9 @@
msn_remove_group(PurpleConnection *gc, PurpleGroup *group)
{
MsnSession *session;
- MsnCmdProc *cmdproc;
const char *gname;
session = gc->proto_data;
- cmdproc = session->notification->cmdproc;
gname = purple_group_get_name(group);
purple_debug_info("msn", "Remove group %s\n", gname);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/msnutils.c
--- a/libpurple/protocols/msn/msnutils.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/msnutils.c Sat Sep 11 19:03:25 2010 +0000
@@ -539,7 +539,7 @@
chlStringParts = (unsigned int *)buf;
/* this is magic */
- for (i = 0; i < (strlen(buf) / 4); i += 2) {
+ for (i = 0; i < (len / 4); i += 2) {
long long temp;
chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/notification.c
--- a/libpurple/protocols/msn/notification.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/notification.c Sat Sep 11 19:03:25 2010 +0000
@@ -93,7 +93,6 @@
MsnCmdProc *cmdproc;
MsnSession *session;
MsnTransaction *trans;
- PurpleAccount *account;
GString *vers;
const char *ver_str;
int i;
@@ -102,7 +101,6 @@
cmdproc = servconn->cmdproc;
session = servconn->session;
- account = session->account;
vers = g_string_new("");
@@ -188,10 +186,8 @@
usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
MsnSession *session;
- PurpleAccount *account;
session = cmdproc->session;
- account = session->account;
if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
{
@@ -1020,7 +1016,6 @@
{
MsnSession *session;
PurpleAccount *account;
- PurpleConnection *gc;
MsnUser *user;
MsnObject *msnobj = NULL;
unsigned long clientid, extcaps;
@@ -1031,7 +1026,6 @@
session = cmdproc->session;
account = session->account;
- gc = purple_account_get_connection(account);
state = cmd->params[1];
passport = cmd->params[2];
@@ -1245,7 +1239,6 @@
{
MsnSession *session;
PurpleAccount *account;
- PurpleConnection *gc;
MsnUser *user;
MsnObject *msnobj;
unsigned long clientid, extcaps;
@@ -1255,7 +1248,6 @@
session = cmdproc->session;
account = session->account;
- gc = purple_account_get_connection(account);
state = cmd->params[0];
passport = cmd->params[1];
@@ -1439,11 +1431,13 @@
MsnSession *session;
MsnSwitchBoard *swboard;
const char *session_id;
+ const char *auth_key;
char *host;
int port;
session = cmdproc->session;
session_id = cmd->params[0];
+ auth_key = cmd->params[3];
msn_parse_socket(cmd->params[1], &host, &port);
@@ -1453,8 +1447,8 @@
swboard = msn_switchboard_new(session);
msn_switchboard_set_invited(swboard, TRUE);
- msn_switchboard_set_session_id(swboard, cmd->params[0]);
- msn_switchboard_set_auth_key(swboard, cmd->params[3]);
+ msn_switchboard_set_session_id(swboard, session_id);
+ msn_switchboard_set_auth_key(swboard, auth_key);
swboard->im_user = g_strdup(cmd->params[4]);
/* msn_switchboard_add_user(swboard, cmd->params[4]); */
@@ -1694,14 +1688,12 @@
size_t len)
{
MsnSession *session;
- PurpleAccount *account;
MsnUser *user;
const char *passport;
xmlnode *payloadNode;
char *psm_str, *str;
session = cmdproc->session;
- account = session->account;
passport = cmd->params[0];
if (g_str_equal(passport, session->user->passport))
@@ -1946,7 +1938,9 @@
{
MsnSession *session;
const char *value;
+#ifdef MSN_PARTIAL_LISTS
const char *clLastChange;
+#endif
session = cmdproc->session;
@@ -1989,9 +1983,9 @@
if ((value = msn_message_get_header_value(msg, "EmailEnabled")) != NULL)
session->passport_info.email_enabled = (gboolean)atol(value);
+#ifdef MSN_PARTIAL_LISTS
/*starting retrieve the contact list*/
clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL);
-#ifdef MSN_PARTIAL_LISTS
/* msn_userlist_load defeats all attempts at trying to detect blist sync issues */
msn_userlist_load(session);
msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange);
@@ -2195,7 +2189,7 @@
if ((type_s = g_hash_table_lookup(table, "Type")) != NULL)
{
int type = atoi(type_s);
- char buf[MSN_BUF_LEN];
+ char buf[MSN_BUF_LEN] = "";
int minutes;
switch (type)
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/session.c
--- a/libpurple/protocols/msn/session.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/session.c Sat Sep 11 19:03:25 2010 +0000
@@ -283,7 +283,7 @@
void
msn_session_activate_login_timeout(MsnSession *session)
{
- if (!session->logged_in) {
+ if (!session->logged_in && session->connected) {
session->login_timeout =
purple_timeout_add_seconds(MSN_LOGIN_FQY_TIMEOUT,
msn_login_timeout_cb, session);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/slp.c
--- a/libpurple/protocols/msn/slp.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/slp.c Sat Sep 11 19:03:25 2010 +0000
@@ -941,7 +941,8 @@
purple_debug_error("msn", "Received non-OK result: %s\n",
error ? error : "Unknown");
- if (type && !strcmp(type, "application/x-msnmsgr-transreqbody")) {
+ if (type && (!strcmp(type, "application/x-msnmsgr-transreqbody")
+ || !strcmp(type, "application/x-msnmsgr-transrespbody"))) {
MsnDirectConn *dc = slpcall->slplink->dc;
if (dc) {
msn_dc_fallback_to_sb(dc);
@@ -1265,8 +1266,6 @@
if (userlist->buddy_icon_window > 0)
{
GQueue *queue;
- PurpleAccount *account;
- const char *username;
queue = userlist->buddy_icon_requests;
@@ -1275,9 +1274,6 @@
user = g_queue_pop_head(queue);
- account = userlist->session->account;
- username = user->passport;
-
userlist->buddy_icon_window--;
request_user_display(user);
@@ -1349,31 +1345,21 @@
got_user_display(MsnSlpCall *slpcall,
const guchar *data, gsize size)
{
- MsnUserList *userlist;
+ MsnSlpLink *slplink;
const char *info;
PurpleAccount *account;
g_return_if_fail(slpcall != NULL);
+ slplink = slpcall->slplink;
info = slpcall->data_info;
if (purple_debug_is_verbose())
- purple_debug_info("msn", "Got User Display: %s\n", slpcall->slplink->remote_user);
-
- userlist = slpcall->slplink->session->userlist;
- account = slpcall->slplink->session->account;
-
- purple_buddy_icons_set_for_user(account, slpcall->slplink->remote_user,
- g_memdup(data, size), size, info);
+ purple_debug_info("msn", "Got User Display: %s\n", slplink->remote_user);
-#if 0
- /* Free one window slot */
- userlist->buddy_icon_window++;
+ account = slplink->session->account;
- purple_debug_info("msn", "got_user_display(): buddy_icon_window++ yields =%d\n",
- userlist->buddy_icon_window);
-
- msn_release_buddy_icon_request(userlist);
-#endif
+ purple_buddy_icons_set_for_user(account, slplink->remote_user,
+ g_memdup(data, size), size, info);
}
static void
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/slplink.c
--- a/libpurple/protocols/msn/slplink.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/slplink.c Sat Sep 11 19:03:25 2010 +0000
@@ -632,7 +632,7 @@
slpmsg = msn_slplink_message_find(slplink, header->session_id, header->id);
if (slpmsg == NULL)
{
- /* Probably the transfer was canceled */
+ /* Probably the transfer was cancelled */
purple_debug_error("msn", "Couldn't find slpmsg\n");
return;
}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/soap.c
--- a/libpurple/protocols/msn/soap.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/soap.c Sat Sep 11 19:03:25 2010 +0000
@@ -68,7 +68,6 @@
GQueue *queue;
MsnSoapRequest *current_request;
- gboolean unsafe_debug;
} MsnSoapConnection;
static gboolean msn_soap_connection_run(gpointer data);
@@ -80,7 +79,6 @@
conn->session = session;
conn->host = g_strdup(host);
conn->queue = g_queue_new();
- conn->unsafe_debug = purple_debug_is_unsafe();
return conn;
}
@@ -509,7 +507,7 @@
purple_debug_info("soap", "read: %s\n", g_strerror(perrno));
if (conn->current_request && conn->current_request->secure &&
- !conn->unsafe_debug)
+ !purple_debug_is_unsafe())
purple_debug_misc("soap", "Received secure request.\n");
else if (count != 0)
purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor);
@@ -659,7 +657,7 @@
g_string_append(conn->buf, "\r\n");
g_string_append(conn->buf, body);
- if (req->secure && !conn->unsafe_debug)
+ if (req->secure && !purple_debug_is_unsafe())
purple_debug_misc("soap", "Sending secure request.\n");
else
purple_debug_misc("soap", "%s\n", conn->buf->str);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/msn/switchboard.c
--- a/libpurple/protocols/msn/switchboard.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/msn/switchboard.c Sat Sep 11 19:03:25 2010 +0000
@@ -767,12 +767,8 @@
static void
iro_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
- PurpleAccount *account;
- PurpleConnection *gc;
MsnSwitchBoard *swboard;
- account = cmdproc->session->account;
- gc = account->gc;
swboard = cmdproc->data;
swboard->total_users = atoi(cmd->params[2]);
@@ -784,16 +780,12 @@
joi_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
{
MsnSession *session;
- PurpleAccount *account;
- PurpleConnection *gc;
MsnSwitchBoard *swboard;
const char *passport;
passport = cmd->params[0];
session = cmdproc->session;
- account = session->account;
- gc = account->gc;
swboard = cmdproc->data;
msn_switchboard_add_user(swboard, passport);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/Makefile.am
--- a/libpurple/protocols/oscar/Makefile.am Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/Makefile.am Sat Sep 11 19:03:25 2010 +0000
@@ -6,10 +6,11 @@
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 @@
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 @@
snac.c \
snactypes.h \
tlv.c \
- util.c
+ userinfo.c \
+ util.c \
+ visibility.c
AM_CFLAGS = $(st)
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/Makefile.mingw
--- a/libpurple/protocols/oscar/Makefile.mingw Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/Makefile.mingw Sat Sep 11 19:03:25 2010 +0000
@@ -41,10 +41,11 @@
## 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 @@
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_oservice.c \
family_popup.c \
- family_oservice.c \
- family_feedbag.c \
family_stats.c \
- family_translate.c \
family_userlookup.c \
flap_connection.c \
misc.c \
@@ -75,7 +73,9 @@
rxhandlers.c \
snac.c \
tlv.c \
- util.c
+ userinfo.c \
+ util.c \
+ visibility.c
OBJECTS = $(C_SRC:%.c=%.o)
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/authorization.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/authorization.c Sat Sep 11 19:03:25 2010 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/bstream.c
--- a/libpurple/protocols/oscar/bstream.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/bstream.c Sat Sep 11 19:03:25 2010 +0000
@@ -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 @@
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 @@
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 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/encoding.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/encoding.c Sat Sep 11 19:03:25 2010 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/encoding.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/oscar/encoding.h Sat Sep 11 19:03:25 2010 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_admin.c
--- a/libpurple/protocols/oscar/family_admin.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_admin.c Sat Sep 11 19:03:25 2010 +0000
@@ -47,7 +47,7 @@
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 @@
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_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_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_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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_advert.c
--- a/libpurple/protocols/oscar/family_advert.c Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_alert.c
--- a/libpurple/protocols/oscar/family_alert.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_alert.c Sat Sep 11 19:03:25 2010 +0000
@@ -73,7 +73,7 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_auth.c
--- a/libpurple/protocols/oscar/family_auth.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_auth.c Sat Sep 11 19:03:25 2010 +0000
@@ -56,17 +56,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_bart.c
--- a/libpurple/protocols/oscar/family_bart.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_bart.c Sat Sep 11 19:03:25 2010 +0000
@@ -56,7 +56,7 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_bos.c
--- a/libpurple/protocols/oscar/family_bos.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_bos.c Sat Sep 11 19:03:25 2010 +0000
@@ -68,98 +68,6 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_buddy.c
--- a/libpurple/protocols/oscar/family_buddy.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c Sat Sep 11 19:03:25 2010 +0000
@@ -88,117 +88,6 @@
}
/*
- * 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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_chat.c
--- a/libpurple/protocols/oscar/family_chat.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_chat.c Sat Sep 11 19:03:25 2010 +0000
@@ -47,74 +47,6 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_chatnav.c
--- a/libpurple/protocols/oscar/family_chatnav.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_chatnav.c Sat Sep 11 19:03:25 2010 +0000
@@ -139,7 +139,7 @@
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 @@
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 @@
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 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_feedbag.c
--- a/libpurple/protocols/oscar/family_feedbag.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c Sat Sep 11 19:03:25 2010 +0000
@@ -660,10 +660,8 @@
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 @@
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);
+ aim_ssi_itemlist_add(&od->ssi.local, NULL, 0x0000, 0x0000, list_type, NULL);
- /* Add that bad boy */
- aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_PERMIT, 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);
+ if (!(del = aim_ssi_itemlist_finditem(od->ssi.local, NULL, name, list_type)))
+ return -EINVAL;
- /* Add that bad boy */
- aim_ssi_itemlist_add(&od->ssi.local, name, 0x0000, 0xFFFF, AIM_SSI_TYPE_DENY, NULL);
-
- /* 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 @@
}
/**
- * 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 @@
* 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 @@
/* 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 @@
}
/*
- * 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
/* 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 @@
}
/*
- * 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 @@
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 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_icbm.c
--- a/libpurple/protocols/oscar/family_icbm.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c Sat Sep 11 19:03:25 2010 +0000
@@ -44,6 +44,7 @@
* Make sure flap_connection_findbygroup is used by all functions.
*/
+#include "encoding.h"
#include "oscar.h"
#include "peer.h"
@@ -108,69 +109,6 @@
}
/*
- * 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
@@ -287,7 +225,7 @@
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);
@@ -345,40 +283,14 @@
*
* 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 ߪ 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)
{
@@ -387,7 +299,6 @@
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;
@@ -395,37 +306,17 @@
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);
@@ -441,52 +332,31 @@
/* 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));
- }
+ byte_stream_put16(&data, args->featureslen);
+ byte_stream_putraw(&data, args->features, args->featureslen);
- if (args->flags & AIM_IMFLAGS_MULTIPART) {
- aim_mpmsg_section_t *sec;
+ /* Insert message text in a TLV (type 0x0101) */
+ byte_stream_put16(&data, 0x0101);
- /* 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 {
+ /* Message block length */
+ byte_stream_put16(&data, args->msglen + 0x04);
- /* Insert message text in a TLV (type 0x0101) */
- byte_stream_put16(&data, 0x0101);
-
- /* Message block length */
- byte_stream_put16(&data, args->msglen + 0x04);
+ /* Character set */
+ byte_stream_put16(&data, args->charset);
+ /* Character subset -- we always use 0 here */
+ byte_stream_put16(&data, 0x0);
- /* Character set */
- byte_stream_put16(&data, args->charset);
- byte_stream_put16(&data, args->charsubset);
-
- /* 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 */
@@ -521,7 +391,7 @@
/* 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 */
@@ -531,33 +401,6 @@
}
/*
- * 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)
@@ -628,7 +471,7 @@
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);
@@ -698,100 +541,7 @@
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);
@@ -844,7 +594,7 @@
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);
}
@@ -879,7 +629,7 @@
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);
}
@@ -934,7 +684,7 @@
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);
}
@@ -997,7 +747,7 @@
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);
}
@@ -1044,17 +794,6 @@
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;
@@ -1083,7 +822,7 @@
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);
}
@@ -1136,17 +875,6 @@
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;
@@ -1176,530 +904,57 @@
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)
+static void
+incomingim_ch1_parsemsg(OscarData *od, aim_userinfo_t *userinfo, ByteStream *message, struct aim_incomingim_ch1_args *args)
{
- 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);
-
+ PurpleAccount *account = purple_connection_get_account(od->gc);
/*
- * TLV t(0005)
- *
- * ICQ data (the UIN and the message).
+ * We're interested in the inner TLV 0x101, which contains precious, precious 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;
-}
+ 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 */
-/*
- * 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 received on unsupported channel. Ignoring. (chan = %04x)\n", channel);
- return 0;
+ msg = byte_stream_getstr(message, msglen);
+ args->msg = oscar_decode_im(account, userinfo->bn, charset, msg, msglen);
+ } else {
+ byte_stream_advance(message, length);
+ }
}
-
- 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)
+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)
{
- 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)
-{
- /* 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 */
-
- /*
- * 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.
- *
- */
- 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;
- }
- }
-
- /* 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)
-{
- 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;
@@ -1708,93 +963,20 @@
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);
@@ -1812,39 +994,16 @@
*/
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);
}
/*
@@ -1862,10 +1021,7 @@
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;
}
@@ -1891,7 +1047,7 @@
* ...
* ...
*/
- while (byte_stream_empty(servdata))
+ while (byte_stream_bytes_left(servdata))
{
guint16 gnlen, numb;
int i;
@@ -1963,7 +1119,7 @@
static void
incomingim_ch2_icqserverrelay_free(OscarData *od, IcbmArgsCh2 *args)
{
- g_free((char *)args->info.rtfmsg.rtfmsg);
+ g_free((char *)args->info.rtfmsg.msg);
}
/*
@@ -1977,33 +1133,34 @@
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;
+ guint16 hdrlen, msglen;
+
+ args->destructor = (void *)incomingim_ch2_icqserverrelay_free;
- if (byte_stream_empty(servdata) < 24)
- /* Someone sent us a short server relay ICBM. Weird. (Maybe?) */
- return;
-
- hdrlen = byte_stream_getle16(servdata);
- byte_stream_advance(servdata, hdrlen);
-
- 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
@@ -2163,7 +1320,7 @@
/*
* 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);
@@ -2188,20 +1345,6 @@
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
*/
@@ -2396,38 +1539,6 @@
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)
{
@@ -2436,7 +1547,7 @@
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);
@@ -2456,9 +1567,7 @@
* 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)
@@ -2485,186 +1594,57 @@
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;
+ ByteStream bs;
+ aim_snacid_t snacid;
+ guint32 header_size, data_size;
+ guint16 cookie2 = (guint16)g_random_int();
- 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;
- }
+ purple_debug_misc("oscar", "Sending message ack to %s\n", bn);
- 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;
- }
+ 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);
- 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 */
+ /* The message header. */
+ aim_im_puticbm(&bs, cookie, 0x0002, bn);
+ byte_stream_put16(&bs, 0x0003); /* reason */
- 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 */
+ /* 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 */
- 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);
-
- 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);
-
- 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);
-
- 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);
-
- purple_prpl_got_user_status(account, bn,
- purple_status_get_id(status),
- "message", status_note, NULL);
-
- 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);
}
/*
@@ -2819,16 +1799,10 @@
}
/*
- * 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;
@@ -2838,8 +1812,7 @@
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);
@@ -2914,7 +1887,7 @@
*/
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);
@@ -3002,7 +1975,7 @@
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(outer_tlvlist);
byte_stream_destroy(&header);
@@ -3088,9 +2061,9 @@
aim_im_puticbm(&bs, cookie, 0x0002, sn);
byte_stream_put16(&bs, 0x0003);
byte_stream_putraw(&bs, plugindata, sizeof(plugindata));
- byte_stream_putraw(&bs, (const guint8 *)statxml, strlen(statxml));
+ 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);
@@ -3135,8 +2108,6 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_icq.c
--- a/libpurple/protocols/oscar/family_icq.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_icq.c Sat Sep 11 19:03:25 2010 +0000
@@ -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;
+#define AIM_ICQ_INFO_REQUEST 0x04b2
+#define AIM_ICQ_ALIAS_REQUEST 0x04ba
- if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
- return -EINVAL;
+static
+int compare_icq_infos(gconstpointer a, gconstpointer b)
+{
+ const struct aim_icq_info* aa = a;
+ const guint16* bb = b;
+ return aa->reqid - *bb;
+}
- purple_debug_info("oscar", "Requesting offline messages\n");
-
- bslen = 2 + 4 + 2 + 2;
-
- byte_stream_new(&bs, 4 + bslen);
+static void aim_icq_freeinfo(struct aim_icq_info *info) {
+ int i;
- 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, 0x003c); /* 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);
-
- 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);
+ 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;
- 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);
+ 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;
+ }
- 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);
-
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,89 +301,13 @@
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;
+ 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;
}
-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);
-
- return 0;
-}
-#endif
-
/*
* Send an SMS message. This is the non-US way. The US-way is to IM
* their cell phone number (+19195551234).
@@ -446,7 +398,7 @@
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 @@
return 0;
}
-static void aim_icq_freeinfo(struct aim_icq_info *info) {
- int i;
+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)
- 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);
+ 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 @@
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 @@
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 @@
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);
+ gotalias(od, 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;
- }
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_invite.c
--- a/libpurple/protocols/oscar/family_invite.c Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_locate.c
--- a/libpurple/protocols/oscar/family_locate.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_locate.c Sat Sep 11 19:03:25 2010 +0000
@@ -245,6 +245,10 @@
{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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,68 +1166,12 @@
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;
@@ -1253,14 +1198,12 @@
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);
g_free(snac2->data);
g_free(snac2);
- return ret;
+ return 1;
}
/*
@@ -1390,7 +1333,7 @@
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);
@@ -1424,41 +1367,7 @@
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);
@@ -1470,7 +1379,6 @@
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;
@@ -1522,140 +1430,12 @@
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.
*
@@ -1683,7 +1463,7 @@
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);
@@ -1731,15 +1511,6 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_odir.c
--- a/libpurple/protocols/oscar/family_odir.c Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_oservice.c
--- a/libpurple/protocols/oscar/family_oservice.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_oservice.c Sat Sep 11 19:03:25 2010 +0000
@@ -73,7 +73,7 @@
}
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 @@
{
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_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_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 @@
}
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 @@
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 @@
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 @@
}
/*
- * 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 @@
}
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 @@
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_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_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 @@
}
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);
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_translate.c
--- a/libpurple/protocols/oscar/family_translate.c Sun Aug 01 00:08:26 2010 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +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 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.
- *
- */
-
-#include "oscar.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;
-
- return 0;
-}
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/family_userlookup.c
--- a/libpurple/protocols/oscar/family_userlookup.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/family_userlookup.c Sat Sep 11 19:03:25 2010 +0000
@@ -75,7 +75,7 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/flap_connection.c
--- a/libpurple/protocols/oscar/flap_connection.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c Sat Sep 11 19:03:25 2010 +0000
@@ -212,7 +212,7 @@
* 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/libaim.c
--- a/libpurple/protocols/oscar/libaim.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/libaim.c Sat Sep 11 19:03:25 2010 +0000
@@ -25,6 +25,7 @@
*/
#include "oscarcommon.h"
+#include "oscar.h"
static PurplePluginProtocolInfo prpl_info =
{
@@ -57,7 +58,7 @@
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 */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/libicq.c
--- a/libpurple/protocols/oscar/libicq.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/libicq.c Sat Sep 11 19:03:25 2010 +0000
@@ -63,11 +63,11 @@
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 */
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/misc.c
--- a/libpurple/protocols/oscar/misc.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/misc.c Sat Sep 11 19:03:25 2010 +0000
@@ -41,7 +41,7 @@
{
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 @@
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 @@
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,7 +91,7 @@
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)))
diff -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/msgcookie.c
--- a/libpurple/protocols/oscar/msgcookie.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/msgcookie.c Sat Sep 11 19:03:25 2010 +0000
@@ -177,18 +177,3 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/odc.c
--- a/libpurple/protocols/oscar/odc.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/odc.c Sat Sep 11 19:03:25 2010 +0000
@@ -19,6 +19,7 @@
*/
/* From the oscar PRPL */
+#include "encoding.h"
#include "oscar.h"
#include "peer.h"
@@ -89,7 +90,7 @@
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 @@
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 @@
/* 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 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/oft.c
--- a/libpurple/protocols/oscar/oft.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/oft.c Sat Sep 11 19:03:25 2010 +0000
@@ -240,7 +240,7 @@
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 -r c49697f075cf -r 6469c68fa093 libpurple/protocols/oscar/oscar.c
--- a/libpurple/protocols/oscar/oscar.c Sun Aug 01 00:08:26 2010 +0000
+++ b/libpurple/protocols/oscar/oscar.c Sat Sep 11 19:03:25 2010 +0000
@@ -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,7 +68,8 @@
| 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};
@@ -99,35 +86,6 @@
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;
-};
-
/* All the libfaim->purple callback functions */
/* Only used when connecting with the old-style BUCP login */
@@ -143,7 +101,6 @@
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 *, ...);
@@ -152,8 +109,6 @@
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 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 *, ...);
@@ -161,16 +116,9 @@
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 *, ...);
@@ -186,10 +134,10 @@
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);
@@ -204,536 +152,6 @@
}
#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)
@@ -764,255 +182,6 @@
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("%s",
- 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;
@@ -1496,22 +665,12 @@
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_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, 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);
@@ -1771,34 +930,6 @@
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;
@@ -2253,18 +1384,18 @@
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)
/*
@@ -2370,17 +1501,11 @@
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) {
@@ -2420,19 +1545,7 @@
}
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);
+ tmp = g_strdup(args->msg);
/*
* Convert iChat color tags to normal font tags.
@@ -2516,8 +1629,7 @@
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;
@@ -2545,35 +1657,20 @@
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)
@@ -2594,8 +1691,7 @@
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)
{
@@ -2603,7 +1699,7 @@
}
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);
@@ -2648,24 +1744,22 @@
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", "
");
+ 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) {
purple_debug_info("oscar", "Sending X-Status Reply\n");
@@ -2683,122 +1777,6 @@
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)
@@ -2842,7 +1820,7 @@
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;
@@ -2895,24 +1873,17 @@
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;
@@ -3014,7 +1985,8 @@
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;
@@ -3375,105 +2347,6 @@
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"), oscar_get_msgerr_reason(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, *base_profile_url = 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);
- base_profile_url = oscar_util_valid_name_icq(userinfo->bn) ? "http://www.icq.com/people" : "http://profiles.aim.com";
- tmp = g_strdup_printf("%s",
- 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);
-
- return 1;
-}
-
static int purple_parse_motd(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
{
char *msg;
@@ -3616,13 +2489,7 @@
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);
@@ -3630,16 +2497,7 @@
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);
@@ -3655,7 +2513,6 @@
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;
@@ -3674,10 +2531,7 @@
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);
@@ -3795,41 +2649,6 @@
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;
@@ -3850,10 +2669,6 @@
*/
warning_level = info->warnlevel/10.0 + 0.5;
-#ifdef CRAZY_WARNING
- purple_presence_set_warning_level(presence, warning_level);
-#endif
-
return 1;
}
@@ -3992,16 +2807,14 @@
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));
@@ -4033,206 +2846,6 @@
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("%s", 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("%s", 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("%s", 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("%s", 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;
@@ -4457,8 +3070,8 @@
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;
@@ -4519,8 +3132,7 @@
g_string_append(msg, "