/*
 * EveryBuddy 
 *
 * Copyright (C) 1999, Torrey Searle <tsearle@uci.edu>
 *
 * 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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/*
 * aim.c
 * AIM implementation
 */

#include <gtk/gtk.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined( _WIN32 )
#include "../libtoc/libtoc.h"
typedef unsigned long u_long;
typedef unsigned long ulong;
#else
#include "libtoc/libtoc.h"
#endif
#include "aim.h"
#include "service.h"
#include "chat_window.h"
#include "away_window.h"
#include "util.h"
#include "status.h"
#include "globals.h"
#include "dialog.h"
#include "message_parse.h"
#include "chat_room.h"
#include "value_pair.h"
#include "info_window.h"

#include "pixmaps/aim_online.xpm"
#include "pixmaps/aim_away.xpm"

struct eb_aim_account_data {
		gint status;
        time_t idle_time;
        gint logged_in_time;
	gint evil;
};

struct eb_aim_local_account_data {
        char password[255];
        int fd;
		toc_conn * conn;
		int input;
		int keep_alive;
		gint status;
};

enum
{
	AIM_ONLINE=0,
	AIM_AWAY=1,
	AIM_OFFLINE=2
};


typedef struct _eb_aim_file_request
{
	toc_conn * conn;
	char nick[255];
	char ip[255];
	short port;
	char cookie[255];
	char filename[255];
} eb_aim_file_request;

/* here is the list of locally stored buddies */

GList * aim_buddies = NULL;

void eb_aim_add_user( eb_account * account );
void eb_aim_login( eb_local_account * account );
void eb_aim_logout( eb_local_account * account );
void aim_info_data_cleanup(info_window * iw);
void aim_info_update(info_window * iw);

static int ref_count = 0;

/*********
 * the following variable is a hack, it if we are changing the selection
 * don't let the corresponding set_current_state get called again
 */

static int is_setting_state = 0;

eb_local_account * aim_find_local_account_by_conn(toc_conn * conn)
{
	GList * node;
	for( node = accounts; node; node = node->next )
	{
		eb_local_account * ela = (eb_local_account *)node->data;
		if(ela->service_id == AIM_SERVICE_ID) 
		{
			struct eb_aim_local_account_data * alad = (struct eb_aim_local_account_data *)ela->protocol_local_account_data;
		    if( alad->conn == conn )
			{
				return ela;
			}
		}
	}
	return NULL;
}

void eb_aim_disconnect( toc_conn * conn )
{
	eb_local_account * ela = conn->account;
#ifdef DEBUG
	printf("eb_aim_disconnect %d %d\n", conn->fd, conn->seq_num);
#endif
	eb_aim_logout(ela);
	eb_aim_login(ela);
}

void eb_aim_join_ack(toc_conn * conn, gchar * id, gchar * name)
{
	eb_chat_room * ecr = find_chat_room_by_name(name, AIM_SERVICE_ID);

#ifdef DEBUG
	fprintf(stderr, "eb_aim_join_ack %s %s\n", id, name );
#endif

	if(!ecr)
		return;
	
#ifdef DEBUG
	fprintf(stderr, "Match found, copying id!!");
#endif

	strcpy( ecr->id, id );

	eb_join_chat_room(ecr);
}

void eb_aim_chat_update_buddy(toc_conn * conn, gchar * id, 
		                      gchar * user, gboolean online )
{
	eb_chat_room * ecr = find_chat_room_by_id(id);
	if(!ecr)
	{
			fprintf(stderr, "Error: unable to fine the chat room!!!\n" );
	}
	if(online)
	{
		eb_account * ea = find_account_by_handle(user, AIM_SERVICE_ID);
		if( ea)
		{
			eb_chat_room_buddy_arrive(ecr, ea->account_contact->nick, user );
		}
		else
		{
			eb_chat_room_buddy_arrive(ecr, user, user);
		}
	}
	else
	{
		eb_chat_room_buddy_leave(ecr, user);
	}
}


