diff --git a/src/conio/cterm.c b/src/conio/cterm.c
index a9f93934b0b66c2acc5551c8de10c6afdecd5399..590b3f03b2dfad2cb0af4e0028660d8e123f794c 100644
--- a/src/conio/cterm.c
+++ b/src/conio/cterm.c
@@ -1391,6 +1391,33 @@ scrolldown(struct cterminal *cterm)
 	GOTOXY(x, y);
 }
 
+static void
+cterm_line_to_scrollback(struct cterminal *cterm, int row)
+{
+	if(cterm->scrollback!=NULL) {
+		int getw;
+
+		cterm->backfilled++;
+		if (cterm->backfilled > cterm->backlines) {
+			cterm->backfilled--;
+			cterm->backstart++;
+			if (cterm->backstart == cterm->backlines)
+				cterm->backstart = 0;
+		}
+		getw = cterm->backwidth;
+		if (getw > cterm->width)
+			getw = cterm->width;
+		if (getw < cterm->backwidth) {
+			memset(cterm->scrollback + cterm->backpos * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth);
+		}
+		vmem_gettext(cterm->x, row, cterm->x + getw - 1, row, cterm->scrollback + cterm->backpos * cterm->backwidth);
+
+		cterm->backpos++;
+		if (cterm->backpos == cterm->backlines)
+			cterm->backpos = 0;
+	}
+}
+
 void
 cterm_scrollup(struct cterminal *cterm)
 {
@@ -1399,24 +1426,10 @@ cterm_scrollup(struct cterminal *cterm)
 	int maxx = TERM_MAXX;
 	int maxy = TERM_MAXY;
 	int x,y;
-	int getw;
 
-	cterm->backpos++;
 	coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &minx, &miny);
 	coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &maxx, &maxy);
-	if(cterm->scrollback!=NULL) {
-		if(cterm->backpos>cterm->backlines) {
-			memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth, cterm->backwidth * sizeof(*cterm->scrollback) * (cterm->backlines - 1));
-			cterm->backpos--;
-		}
-		getw = cterm->backwidth;
-		if (getw > cterm->width)
-			getw = cterm->width;
-		if (getw < cterm->backwidth) {
-			memset(cterm->scrollback + (cterm->backpos - 1) * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth);
-		}
-		vmem_gettext(cterm->x, miny, cterm->x + getw - 1, miny, cterm->scrollback + (cterm->backpos - 1) * cterm->backwidth);
-	}
+	cterm_line_to_scrollback(cterm, miny);
 	MOVETEXT(minx, miny + 1, maxx, maxy, minx, miny);
 	CURR_XY(&x, &y);
 	cterm_clrblk(cterm, minx, maxy, minx + TERM_MAXX - 1, maxy);
@@ -1500,26 +1513,15 @@ clear2bol(struct cterminal * cterm)
 void
 cterm_clearscreen(struct cterminal *cterm, char attr)
 {
-	int getw;
-
 	if(!cterm->started)
 		cterm_start(cterm);
 
-	if(cterm->scrollback!=NULL) {
-		cterm->backpos+=cterm->height;
-		if(cterm->backpos>cterm->backlines) {
-			memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * (cterm->backpos - cterm->backlines), cterm->backwidth * sizeof(*cterm->scrollback) * (cterm->backlines - (cterm->backpos - cterm->backlines)));
-			cterm->backpos=cterm->backlines;
-		}
-		getw = cterm->backwidth;
-		if (getw > cterm->width)
-			getw = cterm->width;
-		if (getw < cterm->backwidth) {
-			memset(cterm->scrollback + (cterm->backpos - cterm->height) * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth * cterm->height);
-		}
-		vmem_gettext(cterm->x, cterm->y, cterm->x + getw - 1, cterm->y + cterm->height - 1,
-		    cterm->scrollback + (cterm->backpos - cterm->height) * cterm->backwidth);
-	}
+	int minx = TERM_MINX;
+	int miny = TERM_MINY;
+	coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &minx, &miny);
+
+	for (int i = 0; i < cterm->height; i++)
+		cterm_line_to_scrollback(cterm, miny + i);
 	CLRSCR();
 	GOTOXY(CURR_MINX, CURR_MINY);
 }
