diff --git a/exec/fseditor.js b/exec/fseditor.js
index 48539ef15042a4d89aef15b0948b516db790165a..6c5ae07aa32ee58e1cc6db27d8bc0166c6ac9a17 100644
--- a/exec/fseditor.js
+++ b/exec/fseditor.js
@@ -3,6 +3,7 @@
 load("sbbsdefs.js");
 
 var line=new Array();
+var quote_line=new Array();
 var xpos=0;									/* Current xpos of insert point */
 var last_xpos=-1;							/* The xpos you'd like to be at.  -1 when not valid
 												Used to retain horiz. position when moving vertically */
@@ -15,9 +16,15 @@ var lines_on_screen=edit_bottom-edit_top+1;	/* Height of edit window */
 var curattr=7;								/* Current attribute */
 var colour_box_displayed=0;					/* Row the colour box is displayed
 												on. used for redraw */
-var graphics_box_displayed=0;				/* Row the graphic box is displayed
-/* Create an initial line... this may not be necessary when replying */
-line[0]=new Line();
+var graphics_box_displayed=0;				/* Row the graphic box is displayed on */
+var quote_window_displayed=0;				/* Row the quote window is displayed on */
+var quote_topline=0;						/* Current index into quote_line[] of quote_top */
+var quote_ypos=0;							/* Current index into line[] of selection point */
+var quote_height=0;							/* Number of quote lines to be displayed */
+var quote_sep_pos=0;						/* Line number the quote seperator is displayed on */
+var quote_ontop=false;						/* true if quote window is at the top */
+var quote_top;								/* Line number of the first quote line */
+var quote_bottom;							/* Line number of the last quote line */
 
 function Line()
 {
@@ -33,6 +40,8 @@ function Line()
 	this.kludged=false;
 	/* Start of actual text (after quote indicator) */
 	this.firstchar=0;
+	/* For selection */
+	this.selected=false;
 }
 
 /*
@@ -685,11 +694,19 @@ function redraw_screen()
 		draw_colour_box();
 	if(graphics_box_displayed)
 		draw_graphic_box();
+	if(quote_window_displayed)
+		draw_quote_window();
 	for(i=edit_top; i<=edit_bottom; i++) {
 		if(colour_box_displayed>0 && i>=colour_box_displayed && i<colour_box_displayed+3)
 			continue;
 		if(graphics_box_displayed>0 && i==graphics_box_displayed)
 			continue;
+		if(quote_window_displayed>0) {
+			if(i>=quote_top && i<=quote_bottom)
+				continue;
+			if(i==quote_sep_pos)
+				continue;
+		}
 		draw_line(i-edit_top+topline);
 	}
 	set_cursor();
@@ -959,12 +976,279 @@ function make_strings(soft,embed_colour)
 	return(new Array(str,attrs));
 }
 
+function draw_quote_selection(l)
+{
+	var yp;
+	var x;
+
+	if(l==undefined || isNaN(l))
+		return;
+	yp=l-quote_topline+quote_top;
+	/* Does this line even exist? */
+	if(quote_line[l]==undefined) {
+		console.attributes=7;
+		console.gotoxy(x+1,yp);
+		console.cleartoeol();
+	}
+	else {
+		/* Is line on the current screen? */
+		if(yp<quote_top)
+			return;
+		if(yp>quote_bottom)
+			return;
+
+		console.gotoxy(1,yp);
+		if(l==quote_ypos) {
+			console.attributes=YELLOW;
+			if(quote_line[l].selected)
+				console.write('*');
+			else
+				console.write('-');
+		}
+		else {
+			if(quote_line[l].selected) {
+				console.attributes=7;
+				console.write('*');
+			}
+			else {
+				console.attributes=ascii(quote_line[l].attr.substr(0,1));
+				console.write(quote_line[l].text.substr(0,1));
+			}
+		}
+	}
+}
+
+/*
+ * Draws a quote line on a screen.  l is the index into quote_line[]
+ */
+function draw_quote_line(l)
+{
+	var yp;
+	var x;
+
+	if(l==undefined || isNaN(l))
+		return;
+	yp=l-quote_topline+quote_top;
+	/* Does this line even exist? */
+	if(quote_line[l]==undefined) {
+		console.attributes=7;
+		console.gotoxy(x+1,yp);
+		console.cleartoeol();
+	}
+	else {
+		/* Is line on the current screen? */
+		if(yp<quote_top)
+			return;
+		if(yp>quote_bottom)
+			return;
+
+		/* ToDo we need to optimize cursor movement somehow... */
+		console.gotoxy(1,yp);
+		x=0;
+		if(l==quote_ypos) {
+			console.attributes=YELLOW;
+			if(quote_line[l].selected)
+				console.write('*');
+			else
+				console.write('-');
+			x++;
+		}
+		else {
+			if(quote_line[l].selected) {
+				console.attributes=7;
+				console.write('*');
+				x++;
+			}
+		}
+		for(; x<quote_line[l].text.length && x<79; x++) {
+			console.attributes=ascii(quote_line[l].attr.substr(x,1));
+			console.write(quote_line[l].text.substr(x,1));
+		}
+		if(x<79) {
+			console.attributes=7;
+			console.cleartoeol();
+		}
+	}
+}
+
+function draw_quote_window()
+{
+	var i;
+
+	/* Draw seperater */
+	console.gotoxy(1,quote_sep_pos);
+	console.attributes=7;
+	console.write("\xc4\xc4\xb4 "+(quote_ontop?"^^^":"vvv")+" Quote "+(quote_ontop?"^^^":"vvv")+" \xc3\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4\xc4");
+	for(i=0; i<quote_height; i++) {
+		draw_quote_line(quote_topline+i);
+	}
+}
+
+function quote_mode()
+{
+	var i;
+	var select_mode=false;
+	var select_start=0;
+
+	quote_height=parseInt(lines_on_screen/2)-1;	/* Rounds down */
+	var curr_ypos=ypos-topline+edit_top;
+
+	/* Decide if quote window should go at top or at bottom */
+	if(curr_ypos>edit_top+quote_height)
+		quote_ontop=true;
+	else
+		quote_ontop=false;
+
+	if(quote_ontop) {
+		quote_sep_pos=edit_top+quote_height;
+		quote_window_displayed=edit_top;
+		quote_top=edit_top;
+		quote_bottom=quote_sep_pos-1;
+	}
+	else {
+		quote_sep_pos=edit_bottom-quote_height;
+		quote_window_displayed=quote_sep_pos;
+		quote_top=quote_sep_pos+1;
+		quote_bottom=edit_bottom;
+	}
+
+	for(i=0;i<quote_line.length;i++)
+		quote_line[i].selected=false;
+
+	draw_quote_window();
+
+	while(1) {
+		set_cursor();
+		key=console.inkey(0,10000);
+		if(key=='')
+			continue;
+		switch(key) {
+			case 'a':
+			case 'A':
+			case '\x01':	/* A and CTRL-A -- Select all */
+				for(i=0;i<quote_line.length;i++)
+					quote_line[i].selected=true;
+				for(i=0; i< quote_height; i++)
+					draw_quote_selection(quote_topline+i);
+				break;
+			case 'n':
+			case 'N':
+			case '\x0e':	/* Unselect all */
+				for(i=0;i<quote_line.length;i++)
+					quote_line[i].selected=false;
+				for(i=0; i< quote_height; i++)
+					draw_quote_selection(quote_topline+i);
+				break;
+			case '\x12':	/* CTRL-R (Quick Redraw in SyncEdit) */
+				redraw_screen();
+				break;
+			case KEY_DOWN:
+				quote_ypos++;
+				if(quote_ypos>=quote_line.length) {
+					quote_ypos=quote_line.length-1;
+					console.beep();
+					break;
+				}
+				if(select_mode) {
+					if(quote_ypos > select_start) {
+						quote_line[quote_ypos].selected=true;
+					}
+					else {
+						quote_line[quote_ypos-1].selected=false;
+					}
+				}
+				if(quote_ypos>=quote_topline+quote_height) {
+					quote_topline++;
+					draw_quote_window();
+					break;
+				}
+				draw_quote_selection(quote_ypos-1);
+				draw_quote_selection(quote_ypos);
+				break;
+			case KEY_UP:
+				quote_ypos--;
+				if(quote_ypos<0) {
+					quote_ypos=0;
+					console.beep();
+					break;
+				}
+				if(select_mode) {
+					if(quote_ypos < select_start) {
+						quote_line[quote_ypos].selected=true;
+					}
+					else {
+						quote_line[quote_ypos+1].selected=false;
+					}
+				}
+				if(quote_ypos<quote_topline) {
+					quote_topline=quote_ypos;
+					draw_quote_window();
+					break;
+				}
+				draw_quote_selection(quote_ypos+1);
+				draw_quote_selection(quote_ypos);
+				break;
+			case ' ':	/* Toggle selection of current line */
+				quote_line[quote_ypos].selected=!quote_line[quote_ypos].selected;
+				draw_quote_selection(quote_ypos);
+				break;
+			case 'B':
+			case 'b':
+			case '\x02':	/* B or CTRL-B toggles "block" mode */
+				select_mode=!select_mode;
+				if(select_mode) {
+					select_start=quote_ypos;
+					quote_line[quote_ypos].selected=true;
+					draw_quote_selection(quote_ypos);
+				}
+				break;
+			case '\x0d':	/* CR */
+				for(i=0; i<quote_line.length-1; i++) {
+					if(quote_line[i].selected) {
+						line.splice(ypos,0,quote_line[i]);
+						ypos++;
+					}
+				}
+				quote_window_displayed=0;
+				redraw_screen();
+				return(false);
+			case '\x1f':
+			case '\x11':	/* CTRL-Q (XOff) (Quick Abort in SyncEdit) */
+				return(true);
+			case '\x18':    /* CTRL-X (PgDn in SyncEdit) */
+				quote_ypos+=quote_height-1;
+				quote_topline+=quote_height-1;
+				if(quote_ypos>=quote_line.length)
+					quote_ypos=quote_line.length-1;
+				if(quote_topline+quote_height>quote_line.length)
+					quote_topline=quote_line.length-quote_height;
+				if(quote_topline<0)
+					quote_topline=0;
+				draw_quote_window();
+				break;
+			case '\x19':    /* CTRL-Y (Delete Line in SyncEdit) */
+				quote_ypos-=quote_height-1;
+				quote_topline-=quote_height-1;
+				if(quote_ypos<0)
+					quote_ypos=0;
+				if(quote_topline<0)
+					quote_topline=0;
+				draw_quote_window();
+				break;
+		}
+	}
+}
+
 /* ToDo: Optimize movement... */