/*the callback to call all callbacks :P */

void eb_aim_callback(gpointer data, gint source, GdkInputCondition condition )
{
#ifdef DEBUG
	struct eb_aim_local_account_data * alad = data;
	toc_conn * conn = alad->conn;
	printf("eb_aim_callback %d %d\n", conn->fd, conn->seq_num);
#endif
	if(source < 0 )
	{
		//gdk_input_remove(*((int*)data));
		g_assert(0);
	}
	toc_callback(((struct eb_aim_local_account_data *)data)->conn);

}

static gint eb_aim_keep_alive(gpointer data )
{
	struct eb_aim_local_account_data * alad = data;
#ifdef DEBUG
	toc_conn * conn = alad->conn;
	printf("eb_aim_keep_alive %d %d\n", conn->fd, conn->seq_num);
#endif
	toc_send_keep_alive(alad->conn);
	return TRUE;
}

static void eb_aim_process_file_request( GtkWidget * widget, gpointer data )
{
	int accepted = (int)gtk_object_get_user_data(GTK_OBJECT(widget));
	eb_aim_file_request * eafr = data;

	if(accepted)
	{
		toc_file_accept( eafr->conn, eafr->nick, eafr->ip, eafr->port,
						 eafr->cookie, eafr->filename );
		g_free(eafr);
	}
	else
	{
		toc_file_cancel( eafr->conn, eafr->nick, eafr->cookie );
		g_free(eafr);
	}
}

static void eb_aim_file_offer(toc_conn * conn, char * nick, char * ip, short port,
							  char * cookie, char * filename )
{
	eb_aim_file_request * eafr = g_new0( eb_aim_file_request, 1);
	char message[1024];

	eafr->conn = conn;
	strncpy( eafr->nick, nick, 255);
	strncpy( eafr->ip,  ip, 255);
	eafr->port = port;
	strncpy( eafr->filename, filename, 255);
	strncpy( eafr->cookie, cookie, 255 );

	g_snprintf( message, 1024, "AIM user %s would like to\nsend you the file\n%s\ndo you want to accept?", nick, filename );

	do_dialog( message, "Incomming AIM File Request", eb_aim_process_file_request, eafr );

}


void eb_aim_chat_invite(toc_conn * conn, gchar * id, gchar * name,
		                gchar * sender, gchar * message )
{
	eb_chat_room * chat_room = g_new0(eb_chat_room, 1);
  	eb_local_account * ela = aim_find_local_account_by_conn(conn);
	strcpy(chat_room->id, id);
	strcpy(chat_room->room_name, name);
	chat_room->connected = FALSE;
	chat_room->protocol_local_chat_room_data = NULL; /* not needed for AIM */
	
	chat_rooms = g_list_append(chat_rooms, chat_room );
	chat_room->chat_room_account =  aim_find_local_account_by_conn(conn);

	invite_dialog( ela, sender, name, strdup(id) );

}


void eb_aim_error_message( char * message )
{
	do_error_dialog(message, "Error");
}
	
void eb_aim_oncoming_buddy(gchar * user, gboolean online, time_t idle, gint evil, gboolean unavailable )
{
	eb_account * ea = find_account_by_handle( user ,AIM_SERVICE_ID);
	struct eb_aim_account_data * aad ;
	
	if(ea)
	{
		aad = ea->protocol_account_data;
	}
	else
	{
		return;
	}


	if (online && (aad->status == AIM_OFFLINE))
	{
		aad->status = AIM_ONLINE;
		buddy_login(ea);
	}
	else if(!online && (aad->status != AIM_OFFLINE))
	{
		aad->status = AIM_OFFLINE;
		buddy_logoff(ea);
	}

	if (online && unavailable)
		aad->status = AIM_AWAY;
	else if (online)
		aad->status = AIM_ONLINE;

	aad->evil = evil;
	aad->idle_time = idle;
	buddy_update_status(ea);
}

/* This is how we deal with incomming chat room messages */

