summaryrefslogtreecommitdiff
path: root/plugins/LangMan/langpack.c
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-05-19 14:01:09 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-05-19 14:01:09 +0000
commit97c496705a49c6cb8fc228b0397d9c7793ad6fb7 (patch)
treeaebb4b88955cb99cb564bd5deeefc047977d1f73 /plugins/LangMan/langpack.c
parent9dd5697955f03c183d5689e4e8dd0fe8927e3817 (diff)
added LangMan
git-svn-id: http://svn.miranda-ng.org/main/trunk@74 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/LangMan/langpack.c')
-rw-r--r--plugins/LangMan/langpack.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/plugins/LangMan/langpack.c b/plugins/LangMan/langpack.c
new file mode 100644
index 0000000000..6ce827c71a
--- /dev/null
+++ b/plugins/LangMan/langpack.c
@@ -0,0 +1,456 @@
+/*
+
+'Language Pack Manager'-Plugin for Miranda IM
+
+Copyright (C) 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 (LangMan-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+/************************* Load ***************************************/
+
+static 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);
+}
+
+static 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)
+{
+ char *p;
+ /* 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(LANGPACK_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 Language Pack Version 1
+ Language: (optional)
+ Locale: 0809
+ Authors: Miranda IM Development Team (multiple tags allowed)
+ Author-email: project-info at miranda-im.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 'LangMan-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);
+ buf = line;
+
+ if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') {
+ pack->codepage = CP_UTF8;
+ buf += 3;
+ }
+
+ if ( lstrcmpA(buf, pszFileVersionHeader )) {
+ fclose(fp);
+ return FALSE;
+ }
+ pack->flags = LPF_NOLOCALE;
+ 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 & LPF_NOLOCALE)) {
+ pack->Locale = MAKELCID((USHORT)strtol(pszColon+1, NULL, 16), SORT_DEFAULT);
+ if(pack->Locale) pack->flags &= ~LPF_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 */
+ }
+ CleanupLanguage(szLanguageA);
+ CleanupAuthors(pack->szAuthors);
+ CleanupEmail(pack->szAuthorEmail);
+ CleanupLastModifiedUsing(pack->szLastModifiedUsing,sizeof(pack->szLastModifiedUsing));
+ /* codepage */
+ if(!(pack->flags&LPF_NOLOCALE))
+ if(GetLocaleInfoA(pack->Locale,LOCALE_IDEFAULTANSICODEPAGE,line,6))
+ pack->codepage=(WORD)atoi(line); /* CP_ACP on error */
+ /* language */
+#if defined(_UNICODE)
+ MultiByteToWideChar(pack->codepage,0,szLanguageA,-1,pack->szLanguage,SIZEOF(pack->szLanguage));
+#else
+ lstrcpyA(pack->szLanguage,szLanguageA); /* buffer safe */
+#endif
+ /* 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)," Language Pack"); /* buffer safe */
+ fclose(fp);
+ return TRUE;
+}
+
+/************************* Enum ***************************************/
+
+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("Plugins\\Language\\"));
+ }
+ /* 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,BOOL fEnglishDefault,WPARAM wParam,LPARAM lParam)
+{
+ BOOL fPackFound=FALSE;
+ BOOL res=FALSE;
+ LANGPACK_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|=LPF_ENABLED;
+ fPackFound=TRUE;
+ /* callback */
+ if(callback!=NULL) res=callback(&pack,wParam,lParam);
+ if(!res) { FindClose(hFind); return FALSE; }
+ }
+ } while(FindNextFile(hFind,&wfd));
+ FindClose(hFind);
+ }
+ }
+
+ /* default: English (GB) */
+ if(fEnglishDefault && callback!=NULL) {
+ ZeroMemory(&pack,sizeof(pack));
+ pack.Locale=LOCALE_USER_DEFAULT; /* miranda uses default locale in this case */
+ lstrcpy(pack.szLanguage,_T("English (default)")); /* buffer safe */
+ lstrcpyA(pack.szAuthors,"Miranda IM Development Team"); /* buffer safe */
+ lstrcpyA(pack.szAuthorEmail,"project-info at miranda-im.org"); /* buffer safe */
+ CleanupEmail(pack.szAuthorEmail); /* correct " at " */
+ CleanupLastModifiedUsing(pack.szLastModifiedUsing,sizeof(pack.szLastModifiedUsing));
+ /* file date */
+ if(GetModuleFileName(NULL,pack.szFileName,SIZEOF(pack.szFileName))) {
+ HANDLE hFile;
+ hFile=CreateFile(pack.szFileName,0,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
+ if(hFile!=INVALID_HANDLE_VALUE) {
+ GetFileTime(hFile,NULL,NULL,&pack.ftFileDate);
+ CloseHandle(hFile);
+ }
+ }
+ pack.flags=LPF_NOLOCALE|LPF_DEFAULT;
+ if(!fPackFound) pack.flags|=LPF_ENABLED;
+ /* callback */
+ if(!callback(&pack,wParam,lParam)) return FALSE;
+ }
+
+ /* 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 LANGPACK_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;
+ }
+}
+
+/************************* Switch *************************************/
+
+BOOL EnablePack(const LANGPACK_INFO *pack,const TCHAR *pszFilePattern)
+{
+ TCHAR szFrom[MAX_PATH],szDest[MAX_PATH];
+ HANDLE hFind;
+ WIN32_FIND_DATA wfd;
+
+ /* disable previous pack */
+ 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;
+ /* 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(pack->flags&LPF_DEFAULT) return TRUE;
+ 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,BOOL fDisableAll)
+{
+ TCHAR szFrom[MAX_PATH],szDest[MAX_PATH],szDir[MAX_PATH],*pszFile;
+ BOOL fDirCreated=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 */
+ 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);
+ }
+ }
+} \ No newline at end of file