changeset 2382:569ae9f2bb89

[gaim-migrate @ 2395] big reorg of code. list.c contains 0 gtk. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 28 Sep 2001 07:46:36 +0000
parents 427ccd7dfdd2
children 3d4bbadf4b8d
files src/Makefile.am src/buddy.c src/dialogs.c src/gaim.h src/list.c src/multi.c src/protocols/icq/gaim_icq.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/msn/msn.c src/protocols/napster/napster.c src/protocols/oscar/oscar.c src/protocols/toc/toc.c src/protocols/yahoo/yay.c src/protocols/zephyr/zephyr.c src/server.c src/util.c
diffstat 17 files changed, 857 insertions(+), 860 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/Makefile.am	Fri Sep 28 07:46:36 2001 +0000
@@ -17,6 +17,7 @@
 			gtkticker.c \
 			html.c \
 			idle.c \
+			list.c \
 			multi.c \
 			perl.c \
 			plugins.c \
@@ -47,6 +48,7 @@
 		gtkticker.c \
 		html.c \
 		idle.c \
+		list.c \
 		multi.c \
 		perl.c \
 		plugins.c \
--- a/src/buddy.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/buddy.c	Fri Sep 28 07:46:36 2001 +0000
@@ -794,31 +794,12 @@
 }
 
 
-void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
+void ui_remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
 {
-	GSList *grp;
-	GSList *mem;
 	struct conversation *c;
 	struct group_show *gs;
 	struct buddy_show *bs;
 
-	struct group *delg;
-	struct buddy *delb;
-
-	/* we assume that gc is not NULL and that the buddy exists somewhere within the
-	 * gc's buddy list, therefore we can safely remove it. we need to ensure this
-	 * via the UI
-	 */
-
-	grp = g_slist_find(gc->groups, rem_g);
-	delg = (struct group *)grp->data;
-	mem = delg->members;
-
-	mem = g_slist_find(mem, rem_b);
-	delb = (struct buddy *)mem->data;
-
-	delg->members = g_slist_remove(delg->members, delb);
-
 	gs = find_group_show(rem_g->name);
 	if (gs) {
 		bs = find_buddy_show(gs, rem_b->name);
@@ -850,63 +831,23 @@
 			update_num_group(gs);
 	}
 
-	c = find_conversation(delb->name);
+	c = find_conversation(rem_b->name);
 	if (c)
 		update_buttons_by_protocol(c);
-	g_free(delb);
-
-	/* we don't flush buddy list to cache because in the case of remove_group that would
-	 * mean writing to the buddy list file once for each buddy, plus one more time */
 }
 
-void remove_group(struct gaim_connection *gc, struct group *rem_g)
+void ui_remove_group(struct gaim_connection *gc, struct group *rem_g)
 {
-	GSList *grp;
-	GSList *mem;
 	struct group_show *gs;
-	GList *tmp = NULL;
-
-	struct group *delg;
-	struct buddy *delb;
-
-	/* we assume that the group actually does exist within the gc, and that the gc is not NULL.
-	 * the UI is responsible for this */
-
-	grp = g_slist_find(gc->groups, rem_g);
-	delg = (struct group *)grp->data;
-	mem = delg->members;
-
-	while (delg->members) {
-		delb = (struct buddy *)delg->members->data;
-		tmp = g_list_append(tmp, g_strdup(delb->name));
-		remove_buddy(gc, delg, delb);	/* this should take care of removing
-						   the group_show if necessary */
-	}
-
-	gc->groups = g_slist_remove(gc->groups, delg);
-
-	if ((gs = find_group_show(delg->name)) != NULL) {
+
+	if ((gs = find_group_show(rem_g->name)) != NULL) {
 		shows = g_slist_remove(shows, gs);
 		gtk_tree_remove_item(GTK_TREE(buddies), gs->item);
 		g_free(gs->name);
 		g_free(gs);
 	}
-	g_free(delg);
-
-	serv_remove_buddies(gc, tmp);
-	while (tmp) {
-		g_free(tmp->data);
-		tmp = g_list_remove(tmp, tmp->data);
-	}
-
-	/* don't flush buddy list to cache in order to be consistent with remove_buddy,
-	 * mostly. remove_group is only called from one place, so we'll let it handle it. */
 }
 
-
-
-
-
 gboolean edit_drag_compare_func(GtkCTree *ctree, GtkCTreeNode *source_node,
 				GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling)
 {
@@ -1233,51 +1174,20 @@
 
 }
 
-struct buddy *add_buddy(struct gaim_connection *gc, char *group, char *buddy, char *show)
+void ui_add_buddy(struct gaim_connection *gc, struct group *g, struct buddy *b)
 {
 	GtkCTreeNode *p = NULL, *n;
 	char *text[1];
 	char buf[256];
-	struct buddy *b;
-	struct group *g;
-	struct group_show *gs = find_group_show(group);
-	char *good;
-
-	if ((b = find_buddy(gc, buddy)) != NULL)
-		return b;
-
-	g = find_group(gc, group);
-
-	if (g == NULL)
-		g = add_group(gc, group);
-
-	b = (struct buddy *)g_new0(struct buddy, 1);
-
-	if (!b)
-		return NULL;
+	struct group_show *gs = find_group_show(g->name);
 
 	b->edittype = EDIT_BUDDY;
-	b->gc = gc;
-	b->present = 0;
-
-	if (gc->prpl->normalize)
-		good = (*gc->prpl->normalize)(buddy);
-	else
-		good = buddy;
-
-	g_snprintf(b->name, sizeof(b->name), "%s", good);
-	g_snprintf(b->show, sizeof(b->show), "%s", show ? (show[0] ? show : good) : good);
-
-	g->members = g_slist_append(g->members, b);
-
-	b->idle = 0;
-	b->caps = 0;
 
 	if (gs)
 		update_num_group(gs);
 
 	if (!blist)
-		return b;
+		return;
 
 	p = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, g);
 	if (strcmp(b->name, b->show)) {
@@ -1288,41 +1198,25 @@
 
 	n = gtk_ctree_insert_node(GTK_CTREE(edittree), p, NULL, text, 5, NULL, NULL, NULL, NULL, 1, 1);
 	gtk_ctree_node_set_row_data(GTK_CTREE(edittree), n, b);
-
-	return b;
 }
 
-
-struct group *add_group(struct gaim_connection *gc, char *group)
+void ui_add_group(struct gaim_connection *gc, struct group *g)
 {
 	GtkCTreeNode *c = NULL, *p;
 	char *text[1];
-	struct group *g = find_group(gc, group);
-	if (g)
-		return g;
-	g = (struct group *)g_new0(struct group, 1);
-	if (!g)
-		return NULL;
 
 	g->edittype = EDIT_GROUP;
-	g->gc = gc;
-	strncpy(g->name, group, sizeof(g->name));
-	gc->groups = g_slist_append(gc->groups, g);
-
-	g->members = NULL;
 
 	if (!blist)
-		return g;
+		return;
 
 	c = gtk_ctree_find_by_row_data(GTK_CTREE(edittree), NULL, gc);
 	text[0] = g->name;
 	p = gtk_ctree_insert_node(GTK_CTREE(edittree), c, NULL, text, 5, NULL, NULL, NULL, NULL, 0, 1);
 	gtk_ctree_node_set_row_data(GTK_CTREE(edittree), p, g);
 
-	if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(group))
-		new_group_show(group);
-
-	return g;
+	if (!(blist_options & OPT_BLIST_NO_MT_GRP) && !find_group_show(g->name))
+		new_group_show(g->name);
 }
 
 
@@ -1513,180 +1407,6 @@
 	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, time(NULL));
 }
 
