/********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * * Copyright 2002-2004 Wilmer van der Gaast and others * \********************************************************************/ /* * nogaim * * Gaim without gaim - for BitlBee * * This file contains functions called by the Gaim IM-modules. It's written * from scratch for BitlBee and doesn't contain any code from Gaim anymore * (except for the function names). * * Copyright 2002-2004 Wilmer van der Gaast */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License with the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define BITLBEE_CORE #include "nogaim.h" #include #include struct prpl *proto_prpl[PROTO_MAX]; char proto_name[PROTO_MAX][8] = { "TOC", "OSCAR", "YAHOO", "ICQ", "MSN", "", "", "", "JABBER", "", "", "", "", "", "", "" }; static char *proto_away_alias[7][5] = { { "Away from computer", "Away", "Extended away", NULL }, { "NA", "N/A", "Not available", NULL }, { "Busy", "Do not disturb", "DND", "Occupied", NULL }, { "Be right back", "BRB", NULL }, { "On the phone", "Phone", "On phone", NULL }, { "Out to lunch", "Lunch", "Food", NULL }, { NULL } }; static char *proto_away_alias_find( GList *gcm, char *away ); static int remove_chat_buddy_silent( struct conversation *b, char *handle ); GSList *connections; /* nogaim.c */ void nogaim_init() { proto_prpl[PROTO_MSN] = g_new0 ( struct prpl, 1 ); #ifdef WITH_MSN msn_init( proto_prpl[PROTO_MSN] ); #endif proto_prpl[PROTO_OSCAR] = g_new0( struct prpl, 1 ); #ifdef WITH_OSCAR oscar_init( proto_prpl[PROTO_OSCAR] ); #endif proto_prpl[PROTO_YAHOO] = g_new0( struct prpl, 1 ); #ifdef WITH_YAHOO byahoo_init( proto_prpl[PROTO_YAHOO] ); #endif proto_prpl[PROTO_JABBER] = g_new0( struct prpl, 1 ); #ifdef WITH_JABBER jabber_init( proto_prpl[PROTO_JABBER] ); #endif } GSList *get_connections() { return connections; } int proto_away( struct gaim_connection *gc, char *away ) { GList *m, *ms; char *s; if( !away ) away = ""; ms = m = gc->prpl->away_states( gc ); while( m ) { 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; } if( m ) { gc->prpl->set_away( gc, m->data, *away ? away : NULL ); } else { s = proto_away_alias_find( ms, away ); if( s ) { gc->prpl->set_away( gc, s, away ); if( set_getint( gc->irc, "debug" ) ) serv_got_crap( gc, "Setting away state to %s", s ); } else gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); } g_list_free( ms ); return( 1 ); } static char *proto_away_alias_find( GList *gcm, char *away ) { GList *m; int i, j; for( i = 0; *proto_away_alias[i]; i ++ ) { for( j = 0; proto_away_alias[i][j]; j ++ ) if( g_strncasecmp( away, proto_away_alias[i][j], strlen( proto_away_alias[i][j] ) ) == 0 ) break; if( !proto_away_alias[i][j] ) /* If we reach the end, this row */ continue; /* is not what we want. Next! */ /* Now find an entry in this row which exists in gcm */ for( j = 0; proto_away_alias[i][j]; j ++ ) { m = gcm; while( m ) { if( g_strcasecmp( proto_away_alias[i][j], m->data ) == 0 ) return( proto_away_alias[i][j] ); m = m->next; } } } return( NULL ); } /* multi.c */ struct gaim_connection *new_gaim_conn( struct aim_user *user ) { struct gaim_connection *gc; account_t *a; gc = g_new0( struct gaim_connection, 1 ); gc->protocol = user->protocol; gc->prpl = proto_prpl[gc->protocol]; g_snprintf( gc->username, sizeof( gc->username ), "%s", user->username ); g_snprintf( gc->password, sizeof( gc->password ), "%s", user->password ); /* [MD] BUGFIX: don't set gc->irc to the global IRC, but use the one from the struct aim_user. * This fixes daemon mode breakage where IRC doesn't point to the currently active connection. */ gc->irc=user->irc; connections = g_slist_append( connections, gc ); user->gc = gc; gc->user = user; // Find the account_t so we can set its gc pointer for( a = gc->irc->accounts; a; a = a->next ) if( ( struct aim_user * ) a->gc == user ) { a->gc = gc; break; } return( gc ); } void destroy_gaim_conn( struct gaim_connection *gc ) { account_t *a; /* Destroy the pointer to this connection from the account list */ for( a = gc->irc->accounts; a; a = a->next ) if( a->gc == gc ) { a->gc = NULL; break; } connections = g_slist_remove( connections, gc ); g_free( gc->user ); g_free( gc ); } void set_login_progress( struct gaim_connection *gc, int step, char *msg ) { serv_got_crap( gc, "Logging in: %s", msg ); } /* Errors *while* logging in */ void hide_login_progress( struct gaim_connection *gc, char *msg ) { serv_got_crap( gc, "Login error: %s", msg ); } /* Errors *after* logging in */ void hide_login_progress_error( struct gaim_connection *gc, char *msg ) { serv_got_crap( gc, "Logged out: %s", msg ); } void serv_got_crap( struct gaim_connection *gc, char *format, ... ) { va_list params; char text[1024], buf[1024]; char *msg; va_start( params, format ); g_vsnprintf( text, sizeof( text ), format, params ); va_end( params ); if( g_strncasecmp( set_getstr( gc->irc, "charset" ), "none", 4 ) != 0 && do_iconv( "UTF8", set_getstr( gc->irc, "charset" ), text, buf, 0, 1024 ) != -1 ) msg = buf; else msg = text; if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) strip_html( msg ); irc_usermsg( gc->irc, "%s(%s) - %s", proto_name[gc->protocol], gc->username, msg ); } static gboolean send_keepalive( gpointer d ) { struct gaim_connection *gc = d; if( gc->prpl && gc->prpl->keepalive ) gc->prpl->keepalive( gc ); return TRUE; } void account_online( struct gaim_connection *gc ) { user_t *u; /* MSN servers sometimes redirect you to a different server and do the whole login sequence again, so subsequent calls to this function should be handled correctly. (IOW, ignored) */ if( gc->flags & OPT_LOGGED_IN ) return; u = user_find( gc->irc, gc->irc->nick ); serv_got_crap( gc, "Logged in" ); gc->keepalive = g_timeout_add( 60000, send_keepalive, gc ); gc->flags |= OPT_LOGGED_IN; if( u && u->away ) proto_away( gc, u->away ); if( gc->protocol == PROTO_ICQ ) { for( u = gc->irc->users; u; u = u->next ) if( u->gc == gc ) break; if( u == NULL ) serv_got_crap( gc, "\x02""***\x02"" BitlBee now supports ICQ server-side contact lists. " "See \x02""help import_buddies\x02"" for more information." ); } } gboolean auto_reconnect( gpointer data ) { account_t *a = data; a->reconnect = 0; account_on( a->irc, a ); return( FALSE ); /* Only have to run the timeout once */ } void cancel_auto_reconnect( account_t *a ) { while( g_source_remove_by_user_data( (gpointer) a ) ); a->reconnect = 0; } void account_offline( struct gaim_connection *gc ) { gc->wants_to_die = TRUE; signoff( gc ); } void signoff( struct gaim_connection *gc ) { irc_t *irc = gc->irc; user_t *t, *u = irc->users; account_t *a; serv_got_crap( gc, "Signing off.." ); gaim_input_remove( gc->keepalive ); gc->keepalive = 0; gc->prpl->close( gc ); gaim_input_remove( gc->inpa ); while( u ) { if( u->gc == gc ) { t = u->next; user_del( irc, u->nick ); u = t; } else u = u->next; } query_del_by_gc( gc->irc, gc ); for( a = irc->accounts; a; a = a->next ) if( a->gc == gc ) break; if( !a ) { /* Uhm... This is very sick. */ } else if( !gc->wants_to_die && set_getint( irc, "auto_reconnect" ) ) { int delay = set_getint( irc, "auto_reconnect_delay" ); serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); a->reconnect = 1; g_timeout_add( delay * 1000, auto_reconnect, a ); } destroy_gaim_conn( gc ); } /* dialogs.c */ void do_error_dialog( struct gaim_connection *gc, char *msg, char *title ) { serv_got_crap( gc, "Error: %s", msg ); } void do_ask_dialog( struct gaim_connection *gc, char *msg, void *data, void *doit, void *dont ) { query_add( gc->irc, gc, msg, doit, dont, data ); } /* list.c */ int bud_list_cache_exists( struct gaim_connection *gc ) { return( 0 ); } void do_import( struct gaim_connection *gc, void *null ) { return; } void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *realname ) { user_t *u; char nick[MAX_NICK_LENGTH+1]; char *s; irc_t *irc = gc->irc; if( set_getint( irc, "debug" ) && 0 ) /* This message is too useless */ serv_got_crap( gc, "Receiving user add from handle: %s", handle ); if( user_findhandle( gc, handle ) ) { if( set_getint( irc, "debug" ) ) serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); return; /* Buddy seems to exist already. Let's ignore this request then... */ } memset( nick, 0, MAX_NICK_LENGTH + 1 ); strcpy( nick, nick_get( gc->irc, handle, gc->protocol, realname ) ); u = user_add( gc->irc, nick ); if( !realname || !*realname ) realname = nick; u->realname = g_strdup( realname ); if( ( s = strchr( handle, '@' ) ) ) { u->host = g_strdup( s + 1 ); u->user = g_strndup( handle, s - handle ); } else if( gc->user->proto_opt[0] && *gc->user->proto_opt[0] ) { u->host = g_strdup( gc->user->proto_opt[0] ); u->user = g_strdup( handle ); /* s/ /_/ ... important for AOL screennames */ for( s = u->user; *s; s ++ ) if( *s == ' ' ) *s = '_'; } else { u->host = g_strdup( proto_name[gc->user->protocol] ); u->user = g_strdup( handle ); } u->gc = gc; u->handle = g_strdup( handle ); u->send_handler = buddy_send_handler; u->last_typing_notice = 0; } struct buddy *find_buddy( struct gaim_connection *gc, char *handle ) { static struct buddy b[1]; user_t *u; u = user_findhandle( gc, handle ); if( !u ) return( NULL ); mem
/*
 * aim_misc.c
 *
 * TODO: Seperate a lot of this into an aim_bos.c.
 *
 * Other things...
 *
 *   - Idle setting 
 * 
 *
 */