void eb_aim_toc_chat_im_in( toc_conn * conn, gchar * id, gchar * user, gchar * message )
{
	eb_chat_room * ecr = find_chat_room_by_id( id );
	eb_account * ea = find_account_by_handle(user, AIM_SERVICE_ID);
	gchar * message2 = linkify(message);

	if(!ecr)
	{
		g_warning("Chat room does not Exist!!!");
		g_free(message2);
		return;
	}

	if( ea)
	{
		eb_chat_room_show_message( ecr, ea->account_contact->nick, message2 );
	}
	else
	{
		eb_chat_room_show_message( ecr, user, message2 );
	}
	g_free(message2);
}

void eb_aim_user_info(toc_conn * conn, gchar * user, gchar * message )
{
	eb_local_account * ela =  aim_find_local_account_by_conn(conn);
	eb_account * sender = NULL;
	eb_local_account * reciever = NULL;


	sender = find_account_by_handle(user, ela->service_id);
	if(sender==NULL)
	{
		eb_account * ea = g_new0(eb_account, 1);
		struct eb_aim_account_data * aad = g_new0(struct eb_aim_account_data, 1);
		strncpy(ea->handle, user, 255);
		ea->service_id = ela->service_id;
		aad->status = AIM_OFFLINE;
		ea->protocol_account_data = aad;
			
		add_unknown(ea);
		sender = ea;
			
	}
	reciever = find_suitable_local_account( ela, ela->service_id );

	if(sender->infowindow == NULL )
	{
		sender->infowindow = eb_info_window_new(reciever, sender);
		gtk_widget_show(sender->infowindow->window);
	}

	sender->infowindow->info_data = strdup(message);
	sender->infowindow->cleanup = aim_info_data_cleanup;
	aim_info_update(sender->infowindow);
}
	

void eb_aim_parse_incoming_im(toc_conn * conn, gchar * user, gchar * message )
{
	    //time_t  t = 0;
  		eb_local_account * ela = aim_find_local_account_by_conn(conn);
#ifdef DEBUG
		struct eb_aim_local_account_data * alad = ela->protocol_local_account_data;
#endif
		
		eb_account * sender = NULL;
		eb_local_account * reciever = NULL;

#ifdef DEBUG
		printf("eb_aim_parse_incomming_im %d %d, %d %d\n", conn->fd, conn->seq_num, alad->conn->fd, alad->conn->seq_num );
#endif

		sender = find_account_by_handle(user, ela->service_id);
		if(sender==NULL)
		{
			eb_account * ea = g_new0(eb_account, 1);
			struct eb_aim_account_data * aad = g_new0(struct eb_aim_account_data, 1);
			strncpy(ea->handle, user, 255);
			ea->service_id = ela->service_id;
			aad->status = AIM_OFFLINE;
			ea->protocol_account_data = aad;
			
			add_unknown(ea);
			//aim_add_buddy(command->conn,screenname);
			sender = ea;
			
#ifdef DEBUG
			g_warning("Sender == NULL");
#endif
		}
		reciever = find_suitable_local_account( ela, ela->service_id);
		//strip_html(msg);

		eb_parse_incomming_message(reciever, sender, message);
		if(reciever == NULL)
		{
			g_warning("Reviever == NULL");
		}

#ifdef DEBUG
        printf("%s %s\n", user, message);
#endif
		return;
}



/*   callbacks used by EveryBuddy    */
gboolean eb_aim_query_connected(eb_account * account)
{		
	struct eb_aim_account_data * aad = account->protocol_account_data;

	if(ref_count <= 0 )
		aad->status = AIM_OFFLINE;
	return aad->status != AIM_OFFLINE;
}

void eb_aim_accept_invite( eb_local_account * account, void * invitation )
{
	gchar * id = invitation;
	eb_chat_room * chat_room = find_chat_room_by_id( id );
	
	struct eb_aim_local_account_data * alad = 
						account->protocol_local_account_data;
	
	toc_conn * conn = alad->conn;

	toc_chat_accept(conn, id);
	eb_join_chat_room( chat_room);
	free(id);
}

