/*
 * 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
 *
 */

#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <time.h>
#include "yahoo.h"
#include "account.h"
#include "service.h"
#include "dialog.h"
#include "status.h"
#include "util.h"
#include "globals.h"
#include "message_parse.h"
#include "value_pair.h"
#include "info_window.h"
#include "netscape_remote.h"

#include "pixmaps/yahoo_online.xpm"
#include "pixmaps/yahoo_away.xpm"

/* Work in Progress */
#define HANDLE_CUSTOM_STATUS

#define DEBUG

typedef struct _eb_yahoo_account_data
{
	gint status;
    gchar *status_message;  /* Waste the space, even if we don't need custom status */
} eb_yahoo_account_data;

typedef struct _eb_yahoo_local_account_data
{
	char password[255];
	struct yahoo_context * context;
	gint input;
	gint ping_timeout_tag;
	gint status;
} eb_yahoo_local_account_data;

typedef struct _eb_yahoo_chat_room_data
{
	gchar *host;
	gboolean connected;
} eb_yahoo_chat_room_data;

typedef struct _yahoo_info_data
{
    gchar *profile;
} yahoo_info_data;


static int ref_count = 0;

struct yahoo_idlabel eb_yahoo_status_codes[] =
{
    { YAHOO_ONLINE, "" },
    { YAHOO_BRB, "(BRB)" },
    { YAHOO_BUSY, "(Busy)" },
    { YAHOO_NOTATHOME, "(Not Home)" },
    { YAHOO_NOTATDESK, "(Not at Desk)" },
    { YAHOO_NOTINOFFICE, "(Not in Office)" },
    { YAHOO_ONPHONE, "(On Phone)" },
    { YAHOO_ONVACATION, "(On Vacation)" },
    { YAHOO_OUTTOLUNCH, "(Out to Lunch)" },
    { YAHOO_STEPPEDOUT, "(Stepped Out)" },
    { YAHOO_INVISIBLE, "(Invisible)" },
    { YAHOO_IDLE, "(Idle)" },
    { YAHOO_OFFLINE, "(Offline)" },
    { YAHOO_CUSTOM, "[Custom]" },
    { 0, NULL }
};

int eb_to_yahoo_state_translation[] = { 
    YAHOO_ONLINE,
    YAHOO_BRB,
    YAHOO_BUSY,
    YAHOO_NOTATHOME,
    YAHOO_NOTATDESK,
    YAHOO_NOTINOFFICE,
    YAHOO_ONPHONE,
    YAHOO_ONVACATION,
    YAHOO_OUTTOLUNCH,
    YAHOO_STEPPEDOUT,
    YAHOO_INVISIBLE,
    YAHOO_IDLE,
    YAHOO_OFFLINE,
    YAHOO_CUSTOM 
};

GList *eb_yahoo_buddies = NULL;

int yahoo_to_eb_state_translation( int state )
{
	int i;
	for( i = 0; i < EB_DISPLAY_YAHOO_CUSTOM; i++ )
	{
		if(eb_to_yahoo_state_translation[i] == state )
		{
			return i;
		}
	}
	return EB_DISPLAY_YAHOO_OFFLINE;
}

#ifdef __STDC__
int YAHOO_DEBUGLOG(char *fmt, ...)
#else
int YAHOO_DEBUGLOG(fmt, va_alist)
    char *fmt;
    va_dcl
#endif
{
    va_list ap;

#ifdef __STDC__
	va_start(ap, fmt);
#else
    va_start(ap);
#endif

    vfprintf(stderr, fmt, ap);
    fflush(stderr);
    va_end(ap);
    return 0;
}


#if defined(DEBUG)
#define YAHOO_DEBUG
#else
#undef YAHOO_DEBUG
#endif

#ifdef YAHOO_DEBUG
#define LOG(x) { YAHOO_DEBUGLOG("%s:%d: ", __FILE__, __LINE__); \
    YAHOO_DEBUGLOG x; \
    YAHOO_DEBUGLOG("\n"); }
#else
#define LOG(x) { }
#endif

#define WARNING(x) { YAHOO_DEBUGLOG("%s:%d: warning: ", __FILE__, __LINE__); \
	YAHOO_DEBUGLOG x; \
	YAHOO_DEBUGLOG("\n"); }


    /* Forward Declarations */

void eb_yahoo_add_user(eb_account * account);
void eb_yahoo_add_user_cached(eb_account * account, gint update_local );
void eb_yahoo_login( eb_local_account * account );
void eb_yahoo_logout( eb_local_account * account );
eb_account * eb_yahoo_new_account( gchar * account );
void eb_yahoo_process_conference_invite(struct yahoo_packet *pkt, 
		eb_yahoo_local_account_data *ylad);
void eb_yahoo_process_conference_add_invite(struct yahoo_packet *pkt, 
		eb_yahoo_local_account_data *ylad);
void eb_yahoo_join_chat_room(eb_chat_room *room);
void yahoo_info_update(info_window *iw);
void yahoo_info_data_cleanup(info_window *iw);

int eb_yahoo_ping_timeout_callback(gpointer data)
{
	eb_yahoo_local_account_data *ylad = (eb_yahoo_local_account_data *) data;

	LOG(("timeout ping sent"));
	if ( ylad && ylad->context )
		yahoo_cmd_ping(ylad->context);
	else
        WARNING(("Your connection appears to been corrupted.  This is bad."));

	return 1;
}

eb_local_account *yahoo_find_local_account_by_context(struct yahoo_context *ctx)
{
    GList *node;

    for ( node = accounts; node; node = node->next )
    {
        eb_local_account *ela = (eb_local_account *)node->data;
        if ( ela->service_id == YAHOO_SERVICE_ID )
        {
            eb_yahoo_local_account_data *ylad = (eb_yahoo_local_account_data *)
                ela->protocol_local_account_data;
            if ( ylad->context == ctx )
                return ela;
        }
    }
	WARNING(("Couldn't locate context ID.  This is a bad thing."));
    return NULL;
}

