aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorulim <a.sporto+bee@gmail.com>2007-12-19 01:24:32 +0100
committerulim <a.sporto+bee@gmail.com>2007-12-19 01:24:32 +0100
commit0fbd3a6d26d8fe747bd5e061748e75f397801064 (patch)
tree7a731363cfd014eb59ce65734c52cbc3d46b1b73
parent793cc254ad2479d95d00266d6cb7ab2bcd158834 (diff)
parent2379566b07de55bd0f59503c39ba253ce2556877 (diff)
Now with sending via a proxy. The proxy is automatically discovered from your
jabber server. Also merged in revs 279..288 from upstream (e.g. PING)
-rw-r--r--account.c7
-rw-r--r--dcc.c1
-rw-r--r--doc/CREDITS1
-rw-r--r--doc/user-guide/commands.xml12
-rw-r--r--doc/user-guide/quickstart.xml4
-rw-r--r--irc_commands.c2
-rw-r--r--lib/misc.c10
-rw-r--r--lib/misc.h2
-rw-r--r--lib/ssl_gnutls.c6
-rw-r--r--nick.c19
-rw-r--r--protocols/jabber/conference.c21
-rw-r--r--protocols/jabber/io.c4
-rw-r--r--protocols/jabber/iq.c174
-rw-r--r--protocols/jabber/jabber.c24
-rw-r--r--protocols/jabber/jabber.h18
-rw-r--r--protocols/jabber/s5bytestream.c298
-rw-r--r--protocols/jabber/si.c10
-rw-r--r--protocols/msn/msn.c2
-rw-r--r--protocols/oscar/aim.h2
-rw-r--r--protocols/oscar/oscar.c28
-rw-r--r--protocols/yahoo/yahoo.c2
-rw-r--r--root_commands.c22
-rw-r--r--tests/check_nick.c12
23 files changed, 539 insertions, 142 deletions
diff --git a/account.c b/account.c
index 388d04d0..4eb78faa 100644
--- a/account.c
+++ b/account.c
@@ -94,10 +94,15 @@ char *set_eval_account( set_t *set, char *value )
{
g_free( acc->server );
if( *value )
+ {
acc->server = g_strdup( value );
+ return value;
+ }
else
+ {
acc->server = NULL;
- return value;
+ return g_strdup( set->def );
+ }
}
else if( strcmp( set->key, "auto_connect" ) == 0 )
{
diff --git a/dcc.c b/dcc.c
index 24673085..2fa3f745 100644
--- a/dcc.c
+++ b/dcc.c
@@ -124,7 +124,6 @@ file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, cha
df = dcc_alloc_transfer( file_name, file_size, ic );
file = df->ft;
file->write = dccs_send_write;
- file->sending = TRUE;
/* listen and request */
if( !dcc_listen( df, &saddr ) ||
diff --git a/doc/CREDITS b/doc/CREDITS
index f805c251..d53f6de0 100644
--- a/doc/CREDITS
+++ b/doc/CREDITS
@@ -54,6 +54,7 @@ The authors thank the following people:
- Ed Schouten, for reporting bugs.
- Greg (gropeep.org), for updating the Yahoo! module to fix some issues
that were there for quite some time already.
+- misc@mandriva.org for lots of Jabber contributions.
- And all other users who help us by sending useful bug reports, positive
feedback, nice patches and cool addons. Mentioning you all would make
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index 8c874014..090acff3 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -16,7 +16,7 @@
</description>
<bitlbee-command name="add">
- <syntax>account add &lt;protocol&gt; &lt;username&gt; &lt;password&gt; [&lt;server&gt;]</syntax>
+ <syntax>account add &lt;protocol&gt; &lt;username&gt; &lt;password&gt;</syntax>
<description>
<para>
@@ -25,7 +25,7 @@
</description>
<bitlbee-command name="jabber">
- <syntax>account add jabber &lt;handle@server.tld&gt; &lt;password&gt; [&lt;servertag&gt;]</syntax>
+ <syntax>account add jabber &lt;handle@server.tld&gt; &lt;password&gt;</syntax>
<description>
<para>
@@ -49,16 +49,16 @@
</bitlbee-command>
<bitlbee-command name="oscar">
- <syntax>account add oscar &lt;handle&gt; &lt;password&gt; [&lt;servername&gt;]</syntax>
+ <syntax>account add oscar &lt;handle&gt; &lt;password&gt;</syntax>
<description>
<para>
- Specifying a server is required for OSCAR, since OSCAR can be used for both ICQ- and AIM-connections. Although these days it's supposed to be possible to connect to ICQ via AIM-servers and vice versa, we like to stick with this separation for now. For ICQ connections, the servername is <emphasis>login.icq.com</emphasis>, for AIM connections it's <emphasis>login.oscar.aol.com</emphasis>.
+ OSCAR is the protocol used to connect to AIM and/or ICQ. The servers will automatically detect if you're using a numeric or non-numeric username so there's no need to tell which network you want to connect to.
</para>
</description>
<ircexample>
- <ircline nick="wilmer">account add oscar 72696705 hobbelmeeuw login.icq.com</ircline>
+ <ircline nick="wilmer">account add oscar 72696705 hobbelmeeuw</ircline>
<ircline nick="root">Account successfully added</ircline>
</ircexample>
</bitlbee-command>
@@ -594,7 +594,7 @@
<bitlbee-setting name="server" type="string" scope="account">
<description>
<para>
- Can be set for Jabber- and OSCAR-connections. For OSCAR, this must be set to <emphasis>login.icq.com</emphasis> if it's an ICQ connection, or <emphasis>login.oscar.aol.com</emphasis> if it's an AIM connection. For Jabber, you have to set this if the servername isn't equal to the part after the @ in the Jabber handle.
+ Can be set for Jabber- and OSCAR-connections. For Jabber, you might have to set this if the servername isn't equal to the part after the @ in the Jabber handle. For OSCAR this shouldn't be necessary anymore in recent BitlBee versions.
</para>
</description>
</bitlbee-setting>
diff --git a/doc/user-guide/quickstart.xml b/doc/user-guide/quickstart.xml
index 520f240f..fcb06c6b 100644
--- a/doc/user-guide/quickstart.xml
+++ b/doc/user-guide/quickstart.xml
@@ -37,12 +37,12 @@ For instance, suppose you have an ICQ account with UIN <emphasis>72696705</empha
</para>
<ircexample>
- <ircline nick="you">account add oscar 72696705 QuickStart login.icq.com</ircline>
+ <ircline nick="you">account add jabber bitlbee@jabber.org QuickStart</ircline>
<ircline nick="root">Account successfully added</ircline>
</ircexample>
<para>
-Other available IM protocols are jabber, msn, and yahoo. Oscar is the protocol used by ICQ and AOL. For oscar, you need to specify the IM-server as a fourth argument (for msn and yahoo there is no fourth argument). For AOL Instant Messenger, the server name is <emphasis>login.oscar.aol.com</emphasis>. For ICQ, the server name is <emphasis>login.icq.com</emphasis>.
+Other available IM protocols are msn, oscar, and yahoo. Oscar is the protocol used by ICQ and AOL.
</para>
<para>
diff --git a/irc_commands.c b/irc_commands.c
index 287a126f..65f0d6c6 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -206,7 +206,7 @@ static void irc_cmd_invite( irc_t *irc, char **cmd )
if( u && c && ( u->ic == c->ic ) )
if( c->ic && c->ic->acc->prpl->chat_invite )
{
- c->ic->acc->prpl->chat_invite( c, "", u->handle );
+ c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
irc_reply( irc, 341, "%s %s", nick, channel );
return;
}
diff --git a/lib/misc.c b/lib/misc.c
index c977029f..d6795ec9 100644
--- a/lib/misc.c
+++ b/lib/misc.c
@@ -44,6 +44,8 @@
#include <resolv.h>
#endif
+#include "ssl_client.h"
+
void strip_linefeed(gchar *text)
{
int i, j;
@@ -590,3 +592,11 @@ char *word_wrap( char *msg, int line_len )
return g_string_free( ret, FALSE );
}
+
+gboolean ssl_sockerr_again( void *ssl )
+{
+ if( ssl )
+ return ssl_errno == SSL_AGAIN;
+ else
+ return sockerr_again();
+}
diff --git a/lib/misc.h b/lib/misc.h
index 1d76f7f2..e0468d73 100644
--- a/lib/misc.h
+++ b/lib/misc.h
@@ -65,4 +65,6 @@ G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol,
G_MODULE_EXPORT char *word_wrap( char *msg, int line_len );
+G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl );
+
#endif
diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c
index 221a2862..b964ab49 100644
--- a/lib/ssl_gnutls.c
+++ b/lib/ssl_gnutls.c
@@ -222,8 +222,10 @@ void ssl_disconnect( void *conn_ )
closesocket( conn->fd );
- gnutls_deinit( conn->session );
- gnutls_certificate_free_credentials( conn->xcred );
+ if( conn->session )
+ gnutls_deinit( conn->session );
+ if( conn->xcred )
+ gnutls_certificate_free_credentials( conn->xcred );
g_free( conn );
}
diff --git a/nick.c b/nick.c
index 88c3faea..4b05f4a7 100644
--- a/nick.c
+++ b/nick.c
@@ -153,10 +153,10 @@ void nick_del( account_t *acc, const char *handle )
/* Character maps, _lc_[x] == _uc_[x] (but uppercase), according to the RFC's.
With one difference, we allow dashes. */
-static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^-_|";
-static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~-_\\";
+static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^`-_|";
+static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~`-_\\";
-void nick_strip( char * nick )
+void nick_strip( char *nick )
{
int i, j;
@@ -169,6 +169,15 @@ void nick_strip( char * nick )
j++;
}
}
+ if( isdigit( nick[0] ) )
+ {
+ char *orig;
+
+ orig = g_strdup( nick );
+ g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
+ g_free( orig );
+ j ++;
+ }
while( j <= MAX_NICK_LENGTH )
nick[j++] = '\0';
}
@@ -177,8 +186,8 @@ int nick_ok( const char *nick )
{
const char *s;
- /* Empty/long nicks are not allowed */
- if( !*nick || strlen( nick ) > MAX_NICK_LENGTH )
+ /* Empty/long nicks are not allowed, nor numbers at [0] */
+ if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
return( 0 );
for( s = nick; *s; s ++ )
diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c
index c5bc0e68..074412ec 100644
--- a/protocols/jabber/conference.c
+++ b/protocols/jabber/conference.c
@@ -175,6 +175,27 @@ int jabber_chat_leave( struct groupchat *c, const char *reason )
return 1;
}
+void jabber_chat_invite( struct groupchat *c, char *who, char *message )
+{
+ struct xt_node *node;
+ struct im_connection *ic = c->ic;
+ struct jabber_chat *jc = c->data;
+
+ node = xt_new_node( "reason", message, NULL );
+
+ node = xt_new_node( "invite", NULL, node );
+ xt_add_attr( node, "to", who );
+
+ node = xt_new_node( "x", NULL, node );
+ xt_add_attr( node, "xmlns", XMLNS_MUC_USER );
+
+ node = jabber_make_packet( "message", NULL, jc->name, node );
+
+ jabber_write_packet( ic, node );
+
+ xt_free_node( node );
+}
+
/* Not really the same syntax as the normal pkt_ functions, but this isn't
called by the xmltree parser directly and this way I can add some extra
parameters so we won't have to repeat too many things done by the caller
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c
index 61cd142e..29561b86 100644
--- a/protocols/jabber/io.c
+++ b/protocols/jabber/io.c
@@ -119,7 +119,7 @@ static gboolean jabber_write_queue( struct im_connection *ic )
return TRUE;
}
- else if( st == 0 || ( st < 0 && !sockerr_again() ) )
+ else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) )
{
/* Set fd to -1 to make sure we won't write to it anymore. */
closesocket( jd->fd ); /* Shouldn't be necessary after errors? */
@@ -230,7 +230,7 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
}
}
}
- else if( st == 0 || ( st < 0 && !sockerr_again() ) )
+ else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) )
{
closesocket( jd->fd );
jd->fd = -1;
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index 8cf6c7f1..2f0959b0 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -49,7 +49,8 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
}
else if( strcmp( type, "get" ) == 0 )
{
- if( !( c = xt_find_node( node->children, "query" ) ) ||
+ if( !( ( c = xt_find_node( node->children, "query" ) ) ||
+ ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
!( s = xt_find_attr( c, "xmlns" ) ) )
{
imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type );
@@ -80,12 +81,21 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) );
xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
}
- else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
+ else if( strcmp( s, XMLNS_PING ) == 0 )
+ {
+ xt_free_node( reply );
+ reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL );
+ if( ( s = xt_find_attr( node, "id" ) ) )
+ xt_add_attr( reply, "id", s );
+ pack = 0;
+ }
+ else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
{
const char *features[] = { XMLNS_VERSION,
XMLNS_TIME,
XMLNS_CHATSTATES,
XMLNS_MUC,
+ XMLNS_PING,
XMLNS_SI,
XMLNS_BYTESTREAMS,
XMLNS_FILETRANSFER,
@@ -564,3 +574,163 @@ int jabber_remove_from_roster( struct im_connection *ic, char *handle )
xt_free_node( node );
return st;
}
+
+xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+
+xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
+{
+ struct xt_node *node, *query;
+ struct jabber_buddy *bud;
+
+ if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
+ {
+ /* Who cares about the unknown... */
+ imcb_log( ic, "Couldnt find the man: %s", bare_jid);
+ return 0;
+ }
+
+ if( bud->features ) /* been here already */
+ return XT_HANDLED;
+
+ node = xt_new_node( "query", NULL, NULL );
+ xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
+
+ if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
+ {
+ imcb_log( ic, "WARNING: Couldn't generate feature query" );
+ xt_free_node( node );
+ }
+
+ jabber_cache_add( ic, query, jabber_iq_parse_features );
+
+ return jabber_write_packet( ic, query );
+}
+
+xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+ struct xt_node *c;
+ struct jabber_buddy *bud;
+ char *feature;
+
+ if( !( c = xt_find_node( node->children, "query" ) ) ||
+ !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
+ {
+ imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
+ return XT_HANDLED;
+ }
+ if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
+ {
+ /* Who cares about the unknown... */
+ imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
+ return 0;
+ }
+
+ c = c->children;
+ while( ( c = xt_find_node( c, "feature" ) ) ) {
+ feature = xt_find_attr( c, "var" );
+ bud->features = g_slist_append(bud->features, g_strdup(feature) );
+ c = c->next;
+ }
+
+ return XT_HANDLED;
+}
+
+xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+
+xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
+{
+ struct xt_node *node, *query;
+ struct jabber_data *jd = ic->proto_data;
+
+ node = xt_new_node( "query", NULL, NULL );
+ xt_add_attr( node, "xmlns", xmlns );
+
+ if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
+ {
+ imcb_log( ic, "WARNING: Couldn't generate server query" );
+ xt_free_node( node );
+ }
+
+ jd->have_streamhosts--;
+ jabber_cache_add( ic, query, jabber_iq_parse_server_features );
+
+ return jabber_write_packet( ic, query );
+}
+
+/*
+ * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
+ */
+xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+ struct xt_node *c;
+ struct jabber_data *jd = ic->proto_data;
+
+ if( !( c = xt_find_node( node->children, "query" ) ) ||
+ !xt_find_attr( node, "from" ) )
+ {
+ imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
+ return XT_HANDLED;
+ }
+
+ jd->have_streamhosts++;
+
+ if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
+ {
+ char *item, *itemjid;
+
+ /* answer from server */
+
+ c = c->children;
+ while( ( c = xt_find_node( c, "item" ) ) )
+ {
+ item = xt_find_attr( c, "name" );
+ itemjid = xt_find_attr( c, "jid" );
+
+ jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
+
+ c = c->next;
+ }
+ } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
+ {
+ char *category, *type;
+
+ /* answer from potential proxy */
+
+ c = c->children;
+ while( ( c = xt_find_node( c, "identity" ) ) )
+ {
+ category = xt_find_attr( c, "category" );
+ type = xt_find_attr( c, "type" );
+
+ if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
+ category && ( strcmp( category, "proxy" ) == 0 ) )
+ jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
+
+ c = c->next;
+ }
+ } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
+ {
+ char *host, *jid;
+ int port;
+
+ /* answer from proxy */
+
+ if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
+ ( host = xt_find_attr( c, "host" ) ) &&
+ ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
+ ( jid = xt_find_attr( c, "jid" ) ) )
+ {
+ jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
+ sh->jid = g_strdup( jid );
+ sh->host = g_strdup( host );
+ sprintf( sh->port, "%u", port );
+
+ imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
+ jd->streamhosts = g_slist_append( jd->streamhosts, sh );
+ }
+ }
+
+ if( jd->have_streamhosts == 0 )
+ jd->have_streamhosts++;
+ return XT_HANDLED;
+}
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 98d2dadf..d028655a 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -76,6 +76,8 @@ static void jabber_login( account_t *acc )
jd->username = g_strdup( acc->user );
jd->server = strchr( jd->username, '@' );
+ jd->fd = jd->r_inpa = jd->w_inpa = -1;
+
if( jd->server == NULL )
{
imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" );
@@ -231,7 +233,8 @@ static void jabber_logout( struct im_connection *ic )
{
struct jabber_data *jd = ic->proto_data;
- jabber_end_stream( ic );
+ if( jd->fd >= 0 )
+ jabber_end_stream( ic );
while( ic->groupchats )
jabber_chat_free( ic->groupchats );
@@ -249,7 +252,8 @@ static void jabber_logout( struct im_connection *ic )
if( jd->tx_len )
g_free( jd->txq );
- g_hash_table_destroy( jd->node_cache );
+ if( jd->node_cache )
+ g_hash_table_destroy( jd->node_cache );
xt_free( jd->xt );
@@ -422,6 +426,20 @@ static void jabber_chat_leave_( struct groupchat *c )
jabber_chat_leave( c, NULL );
}
+static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg )
+{
+ struct jabber_chat *jc = c->data;
+ gchar *msg_alt = NULL;
+
+ if( msg == NULL )
+ msg_alt = g_strdup_printf( "%s invited you to %s", c->ic->acc->user, jc->name );
+
+ if( c && who )
+ jabber_chat_invite( c, who, msg ? msg : msg_alt );
+
+ g_free( msg_alt );
+}
+
static void jabber_keepalive( struct im_connection *ic )
{
/* Just any whitespace character is enough as a keepalive for XMPP sessions. */
@@ -493,7 +511,7 @@ void jabber_initmodule()
ret->remove_buddy = jabber_remove_buddy;
ret->chat_msg = jabber_chat_msg_;
ret->chat_topic = jabber_chat_topic_;
-// ret->chat_invite = jabber_chat_invite;
+ ret->chat_invite = jabber_chat_invite_;
ret->chat_leave = jabber_chat_leave_;
ret->chat_join = jabber_chat_join_;
ret->keepalive = jabber_keepalive;
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index c518f541..3251b49b 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -56,6 +56,14 @@ typedef enum
have a real JID. */
} jabber_buddy_flags_t;
+/* Stores a streamhost's(a.k.a. proxy) data */
+typedef struct
+{
+ char *jid;
+ char *host;
+ char port[6];
+} jabber_streamhost_t;
+
struct jabber_data
{
struct im_connection *ic;
@@ -82,6 +90,8 @@ struct jabber_data
GHashTable *buddies;
GSList *filetransfers;
+ GSList *streamhosts;
+ int have_streamhosts;
};
struct jabber_away_state
@@ -110,6 +120,7 @@ struct jabber_buddy
int priority;
struct jabber_away_state *away_state;
char *away_message;
+ GSList *features;
time_t last_act;
jabber_buddy_flags_t flags;
@@ -177,11 +188,13 @@ struct jabber_transfer
#define XMLNS_AUTH "jabber:iq:auth" /* XEP-0078 */
#define XMLNS_VERSION "jabber:iq:version" /* XEP-0092 */
#define XMLNS_TIME "jabber:iq:time" /* XEP-0090 */
+#define XMLNS_PING "urn:xmpp:ping" /* XEP-0199 */
#define XMLNS_VCARD "vcard-temp" /* XEP-0054 */
#define XMLNS_DELAY "jabber:x:delay" /* XEP-0091 */
#define XMLNS_XDATA "jabber:x:data" /* XEP-0004 */
#define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* XEP-0085 */
-#define XMLNS_DISCOVER "http://jabber.org/protocol/disco#info" /* XEP-0030 */
+#define XMLNS_DISCO_INFO "http://jabber.org/protocol/disco#info" /* XEP-0030 */
+#define XMLNS_DISCO_ITEMS "http://jabber.org/protocol/disco#items" /* XEP-0030 */
#define XMLNS_MUC "http://jabber.org/protocol/muc" /* XEP-0045 */
#define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user" /* XEP-0045 */
#define XMLNS_FEATURE "http://jabber.org/protocol/feature-neg" /* XEP-0020 */
@@ -198,6 +211,8 @@ int jabber_get_roster( struct im_connection *ic );
int jabber_get_vcard( struct im_connection *ic, char *bare_jid );
int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
int jabber_remove_from_roster( struct im_connection *ic, char *handle );
+xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
+xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
/* si.c */
int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
@@ -278,5 +293,6 @@ int jabber_chat_topic( struct groupchat *c, char *topic );
int jabber_chat_leave( struct groupchat *c, const char *reason );
void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
+void jabber_chat_invite( struct groupchat *c, char *who, char *message );
#endif
diff --git a/protocols/jabber/s5bytestream.c b/protocols/jabber/s5bytestream.c
index de173d19..4770feda 100644
--- a/protocols/jabber/s5bytestream.c
+++ b/protocols/jabber/s5bytestream.c
@@ -29,8 +29,8 @@ struct bs_transfer {
struct jabber_transfer *tf;
- /* <query> element and <streamhost> elements */
- struct xt_node *qnode, *shnode;
+ jabber_streamhost_t *sh;
+ GSList *streamhosts;
enum
{
@@ -73,7 +73,7 @@ struct socks5_message
gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... );
void jabber_bs_canceled( file_transfer_t *ft , char *reason );
-void jabber_bs_free_transfer( file_transfer_t *ft);
+void jabber_bs_free_transfer( file_transfer_t *ft );
gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition cond );
gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents );
gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen );
@@ -83,12 +83,14 @@ gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond );
gboolean jabber_bs_recv_write_request( file_transfer_t *ft );
gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond );
gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error );
-int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
+int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode );
gboolean jabber_bs_send_handshake_abort( struct bs_transfer *bt, char *error );
-gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port );
+gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts );
gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition cond );
gboolean jabber_bs_send_listen( struct bs_transfer *bt, struct sockaddr_storage *saddr, char *host, char *port );
+static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+void jabber_bs_send_activate( struct bs_transfer *bt );
/*
* Frees a bs_transfer struct and calls the SI free function
@@ -96,6 +98,7 @@ gboolean jabber_bs_send_listen( struct bs_transfer *bt, struct sockaddr_storage
void jabber_bs_free_transfer( file_transfer_t *ft) {
struct jabber_transfer *tf = ft->data;
struct bs_transfer *bt = tf->streamhandle;
+ jabber_streamhost_t *sh;
if ( tf->watch_in )
b_event_remove( tf->watch_in );
@@ -104,12 +107,25 @@ void jabber_bs_free_transfer( file_transfer_t *ft) {
b_event_remove( tf->watch_out );
g_free( bt->pseudoadr );
- xt_free_node( bt->qnode );
+
+ while( bt->streamhosts )
+ {
+ sh = bt->streamhosts->data;
+ bt->streamhosts = g_slist_remove( bt->streamhosts, sh );
+ g_free( sh->jid );
+ g_free( sh->host );
+ g_free( sh );
+ }
+
g_free( bt );
jabber_si_free_transfer( ft );
}
+/*
+ * Checks if buflen data is available on the socket and
+ * writes it to buffer if that's the case.
+ */
gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen )
{
int ret;
@@ -146,6 +162,10 @@ gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition co
return FALSE;
}
+/*
+ * Polls the socket, checks for errors and removes a connect timer
+ * if there is one.
+ */
gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents )
{
struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR };
@@ -180,6 +200,9 @@ gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents )
return TRUE;
}
+/*
+ * Used for receive and send path.
+ */
gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... )
{
va_list params;
@@ -190,9 +213,9 @@ gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... )
sprintf( error, "internal error parsing error string (BUG)" );
va_end( params );
if( bt->tf->ft->sending )
- return jabber_bs_recv_handshake_abort( bt, error );
- else
return jabber_bs_send_handshake_abort( bt, error );
+ else
+ return jabber_bs_recv_handshake_abort( bt, error );
}
/* Bad luck */
@@ -213,6 +236,8 @@ int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, stru
struct jabber_transfer *tf = NULL;
GSList *tflist;
struct bs_transfer *bt;
+ GSList *shlist=NULL;
+ struct xt_node *shnode;
sha1_state_t sha;
char hash_hex[41];
@@ -235,6 +260,30 @@ int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, stru
return XT_HANDLED;
}
+ shnode = qnode->children;
+ while( ( shnode = xt_find_node( shnode, "streamhost" ) ) )
+ {
+ char *jid, *host;
+ int port;
+ if( ( jid = xt_find_attr( shnode, "jid" ) ) &&
+ ( host = xt_find_attr( shnode, "host" ) ) &&
+ ( ( port = atoi( xt_find_attr( shnode, "port" ) ) ) ) )
+ {
+ jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
+ sh->jid = g_strdup(jid);
+ sh->host = g_strdup(host);
+ sprintf( sh->port, "%u", port );
+ shlist = g_slist_append( shlist, sh );
+ }
+ shnode = shnode->next;
+ }
+
+ if( !shlist )
+ {
+ imcb_log( ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries");
+ return XT_HANDLED;
+ }
+
/* Let's see if we can find out what this bytestream should be for... */
for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
@@ -273,8 +322,8 @@ int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, stru
bt = g_new0( struct bs_transfer, 1 );
bt->tf = tf;
- bt->qnode = xt_dup( qnode );
- bt->shnode = bt->qnode->children;
+ bt->streamhosts = shlist;
+ bt->sh = shlist->data;
bt->phase = BS_PHASE_CONNECT;
bt->pseudoadr = g_strdup( hash_hex );
tf->streamhandle = bt;
@@ -284,6 +333,7 @@ int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, stru
return XT_HANDLED;
}
+
/*
* This is what a protocol handshake can look like in cooperative multitasking :)
* Might be confusing at first because it's called from different places and is recursing.
@@ -304,45 +354,35 @@ gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition con
{
case BS_PHASE_CONNECT:
{
- struct xt_node *c;
- char *host, *port;
struct addrinfo hints, *rp;
- if( ( c = bt->shnode = xt_find_node( bt->shnode, "streamhost" ) ) &&
- ( port = xt_find_attr( c, "port" ) ) &&
- ( host = xt_find_attr( c, "host" ) ) &&
- xt_find_attr( c, "jid" ) )
- {
- memset( &hints, 0, sizeof( struct addrinfo ) );
- hints.ai_socktype = SOCK_STREAM;
+ memset( &hints, 0, sizeof( struct addrinfo ) );
+ hints.ai_socktype = SOCK_STREAM;
- if ( getaddrinfo( host, port, &hints, &rp ) != 0 )
- return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
+ if ( getaddrinfo( bt->sh->host, bt->sh->port, &hints, &rp ) != 0 )
+ return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
- ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
+ ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
- sock_make_nonblocking( fd );
+ sock_make_nonblocking( fd );
- imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port );
+ imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host, bt->sh->port );
- if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
- ( errno != EINPROGRESS ) )
- return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
+ if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
+ ( errno != EINPROGRESS ) )
+ return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
- freeaddrinfo( rp );
+ freeaddrinfo( rp );
- bt->phase = BS_PHASE_CONNECTED;
-
- bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
+ bt->phase = BS_PHASE_CONNECTED;
+
+ bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
- /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
- bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
+ /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
+ bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
- bt->tf->watch_in = 0;
- return FALSE;
- } else
- return jabber_bs_abort( bt, c ? "incomplete streamhost entry: host=%s port=%s jid=%s" : NULL,
- host, port, xt_find_attr( c, "jid" ) );
+ bt->tf->watch_in = 0;
+ return FALSE;
}
case BS_PHASE_CONNECTED:
{
@@ -421,7 +461,10 @@ gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition con
socks5_reply.atyp,
socks5_reply.addrlen);
- jabber_bs_recv_answer_request( bt );
+ if( bt->tf->ft->sending )
+ jabber_bs_send_activate( bt );
+ else
+ jabber_bs_recv_answer_request( bt );
return FALSE;
}
@@ -446,24 +489,24 @@ gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error )
{
struct jabber_transfer *tf = bt->tf;
struct xt_node *reply, *iqnode;
+ GSList *shlist;
+
+ imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",
+ tf->ft->file_name,
+ bt->sh->host,
+ bt->sh->port,
+ error );
- if( bt->shnode )
+ /* Alright, this streamhost failed, let's try the next... */
+ bt->phase = BS_PHASE_CONNECT;
+ shlist = g_slist_find( bt->streamhosts, bt->sh );
+ if( shlist && shlist->next )
{
- imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",
- tf->ft->file_name,
- xt_find_attr( bt->shnode, "host" ),
- xt_find_attr( bt->shnode, "port" ),
- error );
-
- /* Alright, this streamhost failed, let's try the next... */
- bt->phase = BS_PHASE_CONNECT;
- bt->shnode = bt->shnode->next;
-
- /* the if is not neccessary but saves us one recursion */
- if( bt->shnode )
- return jabber_bs_recv_handshake( bt, 0, 0 );
+ bt->sh = shlist->next->data;
+ return jabber_bs_recv_handshake( bt, 0, 0 );
}
+
/* out of stream hosts */
iqnode = jabber_make_packet( "iq", "result", tf->ini_jid, NULL );
@@ -494,16 +537,15 @@ void jabber_bs_recv_answer_request( struct bs_transfer *bt )
imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s",
tf->ft->file_name,
- xt_find_attr( bt->shnode, "host" ),
- xt_find_attr( bt->shnode, "port" ) );
+ bt->sh->host,
+ bt->sh->port );
tf->ft->data = tf;
- tf->ft->started = time( NULL );
tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt );
tf->ft->write_request = jabber_bs_recv_write_request;
reply = xt_new_node( "streamhost-used", NULL, NULL );
- xt_add_attr( reply, "jid", xt_find_attr( bt->shnode, "jid" ) );
+ xt_add_attr( reply, "jid", bt->sh->jid );
reply = xt_new_node( "query", NULL, reply );
xt_add_attr( reply, "xmlns", XMLNS_BYTESTREAMS );
@@ -550,6 +592,9 @@ gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond )
if( ret == 0 )
return jabber_bs_abort( bt, "Remote end closed connection" );
+ if( tf->bytesread == 0 )
+ tf->ft->started = time( NULL );
+
tf->bytesread += ret;
tf->ft->write( tf->ft, tf->ft->buffer, ret );
@@ -602,8 +647,12 @@ gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int l
if( tf->watch_out )
return jabber_bs_abort( bt, "BUG: write() called while watching " );
+ /* TODO: catch broken pipe */
ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending" );
+ if( tf->byteswritten == 0 )
+ tf->ft->started = time( NULL );
+
tf->byteswritten += ret;
/* TODO: this should really not be fatal */
@@ -664,24 +713,110 @@ static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt
tf->accepted = TRUE;
- if( bt->phase == BS_PHASE_REPLY )
+ if( strcmp( jid, tf->ini_jid ) == 0 )
{
- /* handshake went through, let's start transferring */
- tf->ft->started = time( NULL );
- tf->ft->write_request( tf->ft );
+ /* we're streamhost and target */
+ if( bt->phase == BS_PHASE_REPLY )
+ {
+ /* handshake went through, let's start transferring */
+ tf->ft->write_request( tf->ft );
+ }
+ } else
+ {
+ /* using a proxy */
+ GSList *shlist;
+ for( shlist = jd->streamhosts ; shlist ; shlist = g_slist_next( shlist ) )
+ {
+ jabber_streamhost_t *sh = shlist->data;
+ if( strcmp( sh->jid, jid ) == 0 )
+ {
+ bt->sh = sh;
+ jabber_bs_recv_handshake( bt, 0, 0 );
+ return XT_HANDLED;
+ }
+ }
+
+ imcb_log( ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid );
}
return XT_HANDLED;
}
+/*
+ * Tell the proxy to activate the stream. Looks like this:
+ *
+ * <iq type=set>
+ * <query xmlns=bs sid=sid>
+ * <activate>tgt_jid</activate>
+ * </query>
+ * </iq>
+ */
+void jabber_bs_send_activate( struct bs_transfer *bt )
+{
+ struct xt_node *node;
+
+ node = xt_new_node( "activate", bt->tf->tgt_jid, NULL );
+ node = xt_new_node( "query", NULL, node );
+ xt_add_attr( node, "xmlns", XMLNS_BYTESTREAMS );
+ xt_add_attr( node, "sid", bt->tf->sid );
+ node = jabber_make_packet( "iq", "set", bt->sh->jid, node );
+
+ jabber_cache_add( bt->tf->ic, node, jabber_bs_send_handle_activate );
+
+ jabber_write_packet( bt->tf->ic, node );
+}
+
+/*
+ * The proxy has activated the bytestream.
+ * We can finally start pushing some data out.
+ */
+static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+ char *sid;
+ GSList *tflist;
+ struct jabber_transfer *tf;
+ struct xt_node *query;
+ struct jabber_data *jd = ic->proto_data;
+
+ query = xt_find_node( orig->children, "query" );
+ sid = xt_find_attr( query, "sid" );
+
+ for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
+ {
+ struct jabber_transfer *tft = tflist->data;
+ if( ( strcmp( tft->sid, sid ) == 0 ) )
+ {
+ tf = tft;
+ break;
+ }
+ }
+
+ if( !tf )
+ {
+ imcb_log( ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream" );
+ return XT_HANDLED;
+ }
+
+ /* handshake went through, let's start transferring */
+ tf->ft->write_request( tf->ft );
+
+ return XT_HANDLED;
+}
+
+/*
+ * Starts a bytestream.
+ */
gboolean jabber_bs_send_start( struct jabber_transfer *tf )
{
- char host[INET6_ADDRSTRLEN], port[6];
+ char host[INET6_ADDRSTRLEN];
struct bs_transfer *bt;
sha1_state_t sha;
char hash_hex[41];
unsigned char hash[20];
- int i;
+ int i,ret;
+ struct jabber_data *jd = tf->ic->proto_data;
+ jabber_streamhost_t sh;
+ GSList *streamhosts = jd->streamhosts;
/* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
sha1_init( &sha );
@@ -701,28 +836,43 @@ gboolean jabber_bs_send_start( struct jabber_transfer *tf )
tf->ft->free = jabber_bs_free_transfer;
tf->ft->canceled = jabber_bs_canceled;
- if ( !jabber_bs_send_listen( bt, &tf->saddr, host, port ) )
+ if ( !jabber_bs_send_listen( bt, &tf->saddr, sh.host = host, sh.port ) )
return FALSE;
bt->tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_send_handshake, bt );
bt->connect_timeout = b_timeout_add( JABBER_BS_LISTEN_TIMEOUT * 1000, jabber_bs_connect_timeout, bt );
- return jabber_bs_send_request( tf, host, port );
+
+ sh.jid = tf->ini_jid;
+
+ /* temporarily add listen address to streamhosts, send the request and remove it */
+ streamhosts = g_slist_prepend( streamhosts, &sh );
+ ret = jabber_bs_send_request( tf, streamhosts);
+ streamhosts = g_slist_remove( streamhosts, &sh );
+
+ return ret;
}
-gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port )
+gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts )
{
- struct xt_node *sh, *query, *iq;
-
- sh = xt_new_node( "streamhost", NULL, NULL );
- xt_add_attr( sh, "jid", tf->ini_jid );
- xt_add_attr( sh, "host", host );
- xt_add_attr( sh, "port", port );
+ struct xt_node *shnode, *query, *iq;
query = xt_new_node( "query", NULL, NULL );
xt_add_attr( query, "xmlns", XMLNS_BYTESTREAMS );
xt_add_attr( query, "sid", tf->sid );
xt_add_attr( query, "mode", "tcp" );
- xt_add_child( query, sh );
+
+ while( streamhosts ) {
+ jabber_streamhost_t *sh = streamhosts->data;
+ shnode = xt_new_node( "streamhost", NULL, NULL );
+ xt_add_attr( shnode, "jid", sh->jid );
+ xt_add_attr( shnode, "host", sh->host );
+ xt_add_attr( shnode, "port", sh->port );
+
+ xt_add_child( query, shnode );
+
+ streamhosts = g_slist_next( streamhosts );
+ }
+
iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query );
xt_add_attr( iq, "from", tf->ini_jid );
@@ -738,6 +888,7 @@ gboolean jabber_bs_send_handshake_abort(struct bs_transfer *bt, char *error )
{
struct jabber_transfer *tf = bt->tf;
+ /* TODO: did the receiver get here somehow??? */
imcb_log( tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s",
tf->ft->file_name,
error );
@@ -900,7 +1051,6 @@ gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition con
if( tf->accepted )
{
/* streamhost-used message came already in(possible?), let's start sending */
- tf->ft->started = time( NULL );
tf->ft->write_request( tf->ft );
}
diff --git a/protocols/jabber/si.c b/protocols/jabber/si.c
index 0b94f81b..1d649da3 100644
--- a/protocols/jabber/si.c
+++ b/protocols/jabber/si.c
@@ -82,6 +82,7 @@ void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft,
{
struct jabber_transfer *tf;
struct jabber_data *jd = ic->proto_data;
+ char *server = jd->server;
imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
@@ -96,8 +97,17 @@ void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft,
jd->filetransfers = g_slist_prepend( jd->filetransfers, tf );
+ /* query the buddy's features */
+ jabber_iq_query_features( ic, who );
+
+ /* query proxies from the server */
+ if( !jd->have_streamhosts )
+ jabber_iq_query_server( ic, server, XMLNS_DISCO_ITEMS );
+
+ /* send the request to our buddy */
jabber_si_send_request( ic, who, tf );
+ /* and start the receive logic */
imcb_file_recv_start( ft );
}
diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c
index df04e30d..aa05dbdd 100644
--- a/protocols/msn/msn.c
+++ b/protocols/msn/msn.c
@@ -240,7 +240,7 @@ static void msn_chat_msg( struct groupchat *c, char *message, int flags )
already severely broken) disappeared here! */
}
-static void msn_chat_invite( struct groupchat *c, char *msg, char *who )
+static void msn_chat_invite( struct groupchat *c, char *who, char *message )
{
struct msn_switchboard *sb = msn_sb_by_chat( c );
char buf[1024];
diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h
index 81ea5f9e..9516996c 100644
--- a/protocols/oscar/aim.h
+++ b/protocols/oscar/aim.h
@@ -93,7 +93,7 @@ typedef guint16 flap_seqnum_t;
* the client to connect to it.
*
*/
-#define AIM_DEFAULT_LOGIN_SERVER "login.oscar.aol.com"
+#define AIM_DEFAULT_LOGIN_SERVER "login.messaging.aol.com"
#define AIM_LOGIN_PORT 5190
/*
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 96983738..c4683046 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -340,7 +340,7 @@ static void oscar_init(account_t *acc)
{
set_t *s;
- s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
+ s = set_add( &acc->set, "server", AIM_DEFAULT_LOGIN_SERVER, set_eval_account, acc );
s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
if (isdigit(acc->user[0])) {
@@ -355,15 +355,7 @@ static void oscar_login(account_t *acc) {
struct im_connection *ic = imcb_new(acc);
struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1);
- if (isdigit(acc->user[0])) {
- odata->icq = TRUE;
- /* This is odd but it's necessary for a proper do_import and do_export.
- We don't do those anymore, but let's stick with it, just in case
- it accidentally fixes something else too... </bitlbee> */
- /* ic->acc->pass[8] = 0;
- Not touching this anymore now that it belongs to account_t!
- Let's hope nothing will break. ;-) */
- } else {
+ if (!isdigit(acc->user[0])) {
ic->flags |= OPT_DOES_HTML;
}
@@ -384,24 +376,14 @@ static void oscar_login(account_t *acc) {
return;
}
- if (acc->server == NULL) {
- imcb_error(ic, "No servername specified");
- imc_logout(ic, FALSE);
- return;
- }
-
- if (g_strcasecmp(acc->server, "login.icq.com") != 0 &&
- g_strcasecmp(acc->server, "login.oscar.aol.com") != 0) {
- imcb_log(ic, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server);
- }
-
imcb_log(ic, _("Signon: %s"), ic->acc->user);
aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0);
aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
conn->status |= AIM_CONN_STATUS_INPROGRESS;
- conn->fd = proxy_connect(acc->server, AIM_LOGIN_PORT, oscar_login_connect, ic);
+ conn->fd = proxy_connect(set_getstr(&acc->set, "server"),
+ AIM_LOGIN_PORT, oscar_login_connect, ic);
if (conn->fd < 0) {
imcb_error(ic, _("Couldn't connect to host"));
imc_logout(ic, TRUE);
@@ -2508,7 +2490,7 @@ void oscar_chat_msg(struct groupchat *c, char *message, int msgflags)
/* return (ret >= 0); */
}
-void oscar_chat_invite(struct groupchat *c, char *message, char *who)
+void oscar_chat_invite(struct groupchat *c, char *who, char *message)
{
struct im_connection *ic = c->ic;
struct oscar_data * od = (struct oscar_data *)ic->proto_data;
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index 28a72877..625f3d1c 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -305,7 +305,7 @@ static void byahoo_chat_msg( struct groupchat *c, char *message, int flags )
yahoo_conference_message( yd->y2_id, NULL, c->data, c->title, message, 1 );
}
-static void byahoo_chat_invite( struct groupchat *c, char *msg, char *who )
+static void byahoo_chat_invite( struct groupchat *c, char *who, char *msg )
{
struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data;
diff --git a/root_commands.c b/root_commands.c
index 2da77519..eea16178 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -198,7 +198,7 @@ static void cmd_drop( irc_t *irc, char **cmd )
irc_usermsg( irc, "Account `%s' removed", irc->nick );
break;
default:
- irc_usermsg( irc, "Error: '%d'", status );
+ irc_usermsg( irc, "Error: `%d'", status );
break;
}
}
@@ -233,7 +233,11 @@ static void cmd_account( irc_t *irc, char **cmd )
a = account_add( irc, prpl, cmd[3], cmd[4] );
if( cmd[5] )
+ {
+ irc_usermsg( irc, "Warning: Passing a servername/other flags to `account add' "
+ "is now deprecated. Use `account set' instead." );
set_setstr( &a->set, "server", cmd[5] );
+ }
irc_usermsg( irc, "Account successfully added" );
}
@@ -316,7 +320,7 @@ static void cmd_account( irc_t *irc, char **cmd )
}
else
{
- irc_usermsg( irc, "No accounts known. Use 'account add' to add one." );
+ irc_usermsg( irc, "No accounts known. Use `account add' to add one." );
}
}
}
@@ -402,9 +406,7 @@ static void cmd_account( irc_t *irc, char **cmd )
return;
}
- if( ( strcmp( cmd[3], "=" ) ) == 0 && cmd[4] )
- irc_usermsg( irc, "Warning: Correct syntax: \002account set <variable> <value>\002 (without =)" );
- else if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
+ if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
set_reset( &a->set, set_name );
else
set_setstr( &a->set, set_name, cmd[3] );
@@ -744,16 +746,11 @@ static void cmd_yesno( irc_t *irc, char **cmd )
static void cmd_set( irc_t *irc, char **cmd )
{
- char *set_name = NULL;
+ char *set_name = cmd[1];
if( cmd[1] && cmd[2] )
{
- if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] )
- {
- irc_usermsg( irc, "Warning: Correct syntax: \002set <variable> <value>\002 (without =)" );
- return;
- }
- else if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
+ if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
{
set_reset( &irc->set, cmd[2] );
set_name = cmd[2];
@@ -761,7 +758,6 @@ static void cmd_set( irc_t *irc, char **cmd )
else
{
set_setstr( &irc->set, cmd[1], cmd[2] );
- set_name = cmd[1];
}
}
if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
diff --git a/tests/check_nick.c b/tests/check_nick.c
index 714c4fdc..6c4267cd 100644
--- a/tests/check_nick.c
+++ b/tests/check_nick.c
@@ -14,11 +14,17 @@ START_TEST(test_nick_strip)
"thisisaveryveryveryverylongnick",
"thisisave:ryveryveryverylongnick",
"t::::est",
+ "test123",
+ "123test",
+ "123",
NULL };
const char *expected[] = { "test", "test", "test",
"thisisaveryveryveryveryl",
"thisisaveryveryveryveryl",
"test",
+ "test123",
+ "_123test",
+ "_123",
NULL };
for (i = 0; get[i]; i++) {
@@ -34,8 +40,8 @@ END_TEST
START_TEST(test_nick_ok_ok)
{
- const char *nicks[] = { "foo", "bar", "bla[", "blie]",
- "BreEZaH", "\\od^~", NULL };
+ const char *nicks[] = { "foo", "bar123", "bla[", "blie]", "BreEZaH",
+ "\\od^~", "_123", "_123test", NULL };
int i;
for (i = 0; nicks[i]; i++) {
@@ -48,7 +54,7 @@ END_TEST
START_TEST(test_nick_ok_notok)
{
const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnick",
- "\nillegalchar", "", "nick%", NULL };
+ "\nillegalchar", "", "nick%", "123test", NULL };
int i;
for (i = 0; nicks[i]; i++) {