Scott Lawrence avatar Scott Lawrence committed b636009

STORM-1880: copy imported dictionary files rather than moving them

Comments (0)

Files changed (3)

indra/newview/llfloaterspellchecksettings.cpp

 #include "llspellcheck.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
+#include "llnotificationsutil.h"
 
 #include <boost/algorithm/string.hpp>
 
 		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))
 		{
-			dict_info = custom_dict_info;
-			break;
+			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
+		{
+			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);
+		}
+
+		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();
 	}
 
-	LLFile::rename(dict_dic, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic");
-	if (gDirUtilp->fileExists(dict_aff))
-	{
-		LLFile::rename(dict_aff, LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff");
-	}
-	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;
+}

indra/newview/llfloaterspellchecksettings.h

 	void onBtnBrowse();
 	void onBtnCancel();
 	void onBtnOK();
+	bool copyFile(const std::string from, const std::string to);
 
 	std::string mDictionaryDir;
 	std::string mDictionaryBasename;

indra/newview/skins/default/xui/en/notifications.xml

   </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"
  name="SaveOutfitAs"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.