void eb_yahoo_decode_yahoo_colors(char *buffer, char *msg)
{
    char *yahoo_colors[]=
    {
        YAHOO_COLOR_BLACK,
        YAHOO_COLOR_BLUE,
        YAHOO_COLOR_LIGHTBLUE,
        YAHOO_COLOR_GRAY,
        YAHOO_COLOR_GREEN,
        YAHOO_COLOR_PINK,
        YAHOO_COLOR_PURPLE,
        YAHOO_COLOR_ORANGE,
        YAHOO_COLOR_RED,
        YAHOO_COLOR_OLIVE
    };
    char *html_colors[]=
        { "<FONT COLOR=\"#000000\">", /* 30 - Black */
          "<FONT COLOR=\"#000080\">", /* 31 - Blue */
          "<FONT COLOR=\"#0000C0\">", /* 32 - Light Blue */
          "<FONT COLOR=\"#808080\">", /* 33 - Gray */
          "<FONT COLOR=\"#008000\">", /* 34 - Green */
          "<FONT COLOR=\"#C000C0\">", /* 35 - Pink */
          "<FONT COLOR=\"#800080\">", /* 36 - Purple */
          "<FONT COLOR=\"#F95002 \">", /* 37 - Orange */
          "<FONT COLOR=\"#800000\">", /* 38 - Red */
          "<FONT COLOR=\"#00C000\">"  /* 39 - Olive */
        };
    int num_colors = sizeof(yahoo_colors)/sizeof(char *);
        
    char *yahoo_styles[]=
    {
        YAHOO_STYLE_ITALICON,
        YAHOO_STYLE_ITALICOFF,
        YAHOO_STYLE_BOLDON,
        YAHOO_STYLE_BOLDOFF,
        YAHOO_STYLE_UNDERLINEON,
        YAHOO_STYLE_UNDERLINEOFF
    };
    char *html_styles[]=
    {
        "<I>",
        "</I>",
        "<B>",
        "</B>",
        "<U>",
        "</U>"
    };
    int num_styles = sizeof(yahoo_styles)/sizeof(char *);
        
    int string_index;
    int color_index;
    int style_index;
    int in_color=0;
    int match = 0;
    char tmp[2];

    tmp[1]='\0';
    buffer[0]='\0';

    for ( string_index=0; msg[string_index]; string_index++)
    {
        match = 0;
        for ( color_index=0; color_index < num_colors; color_index ++)
        {
            if ( !strncmp(yahoo_colors[color_index], &msg[string_index],
                        strlen(yahoo_colors[color_index])) )
            {
                if ( in_color )
                {
                    strcat(buffer, "</FONT>");
                }
                strcat(buffer, html_colors[color_index]);
                string_index+=(strlen(yahoo_colors[color_index])-1);
                in_color=1;
                match = 1;
            }
        } 
        for ( style_index=0; style_index < num_styles; style_index ++)
        {
            if ( !strncmp(yahoo_styles[style_index], &msg[string_index],
                        strlen(yahoo_styles[style_index])) )
            {
                strcat(buffer, html_styles[style_index]);
                string_index+=(strlen(yahoo_styles[style_index])-1);
                match = 1;
            }
        }
        if ( !strncmp(YAHOO_STYLE_URLON, &msg[string_index],
                    strlen(YAHOO_STYLE_URLON)) )
        {
            char *end_of_url;
            int length_of_url;

            string_index+=(strlen(YAHOO_STYLE_URLON));
            end_of_url = strstr(&msg[string_index], YAHOO_STYLE_URLOFF);
            length_of_url = end_of_url - &msg[string_index];
            if ( end_of_url != NULL )
            {
                strcat(buffer, "<A HREF=\"");
                strncat(buffer, &msg[string_index], length_of_url);
                strcat(buffer, "\">");
                match = 1;
            }
            string_index--;
        }
        if ( !strncmp(YAHOO_STYLE_URLOFF, &msg[string_index],
                    strlen(YAHOO_STYLE_URLOFF)) )
        {
            strcat(buffer, "</A>");
            string_index+=(strlen(YAHOO_STYLE_URLOFF)-1);
            match = 1;
        }
        if ( !match )
        {
            tmp[0]=msg[string_index];
            strcat(buffer, tmp);
        }
    }
    if ( strstr(buffer, "<font ") != NULL )
    {
        char *p;
        if ( (p=strstr(buffer, "size=")) != NULL ) /* size="10" */
        {
            p[7]=p[6];
            p[6]='+';
        }
    }
	if(in_color)
	{
		strcat(buffer, "</font>");
	}
    LOG(("post-color buffer: %s", buffer));
}

void eb_yahoo_process_conference_message(struct yahoo_packet *pkt, 
		eb_yahoo_local_account_data *ylad)
{
	eb_chat_room *ecr = find_chat_room_by_id ( pkt->conf_id );

	if ( ecr == NULL )
	{
		LOG(("chat room %s does not exist!", pkt->conf_id));
		return;
	}
	LOG(("conference message: conf=%s, handle=%s, message=%s",
				pkt->conf_id, pkt->conf_user, pkt->conf_msg));
	eb_chat_room_show_message(ecr, pkt->conf_user, pkt->conf_msg);
}

void eb_yahoo_process_conference_logon(struct yahoo_packet *pkt,
		eb_yahoo_local_account_data *ylad)
{
	/* pkt contains:

		pkt->conf_id       The conference ID
		pkt->conf_user     The person who joined or left?
	*/

	eb_chat_room *room;
	eb_local_account *ela = yahoo_find_local_account_by_context(ylad->context);

	if ( !strcmp(pkt->conf_user, ela->handle) ) /* If it was us */
	{
		return;
	}
	
	LOG(("(I am %s) %s joined conference %s", ela->handle,
				pkt->conf_user, pkt->conf_id));
	room = find_chat_room_by_id(pkt->conf_id);

	if ( !room )
	{
		LOG(("but we don't seem to know about conference %s", pkt->conf_id));
		return;
	}

	eb_chat_room_buddy_arrive(room, pkt->conf_user, pkt->conf_user);
}

void eb_yahoo_process_conference_logoff(struct yahoo_packet *pkt,
		eb_yahoo_local_account_data *ylad)
{
	eb_chat_room *room = find_chat_room_by_id(pkt->conf_id);
	eb_yahoo_chat_room_data *ycrd;

	LOG(("%s left conference %s", pkt->conf_user, pkt->conf_id));
	if ( !room )
	{
		LOG (("but we don't seem to know about conference %s",
					pkt->conf_id));
		return;
	}
	ycrd = (eb_yahoo_chat_room_data *)room->protocol_local_chat_room_data;

	if ( !strcmp(ycrd->host, pkt->conf_user) &&
			!strcmp(room->room_name, pkt->conf_id) )
	{
		/* FIXME -- we need to destroy the chat_room, and it probably
		   wants a generic soluton... */
		LOG(("destroying chatroom %s because host %s left",
					pkt->conf_id, pkt->conf_user));
		gtk_widget_destroy(room->window);
		return;
	}

	eb_chat_room_buddy_leave(room, pkt->conf_user);
}

void eb_yahoo_open_mail(GtkWidget *w, gpointer data)
{
    int result = (int)gtk_object_get_user_data(GTK_OBJECT(w));

    if ( result ) netscape_open_url("http://mail.yahoo.com/");
}

void eb_yahoo_process_newmail(struct yahoo_packet *pkt,
        eb_yahoo_local_account_data *ylad)
{
    int new_mail_count = 0;
    int new_personal_mail_count = 0;
    char buffer[1024];

    if ( pkt->service == YAHOO_SERVICE_NEWMAIL )
    {
        new_mail_count = pkt->mail_status;
    }
    else
    {
        new_personal_mail_count = pkt->mail_status;
    }

    if ( new_mail_count && new_personal_mail_count )
    {
        snprintf(buffer,1024, 
                "You have %d new message%s and %d new personal message%s on Yahoo Mail.",
                new_mail_count, new_mail_count > 1 ? "s" : "",
                new_personal_mail_count, 
                new_personal_mail_count > 1 ? "s" : "");
    } else if ( new_mail_count )
    {
        snprintf(buffer,1024, "You have %d new message%s on Yahoo Mail.",
                new_mail_count, new_mail_count > 1 ? "s" : "" );
    } else if ( new_personal_mail_count )
    {
        snprintf(buffer,1024, "You have %d new personal message%s on Yahoo Mail.",
                new_personal_mail_count, 
                new_personal_mail_count > 1 ? "s" : "");
    }
    else
    {
        return;
    /* I don't think we want this dialog 
        snprintf(buffer,1024, "You have no new Yahoo Mail."); */
    }
    strcat(buffer, "\n\nWould you like to view your Yahoo Mail now?");
    do_dialog(buffer, "Yahoo Mail Notification", eb_yahoo_open_mail, NULL);
}