diff --git a/src/conio/cterm.h b/src/conio/cterm.h
index fc808d51cb3aa979dd6385a261e0da35dabba8fc..de8bedcbdbbdade2ea2bbcc9805640b5446ac5c6 100644
--- a/src/conio/cterm.h
+++ b/src/conio/cterm.h
@@ -99,6 +99,7 @@ struct cterminal {
 	int					right_margin;
 	int					quiet;			// No sounds are made
 	struct vmem_cell	*scrollback;
+	int					backfilled;		// Number of lines copied into scrollback
 	int					backlines;		// Number of lines in scrollback
 	int					backwidth;		// Number of columns in scrollback
 	char				DA[1024];		// Device Attributes
@@ -170,7 +171,8 @@ struct cterminal {
 	link_list_t			notes;
 	sem_t				playnote_thread_terminated;
 	sem_t				note_completed_sem;
-	int					backpos;
+	int					backpos; // Position where new lines will be added
+	int					backstart; // First line of scrollback
 	int					xpos;
 	int					ypos;
 	cterm_log_t			log;
diff --git a/src/syncterm/bbslist.c b/src/syncterm/bbslist.c
index d36c0d98e92e1116bd2cf3db71e02e0a2702d873..a5ed0a160fe21c0aa765d393e2343d49f736cc66 100644
--- a/src/syncterm/bbslist.c
+++ b/src/syncterm/bbslist.c
@@ -368,6 +368,7 @@ viewofflinescroll(void)
 	struct  text_info  txtinfo;
 	struct  text_info  sbtxtinfo;
 	struct mouse_event mevent;
+	int scrollback_pos;
 
 	if (scrollback_buf == NULL)
 		return;
@@ -403,10 +404,11 @@ viewofflinescroll(void)
 	setfont(0, false, 4);
 	drawwin();
 	set_modepalette(palettes[COLOUR_PALETTE]);
-	top = scrollback_pos;
 	gotoxy(1, 1);
 	textattr(uifc.hclr | (uifc.bclr << 4) | BLINK);
 	gettextinfo(&sbtxtinfo);
+	scrollback_pos = scrollback_lines - sbtxtinfo.screenheight;
+	top = scrollback_pos;
 	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_START);
 	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_MOVE);
 	ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_END);