void eb_aim_decline_invite( eb_local_account * account, void * invitation )
{
	char * id = invitation;
	free( id );
}


void eb_aim_send_chat_room_message( eb_chat_room * room, gchar * message )
{
	struct eb_aim_local_account_data * alad = room->chat_room_account->protocol_local_account_data;
	toc_conn * conn = alad->conn;
	gchar * message2 = linkify(message);

	toc_chat_send(conn, room->id, message2 );
	g_free(message2);
}

void eb_aim_join_chat_room( eb_chat_room * room )
{
	struct eb_aim_local_account_data * alad = room->chat_room_account->protocol_local_account_data;
	toc_conn * conn = alad->conn;
	toc_chat_join(conn, room->room_name);
}

void eb_aim_leave_chat_room( eb_chat_room * room )
{
	struct eb_aim_local_account_data * alad = room->chat_room_account->protocol_local_account_data;
	toc_conn * conn = alad->conn;
	toc_chat_leave(conn, room->id);
}

eb_chat_room * eb_aim_make_chat_room(gchar * name, eb_local_account * account )
{
	eb_chat_room * ecr = g_new0(eb_chat_room, 1);

	strcpy( ecr->room_name, name );
	ecr->fellows = NULL;
	ecr->connected = FALSE;
	ecr->chat_room_account = account;
	eb_aim_join_chat_room(ecr);
	

	return ecr;
}

eb_account * eb_aim_new_account( gchar * account )
{
	eb_account * a = g_new0(eb_account, 1);
	struct eb_aim_account_data * aad = g_new0(struct eb_aim_account_data, 1);

	a->protocol_account_data = aad;
	strncpy(a->handle, account, 255);
	a->service_id = AIM_SERVICE_ID;
	aad->status = AIM_OFFLINE;

	return a;
}

void eb_aim_del_user( eb_account * account )
{
	GList * node;
	assert( eb_services[account->service_id].protocol_id == AIM_PROTOCOL_ID );
	for( node = accounts; node; node=node->next )
	{
		eb_local_account * ela = node->data;
		if( ela->connected && ela->service_id == account->service_id)
		{
			struct eb_aim_local_account_data * alad = ela->protocol_local_account_data;
			toc_remove_buddy(alad->conn,account->handle);
		}
	}
}

void eb_aim_add_user( eb_account * account )
{
	GList * node;
	assert( eb_services[account->service_id].protocol_id == AIM_PROTOCOL_ID );
	
	aim_buddies = g_list_append(aim_buddies, account->handle);

	for( node = accounts; node; node=node->next )
	{
		eb_local_account * ela = node->data;
		if( ela->connected && ela->service_id == account->service_id)
		{
			struct eb_aim_local_account_data * alad = ela->protocol_local_account_data;
			toc_add_buddy(alad->conn,account->handle);
		}
		
	}
}


void eb_aim_login( eb_local_account * account )
{
								  
	struct eb_aim_local_account_data * alad;
	account->connected = 1;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;
	

	alad->conn = toc_signon( account->handle, alad->password );
	if(!alad->conn)
	{
		g_warning("FAILED TO CONNECT TO AIM SERVER!!!!!!!!!!!!");
		return;
	}
	if(alad->conn->fd == -1 )
	{
			g_warning("eb_aim UNKNOWN CONNECTION PROBLEM");
		return;
	}
#ifdef DEBUG
	printf("eb_aim_login %d %d\n", alad->conn->fd, alad->conn->seq_num );
#endif
	alad->conn->account = account;
	alad->status = AIM_ONLINE;
	toc_aim_buddies_pointer(aim_buddies);
	ref_count++;
	alad->input = gdk_input_add(alad->conn->fd, GDK_INPUT_READ, eb_aim_callback, alad);
		
	alad->keep_alive = gtk_timeout_add((guint32)60000, eb_aim_keep_alive, (gpointer)alad );

	is_setting_state = 1;
	
	if(account->status_menu)
	{
		gtk_check_menu_item_set_active
		(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, AIM_ONLINE)->data
				), TRUE
		);

	}

	is_setting_state = 0;
								  
}