void eb_yahoo_process_packet_status(struct yahoo_packet *pkt,
        eb_yahoo_local_account_data *ylad)
{
    int i;
	int refresh=0;
    eb_local_account *ela;

    ela = yahoo_find_local_account_by_context(ylad->context);

    if ( pkt->service == YAHOO_SERVICE_LOGOFF &&
            !strcmp(pkt->active_id, ela->handle))
    {
        if ( pkt->msgtype == 0xFFFFFFFF && 
                (ylad->context->connect_mode != YAHOO_CONNECT_HTTP 
                 && ylad->context->connect_mode != YAHOO_CONNECT_HTTPPROXY ))
        {
            WARNING(("warning: you just got logged off from Yahoo.\nThis is probably because of a duplicate login."));
            eb_yahoo_logout(ela);
        }
        return;
    }

    for ( i = 0; i < pkt->idstatus_count; i++)
    {
        eb_account * ea;
        eb_yahoo_account_data *yad;
        struct yahoo_idstatus *rec = pkt->idstatus[i];
        
        ea = find_account_by_handle(rec->id, YAHOO_SERVICE_ID);
        if ( !ea )
        {
            struct yahoo_buddy **buddy;
            LOG(("Warning: server set status for %s, but I don't know them", rec->id));

            for(buddy=ylad->context->buddies; *buddy; buddy++)
            {
                struct yahoo_buddy *bud = *buddy;

                if ( !strcasecmp(rec->id, bud->id) )
                {
                    LOG(("Adding %s to group %s", bud->id, bud->group));
                    ea = eb_yahoo_new_account( bud->id );

                    if ( !find_contact_by_nick(bud->id) )
                    {
                        LOG(("Need to add a new contact too"));
                        if ( !find_grouplist_by_name(bud->group) )
                        {
                            LOG(("And the group doesn't exist, either"));
                            add_group(bud->group);
                        }
                        add_new_contact(bud->group, bud->id, YAHOO_SERVICE_ID);
                    }
                    if ( !find_grouplist_by_name(bud->group) )
                    {
                        LOG(("..adding group %s first", bud->group));
                        add_group(bud->group);
                    }
                    add_account(bud->id, ea);
                    refresh=1;
                } /* endif rec->id == bud->id */
            } /* endfor */
            if ( !ea )
            {
                LOG(("Warning: tried to find %s, but couldn't", rec->id));
                return;
            }
            write_contact_list();
			refresh = 0;
			MakeEditContactList();
        }

        LOG(("Setting status for %s to %d", rec->id, rec->status));
		if ( rec->status_msg )
		{
			LOG(("custom status message was %s", rec->status_msg));
		}

        yad = (eb_yahoo_account_data *) ea->protocol_account_data;

#ifdef HANDLE_CUSTOM_STATUS
		if ( yad->status_message )
		{
			g_free(yad->status_message);
			yad->status_message = NULL;
		}
#endif
        if ( pkt->service == YAHOO_SERVICE_LOGOFF )
        {
            yad->status = YAHOO_OFFLINE;
			buddy_logoff(ea);
        }
        else
        {
            yad->status = rec->status;
			buddy_login(ea);
        }
#ifdef HANDLE_CUSTOM_STATUS
		if ( yad->status == YAHOO_STATUS_CUSTOM )
		{
            yad->status_message = g_new(char, strlen(rec->status_msg)+3);
            sprintf(yad->status_message, "(%s)", rec->status_msg);
		}
#endif
		buddy_update_status(ea);
    }
	if ( refresh )
	{
   		MakeEditContactList();
	}
}

void eb_yahoo_process_packet_message(struct yahoo_packet *pkt, 
        eb_yahoo_local_account_data *ylad)
{
    LOG(("eb_yahoo_process_packet_message"));

    if ( pkt->msgtype == YAHOO_MSGTYPE_STATUS)
    {
        LOG(("message status update? = %d", pkt->msg_status));
    }
    if ( pkt->msg )
    {
        if ( pkt->msgtype == YAHOO_MSGTYPE_BOUNCE )
        {
            /* assumedly, if the user is offline, we already know this, but
               there might be a way for the user to have gone offline and
               us not know it yet */
            LOG(("<message not sent, user not online>"));
        }
        else
        {
            eb_account *sender = NULL;
            eb_local_account *receiver = NULL;
            char buff[2048];

            /* Timestamp is only set if it is an offline message */

            if ( pkt->msg_timestamp && pkt->msg_timestamp[0] != 0 )
            {
				char newmessage[2048];
                time_t message_time;
                char timestr[2048];

                LOG(("offline message timestamp = %s", pkt->msg_timestamp));
                message_time = atol(pkt->msg_timestamp);
                strncpy(timestr, ctime(&message_time), sizeof(timestr));
                timestr[strlen(timestr)-1] = '\0';

				sprintf(newmessage, "<FONT COLOR=\"#0000FF\">[Offline message from %s at %s]</FONT><BR>%s", pkt->msg_id, timestr, pkt->msg);

				sender = find_account_by_handle(pkt->msg_id, YAHOO_SERVICE_ID);
				if ( sender == NULL )
				{
					eb_account *ea = g_new0(eb_account, 1);
					eb_yahoo_account_data *yad = g_new(eb_yahoo_account_data,1);
	
					strncpy(ea->handle, pkt->msg_id, 255);
					ea->service_id = YAHOO_SERVICE_ID;
					yad->status = YAHOO_OFFLINE;
					yad->status_message = NULL;
					ea->protocol_account_data = yad;
					add_unknown(ea);
					sender = ea;
//					refresh_contact_list();
					MakeEditContactList();
				}
				receiver = yahoo_find_local_account_by_context(ylad->context);
                eb_yahoo_decode_yahoo_colors(buff, newmessage);
	            eb_parse_incomming_message(receiver, sender, buff);
				LOG(("<incoming offline message: %s: %s>", pkt->msg_id, pkt->msg));
            }
			else /* not an offline message */
			{
				sender = find_account_by_handle(pkt->msg_id, YAHOO_SERVICE_ID);

	            if ( sender == NULL )
	            {
	                eb_account *ea = g_new0(eb_account, 1);
	                eb_yahoo_account_data *yad = g_new(eb_yahoo_account_data,1);
	
	                strncpy(ea->handle, pkt->msg_id, 255);
	                ea->service_id = YAHOO_SERVICE_ID;
	                yad->status = YAHOO_ONLINE;
					yad->status_message = NULL;
	                ea->protocol_account_data = yad;

	                add_unknown(ea);
	                sender = ea;
//	                refresh_contact_list();
	                MakeEditContactList();
	            }
	            receiver = yahoo_find_local_account_by_context(ylad->context);

	            LOG(("<incoming message: %s: %s>", pkt->msg_id, pkt->msg));
                eb_yahoo_decode_yahoo_colors(buff, pkt->msg);
	            eb_parse_incomming_message(receiver, sender, buff);

			}
        }
    }
}

