pidgin/ljfisher-ssl-client-auth

bd59fb755f66
merge of 'a47ab1a2fcf24f136b572c4ede8024299e18aff0'
and 'b1c0ce2787e6840ac9efaacef248122b733ad04c'
--- a/COPYRIGHT Mon Mar 07 06:42:57 2011 +0000
+++ b/COPYRIGHT Mon Mar 07 06:43:26 2011 +0000
@@ -49,6 +49,7 @@
Carlos Bederian
Dave Bell
Igor Belyi
+David Benjamin
Brian Bernas
Paul Betts
Runa Bhattacharjee
@@ -399,6 +400,7 @@
Eric Polino <aluink@gmail.com>
Ari Pollak
Stephen Pope
+Cristi Posoiu
Nathan Poznick
Jory A. Pratt
David Preece
--- a/ChangeLog Mon Mar 07 06:42:57 2011 +0000
+++ b/ChangeLog Mon Mar 07 06:43:26 2011 +0000
@@ -3,6 +3,17 @@
version 2.7.11 (??/??/????):
General:
* Our bundled libgadu should now build on HP-UX.
+ * Fix some instances of file transfers never completing. (Cristi Posoiu)
+ (#12472)
+
+ Pidgin:
+ * Sort by Status no longer causes buddies to move around when you
+ click them.
+ * Fix embedding in the system tray on older GTK+ releases (such as on
+ CentOS 5.5 and older Fedora).
+ * No longer require libstartup-notification for startup notification
+ support. GTK+ has included support for years, so use it instead. (David
+ Benjamin) (#13245)
AIM:
* Fix a bug where some buddies from your buddy list might not show up.
@@ -15,8 +26,13 @@
XMPP:
* Fix building on platforms with an older glib (inadvertantly broken in
2.7.10). (#13329)
- * Don't treat the on-join status storms as 'new arrivals'. (#a14527)
- (Thijs Alkemade)
+ * Don't treat the on-join status storms as 'new arrivals'. (Thijs
+ Alkemade) (#a14527)
+ * Extend the /join command to support room JIDs, enabling you to join
+ a room on any server. (Solarius, Matěj Cepl, wyuka) (#4526)
+ * Add support for receiving a limited amount of history when joining a
+ room (not currently supported by Pidgin and Finch). (Thijs Alkemade)
+ (#10986, #a14219)
version 2.7.10 (02/06/2011):
General:
@@ -323,6 +339,40 @@
* Bonjour support now requires Apple Bonjour Print Services version
2.0.0 or newer (http://support.apple.com/kb/dl999).
+ 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
--- a/ChangeLog.API Mon Mar 07 06:42:57 2011 +0000
+++ b/ChangeLog.API Mon Mar 07 06:43:26 2011 +0000
@@ -1,6 +1,15 @@
Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
version 2.7.11 (??/??/????):
+ * libpurple:
+ Added:
+ * Four entries in the GHashTable passed when joining
+ an XMPP chat room which allow the UI to request a limited
+ amount of history. See XEP-0045 7.1.16 for details; the
+ entries are named history_maxchars, history_maxstanzas,
+ history_seconds, and history_since. history_since must be
+ interpretable by purple_str_to_time, and the prpl takes care
+ of formatting the time properly.
* Perl:
Added:
* Purple::find_conversation_with_account
--- a/configure.ac Mon Mar 07 06:42:57 2011 +0000
+++ b/configure.ac Mon Mar 07 06:43:26 2011 +0000
@@ -541,27 +541,6 @@
fi
dnl #######################################################################
- dnl # Check for startup notification
- dnl #######################################################################
- if test "x$enable_startup_notification" = "xyes"; then
- PKG_CHECK_MODULES(STARTUP_NOTIFICATION, [libstartup-notification-1.0 >= 0.5], , [
- AC_MSG_RESULT(no)
- enable_startup_notification="no"
- if test "x$force_deps" = "xyes" ; then
- AC_MSG_ERROR([
-Startup notification development headers not found.
-Use --disable-startup-notification if you do not need it.
-])
- fi])
-
- if test "x$enable_startup_notification" = "xyes"; then
- AC_DEFINE(HAVE_STARTUP_NOTIFICATION, 1, [Define if we're using libstartup-notification.])
- AC_SUBST(STARTUP_NOTIFICATION_CFLAGS)
- AC_SUBST(STARTUP_NOTIFICATION_LIBS)
- fi
- fi
-
- dnl #######################################################################
dnl # Check for GtkSpell
dnl #######################################################################
if test "x$enable_gtkspell" = "xyes" ; then
--- a/libpurple/ft.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/ft.c Mon Mar 07 06:43:26 2011 +0000
@@ -1100,9 +1100,11 @@
r = write(xfer->fd, buffer, s);
if (r < 0 && errno == EAGAIN)
r = 0;
- if ((purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer))
- purple_xfer_set_completed(xfer, TRUE);
}
+ if (r >= 0 && (purple_xfer_get_bytes_sent(xfer)+r) >= purple_xfer_get_size(xfer) &&
+ !purple_xfer_is_completed(xfer))
+ purple_xfer_set_completed(xfer, TRUE);
+
return r;
}
--- a/libpurple/protocols/jabber/chat.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/jabber/chat.c Mon Mar 07 06:43:26 2011 +0000
@@ -281,6 +281,14 @@
char *jid;
+ char *history_maxchars;
+ char *history_maxstanzas;
+ char *history_seconds;
+ char *history_since;
+
+ struct tm history_since_datetime;
+ const char *history_since_string = NULL;
+
chat = jabber_chat_new(js, room, server, handle, password, data);
if (chat == NULL)
return NULL;
@@ -297,6 +305,22 @@
xmlnode_set_attrib(presence, "to", jid);
g_free(jid);
+ history_maxchars = g_hash_table_lookup(data, "history_maxchars");
+ history_maxstanzas = g_hash_table_lookup(data, "history_maxstanzas");
+ history_seconds = g_hash_table_lookup(data, "history_seconds");
+ history_since = g_hash_table_lookup(data, "history_since");
+
+ if (history_since) {
+ if (purple_str_to_time(history_since, TRUE, &history_since_datetime, NULL, NULL) != 0) {
+ history_since_string = purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", &history_since_datetime);
+ } else {
+ history_since_string = NULL;
+
+ purple_debug_error("jabber", "Invalid date format for history_since"
+ " while requesting history: %s", history_since);
+ }
+ }
+
x = xmlnode_new_child(presence, "x");
xmlnode_set_namespace(x, "http://jabber.org/protocol/muc");
@@ -305,6 +329,27 @@
xmlnode_insert_data(p, password, -1);
}
+ if ((history_maxchars && *history_maxchars)
+ || (history_maxstanzas && *history_maxstanzas)
+ || (history_seconds && *history_seconds)
+ || (history_since_string && *history_since_string)) {
+
+ xmlnode *history = xmlnode_new_child(x, "history");
+
+ if (history_maxchars && *history_maxchars) {
+ xmlnode_set_attrib(history, "maxchars", history_maxchars);
+ }
+ if (history_maxstanzas && *history_maxstanzas) {
+ xmlnode_set_attrib(history, "maxstanzas", history_maxstanzas);
+ }
+ if (history_seconds && *history_seconds) {
+ xmlnode_set_attrib(history, "seconds", history_seconds);
+ }
+ if (history_since_string && *history_since_string) {
+ xmlnode_set_attrib(history, "since", history_since_string);
+ }
+ }
+
jabber_send(js, presence);
xmlnode_free(presence);
--- a/libpurple/protocols/jabber/jabber.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/jabber/jabber.c Mon Mar 07 06:43:26 2011 +0000
@@ -3004,21 +3004,44 @@
{
JabberChat *chat = jabber_chat_find_by_conv(conv);
GHashTable *components;
-
- if(!chat || !args || !args[0])
+ JabberID *jid;
+ const char *room = NULL, *server = NULL, *handle = NULL;
+
+ if (!chat || !args || !args[0])
return PURPLE_CMD_RET_FAILED;
components = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
- g_hash_table_replace(components, "room", args[0]);
- g_hash_table_replace(components, "server", chat->server);
- g_hash_table_replace(components, "handle", chat->handle);
- if(args[1])
- g_hash_table_replace(components, "password", args[1]);
+ jid = jabber_id_new(args[0]);
+ if (jid) {
+ room = jid->node;
+ server = jid->domain;
+ handle = jid->resource ? jid->resource : chat->handle;
+ } else {
+ /* If jabber_id_new failed, the user may have just passed in
+ * a room name. For backward compatibility, handle that here.
+ */
+ if (strchr(args[0], '@')) {
+ *error = g_strdup(_("Invalid XMPP ID"));
+ return PURPLE_CMD_RET_FAILED;
+ }
+
+ room = args[0];
+ server = chat->server;
+ handle = chat->handle;
+ }
+
+ g_hash_table_insert(components, "room", (gpointer)room);
+ g_hash_table_insert(components, "server", (gpointer)server);
+ g_hash_table_insert(components, "handle", (gpointer)handle);
+
+ if (args[1])
+ g_hash_table_insert(components, "password", args[1]);
jabber_chat_join(purple_conversation_get_gc(conv), components);
g_hash_table_destroy(components);
+ jabber_id_free(jid);
return PURPLE_CMD_RET_OK;
}
@@ -3646,6 +3669,7 @@
PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber",
jabber_cmd_chat_join,
_("join: &lt;room&gt; [password]: Join a chat on this server."),
+ /* _("join: &lt;room[@server]&gt; [password]: Join a chat."), */
NULL);
commands = g_slist_prepend(commands, GUINT_TO_POINTER(id));
--- a/libpurple/protocols/jabber/jutil.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/jabber/jutil.c Mon Mar 07 06:43:26 2011 +0000
@@ -501,12 +501,9 @@
jabber_id_free(JabberID *jid)
{
if(jid) {
- if(jid->node)
- g_free(jid->node);
- if(jid->domain)
- g_free(jid->domain);
- if(jid->resource)
- g_free(jid->resource);
+ g_free(jid->node);
+ g_free(jid->domain);
+ g_free(jid->resource);
g_free(jid);
}
}
--- a/libpurple/protocols/jabber/message.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/jabber/message.c Mon Mar 07 06:43:26 2011 +0000
@@ -1140,6 +1140,12 @@
if(!who || !msg)
return 0;
+ if (purple_debug_is_verbose()) {
+ /* TODO: Maybe we need purple_debug_is_really_verbose? :) */
+ purple_debug_misc("jabber", "jabber_message_send_im: who='%s'\n"
+ "\tmsg='%s'\n", who, msg);
+ }
+
resource = jabber_get_resource(who);
jb = jabber_buddy_find(gc->proto_data, who, TRUE);
--- a/libpurple/protocols/msn/contact.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/contact.c Mon Mar 07 06:43:26 2011 +0000
@@ -363,10 +363,9 @@
char *type;
char *member_id;
MsnUser *user;
- xmlnode *annotation, *display;
+ xmlnode *annotation;
guint nid = MSN_NETWORK_UNKNOWN;
char *invite = NULL;
- char *display_text;
passport = xmlnode_get_data(xmlnode_get_child(member, node));
if (!msn_email_is_valid(passport)) {
@@ -376,13 +375,8 @@
type = xmlnode_get_data(xmlnode_get_child(member, "Type"));
member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId"));
- if ((display = xmlnode_get_child(member, "DisplayName"))) {
- display_text = xmlnode_get_data(display);
- } else {
- display_text = NULL;
- }
- user = msn_userlist_find_add_user(session->userlist, passport, display_text);
+ user = msn_userlist_find_add_user(session->userlist, passport, NULL);
for (annotation = xmlnode_get_child(member, "Annotations/Annotation");
annotation;
@@ -423,7 +417,6 @@
g_free(type);
g_free(member_id);
g_free(invite);
- g_free(display_text);
}
static void
--- a/libpurple/protocols/msn/msn.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/msn.c Mon Mar 07 06:43:26 2011 +0000
@@ -110,11 +110,9 @@
g_return_val_if_fail(str != NULL, NULL);
- g_snprintf(buf, sizeof(buf), "%s%s", str,
- (strchr(str, '@') ? "" : "@hotmail.com"));
-
- tmp = g_utf8_strdown(buf, -1);
- strncpy(buf, tmp, sizeof(buf));
+ tmp = g_strchomp(g_utf8_strdown(str, -1));
+ g_snprintf(buf, sizeof(buf), "%s%s", tmp,
+ (strchr(tmp, '@') ? "" : "@hotmail.com"));
g_free(tmp);
return buf;
--- a/libpurple/protocols/msn/p2p.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/p2p.c Mon Mar 07 06:43:26 2011 +0000
@@ -23,72 +23,139 @@
*/
#include "internal.h"
+#include "debug.h"
#include "p2p.h"
#include "msnutils.h"
MsnP2PInfo *
-msn_p2p_info_new(void)
+msn_p2p_info_new(MsnP2PVersion version)
{
- return g_new0(MsnP2PInfo, 1);
+ MsnP2PInfo *info = g_new0(MsnP2PInfo, 1);
+ info->version = version;
+
+ switch (version) {
+ case MSN_P2P_VERSION_ONE:
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", version);
+ g_free(info);
+ info = NULL;
+ }
+
+ return info;
}
MsnP2PInfo *
msn_p2p_info_dup(MsnP2PInfo *info)
{
MsnP2PInfo *new_info = g_new0(MsnP2PInfo, 1);
- *new_info = *info;
+
+ new_info->version = info->version;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ case MSN_P2P_VERSION_TWO:
+ *new_info = *info;
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ g_free(new_info);
+ new_info = NULL;
+ }
+
return new_info;
}
void
msn_p2p_info_free(MsnP2PInfo *info)
{
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
g_free(info);
}
size_t
msn_p2p_header_from_wire(MsnP2PInfo *info, const char *wire)
{
- MsnP2PHeader *header;
+ size_t len;
- header = &info->header;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE: {
+ MsnP2PHeader *header = &info->header.v1;
- header->session_id = msn_pop32le(wire);
- header->id = msn_pop32le(wire);
- header->offset = msn_pop64le(wire);
- header->total_size = msn_pop64le(wire);
- header->length = msn_pop32le(wire);
- header->flags = msn_pop32le(wire);
- header->ack_id = msn_pop32le(wire);
- header->ack_sub_id = msn_pop32le(wire);
- header->ack_size = msn_pop64le(wire);
+ header->session_id = msn_pop32le(wire);
+ header->id = msn_pop32le(wire);
+ header->offset = msn_pop64le(wire);
+ header->total_size = msn_pop64le(wire);
+ header->length = msn_pop32le(wire);
+ header->flags = msn_pop32le(wire);
+ header->ack_id = msn_pop32le(wire);
+ header->ack_sub_id = msn_pop32le(wire);
+ header->ack_size = msn_pop64le(wire);
- return P2P_PACKET_HEADER_SIZE;
+ len = P2P_PACKET_HEADER_SIZE;
+ break;
+ }
+
+ case MSN_P2P_VERSION_TWO:
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return len;
}
char *
msn_p2p_header_to_wire(MsnP2PInfo *info, size_t *len)
{
- MsnP2PHeader *header;
- char *wire;
+ char *wire = NULL;
char *tmp;
- header = &info->header;
- tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE);
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE: {
+ MsnP2PHeader *header = &info->header.v1;
+ tmp = wire = g_new(char, P2P_PACKET_HEADER_SIZE);
+
+ msn_push32le(tmp, header->session_id);
+ msn_push32le(tmp, header->id);
+ msn_push64le(tmp, header->offset);
+ msn_push64le(tmp, header->total_size);
+ msn_push32le(tmp, header->length);
+ msn_push32le(tmp, header->flags);
+ msn_push32le(tmp, header->ack_id);
+ msn_push32le(tmp, header->ack_sub_id);
+ msn_push64le(tmp, header->ack_size);
- msn_push32le(tmp, header->session_id);
- msn_push32le(tmp, header->id);
- msn_push64le(tmp, header->offset);
- msn_push64le(tmp, header->total_size);
- msn_push32le(tmp, header->length);
- msn_push32le(tmp, header->flags);
- msn_push32le(tmp, header->ack_id);
- msn_push32le(tmp, header->ack_sub_id);
- msn_push64le(tmp, header->ack_size);
+ if (len)
+ *len = P2P_PACKET_HEADER_SIZE;
+
+ break;
+ }
- if (len)
- *len = P2P_PACKET_HEADER_SIZE;
+ case MSN_P2P_VERSION_TWO:
+ if (len)
+ *len = 0;
+
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
return wire;
@@ -127,15 +194,30 @@
void
msn_p2p_info_to_string(MsnP2PInfo *info, GString *str)
{
- g_string_append_printf(str, "Session ID: %u\r\n", info->header.session_id);
- g_string_append_printf(str, "ID: %u\r\n", info->header.id);
- g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", info->header.offset);
- g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", info->header.total_size);
- g_string_append_printf(str, "Length: %u\r\n", info->header.length);
- g_string_append_printf(str, "Flags: 0x%x\r\n", info->header.flags);
- g_string_append_printf(str, "ACK ID: %u\r\n", info->header.ack_id);
- g_string_append_printf(str, "SUB ID: %u\r\n", info->header.ack_sub_id);
- g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", info->header.ack_size);
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE: {
+ MsnP2PHeader *header = &info->header.v1;
+ g_string_append_printf(str, "Session ID: %u\r\n", header->session_id);
+ g_string_append_printf(str, "ID: %u\r\n", header->id);
+ g_string_append_printf(str, "Offset: %" G_GUINT64_FORMAT "\r\n", header->offset);
+ g_string_append_printf(str, "Total size: %" G_GUINT64_FORMAT "\r\n", header->total_size);
+ g_string_append_printf(str, "Length: %u\r\n", header->length);
+ g_string_append_printf(str, "Flags: 0x%x\r\n", header->flags);
+ g_string_append_printf(str, "ACK ID: %u\r\n", header->ack_id);
+ g_string_append_printf(str, "SUB ID: %u\r\n", header->ack_sub_id);
+ g_string_append_printf(str, "ACK Size: %" G_GUINT64_FORMAT "\r\n", header->ack_size);
+
+ break;
+ }
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
g_string_append_printf(str, "Footer: 0x%08X\r\n", info->footer.value);
}
@@ -150,67 +232,232 @@
gboolean
msn_p2p_info_is_valid(MsnP2PInfo *info)
{
- return info->header.total_size >= info->header.length;
+ gboolean valid = FALSE;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ valid = info->header.v1.total_size >= info->header.v1.length;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return valid;
}
gboolean
msn_p2p_info_is_final(MsnP2PInfo *info)
{
- return info->header.offset + info->header.length >= info->header.total_size;
+ gboolean final = FALSE;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ final = info->header.v1.offset + info->header.v1.length >= info->header.v1.total_size;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return final;
}
guint32
msn_p2p_info_get_session_id(MsnP2PInfo *info)
{
- return info->header.session_id;
+ guint32 session_id = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ session_id = info->header.v1.session_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return session_id;
}
guint32
msn_p2p_info_get_id(MsnP2PInfo *info)
{
- return info->header.id;
+ guint32 id = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ id = info->header.v1.id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return id;
}
guint64
msn_p2p_info_get_offset(MsnP2PInfo *info)
{
- return info->header.offset;
+ guint64 offset = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ offset = info->header.v1.offset;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return offset;
}
guint64
msn_p2p_info_get_total_size(MsnP2PInfo *info)
{
- return info->header.total_size;
+ guint64 total_size = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ total_size = info->header.v1.total_size;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return total_size;
}
guint32
msn_p2p_info_get_length(MsnP2PInfo *info)
{
- return info->header.length;
+ guint32 length = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ length = info->header.v1.length;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return length;
}
guint32
msn_p2p_info_get_flags(MsnP2PInfo *info)
{
- return info->header.flags;
+ guint32 flags = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ flags = info->header.v1.flags;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return flags;
}
guint32
msn_p2p_info_get_ack_id(MsnP2PInfo *info)
{
- return info->header.ack_id;
+ guint32 ack_id = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ ack_id = info->header.v1.ack_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return ack_id;
}
guint32
msn_p2p_info_get_ack_sub_id(MsnP2PInfo *info)
{
- return info->header.ack_sub_id;
+ guint32 ack_sub_id = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ ack_sub_id = info->header.v1.ack_sub_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return ack_sub_id;
}
guint64
msn_p2p_info_get_ack_size(MsnP2PInfo *info)
{
- return info->header.ack_size;
+ guint64 ack_size = 0;
+
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ ack_size = info->header.v1.ack_size;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
+ return ack_size;
}
guint32
@@ -222,55 +469,156 @@
void
msn_p2p_info_set_session_id(MsnP2PInfo *info, guint32 session_id)
{
- info->header.session_id = session_id;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.session_id = session_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
}
void
msn_p2p_info_set_id(MsnP2PInfo *info, guint32 id)
{
- info->header.id = id;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.id = id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
+
}
void
msn_p2p_info_set_offset(MsnP2PInfo *info, guint64 offset)
{
- info->header.offset = offset;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.offset = offset;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_total_size(MsnP2PInfo *info, guint64 total_size)
{
- info->header.total_size = total_size;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.total_size = total_size;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_length(MsnP2PInfo *info, guint32 length)
{
- info->header.length = length;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.length = length;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_flags(MsnP2PInfo *info, guint32 flags)
{
- info->header.flags = flags;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.flags = flags;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_ack_id(MsnP2PInfo *info, guint32 ack_id)
{
- info->header.ack_id = ack_id;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.ack_id = ack_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_ack_sub_id(MsnP2PInfo *info, guint32 ack_sub_id)
{
- info->header.ack_sub_id = ack_sub_id;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.ack_sub_id = ack_sub_id;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
msn_p2p_info_set_ack_size(MsnP2PInfo *info, guint64 ack_size)
{
- info->header.ack_size = ack_size;
+ switch (info->version) {
+ case MSN_P2P_VERSION_ONE:
+ info->header.v1.ack_size = ack_size;
+ break;
+
+ case MSN_P2P_VERSION_TWO:
+ /* Nothing to do! */
+ break;
+
+ default:
+ purple_debug_error("msn", "Invalid P2P Info version: %d\n", info->version);
+ }
}
void
--- a/libpurple/protocols/msn/p2p.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/p2p.h Mon Mar 07 06:43:26 2011 +0000
@@ -58,8 +58,18 @@
} MsnP2PFooter;
#define P2P_PACKET_FOOTER_SIZE (1 * 4)
+typedef enum
+{
+ MSN_P2P_VERSION_ONE = 0,
+ MSN_P2P_VERSION_TWO = 1,
+} MsnP2PVersion;
+
typedef struct {
- MsnP2PHeader header;
+ MsnP2PVersion version;
+ union {
+ MsnP2PHeader v1;
+ MsnP2Pv2Header v2;
+ } header;
MsnP2PFooter footer;
} MsnP2PInfo;
@@ -94,7 +104,7 @@
} MsnP2PAppId;
MsnP2PInfo *
-msn_p2p_info_new(void);
+msn_p2p_info_new(MsnP2PVersion version);
MsnP2PInfo *
msn_p2p_info_dup(MsnP2PInfo *info);
--- a/libpurple/protocols/msn/slpmsg.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg.c Mon Mar 07 06:43:26 2011 +0000
@@ -48,7 +48,7 @@
else
slpmsg->slplink = NULL;
- slpmsg->p2p_info = msn_p2p_info_new();
+ slpmsg->p2p_info = msn_p2p_info_new(MSN_P2P_VERSION_ONE);
return slpmsg;
}
--- a/libpurple/protocols/msn/slpmsg_part.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/slpmsg_part.c Mon Mar 07 06:43:26 2011 +0000
@@ -54,7 +54,7 @@
}
part = msn_slpmsgpart_new(NULL);
- part->info = msn_p2p_info_new();
+ part->info = msn_p2p_info_new(MSN_P2P_VERSION_ONE);
/* Extract the binary SLP header */
len = msn_p2p_header_from_wire(part->info, data);
--- a/libpurple/protocols/msn/switchboard.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/switchboard.c Mon Mar 07 06:43:26 2011 +0000
@@ -265,12 +265,6 @@
return;
}
- /* Don't add ourselves either... */
- if (g_str_equal(passport, purple_account_get_username(account))) {
- g_free(passport);
- return;
- }
-
if (!msnuser) {
purple_debug_info("msn","User %s is not on our list.\n", passport);
msnuser = msn_user_new(userlist, passport, NULL);
--- a/libpurple/protocols/msn/user.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/msn/user.c Mon Mar 07 06:43:26 2011 +0000
@@ -223,7 +223,10 @@
{
g_return_val_if_fail(user != NULL, FALSE);
- if (user->friendly_name && name && (!strcmp(user->friendly_name, name) ||
+ if (!name)
+ return FALSE;
+
+ if (user->friendly_name && (!strcmp(user->friendly_name, name) ||
!strcmp(user->passport, name)))
return FALSE;
--- a/libpurple/protocols/mxit/Makefile.am Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/Makefile.am Mon Mar 07 06:43:26 2011 +0000
@@ -33,7 +33,9 @@
roster.c \
roster.h \
splashscreen.c \
- splashscreen.h
+ splashscreen.h \
+ voicevideo.c \
+ voicevideo.h
AM_CFLAGS = $(st)
--- a/libpurple/protocols/mxit/Makefile.mingw Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/Makefile.mingw Mon Mar 07 06:43:26 2011 +0000
@@ -51,7 +51,8 @@
profile.c \
protocol.c \
roster.c \
- splashscreen.c
+ splashscreen.c \
+ voicevideo.c
OBJECTS = $(C_SRC:%.c=%.o)
--- a/libpurple/protocols/mxit/actions.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/actions.c Mon Mar 07 06:43:26 2011 +0000
@@ -314,12 +314,11 @@
{
char version[256];
- g_snprintf( version, sizeof( version ), "MXit libPurple Plugin v%s\n"
+ g_snprintf( version, sizeof( version ),
"MXit Client Protocol v%i.%i\n\n"
"Author:\nPieter Loubser\n\n"
"Contributors:\nAndrew Victor\n\n"
"Testers:\nBraeme Le Roux\n\n",
- MXIT_PLUGIN_VERSION,
( MXIT_CP_PROTO_VESION / 10 ), ( MXIT_CP_PROTO_VESION % 10 ) );
mxit_popup( PURPLE_NOTIFY_MSG_INFO, _( "About" ), version );
--- a/libpurple/protocols/mxit/chunk.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/chunk.c Mon Mar 07 06:43:26 2011 +0000
@@ -406,10 +406,9 @@
* @param chunkdata Chunked-data buffer
* @param mxitId The username who's avatar to download
* @param avatarId The Id of the avatar image (as string)
- * @param imgsize The resolution of the avatar image
* @return The number of bytes encoded in the buffer
*/
-int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize )
+int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId )
{
int pos = 0;
@@ -432,7 +431,7 @@
pos += add_int16( &chunkdata[pos], 1 );
/* image size [4 bytes] */
- pos += add_int32( &chunkdata[pos], imgsize );
+ pos += add_int32( &chunkdata[pos], MXIT_AVATAR_SIZE );
return pos;
}
--- a/libpurple/protocols/mxit/chunk.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/chunk.h Mon Mar 07 06:43:26 2011 +0000
@@ -152,7 +152,7 @@
int mxit_chunk_create_get( char* chunkdata, const char* fileid, int filesize, int offset );
int mxit_chunk_create_received( char* chunkdata, const char* fileid, unsigned char status );
int mxit_chunk_create_set_avatar( char* chunkdata, const unsigned char* data, int datalen );
-int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId, unsigned int imgsize );
+int mxit_chunk_create_get_avatar( char* chunkdata, const char* mxitId, const char* avatarId );
/* Decode chunk */
void mxit_chunk_parse_offer( char* chunkdata, int datalen, struct offerfile_chunk* offer );
--- a/libpurple/protocols/mxit/formcmds.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/formcmds.c Mon Mar 07 06:43:26 2011 +0000
@@ -47,7 +47,11 @@
MXIT_CMD_REPLY, /* Reply (reply) */
MXIT_CMD_PLATREQ, /* Platform Request (platreq) */
MXIT_CMD_SELECTCONTACT, /* Select Contact (selc) */
- MXIT_CMD_IMAGE /* Inline image (img) */
+ MXIT_CMD_IMAGE, /* Inline image (img) */
+ MXIT_CMD_SCREENCONFIG, /* Chat-screen config (csc) */
+ MXIT_CMD_SCREENINFO, /* Chat-screen info (csi) */
+ MXIT_CMD_IMAGESTRIP, /* Image Strip (is) */
+ MXIT_CMD_TABLE /* Table (tbl) */
} MXitCommandType;
@@ -87,7 +91,7 @@
goto done;
}
- /* lets first see if we dont have the inline image already in cache */
+ /* lets first see if we don't have the inline image already in cache */
if (g_hash_table_lookup(iireq->mx->session->iimages, iireq->url)) {
/* inline image found in the cache, so we just ignore this reply */
goto done;
@@ -149,8 +153,16 @@
else if (strcmp(type, "selc") == 0) /* select contact */
return MXIT_CMD_SELECTCONTACT;
}
- else if (strcmp(op, "img") == 0)
- return MXIT_CMD_IMAGE;
+ else if (strcmp(op, "img") == 0) /* inline image */
+ return MXIT_CMD_IMAGE;
+ else if (strcmp(op, "csc") == 0) /* chat-screen config */
+ return MXIT_CMD_SCREENCONFIG;
+ else if (strcmp(op, "csi") == 0) /* chat-screen info */
+ return MXIT_CMD_SCREENINFO;
+ else if (strcmp(op, "is") == 0) /* image-strip */
+ return MXIT_CMD_IMAGESTRIP;
+ else if (strcmp(op, "tbl") == 0) /* table */
+ return MXIT_CMD_TABLE;
}
return MXIT_CMD_UNKNOWN;
@@ -333,7 +345,7 @@
g_string_append_printf(msg, "%s%s>", MXIT_II_TAG, iireq->url);
mx->got_img = TRUE;
- /* lets first see if we dont have the inline image already in cache */
+ /* lets first see if we don't have the inline image already in cache */
if (g_hash_table_lookup(mx->session->iimages, iireq->url)) {
/* inline image found in the cache, so we do not have to request it from the web */
g_free(iireq);
--- a/libpurple/protocols/mxit/login.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/login.c Mon Mar 07 06:43:26 2011 +0000
@@ -84,7 +84,7 @@
session->iimages = g_hash_table_new( g_str_hash, g_str_equal );
session->rx_state = RX_STATE_RLEN;
session->http_interval = MXIT_HTTP_POLL_MIN;
- session->http_last_poll = time( NULL );
+ session->http_last_poll = mxit_now_milli();
return session;
}
@@ -106,7 +106,7 @@
purple_connection_update_progress( session->con, _( "Logging In..." ), 2, 4 );
/* create a timer to send a ping packet if the connection is idle */
- session->last_tx = time( NULL );
+ session->last_tx = mxit_now_milli();
/* encrypt the user password */
session->encpwd = mxit_encrypt_password( session );
@@ -141,9 +141,10 @@
}
/* This timer might already exist if we're registering a new account */
- if ( session->q_timer == 0 )
+ if ( session->q_timer == 0 ) {
/* start the tx queue manager timer */
- session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue, session );
+ session->q_timer = purple_timeout_add_seconds( 2, mxit_manage_queue_slow, session );
+ }
}
@@ -238,7 +239,7 @@
/* nickname */
str = purple_request_fields_get_string( fields, "nickname" );
if ( ( !str ) || ( strlen( str ) < 3 ) ) {
- err = _( "The Display Name you entered is invalid." );
+ err = _( "The Display Name you entered is too short." );
goto out;
}
g_strlcpy( profile->nickname, str, sizeof( profile->nickname ) );
@@ -546,8 +547,8 @@
/* get state */
state = purple_account_get_int( session->acc, MXIT_CONFIG_STATE, MXIT_STATE_LOGIN );
- url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%s&clientid=%s&cat=%s&chalresp=%s&cc=%s&loc=%s&path=%i&brand=%s&model=%s&h=%i&w=%i&ts=%li",
- session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), MXIT_CP_RELEASE, MXIT_CLIENT_ID, MXIT_CP_ARCH,
+ url = g_strdup_printf( "%s?type=getpid&sessionid=%s&login=%s&ver=%i.%i.%i&clientid=%s&cat=%s&chalresp=%s&cc=%s&loc=%s&path=%i&brand=%s&model=%s&h=%i&w=%i&ts=%li",
+ session->logindata->wapserver, session->logindata->sessionid, purple_url_encode( session->acc->username ), PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CLIENT_ID, MXIT_CP_ARCH,
captcha_resp, session->logindata->cc, session->logindata->locale, ( state == MXIT_STATE_REGISTER1 ) ? 0 : 1, MXIT_CP_PLATFORM, MXIT_CP_OS,
MXIT_CAPTCHA_HEIGHT, MXIT_CAPTCHA_WIDTH, time( NULL ) );
url_data = purple_util_fetch_url_request( url, TRUE, MXIT_HTTP_USERAGENT, TRUE, NULL, FALSE, mxit_cb_clientinfo2, session );
@@ -762,6 +763,12 @@
{
purple_debug_info( MXIT_PLUGIN_ID, "mxit_reconnect\n" );
+ /* remove the input cb function */
+ if ( session->con->inpa ) {
+ purple_input_remove( session->con->inpa );
+ session->con->inpa = 0;
+ }
+
/* close existing connection */
session->flags &= ~MXIT_FLAG_CONNECTED;
purple_proxy_connect_cancel_with_handle( session->con );
--- a/libpurple/protocols/mxit/mxit.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.c Mon Mar 07 06:43:26 2011 +0000
@@ -37,6 +37,7 @@
#include "filexfer.h"
#include "actions.h"
#include "multimx.h"
+#include "voicevideo.h"
#ifdef MXIT_LINK_CLICK
@@ -524,7 +525,7 @@
if ( session->http )
return;
- if ( session->last_tx <= time( NULL ) - MXIT_PING_INTERVAL ) {
+ if ( session->last_tx <= ( mxit_now_milli() - ( MXIT_PING_INTERVAL * 1000 ) ) ) {
/*
* this connection has been idle for too long, better ping
* the server before it kills our connection.
@@ -559,6 +560,8 @@
*/
static void mxit_get_info( PurpleConnection *gc, const char *who )
{
+ PurpleBuddy* buddy;
+ struct contact* contact;
struct MXitSession* session = (struct MXitSession*) gc->proto_data;
const char* profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME,
CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_REGCOUNTRY, CP_PROFILE_LASTSEEN,
@@ -566,6 +569,22 @@
purple_debug_info( MXIT_PLUGIN_ID, "mxit_get_info: '%s'\n", who );
+ /* find the buddy information for this contact (reference: "libpurple/blist.h") */
+ buddy = purple_find_buddy( session->acc, who );
+ if ( !buddy ) {
+ purple_debug_warning( MXIT_PLUGIN_ID, "mxit_get_info: unable to find the buddy '%s'\n", who );
+ return;
+ }
+
+ contact = purple_buddy_get_protocol_data( buddy );
+ if ( !contact )
+ return;
+
+ /* only MXit users have profiles */
+ if ( contact->type != MXIT_TYPE_MXIT ) {
+ mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "No profile available" ), _( "This contact does not have a profile." ) );
+ return;
+ }
/* send profile request */
mxit_send_extprofile_request( session, who, ARRAY_SIZE( profilelist ), profilelist );
@@ -588,7 +607,33 @@
/*------------------------------------------------------------------------
- * Buddy list menu.
+ * Re-Invite was selected from the buddy-list menu.
+ *
+ * @param node The entry in the buddy list.
+ * @param ignored (not used)
+ */
+static void mxit_reinvite( PurpleBlistNode *node, gpointer ignored )
+{
+ PurpleBuddy* buddy;
+ struct contact* contact;
+ PurpleConnection* gc;
+ struct MXitSession* session;
+
+ buddy = (PurpleBuddy *)node;
+ gc = purple_account_get_connection( purple_buddy_get_account( buddy ) );
+ session = gc->proto_data;
+
+ contact = purple_buddy_get_protocol_data( (PurpleBuddy*) node );
+ if ( !contact )
+ return;
+
+ /* send a new invite */
+ mxit_send_invite( session, contact->username, contact->alias, contact->groupname );
+}
+
+
+/*------------------------------------------------------------------------
+ * Buddy-list menu.
*
* @param node The entry in the buddy list.
*/
@@ -597,6 +642,7 @@
PurpleBuddy* buddy;
struct contact* contact;
GList* m = NULL;
+ PurpleMenuAction* act;
if ( !PURPLE_BLIST_NODE_IS_BUDDY( node ) )
return NULL;
@@ -606,6 +652,12 @@
if ( !contact )
return NULL;
+ if ( ( contact->subtype == MXIT_SUBTYPE_DELETED ) || ( contact->subtype == MXIT_SUBTYPE_REJECTED ) || ( contact->subtype == MXIT_SUBTYPE_NONE ) ) {
+ /* contact is in Deleted, Rejected or None state */
+ act = purple_menu_action_new( _( "Re-Invite" ), PURPLE_CALLBACK( mxit_reinvite ), NULL, NULL );
+ m = g_list_append(m, act);
+ }
+
return m;
}
@@ -686,8 +738,8 @@
NULL, /* attention_types */
sizeof( PurplePluginProtocolInfo ), /* struct_size */
mxit_get_text_table, /* get_account_text_table */
- NULL, /* initiate_media */
- NULL, /* get_media_caps */
+ mxit_media_initiate, /* initiate_media */
+ mxit_media_caps, /* get_media_caps */
mxit_get_moods, /* get_moods */
NULL, /* set_public_alias */
NULL /* get_public_alias */
@@ -706,7 +758,7 @@
MXIT_PLUGIN_ID, /* plugin id (must be unique) */
MXIT_PLUGIN_NAME, /* plugin name (this will be displayed in the UI) */
- MXIT_PLUGIN_VERSION, /* version of the plugin */
+ DISPLAY_VERSION, /* version of the plugin */
MXIT_PLUGIN_SUMMARY, /* short summary of the plugin */
MXIT_PLUGIN_DESC, /* description of the plugin (can be long) */
--- a/libpurple/protocols/mxit/mxit.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.h Mon Mar 07 06:43:26 2011 +0000
@@ -63,13 +63,12 @@
/* Plugin details */
#define MXIT_PLUGIN_ID "prpl-loubserp-mxit"
#define MXIT_PLUGIN_NAME "MXit"
-#define MXIT_PLUGIN_VERSION "2.4.0"
#define MXIT_PLUGIN_EMAIL "Pieter Loubser <libpurple@mxit.com>"
#define MXIT_PLUGIN_WWW "http://www.mxit.com"
#define MXIT_PLUGIN_SUMMARY "MXit Protocol Plugin"
#define MXIT_PLUGIN_DESC "MXit"
-#define MXIT_HTTP_USERAGENT "libpurple-"MXIT_PLUGIN_VERSION
+#define MXIT_HTTP_USERAGENT "libpurple-"DISPLAY_VERSION
/* default connection settings */
@@ -111,7 +110,6 @@
/* define this to enable the link clicking support */
#define MXIT_LINK_CLICK
-
#ifdef MXIT_LINK_CLICK
#define MXIT_LINK_PREFIX "gopher://"
#define MXIT_LINK_KEY "MXIT"
@@ -137,10 +135,13 @@
unsigned int http_seqno; /* HTTP request sequence number */
guint http_timer_id; /* timer resource id (pidgin) */
int http_interval; /* poll inverval */
- time_t http_last_poll; /* the last time a poll has been sent */
+ gint64 http_last_poll; /* the last time a poll has been sent */
guint http_handler; /* HTTP connection handler */
void* http_out_req; /* HTTP outstanding request */
+ /* other servers */
+ char voip_server[HOST_NAME_MAX]; /* voice/video server */
+
/* client */
struct login_data* logindata;
char* encpwd; /* encrypted password */
@@ -159,7 +160,7 @@
/* transmit */
struct tx_queue queue; /* transmit packet queue (FIFO mode) */
- time_t last_tx; /* timestamp of last packet sent */
+ gint64 last_tx; /* timestamp of last packet sent */
int outack; /* outstanding ack packet */
guint q_timer; /* timer handler for managing queue */
@@ -169,7 +170,7 @@
unsigned int rx_i; /* receive buffer current index */
int rx_res; /* amount of bytes still outstanding for the current packet */
char rx_state; /* current receiver state */
- time_t last_rx; /* timestamp of last packet received */
+ gint64 last_rx; /* timestamp of last packet received */
GList* active_chats; /* list of all our contacts we received messages from (active chats) */
/* groupchat */
--- a/libpurple/protocols/mxit/profile.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/profile.c Mon Mar 07 06:43:26 2011 +0000
@@ -108,10 +108,10 @@
*/
static const char* datetime( gint64 msecs )
{
- time_t secs = msecs / 1000;
+ time_t secs = msecs / 1000;
- struct tm t;
- localtime_r( &secs, &t );
+ struct tm t;
+ localtime_r( &secs, &t );
return purple_utf8_strftime( "%d-%m-%Y %H:%M:%S", &t );
}
@@ -140,13 +140,10 @@
purple_notify_user_info_add_pair( info, _( "Display Name" ), profile->nickname );
purple_notify_user_info_add_pair( info, _( "Birthday" ), profile->birthday );
purple_notify_user_info_add_pair( info, _( "Gender" ), profile->male ? _( "Male" ) : _( "Female" ) );
-// purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
/* optional information */
-// purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
purple_notify_user_info_add_pair( info, _( "First Name" ), profile->firstname );
purple_notify_user_info_add_pair( info, _( "Last Name" ), profile->lastname );
-// purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
purple_notify_user_info_add_pair( info, _( "Country" ), profile->regcountry );
purple_notify_user_info_add_section_break( info );
--- a/libpurple/protocols/mxit/protocol.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.c Mon Mar 07 06:43:26 2011 +0000
@@ -37,6 +37,7 @@
#include "login.h"
#include "formcmds.h"
#include "http.h"
+#include "voicevideo.h"
#define MXIT_MS_OFFSET 3
@@ -45,6 +46,18 @@
#define CP_REC_TERM ( ( session->http ) ? CP_HTTP_REC_TERM : CP_SOCK_REC_TERM )
+/*------------------------------------------------------------------------
+ * return the current timestamp in milliseconds
+ */
+gint64 mxit_now_milli( void )
+{
+ GTimeVal now;
+
+ g_get_current_time( &now );
+
+ return ( ( now.tv_sec * 1000 ) + ( now.tv_usec / 1000 ) );
+}
+
/*------------------------------------------------------------------------
* Display a notification popup message to the user.
@@ -411,7 +424,7 @@
}
/* update the timestamp of the last-transmitted packet */
- session->last_tx = time( NULL );
+ session->last_tx = mxit_now_milli();
/*
* we need to remember that we are still waiting for the ACK from
@@ -474,17 +487,13 @@
packet->datalen = datalen;
- /*
- * shortcut: first check if there are any commands still outstanding.
- * if not, then we might as well just write this packet directly and
- * skip the whole queueing thing
- */
- if ( session->outack == 0 ) {
- /* no outstanding ACKs, so we might as well write it directly */
+ /* shortcut */
+ if ( ( session->queue.count == 0 ) && ( session->outack == 0 ) ) {
+ /* the queue is empty and there are no outstanding acks so we can write it directly */
mxit_send_packet( session, packet );
}
else {
- /* ACK still outstanding, so we need to queue this request until we have the ACK */
+ /* we need to queue this packet */
if ( ( packet->cmd == CP_CMD_PING ) || ( packet->cmd == CP_CMD_POLL ) ) {
/* we do NOT queue HTTP poll nor socket ping packets */
@@ -503,42 +512,89 @@
/*------------------------------------------------------------------------
- * Callback to manage the packet send queue (send next packet, timeout's, etc).
+ * Manage the packet send queue (send next packet, timeout's, etc).
*
* @param session The MXit session object
*/
-gboolean mxit_manage_queue( gpointer user_data )
+static void mxit_manage_queue( struct MXitSession* session )
{
- struct MXitSession* session = (struct MXitSession*) user_data;
struct tx_packet* packet = NULL;
+ gint64 now = mxit_now_milli();
if ( !( session->flags & MXIT_FLAG_CONNECTED ) ) {
/* we are not connected, so ignore the queue */
- return TRUE;
+ return;
}
else if ( session->outack > 0 ) {
/* we are still waiting for an outstanding ACK from the MXit server */
- if ( session->last_tx <= time( NULL ) - MXIT_ACK_TIMEOUT ) {
+ if ( session->last_tx <= mxit_now_milli() - ( MXIT_ACK_TIMEOUT * 1000 ) ) {
/* ack timeout! so we close the connection here */
purple_debug_info( MXIT_PLUGIN_ID, "mxit_manage_queue: Timeout awaiting ACK for command '%i'\n", session->outack );
purple_connection_error( session->con, _( "Timeout while waiting for a response from the MXit server." ) );
}
- return TRUE;
+ return;
+ }
+
+ /*
+ * the mxit server has flood detection and it prevents you from sending messages to fast.
+ * this is a self defense mechanism, a very annoying feature. so the client must ensure that
+ * it does not send messages too fast otherwise mxit will ignore the user for 30 seconds.
+ * this is what we are trying to avoid here..
+ */
+ if ( session->last_tx > ( now - MXIT_TX_DELAY ) ) {
+ /* we need to wait a little before sending the next packet, so schedule a wakeup call */
+ gint64 tdiff = now - ( session->last_tx );
+ guint delay = ( MXIT_TX_DELAY - tdiff ) + 9;
+ if ( delay <= 0 )
+ delay = MXIT_TX_DELAY;
+ purple_timeout_add( delay, mxit_manage_queue_fast, session );
+ }
+ else {
+ /* get the next packet from the queue to send */
+ packet = pop_tx_packet( session );
+ if ( packet != NULL ) {
+ /* there was a packet waiting to be sent to the server, now is the time to do something about it */
+
+ /* send the packet to MXit server */
+ mxit_send_packet( session, packet );
+ }
}
-
- packet = pop_tx_packet( session );
- if ( packet != NULL ) {
- /* there was a packet waiting to be sent to the server, now is the time to do something about it */
-
- /* send the packet to MXit server */
- mxit_send_packet( session, packet );
- }
-
+}
+
+
+/*------------------------------------------------------------------------
+ * Slow callback to manage the packet send queue.
+ *
+ * @param session The MXit session object
+ */
+gboolean mxit_manage_queue_slow( gpointer user_data )
+{
+ struct MXitSession* session = (struct MXitSession*) user_data;
+
+ mxit_manage_queue( session );
+
+ /* continue running */
return TRUE;
}
/*------------------------------------------------------------------------
+ * Fast callback to manage the packet send queue.
+ *
+ * @param session The MXit session object
+ */
+gboolean mxit_manage_queue_fast( gpointer user_data )
+{
+ struct MXitSession* session = (struct MXitSession*) user_data;
+
+ mxit_manage_queue( session );
+
+ /* stop running */
+ return FALSE;
+}
+
+
+/*------------------------------------------------------------------------
* Callback to manage HTTP server polling (HTTP connections ONLY)
*
* @param session The MXit session object
@@ -547,9 +603,9 @@
{
struct MXitSession* session = (struct MXitSession*) user_data;
gboolean poll = FALSE;
- time_t now = time( NULL );
+ gint64 now = mxit_now_milli();
int polldiff;
- int rxdiff;
+ gint64 rxdiff;
if ( !( session->flags & MXIT_FLAG_LOGGEDIN ) ) {
/* we only poll if we are actually logged in */
@@ -579,7 +635,7 @@
if ( poll ) {
/* send poll request */
- session->http_last_poll = time( NULL );
+ session->http_last_poll = mxit_now_milli();
mxit_send_poll( session );
}
@@ -638,21 +694,36 @@
const char* locale;
char data[CP_MAX_PACKET];
int datalen;
+ char* clientVersion;
+ unsigned int features = MXIT_CP_FEATURES;
locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE );
+ /* Voice and Video supported */
+ if (mxit_audio_enabled() && mxit_video_enabled())
+ features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO);
+ else if (mxit_audio_enabled())
+ features |= MXIT_CF_VOICE;
+
+ /* generate client version string (eg, P-2.7.10-Y-PURPLE) */
+ clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM );
+
/* convert the packet to a byte stream */
datalen = snprintf( data, sizeof( data ),
"ms=%s%c%s%c%i%c%s%c" /* "ms"=password\1version\1maxreplyLen\1name\1 */
"%s%c%i%c%s%c%s%c" /* dateOfBirth\1gender\1location\1capabilities\1 */
- "%s%c%i%c%s%c%s", /* dc\1features\1dialingcode\1locale */
- session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM,
+ "%s%c%i%c%s%c%s" /* dc\1features\1dialingcode\1locale */
+ "%c%i%c%i", /* \1protocolVer\1lastRosterUpdate */
+ session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, CP_MAX_FILESIZE, CP_FLD_TERM, profile->nickname, CP_FLD_TERM,
profile->birthday, CP_FLD_TERM, ( profile->male ) ? 1 : 0, CP_FLD_TERM, MXIT_DEFAULT_LOC, CP_FLD_TERM, MXIT_CP_CAP, CP_FLD_TERM,
- session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale
+ session->distcode, CP_FLD_TERM, features, CP_FLD_TERM, session->dialcode, CP_FLD_TERM, locale,
+ CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0
);
/* queue packet for transmission */
mxit_queue_packet( session, data, datalen, CP_CMD_REGISTER );
+
+ g_free( clientVersion );
}
@@ -663,21 +734,32 @@
*/
void mxit_send_login( struct MXitSession* session )
{
- const char* splashId;
- const char* locale;
- char data[CP_MAX_PACKET];
- int datalen;
+ const char* splashId;
+ const char* locale;
+ char data[CP_MAX_PACKET];
+ int datalen;
+ char* clientVersion;
+ unsigned int features = MXIT_CP_FEATURES;
locale = purple_account_get_string( session->acc, MXIT_CONFIG_LOCALE, MXIT_DEFAULT_LOCALE );
+ /* Voice and Video supported */
+ if (mxit_audio_enabled() && mxit_video_enabled())
+ features |= (MXIT_CF_VOICE | MXIT_CF_VIDEO);
+ else if (mxit_audio_enabled())
+ features |= MXIT_CF_VOICE;
+
+ /* generate client version string (eg, P-2.7.10-Y-PURPLE) */
+ clientVersion = g_strdup_printf( "%c-%i.%i.%i-%s-%s", MXIT_CP_DISTCODE, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_MICRO_VERSION, MXIT_CP_ARCH, MXIT_CP_PLATFORM );
+
/* convert the packet to a byte stream */
datalen = snprintf( data, sizeof( data ),
"ms=%s%c%s%c%i%c" /* "ms"=password\1version\1getContacts\1 */
"%s%c%s%c%i%c" /* capabilities\1dc\1features\1 */
"%s%c%s%c" /* dialingcode\1locale\1 */
"%i%c%i%c%i", /* maxReplyLen\1protocolVer\1lastRosterUpdate */
- session->encpwd, CP_FLD_TERM, MXIT_CP_VERSION, CP_FLD_TERM, 1, CP_FLD_TERM,
- MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, MXIT_CP_FEATURES, CP_FLD_TERM,
+ session->encpwd, CP_FLD_TERM, clientVersion, CP_FLD_TERM, 1, CP_FLD_TERM,
+ MXIT_CP_CAP, CP_FLD_TERM, session->distcode, CP_FLD_TERM, features, CP_FLD_TERM,
session->dialcode, CP_FLD_TERM, locale, CP_FLD_TERM,
CP_MAX_FILESIZE, CP_FLD_TERM, MXIT_CP_PROTO_VESION, CP_FLD_TERM, 0
);
@@ -689,6 +771,8 @@
/* queue packet for transmission */
mxit_queue_packet( session, data, datalen, CP_CMD_LOGIN );
+
+ g_free( clientVersion );
}
@@ -732,7 +816,7 @@
* @param session The MXit session object
* @param username Username who's profile is being requested (NULL = our own)
* @param nr_attribs Number of attributes being requested
- * @param attributes The names of the attributes
+ * @param attribute The names of the attributes
*/
void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] )
{
@@ -742,7 +826,8 @@
datalen = snprintf( data, sizeof( data ),
"ms=%s%c%i", /* "ms="mxitid\1nr_attributes */
- (username ? username : ""), CP_FLD_TERM, nr_attrib);
+ ( username ? username : "" ), CP_FLD_TERM, nr_attrib
+ );
/* add attributes */
for ( i = 0; i < nr_attrib; i++ )
@@ -790,6 +875,63 @@
/*------------------------------------------------------------------------
+ * Send packet to request list of suggested friends.
+ *
+ * @param session The MXit session object
+ * @param max Maximum number of results to return
+ * @param nr_attribs Number of attributes being requested
+ * @param attribute The names of the attributes
+ */
+void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] )
+{
+ char data[CP_MAX_PACKET];
+ int datalen;
+ unsigned int i;
+
+ /* convert the packet to a byte stream */
+ datalen = snprintf( data, sizeof( data ),
+ "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */
+ CP_SUGGEST_FRIENDS, CP_FLD_TERM, "", CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib );
+
+ /* add attributes */
+ for ( i = 0; i < nr_attrib; i++ )
+ datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] );
+
+ /* queue packet for transmission */
+ mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS );
+}
+
+
+/*------------------------------------------------------------------------
+ * Send packet to perform a search for users.
+ *
+ * @param session The MXit session object
+ * @param max Maximum number of results to return
+ * @param text The search text
+ * @param nr_attribs Number of attributes being requested
+ * @param attribute The names of the attributes
+ */
+void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] )
+{
+ char data[CP_MAX_PACKET];
+ int datalen;
+ unsigned int i;
+
+ /* convert the packet to a byte stream */
+ datalen = snprintf( data, sizeof( data ),
+ "ms=%i%c%s%c%i%c%i", /* inputType \1 input \ 1 maxSuggestions \1 numAttributes \1 name0 ... \1 nameN */
+ CP_SUGGEST_SEARCH, CP_FLD_TERM, text, CP_FLD_TERM, max, CP_FLD_TERM, nr_attrib );
+
+ /* add attributes */
+ for ( i = 0; i < nr_attrib; i++ )
+ datalen += sprintf( data + datalen, "%c%s", CP_FLD_TERM, attribute[i] );
+
+ /* queue packet for transmission */
+ mxit_queue_packet( session, data, datalen, CP_CMD_SUGGESTCONTACTS );
+}
+
+
+/*------------------------------------------------------------------------
* Send a presence update packet to the MXit server.
*
* @param session The MXit session object
@@ -1039,7 +1181,6 @@
* @param nr_usernames Number of users being invited
* @param usernames The usernames of the users being invited
*/
-
void mxit_send_groupchat_invite( struct MXitSession* session, const char* roomid, int nr_usernames, const char* usernames[] )
{
char data[CP_MAX_PACKET];
@@ -1271,7 +1412,7 @@
/* map chunk header over data buffer */
chunk = &data[datalen];
- size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId, MXIT_AVATAR_SIZE );
+ size = mxit_chunk_create_get_avatar( chunk_data(chunk), mxitId, avatarId );
if ( size < 0 ) {
purple_debug_error( MXIT_PLUGIN_ID, "Error creating get avatar chunk (%i)\n", size );
return;
@@ -1322,6 +1463,10 @@
if ( records[1]->fcount >= 9 )
session->uid = g_strdup( records[1]->fields[8]->data );
+ /* extract VoIP server (from protocol 6.2) */
+ if ( records[1]->fcount >= 11 )
+ g_strlcpy( session->voip_server, records[1]->fields[10]->data, sizeof( session->voip_server ) );
+
/* display the current splash-screen */
if ( splash_popup_enabled( session ) )
splash_display( session );
@@ -1567,13 +1712,13 @@
*/
static void mxit_parse_cmd_presence( struct MXitSession* session, struct record** records, int rcount )
{
- struct record* rec;
int i;
purple_debug_info( MXIT_PLUGIN_ID, "mxit_parse_cmd_presence (%i recs)\n", rcount );
for ( i = 0; i < rcount; i++ ) {
- rec = records[i];
+ struct record* rec = records[i];
+ int flags = 0;
if ( rec->fcount < 6 ) {
purple_debug_error( MXIT_PLUGIN_ID, "BAD PRESENCE RECORD! %i fields\n", rec->fcount );
@@ -1582,12 +1727,15 @@
/*
* The format of the record is:
- * contactAddressN\1presenceN\1moodN\1customMoodN\1statusMsgN\1avatarIdN
+ * contactAddressN \1 presenceN \1 moodN \1 customMoodN \1 statusMsgN \1 avatarIdN [ \1 flagsN ]
*/
mxit_strip_domain( rec->fields[0]->data ); /* contactAddress */
+ if ( rec->fcount >= 7 ) /* flags field is included */
+ flags = atoi( rec->fields[6]->data );
+
mxit_update_buddy_presence( session, rec->fields[0]->data, atoi( rec->fields[1]->data ), atoi( rec->fields[2]->data ),
- rec->fields[3]->data, rec->fields[4]->data );
+ rec->fields[3]->data, rec->fields[4]->data, flags );
mxit_update_buddy_avatar( session, rec->fields[0]->data, rec->fields[5]->data );
}
}
@@ -1908,7 +2056,7 @@
{
/* ignore ping/poll packets */
if ( ( packet->cmd != CP_CMD_PING ) && ( packet->cmd != CP_CMD_POLL ) )
- session->last_rx = time( NULL );
+ session->last_rx = mxit_now_milli();
/*
* when we pass the packet records to the next level for parsing
--- a/libpurple/protocols/mxit/protocol.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.h Mon Mar 07 06:43:26 2011 +0000
@@ -75,6 +75,8 @@
#define MXIT_CF_NO_AVATARS 0x200000
#define MXIT_CF_GAMING 0x400000
#define MXIT_CF_GAMING_UPDATE 0x800000
+#define MXIT_CF_VOICE 0x1000000
+#define MXIT_CF_VIDEO 0x2000000
/* Client features supported by this implementation */
#define MXIT_CP_FEATURES ( MXIT_CF_FILE_TRANSFER | MXIT_CF_FILE_ACCESS | MXIT_CF_AUDIO | MXIT_CF_MARKUP | MXIT_CF_EXT_MARKUP | MXIT_CF_NO_GATEWAYS | MXIT_CF_IMAGES | MXIT_CF_COMMANDS | MXIT_CF_VIBES | MXIT_CF_MIDP2 )
@@ -82,14 +84,13 @@
#define MXIT_PING_INTERVAL ( 5 * 60 ) /* ping the server after X seconds of being idle (5 minutes) */
#define MXIT_ACK_TIMEOUT ( 30 ) /* timeout after waiting X seconds for an ack from the server (30 seconds) */
+#define MXIT_TX_DELAY ( 100 ) /* delay between sending consecutive packets (100 ms) */
/* MXit client version */
-#define MXIT_CP_DISTCODE "P" /* client distribution code (magic, do not touch!) */
-#define MXIT_CP_RELEASE "5.9.0" /* client version */
+#define MXIT_CP_DISTCODE 'P' /* client distribution code (magic, do not touch!) */
#define MXIT_CP_ARCH "Y" /* client architecture series (Y not for Yoda but for PC-client) */
#define MXIT_CLIENT_ID "LP" /* client ID as specified by MXit */
#define MXIT_CP_PLATFORM "PURPLE" /* client platform */
-#define MXIT_CP_VERSION MXIT_CP_DISTCODE"-"MXIT_CP_RELEASE"-"MXIT_CP_ARCH"-"MXIT_CP_PLATFORM
#define MXIT_CP_PROTO_VESION 60 /* client protocol version */
/* set operating system name */
@@ -107,7 +108,7 @@
#define MXIT_CP_CAP "utf8=true;cid="MXIT_CLIENT_ID
/* Client settings */
-#define MAX_QUEUE_SIZE ( 1 << 4 ) /* tx queue size (16 packets) */
+#define MAX_QUEUE_SIZE ( 1 << 5 ) /* tx queue size (32 packets) */
#define MXIT_POPUP_WIN_NAME "MXit Notification" /* popup window name */
#define MXIT_MAX_ATTRIBS 10 /* maximum profile attributes supported */
#define MXIT_DEFAULT_LOCALE "en" /* default locale setting */
@@ -125,6 +126,7 @@
#define CP_CMD_TX_MSG 0x000A /* (10) send new message */
#define CP_CMD_REGISTER 0x000B /* (11) register */
//#define CP_CMD_PROFILE_SET 0x000C /* (12) set profile (DEPRECATED see CP_CMD_EXTPROFILE_SET) */
+#define CP_CMD_SUGGESTCONTACTS 0x000D /* (13) suggest contacts */
#define CP_CMD_POLL 0x0011 /* (17) poll the HTTP server for an update */
//#define CP_CMD_PROFILE_GET 0x001A /* (26) get profile (DEPRECATED see CP_CMD_EXTPROFILE_GET) */
#define CP_CMD_MEDIA 0x001B /* (27) get multimedia message */
@@ -202,6 +204,12 @@
/* profile flags */
#define CP_PROF_DOBLOCKED 0x40 /* date-of-birth cannot be changed */
+/* suggestion types */
+#define CP_SUGGEST_ADDRESSBOOK 0 /* address book search */
+#define CP_SUGGEST_FRIENDS 1 /* suggested friends */
+#define CP_SUGGEST_SEARCH 2 /* free-text search */
+#define CP_SUGGEST_MXITID 3 /* MXitId search */
+
/* define this to enable protocol debugging (very verbose logging) */
#define DEBUG_PROTOCOL
@@ -277,7 +285,8 @@
gboolean find_active_chat( const GList* chats, const char* who );
void mxit_cb_rx( gpointer data, gint source, PurpleInputCondition cond );
-gboolean mxit_manage_queue( gpointer user_data );
+gboolean mxit_manage_queue_slow( gpointer user_data );
+gboolean mxit_manage_queue_fast( gpointer user_data );
gboolean mxit_manage_polling( gpointer user_data );
void mxit_send_register( struct MXitSession* session );
@@ -293,6 +302,9 @@
void mxit_send_extprofile_update( struct MXitSession* session, const char* password, unsigned int nr_attrib, const char* attributes );
void mxit_send_extprofile_request( struct MXitSession* session, const char* username, unsigned int nr_attrib, const char* attribute[] );
+void mxit_send_suggest_friends( struct MXitSession* session, int max, unsigned int nr_attrib, const char* attribute[] );
+void mxit_send_suggest_search( struct MXitSession* session, int max, const char* text, unsigned int nr_attrib, const char* attribute[] );
+
void mxit_send_invite( struct MXitSession* session, const char* username, const char* alias, const char* groupname );
void mxit_send_remove( struct MXitSession* session, const char* username );
void mxit_send_allow_sub( struct MXitSession* session, const char* username, const char* alias );
@@ -314,6 +326,7 @@
int mxit_parse_packet( struct MXitSession* session );
void dump_bytes( struct MXitSession* session, const char* buf, int len );
void mxit_close_connection( struct MXitSession* session );
+gint64 mxit_now_milli( void );
#endif /* _MXIT_PROTO_H_ */
--- a/libpurple/protocols/mxit/roster.c Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/roster.c Mon Mar 07 06:43:26 2011 +0000
@@ -443,8 +443,9 @@
* @param mood The new mood for the contact
* @param customMood The custom mood identifier
* @param statusMsg This is the contact's status message
+ * @param flags The contact's presence flags.
*/
-void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg )
+void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags )
{
PurpleBuddy* buddy = NULL;
struct contact* contact = NULL;
@@ -470,6 +471,7 @@
contact->presence = presence;
contact->mood = mood;
+ contact->capabilities = flags;
/* validate mood */
if (( contact->mood < MXIT_MOOD_NONE ) || ( contact->mood > MXIT_MOOD_STRESSED ))
--- a/libpurple/protocols/mxit/roster.h Mon Mar 07 06:42:57 2011 +0000
+++ b/libpurple/protocols/mxit/roster.h Mon Mar 07 06:43:26 2011 +0000
@@ -79,6 +79,11 @@
#define MXIT_CFLAG_FOCUS_SEND_BLANK 0x20000
+/* MXit presence flags */
+#define MXIT_PFLAG_VOICE 0x1
+#define MXIT_PFLAG_VIDEO 0x2
+
+
/* Subscription types */
#define MXIT_SUBTYPE_BOTH 'B'
#define MXIT_SUBTYPE_PENDING 'P'
@@ -108,6 +113,7 @@
short mood; /* contact current mood */
int flags; /* contact flags */
short presence; /* presence state */
+ int capabilities; /* contact capabilities */
short subtype; /* subscription type */
char* msg; /* invite/rejection message */
@@ -129,7 +135,7 @@
/* MXit Protocol callbacks */
void mxit_update_contact( struct MXitSession* session, struct contact* contact );
-void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg );
+void mxit_update_buddy_presence( struct MXitSession* session, const char* username, short presence, short mood, const char* customMood, const char* statusMsg, int flags );
void mxit_update_buddy_avatar( struct MXitSession* session, const char* username, const char* avatarId );
void mxit_new_subscription( struct MXitSession* session, struct contact* contact );
void mxit_update_blist( struct MXitSession* session );
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/mxit/voicevideo.c Mon Mar 07 06:43:26 2011 +0000
@@ -0,0 +1,154 @@
+/*
+ * MXit Protocol libPurple Plugin
+ *
+ * -- voice & video --
+ *
+ * Andrew Victor <libpurple@mxit.com>
+ *
+ * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd.
+ * <http://www.mxitlifestyle.com>
+ *
+ * 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 "purple.h"
+#include "mxit.h"
+#include "roster.h"
+#include "voicevideo.h"
+
+#if defined(USE_VV) && defined(MXIT_DEV_VV)
+
+#warning "MXit VV support enabled."
+
+/*------------------------------------------------------------------------
+ * Does this client support Voice?
+ */
+gboolean mxit_audio_enabled(void)
+{
+ PurpleMediaManager *manager = purple_media_manager_get();
+ PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager);
+
+ return (caps & PURPLE_MEDIA_CAPS_AUDIO);
+}
+
+/*------------------------------------------------------------------------
+ * Does this client support Voice and Video?
+ */
+gboolean mxit_video_enabled(void)
+{
+ PurpleMediaManager *manager = purple_media_manager_get();
+ PurpleMediaCaps caps = purple_media_manager_get_ui_caps(manager);
+
+ return (caps & PURPLE_MEDIA_CAPS_VIDEO);
+}
+
+/*------------------------------------------------------------------------
+ * Return the list of media capabilities this contact supports.
+ *
+ * @param account The MXit account object
+ * @param who The username of the contact.
+ * @return The media capabilities supported
+ */
+PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who)
+{
+ struct MXitSession* session = purple_account_get_connection(account)->proto_data;
+ PurpleBuddy* buddy;
+ struct contact* contact;
+ PurpleMediaCaps capa = PURPLE_MEDIA_CAPS_NONE;
+
+ purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_caps: buddy '%s'\n", who);
+
+ /* We need to have a voice/video server */
+ if (strlen(session->voip_server) == 0)
+ return PURPLE_MEDIA_CAPS_NONE;
+
+ /* find the buddy information for this contact (reference: "libpurple/blist.h") */
+ buddy = purple_find_buddy(account, who);
+ if (!buddy) {
+ purple_debug_warning(MXIT_PLUGIN_ID, "mxit_media_caps: unable to find the buddy '%s'\n", who);
+ return PURPLE_MEDIA_CAPS_NONE;
+ }
+
+ contact = purple_buddy_get_protocol_data(buddy);
+ if (!contact)
+ return PURPLE_MEDIA_CAPS_NONE;
+
+ /* can only communicate with MXit users */
+ if (contact->type != MXIT_TYPE_MXIT)
+ return PURPLE_MEDIA_CAPS_NONE;
+
+ /* and only with contacts in the 'Both' subscription state */
+ if (contact->subtype != MXIT_SUBTYPE_BOTH)
+ return PURPLE_MEDIA_CAPS_NONE;
+
+ /* and only when they're online */
+ if (contact->presence == MXIT_PRESENCE_OFFLINE)
+ return MXIT_PRESENCE_OFFLINE;
+
+ /* they support voice-only */
+ if (contact->capabilities & MXIT_PFLAG_VOICE)
+ capa |= PURPLE_MEDIA_CAPS_AUDIO;
+
+ /* they support voice-and-video */
+ if (contact->capabilities & MXIT_PFLAG_VIDEO)
+ capa |= (PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_AUDIO_VIDEO);
+
+ return capa;
+}
+
+
+/*------------------------------------------------------------------------
+ * Initiate a voice/video session with a contact.
+ *
+ * @param account The MXit account object
+ * @param who The username of the contact.
+ * @param type The type of media session to initiate
+ * @return TRUE if session was initiated
+ */
+gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type)
+{
+ purple_debug_info(MXIT_PLUGIN_ID, "mxit_media_initiate: buddy '%s'\n", who);
+
+ return FALSE;
+}
+
+#else
+
+/*
+ * Voice and Video not supported.
+ */
+
+gboolean mxit_audio_enabled(void)
+{
+ return FALSE;
+}
+
+gboolean mxit_video_enabled(void)
+{
+ return FALSE;
+}
+
+PurpleMediaCaps mxit_media_caps(PurpleAccount *account, const char *who)
+{
+ return PURPLE_MEDIA_CAPS_NONE;
+}
+
+gboolean mxit_media_initiate(PurpleAccount *account, const char *who, PurpleMediaSessionType type)
+{
+ return FALSE;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/mxit/voicevideo.h Mon Mar 07 06:43:26 2011 +0000
@@ -0,0 +1,41 @@
+/*
+ * MXit Protocol libPurple Plugin
+ *
+ * -- voice & video --
+ *
+ * Andrew Victor <libpurple@mxit.com>
+ *
+ * (C) Copyright 2010 MXit Lifestyle (Pty) Ltd.
+ * <http://www.mxitlifestyle.com>
+ *
+ * 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 _MXIT_VOICEVICEO_H_
+#define _MXIT_VOICEVIDEO_H_
+
+#include "media.h"
+
+
+#undef MXIT_DEV_VV
+
+
+gboolean mxit_audio_enabled(void);
+gboolean mxit_video_enabled(void);
+PurpleMediaCaps mxit_media_caps(PurpleAccount* account, const char* who);
+gboolean mxit_media_initiate(PurpleAccount* account, const char* who, PurpleMediaSessionType type);
+
+
+#endif /* _MXIT_VOICEVIDEO_H_ */
--- a/pidgin/Makefile.am Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/Makefile.am Mon Mar 07 06:43:26 2011 +0000
@@ -156,7 +156,6 @@
$(SM_LIBS) \
$(INTLLIBS) \
$(GTKSPELL_LIBS) \
- $(STARTUP_NOTIFICATION_LIBS) \
$(LIBXML_LIBS) \
$(GTK_LIBS) \
$(top_builddir)/libpurple/libpurple.la
@@ -180,7 +179,6 @@
$(GTK_CFLAGS) \
$(DBUS_CFLAGS) \
$(GTKSPELL_CFLAGS) \
- $(STARTUP_NOTIFICATION_CFLAGS) \
$(LIBXML_CFLAGS) \
$(INTGG_CFLAGS)
endif # ENABLE_GTK
--- a/pidgin/gtkblist.c Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/gtkblist.c Mon Mar 07 06:43:26 2011 +0000
@@ -7743,7 +7743,7 @@
gtk_tree_store_append(gtkblist->treemodel, iter, &groupiter);
return;
} else {
- sort_method_none(node, blist, groupiter, cur, iter);
+ sort_method_alphabetical(node, blist, groupiter, cur, iter);
return;
}
--- a/pidgin/gtkdialogs.c Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/gtkdialogs.c Mon Mar 07 06:43:26 2011 +0000
@@ -650,14 +650,6 @@
else
g_string_append(str, " <b>Perl:</b> Disabled<br/>");
-#ifndef _WIN32
-#ifdef HAVE_STARTUP_NOTIFICATION
- g_string_append(str, " <b>Startup Notification:</b> Enabled<br/>");
-#else
- g_string_append(str, " <b>Startup Notification:</b> Disabled<br/>");
-#endif
-#endif
-
if (purple_plugins_find_with_id("core-tcl") != NULL) {
g_string_append(str, " <b>Tcl:</b> Enabled<br/>");
#ifdef HAVE_TK
--- a/pidgin/gtkdocklet-gtk.c Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/gtkdocklet-gtk.c Mon Mar 07 06:43:26 2011 +0000
@@ -47,19 +47,37 @@
static gboolean
docklet_gtk_embed_timeout_cb(gpointer data)
{
- /* The docklet was not embedded within the timeout.
- * Remove it as a visibility manager, but leave the plugin
- * loaded so that it can embed automatically if/when a notification
- * area becomes available.
- */
- purple_debug_info("docklet", "failed to embed within timeout\n");
- pidgin_docklet_remove();
- purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
+#if !GTK_CHECK_VERSION(2,12,0)
+ if (gtk_status_icon_is_embedded(docklet)) {
+ /* Older GTK+ (<2.12) don't implement the embedded signal, but the
+ information is still accessable through the above function. */
+ purple_debug_info("docklet", "embedded\n");
+ pidgin_docklet_embedded();
+ purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
+ }
+ else
+#endif
+ {
+ /* The docklet was not embedded within the timeout.
+ * Remove it as a visibility manager, but leave the plugin
+ * loaded so that it can embed automatically if/when a notification
+ * area becomes available.
+ */
+ purple_debug_info("docklet", "failed to embed within timeout\n");
+ pidgin_docklet_remove();
+ purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
+ }
+
+#if GTK_CHECK_VERSION(2,12,0)
embed_timeout = 0;
return FALSE;
+#else
+ return TRUE;
+#endif
}
+#if GTK_CHECK_VERSION(2,12,0)
static gboolean
docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
{
@@ -82,6 +100,7 @@
return TRUE;
}
+#endif
static void
docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data)
@@ -206,7 +225,9 @@
g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
+#if GTK_CHECK_VERSION(2,12,0)
g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
+#endif
g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
gtk_status_icon_set_visible(docklet, TRUE);
@@ -226,11 +247,15 @@
*/
if (!recreate) {
pidgin_docklet_embedded();
+#if GTK_CHECK_VERSION(2,12,0)
if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
} else {
embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
}
+#else
+ embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
+#endif
}
purple_debug_info("docklet", "GTK+ created\n");
--- a/pidgin/gtkmain.c Mon Mar 07 06:42:57 2011 +0000
+++ b/pidgin/gtkmain.c Mon Mar 07 06:43:26 2011 +0000
@@ -76,18 +76,6 @@
#include <getopt.h>
-#ifdef HAVE_STARTUP_NOTIFICATION
-# define SN_API_NOT_YET_FROZEN
-# include <libsn/sn-launchee.h>
-# include <gdk/gdkx.h>
-#endif
-
-
-
-#ifdef HAVE_STARTUP_NOTIFICATION
-static SnLauncheeContext *sn_context = NULL;
-static SnDisplay *sn_display = NULL;
-#endif
#ifdef HAVE_SIGNAL_H
@@ -472,42 +460,6 @@
g_free(text);
}
-#ifdef HAVE_STARTUP_NOTIFICATION
-static void
-sn_error_trap_push(SnDisplay *display, Display *xdisplay)
-{
- gdk_error_trap_push();
-}
-
-static void
-sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
-{
- gdk_error_trap_pop();
-}
-
-static void
-startup_notification_complete(void)
-{
- Display *xdisplay;
-
- xdisplay = GDK_DISPLAY();
- sn_display = sn_display_new(xdisplay,
- sn_error_trap_push,
- sn_error_trap_pop);
- sn_context =
- sn_launchee_context_new_from_environment(sn_display,
- DefaultScreen(xdisplay));
-
- if (sn_context != NULL)
- {
- sn_launchee_context_complete(sn_context);
- sn_launchee_context_unref(sn_context);
-
- sn_display_unref(sn_display);
- }
-}
-#endif /* HAVE_STARTUP_NOTIFICATION */
-
/* FUCKING GET ME A TOWEL! */
#ifdef _WIN32
/* suppress gcc "no previous prototype" warning */
@@ -876,6 +828,7 @@
dbus_connection_send_with_reply_and_block(conn, message, -1, NULL);
dbus_message_unref(message);
#endif
+ gdk_notify_startup_complete();
purple_core_quit();
g_printerr(_("Exiting because another libpurple client is already running.\n"));
#ifdef HAVE_SIGNAL_H
@@ -967,9 +920,10 @@
g_list_free(active_accounts);
}
-#ifdef HAVE_STARTUP_NOTIFICATION
- startup_notification_complete();
-#endif
+ /* GTK clears the notification for us when opening the first window,
+ * but we may have launched with only a status icon, so clear the it
+ * just in case. */
+ gdk_notify_startup_complete();
#ifdef _WIN32
winpidgin_post_init();
--- a/po/de.po Mon Mar 07 06:42:57 2011 +0000
+++ b/po/de.po Mon Mar 07 06:43:26 2011 +0000
@@ -11,8 +11,8 @@
msgstr ""
"Project-Id-Version: de\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-02-06 14:22+0100\n"
-"PO-Revision-Date: 2011-02-06 14:22+0100\n"
+"POT-Creation-Date: 2011-03-06 12:25+0100\n"
+"PO-Revision-Date: 2011-03-06 12:25+0100\n"
"Last-Translator: Jochen Kemnade <jochenkemnade@web.de>\n"
"Language-Team: German <de@li.org>\n"
"Language: de\n"
@@ -3239,9 +3239,7 @@
msgstr "UIN"
#. first name
-#. purple_notify_user_info_add_pair( info, _( "Hidden Number" ), profile->hidden ? _( "Yes" ) : _( "No" ) );
#. optional information
-#. purple_notify_user_info_add_pair( info, _( "Title" ), profile->title );
msgid "First Name"
msgstr "Vorname"
@@ -4010,7 +4008,6 @@
msgid "Postal Code"
msgstr "Postleitzahl"
-#. purple_notify_user_info_add_pair( info, _( "Email" ), profile->email );
msgid "Country"
msgstr "Land"
@@ -6148,6 +6145,9 @@
msgid "Connecting..."
msgstr "Verbinde..."
+msgid "The Display Name you entered is too short."
+msgstr "Der eingegebene Anzeigename ist zu kurz."
+
msgid "The PIN you entered has an invalid length [7-10]."
msgstr "Die eingegebene PIN hat eine ungültige Länge [7-10]."
@@ -6227,33 +6227,6 @@
msgid "Retrieving User Information..."
msgstr "Abrufen der Benutzerinformationen..."
-msgid "Loading menu..."
-msgstr "Lade das Menü..."
-
-msgid "Status Message"
-msgstr "Status-Nachricht"
-
-msgid "Rejection Message"
-msgstr "Ablehnungsnachricht"
-
-#. hidden number
-msgid "Hidden Number"
-msgstr "Versteckte Nummer"
-
-msgid "Your MXit ID..."
-msgstr "Ihre MXit-ID..."
-
-#. Configuration options
-#. WAP server (reference: "libpurple/accountopt.h")
-msgid "WAP Server"
-msgstr "WAP-Server"
-
-msgid "Connect via HTTP"
-msgstr "Über HTTP verbinden"
-
-msgid "Enable splash-screen popup"
-msgstr "Startbildschirm-Popup aktivieren"
-
#. you were kicked
msgid "You have been kicked from this MultiMX."
msgstr "Sie wurden von MultiMX hinausgeworfen."
@@ -6268,6 +6241,43 @@
msgid "You have invited"
msgstr "Sie haben eingeladen"
+msgid "Loading menu..."
+msgstr "Lade das Menü..."
+
+msgid "Status Message"
+msgstr "Status-Nachricht"
+
+msgid "Rejection Message"
+msgstr "Ablehnungsnachricht"
+
+#. hidden number
+msgid "Hidden Number"
+msgstr "Versteckte Nummer"
+
+msgid "No profile available"
+msgstr "Kein Profil verfügbar"
+
+msgid "This contact does not have a profile."
+msgstr "Dieser Kontakt hat kein Profil."
+
+msgid "Your MXit ID..."
+msgstr "Ihre MXit-ID..."
+
+#. contact is in Deleted, Rejected or None state
+msgid "Re-Invite"
+msgstr "Erneut einladen"
+
+#. Configuration options
+#. WAP server (reference: "libpurple/accountopt.h")
+msgid "WAP Server"
+msgstr "WAP-Server"
+
+msgid "Connect via HTTP"
+msgstr "Über HTTP verbinden"
+
+msgid "Enable splash-screen popup"
+msgstr "Startbildschirm-Popup aktivieren"
+
msgid "Last Online"
msgstr "Zuletzt online"
@@ -7571,6 +7581,14 @@
msgid "You have been disconnected from chat room %s."
msgstr "Die Verbindung zum Raum %s wurde unterbrochen."
+msgid "The new formatting is invalid."
+msgstr "Die neue Formatierung ist ungültig."
+
+msgid "Username formatting can change only capitalization and whitespace."
+msgstr ""
+"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und "
+"Leerzeichen ändern."
+
msgid "Pop-Up Message"
msgstr "Pop-Up Nachricht"
@@ -7846,14 +7864,6 @@
msgid "ICQ Privacy Options"
msgstr "ICQ Privatsphärenoptionen"
-msgid "The new formatting is invalid."
-msgstr "Die neue Formatierung ist ungültig."
-
-msgid "Username formatting can change only capitalization and whitespace."
-msgstr ""
-"Benutzernamen-Formatierung kann nur die Groß-/Kleinschreibung und "
-"Leerzeichen ändern."
-
msgid "Change Address To:"
msgstr "Ändere die Adresse zu:"
@@ -7961,75 +7971,6 @@
"ist notwendig für IM-Bilder. Da Ihre IP-Adresse verwendet wird, kann dies "
"eine Verletzung der Privatsphäre bedeuten."
-msgid "Invalid SNAC"
-msgstr "Ungültiger SNAC"
-
-msgid "Server rate limit exceeded"
-msgstr "Server-Datenrate überschritten"
-
-msgid "Client rate limit exceeded"
-msgstr "Client-Datenrate überschritten"
-
-msgid "Service unavailable"
-msgstr "Dienst nicht verfügbar"
-
-msgid "Service not defined"
-msgstr "Dienst nicht definiert"
-
-msgid "Obsolete SNAC"
-msgstr "Obsoleter SNAC"
-
-msgid "Not supported by host"
-msgstr "Nicht unterstützt vom Host"
-
-msgid "Not supported by client"
-msgstr "Nicht unterstützt vom Client"
-
-msgid "Refused by client"
-msgstr "Abgelehnt vom Client"
-
-msgid "Reply too big"
-msgstr "Antwort zu groß"
-
-msgid "Responses lost"
-msgstr "Antworten verloren"
-
-msgid "Request denied"
-msgstr "Anfrage verweigert"
-
-msgid "Busted SNAC payload"
-msgstr "Ruinierte SNAC-Daten"
-
-msgid "Insufficient rights"
-msgstr "Ungenügende Rechte"
-
-msgid "In local permit/deny"
-msgstr "In lokaler erlaubt/verboten-Liste"
-
-msgid "Warning level too high (sender)"
-msgstr "Warnstufe zu hoch (Absender)"
-
-msgid "Warning level too high (receiver)"
-msgstr "Warnstufe zu hoch (Empfänger)"
-
-msgid "User temporarily unavailable"
-msgstr "Benutzer ist temporär nicht verfügbar"
-
-msgid "No match"
-msgstr "Keine Übereinstimmung"
-
-msgid "List overflow"
-msgstr "Listenüberlauf"
-
-msgid "Request ambiguous"
-msgstr "Anfrage ist nicht eindeutig"
-
-msgid "Queue full"
-msgstr "Warteschlange voll"
-
-msgid "Not while on AOL"
-msgstr "Nicht solange bei AOL angemeldet"
-
#. Label
msgid "Buddy Icon"
msgstr "Buddy-Icon"
@@ -8148,6 +8089,75 @@
msgid "Capabilities"
msgstr "Fähigkeiten"
+msgid "Invalid SNAC"
+msgstr "Ungültiger SNAC"
+
+msgid "Server rate limit exceeded"
+msgstr "Server-Datenrate überschritten"
+
+msgid "Client rate limit exceeded"
+msgstr "Client-Datenrate überschritten"
+
+msgid "Service unavailable"
+msgstr "Dienst nicht verfügbar"
+
+msgid "Service not defined"
+msgstr "Dienst nicht definiert"
+
+msgid "Obsolete SNAC"
+msgstr "Obsoleter SNAC"
+
+msgid "Not supported by host"
+msgstr "Nicht unterstützt vom Host"
+
+msgid "Not supported by client"
+msgstr "Nicht unterstützt vom Client"
+
+msgid "Refused by client"
+msgstr "Abgelehnt vom Client"
+
+msgid "Reply too big"
+msgstr "Antwort zu groß"
+
+msgid "Responses lost"
+msgstr "Antworten verloren"
+
+msgid "Request denied"
+msgstr "Anfrage verweigert"
+
+msgid "Busted SNAC payload"
+msgstr "Ruinierte SNAC-Daten"
+
+msgid "Insufficient rights"
+msgstr "Ungenügende Rechte"
+
+msgid "In local permit/deny"
+msgstr "In lokaler erlaubt/verboten-Liste"
+
+msgid "Warning level too high (sender)"
+msgstr "Warnstufe zu hoch (Absender)"
+
+msgid "Warning level too high (receiver)"
+msgstr "Warnstufe zu hoch (Empfänger)"
+
+msgid "User temporarily unavailable"
+msgstr "Benutzer ist temporär nicht verfügbar"
+
+msgid "No match"
+msgstr "Keine Übereinstimmung"
+
+msgid "List overflow"
+msgstr "Listenüberlauf"
+
+msgid "Request ambiguous"
+msgstr "Anfrage ist nicht eindeutig"
+
+msgid "Queue full"
+msgstr "Warteschlange voll"
+
+msgid "Not while on AOL"
+msgstr "Nicht solange bei AOL angemeldet"
+
#. Translators: This string is a menu option that, if selected, will cause
#. you to appear online to the chosen user even when your status is set to
#. Invisible.