view src/prpl.c @ 2906:538c58b43eff

[gaim-migrate @ 2919] save save me from this wandered around the town all the thousand things i might miss and you think we'll suffer much think we'll close our eyes just to see the light pass us by with tomorrow coming hope that i don't let you down again said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see sit we'll take our time watching the flowers grow all the friends we've known say goodbye and you did you suffer much did you close your eyes just to see the night rush on by gathered all around you hope that we don't let you down again i said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see i said i'm so glad to be here does it mean a thing if only i could breathe what you breathe if only i could see what you see if only i could just believe a thing --Moist, "Breathe" (as transcribed by http://www.veddma.com/veddma/moist.htm) Patches from: Ari Pollak Ben Miller Mark Doliner Sean Egan Vincas Ciziunas Thanks everyone. Somewhere in the middle of all of this it started to get really tedious and annoying. I think it's getting close to the point where I quit. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 21 Dec 2001 10:23:04 +0000
parents 87d11d2a7d59
children 0f1766887ddd
line wrap: on
line source

/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
 * 
 * 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 "gaim.h"
#include "prpl.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "pixmaps/ok.xpm"
#include "pixmaps/cancel.xpm"
#include "pixmaps/tb_forward.xpm"

GSList *protocols = NULL;

GtkWidget *protomenu = NULL;

struct _prompt {
	GtkWidget *window;
	GtkWidget *entry;
	void (*doit)(void *, char *);
	void (*dont)(void *);
	void *data;
};

struct prpl *find_prpl(int prot)
{
	GSList *e = protocols;
	struct prpl *r;

	while (e) {
		r = (struct prpl *)e->data;
		if (r->protocol == prot)
			return r;
		e = e->next;
	}

	return NULL;
}

static gint proto_compare(struct prpl *a, struct prpl *b)
{
	/* neg if a before b, 0 if equal, pos if a after b */
	return a->protocol - b->protocol;
}

void load_protocol(proto_init pi, int size)
{
	struct prpl *p;
	struct prpl *old;
	if (size != sizeof(struct prpl)) {
		do_error_dialog(_("You have attempted to load a protocol which was not compiled"
				  " from the same version of the source as this application was."
				  " Unfortunately, because it is not the same version I cannot"
				  " safely tell you which one it was. Needless to say, it was not"
				  " successfully loaded."), _("Protocol Error"));
		return;
	}
	p = g_new0(struct prpl, 1);
	pi(p);
	if ((old = find_prpl(p->protocol)) != NULL)
		unload_protocol(old);
	protocols = g_slist_insert_sorted(protocols, p, (GCompareFunc)proto_compare);
	regenerate_user_list();
}

void unload_protocol(struct prpl *p)
{
	GSList *c = connections;
	struct gaim_connection *g;
	while (c) {
		g = (struct gaim_connection *)c->data;
		if (g->prpl == p) {
			char buf[256];
			g_snprintf(buf, sizeof buf, _("%s was using %s, which got removed."
						      " %s is now offline."), g->username,
				   p->name(), g->username);
			do_error_dialog(buf, _("Disconnect"));
			signoff(g);
			c = connections;
		} else
			c = c->next;
	}
	protocols = g_slist_remove(protocols, p);
	g_free(p);
	regenerate_user_list();
}

STATIC_PROTO_INIT

static void des_win(GtkWidget *a, GtkWidget *b)
{
	gtk_widget_destroy(b);
}

static void rem_win(GtkWidget *a, GtkWidget *b)
{
	void *d = gtk_object_get_user_data(GTK_OBJECT(a));
	if (d)
		gtk_signal_disconnect_by_data(GTK_OBJECT(b), d);
	gtk_widget_destroy(b);
}