void eb_yahoo_process_packets(eb_yahoo_local_account_data *ylad)
{
    struct yahoo_rawpacket *rawpkt;
    struct yahoo_packet *pkt;

    LOG(("eb_yahoo_process_packets"));

    /* Sanity check */
    if ( ylad->context == NULL )
    {
        WARNING(("Your connection appears to been corrupted.  This is bad."));
        return;
    }

    /* don't do anything if buffer is too small */
    if ( ylad->context->io_buf_curlen <= 103 )
    {
        return;
    }

    /* process each packet in turn */
    /* we have to monitor ylad->context because it's possible
       that one of these packets will log us off, and if that
       happens part of the logoff process will free ylad->context */
    while ( ylad->context && ( rawpkt = yahoo_getpacket(ylad->context)))
    {
        pkt = yahoo_parsepacket(ylad->context, rawpkt);

        switch(pkt->service)
        {
            case YAHOO_SERVICE_USERSTAT:
            case YAHOO_SERVICE_CHATLOGON:
            case YAHOO_SERVICE_CHATLOGOFF:
            case YAHOO_SERVICE_LOGON:
            case YAHOO_SERVICE_LOGOFF:
            case YAHOO_SERVICE_ISAWAY:
            case YAHOO_SERVICE_ISBACK:
                LOG(("status packet: %s", 
                            yahoo_get_service_string(pkt->service)));
                eb_yahoo_process_packet_status(pkt, ylad);
                break;

            case YAHOO_SERVICE_MESSAGE:
            case YAHOO_SERVICE_CHATMSG:
            case YAHOO_SERVICE_SYSMESSAGE:
                eb_yahoo_process_packet_message(pkt, ylad);
                break;

			case YAHOO_SERVICE_CONFINVITE:
				eb_yahoo_process_conference_invite(pkt, ylad);
				break;
			case YAHOO_SERVICE_CONFADDINVITE:
				eb_yahoo_process_conference_add_invite(pkt, ylad);
				break;
			case YAHOO_SERVICE_CONFMSG:
				eb_yahoo_process_conference_message(pkt, ylad);
				break;
			case YAHOO_SERVICE_CONFLOGON:
				eb_yahoo_process_conference_logon(pkt, ylad);
				break;
			case YAHOO_SERVICE_CONFLOGOFF:
				eb_yahoo_process_conference_logoff(pkt, ylad);
				break;
            case YAHOO_SERVICE_NEWMAIL:
            case YAHOO_SERVICE_NEWPERSONALMAIL:
                eb_yahoo_process_newmail(pkt, ylad);
                break;
            default:
                LOG(("warning: unhandled packet type: %s [%d]", 
							yahoo_get_service_string(pkt->service),
							pkt->service));
                break;
        }
        yahoo_free_packet(pkt);
        yahoo_free_rawpacket(rawpkt);
    }
}

void eb_yahoo_callback(gpointer data, gint source, GdkInputCondition condition)
{
    eb_yahoo_local_account_data *ylad = data;
#ifdef YAHOO_DEBUG
    char buffer[255]={0};
    
    if ( condition & GDK_INPUT_READ )
    {
        strcat(buffer, "READ ");
    }
    if ( condition & GDK_INPUT_WRITE )
    {
        strcat(buffer, "WRITE ");
    }
    if ( condition & GDK_INPUT_EXCEPTION )
    {
        strcat(buffer, "EXCEPTION");
    }
    LOG(("GdkInputCondition: %s",buffer));
#endif

    LOG(("eb_yahoo_callback"));

    /* First thing's first.  If we got logged off, then we will have a
       NULL context pointer, so do nothing. */

    if ( ylad->context == NULL )
    {
        LOG(("context is NULL"));
        return;
    }

    /* Ok, GtkYahoo did something like this:

          if ( condition == GDK_INPUT_READ )

       aim.c did something like this:

          if ( source > 0 )

       I'm going to take the road that source should be the sockfd that there
       was input on.  I don't want to require condition == GDK_INPUT_READ,
       because maybe it was an exception or something (?).  OTOH, I don't
       want to try to read if it's not my socket, so I'm going to do:

          if ( source == ylad->context->sockfd )

       This appears to work.

    */

    if ( source == ylad->context->sockfd )
    {
        if ( !yahoo_getdata(ylad->context) )
        {
            eb_local_account *ea = yahoo_find_local_account_by_context
                ( ylad->context );
            WARNING(("Yahoo server disconnected -- attempting to reconnect."));
    
            ref_count--;
            gdk_input_remove(ylad->input);
            gtk_timeout_remove(ylad->ping_timeout_tag);
            eb_yahoo_login(ea);
            return;
        }
        eb_yahoo_process_packets(ylad);
        return;
    }
	LOG(("got called with %d as the source (my socket was %d)", source,
                ylad->context->sockfd));
}

gboolean eb_yahoo_query_connected(eb_account * account )
{
    eb_yahoo_account_data *yad = account->protocol_account_data;
#if defined(ENABLE_LIBYAHOO_DEBUG)
    extern void DBG_Enable(char *);

	DBG_Enable("all");  /* Turn on debugging for libyahoo */
#endif

    if ( ref_count <= 0 )
    {
        yad->status = YAHOO_OFFLINE;
    }
/*    LOG(("eb_yahoo_query_connected: %s is %s",
                account->handle,
                ( yad->status == YAHOO_OFFLINE ? "Offline" : "Online"))); */
    return yad->status != YAHOO_OFFLINE;
}

void eb_yahoo_add_buddies(eb_yahoo_local_account_data *ylad, 
        GList *buddies)
{
    GList *node;
    if ( !ylad )
    {
        LOG(("eb_yahoo_add_buddies called with null context"));
        return;
    }
    for(node = buddies; node; node = node->next)
    {
        eb_account *ea = find_account_by_handle(node->data, YAHOO_SERVICE_ID);
        eb_yahoo_add_user_cached(ea, 0);
    }
}