-struct group *find_group(struct gaim_connection *gc, char *group)
-{
-	struct group *g;
-	GSList *grp;
-	GSList *c = connections;
-	struct gaim_connection *z;
-	char *grpname = g_malloc(strlen(group) + 1);
-
-	strcpy(grpname, normalize (group));
-	if (gc) {
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
-			if (!g_strcasecmp(normalize (g->name), grpname)) {
-				g_free(grpname);
-				return g;
-			}
-			grp = g_slist_next(grp);
-		}
-
-		g_free(grpname);
-		return NULL;
-	} else {
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-				if (!g_strcasecmp(normalize (g->name), grpname)) {
-					g_free(grpname);
-					return g;
-				}
-				grp = g_slist_next(grp);
-			}
-
-			c = c->next;
-		}
-		g_free(grpname);
-		return NULL;
-	}
-}
-
-
-struct group *find_group_by_buddy(struct gaim_connection *gc, char *who)
-{
-	struct group *g;
-	struct buddy *b;
-	GSList *grp;
-	GSList *mem;
-	char *whoname;
-	char *(*norm)(const char *);
-
-	if (gc) {
-		if (gc->prpl->normalize)
-			norm = gc->prpl->normalize;
-		else
-			norm = normalize;
-		whoname = g_strdup((*norm)(who));
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
-
-			mem = g->members;
-			while (mem) {
-				b = (struct buddy *)mem->data;
-				if (!strcmp((*norm)(b->name), whoname)) {
-					g_free(whoname);
-					return g;
-				}
-				mem = mem->next;
-			}
-			grp = g_slist_next(grp);
-		}
-		g_free(whoname);
-		return NULL;
-	} else {
-		GSList *c = connections;
-		struct gaim_connection *z;
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			if (z->prpl->normalize)
-				norm = z->prpl->normalize;
-			else
-				norm = normalize;
-			whoname = g_strdup((*norm)(who));
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-
-				mem = g->members;
-				while (mem) {
-					b = (struct buddy *)mem->data;
-					if (!strcmp((*norm)(b->name), whoname)) {
-						g_free(whoname);
-						return g;
-					}
-					mem = mem->next;
-				}
-				grp = g_slist_next(grp);
-			}
-			c = c->next;
-			g_free(whoname);
-		}
-		return NULL;
-	}
-}
-
-
-struct buddy *find_buddy(struct gaim_connection *gc, char *who)
-{
-	struct group *g;
-	struct buddy *b;
-	GSList *grp;
-	GSList *c;
-	struct gaim_connection *z;
-	GSList *mem;
-	char *whoname;
-	char *(*norm)(const char *);
-
-	if (gc) {
-		if (gc->prpl->normalize)
-			norm = gc->prpl->normalize;
-		else
-			norm = normalize;
-		whoname = g_strdup((*norm)(who));
-		grp = gc->groups;
-		while (grp) {
-			g = (struct group *)grp->data;
-
-			mem = g->members;
-			while (mem) {
-				b = (struct buddy *)mem->data;
-				if (!strcmp((*norm)(b->name), whoname)) {
-					g_free(whoname);
-					return b;
-				}
-				mem = mem->next;
-			}
-			grp = g_slist_next(grp);
-		}
-		g_free(whoname);
-		return NULL;
-	} else {
-		c = connections;
-		while (c) {
-			z = (struct gaim_connection *)c->data;
-			if (z->prpl->normalize)
-				norm = z->prpl->normalize;
-			else
-				norm = normalize;
-			whoname = g_strdup((*norm)(who));
-			grp = z->groups;
-			while (grp) {
-				g = (struct group *)grp->data;
-
-				mem = g->members;
-				while (mem) {
-					b = (struct buddy *)mem->data;
-					if (!strcmp((*norm)(b->name), whoname)) {
-						g_free(whoname);
-						return b;
-					}
-					mem = mem->next;
-				}
-				grp = g_slist_next(grp);
-			}
-			c = c->next;
-			g_free(whoname);
-		}
-		return NULL;
-	}
-}
-
-
 void rem_bp(GtkWidget *w, struct buddy_pounce *b)
 {
 	buddy_pounces = g_list_remove(buddy_pounces, b);
@@ -2896,145 +2616,3 @@
 	update_button_pix();
 	gtk_widget_show(blist);
 }
-
-void parse_toc_buddy_list(struct gaim_connection *gc, char *config, int from_do_import)
-{
-	char *c;
-	char current[256];
-	char *name;
-	GList *bud;
-	int how_many = 0;
-
-	bud = NULL;
-
-	if (config != NULL) {
-
-		/* skip "CONFIG:" (if it exists) */
-		c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
-		    strtok(config, "\n") :
-		    strtok(config + 6 /* sizeof(struct sflap_hdr) */  + strlen("CONFIG:"), "\n");
-		do {
-			if (c == NULL)
-				break;
-			if (*c == 'g') {
-				strncpy(current, c + 2, sizeof(current));
-				add_group(gc, current);
-				how_many++;
-			} else if (*c == 'b' && !find_buddy(gc, c + 2)) {
-				char nm[80], sw[80], *tmp = c + 2;
-				int i = 0;
-				while (*tmp != ':' && *tmp)
-					nm[i++] = *tmp++;
-				if (*tmp == ':')
-					*tmp++ = '\0';
-				nm[i] = '\0';
-				i = 0;
-				while (*tmp)
-					sw[i++] = *tmp++;
-				sw[i] = '\0';
-				if (!find_buddy(gc, nm))
-					add_buddy(gc, current, nm, sw);
-				how_many++;
-
-				bud = g_list_append(bud, c + 2);
-			} else if (*c == 'p') {
-				GSList *d = gc->permit;
-				char *n;
-				name = g_malloc(strlen(c + 2) + 2);
-				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
-				n = g_strdup(normalize (name));
-				while (d) {
-					if (!g_strcasecmp(n, normalize (d->data)))
-						 break;
-					d = d->next;
-				}
-				g_free(n);
-				if (!d)
-					gc->permit = g_slist_append(gc->permit, name);
-				else
-					g_free(name);
-			} else if (*c == 'd') {
-				GSList *d = gc->deny;
-				char *n;
-				name = g_malloc(strlen(c + 2) + 2);
-				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
-				n = g_strdup(normalize (name));
-				while (d) {
-					if (!g_strcasecmp(n, normalize (d->data)))
-						 break;
-					d = d->next;
-				}
-				g_free(n);
-				if (!d)
-					gc->deny = g_slist_append(gc->deny, name);
-				else
-					g_free(name);
-			} else if (!strncmp("toc", c, 3)) {
-				sscanf(c + strlen(c) - 1, "%d", &gc->permdeny);
-				debug_printf("permdeny: %d\n", gc->permdeny);
-				if (gc->permdeny == 0)
-					gc->permdeny = 1;
-			} else if (*c == 'm') {
-				sscanf(c + 2, "%d", &gc->permdeny);
-				debug_printf("permdeny: %d\n", gc->permdeny);
-				if (gc->permdeny == 0)
-					gc->permdeny = 1;
-			}
-		} while ((c = strtok(NULL, "\n")));
-
-		if (bud != NULL) {
-			serv_add_buddies(gc, bud);
-			g_list_free(bud);
-		}
-		serv_set_permit_deny(gc);
-	}
-
-	/* perhaps the server dropped the buddy list, try importing from
-	   cache */
-
-	if (how_many == 0 && !from_do_import) {
-		do_import((GtkWidget *)NULL, gc);
-	} else if (gc && (bud_list_cache_exists(gc) == FALSE)) {
-		do_export(gc);
-	}
-}
-
-void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
-{
-	GSList *grp = gc->groups;
-	GSList *mem;
-	struct group *g;
-	struct buddy *b;
-	GSList *plist = gc->permit;
-	GSList *dlist = gc->deny;
-
-	int pos = 0;
-
-	if (!gc->permdeny)
-		gc->permdeny = 1;
-
-	pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny);
-	while (len > pos && grp) {
-		g = (struct group *)grp->data;
-		pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
-		mem = g->members;
-		while (len > pos && mem) {
-			b = (struct buddy *)mem->data;
-			pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
-					  (show && strcmp(b->name, b->show)) ? ":" : "",
-					  (show && strcmp(b->name, b->show)) ? b->show : "");
-			mem = mem->next;
-		}
-		grp = g_slist_next(grp);
-	}
-
-	while (len > pos && plist) {
-		pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data);
-		plist = plist->next;
-	}
-
-	while (len > pos && dlist) {
-		pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data);
-		dlist = dlist->next;
-	}
-}
--- a/src/dialogs.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/dialogs.c	Fri Sep 28 07:46:36 2001 +0000
@@ -2781,122 +2781,46 @@
 /*  The dialog for import/export                                          */
 /*------------------------------------------------------------------------*/
 