void do_ask_dialog(const char *text, void *data, void *doit, void *dont)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *button;

	GAIM_DIALOG(window);
	gtk_window_set_wmclass(GTK_WINDOW(window), "accept", "Gaim");
	gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
	gtk_window_set_title(GTK_WINDOW(window), _("Accept?"));
	gtk_widget_realize(window);
	aol_icon(window->window);
	if (dont)
		gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(dont), data);

	vbox = gtk_vbox_new(FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_container_add(GTK_CONTAINER(window), vbox);

	label = gtk_label_new(text);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	button = picture_button(window, _("Cancel"), cancel_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(des_win), window);

	button = picture_button(window, _("Accept"), ok_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
	if (dont)
		gtk_object_set_user_data(GTK_OBJECT(button), data);
	if (doit)
		gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(doit), data);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(rem_win), window);

	gtk_widget_show_all(window);
}

static void des_prompt(GtkWidget *w, struct _prompt *p)
{
	if (p->dont)
		(p->dont)(p->data);
	gtk_widget_destroy(p->window);
	g_free(p);
}

static void act_prompt(GtkWidget *w, struct _prompt *p)
{
	if (p->doit)
		(p->doit)(p->data, gtk_entry_get_text(GTK_ENTRY(p->entry)));
	gtk_widget_destroy(p->window);
}

void do_prompt_dialog(const char *text, const char *def, void *data, void *doit, void *dont)
{
	GtkWidget *window;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *label;
	GtkWidget *entry;
	GtkWidget *button;
	struct _prompt *p;

	p = g_new0(struct _prompt, 1);
	p->data = data;
	p->doit = doit;
	p->dont = dont;

	GAIM_DIALOG(window);
	p->window = window;
	gtk_window_set_wmclass(GTK_WINDOW(window), "prompt", "Gaim");
	gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
	gtk_window_set_title(GTK_WINDOW(window), _("Gaim - Prompt"));
	gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(des_prompt), p);
	gtk_widget_realize(window);
	aol_icon(window->window);

	vbox = gtk_vbox_new(FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_container_add(GTK_CONTAINER(window), vbox);

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	label = gtk_label_new(text);
	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);

	entry = gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
	if (def)
		gtk_entry_set_text(GTK_ENTRY(entry), def);
	gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(act_prompt), p);
	p->entry = entry;

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	button = picture_button(window, _("Cancel"), cancel_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(des_win), window);

	button = picture_button(window, _("Accept"), ok_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(act_prompt), p);

	gtk_widget_show_all(window);
}

static void proto_act(GtkObject *obj, struct gaim_connection *gc)
{
	char *act = gtk_object_get_user_data(obj);
	gc->prpl->do_action(gc, act);
}

void do_proto_menu()
{
	GtkWidget *menuitem;
	GtkWidget *submenu;
	GList *l;
	GSList *c = connections;
	struct gaim_connection *gc = NULL;
	int count = 0;
	char buf[256];

	if (!protomenu)
		return;

	l = gtk_container_children(GTK_CONTAINER(protomenu));
	while (l) {
		gtk_container_remove(GTK_CONTAINER(protomenu), GTK_WIDGET(l->data));
		l = l->next;
	}

	while (c) {
		gc = c->data;
		if (gc->prpl->actions && gc->prpl->do_action)
			count++;
		c = g_slist_next(c);
	}
	c = connections;

	if (!count) {
		g_snprintf(buf, sizeof(buf), "No actions available");
		menuitem = gtk_menu_item_new_with_label(buf);
		gtk_menu_append(GTK_MENU(protomenu), menuitem);
		gtk_widget_show(menuitem);
		return;
	}

	if (count == 1) {
		GList *tmp, *act;
		while (c) {
			gc = c->data;
			if (gc->prpl->actions && gc->prpl->do_action)
				break;
			c = g_slist_next(c);
		}

		tmp = act = gc->prpl->actions();

		while (act) {
			if (act->data == NULL) {
				gaim_separator(protomenu);
				act = g_list_next(act);
				continue;
			}

			menuitem = gtk_menu_item_new_with_label(act->data);
			gtk_object_set_user_data(GTK_OBJECT(menuitem), act->data);
			gtk_menu_append(GTK_MENU(protomenu), menuitem);
			gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
					   GTK_SIGNAL_FUNC(proto_act), gc);
			gtk_widget_show(menuitem);

			act = g_list_next(act);
		}

		g_list_free(tmp);
	} else {
		while (c) {
			GList *tmp, *act;
			gc = c->data;
			if (!gc->prpl->actions || !gc->prpl->do_action) {
				c = g_slist_next(c);
				continue;
			}

			g_snprintf(buf, sizeof(buf), "%s (%s)", gc->username, gc->prpl->name());
			menuitem = gtk_menu_item_new_with_label(buf);
			gtk_menu_append(GTK_MENU(protomenu), menuitem);
			gtk_widget_show(menuitem);

			submenu = gtk_menu_new();
			gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
			gtk_widget_show(submenu);

			tmp = act = gc->prpl->actions();

			while (act) {
				if (act->data == NULL) {
					gaim_separator(submenu);
					act = g_list_next(act);
					continue;
				}

				menuitem = gtk_menu_item_new_with_label(act->data);
				gtk_object_set_user_data(GTK_OBJECT(menuitem), act->data);
				gtk_menu_append(GTK_MENU(submenu), menuitem);
				gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
						   GTK_SIGNAL_FUNC(proto_act), gc);
				gtk_widget_show(menuitem);

				act = g_list_next(act);
			}

			g_list_free(tmp);
			c = g_slist_next(c);
		}
	}
}