-function edit()
+function edit(quote_first)
 {
 	var key;
 
 	redraw_screen();
+	if(quote_first) {
+		if(quote_mode())
+			return;
+	}
 	while(1) {
 		key=console.inkey(0,10000);
 		if(key=='')
@@ -1050,7 +1334,7 @@ function edit()
 				status_line();
 				erase_colour_box();
 				break;
-			case '\x02':	/* KEY_HOME */
+			case '\x02':	/* CTRL-B KEY_HOME */
 				last_xpos=-1;
 				xpos=0;
 				set_cursor();
@@ -1079,12 +1363,12 @@ function edit()
 				break;
 			case '\x04':	/* CTRL-D (Quick Find in SyncEdit)*/
 				break;
-			case '\x05':	/* KEY_END */
+			case '\x05':	/* CTRL-E KEY_END */
 				last_xpos=-1;
 				xpos=line[ypos].text.length;
 				set_cursor();
 				break;
-			case '\x06':	/* KEY_RIGHT */
+			case '\x06':	/* CTRL-F KEY_RIGHT */
 				last_xpos=-1;
 				xpos++;
 				if(xpos>line[ypos].text.length) {
@@ -1101,7 +1385,8 @@ function edit()
 				}
 				set_cursor();
 				break;
-			case '\x08':	/* Backspace */
+			/* CTRL-G drops through to default */
+			case '\x08':	/* CTRL-H Backspace */
 				last_xpos=-1;
 				if(xpos>0) {
 					line[ypos].text=line[ypos].text.substr(0,xpos-1)
@@ -1120,9 +1405,9 @@ function edit()
 					draw_line(ypos,xpos);
 				set_cursor();
 				break;
-			case '\x09':	/* TAB... ToDo expand to spaces */
+			case '\x09':	/* CTRL-I TAB... ToDo expand to spaces */
 				break;
-			case '\x0a':	/* KEY_DOWN (Insert Line in SyncEdit) */
+			case '\x0a':	/* CTRL-J KEY_DOWN (Insert Line in SyncEdit) */
 				if(last_xpos==-1)
 					last_xpos=xpos;
 				try_next_line();
@@ -1136,7 +1421,7 @@ function edit()
 				xpos=0;
 				set_cursor();
 				break;
-			case '\x0d':	/* CR */
+			case '\x0d':	/* CTRL-M CR */
 				last_xpos=-1;
 				if(insert) {
 					add_new_line_below(ypos);
@@ -1180,6 +1465,8 @@ function edit()
 			case '\x14':	/* CTRL-T (Justify Line in SyncEdit) */
 				break;
 			case '\x15':	/* CTRL-U (Quick Quote in SyncEdit) */
+				if(quote_mode())
+					return;
 				break;
 			case '\x16':	/* CTRL-V (Toggle insert mode) */
 				insert=!insert;
@@ -1297,7 +1584,7 @@ function edit()
 				break;
 			case '\x1c':	/* CTRL-\ (RegExp) */
 				break;
-			case '\x1d':	/* KEY_LEFT */
+			case '\x1d':	/* CTRL-] KEY_LEFT */
 				last_xpos=-1;
 				xpos--;
 				if(xpos<0) {
@@ -1306,14 +1593,14 @@ function edit()
 				}
 				set_cursor();
 				break;
-			case '\x1e':	/* KEY_UP */
+			case '\x1e':	/* CTRL-^ KEY_UP */
 				if(last_xpos==-1)
 					last_xpos=xpos;
 				try_prev_line();
 				set_cursor();
 				break;
-			case '\x1f':	/* CTRL-_ */
-				break;
+			case '\x1f':	/* CTRL-_ Safe quick-abort*/
+				return;
 			case '\x7f':	/* DELETE */
 				last_xpos=-1;
 				if(xpos>=line[ypos].text.length)
@@ -1369,19 +1656,18 @@ var old_status=bbs.sys_status;
 bbs.sys_status&=~SS_PAUSEON;
 bbs.sys_status|=SS_PAUSEOFF;
 var oldpass=console.ctrlkey_passthru;
-console.ctrlkey_passthru="+ACGLOQRVWXYZ";
+console.ctrlkey_passthru="+ACGLOQRUVWXYZ";
+/* Enable delete line in SyncTERM (Disabling ANSI Music in the process) */
+console.write("\033[=1M");
 console.clear();
 var f=new File(system.node_dir+"QUOTES.TXT");
+line.push(new Line());
 if(f.open("r",false)) {
-	line=make_lines(quote_msg(word_wrap(f.read(),76)),'');
-	ypos=line.length;
-	if(ypos>=topline+lines_on_screen)
-		topline=ypos-lines_on_screen+1;
-	line.push(new Line());
+	quote_line=make_lines(quote_msg(word_wrap(f.read(),76)),'');
+	ypos=0;
+	edit(true);
 }
-file='';	/* Free up the memory */
-/* Enable delete line in SyncTERM (Disabling ANSI Music in the process) */
-console.write("\033[=1M");
-edit();
+else
+	edit(false);
 console.ctrlkey_passthru=oldpass;
 bbs.sys_status=old_status;