diff options
Diffstat (limited to 'protocols/nogaim.c')
| -rw-r--r-- | protocols/nogaim.c | 264 | 
1 files changed, 196 insertions, 68 deletions
diff --git a/protocols/nogaim.c b/protocols/nogaim.c index a9eb207a..0c2094e2 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -1,7 +1,7 @@    /********************************************************************\    * BitlBee -- An IRC to other IM-networks gateway                     *    *                                                                    * -  * Copyright 2002-2006 Wilmer van der Gaast and others                * +  * Copyright 2002-2010 Wilmer van der Gaast and others                *    \********************************************************************/  /* @@ -38,6 +38,7 @@  #include "chat.h"  static int remove_chat_buddy_silent( struct groupchat *b, const char *handle ); +static char *format_timestamp( irc_t *irc, time_t msg_ts );  GSList *connections; @@ -97,7 +98,19 @@ GList *protocols = NULL;  void register_protocol (struct prpl *p)  { -	protocols = g_list_append(protocols, p); +	int i; +	gboolean refused = global.conf->protocols != NULL; +  +	for (i = 0; global.conf->protocols && global.conf->protocols[i]; i++) + 	{ + 		if (g_strcasecmp(p->name, global.conf->protocols[i]) == 0) +			refused = FALSE; + 	} + +	if (refused) +		log_message(LOGLVL_WARNING, "Protocol %s disabled\n", p->name); +	else +		protocols = g_list_append(protocols, p);  }  struct prpl *find_protocol(const char *name) @@ -272,9 +285,8 @@ void imcb_connected( struct im_connection *ic )  	ic->keepalive = b_timeout_add( 60000, send_keepalive, ic );  	ic->flags |= OPT_LOGGED_IN; -	/* Also necessary when we're not away, at least for some of the -	   protocols. */ -	imc_set_away( ic, u->away ); +	/* Necessary to send initial presence status, even if we're not away. */ +	imc_away_send_update( ic );  	/* Apparently we're connected successfully, so reset the  	   exponential backoff timer. */ @@ -376,7 +388,7 @@ void imcb_ask( struct im_connection *ic, char *msg, void *data,  /* list.c */ -void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ) +void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )  {  	user_t *u;  	char nick[MAX_NICK_LENGTH+1], *s; @@ -450,9 +462,10 @@ struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )  	return( b );  } -void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) +void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )  {  	user_t *u = user_findhandle( ic, handle ); +	char *set;  	if( !u || !realname ) return; @@ -465,9 +478,26 @@ void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname )  		if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )  			imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );  	} +	 +	set = set_getstr( &ic->acc->set, "nick_source" ); +	if( strcmp( set, "handle" ) != 0 ) +	{ +		char *name = g_strdup( realname ); +		 +		if( strcmp( set, "first_name" ) == 0 ) +		{ +			int i; +			for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {} +			name[i] = '\0'; +		} +		 +		imcb_buddy_nick_hint( ic, handle, name ); +		 +		g_free( name ); +	}  } -void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) +void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )  {  	user_t *u; @@ -477,7 +507,7 @@ void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group )  /* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM     modules to suggest a nickname for a handle. */ -void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) +void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )  {  	user_t *u = user_findhandle( ic, handle );  	char newnick[MAX_NICK_LENGTH+1], *orig_nick; @@ -622,11 +652,9 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,  	oa = u->away != NULL;  	oo = u->online; -	if( u->away ) -	{ -		g_free( u->away ); -		u->away = NULL; -	} +	g_free( u->away ); +	g_free( u->status_msg ); +	u->away = u->status_msg = NULL;  	if( ( flags & OPT_LOGGED_IN ) && !u->online )  	{ @@ -664,7 +692,10 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,  			u->away = g_strdup( "Away" );  		}  	} -	/* else waste_any_state_information_for_now(); */ +	else +	{ +		u->status_msg = g_strdup( message ); +	}  	/* LISPy... */  	if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&		/* Don't do a thing when user doesn't want it */ @@ -689,10 +720,10 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags,  	}  } -void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ) +void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )  {  	irc_t *irc = ic->irc; -	char *wrapped; +	char *wrapped, *ts;  	user_t *u;  	u = user_findhandle( ic, handle ); @@ -734,10 +765,18 @@ void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t  	if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||  	    ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )  		strip_html( msg ); - +	 +	if( ( ts = format_timestamp( irc, sent_at ) ) ) +	{ +		char *new = g_strconcat( ts, msg, NULL ); +		g_free( ts ); +		ts = msg = new; +	} +	  	wrapped = word_wrap( msg, 425 );  	irc_msgfrom( irc, u->nick, wrapped );  	g_free( wrapped ); +	g_free( ts );  }  void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) @@ -822,7 +861,7 @@ void imcb_chat_free( struct groupchat *c )  	}  } -void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ) +void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )  {  	struct im_connection *ic = c->ic;  	char *wrapped; @@ -841,7 +880,9 @@ void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, t  	wrapped = word_wrap( msg, 425 );  	if( c && u )  	{ -		irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, "", wrapped ); +		char *ts = format_timestamp( ic->irc, sent_at ); +		irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped ); +		g_free( ts );  	}  	else  	{ @@ -894,7 +935,7 @@ void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at  /* buddy_chat.c */ -void imcb_chat_add_buddy( struct groupchat *b, char *handle ) +void imcb_chat_add_buddy( struct groupchat *b, const char *handle )  {  	user_t *u = user_findhandle( b->ic, handle );  	int me = 0; @@ -929,7 +970,7 @@ void imcb_chat_add_buddy( struct groupchat *b, char *handle )  }  /* This function is one BIG hack... :-( EREWRITE */ -void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) +void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )  {  	user_t *u;  	int me = 0; @@ -1035,8 +1076,94 @@ char *set_eval_away_devoice( set_t *set, char *value )  	return value;  } +char *set_eval_timezone( set_t *set, char *value ) +{ +	char *s; +	 +	if( strcmp( value, "local" ) == 0 || +	    strcmp( value, "gmt" ) == 0 || strcmp( value, "utc" ) == 0 ) +		return value; +	 +	/* Otherwise: +/- at the beginning optional, then one or more numbers, +	   possibly followed by a colon and more numbers. Don't bother bound- +	   checking them since users are free to shoot themselves in the foot. */ +	s = value; +	if( *s == '+' || *s == '-' ) +		s ++; +	 +	/* \d+ */ +	if( !isdigit( *s ) ) +		return SET_INVALID; +	while( *s && isdigit( *s ) ) s ++; +	 +	/* EOS? */ +	if( *s == '\0' ) +		return value; +	 +	/* Otherwise, colon */ +	if( *s != ':' ) +		return SET_INVALID; +	s ++; +	 +	/* \d+ */ +	if( !isdigit( *s ) ) +		return SET_INVALID; +	while( *s && isdigit( *s ) ) s ++; +	 +	/* EOS */ +	return *s == '\0' ? value : SET_INVALID; +} - +static char *format_timestamp( irc_t *irc, time_t msg_ts ) +{ +	time_t now_ts = time( NULL ); +	struct tm now, msg; +	char *set; +	 +	/* If the timestamp is <= 0 or less than a minute ago, discard it as +	   it doesn't seem to add to much useful info and/or might be noise. */ +	if( msg_ts <= 0 || msg_ts > now_ts - 60 ) +		return NULL; +	 +	set = set_getstr( &irc->set, "timezone" ); +	if( strcmp( set, "local" ) == 0 ) +	{ +		localtime_r( &now_ts, &now ); +		localtime_r( &msg_ts, &msg ); +	} +	else +	{ +		int hr, min = 0, sign = 60; +		 +		if( set[0] == '-' ) +		{ +			sign *= -1; +			set ++; +		} +		else if( set[0] == '+' ) +		{ +			set ++; +		} +		 +		if( sscanf( set, "%d:%d", &hr, &min ) >= 1 ) +		{ +			msg_ts += sign * ( hr * 60 + min ); +			now_ts += sign * ( hr * 60 + min ); +		} +		 +		gmtime_r( &now_ts, &now ); +		gmtime_r( &msg_ts, &msg ); +	} +	 +	if( msg.tm_year == now.tm_year && msg.tm_yday == now.tm_yday ) +		return g_strdup_printf( "\x02[\x02\x02\x02%02d:%02d:%02d\x02]\x02 ", +		                        msg.tm_hour, msg.tm_min, msg.tm_sec ); +	else +		return g_strdup_printf( "\x02[\x02\x02\x02%04d-%02d-%02d " +		                        "%02d:%02d:%02d\x02]\x02 ", +		                        msg.tm_year + 1900, msg.tm_mon, msg.tm_mday, +		                        msg.tm_hour, msg.tm_min, msg.tm_sec ); +}  /* The plan is to not allow straight calls to prpl functions anymore, but do     them all from some wrappers. We'll start to define some down here: */ @@ -1074,51 +1201,30 @@ int imc_chat_msg( struct groupchat *c, char *msg, int flags )  	return 1;  } -static char *imc_away_alias_find( GList *gcm, char *away ); +static char *imc_away_state_find( GList *gcm, char *away, char **message ); -int imc_set_away( struct im_connection *ic, char *away ) +int imc_away_send_update( struct im_connection *ic )  { -	GList *m, *ms; -	char *s; -	 -	if( !away ) away = ""; -	ms = m = ic->acc->prpl->away_states( ic ); +	char *away, *msg = NULL; -	while( m ) +	away = set_getstr( &ic->acc->set, "away" ) ? +	     : set_getstr( &ic->irc->set, "away" ); +	if( away && *away )  	{ -		if( *away ) -		{ -			if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) -				break; -		} -		else -		{ -			if( g_strcasecmp( m->data, "Available" ) == 0 ) -				break; -			if( g_strcasecmp( m->data, "Online" ) == 0 ) -				break; -		} -		m = m->next; +		GList *m = ic->acc->prpl->away_states( ic ); +		msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; +		away = imc_away_state_find( m, away, &msg ) ? : m->data;  	} -	 -	if( m ) +	else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE )  	{ -		ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL ); -	} -	else -	{ -		s = imc_away_alias_find( ms, away ); -		if( s ) -		{ -			ic->acc->prpl->set_away( ic, s, away ); -			if( set_getbool( &ic->irc->set, "debug" ) ) -				imcb_log( ic, "Setting away state to %s", s ); -		} -		else -			ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away ); +		away = NULL; +		msg = set_getstr( &ic->acc->set, "status" ) ? +		    : set_getstr( &ic->irc->set, "status" );  	} -	return( 1 ); +	ic->acc->prpl->set_away( ic, away, msg ); +	 +	return 1;  }  static char *imc_away_alias_list[8][5] = @@ -1133,16 +1239,33 @@ static char *imc_away_alias_list[8][5] =  	{ NULL }  }; -static char *imc_away_alias_find( GList *gcm, char *away ) +static char *imc_away_state_find( GList *gcm, char *away, char **message )  {  	GList *m;  	int i, j; +	for( m = gcm; m; m = m->next ) +		if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) +		{ +			/* At least the Yahoo! module works better if message +			   contains no data unless it adds something to what +			   we have in state already. */ +			if( strlen( m->data ) == strlen( away ) ) +				*message = NULL; +			 +			return m->data; +		} +	  	for( i = 0; *imc_away_alias_list[i]; i ++ )  	{ +		int keep_message; +		  		for( j = 0; imc_away_alias_list[i][j]; j ++ )  			if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 ) +			{ +				keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] );  				break; +			}  		if( !imc_away_alias_list[i][j] )	/* If we reach the end, this row */  			continue;			/* is not what we want. Next!    */ @@ -1150,17 +1273,22 @@ static char *imc_away_alias_find( GList *gcm, char *away )  		/* Now find an entry in this row which exists in gcm */  		for( j = 0; imc_away_alias_list[i][j]; j ++ )  		{ -			m = gcm; -			while( m ) -			{ +			for( m = gcm; m; m = m->next )  				if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 ) -					return( imc_away_alias_list[i][j] ); -				m = m->next; -			} +				{ +					if( !keep_message ) +						*message = NULL; +					 +					return imc_away_alias_list[i][j]; +				}  		} +		 +		/* No need to look further, apparently this state doesn't +		   have any good alias for this protocol. */ +		break;  	} -	return( NULL ); +	return NULL;  }  void imc_add_allow( struct im_connection *ic, char *handle )  | 
