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 ) |