diff options
| author | ulim <a.sporto+bee@gmail.com> | 2007-12-19 01:24:32 +0100 | 
|---|---|---|
| committer | ulim <a.sporto+bee@gmail.com> | 2007-12-19 01:24:32 +0100 | 
| commit | 0fbd3a6d26d8fe747bd5e061748e75f397801064 (patch) | |
| tree | 7a731363cfd014eb59ce65734c52cbc3d46b1b73 | |
| parent | 793cc254ad2479d95d00266d6cb7ab2bcd158834 (diff) | |
| parent | 2379566b07de55bd0f59503c39ba253ce2556877 (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.c | 7 | ||||
| -rw-r--r-- | dcc.c | 1 | ||||
| -rw-r--r-- | doc/CREDITS | 1 | ||||
| -rw-r--r-- | doc/user-guide/commands.xml | 12 | ||||
| -rw-r--r-- | doc/user-guide/quickstart.xml | 4 | ||||
| -rw-r--r-- | irc_commands.c | 2 | ||||
| -rw-r--r-- | lib/misc.c | 10 | ||||
| -rw-r--r-- | lib/misc.h | 2 | ||||
| -rw-r--r-- | lib/ssl_gnutls.c | 6 | ||||
| -rw-r--r-- | nick.c | 19 | ||||
| -rw-r--r-- | protocols/jabber/conference.c | 21 | ||||
| -rw-r--r-- | protocols/jabber/io.c | 4 | ||||
| -rw-r--r-- | protocols/jabber/iq.c | 174 | ||||
| -rw-r--r-- | protocols/jabber/jabber.c | 24 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 18 | ||||
| -rw-r--r-- | protocols/jabber/s5bytestream.c | 298 | ||||
| -rw-r--r-- | protocols/jabber/si.c | 10 | ||||
| -rw-r--r-- | protocols/msn/msn.c | 2 | ||||
| -rw-r--r-- | protocols/oscar/aim.h | 2 | ||||
| -rw-r--r-- | protocols/oscar/oscar.c | 28 | ||||
| -rw-r--r-- | protocols/yahoo/yahoo.c | 2 | ||||
| -rw-r--r-- | root_commands.c | 22 | ||||
| -rw-r--r-- | tests/check_nick.c | 12 | 
23 files changed, 539 insertions, 142 deletions
| @@ -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 )  	{ @@ -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 <protocol> <username> <password> [<server>]</syntax> +			<syntax>account add <protocol> <username> <password></syntax>  			<description>  				<para> @@ -25,7 +25,7 @@  			</description>  			<bitlbee-command name="jabber"> -				<syntax>account add jabber <handle@server.tld> <password> [<servertag>]</syntax> +				<syntax>account add jabber <handle@server.tld> <password></syntax>  				<description>  					<para> @@ -49,16 +49,16 @@  			</bitlbee-command>  			<bitlbee-command name="oscar"> -				<syntax>account add oscar <handle> <password> [<servername>]</syntax> +				<syntax>account add oscar <handle> <password></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;  		} @@ -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(); +} @@ -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 );  } @@ -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++) { | 
