view console/gntconv.c @ 13914:3ae8a3935406

[gaim-migrate @ 16414] First stab at trying to fix the MSN http connect method. It still doesn't work, and I'm not sure why, but it gets a lot farther in the signon process now. For those unfamiliar with the issue, the MSN http connect method stopped working after all the non-blocking I/O changes. The http connect method is apparently used by lots of people behind silly firewalls and stuff, and therefore we really shouldn't release Gaim 2.0.0 without it working, because people will complain. The two main problems were 1. The outgoing message queue was removed in favor of buffering all data to one large buffer. This sounds good in theory... but apparently each message sent to and from the server has a "SessionID" in the HTTP header. Every message we send should use the same SessionID as the last packet we received from the server. So basically you can't put two messages into the outgoing buffer at the same time because you don't have the correct SessionID to use for the second message. You have to wait until you get the reply from the server. 2. There were some strange buffer problems with using the wrong variable when trying to combine the header+body into one buffer before sending the message. I also fixed a small memleak or two, added some comments, and tried to clean up the code a little. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 03 Jul 2006 20:39:04 +0000
parents cc60d0861337
children fdf2dbed6faa
line wrap: on
line source

#include <string.h>
#include <util.h>

#include "gntgaim.h"
#include "gntconv.h"

#include "gnt.h"
#include "gntbox.h"
#include "gntentry.h"
#include "gnttextview.h"

GHashTable *ggconvs;

typedef struct _GGConv GGConv;
typedef struct _GGConvChat GGConvChat;
typedef struct _GGConvIm GGConvIm;

struct _GGConv
{
	GaimConversation *conv;

	GntWidget *window;        /* the container */
	GntWidget *entry;         /* entry */
	GntWidget *tv;            /* text-view */

	union
	{
		GGConvChat *chat;
		GGConvIm *im;
	} u;
};

struct _GGConvChat
{
	GntWidget *userlist;       /* the userlist */
};

struct _GGConvIm
{
	void *nothing_for_now;
};

static gboolean
entry_key_pressed(GntWidget *w, const char *key, GGConv *ggconv)
{
	if (key[0] == '\r' && key[1] == 0)
	{
		const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry));
		switch (gaim_conversation_get_type(ggconv->conv))
		{
			case GAIM_CONV_TYPE_IM:
				gaim_conv_im_send_with_flags(GAIM_CONV_IM(ggconv->conv), text, GAIM_MESSAGE_SEND);
				break;
			case GAIM_CONV_TYPE_CHAT:
				gaim_conv_chat_send(GAIM_CONV_CHAT(ggconv->conv), text);
				break;
			default:
				g_return_val_if_reached(FALSE);
		}
		gnt_entry_clear(GNT_ENTRY(ggconv->entry));
		return TRUE;
	}
	else if (key[0] == 27)
	{
		if (strcmp(key+1, GNT_KEY_DOWN) == 0)
			gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 1);
		else if (strcmp(key+1, GNT_KEY_UP) == 0)
			gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -1);
		else if (strcmp(key+1, GNT_KEY_PGDOWN) == 0)
			gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), ggconv->tv->priv.height - 2);
		else if (strcmp(key+1, GNT_KEY_PGUP) == 0)
			gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), -(ggconv->tv->priv.height - 2));
		else
			return FALSE;
		return TRUE;
	}

	return FALSE;
}

static void
closing_window(GntWidget *window, GGConv *ggconv)
{
	ggconv->window = NULL;
	gaim_conversation_destroy(ggconv->conv);
}

static void
gg_create_conversation(GaimConversation *conv)
{
	GGConv *ggc = g_hash_table_lookup(ggconvs, conv);
	char *title;
	GaimConversationType type;

	if (ggc)
		return;

	ggc = g_new0(GGConv, 1);
	g_hash_table_insert(ggconvs, conv, ggc);

	ggc->conv = conv;

	type = gaim_conversation_get_type(conv);
	title = g_strdup_printf(_("%s"), gaim_conversation_get_name(conv));
	ggc->window = gnt_box_new(FALSE, TRUE);
	gnt_box_set_title(GNT_BOX(ggc->window), title);
	gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE);
	gnt_widget_set_name(ggc->window, title);

	ggc->tv = gnt_text_view_new();
	gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv);
	gnt_widget_set_name(ggc->tv, "conversation-window-textview");
	gnt_widget_set_size(ggc->tv, getmaxx(stdscr) - 40, getmaxy(stdscr) - 15);

	ggc->entry = gnt_entry_new(NULL);
	gnt_box_add_widget(GNT_BOX(ggc->window), ggc->entry);
	gnt_widget_set_name(ggc->entry, "conversation-window-entry");
	gnt_widget_set_size(ggc->entry, getmaxx(stdscr) - 40, 1);

	g_signal_connect(G_OBJECT(ggc->entry), "key_pressed", G_CALLBACK(entry_key_pressed), ggc);
	g_signal_connect(G_OBJECT(ggc->window), "destroy", G_CALLBACK(closing_window), ggc);

	gnt_widget_set_position(ggc->window, 32, 0);
	gnt_widget_show(ggc->window);

	g_free(title);
}