void eb_yahoo_login( eb_local_account * account )
{
	struct yahoo_options yahoo_options;
	int retrys;
    int result;
	eb_yahoo_local_account_data * eylad = account->protocol_local_account_data;

    LOG(("eb_yahoo_login"));
	yahoo_options.connect_mode = YAHOO_CONNECT_NORMAL;
    yahoo_options.proxy_host = NULL;
    account->connected = 0;
	eylad->context = yahoo_init(account->handle, eylad->password, &yahoo_options);
    eylad->status = EB_DISPLAY_YAHOO_OFFLINE;

    if ( eylad->context == NULL )
    {
        do_error_dialog("Could not log into Yahoo service.  Please verify that \
your username and password are correctly typed.", "Yahoo Login Failed");
        return;
    }

	for( retrys = 0; !yahoo_connect(eylad->context) && retrys < 5; retrys++ )
        sleep(2);

    if ( retrys >= 5 )
    {
        LOG(("eb_yahoo_login: retries == %d, aborting", retrys));
        do_error_dialog("Could not log into Yahoo service.  Please verify that \
your username and password are correctly typed.", "Yahoo Login Failed");
        account->connected = 0;
        eylad->status = YAHOO_OFFLINE;
        return;
    }

    LOG(("connected after %d try(s)", retrys));

	result = yahoo_get_config(eylad->context);
    if ( ! result )
    {
        LOG(("Yahoo didn't get config"));
        do_error_dialog("Could not log into Yahoo service.  Please verify that \
your username and password are correctly typed.", "Yahoo Login Failed");
        return;
    }

 	/* Shove random new buddies somewhere */
 	if (eylad->context && eylad->context->buddies) {
 	  struct yahoo_buddy **buddies;
 	  eb_account * ea = NULL;
 	  int changed = 0;
	  
 	  for(buddies=eylad->context->buddies; *buddies; buddies++) {
 		struct yahoo_buddy *bud = *buddies;
 		
 		if ( find_contact_by_handle(bud->id) ) 
 		  continue;
		
 		if ( !find_contact_by_nick(bud->id) ) 
 		  {
 			changed = 1;
 			LOG(("eb_yahooo_login: Need to add a new contact \"%s\"",bud->id));
 			if ( !find_grouplist_by_name(bud->group) )
 			  {
 				LOG(("... and the group \"%s\"doesn't exist, either",bud->group));
 				add_group(bud->group);
 			  }
 			add_new_contact(bud->group, bud->id, YAHOO_SERVICE_ID);
 		  }
		
 		ea = eb_yahoo_new_account( bud->id );
 		add_account(bud->id, ea);
		
 	  }
	  
 	  if (changed) {
 		write_contact_list();
 		// MakeEditContactList();
 	  }
	  
 	}


	result = yahoo_cmd_logon(eylad->context, YAHOO_ONLINE);
    if ( result /* yahoo_cmd_logon results zero on failure */ )
    {
        LOG(("Yahoo didn't logon"));
        do_error_dialog("Could not log into Yahoo service.  Please verify that \
your username and password are correctly typed.", "Yahoo Login Failed");
        account->connected=0;
        eylad->status = YAHOO_OFFLINE;
        return;
    }
    account->connected = 1;
    eylad->status = EB_DISPLAY_YAHOO_ONLINE;
    eb_yahoo_add_buddies(eylad, eb_yahoo_buddies);
    LOG(("Adding GDK input source %d", eylad->context->sockfd));
    eylad->input = gdk_input_add(eylad->context->sockfd, GDK_INPUT_READ, eb_yahoo_callback, eylad);
	eylad->ping_timeout_tag = gtk_timeout_add(2*60*1000,
			(void *) eb_yahoo_ping_timeout_callback, eylad);
	ref_count++;
}

void eb_yahoo_logout( eb_local_account * account )
{
	GList *l;
    eb_yahoo_local_account_data *ylad;

    if ( account->connected == 0 )
    {
        LOG(("eb_yahoo_logout called for already logged out account!"));
        return;
    }

    LOG(("eb_yahoo_logout"));
    ylad = (eb_yahoo_local_account_data *)account->protocol_local_account_data;
    if ( ylad == NULL || ylad->context == NULL )
    {
        return;
    }

    gdk_input_remove(ylad->input);
    gtk_timeout_remove(ylad->ping_timeout_tag);
    yahoo_cmd_logoff(ylad->context);
    g_free(ylad->context);
    ylad->context = NULL;
    ylad->status = YAHOO_OFFLINE;
    ref_count--;
    account->connected = 0;
	
	for (l = eb_yahoo_buddies; l ; l = l->next) {
		eb_account * ea;
        ea = find_account_by_handle(l->data, YAHOO_SERVICE_ID);
		buddy_logoff(ea);
		buddy_update_status(ea);
	}
}

void eb_yahoo_send_im( eb_local_account * account_from,
					eb_account * account_to,
					gchar *message )
{
    eb_yahoo_local_account_data *ylad = (eb_yahoo_local_account_data *)
        account_from->protocol_local_account_data;

    LOG(("eb_yahoo_send_im: %s => %s: %s", account_from->handle, 
                account_to->handle, message));
	if ( eb_yahoo_query_connected(account_to) )
	{
		yahoo_cmd_msg(ylad->context, account_from->handle,
            account_to->handle, message);
	}
	else
	{
		LOG(("eb_yahoo_send_im: %s is offline, sending as offline message",
					account_to->handle));
		yahoo_cmd_msg_offline(ylad->context,
				account_from->handle, account_to->handle,
				message);
	}
}

eb_local_account * eb_yahoo_read_local_account_config( GList * pairs )
{
    eb_local_account *ela = g_new0(eb_local_account, 1);
    eb_yahoo_local_account_data *yla = g_new0(eb_yahoo_local_account_data, 1);

    LOG(("eb_yahoo_read_local_account_config"));
    ela -> handle = strdup(value_pair_get_value(pairs, "SCREEN_NAME"));
    strncpy(ela->alias, ela->handle, 255);
    strncpy(yla->password, value_pair_get_value(pairs, "PASSWORD"), 255);

    ela->service_id = YAHOO_SERVICE_ID;
    ela->protocol_local_account_data = yla;
    yla->status = YAHOO_OFFLINE;

    return ela;
}

GList * eb_yahoo_write_local_config( eb_local_account * account )
{
	eb_yahoo_local_account_data * yla = account->protocol_local_account_data;
	GList * list = NULL;
	value_pair * vp;

	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, yla->password);

	list = g_list_append(list, vp);

	return list;
}

eb_account * eb_yahoo_read_account_config( GList * config, struct contact *contact )
{
    eb_account *ea = g_new0(eb_account, 1);
    eb_yahoo_account_data *ylad = g_new0(eb_yahoo_account_data, 1);

    LOG(("eb_yahoo_read_account_config"));
    ylad->status = YAHOO_OFFLINE; /* we'll get told by the server if they're online */
	ylad->status_message = NULL;

    strncpy(ea->handle, value_pair_get_value(config, "NAME"), 255);

    ea->service_id = YAHOO_SERVICE_ID;
    ea->protocol_account_data = ylad;
    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_yahoo_add_user(ea);

	return ea;
}

GList * eb_yahoo_get_states()
{
    GList *states = NULL;

    LOG(("eb_yahoo_get_states"));
    states = g_list_append(states, "Available");
    states = g_list_append(states, "Be Right Back");
    states = g_list_append(states, "Busy");
    states = g_list_append(states, "Not at Home");
    states = g_list_append(states, "Not at my Desk");
    states = g_list_append(states, "Not in the Office");
    states = g_list_append(states, "On the Phone");
    states = g_list_append(states, "On Vacation");
    states = g_list_append(states, "Out to Lunch");
    states = g_list_append(states, "Stepped Out");
    states = g_list_append(states, "Invisible");
    states = g_list_append(states, "Idle");
    states = g_list_append(states, "Offline");

	return states;
}

gint eb_yahoo_get_current_state( eb_local_account * account )
{
    eb_yahoo_local_account_data * ylad;

    LOG(("eb_yahoo_get_current_state"));
    ylad = (eb_yahoo_local_account_data *)account->protocol_local_account_data;
    if ( eb_services[account->service_id].protocol_id != YAHOO_PROTOCOL_ID)
    {
        LOG(("eb_yahoo_get_current_state: protocol_id != YAHOO_PROTOCOL_ID"));
    }
	return ylad->status;
}

