diff -u -r links-0.96-orig/default.c links-0.96/default.c
--- links-0.96-orig/default.c	Sun Apr  8 22:46:18 2001
+++ links-0.96/default.c	Wed Aug 29 09:48:33 2001
@@ -854,6 +854,9 @@
 unsigned char http_proxy[MAX_STR_LEN] = "";
 unsigned char ftp_proxy[MAX_STR_LEN] = "";
 
+unsigned char fake_referer[MAX_STR_LEN] = "";
+int referer;   /* values: REFERER_NONE (default), REFERER_SAME_URL, REFERER_FAKE */
+
 unsigned char download_dir[MAX_STR_LEN] = "";
 
 unsigned char default_anon_pass[MAX_STR_LEN] = "somebody@host.domain";
@@ -896,6 +899,8 @@
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.allow_blacklist, "http_bugs.allow_blacklist", "http-bugs.allow-blacklist",
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_302_redirect, "http_bugs.bug_302_redirect", "http-bugs.bug-302-redirect",
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_post_no_keepalive, "http_bugs.bug_post_no_keepalive", "http-bugs.bug_post-no-keepalive",
+	1, gen_cmd, num_rd, num_wr, 0, 2, &referer, "http_referer", "http-referer",
+	1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, fake_referer, "fake_referer", "fake-referer",
 	1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, default_anon_pass, "ftp.anonymous_password", "ftp.anonymous-password",
 	1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", "assume-codepage",
 	1, NULL, term_rd, term_wr, 0, 0, NULL, "terminal", NULL,
diff -u -r links-0.96-orig/http.c links-0.96/http.c
--- links-0.96-orig/http.c	Mon Jun 18 21:59:55 2001
+++ links-0.96/http.c	Wed Aug 29 09:48:33 2001
@@ -241,6 +241,23 @@
 	add_to_str(&hdr, &l, "User-Agent: Links (" VERSION_STRING "; ");
 	add_to_str(&hdr, &l, system_name);
 	add_to_str(&hdr, &l, ")\r\n");
+
+	switch (referer)
+	{
+		case REFERER_FAKE:
+		add_to_str(&hdr, &l, "Referer: ");
+		add_to_str(&hdr, &l, fake_referer);
+		add_to_str(&hdr, &l, "\r\n");
+		break;
+		
+		case REFERER_SAME_URL:
+		add_to_str(&hdr, &l, "Referer: ");
+		if (!post) add_to_str(&hdr, &l, u);
+		else add_bytes_to_str(&hdr, &l, u, post - u - 1);
+		add_to_str(&hdr, &l, "\r\n");
+		break;
+	}
+
 	add_to_str(&hdr, &l, "Accept: */*\r\n");
 	if (!(accept_charset)) {
 		int i;
diff -u -r links-0.96-orig/intl/english.lng links-0.96/intl/english.lng
--- links-0.96-orig/intl/english.lng	Mon Jun 11 12:00:52 2001
+++ links-0.96/intl/english.lng	Wed Aug 29 09:48:33 2001
@@ -138,6 +138,10 @@
 T_CANT_GET_SOCKET_STATE, "Can't get socket state",
 T_BAD_HTTP_RESPONSE, "Bad HTTP response",
 T_HTTP_100, "HTTP 100 (???)",
+T_FAKE_REFERER, "Fixed HTTP Referer",
+T_REFERER_NONE, "No referer",
+T_REFERER_SAME_URL, "Send requested URL as referer",
+T_REFERER_FAKE, "Fixed referer",
 T_NO_CONTENT, "No content",
 T_UNKNOWN_FILE_TYPE, "Unknown file type",
 T_ERROR_OPENING_FILE, "Error opening file",
diff -u -r links-0.96-orig/links.h links-0.96/links.h
--- links-0.96-orig/links.h	Mon Jun 11 12:14:25 2001
+++ links-0.96/links.h	Wed Aug 29 09:48:34 2001
@@ -1988,8 +1988,14 @@
 extern struct rgb default_link;
 extern struct rgb default_vlink;
 
+#define REFERER_NONE 0
+#define REFERER_SAME_URL 1
+#define REFERER_FAKE 2
+
 extern unsigned char http_proxy[];
 extern unsigned char ftp_proxy[];
+extern unsigned char fake_referer[];
+extern int referer;
 extern unsigned char no_proxy_for[];
 extern unsigned char download_dir[];
 
diff -u -r links-0.96-orig/menu.c links-0.96/menu.c
--- links-0.96-orig/menu.c	Wed Apr 25 23:08:28 2001
+++ links-0.96/menu.c	Wed Aug 29 09:44:57 2001
@@ -438,16 +438,54 @@
  	do_dialog(term, d, getml(d, NULL));
 }
 