void eb_aim_send_invite( eb_local_account * account, eb_chat_room * room,
						 char * user, char * message)
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;
	toc_invite( alad->conn, room->id, user, message );
}
	

void eb_aim_logout( eb_local_account * account )
{
	GList *l;
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;
#ifdef DEBUG
	printf("eb_aim_logout %d %d\n", alad->conn->fd, alad->conn->seq_num );
#endif
	gdk_input_remove(alad->input);
	gtk_timeout_remove(alad->keep_alive);
	if(alad->conn)
	{
		toc_signoff(alad->conn);
		g_free(alad->conn);
		alad->conn = NULL;
	}
	else
	{
		return;
	}
#if 0
	if(account->status_menu)
	{
		gtk_check_menu_item_set_active
		(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, AIM_ONLINE)->data
				), FALSE
		);

	}
#endif
	alad->status=AIM_OFFLINE;
	ref_count--;
	account->connected = 0;

	is_setting_state = 1;

	if(account->status_menu)
	{
		gtk_check_menu_item_set_active
		(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, AIM_OFFLINE)->data
				), TRUE
		);

	}

	is_setting_state = 0;

	/* Make sure each AIM buddy gets logged off from the status window */
	for (l = aim_buddies; l ; l = l->next) {
		eb_aim_oncoming_buddy(l->data, FALSE, 0, 0, FALSE);
	}
	
}

void eb_aim_send_im( eb_local_account * account_from,
				  eb_account * account_to,
				  gchar * message )
{
	struct eb_aim_local_account_data * plad = (struct eb_aim_local_account_data*)account_from->protocol_local_account_data;
	gchar * message2 = linkify(message);
	toc_send_im(plad->conn,account_to->handle, message2);
#if DEBUG
	printf("eb_aim_send_im %d %d\n", plad->conn->fd, plad->conn->seq_num);
	g_warning("eb_aim_send_im %s", message);
#endif

	g_free(message2);
}
		
eb_local_account * eb_aim_read_local_config(GList * pairs)
{
	
	eb_local_account * ela = g_new0(eb_local_account, 1);
	struct eb_aim_local_account_data * ala = g_new0(struct eb_aim_local_account_data, 1);
	
    /*you know, eventually error handling should be put in here*/
    ela->handle=strdup(value_pair_get_value(pairs, "SCREEN_NAME"));
	strncpy(ela->alias, ela->handle, 255);
    strncpy(ala->password, value_pair_get_value(pairs, "PASSWORD"), 255);

    ela->service_id = AIM_SERVICE_ID;
    ela->protocol_local_account_data = ala;
	ala->status = AIM_OFFLINE;

    return ela;
}

GList * eb_aim_write_local_config( eb_local_account * account )
{
	GList * list = NULL;
	value_pair * vp;
	struct eb_aim_local_account_data * alad = account->protocol_local_account_data; 

	vp = g_new0(value_pair, 1);

	strcpy(vp->key, "SCREEN_NAME");
	strcpy(vp->value, account->handle );

	list = g_list_append( list, vp );

	vp = g_new0(value_pair, 1);

	strcpy(vp->key, "PASSWORD");
	strcpy(vp->value, alad->password);

	list = g_list_append(list, vp);

	return list;
}
			
		
	

eb_account * eb_aim_read_config( GList * config, struct contact *contact )
{
    eb_account * ea = g_new0(eb_account, 1 );
    struct eb_aim_account_data * aad =  g_new0(struct eb_aim_account_data,1);
	
	aad->status = AIM_OFFLINE;

    /*you know, eventually error handling should be put in here*/
    strncpy(ea->handle, value_pair_get_value( config, "NAME"), 255);

    ea->service_id = AIM_SERVICE_ID;
    ea->protocol_account_data = aad;
    ea->account_contact = contact;
	ea->list_item = NULL;
	ea->online = 0;
	ea->status = NULL;
	ea->pix = NULL;
	ea->icon_handler = -1;
	ea->status_handler = -1;
	
	eb_aim_add_user(ea);

    return ea;
}

