diff options
Diffstat (limited to 'plugins/ContextHelp/src/helppack.cpp')
-rw-r--r-- | plugins/ContextHelp/src/helppack.cpp | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/plugins/ContextHelp/src/helppack.cpp b/plugins/ContextHelp/src/helppack.cpp new file mode 100644 index 0000000000..c8a21105aa --- /dev/null +++ b/plugins/ContextHelp/src/helppack.cpp @@ -0,0 +1,520 @@ +/*
+Miranda IM Help Plugin
+Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program (Help-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "stdafx.h"
+
+
+/**************************** LOAD PACK ***************************/
+
+void TrimStringSimple(char *str)
+{
+ if (str[lstrlenA(str) - 1] == '\n')
+ str[lstrlenA(str) - 1] = '\0';
+ if (str[lstrlenA(str) - 1] == '\r')
+ str[lstrlenA(str) - 1] = '\0';
+}
+
+void TrimString(char *str)
+{
+ int len, start;
+ len = lstrlenA(str);
+ while (str[0] != '\0' && ((unsigned char)str[len - 1] <= ' '))
+ str[--len] = 0;
+ for (start = 0; str[start] && ((unsigned char)str[start] <= ' '); start++);
+ MoveMemory(str, str + start, len - start + 1);
+}
+
+BOOL IsEmpty(const char *str)
+{
+ int i;
+ for (i = 0; str[i] != '\0'; i++)
+ if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n')
+ return FALSE;
+ return TRUE;
+}
+
+static void CleanupLanguage(char *szLanguage, LCID locale)
+{
+ char *p;
+ if (PRIMARYLANGID(LANGIDFROMLCID(locale)) != LANG_ENGLISH) {
+ /* remove any appended ' (default)' */
+ p = strstr(szLanguage, " (default)");
+ if (p != NULL)
+ *p = '\0';
+ }
+}
+
+static void CleanupAuthors(char *szAuthors)
+{
+ char *p, *p2;
+ /* remove trailing dot (if any) */
+ p = &szAuthors[lstrlenA(szAuthors) - 1];
+ if (*p == '.')
+ *p = '\0';
+ /* remove any extra info in parentheses, which is ok
+ * but makes the list very long for some packs */
+ for (;;) {
+ p = strchr(szAuthors, '(');
+ p2 = strchr(szAuthors, ')');
+ if (p == NULL || p2 == NULL) {
+ p = strchr(szAuthors, '[');
+ p2 = strchr(szAuthors, ']');
+ if (p == NULL || p2 == NULL)
+ break;
+ }
+ if (*(p - 1) == ' ')
+ --p;
+ MoveMemory(p, p2 + 1, lstrlenA(p2 + 1) + 1);
+ }
+}
+
+static void CleanupEmail(char *szAuthorEmail)
+{
+ char c, *p, *pAt;
+ /* replace ' dot ' with '.' (may be removed) */
+ p = strstr(szAuthorEmail, " dot ");
+ if (p != NULL) {
+ *p = '.';
+ MoveMemory(p + 1, p + 5, lstrlenA(p + 5) + 1);
+ }
+ /* also allow ' at ' instead of '@' for obfuscation */
+ p = strstr(szAuthorEmail, " at ");
+ if (p != NULL) {
+ *p = '@';
+ MoveMemory(p + 1, p + 4, lstrlenA(p + 4) + 1);
+ }
+ /* is valid? */
+ pAt = strchr(szAuthorEmail, '@');
+ if (pAt == NULL) {
+ szAuthorEmail[0] = '\0';
+ return;
+ }
+ /* strip-off extra text except exactly one email address
+ * this is needed as a click on the email addres brings up the mail client */
+ for (c = ' ';; c = ',') {
+ p = strchr(pAt, c);
+ if (p != NULL)
+ *p = '\0';
+ p = strrchr(szAuthorEmail, c);
+ if (p != NULL)
+ MoveMemory(szAuthorEmail, p + 1, lstrlenA(p + 1) + 1);
+ if (c == ',')
+ break;
+ }
+ p = strstr(szAuthorEmail, "__");
+ if (p != NULL)
+ MoveMemory(szAuthorEmail, p + 2, lstrlenA(p + 2) + 1);
+ /* lower case */
+ CharLowerA(szAuthorEmail);
+ /* 'none' specified */
+ if (!lstrcmpiA(szAuthorEmail, "none"))
+ szAuthorEmail[0] = '\0';
+}
+
+static void CleanupLastModifiedUsing(char *szLastModifiedUsing, int nSize)
+{
+ char *p;
+ /* remove 'Unicode', as it doesn't matter */
+ p = strstr(szLastModifiedUsing, " Unicode");
+ if (p != NULL) MoveMemory(p, p + 8, lstrlenA(p + 8) + 1);
+ /* use 'Miranda IM' instead of 'Miranda' */
+ p = strstr(szLastModifiedUsing, "Miranda");
+ if (p != NULL && strncmp(p + 7, " IM", 3)) {
+ MoveMemory(p + 10, p + 7, lstrlenA(p + 7) + 1);
+ CopyMemory(p + 7, " IM", 3);
+ }
+ /* use 'Plugin' instead of 'plugin' */
+ p = strstr(szLastModifiedUsing, " plugin");
+ if (p != NULL)
+ CopyMemory(p, " Plugin", 7);
+ /* remove 'v' prefix */
+ p = strstr(szLastModifiedUsing, " v0.");
+ if (p != NULL)
+ MoveMemory(p + 1, p + 2, lstrlenA(p + 2) + 1);
+ /* default if empty */
+ if (!szLastModifiedUsing[0]) {
+ lstrcpynA(szLastModifiedUsing, MIRANDANAME" ", nSize);
+ CallService(MS_SYSTEM_GETVERSIONTEXT, nSize - lstrlenA(szLastModifiedUsing), (LPARAM)szLastModifiedUsing + lstrlenA(szLastModifiedUsing));
+ }
+}
+
+// pack struct should be initialized to zero before call
+// pack->szFileName needs to be filled in before call
+static BOOL LoadPackData(HELPPACK_INFO *pack, BOOL fEnabledPacks, const char *pszFileVersionHeader)
+{
+ FILE *fp;
+ TCHAR szFileName[MAX_PATH];
+ char line[4096], *pszColon, *buf;
+ char szLanguageA[64]; /* same size as pack->szLanguage */
+ /*
+ Miranda Help Pack Version 1
+ Language: (optional)
+ Locale: 0809
+ Authors: Miranda NG Development Team (multiple tags allowed)
+ Author-email: project-info at miranda-ng.org (" at " instead of "@" allowed)
+ Last-Modified-Using: Miranda IM 0.7
+ Plugins-included: (multiple tags allowed)
+ X-FLName: name as used on the file listing (non-standard extension)
+ X-Version: 1.2.3.4 (non-standard extension)
+ see 'Help-Translation.txt' for some header quidelines
+ */
+ if (!GetPackPath(szFileName, sizeof(szFileName), fEnabledPacks, pack->szFileName))
+ return FALSE;
+ fp = _tfopen(szFileName, _T("rt"));
+ if (fp == NULL)
+ return FALSE;
+ fgets(line, sizeof(line), fp);
+ TrimString(line);
+ if (lstrcmpA(line, pszFileVersionHeader)) {
+ fclose(fp);
+ return FALSE;
+ }
+ pack->flags = HPF_NOLOCALE;
+ pack->Locale = LOCALE_USER_DEFAULT;
+ szLanguageA[0] = '\0';
+ while (!feof(fp)) {
+ if (fgets(line, sizeof(line), fp) == NULL)
+ break;
+ TrimString(line);
+ if (IsEmpty(line) || line[0] == ';' || line[0] == '\0')
+ continue;
+ if (line[0] == '[')
+ break;
+ pszColon = strchr(line, ':');
+ if (pszColon == NULL)
+ continue;
+ *pszColon = '\0';
+ TrimString(pszColon + 1);
+ if (!lstrcmpA(line, "Language") && !pack->szLanguage[0])
+ lstrcpynA(szLanguageA, pszColon + 1, sizeof(szLanguageA)); /* buffer safe */
+ else if (!lstrcmpA(line, "Last-Modified-Using") && !pack->szLastModifiedUsing[0])
+ lstrcpynA(pack->szLastModifiedUsing, pszColon + 1, sizeof(pack->szLastModifiedUsing)); /* buffer safe */
+ else if (!lstrcmpA(line, "Authors")) {
+ buf = pack->szAuthors + lstrlenA(pack->szAuthors); /* allow multiple tags */
+ if ((sizeof(pack->szAuthors) - lstrlenA(pack->szAuthors))>0) /* buffer safe */
+ mir_snprintf(buf, sizeof(pack->szAuthors) - lstrlenA(pack->szAuthors), (pack->szAuthors[0] == '\0') ? "%s" : " %s", pszColon + 1);
+ }
+ else if (!lstrcmpA(line, "Author-email") && !pack->szAuthorEmail[0])
+ lstrcpynA(pack->szAuthorEmail, pszColon + 1, sizeof(pack->szAuthorEmail)); /* buffer safe */
+ else if (!lstrcmpA(line, "Locale") && pack->flags&HPF_NOLOCALE) {
+ pack->Locale = MAKELCID((USHORT)strtol(pszColon + 1, NULL, 16), SORT_DEFAULT);
+ if (pack->Locale)
+ pack->flags &= ~HPF_NOLOCALE;
+ }
+ else if (!lstrcmpA(line, "Plugins-included")) {
+ buf = pack->szPluginsIncluded + lstrlenA(pack->szPluginsIncluded); /* allow multiple tags */
+ if ((sizeof(pack->szPluginsIncluded) - lstrlenA(pack->szPluginsIncluded))>0) /* buffer safe */
+ mir_snprintf(buf, sizeof(pack->szPluginsIncluded) - lstrlenA(pack->szPluginsIncluded), (pack->szPluginsIncluded[0] == '\0') ? "%s" : ", %s", CharLowerA(pszColon + 1));
+ }
+ else if (!lstrcmpA(line, "X-Version") && !pack->szVersion[0])
+ lstrcpynA(pack->szVersion, pszColon + 1, sizeof(pack->szVersion)); /* buffer safe */
+ else if (!lstrcmpA(line, "X-FLName") && !pack->szFLName[0])
+ lstrcpynA(pack->szFLName, pszColon + 1, sizeof(pack->szFLName)); /* buffer safe */
+ }
+ /* default */
+ if (PRIMARYLANGID(LANGIDFROMLCID(pack->Locale)) == LANG_ENGLISH && strstr(szLanguageA, " (default)") != NULL)
+ pack->flags |= HPF_DEFAULT;
+ CleanupLanguage(szLanguageA, pack->Locale);
+ CleanupAuthors(pack->szAuthors);
+ CleanupEmail(pack->szAuthorEmail);
+ CleanupLastModifiedUsing(pack->szLastModifiedUsing, sizeof(pack->szLastModifiedUsing));
+ /* codepage */
+ if (!(pack->flags&HPF_NOLOCALE))
+ if (GetLocaleInfoA(pack->Locale, LOCALE_IDEFAULTANSICODEPAGE, line, 6))
+ pack->codepage = (WORD)atoi(line); /* CP_ACP on error */
+ /* language */
+ MultiByteToWideChar(pack->codepage, 0, szLanguageA, -1, pack->szLanguage, sizeof(pack->szLanguage));
+ /* ensure the pack always has a language name */
+ if (!pack->szLanguage[0] && !GetLocaleInfo(pack->Locale, LOCALE_SENGLANGUAGE, pack->szLanguage, sizeof(pack->szLanguage))) {
+ TCHAR *p;
+ lstrcpyn(pack->szLanguage, pack->szFileName, sizeof(pack->szLanguage)); /* buffer safe */
+ p = _tcsrchr(pack->szLanguage, _T('.'));
+ if (p != NULL)
+ *p = '\0';
+ }
+ /* ensure the pack always has a filelisting name */
+ if (!pack->szFLName[0])
+ lstrcatA(lstrcpyA(pack->szFLName, szLanguageA), " Help Pack"); /* buffer safe */
+ fclose(fp);
+
+ return TRUE;
+}
+
+/**************************** ENUM PACKS **************************/
+
+BOOL GetPackPath(TCHAR *pszPath, int nSize, BOOL fEnabledPacks, const TCHAR *pszFile)
+{
+ TCHAR *p;
+ /* main path */
+ if (!GetModuleFileName(NULL, pszPath, nSize))
+ return FALSE;
+ p = _tcsrchr(pszPath, _T('\\'));
+ if (p != NULL)
+ *(p + 1) = _T('\0');
+ /* subdirectory */
+ if (!fEnabledPacks) {
+ if (nSize<(lstrlen(pszPath) + 10))
+ return FALSE;
+ lstrcat(pszPath, _T("Languages\\"));
+ }
+ /* file name */
+ if (pszFile != NULL) {
+ if (nSize < (lstrlen(pszFile) + 11))
+ return FALSE;
+ lstrcat(pszPath, pszFile);
+ }
+
+ return TRUE;
+}
+
+// callback is allowed to be NULL
+// returns TRUE if any pack exists except default
+BOOL EnumPacks(ENUM_PACKS_CALLBACK callback, const TCHAR *pszFilePattern, const char *pszFileVersionHeader, WPARAM wParam, LPARAM lParam)
+{
+ BOOL fPackFound = FALSE;
+ BOOL res = FALSE;
+ HELPPACK_INFO pack;
+ WIN32_FIND_DATA wfd;
+ HANDLE hFind;
+
+ /* enabled packs */
+ if (GetPackPath(pack.szFileName, sizeof(pack.szFileName), TRUE, pszFilePattern)) {
+ hFind = FindFirstFile(pack.szFileName, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if ((lstrlen(wfd.cFileName) < 4) || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+
+ /* get data */
+ ZeroMemory(&pack, sizeof(pack));
+ lstrcpy(pack.szFileName, CharLower(wfd.cFileName)); /* buffer safe */
+ if (LoadPackData(&pack, TRUE, pszFileVersionHeader)) {
+ pack.ftFileDate = wfd.ftLastWriteTime;
+
+ /* enabled? */
+ if (!fPackFound)
+ pack.flags |= HPF_ENABLED;
+ fPackFound = TRUE;
+
+ /* callback */
+ if (callback != NULL)
+ res = callback(&pack, wParam, lParam);
+ if (!res) {
+ FindClose(hFind);
+ return FALSE;
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+ }
+
+ /* disabled packs */
+ if (GetPackPath(pack.szFileName, sizeof(pack.szFileName), FALSE, pszFilePattern)) {
+ hFind = FindFirstFile(pack.szFileName, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if (lstrlen(wfd.cFileName) < 4 || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+
+ /* get data */
+ ZeroMemory(&pack, sizeof(pack));
+ lstrcpy(pack.szFileName, CharLower(wfd.cFileName)); /* buffer safe */
+ if (LoadPackData(&pack, FALSE, pszFileVersionHeader)) {
+ pack.ftFileDate = wfd.ftLastWriteTime;
+ fPackFound = TRUE;
+
+ /* callback */
+ if (callback != NULL)
+ res = callback(&pack, wParam, lParam);
+ if (!res) {
+ FindClose(hFind);
+ return FALSE;
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+ }
+
+ return fPackFound;
+}
+
+BOOL IsPluginIncluded(const HELPPACK_INFO *pack, char *pszFileBaseName)
+{
+ char *p;
+ if (!lstrcmpiA(pszFileBaseName, "png2dib") || !lstrcmpiA(pszFileBaseName, "loadavatars"))
+ return TRUE; /* workaround: does not need no translation */
+ for (p = (char*)pack->szPluginsIncluded;;) {
+ p = strstr(p, CharLowerA(pszFileBaseName));
+ if (p == NULL)
+ return FALSE;
+ if (p == pack->szPluginsIncluded || *(p - 1) == ' ' || *(p - 1) == ',') {
+ p += lstrlenA(pszFileBaseName) + 1;
+ if (*p == ',' || *p == ' ' || *p == 0)
+ return TRUE;
+ }
+ else
+ p += lstrlenA(pszFileBaseName) + 1;
+ }
+
+ return FALSE;
+}
+
+/**************************** SWITCH PACKS ************************/
+
+BOOL EnablePack(const HELPPACK_INFO *pack, const TCHAR *pszFilePattern)
+{
+ TCHAR szFrom[MAX_PATH], szDest[MAX_PATH];
+
+ /* disable previous pack */
+ if (GetPackPath(szFrom, sizeof(szFrom), TRUE, pszFilePattern)) {
+ WIN32_FIND_DATA wfd;
+ HANDLE hFind = FindFirstFile(szFrom, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if (lstrlen(wfd.cFileName) < 4 || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+ /* ensure dir exists */
+ if (GetPackPath(szFrom, sizeof(szFrom), FALSE, NULL))
+ CreateDirectory(szFrom, NULL);
+ /* move file */
+ if (GetPackPath(szFrom, sizeof(szFrom), TRUE, wfd.cFileName))
+ if (GetPackPath(szDest, sizeof(szDest), FALSE, wfd.cFileName))
+ if (!MoveFile(szFrom, szDest) && GetLastError() == ERROR_ALREADY_EXISTS) {
+ DeleteFile(szDest);
+ MoveFile(szFrom, szDest);
+ }
+ break;
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+ }
+
+ /* enable current pack */
+ if (GetPackPath(szFrom, sizeof(szFrom), FALSE, pack->szFileName))
+ if (GetPackPath(szDest, sizeof(szDest), TRUE, pack->szFileName))
+ return MoveFile(szFrom, szDest);
+
+ return FALSE;
+}
+
+void CorrectPacks(const TCHAR *pszFilePattern, const TCHAR *pszDefaultFile, BOOL fDisableAll)
+{
+ TCHAR szFrom[MAX_PATH], szDest[MAX_PATH], szDir[MAX_PATH], *pszFile;
+ BOOL fDirCreated = FALSE, fOneEnabled = FALSE;
+ HANDLE hFind;
+ WIN32_FIND_DATA wfd;
+
+ /* main path */
+ if (!GetModuleFileName(NULL, szDir, sizeof(szDir)))
+ return;
+ pszFile = _tcsrchr(szDir, _T('\\'));
+ if (pszFile != NULL)
+ *pszFile = _T('\0');
+
+ /* move wrongly placed packs from 'Plugins' to 'Language' */
+ mir_sntprintf(szFrom, sizeof(szFrom), _T("%s\\Plugins\\%s"), szDir, pszFilePattern);
+ hFind = FindFirstFile(szFrom, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if (lstrlen(wfd.cFileName) < 4 || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+
+ /* ensure dir exists */
+ if (!fDirCreated && GetPackPath(szFrom, sizeof(szFrom), FALSE, NULL))
+ fDirCreated = CreateDirectory(szFrom, NULL);
+
+ /* move file */
+ if (GetPackPath(szDest, sizeof(szDest), FALSE, wfd.cFileName)) {
+ mir_sntprintf(szFrom, sizeof(szFrom), _T("%s\\Plugins\\%s"), szDir, wfd.cFileName);
+ if (!MoveFile(szFrom, szDest) && GetLastError() == ERROR_ALREADY_EXISTS) {
+ DeleteFile(szDest);
+ MoveFile(szFrom, szDest);
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+
+ /* disable all packs except one */
+ if (GetPackPath(szFrom, sizeof(szFrom), TRUE, pszFilePattern)) {
+ hFind = FindFirstFile(szFrom, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if (lstrlen(wfd.cFileName) < 4 || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+ /* skip first file */
+ fOneEnabled = TRUE;
+ if (!fDisableAll) {
+ fDisableAll = TRUE;
+ continue;
+ }
+ /* ensure dir exists */
+ if (!fDirCreated && GetPackPath(szFrom, sizeof(szFrom), FALSE, NULL))
+ fDirCreated = CreateDirectory(szFrom, NULL);
+ /* move file */
+ if (GetPackPath(szFrom, sizeof(szFrom), TRUE, wfd.cFileName))
+ if (GetPackPath(szDest, sizeof(szDest), FALSE, wfd.cFileName)) {
+ if (!MoveFile(szFrom, szDest) && GetLastError() == ERROR_ALREADY_EXISTS) {
+ DeleteFile(szDest);
+ MoveFile(szFrom, szDest);
+ }
+ }
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+ }
+
+ /* ensure one is enabled if installed */
+ if (!fOneEnabled) {
+ /* try to move english */
+ if (GetPackPath(szFrom, sizeof(szFrom), FALSE, pszDefaultFile))
+ if (GetPackPath(szDest, sizeof(szDest), TRUE, pszDefaultFile))
+ fOneEnabled = MoveFile(szFrom, szDest);
+ /* fallback on other one */
+ if (!fOneEnabled)
+ if (GetPackPath(szFrom, sizeof(szFrom), FALSE, pszFilePattern)) {
+ hFind = FindFirstFile(szFrom, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ continue;
+ if (lstrlen(wfd.cFileName) < 4 || wfd.cFileName[lstrlen(wfd.cFileName) - 4] != _T('.'))
+ continue;
+ /* move first file */
+ if (GetPackPath(szFrom, sizeof(szFrom), FALSE, wfd.cFileName))
+ if (GetPackPath(szDest, sizeof(szDest), TRUE, wfd.cFileName))
+ MoveFile(szFrom, szDest);
+ break;
+ } while (FindNextFile(hFind, &wfd));
+ FindClose(hFind);
+ }
+ }
+ }
+}
|