static void
gg_destroy_conversation(GaimConversation *conv)
{
	g_hash_table_remove(ggconvs, conv);
}

static void
gg_write_common(GaimConversation *conv, const char *who, const char *message,
		GaimMessageFlags flags, time_t mtime)
{
	GGConv *ggconv = g_hash_table_lookup(ggconvs, conv);
	char *strip;
	GntTextViewFlags fl = 0;

	g_return_if_fail(ggconv != NULL);

	if (who && *who && (flags & (GAIM_MESSAGE_SEND | GAIM_MESSAGE_RECV)))
	{
		char * name = g_strdup_printf("%s: ", who);
		gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
				name, GNT_TEXT_FLAG_BOLD);
		g_free(name);
	}
	else
		fl = GNT_TEXT_FLAG_DIM;

	if (flags & GAIM_MESSAGE_ERROR)
		fl |= GNT_TEXT_FLAG_BOLD;
	if (flags & GAIM_MESSAGE_NICK)
		fl |= GNT_TEXT_FLAG_UNDERLINE;

	strip = gaim_markup_strip_html(message);
	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
				strip, fl);
	gnt_text_view_next_line(GNT_TEXT_VIEW(ggconv->tv));
	gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0);

	g_free(strip);

	if (flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_NICK | GAIM_MESSAGE_ERROR))
		gnt_widget_set_urgent(ggconv->tv);
}

static void
gg_write_chat(GaimConversation *conv, const char *who, const char *message,
		GaimMessageFlags flags, time_t mtime)
{
	gg_write_common(conv, who, message, flags, mtime);
}

static void
gg_write_im(GaimConversation *conv, const char *who, const char *message,
		GaimMessageFlags flags, time_t mtime)
{
	if (flags & GAIM_MESSAGE_SEND)
	{
		who = gaim_connection_get_display_name(conv->account->gc);
		if (!who)
			who = gaim_account_get_alias(conv->account);
		if (!who)
			who = gaim_account_get_username(conv->account);
	}
	else if (flags & GAIM_MESSAGE_RECV)
		who = gaim_conversation_get_name(conv);

	gg_write_common(conv, who, message, flags, mtime);
}

static void
gg_write_conv(GaimConversation *conv, const char *who, const char *alias,
		const char *message, GaimMessageFlags flags, time_t mtime)
{
	const char *name;
	if (alias && *alias)
		name = alias;
	else if (who && *who)
		name = who;
	else
		name = NULL;

	gg_write_common(conv, name, message, flags, mtime);
}

static void
gg_chat_add_users(GaimConversation *conv, GList *users, GList *flags, GList *aliases, gboolean new_arrivals)
{}

static void
gg_chat_rename_user(GaimConversation *conv, const char *old, const char *new_n, const char *new_a)
{}

static void
gg_chat_remove_user(GaimConversation *conv, GList *list)
{}

static void
gg_chat_update_user(GaimConversation *conv, const char *user)
{}

static GaimConversationUiOps conv_ui_ops = 
{
	.create_conversation = gg_create_conversation,
	.destroy_conversation = gg_destroy_conversation,
	.write_chat = gg_write_chat,
	.write_im = gg_write_im,
	.write_conv = gg_write_conv,
	.chat_add_users = gg_chat_add_users,
	.chat_rename_user = gg_chat_rename_user,
	.chat_remove_users = gg_chat_remove_user,
	.chat_update_user = gg_chat_update_user,
	.present = NULL,
	.has_focus = NULL,
	.custom_smiley_add = NULL,
	.custom_smiley_write = NULL,
	.custom_smiley_close = NULL
};

static void
destroy_ggconv(gpointer data)
{
	GGConv *conv = data;
	gnt_widget_destroy(conv->window);
	g_free(conv);
}

GaimConversationUiOps *gg_conv_get_ui_ops()
{
	return &conv_ui_ops;
}


void gg_conversation_init()
{
	ggconvs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_ggconv);
}

void gg_conversation_uninit()
{
	g_hash_table_destroy(ggconvs);
	ggconvs = NULL;
}