#include <aim.h> 

/* 
 * aim_bos_setprofile(profile)
 *
 * Gives BOS your profile.
 * 
 */
int aim_bos_setprofile(aim_session_t *sess, aim_conn_t *conn, const char *profile, const char *awaymsg, guint32 caps)
{
	static const char defencoding[] = {"text/aolrtf; charset=\"utf-8\""};
	aim_frame_t *fr;
	aim_tlvlist_t *tl = NULL;
	aim_snacid_t snacid;

	/* Build to packet first to get real length */
	if (profile) {
		aim_addtlvtochain_raw(&tl, 0x0001, strlen(defencoding), (guint8 *)defencoding);
		aim_addtlvtochain_raw(&tl, 0x0002, strlen(profile), (guint8 *)profile);
	}

	/*
	 * So here's how this works:
	 *   - You are away when you have a non-zero-length type 4 TLV stored.
	 *   - You become unaway when you clear the TLV with a zero-length
	 *       type 4 TLV.
	 *   - If you do not send the type 4 TLV, your status does not change
	 *       (that is, if you were away, you'll remain away).
	 */
	if (awaymsg) {
		if (strlen(awaymsg)) {
			aim_addtlvtochain_raw(&tl, 0x0003, strlen(defencoding), (guint8 *)defencoding);
			aim_addtlvtochain_raw(&tl, 0x0004, strlen(awaymsg), (guint8 *)awaymsg);
		} else
			aim_addtlvtochain_noval(&tl, 0x0004);
	}

	aim_addtlvtochain_caps(&tl, 0x0005, caps);

	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + aim_sizetlvchain(&tl))))
		return -ENOMEM;

	snacid = aim_cachesnac(sess, 0x0002, 0x0004, 0x0000, NULL, 0);