From 02f0f87f95c7f47a93d20de9478bf0b2d5c6e4e6 Mon Sep 17 00:00:00 2001
From: Oz Linden <oz@lindenlab.com>
Date: Thu, 14 Jun 2012 21:21:42 -0400
Subject: [PATCH] STORM-1880: copy imported dictionary files rather than moving
 them

---
 indra/newview/llfloaterspellchecksettings.cpp | 124 +++++++++++++-----
 indra/newview/llfloaterspellchecksettings.h   |   1 +
 .../skins/default/xui/en/notifications.xml    |  11 ++
 3 files changed, 105 insertions(+), 31 deletions(-)

diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp
index 5116ec50a6a..758ac23b4c2 100644
--- a/indra/newview/llfloaterspellchecksettings.cpp
+++ b/indra/newview/llfloaterspellchecksettings.cpp
@@ -35,6 +35,7 @@
 #include "llspellcheck.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
+#include "llnotificationsutil.h"
 
 #include <boost/algorithm/string.hpp>
 
@@ -291,47 +292,108 @@ void LLFloaterSpellCheckerImport::onBtnOK()
 		return;
 	}
 
-	LLSD custom_dict_info;
-	custom_dict_info["is_primary"] = (bool)gDirUtilp->fileExists(dict_aff);
-	custom_dict_info["name"] = mDictionaryBasename;
-	custom_dict_info["language"] = dict_language;
-
-	LLSD custom_dict_map;
-	llifstream custom_file_in(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml");
-	if (custom_file_in.is_open())
+	bool imported = false;
+	std::string settings_dic = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic";
+	if ( copyFile( dict_dic, settings_dic ) )
 	{
-		LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file_in);
-		custom_file_in.close();
-	}
-	
-	LLSD::array_iterator it = custom_dict_map.beginArray();
-	for (; it != custom_dict_map.endArray(); ++it)
-	{
-		LLSD& dict_info = *it;
-		if (dict_info["name"].asString() == mDictionaryBasename)
+		if (gDirUtilp->fileExists(dict_aff))
+		{
+			std::string settings_aff = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff";
+			if (copyFile( dict_aff, settings_aff ))
+			{
+				imported = true;
+			}
+			else
+			{
+				LLSD args = LLSD::emptyMap();
+				args["FROM_NAME"] = dict_aff;
+				args["TO_NAME"] = settings_aff;
+				LLNotificationsUtil::add("SpellingDictImportFailed", args);
+			}
+		}
+		else
 		{
-			dict_info = custom_dict_info;
-			break;
+			imported = true;
 		}
 	}
-	if (custom_dict_map.endArray() == it)
+	else
 	{
-		custom_dict_map.append(custom_dict_info);
+		LLSD args = LLSD::emptyMap();
+		args["FROM_NAME"] = dict_dic;
+		args["TO_NAME"] = settings_dic;
+		LLNotificationsUtil::add("SpellingDictImportFailed", args);
 	}
 
-	llofstream custom_file_out(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml", std::ios::trunc);
-	if (custom_file_out.is_open())
+	if ( imported )
 	{
-		LLSDSerialize::toPrettyXML(custom_dict_map, custom_file_out);
-		custom_file_out.close();
-	}
+		LLSD custom_dict_info;
+		custom_dict_info["is_primary"] = (bool)gDirUtilp->fileExists(dict_aff);
+		custom_dict_info["name"] = mDictionaryBasename;
+		custom_dict_info["language"] = dict_language;
+
+		LLSD custom_dict_map;
+		llifstream custom_file_in(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml");
+		if (custom_file_in.is_open())
+		{
+			LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file_in);
+			custom_file_in.close();
+		}
+	
+		LLSD::array_iterator it = custom_dict_map.beginArray();
+		for (; it != custom_dict_map.endArray(); ++it)
+		{
+			LLSD& dict_info = *it;
+			if (dict_info["name"].asString() == mDictionaryBasename)
+			{
+				dict_info = custom_dict_info;
+				break;
+			}
+		}
+		if (custom_dict_map.endArray() == it)
+		{
+			custom_dict_map.append(custom_dict_info);
+		}
 
-	LLFile::rename(dict_dic, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic");
-	if (gDirUtilp->fileExists(dict_aff))
-	{
-		LLFile::rename(dict_aff, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff");
+		llofstream custom_file_out(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml", std::ios::trunc);
+		if (custom_file_out.is_open())
+		{
+			LLSDSerialize::toPrettyXML(custom_dict_map, custom_file_out);
+			custom_file_out.close();
+		}
+
+		LLSpellChecker::refreshDictionaryMap();
 	}
-	LLSpellChecker::refreshDictionaryMap();
 
 	closeFloater(false);
 }
+
+bool LLFloaterSpellCheckerImport::copyFile(const std::string from, const std::string to)
+{
+	bool copied = false;
+	LLFILE* in = LLFile::fopen(from, "rb");		/* Flawfinder: ignore */	 	
+	if (in)	 	
+	{	 	
+		LLFILE* out = LLFile::fopen(to, "wb");		/* Flawfinder: ignore */
+		if (out)
+		{
+			char buf[16384];		/* Flawfinder: ignore */ 	
+			size_t readbytes;
+			bool write_ok = true;
+			while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
+			{
+				if (fwrite(buf, 1, readbytes, out) != readbytes)
+				{
+					LL_WARNS("SpellCheck") << "Short write" << LL_ENDL; 
+					write_ok = false;
+				}
+			}
+			if ( write_ok )
+			{
+				copied = true;
+			}
+			fclose(out);
+		}
+	}
+	fclose(in);
+	return copied;
+}
diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h
index 4bc68e2a884..8c4ac22bc67 100644
--- a/indra/newview/llfloaterspellchecksettings.h
+++ b/indra/newview/llfloaterspellchecksettings.h
@@ -58,6 +58,7 @@ class LLFloaterSpellCheckerImport : public LLFloater
 	void onBtnBrowse();
 	void onBtnCancel();
 	void onBtnOK();
+	bool copyFile(const std::string from, const std::string to);
 
 	std::string mDictionaryDir;
 	std::string mDictionaryBasename;
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index bc69e973ed6..c04e33fe8e5 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2396,6 +2396,17 @@ Would you be my friend?
     <tag>fail</tag>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="SpellingDictImportFailed"
+   type="alertmodal">
+    Unable to copy
+    [FROM_NAME]
+    to
+    [TO_NAME]
+    <tag>fail</tag>
+  </notification>
+
   <notification
  icon="alertmodal.tga"
  label="Save Outfit"
-- 
GitLab