-static gchar *get_screenname_filename(const char *name)
-{
-	gchar **split;
-	gchar *good;
-	int i;
-
-	split = g_strsplit(name, G_DIR_SEPARATOR_S, -1);
-	good = g_strjoinv(NULL, split);
-	g_strfreev(split);
-
-	for (i = 0; i < strlen(good); i++)
-		good[i] = toupper(good[i]);
-
-	return good;
-}
-
-/* see if a buddy list cache file for this user exists */
-
-gboolean bud_list_cache_exists(struct gaim_connection *gc)
+static void do_import_dialog(GtkWidget *w, struct gaim_connection *gc)
 {
-	gboolean ret = FALSE;
-	char path[PATHSIZE];
-	char *file;
-	struct stat sbuf;
-	char *g_screenname;
-
-	g_screenname = get_screenname_filename(gc->username);
-
-	file = gaim_user_dir();
-	if (file != (char *)NULL) {
-		g_snprintf(path, sizeof path, "%s/%s.%d.blist", file, g_screenname,
-			   (gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
-		if (!stat(path, &sbuf)) {
-			debug_printf("%s exists.\n", path);
-			ret = TRUE;
-		} else {
-			char path2[PATHSIZE];
-			debug_printf("%s does not exist.\n", path);
-			g_snprintf(path2, sizeof path2, "%s/%s.blist", file, g_screenname);
-			if (!stat(path2, &sbuf)) {
-				debug_printf("%s exists, moving to %s\n", path2, path);
-				if (rename(path2, path))
-					debug_printf("rename didn't work!\n");
-				else
-					ret = TRUE;
-			}
-		}
-		g_free(file);
+	char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(importdialog));
+	if (file_is_dir(file, importdialog)) {
+		return;
 	}
-	g_free(g_screenname);
-	return ret;
+	/* FIXME : import buddy list file. moderately important */
+	do_import(connections->data, file);
+	destroy_dialog(NULL, importdialog);
+	importdialog = NULL;
+	do_export(connections->data);
 }
 
-/* if dummy is 0, save to ~/.gaim/screenname.blist, where screenname is each
- * signed in user. Else, let user choose */
-
-void do_export(struct gaim_connection *g)
+void show_import_dialog()
 {
-	FILE *dir;
-	FILE *f;
-	char buf[32 * 1024];
-	char *file;
-	char path[PATHSIZE];
-	char *g_screenname;
-
-	/*
-	   if ( show_dialog == 1 ) {
-	   file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(exportdialog));
-	   strncpy( path, file, PATHSIZE - 1 );
-	   if (file_is_dir(path, exportdialog)) {
-	   return;
-	   }
-	   if ((f = fopen(path,"w"))) {
-	   toc_build_config(connections->data, buf, 8192 - 1, TRUE);
-	   fprintf(f, "%s\n", buf);
-	   fclose(f);
-	   chmod(buf, S_IRUSR | S_IWUSR);
-	   } else {
-	   g_snprintf(buf, BUF_LONG / 2, _("Error writing file %s"), file);
-	   do_error_dialog(buf, _("Error"));
-	   }
-	   destroy_dialog(NULL, exportdialog);
-	   exportdialog = NULL;
-	   } else {
-	 */
-
-	file = gaim_user_dir();
-	if (!file)
-		return;
-
-	strcpy(buf, file);
-	dir = fopen(buf, "r");
-	if (!dir)
-		mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
-	else
-		fclose(dir);
-
-	g_screenname = get_screenname_filename(g->username);
-
-	sprintf(path, "%s/%s.%d.blist", file, g_screenname,
-		(g->protocol == PROTO_OSCAR) ? PROTO_TOC : g->protocol);
-	if ((f = fopen(path, "w"))) {
-		debug_printf("writing %s\n", path);
-		toc_build_config(g, buf, 8192 - 1, TRUE);
-		fprintf(f, "%s\n", buf);
-		fclose(f);
-		chmod(buf, S_IRUSR | S_IWUSR);
-	} else {
-		debug_printf("unable to write %s\n", path);
+	char *buf = g_malloc(BUF_LEN);
+	if (!importdialog) {
+		importdialog = gtk_file_selection_new(_("Gaim - Import Buddy List"));
+
+		gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(importdialog));
+
+		g_snprintf(buf, BUF_LEN - 1, "%s/", getenv("HOME"));
+
+		gtk_file_selection_set_filename(GTK_FILE_SELECTION(importdialog), buf);
+		gtk_signal_connect(GTK_OBJECT(importdialog), "destroy",
+				   GTK_SIGNAL_FUNC(destroy_dialog), importdialog);
+
+		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->ok_button),
+				   "clicked", GTK_SIGNAL_FUNC(do_import_dialog), NULL);
+		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->cancel_button),
+				   "clicked", GTK_SIGNAL_FUNC(destroy_dialog), importdialog);
+
+
 	}
 
-	g_free(g_screenname);
-	g_free(file);
+	g_free(buf);
+	gtk_widget_show(importdialog);
+	gdk_window_raise(importdialog->window);
 }
 
-
 /*
 void show_export_dialog()
 {
@@ -2928,157 +2852,6 @@
 }
 */
 
