diff --git a/PwTech.cbproj b/PwTech.cbproj
index 8ef8d09..af7f911 100644
--- a/PwTech.cbproj
+++ b/PwTech.cbproj
@@ -161,13 +161,13 @@
graphics\pwtech.ico
LUA_INT_TYPE=1;$(Defines)
3
- CompanyName=;FileDescription=Password Tech executable;FileVersion=3.5.4.0;InternalName=;LegalCopyright=Copyright 2002-2023 by Christian Thöing;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=Password Tech;ProductVersion=3.5.4;Comments=
+ CompanyName=;FileDescription=Password Tech executable;FileVersion=3.5.5.0;InternalName=;LegalCopyright=Copyright 2002-2023 by Christian Thöing;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=Password Tech;ProductVersion=3.5.5;Comments=
PerMonitorV2
false
5
Debug
true
- 4
+ 5
false
true
@@ -176,7 +176,7 @@
$(BDS)\bin\default_app.manifest
PerMonitorV2
true
- pwtech.ico
+ PwTech_Icon.ico
3
5
false
@@ -184,10 +184,34 @@
Debug
true
false
- 4
- CompanyName=;FileDescription=Password Tech executable;FileVersion=3.5.4.0;InternalName=;LegalCopyright=Copyright (c) 2002-2024 Christian Thöing;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=3.5.4;Comments=
+ 5
+ CompanyName=;FileDescription=Password Tech executable;FileVersion=3.5.5.0;InternalName=;LegalCopyright=Copyright (c) 2002-2024 Christian Thöing;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=3.5.5;Comments=
+
+ ICON
+ A
+
+
+ ICON
+ Icon_Blue
+
+
+ ICON
+ Icon_Colors
+
+
+ ICON
+ Icon_Green
+
+
+ ICON
+ Icon_Orange
+
+
+ ICON
+ Icon_Red
+
0
@@ -564,25 +588,25 @@
90
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
+
+
-
+
+
+
+
@@ -700,8 +724,50 @@
+
+
+ PwTech.exe
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
+
+
+ .\
+ true
+
+
diff --git a/PwTech.cpp b/PwTech.cpp
index 2309ef4..207eb16 100644
--- a/PwTech.cpp
+++ b/PwTech.cpp
@@ -10,25 +10,25 @@
//---------------------------------------------------------------------------
#include
#include
-USEFORM("src\main\PasswManager.cpp", PasswMngForm);
-USEFORM("src\main\PasswMngColSelect.cpp", PasswMngColDlg);
-USEFORM("src\main\PasswMngDbProp.cpp", PasswMngDbPropDlg);
-USEFORM("src\main\MPPasswGen.cpp", MPPasswGenForm);
USEFORM("src\main\PasswEnter.cpp", PasswEnterDlg);
USEFORM("src\main\PasswList.cpp", PasswListForm);
-USEFORM("src\main\PasswOptions.cpp", PasswOptionsDlg);
-USEFORM("src\main\ProfileEditor.cpp", ProfileEditDlg);
-USEFORM("src\main\Progress.cpp", ProgressForm);
-USEFORM("src\main\PasswMngDbSettings.cpp", PasswDbSettingsDlg);
+USEFORM("src\main\PasswManager.cpp", PasswMngForm);
+USEFORM("src\main\Main.cpp", MainForm);
+USEFORM("src\main\MPPasswGen.cpp", MPPasswGenForm);
USEFORM("src\main\PasswMngKeyValEdit.cpp", PasswMngKeyValDlg);
USEFORM("src\main\PasswMngPwHistory.cpp", PasswHistoryDlg);
-USEFORM("src\main\About.cpp", AboutForm);
-USEFORM("src\main\CharSetBuilder.cpp", CharSetBuilderForm);
+USEFORM("src\main\PasswOptions.cpp", PasswOptionsDlg);
+USEFORM("src\main\PasswMngColSelect.cpp", PasswMngColDlg);
+USEFORM("src\main\PasswMngDbProp.cpp", PasswMngDbPropDlg);
+USEFORM("src\main\PasswMngDbSettings.cpp", PasswDbSettingsDlg);
USEFORM("src\main\InfoBox.cpp", InfoBoxForm);
-USEFORM("src\main\Main.cpp", MainForm);
USEFORM("src\main\Configuration.cpp", ConfigurationDlg);
USEFORM("src\main\CreateRandDataFile.cpp", CreateRandDataFileDlg);
USEFORM("src\main\CreateTrigramFile.cpp", CreateTrigramFileDlg);
+USEFORM("src\main\About.cpp", AboutForm);
+USEFORM("src\main\CharSetBuilder.cpp", CharSetBuilderForm);
+USEFORM("src\main\ProfileEditor.cpp", ProfileEditDlg);
+USEFORM("src\main\Progress.cpp", ProgressForm);
USEFORM("src\main\ProvideEntropy.cpp", ProvideEntropyDlg);
USEFORM("src\main\QuickHelp.cpp", QuickHelpForm);
//---------------------------------------------------------------------------
@@ -144,6 +144,18 @@ int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
if (g_sAppDataPath.IsEmpty())
g_sAppDataPath = g_sExePath;
+ AnsiString asDonorKey = g_pIni->ReadString("Main", "DonorKey", "");
+ if (!asDonorKey.IsEmpty()) {
+ auto result = CheckDonorKey(asDonorKey);
+
+ g_donorInfo.Valid = std::get<0>(result);
+ if (g_donorInfo.Valid == DONOR_KEY_VALID) {
+ g_donorInfo.Key = asDonorKey.Trim();
+ g_donorInfo.Id = std::get<2>(result);
+ g_donorInfo.Type = std::get<1>(result);
+ }
+ }
+
const WString DEFAULT_STYLE_NAME = "Windows";
g_config.UiStyleName = DEFAULT_STYLE_NAME;
@@ -155,6 +167,19 @@ int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
g_config.UiStyleName = sStyleName;
}
+ WString sAppIconName = g_pIni->ReadString("Main", "AppIcon", WString());
+ if (!sAppIconName.IsEmpty() && g_donorInfo.Valid == DONOR_KEY_VALID) {
+ auto it = std::find_if(AppIconNames.begin(), AppIconNames.end(),
+ [&sAppIconName](const std::pair& p)
+ { return p.first == sAppIconName; });
+ if (it != AppIconNames.end()) {
+ g_config.AppIconName = sAppIconName;
+ if (it != AppIconNames.begin())
+ Application->Icon->LoadFromResourceName(reinterpret_cast(
+ HInstance), it->second);
+ }
+ }
+
Application->CreateForm(__classid(TMainForm), &MainForm);
Application->CreateForm(__classid(TAboutForm), &AboutForm);
Application->CreateForm(__classid(TConfigurationDlg), &ConfigurationDlg);
diff --git a/PwTech_resources.rc b/PwTech_resources.rc
new file mode 100644
index 0000000..32f253e
--- /dev/null
+++ b/PwTech_resources.rc
@@ -0,0 +1,6 @@
+A ICON "graphics\\pwtech_default.ico"
+Icon_Blue ICON "graphics\\pwtech_icon_blue.ico"
+Icon_Colors ICON "graphics\\pwtech_icon_colored.ico"
+Icon_Green ICON "graphics\\pwtech_icon_green.ico"
+Icon_Orange ICON "graphics\\pwtech_icon_orange.ico"
+Icon_Red ICON "graphics\\pwtech_icon_red.ico"
diff --git a/changes.txt b/changes.txt
index 6f79bda..4347f78 100644
--- a/changes.txt
+++ b/changes.txt
@@ -3,7 +3,32 @@
Copyright (c) 2002-2024 by Christian Thöing
-Version 3.5.4
+Version 3.5.5
+
+NEW FEATURES:
+
+- Advanced Password Options: New option "Remove leading and trailing whitespace
+ characters" to remove space and tab characters at the beginning and end of
+ passwords
+- Configuration | General: New option "Application icon" to change PwTech's
+ icon displayed on the task bar, system tray, etc. during runtime
+- Configuration | Language: New "Install" and "Remove" buttons to add or
+ remove language files to/from the current PwTech installation
+
+CHANGES & IMPROVEMENTS:
+
+- Language files can also be copied to the "AppData" folder (usually
+ "C:\Users\{user}\AppData\Roaming\Password Tech"), which makes it easier
+ to install new languages if PwTech has been installed to the "Program Files"
+ folder (which usually requires admin privileges for write access)
+
+FIXES:
+
+- PO language files with empty fields in header not loaded properly
+
+----------
+
+Version 3.5.4 (2024-02-14)
NEW FEATURES:
diff --git a/graphics/pwtech_default.ico b/graphics/pwtech_default.ico
new file mode 100644
index 0000000..a6f821f
Binary files /dev/null and b/graphics/pwtech_default.ico differ
diff --git a/graphics/pwtech_icon_blue.ico b/graphics/pwtech_icon_blue.ico
new file mode 100644
index 0000000..64ab128
Binary files /dev/null and b/graphics/pwtech_icon_blue.ico differ
diff --git a/graphics/pwtech_icon_colored.ico b/graphics/pwtech_icon_colored.ico
new file mode 100644
index 0000000..2479247
Binary files /dev/null and b/graphics/pwtech_icon_colored.ico differ
diff --git a/graphics/pwtech_icon_green.ico b/graphics/pwtech_icon_green.ico
new file mode 100644
index 0000000..adb8ee9
Binary files /dev/null and b/graphics/pwtech_icon_green.ico differ
diff --git a/graphics/pwtech_icon_orange.ico b/graphics/pwtech_icon_orange.ico
new file mode 100644
index 0000000..4106de3
Binary files /dev/null and b/graphics/pwtech_icon_orange.ico differ
diff --git a/graphics/pwtech_icon_red.ico b/graphics/pwtech_icon_red.ico
new file mode 100644
index 0000000..38605d3
Binary files /dev/null and b/graphics/pwtech_icon_red.ico differ
diff --git a/languages/English.pot b/languages/English.pot
index dad0a5e..994a3b8 100644
--- a/languages/English.pot
+++ b/languages/English.pot
@@ -15,10 +15,9 @@
# for floating point numbers, "%s" for strings, etc.), and the original strings
# are still provided in the old format to avoid merge conflicts when updating
# existing translations.
-
msgid ""
msgstr ""
-"Project-Id-Version: Password Tech 3.5.4\n"
+"Project-Id-Version: Password Tech 3.5.5\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
@@ -1016,6 +1015,10 @@ msgstr ""
msgid "User interface style:"
msgstr ""
+#. Configuration window, General
+msgid "Application icon:"
+msgstr ""
+
#. Configuration window, General
msgid "Change font for the GUI controls:"
msgstr ""
@@ -1192,6 +1195,52 @@ msgstr ""
msgid "Select language:"
msgstr ""
+#. Configuration window, Language
+msgid "Install..."
+msgstr ""
+
+#. Configuration window, Language, Install
+msgid "Language already installed"
+msgstr ""
+
+#. Configuration window, Language, Install
+msgid ""
+"Language file already exists:\n"
+"\"%1\""
+msgstr ""
+
+#. Configuration window, Language, Install
+msgid "Language \"%1\" installed successfully."
+msgstr ""
+
+#. Configuration window, Language, Install
+msgid ""
+"Could not copy file \"%1\" to\n"
+"\"%2\""
+msgstr ""
+
+#. Configuration window, Language, Install
+msgid ""
+"Could not install language:\n"
+"%1."
+msgstr ""
+
+#. Configuration window, Language, Remove
+msgid ""
+"Are you sure you want to remove\n"
+"\"%1\"?"
+msgstr ""
+
+#. Configuration window, Language, Remove
+msgid "Language \"%1\" successfully removed."
+msgstr ""
+
+#. Configuration window, Language, Remove
+msgid ""
+"Could not delete file\n"
+"\"%1\"."
+msgstr ""
+
#. Configuration window, Database
msgid "Clear clipboard when closing/locking database"
msgstr ""
@@ -1413,6 +1462,10 @@ msgstr ""
msgid "Exclude repeating consecutive characters (e.g. aa, 11)"
msgstr ""
+#. Advanced Password Options window, list of boolean options (checkboxes)
+msgid "Remove leading and trailing whitespace characters"
+msgstr ""
+
#. Advanced Password Options window, list of boolean options (checkboxes)
msgid "Exclude duplicate entries in password lists"
msgstr ""
diff --git a/languages/German.po b/languages/German.po
index 5404f29..ac8ca02 100644
--- a/languages/German.po
+++ b/languages/German.po
@@ -1,4 +1,4 @@
-# German translation of Password Tech 3.5.3
+# German translation of Password Tech 3.5.5
# Released under the GNU General Public License
#
# !!! NOTE ON FORMAT STRINGS !!!
@@ -20,7 +20,7 @@
#. Add header entry "X-PasswordTech-Manual: ..." to provide language-specific manual
msgid ""
msgstr ""
-"Project-Id-Version: Password Tech 3.5.4\n"
+"Project-Id-Version: Password Tech 3.5.5\n"
"Last-Translator: Christian Thöing\n"
"Language: de\n"
@@ -1136,6 +1136,10 @@ msgstr "Datenbank"
msgid "User interface style:"
msgstr "Stil der Benutzeroberfläche:"
+#. Configuration window, General
+msgid "Application icon:"
+msgstr "Programm-Symbol:"
+
#. Configuration window, General
msgid "Change font for the GUI controls:"
msgstr "Schriftart für GUI-Steuerelemente ändern:"
@@ -1312,6 +1316,42 @@ msgstr "Zeichensequenz für Zeilenumbruch (\"newline\")"
msgid "Select language:"
msgstr "Sprache auswählen:"
+#. Configuration window, Language
+msgid "Install..."
+msgstr "Installieren..."
+
+#. Configuration window, Language, Install
+msgid "Language already installed"
+msgstr "Sprache bereits installiert"
+
+#. Configuration window, Language, Install
+msgid "Language file already exists:\n\"%1\""
+msgstr "Sprachdatei existiert bereits:\n"%1\""
+
+#. Configuration window, Language, Install
+msgid "Language \"%1\" installed successfully."
+msgstr "Sprache \"%1\" erfolgreich installiert."
+
+#. Configuration window, Language, Install
+msgid "Could not copy file \"%1\" to\n\"%2\""
+msgstr "Konnte Datei \"%1\" nicht kopieren nach\n\"%2\""
+
+#. Configuration window, Language, Install
+msgid "Could not install language:\n%1."
+msgstr "Konnte Sprache nicht installieren:\n%1."
+
+#. Configuration window, Language, Remove
+msgid "Are you sure you want to remove\n\"%1\"?"
+msgstr "Sind Sie sicher, dass Sie\n\"%1\" entfernen möchten?"
+
+#. Configuration window, Language, Remove
+msgid "Language \"%1\" successfully removed."
+msgstr "Sprache \"%1\" erfolgreich entfernt."
+
+#. Configuration window, Language, Remove
+msgid "Could not delete file\n\"%1\"."
+msgstr "Konnte Datei nicht löschen:\n\"%1\"."
+
#. Configuration window, Database
msgid "Clear clipboard when closing/locking database"
msgstr "Zwischenablage löschen, wenn Datenbank geschlossen/gesperrt wird"
@@ -1538,6 +1578,10 @@ msgstr "Nur Zeichen aus benutzerdefiniertem Zeichensatz verwenden"
msgid "Exclude repeating consecutive characters (e.g. aa, 11)"
msgstr "Folge desselben Zeichens ausschließen (z.B. aa, 11)"
+#. Advanced Password Options window, list of boolean options (checkboxes)
+msgid "Remove leading and trailing whitespace characters"
+msgstr "Leerraum- (whitespace) Zeichen am Anfang und Ende entfernen"
+
#. Advanced Password Options window, list of boolean options (checkboxes)
msgid "Exclude duplicate entries in password lists"
msgstr "Doppelte Einträge in Passwort-Listen ausschließen"
diff --git a/manual/manual.odt b/manual/manual.odt
index ff63a79..55ad014 100644
Binary files a/manual/manual.odt and b/manual/manual.odt differ
diff --git a/setup/PWTech.iss b/setup/PWTech.iss
index f3c12e9..d68033a 100644
--- a/setup/PWTech.iss
+++ b/setup/PWTech.iss
@@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Password Tech"
-#define MyAppVersion "3.5.4"
+#define MyAppVersion "3.5.5"
#define MyAppPublisher "Christian Thöing"
#define MyAppURL "http://pwgen-win.sourceforge.net"
#define MyAppExeName "PwTech.exe"
@@ -62,7 +62,7 @@ Source: "C:\Projekte\PWGen3\manual\scripting.pdf"; DestDir: "{app}"; Flags: igno
Source: "C:\Projekte\PWGen3\license.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Projekte\PWGen3\common_passwords.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Projekte\PWGen3\changes.txt"; DestDir: "{app}"; Flags: ignoreversion
-Source: "C:\Projekte\PWGen3\Win64\Release\German.po"; DestDir: "{app}"; Flags: ignoreversion
+Source: "C:\Projekte\PWGen3\German.po"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
diff --git a/src/crypto/CryptText.cpp b/src/crypto/CryptText.cpp
index 45efc98..3369172 100644
--- a/src/crypto/CryptText.cpp
+++ b/src/crypto/CryptText.cpp
@@ -60,7 +60,8 @@ static void initCrypto(aes_context* pCryptCtx,
if (nVersion == 0) {
derivedKey.Zeroize();
- memcpy(derivedKey, pSalt, 16);
+ //memcpy(derivedKey, pSalt, 16);
+ derivedKey.Copy(0, pSalt, 16);
// hash the salt and the key together 8192 times
for (int i = 0; i < 8192; i++) {
@@ -119,9 +120,9 @@ int EncryptText(const SecureWString* psText,
word32 lBufSize = HEADER_SIZE + lTextLen + lTextLen / 16 + 64 + 3 + HMAC_LENGTH;
// ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// header security margins for compression
- lBufSize = 16 + 16 * ((lBufSize + 15) / 16);
- // ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // IV adjust to blocklength
+ lBufSize = 16 + alignToBlockSize(lBufSize, 16);
+ // ^^
+ // IV
// allocate some memory for the output buffer and the work buffer
SecureMem buf(lBufSize), workBuf(LZO1X_1_MEM_COMPRESS);
@@ -129,20 +130,25 @@ int EncryptText(const SecureWString* psText,
// get a new initialization vector (IV)
randGen.GetData(buf, 16);
- word8* pCryptBuf = &buf[16];
+ //word8* pCryptBuf = &buf[16];
+ word32 lBufPos = 16;
// create header and copy it to the buffer
CryptTextHeader header;
memcpy(header.Magic, CRYPTTEXT_MAGIC, sizeof(CRYPTTEXT_MAGIC));
header.Version = static_cast(CRYPTTEXT_VERSION);
header.TextBytes = lTextLen;
- memcpy(pCryptBuf, &header, HEADER_SIZE);
+ //memcpy(pCryptBuf, &header, HEADER_SIZE);
+ buf.Copy(lBufPos, reinterpret_cast(&header), HEADER_SIZE);
+ lBufPos += HEADER_SIZE;
// compress the text
lzo_uint comprLen;
- lzo1x_1_compress(asTextUtf8.Bytes(), lTextLen, pCryptBuf + HEADER_SIZE,
+ lzo1x_1_compress(asTextUtf8.Bytes(), lTextLen, &buf[lBufPos],
&comprLen, workBuf);
+ lBufPos += comprLen;
+
// destroy the text buffer and the work memory
asTextUtf8.Clear();
workBuf.Clear();
@@ -170,16 +176,17 @@ int EncryptText(const SecureWString* psText,
// compute the HMAC of the compressed message
word8 hmac[32];
- sha256_hmac_update(hashCtx, pCryptBuf, HEADER_SIZE + comprLen);
+ sha256_hmac_update(hashCtx, &buf[16], HEADER_SIZE + comprLen);
sha256_hmac_finish(hashCtx, hmac);
hashCtx.Clear();
// copy the HMAC to the buffer
- memcpy(pCryptBuf + HEADER_SIZE + comprLen, hmac, HMAC_LENGTH);
+ //memcpy(pCryptBuf + HEADER_SIZE + comprLen, hmac, HMAC_LENGTH);
+ buf.Copy(lBufPos, hmac, HMAC_LENGTH);
// now encrypt the buffer (*with* HMAC)
- aes_crypt_cbc(cryptCtx, AES_ENCRYPT, lCryptLen, iv, pCryptBuf, pCryptBuf);
+ aes_crypt_cbc(cryptCtx, AES_ENCRYPT, lCryptLen, iv, &buf[16], &buf[16]);
cryptCtx.Clear();
@@ -190,10 +197,10 @@ int EncryptText(const SecureWString* psText,
base64_encode(nullptr, &outBufSize, nullptr, lConvertLen, BASE64_LINE_LENGTH);
// create a new buffer for base64
- SecureMem outBuf(outBufSize + 1);
+ SecureMem outBuf(outBufSize);
base64_encode(outBuf, &outBufSize, buf, lConvertLen, BASE64_LINE_LENGTH);
- outBuf.back() = '\0';
+ //outBuf.back() = '\0';
// copy the output buffer to the clipboard
SetClipboardTextBufAnsi(reinterpret_cast(outBuf.c_str()));
@@ -230,8 +237,8 @@ int DecryptText(const SecureWString* psText,
if (psText->IsStrEmpty())
return CRYPTTEXT_ERROR_NOTEXT;
lTextLen = psText->StrLen();
- asText.New(lTextLen + 1);
- for (word32 i = 0; i <= lTextLen; i++) // also copy terminating zero
+ asText.NewStr(lTextLen);
+ for (word32 i = 0; i < lTextLen; i++)
asText[i] = (*psText)[i];
}
else {
@@ -249,7 +256,7 @@ int DecryptText(const SecureWString* psText,
return CRYPTTEXT_ERROR_TEXTCORRUPTED;
SecureMem buf(bufSize);
- base64_decode(buf, &bufSize, reinterpret_cast(asText.Data()), lTextLen);
+ base64_decode(buf, &bufSize, asText.Bytes(), lTextLen);
asText.Clear();
@@ -257,7 +264,7 @@ int DecryptText(const SecureWString* psText,
if ((bufSize & 0x0F) != 0)
return CRYPTTEXT_ERROR_TEXTCORRUPTED;
- word8* pCryptBuf = &buf[16];
+ //word8* pCryptBuf = &buf[16];
word32 lHmacLen = (nVersion == 0) ? 16 : HMAC_LENGTH;
word32 lCryptLen = bufSize - 16;
@@ -292,20 +299,20 @@ int DecryptText(const SecureWString* psText,
hashCtx.Clear();
// verify the HMAC
- if (memcmp(pCryptBuf + lCryptLen, hmac, lHmacLen) != 0)
+ if (memcmp(&buf[16 + lCryptLen], hmac, lHmacLen) != 0)
return CRYPTTEXT_ERROR_BADKEY;
// decrypt the buffer
- aes_crypt_cbc(cryptCtx, AES_DECRYPT, lCryptLen, iv, pCryptBuf, pCryptBuf);
+ aes_crypt_cbc(cryptCtx, AES_DECRYPT, lCryptLen, iv, &buf[16], &buf[16]);
// get the text length
- memcpy(&header.TextBytes, pCryptBuf, lHeaderSize);
+ memcpy(&header.TextBytes, &buf[16], lHeaderSize);
}
else {
// decrypt the first block and check the magic string
- aes_crypt_cbc(cryptCtx, AES_DECRYPT, 16, iv, pCryptBuf, pCryptBuf);
+ aes_crypt_cbc(cryptCtx, AES_DECRYPT, 16, iv, &buf[16], &buf[16]);
- memcpy(&header, pCryptBuf, HEADER_SIZE);
+ memcpy(&header, &buf[16], HEADER_SIZE);
if (memcmp(header.Magic, CRYPTTEXT_MAGIC, sizeof(CRYPTTEXT_MAGIC)) != 0)
return CRYPTTEXT_ERROR_BADKEY;
@@ -320,21 +327,21 @@ int DecryptText(const SecureWString* psText,
// now decrypt the rest
if (lCryptLen > 16)
aes_crypt_cbc(cryptCtx, AES_DECRYPT, lCryptLen - 16, iv,
- pCryptBuf + 16, pCryptBuf + 16);
+ &buf[32], &buf[32]);
if (encHmac)
lCryptLen -= 16 - bLastBlock;
// compute the HMAC of the plaintext
- sha256_hmac_update(hashCtx, pCryptBuf, (encHmac) ?
+ sha256_hmac_update(hashCtx, &buf[16], encHmac ?
lCryptLen - lHmacLen : lCryptLen);
sha256_hmac_finish(hashCtx, hmac);
hashCtx.Clear();
// verify the HMAC
- if (memcmp((encHmac) ? pCryptBuf + lCryptLen - lHmacLen :
- pCryptBuf + lCryptLen, hmac, lHmacLen) != 0)
+ if (memcmp(encHmac ? &buf[16 + lCryptLen - lHmacLen] :
+ &buf[16 + lCryptLen], hmac, lHmacLen) != 0)
return CRYPTTEXT_ERROR_BADKEY;
}
@@ -354,7 +361,7 @@ int DecryptText(const SecureWString* psText,
// decompress this buffer
lzo_uint decomprLen = header.TextBytes;
- if (lzo1x_decompress_safe(pCryptBuf + lHeaderSize, lToDecompr,
+ if (lzo1x_decompress_safe(&buf[16 + lHeaderSize], lToDecompr,
reinterpret_cast(asOutBuf.Data()), &decomprLen, nullptr) != LZO_E_OK)
return CRYPTTEXT_ERROR_DECOMPRFAILED;
diff --git a/src/crypto/chacha.c b/src/crypto/chacha.c
index 67b036c..fb88089 100644
--- a/src/crypto/chacha.c
+++ b/src/crypto/chacha.c
@@ -31,9 +31,12 @@ Modified for Password Tech by C.T.
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
#define DEFAULT_NROUNDS 20
+
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
+
void chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
{
const char *constants;
@@ -205,9 +208,113 @@ void chacha_decrypt_bytes(chacha_ctx *x,const u8 *c,u8 *m,u32 bytes)
}
void chacha_keystream_bytes(chacha_ctx *x,u8 *stream,u32 bytes)
{
+ /* alternative:
memset(stream, 0, bytes);
chacha_encrypt_bytes(x,stream,stream,bytes);
+ */
+ u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ u8 *c = stream;
+ u8 *ctarget;
+ u8 tmp[64];
+ int i;
+ if (!bytes) return;
+ j0 = x->input[0];
+ j1 = x->input[1];
+ j2 = x->input[2];
+ j3 = x->input[3];
+ j4 = x->input[4];
+ j5 = x->input[5];
+ j6 = x->input[6];
+ j7 = x->input[7];
+ j8 = x->input[8];
+ j9 = x->input[9];
+ j10 = x->input[10];
+ j11 = x->input[11];
+ j12 = x->input[12];
+ j13 = x->input[13];
+ j14 = x->input[14];
+ j15 = x->input[15];
+ for (;;) {
+ if (bytes < 64) {
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = x->nrounds;i > 0;i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12)
+ QUARTERROUND( x1, x5, x9,x13)
+ QUARTERROUND( x2, x6,x10,x14)
+ QUARTERROUND( x3, x7,x11,x15)
+ QUARTERROUND( x0, x5,x10,x15)
+ QUARTERROUND( x1, x6,x11,x12)
+ QUARTERROUND( x2, x7, x8,x13)
+ QUARTERROUND( x3, x4, x9,x14)
+ }
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+ j12 = PLUSONE(j12);
+ if (!j12) {
+ j13 = PLUSONE(j13);
+ }
+ U32TO8_LITTLE(c + 0,x0);
+ U32TO8_LITTLE(c + 4,x1);
+ U32TO8_LITTLE(c + 8,x2);
+ U32TO8_LITTLE(c + 12,x3);
+ U32TO8_LITTLE(c + 16,x4);
+ U32TO8_LITTLE(c + 20,x5);
+ U32TO8_LITTLE(c + 24,x6);
+ U32TO8_LITTLE(c + 28,x7);
+ U32TO8_LITTLE(c + 32,x8);
+ U32TO8_LITTLE(c + 36,x9);
+ U32TO8_LITTLE(c + 40,x10);
+ U32TO8_LITTLE(c + 44,x11);
+ U32TO8_LITTLE(c + 48,x12);
+ U32TO8_LITTLE(c + 52,x13);
+ U32TO8_LITTLE(c + 56,x14);
+ U32TO8_LITTLE(c + 60,x15);
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+ }
+ x->input[12] = j12;
+ x->input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+ }
}
+
/* Test vectors taken from RFC 7539 */
static const u8 test_key[3][32] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
diff --git a/src/main/About.cpp b/src/main/About.cpp
index afa9397..2cb096d 100644
--- a/src/main/About.cpp
+++ b/src/main/About.cpp
@@ -92,9 +92,9 @@ void __fastcall TAboutForm::LinkClick(TObject *Sender, const UnicodeString Link,
//---------------------------------------------------------------------------
void __fastcall TAboutForm::SetDonorUI(void)
{
- if (g_asDonorInfo.IsEmpty())
- AboutForm->DonorLbl->Caption = "Community";
+ if (g_donorInfo.Valid == DONOR_KEY_VALID)
+ AboutForm->DonorLbl->Caption = TRL("Donor ID:") + " " + g_donorInfo.Id;
else
- AboutForm->DonorLbl->Caption = TRL("Donor ID:") + " " + g_asDonorInfo;
+ AboutForm->DonorLbl->Caption = "Community";
}
//---------------------------------------------------------------------------
diff --git a/src/main/About.dfm b/src/main/About.dfm
index 9a6cb9d..79da460 100644
Binary files a/src/main/About.dfm and b/src/main/About.dfm differ
diff --git a/src/main/Configuration.cpp b/src/main/Configuration.cpp
index c89db49..f5a5390 100644
--- a/src/main/Configuration.cpp
+++ b/src/main/Configuration.cpp
@@ -53,6 +53,15 @@ const int RANDOM_POOL_CIPHER_INFO[NUM_RANDOM_POOL_CIPHERS][2] =
//{ 256, 128 }
};
+const std::vector> AppIconNames = {
+ { "Default (dark)", "A" },
+ { "Blue", "Icon_Blue" },
+ { "Red", "Icon_Red" },
+ { "Orange", "Icon_Orange" },
+ { "Green", "Icon_Green" },
+ { "Colors", "Icon_Colors" }
+};
+
//---------------------------------------------------------------------------
__fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
: TForm(Owner) //, m_pLangList(nullptr)
@@ -70,7 +79,15 @@ __fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
UiStylesList->Items->Add(sName);
}
- for (int i = 0; i < NUM_RANDOM_POOL_CIPHERS; i++) {
+ auto icon = std::make_unique();
+ int i = 0;
+ for (const auto& p : AppIconNames) {
+ icon->LoadFromResourceName(reinterpret_cast(HInstance), p.second);
+ AppIconImageList->AddIcon(icon.get());
+ AppIconList->ItemsEx->AddItem(p.first, i++, -1, -1, -1, nullptr);
+ }
+
+ for (i = 0; i < NUM_RANDOM_POOL_CIPHERS; i++) {
WString sCipher = TRLFormat("%1 (%2-bit key, operates on %3-bit blocks)",
{ RANDOM_POOL_CIPHER_NAMES[i],
IntToStr(RANDOM_POOL_CIPHER_INFO[i][0]),
@@ -78,7 +95,7 @@ __fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
RandomPoolCipherList->Items->Add(sCipher);
}
- for (int i = 0; i <= 10; i++)
+ for (i = 0; i <= 10; i++)
BenchmarkMemList->Items->Add(IntToStr(1 << i) + " MB");
BenchmarkMemList->ItemIndex = 6;
@@ -86,6 +103,7 @@ __fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
TRLCaption(this);
TRLCaption(GeneralSheet);
TRLCaption(UiStyleLbl);
+ TRLCaption(AppIconLbl);
TRLCaption(ChangeFontLbl);
TRLCaption(SelectFontBtn);
TRLCaption(ShowSysTrayIconConstCheck);
@@ -113,7 +131,6 @@ __fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
TRLCaption(HotKeyView->Columns->Items[0]);
TRLCaption(HotKeyView->Columns->Items[1]);
- int i;
for (i = 0; i < HotKeyActionsList->Items->Count; i++)
HotKeyActionsList->Items->Strings[i] =
TRL(HotKeyActionsList->Items->Strings[i]);
@@ -130,6 +147,8 @@ __fastcall TConfigurationDlg::TConfigurationDlg(TComponent* Owner)
TRLCaption(LanguageSheet);
TRLCaption(SelectLanguageLbl);
+ TRLCaption(InstallLanguageBtn);
+ TRLCaption(RemoveLanguageBtn);
TRLCaption(DatabaseSheet);
TRLCaption(ClearClipCloseLockCheck);
@@ -177,6 +196,7 @@ void __fastcall TConfigurationDlg::SaveConfig(void)
void __fastcall TConfigurationDlg::GetOptions(Configuration& config)
{
config.UiStyleName = UiStylesList->Text;
+ config.AppIconName = AppIconList->Text;
config.GUIFontString = FontToString(FontDlg->Font);
config.AutoClearClip = AutoClearClipCheck->Checked;
config.AutoClearClipTime = AutoClearClipTimeSpinBtn->Position;
@@ -197,7 +217,7 @@ void __fastcall TConfigurationDlg::GetOptions(Configuration& config)
config.FileEncoding = CharacterEncoding(CharEncodingGroup->ItemIndex);
config.FileNewlineChar = NewlineChar(NewlineCharGroup->ItemIndex);
config.HotKeys = m_hotKeys;
- config.LanguageIndex = LanguageList->ItemIndex;
+ config.Language = g_languages.at(LanguageList->ItemIndex);
//config.Database.ClearClipMinimize = ClearClipMinimizeCheck->Checked;
config.Database.ClearClipCloseLock = ClearClipCloseLockCheck->Checked;
config.Database.LockMinimize = LockMinimizeCheck->Checked;
@@ -229,6 +249,7 @@ void __fastcall TConfigurationDlg::SetOptions(const Configuration& config)
if (nIndex < 0)
nIndex = UiStylesList->Items->IndexOf("Windows");
UiStylesList->ItemIndex = nIndex;
+ AppIconList->ItemIndex = std::max(0, AppIconList->Items->IndexOf(config.AppIconName));
StringToFont(config.GUIFontString, FontDlg->Font);
ShowFontSample(FontDlg->Font);
RandomPoolCipherList->ItemIndex = config.RandomPoolCipher;
@@ -252,7 +273,8 @@ void __fastcall TConfigurationDlg::SetOptions(const Configuration& config)
UpdateCheckGroup->ItemIndex = config.AutoCheckUpdates;
CharEncodingGroup->ItemIndex = static_cast(config.FileEncoding);
NewlineCharGroup->ItemIndex = static_cast(config.FileNewlineChar);
- LanguageList->ItemIndex = config.LanguageIndex;
+ auto it = std::find(g_languages.begin(), g_languages.end(), config.Language.Code);
+ LanguageList->ItemIndex = it != g_languages.end() ? it - g_languages.begin() : 0;
LanguageListSelect(this);
m_hotKeys = config.HotKeys;
UpdateHotKeyList();
@@ -279,11 +301,10 @@ void __fastcall TConfigurationDlg::SetOptions(const Configuration& config)
DefaultAutotypeSeqBox->Text = config.Database.DefaultAutotypeSequence;
}
//---------------------------------------------------------------------------
-void __fastcall TConfigurationDlg::SetLanguageList(
- const std::vector& languages)
+void __fastcall TConfigurationDlg::LoadLanguages(void)
{
- m_langList = languages;
- for (const auto& entry : m_langList)
+ LanguageList->Clear();
+ for (const auto& entry : g_languages)
{
LanguageList->Items->Add(FormatW("%1 (v%2)", { entry.Name,
entry.Version }));
@@ -468,9 +489,9 @@ void __fastcall TConfigurationDlg::BenchmarkBtnClick(TObject *Sender)
rp.SetCipher(static_cast(i));
Stopwatch clock;
rp.GetData(buf.get(), lBufSize);
- double rate = lDataSizeMB / clock.ElapsedSeconds();
- sResult += "\n" + FormatW("%1: %2 MB/s", { RANDOM_POOL_CIPHER_NAMES[i],
- FormatFloat("0.00", rate) });
+ long double rate = lDataSizeMB / clock.ElapsedSeconds();
+ sResult += "\n" + Format("%s: %.2f MB/s", ARRAYOFCONST((
+ RANDOM_POOL_CIPHER_NAMES[i], rate)));
}
Screen->Cursor = crDefault;
MsgBox(TRLFormat("Benchmark results (data size: %1 MB):",
@@ -480,8 +501,8 @@ void __fastcall TConfigurationDlg::BenchmarkBtnClick(TObject *Sender)
void __fastcall TConfigurationDlg::ConvertLangFileBtnClick(TObject *Sender)
{
int nIndex = LanguageList->ItemIndex;
- if (nIndex > 0 && nIndex < m_langList.size()) {
- const auto& entry = m_langList[nIndex];
+ if (nIndex > 0 && nIndex < g_languages.size()) {
+ const auto& entry = g_languages[nIndex];
//if (SameText(ExtractFileExt(entry.FileName), ".lng")) {
TopMostManager::GetInstance().NormalizeTopMosts(this);
bool blSuccess = SaveDlg->Execute();
@@ -505,11 +526,12 @@ void __fastcall TConfigurationDlg::LanguageListSelect(TObject *Sender)
{
bool blEnabled = false;
int nIndex = LanguageList->ItemIndex;
- if (nIndex > 0 && nIndex < m_langList.size()) {
- const auto& entry = m_langList[nIndex];
+ if (nIndex > 0 && nIndex < g_languages.size()) {
+ const auto& entry = g_languages[nIndex];
blEnabled = SameText(ExtractFileExt(entry.FileName), ".lng");
}
ConvertLangFileBtn->Enabled = blEnabled;
+ RemoveLanguageBtn->Enabled = nIndex > 0;
}
//---------------------------------------------------------------------------
void __fastcall TConfigurationDlg::SelectFontMenu_RestoreDefaultClick(TObject *Sender)
@@ -527,4 +549,84 @@ void __fastcall TConfigurationDlg::LoadProfileStartupCheckClick(TObject *Sender)
LoadProfileBox->Enabled = LoadProfileStartupCheck->Checked;
}
//---------------------------------------------------------------------------
+void __fastcall TConfigurationDlg::InstallLanguageBtnClick(TObject *Sender)
+{
+ TopMostManager::GetInstance().NormalizeTopMosts(this);
+ bool blSuccess = OpenDlg->Execute();
+ TopMostManager::GetInstance().RestoreTopMosts(this);
+ if (!blSuccess) return;
+
+ WString sMsg;
+ try {
+ WString sSrc = OpenDlg->FileName;
+ LanguageSupport ls(sSrc, true);
+ if (std::find(g_languages.begin(), g_languages.end(), ls.LanguageCode)
+ != g_languages.end())
+ {
+ throw Exception(TRL("Language already installed"));
+ }
+
+ const auto destinations = { g_sAppDataPath, g_sExePath };
+ WString sDest;
+ for (const auto& sPath : destinations) {
+ if (sPath.IsEmpty()) continue;
+ sDest = sPath + ExtractFileName(sSrc);
+ if (FileExists(sDest)) {
+ throw Exception(TRLFormat("Language file already exists:\n\"%1\"", { sDest }));
+ }
+ if (CopyFile(sSrc.c_str(), sDest.c_str(), true)) {
+ LanguageEntry e;
+ e.FileName = sSrc;
+ e.Code = ls.LanguageCode;
+ e.Name = ls.LanguageName;
+ e.Version = ls.LanguageVersion;
+ g_languages.push_back(e);
+ int nIndex = LanguageList->ItemIndex;
+ LoadLanguages();
+ LanguageList->ItemIndex = nIndex;
+ MsgBox(TRLFormat("Language \"%1\" installed successfully.", { ls.LanguageName }),
+ MB_ICONINFORMATION);
+ return;
+ }
+ break;
+ }
+
+ sMsg = TRLFormat("Could not copy file \"%1\" to\n\"%2\"", { sSrc, sDest });
+ }
+ catch (Exception& e) {
+ sMsg = e.Message;
+ }
+
+ MsgBox(TRLFormat("Could not install language:\n%1.", { sMsg }), MB_ICONERROR);
+}
+//---------------------------------------------------------------------------
+void __fastcall TConfigurationDlg::RemoveLanguageBtnClick(TObject *Sender)
+{
+ int nIndex = LanguageList->ItemIndex;
+ if (nIndex > 0 && nIndex < g_languages.size()) {
+ auto e = g_languages[nIndex];
+ if (MsgBox(TRLFormat("Are you sure you want to remove\n\"%1\"?", { e.Name }),
+ MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON2) == IDYES)
+ {
+ if (DeleteFile(e.FileName.c_str())) {
+ g_languages.erase(g_languages.begin() + nIndex);
+ LoadLanguages();
+ LanguageList->ItemIndex = 0;
+ MsgBox(TRLFormat("Language \"%1\" successfully removed.", { e.Name }),
+ MB_ICONINFORMATION);
+ }
+ else {
+ MsgBox(TRLFormat("Could not delete file\n\"%1\".", { e.FileName }),
+ MB_ICONERROR);
+ }
+ }
+ }
+}
+//---------------------------------------------------------------------------
+void __fastcall TConfigurationDlg::SetDonorUI(void)
+{
+ AppIconLbl->Enabled = g_donorInfo.Valid == DONOR_KEY_VALID;
+ AppIconList->Enabled = g_donorInfo.Valid == DONOR_KEY_VALID;
+}
+//---------------------------------------------------------------------------
diff --git a/src/main/Configuration.dfm b/src/main/Configuration.dfm
index f21c26f..366e75e 100644
--- a/src/main/Configuration.dfm
+++ b/src/main/Configuration.dfm
@@ -3,8 +3,8 @@ object ConfigurationDlg: TConfigurationDlg
Top = 187
BorderIcons = [biSystemMenu, biMaximize]
Caption = 'Configuration'
- ClientHeight = 519
- ClientWidth = 551
+ ClientHeight = 517
+ ClientWidth = 552
Color = clBtnFace
Constraints.MinHeight = 456
Constraints.MinWidth = 443
@@ -84,6 +84,17 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Bottom = 4
Caption = 'User interface style:'
end
+ object AppIconLbl: TLabel
+ Left = 280
+ Top = 20
+ Width = 99
+ Height = 17
+ Margins.Left = 4
+ Margins.Top = 4
+ Margins.Right = 4
+ Margins.Bottom = 4
+ Caption = 'Application icon:'
+ end
object SelectFontBtn: TButton
Left = 10
Top = 114
@@ -96,7 +107,7 @@ object ConfigurationDlg: TConfigurationDlg
Caption = 'Select font'
DropDownMenu = SelectFontMenu
Style = bsSplitButton
- TabOrder = 1
+ TabOrder = 2
OnClick = SelectFontBtnClick
end
object ShowSysTrayIconConstCheck: TCheckBox
@@ -109,7 +120,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Right = 4
Margins.Bottom = 4
Caption = 'Show system tray icon constantly'
- TabOrder = 2
+ TabOrder = 3
end
object MinimizeToSysTrayCheck: TCheckBox
Left = 10
@@ -121,7 +132,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Right = 4
Margins.Bottom = 4
Caption = 'Minimize program to system tray'
- TabOrder = 3
+ TabOrder = 4
end
object AutotypeDelayBox: TEdit
Left = 326
@@ -133,7 +144,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Right = 4
Margins.Bottom = 4
AutoSelect = False
- TabOrder = 5
+ TabOrder = 6
Text = '0'
end
object AutotypeDelaySpinBtn: TUpDown
@@ -147,7 +158,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Bottom = 4
Associate = AutotypeDelayBox
Max = 1000
- TabOrder = 6
+ TabOrder = 7
end
object MinimizeAutotypeCheck: TCheckBox
Left = 10
@@ -159,7 +170,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Right = 4
Margins.Bottom = 4
Caption = 'Minimize before performing autotype'
- TabOrder = 4
+ TabOrder = 5
end
object AskBeforeExitCheck: TCheckBox
Left = 10
@@ -172,7 +183,7 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Bottom = 4
Anchors = [akLeft, akTop, akRight]
Caption = 'Ask before exiting application'
- TabOrder = 7
+ TabOrder = 8
end
object LaunchSystemStartupCheck: TCheckBox
Left = 10
@@ -184,19 +195,18 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Right = 4
Margins.Bottom = 4
Caption = 'Launch application on system startup (for current user)'
- TabOrder = 8
+ TabOrder = 11
end
object UiStylesList: TComboBox
Left = 10
Top = 44
- Width = 492
+ Width = 241
Height = 25
Margins.Left = 4
Margins.Top = 4
Margins.Right = 4
Margins.Bottom = 4
Style = csDropDownList
- Anchors = [akLeft, akTop, akRight]
Sorted = True
TabOrder = 0
end
@@ -226,6 +236,20 @@ object ConfigurationDlg: TConfigurationDlg
Anchors = [akLeft, akTop, akRight]
TabOrder = 10
end
+ object AppIconList: TComboBoxEx
+ Left = 280
+ Top = 44
+ Width = 222
+ Height = 26
+ Margins.Left = 4
+ Margins.Top = 4
+ Margins.Right = 4
+ Margins.Bottom = 4
+ ItemsEx = <>
+ Style = csExDropDownList
+ TabOrder = 1
+ Images = AppIconImageList
+ end
end
object SecuritySheet: TTabSheet
Margins.Left = 4
@@ -652,8 +676,8 @@ object ConfigurationDlg: TConfigurationDlg
OnSelect = LanguageListSelect
end
object ConvertLangFileBtn: TButton
- Left = 10
- Top = 78
+ Left = 220
+ Top = 77
Width = 248
Height = 31
Margins.Left = 4
@@ -662,9 +686,35 @@ object ConfigurationDlg: TConfigurationDlg
Margins.Bottom = 4
Caption = 'Convert to new PO file format...'
Enabled = False
- TabOrder = 1
+ TabOrder = 3
OnClick = ConvertLangFileBtnClick
end
+ object InstallLanguageBtn: TButton
+ Left = 10
+ Top = 77
+ Width = 100
+ Height = 31
+ Margins.Left = 4
+ Margins.Top = 4
+ Margins.Right = 4
+ Margins.Bottom = 4
+ Caption = 'Install...'
+ TabOrder = 1
+ OnClick = InstallLanguageBtnClick
+ end
+ object RemoveLanguageBtn: TButton
+ Left = 118
+ Top = 77
+ Width = 94
+ Height = 31
+ Margins.Left = 4
+ Margins.Top = 4
+ Margins.Right = 4
+ Margins.Bottom = 4
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = RemoveLanguageBtnClick
+ end
end
object DatabaseSheet: TTabSheet
Margins.Left = 4
@@ -998,11 +1048,21 @@ object ConfigurationDlg: TConfigurationDlg
Top = 452
end
object SelectFontMenu: TPopupMenu
- Left = 31
- Top = 408
+ Left = 29
+ Top = 470
object SelectFontMenu_RestoreDefault: TMenuItem
Caption = 'Restore Default'
OnClick = SelectFontMenu_RestoreDefaultClick
end
end
+ object AppIconImageList: TImageList
+ Left = 489
+ Top = 405
+ end
+ object OpenDlg: TOpenDialog
+ Filter = 'Language files|*.po|All files|*.*'
+ Title = 'Select language file to install'
+ Left = 31
+ Top = 163
+ end
end
diff --git a/src/main/Configuration.h b/src/main/Configuration.h
index 7adc406..e4f1980 100644
--- a/src/main/Configuration.h
+++ b/src/main/Configuration.h
@@ -30,6 +30,8 @@
#include
#include
#include
+#include
+#include
#include