GList * eb_aim_get_states()
{
	GList * states = NULL;
	states = g_list_append(states, "Online");
	states = g_list_append(states, "Away");
	states = g_list_append(states, "Offline");
	
	return states;
}

gint eb_aim_get_current_state(eb_local_account * account )
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;
	assert( eb_services[account->service_id].protocol_id == AIM_PROTOCOL_ID );

	return alad->status;
}

void eb_aim_set_current_state( eb_local_account * account, gint state )
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;

	/* stop the recursion */
	if( is_setting_state )
		return;

#ifdef DEBUG
	printf("eb_set_current_state %d\n", state );
#endif
//	assert( eb_services[account->service_id].protocol_id == AIM_PROTOCOL_ID );
	if(account == NULL || account->protocol_local_account_data == NULL )
	{
		g_warning("ACCOUNT state == NULL!!!!!!!!!!!!!!!!!!!!!");
	}

	switch(state) {
	case AIM_ONLINE:
		if (account->connected == 0) {
			eb_aim_login(account);
			account->connected = 1;
		}
		toc_set_away(alad->conn, NULL);
		break;
	case AIM_AWAY:
		if (account->connected == 0) {
			eb_aim_login(account);
			account->connected = 1;
		}
		if (is_away)
			toc_set_away(alad->conn, gtk_entry_get_text(GTK_ENTRY(away_message)));
		else
			toc_set_away(alad->conn, "User is currently away");
		break;
	case AIM_OFFLINE:
		if (account->connected == 1) {
			eb_aim_logout(account);
			account->connected = 0;
		}
		break;
	}
	alad->status = state;

}

void eb_aim_set_away(eb_local_account * account, gchar * message)
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)account->protocol_local_account_data;

	if (message) {
		if(account->status_menu)
		{
			gtk_check_menu_item_set_active
			(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, AIM_AWAY)->data
				), TRUE
			);

		}
		toc_set_away(alad->conn, message);
	} else {
		if(account->status_menu)
		{
			gtk_check_menu_item_set_active
			(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, AIM_ONLINE)->data
				), TRUE
			);

		}
	}
}

static gint pixmaps = 0;
static GdkPixmap * eb_aim_pixmap[AIM_OFFLINE+1];
static GdkBitmap * eb_aim_bitmap[AIM_OFFLINE+1];

void eb_aim_init_pixmaps()
{
	gint i;
	gchar ** xpm;
	
	for (i=AIM_ONLINE; i<=AIM_OFFLINE; i++) {
		switch(i) {
		case AIM_AWAY:
			xpm = aim_away_xpm;
			break;
		default:
			xpm = aim_online_xpm;
			break;
		}
		eb_aim_pixmap[i] = gdk_pixmap_create_from_xpm_d(statuswindow->window,
			&eb_aim_bitmap[i], NULL, xpm);
	}
	pixmaps = 1;
}

void eb_aim_get_status_pixmap( eb_account * account, GdkPixmap ** pm, GdkBitmap ** bm )
{
	struct eb_aim_account_data * aad;
	
	if (!pixmaps)
		eb_aim_init_pixmaps();
	
	aad = account->protocol_account_data;
	
	*pm = eb_aim_pixmap[aad->status];
	*bm = eb_aim_bitmap[aad->status];
}