@@ -415,10 +417,10 @@ viewofflinescroll(void)
 	showmouse();
 
 	for (i = 0; !i && !quitting;) {
-		if (top < 1)
-			top = 1;
-		if (top > (int)scrollback_lines)
-			top = scrollback_lines;
+		if (top < 0)
+			top = 0;
+		if (top > scrollback_pos)
+			top = scrollback_pos;
 		vmem_puttext(((sbtxtinfo.screenwidth - scrollback_cols) / 2) + 1, 1,
 		    (sbtxtinfo.screenwidth - scrollback_cols) / 2 + scrollback_cols,
 		    sbtxtinfo.screenheight,
diff --git a/src/syncterm/menu.c b/src/syncterm/menu.c
index 7a0af78b6181dee128b28f2747e8e8ba1e2e6720..e17c5d2f4cd7047c5b21af508bac67e7ecf948d1 100644
--- a/src/syncterm/menu.c
+++ b/src/syncterm/menu.c
@@ -35,19 +35,25 @@ viewscroll(void)
         /* too large for alloca() */
 	scrollback =
 	    malloc((scrollback_buf
-	        == NULL ? 0 : (term.width * sizeof(*scrollback) * settings.backlines))
+	        == NULL ? 0 : (term.width * sizeof(*scrollback) * cterm->backlines))
 	        + (txtinfo.screenheight * txtinfo.screenwidth * sizeof(*scrollback)));
 	if (scrollback == NULL)
 		return;
-	memcpy(scrollback, cterm->scrollback, term.width * sizeof(*scrollback) * settings.backlines);
-	vmem_gettext(1, 1, txtinfo.screenwidth, txtinfo.screenheight, scrollback + (cterm->backpos) * cterm->width);
+	int lines = 0;
+	if (cterm->backstart > 0) {
+		lines = cterm->backlines - cterm->backstart;
+		memcpy(scrollback, cterm->scrollback + term.width * cterm->backstart, term.width * lines * sizeof(*scrollback));
+	}
+	memcpy(scrollback + term.width * lines, cterm->scrollback, term.width * sizeof(*scrollback) * cterm->backpos);
+	int sblines = cterm->backpos + lines;
+	vmem_gettext(1, 1, txtinfo.screenwidth, txtinfo.screenheight, scrollback + sblines * cterm->width);
 	savscrn = savescreen();
 	setfont(0, false, 1);
 	setfont(0, false, 2);
 	setfont(0, false, 3);
 	setfont(0, false, 4);
 	drawwin();
-	top = cterm->backpos;
+	top = sblines;
 	set_modepalette(palettes[COLOUR_PALETTE]);
 	gotoxy(1, 1);
 	textattr(uifc.hclr | (uifc.bclr << 4) | BLINK);
@@ -57,10 +63,10 @@ viewscroll(void)
 	ciomouse_addevent(CIOLIB_BUTTON_4_PRESS);
 	ciomouse_addevent(CIOLIB_BUTTON_5_PRESS);
 	for (i = 0; (!i) && (!quitting);) {
-		if (top < 1)
-			top = 1;
-		if (top > cterm->backpos)
-			top = cterm->backpos;
+		if (top < 0)
+			top = 0;
+		if (top > sblines)
+			top = sblines;
 		vmem_puttext(term.x - 1, term.y - 1, term.x + term.width - 2, term.y + term.height - 2,
 		    scrollback + (term.width * top));
 		cputs("Scrollback");
@@ -86,7 +92,7 @@ viewscroll(void)
 								break;
 							case CIOLIB_BUTTON_5_PRESS:
 								top++;
-								if (top > cterm->backpos)
+								if (top > sblines)
 									i = 1;
 								break;
 						}
diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c
index 3c7142bf2ccb5382b6d9f055dd31f32c4932fa4c..0e4e51902187028b8e2f2ba89bbaf664a8409e7a 100644
--- a/src/syncterm/syncterm.c
+++ b/src/syncterm/syncterm.c
@@ -143,7 +143,6 @@ struct syncterm_settings settings;
 char                    *font_names[sizeof(conio_fontdata) / sizeof(struct conio_font_data_struct)];
 struct vmem_cell        *scrollback_buf = NULL;
 unsigned int             scrollback_lines = 0;
-unsigned int             scrollback_pos = 0;
 unsigned int             scrollback_mode = C80;
 unsigned int             scrollback_cols = 80;
 int                      safe_mode = 0;
diff --git a/src/syncterm/syncterm.h b/src/syncterm/syncterm.h
index 5ca4a7565200bfa0d97ab606be1ecb56dc20b412..afb3e271172be667730c5c6c5be6597233abd085 100644
--- a/src/syncterm/syncterm.h
+++ b/src/syncterm/syncterm.h
@@ -86,10 +86,7 @@ extern char                    *inpath;
 extern char                    *list_override;
 extern const char              *syncterm_version;
 extern struct vmem_cell        *scrollback_buf;
-extern uint32_t                *scrollback_fbuf;
-extern uint32_t                *scrollback_bbuf;
 extern unsigned int             scrollback_lines;
-extern unsigned int             scrollback_pos;
 extern unsigned int             scrollback_mode;
 extern unsigned int             scrollback_cols;
 extern struct syncterm_settings settings;
diff --git a/src/syncterm/term.c b/src/syncterm/term.c
index 0264b3b4b624c94ed7d6f0a8b716d06d3e9ab93a..fb49a6c3cbcd068bb5603c0854ada60e4cd9f397 100644
--- a/src/syncterm/term.c
+++ b/src/syncterm/term.c
@@ -4080,6 +4080,43 @@ normalize_entry(struct bbslist *bbs)
 	}
 }
 
