diff options
author | Sven Moritz Hallberg <pesco@khjk.org> | 2010-07-11 19:21:21 +0200 |
---|---|---|
committer | Sven Moritz Hallberg <pesco@khjk.org> | 2010-07-11 19:21:21 +0200 |
commit | eb6df6a280c458546ebc57126e63a828674b4cd8 (patch) | |
tree | b8eead746fe97b7fb4bcf9a518c452ad87caed65 | |
parent | 37598495deeb42e1cd216a0a4ba8068e4a6da453 (diff) | |
parent | 00540d40be63b4db537a661d1a17c49a1790f79c (diff) |
merge with upstraem bitlbee 1.2.8
-rw-r--r-- | bitlbee.h | 4 | ||||
-rw-r--r-- | doc/CHANGES | 19 | ||||
-rw-r--r-- | doc/user-guide/commands.xml | 33 | ||||
-rw-r--r-- | protocols/jabber/iq.c | 4 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 7 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 1 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 26 | ||||
-rw-r--r-- | protocols/jabber/message.c | 2 | ||||
-rw-r--r-- | protocols/twitter/twitter.c | 44 | ||||
-rw-r--r-- | protocols/twitter/twitter.h | 8 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.c | 77 | ||||
-rw-r--r-- | protocols/twitter/twitter_lib.h | 6 | ||||
-rw-r--r-- | storage_xml.c | 26 |
13 files changed, 205 insertions, 52 deletions
@@ -37,10 +37,10 @@ #define _WIN32_WINNT 0x0501 #define PACKAGE "BitlBee" -#define BITLBEE_VERSION "1.2.7" +#define BITLBEE_VERSION "1.2.8" #define VERSION BITLBEE_VERSION #define BITLBEE_VER(a,b,c) (((a) << 16) + ((b) << 8) + (c)) -#define BITLBEE_VERSION_CODE BITLBEE_VER(1, 2, 7) +#define BITLBEE_VERSION_CODE BITLBEE_VER(1, 2, 8) #define MAX_STRING 511 diff --git a/doc/CHANGES b/doc/CHANGES index 7359a050..25db8a70 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -3,6 +3,25 @@ found in the bzr commit logs, for example you can try: http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on +Version 1.2.8: +- Now always using the AIM-style authentication method for OSCAR connections, + even when connecting to ICQ. This solves login issues some people were + having. (If you have problems, try changing the old_icq_auth setting.) +- Twitter: + * Allow changing the Twitter API base URL so the module can also be used + for identi.ca or any other compatible network. + * Fetch the full list of Twitter contacts instead of slowly adding all + contacts as they post a message. + * Fixed message length counting. + * Allow following/unfollowing people using the usual add/remove commands. + * Better error reporting. +- Added a user_agent setting to the Jabber module to get around artificial + client restrictions. +- Allow nick changes (although only before register/identify). +- Some more minor bugfixes/etc. + +Finished 4 Jul 2010 + Version 1.2.7: - Fixed problems with MSN Messenger authentication. ("Could not parse Passport server response") diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 9aa99775..6e0c24d5 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -632,6 +632,24 @@ </description> </bitlbee-setting> + <bitlbee-setting name="base_url" type="string" scope="account"> + <default>http://twitter.com</default> + + <description> + <para> + There are more services that understand the Twitter API than just Twitter.com. BitlBee can connect to all Twitter API implementations. + </para> + + <para> + For example, set this setting to <emphasis>http://identi.ca/api</emphasis> to use Identi.ca. + </para> + + <para> + Keep two things in mind: When not using Twitter, you <emphasis>must</emphasis> also disable the <emphasis>oauth</emphasis> setting as it currently only works with Twitter. If you're still having issues, make sure there is <emphasis>no</emphasis> slash at the end of the URL you enter here. + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="buddy_sendbuffer" type="boolean" scope="global"> <default>false</default> @@ -1230,6 +1248,20 @@ </description> </bitlbee-setting> + <bitlbee-setting name="user_agent" type="string" scope="account"> + <default>BitlBee</default> + + <description> + <para> + Some Jabber servers are configured to only allow a few (or even just one) kinds of XMPP clients to connect to them. + </para> + + <para> + You can change this setting to make BitlBee present itself as a different client, so that you can still connect to these servers. + </para> + </description> + </bitlbee-setting> + <bitlbee-setting name="voice_buddies" type="string" scope="global"> <default>notaway</default> <possible-values>encrypted, trusted, notaway, online, false</possible-values> @@ -1243,7 +1275,6 @@ If "false", the flag is never set. On "notaway", the flag is removed for users marked as "away" and set for all others. On "encrypted", the flag is set for users with whom we have an encrypted connection. On "trusted", it is set only for encrypted connections using a trusted key. On "online", the flag is set whenever the user is online; only meaningful in conjunction with "show_offline". </para> </description> - </bitlbee-setting> <bitlbee-setting name="web_aware" type="string" scope="account"> diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 95b21e1e..68777b0b 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -64,7 +64,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) /* Of course this is a very essential query to support. ;-) */ if( strcmp( s, XMLNS_VERSION ) == 0 ) { - xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) ); + xt_add_child( reply, xt_new_node( "name", set_getstr( &ic->acc->set, "user_agent" ), NULL ) ); xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) ); xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) ); } @@ -104,7 +104,7 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) c = xt_new_node( "identity", NULL, NULL ); xt_add_attr( c, "category", "client" ); xt_add_attr( c, "type", "pc" ); - xt_add_attr( c, "name", "BitlBee" ); + xt_add_attr( c, "name", set_getstr( &ic->acc->set, "user_agent" ) ); xt_add_child( reply, c ); for( f = features; *f; f ++ ) diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 2841c0db..5cc00c9f 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -79,6 +79,8 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "tls", "try", set_eval_tls, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc ); + s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; @@ -285,6 +287,8 @@ static void jabber_logout( struct im_connection *ic ) if( jd->node_cache ) g_hash_table_destroy( jd->node_cache ); + jabber_buddy_remove_all( ic ); + xt_free( jd->xt ); g_free( jd->away_message ); @@ -469,7 +473,8 @@ static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg ) static void jabber_keepalive( struct im_connection *ic ) { /* Just any whitespace character is enough as a keepalive for XMPP sessions. */ - jabber_write( ic, "\n", 1 ); + if( !jabber_write( ic, "\n", 1 ) ) + return; /* This runs the garbage collection every minute, which means every packet is in the cache for about a minute (which should be enough AFAIK). */ diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 40cf3957..3f4144b8 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -229,6 +229,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, g struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags ); int jabber_buddy_remove( struct im_connection *ic, char *full_jid ); int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ); +void jabber_buddy_remove_all( struct im_connection *ic ); time_t jabber_get_timestamp( struct xt_node *xt ); struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); void jabber_error_free( struct jabber_error *err ); diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index b8b625f7..651b7068 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -664,6 +664,32 @@ int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid ) } } +static gboolean jabber_buddy_remove_all_cb( gpointer key, gpointer value, gpointer data ) +{ + struct jabber_buddy *bud, *next; + + bud = value; + while( bud ) + { + next = bud->next; + g_free( bud->ext_jid ); + g_free( bud->full_jid ); + g_free( bud->away_message ); + g_free( bud ); + bud = next; + } + + return TRUE; +} + +void jabber_buddy_remove_all( struct im_connection *ic ) +{ + struct jabber_data *jd = ic->proto_data; + + g_hash_table_foreach_remove( jd->buddies, jabber_buddy_remove_all_cb, NULL ); + g_hash_table_destroy( jd->buddies ); +} + time_t jabber_get_timestamp( struct xt_node *xt ) { struct xt_node *c; diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index e8161029..fa915bd8 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -54,7 +54,7 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) char *ns = xt_find_attr( c, "xmlns" ), *room; struct xt_node *inv, *reason; - if( strcmp( ns, XMLNS_MUC_USER ) == 0 && + if( ns && strcmp( ns, XMLNS_MUC_USER ) == 0 && ( inv = xt_find_node( c->children, "invite" ) ) ) { room = from; diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 90fca1fa..fca619c3 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -39,11 +39,6 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond) if (!g_slist_find( twitter_connections, ic )) return 0; - // If the user uses multiple private message windows we need to get the - // users buddies. - if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "many") == 0) - twitter_get_statuses_friends(ic, -1); - // Do stuff.. twitter_get_home_timeline(ic, -1); @@ -55,7 +50,7 @@ static void twitter_main_loop_start( struct im_connection *ic ) { struct twitter_data *td = ic->proto_data; - imcb_log( ic, "Connecting to Twitter" ); + imcb_log( ic, "Getting initial statuses" ); // Run this once. After this queue the main loop function. twitter_main_loop(ic, -1, 0); @@ -65,6 +60,23 @@ static void twitter_main_loop_start( struct im_connection *ic ) td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); } +static void twitter_oauth_start( struct im_connection *ic ); + +void twitter_login_finish( struct im_connection *ic ) +{ + struct twitter_data *td = ic->proto_data; + + if( set_getbool( &ic->acc->set, "oauth" ) && !td->oauth_info ) + twitter_oauth_start( ic ); + else if( g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "one" ) != 0 && + !( td->flags & TWITTER_HAVE_FRIENDS ) ) + { + imcb_log( ic, "Getting contact list" ); + twitter_get_statuses_friends( ic, -1 ); + } + else + twitter_main_loop_start( ic ); +} static const struct oauth_service twitter_oauth = { @@ -127,7 +139,7 @@ static gboolean twitter_oauth_callback( struct oauth_info *info ) g_free( ic->acc->pass ); ic->acc->pass = oauth_to_string( info ); - twitter_main_loop_start( ic ); + twitter_login_finish( ic ); } return TRUE; @@ -210,10 +222,9 @@ static void twitter_login( account_t *acc ) imcb_add_buddy( ic, name, NULL ); imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL ); - if( td->oauth_info || !set_getbool( &acc->set, "oauth" ) ) - twitter_main_loop_start( ic ); - else - twitter_oauth_start( ic ); + imcb_log( ic, "Connecting" ); + + twitter_login_finish( ic ); } /** @@ -235,6 +246,8 @@ static void twitter_logout( struct im_connection *ic ) if( td ) { oauth_info_free( td->oauth_info ); + g_free( td->url_host ); + g_free( td->url_path ); g_free( td->pass ); g_free( td ); } @@ -255,7 +268,14 @@ static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message if( set_getbool( &ic->acc->set, "oauth" ) && td->oauth_info && td->oauth_info->token == NULL ) { - if( !oauth_access_token( message, td->oauth_info ) ) + char pin[strlen(message)+1], *s; + + strcpy( pin, message ); + for( s = pin + sizeof( pin ) - 2; s > pin && isspace( *s ); s -- ) + *s = '\0'; + for( s = pin; *s && isspace( *s ); s ++ ) {} + + if( !oauth_access_token( s, td->oauth_info ) ) { imcb_error( ic, "OAuth error: %s", "Failed to send access token request" ); imc_logout( ic, TRUE ); diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 614919f9..e61d32be 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -32,6 +32,11 @@ #define debug( text... ) #endif +typedef enum +{ + TWITTER_HAVE_FRIENDS = 1, +} twitter_flags_t; + struct twitter_data { char* user; @@ -41,6 +46,7 @@ struct twitter_data gint main_loop_id; struct groupchat *home_timeline_gc; gint http_fails; + twitter_flags_t flags; gboolean url_ssl; int url_port; @@ -55,4 +61,6 @@ struct twitter_data */ GSList *twitter_connections; +void twitter_login_finish( struct im_connection *ic ); + #endif //_TWITTER_H diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 585bdd43..d1b65c26 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -41,7 +41,7 @@ struct twitter_xml_list { int type; - int next_cursor; + gint64 next_cursor; GSList *list; gpointer data; }; @@ -58,6 +58,8 @@ struct twitter_xml_status { guint64 id; }; +static void twitter_groupchat_init(struct im_connection *ic); + /** * Frees a twitter_xml_user struct. */ @@ -152,12 +154,12 @@ static void twitter_http_get_friends_ids(struct http_request *req); /** * Get the friends ids. */ -void twitter_get_friends_ids(struct im_connection *ic, int next_cursor) +void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor) { // Primitive, but hey! It works... char* args[2]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2); g_free(args[1]); @@ -168,8 +170,12 @@ void twitter_get_friends_ids(struct im_connection *ic, int next_cursor) */ static xt_status twitter_xt_next_cursor( struct xt_node *node, struct twitter_xml_list *txl ) { - // Do something with the cursor. - txl->next_cursor = node->text != NULL ? atoi(node->text) : -1; + char *end = NULL; + + if( node->text ) + txl->next_cursor = g_ascii_strtoll( node->text, &end, 10 ); + if( end == NULL ) + txl->next_cursor = -1; return XT_HANDLED; } @@ -412,13 +418,13 @@ static void twitter_http_get_home_timeline(struct http_request *req); /** * Get the timeline. */ -void twitter_get_home_timeline(struct im_connection *ic, int next_cursor) +void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor) { struct twitter_data *td = ic->proto_data; char* args[4]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); if (td->home_timeline_id) { args[2] = "since_id"; args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id); @@ -432,6 +438,19 @@ void twitter_get_home_timeline(struct im_connection *ic, int next_cursor) } } +static void twitter_groupchat_init(struct im_connection *ic) +{ + char *name_hint; + struct groupchat *gc; + struct twitter_data *td = ic->proto_data; + + td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); + + name_hint = g_strdup_printf( "Twitter_%s", ic->acc->user ); + imcb_chat_name_hint( gc, name_hint ); + g_free( name_hint ); +} + /** * Function that is called to see the statuses in a groupchat window. */ @@ -444,18 +463,11 @@ static void twitter_groupchat(struct im_connection *ic, GSList *list) // Create a new groupchat if it does not exsist. if (!td->home_timeline_gc) - { - char *name_hint = g_strdup_printf( "Twitter_%s", ic->acc->user ); - td->home_timeline_gc = gc = imcb_chat_new( ic, "home/timeline" ); - imcb_chat_name_hint( gc, name_hint ); - g_free( name_hint ); - // Add the current user to the chat... + twitter_groupchat_init(ic); + + gc = td->home_timeline_gc; + if (!gc->joined) imcb_chat_add_buddy( gc, ic->acc->user ); - } - else - { - gc = td->home_timeline_gc; - } for ( l = list; l ; l = g_slist_next(l) ) { @@ -603,15 +615,23 @@ static void twitter_http_get_statuses_friends(struct http_request *req) td = ic->proto_data; // Check if the HTTP request went well. - if (req->status_code != 200) { + if (req->status_code == 401) + { + imcb_error( ic, "Authentication failure" ); + imc_logout( ic, FALSE ); + return; + } else if (req->status_code != 200) { // It didn't go well, output the error and return. - if (++td->http_fails >= 5) - imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req)); - + imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s", twitter_parse_error(req)); + imc_logout( ic, TRUE ); return; } else { td->http_fails = 0; } + + if( !td->home_timeline_gc && + g_strcasecmp( set_getstr( &ic->acc->set, "mode" ), "chat" ) == 0 ) + twitter_groupchat_init( ic ); txl = g_new0(struct twitter_xml_list, 1); txl->list = NULL; @@ -633,8 +653,15 @@ static void twitter_http_get_statuses_friends(struct http_request *req) // if the next_cursor is set to something bigger then 0 there are more friends to gather. if (txl->next_cursor > 0) + { twitter_get_statuses_friends(ic, txl->next_cursor); - + } + else + { + td->flags |= TWITTER_HAVE_FRIENDS; + twitter_login_finish(ic); + } + // Free the structure. txl_free(txl); g_free(txl); @@ -643,11 +670,11 @@ static void twitter_http_get_statuses_friends(struct http_request *req) /** * Get the friends. */ -void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor) +void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor) { char* args[2]; args[0] = "cursor"; - args[1] = g_strdup_printf ("%d", next_cursor); + args[1] = g_strdup_printf ("%lld", (long long) next_cursor); twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args, 2); diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index 65a596cc..6b90f9bb 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -75,9 +75,9 @@ #define TWITTER_BLOCKS_CREATE_URL "/blocks/create/" #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/" -void twitter_get_friends_ids(struct im_connection *ic, int next_cursor); -void twitter_get_home_timeline(struct im_connection *ic, int next_cursor); -void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor); +void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor); +void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor); +void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor); void twitter_post_status(struct im_connection *ic, char *msg); void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message); diff --git a/storage_xml.c b/storage_xml.c index 8c524ca9..7321637c 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -59,6 +59,7 @@ struct xml_parsedata char *given_nick; char *given_pass; xml_pass_st pass_st; + int unknown_tag; }; static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key ) @@ -86,7 +87,11 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na struct xml_parsedata *xd = data; irc_t *irc = xd->irc; - if( g_strcasecmp( element_name, "user" ) == 0 ) + if( xd->unknown_tag > 0 ) + { + xd->unknown_tag ++; + } + else if( g_strcasecmp( element_name, "user" ) == 0 ) { char *nick = xml_attr( attr_names, attr_values, "nick" ); char *pass = xml_attr( attr_names, attr_values, "password" ); @@ -224,8 +229,15 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else { + xd->unknown_tag ++; + irc_usermsg( irc, "Warning: Unknown XML tag found in configuration file (%s). " + "This may happen when downgrading BitlBee versions. " + "This tag will be skipped and the information will be lost " + "once you save your settings.", element_name ); + /* g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "Unkown element: %s", element_name ); + */ } } @@ -233,7 +245,11 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name { struct xml_parsedata *xd = data; - if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) + if( xd->unknown_tag > 0 ) + { + xd->unknown_tag --; + } + else if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) { g_free( xd->current_setting ); xd->current_setting = NULL; @@ -403,8 +419,8 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) if( !overwrite && g_access( path, F_OK ) == 0 ) return STORAGE_ALREADY_EXISTS; - strcat( path, "~" ); - if( ( fd = open( path, O_WRONLY | O_CREAT | O_TRUNC, 0600 ) ) < 0 ) + strcat( path, ".XXXXXX" ); + if( ( fd = mkstemp( path ) ) < 0 ) { irc_usermsg( irc, "Error while opening configuration file." ); return STORAGE_OTHER_ERROR; @@ -498,7 +514,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) fsync( fd ); close( fd ); - path2 = g_strndup( path, strlen( path ) - 1 ); + path2 = g_strndup( path, strlen( path ) - 7 ); if( rename( path, path2 ) != 0 ) { irc_usermsg( irc, "Error while renaming temporary configuration file." ); |