struct mail_notify {
	struct gaim_connection *gc;
	GtkWidget *email_win;
	GtkWidget *email_label;
	char *url;
};
GSList *mailnots = NULL;

static struct mail_notify *find_mail_notify(struct gaim_connection *gc)
{
	GSList *m = mailnots;
	while (m) {
		if (((struct mail_notify *)m->data)->gc == gc)
			return m->data;
		m = m->next;
	}
	return NULL;
}

static void des_email_win(GtkWidget *w, struct mail_notify *mn)
{
	if (w != mn->email_win) {
		gtk_widget_destroy(mn->email_win);
		return;
	}
	debug_printf("removing mail notification\n");
	mailnots = g_slist_remove(mailnots, mn);
	if (mn->url)
		g_free(mn->url);
	g_free(mn);
}

void connection_has_mail(struct gaim_connection *gc, int count, const char *from, const char *subject, const char *url)
{
	GtkWidget *hbox;
	GtkWidget *vbox;
	GtkWidget *urlbut;
	GtkWidget *close;

	struct mail_notify *mn;
	char buf[2048];

	if (!(gc->user->options & OPT_USR_MAIL_CHECK))
		return;

	if (!(mn = find_mail_notify(gc))) {
		mn = g_new0(struct mail_notify, 1);
		mn->gc = gc;
		mailnots = g_slist_append(mailnots, mn);
	}

	if (count < 0 && from && subject) {
		g_snprintf(buf, sizeof buf, "%s has mail from %s: %s", gc->username, from, subject);
	} else if (count) {
		g_snprintf(buf, sizeof buf, "%s has %d new message%s.",
			   gc->username, count, count == 1 ? "" : "s");
	} else if (mn->email_win) {
		gtk_widget_destroy(mn->email_win);
		return;
	} else
		return;

	if (mn->email_win) {
		gtk_label_set_text(GTK_LABEL(mn->email_label), buf);
		return;
	}


	GAIM_DIALOG(mn->email_win);
	gtk_window_set_wmclass(GTK_WINDOW(mn->email_win), "mail", "Gaim");
	gtk_window_set_policy(GTK_WINDOW(mn->email_win), FALSE, TRUE, TRUE);
	gtk_window_set_title(GTK_WINDOW(mn->email_win), _("Gaim - New Mail"));
	gtk_signal_connect(GTK_OBJECT(mn->email_win), "destroy", GTK_SIGNAL_FUNC(des_email_win), mn);
	gtk_widget_realize(mn->email_win);
	aol_icon(mn->email_win->window);

	vbox = gtk_vbox_new(FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_container_add(GTK_CONTAINER(mn->email_win), vbox);
	gtk_widget_show(vbox);

	mn->email_label = gtk_label_new(buf);
	gtk_label_set_text(GTK_LABEL(mn->email_label), buf);
	gtk_box_pack_start(GTK_BOX(vbox), mn->email_label, 0, 0, 5);
	gtk_widget_show(mn->email_label);

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show(hbox);

	close = picture_button(mn->email_win, _("Close"), cancel_xpm);
	gtk_window_set_focus(GTK_WINDOW(mn->email_win), close);
	gtk_box_pack_end(GTK_BOX(hbox), close, 0, 0, 5);
	gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(des_email_win), mn);

	if (url) {
		mn->url = g_strdup(url);
		urlbut = picture_button(mn->email_win, _("Open Mail"), tb_forward_xpm);
		gtk_box_pack_end(GTK_BOX(hbox), urlbut, 0, 0, 5);
		gtk_signal_connect(GTK_OBJECT(urlbut), "clicked", GTK_SIGNAL_FUNC(open_url), mn->url);
		gtk_signal_connect(GTK_OBJECT(urlbut), "clicked", GTK_SIGNAL_FUNC(des_email_win), mn);
	}

	gtk_widget_show(mn->email_win);
}

