diff --git a/exec/SlyEdit.js b/exec/SlyEdit.js
index b5e54e5a502ca98aadfee80b44a56d1db00e6acc..1c8ac669acf26082ef06428f976cdc2245da46e5 100644
--- a/exec/SlyEdit.js
+++ b/exec/SlyEdit.js
@@ -93,6 +93,11 @@
  *                              terminals send a delete for backspace, particularly
  *                              with keyboards that have a delete key but no backspace
  *                              key.
+ * 2019-08-15 Eric Oulashin     Version 1.70
+ *                              Fix for a bug introduced in the flowing-line update in 1.68
+ *                              where some quote blocks were sometimes not being included when
+ *                              saving a message.  Also, quote lines are now wrapped
+ *                              to the user's terminal width rather than 80 columns.
  */
 
 /* Command-line arguments:
@@ -189,8 +194,8 @@ if (console.screen_columns < 80)
 }
 
 // Constants
-const EDITOR_VERSION = "1.69";
-const EDITOR_VER_DATE = "2019-08-14";
+const EDITOR_VERSION = "1.70";
+const EDITOR_VER_DATE = "2019-08-15";
 
 
 // Program variables
@@ -2789,7 +2794,8 @@ function doQuoteSelection(pCurpos, pCurrentWordLength)
 			gQuoteLinesTopIndex = 0;
 
 			// Update the quote line prefix text and wrap the quote lines
-			var maxQuoteLineLength = 79;
+			//var maxQuoteLineLength = 79;
+			var maxQuoteLineLength = console.screen_columns - 1;
 			setQuotePrefix();
 			if (gConfigSettings.reWrapQuoteLines)
 			{
diff --git a/exec/SlyEdit_Misc.js b/exec/SlyEdit_Misc.js
index c6be665c2ffe6674f3849628b96cc0e2ee5d5d48..0e1ef66016ed61b409caed89e7f2b24d05690f5a 100644
--- a/exec/SlyEdit_Misc.js
+++ b/exec/SlyEdit_Misc.js
@@ -4884,8 +4884,6 @@ function centeredText(pWidth, pText)
 //               end: One past the end index of the non-quote block
 function findNonQuoteBlockIndexes(pTextLines)
 {
-	// TODO: findQuoteAndNonQuoteBlockIndexes() isn't identifying non-quote
-	// blocks when there is a single line in a non-quote block.
 	if (typeof(pTextLines) != "object")
 		return [];
 	if (pTextLines.length == 0)
@@ -4921,6 +4919,59 @@ function findNonQuoteBlockIndexes(pTextLines)
 	return nonQuoteBlockIdxes;
 }
 
+// Finds start & end indexes of quote blocks in the message lines.
+//
+// Parameters:
+//  pTextLines: The array of message lines
+//
+// Return value: An array of objects containing the following properties:
+//               start: The start index of a non-quote block
+//               end: One past the end index of the non-quote block
+//               prefix: The string prefix for the quote block
+function findQuoteBlockIndexes(pTextLines)
+{
+	if (typeof(pTextLines) != "object")
+		return [];
+	if (pTextLines.length == 0)
+		return [];
+	// Edge case: If there's only one line and if it's a quote block, then
+	// return an array with an element about it.
+	else if (pTextLines.length == 1)
+		return (pTextLines[0].isQuoteLine ? [{ start: 0, end: 1}] : []);
+
+	var quoteBlockIdxes = [];
+	var startIdx = 0;
+	var lastEndIdx = 0;
+	var inQuoteBlock = pTextLines[0].isQuoteLine;
+	for (var i = 1; i < pTextLines.length; ++i)
+	{
+		if (pTextLines[i].isQuoteLine != inQuoteBlock)
+		{
+			if (!pTextLines[i].isQuoteLine)
+			{
+				quoteBlockIdxes.push({ start: startIdx, end: i });
+				lastEndIdx = i;
+			}
+			else
+				startIdx = i;
+			inQuoteBlock = pTextLines[i].isQuoteLine;
+		}
+	}
+	// Edge case: If the last line in the array is a quote block, then ensure
+	// the last non-quote block is added to quoteBlockIdxes
+	if (pTextLines[pTextLines.length-1].isQuoteLine)
+		quoteBlockIdxes.push({ start: startIdx, end: pTextLines.length });
+
+	// Find the common prefixes in each quote block
+	for (var quoteBlockI = 0; quoteBlockI < quoteBlockIdxes.length; ++quoteBlockI)
+	{
+		var linePrefix = commonEditLinesPrefix(pTextLines, quoteBlockIdxes[quoteBlockI].start, quoteBlockIdxes[quoteBlockI].end, ">", true);
+		quoteBlockIdxes[quoteBlockI].prefix = linePrefix;
+	}
+
+	return quoteBlockIdxes;
+}
+
 // Finds start & end indexes of quote blocks and non-quote blocks in the message lines.
 //
 // Parameters:
@@ -4930,6 +4981,7 @@ function findNonQuoteBlockIndexes(pTextLines)
 //               quoteBlocks: An array of objects containing the following properties:
 //                            start: The start index of a quote block
 //                            end: One past the end index of the quote block
+//                            prefix: The string prefix for the quote block
 //               nonQuoteBlocks: An array of objects containing the following properties:
 //                               start: The start index of a non-quote block
 //                               end: One past the end index of the non-quote block
@@ -4941,46 +4993,15 @@ function findNonQuoteBlockIndexes(pTextLines)
 function findQuoteAndNonQuoteBlockIndexes(pTextLines)
 {
 	var retObj = {
-		quoteBlocks: [],
+		quoteBlocks: findQuoteBlockIndexes(pTextLines),
 		nonQuoteBlocks: findNonQuoteBlockIndexes(pTextLines),
 		allBlocks: []
 	};
 
-	// Edge case: If there's only one line and if it's a quote block, then
-	// return an array with an element about it.
-	if (pTextLines.length == 1)
-	{
-		if (pTextLines[0].isQuoteLine)
-		{
-			retObj.quoteBlocks.push({ start: 0, end: 1});
-			retObj.allBlocks.push({ isQuoteBlock: true, start: 0, end: 1});
-		}
-		else
-			retObj.allBlocks.push({ isQuoteBlock: false, start: retObj.nonQuoteBlocks[0].start, end: retObj.nonQuoteBlocks[0].end});
-		return retObj;
-	}
-
-	for (var nonQuoteBlockI = 0; nonQuoteBlockI < retObj.nonQuoteBlocks.length; ++nonQuoteBlockI)
-	{
-		if ((nonQuoteBlockI == 0) && (retObj.nonQuoteBlocks[nonQuoteBlockI].start > 0))
-			retObj.quoteBlocks.push({start: 0, end: retObj.nonQuoteBlocks[nonQuoteBlockI].start});
-		else if (nonQuoteBlockI < retObj.nonQuoteBlocks.length - 1)
-		{
-			var nextI = nonQuoteBlockI + 1;
-			//retObj.quoteBlocks.push({start: retObj.nonQuoteBlocks[nonQuoteBlockI].end+1, end: retObj.nonQuoteBlocks[nextI].start});
-			retObj.quoteBlocks.push({start: retObj.nonQuoteBlocks[nonQuoteBlockI].end, end: retObj.nonQuoteBlocks[nextI].start});
-		}
-		else if (nonQuoteBlockI == retObj.nonQuoteBlocks.length - 1)
-		{
-			if (retObj.nonQuoteBlocks[nonQuoteBlockI].end < pTextLines.length)
-				retObj.quoteBlocks.push({start: retObj.nonQuoteBlocks[nonQuoteBlockI].end+1, end: pTextLines.length});
-		}
-	}
-
 	// Go through both the quote and non-quote blocks and populate allBlocks.
 	// Then sort allBlocks (by start index, which should be goood enough to sort with).
 	for (var i = 0; i < retObj.quoteBlocks.length; ++i)
-		retObj.allBlocks.push({ isQuoteBlock: true, start: retObj.quoteBlocks[i].start, end: retObj.quoteBlocks[i].end });
+		retObj.allBlocks.push({ isQuoteBlock: true, start: retObj.quoteBlocks[i].start, end: retObj.quoteBlocks[i].end, prefix: retObj.quoteBlocks[i].prefix });
 	for (var i = 0; i < retObj.nonQuoteBlocks.length; ++i)
 		retObj.allBlocks.push({ isQuoteBlock: false, start: retObj.nonQuoteBlocks[i].start, end: retObj.nonQuoteBlocks[i].end });
 	retObj.allBlocks.sort(function(obj1, obj2) {
@@ -4997,6 +5018,86 @@ function findQuoteAndNonQuoteBlockIndexes(pTextLines)
 	return retObj;
 }
 
+function commonPrefixUtil(pStr1, pStr2)
+{
+	var result = "";
+
+	var n1 = pStr1.length;
+	var n2 = pStr2.length;
+
+	for (var i = 0, j = 0; (i <= n1 - 1) && (j <= n2 - 1); ++i, ++j)
+	{
+		if (pStr1.charAt(i) != pStr2.charAt(j))
+			break;
+		else
+			result += pStr1.charAt(i);
+	}
+
+	return result;
+}
+
+function commonPrefix(pStringArr, pLastPrefixChar, lastCharShouldBeSpace)
+{
+	if (pStringArr.length == 0)
+		return "";
+
+	var prefix = pStringArr[0];
+	for (var i = 1; i < pStringArr.length; ++i)
+		prefix = commonPrefixUtil(prefix, pStringArr[i]);
+
+	if (typeof(pLastPrefixChar) == "string")
+	{
+		var idx = prefix.lastIndexOf(pLastPrefixChar);
+		if (idx > -1)
+			prefix = prefix.substr(0, idx+1);
+	}
+
+	if ((prefix.length > 0) && lastCharShouldBeSpace)
+	{
+		if (prefix.charAt(prefix.length-1) != " ")
+			prefix += " ";
+	}
+
+	return prefix;
+}
+
+function commonEditLinesPrefix(pEditLines, pStartIdx, pEndIdx, pLastPrefixChar, lastCharShouldBeSpace)
+{
+	if (pEditLines.length == 0)
+		return "";
+
+	if ((pStartIdx < 0) || (pStartIdx >= pEditLines.length) || (pEndIdx < 0) || (pEndIdx >= pEditLines.length))
+		return "";
+
+	// Look for the first non-blank line and set that as the prefix
+	var prefix = "";
+	for (var i = pStartIdx; (i < pEndIdx) && (prefix.length == 0); ++i)
+	{
+		if (pEditLines[i].text.length > 0)
+			prefix = pEditLines[i].text;
+	}
+	for (var i = pStartIdx+1; i < pEndIdx; ++i)
+	{
+		if (pEditLines[i].text.length > 0)
+			prefix = commonPrefixUtil(prefix, pEditLines[i].text);
+	}
+
+	if (typeof(pLastPrefixChar) == "string")
+	{
+		var idx = prefix.lastIndexOf(pLastPrefixChar);
+		if (idx > -1)
+			prefix = prefix.substr(0, idx+1);
+	}
+
+	if ((prefix.length > 0) && lastCharShouldBeSpace)
+	{
+		if (prefix.charAt(prefix.length-1) != " ")
+			prefix += " ";
+	}
+
+	return prefix;
+}
+
 // This function displays debug text at a given location on the screen, then
 // moves the cursor back to a given location.
 //