-/* if gc is non-NULL, then import from ~/.gaim/gc->username.blist, else let user
-   choose */
-
-void do_import(GtkWidget *w, struct gaim_connection *gc)
-{
-	char *buf = g_malloc(BUF_LONG * 2);
-	char *buf2;
-	char *first = g_malloc(64);
-	char *file;
-	char path[PATHSIZE];
-	char *g_screenname;
-	int len;
-	FILE *f;
-	gboolean from_dialog = FALSE;
-
-	if (!gc) {
-		debug_printf("want to import file ");
-		file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(importdialog));
-		debug_printf("%s", file);
-		if (file_is_dir(file, importdialog)) {
-			debug_printf(" but it is a directory\n");
-			g_free(buf);
-			g_free(first);
-			return;
-		}
-		strncpy(path, file, PATHSIZE - 1);
-		/* FIXME : import buddy list file. moderately important */
-		gc = connections->data;
-		from_dialog = TRUE;
-	} else {
-		g_screenname = get_screenname_filename(gc->username);
-
-		file = gaim_user_dir();
-		if (file != (char *)NULL) {
-			sprintf(path, "%s/%s.%d.blist", file, g_screenname,
-				(gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
-			g_free(file);
-			g_free(g_screenname);
-		} else {
-			g_free(g_screenname);
-			g_free(buf);
-			g_free(first);
-			return;
-		}
-	}
-
-	if (!(f = fopen(path, "r"))) {
-		if (from_dialog) {
-			debug_printf(" but it can't be opened\n");
-			g_snprintf(buf, BUF_LONG / 2, _("Error reading file %s"), path);
-			do_error_dialog(buf, _("Error"));
-			destroy_dialog(NULL, importdialog);
-			importdialog = NULL;
-		}
-		debug_printf("Unable to open %s.\n", path);
-		g_free(buf);
-		g_free(first);
-		return;
-	}
-
-	fgets(first, 64, f);
-
-	/* AIM 4 buddy list */
-	if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
-		debug_printf("aim 4\n");
-		rewind(f);
-		translate_blt(f, buf);
-		debug_printf("%s\n", buf);
-		buf2 = buf;
-		buf = g_malloc(8193);
-		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
-		g_free(buf2);
-		/* AIM 3 buddy list */
-	} else if (strstr(first, "group") != NULL) {
-		debug_printf("aim 3\n");
-		rewind(f);
-		translate_lst(f, buf);
-		debug_printf("%s\n", buf);
-		buf2 = buf;
-		buf = g_malloc(8193);
-		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
-		g_free(buf2);
-		/* GAIM buddy list - no translation */
-	} else if (first[0] == 'm') {
-		rewind(f);
-		len = fread(buf, 1, BUF_LONG * 2, f);
-		buf[len] = '\0';
-		buf2 = buf;
-		buf = g_malloc(8193);
-		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
-		g_free(buf2);
-		/* Something else */
-	} else {
-		if (from_dialog) {
-			debug_printf(" but I don't recognize the format\n");
-			destroy_dialog(NULL, importdialog);
-			importdialog = NULL;
-		}
-		g_free(buf);
-		g_free(first);
-		fclose(f);
-		return;
-	}
-
-	if (from_dialog)
-		debug_printf("\n");
-
-	parse_toc_buddy_list(gc, buf, 1);
-
-	fclose(f);
-
-	if (from_dialog) {
-		/* save what we just did to cache */
-
-		do_export(gc);
-		destroy_dialog(NULL, importdialog);
-		importdialog = NULL;
-	}
-
-	g_free(buf);
-	g_free(first);
-}
-
-void show_import_dialog()
-{
-	char *buf = g_malloc(BUF_LEN);
-	if (!importdialog) {
-		importdialog = gtk_file_selection_new(_("Gaim - Import Buddy List"));
-
-		gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(importdialog));
-
-		g_snprintf(buf, BUF_LEN - 1, "%s/", getenv("HOME"));
-
-		gtk_file_selection_set_filename(GTK_FILE_SELECTION(importdialog), buf);
-		gtk_signal_connect(GTK_OBJECT(importdialog), "destroy",
-				   GTK_SIGNAL_FUNC(destroy_dialog), importdialog);
-
-		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->ok_button),
-				   "clicked", GTK_SIGNAL_FUNC(do_import), NULL);
-		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(importdialog)->cancel_button),
-				   "clicked", GTK_SIGNAL_FUNC(destroy_dialog), importdialog);
-
-
-	}
-
-	g_free(buf);
-	gtk_widget_show(importdialog);
-	gdk_window_raise(importdialog->window);
-}
-
-
 /*------------------------------------------------------------------------*/
 /*  The dialog for new away messages                                      */
 /*------------------------------------------------------------------------*/
--- a/src/gaim.h	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/gaim.h	Fri Sep 28 07:46:36 2001 +0000
@@ -631,8 +631,6 @@
 extern char *away_subs(char *, char *);
 extern GtkWidget *picture_button(GtkWidget *, char *, char **);
 extern GtkWidget *picture_button2(GtkWidget *, char *, char **, short);
-extern void translate_lst (FILE *, char *);
-extern void translate_blt (FILE *, char *);
 extern char *stylize(gchar *, int);
 extern void show_usage (int, char *);
 extern int do_auto_login (char *);
@@ -676,7 +674,6 @@
 extern void serv_chat_leave(struct gaim_connection *, int);
 extern void serv_chat_whisper(struct gaim_connection *, int, char *, char *);
 extern int serv_chat_send(struct gaim_connection *, int, char *);
-extern void update_keepalive(struct gaim_connection *, gboolean);
 
 /* output from serv */
 extern void serv_got_update(struct gaim_connection *, char *, int, int, time_t, time_t, int, gushort);
@@ -750,7 +747,6 @@
 extern void signoff_all(gpointer, gpointer);
 extern void do_im_back();
 extern void set_buddy(struct gaim_connection *, struct buddy *);
-extern struct group *add_group(struct gaim_connection *, char *);
 extern void add_category(char *);
 extern void build_edit_tree();
 extern void remove_person(struct group *, struct buddy *);
@@ -761,8 +757,13 @@
 extern struct group *find_group(struct gaim_connection *, char *);
 extern struct group *find_group_by_buddy(struct gaim_connection *, char *);
 extern void remove_buddy(struct gaim_connection *, struct group *, struct buddy *);
+extern void ui_remove_buddy(struct gaim_connection *, struct group *, struct buddy *);
 extern struct buddy *add_buddy(struct gaim_connection *, char *, char *, char *);
+extern void ui_add_buddy(struct gaim_connection *, struct group *, struct buddy *);
 extern void remove_group(struct gaim_connection *, struct group *);
+extern void ui_remove_group(struct gaim_connection *, struct group *);
+extern struct group *add_group(struct gaim_connection *, char *);
+extern void ui_add_group(struct gaim_connection *, struct group *);
 extern void toggle_buddy_pixmaps();
 extern void gaim_separator(GtkWidget *);
 extern void redo_buddy_list(); /* you really shouldn't call this function */
@@ -867,7 +868,7 @@
 extern void show_ee_dialog(int);
 extern void show_add_link(GtkWidget *,struct conversation *);
 extern void show_change_passwd(struct gaim_connection *);
-extern void do_import(GtkWidget *, struct gaim_connection *);
+extern void do_import(struct gaim_connection *, char *);
 extern int bud_list_cache_exists(struct gaim_connection *);
 extern void show_smiley_dialog(struct conversation *, GtkWidget *);
 extern void close_smiley_dialog(GtkWidget *widget, struct conversation *c);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/list.c	Fri Sep 28 07:46:36 2001 +0000