void eb_yahoo_set_current_state(eb_local_account * account, gint state )
{
    eb_yahoo_local_account_data *ylad;
    int yahoo_state=eb_to_yahoo_state_translation[state];

    LOG(("eb_yahoo_set_current_state to %d/%d",
               yahoo_state, state));
    if ( account == NULL )
    {
        g_warning("ACCOUNT is NULL");
        return;
    }
    if ( account->protocol_local_account_data == NULL )
    {
        g_warning("Account Protocol Local Data is NULL");
    }

    ylad = (eb_yahoo_local_account_data *)account->protocol_local_account_data;
    if ( eb_services[account->service_id].protocol_id != YAHOO_PROTOCOL_ID)
    {
        LOG(("eb_yahoo_get_current_state: protocol_id != YAHOO_PROTOCOL_ID"));
    }

    LOG(("ylad->status = %d, state = %d, yahoo_state = %d",
                ylad->status, state, yahoo_state));
    LOG(("account->connected = %d", account->connected));


    /* Sanity check */
#ifdef YAHOO_DEBUG
    if ( ylad->status == YAHOO_OFFLINE && account->connected == 1 )
    {
        LOG(("Sanity Check: ylad->status == offline but account->connected == 1"));
    }
    if ( ylad->status != YAHOO_OFFLINE && account->connected == 0 )
    {
        LOG(("Sanity Check: ylad->status == online but account->connected == 0"));
    }
#endif

    if ( ylad->status == YAHOO_OFFLINE && yahoo_state != YAHOO_OFFLINE )
    {
        eb_yahoo_login(account);
        if ( account->connected == 0 )
        {
            LOG(("Could not login: not setting status"));
        }
    }
    else if ( ylad->status != YAHOO_OFFLINE && yahoo_state == YAHOO_OFFLINE )
    {
        eb_yahoo_logout(account);
        ylad->status = yahoo_state;
        return;
    }
    if ( account->connected == 0 )
    {
        LOG(("Not setting state for offline account"));
        return;
    }
    ylad->status = yahoo_state;

	if (state == YAHOO_ONLINE)
    	yahoo_cmd_set_back_mode(ylad->context, yahoo_state, " ");
	else
    	yahoo_cmd_set_away_mode(ylad->context, yahoo_state, " ");
		
}

void eb_yahoo_add_user_cached(eb_account * account, gint update_local )
{
    GList *node;

    if ( update_local )
    {
        eb_yahoo_buddies = g_list_append(eb_yahoo_buddies, account->handle);
    }

    LOG(("eb_yahoo_add_user_cached"));
    for ( node = accounts ; node ; node=node->next )
    {
        eb_local_account *ela = node->data;
        if ( ela->connected && ela->service_id == YAHOO_SERVICE_ID )
        {
            eb_yahoo_local_account_data *ylad = ela->protocol_local_account_data;
            eb_yahoo_account_data *yad = 
                (eb_yahoo_account_data *) account->protocol_account_data;
            struct yahoo_buddy **buddy;

            yad->status = YAHOO_OFFLINE;

            /* find out if this is already a buddy */
            for ( buddy = ylad->context->buddies; *buddy; buddy++ )
            {
                struct yahoo_buddy *bud = *buddy;

                if ( !strcmp(bud->id, account->handle) )
                {
                    LOG(("buddy %s exists, not adding", account->handle));
                    /* buddy exists */
                    /* yahoo_cmd_user_status(ylad->context); */
					return;
                }
            }
#if 1
            LOG(("Adding buddy %s to group %s", account->handle,
                        account->account_contact->group->name));

            yahoo_add_buddy(ylad->context, account->handle,
                    ela->handle, 
                    account->account_contact->group->name ,
                    "" /* No message */ );
#endif
            yahoo_cmd_user_status(ylad->context);
        }
    }
}

void eb_yahoo_add_user(eb_account *account)
{
    eb_yahoo_add_user_cached(account, 1);
}

void eb_yahoo_del_user( eb_account * account )
{
    GList *node;

    LOG(("eb_yahoo_del_user: %s", account->handle));

    for (node = accounts; node; node=node->next)
    {
        eb_local_account *ela = (eb_local_account *) node->data;
        if ( ela->connected && ela->service_id == YAHOO_SERVICE_ID )
        {
            eb_yahoo_local_account_data *ylad = ela->protocol_local_account_data;

            yahoo_remove_buddy(ylad->context,
                    account->handle, 
                    ela->handle,
                    (account->account_contact == NULL ? "Default" :
                    account->account_contact->group->name),
                    "");
            yahoo_cmd_user_status(ylad->context);
        }
    }
}

eb_account * eb_yahoo_new_account( gchar * account )
{
    eb_account * acct = g_new0(eb_account, 1);
    eb_yahoo_account_data *yad = g_new0(eb_yahoo_account_data, 1);

    LOG(("eb_yahoo_new_account"));

    acct->protocol_account_data = yad;
    strncpy(acct->handle, account, 255);
    acct->service_id = YAHOO_SERVICE_ID;
    yad->status = YAHOO_OFFLINE;
	yad->status_message = NULL;
	return acct;
}

static gint pixmaps = 0;
static GdkPixmap * eb_yahoo_pixmap[EB_DISPLAY_YAHOO_CUSTOM+1];
static GdkBitmap * eb_yahoo_bitmap[EB_DISPLAY_YAHOO_CUSTOM+1];

void eb_yahoo_init_pixmaps()
{
	gint i;
	gchar ** xpm;
	
	for (i=EB_DISPLAY_YAHOO_ONLINE; i<=EB_DISPLAY_YAHOO_CUSTOM; i++) {
		switch(i) {
		case EB_DISPLAY_YAHOO_ONLINE:
		case EB_DISPLAY_YAHOO_OFFLINE:
			xpm = yahoo_online_xpm;
			break;
		default:
			xpm = yahoo_away_xpm;
			break;
		}
		eb_yahoo_pixmap[i] = gdk_pixmap_create_from_xpm_d(statuswindow->window,
			&eb_yahoo_bitmap[i], NULL, xpm);
	}
	pixmaps = 1;
}

void eb_yahoo_get_status_pixmap( eb_account * account, GdkPixmap ** pm, GdkBitmap ** bm )
{
	eb_yahoo_account_data * yad;
	
	if (!pixmaps)
		eb_yahoo_init_pixmaps();
	
	yad = account->protocol_account_data;
	
	*pm = eb_yahoo_pixmap[yahoo_to_eb_state_translation(yad->status)];
	*bm = eb_yahoo_bitmap[yahoo_to_eb_state_translation(yad->status)];
}