struct icon_data {
	struct gaim_connection *gc;
	char *who;
	void *data;
	int len;
};

static GList *icons = NULL;

static gint find_icon_data(gconstpointer a, gconstpointer b)
{
	const struct icon_data *x = a;
	const struct icon_data *y = b;

	return ((x->gc != y->gc) || g_strcasecmp(x->who, y->who));
}

void set_icon_data(struct gaim_connection *gc, char *who, void *data, int len)
{
	struct icon_data tmp = { gc, normalize(who), NULL, 0 };
	GList *l = g_list_find_custom(icons, &tmp, find_icon_data);
	struct icon_data *id = l ? l->data : NULL;

	if (id) {
		g_free(id->data);
		if (!data) {
			icons = g_list_remove(icons, id);
			g_free(id->who);
			g_free(id);
			return;
		}
	} else if (data) {
		id = g_new0(struct icon_data, 1);
		icons = g_list_append(icons, id);
		id->gc = gc;
		id->who = g_strdup(normalize(who));
	} else {
		return;
	}

	debug_printf("Got icon for %s (length %d)\n", who, len);

	id->data = g_memdup(data, len);
	id->len = len;

	got_new_icon(gc, who);
}

void remove_icon_data(struct gaim_connection *gc)
{
	GList *list = icons;
	struct icon_data *id;

	while (list) {
		id = list->data;
		if (id->gc == gc) {
			g_free(id->data);
			g_free(id->who);
			list = icons = g_list_remove(icons, id);
			g_free(id);
		} else
			list = list->next;
	}
}

void *get_icon_data(struct gaim_connection *gc, char *who, int *len)
{
	struct icon_data tmp = { gc, normalize(who), NULL, 0 };
	GList *l = g_list_find_custom(icons, &tmp, find_icon_data);
	struct icon_data *id = l ? l->data : NULL;

	if (id) {
		*len = id->len;
		return id->data;
	}

	*len = 0;
	return NULL;
}

struct got_add {
	struct gaim_connection *gc;
	char *who;
	char *alias;
};

static void dont_add(gpointer x, struct got_add *ga)
{
	g_free(ga->who);
	if (ga->alias)
		g_free(ga->alias);
	g_free(ga);
}

static void do_add(gpointer x, struct got_add *ga)
{
	if (g_slist_find(connections, ga->gc))
		show_add_buddy(ga->gc, ga->who, NULL, ga->alias);
}