-unsigned char *http_labels[] = { TEXT(T_USE_HTTP_10), TEXT(T_ALLOW_SERVER_BLACKLIST), TEXT(T_BROKEN_302_REDIRECT), TEXT(T_NO_KEEPALIVE_AFTER_POST_REQUEST) };
+unsigned char *http_labels[] = { TEXT(T_USE_HTTP_10), TEXT(T_ALLOW_SERVER_BLACKLIST), TEXT(T_BROKEN_302_REDIRECT), TEXT(T_NO_KEEPALIVE_AFTER_POST_REQUEST), TEXT(T_REFERER_NONE), TEXT(T_REFERER_SAME_URL), TEXT(T_REFERER_FAKE), TEXT(T_FAKE_REFERER) };
+
+void httpopt_fn(struct dialog_data *dlg)
+{
+	struct terminal *term = dlg->win->term;
+	int max = 0, min = 0;
+	int w, rw;
+	int y = 0;
+	checkboxes_width(term, dlg->dlg->udata, &max, max_text_width);
+	checkboxes_width(term, dlg->dlg->udata, &min, min_text_width);
+	max_text_width(term, http_labels[7], &max);
+	min_text_width(term, http_labels[7], &min);
+	max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
+	min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
+	w = term->x * 9 / 10 - 2 * DIALOG_LB;
+	if (w > max) w = max;
+	if (w < min) w = min;
+	if (w > term->x - 2 * DIALOG_LB) w = term->x - 2 * DIALOG_LB;
+	if (w < 5) w = 5;
+	rw = 0;
+	dlg_format_checkboxes(NULL, term, dlg->items, dlg->n - 3, 0, &y, w, &rw, dlg->dlg->udata);
+	y++;
+	dlg_format_text(NULL, term, http_labels[7], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
+	y+=2;
+	dlg_format_buttons(NULL, term, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
+	w = rw;
+	dlg->xw = rw + 2 * DIALOG_LB;
+	dlg->yw = y + 2 * DIALOG_TB;
+	center_dlg(dlg);
+	draw_dlg(dlg);
+	y = dlg->y + DIALOG_TB + 1;
+	dlg_format_checkboxes(term, term, dlg->items, dlg->n - 3, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
+	y++;
+	dlg_format_text(term, term, http_labels[7], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
+	dlg_format_field(term, term, dlg->items + 7, dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
+	y++;
+	dlg_format_buttons(term, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
+}
+
 
 int dlg_http_options(struct dialog_data *dlg, struct dialog_item_data *di)
 {
 	struct http_bugs *bugs = (struct http_bugs *)di->cdata;
 	struct dialog *d;
-	if (!(d = mem_alloc(sizeof(struct dialog) + 7 * sizeof(struct dialog_item)))) return 0;
-	memset(d, 0, sizeof(struct dialog) + 7 * sizeof(struct dialog_item));
+	if (!(d = mem_alloc(sizeof(struct dialog) + 11 * sizeof(struct dialog_item)))) return 0;
+	memset(d, 0, sizeof(struct dialog) + 11 * sizeof(struct dialog_item));
 	d->title = TEXT(T_HTTP_BUG_WORKAROUNDS);
-	d->fn = checkbox_list_fn;
+	d->fn = httpopt_fn;
 	d->udata = http_labels;
 	d->items[0].type = D_CHECKBOX;
 	d->items[0].gid = 0;
@@ -465,15 +503,33 @@
 	d->items[3].gid = 0;
 	d->items[3].dlen = sizeof(int);
 	d->items[3].data = (void *)&bugs->bug_post_no_keepalive;
-	d->items[4].type = D_BUTTON;
-	d->items[4].gid = B_ENTER;
-	d->items[4].fn = ok_dialog;
-	d->items[4].text = TEXT(T_OK);
-	d->items[5].type = D_BUTTON;
-	d->items[5].gid = B_ESC;
-	d->items[5].fn = cancel_dialog;
-	d->items[5].text = TEXT(T_CANCEL);
-	d->items[6].type = D_END;
+	d->items[4].type = D_CHECKBOX;
+	d->items[4].gid = 1;
+	d->items[4].gnum = REFERER_NONE;
+	d->items[4].dlen = sizeof(int);
+	d->items[4].data = (void *)&referer;
+	d->items[5].type = D_CHECKBOX;
+	d->items[5].gid = 1;
+	d->items[5].gnum = REFERER_SAME_URL;
+	d->items[5].dlen = sizeof(int);
+	d->items[5].data = (void *)&referer;
+	d->items[6].type = D_CHECKBOX;
+	d->items[6].gid = 1;
+	d->items[6].gnum = REFERER_FAKE;
+	d->items[6].dlen = sizeof(int);
+	d->items[6].data = (void *)&referer;
+	d->items[7].type = D_FIELD;
+	d->items[7].dlen = MAX_STR_LEN;
+	d->items[7].data = fake_referer;
+	d->items[8].type = D_BUTTON;
+	d->items[8].gid = B_ENTER;
+	d->items[8].fn = ok_dialog;
+	d->items[8].text = TEXT(T_OK);
+	d->items[9].type = D_BUTTON;
+	d->items[9].gid = B_ESC;
+	d->items[9].fn = cancel_dialog;
+	d->items[9].text = TEXT(T_CANCEL);
+	d->items[10].type = D_END;
  	do_dialog(dlg->win->term, d, getml(d, NULL));
 	return 0;
 }
diff -ru links-0.96/default.c links-0.96+true-referer/default.c
--- links-0.96/default.c	Sat Sep  1 19:13:46 2001
+++ links-0.96+true-referer/default.c	Sat Sep  1 18:29:54 2001
@@ -855,7 +855,7 @@
 unsigned char ftp_proxy[MAX_STR_LEN] = "";
 
 unsigned char fake_referer[MAX_STR_LEN] = "";
-int referer;   /* values: REFERER_NONE (default), REFERER_SAME_URL, REFERER_FAKE */
+int referer;   /* values: REFERER_NONE (default), REFERER_TRUE, REFERER_SAME_URL, REFERER_FAKE */
 
 unsigned char download_dir[MAX_STR_LEN] = "";
 
@@ -899,7 +899,7 @@
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.allow_blacklist, "http_bugs.allow_blacklist", "http-bugs.allow-blacklist",
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_302_redirect, "http_bugs.bug_302_redirect", "http-bugs.bug-302-redirect",
 	1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_post_no_keepalive, "http_bugs.bug_post_no_keepalive", "http-bugs.bug_post-no-keepalive",
-	1, gen_cmd, num_rd, num_wr, 0, 2, &referer, "http_referer", "http-referer",
+	1, gen_cmd, num_rd, num_wr, 0, 3, &referer, "http_referer", "http-referer",
 	1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, fake_referer, "fake_referer", "fake-referer",
 	1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, default_anon_pass, "ftp.anonymous_password", "ftp.anonymous-password",
 	1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", "assume-codepage",
diff -ru links-0.96/http.c links-0.96+true-referer/http.c
--- links-0.96/http.c	Sat Sep  1 19:13:46 2001
+++ links-0.96+true-referer/http.c	Sat Sep  1 19:14:41 2001
@@ -249,9 +249,32 @@
 		add_to_str(&hdr, &l, fake_referer);
 		add_to_str(&hdr, &l, "\r\n");
 		break;
+
+		case REFERER_TRUE:
+		if (c->prev_url && c->prev_url[0])
+		{
+		  unsigned char *etk;
+		  add_to_str(&hdr, &l, "Referer: ");
+		  if (etk = strchr(c->prev_url, '\1')) /* braindead ;-) */
+		    add_bytes_to_str(&hdr, &l, c->prev_url, etk - c->prev_url);
+		  else
+		    add_to_str(&hdr, &l, c->prev_url);
+		  add_to_str(&hdr, &l, "\r\n");
+	        }
+		break;
 		
 		case REFERER_SAME_URL:
-		add_to_str(&hdr, &l, "Referer: ");
+		add_to_str(&hdr, &l, "Referer: http://");
+		if ((h = get_host_name(host))) {
+			add_to_str(&hdr, &l, h);
+			mem_free(h);
+			if ((h = get_port_str(host))) {
+				add_to_str(&hdr, &l, ":");
+				add_to_str(&hdr, &l, h);
+				mem_free(h);
+			}
+		}
+		if (upcase(c->url[0]) != 'P') add_to_str(&hdr, &l, "/");
 		if (!post) add_to_str(&hdr, &l, u);
 		else add_bytes_to_str(&hdr, &l, u, post - u - 1);
 		add_to_str(&hdr, &l, "\r\n");
diff -ru links-0.96/intl/czech.lng links-0.96+true-referer/intl/czech.lng
--- links-0.96/intl/czech.lng	Sat Sep  1 19:13:43 2001
+++ links-0.96+true-referer/intl/czech.lng	Sat Sep  1 12:31:53 2001
@@ -138,6 +138,11 @@
 T_CANT_GET_SOCKET_STATE, "Nemůžu zjistit stav socketu",
 T_BAD_HTTP_RESPONSE, "Špatná HTTP odpověď (asi bugovitý server)",
 T_HTTP_100, "HTTP 100 (?)",
+T_FAKE_REFERER, "Falešný HTTP referer",
+T_REFERER_NONE, "Neposílat HTTP referer",
+T_REFERER_TRUE, "Posílat předchozí URL jako referer (normalní a NEBEZPEČNÉ)",
+T_REFERER_SAME_URL, "Posílat vyžádané URL jako referer",
+T_REFERER_FAKE, "Posílat falešný HTTP referer",
 T_NO_CONTENT, "Žádnej obsah",
 T_UNKNOWN_FILE_TYPE, "Neznámej typ souboru",
 T_ERROR_OPENING_FILE, "Chybička při čtení souboru",
diff -ru links-0.96/intl/english.lng links-0.96+true-referer/intl/english.lng
--- links-0.96/intl/english.lng	Sat Sep  1 19:13:46 2001
+++ links-0.96+true-referer/intl/english.lng	Sat Sep  1 12:29:40 2001
@@ -140,6 +140,7 @@
 T_HTTP_100, "HTTP 100 (???)",
 T_FAKE_REFERER, "Fixed HTTP Referer",
 T_REFERER_NONE, "No referer",
+T_REFERER_TRUE, "Send previous URL as referer (normal operation, INSECURE)",
 T_REFERER_SAME_URL, "Send requested URL as referer",
 T_REFERER_FAKE, "Fixed referer",
 T_NO_CONTENT, "No content",
diff -ru links-0.96/links.h links-0.96+true-referer/links.h
--- links-0.96/links.h	Sat Sep  1 19:13:46 2001
+++ links-0.96+true-referer/links.h	Sat Sep  1 17:06:00 2001
@@ -637,6 +637,7 @@
 	struct connection *prev;
 	tcount count;
 	unsigned char *url;
+	unsigned char *prev_url;
 	int running;
 	int state;
 	int prev_error;
@@ -759,7 +760,7 @@
 void retry_connection(struct connection *c);
 void abort_connection(struct connection *c);
 void end_connection(struct connection *c);
-int load_url(unsigned char *, struct status *, int, int);
+int load_url(unsigned char *, unsigned char *, struct status *, int, int);
 void change_connection(struct status *, struct status *, int);
 void detach_connection(struct status *, int);
 void abort_all_connections();
@@ -1471,6 +1472,7 @@
 	unsigned char *tq_prog;
 	int tq_prog_flags;
 	unsigned char *dn_url;
+	unsigned char *ref_url;
 	unsigned char *search_word;
 	unsigned char *last_search_word;
 	int search_direction;
@@ -1998,6 +2000,7 @@
 #define REFERER_NONE 0
 #define REFERER_SAME_URL 1
 #define REFERER_FAKE 2
+#define REFERER_TRUE 3
 
 extern unsigned char http_proxy[];
 extern unsigned char ftp_proxy[];
diff -ru links-0.96/main.c links-0.96+true-referer/main.c
--- links-0.96/main.c	Sat Sep  1 19:13:43 2001
+++ links-0.96+true-referer/main.c	Sat Sep  1 12:55:46 2001
@@ -163,7 +163,7 @@
 		if (stat->state >= 0) change_connection(stat, NULL, PRI_CANCEL);
 		u = stracpy(ce->redirect);
 		if (!http_bugs.bug_302_redirect) if (!ce->redirect_get && (p = strchr(ce->url, POST_CHAR))) add_to_strn(&u, p);
-		load_url(u, stat, PRI_MAIN, 0);
+		load_url(u, ce->url, stat, PRI_MAIN, 0);
 		mem_free(u);
 		return;
 	}
@@ -283,7 +283,7 @@
 		dump_stat.end = end_dump;
 		dump_pos = 0;
 		if (!(uu = translate_url(u, wd = get_cwd()))) uu = stracpy(u);
-		if (load_url(uu, &dump_stat, PRI_MAIN, 0)) goto ttt;
+		if (load_url(uu, NULL, &dump_stat, PRI_MAIN, 0)) goto ttt;
 		mem_free(uu);
 		if (wd) mem_free(wd);
 	}
diff -ru links-0.96/menu.c links-0.96+true-referer/menu.c
--- links-0.96/menu.c	Sat Sep  1 19:13:46 2001
+++ links-0.96+true-referer/menu.c	Sat Sep  1 12:28:06 2001
@@ -454,7 +454,7 @@
  	do_dialog(term, d, getml(d, NULL));
 }
 
-unsigned char *http_labels[] = { TEXT(T_USE_HTTP_10), TEXT(T_ALLOW_SERVER_BLACKLIST), TEXT(T_BROKEN_302_REDIRECT), TEXT(T_NO_KEEPALIVE_AFTER_POST_REQUEST), TEXT(T_REFERER_NONE), TEXT(T_REFERER_SAME_URL), TEXT(T_REFERER_FAKE), TEXT(T_FAKE_REFERER) };
+unsigned char *http_labels[] = { TEXT(T_USE_HTTP_10), TEXT(T_ALLOW_SERVER_BLACKLIST), TEXT(T_BROKEN_302_REDIRECT), TEXT(T_NO_KEEPALIVE_AFTER_POST_REQUEST), TEXT(T_REFERER_NONE), TEXT(T_REFERER_TRUE), TEXT(T_REFERER_SAME_URL), TEXT(T_REFERER_FAKE), TEXT(T_FAKE_REFERER) };
 
 void httpopt_fn(struct dialog_data *dlg)
 {
@@ -464,8 +464,8 @@
 	int y = 0;
 	checkboxes_width(term, dlg->dlg->udata, &max, max_text_width);
 	checkboxes_width(term, dlg->dlg->udata, &min, min_text_width);
-	max_text_width(term, http_labels[7], &max);
-	min_text_width(term, http_labels[7], &min);
+	max_text_width(term, http_labels[8], &max);
+	min_text_width(term, http_labels[8], &min);
 	max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
 	min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
@@ -476,7 +476,7 @@
 	rw = 0;
 	dlg_format_checkboxes(NULL, term, dlg->items, dlg->n - 3, 0, &y, w, &rw, dlg->dlg->udata);
 	y++;
-	dlg_format_text(NULL, term, http_labels[7], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
+	dlg_format_text(NULL, term, http_labels[8], 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
 	y+=2;
 	dlg_format_buttons(NULL, term, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw, AL_CENTER);
 	w = rw;
@@ -487,8 +487,8 @@
 	y = dlg->y + DIALOG_TB + 1;
 	dlg_format_checkboxes(term, term, dlg->items, dlg->n - 3, dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
 	y++;
-	dlg_format_text(term, term, http_labels[7], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
-	dlg_format_field(term, term, dlg->items + 7, dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
+	dlg_format_text(term, term, http_labels[8], dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
+	dlg_format_field(term, term, dlg->items + 8, dlg->x + DIALOG_LB, &y, w, NULL, AL_LEFT);
 	y++;
 	dlg_format_buttons(term, term, dlg->items + dlg->n - 2, 2, dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
 }
@@ -498,8 +498,8 @@
 {
 	struct http_bugs *bugs = (struct http_bugs *)di->cdata;
 	struct dialog *d;
-	if (!(d = mem_alloc(sizeof(struct dialog) + 11 * sizeof(struct dialog_item)))) return 0;
-	memset(d, 0, sizeof(struct dialog) + 11 * sizeof(struct dialog_item));
+	if (!(d = mem_alloc(sizeof(struct dialog) + 12 * sizeof(struct dialog_item)))) return 0;
+	memset(d, 0, sizeof(struct dialog) + 12 * sizeof(struct dialog_item));
 	d->title = TEXT(T_HTTP_BUG_WORKAROUNDS);
 	d->fn = httpopt_fn;
 	d->udata = http_labels;
@@ -526,26 +526,31 @@
 	d->items[4].data = (void *)&referer;
 	d->items[5].type = D_CHECKBOX;
 	d->items[5].gid = 1;
-	d->items[5].gnum = REFERER_SAME_URL;
+	d->items[5].gnum = REFERER_TRUE;
 	d->items[5].dlen = sizeof(int);
 	d->items[5].data = (void *)&referer;
 	d->items[6].type = D_CHECKBOX;
 	d->items[6].gid = 1;
-	d->items[6].gnum = REFERER_FAKE;
+	d->items[6].gnum = REFERER_SAME_URL;
 	d->items[6].dlen = sizeof(int);
 	d->items[6].data = (void *)&referer;
-	d->items[7].type = D_FIELD;
-	d->items[7].dlen = MAX_STR_LEN;
-	d->items[7].data = fake_referer;
-	d->items[8].type = D_BUTTON;
-	d->items[8].gid = B_ENTER;
-	d->items[8].fn = ok_dialog;
-	d->items[8].text = TEXT(T_OK);
+	d->items[7].type = D_CHECKBOX;
+	d->items[7].gid = 1;
+	d->items[7].gnum = REFERER_FAKE;
+	d->items[7].dlen = sizeof(int);
+	d->items[7].data = (void *)&referer;
+	d->items[8].type = D_FIELD;
+	d->items[8].dlen = MAX_STR_LEN;
+	d->items[8].data = fake_referer;
 	d->items[9].type = D_BUTTON;
-	d->items[9].gid = B_ESC;
-	d->items[9].fn = cancel_dialog;
-	d->items[9].text = TEXT(T_CANCEL);
-	d->items[10].type = D_END;
+	d->items[9].gid = B_ENTER;
+	d->items[9].fn = ok_dialog;
+	d->items[9].text = TEXT(T_OK);
+	d->items[10].type = D_BUTTON;
+	d->items[10].gid = B_ESC;
+	d->items[10].fn = cancel_dialog;
+	d->items[10].text = TEXT(T_CANCEL);
+	d->items[11].type = D_END;
  	do_dialog(dlg->win->term, d, getml(d, NULL));
 	return 0;
 }
diff -ru links-0.96/sched.c links-0.96+true-referer/sched.c
--- links-0.96/sched.c	Mon Jun 11 12:04:54 2001
+++ links-0.96+true-referer/sched.c	Sat Sep  1 16:21:57 2001
@@ -527,7 +527,7 @@
 	return u;
 }
 
-int load_url(unsigned char *url, struct status *stat, int pri, int no_cache)
+int load_url(unsigned char *url, unsigned char *prev_url, struct status *stat, int pri, int no_cache)
 {
 	struct cache_entry *e = NULL;
 	struct connection *c;
@@ -587,6 +587,7 @@
 	memset(c, 0, sizeof(struct connection));
 	c->count = connection_count++;
 	c->url = u;
+	c->prev_url = prev_url;
 	c->running = 0;
 	c->prev_error = 0;
 	c->from = no_cache >= NC_RELOAD || !e || e->frag.next == &e->frag || ((struct fragment *)e->frag.next)->offset ? 0 : ((struct fragment *)e->frag.next)->length;
diff -ru links-0.96/session.c links-0.96+true-referer/session.c
--- links-0.96/session.c	Sat Sep  1 19:13:43 2001
+++ links-0.96+true-referer/session.c	Sat Sep  1 18:06:16 2001
@@ -518,7 +518,7 @@
 			down->win->handler(down->win, &ev, 0);
 		}
 		/*if (!strchr(down->url, POST_CHAR)) {*/
-			load_url(down->url, &down->stat, PRI_DOWNLOAD, NC_CACHE);
+			load_url(down->url, ce->url, &down->stat, PRI_DOWNLOAD, NC_CACHE);
 			return;
 		/*} else {
 			unsigned char *msg = init_str();
@@ -676,7 +676,7 @@
 	down->ses = ses;
 	down->remotetime = 0;
 	add_to_list(downloads, down);
-	load_url(url, &down->stat, PRI_DOWNLOAD, NC_CACHE);
+	load_url(url, ses->ref_url, &down->stat, PRI_DOWNLOAD, NC_CACHE);
 	display_download(ses->term, down, ses);
 }
 
@@ -849,7 +849,7 @@
 	w->ses->loading_url = stracpy(w->url);
 	w->ses->wtd = w->wtd;
 	w->ses->wtd_target = w->target;
-	load_url(w->ses->loading_url, &w->ses->loading, w->pri, w->cache);
+	load_url(w->ses->loading_url, w->ses->ref_url, &w->ses->loading, w->pri, w->cache);
 }
 
 void post_no(struct wtd_data *w)
@@ -876,7 +876,7 @@
 		ses->loading_url = url;
 		ses->wtd = wtd;
 		ses->wtd_target = target;
-		load_url(url, &ses->loading, pri, cache);
+		load_url(url, ses->ref_url, &ses->loading, pri, cache);
 		return;
 	}
 	w->ses = ses;
@@ -897,6 +897,7 @@
 int do_move(struct session *ses, struct status **stat)
 {
 	struct cache_entry *ce = NULL;
+	int l = 0;
 	if (!ses->loading_url) {
 		internal("no ses->loading_url");
 		return 0;
@@ -917,6 +918,9 @@
 		abort_loading(ses);
 		if (!list_empty(ses->history)) *stat = &cur_loc(ses)->stat;
 		else *stat = NULL;
+		if (ses->ref_url) mem_free(ses->ref_url);
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, ce->url);
 		if (w == WTD_FORWARD || w == WTD_IMGMAP) {
 			ses_goto(ses, u, ses->wtd_target, PRI_MAIN, NC_CACHE, w, gp, end_load, 1);
 			return 2;
@@ -1192,6 +1196,7 @@
 {
 	static int stop_recursion = 0;
 	struct file_to_load *ftl;
+	struct f_data_c *fd = current_frame(ses);
 	int more;
 	if (stop_recursion) return;
 	stop_recursion = 1;
@@ -1199,7 +1204,7 @@
 		more = 0;
 		foreach(ftl, ses->more_files) if (!ftl->req_sent) {
 			ftl->req_sent = 1;
-			load_url(ftl->url, &ftl->stat, ftl->pri, NC_CACHE);
+			load_url(ftl->url, fd?fd->f_data?fd->f_data->url:NULL:NULL, &ftl->stat, ftl->pri, NC_CACHE);
 			more = 1;
 		}
 	} while (more);
@@ -1390,6 +1395,7 @@
 	if (ses->tq_goto_position) mem_free(ses->tq_goto_position);
 	if (ses->tq_prog) mem_free(ses->tq_prog);
 	if (ses->dn_url) mem_free(ses->dn_url);
+	if (ses->ref_url) mem_free(ses->ref_url),ses->ref_url=NULL;
 	if (ses->search_word) mem_free(ses->search_word);
 	if (ses->last_search_word) mem_free(ses->last_search_word);
 	del_from_list(ses);
@@ -1409,6 +1415,7 @@
 void reload(struct session *ses, int no_cache)
 {
 	struct location *l;
+	struct f_data_c *fd = current_frame(ses);
 	abort_loading(ses);
 	if (no_cache == -1) no_cache = ++ses->reloadlevel;
 	else ses->reloadlevel = no_cache;
@@ -1416,12 +1423,12 @@
 		struct file_to_load *ftl;
 		l->stat.data = ses;
 		l->stat.end = (void *)doc_end_load;
-		load_url(l->vs.url, &l->stat, PRI_MAIN, no_cache);
+		load_url(l->vs.url, ses->ref_url, &l->stat, PRI_MAIN, no_cache);
 		foreach(ftl, ses->more_files) {
 			if (ftl->req_sent && ftl->stat.state >= 0) continue;
 			ftl->stat.data = ftl;
 			ftl->stat.end = (void *)file_end_load;
-			load_url(ftl->url, &ftl->stat, PRI_FRAME, no_cache);
+			load_url(ftl->url, fd?fd->f_data?fd->f_data->url:NULL:NULL, &ftl->stat, PRI_FRAME, no_cache);
 		}
 	}
 }
@@ -1444,6 +1451,9 @@
 void go_back(struct session *ses)
 {
 	unsigned char *url;
+	struct f_data_c *fd = current_frame(ses);
+	int l = 0;
+	
 	ses->reloadlevel = NC_CACHE;
 	if (ses->wtd) {
 		if (1 || ses->wtd != WTD_BACK) {
@@ -1458,6 +1468,11 @@
 	abort_loading(ses);
 	if (!(url = stracpy(((struct location *)ses->history.next)->next->vs.url)))
 		return;
+	if (ses->ref_url) mem_free(ses->ref_url),ses->ref_url=NULL;
+	if (fd && fd->f_data && fd->f_data->url) {
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, fd->f_data->url);
+	}
 	ses_goto(ses, url, NULL, PRI_MAIN, NC_ALWAYS_CACHE, WTD_BACK, NULL, end_load, 0);
 }
 
@@ -1489,6 +1504,9 @@
 	unsigned char *u;
 	unsigned char *pos;
 	void (*fn)(struct session *, unsigned char *);
+	struct f_data_c *fd = current_frame(ses);
+	int l = 0;
+	
 #ifdef HAVE_LUA
 	unsigned char *tofree = NULL;
 	if (!(url = follow_url_hook(ses, url))) goto end;
@@ -1515,6 +1533,11 @@
 		}
 	}
 	abort_loading(ses);
+	if (ses->ref_url) mem_free(ses->ref_url), ses->ref_url=NULL;
+	if (fd && fd->f_data && fd->f_data->url) {
+ 		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, fd->f_data->url);
+	}
 	ses_goto(ses, u, target, PRI_MAIN, NC_CACHE, wtd, pos, end_load, 0);
 	/*abort_loading(ses);*/
 	end:
diff -ru links-0.96/view.c links-0.96+true-referer/view.c
--- links-0.96/view.c	Sat Sep  1 19:13:43 2001
+++ links-0.96+true-referer/view.c	Sat Sep  1 17:13:38 2001
@@ -2115,6 +2115,8 @@
 void frm_download(struct session *ses, struct f_data_c *fd)
 {
 	struct link *link;
+	int l = 0;
+	
 	if (fd->vs->current_link == -1) return;
 	if (ses->dn_url) mem_free(ses->dn_url), ses->dn_url = NULL;
 	link = &fd->f_data->links[fd->vs->current_link];
@@ -2125,6 +2127,9 @@
 			ses->dn_url = NULL;
 			return;
 		}
+		if (ses->ref_url) mem_free(ses->ref_url);
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, fd->f_data->url);
 		query_file(ses, ses->dn_url, start_download, NULL);
 	}
 }
@@ -2132,21 +2137,33 @@
 void send_download_image(struct terminal *term, void *xxx, struct session *ses)
 {
 	struct f_data_c *fd = current_frame(ses);
+	int l = 0;
+	
 	if (!fd) return;
 	if (fd->vs->current_link == -1) return;
 	if (ses->dn_url) mem_free(ses->dn_url);
-	if ((ses->dn_url = stracpy(fd->f_data->links[fd->vs->current_link].where_img)))
+	if ((ses->dn_url = stracpy(fd->f_data->links[fd->vs->current_link].where_img))) {
+		if (ses->ref_url) mem_free(ses->ref_url);
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, fd->f_data->url);
 		query_file(ses, ses->dn_url, start_download, NULL);
+	}
 }
 
 void send_download(struct terminal *term, void *xxx, struct session *ses)
 {
 	struct f_data_c *fd = current_frame(ses);
+	int l = 0;
+	
 	if (!fd) return;
 	if (fd->vs->current_link == -1) return;
 	if (ses->dn_url) mem_free(ses->dn_url);
-	if ((ses->dn_url = get_link_url(ses, fd, &fd->f_data->links[fd->vs->current_link])))
+	if ((ses->dn_url = get_link_url(ses, fd, &fd->f_data->links[fd->vs->current_link]))) {
+		if (ses->ref_url) mem_free(ses->ref_url);
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &l, fd->f_data->url);
 		query_file(ses, ses->dn_url, start_download, NULL);
+	}
 }
 
 /* open a link in a new xterm */
@@ -2209,14 +2226,20 @@
 
 void save_url(struct session *ses, unsigned char *url)
 {
+	struct f_data_c *fd = current_frame(ses);
 	unsigned char *u;
+	int l = 0;
+	
 	if (!(u = translate_url(url, ses->term->cwd))) {
 		struct status stat = { NULL, NULL, NULL, NULL, S_BAD_URL, PRI_CANCEL, 0, NULL, NULL };
 		print_error_dialog(ses, &stat, TEXT(T_ERROR));
 		return;
 	}
 	if (ses->dn_url) mem_free(ses->dn_url);
+	if (ses->ref_url) mem_free(ses->ref_url);
 	ses->dn_url = u;
+	ses->ref_url = init_str();
+	add_to_str(&ses->ref_url, &l, fd->f_data->url);
 	query_file(ses, ses->dn_url, start_download, NULL);
 }
 
@@ -2232,12 +2255,19 @@
 
 void save_as(struct terminal *term, void *xxx, struct session *ses)
 {
+	struct f_data_c *fd = current_frame(ses);
 	struct location *l;
+	int len = 0;
+	
 	if (list_empty(ses->history)) return;
 	l = cur_loc(ses);
 	if (ses->dn_url) mem_free(ses->dn_url);
-	if ((ses->dn_url = stracpy(l->vs.url)))
+	if ((ses->dn_url = stracpy(l->vs.url))) {
+		if (ses->ref_url) mem_free(ses->ref_url);
+		ses->ref_url = init_str();
+		add_to_str(&ses->ref_url, &len, fd->f_data->url);
 		query_file(ses, ses->dn_url, start_download, NULL);
+	}
 }
 
 void save_formatted(struct session *ses, unsigned char *file)
diff -ru links-0.96/kbdbind.c links-0.96+editarea/kbdbind.c
--- links-0.96/kbdbind.c	Sat Sep  8 08:02:45 2001
+++ links-0.96+editarea/kbdbind.c	Sat Sep  8 08:02:21 2001
@@ -154,6 +154,7 @@
 		"document-info",
 		"down",
 		"download",
+		"edit",
 		"end",
 		"enter",
 		"file-menu",
@@ -358,6 +359,8 @@
 	{ ACT_DOWN, KBD_DOWN, 0 },
 	{ ACT_END, KBD_END, 0 },
 	{ ACT_END, 'E', KBD_CTRL },
+	{ ACT_EDIT, KBD_F4 },
+	{ ACT_EDIT, 'T', KBD_CTRL },
 	{ ACT_COPY_CLIPBOARD, KBD_INS, KBD_CTRL },
 	{ ACT_COPY_CLIPBOARD, 'B', KBD_CTRL },
 	{ ACT_CUT_CLIPBOARD, 'X', KBD_CTRL },
diff -ru links-0.96/links.h links-0.96+editarea/links.h
--- links-0.96/links.h	Sat Sep  8 08:02:52 2001
+++ links-0.96+editarea/links.h	Sat Sep  8 07:59:17 2001
@@ -1713,6 +1713,9 @@
 
 /* view.c */
 
+extern int textarea_editor;
+void textarea_edit(int, struct terminal *, struct form_control *, struct form_state *);
+
 int can_open_in_new(struct terminal *);
 void open_in_new_window(struct terminal *, void (*)(struct terminal *, void (*)(struct terminal *, unsigned char *, unsigned char *), struct session *ses), struct session *);
 void send_open_in_new_xterm(struct terminal *term, void (*open_window)(struct terminal *term, unsigned char *, unsigned char *), struct session *ses);
@@ -2121,6 +2124,7 @@
 	ACT_DOCUMENT_INFO,
 	ACT_DOWN,
 	ACT_DOWNLOAD,
+	ACT_EDIT,
 	ACT_END,
 	ACT_ENTER,
 	ACT_FILE_MENU,
diff -ru links-0.96/terminal.c links-0.96+editarea/terminal.c
--- links-0.96/terminal.c	Tue Apr 17 17:51:49 2001
+++ links-0.96+editarea/terminal.c	Sat Sep  8 07:59:17 2001
@@ -698,6 +698,8 @@
 	set_handlers(term->fdin, (void (*)(void *))in_term, NULL, (void (*)(void *))destroy_terminal, term);
 	unblock_itrm(term->fdin);
 	redraw_terminal_cls(term);
+	if (textarea_editor)	/* XXX */
+		textarea_edit(1, NULL, NULL, NULL);
 }
 
 void exec_on_terminal(struct terminal *term, unsigned char *path, unsigned char *delete, int fg)
diff -ru links-0.96/view.c links-0.96+editarea/view.c
--- links-0.96/view.c	Sat Sep  8 08:02:52 2001
+++ links-0.96+editarea/view.c	Sat Sep  8 07:59:17 2001
@@ -1449,6 +1449,55 @@
 	return -1;
 }
 
+int textarea_editor = 0;
+
+void textarea_edit(int op, struct terminal *term_, struct form_control *form_, struct form_state *fs_)
+{
+	static int form_maxlength;
+	static struct form_state *fs;
+	static struct terminal *term;
+	static char *fn = NULL;
+	char *ed, *ex;
+	FILE *taf;
+	int flen;
+
+	if (form_) form_maxlength = form_->maxlength;
+	if (fs_) fs = fs_;
+	if (term_) term = term_;
+	
+	if (! fn) fn = tempnam(NULL, "linksarea");
+
+	if (! op) {
+		taf = fopen(fn, "w");
+		fwrite(fs->value, strlen(fs->value), 1, taf);
+		fclose(taf);
+					
+		ed = getenv("EDITOR");
+		if (! ed) ed = "vi";
+		ex = mem_alloc(strlen(ed) + strlen(fn) + 2);
+		sprintf(ex, "%s %s", ed, fn);
+		exec_on_terminal(term, ex, "", 1);
+		mem_free(ex);
+
+		textarea_editor = 1;
+		
+	} else {
+	  
+		taf = fopen(fn, "r+");
+		if (taf) {
+			fseek(taf, 0, SEEK_END); flen = ftell(taf); fseek(taf, 0, SEEK_SET);
+			if (flen <= form_maxlength) {
+				mem_free(fs->value);
+				fs->value = mem_alloc(flen + 1);
+				fread(fs->value, flen, 1, taf); fs->value[flen] = 0;
+				fs->state = flen;
+			}
+			fclose(taf);
+		}
+		textarea_editor = 0; fn = NULL;
+	}
+}
+
 int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct event *ev, int rep)
 {
 	struct form_control *form = l->form;
@@ -1540,6 +1589,10 @@
 						mem_free(ln);
 					}
 				} else fs->state = strlen(fs->value);