@@ -0,0 +1,774 @@
+/*
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "gaim.h"
+#include "prpl.h"
+
+#define PATHSIZE 1024
+
+void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
+{
+	GSList *grp;
+	GSList *mem;
+
+	struct group *delg;
+	struct buddy *delb;
+
+	/* we assume that gc is not NULL and that the buddy exists somewhere within the
+	 * gc's buddy list, therefore we can safely remove it. we need to ensure this
+	 * via the UI
+	 */
+
+	grp = g_slist_find(gc->groups, rem_g);
+	delg = (struct group *)grp->data;
+	mem = delg->members;
+
+	mem = g_slist_find(mem, rem_b);
+	delb = (struct buddy *)mem->data;
+
+	delg->members = g_slist_remove(delg->members, delb);
+
+	ui_remove_buddy(gc, rem_g, rem_b);
+
+	g_free(rem_b);
+
+	/* we don't flush buddy list to cache because in the case of remove_group that would
+	 * mean writing to the buddy list file once for each buddy, plus one more time */
+}
+
+void remove_group(struct gaim_connection *gc, struct group *rem_g)
+{
+	GSList *grp;
+	GSList *mem;
+	GList *tmp = NULL;
+
+	struct group *delg;
+	struct buddy *delb;
+
+	/* we assume that the group actually does exist within the gc, and that the gc is not NULL.
+	 * the UI is responsible for this */
+
+	grp = g_slist_find(gc->groups, rem_g);
+	delg = (struct group *)grp->data;
+	mem = delg->members;
+
+	while (delg->members) {
+		delb = (struct buddy *)delg->members->data;
+		tmp = g_list_append(tmp, g_strdup(delb->name));
+		remove_buddy(gc, delg, delb);	/* this should take care of removing
+						   the group_show if necessary */
+	}
+
+	gc->groups = g_slist_remove(gc->groups, delg);
+
+	serv_remove_buddies(gc, tmp);
+	while (tmp) {
+		g_free(tmp->data);
+		tmp = g_list_remove(tmp, tmp->data);
+	}
+
+	ui_remove_group(gc, rem_g);
+
+	g_free(rem_g);
+
+	/* don't flush buddy list to cache in order to be consistent with remove_buddy,
+	 * mostly. remove_group is only called from one place, so we'll let it handle it. */
+}
+
+struct buddy *add_buddy(struct gaim_connection *gc, char *group, char *buddy, char *show)
+{
+	struct buddy *b;
+	struct group *g;
+	char *good;
+
+	if ((b = find_buddy(gc, buddy)) != NULL)
+		return b;
+
+	g = find_group(gc, group);
+
+	if (g == NULL)
+		g = add_group(gc, group);
+
+	b = (struct buddy *)g_new0(struct buddy, 1);
+
+	if (!b)
+		return NULL;
+
+	b->gc = gc;
+	b->present = 0;
+
+	if (gc->prpl->normalize)
+		good = (*gc->prpl->normalize)(buddy);
+	else
+		good = buddy;
+
+	g_snprintf(b->name, sizeof(b->name), "%s", good);
+	g_snprintf(b->show, sizeof(b->show), "%s", show ? (show[0] ? show : good) : good);
+
+	g->members = g_slist_append(g->members, b);
+
+	b->idle = 0;
+	b->caps = 0;
+
+	ui_add_buddy(gc, g, b);
+
+	return b;
+}
+
+struct group *add_group(struct gaim_connection *gc, char *group)
+{
+	struct group *g = find_group(gc, group);
+	if (g)
+		return g;
+	g = (struct group *)g_new0(struct group, 1);
+	if (!g)
+		return NULL;
+
+	g->gc = gc;
+	strncpy(g->name, group, sizeof(g->name));
+	gc->groups = g_slist_append(gc->groups, g);
+
+	g->members = NULL;
+
+	ui_add_group(gc, g);
+
+	return g;
+}
+
+struct group *find_group(struct gaim_connection *gc, char *group)
+{
+	struct group *g;
+	GSList *grp;
+	GSList *c = connections;
+	struct gaim_connection *z;
+	char *grpname = g_malloc(strlen(group) + 1);
+
+	strcpy(grpname, normalize (group));
+	if (gc) {
+		grp = gc->groups;
+		while (grp) {
+			g = (struct group *)grp->data;
+			if (!g_strcasecmp(normalize (g->name), grpname)) {
+				g_free(grpname);
+				return g;
+			}
+			grp = g_slist_next(grp);
+		}
+
+		g_free(grpname);
+		return NULL;
+	} else {
+		while (c) {
+			z = (struct gaim_connection *)c->data;
+			grp = z->groups;
+			while (grp) {
+				g = (struct group *)grp->data;
+				if (!g_strcasecmp(normalize (g->name), grpname)) {
+					g_free(grpname);
+					return g;
+				}
+				grp = g_slist_next(grp);
+			}
+
+			c = c->next;
+		}
+		g_free(grpname);
+		return NULL;
+	}
+}
+
+struct group *find_group_by_buddy(struct gaim_connection *gc, char *who)
+{
+	struct group *g;
+	struct buddy *b;
+	GSList *grp;
+	GSList *mem;
+	char *whoname;
+	char *(*norm)(const char *);
+
+	if (gc) {
+		if (gc->prpl->normalize)
+			norm = gc->prpl->normalize;
+		else
+			norm = normalize;
+		whoname = g_strdup((*norm)(who));
+		grp = gc->groups;
+		while (grp) {
+			g = (struct group *)grp->data;
+
+			mem = g->members;
+			while (mem) {
+				b = (struct buddy *)mem->data;
+				if (!strcmp((*norm)(b->name), whoname)) {
+					g_free(whoname);
+					return g;
+				}
+				mem = mem->next;
+			}
+			grp = g_slist_next(grp);
+		}
+		g_free(whoname);
+		return NULL;
+	} else {
+		GSList *c = connections;
+		struct gaim_connection *z;
+		while (c) {
+			z = (struct gaim_connection *)c->data;
+			if (z->prpl->normalize)
+				norm = z->prpl->normalize;
+			else
+				norm = normalize;
+			whoname = g_strdup((*norm)(who));
+			grp = z->groups;
+			while (grp) {
+				g = (struct group *)grp->data;
+
+				mem = g->members;
+				while (mem) {
+					b = (struct buddy *)mem->data;
+					if (!strcmp((*norm)(b->name), whoname)) {
+						g_free(whoname);
+						return g;
+					}
+					mem = mem->next;
+				}
+				grp = g_slist_next(grp);
+			}
+			c = c->next;
+			g_free(whoname);
+		}
+		return NULL;
+	}
+}
+
+struct buddy *find_buddy(struct gaim_connection *gc, char *who)
+{
+	struct group *g;
+	struct buddy *b;
+	GSList *grp;
+	GSList *c;
+	struct gaim_connection *z;
+	GSList *mem;
+	char *whoname;
+	char *(*norm)(const char *);
+
+	if (gc) {
+		if (gc->prpl->normalize)
+			norm = gc->prpl->normalize;
+		else
+			norm = normalize;
+		whoname = g_strdup((*norm)(who));
+		grp = gc->groups;
+		while (grp) {
+			g = (struct group *)grp->data;
+
+			mem = g->members;
+			while (mem) {
+				b = (struct buddy *)mem->data;
+				if (!strcmp((*norm)(b->name), whoname)) {
+					g_free(whoname);
+					return b;
+				}
+				mem = mem->next;
+			}
+			grp = g_slist_next(grp);
+		}
+		g_free(whoname);
+		return NULL;
+	} else {
+		c = connections;
+		while (c) {
+			z = (struct gaim_connection *)c->data;
+			if (z->prpl->normalize)
+				norm = z->prpl->normalize;
+			else
+				norm = normalize;
+			whoname = g_strdup((*norm)(who));
+			grp = z->groups;
+			while (grp) {
+				g = (struct group *)grp->data;
+
+				mem = g->members;
+				while (mem) {
+					b = (struct buddy *)mem->data;
+					if (!strcmp((*norm)(b->name), whoname)) {
+						g_free(whoname);
+						return b;
+					}
+					mem = mem->next;
+				}
+				grp = g_slist_next(grp);
+			}
+			c = c->next;
+			g_free(whoname);
+		}
+		return NULL;
+	}
+}
+
+void parse_toc_buddy_list(struct gaim_connection *gc, char *config, int from_do_import)
+{
+	char *c;
+	char current[256];
+	char *name;
+	GList *bud;
+	int how_many = 0;
+
+	bud = NULL;
+
+	if (config != NULL) {
+
+		/* skip "CONFIG:" (if it exists) */
+		c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
+		    strtok(config, "\n") :
+		    strtok(config + 6 /* sizeof(struct sflap_hdr) */  + strlen("CONFIG:"), "\n");
+		do {
+			if (c == NULL)
+				break;
+			if (*c == 'g') {
+				strncpy(current, c + 2, sizeof(current));
+				add_group(gc, current);
+				how_many++;
+			} else if (*c == 'b' && !find_buddy(gc, c + 2)) {
+				char nm[80], sw[80], *tmp = c + 2;
+				int i = 0;
+				while (*tmp != ':' && *tmp)
+					nm[i++] = *tmp++;
+				if (*tmp == ':')
+					*tmp++ = '\0';
+				nm[i] = '\0';
+				i = 0;
+				while (*tmp)
+					sw[i++] = *tmp++;
+				sw[i] = '\0';
+				if (!find_buddy(gc, nm))
+					add_buddy(gc, current, nm, sw);
+				how_many++;
+
+				bud = g_list_append(bud, c + 2);
+			} else if (*c == 'p') {
+				GSList *d = gc->permit;
+				char *n;
+				name = g_malloc(strlen(c + 2) + 2);
+				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
+				n = g_strdup(normalize (name));
+				while (d) {
+					if (!g_strcasecmp(n, normalize (d->data)))
+						 break;
+					d = d->next;
+				}
+				g_free(n);
+				if (!d)
+					gc->permit = g_slist_append(gc->permit, name);
+				else
+					g_free(name);
+			} else if (*c == 'd') {
+				GSList *d = gc->deny;
+				char *n;
+				name = g_malloc(strlen(c + 2) + 2);
+				g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
+				n = g_strdup(normalize (name));
+				while (d) {
+					if (!g_strcasecmp(n, normalize (d->data)))
+						 break;
+					d = d->next;
+				}
+				g_free(n);
+				if (!d)
+					gc->deny = g_slist_append(gc->deny, name);
+				else
+					g_free(name);
+			} else if (!strncmp("toc", c, 3)) {
+				sscanf(c + strlen(c) - 1, "%d", &gc->permdeny);
+				debug_printf("permdeny: %d\n", gc->permdeny);
+				if (gc->permdeny == 0)
+					gc->permdeny = 1;
+			} else if (*c == 'm') {
+				sscanf(c + 2, "%d", &gc->permdeny);
+				debug_printf("permdeny: %d\n", gc->permdeny);
+				if (gc->permdeny == 0)
+					gc->permdeny = 1;
+			}
+		} while ((c = strtok(NULL, "\n")));
+
+		if (bud != NULL) {
+			serv_add_buddies(gc, bud);
+			g_list_free(bud);
+		}
+		serv_set_permit_deny(gc);
+	}
+
+	/* perhaps the server dropped the buddy list, try importing from
+	   cache */
+
+	if (how_many == 0 && !from_do_import) {
+		do_import(gc, NULL);
+	} else if (gc && (bud_list_cache_exists(gc) == FALSE)) {
+		do_export(gc);
+	}
+}
+
+void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
+{
+	GSList *grp = gc->groups;
+	GSList *mem;
+	struct group *g;
+	struct buddy *b;
+	GSList *plist = gc->permit;
+	GSList *dlist = gc->deny;
+
+	int pos = 0;
+
+	if (!gc->permdeny)
+		gc->permdeny = 1;
+
+	pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny);
+	while (len > pos && grp) {
+		g = (struct group *)grp->data;
+		pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
+		mem = g->members;
+		while (len > pos && mem) {
+			b = (struct buddy *)mem->data;
+			pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
+					  (show && strcmp(b->name, b->show)) ? ":" : "",
+					  (show && strcmp(b->name, b->show)) ? b->show : "");
+			mem = mem->next;
+		}
+		grp = g_slist_next(grp);
+	}
+
+	while (len > pos && plist) {
+		pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data);
+		plist = plist->next;
+	}
+
+	while (len > pos && dlist) {
+		pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data);
+		dlist = dlist->next;
+	}
+}
+
+/* remove leading whitespace from a string */
+static char *remove_spaces(char *str)
+{
+	int i;
+	char *new;
+
+	if (str == NULL)
+		return NULL;
+
+	i = strspn(str, " \t\n\r\f");
+	new = &str[i];
+
+	return new;
+}
+
+
+/* translate an AIM 3 buddylist (*.lst) to a GAIM buddylist */
+static void translate_lst(FILE *src_fp, char *dest)
+{
+	char line[BUF_LEN], *line2;
+	char *name;
+	int i;
+
+	sprintf(dest, "m 1\n");
+
+	while (fgets(line, BUF_LEN, src_fp)) {
+		line2 = remove_spaces(line);
+		if (strstr(line2, "group") == line2) {
+			name = strpbrk(line2, " \t\n\r\f") + 1;
+			strcat(dest, "g ");
+			for (i = 0; i < strcspn(name, "\n\r"); i++)
+				if (name[i] != '\"')
+					strncat(dest, &name[i], 1);
+			strcat(dest, "\n");
+		}
+		if (strstr(line2, "buddy") == line2) {
+			name = strpbrk(line2, " \t\n\r\f") + 1;
+			strcat(dest, "b ");
+			for (i = 0; i < strcspn(name, "\n\r"); i++)
+				if (name[i] != '\"')
+					strncat(dest, &name[i], 1);
+			strcat(dest, "\n");
+		}
+	}
+
+	return;
+}
+
+
+/* translate an AIM 4 buddylist (*.blt) to GAIM format */
+static void translate_blt(FILE *src_fp, char *dest)
+{
+	int i;
+	char line[BUF_LEN];
+	char *buddy;
+
+	sprintf(dest, "m 1\n");
+
+	while (strstr(fgets(line, BUF_LEN, src_fp), "Buddy") == NULL);
+	while (strstr(fgets(line, BUF_LEN, src_fp), "list") == NULL);
+
+	while (1) {
+		fgets(line, BUF_LEN, src_fp);
+		if (strchr(line, '}') != NULL)
+			break;
+
+		/* Syntax starting with "<group> {" */
+		if (strchr(line, '{') != NULL) {
+			strcat(dest, "g ");
+			buddy = remove_spaces(strtok(line, "{"));
+			for (i = 0; i < strlen(buddy); i++) {
+				if (buddy[i] != '\"')
+					strncat(dest, &buddy[i], 1);
+			}
+			strcat(dest, "\n");
+			while (strchr(fgets(line, BUF_LEN, src_fp), '}') == NULL) {
+				buddy = remove_spaces(line);
+				strcat(dest, "b ");
+				if (strchr(buddy, '\"') != NULL) {
+					buddy++;
+					strncat(dest, buddy, strchr(buddy, '\"') - buddy);
+					strcat(dest, "\n");
+				} else
+					strcat(dest, buddy);
+			}
+		}
+		/* Syntax "group buddy buddy ..." */
+		else {
+			buddy = remove_spaces(strtok(line, " \n"));
+			strcat(dest, "g ");
+			if (strchr(buddy, '\"') != NULL) {
+				strcat(dest, &buddy[1]);
+				strcat(dest, " ");
+				buddy = remove_spaces(strtok(NULL, " \n"));
+				while (strchr(buddy, '\"') == NULL) {
+					strcat(dest, buddy);
+					strcat(dest, " ");
+					buddy = remove_spaces(strtok(NULL, " \n"));
+				}
+				strncat(dest, buddy, strlen(buddy) - 1);
+			} else {
+				strcat(dest, buddy);
+			}
+			strcat(dest, "\n");
+			while ((buddy = remove_spaces(strtok(NULL, " \n"))) != NULL) {
+				strcat(dest, "b ");
+				if (strchr(buddy, '\"') != NULL) {
+					strcat(dest, &buddy[1]);
+					strcat(dest, " ");
+					buddy = remove_spaces(strtok(NULL, " \n"));
+					while (strchr(buddy, '\"') == NULL) {
+						strcat(dest, buddy);
+						strcat(dest, " ");
+						buddy = remove_spaces(strtok(NULL, " \n"));
+					}
+					strncat(dest, buddy, strlen(buddy) - 1);
+				} else {
+					strcat(dest, buddy);
+				}
+				strcat(dest, "\n");
+			}
+		}
+	}
+
+	return;
+}
+
+static gchar *get_screenname_filename(const char *name)
+{
+	gchar **split;
+	gchar *good;
+
+	split = g_strsplit(name, G_DIR_SEPARATOR_S, -1);
+	good = g_strjoinv(NULL, split);
+	g_strfreev(split);
+
+	g_strup(good);
+
+	return good;
+}
+
+/* see if a buddy list cache file for this user exists */
+
+gboolean bud_list_cache_exists(struct gaim_connection *gc)
+{
+	gboolean ret = FALSE;
+	char path[PATHSIZE];
+	char *file;
+	struct stat sbuf;
+	char *g_screenname;
+
+	g_screenname = get_screenname_filename(gc->username);
+
+	file = gaim_user_dir();
+	if (file != (char *)NULL) {
+		g_snprintf(path, sizeof path, "%s/%s.%d.blist", file, g_screenname,
+			   (gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
+		if (!stat(path, &sbuf)) {
+			debug_printf("%s exists.\n", path);
+			ret = TRUE;
+		} else {
+			char path2[PATHSIZE];
+			debug_printf("%s does not exist.\n", path);
+			g_snprintf(path2, sizeof path2, "%s/%s.blist", file, g_screenname);
+			if (!stat(path2, &sbuf)) {
+				debug_printf("%s exists, moving to %s\n", path2, path);
+				if (rename(path2, path))
+					debug_printf("rename didn't work!\n");
+				else
+					ret = TRUE;
+			}
+		}
+		g_free(file);
+	}
+	g_free(g_screenname);
+	return ret;
+}
+
+void do_import(struct gaim_connection *gc, char *filename)
+{
+	char *buf = g_malloc(BUF_LONG * 2);
+	char *buf2;
+	char *first = g_malloc(64);
+	char *file;
+	char path[PATHSIZE];
+	char *g_screenname;
+	int len;
+	FILE *f;
+
+	if (filename) {
+		g_snprintf(path, sizeof(path), "%s", filename);
+	} else {
+		g_screenname = get_screenname_filename(gc->username);
+
+		file = gaim_user_dir();
+		if (file != (char *)NULL) {
+			sprintf(path, "%s/%s.%d.blist", file, g_screenname,
+				(gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
+			g_free(file);
+			g_free(g_screenname);
+		} else {
+			g_free(g_screenname);
+			g_free(buf);
+			g_free(first);
+			return;
+		}
+	}
+
+	if (!(f = fopen(path, "r"))) {
+		debug_printf("Unable to open %s.\n", path);
+		g_free(buf);
+		g_free(first);
+		return;
+	}
+
+	fgets(first, 64, f);
+
+	/* AIM 4 buddy list */
+	if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
+		debug_printf("aim 4\n");
+		rewind(f);
+		translate_blt(f, buf);
+		debug_printf("%s\n", buf);
+		buf2 = buf;
+		buf = g_malloc(8193);
+		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
+		g_free(buf2);
+		/* AIM 3 buddy list */
+	} else if (strstr(first, "group") != NULL) {
+		debug_printf("aim 3\n");
+		rewind(f);
+		translate_lst(f, buf);
+		debug_printf("%s\n", buf);
+		buf2 = buf;
+		buf = g_malloc(8193);
+		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
+		g_free(buf2);
+		/* GAIM buddy list - no translation */
+	} else if (first[0] == 'm') {
+		rewind(f);
+		len = fread(buf, 1, BUF_LONG * 2, f);
+		buf[len] = '\0';
+		buf2 = buf;
+		buf = g_malloc(8193);
+		g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
+		g_free(buf2);
+		/* Something else */
+	} else {
+		g_free(buf);
+		g_free(first);
+		fclose(f);
+		return;
+	}
+
+	parse_toc_buddy_list(gc, buf, 1);
+
+	fclose(f);
+
+	g_free(buf);
+	g_free(first);
+}
+
+void do_export(struct gaim_connection *g)
+{
+	FILE *dir;
+	FILE *f;
+	char buf[32 * 1024];
+	char *file;
+	char path[PATHSIZE];
+	char *g_screenname;
+
+	file = gaim_user_dir();
+	if (!file)
+		return;
+
+	strcpy(buf, file);
+	dir = fopen(buf, "r");
+	if (!dir)
+		mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
+	else
+		fclose(dir);
+
+	g_screenname = get_screenname_filename(g->username);
+
+	sprintf(path, "%s/%s.%d.blist", file, g_screenname,
+		(g->protocol == PROTO_OSCAR) ? PROTO_TOC : g->protocol);
+	if ((f = fopen(path, "w"))) {
+		debug_printf("writing %s\n", path);
+		toc_build_config(g, buf, 8192 - 1, TRUE);
+		fprintf(f, "%s\n", buf);
+		fclose(f);
+		chmod(buf, S_IRUSR | S_IWUSR);
+	} else {
+		debug_printf("unable to write %s\n", path);
+	}
+
+	g_free(g_screenname);
+	g_free(file);
+}
--- a/src/multi.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/multi.c	Fri Sep 28 07:46:36 2001 +0000
@@ -68,7 +68,7 @@
 	g_snprintf(gc->password, sizeof(gc->password), "%s", user->password);
 	gc->options = user->options;
 	gc->keepalive = 0;
-	gc->inpa = -1;
+	gc->inpa = 0;
 	gc->buddy_chats = NULL;
 	gc->groups = NULL;
 	gc->permit = NULL;
@@ -1099,7 +1099,6 @@
 	debug_printf("date: %s\n", full_date());
 	plugin_event(event_signoff, gc, 0, 0, 0);
 	system_log(log_signoff, gc, NULL, OPT_LOG_BUDDY_SIGNON | OPT_LOG_MY_SIGNON);
-	update_keepalive(gc, FALSE);
 
 	/* UI stuff */
 	convo_menu_remove(gc);
--- a/src/protocols/icq/gaim_icq.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/icq/gaim_icq.c	Fri Sep 28 07:46:36 2001 +0000
@@ -304,7 +304,7 @@
 
 	icq_ContactClear(id->link);
 	if (bud_list_cache_exists(gc))
-		do_import(NULL, gc);
+		do_import(gc, NULL);
 
 	if (icq_Connect(link, "icq.mirabilis.com", 4000) < 1) {
 		hide_login_progress(gc, "Unable to connect");
--- a/src/protocols/irc/irc.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/irc/irc.c	Fri Sep 28 07:46:36 2001 +0000
@@ -710,7 +710,7 @@
 		serv_finish_login(gc);
 
 		if (bud_list_cache_exists(gc))
-			do_import(NULL, gc);
+			do_import(gc, NULL);
 
 		/* we don't call this now because otherwise some IRC servers might not like us */
 		idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc);
--- a/src/protocols/jabber/jabber.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/jabber/jabber.c	Fri Sep 28 07:46:36 2001 +0000
@@ -968,7 +968,7 @@
 		serv_finish_login(GJ_GC(j));
 
 		if (bud_list_cache_exists(GJ_GC(j)))
-			do_import(NULL, GJ_GC(j));
+			do_import(GJ_GC(j), NULL);
 
 		((struct jabber_data *)GJ_GC(j)->proto_data)->did_import = TRUE;
 
--- a/src/protocols/msn/msn.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/msn/msn.c	Fri Sep 28 07:46:36 2001 +0000
@@ -738,7 +738,7 @@
 			md->fl = g_slist_append(md->fl, b);
 		} else if (!md->imported) {
 			if (bud_list_cache_exists(gc))
-				do_import(NULL, gc);
+				do_import(gc, NULL);
 			md->imported = TRUE;
 			while (md->fl) {
 				struct msn_buddy *mb = md->fl->data;
--- a/src/protocols/napster/napster.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/napster/napster.c	Fri Sep 28 07:46:36 2001 +0000
@@ -392,7 +392,7 @@
 		serv_finish_login(gc);
 
 		if (bud_list_cache_exists(gc))
-			do_import(NULL, gc);
+			do_import(gc, NULL);
 
 		return;
 	}
--- a/src/protocols/oscar/oscar.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/oscar/oscar.c	Fri Sep 28 07:46:36 2001 +0000
@@ -1905,7 +1905,7 @@
 	serv_finish_login(gc);
 
 	if (bud_list_cache_exists(gc))
-		do_import(NULL, gc);
+		do_import(gc, NULL);
 
 	debug_printf("buddy list loaded\n");
 
--- a/src/protocols/toc/toc.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/toc/toc.c	Fri Sep 28 07:46:36 2001 +0000
@@ -547,7 +547,7 @@
 		account_online(gc);
 		serv_finish_login(gc);
 
-		do_import(0, gc);
+		do_import(gc, NULL);
 
 		/* Client sends TOC toc_init_done message */
 		debug_printf("* Client sends TOC toc_init_done message\n");
@@ -582,7 +582,7 @@
 				signoff(gc);
 				return;
 			}
-			do_import(0, gc);
+			do_import(gc, NULL);
 			g_snprintf(snd, sizeof snd, "toc_init_done");
 			sflap_send(gc, snd, -1, TYPE_DATA);
 			do_error_dialog(_("TOC has come back from its pause. You may now send"
--- a/src/protocols/yahoo/yay.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/yahoo/yay.c	Fri Sep 28 07:46:36 2001 +0000
@@ -259,7 +259,7 @@
 	}
 
 	if (bud_list_cache_exists(gc))
-		do_import(NULL, gc);
+		do_import(gc, NULL);
 
 	grps = yd->sess->groups;
 	while (grps) {
--- a/src/protocols/zephyr/zephyr.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/protocols/zephyr/zephyr.c	Fri Sep 28 07:46:36 2001 +0000
@@ -577,7 +577,7 @@
 	serv_finish_login(zgc);
 
 	if (bud_list_cache_exists(zgc))
-		do_import(NULL, zgc);
+		do_import(zgc, NULL);
 	process_anyone();
 	process_zsubs();
 
--- a/src/server.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/server.c	Fri Sep 28 07:46:36 2001 +0000
@@ -53,6 +53,26 @@
 	}
 }
 
+static gboolean send_keepalive(gpointer d)
+{
+	struct gaim_connection *gc = d;
+	if (gc->prpl && gc->prpl->keepalive)
+		(*gc->prpl->keepalive)(gc);
+	return TRUE;
+}
+
+static void update_keepalive(struct gaim_connection *gc, gboolean on)
+{
+	if (on && !gc->keepalive) {
+		debug_printf("allowing NOP\n");
+		gc->keepalive = g_timeout_add(60000, send_keepalive, gc);
+	} else if (!on && gc->keepalive > 0) {
+		debug_printf("removing NOP\n");
+		g_source_remove(gc->keepalive);
+		gc->keepalive = 0;
+	}
+}
+
 void serv_close(struct gaim_connection *gc)
 {
 	while (gc->buddy_chats) {
@@ -65,9 +85,7 @@
 		g_source_remove(gc->idle_timer);
 	gc->idle_timer = 0;
 
-	if (gc->keepalive > 0)
-		g_source_remove(gc->keepalive);
-	gc->keepalive = 0;
+	update_keepalive(gc, FALSE);
 
 	if (gc->prpl && gc->prpl->close)
 		(*gc->prpl->close)(gc);
@@ -914,22 +932,3 @@
 	chat_write(b, who, w, buf, mtime);
 	g_free(buf);
 }
-
-void send_keepalive(gpointer d)
-{
-	struct gaim_connection *gc = (struct gaim_connection *)d;
-	if (gc->prpl && gc->prpl->keepalive)
-		(*gc->prpl->keepalive)(gc);
-}
-
-void update_keepalive(struct gaim_connection *gc, gboolean on)
-{
-	if (on && !gc->keepalive && blist) {
-		debug_printf("allowing NOP\n");
-		gc->keepalive = g_timeout_add(60000, send_keepalive, gc);
-	} else if (!on && gc->keepalive > 0) {
-		debug_printf("removing NOP\n");
-		g_source_remove(gc->keepalive);
-		gc->keepalive = 0;
-	}
-}
--- a/src/util.c	Fri Sep 28 05:17:16 2001 +0000
+++ b/src/util.c	Fri Sep 28 07:46:36 2001 +0000
@@ -716,135 +716,6 @@
 	return (cpy);
 }
 
-
-
-/* remove leading whitespace from a string */
-char *remove_spaces(char *str)
-{
-	int i;
-	char *new;
-
-	if (str == NULL)
-		return NULL;
-
-	i = strspn(str, " \t\n\r\f");
-	new = &str[i];
-
-	return new;
-}
-
-
-/* translate an AIM 3 buddylist (*.lst) to a GAIM buddylist */
-void translate_lst(FILE *src_fp, char *dest)
-{
-	char line[BUF_LEN], *line2;
-	char *name;
-	int i;
-
-	sprintf(dest, "m 1\n");
-
-	while (fgets(line, BUF_LEN, src_fp)) {
-		line2 = remove_spaces(line);
-		if (strstr(line2, "group") == line2) {
-			name = strpbrk(line2, " \t\n\r\f") + 1;
-			strcat(dest, "g ");
-			for (i = 0; i < strcspn(name, "\n\r"); i++)
-				if (name[i] != '\"')
-					strncat(dest, &name[i], 1);
-			strcat(dest, "\n");
-		}
-		if (strstr(line2, "buddy") == line2) {
-			name = strpbrk(line2, " \t\n\r\f") + 1;
-			strcat(dest, "b ");
-			for (i = 0; i < strcspn(name, "\n\r"); i++)
-				if (name[i] != '\"')
-					strncat(dest, &name[i], 1);
-			strcat(dest, "\n");
-		}
-	}
-
-	return;
-}
-
-
-/* translate an AIM 4 buddylist (*.blt) to GAIM format */
-void translate_blt(FILE *src_fp, char *dest)
-{
-	int i;
-	char line[BUF_LEN];
-	char *buddy;
-
-	sprintf(dest, "m 1\n");
-
-	while (strstr(fgets(line, BUF_LEN, src_fp), "Buddy") == NULL);
-	while (strstr(fgets(line, BUF_LEN, src_fp), "list") == NULL);
-
-	while (1) {
-		fgets(line, BUF_LEN, src_fp);
-		if (strchr(line, '}') != NULL)
-			break;
-
-		/* Syntax starting with "<group> {" */
-		if (strchr(line, '{') != NULL) {
-			strcat(dest, "g ");
-			buddy = remove_spaces(strtok(line, "{"));
-			for (i = 0; i < strlen(buddy); i++) {
-				if (buddy[i] != '\"')
-					strncat(dest, &buddy[i], 1);
-			}
-			strcat(dest, "\n");
-			while (strchr(fgets(line, BUF_LEN, src_fp), '}') == NULL) {
-				buddy = remove_spaces(line);
-				strcat(dest, "b ");
-				if (strchr(buddy, '\"') != NULL) {
-					buddy++;
-					strncat(dest, buddy, strchr(buddy, '\"') - buddy);
-					strcat(dest, "\n");
-				} else
-					strcat(dest, buddy);
-			}
-		}
-		/* Syntax "group buddy buddy ..." */
-		else {
-			buddy = remove_spaces(strtok(line, " \n"));
-			strcat(dest, "g ");
-			if (strchr(buddy, '\"') != NULL) {
-				strcat(dest, &buddy[1]);
-				strcat(dest, " ");
-				buddy = remove_spaces(strtok(NULL, " \n"));
-				while (strchr(buddy, '\"') == NULL) {
-					strcat(dest, buddy);
-					strcat(dest, " ");
-					buddy = remove_spaces(strtok(NULL, " \n"));
-				}
-				strncat(dest, buddy, strlen(buddy) - 1);
-			} else {
-				strcat(dest, buddy);
-			}
-			strcat(dest, "\n");
-			while ((buddy = remove_spaces(strtok(NULL, " \n"))) != NULL) {
-				strcat(dest, "b ");
-				if (strchr(buddy, '\"') != NULL) {
-					strcat(dest, &buddy[1]);
-					strcat(dest, " ");
-					buddy = remove_spaces(strtok(NULL, " \n"));
-					while (strchr(buddy, '\"') == NULL) {
-						strcat(dest, buddy);
-						strcat(dest, " ");
-						buddy = remove_spaces(strtok(NULL, " \n"));
-					}
-					strncat(dest, buddy, strlen(buddy) - 1);
-				} else {
-					strcat(dest, buddy);
-				}
-				strcat(dest, "\n");
-			}
-		}
-	}
-
-	return;
-}
-
 char *stylize(gchar *text, int length)
 {
 	gchar *buf;