void show_got_added(struct gaim_connection *gc, const char *id,
		    const char *who, const char *alias, const char *msg)
{
	char buf[BUF_LONG];
	struct got_add *ga = g_new0(struct got_add, 1);

	ga->gc = gc;
	ga->who = g_strdup(who);
	ga->alias = alias ? g_strdup(alias) : NULL;

	g_snprintf(buf, sizeof(buf), _("%s%s%s%s has made %s their buddy%s%s%s"),
		   who,
		   alias ? " (" : "",
		   alias ? alias : "",
		   alias ? ")" : "",
		   id ? id : gc->displayname[0] ? gc->displayname : gc->username,
		   msg ? ": " : ".",
		   msg ? msg : "",
		   find_buddy(gc, ga->who) ? "" : _("\n\nDo you wish to add them to your buddy list?"));
	if (find_buddy(gc, ga->who))
		do_error_dialog(buf, "Added to List");
	else
		do_ask_dialog(buf, ga, do_add, dont_add);
}

static GtkWidget *regdlg = NULL;
static GtkWidget *reg_list = NULL;
static GtkWidget *reg_area = NULL;
static GtkWidget *reg_reg = NULL;

static void delete_regdlg()
{
	GtkWidget *tmp = regdlg;
	regdlg = NULL;
	if (tmp)
		gtk_widget_destroy(tmp);
}

static void reset_reg_dlg()
{
	GSList *P = protocols;

	if (!regdlg)
		return;

	while (GTK_BOX(reg_list)->children)
		gtk_container_remove(GTK_CONTAINER(reg_list),
				     ((GtkBoxChild *)GTK_BOX(reg_list)->children->data)->widget);

	while (GTK_BOX(reg_area)->children)
		gtk_container_remove(GTK_CONTAINER(reg_area),
				     ((GtkBoxChild *)GTK_BOX(reg_area)->children->data)->widget);

	while (P) {
		struct prpl *p = P->data;
		if (p->register_user)
			break;
		P = P->next;
	}

	if (!P) {
		GtkWidget *no = gtk_label_new(_("You do not currently have any protocols available"
						" that are able to register new accounts."));
		gtk_box_pack_start(GTK_BOX(reg_area), no, FALSE, FALSE, 5);
		gtk_widget_show(no);

		gtk_widget_set_sensitive(reg_reg, FALSE);

		return;
	}

	gtk_widget_set_sensitive(reg_reg, TRUE);

	while (P) {	/* we can safely ignore all the previous ones */
		struct prpl *p = P->data;
		P = P->next;

		if (!p->register_user)
			continue;

		/* do stuff */
	}
}

void register_dialog()
{
	/* this is just one big hack */
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkWidget *hbox;
	GtkWidget *close;

	if (regdlg) {
		gdk_window_raise(regdlg->window);
		return;
	}

	regdlg = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(regdlg), _("Gaim - Registration"));
	gtk_window_set_wmclass(GTK_WINDOW(regdlg), "register", "Gaim");
	gtk_widget_realize(regdlg);
	aol_icon(regdlg->window);
	gtk_signal_connect(GTK_OBJECT(regdlg), "destroy", GTK_SIGNAL_FUNC(delete_regdlg), NULL);

	vbox = gtk_vbox_new(FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_container_add(GTK_CONTAINER(regdlg), vbox);
	gtk_widget_show(vbox);

	reg_list = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), reg_list, FALSE, FALSE, 5);
	gtk_widget_show(reg_list);

	frame = gtk_frame_new(_("Registration Information"));
	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
	gtk_widget_show(frame);

	reg_area = gtk_hbox_new(FALSE, 5);
	gtk_container_add(GTK_CONTAINER(frame), reg_area);
	gtk_widget_show(reg_area);

	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
	gtk_widget_show(hbox);

	close = picture_button(regdlg, _("Close"), cancel_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), close, FALSE, FALSE, 5);
	gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(delete_regdlg), NULL);
	gtk_widget_show(close);

	reg_reg = picture_button(regdlg, _("Register"), ok_xpm);
	gtk_box_pack_end(GTK_BOX(hbox), reg_reg, FALSE, FALSE, 5);
	gtk_widget_show(reg_reg);

	/* fuck me */
	reset_reg_dlg();

	gtk_widget_show(regdlg);
}