+static void
+finish_scrollback(void)
+{
+	scrollback_buf = cterm->scrollback;
+	scrollback_cols = cterm->backwidth;
+	// TODO: Set scrollback_mode here?
+	if (cterm->scrollback != NULL) {
+		cterm_clearscreen(cterm, cterm->attr); /* Clear screen into
+							* scrollback */
+
+		// Now make the scrollback a linear buffer instead of a ring buffer
+		if (cterm->backstart) {
+			struct vmem_cell     *bottom;
+			int topsz = cterm->backlines - cterm->backstart;
+
+			bottom = malloc(cterm->backwidth * cterm->backstart * sizeof(*bottom));
+			if (bottom) {
+				memcpy(bottom, cterm->scrollback, cterm->backwidth * cterm->backstart * sizeof(*bottom));
+				memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * cterm->backstart, cterm->backwidth * topsz * sizeof(*cterm->scrollback));
+				memcpy(cterm->scrollback + cterm->backwidth * topsz, bottom, cterm->backwidth * cterm->backstart * sizeof(*bottom));
+				free(bottom);
+				scrollback_lines = cterm->backlines;
+			}
+			else {
+				memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * cterm->backstart, cterm->backwidth * topsz * sizeof(*cterm->scrollback));
+				scrollback_lines = topsz;
+			}
+		}
+		else {
+			scrollback_lines = cterm->backpos;
+		}
+	}
+	else {
+		scrollback_lines = 0;
+	}
+}
+
 bool
 doterm(struct bbslist *bbs)
 {
@@ -4153,7 +4190,6 @@ doterm(struct bbslist *bbs)
 	else {
 		FREE_AND_NULL(scrollback_buf);
 	}
-	scrollback_lines = 0;
 	scrollback_mode = txtinfo.currmode;
 	cterm = cterm_init(term.height,
 	        term.width,
@@ -4173,7 +4209,6 @@ doterm(struct bbslist *bbs)
 	cterm->mouse_state_change_cbdata = &ms;
 	cterm->mouse_state_query = mouse_state_query;
 	cterm->mouse_state_query_cbdata = &ms;
-	scrollback_cols = term.width;
 	cterm->music_enable = bbs->music;
 	ch[1] = 0;
 	zrqbuf[0] = 0;
@@ -4218,10 +4253,7 @@ doterm(struct bbslist *bbs)
 								uifcmsg("Disconnected",
 								    "`Disconnected`\n\nRemote host dropped connection");
 							check_exit(false);
-							scrollback_pos = cterm->backpos;
-							cterm_clearscreen(cterm, cterm->attr); /* Clear screen into
-                                                                                                * scrollback */
-							scrollback_lines = cterm->backpos;
+							finish_scrollback();
 							cterm_end(cterm, 0);
 							cterm = NULL;
 							// TODO: Do this before the popup to avoid being rude...
@@ -4559,10 +4591,7 @@ doterm(struct bbslist *bbs)
 					    "Selecting Yes closes the connection\n")) {
 						freescreen(savscrn);
 						setup_mouse_events(&ms);
-						scrollback_pos = cterm->backpos;
-						cterm_clearscreen(cterm, cterm->attr); /* Clear screen into
-                                                                                        * scrollback */
-						scrollback_lines = cterm->backpos;
+						finish_scrollback();
 						cterm_end(cterm, 0);
 						cterm = NULL;
 						conn_close();
@@ -4591,10 +4620,7 @@ doterm(struct bbslist *bbs)
 					j = wherey();
 					switch (syncmenu(bbs, &speed)) {
 						case -1:
-							scrollback_pos = cterm->backpos;
-							cterm_clearscreen(cterm, cterm->attr); /* Clear screen into
-                                                                                                * scrollback */
-							scrollback_lines = cterm->backpos;
+							finish_scrollback();
 							cterm_end(cterm, 0);
 							cterm = NULL;
 							conn_close();
@@ -4640,10 +4666,7 @@ doterm(struct bbslist *bbs)
 							break;
 						case 13:
 #endif
-							scrollback_pos = cterm->backpos;
-							cterm_clearscreen(cterm, cterm->attr); /* Clear screen into
-                                                                                                * scrollback */
-							scrollback_lines = cterm->backpos;
+							finish_scrollback();
 							cterm_end(cterm, 0);
 							cterm = NULL;
 							conn_close();
@@ -5089,5 +5112,6 @@ doterm(struct bbslist *bbs)
  *       hidemouse();
  *       hold_update=oldmc;
  */
+	finish_scrollback();
 	return false;
 }