+				break;
+			case ACT_EDIT:
+				if (form->type == FC_TEXTAREA && !form->ro)
+				  	textarea_edit(0, ses->term, form, fs);
 				break;
 			case ACT_COPY_CLIPBOARD:
 				set_clipboard_text(fs->value);
diff -ru links-0.96/cookies.c links-0.96+cookies-expire/cookies.c
--- links-0.96/cookies.c	Wed Jun  6 18:32:50 2001
+++ links-0.96+cookies-expire/cookies.c	Sun Sep  2 22:39:19 2001
@@ -13,8 +13,8 @@
 	struct cookie *prev;
 	unsigned char *name, *value;
 	unsigned char *server;
-	unsigned char *expires;
 	unsigned char *path, *domain;
+	time_t expires; /* zero means undefined */
 	int secure;
 	int id;
 };
@@ -46,7 +46,6 @@
 	mem_free(c->name);
 	mem_free(c->value);
 	if (c->server) mem_free(c->server);
-	if (c->expires) mem_free(c->expires);
 	if (c->path) mem_free(c->path);
 	if (c->domain) mem_free(c->domain);
 }
@@ -76,7 +75,7 @@
 {
 	struct cookie *cookie;
 	struct c_server *cs;
-	unsigned char *p, *q, *s, *server, *document;
+	unsigned char *p, *q, *s, *server, *date, *document;
 	if (accept_cookies == ACCEPT_NONE) return 0;
 	for (p = str; *p != ';' && *p; p++) if (WHITECHAR(*p)) return 0;
 	for (q = str; *q != '='; q++) if (!*q || q >= p) return 0;
@@ -87,7 +86,13 @@
 	cookie->name = memacpy(str, q - str);
 	cookie->value = memacpy(q + 1, p - q - 1);
 	cookie->server = stracpy(server);
-	cookie->expires = parse_header_param(str, "expires");
+	date = parse_header_param(str, "expires");
+	if (date) {
+		cookie->expires = parse_http_date(date);
+		if (! cookie->expires) cookie->expires++; /* no harm and we can use zero then */
+		mem_free(date);
+	} else
+		cookie->expires = 0;
 	if (!(cookie->path = parse_header_param(str, "path"))) {
 		unsigned char *w;
 		cookie->path = stracpy("/");
@@ -234,7 +239,7 @@
 
 int cookie_expired(struct cookie *c)
 {
-	return 0;	/* !!! FIXME */
+  	return (c->expires && c->expires < time(NULL));
 }
 
 void send_cookies(unsigned char **s, int *l, unsigned char *url)
diff -ru links-0.96/cookies.c links-0.96+cookies-save/cookies.c
--- links-0.96/cookies.c	Mon Oct  1 14:09:20 2001
+++ links-0.96+cookies-save/cookies.c	Mon Oct  1 14:08:15 2001
@@ -43,8 +43,8 @@
 
 void free_cookie(struct cookie *c)
 {
-	mem_free(c->name);
-	mem_free(c->value);
+	if (c->name) mem_free(c->name);
+	if (c->value) mem_free(c->value);
 	if (c->server) mem_free(c->server);
 	if (c->path) mem_free(c->path);
 	if (c->domain) mem_free(c->domain);
@@ -276,15 +276,99 @@
 
 void init_cookies()
 {
-	/* !!! FIXME: read cookies */
+	unsigned char in_buffer[MAX_STR_LEN];
+	unsigned char *cookfile, *p, *q;
+	FILE *fp;
+
+	/* must be called after init_home */
+	if (! links_home) return;
+	
+	cookfile = stracpy(links_home);
+	if (! cookfile) return;
+	add_to_strn(&cookfile, "cookies");
+
+	fp = fopen(cookfile, "r");
+	mem_free(cookfile);
+	if (fp == NULL) return;
+	
+	while (fgets(in_buffer, MAX_STR_LEN, fp)) {
+		struct cookie *cookie;
+		
+		if (!(cookie = mem_alloc(sizeof(struct cookie)))) return;
+		memset(cookie, 0, sizeof(struct cookie));
+		
+		q = in_buffer; p = strchr(in_buffer, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->name = stracpy(q);
+		
+		q = p; p = strchr(p, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->value = stracpy(q);
+		
+		q = p; p = strchr(p, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->server = stracpy(q);
+		
+		q = p; p = strchr(p, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->path = stracpy(q);
+		
+		q = p; p = strchr(p, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->domain = stracpy(q);
+		
+		q = p; p = strchr(p, ' ');
+		if (p == NULL) goto inv;
+		*p++ = '\0';
+		cookie->expires = atoi(q);
+		
+		cookie->secure = atoi(p);
+		
+		cookie->id = cookie_id++;
+
+		accept_cookie(cookie);
+
+		continue;
+
+inv:
+		free_cookie(cookie);
+		free(cookie);
+	}
+	fclose(fp);
 }
 
 void cleanup_cookies()
 {
 	struct cookie *c;
+	unsigned char *cookfile;
+	FILE *fp;
+	
 	free_list(c_domains);
-	/* !!! FIXME: save cookies */
-	foreach (c, cookies) free_cookie(c);
+
+	cookfile = stracpy(links_home);
+	if (! cookfile) return;
+	add_to_strn(&cookfile, "cookies");
+
+	fp = fopen(cookfile, "w");
+	mem_free(cookfile);
+	if (fp == NULL) return;
+	
+	foreach (c, cookies) {
+		if (c->expires && ! cookie_expired(c))
+			fprintf(fp, "%s %s %s %s %s %d %d\n", c->name, c->value,
+			    c->server?c->server:(unsigned char *)"", c->path?c->path:(unsigned char *)"",
+			    c->domain?c->domain:(unsigned char *)"", c->expires, c->secure);
+
+		free_cookie(c);
+	}
+
+	fclose(fp);
+	
 	free_list(cookies);
 }
 
diff -ru links-0.96/cookies.c links-0.96+cookies-resave/cookies.c
--- links-0.96/cookies.c	Tue Oct  2 17:29:36 2001
+++ links-0.96+cookies-resave/cookies.c	Tue Oct  2 17:28:50 2001
@@ -1,5 +1,8 @@
 #include "links.h"
 
+/* #undef it defaultly */
+#define COOKIES_RESAVE	1
+
 #define ACCEPT_NONE	0
 #define ACCEPT_ASK	1
 #define ACCEPT_ALL	2
@@ -41,6 +44,8 @@
 void accept_cookie(struct cookie *);
 void delete_cookie(struct cookie *);
 
+void load_cookies(), save_cookies();
+
 void free_cookie(struct cookie *c)
 {
 	if (c->name) mem_free(c->name);
@@ -161,6 +166,9 @@
 	if (!(cd = mem_alloc(sizeof(struct c_domain) + strlen(c->domain) + 1))) return;
 	strcpy(cd->domain, c->domain);
 	add_to_list(c_domains, cd);
+#ifdef COOKIES_RESAVE
+	save_cookies();
+#endif
 }
 
 void delete_cookie(struct cookie *c)
@@ -177,6 +185,9 @@
 	del_from_list(c);
 	free_cookie(c);
 	mem_free(c);
+#ifdef COOKIES_RESAVE
+	save_cookies();
+#endif
 }
 
 struct cookie *find_cookie_id(void *idp)
@@ -261,6 +272,9 @@
 			del_from_list(d);
 			free_cookie(d);
 			mem_free(d);
+#ifdef COOKIES_RESAVE
+			save_cookies();
+#endif
 			continue;
 		}
 		if (c->secure) continue;
@@ -274,11 +288,11 @@
 	mem_free(server);
 }
 
-void init_cookies()
-{
+void load_cookies() {
 	unsigned char in_buffer[MAX_STR_LEN];
 	unsigned char *cookfile, *p, *q;
 	FILE *fp;
+	struct cookie *c;
 
 	/* must be called after init_home */
 	if (! links_home) return;
@@ -287,6 +301,13 @@
 	if (! cookfile) return;
 	add_to_strn(&cookfile, "cookies");
 
+	/* do it here, as we will delete whole cookies list if the file was removed */
+	free_list(c_domains);
+
+	foreach(c, cookies)
+		free_cookie(c);
+	free_list(cookies);
+
 	fp = fopen(cookfile, "r");
 	mem_free(cookfile);
 	if (fp == NULL) return;
@@ -337,18 +358,17 @@
 
 inv:
 		free_cookie(cookie);
-		free(cookie);
+		mem_free(cookie);
 	}
 	fclose(fp);
 }
 
-void cleanup_cookies()
-{
+int cquit = 0; /* XXX */
+
+void save_cookies() {
 	struct cookie *c;
 	unsigned char *cookfile;
 	FILE *fp;
-	
-	free_list(c_domains);
 
 	cookfile = stracpy(links_home);
 	if (! cookfile) return;
@@ -364,11 +384,25 @@
 			    c->server?c->server:(unsigned char *)"", c->path?c->path:(unsigned char *)"",
 			    c->domain?c->domain:(unsigned char *)"", c->expires, c->secure);
 
-		free_cookie(c);
+		if (cquit)
+			free_cookie(c);
 	}
 
 	fclose(fp);
+}
+
+void init_cookies()
+{
+	load_cookies();
+}
+
+void cleanup_cookies()
+{
+	free_list(c_domains);
+	
+	cquit = 1;
+	save_cookies();
+	cquit = 0;
 	
 	free_list(cookies);
 }
-
diff -ru links-0.96/kbdbind.c links-0.96+cookies-resave/kbdbind.c
--- links-0.96/kbdbind.c	Tue Oct  2 14:24:38 2001
+++ links-0.96+cookies-resave/kbdbind.c	Tue Oct  2 14:40:40 2001
@@ -148,6 +148,7 @@
 		"back",
 		"backspace",
 		"bookmark-manager",
+		"cookies-load",
 		"copy-clipboard",
 		"cut-clipboard",
 		"delete",
@@ -336,6 +337,7 @@
 	{ ACT_ADD_BOOKMARK, 'A' },
 	{ ACT_BOOKMARK_MANAGER, 's' },
 	{ ACT_BOOKMARK_MANAGER, 'S' },
+	{ ACT_COOKIES_LOAD, 'K', KBD_CTRL },
 	{ ACT_QUIT, 'q' },
 	{ ACT_REALLYQUIT, 'Q' },
 	{ ACT_DOCUMENT_INFO, '=' },
diff -ru links-0.96/links.h links-0.96+cookies-resave/links.h
--- links-0.96/links.h	Tue Oct  2 14:24:38 2001
+++ links-0.96+cookies-resave/links.h	Tue Oct  2 14:41:36 2001
@@ -831,6 +831,7 @@
 
 int set_cookie(struct terminal *, unsigned char *, unsigned char *);
 void send_cookies(unsigned char **, int *, unsigned char *);
+void load_cookies();
 void init_cookies();
 void cleanup_cookies();
 
@@ -2118,6 +2119,7 @@
 	ACT_BACK,
 	ACT_BACKSPACE,
 	ACT_BOOKMARK_MANAGER,
+	ACT_COOKIES_LOAD,
 	ACT_COPY_CLIPBOARD,
 	ACT_CUT_CLIPBOARD,
 	ACT_DELETE,
diff -ru links-0.96/view.c links-0.96+cookies-resave/view.c
--- links-0.96/view.c	Tue Oct  2 14:24:38 2001
+++ links-0.96+cookies-resave/view.c	Tue Oct  2 14:43:25 2001
@@ -2089,6 +2089,9 @@
 			case ACT_BOOKMARK_MANAGER:
 				if (!anonymous) menu_bookmark_manager(ses->term, NULL, ses);
 				goto x;
+			case ACT_COOKIES_LOAD:
+				if (!anonymous) load_cookies();
+				goto x;
 			case ACT_REALLYQUIT:
 				reallyquit:
 				exit_prog(ses->term, (void *)1, ses);
diff -ur links-0.96/charsets.c links-0.96+crfix/charsets.c
--- links-0.96/charsets.c	Sun Dec 31 23:26:52 2000
+++ links-0.96+crfix/charsets.c	Tue Sep 18 14:49:56 2001
@@ -242,6 +242,7 @@
 				else return NULL;
 				if (n >= 0x10000) return NULL;
 			} while (--l);
+			if (n == 13) n = 10; /* be lynx-like, be broken, be smart */
 		}
 	} else {
 		int s = 0, e = N_ENTITIES - 1;
diff -ur links-0.96/main.c links-0.96+moved/main.c
--- links-0.96/main.c	Wed Sep  5 21:23:39 2001
+++ links-0.96+moved/main.c	Wed Sep  5 21:18:39 2001
@@ -161,7 +161,7 @@
 	if (ce && ce->redirect) {
 		unsigned char *u, *p;
 		if (stat->state >= 0) change_connection(stat, NULL, PRI_CANCEL);
-		u = stracpy(ce->redirect);
+		u = join_urls(ce->url, ce->redirect);
 		if (!http_bugs.bug_302_redirect) if (!ce->redirect_get && (p = strchr(ce->url, POST_CHAR))) add_to_strn(&u, p);
 		load_url(u, ce->url, stat, PRI_MAIN, 0);
 		mem_free(u);