gchar * eb_yahoo_get_status_string( eb_account * account )
{
    eb_yahoo_account_data *yad = account->protocol_account_data;
    int i;

#ifdef HANDLE_CUSTOM_STATUS
	if ( yad->status == YAHOO_STATUS_CUSTOM && yad->status_message )
	{
		LOG(("eb_yahoo_get_status_string: %s is %s", account->handle,
					yad->status_message));
		return yad->status_message;
	}
#endif
    for ( i = 0; eb_yahoo_status_codes[i].label; i++ )
    {
        if ( eb_yahoo_status_codes[i].id == yad->status )
        {
/*             LOG(("eb_yahoo_get_status_string: %s is %s", 
                        account->handle, eb_yahoo_status_codes[i].label)); */
            return eb_yahoo_status_codes[i].label;
        }
    }

    LOG(("eb_yahoo_get_status_string: %s is Unknown [%d]", account->handle,
                yad->status));
    return "Unk";
}

void eb_yahoo_set_idle(eb_local_account * account, gint idle )
{
    eb_yahoo_local_account_data *ylad;

    LOG(("eb_yahoo_set_idle: %d", idle));

    ylad = ( eb_yahoo_local_account_data *) account->protocol_local_account_data;
    if ((idle == 0) && (eb_yahoo_get_current_state(account) == YAHOO_IDLE))
    {
		if(account->status_menu)
		{
			gtk_check_menu_item_set_active
			(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, EB_DISPLAY_YAHOO_ONLINE)->data
				), TRUE
			);

		}
    }
    else if ((idle >= 600) && (eb_yahoo_get_current_state(account) == YAHOO_ONLINE))
    {
		if(account->status_menu)
		{
			gtk_check_menu_item_set_active
			(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, EB_DISPLAY_YAHOO_IDLE)->data
				), TRUE
			);

		}
    }
}

void eb_yahoo_set_away(eb_local_account * account, gchar * message )
{
    eb_yahoo_local_account_data *ylad;

    ylad = ( eb_yahoo_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, EB_DISPLAY_YAHOO_ONLINE)->data
				), TRUE
			);

		}
    }
    else
    {
		if(account->status_menu)
		{
			gtk_check_menu_item_set_active
			(
				GTK_CHECK_MENU_ITEM
				(
					g_slist_nth(account->status_menu, EB_DISPLAY_YAHOO_BRB)->data
				), TRUE
			);

		}
    }
}

void eb_yahoo_process_conference_add_invite(struct yahoo_packet *pkt, 
		eb_yahoo_local_account_data *ylad)
{
	char **userlist;
	eb_local_account *ea = yahoo_find_local_account_by_context(ylad->context);
	eb_chat_room *chat_room;
	eb_yahoo_chat_room_data *ycrd;

	LOG(("conference addl invite: from %s to conf_id %s", pkt->conf_inviter,
				pkt->conf_id));

	chat_room = find_chat_room_by_id (pkt->conf_id);
	if ( chat_room )
	{
		/* Probably someone just accepted the invitation? */
		return;
	}

	chat_room = g_new0(eb_chat_room, 1);
	ycrd = g_new0(eb_yahoo_chat_room_data, 1);
	strcpy(chat_room->id, pkt->conf_id );
	strcpy(chat_room->room_name, pkt->conf_id);
	ycrd->host = g_strdup(pkt->conf_inviter);
	chat_room->protocol_local_chat_room_data = (void *) ycrd;
	chat_room->fellows=NULL;
	chat_room->connected = FALSE;
	
	chat_rooms = g_list_append(chat_rooms, chat_room);
	chat_room->chat_room_account = ea;

	LOG(("Initial conference members from invitation: "));
//	chat_room->fellows = g_list_append(NULL, ea->handle);

	eb_join_chat_room(chat_room);

	for ( userlist = pkt->conf_userlist; *userlist; userlist++)
	{
		LOG(("==> %s", *userlist));
		eb_chat_room_buddy_arrive(chat_room, *userlist, *userlist);
	}
}
void eb_yahoo_process_conference_invite(struct yahoo_packet *pkt, 
		eb_yahoo_local_account_data *ylad)
{
	char **userlist;
	eb_local_account *ea = yahoo_find_local_account_by_context(ylad->context);
	eb_chat_room *chat_room;
	eb_yahoo_chat_room_data *ycrd;

	LOG(("conference invite: from %s to conf_id %s", pkt->conf_host,
				pkt->conf_id));

	chat_room = find_chat_room_by_id (pkt->conf_id);
	if ( chat_room )
	{
		/* Probably someone just accepted the invitation? */
		return;
	}

	if ( pkt->conf_host )
	{
		if (!strncmp("None of the users", pkt->conf_host, 17))
		{
			LOG(("conference was rejected by server"));
			chat_room = find_chat_room_by_id(pkt->conf_id);
			if ( !chat_room )
			{
				LOG(("but we didn't know about it"));
				return;
			}
			gtk_widget_destroy(chat_room->window);
			return;
		}
	}

	chat_room = g_new0(eb_chat_room, 1);
	ycrd = g_new0(eb_yahoo_chat_room_data, 1);
	strcpy(chat_room->id, pkt->conf_id );
	strcpy(chat_room->room_name, pkt->conf_id);
	ycrd->host = g_strdup(pkt->conf_host);
	chat_room->protocol_local_chat_room_data = (void *) ycrd;
	chat_room->fellows=NULL;
	chat_room->connected = FALSE;
	
	chat_rooms = g_list_append(chat_rooms, chat_room);
	chat_room->chat_room_account = ea;

	LOG(("Initial conference members from invitation: "));
//	chat_room->fellows = g_list_append(NULL, ea->handle);

	eb_join_chat_room(chat_room);
	eb_yahoo_join_chat_room(chat_room);
	eb_chat_room_buddy_arrive(chat_room, pkt->conf_host, pkt->conf_host);

	for ( userlist = pkt->conf_userlist; *userlist; userlist++)
	{
		LOG(("==> %s", *userlist));
		eb_chat_room_buddy_arrive(chat_room, *userlist, *userlist);
	}
}

char **yahoo_conference_get_userlist(GList *fellows, char *handle)
{
	GList *node;
	char **userlist;
	char **user;

	if ( !fellows ) /* Empty userlist */
		return NULL;

	userlist = g_new0(char *, g_list_length(fellows));

	LOG(("building userlist except handle %s:", handle));

	for ( user=userlist, node=fellows; node; node=node->next )
	{
		LOG(("                : %s", node->data));
		if ( !strcmp(node->data, handle))
		{
			LOG(("MATCH--skipping"));
			continue;
		}
		if ( ((char *)node->data)[0] == '\0' )
		{
			LOG(("NULL--skipping"));
			continue;
		}
		*(user++) = g_strdup(node->data);
	}
	user = NULL;

	return userlist;
}

void yahoo_conference_free_userlist(char **userlist)
{
	char **user;

	if ( userlist == NULL ) /* Empty Userlist */
		return;

	for ( user = userlist; *user; user++ )
	{
		g_free(*user);
	}
	g_free(userlist);
}

void eb_yahoo_send_chat_room_message(eb_chat_room *room, gchar *message)
{
	eb_yahoo_local_account_data *ylad = room->chat_room_account->protocol_local_account_data;
	eb_yahoo_chat_room_data *ycrd = (eb_yahoo_chat_room_data *)room->protocol_local_chat_room_data;
	char **userlist;

	userlist = yahoo_conference_get_userlist(room->fellows, ycrd->host);

	LOG (("sending conference message %s to conference %s",
				message, room->room_name));

	yahoo_cmd_conf_msg(ylad->context, room->room_name, userlist, message);
	yahoo_conference_free_userlist(userlist);
}