gchar * eb_aim_get_status_string( eb_account * account )
{
	static gchar string[255], buf[255];
	struct eb_aim_account_data * aad = account->protocol_account_data;
	strcpy(buf, "");
	strcpy(string, "");
	if(aad->idle_time)
	{
		int hours, minutes, days;
		minutes = (time(NULL) - aad->idle_time)/60;
		hours = minutes/60;
		minutes = minutes%60;
		days = hours/24;
		hours = hours%24;
		if( days )
		{
			g_snprintf( buf, 255, " (%d:%02d:%02d)", days, hours, minutes );
		}
		else if(hours)
		{
			g_snprintf( buf, 255, " (%d:%02d)", hours, minutes);
		}
		else
		{
			g_snprintf( buf, 255, " (%d)", minutes); 
		}
	}

	if (aad->evil)
		g_snprintf(string, 255, "[%d%%]%s", aad->evil, buf);
	else
		g_snprintf(string, 255, "%s", buf);
		
	if (!account->online)
		g_snprintf(string, 255, "(Offline)");		

	return string;
}

void eb_aim_set_idle( eb_local_account * ela, gint idle )
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)ela->protocol_local_account_data;
#ifdef DEBUG
	printf("eb_aim_set_idle %d %d\n", alad->conn->fd, alad->conn->seq_num );
#endif
	toc_set_idle( alad->conn, idle );
}

void eb_aim_get_info( eb_local_account * from, eb_account * account_to )
{
	struct eb_aim_local_account_data * alad;
	alad = (struct eb_aim_local_account_data *)from->protocol_local_account_data;

	toc_get_info( alad->conn, account_to->handle );
}

void aim_info_update(info_window * iw)
{
	char * data = (char *)iw->info_data;
	clear_info_window(iw);
	gtk_html_append_text(GTK_HTML(iw->info), data, 0);
	gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(iw->scrollwindow)),0);
}

void aim_info_data_cleanup(info_window * iw)
{
}


struct service_callbacks * aim_query_callbacks()
{
	struct service_callbacks * sc;
	
	toc_im_in = eb_aim_parse_incoming_im;
	update_user_status = eb_aim_oncoming_buddy; 
	toc_error_message = eb_aim_error_message;
	toc_disconnect = eb_aim_disconnect;
	toc_chat_im_in = eb_aim_toc_chat_im_in;
	toc_chat_invite = eb_aim_chat_invite;
	toc_join_ack = eb_aim_join_ack;
	toc_chat_update_buddy = eb_aim_chat_update_buddy;
	toc_begin_file_recieve = progress_window_new;
	toc_update_file_status = update_progress;
	toc_complete_file_recieve = progress_window_close;
	toc_file_offer = eb_aim_file_offer;
	toc_user_info = eb_aim_user_info;

	sc = g_new0( struct service_callbacks, 1 );
	sc->query_connected = eb_aim_query_connected;
	sc->login = eb_aim_login;
    sc->logout = eb_aim_logout;
	sc->send_im = eb_aim_send_im;
	sc->read_local_account_config = eb_aim_read_local_config;
	sc->write_local_config = eb_aim_write_local_config;
	sc->read_account_config = eb_aim_read_config;
	sc->get_states = eb_aim_get_states;
	sc->get_current_state = eb_aim_get_current_state;
	sc->set_current_state = eb_aim_set_current_state;
	sc->add_user = eb_aim_add_user;
	sc->del_user = eb_aim_del_user;
	sc->new_account = eb_aim_new_account;
	sc->get_status_string = eb_aim_get_status_string;
	sc->get_status_pixmap = eb_aim_get_status_pixmap;
	sc->set_idle = eb_aim_set_idle;
	sc->set_away = eb_aim_set_away;
	sc->send_chat_room_message = eb_aim_send_chat_room_message;
	sc->join_chat_room = eb_aim_join_chat_room;
	sc->leave_chat_room = eb_aim_leave_chat_room;
	sc->make_chat_room = eb_aim_make_chat_room;
	sc->send_invite = eb_aim_send_invite;
	sc->accept_invite = eb_aim_accept_invite;
	sc->decline_invite = eb_aim_decline_invite;
	sc->get_info = eb_aim_get_info;
	
	return sc;
}
		