void eb_yahoo_join_chat_room(eb_chat_room *room)
{
	eb_yahoo_local_account_data *ylad = room->chat_room_account->protocol_local_account_data;
	eb_yahoo_chat_room_data *ycrd = (eb_yahoo_chat_room_data *)room->protocol_local_chat_room_data;
	char **userlist;

	LOG(("joining chat room id %s", room->room_name));

	userlist = yahoo_conference_get_userlist(room->fellows, 
			room->chat_room_account->handle);
	if ( !userlist ) /* We're not connected yet */
	{
		return;
	}

	yahoo_cmd_conf_logon(ylad->context, room->room_name, ycrd->host,
		userlist);
	yahoo_conference_free_userlist(userlist);
}

void eb_yahoo_send_chat_room_invitation(eb_local_account *ela,
		eb_chat_room *ecr, char *user, char *message)
{
	eb_yahoo_local_account_data *ylad = (eb_yahoo_local_account_data *) 
		ela->protocol_local_account_data;
	eb_yahoo_chat_room_data *ycrd = (eb_yahoo_chat_room_data *)
		ecr->protocol_local_chat_room_data;
	char **userlist;

	LOG(("inviting %s to conference %s", user, ecr->id));


	if ( ycrd -> connected )
	{
		userlist = yahoo_conference_get_userlist(ecr->fellows, 
				ecr->chat_room_account->handle);
		yahoo_cmd_conf_invite(ylad->context, ecr->id, userlist, user, message);
	} else
	{
		eb_chat_room_buddy_arrive(ecr, user, user);
		userlist = yahoo_conference_get_userlist(ecr->fellows,
				ecr->chat_room_account->handle);
		yahoo_cmd_start_conf(ylad->context, ecr->id,
				userlist, "Everybuddy", 0 /* or 1 for voice chat */);
		eb_chat_room_buddy_leave(ecr, user);
		ycrd->connected = TRUE;
	}
	yahoo_conference_free_userlist(userlist);
}

eb_chat_room *eb_yahoo_make_chat_room(char *name, eb_local_account *ela)
{
	eb_chat_room *ecr = g_new0(eb_chat_room, 1);
	eb_yahoo_chat_room_data *ycrd = g_new0(eb_yahoo_chat_room_data, 1);

	strcpy( ecr->room_name, name );
	strcpy( ecr->id, name);
	ecr->fellows = NULL;
	ecr->connected = FALSE;
	ecr->chat_room_account = ela;
	ecr->protocol_local_chat_room_data = ycrd;
	ycrd->host = g_strdup(ela->handle);
	ycrd->connected = FALSE;
	eb_join_chat_room(ecr);
	eb_chat_room_buddy_arrive(ecr, ela->handle, ela->handle);
	return ecr;
}


void eb_yahoo_leave_chat_room(eb_chat_room *room)
{
	eb_yahoo_local_account_data *ylad = room->chat_room_account->protocol_local_account_data;
	eb_yahoo_chat_room_data *ycrd = (eb_yahoo_chat_room_data *)room->protocol_local_chat_room_data;
	char **userlist;

	LOG(("leaving chat room id %s", room->room_name));

	if ( ycrd->connected )
	{
		userlist = yahoo_conference_get_userlist(room->fellows,
				room->chat_room_account->handle);
		yahoo_cmd_conf_logoff(ylad->context, room->room_name, userlist);
		yahoo_conference_free_userlist(userlist);
	}
}

void eb_yahoo_get_info( eb_local_account * reciever, eb_account * sender)
{
   gchar buff[1024];

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

   if(sender->infowindow->info_type == -1 || sender->infowindow->info_data == NULL){
      if(sender->infowindow->info_data == NULL) {
        sender->infowindow->info_data = malloc(sizeof(yahoo_info_data));
        ((yahoo_info_data *)sender->infowindow->info_data)->profile = NULL;
        sender->infowindow->cleanup = yahoo_info_data_cleanup;
      }
      sender->infowindow->info_type = YAHOO_SERVICE_ID;
    }
    if(sender->infowindow->info_type != YAHOO_SERVICE_ID) {
       /*hmm, I wonder what should really be done here*/
       return; 
    }
    sprintf(buff,"http://profiles.yahoo.com/%s",sender->handle);
    if( ((yahoo_info_data *)sender->infowindow->info_data)->profile != NULL)
      free(((yahoo_info_data *)sender->infowindow->info_data)->profile);
    ((yahoo_info_data *)sender->infowindow->info_data)->profile = malloc(strlen(buff)+1);
    strcpy(((yahoo_info_data *)sender->infowindow->info_data)->profile,buff);

    yahoo_info_update(sender->infowindow);
}


void yahoo_info_update(info_window *iw) {
  gchar buff[1024];
  yahoo_info_data * yid = (yahoo_info_data *)iw->info_data;

  clear_info_window(iw);
  sprintf(buff,"Profile for <B>%s</B><BR><HR>",iw->remote_account->handle);
  gtk_html_append_text(GTK_HTML(iw->info),buff,0);
  sprintf(buff,"<a href=\"%s\">%s</a>",yid->profile,yid->profile);
  gtk_html_append_text(GTK_HTML(iw->info),buff,0);
}

void yahoo_info_data_cleanup(info_window *iw){
  yahoo_info_data * yid = (yahoo_info_data *)iw->info_data;
  if(yid->profile != NULL) free(yid->profile);
}

struct service_callbacks * yahoo_query_callbacks()
{
	struct service_callbacks * sc;
	
    LOG(("yahoo_query_callbacks"));
	sc = g_new0( struct service_callbacks, 1);
	sc->query_connected = eb_yahoo_query_connected;
	sc->login = eb_yahoo_login;
	sc->logout = eb_yahoo_logout;
	sc->send_im = eb_yahoo_send_im;
	sc->read_local_account_config = eb_yahoo_read_local_account_config;
	sc->write_local_config = eb_yahoo_write_local_config;
	sc->read_account_config = eb_yahoo_read_account_config;
	sc->get_states = eb_yahoo_get_states;
	sc->get_current_state = eb_yahoo_get_current_state;
	sc->set_current_state = eb_yahoo_set_current_state;
	sc->add_user = eb_yahoo_add_user;
	sc->del_user = eb_yahoo_del_user;
	sc->new_account = eb_yahoo_new_account;
	sc->get_status_string = eb_yahoo_get_status_string;
	sc->get_status_pixmap = eb_yahoo_get_status_pixmap;
	sc->set_idle = eb_yahoo_set_idle;
	sc->set_away = eb_yahoo_set_away;
	sc->send_chat_room_message = eb_yahoo_send_chat_room_message;
	sc->join_chat_room = eb_yahoo_join_chat_room;
	sc->leave_chat_room = eb_yahoo_leave_chat_room;
	sc->make_chat_room = eb_yahoo_make_chat_room;
	sc->send_invite = eb_yahoo_send_chat_room_invitation;
        sc->get_info = eb_yahoo_get_info;
	
	return sc;
}
